From 93e365a97a85b2310e90f7b49adbe632c3aa85ea Mon Sep 17 00:00:00 2001 From: Felix Erdmann Date: Thu, 6 Jun 2024 14:55:08 +0200 Subject: [PATCH 1/4] chore: rewrite basesensor to superclass --- .../boards/sensebox_mcu_esp32s2.json | 55 ------- senseBox-bike-atrai-v2/platformio.ini | 7 +- senseBox-bike-atrai-v2/src/main.cpp | 21 ++- .../AccelerationSensor/AccelerationSensor.cpp | 83 +++-------- .../AccelerationSensor/AccelerationSensor.h | 22 +-- .../src/sensors/BaseSensor.cpp | 49 +++++++ .../src/sensors/BaseSensor.h | 35 +++++ .../sensors/DistanceSensor/DistanceSensor.cpp | 101 ++++--------- .../sensors/DistanceSensor/DistanceSensor.h | 29 ++-- .../src/sensors/DustSensor/DustSensor.cpp | 138 +++++++----------- .../src/sensors/DustSensor/DustSensor.h | 24 ++- .../src/sensors/SampleSensor/SampleSensor.cpp | 37 +++++ .../src/sensors/SampleSensor/SampleSensor.h | 19 +++ senseBox-bike-atrai-v2/src/sensors/Sensor.cpp | 6 - senseBox-bike-atrai-v2/src/sensors/Sensor.h | 27 ---- .../TempHumiditySensor/TempHumiditySensor.cpp | 79 +++------- .../TempHumiditySensor/TempHumiditySensor.h | 25 +--- 17 files changed, 303 insertions(+), 454 deletions(-) delete mode 100644 senseBox-bike-atrai-v2/boards/sensebox_mcu_esp32s2.json create mode 100644 senseBox-bike-atrai-v2/src/sensors/BaseSensor.cpp create mode 100644 senseBox-bike-atrai-v2/src/sensors/BaseSensor.h create mode 100644 senseBox-bike-atrai-v2/src/sensors/SampleSensor/SampleSensor.cpp create mode 100644 senseBox-bike-atrai-v2/src/sensors/SampleSensor/SampleSensor.h delete mode 100644 senseBox-bike-atrai-v2/src/sensors/Sensor.cpp delete mode 100644 senseBox-bike-atrai-v2/src/sensors/Sensor.h diff --git a/senseBox-bike-atrai-v2/boards/sensebox_mcu_esp32s2.json b/senseBox-bike-atrai-v2/boards/sensebox_mcu_esp32s2.json deleted file mode 100644 index c031fa6..0000000 --- a/senseBox-bike-atrai-v2/boards/sensebox_mcu_esp32s2.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "build": { - "arduino":{ - "ldscript": "esp32_out.ld" - }, - "core": "esp32", - "extra_flags": [ - "-DARDUINO_SENSEBOX_MCU_ESP32S2", - "-DARDUINO_USB_CDC_ON_BOOT=1", - "-DBOARD_HAS_PSRAM", - "-DARDUINO_USB_MSC_ON_BOOT=1" - ], - "f_cpu": "240000000L", - "f_flash": "80000000L", - "hwids": [ - [ - "0x303A", - "0x81B8" - ], - [ - "0x303A", - "0x81B9" - ], - [ - "0x303A", - "0x81BA" - ] - ], - "flash_mode": "qio", - "mcu": "esp32s2", - "variant": "sensebox_mcu_esp32s2" - }, - "connectivity": [ - "wifi" - ], - "debug": { - "openocd_target": "esp32s2.cfg" - }, - "frameworks": [ - "arduino", - "espidf" - ], - "name": "senseBox MCU S2", - "upload": { - "flash_size": "4MB", - "maximum_ram_size": 327680, - "maximum_size": 4194304, - "use_1200bps_touch": true, - "wait_for_upload_port": true, - "require_upload_port": true, - "speed": 460800 - }, - "vendor": "senseBox", - "url": "https://sensebox.de/" - } \ No newline at end of file diff --git a/senseBox-bike-atrai-v2/platformio.ini b/senseBox-bike-atrai-v2/platformio.ini index 13a1d78..d733dd5 100644 --- a/senseBox-bike-atrai-v2/platformio.ini +++ b/senseBox-bike-atrai-v2/platformio.ini @@ -11,12 +11,8 @@ [env:sensebox_mcu_esp32s2] platform = espressif32 board = sensebox_mcu_esp32s2 -platform_packages = - platformio/framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.17 +platform_packages = platformio/framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.17 framework = arduino -build = - include_dir = lib/sensors -lib_ldf_mode = deep lib_deps = adafruit/Adafruit SSD1306 @ ^2.5.10 adafruit/Adafruit HDC1000 Library@^2.0.2 @@ -26,3 +22,4 @@ lib_deps = stm32duino/STM32duino VL53L8CX@^1.0.3 adafruit/Adafruit MPU6050@^2.2.6 sensebox/SenseBoxBLE@^1.1.0 + adafruit/Adafruit NeoPixel@^1.12.2 diff --git a/senseBox-bike-atrai-v2/src/main.cpp b/senseBox-bike-atrai-v2/src/main.cpp index f178a16..07f9824 100644 --- a/senseBox-bike-atrai-v2/src/main.cpp +++ b/senseBox-bike-atrai-v2/src/main.cpp @@ -1,6 +1,4 @@ #include -#include -#include #include "sensors/TempHumiditySensor/TempHumiditySensor.h" #include "sensors/DustSensor/DustSensor.h" #include "sensors/DistanceSensor/DistanceSensor.h" @@ -8,8 +6,10 @@ #include "display/Display.h" #include "ble/BLEModule.h" -TempHumiditySensor tempHumiditySensor; +#include "Adafruit_NeoPixel.h" + DustSensor dustSensor; +TempHumiditySensor tempHumiditySensor; DistanceSensor distanceSensor; AccelerationSensor accelerationSensor; @@ -17,10 +17,17 @@ SBDisplay display; BLEModule bleModule; +Adafruit_NeoPixel rgb_led = Adafruit_NeoPixel(1, 1, NEO_GRB + NEO_KHZ800); + void setup() { Serial.begin(115200); delay(1000); + + rgb_led.begin(); + + rgb_led.setBrightness(30); + SBDisplay::begin(); pinMode(IO_ENABLE, OUTPUT); @@ -58,8 +65,8 @@ void setup() // Serial.printf("DustSensor [%s]\n", uuid.c_str()); // }, "UUID-Dust"); - // distanceSensor.subscribe([](String uuid, std::vector values) - // { Serial.printf("DistanceSensor [%s]: %.2f\n", uuid.c_str(), values[0]); }); + // distanceSensor.subscribe([](std::vector values) + // { Serial.printf("DistanceSensor [%s]: %.2f\n", values[0]); }); // accelerationSensor.subscribe([](String uuid, std::vector values) // { @@ -68,13 +75,13 @@ void setup() // float z = values[2]; // Serial.printf("Acceleration [%s]: %.2f, %.2f, %.2f\n", uuid.c_str(), x, y, z); }); - tempHumiditySensor.startSubscription(); dustSensor.startSubscription(); + tempHumiditySensor.startSubscription(); distanceSensor.startSubscription(); accelerationSensor.startSubscription(); - tempHumiditySensor.startBLE(); dustSensor.startBLE(); + tempHumiditySensor.startBLE(); distanceSensor.startBLE(); accelerationSensor.startBLE(); diff --git a/senseBox-bike-atrai-v2/src/sensors/AccelerationSensor/AccelerationSensor.cpp b/senseBox-bike-atrai-v2/src/sensors/AccelerationSensor/AccelerationSensor.cpp index 05d0066..6a1b614 100644 --- a/senseBox-bike-atrai-v2/src/sensors/AccelerationSensor/AccelerationSensor.cpp +++ b/senseBox-bike-atrai-v2/src/sensors/AccelerationSensor/AccelerationSensor.cpp @@ -1,18 +1,14 @@ #include "AccelerationSensor.h" -#include -#include -#include +AccelerationSensor::AccelerationSensor() : BaseSensor("accelerationSensorTask", 2048, 100) {} -const String AccelerationSensor::accUUID = "B944AF10F4954560968F2F0D18CAB522"; +String accUUID = "B944AF10F4954560968F2F0D18CAB522"; +int accCharacteristic = 0; Adafruit_MPU6050 mpu; -int accCharacteristic = 0; - -void AccelerationSensor::begin() +void AccelerationSensor::initSensor() { - if (!mpu.begin(0x68, &Wire1)) { Serial.println("MPU6050 Chip wurde nicht gefunden"); @@ -28,75 +24,30 @@ void AccelerationSensor::begin() }; accCharacteristic = BLEModule::createCharacteristic(accUUID.c_str()); - - sendBLE = false; - activeSubscription = true; - xTaskCreate(sensorTask, "AccelerationSensorTask", 2048, this, 1, NULL); -} - -void AccelerationSensor::subscribe(std::function)> callback) -{ - this->measurementCallback = callback; } -void AccelerationSensor::startSubscription() +void AccelerationSensor::readSensorData() { - activeSubscription = true; -} + sensors_event_t a, g, temp; -void AccelerationSensor::stopSubscription() -{ - activeSubscription = false; -} + mpu.getEvent(&a, &g, &temp); -void AccelerationSensor::startBLE() -{ - setBLEStatus(true); -} + float x = a.acceleration.x; + float y = a.acceleration.y; + float z = a.acceleration.z; -void AccelerationSensor::stopBLE() -{ - setBLEStatus(false); -} - -void AccelerationSensor::sensorTask(void *pvParameters) -{ - AccelerationSensor *sensor = static_cast(pvParameters); - - while (true) + if (measurementCallback) { - if (sensor->activeSubscription) - { - - sensors_event_t a, g, temp; - - mpu.getEvent(&a, &g, &temp); - - float x = a.acceleration.x; - float y = a.acceleration.y; - float z = a.acceleration.z; - - if (sensor->measurementCallback) - { - sensor->measurementCallback(sensor->uuid, {x, y, z}); - } - - if (sensor->sendBLE) - { - sensor->notifyBLE(x, y, z); - } - } + measurementCallback({x, y, z}); + } - vTaskDelay(pdMS_TO_TICKS(500)); + if (sendBLE) + { + notifyBLE(x, y, z); } } void AccelerationSensor::notifyBLE(float x, float y, float z) { - // print characteristic - Serial.print("Acceleration Characteristic: "); - Serial.println(accCharacteristic); - Serial.printf("Acceleration: x: %f, y: %f, z: %f\n", x, y, z); - BLEModule::writeBLE(accCharacteristic, x, y, z); -} +} \ No newline at end of file diff --git a/senseBox-bike-atrai-v2/src/sensors/AccelerationSensor/AccelerationSensor.h b/senseBox-bike-atrai-v2/src/sensors/AccelerationSensor/AccelerationSensor.h index 39697ca..0b0d5fe 100644 --- a/senseBox-bike-atrai-v2/src/sensors/AccelerationSensor/AccelerationSensor.h +++ b/senseBox-bike-atrai-v2/src/sensors/AccelerationSensor/AccelerationSensor.h @@ -1,25 +1,17 @@ #ifndef ACCELERATION_SENSOR_H #define ACCELERATION_SENSOR_H -#include "../Sensor.h" +#include "../BaseSensor.h" +#include -class AccelerationSensor : public Sensor +class AccelerationSensor : public BaseSensor { public: - void begin() override; - void subscribe(std::function)> callback) override; - void startSubscription() override; - void stopSubscription() override; - void startBLE() override; - void stopBLE() override; + AccelerationSensor(); -private: - std::function)> measurementCallback; - String uuid; - - static const String accUUID; - - static void sensorTask(void *pvParameters); +protected: + void initSensor() override; + void readSensorData() override; void notifyBLE(float x, float y, float z); }; diff --git a/senseBox-bike-atrai-v2/src/sensors/BaseSensor.cpp b/senseBox-bike-atrai-v2/src/sensors/BaseSensor.cpp new file mode 100644 index 0000000..0f84044 --- /dev/null +++ b/senseBox-bike-atrai-v2/src/sensors/BaseSensor.cpp @@ -0,0 +1,49 @@ +#include "BaseSensor.h" + +BaseSensor::BaseSensor(const char *taskName, uint32_t taskStackSize, uint32_t taskDelay) + : activeSubscription(false), sendBLE(false), taskStackSize(taskStackSize), taskDelay(taskDelay) {} + +void BaseSensor::begin() +{ + initSensor(); + delay(1000); + xTaskCreate(sensorTask, taskName, taskStackSize, this, 1, NULL); +} + +void BaseSensor::subscribe(std::function)> callback) +{ + this->measurementCallback = callback; +} + +void BaseSensor::startSubscription() +{ + activeSubscription = true; +} + +void BaseSensor::stopSubscription() +{ + activeSubscription = false; +} + +void BaseSensor::startBLE() +{ + sendBLE = true; +} + +void BaseSensor::stopBLE() +{ + sendBLE = false; +} + +void BaseSensor::sensorTask(void *pvParameters) +{ + BaseSensor *sensor = static_cast(pvParameters); + while (true) + { + if (sensor->activeSubscription) + { + sensor->readSensorData(); + } + vTaskDelay(pdMS_TO_TICKS(sensor->taskDelay)); + } +} \ No newline at end of file diff --git a/senseBox-bike-atrai-v2/src/sensors/BaseSensor.h b/senseBox-bike-atrai-v2/src/sensors/BaseSensor.h new file mode 100644 index 0000000..912e07f --- /dev/null +++ b/senseBox-bike-atrai-v2/src/sensors/BaseSensor.h @@ -0,0 +1,35 @@ +#ifndef BASESENSOR_H +#define BASESENSOR_H + +#include +#include +#include +#include "../ble/BLEModule.h" + +class BaseSensor +{ +public: + BaseSensor(const char *taskName, uint32_t taskStackSize = 8192, uint32_t taskDelay = 1000); + + void begin(); + void subscribe(std::function)> callback); + void startSubscription(); + void stopSubscription(); + void startBLE(); + void stopBLE(); + +protected: + virtual void initSensor() = 0; + virtual void readSensorData() = 0; + static void sensorTask(void *pvParameters); + bool activeSubscription; + bool sendBLE; + std::function)> measurementCallback; + +private: + const char *taskName; + uint32_t taskStackSize; + uint32_t taskDelay; +}; + +#endif // BASESENSOR_H diff --git a/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp index 712100d..6312412 100644 --- a/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp +++ b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp @@ -1,104 +1,59 @@ #include "DistanceSensor.h" -#include -#include -#include +DistanceSensor::DistanceSensor() : BaseSensor("distanceTask", 8192, 100) {} -const String DistanceSensor::distanceUUID = "B3491B60C0F34306A30D49C91F37A62B"; +String distanceUUID = "B3491B60C0F34306A30D49C91F37A62B"; +int distanceCharacteristic = 0; VL53L8CX sensor_vl53l8cx_top(&Wire, -1, -1); -int distanceCharacteristic = 0; - -void DistanceSensor::begin() +void DistanceSensor::initSensor() { - Wire.begin(); - Wire.setClock(1000000); // Sensor has max I2C freq of 1MHz - sensor_vl53l8cx_top.begin(); sensor_vl53l8cx_top.init_sensor(); sensor_vl53l8cx_top.vl53l8cx_set_ranging_frequency_hz(30); sensor_vl53l8cx_top.vl53l8cx_set_resolution(VL53L8CX_RESOLUTION_8X8); sensor_vl53l8cx_top.vl53l8cx_start_ranging(); distanceCharacteristic = BLEModule::createCharacteristic(distanceUUID.c_str()); - - sendBLE = false; - activeSubscription = true; - xTaskCreate(sensorTask, "DistanceSensorTask", 8192, this, 1, NULL); } -void DistanceSensor::subscribe(std::function)> callback) +void DistanceSensor::readSensorData() { - this->measurementCallback = callback; -} - -void DistanceSensor::startSubscription() -{ - activeSubscription = true; -} - -void DistanceSensor::stopSubscription() -{ - activeSubscription = false; -} - -void DistanceSensor::startBLE() -{ - setBLEStatus(true); -} - -void DistanceSensor::stopBLE() -{ - setBLEStatus(false); -} - -void DistanceSensor::sensorTask(void *pvParameters) -{ - DistanceSensor *sensor = static_cast(pvParameters); + Serial.println("Reading distance sensor data..."); VL53L8CX_ResultsData Results; uint8_t NewDataReady = 0; - uint8_t status; + uint8_t status = sensor_vl53l8cx_top.vl53l8cx_check_data_ready(&NewDataReady); - while (true) + float distance = -1.0; + + if ((!status) && (NewDataReady != 0)) { - if (sensor->activeSubscription) + sensor_vl53l8cx_top.vl53l8cx_get_ranging_data(&Results); + float min = 10000.0; + for (int i = 0; i < VL53L8CX_RESOLUTION_8X8 * VL53L8CX_NB_TARGET_PER_ZONE; i++) { - float oldVl53l8cxMin = -1.0; - status = sensor_vl53l8cx_top.vl53l8cx_check_data_ready(&NewDataReady); - - if ((!status) && (NewDataReady != 0)) + if (Results.target_status[i] != 255) { - sensor_vl53l8cx_top.vl53l8cx_get_ranging_data(&Results); - float min = 10000.0; - for (int i = 0; i < VL53L8CX_RESOLUTION_8X8 * VL53L8CX_NB_TARGET_PER_ZONE; i++) + float distance = Results.distance_mm[i]; + if (min > distance) { - if ((&Results)->target_status[i] != 255) - { - float distance = (&Results)->distance_mm[i]; - if (min > distance) - { - min = distance; - } - } + min = distance; } - oldVl53l8cxMin = (min == 10000.0) ? 0.0 : min; - } - - float distance = oldVl53l8cxMin / 10.0; - - if (sensor->measurementCallback) - { - sensor->measurementCallback(sensor->uuid, {distance}); - } - - if (sensor->sendBLE) - { - sensor->notifyBLE(distance); } } + distance = (min == 10000.0) ? 0.0 : min / 10.0; + Serial.printf("Distance: %.2f cm\n", distance); + } - vTaskDelay(pdMS_TO_TICKS(1000)); + if (measurementCallback) + { + measurementCallback({distance}); + } + + if (sendBLE) + { + notifyBLE(distance); } } diff --git a/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.h b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.h index 801484f..62da62a 100644 --- a/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.h +++ b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.h @@ -1,26 +1,19 @@ -#ifndef DISTANCE_SENSOR_H -#define DISTANCE_SENSOR_H +#ifndef DISTANCESENSOR_H +#define DISTANCESENSOR_H -#include "../Sensor.h" +#include "../BaseSensor.h" +#include +#include -class DistanceSensor : public Sensor +class DistanceSensor : public BaseSensor { public: - void begin() override; - void subscribe(std::function)> callback) override; - void startSubscription() override; - void stopSubscription() override; - void startBLE() override; - void stopBLE() override; + DistanceSensor(); -private: - std::function)> measurementCallback; - String uuid; - - static const String distanceUUID; - - static void sensorTask(void *pvParameters); +protected: + void initSensor() override; + void readSensorData() override; void notifyBLE(float distance); }; -#endif // DISTANCE_SENSOR_H +#endif // DISTANCESENSOR_H diff --git a/senseBox-bike-atrai-v2/src/sensors/DustSensor/DustSensor.cpp b/senseBox-bike-atrai-v2/src/sensors/DustSensor/DustSensor.cpp index 9e851f2..76e7e2e 100644 --- a/senseBox-bike-atrai-v2/src/sensors/DustSensor/DustSensor.cpp +++ b/senseBox-bike-atrai-v2/src/sensors/DustSensor/DustSensor.cpp @@ -1,19 +1,20 @@ #include "DustSensor.h" -#include -#include -#include -const String DustSensor::pmUUID = "7E14E07084EA489FB45AE1317364B979"; +DustSensor::DustSensor() : BaseSensor("DustSensorTask", 2048, 1000) {} +String dustUUID = "7E14E07084EA489FB45AE1317364B979"; int dustCharacteristic = 0; -void DustSensor::begin() +// add more if needed + +void DustSensor::initSensor() { int16_t ret; uint8_t auto_clean_days = 4; uint32_t auto_clean; - Serial.println("Dust Setup"); + Serial.begin(9600); + delay(2000); sensirion_i2c_init(); @@ -23,6 +24,8 @@ void DustSensor::begin() delay(500); } + Serial.print("SPS sensor probing successful\n"); + ret = sps30_set_fan_auto_cleaning_interval_days(auto_clean_days); if (ret) { @@ -36,100 +39,59 @@ void DustSensor::begin() Serial.print("error starting measurement\n"); } - dustCharacteristic = BLEModule::createCharacteristic(pmUUID.c_str()); - - sendBLE = false; - activeSubscription = true; - - xTaskCreate(sensorTask, "DustSensorTask", 2048, this, 1, NULL); -} - -void DustSensor::subscribe(std::function)> callback) -{ - this->measurementCallback = callback; -} + Serial.print("measurements started\n"); -void DustSensor::startSubscription() -{ - activeSubscription = true; -} - -void DustSensor::stopSubscription() -{ - activeSubscription = false; -} - -void DustSensor::startBLE() -{ - setBLEStatus(true); + dustCharacteristic = BLEModule::createCharacteristic(dustUUID.c_str()); } -void DustSensor::stopBLE() +void DustSensor::readSensorData() { - setBLEStatus(false); -} - -void DustSensor::sensorTask(void *pvParameters) -{ - DustSensor *sensor = static_cast(pvParameters); + struct sps30_measurement m; + char serial[SPS30_MAX_SERIAL_LEN]; + uint16_t data_ready; + int16_t ret; - while (true) + do { - if (sensor->activeSubscription) + ret = sps30_read_data_ready(&data_ready); + if (ret < 0) { + Serial.print("error reading data-ready flag: "); + Serial.println(ret); + } + else if (!data_ready) + Serial.print("data not ready, no new measurement available\n"); + else + break; + delay(100); /* retry in 100ms */ + } while (1); + + ret = sps30_read_measurement(&m); + if (ret < 0) + { + Serial.print("error reading measurement\n"); + } + else + { - struct sps30_measurement m; - char serial[SPS30_MAX_SERIAL_LEN]; - uint16_t data_ready; - int16_t ret; - - do - { - ret = sps30_read_data_ready(&data_ready); - if (ret < 0) - { - Serial.print("error reading data-ready flag: "); - Serial.println(ret); - } - else if (!data_ready) - Serial.print("data not ready, no new measurement available\n"); - else - break; - delay(100); /* retry in 100ms */ - } while (1); - - ret = sps30_read_measurement(&m); - if (ret < 0) - { - Serial.print("error reading measurement\n"); - } - else - { - float pm1 = m.mc_1p0; - float pm2_5 = m.mc_2p5; - float pm4 = m.mc_4p0; - float pm10 = m.mc_10p0; - - if (sensor->measurementCallback) - { - sensor->measurementCallback(sensor->uuid, {pm1, pm2_5, pm4, pm10}); - } - - if (sensor->sendBLE) - { - sensor->notifyBLE(pm1, pm2_5, pm4, pm10); - } - } + float pm1 = m.mc_1p0; + float pm2_5 = m.mc_2p5; + float pm4 = m.mc_4p0; + float pm10 = m.mc_10p0; + + if (measurementCallback) + { + measurementCallback({pm1, pm2_5, pm4, pm10}); } - vTaskDelay(pdMS_TO_TICKS(2000)); + if (sendBLE) + { + notifyBLE(pm1, pm2_5, pm4, pm10); + } } } void DustSensor::notifyBLE(float pm1, float pm2_5, float pm4, float pm10) { - Serial.print("Dust Characteristic: "); - Serial.println(dustCharacteristic); - Serial.printf("Dust: PM1: %f, PM2.5: %f, PM4: %f, PM10: %f\n", pm1, pm2_5, pm4, pm10); - BLEModule::writeBLE(characteristicId, pm1, pm2_5, pm4, pm10); -} + BLEModule::writeBLE(dustCharacteristic, pm1, pm2_5, pm4, pm10); +} \ No newline at end of file diff --git a/senseBox-bike-atrai-v2/src/sensors/DustSensor/DustSensor.h b/senseBox-bike-atrai-v2/src/sensors/DustSensor/DustSensor.h index 0e6e89b..2dea590 100644 --- a/senseBox-bike-atrai-v2/src/sensors/DustSensor/DustSensor.h +++ b/senseBox-bike-atrai-v2/src/sensors/DustSensor/DustSensor.h @@ -1,25 +1,19 @@ #ifndef DUST_SENSOR_H #define DUST_SENSOR_H -#include "../Sensor.h" +#include "../BaseSensor.h" +#include -class DustSensor : public Sensor +// include necceary libraries + +class DustSensor : public BaseSensor { public: - void begin() override; - void subscribe(std::function)> callback) override; - void startSubscription() override; - void stopSubscription() override; - void startBLE() override; - void stopBLE() override; - -private: - std::function)> measurementCallback; - String uuid; - - static const String pmUUID; + DustSensor(); - static void sensorTask(void *pvParameters); +protected: + void initSensor() override; + void readSensorData() override; void notifyBLE(float pm1, float pm2_5, float pm4, float pm10); }; diff --git a/senseBox-bike-atrai-v2/src/sensors/SampleSensor/SampleSensor.cpp b/senseBox-bike-atrai-v2/src/sensors/SampleSensor/SampleSensor.cpp new file mode 100644 index 0000000..9838781 --- /dev/null +++ b/senseBox-bike-atrai-v2/src/sensors/SampleSensor/SampleSensor.cpp @@ -0,0 +1,37 @@ +#include "SampleSensor.h" + +SampleSensor::SampleSensor() : BaseSensor("sampleSensorTask", 2048, 1000) {} + +String sampleUUID = "00000000000000000"; +int sampleCharacteristic = 0; + +// add more if needed + +void SampleSensor::initSensor() +{ + // init sensor + + sampleCharacteristic = BLEModule::createCharacteristic(sampleUUID.c_str()); + // add more if needed +} + +void SampleSensor::readSensorData() +{ + float sampleValue = 0.0; + // read sensor data + + if (measurementCallback) + { + measurementCallback({sampleValue}); + } + + if (sendBLE) + { + notifyBLE(sampleValue); + } +} + +void SampleSensor::notifyBLE(float sampleValue) +{ + BLEModule::writeBLE(sampleCharacteristic, sampleValue); +} \ No newline at end of file diff --git a/senseBox-bike-atrai-v2/src/sensors/SampleSensor/SampleSensor.h b/senseBox-bike-atrai-v2/src/sensors/SampleSensor/SampleSensor.h new file mode 100644 index 0000000..3cf5676 --- /dev/null +++ b/senseBox-bike-atrai-v2/src/sensors/SampleSensor/SampleSensor.h @@ -0,0 +1,19 @@ +#ifndef SAMPLE_SENSOR_H +#define SAMPLE_SENSOR_H + +#include "../BaseSensor.h" + +// include necceary libraries + +class SampleSensor : public BaseSensor +{ +public: + SampleSensor(); + +protected: + void initSensor() override; + void readSensorData() override; + void notifyBLE(float sampleValue); // change this to match the data type of the sensor data +}; + +#endif // SAMPLE_SENSOR_H diff --git a/senseBox-bike-atrai-v2/src/sensors/Sensor.cpp b/senseBox-bike-atrai-v2/src/sensors/Sensor.cpp deleted file mode 100644 index 6b9a34a..0000000 --- a/senseBox-bike-atrai-v2/src/sensors/Sensor.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "Sensor.h" - -void Sensor::setBLEStatus(bool status) -{ - sendBLE = status; -} diff --git a/senseBox-bike-atrai-v2/src/sensors/Sensor.h b/senseBox-bike-atrai-v2/src/sensors/Sensor.h deleted file mode 100644 index b7570a7..0000000 --- a/senseBox-bike-atrai-v2/src/sensors/Sensor.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef SENSOR_H -#define SENSOR_H - -#include -#include -#include -#include "../ble/BLEModule.h" - -class Sensor -{ -public: - virtual void begin() = 0; - virtual void subscribe(std::function)> callback) = 0; - virtual void startSubscription() = 0; - virtual void stopSubscription() = 0; - virtual void startBLE() = 0; - virtual void stopBLE() = 0; - -protected: - bool sendBLE; - bool activeSubscription; - - int characteristicId; - void setBLEStatus(bool status); -}; - -#endif // SENSOR_H diff --git a/senseBox-bike-atrai-v2/src/sensors/TempHumiditySensor/TempHumiditySensor.cpp b/senseBox-bike-atrai-v2/src/sensors/TempHumiditySensor/TempHumiditySensor.cpp index edbfd19..6972c5e 100644 --- a/senseBox-bike-atrai-v2/src/sensors/TempHumiditySensor/TempHumiditySensor.cpp +++ b/senseBox-bike-atrai-v2/src/sensors/TempHumiditySensor/TempHumiditySensor.cpp @@ -1,18 +1,16 @@ #include "TempHumiditySensor.h" -#include -#include -#include "Adafruit_HDC1000.h" +TempHumiditySensor::TempHumiditySensor() : BaseSensor("temperatureHumidityTask", 2048, 1000) {} -const String TempHumiditySensor::tempUUID = "2CDF217435BEFDC44CA26FD173F8B3A8"; -const String TempHumiditySensor::humUUID = "772DF7EC8CDC4EA986AF410ABE0BA257"; +String tempUUID = "2CDF217435BEFDC44CA26FD173F8B3A8"; +String humUUID = "772DF7EC8CDC4EA986AF410ABE0BA257"; int temperatureCharacteristic = 0; int humidityCharacteristic = 0; -Adafruit_HDC1000 hdc = Adafruit_HDC1000(); +Adafruit_HDC1000 hdc; -void TempHumiditySensor::begin() +void TempHumiditySensor::initSensor() { if (!hdc.begin()) { @@ -23,69 +21,26 @@ void TempHumiditySensor::begin() temperatureCharacteristic = BLEModule::createCharacteristic(tempUUID.c_str()); humidityCharacteristic = BLEModule::createCharacteristic(humUUID.c_str()); - - sendBLE = false; - activeSubscription = true; - xTaskCreate(sensorTask, "TempHumiditySensorTask", 2048, this, 1, NULL); -} - -void TempHumiditySensor::subscribe(std::function)> callback) -{ - this->measurementCallback = callback; -} - -void TempHumiditySensor::startSubscription() -{ - activeSubscription = true; -} - -void TempHumiditySensor::stopSubscription() -{ - activeSubscription = false; -} - -void TempHumiditySensor::startBLE() -{ - setBLEStatus(true); -} - -void TempHumiditySensor::stopBLE() -{ - setBLEStatus(false); } -void TempHumiditySensor::sensorTask(void *pvParameters) +void TempHumiditySensor::readSensorData() { - TempHumiditySensor *sensor = static_cast(pvParameters); + float temperature = hdc.readTemperature(); + float humidity = hdc.readHumidity(); - while (true) + if (measurementCallback) { - if (sensor->activeSubscription) - { - float temperature = hdc.readTemperature(); - float humidity = hdc.readHumidity(); - - if (sensor->measurementCallback) - { - sensor->measurementCallback(sensor->uuid, {temperature, humidity}); - } - - if (sensor->sendBLE) - { - sensor->notifyBLE(temperature, humidity); - } - } + measurementCallback({temperature, humidity}); + } - vTaskDelay(pdMS_TO_TICKS(5000)); + if (sendBLE) + { + notifyBLE(temperature, humidity); } } -void TempHumiditySensor::notifyBLE(float temperature, float humidity) +void TempHumiditySensor::notifyBLE(float temoperature, float humidity) { - Serial.println("Notifying BLE"); - Serial.println(temperature); - Serial.println(temperatureCharacteristic); - - BLEModule::writeBLE(temperatureCharacteristic, temperature); + BLEModule::writeBLE(temperatureCharacteristic, temoperature); BLEModule::writeBLE(humidityCharacteristic, humidity); -} +} \ No newline at end of file diff --git a/senseBox-bike-atrai-v2/src/sensors/TempHumiditySensor/TempHumiditySensor.h b/senseBox-bike-atrai-v2/src/sensors/TempHumiditySensor/TempHumiditySensor.h index 728c068..84f0448 100644 --- a/senseBox-bike-atrai-v2/src/sensors/TempHumiditySensor/TempHumiditySensor.h +++ b/senseBox-bike-atrai-v2/src/sensors/TempHumiditySensor/TempHumiditySensor.h @@ -1,27 +1,18 @@ #ifndef TEMP_HUMIDITY_SENSOR_H #define TEMP_HUMIDITY_SENSOR_H -#include "../Sensor.h" +#include "../BaseSensor.h" +#include "Adafruit_HDC1000.h" -class TempHumiditySensor : public Sensor +class TempHumiditySensor : public BaseSensor { public: - void begin() override; - void subscribe(std::function)> callback) override; - void startSubscription() override; - void stopSubscription() override; - void startBLE() override; - void stopBLE() override; + TempHumiditySensor(); -private: - std::function)> measurementCallback; - String uuid; - - static const String tempUUID; - static const String humUUID; - - static void sensorTask(void *pvParameters); +protected: + void initSensor() override; + void readSensorData() override; void notifyBLE(float temperature, float humidity); }; -#endif // TEMP_HUMIDITY_SENSOR_H +#endif // DISTANCESENSOR_H From 051ebfb822226a2caadaa4908e19fad25823d441 Mon Sep 17 00:00:00 2001 From: PaulaScharf Date: Fri, 7 Jun 2024 12:54:56 +0200 Subject: [PATCH 2/4] add takeover prediction --- senseBox-bike-atrai-v2/platformio.ini | 1 + .../sensors/DistanceSensor/DistanceSensor.cpp | 167 +++++- .../sensors/DistanceSensor/DistanceSensor.h | 2 +- .../src/sensors/DistanceSensor/model_data.h | 545 ++++++++++++++++++ 4 files changed, 697 insertions(+), 18 deletions(-) create mode 100644 senseBox-bike-atrai-v2/src/sensors/DistanceSensor/model_data.h diff --git a/senseBox-bike-atrai-v2/platformio.ini b/senseBox-bike-atrai-v2/platformio.ini index d733dd5..2c52940 100644 --- a/senseBox-bike-atrai-v2/platformio.ini +++ b/senseBox-bike-atrai-v2/platformio.ini @@ -23,3 +23,4 @@ lib_deps = adafruit/Adafruit MPU6050@^2.2.6 sensebox/SenseBoxBLE@^1.1.0 adafruit/Adafruit NeoPixel@^1.12.2 + tanakamasayuki/TensorFlowLite_ESP32@^1.0.0 diff --git a/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp index 6312412..57d78bf 100644 --- a/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp +++ b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp @@ -5,16 +5,100 @@ DistanceSensor::DistanceSensor() : BaseSensor("distanceTask", 8192, 100) {} String distanceUUID = "B3491B60C0F34306A30D49C91F37A62B"; int distanceCharacteristic = 0; +#include "model_data.h" +#include +#include + +#include +#include +#include "tensorflow/lite/micro/kernels/micro_ops.h" +#include "tensorflow/lite/micro/micro_interpreter.h" +#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" +#include "tensorflow/lite/micro/all_ops_resolver.h" +#include "tensorflow/lite/schema/schema_generated.h" +#include + +String overtakingUUID = "FC01C6882C444965AE18373AF9FED18D"; +int overtakingCharacteristic = 0; + VL53L8CX sensor_vl53l8cx_top(&Wire, -1, -1); +const int kChannelNumber = 64; +const int kFrameNumber = 20; +const tflite::Model* model = nullptr; +tflite::MicroInterpreter* interpreter = nullptr; +TfLiteTensor* model_input = nullptr; +int input_length; +// Create an area of memory to use for input, output, and intermediate arrays. +// The size of this will depend on the model you're using, and may need to be +// determined by experimentation. +constexpr int kTensorArenaSize = 14 * 1024 + 1008 ; +uint8_t tensor_arena[kTensorArenaSize]; + +// A buffer holding the last 20 sets of 8x8 pixels +const int RING_BUFFER_SIZE = 1280; +float save_data[RING_BUFFER_SIZE] = {0.0}; +// Most recent position in the save_data buffer +int begin_index = 0; +// True if there is not yet enough data to run inference +bool pending_initial_data = true; + +long prevMeasureTime = millis(); +long prevBleTime = millis(); void DistanceSensor::initSensor() { + // ------------------------------ setup VL53L8CX ------------------------------ + Serial.println("setting up VL53L8CX..."); + Wire.begin(); + Wire.setClock(1000000); // Sensor has max I2C freq of 1MHz + sensor_vl53l8cx_top.begin(); sensor_vl53l8cx_top.init_sensor(); sensor_vl53l8cx_top.vl53l8cx_set_ranging_frequency_hz(30); sensor_vl53l8cx_top.vl53l8cx_set_resolution(VL53L8CX_RESOLUTION_8X8); sensor_vl53l8cx_top.vl53l8cx_start_ranging(); + // -------------------------- setup tensorflow model -------------------------- + Serial.println("setting up tensorflow..."); + model = tflite::GetModel(g_model_data); + if (model->version() != TFLITE_SCHEMA_VERSION) { + Serial.printf("Model provided is schema version %d not equal " + "to supported version %d.", + model->version(), TFLITE_SCHEMA_VERSION); + return; + } + static tflite::MicroErrorReporter tflErrorReporter; + // This imports all operations, which is more intensive, than just importing the ones we need. + // If we ever run out of storage with a model, we can check here to free some space + static tflite::AllOpsResolver resolver; + // Build an interpreter to run the model with. + static tflite::MicroInterpreter static_interpreter( + model, resolver, (uint8_t*)(tensor_arena), (size_t)(kTensorArenaSize), &tflErrorReporter); + interpreter = &static_interpreter; + // Allocate memory from the tensor_arena for the model's tensors. + interpreter->AllocateTensors(); + // Obtain pointer to the model's input tensor. + model_input = interpreter->input(0); + if ((model_input->dims->size != 3) || (model_input->dims->data[0] != 1) || + (model_input->dims->data[1] != kFrameNumber) || + (model_input->dims->data[2] != kChannelNumber) || + (model_input->type != kTfLiteFloat32)) { + Serial.println(model_input->dims->size); + Serial.println(model_input->dims->data[0]); + Serial.println(model_input->dims->data[1]); + Serial.println(model_input->dims->data[2]); + Serial.println(model_input->type); + Serial.println("Bad input tensor parameters in model"); + return; + } + input_length = model_input->bytes / sizeof(float); + // ----------------------------- setup complete ----------------------------- + Serial.println("setup complete"); distanceCharacteristic = BLEModule::createCharacteristic(distanceUUID.c_str()); + overtakingCharacteristic = BLEModule::createCharacteristic(overtakingUUID.c_str()); + + sendBLE = false; + activeSubscription = true; + xTaskCreate(sensorTask, "DistanceSensorTask", 8192*2, this, 1, NULL); } void DistanceSensor::readSensorData() @@ -28,36 +112,85 @@ void DistanceSensor::readSensorData() float distance = -1.0; if ((!status) && (NewDataReady != 0)) - { + { sensor_vl53l8cx_top.vl53l8cx_get_ranging_data(&Results); + float overtakingPredictionPercentage = -1.0; + float oldVl53l8cxMin = -1.0; float min = 10000.0; - for (int i = 0; i < VL53L8CX_RESOLUTION_8X8 * VL53L8CX_NB_TARGET_PER_ZONE; i++) + for (int j = 0; j < VL53L8CX_RESOLUTION_8X8; j += 8) { - if (Results.target_status[i] != 255) + for (int l = 0; l < VL53L8CX_NB_TARGET_PER_ZONE; l++) { - float distance = Results.distance_mm[i]; - if (min > distance) + for (int k = (8 - 1); k >= 0; k--) { - min = distance; + if ((float)(&Results)->target_status[(VL53L8CX_NB_TARGET_PER_ZONE * (j+k)) + l] != 255) + { + if((float)(&Results)->distance_mm[(VL53L8CX_NB_TARGET_PER_ZONE * (j+k)) + l] > 2000.0){ + save_data[begin_index++] = 0.0; + } else { + save_data[begin_index++] = (float)(&Results)->distance_mm[(VL53L8CX_NB_TARGET_PER_ZONE * (j+k)) + l]; + } + float distance = ((&Results)->distance_mm[(VL53L8CX_NB_TARGET_PER_ZONE * (j+k)) + l])/10; + if (min > distance) + { + min = distance; + } + } + else { + save_data[begin_index++] = 0.0; + } } } } - distance = (min == 10000.0) ? 0.0 : min / 10.0; - Serial.printf("Distance: %.2f cm\n", distance); - } + oldVl53l8cxMin = (min == 10000.0) ? 0.0 : min; - if (measurementCallback) - { - measurementCallback({distance}); - } + // If we reached the end of the circle buffer, reset + if (begin_index >= (RING_BUFFER_SIZE)) { + begin_index = 0; + // Check if we are ready for prediction or still pending more initial data + if (pending_initial_data) { + pending_initial_data = false; + } + } + if (!pending_initial_data) { + for (int i = 0; i < input_length; ++i) { + int ring_array_index = begin_index + i - input_length; + if (ring_array_index < 0) { + ring_array_index += (RING_BUFFER_SIZE); + } + // normalize + model_input->data.f[i] = save_data[ring_array_index]/2000.0; + } + // Run inference, and report any error. + TfLiteStatus invoke_status = interpreter->Invoke(); + if (invoke_status == kTfLiteOk) { + const float* prediction_scores = interpreter->output(0)->data.f; + overtakingPredictionPercentage = prediction_scores[0]; + } + } + + float distance = oldVl53l8cxMin; - if (sendBLE) - { - notifyBLE(distance); + if (measurementCallback) + { + measurementCallback({distance, overtakingPredictionPercentage}); + } + + if (sendBLE && (millis()-prevBleTime)>=1000) + { + notifyBLE(distance,overtakingPredictionPercentage); + prevBleTime = millis(); + } + } + if((millis()-prevMeasureTime)<65){ + vTaskDelay(pdMS_TO_TICKS(65-(millis()-prevMeasureTime))); } + Serial.println(millis()-prevMeasureTime); + prevMeasureTime=millis(); } -void DistanceSensor::notifyBLE(float distance) +void DistanceSensor::notifyBLE(float distance, float overtakingPredictionPercentage) { BLEModule::writeBLE(distanceCharacteristic, distance); + BLEModule::writeBLE(overtakingCharacteristic, overtakingPredictionPercentage); } diff --git a/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.h b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.h index 62da62a..5b2fcac 100644 --- a/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.h +++ b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.h @@ -13,7 +13,7 @@ class DistanceSensor : public BaseSensor protected: void initSensor() override; void readSensorData() override; - void notifyBLE(float distance); + void notifyBLE(float distance, float overtakingPredictionPercentage); }; #endif // DISTANCESENSOR_H diff --git a/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/model_data.h b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/model_data.h new file mode 100644 index 0000000..7d7d290 --- /dev/null +++ b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/model_data.h @@ -0,0 +1,545 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +// This is a standard TensorFlow Lite model file that has been converted into a +// C data array, so it can be easily compiled into a binary for devices that +// don't have a file system. It was created using the command: +// xxd -i magic_wand_model.tflite > magic_wand_model_data.cc + +#ifndef TENSORFLOW_LITE_MICRO_MODEL_DATA_H_ +#define TENSORFLOW_LITE_MICRO_MODEL_DATA_H_ + +extern const unsigned char g_model_data[] PROGMEM = { + 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, 0xfc, 0x0d, 0x00, 0x00, + 0x0c, 0x0e, 0x00, 0x00, 0x7c, 0x17, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd2, 0xf0, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x38, 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, 0x11, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6e, 0x73, + 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xd6, 0xf0, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x72, 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x5f, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xdc, 0xff, 0xff, 0xff, 0x14, 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, 0x13, 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, + 0x15, 0x00, 0x00, 0x00, 0x18, 0x0d, 0x00, 0x00, 0x10, 0x0d, 0x00, 0x00, + 0xd8, 0x0c, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, + 0x60, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x00, 0x0c, 0x01, 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, 0x74, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xa6, 0xf1, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0e, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x2e, 0x31, 0x35, + 0x2e, 0x30, 0x00, 0x00, 0x12, 0xf2, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x31, 0x2e, 0x31, 0x34, 0x2e, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0xea, 0xff, 0xff, + 0x78, 0xea, 0xff, 0xff, 0x7c, 0xea, 0xff, 0xff, 0x80, 0xea, 0xff, 0xff, + 0x84, 0xea, 0xff, 0xff, 0x88, 0xea, 0xff, 0xff, 0x8c, 0xea, 0xff, 0xff, + 0x90, 0xea, 0xff, 0xff, 0x4e, 0xf2, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0xe6, 0x0d, 0x1f, 0xc0, 0x71, 0x83, 0xca, 0xbf, + 0xb2, 0x37, 0x0b, 0xc0, 0xb8, 0xcc, 0x1b, 0x40, 0xc8, 0x1c, 0x33, 0xc0, + 0xe9, 0x4a, 0xdf, 0xbf, 0x71, 0xa9, 0x15, 0xc0, 0x57, 0xc5, 0x1c, 0x40, + 0xeb, 0x7e, 0x14, 0x40, 0x98, 0xb0, 0x20, 0x40, 0x82, 0xf2, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x96, 0xf2, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa6, 0xf2, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0xb6, 0xf2, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc6, 0xf2, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xd6, 0xf2, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xec, 0x89, 0x08, 0xbe, + 0xe6, 0xf2, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x40, 0x0b, 0x00, 0x00, + 0xcb, 0x23, 0x12, 0xbf, 0xbe, 0x55, 0xa0, 0x3c, 0x9d, 0x9e, 0x09, 0xbd, + 0x8e, 0xac, 0x7d, 0x3e, 0xeb, 0x35, 0xce, 0x3e, 0x09, 0x66, 0xf6, 0x3e, + 0x43, 0x5b, 0x36, 0x3f, 0xd0, 0xd8, 0x86, 0x3e, 0xa1, 0x66, 0x02, 0xbf, + 0x8f, 0xe2, 0x56, 0xbf, 0x3f, 0x96, 0x2e, 0xbf, 0x77, 0x1c, 0x5e, 0xbf, + 0xdc, 0x15, 0x62, 0xbe, 0x20, 0x26, 0xa9, 0xbd, 0x61, 0xcc, 0xf1, 0xbe, + 0xe6, 0x25, 0xae, 0xbe, 0x56, 0x78, 0xe1, 0xbd, 0x2d, 0x26, 0x1d, 0x3e, + 0x8d, 0xe7, 0xd9, 0xbe, 0xd7, 0x72, 0x47, 0xbe, 0x69, 0x4a, 0xa1, 0xbe, + 0x5e, 0x68, 0x02, 0x3f, 0x01, 0x28, 0x41, 0x3e, 0x11, 0xbf, 0x0c, 0xbe, + 0x22, 0x86, 0x9f, 0xbe, 0x02, 0xb1, 0x5f, 0xbd, 0x8f, 0x94, 0x82, 0xbc, + 0x2f, 0xb3, 0x3f, 0x3d, 0x5b, 0x7a, 0x25, 0x3f, 0xcb, 0x2c, 0x28, 0x3f, + 0x76, 0x26, 0x23, 0x3f, 0x2c, 0x18, 0xbc, 0x3e, 0x8e, 0x1a, 0x11, 0xbf, + 0xf4, 0x2f, 0x45, 0xbf, 0x6b, 0x00, 0x37, 0xbf, 0x64, 0x16, 0x0b, 0xbf, + 0x66, 0xf2, 0x90, 0xbd, 0x0c, 0xc3, 0x79, 0xbe, 0x7c, 0xa4, 0x8f, 0xbe, + 0xfe, 0x49, 0x23, 0xbd, 0x8c, 0xba, 0xae, 0x3e, 0xd2, 0x09, 0x26, 0x3e, + 0x0b, 0x51, 0x0b, 0xbf, 0xa6, 0xc6, 0x27, 0xbe, 0x09, 0xc0, 0x48, 0xbe, + 0x80, 0x9c, 0x07, 0x3f, 0x83, 0x91, 0x11, 0x3f, 0x8b, 0x6c, 0x30, 0x3e, + 0x57, 0x39, 0x68, 0xbd, 0x6e, 0x1e, 0xcd, 0x3e, 0x5b, 0x5b, 0xf9, 0x3e, + 0x15, 0x22, 0x01, 0x3f, 0x56, 0x54, 0x15, 0x3f, 0x79, 0x43, 0x59, 0x3f, + 0x79, 0x7b, 0x60, 0x3f, 0x3d, 0x1e, 0x17, 0x3f, 0xa9, 0x05, 0x00, 0xbe, + 0xff, 0x73, 0xca, 0xbe, 0xac, 0xbc, 0xe2, 0xbe, 0x37, 0x8a, 0xd8, 0xbe, + 0xb9, 0x2a, 0x57, 0xbd, 0x88, 0x36, 0x32, 0xbd, 0x3c, 0x13, 0x4e, 0xbe, + 0xa8, 0xbf, 0x82, 0xbe, 0xd2, 0x5b, 0xba, 0x3e, 0xeb, 0x06, 0xb4, 0x3e, + 0x21, 0x7e, 0xdc, 0xbd, 0xe4, 0x37, 0xc6, 0xbd, 0x03, 0x3f, 0x23, 0xbe, + 0xd9, 0x14, 0x48, 0x3f, 0x1a, 0x4c, 0x68, 0x3e, 0x35, 0x48, 0x30, 0x3e, + 0xaa, 0x7f, 0xab, 0x3e, 0x0a, 0xb9, 0xd0, 0x3e, 0x4f, 0x7a, 0x82, 0x3e, + 0x7c, 0xc2, 0x2e, 0x3f, 0x47, 0x99, 0x92, 0x3f, 0x95, 0x49, 0x1f, 0x3f, + 0x83, 0x3d, 0x04, 0x3f, 0x2b, 0x10, 0x0b, 0x3e, 0x4e, 0xd7, 0x3f, 0xbe, + 0x73, 0xf2, 0xe4, 0x3d, 0xed, 0xb5, 0x10, 0xbf, 0x97, 0x31, 0x18, 0xbf, + 0xdb, 0x61, 0x10, 0x3d, 0xc8, 0xb3, 0x81, 0xbe, 0x02, 0x52, 0x66, 0xbf, + 0x02, 0x09, 0x4f, 0xbf, 0x03, 0xb6, 0x82, 0x3f, 0x79, 0xe5, 0x41, 0x3f, + 0xeb, 0x33, 0x1e, 0xbe, 0x90, 0x80, 0xe4, 0xbd, 0xef, 0x60, 0xa9, 0x3e, + 0x15, 0x53, 0x35, 0x3f, 0xe0, 0x86, 0x08, 0xbe, 0xb9, 0xa2, 0xff, 0xbe, + 0x5d, 0x6f, 0x87, 0x3e, 0xd2, 0x1b, 0x03, 0x3f, 0x90, 0xf9, 0x9d, 0x3e, + 0x3d, 0x7d, 0x20, 0x3f, 0x7e, 0x82, 0x55, 0x3f, 0xcb, 0x45, 0xe2, 0x3e, + 0xbe, 0xa8, 0xf1, 0x3d, 0x5a, 0x1e, 0xba, 0xbb, 0x78, 0x5d, 0xa0, 0xbe, + 0x8c, 0xc4, 0xe6, 0x3d, 0x30, 0x38, 0x0c, 0xbf, 0xcd, 0x9f, 0x0c, 0xbf, + 0x0e, 0xae, 0x1f, 0xbe, 0x9f, 0xdb, 0x06, 0xbe, 0x57, 0x2a, 0x85, 0xbf, + 0x6d, 0xd5, 0x94, 0xbf, 0x89, 0x7d, 0x48, 0x3f, 0xee, 0x34, 0xf2, 0x3e, + 0x0c, 0x6c, 0xaa, 0xbe, 0x0d, 0x5b, 0x06, 0xbe, 0x7f, 0xfa, 0x82, 0x3c, + 0x17, 0x06, 0x3a, 0x3f, 0x6c, 0x60, 0xed, 0xbc, 0x92, 0x92, 0x61, 0xbf, + 0x7c, 0x1e, 0xc7, 0x3e, 0x62, 0xdb, 0xe4, 0x3e, 0x1d, 0x8e, 0xb6, 0x3e, + 0x2a, 0xc2, 0xc3, 0x3e, 0x22, 0x4c, 0x82, 0x3f, 0x50, 0x40, 0x9f, 0x3e, + 0xf4, 0xed, 0x01, 0x3e, 0x9e, 0xf9, 0xbc, 0xbe, 0xa0, 0x05, 0x87, 0xbe, + 0xa2, 0xe9, 0x21, 0xbe, 0x8d, 0xb7, 0x30, 0xbf, 0xe9, 0x84, 0x11, 0xbf, + 0xba, 0x2f, 0x5e, 0x3d, 0xb3, 0x03, 0xde, 0xbe, 0xf5, 0xc1, 0x8f, 0xbf, + 0xff, 0x0d, 0x92, 0xbf, 0x9d, 0x63, 0x27, 0x3f, 0x00, 0x0f, 0xb5, 0x3e, + 0xdb, 0x51, 0xca, 0xbe, 0x79, 0x3a, 0x0a, 0xbf, 0x4d, 0xeb, 0x20, 0x3e, + 0x6a, 0xa3, 0xe9, 0x3e, 0x23, 0x58, 0x34, 0xbd, 0xbe, 0x95, 0x64, 0xbf, + 0xf8, 0xe3, 0x13, 0xbf, 0x24, 0xcc, 0x03, 0xbf, 0x75, 0x1f, 0x88, 0xbd, + 0xf9, 0xd4, 0x0d, 0xbe, 0x83, 0x14, 0xd7, 0xbd, 0x88, 0x8e, 0x20, 0x3f, + 0x89, 0xe6, 0x7c, 0x3f, 0xd2, 0xce, 0xbc, 0x3e, 0x93, 0x93, 0x43, 0xbf, + 0x96, 0x0e, 0x27, 0xbf, 0x7b, 0x24, 0x40, 0xbf, 0x6a, 0xdc, 0x4b, 0xbf, + 0xca, 0xbe, 0x8a, 0xbe, 0xef, 0x85, 0x6e, 0xbe, 0xd1, 0x1d, 0x95, 0xbe, + 0xab, 0x89, 0xc1, 0xbe, 0x18, 0x05, 0x71, 0xbe, 0x89, 0xa6, 0x09, 0xbe, + 0xcd, 0x29, 0x3f, 0xbf, 0x2c, 0x79, 0xf2, 0xbe, 0x93, 0xc5, 0xbb, 0xbe, + 0x7c, 0x5a, 0xec, 0x3e, 0xae, 0x1c, 0x00, 0x3f, 0x44, 0xa5, 0x34, 0x3e, + 0x0d, 0x7b, 0x20, 0xbf, 0x6d, 0xee, 0xa1, 0xbd, 0x03, 0x2c, 0xa9, 0x3d, + 0xec, 0x4b, 0x81, 0x3e, 0xb3, 0x37, 0xaf, 0x3c, 0x20, 0x8b, 0x5d, 0x3f, + 0x22, 0x0c, 0x54, 0x3f, 0x4d, 0x4e, 0x28, 0x3f, 0x2f, 0x4a, 0x2d, 0xbf, + 0x24, 0x48, 0x2e, 0xbf, 0xee, 0x5b, 0x54, 0xbf, 0xde, 0xc2, 0x14, 0xbf, + 0x9b, 0xe2, 0x04, 0xbe, 0x7a, 0xae, 0x91, 0xbe, 0x00, 0x3f, 0xc0, 0xbd, + 0xc8, 0xc7, 0x1b, 0x3e, 0x8a, 0xe2, 0xc2, 0xbd, 0xc4, 0x32, 0x22, 0x3e, + 0x60, 0xb6, 0x90, 0xbe, 0xb2, 0x2e, 0xb6, 0xbd, 0xf6, 0xc8, 0xba, 0xbe, + 0x16, 0x93, 0xe9, 0x3e, 0x9f, 0x66, 0x39, 0x3f, 0x90, 0xa2, 0xeb, 0x3e, + 0xf9, 0x56, 0x22, 0xbd, 0x2e, 0xc1, 0xa5, 0x3d, 0x28, 0x96, 0xbc, 0x3e, + 0x81, 0x74, 0xfb, 0x3e, 0xb9, 0x78, 0x3a, 0x3f, 0x2d, 0x34, 0x90, 0x3f, + 0xbb, 0x7a, 0x7a, 0x3f, 0xf2, 0xf5, 0x57, 0x3f, 0x48, 0x7d, 0x17, 0xbe, + 0xf4, 0x4e, 0xc7, 0xbe, 0xaf, 0x9d, 0x67, 0xbe, 0x46, 0xfb, 0xdf, 0xbe, + 0x77, 0xd1, 0x8e, 0x3c, 0x18, 0x8e, 0x09, 0xbe, 0x43, 0x3e, 0xe2, 0x3c, + 0x73, 0xa7, 0x9d, 0x3d, 0xc7, 0xf9, 0x69, 0x3e, 0xcd, 0x1c, 0xd5, 0x3e, + 0x71, 0x9d, 0x63, 0x3c, 0xf9, 0x3b, 0xa9, 0xbe, 0xba, 0x97, 0x85, 0xbe, + 0x84, 0xff, 0x44, 0x3f, 0x5b, 0x36, 0xdb, 0x3e, 0x60, 0xe1, 0xf0, 0x3e, + 0x27, 0xdb, 0x4c, 0x3f, 0xf9, 0xba, 0xba, 0x3e, 0x92, 0x5f, 0xee, 0x3e, + 0xba, 0x45, 0x8b, 0x3e, 0xee, 0x9c, 0xa2, 0x3e, 0xbf, 0xe7, 0xdd, 0x3e, + 0x72, 0xae, 0x06, 0xbe, 0x9b, 0xaf, 0x99, 0x3e, 0x18, 0x54, 0x4b, 0x3f, + 0xf9, 0x99, 0xc0, 0x3e, 0xd4, 0xbc, 0x5d, 0x3f, 0xa1, 0xb2, 0x74, 0x3f, + 0xcb, 0x91, 0x44, 0x3f, 0x48, 0x4e, 0x6d, 0x3f, 0xb8, 0xce, 0x6b, 0x3f, + 0xd0, 0x01, 0x23, 0x3f, 0xc2, 0x58, 0xc9, 0xbf, 0x3c, 0x9d, 0x78, 0xbf, + 0x96, 0x70, 0x58, 0xbf, 0x75, 0x0e, 0x0a, 0xbe, 0xab, 0x00, 0xb6, 0xbe, + 0xc3, 0x32, 0x91, 0xbe, 0x12, 0xc2, 0x4c, 0xbe, 0x42, 0x12, 0x03, 0xbf, + 0x6a, 0xa6, 0xf2, 0x3e, 0x8d, 0x83, 0x62, 0x3e, 0x9d, 0x95, 0x8c, 0x3e, + 0x0b, 0xf6, 0x06, 0x3e, 0x39, 0xf7, 0x94, 0x3d, 0x8a, 0x9d, 0x06, 0x3f, + 0xaf, 0xa7, 0x0e, 0xbe, 0xe0, 0x0e, 0xac, 0x3e, 0xbd, 0xb1, 0xcb, 0x3e, + 0x4e, 0x53, 0x04, 0xbe, 0x8b, 0x3d, 0x44, 0x3f, 0xfe, 0x3a, 0x62, 0x3f, + 0x42, 0xce, 0x99, 0x3e, 0x9a, 0x56, 0x99, 0x3f, 0x74, 0x62, 0x7e, 0x3f, + 0x97, 0x9e, 0x2f, 0x3f, 0x8f, 0xd6, 0x16, 0xc0, 0x8b, 0x05, 0xbb, 0xbf, + 0x4b, 0x20, 0xad, 0xbf, 0xe2, 0x43, 0xf0, 0xbe, 0x60, 0xc2, 0x5d, 0xbf, + 0x06, 0x14, 0xff, 0xbe, 0xcb, 0xb3, 0x3d, 0xbf, 0x1a, 0xe2, 0x95, 0xbf, + 0x20, 0x9e, 0x77, 0xbc, 0x52, 0x9a, 0x0f, 0xbe, 0x18, 0x4b, 0x38, 0x3e, + 0xde, 0xf9, 0x24, 0xbd, 0x5a, 0x12, 0x86, 0xbd, 0x60, 0x2e, 0x70, 0x3e, + 0x35, 0x13, 0xa7, 0xbe, 0x45, 0x2d, 0xf7, 0x3a, 0x7e, 0x90, 0x1c, 0xbf, + 0x30, 0xc2, 0x0e, 0xbf, 0x1e, 0x61, 0xac, 0x3e, 0x84, 0x9a, 0x04, 0x3f, + 0xb2, 0xb9, 0xee, 0x3d, 0x04, 0xba, 0x6e, 0x3f, 0x1a, 0x2e, 0x20, 0x3f, + 0x28, 0x30, 0xf1, 0x3d, 0x7c, 0xbd, 0x03, 0xc0, 0x8c, 0x80, 0xf5, 0xbf, + 0x2b, 0x54, 0xd0, 0xbf, 0x9c, 0x63, 0x89, 0xbf, 0xe1, 0x08, 0xc4, 0xbf, + 0xc4, 0x5c, 0x7d, 0xbf, 0xdf, 0xfa, 0xd6, 0xbf, 0x2d, 0x48, 0xe3, 0xbf, + 0xb3, 0x10, 0x13, 0xbf, 0xff, 0xa9, 0x82, 0xbe, 0x49, 0x0c, 0x9c, 0xbe, + 0xd8, 0x34, 0x6c, 0xbe, 0x6d, 0x3b, 0xbe, 0xbe, 0x63, 0x2c, 0xd2, 0x3e, + 0xcd, 0xad, 0x39, 0x3f, 0xed, 0xfa, 0x9e, 0x3e, 0xb5, 0x78, 0x86, 0xbf, + 0x9b, 0x85, 0x08, 0xbf, 0xe1, 0xd2, 0x81, 0xbf, 0x0f, 0x69, 0x77, 0xbf, + 0xa6, 0x23, 0x72, 0xbf, 0xfa, 0xc5, 0x06, 0xbf, 0x13, 0x17, 0xe9, 0xbd, + 0xbf, 0x2f, 0x19, 0xbe, 0x7b, 0x48, 0x94, 0xbe, 0x79, 0x83, 0x30, 0xbd, + 0x59, 0x93, 0x34, 0xbf, 0xf9, 0xfc, 0x93, 0xbe, 0x8b, 0x88, 0x45, 0xbe, + 0x63, 0xcc, 0x13, 0x3f, 0x5e, 0x79, 0xf4, 0x3e, 0x20, 0xcc, 0xa8, 0x3d, + 0x93, 0x09, 0x01, 0xbf, 0x6a, 0x4a, 0x09, 0xbf, 0xa2, 0x27, 0xad, 0xbe, + 0x30, 0xec, 0xdf, 0xbd, 0xc6, 0x19, 0x08, 0x3e, 0x4a, 0x4c, 0x44, 0x3f, + 0x27, 0xa3, 0x91, 0x3f, 0x54, 0x7c, 0xf5, 0x3e, 0xc8, 0xc0, 0x46, 0xbf, + 0xb1, 0x49, 0x5d, 0xbf, 0x61, 0xe6, 0x26, 0xbf, 0xa3, 0xba, 0xf8, 0xbe, + 0x9d, 0x69, 0xe8, 0xbe, 0x0c, 0xb2, 0x89, 0xbe, 0xd7, 0xa9, 0x2c, 0xbd, + 0x6f, 0x78, 0x86, 0x3e, 0x83, 0x1f, 0x7d, 0xbe, 0xa1, 0xe8, 0xa2, 0xbd, + 0x95, 0xeb, 0x02, 0xbf, 0x7b, 0x21, 0x9b, 0xbd, 0x69, 0x29, 0x57, 0xbe, + 0x95, 0x7f, 0x38, 0x3f, 0xb8, 0x02, 0x42, 0x3f, 0x7e, 0x1b, 0x47, 0x3f, + 0xf9, 0x6e, 0x2d, 0xbe, 0x09, 0x41, 0x0a, 0xbe, 0x2d, 0x9f, 0x07, 0x3e, + 0x80, 0x20, 0x29, 0x3e, 0xe2, 0x15, 0xe8, 0x3e, 0x21, 0x2f, 0x8a, 0x3f, + 0xfb, 0xa8, 0xb7, 0x3f, 0x41, 0x96, 0x55, 0x3f, 0x50, 0x09, 0xdf, 0xbe, + 0x9c, 0x5f, 0x93, 0xbe, 0xba, 0xac, 0x17, 0xbf, 0x19, 0xb4, 0x2a, 0xbf, + 0x5b, 0x6e, 0xc4, 0xbe, 0x1d, 0x54, 0x16, 0xbd, 0x31, 0xd0, 0xac, 0x3d, + 0x4e, 0x6f, 0xa1, 0x3e, 0xae, 0xa7, 0xb7, 0x3e, 0x25, 0xe7, 0x94, 0x3e, + 0x62, 0x86, 0xbc, 0xbe, 0x06, 0xea, 0x04, 0xbe, 0xc7, 0x5b, 0xe5, 0x3c, + 0x5c, 0x7d, 0x62, 0x3f, 0x2c, 0xe9, 0x22, 0x3f, 0x89, 0x2d, 0x47, 0x3f, + 0xc2, 0xec, 0xaa, 0xbc, 0x1c, 0x66, 0xe5, 0x3e, 0xef, 0x7c, 0xca, 0x3e, + 0xb6, 0x38, 0x0c, 0x3e, 0x00, 0xf4, 0x3f, 0x3f, 0x88, 0x9b, 0x12, 0x3f, + 0x9d, 0x6a, 0x0c, 0x3f, 0xc7, 0x0c, 0x0a, 0x3e, 0x1a, 0x9f, 0x49, 0xbe, + 0xeb, 0xa9, 0x4a, 0xbe, 0x06, 0x65, 0x37, 0xbf, 0xe2, 0x1c, 0x4c, 0xbf, + 0x9b, 0x66, 0x26, 0xbe, 0x99, 0x55, 0x8e, 0xbb, 0x66, 0x70, 0x3e, 0xbf, + 0x60, 0xa3, 0x5a, 0xbf, 0x06, 0xa0, 0x2b, 0x3f, 0x89, 0xc0, 0xb2, 0x3e, + 0x1c, 0x94, 0xad, 0xbd, 0x31, 0x11, 0x4d, 0xbe, 0x08, 0xfc, 0xe4, 0x3d, + 0xbe, 0xd7, 0x3d, 0x3f, 0x89, 0x0f, 0x9a, 0x3e, 0x4e, 0xb8, 0x1e, 0xbf, + 0xf6, 0x45, 0x5b, 0x3e, 0x41, 0x7f, 0xe5, 0x3d, 0x3a, 0x33, 0xa1, 0x3e, + 0xec, 0x75, 0xa4, 0x3e, 0xd6, 0x76, 0x06, 0x3f, 0x24, 0x9f, 0x22, 0x3f, + 0x5f, 0x4a, 0xf4, 0x3e, 0x99, 0x13, 0x6a, 0x3e, 0x68, 0x4e, 0x3b, 0xbd, + 0xd6, 0x43, 0x99, 0xbe, 0xf2, 0x0c, 0x2d, 0xbf, 0xa3, 0xbb, 0x63, 0xbf, + 0xf8, 0x36, 0xed, 0xbd, 0x0e, 0x2d, 0xa0, 0x3c, 0x15, 0x25, 0x23, 0xbf, + 0xd8, 0x3d, 0x41, 0xbf, 0xcb, 0x56, 0x39, 0x3f, 0xc6, 0x9d, 0x06, 0x3f, + 0xf3, 0xe9, 0xd9, 0xbe, 0xd3, 0x56, 0x7f, 0xbe, 0xca, 0xfc, 0xe8, 0xbc, + 0xba, 0x2c, 0xf5, 0x3e, 0x8c, 0x0d, 0x26, 0x3e, 0x49, 0x25, 0xae, 0xbe, + 0x8f, 0xc3, 0x91, 0x3e, 0xc2, 0xa5, 0x94, 0x3e, 0xa3, 0x03, 0xa8, 0x3e, + 0xb6, 0x64, 0xf3, 0x3e, 0x82, 0xfe, 0x08, 0x3f, 0x45, 0x91, 0x25, 0x3f, + 0xd4, 0xaa, 0xb3, 0x3e, 0x96, 0x46, 0x0c, 0x3d, 0x1b, 0xec, 0x11, 0xbe, + 0xf6, 0xe0, 0x49, 0xbe, 0xcd, 0x7e, 0x01, 0xbf, 0xa5, 0x6a, 0x20, 0xbf, + 0x12, 0xfb, 0x75, 0xbe, 0x2e, 0x51, 0xa3, 0xbd, 0x69, 0xdb, 0x17, 0xbf, + 0xdd, 0xf7, 0x54, 0xbf, 0x07, 0xa2, 0x13, 0x3f, 0x23, 0xbd, 0x9f, 0x3e, + 0xe4, 0xb5, 0x1a, 0xbe, 0xa2, 0x81, 0xe7, 0xbe, 0x74, 0xf8, 0x9f, 0xbe, + 0x08, 0xd7, 0x31, 0x3f, 0x7a, 0xbc, 0xcb, 0xbc, 0x2b, 0x4a, 0xc9, 0xbe, + 0xe9, 0x89, 0x12, 0xbf, 0x78, 0x78, 0xe3, 0xbe, 0x35, 0x0d, 0xb7, 0xbe, + 0x53, 0x1f, 0x2b, 0xbe, 0x0a, 0x39, 0x82, 0x3d, 0xeb, 0xba, 0x3b, 0x3f, + 0x0f, 0xe3, 0x4a, 0x3f, 0x9a, 0x5f, 0x22, 0x3f, 0x87, 0xd5, 0x06, 0xbf, + 0x58, 0x5c, 0x70, 0xbf, 0x85, 0x41, 0x67, 0xbf, 0x5e, 0xcd, 0x3c, 0xbf, + 0x81, 0xb7, 0x3d, 0xbf, 0x69, 0xd9, 0x6c, 0xbe, 0x2e, 0xf0, 0x53, 0xbd, + 0xad, 0x74, 0x53, 0x3c, 0xce, 0x4f, 0x82, 0x3d, 0x5f, 0x8d, 0xbc, 0x3e, + 0xa5, 0xeb, 0x1d, 0xbf, 0x79, 0xb2, 0x38, 0xbe, 0x2d, 0x13, 0xf3, 0xbe, + 0x5e, 0xaa, 0xc0, 0x3c, 0x23, 0x2b, 0x75, 0x3e, 0xa0, 0xbb, 0xd3, 0x3e, + 0xc9, 0x10, 0xb6, 0x3b, 0xc0, 0x83, 0x25, 0x3d, 0xc7, 0x56, 0x93, 0xbc, + 0x6c, 0x09, 0x38, 0xbd, 0xbc, 0x4b, 0x4b, 0x3e, 0xf3, 0x9a, 0x57, 0x3f, + 0xf6, 0xde, 0x99, 0x3f, 0xe3, 0xfd, 0x13, 0x3f, 0x65, 0xdf, 0xfd, 0xbe, + 0xc2, 0xea, 0x3d, 0xbf, 0x37, 0x05, 0x02, 0xbf, 0x7d, 0xa6, 0x3e, 0xbf, + 0x6f, 0x8e, 0x1c, 0xbf, 0x9c, 0x78, 0x69, 0xbe, 0xe3, 0xef, 0xfb, 0xbd, + 0xd9, 0xcb, 0x1c, 0x3e, 0xba, 0x78, 0xea, 0x3e, 0x89, 0x2c, 0x26, 0x3c, + 0x14, 0x6c, 0x86, 0xbe, 0x30, 0x69, 0x3c, 0xbe, 0x53, 0xe1, 0xc7, 0xbe, + 0xd1, 0xc7, 0xde, 0x3d, 0x50, 0x51, 0xf4, 0x3e, 0xb2, 0x18, 0xfe, 0x3e, + 0xb2, 0x99, 0x17, 0x3e, 0xda, 0x24, 0x93, 0x3e, 0xbd, 0xce, 0xe5, 0x3e, + 0xd6, 0xc2, 0xe8, 0x3e, 0xcd, 0xff, 0x0d, 0x3f, 0x8a, 0x38, 0x5e, 0x3f, + 0xaf, 0xcb, 0x8b, 0x3f, 0xae, 0x72, 0x6e, 0x3f, 0xe2, 0x96, 0x9d, 0xbd, + 0xb7, 0x8e, 0x3e, 0xbe, 0x29, 0x0a, 0x56, 0xbe, 0x8a, 0x36, 0xe6, 0xbe, + 0xfd, 0x6f, 0xe2, 0xbe, 0x22, 0xd7, 0x48, 0xbe, 0x95, 0x68, 0x2f, 0xbe, + 0x24, 0x7b, 0xc8, 0xbc, 0x3b, 0xe5, 0x04, 0x3f, 0xc4, 0x38, 0xf2, 0x3e, + 0x64, 0x7e, 0x28, 0xbe, 0x4e, 0xa4, 0x78, 0xbe, 0xe1, 0x73, 0x7b, 0xbe, + 0x58, 0xba, 0xb0, 0x3d, 0xa2, 0x63, 0x07, 0x3e, 0x1c, 0x86, 0x1b, 0x3f, + 0xc0, 0x8c, 0x82, 0xbb, 0x62, 0xc8, 0xcc, 0x3e, 0xc8, 0xab, 0xf1, 0x3e, + 0x9d, 0xeb, 0x1d, 0x3f, 0xbb, 0x20, 0x5b, 0x3f, 0xe2, 0xd8, 0x46, 0x3f, + 0xec, 0x50, 0x0b, 0x3f, 0xe2, 0xb8, 0xe2, 0x3e, 0xac, 0x40, 0x01, 0x3d, + 0x7e, 0x19, 0x0e, 0x3f, 0xd1, 0xb4, 0x0b, 0x3f, 0x35, 0xaf, 0x78, 0x3f, + 0x39, 0x06, 0x8b, 0x3f, 0xdf, 0xda, 0x97, 0x3f, 0xe1, 0x3a, 0x9a, 0x3f, + 0x2a, 0x1a, 0x6b, 0x3f, 0x41, 0x24, 0x69, 0x3e, 0x9f, 0xeb, 0x99, 0xbd, + 0xc0, 0x88, 0xb2, 0x3d, 0x18, 0x1f, 0xa5, 0x3e, 0xdc, 0xd2, 0x12, 0x3f, + 0x31, 0xa6, 0xab, 0x3e, 0xd0, 0x2d, 0x2f, 0xbc, 0x9a, 0x7b, 0x5d, 0x3e, + 0xb5, 0xd8, 0xc8, 0xbf, 0x14, 0xce, 0x3a, 0xbf, 0x99, 0x6b, 0xe0, 0xbe, + 0xdf, 0x37, 0x30, 0x3d, 0x5a, 0x83, 0x0f, 0x3e, 0x32, 0xaa, 0xd0, 0x3e, + 0x06, 0x97, 0x66, 0x3c, 0xcd, 0xa3, 0x85, 0x3e, 0xd5, 0x8f, 0xca, 0xbe, + 0x8c, 0xd4, 0x3c, 0x3e, 0x7e, 0x96, 0x93, 0x3c, 0xd1, 0x92, 0x00, 0x3f, + 0xb7, 0x32, 0xce, 0x3e, 0xd8, 0xf9, 0x5d, 0x3f, 0x4c, 0x0a, 0x2d, 0x3f, + 0xa2, 0xa1, 0x6c, 0x3f, 0xbf, 0xfc, 0xf7, 0x3d, 0x5a, 0x4d, 0xc8, 0xbe, + 0x87, 0x31, 0xdc, 0xbd, 0x97, 0x27, 0x5d, 0xbd, 0xf2, 0x9a, 0x8c, 0x3e, + 0x74, 0x3f, 0xf3, 0xbd, 0xec, 0x45, 0x8f, 0xbe, 0xd6, 0x50, 0x1f, 0xbe, + 0x5e, 0x36, 0x1d, 0xc0, 0xd7, 0xc4, 0xe8, 0xbf, 0x72, 0x4b, 0xc0, 0xbf, + 0x30, 0x1e, 0x8a, 0xbf, 0x61, 0xce, 0x0c, 0xbf, 0x75, 0xee, 0xaa, 0xbe, + 0xba, 0x01, 0x79, 0xbf, 0xef, 0xa2, 0x41, 0xbf, 0xc4, 0xd3, 0xc5, 0xbf, + 0xbc, 0x63, 0x7c, 0xbf, 0xed, 0xaa, 0xfe, 0xbe, 0xd1, 0xc4, 0x97, 0x3c, + 0x8f, 0x71, 0xd3, 0xbb, 0x6e, 0x24, 0x9c, 0x3e, 0x7f, 0x4c, 0x09, 0x3d, + 0x5a, 0xd7, 0x3e, 0x3e, 0x79, 0x99, 0xf0, 0xbe, 0x7d, 0x6d, 0x8c, 0xbe, + 0xed, 0x30, 0x44, 0xbd, 0x44, 0xa7, 0x2a, 0xbe, 0xca, 0xad, 0x19, 0x3e, + 0x8f, 0x05, 0xa7, 0xbd, 0x3f, 0x40, 0x8a, 0xbf, 0x9f, 0x9b, 0x96, 0xbf, + 0x88, 0x9d, 0xc6, 0x3e, 0xf7, 0x0b, 0x5d, 0x3e, 0xba, 0x96, 0xaa, 0x3e, + 0x3c, 0x7b, 0x97, 0x3e, 0x3b, 0x3c, 0x1d, 0x3e, 0xa0, 0x8c, 0xc5, 0x3e, + 0x56, 0xa8, 0x00, 0xbe, 0xd6, 0xa1, 0xde, 0x3e, 0x93, 0x84, 0xcc, 0x3e, + 0x3b, 0x31, 0x56, 0x3e, 0x5d, 0xd7, 0x0e, 0x3f, 0x77, 0x7d, 0x63, 0x3f, + 0xda, 0x89, 0x0f, 0x3f, 0x4f, 0x97, 0x5c, 0x3f, 0x27, 0xd4, 0x54, 0x3f, + 0x70, 0x2f, 0x39, 0x3f, 0x65, 0xd6, 0x80, 0xbf, 0xb9, 0xba, 0x81, 0xbf, + 0xe2, 0xe6, 0x8d, 0xbf, 0x49, 0x66, 0x99, 0xbe, 0x55, 0x77, 0x4b, 0xbf, + 0x1f, 0x2b, 0xab, 0xbe, 0x4b, 0xac, 0x9f, 0xbe, 0xc9, 0xe9, 0x74, 0xbf, + 0x26, 0x59, 0xdf, 0x3e, 0x3c, 0x6e, 0x85, 0x3d, 0x38, 0x30, 0x8e, 0x3e, + 0x8f, 0x23, 0x5d, 0x3e, 0x80, 0x02, 0x0f, 0x3d, 0xcb, 0x82, 0xb8, 0x3e, + 0x24, 0x61, 0x88, 0xbe, 0xa8, 0x86, 0xad, 0x3e, 0x76, 0x04, 0xa1, 0x3e, + 0x7d, 0x81, 0x4e, 0xbe, 0x5d, 0xf4, 0x18, 0x3f, 0xb6, 0xa3, 0x17, 0x3f, + 0x62, 0x1e, 0x31, 0x3e, 0x78, 0x5d, 0x76, 0x3f, 0xa9, 0xc0, 0x70, 0x3f, + 0x3d, 0x88, 0x1c, 0x3f, 0x5b, 0x36, 0xa1, 0xbf, 0x8e, 0x8e, 0x84, 0xbf, + 0xa8, 0x04, 0xb1, 0xbf, 0xa4, 0xb0, 0x3d, 0xbf, 0xd5, 0x9c, 0x77, 0xbf, + 0x4d, 0x85, 0x3b, 0xbf, 0xc0, 0x31, 0x35, 0xbf, 0x41, 0xdf, 0x95, 0xbf, + 0x07, 0xaa, 0x98, 0x3e, 0xee, 0x1d, 0x9f, 0x3d, 0x4e, 0x74, 0x95, 0x3e, + 0xe9, 0x89, 0x20, 0x3e, 0x1e, 0xbc, 0xa8, 0xbd, 0x62, 0x49, 0x6e, 0x3e, + 0xaf, 0xf3, 0xad, 0xbe, 0x61, 0x52, 0xbb, 0x3d, 0xda, 0x70, 0x6c, 0x3e, + 0x66, 0x9c, 0xb7, 0xbe, 0xd7, 0xbc, 0x09, 0x3f, 0xc8, 0x66, 0x24, 0x3f, + 0xdb, 0x10, 0xb7, 0x3d, 0x07, 0x31, 0x33, 0x3f, 0x0b, 0x16, 0x10, 0x3f, + 0x3d, 0xf2, 0x2e, 0x3e, 0x53, 0x56, 0xd9, 0xbf, 0x24, 0x16, 0xb8, 0xbf, + 0xa1, 0x28, 0x90, 0xbf, 0x59, 0x5c, 0x8d, 0xbf, 0x22, 0x49, 0x73, 0xbf, + 0x36, 0x9f, 0x50, 0xbf, 0x9e, 0xb5, 0x53, 0xbf, 0x73, 0xc9, 0xc2, 0xbf, + 0xb8, 0x73, 0x4a, 0x3f, 0x05, 0x09, 0xc7, 0x3e, 0x9b, 0xba, 0x18, 0x3f, + 0x2b, 0x43, 0xa3, 0x3e, 0xd5, 0xa6, 0x8d, 0x3e, 0x77, 0x16, 0x0a, 0x3f, + 0x48, 0xd7, 0x13, 0xbe, 0x39, 0x6b, 0x04, 0x3f, 0xa0, 0xde, 0x74, 0x3f, + 0xd0, 0xc3, 0x7c, 0x3e, 0x7f, 0x40, 0x46, 0x3f, 0xed, 0xeb, 0x82, 0x3f, + 0x37, 0x20, 0x49, 0x3f, 0xec, 0xfa, 0xa5, 0x3f, 0x99, 0x65, 0x88, 0x3f, + 0xf6, 0xd1, 0x35, 0x3f, 0xc2, 0x09, 0xc5, 0xbf, 0xd7, 0x7a, 0xa7, 0xbf, + 0x1b, 0xf0, 0x93, 0xbf, 0x00, 0x17, 0x06, 0xbf, 0x4c, 0x4e, 0x71, 0xbf, + 0x6a, 0x68, 0x11, 0xbf, 0x8b, 0x97, 0xdf, 0xbe, 0x0b, 0x4e, 0x8c, 0xbf, + 0xce, 0xb4, 0x20, 0x3f, 0x2c, 0xcf, 0x89, 0x3e, 0x2c, 0x47, 0x9f, 0x3e, + 0x4f, 0x7e, 0xa7, 0x3e, 0xf0, 0x4d, 0xc3, 0x3d, 0x5a, 0xb2, 0x01, 0x3f, + 0xa8, 0xdb, 0x88, 0xbe, 0x55, 0x0a, 0xd4, 0x3e, 0x75, 0x42, 0xc7, 0x3e, + 0x8b, 0xd7, 0x9c, 0xbc, 0xed, 0x35, 0x86, 0x3f, 0x3b, 0x58, 0x5e, 0x3f, + 0x95, 0xf9, 0x9f, 0x3e, 0xe7, 0xd9, 0x9d, 0x3f, 0x7b, 0x5d, 0x97, 0x3f, + 0x67, 0x3e, 0x2c, 0x3f, 0xb2, 0x33, 0x09, 0xc0, 0xc8, 0x5a, 0xe9, 0xbf, + 0x88, 0xec, 0xfa, 0xbf, 0xcb, 0x02, 0x92, 0xbf, 0xf4, 0xb5, 0x94, 0xbf, + 0xa4, 0xc4, 0x74, 0xbf, 0x07, 0xe2, 0x70, 0xbf, 0x7a, 0x62, 0xa0, 0xbf, + 0x60, 0x74, 0xbe, 0x3e, 0xbb, 0x00, 0x0c, 0xbd, 0xca, 0x93, 0xea, 0x3e, + 0x3e, 0xf8, 0x07, 0x3e, 0x4f, 0xce, 0x3e, 0xbe, 0xd4, 0x31, 0xa4, 0x3e, + 0x13, 0x25, 0xea, 0xbe, 0x5e, 0x2c, 0xf8, 0x3d, 0x7e, 0xa8, 0x17, 0xbe, + 0x61, 0x7d, 0x2d, 0xbf, 0x6e, 0x8d, 0x73, 0x3f, 0x24, 0x08, 0x56, 0x3f, + 0x00, 0xb5, 0x3d, 0xbd, 0xdf, 0x27, 0x86, 0x3f, 0x39, 0x82, 0x64, 0x3f, + 0xf6, 0xce, 0xbe, 0x3e, 0x08, 0xf3, 0x05, 0xc0, 0x1d, 0x18, 0xee, 0xbf, + 0x7e, 0xa0, 0x03, 0xc0, 0xd1, 0x1b, 0xbb, 0xbf, 0xd7, 0x15, 0xbc, 0xbf, + 0x5a, 0x3d, 0xac, 0xbf, 0x3b, 0x6b, 0xc1, 0xbf, 0x08, 0x06, 0xde, 0xbf, + 0x32, 0xfe, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x74, 0x6b, 0x7c, 0xbe, 0x5b, 0xf0, 0x96, 0xbe, 0xc8, 0xcf, 0x84, 0xbe, + 0xda, 0xce, 0x5a, 0x3d, 0xe2, 0xab, 0x50, 0x3f, 0x67, 0xf2, 0x82, 0xbe, + 0x8f, 0xac, 0x9e, 0xbe, 0x72, 0x63, 0x95, 0x3a, 0x4e, 0x77, 0x60, 0x3d, + 0x47, 0xa6, 0xb8, 0x3d, 0xac, 0xf6, 0xff, 0xff, 0xb0, 0xf6, 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, 0x24, 0x02, 0x00, 0x00, + 0x28, 0x02, 0x00, 0x00, 0x2c, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0xd4, 0x01, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, + 0xf4, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2a, 0xff, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0xd6, 0xfe, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x60, 0xf7, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x10, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x94, 0xf7, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3a, 0xff, 0xff, 0xff, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x13, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 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, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0xba, 0xff, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3b, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x0b, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x24, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x04, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, + 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0xb0, 0x06, 0x00, 0x00, 0x40, 0x06, 0x00, 0x00, 0xd4, 0x05, 0x00, 0x00, + 0x80, 0x05, 0x00, 0x00, 0x24, 0x05, 0x00, 0x00, 0xb4, 0x04, 0x00, 0x00, + 0x64, 0x04, 0x00, 0x00, 0x14, 0x04, 0x00, 0x00, 0xa8, 0x03, 0x00, 0x00, + 0x60, 0x03, 0x00, 0x00, 0x14, 0x03, 0x00, 0x00, 0xc4, 0x02, 0x00, 0x00, + 0x70, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, + 0xd4, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xae, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x94, 0xf9, 0xff, 0xff, 0x19, 0x00, 0x00, 0x00, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x66, 0x75, 0x6c, 0x50, 0x61, 0x72, 0x74, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x43, 0x61, 0x6c, 0x6c, 0x3a, + 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x06, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xec, 0xf9, 0xff, 0xff, + 0x30, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x2f, 0x4d, 0x61, 0x74, + 0x4d, 0x75, 0x6c, 0x3b, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x2f, 0x42, 0x69, 0x61, + 0x73, 0x41, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x76, 0xfa, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, + 0x5c, 0xfa, 0xff, 0xff, 0x28, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x67, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x5f, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x6f, + 0x6f, 0x6c, 0x69, 0x6e, 0x67, 0x32, 0x64, 0x2f, 0x4d, 0x65, 0x61, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0xde, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x14, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0xcc, 0xfa, 0xff, 0xff, 0x72, 0x00, 0x00, 0x00, + 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x63, + 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x3b, 0x73, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x63, 0x6f, + 0x6e, 0x76, 0x32, 0x64, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, 0x64, + 0x3b, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, + 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, + 0x44, 0x3b, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x2f, 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x2f, 0x42, 0x69, 0x61, 0x73, + 0x41, 0x64, 0x64, 0x2f, 0x52, 0x65, 0x61, 0x64, 0x56, 0x61, 0x72, 0x69, + 0x61, 0x62, 0x6c, 0x65, 0x4f, 0x70, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x9e, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x14, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x8c, 0xfb, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, + 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x72, + 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2f, 0x52, 0x65, 0x73, 0x68, 0x61, + 0x70, 0x65, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x82, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x30, 0x00, 0x00, 0x00, 0xe0, 0xfb, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, + 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x72, + 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2f, 0x52, 0x65, 0x73, 0x68, 0x61, + 0x70, 0x65, 0x2f, 0x73, 0x68, 0x61, 0x70, 0x65, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd2, 0xfd, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x00, + 0x30, 0xfc, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x72, 0x65, 0x73, 0x68, 0x61, + 0x70, 0x65, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, 0x64, 0x5f, 0x73, + 0x6c, 0x69, 0x63, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x28, 0x00, 0x00, 0x00, 0x7c, 0xfc, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00, + 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x72, + 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2f, 0x53, 0x68, 0x61, 0x70, 0x65, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x56, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0xc0, 0xfc, 0xff, 0xff, 0x17, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, + 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xaa, 0xfe, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x48, 0x00, 0x00, 0x00, + 0x08, 0xfd, 0xff, 0xff, 0x3a, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x67, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x5f, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x6f, + 0x6f, 0x6c, 0x69, 0x6e, 0x67, 0x32, 0x64, 0x2f, 0x4d, 0x65, 0x61, 0x6e, + 0x2f, 0x72, 0x65, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x12, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x00, 0x70, 0xfd, 0xff, 0xff, + 0x22, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x2f, 0x72, 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2f, 0x52, + 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2f, 0x73, 0x68, 0x61, 0x70, 0x65, + 0x2f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00, 0x00, + 0xbc, 0xfd, 0xff, 0xff, 0x22, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x72, 0x65, 0x73, 0x68, 0x61, + 0x70, 0x65, 0x2f, 0x52, 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2f, 0x73, + 0x68, 0x61, 0x70, 0x65, 0x2f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xaa, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x34, 0x00, 0x00, 0x00, 0x08, 0xfe, 0xff, 0xff, 0x26, 0x00, 0x00, 0x00, + 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x72, + 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x64, + 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2f, 0x73, 0x74, 0x61, + 0x63, 0x6b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 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, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x38, 0x00, 0x00, 0x00, 0x74, 0xfe, 0xff, 0xff, 0x28, 0x00, 0x00, 0x00, + 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x72, + 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2f, 0x73, 0x74, 0x72, 0x69, 0x64, + 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2f, 0x73, 0x74, 0x61, + 0x63, 0x6b, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x5e, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0xc8, 0xfe, 0xff, 0xff, 0x27, 0x00, 0x00, 0x00, + 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x64, + 0x65, 0x6e, 0x73, 0x65, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, 0x64, + 0x2f, 0x52, 0x65, 0x61, 0x64, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, + 0x65, 0x4f, 0x70, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xae, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x18, 0xff, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x76, 0x32, + 0x64, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, + 0x18, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, + 0x28, 0x00, 0x00, 0x00, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x2f, 0x42, 0x69, + 0x61, 0x73, 0x41, 0x64, 0x64, 0x2f, 0x52, 0x65, 0x61, 0x64, 0x56, 0x61, + 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4f, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, + 0x1c, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x5f, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x68, + 0x61, 0x70, 0x65, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x3a, 0x30, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xac, 0xff, 0xff, 0xff, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0e, 0xb8, 0xff, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0xc4, 0xff, 0xff, 0xff, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x28, 0xd0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xdc, 0xff, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x16, 0xe8, 0xff, 0xff, 0xff, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x53, 0xf4, 0xff, 0xff, 0xff, 0x2d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2d, 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x4d}; +extern const int model_tflite_len PROGMEM = 6208; + +#endif // TENSORFLOW_LITE_MICRO_MODEL_DATA_H_ \ No newline at end of file From bec8f75dd196e01703e7c31122755f4b26294d48 Mon Sep 17 00:00:00 2001 From: Felix Erdmann Date: Tue, 11 Jun 2024 14:10:20 +0200 Subject: [PATCH 3/4] fix: distance sensor merge --- .../sensors/DistanceSensor/DistanceSensor.cpp | 81 ++++++++++--------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp index 94cd1b7..4777c59 100644 --- a/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp +++ b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp @@ -8,7 +8,6 @@ int distanceCharacteristic = 0; String overtakingUUID = "FC01C6882C444965AE18373AF9FED18D"; int overtakingCharacteristic = 0; - #include "model_data.h" #include #include @@ -25,14 +24,14 @@ int overtakingCharacteristic = 0; VL53L8CX sensor_vl53l8cx_top(&Wire, -1, -1); const int kChannelNumber = 64; const int kFrameNumber = 20; -const tflite::Model* model = nullptr; -tflite::MicroInterpreter* interpreter = nullptr; -TfLiteTensor* model_input = nullptr; +const tflite::Model *model = nullptr; +tflite::MicroInterpreter *interpreter = nullptr; +TfLiteTensor *model_input = nullptr; int input_length; // Create an area of memory to use for input, output, and intermediate arrays. // The size of this will depend on the model you're using, and may need to be // determined by experimentation. -constexpr int kTensorArenaSize = 14 * 1024 + 1008 ; +constexpr int kTensorArenaSize = 14 * 1024 + 1008; uint8_t tensor_arena[kTensorArenaSize]; // A buffer holding the last 20 sets of 8x8 pixels @@ -60,10 +59,11 @@ void DistanceSensor::initSensor() // -------------------------- setup tensorflow model -------------------------- Serial.println("setting up tensorflow..."); model = tflite::GetModel(g_model_data); - if (model->version() != TFLITE_SCHEMA_VERSION) { + if (model->version() != TFLITE_SCHEMA_VERSION) + { Serial.printf("Model provided is schema version %d not equal " - "to supported version %d.", - model->version(), TFLITE_SCHEMA_VERSION); + "to supported version %d.", + model->version(), TFLITE_SCHEMA_VERSION); return; } static tflite::MicroErrorReporter tflErrorReporter; @@ -72,7 +72,7 @@ void DistanceSensor::initSensor() static tflite::AllOpsResolver resolver; // Build an interpreter to run the model with. static tflite::MicroInterpreter static_interpreter( - model, resolver, (uint8_t*)(tensor_arena), (size_t)(kTensorArenaSize), &tflErrorReporter); + model, resolver, (uint8_t *)(tensor_arena), (size_t)(kTensorArenaSize), &tflErrorReporter); interpreter = &static_interpreter; // Allocate memory from the tensor_arena for the model's tensors. interpreter->AllocateTensors(); @@ -80,8 +80,9 @@ void DistanceSensor::initSensor() model_input = interpreter->input(0); if ((model_input->dims->size != 3) || (model_input->dims->data[0] != 1) || (model_input->dims->data[1] != kFrameNumber) || - (model_input->dims->data[2] != kChannelNumber) || - (model_input->type != kTfLiteFloat32)) { + (model_input->dims->data[2] != kChannelNumber) || + (model_input->type != kTfLiteFloat32)) + { Serial.println(model_input->dims->size); Serial.println(model_input->dims->data[0]); Serial.println(model_input->dims->data[1]); @@ -109,7 +110,7 @@ void DistanceSensor::readSensorData() float distance = -1.0; if ((!status) && (NewDataReady != 0)) - { + { sensor_vl53l8cx_top.vl53l8cx_get_ranging_data(&Results); float overtakingPredictionPercentage = -1.0; float oldVl53l8cxMin = -1.0; @@ -120,20 +121,24 @@ void DistanceSensor::readSensorData() { for (int k = (8 - 1); k >= 0; k--) { - if ((float)(&Results)->target_status[(VL53L8CX_NB_TARGET_PER_ZONE * (j+k)) + l] != 255) + if ((float)(&Results)->target_status[(VL53L8CX_NB_TARGET_PER_ZONE * (j + k)) + l] != 255) { - if((float)(&Results)->distance_mm[(VL53L8CX_NB_TARGET_PER_ZONE * (j+k)) + l] > 2000.0){ + if ((float)(&Results)->distance_mm[(VL53L8CX_NB_TARGET_PER_ZONE * (j + k)) + l] > 2000.0) + { save_data[begin_index++] = 0.0; - } else { - save_data[begin_index++] = (float)(&Results)->distance_mm[(VL53L8CX_NB_TARGET_PER_ZONE * (j+k)) + l]; } - float distance = ((&Results)->distance_mm[(VL53L8CX_NB_TARGET_PER_ZONE * (j+k)) + l])/10; + else + { + save_data[begin_index++] = (float)(&Results)->distance_mm[(VL53L8CX_NB_TARGET_PER_ZONE * (j + k)) + l]; + } + float distance = ((&Results)->distance_mm[(VL53L8CX_NB_TARGET_PER_ZONE * (j + k)) + l]) / 10; if (min > distance) { min = distance; } } - else { + else + { save_data[begin_index++] = 0.0; } } @@ -142,51 +147,55 @@ void DistanceSensor::readSensorData() oldVl53l8cxMin = (min == 10000.0) ? 0.0 : min; // If we reached the end of the circle buffer, reset - if (begin_index >= (RING_BUFFER_SIZE)) { + if (begin_index >= (RING_BUFFER_SIZE)) + { begin_index = 0; // Check if we are ready for prediction or still pending more initial data - if (pending_initial_data) { + if (pending_initial_data) + { pending_initial_data = false; } } - if (!pending_initial_data) { - for (int i = 0; i < input_length; ++i) { + if (!pending_initial_data) + { + for (int i = 0; i < input_length; ++i) + { int ring_array_index = begin_index + i - input_length; - if (ring_array_index < 0) { + if (ring_array_index < 0) + { ring_array_index += (RING_BUFFER_SIZE); } // normalize - model_input->data.f[i] = save_data[ring_array_index]/2000.0; + model_input->data.f[i] = save_data[ring_array_index] / 2000.0; } // Run inference, and report any error. TfLiteStatus invoke_status = interpreter->Invoke(); - if (invoke_status == kTfLiteOk) { - const float* prediction_scores = interpreter->output(0)->data.f; + if (invoke_status == kTfLiteOk) + { + const float *prediction_scores = interpreter->output(0)->data.f; overtakingPredictionPercentage = prediction_scores[0]; } } - distance = (min == 10000.0) ? 0.0 : min / 10.0; - Serial.printf("Distance: %.2f cm\n", distance); - } - float distance = oldVl53l8cxMin; + oldVl53l8cxMin = (min == 10000.0) ? 0.0 : min; if (measurementCallback) { measurementCallback({distance, overtakingPredictionPercentage}); } - if (sendBLE && (millis()-prevBleTime)>=1000) + if (sendBLE && (millis() - prevBleTime) >= 1000) { - notifyBLE(distance,overtakingPredictionPercentage); + notifyBLE(distance, overtakingPredictionPercentage); prevBleTime = millis(); } } - if((millis()-prevMeasureTime)<65){ - vTaskDelay(pdMS_TO_TICKS(65-(millis()-prevMeasureTime))); + if ((millis() - prevMeasureTime) < 65) + { + vTaskDelay(pdMS_TO_TICKS(65 - (millis() - prevMeasureTime))); } - Serial.println(millis()-prevMeasureTime); - prevMeasureTime=millis(); + Serial.println(millis() - prevMeasureTime); + prevMeasureTime = millis(); } void DistanceSensor::notifyBLE(float distance, float overtakingPredictionPercentage) From 728616408d0a234c6af5c641477108965827fd2a Mon Sep 17 00:00:00 2001 From: Felix Erdmann Date: Tue, 11 Jun 2024 14:11:57 +0200 Subject: [PATCH 4/4] chore: organize distancesensor file --- .../sensors/DistanceSensor/DistanceSensor.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp index 4777c59..3d366ae 100644 --- a/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp +++ b/senseBox-bike-atrai-v2/src/sensors/DistanceSensor/DistanceSensor.cpp @@ -1,13 +1,5 @@ #include "DistanceSensor.h" -DistanceSensor::DistanceSensor() : BaseSensor("distanceTask", 8192, 100) {} - -String distanceUUID = "B3491B60C0F34306A30D49C91F37A62B"; -int distanceCharacteristic = 0; - -String overtakingUUID = "FC01C6882C444965AE18373AF9FED18D"; -int overtakingCharacteristic = 0; - #include "model_data.h" #include #include @@ -21,6 +13,14 @@ int overtakingCharacteristic = 0; #include "tensorflow/lite/schema/schema_generated.h" #include +DistanceSensor::DistanceSensor() : BaseSensor("distanceTask", 8192, 100) {} + +String distanceUUID = "B3491B60C0F34306A30D49C91F37A62B"; +int distanceCharacteristic = 0; + +String overtakingUUID = "FC01C6882C444965AE18373AF9FED18D"; +int overtakingCharacteristic = 0; + VL53L8CX sensor_vl53l8cx_top(&Wire, -1, -1); const int kChannelNumber = 64; const int kFrameNumber = 20; @@ -177,7 +177,7 @@ void DistanceSensor::readSensorData() } } - oldVl53l8cxMin = (min == 10000.0) ? 0.0 : min; + float distance = oldVl53l8cxMin; if (measurementCallback) { @@ -202,4 +202,4 @@ void DistanceSensor::notifyBLE(float distance, float overtakingPredictionPercent { BLEModule::writeBLE(distanceCharacteristic, distance); BLEModule::writeBLE(overtakingCharacteristic, overtakingPredictionPercentage); -} +} \ No newline at end of file