From cccba04026b4392ecb0271f2a1379501537eb012 Mon Sep 17 00:00:00 2001 From: GOB Date: Thu, 15 Dec 2022 01:58:31 +0900 Subject: [PATCH 01/31] Add receive jma forecast and display forecast --- .gitignore | 5 +- platformio.ini | 114 ++-- src/aq_talk.cpp | 352 +++++++++++- src/aq_talk.hpp | 11 +- src/cpu_usage.cpp | 47 ++ src/cpu_usage.hpp | 14 + src/jma/jma_definition.cpp | 800 +++++++++++++++++++++++++++ src/jma/jma_definition.hpp | 20 + src/jma/jma_forecast.cpp | 210 +++++++ src/jma/jma_forecast.hpp | 167 ++++++ src/jma/jma_forecast_handler.cpp | 525 ++++++++++++++++++ src/jma/jma_forecast_handler.hpp | 267 +++++++++ src/jma/jma_task.cpp | 152 ++++++ src/jma/jma_task.hpp | 18 + src/main.cpp | 819 ++++++++++++++-------------- src/ponko_avatar.cpp | 220 ++++++-- src/ponko_avatar.hpp | 35 +- src/res/resource.h | 104 +++- src/u8g2_font_profont22_tr.cpp | 3 +- src/{ => wb2}/wxbeacon2.cpp | 10 +- src/{ => wb2}/wxbeacon2.hpp | 2 +- src/{ => wb2}/wxbeacon2_ble.cpp | 0 src/{ => wb2}/wxbeacon2_ble.hpp | 0 src/wb2/wxbeacon2_communication.cpp | 264 +++++++++ src/wb2/wxbeacon2_communication.hpp | 19 + src/{ => wb2}/wxbeacon2_log.hpp | 3 + src/wni_ticker.cpp | 105 ++-- src/wni_ticker.hpp | 31 +- 28 files changed, 3738 insertions(+), 579 deletions(-) create mode 100644 src/cpu_usage.cpp create mode 100644 src/cpu_usage.hpp create mode 100644 src/jma/jma_definition.cpp create mode 100644 src/jma/jma_definition.hpp create mode 100644 src/jma/jma_forecast.cpp create mode 100644 src/jma/jma_forecast.hpp create mode 100644 src/jma/jma_forecast_handler.cpp create mode 100644 src/jma/jma_forecast_handler.hpp create mode 100644 src/jma/jma_task.cpp create mode 100644 src/jma/jma_task.hpp rename src/{ => wb2}/wxbeacon2.cpp (92%) rename src/{ => wb2}/wxbeacon2.hpp (99%) rename src/{ => wb2}/wxbeacon2_ble.cpp (100%) rename src/{ => wb2}/wxbeacon2_ble.hpp (100%) create mode 100644 src/wb2/wxbeacon2_communication.cpp create mode 100644 src/wb2/wxbeacon2_communication.hpp rename src/{ => wb2}/wxbeacon2_log.hpp (98%) diff --git a/.gitignore b/.gitignore index 2024720..c68df03 100644 --- a/.gitignore +++ b/.gitignore @@ -33,7 +33,4 @@ # resources -ponko_face.cpp -ponko_mouth_*.cpp -logo.cpp - +/src/res/*.cpp diff --git a/platformio.ini b/platformio.ini index 6b660a7..e83ba5e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,63 +1,35 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html - - ;----------------------------------------------------------------------- ; M5S_WxBeacon2 ; NOTE : Please save ssid/pass credential to your M5Stack before invoke this program. ; WiFi.begin() use it. ;----------------------------------------------------------------------- [env] -platform = espressif32@3.4.0 -;platform = espressif32@4.4.0 +platform = espressif32@4.4.0 +;platform = espressif32 +framework = arduino board_build.flash_mode = qio board_build.f_flash = 80000000L board_build.f_cpu = 240000000L -framework = arduino -;The libraries are shared between ArduinoIDE and PlatformIO. -;lib_extra_dirs is the ArduinoIDE library directory. -lib_extra_dirs = ~/projects/M5Stack/libraries/ +; https://github.com/tanakamasayuki/aquestalk download zip and extract ./lib folder. +lib_extra_dirs = /lib lib_ldf_mode = deep -;lib_deps=m5stack/M5Unified - -monitor_port = /dev/cu.SLAB_USBtoUART +lib_deps = m5stack/M5Unified + h2zero/NimBLE-Arduino + https://github.com/mrfaptastic/json-streaming-parser2.git @ ^2.0.3 + https://github.com/GOB52/gob_datetime.git @ ^0.1.1 + monitor_speed = 115200 -;monitor_filters = time, esp32_exception_decoder monitor_filters = esp32_exception_decoder, time - upload_speed = 921600 -upload_port = /dev/cu.SLAB_USBtoUART - -; Definition if you want. -; M5S_WXBEACON2_GMT_OFFSET_HOUR : Your time zone(Unit: 1 hour). e.g. +9 (JST) -; M5S_WXBEACON2_DAYLIGHT_OFFSET_SEC : Your daylight time (Unit : 1 second). -; M5S_WXBEACON2_WIFI_HOST_NAME : Your host name for WiFi connection. ("arduino-esp32" as default) -; -build_flags = -Wall -Wextra -Wreturn-local-addr - -D M5S_WXBEACON2_GMT_OFFSET_HOUR=+9 - -D M5S_WXBEACON2_WIFI_HOST_NAME="gob-m5sg" - -;----------------------------------------------------------------------- -[env:release_core2] -board = m5stack-core2 -build_type = release -build_flags = ${env.build_flags} - -DCORE_DEBUG_LEVEL=1 - -DLOG_LOCAL_LEVEL=4 - -DWB2_LOG_LEVEL=5 - -DMYNEWT_VAL_BLE_HS_LOG_LVL=5 -[env:release_core] -board = m5stack-core-esp32 +; Definition +; M5S_WXBEACON2_TIMEZONE_LOCATION : Your time-zone location string. default as "Asia/Tokyo" (e.g. "Asia/Tokyo" "America/Los_Angeles" "Australia/Lord_Howe") +build_flags = -Wall -Wextra -Wreturn-local-addr -Werror=format -Werror=return-local-addr + -D M5S_WXBEACON2_TIMEZONE_LOCATION=\"Asia/Tokyo\" + +[release_env] build_type = release build_flags = ${env.build_flags} -DCORE_DEBUG_LEVEL=1 @@ -65,8 +37,7 @@ build_flags = ${env.build_flags} -DWB2_LOG_LEVEL=5 -DMYNEWT_VAL_BLE_HS_LOG_LVL=5 -[env:release_log] -board = m5stack-core-esp32 +[log_env] build_type = release build_flags = ${env.build_flags} -DCORE_DEBUG_LEVEL=5 @@ -74,9 +45,7 @@ build_flags = ${env.build_flags} -DWB2_LOG_LEVEL=5 -DMYNEWT_VAL_BLE_HS_LOG_LVL=0 - -[env:debug] -board = m5stack-core-esp32 +[debug_env] build_type = debug build_flags = ${env.build_flags} -DCORE_DEBUG_LEVEL=5 @@ -84,4 +53,51 @@ build_flags = ${env.build_flags} -DWB2_LOG_LEVEL=5 -DMYNEWT_VAL_BLE_HS_LOG_LVL=0 +[core2_env] +build_flags = ${env.build_flags} + -DBOARD_HAS_PSRAM + -mfix-esp32-psram-cache-issue + +[m5s_env] +;board_build.partitions = no_ota.csv +board_build.partitions = min_spiffs.csv + +;----------------------------------------------------------------------- +; M5Stack Core2 +[env:core2_release] +extends=release_env, core2_env +board = m5stack-core2 + +[env:core2_log] +extends=log_env, core2_env +board = m5stack-core2 + +[env:core2_debug] +extends=debug_env, core2_env +board = m5stack-core2 + +; M5Stack BASIC +[env:basic_release] +extends=release_env, m5s_env +board = m5stack-core-esp32 + +[env:basic_map] +extends=release_env, m5s_env +board = m5stack-core-esp32 +build_flags = ${env.build_flags} + -Wl,-Map,output.map + +[env:basic_log] +extends=log_env, m5s_env +board = m5stack-core-esp32 + +[env:basic_debug] +extends=debug_env, m5s_env +board = m5stack-core-esp32 + +[env:basic_master] +extends=release_env, m5s_env +board = m5stack-core-esp32 +build_flags = ${env.build_flags} + -D NDEBUG diff --git a/src/aq_talk.cpp b/src/aq_talk.cpp index 76b8bb7..b533389 100644 --- a/src/aq_talk.cpp +++ b/src/aq_talk.cpp @@ -8,17 +8,313 @@ #include #include #include +#include +#include +#include +#include "wb2/wxbeacon2_log.hpp" namespace { +// weatcher codeto aqtalk +PROGMEM const char wc_100[] = "hare"; +PROGMEM const char wc_101[] = "hare,tokidoki'kumori"; +PROGMEM const char wc_102[] = "hare,ichiji'ame"; +PROGMEM const char wc_103[] = "hare,tokidoki'ame"; +PROGMEM const char wc_104[] = "hare,ichiji'yuki"; +PROGMEM const char wc_105[] = "hare'tokidoki'yuki"; +PROGMEM const char wc_106[] = "hare,ichiji'ame'kayuki"; +PROGMEM const char wc_107[] = "hare,tokidoki'ame'kayuki"; +PROGMEM const char wc_108[] = "hare,ichiji'ame'karai'u"; +PROGMEM const char wc_110[] = "hare,nochitokidoki'kumori"; +PROGMEM const char wc_111[] = "hare,nochi'kumori"; +PROGMEM const char wc_112[] = "hare,nochiichiji'ame"; +PROGMEM const char wc_113[] = "hare,nochitokidoki'ame"; +PROGMEM const char wc_114[] = "hare,nochi'ame"; +PROGMEM const char wc_115[] = "hare,nochiichiji'yuki"; +PROGMEM const char wc_116[] = "hare,nochitokidoki'yuki"; +PROGMEM const char wc_117[] = "hare,nochi'yuki"; +PROGMEM const char wc_118[] = "hare,nochi/ame'kayuki"; +PROGMEM const char wc_119[] = "hare,nochi/ame'karai'u"; +PROGMEM const char wc_120[] = "hare,asayuuichiji'ame"; +PROGMEM const char wc_121[] = "hare,asanouchiichiji'ame"; +PROGMEM const char wc_122[] = "hare,yuugataichiji'ame"; +PROGMEM const char wc_123[] = "hare,yamazoi'rai'u"; +PROGMEM const char wc_124[] = "hare,yamazoi'yuki"; +PROGMEM const char wc_125[] = "hare,gogowa'rai'u"; +PROGMEM const char wc_126[] = "hare,hirugorokara'ame"; +PROGMEM const char wc_127[] = "hare,yuugatakara'ame"; +PROGMEM const char wc_128[] = "hare,yoruwa'ame"; +PROGMEM const char wc_130[] = "asanouchikiri,nochi'hare"; +PROGMEM const char wc_131[] = "hare,akegata'kiri"; +PROGMEM const char wc_132[] = "hare,asayuu'kumori"; +PROGMEM const char wc_140[] = "hare,tokidoki'amede/kaminario'tomonau"; +PROGMEM const char wc_160[] = "hare,ichiji'yuki'kaame"; +PROGMEM const char wc_170[] = "hare,tokidoki'yuki'kaame"; +PROGMEM const char wc_181[] = "hare,nochi'yuki'kaame"; + +PROGMEM const char wc_200[] = "kumori"; +PROGMEM const char wc_201[] = "kumori,tokidoki'hare"; +PROGMEM const char wc_202[] = "kumori,ichiji'ame"; +PROGMEM const char wc_203[] = "kumori,tokidoki'ame"; +PROGMEM const char wc_204[] = "kumori,ichiji'yuki"; +PROGMEM const char wc_205[] = "kumori,tokidoki'yuki"; +PROGMEM const char wc_206[] = "kumori,ichiji'ame'kayuki"; +PROGMEM const char wc_207[] = "kumori,tokidoki'ame'kayuki"; +PROGMEM const char wc_208[] = "kumori,ichiji'ame'karai'u"; +PROGMEM const char wc_209[] = "kiri"; +PROGMEM const char wc_210[] = "kumori,nochitokidoki'hare"; +PROGMEM const char wc_211[] = "kumori,nochi'hare"; +PROGMEM const char wc_212[] = "kumori,nochiichiji'ame"; +PROGMEM const char wc_213[] = "kumori,nochitokidoki'ame"; +PROGMEM const char wc_214[] = "kumori,nochi'ame"; +PROGMEM const char wc_215[] = "kumori,nochiichiji'yuki"; +PROGMEM const char wc_216[] = "kumori,nochitokidoki'yuki"; +PROGMEM const char wc_217[] = "kumori,nochi'yuki"; +PROGMEM const char wc_218[] = "kumori,nochi/ame'kayuki"; +PROGMEM const char wc_219[] = "kumori,nochi/ame'karai'u"; +PROGMEM const char wc_220[] = "kumori,asayuuichiji'ame"; +PROGMEM const char wc_221[] = "kumori,asanouchiichiji'ame"; +PROGMEM const char wc_222[] = "kumori,yuugataichiji'ame"; +PROGMEM const char wc_223[] = "kumori,niccyu-tokidoki'hare"; +PROGMEM const char wc_224[] = "kumori,hirugorokara'ame"; +PROGMEM const char wc_225[] = "kumori,yuugatakara'ame"; +PROGMEM const char wc_226[] = "kumori,yoruwa'ame"; +PROGMEM const char wc_228[] = "kumori,hirugorokara'yuki"; +PROGMEM const char wc_229[] = "kumori,yuugatakara'yuki"; +PROGMEM const char wc_230[] = "kumori,yoruwa'yuki"; +PROGMEM const char wc_231[] = "kumori,kaijyo-kaiganwa'kiri'ka'kirisame"; +PROGMEM const char wc_240[] = "kumori,tokidoki'amede/kaminariotomonau"; +PROGMEM const char wc_250[] = "kumori,tokidoki'yukide/kaminariotomonau"; +PROGMEM const char wc_260[] = "kumori,ichiji'yuki'kaame"; +PROGMEM const char wc_270[] = "kumori,tokidoki'yuki'kaame"; +PROGMEM const char wc_281[] = "kumori,nochi'yuki'kaame"; + +PROGMEM const char wc_300[] = "a'me"; +PROGMEM const char wc_301[] = "a'me,tokidoki'hare"; +PROGMEM const char wc_302[] = "a'me,tokidoki'yamu"; +PROGMEM const char wc_303[] = "a'me,tokidoki'yuki"; +PROGMEM const char wc_304[] = "a'me'kayuki"; +PROGMEM const char wc_306[] = "ooa'me"; +PROGMEM const char wc_308[] = "a'mede,bo-fu-o'tomonau"; +PROGMEM const char wc_309[] = "a'me,ichiji'yuki"; +PROGMEM const char wc_311[] = "a'me,nochi'hare"; +PROGMEM const char wc_313[] = "a'me,nochi'kumori"; +PROGMEM const char wc_314[] = "a'me,nochitokidoki'yuki"; +PROGMEM const char wc_315[] = "a'me,nochi'yuki"; +PROGMEM const char wc_316[] = "ame/ka'yuki,nochi'hare"; +PROGMEM const char wc_317[] = "ame/ka'yuki,nochi'kumori"; +PROGMEM const char wc_320[] = "asanouchi,a'me,nochi'hare"; +PROGMEM const char wc_321[] = "asanouchi,a'me,nochi'kumori"; +PROGMEM const char wc_322[] = "a'me,asabann/ichiji'yuki"; +PROGMEM const char wc_323[] = "a'me,hirugorokara'hare"; +PROGMEM const char wc_324[] = "a'me,yuugatajarawa'hare"; +PROGMEM const char wc_325[] = "a'me,yoruwa'hare"; +PROGMEM const char wc_326[] = "a'me,yuugatakara'yuki"; +PROGMEM const char wc_327[] = "a'me,yoruwa'yuki"; +PROGMEM const char wc_328[] = "a'me,ichiji'tuyoku'furu"; +PROGMEM const char wc_329[] = "a'me,ichiji'mizore"; +PROGMEM const char wc_340[] = "yuki/ka'ame"; +PROGMEM const char wc_350[] = "a'mede,kaminario'tomonau"; +PROGMEM const char wc_361[] = "yuki/ka'ame,nochi'hare"; +PROGMEM const char wc_371[] = "yuki/ka'ame,nochi'kumori"; + +PROGMEM const char wc_400[] = "yuki"; +PROGMEM const char wc_401[] = "yuki,tokidoki'hare"; +PROGMEM const char wc_402[] = "yuki,tokidokiyamu"; +PROGMEM const char wc_403[] = "yuki,tokidoki'ame"; +PROGMEM const char wc_405[] = "ooyuki"; +PROGMEM const char wc_406[] = "fu--'u,tsuyoi"; +PROGMEM const char wc_407[] = "bo-'fu-u"; +PROGMEM const char wc_409[] = "yuki,ichji'ame"; +PROGMEM const char wc_411[] = "yuki,nochi'hare"; +PROGMEM const char wc_413[] = "yuki,nochi'kumori"; +PROGMEM const char wc_414[] = "yuki,onchi'ame"; +PROGMEM const char wc_420[] = "asanouchi,yuki,nochi'hare"; +PROGMEM const char wc_421[] = "asanouchi,yuki,nochi'kumori"; +PROGMEM const char wc_422[] = "yuki,hirugorokara'ame"; +PROGMEM const char wc_423[] = "yuki,yuugatakara'ame"; +PROGMEM const char wc_425[] = "yuki,ichiji'tsuyoku'furu"; +PROGMEM const char wc_426[] = "yuki,nochi'mizore"; +PROGMEM const char wc_427[] = "yuki,ichiji'mizore"; +PROGMEM const char wc_450[] = "yukide,kaminario'tomonau"; + +const std::map weatherCodeTable = +{ + { 100, wc_100 }, + { 101, wc_101 }, + { 102, wc_102 }, + { 103, wc_103 }, + { 104, wc_104 }, + { 105, wc_105 }, + { 106, wc_106 }, + { 107, wc_107 }, + { 108, wc_108 }, + { 110, wc_110 }, + { 111, wc_111 }, + { 112, wc_112 }, + { 113, wc_113 }, + { 114, wc_114 }, + { 115, wc_115 }, + { 116, wc_116 }, + { 117, wc_117 }, + { 118, wc_118 }, + { 119, wc_119 }, + { 120, wc_120 }, + { 121, wc_121 }, + { 122, wc_122 }, + { 123, wc_123 }, + { 124, wc_124 }, + { 125, wc_125 }, + { 126, wc_126 }, + { 127, wc_127 }, + { 128, wc_128 }, + { 130, wc_130 }, + { 131, wc_131 }, + { 132, wc_132 }, + { 140, wc_140 }, + { 160, wc_160 }, + { 170, wc_170 }, + { 181, wc_181 }, + { 200, wc_200 }, + { 201, wc_201 }, + { 202, wc_202 }, + { 203, wc_203 }, + { 204, wc_204 }, + { 205, wc_205 }, + { 206, wc_206 }, + { 207, wc_207 }, + { 208, wc_208 }, + { 209, wc_209 }, + { 210, wc_210 }, + { 211, wc_211 }, + { 212, wc_212 }, + { 213, wc_213 }, + { 214, wc_214 }, + { 215, wc_215 }, + { 216, wc_216 }, + { 217, wc_217 }, + { 218, wc_218 }, + { 219, wc_219 }, + { 220, wc_220 }, + { 221, wc_221 }, + { 222, wc_222 }, + { 223, wc_223 }, + { 224, wc_224 }, + { 225, wc_225 }, + { 226, wc_226 }, + { 228, wc_228 }, + { 229, wc_229 }, + { 230, wc_230 }, + { 231, wc_231 }, + { 240, wc_240 }, + { 250, wc_250 }, + { 260, wc_260 }, + { 270, wc_270 }, + { 281, wc_281 }, + { 300, wc_300 }, + { 301, wc_301 }, + { 302, wc_302 }, + { 303, wc_303 }, + { 304, wc_304 }, + { 306, wc_306 }, + { 308, wc_308 }, + { 309, wc_309 }, + { 311, wc_311 }, + { 313, wc_313 }, + { 314, wc_314 }, + { 315, wc_315 }, + { 316, wc_316 }, + { 317, wc_317 }, + { 320, wc_320 }, + { 321, wc_321 }, + { 322, wc_322 }, + { 323, wc_323 }, + { 324, wc_324 }, + { 325, wc_325 }, + { 326, wc_326 }, + { 327, wc_327 }, + { 328, wc_328 }, + { 329, wc_329 }, + { 340, wc_340 }, + { 350, wc_350 }, + { 361, wc_361 }, + { 371, wc_371 }, + { 400, wc_400 }, + { 401, wc_401 }, + { 402, wc_402 }, + { 403, wc_403 }, + { 405, wc_405 }, + { 406, wc_406 }, + { 407, wc_407 }, + { 409, wc_409 }, + { 411, wc_411 }, + { 413, wc_413 }, + { 414, wc_414 }, + { 420, wc_420 }, + { 421, wc_421 }, + { 422, wc_422 }, + { 423, wc_423 }, + { 425, wc_425 }, + { 426, wc_426 }, + { 427, wc_427 }, + { 450, wc_450 }, +}; + +PROGMEM const char oc_16000[] = "sapporo"; +PROGMEM const char oc_40000[] = "sendai"; +PROGMEM const char oc_130000[] = "to-kyo-"; +PROGMEM const char oc_150000[] = "niigata"; +PROGMEM const char oc_170000[] = "kanazawa"; +PROGMEM const char oc_230000[] = "nagoya"; +PROGMEM const char oc_270000[] = "o-saka"; +PROGMEM const char oc_340000[] = "hirosima"; +PROGMEM const char oc_390000[] = "ko-chi"; +PROGMEM const char oc_400000[] = "fukuoka"; +PROGMEM const char oc_471000[] = "naha"; + +const std::map officeCodeTable = +{ + { 16000, oc_16000 }, + { 40000, oc_40000 }, + { 130000, oc_130000 }, + { 150000, oc_150000 }, + { 170000, oc_170000 }, + { 230000, oc_230000 }, + { 270000, oc_270000 }, + { 340000, oc_340000 }, + { 390000, oc_390000 }, + { 400000, oc_400000 }, + { 471000, oc_471000 }, +}; + constexpr uint8_t m5spk_virtual_channel = 0; constexpr std::size_t LEN_FRAME = 32; +aq_talk::aq_talk_callback callbackOnEnd; uint32_t workbuf[AQ_SIZE_WORKBUF]; TaskHandle_t task_handle = nullptr; volatile bool is_talking = false; volatile uint32_t level = 0; +std::vector koeQueue; +uint16_t koeSpeed = 100; +uint16_t koeLenPause = 256U; + +std::vector split(const char* s, const char* separator = ",") +{ + std::vector out; + char dup[strlen(s) + 1]; + snprintf(dup, sizeof(dup), "%s", s); + + auto p = strtok(dup, separator); + if(p) + { + out.emplace_back(p); + while((p = strtok(nullptr, separator))) { out.emplace_back(p); } + } + return out; +} + void calcGainAverage(const int16_t* wav, const size_t len) { uint32_t acc = 0; @@ -36,17 +332,32 @@ void talk_task(void*) for (;;) { ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); // wait notify + while (is_talking) { uint16_t len = 0; - if (CAqTkPicoF_SyntheFrame(wav[tri_index], &len)) { is_talking = false; break; } + if (CAqTkPicoF_SyntheFrame(wav[tri_index], &len)) + { + if(koeQueue.empty()) + { + is_talking = false; + break; + } + // Connect + auto ret = CAqTkPicoF_SetKoe(reinterpret_cast(koeQueue.front().c_str()), koeSpeed, koeLenPause); + WB2_LOGD("Connect Koe %d [%s]", ret, koeQueue.front().c_str()); + koeQueue.erase(koeQueue.begin()); + continue; + } if(len) { calcGainAverage(wav[tri_index], len); M5.Speaker.playRaw(wav[tri_index], len, 8000, false, 1, m5spk_virtual_channel, false); tri_index = tri_index < 2 ? tri_index + 1 : 0; } + delay(1); } + if(callbackOnEnd) { callbackOnEnd(); } } } // @@ -54,13 +365,14 @@ void talk_task(void*) namespace aq_talk { -bool setup() +bool initialize(const UBaseType_t priority, const BaseType_t core, aq_talk_callback f) { if(!task_handle) { - xTaskCreateUniversal(talk_task, "aq_talk_task", 4096, nullptr, 1, &task_handle, APP_CPU_NUM); + xTaskCreateUniversal(talk_task, "aq_talk_task", 4 * 1024, nullptr, priority, &task_handle, core); + callbackOnEnd = f; return task_handle - && CAqTkPicoF_Init(workbuf, LEN_FRAME, "XXX-XXX-XXX") == 0; + && CAqTkPicoF_Init(workbuf, LEN_FRAME, "XXX-XXX-XXX") == 0; // } return true; } @@ -82,6 +394,7 @@ bool busy() { return is_talking; } void waitAquesTalk(void) { while (is_talking) { vTaskDelay(1); } + koeQueue.clear(); } void stopAquesTalk(void) @@ -89,15 +402,42 @@ void stopAquesTalk(void) if (is_talking) { is_talking = false; vTaskDelay(1); } } -void playAquesTalk(const char *koe, uint16_t speed, uint16_t lenPause) +bool playAquesTalk(const char *koe, const uint16_t speed, const uint16_t lenPause) { stopAquesTalk(); - auto ret = CAqTkPicoF_SetKoe(reinterpret_cast(koe), speed, lenPause); + waitAquesTalk(); + + + // Split and store queue. (CAqTkPicoF_SetKoe has a length limitation) + koeQueue.clear(); + koeQueue = split(koe, "#"); + koeSpeed = speed; + koeLenPause = lenPause; + WB2_LOGV("queue:%zu", koeQueue.size()); + + if(koeQueue.empty()) { return false; } + + // auto ret = CAqTkPicoF_SetKoe(reinterpret_cast(koe), speed, lenPause); + auto ret = CAqTkPicoF_SetKoe(reinterpret_cast(koeQueue.front().c_str()), speed, lenPause); + WB2_LOGD("Koe %d [%s]", ret, koeQueue.front().c_str()); + koeQueue.erase(koeQueue.begin()); if(ret == 0) { is_talking = true; xTaskNotifyGive(task_handle); } + return ret == 0; } + +const char* weatherCodeToTalk(const jma::weathercode_t wc) +{ + return weatherCodeTable.count(wc) == 1 ? weatherCodeTable.at(wc) : ""; +} + +const char* officeCodeToTalk(const jma::officecode_t oc) +{ + return officeCodeTable.count(oc) == 1 ? officeCodeTable.at(oc) : ""; +} + // } diff --git a/src/aq_talk.hpp b/src/aq_talk.hpp index 31c529c..3e294d0 100644 --- a/src/aq_talk.hpp +++ b/src/aq_talk.hpp @@ -5,12 +5,13 @@ #ifndef AQ_TALK_HPP #define AQ_TALK_HPP -#include +#include "jma/jma_definition.hpp" +//#include namespace aq_talk { - -bool setup(); +using aq_talk_callback = void(*)(); +bool initialize(const UBaseType_t priority, const BaseType_t core, aq_talk_callback f = nullptr); void finalize(); bool busy(); @@ -18,8 +19,10 @@ uint32_t getGain(); void waitAquesTalk(void); void stopAquesTalk(void); -void playAquesTalk(const char *koe, uint16_t speed = 100, uint16_t lenPause = 256U); +bool playAquesTalk(const char *koe, const uint16_t speed = 100, const uint16_t lenPause = 0xFFFFU); +const char* weatherCodeToTalk(const jma::weathercode_t wc); +const char* officeCodeToTalk(const jma::officecode_t oc); // } #endif diff --git a/src/cpu_usage.cpp b/src/cpu_usage.cpp new file mode 100644 index 0000000..6e47bbd --- /dev/null +++ b/src/cpu_usage.cpp @@ -0,0 +1,47 @@ + +#include "cpu_usage.hpp" +#include + +namespace +{ +bool initialized = false; +long idle_cnt_0, idle_cnt_1, tick_cnt_0, tick_cnt_1; + +bool IRAM_ATTR function_idle_0(){ ++idle_cnt_0; return true; } +void IRAM_ATTR function_tick_0(){ ++tick_cnt_0; } +bool IRAM_ATTR function_idle_1(){ ++idle_cnt_1; return true; } +void IRAM_ATTR function_tick_1(){ ++tick_cnt_1; } +// +} + +namespace cpu_usage +{ + +bool initialize() +{ + if(initialized) { return false; } + + auto i0= esp_register_freertos_idle_hook_for_cpu(function_idle_0, 0); + auto t0 = esp_register_freertos_tick_hook_for_cpu(function_tick_0, 0); + auto i1 = esp_register_freertos_idle_hook_for_cpu(function_idle_1, 1); + auto t1 = esp_register_freertos_tick_hook_for_cpu(function_tick_1, 1); + initialized = (i0 == ESP_OK) && (t0 == ESP_OK) && (i1 == ESP_OK) && (t1 == ESP_OK); + return initialized; +} + +void reset() +{ + idle_cnt_0 = idle_cnt_1 = tick_cnt_0 = tick_cnt_1 = 0; +} + +float cpu0() +{ + return (tick_cnt_0 ? (idle_cnt_0 * 100.0f / tick_cnt_0) : 100.0f); +} + +float cpu1() +{ + return (tick_cnt_1 ? (idle_cnt_1 * 100.0f / tick_cnt_1) : 100.0f); +} +// +} diff --git a/src/cpu_usage.hpp b/src/cpu_usage.hpp new file mode 100644 index 0000000..584362b --- /dev/null +++ b/src/cpu_usage.hpp @@ -0,0 +1,14 @@ + +#ifndef CPP_USAGE_HPP +#define CPP_USAGE_HPP + +namespace cpu_usage +{ +bool initialize(); + +void reset(); + +float cpu0(); +float cpu1(); +} +#endif diff --git a/src/jma/jma_definition.cpp b/src/jma/jma_definition.cpp new file mode 100644 index 0000000..1747edb --- /dev/null +++ b/src/jma/jma_definition.cpp @@ -0,0 +1,800 @@ + +#include "jma_definition.hpp" +#include +#include +#include + +namespace +{ + +// Weatcher code string +#if 1 + +PROGMEM const char wc_100[] = "晴"; +PROGMEM const char wc_101[] = "晴時々曇"; +PROGMEM const char wc_102[] = "晴一時雨"; +PROGMEM const char wc_103[] = "晴時々雨"; +PROGMEM const char wc_104[] = "晴一時雪"; +PROGMEM const char wc_105[] = "晴時々雪"; +PROGMEM const char wc_106[] = "晴一時雨か雪"; +PROGMEM const char wc_107[] = "晴時々雨か雪"; +PROGMEM const char wc_108[] = "晴一時雨か雷雨"; +PROGMEM const char wc_110[] = "晴後時々曇"; +PROGMEM const char wc_111[] = "晴後曇"; +PROGMEM const char wc_112[] = "晴後一時雨"; +PROGMEM const char wc_113[] = "晴後時々雨"; +PROGMEM const char wc_114[] = "晴後雨"; +PROGMEM const char wc_115[] = "晴後一時雪"; +PROGMEM const char wc_116[] = "晴後時々雪"; +PROGMEM const char wc_117[] = "晴後雪"; +PROGMEM const char wc_118[] = "晴後雨か雪"; +PROGMEM const char wc_119[] = "晴後雨か雷雨"; +PROGMEM const char wc_120[] = "晴朝夕一時雨"; +PROGMEM const char wc_121[] = "晴朝の内一時雨"; +PROGMEM const char wc_122[] = "晴夕方一時雨"; +PROGMEM const char wc_123[] = "晴山沿い雷雨"; +PROGMEM const char wc_124[] = "晴山沿い雪"; +PROGMEM const char wc_125[] = "晴午後は雷雨"; +PROGMEM const char wc_126[] = "晴昼頃から雨"; +PROGMEM const char wc_127[] = "晴夕方から雨"; +PROGMEM const char wc_128[] = "晴夜は雨"; +PROGMEM const char wc_130[] = "朝の内霧後晴"; +PROGMEM const char wc_131[] = "晴明け方霧"; +PROGMEM const char wc_132[] = "晴朝夕曇"; +PROGMEM const char wc_140[] = "晴時々雨で雷を伴う"; +PROGMEM const char wc_160[] = "晴一時雪か雨"; +PROGMEM const char wc_170[] = "晴時々雪か雨"; +PROGMEM const char wc_181[] = "晴後雪か雨"; +PROGMEM const char wc_200[] = "曇"; +PROGMEM const char wc_201[] = "曇時々晴"; +PROGMEM const char wc_202[] = "曇一時雨"; +PROGMEM const char wc_203[] = "曇時々雨"; +PROGMEM const char wc_204[] = "曇一時雪"; +PROGMEM const char wc_205[] = "曇時々雪"; +PROGMEM const char wc_206[] = "曇一時雨か雪"; +PROGMEM const char wc_207[] = "曇時々雨か雪"; +PROGMEM const char wc_208[] = "曇一時雨か雷雨"; +PROGMEM const char wc_209[] = "霧"; +PROGMEM const char wc_210[] = "曇後時々晴"; +PROGMEM const char wc_211[] = "曇後晴"; +PROGMEM const char wc_212[] = "曇後一時雨"; +PROGMEM const char wc_213[] = "曇後時々雨"; +PROGMEM const char wc_214[] = "曇後雨"; +PROGMEM const char wc_215[] = "曇後一時雪"; +PROGMEM const char wc_216[] = "曇後時々雪"; +PROGMEM const char wc_217[] = "曇後雪"; +PROGMEM const char wc_218[] = "曇後雨か雪"; +PROGMEM const char wc_219[] = "曇後雨か雷雨"; +PROGMEM const char wc_220[] = "曇朝夕一時雨"; +PROGMEM const char wc_221[] = "曇朝の内一時雨"; +PROGMEM const char wc_222[] = "曇夕方一時雨"; +PROGMEM const char wc_223[] = "曇日中時々晴"; +PROGMEM const char wc_224[] = "曇昼頃から雨"; +PROGMEM const char wc_225[] = "曇夕方から雨"; +PROGMEM const char wc_226[] = "曇夜は雨"; +PROGMEM const char wc_228[] = "曇昼頃から雪"; +PROGMEM const char wc_229[] = "曇夕方から雪"; +PROGMEM const char wc_230[] = "曇夜は雪"; +PROGMEM const char wc_231[] = "曇海上海岸は霧か霧雨"; +PROGMEM const char wc_240[] = "曇時々雨で雷を伴う"; +PROGMEM const char wc_250[] = "曇時々雪で雷を伴う"; +PROGMEM const char wc_260[] = "曇一時雪か雨"; +PROGMEM const char wc_270[] = "曇時々雪か雨"; +PROGMEM const char wc_281[] = "曇後雪か雨"; +PROGMEM const char wc_300[] = "雨"; +PROGMEM const char wc_301[] = "雨時々晴"; +PROGMEM const char wc_302[] = "雨時々止む"; +PROGMEM const char wc_303[] = "雨時々雪"; +PROGMEM const char wc_304[] = "雨か雪"; +PROGMEM const char wc_306[] = "大雨"; +PROGMEM const char wc_308[] = "雨で暴風を伴う"; +PROGMEM const char wc_309[] = "雨一時雪"; +PROGMEM const char wc_311[] = "雨後晴"; +PROGMEM const char wc_313[] = "雨後曇"; +PROGMEM const char wc_314[] = "雨後時々雪"; +PROGMEM const char wc_315[] = "雨後雪"; +PROGMEM const char wc_316[] = "雨か雪後晴"; +PROGMEM const char wc_317[] = "雨か雪後曇"; +PROGMEM const char wc_320[] = "朝の内雨後晴"; +PROGMEM const char wc_321[] = "朝の内雨後曇"; +PROGMEM const char wc_322[] = "雨朝晩一時雪"; +PROGMEM const char wc_323[] = "雨昼頃から晴"; +PROGMEM const char wc_324[] = "雨夕方から晴"; +PROGMEM const char wc_325[] = "雨夜は晴"; +PROGMEM const char wc_326[] = "雨夕方から雪"; +PROGMEM const char wc_327[] = "雨夜は雪"; +PROGMEM const char wc_328[] = "雨一時強く降る"; +PROGMEM const char wc_329[] = "雨一時みぞれ"; +PROGMEM const char wc_340[] = "雪か雨"; +PROGMEM const char wc_350[] = "雨で雷を伴う"; +PROGMEM const char wc_361[] = "雪か雨後晴"; +PROGMEM const char wc_371[] = "雪か雨後曇"; +PROGMEM const char wc_400[] = "雪"; +PROGMEM const char wc_401[] = "雪時々晴"; +PROGMEM const char wc_402[] = "雪時々止む"; +PROGMEM const char wc_403[] = "雪時々雨"; +PROGMEM const char wc_405[] = "大雪"; +PROGMEM const char wc_406[] = "風雪強い"; +PROGMEM const char wc_407[] = "暴風雪"; +PROGMEM const char wc_409[] = "雪一時雨"; +PROGMEM const char wc_411[] = "雪後晴"; +PROGMEM const char wc_413[] = "雪後曇"; +PROGMEM const char wc_414[] = "雪後雨"; +PROGMEM const char wc_420[] = "朝の内雪後晴"; +PROGMEM const char wc_421[] = "朝の内雪後曇"; +PROGMEM const char wc_422[] = "雪昼頃から雨"; +PROGMEM const char wc_423[] = "雪夕方から雨"; +PROGMEM const char wc_425[] = "雪一時強く降る"; +PROGMEM const char wc_426[] = "雪後みぞれ"; +PROGMEM const char wc_427[] = "雪一時みぞれ"; +PROGMEM const char wc_450[] = "雪で雷を伴う"; + +#else + +PROGMEM const char wc_100[] = "CLEAR"; +PROGMEM const char wc_101[] = "PARTLY CLOUDY"; +PROGMEM const char wc_102[] = "CLEAR, OCCASIONAL SCATTERED SHOWERS"; +PROGMEM const char wc_103[] = "CLEAR, FREQUENT SCATTERED SHOWERS"; +PROGMEM const char wc_104[] = "CLEAR, SNOW FLURRIES"; +PROGMEM const char wc_105[] = "CLEAR, FREQUENT SNOW FLURRIES"; +PROGMEM const char wc_106[] = "CLEAR, OCCASIONAL SCATTERED SHOWERS OR SNOW FLURRIES"; +PROGMEM const char wc_107[] = "CLEAR, FREQUENT SCATTERED SHOWERS OR SNOW FLURRIES"; +PROGMEM const char wc_108[] = "CLEAR, OCCASIONAL SCATTERED SHOWERS AND/OR THUNDER"; +PROGMEM const char wc_110[] = "CLEAR, PARTLY CLOUDY LATER"; +PROGMEM const char wc_111[] = "CLEAR, CLOUDY LATER"; +PROGMEM const char wc_112[] = "CLEAR, OCCASIONAL SCATTERED SHOWERS LATER"; +PROGMEM const char wc_113[] = "CLEAR, FREQUENT SCATTERED SHOWERS LATER"; +PROGMEM const char wc_114[] = "CLEAR,RAIN LATER"; +PROGMEM const char wc_115[] = "CLEAR, OCCASIONAL SNOW FLURRIES LATER"; +PROGMEM const char wc_116[] = "CLEAR, FREQUENT SNOW FLURRIES LATER"; +PROGMEM const char wc_117[] = "CLEAR,SNOW LATER"; +PROGMEM const char wc_118[] = "CLEAR, RAIN OR SNOW LATER"; +PROGMEM const char wc_119[] = "CLEAR, RAIN AND/OR THUNDER LATER"; +PROGMEM const char wc_120[] = "OCCASIONAL SCATTERED SHOWERS IN THE MORNING AND EVENING, CLEAR DURING THE DAY"; +PROGMEM const char wc_121[] = "OCCASIONAL SCATTERED SHOWERS IN THE MORNING, CLEAR DURING THE DAY"; +PROGMEM const char wc_122[] = "CLEAR, OCCASIONAL SCATTERED SHOWERS IN THE EVENING"; +PROGMEM const char wc_123[] = "CLEAR IN THE PLAINS, RAIN AND THUNDER NEAR MOUTAINOUS AREAS"; +PROGMEM const char wc_124[] = "CLEAR IN THE PLAINS, SNOW NEAR MOUTAINOUS AREAS"; +PROGMEM const char wc_125[] = "CLEAR, RAIN AND THUNDER IN THE AFTERNOON"; +PROGMEM const char wc_126[] = "CLEAR, RAIN IN THE AFTERNOON"; +PROGMEM const char wc_127[] = "CLEAR, RAIN IN THE EVENING"; +PROGMEM const char wc_128[] = "CLEAR, RAIN IN THE NIGHT"; +PROGMEM const char wc_130[] = "FOG IN THE MORNING, CLEAR LATER"; +PROGMEM const char wc_131[] = "FOG AROUND DAWN, CLEAR LATER"; +PROGMEM const char wc_132[] = "CLOUDY IN THE MORNING AND EVENING, CLEAR DURING THE DAY"; +PROGMEM const char wc_140[] = "CLEAR, FREQUENT SCATTERED SHOWERS AND THUNDER"; +PROGMEM const char wc_160[] = "CLEAR, SNOW FLURRIES OR OCCASIONAL SCATTERED SHOWERS"; +PROGMEM const char wc_170[] = "CLEAR, FREQUENT SNOW FLURRIES OR SCATTERED SHOWERS"; +PROGMEM const char wc_181[] = "CLEAR, SNOW OR RAIN LATER"; +PROGMEM const char wc_200[] = "CLOUDY"; +PROGMEM const char wc_201[] = "MOSTLY CLOUDY"; +PROGMEM const char wc_202[] = "CLOUDY, OCCASIONAL SCATTERED SHOWERS"; +PROGMEM const char wc_203[] = "CLOUDY, FREQUENT SCATTERED SHOWERS"; +PROGMEM const char wc_204[] = "CLOUDY, OCCASIONAL SNOW FLURRIES"; +PROGMEM const char wc_205[] = "CLOUDY FREQUENT SNOW FLURRIES"; +PROGMEM const char wc_206[] = "CLOUDY, OCCASIONAL SCATTERED SHOWERS OR SNOW FLURRIES"; +PROGMEM const char wc_207[] = "CLOUDY, FREQUENT SCCATERED SHOWERS OR SNOW FLURRIES"; +PROGMEM const char wc_208[] = "CLOUDY, OCCASIONAL SCATTERED SHOWERS AND/OR THUNDER"; +PROGMEM const char wc_209[] = "FOG"; +PROGMEM const char wc_210[] = "CLOUDY, PARTLY CLOUDY LATER"; +PROGMEM const char wc_211[] = "CLOUDY, CLEAR LATER"; +PROGMEM const char wc_212[] = "CLOUDY, OCCASIONAL SCATTERED SHOWERS LATER"; +PROGMEM const char wc_213[] = "CLOUDY, FREQUENT SCATTERED SHOWERS LATER"; +PROGMEM const char wc_214[] = "CLOUDY, RAIN LATER"; +PROGMEM const char wc_215[] = "CLOUDY, SNOW FLURRIES LATER"; +PROGMEM const char wc_216[] = "CLOUDY, FREQUENT SNOW FLURRIES LATER"; +PROGMEM const char wc_217[] = "CLOUDY, SNOW LATER"; +PROGMEM const char wc_218[] = "CLOUDY, RAIN OR SNOW LATER"; +PROGMEM const char wc_219[] = "CLOUDY, RAIN AND/OR THUNDER LATER"; +PROGMEM const char wc_220[] = "OCCASIONAL SCCATERED SHOWERS IN THE MORNING AND EVENING, CLOUDY DURING THE DAY"; +PROGMEM const char wc_221[] = "CLOUDY OCCASIONAL SCCATERED SHOWERS IN THE MORNING"; +PROGMEM const char wc_222[] = "CLOUDY, OCCASIONAL SCCATERED SHOWERS IN THE EVENING"; +PROGMEM const char wc_223[] = "CLOUDY IN THE MORNING AND EVENING, PARTLY CLOUDY DURING THE DAY,"; +PROGMEM const char wc_224[] = "CLOUDY, RAIN IN THE AFTERNOON"; +PROGMEM const char wc_225[] = "CLOUDY, RAIN IN THE EVENING"; +PROGMEM const char wc_226[] = "CLOUDY, RAIN IN THE NIGHT"; +PROGMEM const char wc_228[] = "CLOUDY, SNOW IN THE AFTERNOON"; +PROGMEM const char wc_229[] = "CLOUDY, SNOW IN THE EVENING"; +PROGMEM const char wc_230[] = "CLOUDY, SNOW IN THE NIGHT"; +PROGMEM const char wc_231[] = "CLOUDY, FOG OR DRIZZLING ON THE SEA AND NEAR SEASHORE"; +PROGMEM const char wc_240[] = "CLOUDY, FREQUENT SCCATERED SHOWERS AND THUNDER"; +PROGMEM const char wc_250[] = "CLOUDY, FREQUENT SNOW AND THUNDER"; +PROGMEM const char wc_260[] = "CLOUDY, SNOW FLURRIES OR OCCASIONAL SCATTERED SHOWERS"; +PROGMEM const char wc_270[] = "CLOUDY, FREQUENT SNOW FLURRIES OR SCATTERED SHOWERS"; +PROGMEM const char wc_281[] = "CLOUDY, SNOW OR RAIN LATER"; +PROGMEM const char wc_300[] = "RAIN"; +PROGMEM const char wc_301[] = "RAIN, PARTLY CLOUDY"; +PROGMEM const char wc_302[] = "SHOWERS THROUGHOUT THE DAY"; +PROGMEM const char wc_303[] = "RAIN,FREQUENT SNOW FLURRIES"; +PROGMEM const char wc_304[] = "RAINORSNOW"; +PROGMEM const char wc_306[] = "HEAVYRAIN"; +PROGMEM const char wc_308[] = "RAINSTORM"; +PROGMEM const char wc_309[] = "RAIN,OCCASIONAL SNOW"; +PROGMEM const char wc_311[] = "RAIN,CLEAR LATER"; +PROGMEM const char wc_313[] = "RAIN,CLOUDY LATER"; +PROGMEM const char wc_314[] = "RAIN, FREQUENT SNOW FLURRIES LATER"; +PROGMEM const char wc_315[] = "RAIN,SNOW LATER"; +PROGMEM const char wc_316[] = "RAIN OR SNOW, CLEAR LATER"; +PROGMEM const char wc_317[] = "RAIN OR SNOW, CLOUDY LATER"; +PROGMEM const char wc_320[] = "RAIN IN THE MORNING, CLEAR LATER"; +PROGMEM const char wc_321[] = "RAIN IN THE MORNING, CLOUDY LATER"; +PROGMEM const char wc_322[] = "OCCASIONAL SNOW IN THE MORNING AND EVENING, RAIN DURING THE DAY"; +PROGMEM const char wc_323[] = "RAIN, CLEAR IN THE AFTERNOON"; +PROGMEM const char wc_324[] = "RAIN, CLEAR IN THE EVENING"; +PROGMEM const char wc_325[] = "RAIN, CLEAR IN THE NIGHT"; +PROGMEM const char wc_326[] = "RAIN, SNOW IN THE EVENING"; +PROGMEM const char wc_327[] = "RAIN,SNOW IN THE NIGHT"; +PROGMEM const char wc_328[] = "RAIN, EXPECT OCCASIONAL HEAVY RAINFALL"; +PROGMEM const char wc_329[] = "RAIN, OCCASIONAL SLEET"; +PROGMEM const char wc_340[] = "SNOWORRAIN"; +PROGMEM const char wc_350[] = "RAIN AND THUNDER"; +PROGMEM const char wc_361[] = "SNOW OR RAIN, CLEAR LATER"; +PROGMEM const char wc_371[] = "SNOW OR RAIN, CLOUDY LATER"; +PROGMEM const char wc_400[] = "SNOW"; +PROGMEM const char wc_401[] = "SNOW, FREQUENT CLEAR"; +PROGMEM const char wc_402[] = "SNOWTHROUGHOUT THE DAY"; +PROGMEM const char wc_403[] = "SNOW,FREQUENT SCCATERED SHOWERS"; +PROGMEM const char wc_405[] = "HEAVYSNOW"; +PROGMEM const char wc_406[] = "SNOWSTORM"; +PROGMEM const char wc_407[] = "HEAVYSNOWSTORM"; +PROGMEM const char wc_409[] = "SNOW, OCCASIONAL SCCATERED SHOWERS"; +PROGMEM const char wc_411[] = "SNOW,CLEAR LATER"; +PROGMEM const char wc_413[] = "SNOW,CLOUDY LATER"; +PROGMEM const char wc_414[] = "SNOW,RAIN LATER"; +PROGMEM const char wc_420[] = "SNOW IN THE MORNING, CLEAR LATER"; +PROGMEM const char wc_421[] = "SNOW IN THE MORNING, CLOUDY LATER"; +PROGMEM const char wc_422[] = "SNOW, RAIN IN THE AFTERNOON"; +PROGMEM const char wc_423[] = "SNOW, RAIN IN THE EVENING"; +PROGMEM const char wc_425[] = "SNOW, EXPECT OCCASIONAL HEAVY SNOWFALL"; +PROGMEM const char wc_426[] = "SNOW, SLEET LATER"; +PROGMEM const char wc_427[] = "SNOW, OCCASIONAL SLEET"; +PROGMEM const char wc_450[] = "SNOW AND THUNDER"; +#endif + +const std::map weatherCodeTable = +{ + { 100, wc_100 }, + { 101, wc_101 }, + { 102, wc_102 }, + { 103, wc_103 }, + { 104, wc_104 }, + { 105, wc_105 }, + { 106, wc_106 }, + { 107, wc_107 }, + { 108, wc_108 }, + { 110, wc_110 }, + { 111, wc_111 }, + { 112, wc_112 }, + { 113, wc_113 }, + { 114, wc_114 }, + { 115, wc_115 }, + { 116, wc_116 }, + { 117, wc_117 }, + { 118, wc_118 }, + { 119, wc_119 }, + { 120, wc_120 }, + { 121, wc_121 }, + { 122, wc_122 }, + { 123, wc_123 }, + { 124, wc_124 }, + { 125, wc_125 }, + { 126, wc_126 }, + { 127, wc_127 }, + { 128, wc_128 }, + { 130, wc_130 }, + { 131, wc_131 }, + { 132, wc_132 }, + { 140, wc_140 }, + { 160, wc_160 }, + { 170, wc_170 }, + { 181, wc_181 }, + { 200, wc_200 }, + { 201, wc_201 }, + { 202, wc_202 }, + { 203, wc_203 }, + { 204, wc_204 }, + { 205, wc_205 }, + { 206, wc_206 }, + { 207, wc_207 }, + { 208, wc_208 }, + { 209, wc_209 }, + { 210, wc_210 }, + { 211, wc_211 }, + { 212, wc_212 }, + { 213, wc_213 }, + { 214, wc_214 }, + { 215, wc_215 }, + { 216, wc_216 }, + { 217, wc_217 }, + { 218, wc_218 }, + { 219, wc_219 }, + { 220, wc_220 }, + { 221, wc_221 }, + { 222, wc_222 }, + { 223, wc_223 }, + { 224, wc_224 }, + { 225, wc_225 }, + { 226, wc_226 }, + { 228, wc_228 }, + { 229, wc_229 }, + { 230, wc_230 }, + { 231, wc_231 }, + { 240, wc_240 }, + { 250, wc_250 }, + { 260, wc_260 }, + { 270, wc_270 }, + { 281, wc_281 }, + { 300, wc_300 }, + { 301, wc_301 }, + { 302, wc_302 }, + { 303, wc_303 }, + { 304, wc_304 }, + { 306, wc_306 }, + { 308, wc_308 }, + { 309, wc_309 }, + { 311, wc_311 }, + { 313, wc_313 }, + { 314, wc_314 }, + { 315, wc_315 }, + { 316, wc_316 }, + { 317, wc_317 }, + { 320, wc_320 }, + { 321, wc_321 }, + { 322, wc_322 }, + { 323, wc_323 }, + { 324, wc_324 }, + { 325, wc_325 }, + { 326, wc_326 }, + { 327, wc_327 }, + { 328, wc_328 }, + { 329, wc_329 }, + { 340, wc_340 }, + { 350, wc_350 }, + { 361, wc_361 }, + { 371, wc_371 }, + { 400, wc_400 }, + { 401, wc_401 }, + { 402, wc_402 }, + { 403, wc_403 }, + { 405, wc_405 }, + { 406, wc_406 }, + { 407, wc_407 }, + { 409, wc_409 }, + { 411, wc_411 }, + { 413, wc_413 }, + { 414, wc_414 }, + { 420, wc_420 }, + { 421, wc_421 }, + { 422, wc_422 }, + { 423, wc_423 }, + { 425, wc_425 }, + { 426, wc_426 }, + { 427, wc_427 }, + { 450, wc_450 }, +}; + +#if 0 +struct JMA_Prefecures +{ + jma::officecode_t representative; // Representative value of offices. + std::vector offices; +}; +const JMA_Prefecures prefectures[] = +{ + { 16000, { 16000, 11000, 13000, 14030, 14100, 15000, 12000, 17000 } }, + { 40000, { 40000, 60000, 70000, 20000, 50000, 30000 } }, + { 130000, { 130000,120000,140000,190000, 90000,100000,110000, 80000,200000 } }, + { 150000, { 150000,170000,180000,160000 } }, + { 230000, { 230000,240000,220000,210000 } }, + { 270000, { 270000,300000,260000,250000,280000,290000 } }, + { 340000, { 340000,310000,330000,320000 } }, + { 370000, { 370000,380000,360000,390000 } }, + { 400000, { 400000,440000,410000,430000,420000,350000 } }, + { 460100, { 460100,450000,460040 } }, + { 471000, { 471000,473000,474000,472000 } }, +}; +#endif + + +// Office code string +#if 1 +# if 0 +PROGMEM const char ocloc_11000[] = "宗谷地方"; +PROGMEM const char ocloc_12000[] = "上川・留萌地方"; +PROGMEM const char ocloc_13000[] = "網走・北見・紋別地方"; +PROGMEM const char ocloc_14100[] = "釧路・根室地方"; +PROGMEM const char ocloc_14030[] = "十勝地方"; +PROGMEM const char ocloc_15000[] = "胆振・日高地方"; +PROGMEM const char ocloc_16000[] = "石狩・空知・後志地方"; +PROGMEM const char ocloc_17000[] = "渡島・檜山地方"; +PROGMEM const char ocloc_20000[] = "青森県"; +PROGMEM const char ocloc_30000[] = "岩手県"; +PROGMEM const char ocloc_40000[] = "宮城県"; +PROGMEM const char ocloc_50000[] = "秋田県"; +PROGMEM const char ocloc_60000[] = "山形県"; +PROGMEM const char ocloc_70000[] = "福島県"; +PROGMEM const char ocloc_80000[] = "茨城県"; +PROGMEM const char ocloc_90000[] = "栃木県"; +PROGMEM const char ocloc_100000[] = "群馬県"; +PROGMEM const char ocloc_110000[] = "埼玉県"; +PROGMEM const char ocloc_120000[] = "千葉県"; +PROGMEM const char ocloc_130000[] = "東京都"; +PROGMEM const char ocloc_140000[] = "神奈川県"; +PROGMEM const char ocloc_150000[] = "新潟県"; +PROGMEM const char ocloc_160000[] = "富山県"; +PROGMEM const char ocloc_170000[] = "石川県"; +PROGMEM const char ocloc_180000[] = "福井県"; +PROGMEM const char ocloc_190000[] = "山梨県"; +PROGMEM const char ocloc_200000[] = "長野県"; +PROGMEM const char ocloc_210000[] = "岐阜県"; +PROGMEM const char ocloc_220000[] = "静岡県"; +PROGMEM const char ocloc_230000[] = "愛知県"; +PROGMEM const char ocloc_240000[] = "三重県"; +PROGMEM const char ocloc_250000[] = "滋賀県"; +PROGMEM const char ocloc_260000[] = "京都府"; +PROGMEM const char ocloc_270000[] = "大阪府"; +PROGMEM const char ocloc_280000[] = "兵庫県"; +PROGMEM const char ocloc_290000[] = "奈良県"; +PROGMEM const char ocloc_300000[] = "和歌山県"; +PROGMEM const char ocloc_310000[] = "鳥取県"; +PROGMEM const char ocloc_320000[] = "島根県"; +PROGMEM const char ocloc_330000[] = "岡山県"; +PROGMEM const char ocloc_340000[] = "広島県"; +PROGMEM const char ocloc_350000[] = "山口県"; +PROGMEM const char ocloc_360000[] = "徳島県"; +PROGMEM const char ocloc_370000[] = "香川県"; +PROGMEM const char ocloc_380000[] = "愛媛県"; +PROGMEM const char ocloc_390000[] = "高知県"; +PROGMEM const char ocloc_400000[] = "福岡県"; +PROGMEM const char ocloc_410000[] = "佐賀県"; +PROGMEM const char ocloc_420000[] = "長崎県"; +PROGMEM const char ocloc_430000[] = "熊本県"; +PROGMEM const char ocloc_440000[] = "大分県"; +PROGMEM const char ocloc_450000[] = "宮崎県"; +PROGMEM const char ocloc_460100[] = "鹿児島県"; +PROGMEM const char ocloc_460040[] = "奄美地方"; +PROGMEM const char ocloc_471000[] = "沖縄本島地方"; +PROGMEM const char ocloc_472000[] = "大東島地方"; +PROGMEM const char ocloc_473000[] = "宮古島地方"; +PROGMEM const char ocloc_474000[] = "八重山地方"; +# else +// +PROGMEM const char ocloc_16000[] = "札幌"; +PROGMEM const char ocloc_40000[] = "仙台"; +PROGMEM const char ocloc_130000[] = "東京"; +PROGMEM const char ocloc_150000[] = "新潟"; +PROGMEM const char ocloc_170000[] = "金沢"; +PROGMEM const char ocloc_230000[] = "名古屋"; +PROGMEM const char ocloc_270000[] = "大阪"; +PROGMEM const char ocloc_340000[] = "広島"; +PROGMEM const char ocloc_390000[] = "高知"; +PROGMEM const char ocloc_400000[] = "福岡"; +PROGMEM const char ocloc_471000[] = "那覇"; + +# endif +#else + +PROGMEM const char ocloc_11000[] = "SOYA"; // Region +PROGMEM const char ocloc_12000[] = "KAMIKAWA RUMOI"; // Region +PROGMEM const char ocloc_13000[] = "ABASHIRI"; // Region +PROGMEM const char ocloc_14100[] = "KUSHIRO NEMURO"; // Region +PROGMEM const char ocloc_14030[] = "TOKACHI"; // Region +PROGMEM const char ocloc_15000[] = "IBURI HIDAKA"; // Region +PROGMEM const char ocloc_16000[] = "ISHIKARI SORACHI"; // Region +PROGMEM const char ocloc_17000[] = "OSHIMA HIYAMA"; // Region +PROGMEM const char ocloc_20000[] = "AOMORI"; +PROGMEM const char ocloc_30000[] = "IWATE"; +PROGMEM const char ocloc_40000[] = "MIYAGI"; +PROGMEM const char ocloc_50000[] = "AKITA"; +PROGMEM const char ocloc_60000[] = "YAMAGATA"; +PROGMEM const char ocloc_70000[] = "FUKUSHIMA"; +PROGMEM const char ocloc_80000[] = "IBARAKI"; +PROGMEM const char ocloc_90000[] = "TOCHIGI"; +PROGMEM const char ocloc_100000[] = "GUNMA"; +PROGMEM const char ocloc_110000[] = "SAITAMA"; +PROGMEM const char ocloc_120000[] = "CHIBA"; +PROGMEM const char ocloc_130000[] = "TOKYO"; +PROGMEM const char ocloc_140000[] = "KANAGAWA"; +PROGMEM const char ocloc_150000[] = "NIIGATA"; +PROGMEM const char ocloc_160000[] = "TOYAMA"; +PROGMEM const char ocloc_170000[] = "ISHIKAWA"; +PROGMEM const char ocloc_180000[] = "FUKUI"; +PROGMEM const char ocloc_190000[] = "YAMANASHI"; +PROGMEM const char ocloc_200000[] = "NAGANO"; +PROGMEM const char ocloc_210000[] = "GIFU"; +PROGMEM const char ocloc_220000[] = "SHIZUOKA"; +PROGMEM const char ocloc_230000[] = "AICHI"; +PROGMEM const char ocloc_240000[] = "MIE"; +PROGMEM const char ocloc_250000[] = "SHIGA"; +PROGMEM const char ocloc_260000[] = "KYOTO"; +PROGMEM const char ocloc_270000[] = "OSAKA"; +PROGMEM const char ocloc_280000[] = "HYOGO"; +PROGMEM const char ocloc_290000[] = "NARA"; +PROGMEM const char ocloc_300000[] = "WAKAYAMA"; +PROGMEM const char ocloc_310000[] = "TOTTORI"; +PROGMEM const char ocloc_320000[] = "SHIANE"; +PROGMEM const char ocloc_330000[] = "OKAYAMA"; +PROGMEM const char ocloc_340000[] = "HIROSHIMA"; +PROGMEM const char ocloc_350000[] = "YAMAGUCHI"; +PROGMEM const char ocloc_360000[] = "TOKUSHIMA"; +PROGMEM const char ocloc_370000[] = "KAGAWA"; +PROGMEM const char ocloc_380000[] = "EHIME"; +PROGMEM const char ocloc_390000[] = "KOUCHI"; +PROGMEM const char ocloc_400000[] = "FUKUOKA"; +PROGMEM const char ocloc_410000[] = "SAGA"; +PROGMEM const char ocloc_420000[] = "NAGASAKI"; +PROGMEM const char ocloc_430000[] = "KUMAMOTO"; +PROGMEM const char ocloc_440000[] = "OOITA"; +PROGMEM const char ocloc_450000[] = "MIYAZAKI"; +PROGMEM const char ocloc_460100[] = "KAGOSHIMA"; +PROGMEM const char ocloc_460040[] = "AMAMI"; // Islands +PROGMEM const char ocloc_471000[] = "OKINAWA"; // Islands +PROGMEM const char ocloc_472000[] = "DAITOU"; // Islands +PROGMEM const char ocloc_473000[] = "MIYAKO"; // Islands +PROGMEM const char ocloc_474000[] = "YAEYAMA"; // Islands +#endif + +#if 0 +const std::map officeCodeTable = +{ + // 北海道 + { 11000, ocloc_11000 }, + { 12000, ocloc_12000 }, + { 13000, ocloc_13000 }, + { 14100, ocloc_14100 }, + { 14030, ocloc_14030 }, + { 15000, ocloc_15000 }, + { 16000, ocloc_16000 }, + { 17000, ocloc_16000 }, + // 東北 + { 20000, ocloc_20000 }, + { 30000, ocloc_30000 }, + { 40000, ocloc_40000 }, + { 50000, ocloc_50000 }, + { 60000, ocloc_60000 }, + { 70000, ocloc_70000 }, + // 関東 + { 80000, ocloc_80000 }, + { 90000, ocloc_90000 }, + { 100000, ocloc_100000 }, + { 110000, ocloc_110000 }, + { 120000, ocloc_120000 }, + { 130000, ocloc_130000 }, + { 140000, ocloc_140000 }, + // 北陸、甲信 + { 150000, ocloc_150000 }, + { 160000, ocloc_160000 }, + { 170000, ocloc_170000 }, + { 180000, ocloc_180000 }, + { 190000, ocloc_190000 }, + { 200000, ocloc_200000 }, + // 東海 + { 210000, ocloc_210000 }, + { 220000, ocloc_220000 }, + { 230000, ocloc_230000 }, + { 240000, ocloc_240000 }, + // 近畿 + { 250000, ocloc_250000 }, + { 260000, ocloc_260000 }, + { 270000, ocloc_270000 }, + { 280000, ocloc_280000 }, + { 290000, ocloc_290000 }, + { 300000, ocloc_300000 }, + // 中国 + { 310000, ocloc_310000 }, + { 320000, ocloc_320000 }, + { 330000, ocloc_330000 }, + { 340000, ocloc_340000 }, + { 350000, ocloc_350000 }, + // 四国 + { 360000, ocloc_360000 }, + { 370000, ocloc_370000 }, + { 380000, ocloc_380000 }, + { 390000, ocloc_390000 }, + // 九州 + { 400000, ocloc_400000 }, + { 410000, ocloc_410000 }, + { 420000, ocloc_420000 }, + { 430000, ocloc_430000 }, + { 440000, ocloc_440000 }, + { 450000, ocloc_450000 }, + { 460100, ocloc_460100 }, + { 460040, ocloc_460040 }, + // 沖縄 + { 471000, ocloc_471000 }, + { 472000, ocloc_472000 }, + { 473000, ocloc_473000 }, + { 474000, ocloc_474000 }, +}; + +#else + +const std::map officeCodeTable = +{ + { 16000, ocloc_16000 }, + { 40000, ocloc_40000 }, + { 130000, ocloc_130000 }, + { 150000, ocloc_150000 }, + { 170000, ocloc_170000 }, + { 230000, ocloc_230000 }, + { 270000, ocloc_270000 }, + { 340000, ocloc_340000 }, + { 390000, ocloc_390000 }, + { 400000, ocloc_400000 }, + { 471000, ocloc_471000 }, +}; + +#endif + +// Weather code to weather icon +const std::map iconTable = +{ + { 100, 100 }, + { 101, 101 }, + { 102, 102 }, + { 103, 102 }, + { 104, 104 }, + { 105, 104 }, + { 106, 102 }, + { 107, 102 }, + { 108, 102 }, + { 110, 110 }, + { 111, 110 }, + { 112, 112 }, + { 113, 112 }, + { 114, 112 }, + { 115, 115 }, + { 116, 115 }, + { 117, 115 }, + { 118, 112 }, + { 119, 112 }, + { 120, 102 }, + { 121, 102 }, + { 122, 112 }, + { 123, 100 }, + { 124, 100 }, + { 125, 112 }, + { 126, 112 }, + { 127, 112 }, + { 128, 112 }, + { 130, 100 }, + { 131, 100 }, + { 132, 101 }, + { 140, 102 }, + { 160, 104 }, + { 170, 104 }, + { 181, 115 }, + { 200, 200 }, + { 201, 201 }, + { 202, 202 }, + { 203, 202 }, + { 204, 204 }, + { 205, 204 }, + { 206, 202 }, + { 207, 202 }, + { 208, 202 }, + { 209, 200 }, + { 210, 210 }, + { 211, 210 }, + { 212, 212 }, + { 213, 212 }, + { 214, 212 }, + { 215, 215 }, + { 216, 215 }, + { 217, 215 }, + { 218, 212 }, + { 219, 212 }, + { 220, 202 }, + { 221, 202 }, + { 222, 212 }, + { 223, 201 }, + { 224, 212 }, + { 225, 212 }, + { 226, 212 }, + { 228, 215 }, + { 229, 215 }, + { 230, 215 }, + { 231, 200 }, + { 240, 202 }, + { 250, 204 }, + { 260, 204 }, + { 270, 204 }, + { 281, 215 }, + { 300, 300 }, + { 301, 301 }, + { 302, 302 }, + { 303, 303 }, + { 304, 300 }, + { 306, 300 }, + { 308, 308 }, + { 309, 303 }, + { 311, 311 }, + { 313, 313 }, + { 314, 314 }, + { 315, 314 }, + { 316, 311 }, + { 317, 313 }, + { 320, 311 }, + { 321, 313 }, + { 322, 303 }, + { 323, 311 }, + { 324, 311 }, + { 325, 311 }, + { 326, 314 }, + { 327, 314 }, + { 328, 300 }, + { 329, 300 }, + { 340, 400 }, + { 350, 300 }, + { 361, 411 }, + { 371, 413 }, + { 400, 400 }, + { 401, 401 }, + { 402, 402 }, + { 403, 403 }, + { 405, 400 }, + { 406, 406 }, + { 407, 406 }, + { 409, 403 }, + { 411, 411 }, + { 413, 413 }, + { 414, 414 }, + { 420, 411 }, + { 421, 413 }, + { 422, 414 }, + { 423, 414 }, + { 425, 400 }, + { 426, 400 }, + { 427, 400 }, + { 450, 400 }, +}; + +// +} + +namespace jma +{ +// DigiCert Global Root CA of www.jma.go.jp. +// Exxpire at Mon, 10 Nov 2031 00:00:00 GMT. +PROGMEM const char root_ca_JMA[] = + "-----BEGIN CERTIFICATE-----" "\n" + "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh" "\n" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3" "\n" + "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD" "\n" + "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT" "\n" + "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j" "\n" + "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG" "\n" + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB" "\n" + "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97" "\n" + "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt" "\n" + "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P" "\n" + "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4" "\n" + "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO" "\n" + "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR" "\n" + "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw" "\n" + "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr" "\n" + "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg" "\n" + "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF" "\n" + "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls" "\n" + "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk" "\n" + "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=" "\n" + "-----END CERTIFICATE-----" "\n" + ; + +const char* weatherCodeToString(const weathercode_t wc) +{ + return weatherCodeTable.count(wc) == 1 ? weatherCodeTable.at(wc) : ""; +} + +const char* officesCodeToString(const officecode_t oc) +{ + return officeCodeTable.count(oc) == 1 ? officeCodeTable.at(oc) : ""; +} + +int16_t weatherCodeToIcon(const weathercode_t wc) +{ + return iconTable.count(wc) == 1 ? iconTable.at(wc) : 0; +} + +// +} diff --git a/src/jma/jma_definition.hpp b/src/jma/jma_definition.hpp new file mode 100644 index 0000000..b294a74 --- /dev/null +++ b/src/jma/jma_definition.hpp @@ -0,0 +1,20 @@ +#ifndef JMA_DEFINITION_HPP +#define JMA_DEFINITION_HPP + +#include + +namespace jma +{ + +using officecode_t = uint32_t; +using weathercode_t = uint16_t; + +const char* weatherCodeToString(const weathercode_t wc); +const char* officesCodeToString(const officecode_t oc); +int16_t weatherCodeToIcon(const weathercode_t wc); + +extern const char root_ca_JMA[]; + +// +} +#endif diff --git a/src/jma/jma_forecast.cpp b/src/jma/jma_forecast.cpp new file mode 100644 index 0000000..e0196ce --- /dev/null +++ b/src/jma/jma_forecast.cpp @@ -0,0 +1,210 @@ + +#include "jma_forecast.hpp" +#include +#include +#include + +namespace +{ +// Exists T::toString()? +template struct has_toString +{ + template static std::true_type check(U*); + static std::false_type check(...); + static T* _cls; + static const bool value = decltype(check(_cls))::value; +}; + +// Like join function of Ruby. (For Integral, Floating-point, and String) +template::value || std::is_integral::value || std::is_same::value, std::nullptr_t>::type = nullptr> +String join(const std::vector& v, const char* separator = ", ") +{ + + return !v.empty() ? std::accumulate(++v.cbegin(), v.cend(), String(v[0]), + [&separator](const String& a, const T& b) + { + return a + separator + String(b); + }): String(); +} + + +// Like join function of Ruby. (For classes that has the toString function.) +template::value, std::nullptr_t>::type = nullptr> +String join(const std::vector& v, const char* separator = ", ") +{ + return !v.empty() ? std::accumulate(++v.cbegin(), v.cend(), v[0].toString(), + [&separator](const String& a, const T& b) + { + return a + separator + b.toString(); + }) : String(); +} + +template constexpr typename std::underlying_type::type to_underlying(T e) noexcept +{ + return static_cast::type>(e); +} +// +} + +namespace jma +{ +// +String Area::toString() const +{ + String s = "name:" + _name + ", code:" + String(_code); + return s; +} + +// +Reliability Reliability::parse(const char* s) +{ + if(!s || !s[0] || s[1]) { return Reliability(Rank::MAX); } + int v = *s - 'A'; + return Reliability((v >= 0 && v < to_underlying(Rank::MAX)) ? (Rank)v : Rank::MAX); +} + +String Reliability::toString() const +{ + static constexpr char tbl[] = { 'A', 'B', 'C', '-'}; + auto v = to_underlying(_rank); + return String((v < to_underlying(Rank::MAX)) ? tbl[v] : tbl[to_underlying(Rank::MAX)]); +} + +// +String Forecast::toString() const +{ + String s; + s += "publishingOffice:" + _publishingOffice + '\n'; + s += "reportDatetime:" + _reportDatetime.toString() + '\n'; + s += "timeSeries[0]:Weather\n" + _tsWeather.toString() + '\n'; + s += "timeSeries[1]:Pop\n" + _tsPop.toString() + '\n'; + s += "timeSeries[2]:Temp\n" + _tsTemp.toString(); + return s; +} + + +String Forecast::TimeSeriesWeather::toString() const +{ + String s; + s = "timeDefine:[" + join(_timeDefines) + "]\n"; + s += join(_areas, "\n"); + return s; +} + +String Forecast::TimeSeriesWeather::Areas::toString() const +{ + String s = _area.toString() + '\n'; + s += "weatherCodes:[" + join(_weatherCodes) + "]\n"; + s += "weathers:[" + join(_weathers) + "]\n"; + s += "winds:[" + join(_winds) + "]\n"; + s += "waves:[" + join(_waves) + "]"; + return s; +} + +String Forecast::TimeSeriesPop::toString() const +{ + String s; + s = "timeDefine:[" + join(_timeDefines) + "]\n"; + s += join(_areas, "\n"); + return s; +} + +String Forecast::TimeSeriesPop::Areas::toString() const +{ + String s = _area.toString() + '\n'; + s += "pops:[" + join(_pops) + "]"; + return s; +} + +String Forecast::TimeSeriesTemp::toString() const +{ + String s; + s = "timeDefine:[" + join(_timeDefines) + "]\n"; + s += join(_areas, "\n"); + return s; +} + +String Forecast::TimeSeriesTemp::Areas::toString() const +{ + String s = _area.toString() + '\n'; + s += "temps:[" + join(_temps) + "]"; + return s; +} + +// +String WeeklyForecast::toString() const +{ + String s; + s += "publishingOffice:" + _publishingOffice + '\n'; + s += "reportDatetime:" + _reportDatetime.toString() + '\n'; + s += "timeSeries[0]:Weather\n" + _tsWeather.toString() + '\n'; + s += "timeSeries[1]:Temp\n" + _tsTemp.toString() + '\n'; + s += "tempAverage\n" + _tempAverage.toString() + '\n'; + s += "precipAverage:\n" + _precipAverage.toString(); + return s; +} + +String WeeklyForecast::TimeSeriesWeather::toString() const +{ + String s; + s = "timeDefine:[" + join(_timeDefines) + "]\n"; + s += join(_areas, "\n"); + return s; +} + +String WeeklyForecast::TimeSeriesWeather::Areas::toString() const +{ + String s = _area.toString() + '\n'; + s += "weatherCodes:[" + join(_weatherCodes) + "]\n"; + s += "pops:[" + join(_pops) + "]\n"; + s += "reliabilities:[" + join(_reliabilities) + ']'; + return s; +} + +String WeeklyForecast::TimeSeriesTemp::toString() const +{ + String s; + s = "timeDefine:[" + join(_timeDefines) + "]\n"; + s += join(_areas, "\n"); + return s; +} + +String WeeklyForecast::TimeSeriesTemp::Areas::toString() const +{ + String s = _area.toString() + '\n'; + s += "tempsMin:[" + join(_tempsMin) + "]\n"; + s += "tempsMinUpper[:" + join(_tempsMinUpper) + "]\n"; + s += "tempsMinLower:[" + join(_tempsMinLower) + "]\n"; + s += "tempsMax:[" + join(_tempsMax) + "]\n"; + s += "tempsMaxUpper:[" + join(_tempsMaxUpper) + "]\n"; + s += "tempsMaxLower:[" + join(_tempsMaxLower) + "]"; + return s; +} + +String WeeklyForecast::TempAverage::toString() const +{ + String s = join(_areas, "\n"); + return s; +} + +String WeeklyForecast::TempAverage::Areas::toString() const +{ + String s = _area.toString() + '\n'; + s += "min:" + String(_min) + ", max:" + String(_max); + return s; +} + +String WeeklyForecast::PrecipAverage::toString() const +{ + String s = join(_areas, "\n"); + return s; +} + +String WeeklyForecast::PrecipAverage::Areas::toString() const +{ + String s = _area.toString() + '\n'; + s += "min:" + String(_min) + ", max:" + String(_max); + return s; +} +// +} diff --git a/src/jma/jma_forecast.hpp b/src/jma/jma_forecast.hpp new file mode 100644 index 0000000..04066d4 --- /dev/null +++ b/src/jma/jma_forecast.hpp @@ -0,0 +1,167 @@ + +#ifndef JMA_FORECAST_HPP +#define JMA_FORECAST_HPP + +#include "jma_definition.hpp" +#include +#include +#include +using goblib::datetime::OffsetDateTime; + +namespace jma +{ + +struct Area +{ + String _name{}; + uint32_t _code{}; + String toString() const; +}; + +struct Reliability +{ + enum class Rank : uint8_t { A, B, C, MAX }; + + explicit Reliability(const Rank r) : _rank(r) {} + explicit Reliability(const char* s) { *this = parse(s); } + static Reliability parse(const char* s); + String toString() const; + private: + Rank _rank{Rank::C}; +}; + +// +struct Forecast +{ + struct TimeSeriesWeather + { + struct Areas + { + Area _area{}; + std::vector _weatherCodes; + std::vector _weathers; + std::vector _winds; + std::vector _waves; + String toString() const; + }; + std::vector _timeDefines; + std::vector _areas; + String toString() const; + }; + struct TimeSeriesPop + { + struct Areas + { + Area _area{}; + std::vector _pops; + String toString() const; + }; + std::vector _timeDefines; + std::vector _areas; + String toString() const; + }; + struct TimeSeriesTemp + { + struct Areas + { + Area _area{}; + std::vector _temps; // Pair 2 elements. [low,high,low,high...] + String toString() const; + }; + std::vector _timeDefines; // Same as _temps length + std::vector _areas; + String toString() const; + }; + + + String _publishingOffice{}; + OffsetDateTime _reportDatetime{}; + TimeSeriesWeather _tsWeather{}; + TimeSeriesPop _tsPop{}; + TimeSeriesTemp _tsTemp{}; + + String toString() const; + + // + bool existsTopWeatherCodes() const { return !_tsWeather._areas.empty() && !_tsWeather._areas[0]._weatherCodes.empty(); } + const std::vector& TopWeatherCodes() const { return _tsWeather._areas[0]._weatherCodes; } + const std::vector& TopWeatherTime() const { return _tsWeather._timeDefines; } + + bool existsTopTemp() const { return !_tsTemp._areas.empty() && !_tsTemp._areas[0]._temps.empty(); } + const std::vector& TopTemp() const { return _tsTemp._areas[0]._temps; } + const std::vector& TopTempTime() const { return _tsTemp._timeDefines; } +}; + + +// 週間予報 +struct WeeklyForecast +{ + struct TimeSeriesWeather + { + struct Areas + { + Area _area; + std::vector _weatherCodes; + std::vector _pops; + std::vector _reliabilities; + String toString() const; + }; + std::vector _timeDefines; + std::vector _areas; + String toString() const; + }; + + struct TimeSeriesTemp + { + struct Areas + { + Area _area; + std::vector _tempsMin; + std::vector _tempsMinUpper; + std::vector _tempsMinLower; + std::vector _tempsMax; + std::vector _tempsMaxUpper; + std::vector _tempsMaxLower; + String toString() const; + }; + std::vector _timeDefines; + std::vector _areas; + String toString() const; + }; + struct TempAverage + { + struct Areas + { + Area _area{}; + float _min{}; + float _max{}; + String toString() const; + }; + std::vector _areas; + String toString() const; + }; + struct PrecipAverage + { + struct Areas + { + Area _area{}; + float _min{}; + float _max{}; + String toString() const; + }; + std::vector _areas; + String toString() const; + }; + + String _publishingOffice; + OffsetDateTime _reportDatetime{}; + TimeSeriesWeather _tsWeather{}; + TimeSeriesTemp _tsTemp{}; + TempAverage _tempAverage; + PrecipAverage _precipAverage; + String toString() const; +}; + +// +} +#endif diff --git a/src/jma/jma_forecast_handler.cpp b/src/jma/jma_forecast_handler.cpp new file mode 100644 index 0000000..94aa584 --- /dev/null +++ b/src/jma/jma_forecast_handler.cpp @@ -0,0 +1,525 @@ + +#include +#include "jma_forecast_handler.hpp" +#include "wb2/wxbeacon2_log.hpp" + +namespace +{ +#ifndef NDEBUG +String fullpath(ElementPath& path) +{ + char buf[256] = ""; + path.toString(buf); + return String(buf); +} +#endif +// +} + +void JMAHandler::startObject(ElementPath path) +{ + // Delegate processing to object. + auto obj = currentObject(); + if(obj) + { + auto nobj = obj->startObject(path); + if(!nobj) { WB2_LOGD("NullObj:%s", fullpath(path).c_str()); } + assert(nobj); + _objects.push(nobj); + return; + } + + Object* nobj = nullptr; + switch(path.getIndex()) + { + case 0: nobj = new Forecast(_forecast); break; + case 1: nobj = new WeeklyForecast(_weeklyForecast); break; + } + if(!nobj) { WB2_LOGD("NullObj:%s", fullpath(path).c_str()); nobj = new Object(); } + _objects.push(nobj); +} + +void JMAHandler::endObject(ElementPath path) +{ + // Delegate processing to object. + auto obj = currentObject(); + if(obj) + { + obj->endObject(path); + delete _objects.top(); + _objects.pop(); + } +} + +void JMAHandler::startArray(ElementPath path) +{ + // Delegate processing to object. + auto obj = currentObject(); + if(obj) { obj->startArray(path); } +} + +void JMAHandler::endArray(ElementPath path) +{ + // Delegate processing to object. + auto obj = currentObject(); + if(obj) { obj->endArray(path); } +} + +void JMAHandler::value(ElementPath path, ElementValue value) +{ + // Delegate processing to object. + auto obj = currentObject(); + if(obj) { obj->value(path, value); } +} + +void JMAHandler::endDocument() +{ + // WB2_LOGD("End of Document: objects %zu", _objects.size()); +} + +// Area +void JMAHandler::Area::value(ElementPath& path, ElementValue& value) +{ + Element e_name { "name", &_v._name }; + Element e_code { "code", &_v._code }; + ElementBase* elements[] = { &e_name, &e_code }; + for(auto& e : elements) + { + if(e->key == path.getKey()) { e->store(value); return; } + + } +} + +// ForeeCast +JMAHandler::Object* JMAHandler::Forecast::startObject(ElementPath& path) +{ + Object* obj = nullptr; + switch(path.getIndex()) + { + case 0: obj = new TimeSeriesWeather(_v._tsWeather); break; + case 1: obj = new TimeSeriesPop(_v._tsPop); break; + case 2: obj = new TimeSeriesTemp(_v._tsTemp); break; + } + return obj ? obj : new Object(); +} + +void JMAHandler::Forecast::value(ElementPath& path, ElementValue& value) +{ + Element e_publishingOffice { "publishingOffice", &_v._publishingOffice }; + Element e_reportDatetime { "reportDatetime", &_v._reportDatetime }; + ElementBase* elements[] = { &e_publishingOffice, &e_reportDatetime }; + for(auto& e : elements) + { + if(e->key == path.getKey()) { e->store(value); return; } + + } +} + +// Forecast::TimeSeriesWeather +JMAHandler::Object* JMAHandler::Forecast::TimeSeriesWeather::startObject(ElementPath& path) +{ + auto parent = path.getParent(); + if(parent && String("areas") == parent->getKey()) + { + _v._areas.emplace_back(); + return new TimeSeriesWeather::Areas(_v._areas.back()); + } + return new Object(); +} + +void JMAHandler::Forecast::TimeSeriesWeather::value(ElementPath& path, ElementValue& value) +{ + auto parent = path.getParent(); + if(!parent) { return; } + Element e_td { "timeDefines", &_v._timeDefines }; + ElementBase* elements[] = { &e_td }; + for(auto& e : elements) + { + if(e->key == parent->getKey()) { e->store(value); return; } + + } +} + +// Forecast::TimeSeriesWeather::Areas +JMAHandler::Object* JMAHandler::Forecast::TimeSeriesWeather::Areas::startObject(ElementPath& path) +{ + if(String("area") == path.getKey()) + { + return new JMAHandler::Area(_v._area); + } + return new Object(); +} + +void JMAHandler::Forecast::TimeSeriesWeather::Areas::value(ElementPath& path, ElementValue& value) +{ + auto parent = path.getParent(); + if(!parent) { return; } + + Element e_codes { "weatherCodes", &_v._weatherCodes }; + // Element e_weathers { "weathers", &_v._weathers }; + // Element e_winds { "winds", &_v._winds }; + // Element e_waves { "waves", &_v._waves }; + // ElementBase* elements[] = { &e_codes, &e_weathers, &e_winds, &e_waves }; + ElementBase* elements[] = { &e_codes }; + for(auto& e : elements) + { + if(e->key == parent->getKey()) { e->store(value); return; } + + } +} + +// Forecast::TimeSeriesPop +JMAHandler::Object* JMAHandler::Forecast::TimeSeriesPop::startObject(ElementPath& path) +{ + auto parent = path.getParent(); + if(parent && String("areas") == parent->getKey()) + { + _v._areas.emplace_back(); + return new TimeSeriesPop::Areas(_v._areas.back()); + } + return new Object(); +} + +void JMAHandler::Forecast::TimeSeriesPop::value(ElementPath& path, ElementValue& value) +{ + auto parent = path.getParent(); + if(!parent) { return; } + Element e_td { "timeDefines", &_v._timeDefines }; + ElementBase* elements[] = { &e_td }; + for(auto& e : elements) + { + if(e->key == parent->getKey()) { e->store(value); return; } + + } +} + +// Forecast::TimeSeriesPop::Areas +JMAHandler::Object* JMAHandler::Forecast::TimeSeriesPop::Areas::startObject(ElementPath& path) +{ + if(String("area") == path.getKey()) + { + return new JMAHandler::Area(_v._area); + } + return new Object(); +} + +void JMAHandler::Forecast::TimeSeriesPop::Areas::value(ElementPath& path, ElementValue& value) +{ + auto parent = path.getParent(); + if(!parent) { return; } + + Element e_pops { "pops", &_v._pops }; + ElementBase* elements[] = { &e_pops }; + for(auto& e : elements) + { + if(e->key == parent->getKey()) { e->store(value); return; } + + } +} + +// Forecast::TimeSeriesTemp +JMAHandler::Object* JMAHandler::Forecast::TimeSeriesTemp::startObject(ElementPath& path) +{ + auto parent = path.getParent(); + if(parent && String("areas") == parent->getKey()) + { + _v._areas.emplace_back(); + return new TimeSeriesTemp::Areas(_v._areas.back()); + } + return new Object(); +} + +void JMAHandler::Forecast::TimeSeriesTemp::value(ElementPath& path, ElementValue& value) +{ + auto parent = path.getParent(); + if(!parent) { return; } + Element e_td { "timeDefines", &_v._timeDefines }; + ElementBase* elements[] = { &e_td }; + for(auto& e : elements) + { + if(e->key == parent->getKey()) { e->store(value); return; } + + } +} + +// Forecast::TimeSeriesTemp::Areas +JMAHandler::Object* JMAHandler::Forecast::TimeSeriesTemp::Areas::startObject(ElementPath& path) +{ + if(String("area") == path.getKey()) + { + return new JMAHandler::Area(_v._area); + } + return new Object(); +} + +void JMAHandler::Forecast::TimeSeriesTemp::Areas::value(ElementPath& path, ElementValue& value) +{ + auto parent = path.getParent(); + if(!parent) { return; } + + Element e_temps { "temps", &_v._temps }; + ElementBase* elements[] = { &e_temps }; + for(auto& e : elements) + { + if(e->key == parent->getKey()) { e->store(value); return; } + + } +} + +// WeeklyForeeCast +JMAHandler::Object* JMAHandler::WeeklyForecast::startObject(ElementPath& path) +{ + Object* obj = nullptr; + auto parent = path.getParent(); + + if(String("timeSeries") == parent->getKey()) + { + switch(path.getIndex()) + { + case 0: obj = new TimeSeriesWeather(_v._tsWeather); break; + case 1: obj = new TimeSeriesTemp(_v._tsTemp); break; + } + } + else if(String("tempAverage") == path.getKey()) + { + obj = new TempAverage(_v._tempAverage); + } + else if(String("precipAverage") == path.getKey()) + { + obj = new PrecipAverage(_v._precipAverage); + } + return obj ? obj : new Object(); +} + +void JMAHandler::WeeklyForecast::value(ElementPath& path, ElementValue& value) +{ + Element e_publishingOffice { "publishingOffice", &_v._publishingOffice }; + Element e_reportDatetime { "reportDatetime", &_v._reportDatetime }; + ElementBase* elements[] = { &e_publishingOffice, &e_reportDatetime }; + for(auto& e : elements) + { + if(e->key == path.getKey()) { e->store(value); return; } + } +} + +// WeeklyForecast::TimeSeriesWeather +JMAHandler::Object* JMAHandler::WeeklyForecast::TimeSeriesWeather::startObject(ElementPath& path) +{ + auto parent = path.getParent(); + if(parent && String("areas") == parent->getKey()) + { + _v._areas.emplace_back(); + return new TimeSeriesWeather::Areas(_v._areas.back()); + } + return new Object(); +} + +void JMAHandler::WeeklyForecast::TimeSeriesWeather::value(ElementPath& path, ElementValue& value) +{ + auto parent = path.getParent(); + if(!parent) { return; } + Element e_td { "timeDefines", &_v._timeDefines }; + ElementBase* elements[] = { &e_td }; + for(auto& e : elements) + { + if(e->key == parent->getKey()) { e->store(value); return; } + + } +} + +// WeeklyForecast::TimeSeriesWeather::Areas +JMAHandler::Object* JMAHandler::WeeklyForecast::TimeSeriesWeather::Areas::startObject(ElementPath& path) +{ + if(String("area") == path.getKey()) + { + return new JMAHandler::Area(_v._area); + } + return new Object(); +} + +void JMAHandler::WeeklyForecast::TimeSeriesWeather::Areas::value(ElementPath& path, ElementValue& value) +{ + auto parent = path.getParent(); + if(!parent) { return; } + + Element e_codes { "weatherCodes", &_v._weatherCodes }; + Element e_pops { "pops", &_v._pops }; + Element e_reliabilities { "reliabilities", &_v._reliabilities }; + ElementBase* elements[] = { &e_codes, &e_pops, &e_reliabilities }; + for(auto& e : elements) + { + if(e->key == parent->getKey()) { e->store(value); return; } + + } +} + +// WeeklyForecast::TimeSeriesTemp +JMAHandler::Object* JMAHandler::WeeklyForecast::TimeSeriesTemp::startObject(ElementPath& path) +{ + auto parent = path.getParent(); + if(parent && String("areas") == parent->getKey()) + { + _v._areas.emplace_back(); + return new TimeSeriesTemp::Areas(_v._areas.back()); + } + return new Object(); +} + +void JMAHandler::WeeklyForecast::TimeSeriesTemp::value(ElementPath& path, ElementValue& value) +{ + auto parent = path.getParent(); + if(!parent) { return; } + Element e_td { "timeDefines", &_v._timeDefines }; + ElementBase* elements[] = { &e_td }; + for(auto& e : elements) + { + if(e->key == parent->getKey()) { e->store(value); return; } + + } +} + +// WeeklyForecast::TimeSeriesTemp::Areas +JMAHandler::Object* JMAHandler::WeeklyForecast::TimeSeriesTemp::Areas::startObject(ElementPath& path) +{ + if(String("area") == path.getKey()) + { + return new JMAHandler::Area(_v._area); + } + return new Object(); +} + +void JMAHandler::WeeklyForecast::TimeSeriesTemp::Areas::value(ElementPath& path, ElementValue& value) +{ + auto parent = path.getParent(); + if(!parent) { return; } + + Element e_tempsMin { "tempsMin", &_v._tempsMin }; + Element e_tempsMinU { "tempsMinUpper", &_v._tempsMinUpper }; + Element e_tempsMinL { "tempsMinLower", &_v._tempsMinLower }; + Element e_tempsMax { "tempsMax", &_v._tempsMax }; + Element e_tempsMaxU { "tempsMaxUpper", &_v._tempsMaxUpper }; + Element e_tempsMaxL { "tempsMaxLower", &_v._tempsMaxLower }; + ElementBase* elements[] = { &e_tempsMin, &e_tempsMinU, &e_tempsMinL, &e_tempsMax, &e_tempsMaxU, &e_tempsMaxL }; + for(auto& e : elements) + { + if(e->key == parent->getKey()) { e->store(value); return; } + + } +} + +// WeeklyForecast::TempAverage +JMAHandler::Object* JMAHandler::WeeklyForecast::TempAverage::startObject(ElementPath& path) +{ + auto parent = path.getParent(); + if(parent && String("areas") == parent->getKey()) + { + _v._areas.emplace_back(); + return new TempAverage::Areas(_v._areas.back()); + } + return new Object(); +} + +void JMAHandler::WeeklyForecast::TempAverage::value(ElementPath& path, ElementValue& value) +{ +} + +// WeeklyForecast::TempAverage::Areas +JMAHandler::Object* JMAHandler::WeeklyForecast::TempAverage::Areas::startObject(ElementPath& path) +{ + if(String("area") == path.getKey()) + { + return new JMAHandler::Area(_v._area); + } + return new Object(); +} + +void JMAHandler::WeeklyForecast::TempAverage::Areas::value(ElementPath& path, ElementValue& value) +{ + auto parent = path.getParent(); + if(!parent) { return; } + + Element e_min { "min", &_v._min }; + Element e_max { "max", &_v._max }; + ElementBase* elements[] = { &e_min, &e_max }; + for(auto& e : elements) + { + if(e->key == parent->getKey()) { e->store(value); return; } + + } +} + +// WeeklyForecast::PrecipAverage +JMAHandler::Object* JMAHandler::WeeklyForecast::PrecipAverage::startObject(ElementPath& path) +{ + auto parent = path.getParent(); + if(parent && String("areas") == parent->getKey()) + { + _v._areas.emplace_back(); + return new PrecipAverage::Areas(_v._areas.back()); + } + return new Object(); +} + +void JMAHandler::WeeklyForecast::PrecipAverage::value(ElementPath& path, ElementValue& value) +{ +} + +// WeeklyForecast::PrecipAverage::Areas +JMAHandler::Object* JMAHandler::WeeklyForecast::PrecipAverage::Areas::startObject(ElementPath& path) +{ + if(String("area") == path.getKey()) + { + return new JMAHandler::Area(_v._area); + } + return new Object(); +} + +void JMAHandler::WeeklyForecast::PrecipAverage::Areas::value(ElementPath& path, ElementValue& value) +{ + auto parent = path.getParent(); + if(!parent) { return; } + + Element e_min { "min", &_v._min }; + Element e_max { "max", &_v._max }; + ElementBase* elements[] = { &e_min, &e_max }; + for(auto& e : elements) + { + if(e->key == parent->getKey()) { e->store(value); return; } + + } +} + +#if 0 +void test_json() +{ + auto mem = esp_get_free_heap_size(); + WB2_LOGD("before:%u", mem); + + { + JsonStreamingParser parser; + JMAHandler handler; + parser.setHandler(&handler); + + + for(auto& e : test) + { + parser.parse(e); + } + printf("--------------------\n"); + printf("%s\n", handler._forecast.toString().c_str()); + printf("--------------------\n"); + printf("%s\n", handler._weeklyForecast.toString().c_str()); + } + + auto mem2 = esp_get_free_heap_size(); + WB2_LOGD("after:%u diff:%d", mem2, mem2 - mem); + + { + JsonStreamingParser parser; + JMAHandler handler; + parser.setHandler(&handler); + } + auto mem3 = esp_get_free_heap_size(); + WB2_LOGD("after:%u diff:%d", mem3, mem3 - mem2); +} +#endif diff --git a/src/jma/jma_forecast_handler.hpp b/src/jma/jma_forecast_handler.hpp new file mode 100644 index 0000000..d654350 --- /dev/null +++ b/src/jma/jma_forecast_handler.hpp @@ -0,0 +1,267 @@ +#ifndef JMA_FORECAST_PARSER_HPP +#define JMA_FORECAST_PARSER_HPP + +#include +#include "jma_forecast.hpp" +#include +#include + + +template struct is_std_vector { static const bool value=false; }; +template struct is_std_vector > { static const bool value=true; }; + +// Store functions for each type. (SFINAE) +struct ElementBase +{ + ElementBase(const char* s) : key(s) {} + virtual void store(ElementValue& s) = 0; + String key; +}; + +template struct Element : public ElementBase +{ + T* value; // Pointer of store target. + Element(const char* key, T* p) : ElementBase(key), value(p) { assert(p); } + virtual void store(ElementValue& ev) override { _store(ev); } // _store function is called based on the type of T. (SFINAE) + + // Integral + template::value && std::is_integral::value, std::nullptr_t>::type = nullptr> + void _store(ElementValue& ev) { *value = ev.isInt() ? ev.getInt() : String(ev.getString()).toInt(); } + // Floating-point + template::value, std::nullptr_t>::type = nullptr> + void _store(ElementValue& ev) { *value = ev.isFloat() ? ev.getFloat() : String(ev.getString()).toFloat(); } + // String + template::value, std::nullptr_t>::type = nullptr> + void _store(ElementValue& ev) { *value = ev.getString(); } + // Boolean + template::value, std::nullptr_t>::type = nullptr> + void _store(ElementValue& ev) { *value = ev.isBool() ? ev.getBool() : (String("true") == ev.getString()); } + // OffsetDateTime + template::value, std::nullptr_t>::type = nullptr> + void _store(ElementValue& ev) { *value = OffsetDateTime::parse(ev.getString()); } + // vector + template::value && std::is_integral::value, std::nullptr_t>::type = nullptr> + void _store(ElementValue& ev) { value->emplace_back(ev.isInt() ? ev.getInt() : String(ev.getString()).toInt()); } + // vector + template::value && std::is_same::value, std::nullptr_t>::type = nullptr> + void _store(ElementValue& ev) { value->emplace_back(ev.getString()); } + // vector + template::value && std::is_same::value, std::nullptr_t>::type = nullptr> + void _store(ElementValue& ev) { value->emplace_back(ev.getString()); } + // vector + template::value && std::is_same::value, std::nullptr_t>::type = nullptr> + void _store(ElementValue& ev) { value->emplace_back(ev.getString()); } +}; + +// +class JMAHandler : public JsonHandler +{ + public: + struct Object // interface class. + { + virtual ~Object(){} + virtual Object* startObject(ElementPath& path) { return new Object(); } + virtual void endObject(ElementPath& path) {} + virtual void startArray(ElementPath& path) {} + virtual void endArray(ElementPath& path) {} + virtual void value(ElementPath& path, ElementValue& value) {} + }; + // + class Area : public Object + { + public: + Area(jma::Area& target) : _v(target) {} + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::Area& _v; + }; + // + class Forecast : public Object + { + // + class TimeSeriesWeather : public Object + { + // + class Areas : public Object + { + public: + Areas(jma::Forecast::TimeSeriesWeather::Areas& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::Forecast::TimeSeriesWeather::Areas& _v; + }; + public: + TimeSeriesWeather(jma::Forecast::TimeSeriesWeather& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::Forecast::TimeSeriesWeather& _v; + }; + // + class TimeSeriesPop : public Object + { + public: + class Areas : public Object + { + public: + Areas(jma::Forecast::TimeSeriesPop::Areas& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::Forecast::TimeSeriesPop::Areas& _v; + }; + TimeSeriesPop(jma::Forecast::TimeSeriesPop& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::Forecast::TimeSeriesPop& _v; + }; + // + class TimeSeriesTemp : public Object + { + public: + class Areas : public Object + { + public: + Areas(jma::Forecast::TimeSeriesTemp::Areas& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::Forecast::TimeSeriesTemp::Areas& _v; + }; + TimeSeriesTemp(jma::Forecast::TimeSeriesTemp& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::Forecast::TimeSeriesTemp& _v; + }; + + public: + Forecast(jma::Forecast& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::Forecast& _v; + }; + + // + class WeeklyForecast : public Object + { + // + class TimeSeriesWeather : public Object + { + // + class Areas : public Object + { + public: + Areas(jma::WeeklyForecast::TimeSeriesWeather::Areas& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::WeeklyForecast::TimeSeriesWeather::Areas& _v; + }; + public: + TimeSeriesWeather(jma::WeeklyForecast::TimeSeriesWeather& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::WeeklyForecast::TimeSeriesWeather& _v; + }; + // + class TimeSeriesTemp : public Object + { + public: + class Areas : public Object + { + public: + Areas(jma::WeeklyForecast::TimeSeriesTemp::Areas& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::WeeklyForecast::TimeSeriesTemp::Areas& _v; + }; + TimeSeriesTemp(jma::WeeklyForecast::TimeSeriesTemp& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::WeeklyForecast::TimeSeriesTemp& _v; + }; + // + class TempAverage : public Object + { + public: + class Areas : public Object + { + public: + Areas(jma::WeeklyForecast::TempAverage::Areas& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::WeeklyForecast::TempAverage::Areas& _v; + }; + TempAverage(jma::WeeklyForecast::TempAverage& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::WeeklyForecast::TempAverage& _v; + }; + // + class PrecipAverage : public Object + { + public: + class Areas : public Object + { + public: + Areas(jma::WeeklyForecast::PrecipAverage::Areas& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::WeeklyForecast::PrecipAverage::Areas& _v; + }; + PrecipAverage(jma::WeeklyForecast::PrecipAverage& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::WeeklyForecast::PrecipAverage& _v; + }; + + public: + WeeklyForecast(jma::WeeklyForecast& target) : _v(target) {} + virtual Object* startObject(ElementPath& path) override; + virtual void value(ElementPath& path, ElementValue& value) override; + private: + jma::WeeklyForecast& _v; + }; + + public: + // JsonHandler overrides + void startDocument() override {} + void endDocument() override; + void startObject(ElementPath path) override; + void endObject(ElementPath path) override; + void startArray(ElementPath path) override; + void endArray(ElementPath path) override; + void whitespace(char /*c*/) override {} + void value(ElementPath path, ElementValue value) override; + + jma::Forecast _forecast{}; + jma::WeeklyForecast _weeklyForecast{}; + + private: + Object* currentObject() const { return !_objects.empty() ? _objects.top() : nullptr; } + std::stack _objects; +}; + + +//void test_json(); +#endif diff --git a/src/jma/jma_task.cpp b/src/jma/jma_task.cpp new file mode 100644 index 0000000..23b7e90 --- /dev/null +++ b/src/jma/jma_task.cpp @@ -0,0 +1,152 @@ + +#include +#include +#include +#include +#include +#include "jma_task.hpp" +#include "jma_forecast_handler.hpp" +#include "wb2/wxbeacon2_log.hpp" + +namespace +{ +// Request JMA forcast by WiFi +TaskHandle_t forecastTask; +volatile bool progressForecast = false; +jma::forecast_callback callback_on_forecast; +PROGMEM const char JMA_FORECAST_URI_FORMAT[] = "https://www.jma.go.jp/bosai/forecast/data/forecast/%06d.json"; +// Cities from which data is obtained. +PROGMEM const jma::officecode_t requestTable[] = +{ + 16000, // Sapporo + 40000, // Sendai + 130000, // Tokyo + 150000, // Niigata + 170000, // Kanazawa + 230000, // Nagoya + 270000, // Oosaka + 340000, // Hiroshima + 390000, // Kochi + 400000, // Fukuoka + 471000, // Okinawa +}; + +void jma_forecast_task(void*) +{ + for(;;) + { + ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); + + // Connect WiFi + int8_t ctry = 3; + do + { + WiFi.mode(WIFI_STA); + WiFi.begin(); + int tcount = 20; + while(tcount-- > 0 && WiFi.status() != WL_CONNECTED) + { + delay(500); + } + if(WiFi.status() == WL_CONNECTED) { break; } + WiFi.disconnect(true); + WiFi.mode(WIFI_OFF); + WB2_LOGD("Retry begin"); + delay(10); + }while(ctry--); + + if(WiFi.status() != WL_CONNECTED) + { + WB2_LOGE("Failed to connect WiFi"); + progressForecast = false; + continue; + } + + // Get each JSON. + for(uint8_t index = 0; index < sizeof(requestTable)/sizeof(requestTable[0]); ++index) + { + char url[128]; + snprintf(url, sizeof(url), JMA_FORECAST_URI_FORMAT, requestTable[index]); + url[sizeof(url) - 1] = '\0'; + + WB2_LOGI("Connect to [%s]", url); + + HTTPClient http; + WiFiClientSecure client; + do + { + client.setCACert(jma::root_ca_JMA); + int8_t gtry = 3; + int httpcode = 0; + // https GET + do + { + http.begin(client, url); + httpcode = http.GET(); + if(httpcode == HTTP_CODE_OK) { break; } + WB2_LOGD("Failed to GET() %d", httpcode); + http.end(); + client.stop(); + }while(gtry--); + + if(httpcode != HTTP_CODE_OK) { break; } + + // parse JSON + JsonStreamingParser parser; + JMAHandler handler; + parser.setHandler(&handler); + while(client.available()) { parser.parse(client.read()); } + + if(callback_on_forecast) { callback_on_forecast(requestTable[index], handler._forecast, handler._weeklyForecast); } + }while(0); + + http.end(); + client.stop(); + } + WB2_LOGD("WiFi disconnect"); + WiFi.disconnect(true); + WiFi.mode(WIFI_OFF); + + // terminate callback + if(callback_on_forecast) + { + JMAHandler dummy; + callback_on_forecast(0 /* End */ , dummy._forecast, dummy._weeklyForecast); + } + + progressForecast = false; + } +} +// +} + +namespace jma +{ + +bool initializeForecast(const UBaseType_t priority, const BaseType_t core, forecast_callback f) +{ + if(!forecastTask) + { + xTaskCreateUniversal(jma_forecast_task, "forecast_task", 8 * 1024, nullptr, priority, &forecastTask, core); + callback_on_forecast = f; + } + return forecastTask != nullptr; +} + +bool busyForecast() +{ + return progressForecast; +} + +// Kick jma_forecast_task +bool requestForecast() +{ + if(busyForecast()) { return false; } + + progressForecast = true; + xTaskNotifyGive(forecastTask); + return true; +} + +// +} diff --git a/src/jma/jma_task.hpp b/src/jma/jma_task.hpp new file mode 100644 index 0000000..e315c4d --- /dev/null +++ b/src/jma/jma_task.hpp @@ -0,0 +1,18 @@ + +#ifndef JMA_TASK_HPP +#define JMA_TASK_HPP + +#include "jma_forecast.hpp" + +namespace jma +{ +using forecast_callback = void(*)(const officecode_t oc, const Forecast& fc, const WeeklyForecast& wfc); + +bool initializeForecast(const UBaseType_t priority, const BaseType_t core, forecast_callback f); +void finalizeForecast(); + +bool requestForecast(); +bool busyForecast(); + +} +#endif diff --git a/src/main.cpp b/src/main.cpp index 96d7ec3..2f1e129 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,57 +8,37 @@ */ #include #include - -#include #include +#include // esp_bt_controller_mem_release +#include // hardware RNG #include -#include -#include -#include "wxbeacon2_ble.hpp" -#include "wxbeacon2_log.hpp" #include "aq_talk.hpp" #include "ponko_avatar.hpp" #include "wni_ticker.hpp" +#include "wb2/wxbeacon2_communication.hpp" +#include "wb2/wxbeacon2_log.hpp" +#include "jma/jma_task.hpp" +#include +#include "cpu_usage.hpp" #include #include - -// Settings -namespace -{ -// Auto talking interval time (Unit:second) -constexpr uint16_t TALKING_INTERVAL_SEC = 60 * 3; -// Measurement interval time (Unit:second) for broadcast mode -constexpr uint16_t MEASUREMENT_INTERVAL_BROADCAST_SEC = 60 * 3; -// turnon LED when got advertise data. -constexpr bool TURNON_LED = false; -} +#include +#include +#include + +#if __has_include () +#include +#else // esp_idf_version.h has been introduced in Arduino 1.0.5 (ESP-IDF3.3) +#define ESP_IDF_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch)) +#define ESP_IDF_VERSION ESP_IDF_VERSION_VAL(3,2,0) +#endif namespace { -// Get std::string that formatted with args. -#if 0 -template std::string formatString(const char* fmt, Args... args) -{ - size_t sz = snprintf(nullptr, 0U, fmt, args...); // calculate length - char buf[sz + 1]; - snprintf(buf, sizeof(buf), fmt, args...); - return std::string(buf, buf + sz + 1); -} -#else -std::string formatString(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - - size_t sz = vsnprintf(nullptr, 0U, fmt, args); // calculate length - char buf[sz + 1]; - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - return std::string(buf, buf + sz + 1); -} -#endif +// Automatic request interval for advertise. +constexpr uint16_t AUTO_REQUEST_ADVERTISE_INTERVAL_SEC = 5 * 60; // NTP serve URL const char* ntpURL[] = @@ -69,206 +49,147 @@ const char* ntpURL[] = }; // For configurate time -#ifdef M5S_WXBEACON2_GMT_OFFSET_HOUR -long gmtOffsetSec = 3600 * M5S_WXBEACON2_GMT_OFFSET_HOUR; -#else -long gmtOffsetSec = 3600 * 9; // JST(GMT+9) as default. +#ifndef M5S_WXBEACON2_TIMEZONE_LOCATION +#define M5S_WXBEACON2_TIMEZONE_LOCATION "Asia/Tokyo" #endif -#ifdef M5S_WXBEACON2_DAYLIGHT_OFFSET_SEC -long daylightOffsetSec = M5S_WXBEACON2_DAYLIGHT_OFFSET_SEC; -#else -long daylightOffsetSec = 0; // 0 as default -#endif +Avatar* avatar; +Ticker* ticker; +bool forceRender = true; // Force rendering all +time_t lastUpdate = -1; +time_t voiceEnd = -1; -#ifdef M5S_WXBEACON2_WIFI_HOST_NAME -#define G_STRINGFY_(s) #s -#define G_STRINGFY(s) G_STRINGFY_(s) -const char* WIFI_HOST_NAME = G_STRINGFY(M5S_WXBEACON2_WIFI_HOST_NAME); -#else -const char* WIFI_HOST_NAME = nullptr; -#endif +// For task settings. (piority low:0) +constexpr UBaseType_t advertisePriority = 2; +constexpr BaseType_t advertiseCore = 1; -// Client -WxBeacon2Client* wb2Client = nullptr; -NimBLEAddress wb2address; // detected wxbeacon2 address +constexpr UBaseType_t forecastPriority = 1; +constexpr BaseType_t forecastCore = 1; -/* - WxBeacon2Client with scoped - Call disconnect on destruct. -*/ -struct ScopedWB2Client -{ - ScopedWB2Client(WxBeacon2Client& client) : _client(client) {} - ~ScopedWB2Client() { _client.disconnect(); } - WxBeacon2Client& client() { return _client; } - private: - WxBeacon2Client& _client; -}; +constexpr UBaseType_t aqtalkPriority = 2; +constexpr BaseType_t aqtalkCore = 1; -/* - Change broadcast mode - @warning Changing to broadcast mode will not work with the WNI application. - @warning If you want to link with the WNI application, call the changeDefaultSetting function. - @warning If the beacon mode is changed, all data stored in WxBeacon2 will be lost. - */ -bool changeBeaconMode() -{ - if(!wb2Client) { WB2_LOGE("Client null"); return false; } - if((uint64_t)wb2address == 0) { WB2_LOGE("Address not yet obtained"); return false; } +constexpr UBaseType_t speakerPriority = 1; +constexpr BaseType_t speakerCore = 0; - ScopedWB2Client wb2(*wb2Client); +// +bool existsBeacon = false; +WxBeacon2::AdvertiseData advertiseData; +bool updatedAdvertise = false; - WB2_LOGI("connect to : %s", wb2address.toString().c_str()); - if(!wb2.client().isConnected() && !wb2.client().connect(wb2address)) - { - WB2_LOGE("Failed to connect"); - return false; - } +// +struct Weather +{ + jma::officecode_t oc; + jma::weathercode_t wc; + int8_t lowTemp, highTemp; - WxBeacon2::ADVSetting setting; - if(!wb2.client().getADVSetting(setting)) + String toString() const { - WB2_LOGE("Failed ti get setting"); - return false; + char buf[128]; + // low == temp means Iinvalid data.(The lowest highest temperature on the day of the announcement is invalid) + if(lowTemp != highTemp) + { + snprintf(buf, sizeof(buf), "[%s] %s %d℃/%d℃", + jma::officesCodeToString(oc), + jma::weatherCodeToString(wc), + lowTemp, highTemp); + } + else + { + snprintf(buf, sizeof(buf), "[%s] %s", + jma::officesCodeToString(oc), + jma::weatherCodeToString(wc)); + } + buf[sizeof(buf)-1] = '\0'; + return String(buf); } - setting._beaconMode = (uint8_t)WxBeacon2::BeaconMode::GeneralBroadcaster2; +}; +std::map > forecast; +OffsetDateTime requestDatetime; +bool updatedForecast = false; + +// Ticker text +PROGMEM const char DEFAULT_TICKER_TEXT[] = "WEATHEROID Type A Airi "; +PROGMEM const char NOTICE_TICKER_TEXT[] = "Press and hold C to put the WxBeacon2 into the broadcast mode. "; +PROGMEM const char NOT_EXISTS_BEACON_TICKER_TEXT[] = "WxBeacon2 IS NOT EXISTS. "; +PROGMEM const char REQUEST_TICKER_TITLE[] = "Request..."; +PROGMEM const char REQUEST_ADV_TICKER_TEXT[] = "Waiting receive Advertise. "; +PROGMEM const char REQUEST_FORECAST_TICKER_TEXT[] = "Waiting receive forecast. "; - if(wb2.client().setADVSetting(setting)) - { - return wb2.client().setMeasurementInterval(MEASUREMENT_INTERVAL_BROADCAST_SEC); - } - return false; +// Get std::string that formatted with args. +#if 0 +template std::string formatString(const char* fmt, Args... args) +{ + size_t sz = snprintf(nullptr, 0U, fmt, args...); // calculate length + char buf[sz + 1]; + snprintf(buf, sizeof(buf), fmt, args...); + return std::string(buf, buf + sz); } - -/* - Change default mode (for WNI Application) - @warning If the beacon mode is changed, all data stored in WxBeacon2 will be lost. - */ -bool changeDefaultSetting() +#else +std::string formatString(const char* fmt, ...) { - if(!wb2Client) { WB2_LOGE("Client null"); return false; } - if((uint64_t)wb2address == 0) { WB2_LOGE("Address not yet obtained"); return false; } - - ScopedWB2Client wb2(*wb2Client); - - WB2_LOGI("connect to : %s", wb2address.toString().c_str()); - if(!wb2.client().isConnected() && !wb2.client().connect(wb2address)) - { - WB2_LOGE("Failed to connect"); - return false; - } + va_list args; + va_start(args, fmt); - // Need set interval and time inforamtion, - if(wb2.client().setADVSetting(WxBeacon2::ADVSetting::DEFAULT_SETTING)) - { - delay(500); - std::tm t; - getLocalTime(&t); - if(wb2.client().setTimeInformation(t)) - { - delay(500); - return wb2.client().setMeasurementInterval(WxBeacon2::MeasurementInterval::DEFAULT_VALUE); - } - } - return false; + size_t sz = vsnprintf(nullptr, 0U, fmt, args); // calculate length + char buf[sz + 1]; + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + return std::string(buf, buf + sz); } +#endif -/* turnon LED 1 second */ -bool turnOnLED() +// Configurate Time by NTP. +void configTime() { - if(!wb2Client) { WB2_LOGE("Client null"); return false; } - if((uint64_t)wb2address == 0) { WB2_LOGE("Address not yet obtained"); return false; } - - ScopedWB2Client wb2(*wb2Client); - - WB2_LOGI("connect to : %s", wb2address.toString().c_str()); - if(!wb2.client().isConnected() && !wb2.client().connect(wb2address)) + // WiFi connect + WiFi.begin(); // Connect to credential in Hardware. (ESP32 saves the last Wifi connection) + int tcount = 20; + while(tcount-- > 0 && WiFi.status() != WL_CONNECTED) { - WB2_LOGE("Failed to connect"); - return false; + M5.Display.printf("."); + delay(500); } - return wb2.client().setLED(1); -} - -// -TaskHandle_t advertiseTask; -WxBeacon2::AdvertiseData advertiseData; -volatile bool updatedAdvertise = false; -volatile bool advertiseBusy = false; -time_t lastUpdate = -1; - -// Task of get advertise data from WxBeacon2. -void wb2_advertise_task(void*) -{ - NimBLEScan* scan = NimBLEDevice::getScan(); - WxBeacon2AdvertiseCallbacks cb; - scan->setAdvertisedDeviceCallbacks(&cb); - scan->setInterval(1000); - scan->setWindow(900); - scan->setActiveScan(true); - - for(;;) + if(WiFi.status() != WL_CONNECTED) { - ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); - - cb.clear(); - - WB2_LOGI("Start scanning"); - scan->start(60, false); - while(scan->isScanning()) { delay(100); } - WB2_LOGI("End of scanning. detected :%d", cb.detected()); - - if(cb.detected()) - { - wb2address = cb.address(); - advertiseData = cb.data(); - lastUpdate = time(nullptr); - if(TURNON_LED) { turnOnLED(); } - } - updatedAdvertise = cb.detected(); - advertiseBusy = false; - scan->clearResults(); + WB2_LOGE("Failed to connect WiFi"); + abort(); } -} -// Kick adverstise_task -void getAdvertiseAsync() -{ - if(!advertiseBusy) + auto ptz = goblib::datetime::locationToPOSIX(M5S_WXBEACON2_TIMEZONE_LOCATION); + WB2_LOGI("tz:[%s]", ptz ? ptz : "NONE"); + configTzTime(ptz ? ptz : "", ntpURL[0], ntpURL[1], ntpURL[2]); + // waiting for time synchronization { - advertiseBusy = true; - updatedAdvertise = false; - xTaskNotifyGive(advertiseTask); + std::tm discard{}; + getLocalTime(&discard, 5 * 1000); } + WiFi.disconnect(true); + WiFi.mode(WIFI_OFF); } -// Getting comms? -bool busyAdvertise() { return advertiseBusy; } - // -Avatar* avatar; -Ticker* ticker; -bool forceFace = true; // Force rendering of the face. +bool canRequest() { return (!busyAdvertise() && !jma::busyForecast()); } -// play voice +// Play advertise void playAdvertiseData(const WxBeacon2::AdvertiseData& data) { - if(data.format() != WxBeacon2::ADVFormat::E) - { - WB2_LOGE("Illegal format"); - return; - } + forceRender = true; + avatar->closeup(); + aq_talk::stopAquesTalk(); + auto de = data.getE(); - if(!de) + if(!existsBeacon || data.format() != WxBeacon2::ADVFormat::E || !de) { - WB2_LOGE("Failed to get E"); + ticker->setText(existsBeacon ? "ERROR" : NOT_EXISTS_BEACON_TICKER_TEXT); + ticker->setColor(Ticker::Color::Purple); return; } - auto s = formatString("kion do." - "situdo pa-sento." + auto vs = formatString("kion do." + "situdo pa-sento." "akarusa rukkusu." "yu-bui ." "kiatu hekutopasukaru." @@ -276,7 +197,7 @@ void playAdvertiseData(const WxBeacon2::AdvertiseData& data) "fukaisisu- ." "neccyu-syoukikendo " "desu." - , + , (float)de->temperature(), (float)de->relativeHumidity(), (int)de->ambientLight(), @@ -286,11 +207,10 @@ void playAdvertiseData(const WxBeacon2::AdvertiseData& data) (float)de->discomfortIndex(), (float)de->heatstroke() ); + aq_talk::playAquesTalk(vs.c_str(), 120); - WB2_LOGV("PLAY:[%s]", s.c_str()); - aq_talk::playAquesTalk(s.c_str(), 110); - - auto ts = formatString("TEMP %3.1fdegC HUM %3.1f%% AL %dlx UV %3.1f PRESURE %4.1fhPa N %3.1fdB DCMFT %3.1f WBGT %3.1f ", + // auto ts = formatString("TEMP %3.1fdegC HUM %3.1f%% AL %dlx UV %3.1f PRESURE %4.1fhPa N %3.1fdB DCMFT %3.1f WBGT %3.1f ", + auto ts = formatString("気温:%3.1f度 湿度:%3.1f%% 明度:%dlx UV指数:%3.1f 気圧:%4.1fhPa 騒音:%3.1fdB 不快指数:%3.1f WBGT:%3.1f ", (float)de->temperature(), (float)de->relativeHumidity(), (int)de->ambientLight(), @@ -300,113 +220,201 @@ void playAdvertiseData(const WxBeacon2::AdvertiseData& data) (float)de->discomfortIndex(), (float)de->heatstroke() ); - WB2_LOGV("TICKER:[%s]", s.c_str()); + ticker->setTitle("WxBeacon2"); + ticker->setLevelWBGT(de->heatstroke()); // Set telop color. ticker->setText(ts.c_str()); } -constexpr char DEFAULT_TICKER_TEXT[] = "WEATHEROID Type A Airi"; -constexpr char NOTICE_TICKER_TEXT[] = "Press and hold C to put the WxBeacon2 into the broadcast mode. "; -#if 0 -bool test_connect() +// Callback on get advertise. +void callbackOnAdvertise(const bool exists, const WxBeacon2::AdvertiseData& ad) { - if(!wb2Client) { WB2_LOGE("Client null"); return false; } - if((uint64_t)wb2address == 0) { WB2_LOGE("Address not yet obtained"); return false; } - - ScopedWB2Client wb2(*wb2Client); + existsBeacon = exists; + updatedAdvertise = true; + advertiseData = ad; +} - WB2_LOGI("connect to : %s", wb2address.toString().c_str()); - if(!wb2.client().isConnected() && !wb2.client().connect(wb2address)) +// Request advertise +void _requestAdvertise() +{ + if(canRequest()) { - WB2_LOGE("Failed to connect"); - return false; + lastUpdate = std::time(nullptr); + requestAdvertise(); + ticker->setTitle(REQUEST_TICKER_TITLE); + } + else + { + WB2_LOGI("Busy"); } - - std::string str; - auto b = wb2.client().getDeviceName(str); - printf("%d DeviceName:%s\n", b, str.c_str()); - - WxBeacon2::GenericAccesssService::Appearance app; - b = wb2.client().getAppearance(app); - printf("%d Appearnce:%x\n", b, app._category); - - WxBeacon2::GenericAccesssService::PeripheralPreferredConnectionParameters params; - b = wb2.client().getPeripheralPreferredConnectionParameters(params); - printf("%d params:%x/%x/%x/%x\n", b, - params._intervalMin, params._intervalMax, params._slaveLatency, params._timeout); - - b = wb2.client().getModelNumber(str); - printf("%d ModelNumber:[%s]\n", b, str.c_str()); - b = wb2.client().getSerialNumber(str); - printf("%d SerialNumber:[%s]\n", b, str.c_str()); - b = wb2.client().getFirmwareRevision(str); - printf("%d FirmRev:[%s]\n", b, str.c_str()); - b = wb2.client().getHardwareRevision(str); - printf("%d HardRev:[%s]\n", b, str.c_str()); - b = wb2.client().getManufacturerName(str); - printf("%d ManufacturerName:[%s]\n", b, str.c_str()); - - return true; } -bool test_getLatestPageData() +// Play forecast +void playForecast() { - if(advertiseData.format() == WxBeacon2::ADVFormat::E) { WB2_LOGE("Not recording mode"); return false; } - - if(!wb2Client) { WB2_LOGE("Client null"); return false; } - if((uint64_t)wb2address == 0) { WB2_LOGE("Address not yet obtained"); return false; } + forceRender = true; + avatar->wipe(72, 32, 0.30f, requestDatetime); + avatar->clearIcon(); - ScopedWB2Client wb2(*wb2Client); - - WB2_LOGI("connect to : %s", wb2address.toString().c_str()); - if(!wb2.client().isConnected() && !wb2.client().connect(wb2address)) + if(forecast.empty()) { - WB2_LOGE("Failed to connect"); - return false; + ticker->setTitle("ERROR"); + ticker->setColor(Ticker::Color::Purple); + ticker->setText(DEFAULT_TICKER_TEXT); + return; } - WxBeacon2::LatestPage lpage; - if(!wb2.client().getLatestPage(lpage)) { WB2_LOGE("Failed to get latest page"); return false; } - printf("Latest: %d,%d\n", lpage._page, lpage._row); + String ts; + ts.reserve(256); + auto vs = formatString("no/tenki'o/osirase'simasu ", + requestDatetime.month(), requestDatetime.day()); - int retryCount = 3; - WxBeacon2::ResponseFlag flag = { 2 }; - do + for(auto& e : forecast) // each date-time { - if(!wb2.client().requestPage(lpage._page, lpage._row)) { continue; } // request - for(;;) // get response flag + WB2_LOGV("%s:[%s] %zu", requestDatetime.toString().c_str(), e.first.toString().c_str(), e.second.size()); + + if(e.first.toLocalDate() != requestDatetime.toLocalDate()) { continue; } // Skip data. + + auto wv = e.second; + std::sort(wv.begin(), wv.end(), [](const Weather& a, const Weather& b) { return a.oc < b.oc; }); // Ascend officecode_t + for(auto& w : wv) { - wb2.client().getResponseFlag(flag); - if((int)flag._updateFlag != 0) { break; } - delay(10); + ts += w.toString() + ' '; + vs += formatString("%s %s #", aq_talk::officeCodeToTalk(w.oc), aq_talk::weatherCodeToTalk(w.wc)); + + avatar->addIcon(w.oc, w.wc); } - }while((int)flag._updateFlag == 2 && retryCount--); - if((int)flag._updateFlag != 1) { WB2_LOGE("Failed to request or get response"); return false; } + ts += " "; + } + aq_talk::playAquesTalk(vs.c_str(), 110); - int cnt = lpage._row + 1; - while(cnt--) + ticker->setTitle("Weather"); + ticker->setText(ts.c_str()); + ticker->setColor(Ticker::Color::Green); +} + +// Callback on get forecast. +void callbackOnForecast(const jma::officecode_t oc, const jma::Forecast& fc, const jma::WeeklyForecast& wfc) +{ + if(oc == 0) { updatedForecast = true; return; } + + if(fc.existsTopWeatherCodes() && fc.existsTopTemp()) + { + auto& wcodes = fc.TopWeatherCodes(); + auto& timedef = fc.TopWeatherTime(); + auto& temps = fc.TopTemp(); + auto& timedefTemps = fc.TopTempTime(); + assert(wcodes.size() == timedef.size()); + assert(temps.size() == timedefTemps.size()); + + WB2_LOGV("wcodes:%zu temps:%zu", wcodes.size(), temps.size()); + + for(uint8_t i = 0; i < wcodes.size(); ++i) + { + Weather weather { oc, wcodes[i], 0, 0 }; + + auto odt = timedef[i]; + auto& v = forecast[odt]; // create if empty. + + auto it = std::find_if(timedefTemps.begin(), timedefTemps.end(), + [&odt](const OffsetDateTime& odtTemps) + { + return odt.toLocalDate() == odtTemps.toLocalDate(); + }); + auto idx = std::distance(timedefTemps.begin(), it); + // Store low/high temps if exists. + if(idx < timedefTemps.size()) + { + weather.lowTemp = temps[idx]; + weather.highTemp = temps[idx+1]; + } + v.push_back(weather); + WB2_LOGV("%s:%u:%u %d/%d", odt.toString().c_str(), weather.oc, weather.wc, weather.lowTemp, weather.highTemp); + } + } + else { - WxBeacon2::ResponseData data; - if(!wb2.client().getResponseData(data)) { WB2_LOGE("Failed to get response data"); return false; } - time_t t = flag._time32 + lpage._interval * data._data._row; - auto lt = std::localtime(&t); - printf("DATA: row:%02d time:%4d/%02d/%02d %02d:%02d:%02d\n", - data._data._row, - lt->tm_year + 1900, - lt->tm_mon + 1, - lt->tm_mday, - lt->tm_hour, - lt->tm_min, - lt->tm_sec); + WB2_LOGD("Failed %d/%d",fc.existsTopWeatherCodes(),fc.existsTopTemp()); } - return true; } + +// Request forecast +void _requestForecast() +{ + if(canRequest()) + { +#if 0 + // TEST + lastUpdate = std::time(nullptr); + forecast.clear(); + OffsetDateTime odt = OffsetDateTime::now(); + requestDatetime = odt; + const jma::officecode_t requestTable[] = + { + 16000, // Sapporo + 40000, // Sendai + 130000, // Tokyo + 150000, // Niigata + 170000, // Kanazawa + 230000, // Nagoya + 270000, // Oosaka + 340000, // Hiroshima + 390000, // Kochi + 400000, // Fukuoka + 471000, // Okinawa + }; + + auto& wv = forecast[odt]; + jma::weathercode_t wc = 200; + for(auto& e : requestTable) + { + wv.push_back({e, wc++, -12, 38}); + } + updatedForecast = true; + return; #endif + + lastUpdate = std::time(nullptr); + forecast.clear(); + requestDatetime = OffsetDateTime::now(); +#if 0 + auto ldt = requestDatetime.toLocalDateTime(); + ldt = goblib::datetime::LocalDateTime::of(ldt.year(), ldt.month(), ldt.day() + 1, ldt.hour(), ldt.minute(), ldt.second()); + requestDatetime = OffsetDateTime::of(ldt, requestDatetime.offset()); +#endif + jma::requestForecast(); + + ticker->setTitle(REQUEST_TICKER_TITLE); + } + else + { + WB2_LOGI("Busy"); + } +} + +void callbackOnEndAqTalk() +{ + voiceEnd = std::time(nullptr); +} + +PROGMEM static const char t0[] = "minnasa--n,ponnbanwa,weza-roido'taipuei,airi'desu"; +PROGMEM static const char t1[] = "konsyu-no/saikaiwa,'kaniza"; +PROGMEM static const char t2[] = "weza-roido'una'na-i wa arimasen"; +const char* talkTable[] = { t0, t1, t2 }; +void talkRandom() +{ + auto idx = esp_random() % (sizeof(talkTable)/sizeof(talkTable[0])); + aq_talk::playAquesTalk(talkTable[idx], 110); +} // } +// Setup void setup() { + WB2_LOGI("Top of setup free:%u internal:%u", esp_get_free_heap_size(), esp_get_free_internal_heap_size()); + WB2_LOGI("PSRAM:size:%u free:%u", ESP.getPsramSize(), ESP.getFreePsram()); + // log level esp_log_level_set("wifi", (esp_log_level_t)0); esp_log_level_set("NimBLE", (esp_log_level_t)0); @@ -414,142 +422,100 @@ void setup() esp_log_level_set("NimBLEDevice", (esp_log_level_t)0); esp_log_level_set("NIMBLE_NVS", (esp_log_level_t)0); + // Incrase heap + esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); + // - M5.begin(); + M5.begin(); auto bd = M5.getBoard(); - WB2_LOGV("board : %x", bd); // 2:M5Stack Basic/Gray 3:Core2 - - auto scfg = M5.Speaker.config(); - scfg.task_priority = 2; - scfg.task_pinned_core = 0; - M5.Speaker.config(scfg); - M5.Speaker.begin(); - M5.Speaker.setVolume(bd == m5::board_t::board_M5Stack ? 128 : 64); - delay(500); - + WB2_LOGI("M5.board : %x", bd); // 2:M5Stack Basic/Gray 3:Core2 if (M5.Display.width() < M5.Display.height()) { M5.Display.setRotation(M5.Display.getRotation() ^ 1); } - M5.Display.setBrightness(30); - M5.Display.clear(); - - M5.Display.fillScreen(TFT_DARKGREY); - M5.Display.setCursor(0,0); - M5.Display.printf("Wifi Connect"); - if(WIFI_HOST_NAME && WIFI_HOST_NAME[0]) - { - WiFi.setHostname(WIFI_HOST_NAME); - } - - // WiFi connect - WiFi.begin(); // Connect to credential in Hardware. (ESP32 saves the last Wifi connection) - int tcount = 10; - while(tcount-- > 0 && WiFi.status() != WL_CONNECTED) - { - delay(500); - M5.Display.printf("."); - } - if(WiFi.status() != WL_CONNECTED) - { - WB2_LOGE("Failed to connect WiFi"); - abort(); - } + auto scfg = M5.Speaker.config(); + scfg.task_priority = speakerPriority; + scfg.task_pinned_core = speakerCore; + M5.Speaker.config(scfg); + M5.Speaker.begin(); + //M5.Speaker.setVolume(bd == m5::board_t::board_M5Stack ? 128 : 64); + M5.Speaker.setVolume(bd == m5::board_t::board_M5Stack ? 80 : 40); - // Configurate local time. - M5.Display.setCursor(0,0); - M5.Display.printf("Configurate time"); + delay(500); + M5.Display.setBrightness(40); + M5.Display.clear(); - configTime(gmtOffsetSec, daylightOffsetSec, ntpURL[0]); - std::tm t; - if(getLocalTime(&t)) - { - WB2_LOGI("Configurate time : %4d/%02d/%02d (%d) %02d:%02d:%02d", - t.tm_year + 1900, - t.tm_mon + 1, - t.tm_mday, - t.tm_wday, - t.tm_hour, - t.tm_min, - t.tm_sec); - } - WiFi.disconnect(true); - WiFi.mode(WIFI_OFF); - - M5.Display.fillScreen(TFT_DARKGREEN); - - // BLE - NimBLEDevice::init(""); - xTaskCreateUniversal(wb2_advertise_task, "advertise_task", 8192, nullptr, 1, &advertiseTask, 1); - assert(advertiseTask); - - // get advertise from WxBeacon2 - auto ret = aq_talk::setup(); - WB2_LOGD("aq_talk::setup : %d", ret); + // Avatar and ticker avatar = new Avatar(); assert(avatar); - ticker = new Ticker(); assert(ticker); ticker->setText(DEFAULT_TICKER_TEXT); - wb2Client = new WxBeacon2Client(); - assert(wb2Client); + // ConfigTime + configTime(); + M5.Display.fillScreen(TFT_DARKGREEN); + + // WxBeacon2 / Forecast + initilizeAdvertise(advertisePriority, advertiseCore, callbackOnAdvertise); + jma::initializeForecast(forecastPriority,forecastCore, callbackOnForecast); - getAdvertiseAsync(); - while(busyAdvertise()) { delay(100); } - if(!updatedAdvertise) - { - WB2_LOGE("Not detected WxBeacon2"); - abort(); - } - if(updatedAdvertise && advertiseData.format() != WxBeacon2::ADVFormat::E) + // AquesTalk + auto ret = aq_talk::initialize(aqtalkPriority, aqtalkCore, callbackOnEndAqTalk); + WB2_LOGD("aq_talk::setup : %d", ret); + + // Get advertise from WxBeacon2. + _requestAdvertise(); + + // { - WB2_LOGE("WxBeacon2 beacon mode is not broadcast2"); - ticker->setLevel(Ticker::Level::Purple); - ticker->setText(NOTICE_TICKER_TEXT); - + goblib::datetime::LocalDateTime ldt = goblib::datetime::LocalDateTime::now(); + WB2_LOGI("Configurated time : %s (%s)", ldt.toString().c_str(), M5S_WXBEACON2_TIMEZONE_LOCATION); + WB2_LOGI("End of setup free:%u internal:%u large:%u large internal:%u", + esp_get_free_heap_size(), esp_get_free_internal_heap_size(), + heap_caps_get_largest_free_block(MALLOC_CAP_DMA), + heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL)); + WB2_LOGI("PSRAM:size:%u free:%u", ESP.getPsramSize(), ESP.getFreePsram()); + WB2_LOGI("ESP-IDF Version %d.%d.%d", + (ESP_IDF_VERSION>>16) & 0xFF, (ESP_IDF_VERSION>>8)&0xFF, ESP_IDF_VERSION & 0xFF); } - - auto mem = esp_get_free_heap_size(); - WB2_LOGV("end of setup %u", mem); + M5.Display.startWrite(); // Occupy DMA Bus + + cpu_usage::initialize(); } namespace { - bool longPressA, longPressB,longPressC; +bool longPressA{false}, longPressB{false},longPressC{false}; } +// Main loop void loop() { + auto start = millis(); M5.update(); // WARNING : If the beacon mode is changed, all data stored in WxBeacon2 will be lost. + // WARNING : After the mode change, Abort system. /* C button - long press : Set beacon mode to GeneralBroadcaster2 (for me) + long press : Set beacon mode to GeneralBroadcaster2 for this application. press : show/hide ticker */ - if(!longPressC && M5.BtnC.pressedFor(1000)) + if(!longPressC && M5.BtnC.pressedFor(1000) && canRequest()) { longPressC = true; WB2_LOGI("Set beacon mode to broadcast mode"); auto b = changeBeaconMode(); - if(b) - { - ticker->setLevel(Ticker::Level::Blue); - ticker->setText(DEFAULT_TICKER_TEXT); - ticker->show(true); - getAdvertiseAsync(); - } - WB2_LOGI("result : %d", b); + WB2_LOGI("Result : %d", b); + abort(); } if(M5.BtnC.wasReleased()) { if(!longPressC) { ticker->show(!ticker->isShow()); - forceFace = true; + forceRender = true; } longPressC = false; } @@ -559,83 +525,106 @@ void loop() long press : Set default setting for WNI aplication. press : (none) */ - if(!longPressB && M5.BtnB.pressedFor(1000)) + if(!longPressB && M5.BtnB.pressedFor(1000) && canRequest()) { longPressB = true; - WB2_LOGI("Set default settins"); + WB2_LOGI("Set default settings"); aq_talk::stopAquesTalk(); auto b = changeDefaultSetting(); - if(b) - { - ticker->setLevel(Ticker::Level::Purple); - ticker->setText(NOTICE_TICKER_TEXT); - ticker->show(true); - } - WB2_LOGI("result : %d", b); + WB2_LOGI("Result : %d", b); + abort(); } if(M5.BtnB.wasReleased()) { if(!longPressB) { - // test_connect(); - // test_getLatestPageData(); - #if 0 - // TEST - auto lv = ticker->level() + 1; - if(lv > 3) { lv = 0; } - ticker->setLevel((Ticker::Level)lv); - #endif + // nop } longPressB = false; } /* A button - long press : (none) - press : Obtain data force. + long press : Obtain forecast force. + press : Obtain beacon datat force. */ if(!longPressA && M5.BtnA.pressedFor(1000)) { longPressA = true; + _requestForecast(); } if(M5.BtnA.wasReleased()) { if(!longPressA) { - if(!busyAdvertise()) - { - aq_talk::stopAquesTalk(); - getAdvertiseAsync(); - } + _requestAdvertise(); } longPressA = false; } - // Obtain data at intervals. time_t t = time(nullptr); - if(!busyAdvertise() && lastUpdate > 0 && std::difftime(t, lastUpdate) >= TALKING_INTERVAL_SEC) + +#if 0 + // Obtain beaocn data at intervals. + + if(canRequest() && lastUpdate > 0 && std::difftime(t, lastUpdate) >= AUTO_REQUEST_ADVERTISE_INTERVAL_SEC) { - getAdvertiseAsync(); + _requestAdvertise(); } +#endif + // Random talking + if(!aq_talk::busy() && voiceEnd > 0 && std::difftime(t, voiceEnd) >= 60) + { + talkRandom(); + } + // Play latest advertise data if exists. if(updatedAdvertise) { updatedAdvertise = false; playAdvertiseData(advertiseData); - auto de = advertiseData.getE(); - if(de) { ticker->setLevelWBGT(de->heatstroke()); } } - // + // Play latest forecast + if(updatedForecast) + { + updatedForecast = false; + playForecast(); + } + + // Update avatar->pump(); ticker->pump(); - M5.Display.startWrite(); // Occupy DMA Bus - avatar->render(&M5.Display, forceFace); forceFace = false; - ticker->render(&M5.Display); - M5.Display.endWrite(); // Do render to display + // Rendering + { + avatar->render(&M5.Display, forceRender); forceRender = false; + ticker->render(&M5.Display); - delay(1000/30); // Keep about 30 FPS -} +#if 0 + M5.Display.setCursor(128, 120); + M5.Display.printf("a:%d f:%d aq:%d s:%d", + busyAdvertise(), jma::busyForecast(), aq_talk::busy(), M5.Speaker.isPlaying()); + M5.Display.setCursor(128, 128); + M5.Display.printf("ih:%06u ilf:%06u", + esp_get_free_internal_heap_size(), + heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL)); + M5.Display.setCursor(128, 136); + M5.Display.printf("c0:%03.1f c1:%03.1f", cpu_usage::cpu0(), cpu_usage::cpu1()); + cpu_usage::reset(); + +#endif + } + // Keep about 30 FPS. + auto end = millis(); +#if 0 + if((end - start) >= (1000/30)) + { + WB2_LOGD("over:%lu", (end - start) - (1000/30)); + } +#endif + + delay((end - start) >= (1000/30) ? 1 : (1000/30) - (end -start)); +} diff --git a/src/ponko_avatar.cpp b/src/ponko_avatar.cpp index 127b7c8..f90b95f 100644 --- a/src/ponko_avatar.cpp +++ b/src/ponko_avatar.cpp @@ -4,50 +4,161 @@ #include "ponko_avatar.hpp" #include "aq_talk.hpp" #include "res/resource.h" +#include "wb2/wxbeacon2_log.hpp" +#include #include +namespace +{ +struct Pos { uint8_t x, y; }; // Half of actual position. +PROGMEM const Pos ocPos[] = { + { 120, 8 }, // sap + { 136, 40 }, // sen + { 128, 72 }, // tok + { 104, 32 }, // nii + { 88, 48 }, // kan + { 104, 80 }, // nag + { 80, 72 }, // osa + { 48, 64 }, // hir + { 48, 84 }, // kou + { 16, 56 }, // fuk + { 8, 32 } // nah +}; +std::map positionTable = +{ + { 16000, &ocPos[0] }, + { 40000, &ocPos[1] }, + { 130000, &ocPos[2] }, + { 150000, &ocPos[3] }, + { 170000, &ocPos[4] }, + { 230000, &ocPos[5] }, + { 270000, &ocPos[6] }, + { 340000, &ocPos[7] }, + { 390000, &ocPos[8] }, + { 400000, &ocPos[9] }, + { 471000, &ocPos[10] }, +}; + +#if 0 +std::map pngTable = +{ + { 100, w100_png }, + { 101, w101_png }, + { 102, w102_png }, + { 104, w104_png }, + { 110, w110_png }, + { 112, w112_png }, + { 115, w115_png }, + { 200, w200_png }, + { 201, w201_png }, + { 202, w202_png }, + { 204, w204_png }, + { 210, w210_png }, + { 212, w212_png }, + { 215, w215_png }, + { 300, w300_png }, + { 301, w301_png }, + { 302, w302_png }, + { 303, w303_png }, + { 311, w311_png }, + { 313, w313_png }, + { 314, w314_png }, + { 400, w400_png }, + { 401, w401_png }, + { 402, w402_png }, + { 403, w403_png }, + { 411, w411_png }, + { 413, w413_png }, + { 414, w414_png }, +}; +#else +struct Png { const uint8_t* p; const size_t sz; }; +std::map pngTable = +{ + { 100, { w100_png, w100_png_len } }, + { 101, { w101_png, w101_png_len } }, + { 102, { w102_png, w102_png_len } }, + { 104, { w104_png, w104_png_len } }, + { 110, { w110_png, w110_png_len } }, + { 112, { w112_png, w112_png_len } }, + { 115, { w115_png, w115_png_len } }, + { 200, { w200_png, w200_png_len } }, + { 201, { w201_png, w201_png_len } }, + { 202, { w202_png, w202_png_len } }, + { 204, { w204_png, w204_png_len } }, + { 210, { w210_png, w210_png_len } }, + { 212, { w212_png, w212_png_len } }, + { 215, { w215_png, w215_png_len } }, + { 300, { w300_png, w300_png_len } }, + { 301, { w301_png, w301_png_len } }, + { 302, { w302_png, w302_png_len } }, + { 303, { w303_png, w303_png_len } }, + { 311, { w311_png, w311_png_len } }, + { 313, { w313_png, w313_png_len } }, + { 314, { w314_png, w314_png_len } }, + { 400, { w400_png, w400_png_len } }, + { 401, { w401_png, w401_png_len } }, + { 402, { w402_png, w402_png_len } }, + { 403, { w403_png, w403_png_len } }, + { 411, { w411_png, w411_png_len } }, + { 413, { w413_png, w413_png_len } }, + { 414, { w414_png, w414_png_len } }, +}; +#endif + + +constexpr uint32_t MAP_FCLR = ::lgfx::color888( 16, 136, 88); // palette 1 +constexpr uint32_t MAP_BCLR = ::lgfx::color888( 0, 80, 160); // palette 0 + +// WARNING : Keep largets free heap 50K for decode PNG. +void drawWeatherIcon(m5gfx::M5GFX* dst, jma::officecode_t oc, jma::weathercode_t wc) +{ + auto ic = jma::weatherCodeToIcon(wc); + if(!ic || pngTable.count(ic) == 0 || positionTable.count(oc) == 0) { return; } + + auto png = pngTable.at(ic); + auto pos = positionTable.at(oc); + WB2_LOGD("%d:%d:%d %zu", oc, wc, ic, png.sz); + auto ret = dst->drawPng(png.p, (uint32_t)png.sz, pos->x * 2, pos->y * 2); + if(ret == 0) { WB2_LOGV("mem:%u", esp_get_free_internal_heap_size()); } +} + +void drawFace(m5gfx::M5GFX* dst, int16_t x, int16_t y, float zoom = 1.0f) +{ + dst->drawBmp(ponko_face_bmp, -1, x, y, 0, 0, 0, 0, zoom, zoom); +} + +// +} Avatar::Avatar() - : _face(nullptr) - , _offMouth(nullptr) + : _offMouth(nullptr) , _mouth{nullptr,nullptr} , _mouthRatio(0) , _lastMouthRatio(0) + , _wipe(false) + , _wipeX(0) + , _wipeY(0) + , _iconInfo(11) { - _face = new gob::Sprite(); - assert(_face && "_face is nullptr"); - _face->createFromBmp(ponko_face_bmp, ponko_face_bmp_len); - + // close auto mc = new LGFX_Sprite(); assert(mc && "mc is nullptr"); mc->createFromBmp(ponko_mouth_close_bmp, ponko_mouth_close_bmp_len); _mouth[Close] = mc; + mc->setPivot(mc->width() * 0.5f + 0.5f, 0); // center,top + // open auto mo = new LGFX_Sprite(); assert(mo && "mo is nullptr"); mo->createFromBmp(ponko_mouth_open_bmp, ponko_mouth_open_bmp_len); - mo->setPivot(mo->width()/2, 0); - + mo->setPivot(mo->width() * 0.5f + 0.5f, 0); // center,top _mouth[Open] = mo; // offscreen for mouth _offMouth= new LGFX_Sprite(); assert(_offMouth && "_offMouth is nullptr"); - _offMouth->createFromBmp(ponko_mouth_open_bmp, ponko_mouth_open_bmp_len); // same as mouth open/close bitmap palette and width/height - - // check - assert(mc->width() == mo->width() && "different widths"); - assert(mc->height() == mo->height() && "different heights"); - assert(_offMouth->width() == mo->width() && "different widths"); - assert(_offMouth->height() == mo->height() && "different heights"); - - assert(_face->getPaletteCount() == 16 && "not 4bpp"); - assert(mc->getPaletteCount() == 16 && "not 4bpp"); - assert(mo->getPaletteCount() == 16 && "not 4bpp"); - assert(_offMouth->getPaletteCount() == 16 && "not 4bpp"); - - assert(memcmp(_face->getPalette(), mc->getPalette(), sizeof(RGBColor) * 16) == 0 && "diffrent palettes"); - assert(memcmp(mc->getPalette(), mo->getPalette(), sizeof(RGBColor) * 16) == 0 && "diffrent palettes"); - assert(memcmp(mo->getPalette(), _offMouth->getPalette(), sizeof(RGBColor) * 16) == 0 && "diffrent palettes"); + _offMouth->createFromBmp(ponko_mouth_open_bmp, ponko_mouth_open_bmp_len); // same as open + _offMouth->setPivot(_offMouth->width() * 0.5f + 0.5f, _offMouth->height() * 0.5f + 0.5f); // center } Avatar::~Avatar() @@ -55,7 +166,6 @@ Avatar::~Avatar() delete _offMouth; delete _mouth[Open]; delete _mouth[Close]; - delete _face; } void Avatar::pump() @@ -65,7 +175,6 @@ void Avatar::pump() _lastMouthRatio = _mouthRatio = 0.0f; return; } - auto gain = aq_talk::getGain(); float f = gain / 12000.0f; @@ -75,12 +184,16 @@ void Avatar::pump() _mouthRatio = ratio; } -void Avatar::render(m5gfx::M5GFX* dst, bool forceFace) +void Avatar::renderCloseup(m5gfx::M5GFX* dst, bool forceRender) { - if(forceFace) { _face->pushSprite(dst, 0, 0); } - - _offMouth->clear(); - _face->pushPartial(_offMouth, 0, 0, MOUTH_WIDTH, MOUTH_HEIGHT, MOUTH_X, MOUTH_Y); + if(forceRender) { drawFace(dst, 0, 0); } + + _offMouth->drawBmp(ponko_face_bmp, -1, 0, 0, _offMouth->width(), _offMouth->height(), MOUTH_X, MOUTH_Y); + if(_mouthRatio > 1.0f) + { + printf("%s:%f\n", __func__, _mouthRatio); + } + if(_mouthRatio != 0.0f) { auto s = _mouth[Open]; @@ -98,3 +211,48 @@ void Avatar::render(m5gfx::M5GFX* dst, bool forceFace) } _offMouth->pushSprite(dst, MOUTH_X, MOUTH_Y); } + +void Avatar::renderWipe(m5gfx::M5GFX* dst, bool forceRender) +{ + if(forceRender) + { + dst->drawBmp(jpmap_bmp, -1, 0, 0, 0, 0, 0, 0, 2.0f, 2.0f); // map + + for(auto& e : _iconInfo) + { + drawWeatherIcon(dst, e.oc, e.wc); + } + + auto ofont = dst->getFont(); + dst->setFont(&tickerFont); + dst->setTextColor(TFT_WHITE); + dst->setCursor(8,8); + dst->printf("%sの天気", _odt.toLocalDate().toString("%m/%d").c_str()); + dst->setFont(ofont); + dst->setTextColor(TFT_WHITE, TFT_BLACK); + + drawFace(dst, _wipeX, _wipeY, _wipeScale); + dst->drawRect(_wipeX, _wipeY, 320 * _wipeScale, 240 * _wipeScale, TFT_WHITE); + } + + _offMouth->drawBmp(ponko_face_bmp, -1, 0, 0, _offMouth->width(), _offMouth->height(), MOUTH_X, MOUTH_Y); + if(_mouthRatio != 0.0f) + { + auto s = _mouth[Open]; + s->pushRotateZoom(_offMouth, + 0 + s->width() * (s->getPivotX() / s->width()), + 0 + s->height() * (s->getPivotY() / s->height()), + 0.0f, 1.0f, _mouthRatio, + 0); + + } + else + { + auto s = _mouth[Close]; + s->pushSprite(_offMouth, 0, 0, 0); + } + _offMouth->pushRotateZoom(dst, + _wipeX + MOUTH_X * _wipeScale + _offMouth->getPivotX() * _wipeScale, + _wipeY + MOUTH_Y * _wipeScale + _offMouth->getPivotY() * _wipeScale, + 0.0f, _wipeScale, _wipeScale, 0); +} diff --git a/src/ponko_avatar.hpp b/src/ponko_avatar.hpp index b0f582d..7b07ea2 100644 --- a/src/ponko_avatar.hpp +++ b/src/ponko_avatar.hpp @@ -5,27 +5,54 @@ #define PONKO_AVATAR_HPP #include -#include "gob_sprite.hpp" +#include"jma/jma_definition.hpp" +#include +#include class Avatar { public: + struct IconInfo { jma::officecode_t oc; jma::weathercode_t wc; }; + Avatar(); virtual ~Avatar(); void pump(); - void render(m5gfx::M5GFX* dst, bool forceFace = false); + void render(m5gfx::M5GFX* dst, const bool forceRender = false) + { + _wipe ? renderWipe(dst, forceRender) : renderCloseup(dst, forceRender); + } + // Change rendering type. + void closeup() { _wipe = false; } + void wipe(const int16_t x, const int16_t y, const float scale, const goblib::datetime::OffsetDateTime& odt) + { + _wipe = true; _wipeX = x; _wipeY = y; _wipeScale = scale; _odt = odt; + } + void clearIcon() { _iconInfo.clear(); } + void addIcon(const jma::officecode_t oc, const jma::weathercode_t wc) + { + _iconInfo.push_back(IconInfo{oc, wc}); + } + constexpr static int16_t MOUTH_X = 136; constexpr static int16_t MOUTH_Y = 168; constexpr static int16_t MOUTH_WIDTH = 48; constexpr static int16_t MOUTH_HEIGHT = 32; private: - enum {Close, Open, Max }; - gob::Sprite* _face; + void renderCloseup(m5gfx::M5GFX* dst, bool forceRender = false); + void renderWipe(m5gfx::M5GFX* dst, bool forceRender = false); + + enum : uint8_t {Close, Open, Max }; LGFX_Sprite* _offMouth; LGFX_Sprite* _mouth[Max]; float _mouthRatio, _lastMouthRatio; + bool _wipe; + float _wipeScale; + int16_t _wipeX, _wipeY; + goblib::datetime::OffsetDateTime _odt; + + std::vector _iconInfo; }; #endif diff --git a/src/res/resource.h b/src/res/resource.h index 04e23ff..fb850af 100644 --- a/src/res/resource.h +++ b/src/res/resource.h @@ -1,23 +1,115 @@ -#ifndef RESOURCE_HPP -#define RESOURCE_HPP +#ifndef RESOURCE_H +#define RESOURCE_H +#include #include #include /* WARNING : face, close, and open image must have the same palettes, and palette index 0 must be a transparent color. */ -// face 4bpp +// face 4bpp bmp3 extern const uint8_t ponko_face_bmp[]; extern const size_t ponko_face_bmp_len; -// mouth(close) 4bpp +// mouth(close) 4bpp bmp3 extern const uint8_t ponko_mouth_close_bmp[]; extern const size_t ponko_mouth_close_bmp_len; -// mouth(open)4bpp +// mouth(open) 4bpp bmp3 extern const uint8_t ponko_mouth_open_bmp[]; extern const size_t ponko_mouth_open_bmp_len; -// WARNING : 1bpp palette 0 is background, 1 is foreground +// 1bpp bmp3 palette 0 is background, 1 is foreground extern const uint8_t logo_bmp[]; extern const size_t logo_bmp_len; +extern const uint8_t jpmap_bmp[]; +extern const size_t jpmap_bmp_len; + +// Text font +extern const lgfx::U8g2font titleFont; +extern const lgfx::U8g2font tickerFont; + +// Weather icon 2bpp png +extern const uint8_t w100_png[]; +extern const size_t w100_png_len; + +extern const uint8_t w101_png[]; +extern const size_t w101_png_len; + +extern const uint8_t w102_png[]; +extern const size_t w102_png_len; + +extern const uint8_t w104_png[]; +extern const size_t w104_png_len; + +extern const uint8_t w110_png[]; +extern const size_t w110_png_len; + +extern const uint8_t w112_png[]; +extern const size_t w112_png_len; + +extern const uint8_t w115_png[]; +extern const size_t w115_png_len; + +extern const uint8_t w200_png[]; +extern const size_t w200_png_len; + +extern const uint8_t w201_png[]; +extern const size_t w201_png_len; + +extern const uint8_t w202_png[]; +extern const size_t w202_png_len; + +extern const uint8_t w204_png[]; +extern const size_t w204_png_len; + +extern const uint8_t w210_png[]; +extern const size_t w210_png_len; + +extern const uint8_t w212_png[]; +extern const size_t w212_png_len; + +extern const uint8_t w215_png[]; +extern const size_t w215_png_len; + +extern const uint8_t w300_png[]; +extern const size_t w300_png_len; + +extern const uint8_t w301_png[]; +extern const size_t w301_png_len; + +extern const uint8_t w302_png[]; +extern const size_t w302_png_len; + +extern const uint8_t w303_png[]; +extern const size_t w303_png_len; + +extern const uint8_t w311_png[]; +extern const size_t w311_png_len; + +extern const uint8_t w313_png[]; +extern const size_t w313_png_len; + +extern const uint8_t w314_png[]; +extern const size_t w314_png_len; + +extern const uint8_t w400_png[]; +extern const size_t w400_png_len; + +extern const uint8_t w401_png[]; +extern const size_t w401_png_len; + +extern const uint8_t w402_png[]; +extern const size_t w402_png_len; + +extern const uint8_t w403_png[]; +extern const size_t w403_png_len; + +extern const uint8_t w411_png[]; +extern const size_t w411_png_len; + +extern const uint8_t w413_png[]; +extern const size_t w413_png_len; + +extern const uint8_t w414_png[]; +extern const size_t w414_png_len; #endif diff --git a/src/u8g2_font_profont22_tr.cpp b/src/u8g2_font_profont22_tr.cpp index d2b6bcc..e1bdbe4 100644 --- a/src/u8g2_font_profont22_tr.cpp +++ b/src/u8g2_font_profont22_tr.cpp @@ -21,8 +21,9 @@ THE SOFTWARE. */ #include "u8g2_font_profont22_tr.h" +#include -const uint8_t u8g2_font_profont22_tr[1704] = +PROGMEM const uint8_t u8g2_font_profont22_tr[1704] = "`\0\4\4\4\5\4\5\5\14\26\0\374\16\374\20\376\2N\4\177\6\213 \5\0\20r!\11\342\30" "rxP\210\0\42\11fTs\20BO\4#\25\252\220r\221H\210\220\7E$\22\42\344A\21\211" "\204\10\1$$*\321q\22(\314\14\212\21\42\212\10!\42h\204\250C\247D\14\22BDH\11\21" diff --git a/src/wxbeacon2.cpp b/src/wb2/wxbeacon2.cpp similarity index 92% rename from src/wxbeacon2.cpp rename to src/wb2/wxbeacon2.cpp index 3bbc30f..5f0af4b 100644 --- a/src/wxbeacon2.cpp +++ b/src/wb2/wxbeacon2.cpp @@ -9,12 +9,12 @@ namespace { -template struct is_stdarray :std::false_type {}; -template struct is_stdarray> : std::true_type {}; +template struct is_std_array :std::false_type {}; +template struct is_std_array> : std::true_type {}; template bool string2array(T& a, const std::string& v) { - static_assert(is_stdarray::value, "T must be std::array"); + static_assert(is_std_array::value, "T must be std::array"); a = {}; if(a.empty() || v.empty() || v.length() == 0) { return false; } @@ -26,9 +26,7 @@ template bool string2array(T& a, const std::string& v) bool toLocalTime(std::tm& t, time_t tt) { t = std::tm{}; - std::tm* lt = std::localtime(&tt); - if(lt) { t = *lt; } - return lt; + return localtime_r(&tt, &t) != nullptr; } // diff --git a/src/wxbeacon2.hpp b/src/wb2/wxbeacon2.hpp similarity index 99% rename from src/wxbeacon2.hpp rename to src/wb2/wxbeacon2.hpp index 5ec8bb9..cee1a9f 100644 --- a/src/wxbeacon2.hpp +++ b/src/wb2/wxbeacon2.hpp @@ -43,7 +43,7 @@ class WxBeacon2 }; constexpr static bool validBeaconMode(const BeaconMode bm) { - return (const uint8_t)bm <= (const uint8_t)BeaconMode::EventBeaconADV && bm != BeaconMode::Unused0; + return (uint8_t)bm <= (uint8_t)BeaconMode::EventBeaconADV && bm != BeaconMode::Unused0; } /*! diff --git a/src/wxbeacon2_ble.cpp b/src/wb2/wxbeacon2_ble.cpp similarity index 100% rename from src/wxbeacon2_ble.cpp rename to src/wb2/wxbeacon2_ble.cpp diff --git a/src/wxbeacon2_ble.hpp b/src/wb2/wxbeacon2_ble.hpp similarity index 100% rename from src/wxbeacon2_ble.hpp rename to src/wb2/wxbeacon2_ble.hpp diff --git a/src/wb2/wxbeacon2_communication.cpp b/src/wb2/wxbeacon2_communication.cpp new file mode 100644 index 0000000..112a441 --- /dev/null +++ b/src/wb2/wxbeacon2_communication.cpp @@ -0,0 +1,264 @@ + +#include +#include +#include "wxbeacon2_communication.hpp" +#include "wxbeacon2_ble.hpp" +#include "wxbeacon2_log.hpp" + +namespace +{ +constexpr uint16_t MEASUREMENT_INTERVAL_BROADCAST_SEC = 60 * 3; // Interval default. + +TaskHandle_t advertiseTask; +volatile bool exists = false; // Exists WxBeacon2? +volatile bool progressAdvertise = false; +advertise_callback callback_on_advertise; + +NimBLEAddress wb2address; // Detected wxbeacon2 address +WxBeacon2Client* wb2Client = nullptr; + +// WxBeacon2Client Scoped init,connect/disconnect,deinit. +struct ScopedWB2Client +{ + ScopedWB2Client(WxBeacon2Client& client, const NimBLEAddress& addr) : _client(client) + { + NimBLEDevice::init(""); + WB2_LOGI("connect to : %s", addr.toString().c_str()); + if(!_client.isConnected() && !_client.connect(addr)) + { + WB2_LOGE("Failed to connect"); + } + } + ~ScopedWB2Client() + { + _client.disconnect(); + NimBLEDevice::deinit(false); + } + WxBeacon2Client& client() { return _client; } + private: + WxBeacon2Client& _client; +}; + +// Task of get advertise data from WxBeacon2. +void wb2_advertise_task(void*) +{ + for(;;) + { + ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); + + WB2_LOGI("Start scanning"); + NimBLEDevice::init(""); + NimBLEScan* scan = NimBLEDevice::getScan(); + WxBeacon2AdvertiseCallbacks cb; + scan->setAdvertisedDeviceCallbacks(&cb); + scan->setInterval(1000); + scan->setWindow(900); + scan->setActiveScan(true); + cb.clear(); + + scan->start(60, false); + while(scan->isScanning()) { delay(100); } + + wb2address = cb.address(); + if(callback_on_advertise) { callback_on_advertise(cb.detected(), cb.data()); } + + scan->stop(); + scan->clearResults(); + NimBLEDevice::deinit(false); + + WB2_LOGI("End of scanning. detected :%d", cb.detected()); + progressAdvertise = false; + } +} +// +} + +bool initilizeAdvertise(const UBaseType_t priority, const BaseType_t core, advertise_callback f) +{ + if(!advertiseTask) + { + xTaskCreateUniversal(wb2_advertise_task, "advertise_task", 4 * 1024, nullptr, priority, &advertiseTask, core); + if(!wb2Client) { wb2Client = new WxBeacon2Client(); } + callback_on_advertise = f; + } + return (wb2Client != nullptr) && (advertiseTask != nullptr); +} + +bool requestAdvertise() +{ + if(busyAdvertise()) { return false; } + + progressAdvertise = true; + xTaskNotifyGive(advertiseTask); + return true; +} + +bool busyAdvertise() { return progressAdvertise; } + +/* + Change broadcast mode + @warning Changing to broadcast mode will not work with the WNI application. + @warning If you want to link with the WNI application, call the changeDefaultSetting function. + @warning If the beacon mode is changed, all data stored in WxBeacon2 will be lost. + */ +bool changeBeaconMode() +{ + if(!wb2Client || ((uint64_t)wb2address == 0) || busyAdvertise()) { WB2_LOGD("Cannot invoke"); return false; } + + ScopedWB2Client wb2(*wb2Client, wb2address); + if(!wb2.client().isConnected()) + { + WB2_LOGE("Failed to connect"); + return false; + } + + WxBeacon2::ADVSetting setting; + if(!wb2.client().getADVSetting(setting)) + { + WB2_LOGE("Failed ti get setting"); + return false; + } + + setting._beaconMode = (uint8_t)WxBeacon2::BeaconMode::GeneralBroadcaster2; + + if(wb2.client().setADVSetting(setting)) + { + return wb2.client().setMeasurementInterval(MEASUREMENT_INTERVAL_BROADCAST_SEC); + } + return false; +} + +/* + Change default mode (for WNI Application) + @warning If the beacon mode is changed, all data stored in WxBeacon2 will be lost. + */ +bool changeDefaultSetting() +{ + if(!wb2Client || ((uint64_t)wb2address == 0) || busyAdvertise()) { WB2_LOGD("Cannot invoke"); return false; } + + ScopedWB2Client wb2(*wb2Client, wb2address); + if(!wb2.client().isConnected()) + { + WB2_LOGE("Failed to connect"); + return false; + } + + // Need set interval and time inforamtion, + if(wb2.client().setADVSetting(WxBeacon2::ADVSetting::DEFAULT_SETTING)) + { + delay(500); + std::tm t{}; + getLocalTime(&t); + if(wb2.client().setTimeInformation(t)) + { + delay(500); + return wb2.client().setMeasurementInterval(WxBeacon2::MeasurementInterval::DEFAULT_VALUE); + } + } + return false; +} + +/* turnon LED 1 second */ +bool turnOnLED() +{ + if(!wb2Client || ((uint64_t)wb2address == 0) || busyAdvertise()) { WB2_LOGD("Cannot invoke"); return false; } + + ScopedWB2Client wb2(*wb2Client, wb2address); + if(!wb2.client().isConnected()) + { + WB2_LOGE("Failed to connect"); + return false; + } + return wb2.client().setLED(1); +} + +#if 0 +bool test_connect() +{ + if(!wb2Client || ((uint64_t)wb2address == 0) || busyAdvertise()) { WB2_LOGD("Cannot invoke"); return false; } + + ScopedWB2Client wb2(*wb2Client, wb2address); + if(!wb2.client().isConnected()) + { + WB2_LOGE("Failed to connect"); + return false; + } + + std::string str; + auto b = wb2.client().getDeviceName(str); + printf("%d DeviceName:%s\n", b, str.c_str()); + + WxBeacon2::GenericAccesssService::Appearance app; + b = wb2.client().getAppearance(app); + printf("%d Appearnce:%x\n", b, app._category); + + WxBeacon2::GenericAccesssService::PeripheralPreferredConnectionParameters params; + b = wb2.client().getPeripheralPreferredConnectionParameters(params); + printf("%d params:%x/%x/%x/%x\n", b, + params._intervalMin, params._intervalMax, params._slaveLatency, params._timeout); + + b = wb2.client().getModelNumber(str); + printf("%d ModelNumber:[%s]\n", b, str.c_str()); + b = wb2.client().getSerialNumber(str); + printf("%d SerialNumber:[%s]\n", b, str.c_str()); + b = wb2.client().getFirmwareRevision(str); + printf("%d FirmRev:[%s]\n", b, str.c_str()); + b = wb2.client().getHardwareRevision(str); + printf("%d HardRev:[%s]\n", b, str.c_str()); + b = wb2.client().getManufacturerName(str); + printf("%d ManufacturerName:[%s]\n", b, str.c_str()); + + return true; +} + +bool test_getLatestPageData() +{ + if(!wb2Client || ((uint64_t)wb2address == 0) || busyAdvertise()) { WB2_LOGD("Cannot invoke"); return false; } + + if(!wb2Client) { WB2_LOGE("Client null"); return false; } + if((uint64_t)wb2address == 0) { WB2_LOGE("Address not yet obtained"); return false; } + + ScopedWB2Client wb2(*wb2Client, wb2address); + if(!wb2.client().isConnected()) + { + WB2_LOGE("Failed to connect"); + return false; + } + + WxBeacon2::LatestPage lpage; + if(!wb2.client().getLatestPage(lpage)) { WB2_LOGE("Failed to get latest page"); return false; } + printf("Latest: %d,%d\n", lpage._page, lpage._row); + + int retryCount = 3; + WxBeacon2::ResponseFlag flag = { 2 }; + do + { + if(!wb2.client().requestPage(lpage._page, lpage._row)) { continue; } // request + for(;;) // get response flag + { + wb2.client().getResponseFlag(flag); + if((int)flag._updateFlag != 0) { break; } + delay(10); + } + }while((int)flag._updateFlag == 2 && retryCount--); + if((int)flag._updateFlag != 1) { WB2_LOGE("Failed to request or get response"); return false; } + + int cnt = lpage._row + 1; + while(cnt--) + { + WxBeacon2::ResponseData data; + if(!wb2.client().getResponseData(data)) { WB2_LOGE("Failed to get response data"); return false; } + time_t t = flag._time32 + lpage._interval * data._data._row; + auto lt = std::localtime(&t); + printf("DATA: row:%02d time:%4d/%02d/%02d %02d:%02d:%02d\n", + data._data._row, + lt->tm_year + 1900, + lt->tm_mon + 1, + lt->tm_mday, + lt->tm_hour, + lt->tm_min, + lt->tm_sec); + } + return true; +} +#endif diff --git a/src/wb2/wxbeacon2_communication.hpp b/src/wb2/wxbeacon2_communication.hpp new file mode 100644 index 0000000..1b57fb4 --- /dev/null +++ b/src/wb2/wxbeacon2_communication.hpp @@ -0,0 +1,19 @@ + +#ifndef WXBEACON2_COMMUNICATION_HPP +#define WXBEACON2_COMMUNICATION_HPP + +#include "wxbeacon2.hpp" + +// callback function on get advertise data. +using advertise_callback = void(*)(const bool exists, const WxBeacon2::AdvertiseData& ad); + +bool initilizeAdvertise(const UBaseType_t priority, const BaseType_t core, advertise_callback f); + +bool busyAdvertise(); + +bool requestAdvertise(); +bool turnOnLED(); +bool changeBeaconMode(); +bool changeDefaultSetting(); + +#endif diff --git a/src/wxbeacon2_log.hpp b/src/wb2/wxbeacon2_log.hpp similarity index 98% rename from src/wxbeacon2_log.hpp rename to src/wb2/wxbeacon2_log.hpp index ca2d598..c38e8d9 100644 --- a/src/wxbeacon2_log.hpp +++ b/src/wb2/wxbeacon2_log.hpp @@ -6,6 +6,8 @@ #ifndef WXBEACON2_LOG_HPP #define WXBEACON2_LOG_HPP +#ifdef ARDUINO + namespace wxbeacon2 { constexpr char tag[] = "WB2"; @@ -47,5 +49,6 @@ constexpr char tag[] = "WB2"; #endif +#endif // #endif diff --git a/src/wni_ticker.cpp b/src/wni_ticker.cpp index 007b653..971c476 100644 --- a/src/wni_ticker.cpp +++ b/src/wni_ticker.cpp @@ -2,16 +2,15 @@ WNI style ticker */ #include "wni_ticker.hpp" +//#include "gob_sprite.hpp" +#include "gob_datetime.hpp" +#include "wb2/wxbeacon2_log.hpp" #include "res/resource.h" -#include "u8g2_font_profont22_tr.h" #include #include -namespace -{ -const lgfx::U8g2font profont22( u8g2_font_profont22_tr ); -// -}; + +using goblib::datetime::LocalTime; const uint32_t Ticker::DECOR_FOREGROUND_COLORS[] = { @@ -19,6 +18,7 @@ const uint32_t Ticker::DECOR_FOREGROUND_COLORS[] = ::lgfx::LGFXBase::color888(188, 188, 0), // yellow ::lgfx::LGFXBase::color888(255, 0, 0), // red ::lgfx::LGFXBase::color888(128, 0, 255), // purple + ::lgfx::LGFXBase::color888( 64, 144, 48), // green }; Ticker::Ticker() @@ -26,45 +26,51 @@ Ticker::Ticker() , _str{} , _twidth(0) , _x(0) + , _speed(2) + , _decorLeftWidth(DECOR_LEFT_WIDTH) , _decorLeft(nullptr) , _decorRight(nullptr) , _logo(nullptr) - , _level(Level::Blue) + , _color(Color::Blue) , _show(true) { // _telop = new LGFX_Sprite(); + assert(_telop); + _telop->setPsram(true); _telop->setColorDepth(1); // 1bpp _telop->createSprite(TELOP_WIDTH, TELOP_HEIGHT); _telop->setBitmapColor(::lgfx::LGFXBase::color24to16(TELOP_FCLR), ::lgfx::LGFXBase::color24to16(TELOP_BCLR)); _telop->setTextColor(1); - _telop->setFont(&profont22); + // _telop->setFont(&titleFont); + _telop->setFont(&tickerFont); // _decorRight = new LGFX_Sprite(); assert(_decorRight); - _decorRight->setColorDepth(1); + _decorRight->setPsram(true); + _decorRight->setColorDepth(1); // 1bpp _decorRight->createSprite(DECOR_RIGHT_WIDTH, DECOR_RIGHT_HEIGHT); - _decorRight->setBitmapColor(::lgfx::LGFXBase::color24to16(DECOR_FOREGROUND_COLORS[_level]), ::lgfx::LGFXBase::color24to16(TELOP_BCLR)); + _decorRight->setBitmapColor(::lgfx::LGFXBase::color24to16(DECOR_FOREGROUND_COLORS[_color]), ::lgfx::LGFXBase::color24to16(TELOP_BCLR)); _decorRight->setTextColor(1); _decorRight->setFont(&fonts::Font0); // _decorLeft = new LGFX_Sprite(); assert(_decorLeft); - _decorLeft->setColorDepth(2); + _decorLeft->setPsram(true); + _decorLeft->setColorDepth(2); // 4bpp _decorLeft->createSprite(DECOR_LEFT_WIDTH, DECOR_LEFT_HEIGHT); _decorLeft->setPaletteColor(0, 255,0,255); // 0: transparent color - ::lgfx::rgb888_t rgb(DECOR_FOREGROUND_COLORS[_level]); - _decorLeft->setPaletteColor(1, rgb.R8(), rgb.G8(), rgb.B8()); // 1: level color + ::lgfx::rgb888_t rgb(DECOR_FOREGROUND_COLORS[_color]); + _decorLeft->setPivot(0,0); //left,top + _decorLeft->setPaletteColor(1, rgb.R8(), rgb.G8(), rgb.B8()); // 1: background color _decorLeft->setPaletteColor(2, 255, 255, 255); // 2: text color - _decorLeft->setFont(&profont22); + _decorLeft->setFont(&titleFont); _decorLeft->setTextColor(2); - _decorLeft->clear(); _decorLeft->fillRect(0,0,DECOR_LEFT_WIDTH, DECOR_LEFT_HEIGHT / 2, 1); _decorLeft->fillRect(0,0,DECOR_LEFT_GAP, DECOR_LEFT_HEIGHT, 1); - _decorLeft->drawString("Ponko", 1, 1); // _logo = new LGFX_Sprite(); @@ -81,26 +87,44 @@ Ticker::~Ticker() delete _telop; } -void Ticker::setLevel(const Level lv) +void Ticker::setColor(const Color c) { - _level = lv; - ::lgfx::rgb888_t rgb(DECOR_FOREGROUND_COLORS[_level]); + _color = c; + ::lgfx::rgb888_t rgb(DECOR_FOREGROUND_COLORS[_color]); _decorLeft->setPaletteColor (1, rgb.R8(), rgb.G8(), rgb.B8()); _decorRight->setPaletteColor(1, rgb.R8(), rgb.G8(), rgb.B8()); } // Set level by WBGT // see also https://www.wbgt.env.go.jp/wbgt.php -void Ticker::setLevelWBGT(float wbgt) +void Ticker::setLevelWBGT(const float wbgt) { - Level lv = (wbgt < 25.0f) ? Level::Blue - : (wbgt < 31.0f) ? Level::Yellow - : Level::Red; - setLevel(lv); + Color lv = (wbgt < 25.0f) ? Color::Blue + : (wbgt < 31.0f) ? Color::Yellow + : Color::Red; + setColor(lv); +} + +void Ticker::setTitle(const char* title) +{ + if(!title || !title[0]) { return; } + + WB2_LOGD("%s", title); + + _decorLeft->clear(); // fill 0 + + auto sz = _decorLeft->textWidth(title); + _decorLeft->fillRect(0,0,sz + 4 /* gap 2 + 2 */, DECOR_LEFT_HEIGHT / 2, 1); + _decorLeft->fillRect(0,0,DECOR_LEFT_GAP, DECOR_LEFT_HEIGHT, 1); + _decorLeft->drawString(title, 2, 1); } void Ticker::setText(const char* str) { + if(!str || !str[0]) { return; } + + WB2_LOGD("%s", str); + _x = _telop->width(); _str[0] = '\0'; _twidth = 0; @@ -111,6 +135,13 @@ void Ticker::setText(const char* str) _str[sizeof(_str) - 1] = '\0'; _twidth = _telop->textWidth(_str); } + +#if 0 + _decorLeft->setFont(&weather_font); + _decorLeft->setTextColor(3); + _decorLeft->drawString("0123", 2, 1); +#endif + } void Ticker::pump() @@ -126,8 +157,8 @@ void Ticker::pump() { _telop->drawString(_str, _x + _twidth, 0); } - // Infinity scroll string to left. - _x -= 2; + // Infinity scroll string. + _x -= _speed; if(_twidth <= bwid) { if(_x < -_twidth) { _x = _telop->width(); } @@ -139,22 +170,16 @@ void Ticker::pump() } // Localtime - std::tm t; _decorRight->clear(); _logo->pushSprite(_decorRight, 0, 0, 0); - if(getLocalTime(&t)) - { - char clockStr[64]; - snprintf(clockStr, sizeof(clockStr), "%02d:%02d", t.tm_hour, t.tm_min); - clockStr[sizeof(clockStr) - 1] = '\0'; - _decorRight->drawString(clockStr, - _decorRight->width()/2 - _decorRight->textWidth(clockStr) / 2, - _decorRight->height() - (_decorRight->fontHeight() + 2) ); - _decorRight->drawString(clockStr, - _decorRight->width()/2 - _decorRight->textWidth(clockStr) / 2 + 1, - _decorRight->height() - (_decorRight->fontHeight() + 2) ); - - } + LocalTime lt = LocalTime::now(); + auto clockStr = lt.toString("%H;%M"); + _decorRight->drawString(clockStr.c_str(), + _decorRight->width()/2 - _decorRight->textWidth(clockStr) / 2, + _decorRight->height() - (_decorRight->fontHeight() + 2) ); + _decorRight->drawString(clockStr.c_str(), + _decorRight->width()/2 - _decorRight->textWidth(clockStr) / 2 + 1, + _decorRight->height() - (_decorRight->fontHeight() + 2) ); } void Ticker::render(m5gfx::M5GFX* dst) diff --git a/src/wni_ticker.hpp b/src/wni_ticker.hpp index 11b30f9..bfa892d 100644 --- a/src/wni_ticker.hpp +++ b/src/wni_ticker.hpp @@ -6,33 +6,38 @@ #include +//namespace gob { class Sprite; } + class Ticker { public: - enum Level : uint8_t { Blue, Yellow, Red, Purple, Max }; + enum Color : uint8_t { Blue, Yellow, Red, Purple, Green, Max }; Ticker(); virtual ~Ticker(); + void setTitle(const char* title); void setText(const char* str); bool isShow() const { return _show; } - void show(bool b) { _show = b; } + void show(const bool b) { _show = b; } void show() { show(true); } void hide() { show(false); } - Level level() const { return _level; } - void setLevel(const Level lv); - void setLevelWBGT(float wbgt); + Color color() const { return _color; } + void setColor(const Color lv); + void setLevelWBGT(const float wbgt); + + void setScrollSpeed(const uint8_t s) { _speed = s; } - virtual void pump(); - virtual void render(m5gfx::M5GFX* dst); + void pump(); + void render(m5gfx::M5GFX* dst); - constexpr static size_t STRING_LEN = 256; + constexpr static size_t STRING_LEN = 384; constexpr static int16_t GAP = 2; //Decoration left - constexpr static int16_t DECOR_LEFT_WIDTH = 64; + constexpr static int16_t DECOR_LEFT_WIDTH = 160; constexpr static int16_t DECOR_LEFT_HEIGHT = 48; constexpr static int16_t DECOR_LEFT_GAP = 4; //Decoration right @@ -50,15 +55,17 @@ class Ticker private: // Telop LGFX_Sprite* _telop; + // gob::Sprite* _telop2; char _str[STRING_LEN + 1/* \0 */]; int16_t _twidth; - int16_t _x; + int16_t _x, _speed; // Decoration + int16_t _decorLeftWidth; LGFX_Sprite* _decorLeft; LGFX_Sprite* _decorRight; LGFX_Sprite* _logo; - // Status - Level _level; + + Color _color; bool _show; }; From 7c45ae40bfd117d657ffd6809968d1191bf505e0 Mon Sep 17 00:00:00 2001 From: GOB Date: Thu, 22 Dec 2022 16:21:01 +0900 Subject: [PATCH 02/31] Move files --- src/{ => res}/u8g2_font_profont22_tr.cpp | 0 src/{ => res}/u8g2_font_profont22_tr.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/{ => res}/u8g2_font_profont22_tr.cpp (100%) rename src/{ => res}/u8g2_font_profont22_tr.h (100%) diff --git a/src/u8g2_font_profont22_tr.cpp b/src/res/u8g2_font_profont22_tr.cpp similarity index 100% rename from src/u8g2_font_profont22_tr.cpp rename to src/res/u8g2_font_profont22_tr.cpp diff --git a/src/u8g2_font_profont22_tr.h b/src/res/u8g2_font_profont22_tr.h similarity index 100% rename from src/u8g2_font_profont22_tr.h rename to src/res/u8g2_font_profont22_tr.h From f2448bd61142d27325ae5d6d7aa2b9f9b07b73c8 Mon Sep 17 00:00:00 2001 From: GOB Date: Thu, 22 Dec 2022 19:22:49 +0900 Subject: [PATCH 03/31] Split weather map. Add progress icon. Add resouces. --- platformio.ini | 11 +++- src/aq_talk.cpp | 6 +- src/main.cpp | 68 +++++++++++++------ src/ponko_avatar.cpp | 148 ++---------------------------------------- src/ponko_avatar.hpp | 33 ++++------ src/progress_icon.cpp | 44 +++++++++++++ src/progress_icon.hpp | 24 +++++++ src/res/resource.h | 12 ++++ src/weather_map.cpp | 109 +++++++++++++++++++++++++++++++ src/weather_map.hpp | 42 ++++++++++++ 10 files changed, 312 insertions(+), 185 deletions(-) create mode 100644 src/progress_icon.cpp create mode 100644 src/progress_icon.hpp create mode 100644 src/weather_map.cpp create mode 100644 src/weather_map.hpp diff --git a/platformio.ini b/platformio.ini index e83ba5e..7ed04b2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,7 +13,7 @@ board_build.f_flash = 80000000L board_build.f_cpu = 240000000L ; https://github.com/tanakamasayuki/aquestalk download zip and extract ./lib folder. -lib_extra_dirs = /lib +;lib_extra_dirs = /lib lib_ldf_mode = deep lib_deps = m5stack/M5Unified h2zero/NimBLE-Arduino @@ -27,7 +27,8 @@ upload_speed = 921600 ; Definition ; M5S_WXBEACON2_TIMEZONE_LOCATION : Your time-zone location string. default as "Asia/Tokyo" (e.g. "Asia/Tokyo" "America/Los_Angeles" "Australia/Lord_Howe") build_flags = -Wall -Wextra -Wreturn-local-addr -Werror=format -Werror=return-local-addr - -D M5S_WXBEACON2_TIMEZONE_LOCATION=\"Asia/Tokyo\" + -D M5S_WXBEACON2_TIMEZONE_LOCATION=\"Asia/Tokyo\" + -D M5S_WXBEACON2_DEBUG_INFO [release_env] build_type = release @@ -76,6 +77,12 @@ board = m5stack-core2 extends=debug_env, core2_env board = m5stack-core2 +[env:core2_master] +extends=release_env, core2_env +board = m5stack-core2 +build_flags = ${env.build_flags} + -D NDEBUG + ; M5Stack BASIC [env:basic_release] extends=release_env, m5s_env diff --git a/src/aq_talk.cpp b/src/aq_talk.cpp index b533389..dd0efe3 100644 --- a/src/aq_talk.cpp +++ b/src/aq_talk.cpp @@ -95,7 +95,7 @@ PROGMEM const char wc_302[] = "a'me,tokidoki'yamu"; PROGMEM const char wc_303[] = "a'me,tokidoki'yuki"; PROGMEM const char wc_304[] = "a'me'kayuki"; PROGMEM const char wc_306[] = "ooa'me"; -PROGMEM const char wc_308[] = "a'mede,bo-fu-o'tomonau"; +PROGMEM const char wc_308[] = "a'mede,bo-fu-uo'tomonau"; PROGMEM const char wc_309[] = "a'me,ichiji'yuki"; PROGMEM const char wc_311[] = "a'me,nochi'hare"; PROGMEM const char wc_313[] = "a'me,nochi'kumori"; @@ -123,8 +123,8 @@ PROGMEM const char wc_401[] = "yuki,tokidoki'hare"; PROGMEM const char wc_402[] = "yuki,tokidokiyamu"; PROGMEM const char wc_403[] = "yuki,tokidoki'ame"; PROGMEM const char wc_405[] = "ooyuki"; -PROGMEM const char wc_406[] = "fu--'u,tsuyoi"; -PROGMEM const char wc_407[] = "bo-'fu-u"; +PROGMEM const char wc_406[] = "fu-setsu,tsuyoi"; +PROGMEM const char wc_407[] = "bo-'fu-setsu"; PROGMEM const char wc_409[] = "yuki,ichji'ame"; PROGMEM const char wc_411[] = "yuki,nochi'hare"; PROGMEM const char wc_413[] = "yuki,nochi'kumori"; diff --git a/src/main.cpp b/src/main.cpp index 2f1e129..9e51629 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,6 +16,8 @@ #include "aq_talk.hpp" #include "ponko_avatar.hpp" #include "wni_ticker.hpp" +#include "weather_map.hpp" +#include "progress_icon.hpp" #include "wb2/wxbeacon2_communication.hpp" #include "wb2/wxbeacon2_log.hpp" #include "jma/jma_task.hpp" @@ -35,6 +37,10 @@ #define ESP_IDF_VERSION ESP_IDF_VERSION_VAL(3,2,0) #endif +using goblib::datetime::LocalTime; +using goblib::datetime::LocalDateTime; +using goblib::datetime::OffsetDateTime; + namespace { // Automatic request interval for advertise. @@ -55,6 +61,8 @@ const char* ntpURL[] = Avatar* avatar; Ticker* ticker; +WeatherMap* weatherMap; +ProgressIcon* progress; bool forceRender = true; // Force rendering all time_t lastUpdate = -1; time_t voiceEnd = -1; @@ -93,7 +101,7 @@ struct Weather snprintf(buf, sizeof(buf), "[%s] %s %d℃/%d℃", jma::officesCodeToString(oc), jma::weatherCodeToString(wc), - lowTemp, highTemp); + highTemp, lowTemp); } else { @@ -106,7 +114,7 @@ struct Weather } }; -std::map > forecast; +std::map > forecast; OffsetDateTime requestDatetime; bool updatedForecast = false; @@ -178,6 +186,7 @@ void playAdvertiseData(const WxBeacon2::AdvertiseData& data) { forceRender = true; avatar->closeup(); + weatherMap->hide(); aq_talk::stopAquesTalk(); auto de = data.getE(); @@ -253,11 +262,13 @@ void _requestAdvertise() void playForecast() { forceRender = true; - avatar->wipe(72, 32, 0.30f, requestDatetime); - avatar->clearIcon(); - + avatar->wipe(72, 32, 0.30f); + weatherMap->setDatetime(requestDatetime); + if(forecast.empty()) { + avatar->closeup(); + weatherMap->hide(); ticker->setTitle("ERROR"); ticker->setColor(Ticker::Color::Purple); ticker->setText(DEFAULT_TICKER_TEXT); @@ -269,6 +280,7 @@ void playForecast() auto vs = formatString("no/tenki'o/osirase'simasu ", requestDatetime.month(), requestDatetime.day()); + weatherMap->clearIcon(); for(auto& e : forecast) // each date-time { WB2_LOGV("%s:[%s] %zu", requestDatetime.toString().c_str(), e.first.toString().c_str(), e.second.size()); @@ -282,7 +294,7 @@ void playForecast() ts += w.toString() + ' '; vs += formatString("%s %s #", aq_talk::officeCodeToTalk(w.oc), aq_talk::weatherCodeToTalk(w.wc)); - avatar->addIcon(w.oc, w.wc); + weatherMap->addIcon(w.oc, w.wc); } ts += " "; } @@ -291,6 +303,7 @@ void playForecast() ticker->setTitle("Weather"); ticker->setText(ts.c_str()); ticker->setColor(Ticker::Color::Green); + weatherMap->show(); } // Callback on get forecast. @@ -376,12 +389,17 @@ void _requestForecast() lastUpdate = std::time(nullptr); forecast.clear(); - requestDatetime = OffsetDateTime::now(); -#if 0 - auto ldt = requestDatetime.toLocalDateTime(); - ldt = goblib::datetime::LocalDateTime::of(ldt.year(), ldt.month(), ldt.day() + 1, ldt.hour(), ldt.minute(), ldt.second()); - requestDatetime = OffsetDateTime::of(ldt, requestDatetime.offset()); -#endif + auto odt = OffsetDateTime::now(); + if(odt.toLocalTime() > LocalTime(17, 0, 0)) + { + auto ldt = odt.toLocalDateTime(); + auto epoch = ldt.toEpochSecond(odt.offset()) + 86400; // next day + ldt = LocalDateTime::ofEpochSecond(epoch, odt.offset()); + odt = OffsetDateTime::of(ldt, odt.offset()); + } + requestDatetime = odt; + WB2_LOGI("request forecast:%s", odt.toString().c_str()); + jma::requestForecast(); ticker->setTitle(REQUEST_TICKER_TITLE); @@ -438,20 +456,27 @@ void setup() scfg.task_pinned_core = speakerCore; M5.Speaker.config(scfg); M5.Speaker.begin(); - //M5.Speaker.setVolume(bd == m5::board_t::board_M5Stack ? 128 : 64); - M5.Speaker.setVolume(bd == m5::board_t::board_M5Stack ? 80 : 40); + M5.Speaker.setVolume(bd == m5::board_t::board_M5Stack ? 128 : 64); + // M5.Speaker.setVolume(bd == m5::board_t::board_M5Stack ? 80 : 40); delay(500); M5.Display.setBrightness(40); M5.Display.clear(); + + WB2_LOGV("objects"); - // Avatar and ticker + // Avatar,Ticker and WeatherMap avatar = new Avatar(); assert(avatar); ticker = new Ticker(); assert(ticker); ticker->setText(DEFAULT_TICKER_TEXT); - + weatherMap = new WeatherMap(); + assert(weatherMap); + progress = new ProgressIcon(); + assert(progress); + + WB2_LOGV("after objects"); // ConfigTime configTime(); M5.Display.fillScreen(TFT_DARKGREEN); @@ -596,13 +621,17 @@ void loop() // Update avatar->pump(); ticker->pump(); - + progress->pump(busyAdvertise(), jma::busyForecast()); + // Rendering { - avatar->render(&M5.Display, forceRender); forceRender = false; + weatherMap->render(&M5.Display, forceRender); + avatar->render(&M5.Display, forceRender); ticker->render(&M5.Display); + progress->render(&M5.Display); + forceRender = false; -#if 0 +#if !defined(NDEBUG) && defined(M5S_WXBEACON2_DEBUG_INFO) M5.Display.setCursor(128, 120); M5.Display.printf("a:%d f:%d aq:%d s:%d", busyAdvertise(), jma::busyForecast(), aq_talk::busy(), M5.Speaker.isPlaying()); @@ -613,7 +642,6 @@ void loop() M5.Display.setCursor(128, 136); M5.Display.printf("c0:%03.1f c1:%03.1f", cpu_usage::cpu0(), cpu_usage::cpu1()); cpu_usage::reset(); - #endif } diff --git a/src/ponko_avatar.cpp b/src/ponko_avatar.cpp index f90b95f..e8c12ff 100644 --- a/src/ponko_avatar.cpp +++ b/src/ponko_avatar.cpp @@ -5,124 +5,10 @@ #include "aq_talk.hpp" #include "res/resource.h" #include "wb2/wxbeacon2_log.hpp" -#include #include namespace { -struct Pos { uint8_t x, y; }; // Half of actual position. -PROGMEM const Pos ocPos[] = { - { 120, 8 }, // sap - { 136, 40 }, // sen - { 128, 72 }, // tok - { 104, 32 }, // nii - { 88, 48 }, // kan - { 104, 80 }, // nag - { 80, 72 }, // osa - { 48, 64 }, // hir - { 48, 84 }, // kou - { 16, 56 }, // fuk - { 8, 32 } // nah -}; -std::map positionTable = -{ - { 16000, &ocPos[0] }, - { 40000, &ocPos[1] }, - { 130000, &ocPos[2] }, - { 150000, &ocPos[3] }, - { 170000, &ocPos[4] }, - { 230000, &ocPos[5] }, - { 270000, &ocPos[6] }, - { 340000, &ocPos[7] }, - { 390000, &ocPos[8] }, - { 400000, &ocPos[9] }, - { 471000, &ocPos[10] }, -}; - -#if 0 -std::map pngTable = -{ - { 100, w100_png }, - { 101, w101_png }, - { 102, w102_png }, - { 104, w104_png }, - { 110, w110_png }, - { 112, w112_png }, - { 115, w115_png }, - { 200, w200_png }, - { 201, w201_png }, - { 202, w202_png }, - { 204, w204_png }, - { 210, w210_png }, - { 212, w212_png }, - { 215, w215_png }, - { 300, w300_png }, - { 301, w301_png }, - { 302, w302_png }, - { 303, w303_png }, - { 311, w311_png }, - { 313, w313_png }, - { 314, w314_png }, - { 400, w400_png }, - { 401, w401_png }, - { 402, w402_png }, - { 403, w403_png }, - { 411, w411_png }, - { 413, w413_png }, - { 414, w414_png }, -}; -#else -struct Png { const uint8_t* p; const size_t sz; }; -std::map pngTable = -{ - { 100, { w100_png, w100_png_len } }, - { 101, { w101_png, w101_png_len } }, - { 102, { w102_png, w102_png_len } }, - { 104, { w104_png, w104_png_len } }, - { 110, { w110_png, w110_png_len } }, - { 112, { w112_png, w112_png_len } }, - { 115, { w115_png, w115_png_len } }, - { 200, { w200_png, w200_png_len } }, - { 201, { w201_png, w201_png_len } }, - { 202, { w202_png, w202_png_len } }, - { 204, { w204_png, w204_png_len } }, - { 210, { w210_png, w210_png_len } }, - { 212, { w212_png, w212_png_len } }, - { 215, { w215_png, w215_png_len } }, - { 300, { w300_png, w300_png_len } }, - { 301, { w301_png, w301_png_len } }, - { 302, { w302_png, w302_png_len } }, - { 303, { w303_png, w303_png_len } }, - { 311, { w311_png, w311_png_len } }, - { 313, { w313_png, w313_png_len } }, - { 314, { w314_png, w314_png_len } }, - { 400, { w400_png, w400_png_len } }, - { 401, { w401_png, w401_png_len } }, - { 402, { w402_png, w402_png_len } }, - { 403, { w403_png, w403_png_len } }, - { 411, { w411_png, w411_png_len } }, - { 413, { w413_png, w413_png_len } }, - { 414, { w414_png, w414_png_len } }, -}; -#endif - - -constexpr uint32_t MAP_FCLR = ::lgfx::color888( 16, 136, 88); // palette 1 -constexpr uint32_t MAP_BCLR = ::lgfx::color888( 0, 80, 160); // palette 0 - -// WARNING : Keep largets free heap 50K for decode PNG. -void drawWeatherIcon(m5gfx::M5GFX* dst, jma::officecode_t oc, jma::weathercode_t wc) -{ - auto ic = jma::weatherCodeToIcon(wc); - if(!ic || pngTable.count(ic) == 0 || positionTable.count(oc) == 0) { return; } - - auto png = pngTable.at(ic); - auto pos = positionTable.at(oc); - WB2_LOGD("%d:%d:%d %zu", oc, wc, ic, png.sz); - auto ret = dst->drawPng(png.p, (uint32_t)png.sz, pos->x * 2, pos->y * 2); - if(ret == 0) { WB2_LOGV("mem:%u", esp_get_free_internal_heap_size()); } -} - void drawFace(m5gfx::M5GFX* dst, int16_t x, int16_t y, float zoom = 1.0f) { dst->drawBmp(ponko_face_bmp, -1, x, y, 0, 0, 0, 0, zoom, zoom); @@ -138,15 +24,14 @@ Avatar::Avatar() , _wipe(false) , _wipeX(0) , _wipeY(0) - , _iconInfo(11) { // close auto mc = new LGFX_Sprite(); assert(mc && "mc is nullptr"); mc->createFromBmp(ponko_mouth_close_bmp, ponko_mouth_close_bmp_len); - _mouth[Close] = mc; mc->setPivot(mc->width() * 0.5f + 0.5f, 0); // center,top - + _mouth[Close] = mc; + // open auto mo = new LGFX_Sprite(); assert(mo && "mo is nullptr"); @@ -175,8 +60,8 @@ void Avatar::pump() _lastMouthRatio = _mouthRatio = 0.0f; return; } - auto gain = aq_talk::getGain(); + auto gain = aq_talk::getGain(); float f = gain / 12000.0f; float ratio = std::min(1.0f, _lastMouthRatio + f / 2.0f); @@ -184,15 +69,11 @@ void Avatar::pump() _mouthRatio = ratio; } -void Avatar::renderCloseup(m5gfx::M5GFX* dst, bool forceRender) +void Avatar::renderCloseup(m5gfx::M5GFX* dst, bool force) { - if(forceRender) { drawFace(dst, 0, 0); } + if(force) { drawFace(dst, 0, 0); } _offMouth->drawBmp(ponko_face_bmp, -1, 0, 0, _offMouth->width(), _offMouth->height(), MOUTH_X, MOUTH_Y); - if(_mouthRatio > 1.0f) - { - printf("%s:%f\n", __func__, _mouthRatio); - } if(_mouthRatio != 0.0f) { @@ -212,25 +93,10 @@ void Avatar::renderCloseup(m5gfx::M5GFX* dst, bool forceRender) _offMouth->pushSprite(dst, MOUTH_X, MOUTH_Y); } -void Avatar::renderWipe(m5gfx::M5GFX* dst, bool forceRender) +void Avatar::renderWipe(m5gfx::M5GFX* dst, bool force) { - if(forceRender) + if(force) { - dst->drawBmp(jpmap_bmp, -1, 0, 0, 0, 0, 0, 0, 2.0f, 2.0f); // map - - for(auto& e : _iconInfo) - { - drawWeatherIcon(dst, e.oc, e.wc); - } - - auto ofont = dst->getFont(); - dst->setFont(&tickerFont); - dst->setTextColor(TFT_WHITE); - dst->setCursor(8,8); - dst->printf("%sの天気", _odt.toLocalDate().toString("%m/%d").c_str()); - dst->setFont(ofont); - dst->setTextColor(TFT_WHITE, TFT_BLACK); - drawFace(dst, _wipeX, _wipeY, _wipeScale); dst->drawRect(_wipeX, _wipeY, 320 * _wipeScale, 240 * _wipeScale, TFT_WHITE); } diff --git a/src/ponko_avatar.hpp b/src/ponko_avatar.hpp index 7b07ea2..3165971 100644 --- a/src/ponko_avatar.hpp +++ b/src/ponko_avatar.hpp @@ -4,6 +4,9 @@ #ifndef PONKO_AVATAR_HPP #define PONKO_AVATAR_HPP +/* + Ponko avatar + */ #include #include"jma/jma_definition.hpp" #include @@ -18,25 +21,20 @@ class Avatar virtual ~Avatar(); void pump(); - void render(m5gfx::M5GFX* dst, const bool forceRender = false) + void render(m5gfx::M5GFX* dst, const bool force = false) { - _wipe ? renderWipe(dst, forceRender) : renderCloseup(dst, forceRender); + _wipe ? renderWipe(dst, force) : renderCloseup(dst, force); } // Change rendering type. void closeup() { _wipe = false; } - void wipe(const int16_t x, const int16_t y, const float scale, const goblib::datetime::OffsetDateTime& odt) + void wipe(const int16_t x, const int16_t y, const float scale) { - _wipe = true; _wipeX = x; _wipeY = y; _wipeScale = scale; _odt = odt; - } - void clearIcon() { _iconInfo.clear(); } - void addIcon(const jma::officecode_t oc, const jma::weathercode_t wc) - { - _iconInfo.push_back(IconInfo{oc, wc}); + _wipe = true; _wipeX = x; _wipeY = y; _wipeScale = scale; } constexpr static int16_t MOUTH_X = 136; - constexpr static int16_t MOUTH_Y = 168; + constexpr static int16_t MOUTH_Y = 168; constexpr static int16_t MOUTH_WIDTH = 48; constexpr static int16_t MOUTH_HEIGHT = 32; @@ -45,14 +43,11 @@ class Avatar void renderWipe(m5gfx::M5GFX* dst, bool forceRender = false); enum : uint8_t {Close, Open, Max }; - LGFX_Sprite* _offMouth; - LGFX_Sprite* _mouth[Max]; - float _mouthRatio, _lastMouthRatio; - bool _wipe; - float _wipeScale; - int16_t _wipeX, _wipeY; - goblib::datetime::OffsetDateTime _odt; - - std::vector _iconInfo; + LGFX_Sprite* _offMouth{}; + LGFX_Sprite* _mouth[Max]{}; + float _mouthRatio{}, _lastMouthRatio{}; + bool _wipe{}; + float _wipeScale{}; + int16_t _wipeX{}, _wipeY{}; }; #endif diff --git a/src/progress_icon.cpp b/src/progress_icon.cpp new file mode 100644 index 0000000..67a8f08 --- /dev/null +++ b/src/progress_icon.cpp @@ -0,0 +1,44 @@ +/* + Icon indicating access to WiFi or BT in progress + */ + +#include "progress_icon.hpp" +#include "res/resource.h" + +namespace +{ +constexpr int16_t ICON_X = 284; +constexpr int16_t ICON_Y = 160; + +inline int32_t roundTrip(const int32_t c) +{ + // return ( (c & 256) + ( (c & 255) ^ (0 - ((c >> 8) & 1)) ) ); + return ( (c & 128) + ( (c & 127) ^ (0 - ((c >> 7) & 1)) ) ); +} + +// +} + +ProgressIcon::ProgressIcon() +{ + _btSprite = new LGFX_Sprite(); + assert(_btSprite); + _btSprite->createFromBmp(bt_bmp, bt_bmp_len); + + _wifiSprite = new LGFX_Sprite(); + assert(_wifiSprite); + _wifiSprite->createFromBmp(bt_bmp, bt_bmp_len); +} + + +// { _bt = bt; _wifi = wifi; } + +void ProgressIcon::render(m5gfx::M5GFX* dst) +{ + auto v = roundTrip(_cnt); + _btSprite->setPaletteColor (1, v * 2, v * 2, v * 2); + _wifiSprite->setPaletteColor(1, v * 2, v * 2, v * 2); + + if(_bt) { _btSprite->pushSprite(dst, ICON_X, ICON_Y, 0); } + if(_wifi) { _wifiSprite->pushSprite(dst, ICON_X, ICON_Y, 0); } +} diff --git a/src/progress_icon.hpp b/src/progress_icon.hpp new file mode 100644 index 0000000..9a45aa8 --- /dev/null +++ b/src/progress_icon.hpp @@ -0,0 +1,24 @@ +/* + Icon indicating access to WiFi or BT in progress + */ +#ifndef PROGRESS_ICON_HPP +#define PROGRESS_ICON_HPP + +#include + +class ProgressIcon +{ + public: + ProgressIcon(); + + inline void pump(const bool bt, const bool wifi) { _bt = bt; _wifi = wifi; ++_cnt; } + void render(m5gfx::M5GFX* dst); + + private: + bool _bt{}, _wifi{}; + uint16_t _cnt{}; + LGFX_Sprite* _btSprite{}; + LGFX_Sprite* _wifiSprite{}; + +}; +#endif diff --git a/src/res/resource.h b/src/res/resource.h index fb850af..2f49949 100644 --- a/src/res/resource.h +++ b/src/res/resource.h @@ -23,6 +23,12 @@ extern const size_t logo_bmp_len; extern const uint8_t jpmap_bmp[]; extern const size_t jpmap_bmp_len; +// 1bpp WifI/BT icon +extern const uint8_t wifi_bmp[]; +extern const size_t wifi_bmp_len; +extern const uint8_t bt_bmp[]; +extern const size_t bt_bmp_len; + // Text font extern const lgfx::U8g2font titleFont; extern const lgfx::U8g2font tickerFont; @@ -82,6 +88,9 @@ extern const size_t w302_png_len; extern const uint8_t w303_png[]; extern const size_t w303_png_len; +extern const uint8_t w308_png[]; +extern const size_t w308_png_len; + extern const uint8_t w311_png[]; extern const size_t w311_png_len; @@ -103,6 +112,9 @@ extern const size_t w402_png_len; extern const uint8_t w403_png[]; extern const size_t w403_png_len; +extern const uint8_t w406_png[]; +extern const size_t w406_png_len; + extern const uint8_t w411_png[]; extern const size_t w411_png_len; diff --git a/src/weather_map.cpp b/src/weather_map.cpp new file mode 100644 index 0000000..8e812bd --- /dev/null +++ b/src/weather_map.cpp @@ -0,0 +1,109 @@ +/* + Weather map + */ +#include "weather_map.hpp" +#include +#include "wb2/wxbeacon2_log.hpp" +#include "res/resource.h" +#include + +namespace +{ +struct Pos { uint8_t x, y; }; // Half of actual position. +PROGMEM const Pos ocPos[] = { + { 120, 8 }, // sap + { 136, 40 }, // sen + { 128, 72 }, // tok + { 104, 32 }, // nii + { 88, 48 }, // kan + { 104, 80 }, // nag + { 80, 72 }, // osa + { 48, 64 }, // hir + { 48, 84 }, // kou + { 16, 56 }, // fuk + { 8, 32 } // nah +}; + +std::map positionTable = +{ + { 16000, &ocPos[0] }, + { 40000, &ocPos[1] }, + { 130000, &ocPos[2] }, + { 150000, &ocPos[3] }, + { 170000, &ocPos[4] }, + { 230000, &ocPos[5] }, + { 270000, &ocPos[6] }, + { 340000, &ocPos[7] }, + { 390000, &ocPos[8] }, + { 400000, &ocPos[9] }, + { 471000, &ocPos[10] }, +}; + +std::map pngTable = +{ + { 100, w100_png }, + { 101, w101_png }, + { 102, w102_png }, + { 104, w104_png }, + { 110, w110_png }, + { 112, w112_png }, + { 115, w115_png }, + { 200, w200_png }, + { 201, w201_png }, + { 202, w202_png }, + { 204, w204_png }, + { 210, w210_png }, + { 212, w212_png }, + { 215, w215_png }, + { 300, w300_png }, + { 301, w301_png }, + { 302, w302_png }, + { 303, w303_png }, + { 308, w308_png }, + { 311, w311_png }, + { 313, w313_png }, + { 314, w314_png }, + { 400, w400_png }, + { 401, w401_png }, + { 402, w402_png }, + { 403, w403_png }, + { 406, w406_png }, + { 411, w411_png }, + { 413, w413_png }, + { 414, w414_png }, +}; + +// WARNING : Keep largets free heap 50K for decode PNG. +void drawWeatherIcon(m5gfx::M5GFX* dst, jma::officecode_t oc, jma::weathercode_t wc) +{ + auto ic = jma::weatherCodeToIcon(wc); + if(!ic || pngTable.count(ic) == 0 || positionTable.count(oc) == 0) { return; } + + auto png = pngTable.at(ic); + auto pos = positionTable.at(oc); + // WB2_LOGD("%d:%d:%d p:%d", oc, wc, ic, png != nullptr); + auto ret = dst->drawPng(png, -1, pos->x * 2, pos->y * 2); + if(ret == 0) { WB2_LOGV("mem:%u", esp_get_free_internal_heap_size()); } +} +// +} + +void WeatherMap::render(m5gfx::M5GFX* dst, bool force) +{ + if(!isShow() || !force) { return; } + + dst->drawBmp(jpmap_bmp, -1, 0, 0, 0, 0, 0, 0, 2.0f, 2.0f); // Japan map + // Icon + for(auto& e : _icons) + { + drawWeatherIcon(dst, e.oc, e.wc); + } + // Day of forecast + auto ofont = dst->getFont(); + dst->setFont(&tickerFont); + dst->setTextColor(TFT_WHITE); + dst->setCursor(8,8); + dst->printf("%sの天気", _odt.toLocalDate().toString("%m/%d").c_str()); + dst->setFont(ofont); + dst->setTextColor(TFT_WHITE, TFT_BLACK); +} diff --git a/src/weather_map.hpp b/src/weather_map.hpp new file mode 100644 index 0000000..38a48ab --- /dev/null +++ b/src/weather_map.hpp @@ -0,0 +1,42 @@ +/* + Weather map + */ +#ifndef WEATHER_MAP_HPP +#define WEATHER_MAP_HPP + +#include +#include +#include "jma/jma_definition.hpp" +#include + +class WeatherMap +{ + public: + struct IconInfo + { + IconInfo(const jma::officecode_t ocv, const jma::weathercode_t wcv) : oc(ocv), wc(wcv) {} + jma::officecode_t oc{}; + jma::weathercode_t wc{}; + }; + + WeatherMap() { _icons.reserve(16); } + + inline void show() { show(true); } + inline void hide() { show(false); } + + void setDatetime(const goblib::datetime::OffsetDateTime& odt) { _odt =odt; } + inline void clearIcon() { _icons.clear(); } + void addIcon(const jma::officecode_t oc, const jma::weathercode_t wc) { _icons.emplace_back(oc, wc); } + + void render(m5gfx::M5GFX* dst, bool forece = false); + + private: + void show(bool b) { _show = b; } + inline bool isShow() const { return _show; } + + private: + bool _show{false}; + goblib::datetime::OffsetDateTime _odt{}; + std::vector _icons{}; +}; +#endif From a648e35f4b11a1e369adcb0ef61a86ba1ecadaaf Mon Sep 17 00:00:00 2001 From: GOB Date: Thu, 22 Dec 2022 22:17:26 +0900 Subject: [PATCH 04/31] Tweaks talk speed for forecast --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 9e51629..344ca44 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -298,7 +298,7 @@ void playForecast() } ts += " "; } - aq_talk::playAquesTalk(vs.c_str(), 110); + aq_talk::playAquesTalk(vs.c_str(), 120); ticker->setTitle("Weather"); ticker->setText(ts.c_str()); From 2c4fbe11a37f6fc310737e8428b53926a9920ff8 Mon Sep 17 00:00:00 2001 From: GOB Date: Thu, 22 Dec 2022 16:20:10 +0900 Subject: [PATCH 05/31] Add request himawari image --- src/himawari/himawari_task.cpp | 168 +++++++++++++++++++++++++++++++++ src/himawari/himawari_task.hpp | 21 +++++ src/main.cpp | 56 ++++++++++- src/wni_ticker.cpp | 1 - 4 files changed, 241 insertions(+), 5 deletions(-) create mode 100644 src/himawari/himawari_task.cpp create mode 100644 src/himawari/himawari_task.hpp diff --git a/src/himawari/himawari_task.cpp b/src/himawari/himawari_task.cpp new file mode 100644 index 0000000..056f581 --- /dev/null +++ b/src/himawari/himawari_task.cpp @@ -0,0 +1,168 @@ +/* + Request image of Weather Satellite "Himawari" + M5Stack Core2 only +*/ +#ifdef ARDUINO_M5STACK_Core2 + +#include +#include +#include +#include +#include "himawari_task.hpp" +#include "wb2/wxbeacon2_log.hpp" + +namespace +{ +// Request himawari image +TaskHandle_t himawariTask; +volatile bool progressHimawari = false; +himawari::image_callback callbackOnImage; + +//PROGMEM const char band_b13 = "b13"; +//PROGMEM const char band_snd = "snd"; + +//PROGMEM const char HIMAWARI_URI_FORMAT[] = "https://www.data.jma.go.jp/mscweb/data/himawari/img/jpn/jpn_%s_%s.jpg"; +PROGMEM const char HIMAWARI_URI_FORMAT[] = "https://www.data.jma.go.jp/mscweb/data/himawari/img/jpn/jpn_b07_1530.jpg"; +// DigiCert Global Root CA of www.data.jma.go.jp. +// Expire at Mon, 10 Nov 2031 00:00:00 GMT +PROGMEM const char root_ca_ECC[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" + "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" + "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n" + "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" + "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n" + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n" + "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n" + "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n" + "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n" + "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n" + "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n" + "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n" + "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n" + "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n" + "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n" + "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n" + "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n" + "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" + "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n" + "-----END CERTIFICATE-----\n"; + +uint8_t* jpg; + + +void himawari_task(void*) +{ + for(;;) + { + ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); + + // Connect WiFi + int8_t ctry = 3; + do + { + WiFi.mode(WIFI_STA); + WiFi.begin(); + int tcount = 20; + while(tcount-- > 0 && WiFi.status() != WL_CONNECTED) + { + delay(500); + } + if(WiFi.status() == WL_CONNECTED) { break; } + WiFi.disconnect(true); + WiFi.mode(WIFI_OFF); + WB2_LOGD("Retry begin"); + delay(10); + }while(ctry--); + + if(WiFi.status() != WL_CONNECTED) + { + WB2_LOGE("Failed to connect WiFi"); + if(callbackOnImage) { callbackOnImage(nullptr); } + progressHimawari = false; + continue; + } + + char url[128]; + snprintf(url ,sizeof(url), HIMAWARI_URI_FORMAT); + + HTTPClient http; + WiFiClientSecure client; + do + { + client.setCACert(root_ca_ECC); + int8_t gtry = 3; + int httpcode = 0; + // https GET + do + { + http.begin(client, url); + httpcode = http.GET(); + if(httpcode == HTTP_CODE_OK) { break; } + WB2_LOGD("Failed to GET() %d", httpcode); + http.end(); + client.stop(); + }while(gtry--); + + if(httpcode != HTTP_CODE_OK) { break; } + + size_t sz = http.getSize(); + WB2_LOGD("jpgsz:%zu", sz); + jpg = (uint8_t*)malloc(sz); + if(!jpg) + { + WB2_LOGD("Failed to allocate"); + break; + } + client.readBytes(jpg, sz); + WB2_LOGD("av:%d" ,client.available()); + }while(0); + http.end(); + client.stop(); + + WB2_LOGD("WiFi disconnect"); + WiFi.disconnect(true); + WiFi.mode(WIFI_OFF); + + if(callbackOnImage) { callbackOnImage(jpg); } + + progressHimawari = false; + } +} +// +} + + + + +namespace himawari +{ + +bool initialize(const UBaseType_t priority, const BaseType_t core, image_callback f) +{ + if(!himawariTask) + { + xTaskCreateUniversal(himawari_task, "himawari_task", 8 * 1024, nullptr, priority, &himawariTask, core); + callbackOnImage = f; + } + return himawariTask != nullptr; +} + +bool busy() +{ + return progressHimawari; +} + +bool request() +{ + if(busy()) { return false; } + + progressHimawari = true; + xTaskNotifyGive(himawariTask); + return true; +} + +// +} +#endif diff --git a/src/himawari/himawari_task.hpp b/src/himawari/himawari_task.hpp new file mode 100644 index 0000000..f6514f8 --- /dev/null +++ b/src/himawari/himawari_task.hpp @@ -0,0 +1,21 @@ +/* + Request image of Weather Satellite "Himawari" + M5Stack Core2 only +*/ +#ifndef HIMAWARI_HPP +#define HIMAWARI_HPP + +# ifdef ARDUINO_M5STACK_Core2 + +namespace himawari +{ +using image_callback = void(*)(const uint8_t* p); + +bool initialize(const UBaseType_t priority, const BaseType_t core, image_callback f); +bool busy(); +bool request(); + +// +} +# endif +#endif diff --git a/src/main.cpp b/src/main.cpp index 344ca44..94666ce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,6 +24,10 @@ #include #include "cpu_usage.hpp" +#ifdef ARDUINO_M5STACK_Core2 +#include "himawari/himawari_task.hpp" +#endif + #include #include #include @@ -74,6 +78,9 @@ constexpr BaseType_t advertiseCore = 1; constexpr UBaseType_t forecastPriority = 1; constexpr BaseType_t forecastCore = 1; +constexpr UBaseType_t himawariPriority = 1; +constexpr BaseType_t himawariCore = 1; + constexpr UBaseType_t aqtalkPriority = 2; constexpr BaseType_t aqtalkCore = 1; @@ -118,6 +125,12 @@ std::map > forecast; OffsetDateTime requestDatetime; bool updatedForecast = false; +// +#ifdef ARDUINO_M5STACK_Core2 +bool updatedHimawari = false; +const uint8_t* himawariImage = nullptr; +#endif + // Ticker text PROGMEM const char DEFAULT_TICKER_TEXT[] = "WEATHEROID Type A Airi "; PROGMEM const char NOTICE_TICKER_TEXT[] = "Press and hold C to put the WxBeacon2 into the broadcast mode. "; @@ -179,7 +192,14 @@ void configTime() } // -bool canRequest() { return (!busyAdvertise() && !jma::busyForecast()); } +bool canRequest() +{ +#ifdef ARDUINO_M5STACK_Core2 + return !busyAdvertise() && !jma::busyForecast() && !himawari::busy(); +#else + return !busyAdvertise() && !jma::busyForecast(); +#endif +} // Play advertise void playAdvertiseData(const WxBeacon2::AdvertiseData& data) @@ -356,6 +376,12 @@ void _requestForecast() { if(canRequest()) { +#if 0 + himawari::request(); + ticker->setTitle(REQUEST_TICKER_TITLE); + return; +#endif + #if 0 // TEST lastUpdate = std::time(nullptr); @@ -415,6 +441,15 @@ void callbackOnEndAqTalk() voiceEnd = std::time(nullptr); } +#ifdef ARDUINO_M5STACK_Core2 +// Request himawari image +void callbackOnImage(const uint8_t* ptr) +{ + himawariImage = ptr; + updatedHimawari = true; +} +#endif + PROGMEM static const char t0[] = "minnasa--n,ponnbanwa,weza-roido'taipuei,airi'desu"; PROGMEM static const char t1[] = "konsyu-no/saikaiwa,'kaniza"; PROGMEM static const char t2[] = "weza-roido'una'na-i wa arimasen"; @@ -481,9 +516,12 @@ void setup() configTime(); M5.Display.fillScreen(TFT_DARKGREEN); - // WxBeacon2 / Forecast + // WxBeacon2 / Forecast / Himawari initilizeAdvertise(advertisePriority, advertiseCore, callbackOnAdvertise); - jma::initializeForecast(forecastPriority,forecastCore, callbackOnForecast); + jma::initializeForecast(forecastPriority, forecastCore, callbackOnForecast); +#ifdef ARDUINO_M5STACK_Core2 + himawari::initialize(himawariPriority, himawariCore, callbackOnImage); +#endif // AquesTalk auto ret = aq_talk::initialize(aqtalkPriority, aqtalkCore, callbackOnEndAqTalk); @@ -621,8 +659,12 @@ void loop() // Update avatar->pump(); ticker->pump(); +#ifdef ARDUINO_M5STACK_Core2 + progress->pump(busyAdvertise(), (jma::busyForecast() || himawari::busy())); +#else progress->pump(busyAdvertise(), jma::busyForecast()); - +#endif + // Rendering { weatherMap->render(&M5.Display, forceRender); @@ -633,8 +675,14 @@ void loop() #if !defined(NDEBUG) && defined(M5S_WXBEACON2_DEBUG_INFO) M5.Display.setCursor(128, 120); +# ifdef ARDUINO_M5STACK_Core2 + M5.Display.printf("a:%d f:%d h:%d aq:%d s:%d", + busyAdvertise(), jma::busyForecast(), himawari::busy(), + aq_talk::busy(), M5.Speaker.isPlaying()); +# else M5.Display.printf("a:%d f:%d aq:%d s:%d", busyAdvertise(), jma::busyForecast(), aq_talk::busy(), M5.Speaker.isPlaying()); +# endif M5.Display.setCursor(128, 128); M5.Display.printf("ih:%06u ilf:%06u", esp_get_free_internal_heap_size(), diff --git a/src/wni_ticker.cpp b/src/wni_ticker.cpp index 971c476..c963f6f 100644 --- a/src/wni_ticker.cpp +++ b/src/wni_ticker.cpp @@ -2,7 +2,6 @@ WNI style ticker */ #include "wni_ticker.hpp" -//#include "gob_sprite.hpp" #include "gob_datetime.hpp" #include "wb2/wxbeacon2_log.hpp" #include "res/resource.h" From 156ad13a3d9169849ca0b56451c97cc41a576d92 Mon Sep 17 00:00:00 2001 From: GOB Date: Fri, 23 Dec 2022 19:30:21 +0900 Subject: [PATCH 06/31] Fixes WiFi task. Add progress bar. --- .gitignore | 2 + src/aq_talk.cpp | 2 +- src/himawari/himawari.cpp | 57 ++++ src/himawari/himawari.hpp | 45 +++ src/himawari/himawari_screen.cpp | 33 +++ src/himawari/himawari_screen.hpp | 36 +++ src/himawari/himawari_task.cpp | 248 ++++++++++++---- src/himawari/himawari_task.hpp | 16 +- src/jma/jma_definition.cpp | 27 -- src/jma/jma_definition.hpp | 3 - src/jma/jma_forecast.cpp | 103 ++----- src/jma/jma_task.cpp | 84 ++++-- src/jma/jma_task.hpp | 3 +- src/main.cpp | 437 ++++++++++++++++++---------- src/progress.cpp | 69 +++++ src/progress.hpp | 34 +++ src/progress_icon.cpp | 44 --- src/progress_icon.hpp | 24 -- src/utility.hpp | 62 ++++ src/wb2/wxbeacon2_communication.cpp | 7 +- 20 files changed, 916 insertions(+), 420 deletions(-) create mode 100644 src/himawari/himawari.cpp create mode 100644 src/himawari/himawari.hpp create mode 100644 src/himawari/himawari_screen.cpp create mode 100644 src/himawari/himawari_screen.hpp create mode 100644 src/progress.cpp create mode 100644 src/progress.hpp delete mode 100644 src/progress_icon.cpp delete mode 100644 src/progress_icon.hpp create mode 100644 src/utility.hpp diff --git a/.gitignore b/.gitignore index c68df03..f3f68a4 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,8 @@ *.out *.app +#pio +/.pio # resources /src/res/*.cpp diff --git a/src/aq_talk.cpp b/src/aq_talk.cpp index dd0efe3..e786bcd 100644 --- a/src/aq_talk.cpp +++ b/src/aq_talk.cpp @@ -355,7 +355,7 @@ void talk_task(void*) M5.Speaker.playRaw(wav[tri_index], len, 8000, false, 1, m5spk_virtual_channel, false); tri_index = tri_index < 2 ? tri_index + 1 : 0; } - delay(1); + delay(2); } if(callbackOnEnd) { callbackOnEnd(); } } diff --git a/src/himawari/himawari.cpp b/src/himawari/himawari.cpp new file mode 100644 index 0000000..d17e5f8 --- /dev/null +++ b/src/himawari/himawari.cpp @@ -0,0 +1,57 @@ + + +#include "himawari.hpp" +#include "utility.hpp" + +namespace +{ +PROGMEM const char band_B13[] = "B13 (Infrared)"; +PROGMEM const char band_B03[] = "B03 (Visible)"; +PROGMEM const char band_B08[] = "B08 (Water Vapor)"; +PROGMEM const char band_B07[] = "B07 (Short Wave Infrared)"; +PROGMEM const char band_DayMicrophysicsRGB[] = "Day Microphysics RGG"; +PROGMEM const char band_NightMicrophysicsRGB[] = "Night Microphysics RGB"; +PROGMEM const char band_DustRGB[] = "Dust RGB"; +PROGMEM const char band_AirmassRGB[] = "Airimass RGB"; +PROGMEM const char band_DaySnowFogRGB[] = "Day Snow-Fog RGB"; +PROGMEM const char band_NaturalColorRGB[] = "Natural Color RGB"; +PROGMEM const char band_TrueColorRGB[] = "True Color RGB (Enhanced)"; +PROGMEM const char band_TrueColorReproductionImage[] = "True Color Reproduction Image"; +PROGMEM const char band_DayConvectiveStormRGB[] = "Day Convective Storm RGB"; +PROGMEM const char band_Sandwich[] = "Sandwich"; +PROGMEM const char band_B03CombinedWithB13[] = "B03 combined with B13"; +PROGMEM const char band_B03AndB13AtNight[] = "B03 and B13 at night"; +PROGMEM const char band_HeavyRainfallPotentialAreas[] = "Heavy rainfall potential areas"; + +PROGMEM const char* bandTable[] = +{ + band_B13, + band_B03, + band_B08, + band_B07, + band_DayMicrophysicsRGB, + band_NightMicrophysicsRGB, + band_DustRGB, + band_AirmassRGB, + band_DaySnowFogRGB, + band_NaturalColorRGB, + band_TrueColorRGB, + band_TrueColorReproductionImage, + band_DayConvectiveStormRGB, + band_Sandwich, + band_B03CombinedWithB13, + band_B03AndB13AtNight, + band_HeavyRainfallPotentialAreas, +}; +// +} + +namespace himawari +{ + +String bandToString(const Band band) +{ + return bandTable[gob::to_underlying(band)]; +} +// +} diff --git a/src/himawari/himawari.hpp b/src/himawari/himawari.hpp new file mode 100644 index 0000000..19dad07 --- /dev/null +++ b/src/himawari/himawari.hpp @@ -0,0 +1,45 @@ + +#ifndef HIMAWARI_HPP +#define HIMAWARI_HPP + +#include + +namespace himawari +{ +// Band type +enum class Band : uint8_t +{ + B13, // Infrared + B03, // Visible + B08, // Water Vapor + B07, // Short Wave Infrared + DayMicrophysicsRGB, + NightMicrophysicsRGB, + DustRGB, + AirmassRGB, + DaySnowFogRGB, + NaturalColorRGB, + TrueColorRGB, // Enhanced + TrueColorReproductionImage, + DayConvectiveStormRGB, + Sandwich, + B03CombinedWithB13, + B03AndB13AtNight, + HeavyRainfallPotentialAreas, + Max +}; +// Area +enum class Area : uint8_t +{ + FullDisk, + Japan, + Australia, + NewZealand, + Max +}; + +String bandToString(const Band band); + +// +} +#endif diff --git a/src/himawari/himawari_screen.cpp b/src/himawari/himawari_screen.cpp new file mode 100644 index 0000000..13c90f5 --- /dev/null +++ b/src/himawari/himawari_screen.cpp @@ -0,0 +1,33 @@ +/* + Render himawari image + */ +#ifdef ARDUINO_M5STACK_Core2 + +#include "himawari_screen.hpp" +#include "wb2/wxbeacon2_log.hpp" +#include "res/resource.h" + +void HimawariScreen::render(m5gfx::M5GFX* dst, const bool force) +{ + if(!isShow() || !force) { return; } + if(_jpg) + { + auto ret = dst->drawJpg(_jpg, -1, 0, 0, 0, 0, 64, 24, 0.5f, 0.5f); + WB2_LOGD("drawJpg %d", ret); + } + + // Day of forecast + String s = _odt.toLocalDateTime().toString("%m/%d %H:%M"); + auto ofont = dst->getFont(); + dst->setFont(&tickerFont); + dst->setTextColor(TFT_BLACK); + dst->setCursor(9,9); + dst->printf("%s", s.c_str()); + dst->setCursor(8,8); + dst->setTextColor(TFT_WHITE); + dst->printf("%s", s.c_str()); + dst->setFont(ofont); + dst->setTextColor(TFT_WHITE, TFT_BLACK); +} + +#endif diff --git a/src/himawari/himawari_screen.hpp b/src/himawari/himawari_screen.hpp new file mode 100644 index 0000000..f28f351 --- /dev/null +++ b/src/himawari/himawari_screen.hpp @@ -0,0 +1,36 @@ +/* + Render himawari image + */ +#ifdef ARDUINO_M5STACK_Core2 +# ifndef HIMAWARI_SCREEN_HPP +# define HIMAWARI_SCREEN_HPP + +#include +#include + +class HimawariScreen +{ + public: + HimawariScreen() = default; + + inline bool isShow() const { return _show; } + inline void show() { show(true); } + inline void hide() { show(false); } + + void set(const goblib::datetime::OffsetDateTime& odt, const uint8_t* jpg) + { + _odt = odt; _jpg = jpg; + } + void render(m5gfx::M5GFX* dst, const bool force); + + private: + inline void show(bool b) { _show = b; } + + private: + bool _show{}; + goblib::datetime::OffsetDateTime _odt{}; + const uint8_t* _jpg{}; +}; + +# endif +#endif diff --git a/src/himawari/himawari_task.cpp b/src/himawari/himawari_task.cpp index 056f581..5857b55 100644 --- a/src/himawari/himawari_task.cpp +++ b/src/himawari/himawari_task.cpp @@ -9,48 +9,113 @@ #include #include #include "himawari_task.hpp" +#include "utility.hpp" #include "wb2/wxbeacon2_log.hpp" +using goblib::datetime::ZoneOffset; +using goblib::datetime::LocalDateTime; +using goblib::datetime::OffsetDateTime; + namespace { -// Request himawari image TaskHandle_t himawariTask; volatile bool progressHimawari = false; +volatile himawari::Band requestBand; +volatile himawari::Area requestArea; +volatile int8_t requestHour; +volatile int8_t requestMinute; +OffsetDateTime requestOdt; himawari::image_callback callbackOnImage; +himawari::progress_callback callbackOnProgress; +uint8_t* jpg; +constexpr size_t blockSize = 1024 * 4; +constexpr time_t ADJUST_GET_TIME = 30 * 60; + +PROGMEM const char band_B13[] = "b13"; +PROGMEM const char band_B03[] = "b03"; +PROGMEM const char band_B08[] = "b08"; +PROGMEM const char band_B07[] = "b07"; +PROGMEM const char band_DayMicrophysicsRGB[] = "dms"; +PROGMEM const char band_NightMicrophysicsRGB[] = "ngt"; +PROGMEM const char band_DustRGB[] = "dst"; +PROGMEM const char band_AirmassRGB[] = "arm"; +PROGMEM const char band_DaySnowFogRGB[] = "dsl"; +PROGMEM const char band_NaturalColorRGB[] = "dnc"; +PROGMEM const char band_TrueColorRGB[] = "tre"; +PROGMEM const char band_TrueColorReproductionImage[] = "trm"; +PROGMEM const char band_DayConvectiveStormRGB[] = "cve"; +PROGMEM const char band_Sandwich[] = "snd"; +PROGMEM const char band_B03CombinedWithB13[] = "vir"; +PROGMEM const char band_B03AndB13AtNight[] = "irv"; +PROGMEM const char band_HeavyRainfallPotentialAreas[] = "hrp"; -//PROGMEM const char band_b13 = "b13"; -//PROGMEM const char band_snd = "snd"; +PROGMEM const char* bandTable[] = +{ + band_B13, + band_B03, + band_B08, + band_B07, + band_DayMicrophysicsRGB, + band_NightMicrophysicsRGB, + band_DustRGB, + band_AirmassRGB, + band_DaySnowFogRGB, + band_NaturalColorRGB, + band_TrueColorRGB, + band_TrueColorReproductionImage, + band_DayConvectiveStormRGB, + band_Sandwich, + band_B03CombinedWithB13, + band_B03AndB13AtNight, + band_HeavyRainfallPotentialAreas, +}; + +PROGMEM const char area_FullDisk[] = "fd_"; +PROGMEM const char area_Japan[] = "jpn"; +PROGMEM const char area_Australia[] = "aus"; +PROGMEM const char area_NewZealand[] = "nzl"; -//PROGMEM const char HIMAWARI_URI_FORMAT[] = "https://www.data.jma.go.jp/mscweb/data/himawari/img/jpn/jpn_%s_%s.jpg"; -PROGMEM const char HIMAWARI_URI_FORMAT[] = "https://www.data.jma.go.jp/mscweb/data/himawari/img/jpn/jpn_b07_1530.jpg"; +PROGMEM const char* areaTable[] = +{ + area_FullDisk, + area_Japan, + area_Australia, + area_NewZealand +}; + +PROGMEM const char HIMAWARI_URI_FORMAT[] = "https://www.data.jma.go.jp/mscweb/data/himawari/img/%s/%s_%s_%02d%02d.jpg"; // DigiCert Global Root CA of www.data.jma.go.jp. // Expire at Mon, 10 Nov 2031 00:00:00 GMT PROGMEM const char root_ca_ECC[] = - "-----BEGIN CERTIFICATE-----\n" - "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" - "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" - "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" - "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n" - "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" - "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n" - "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n" - "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n" - "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n" - "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n" - "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n" - "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n" - "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n" - "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n" - "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n" - "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n" - "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n" - "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n" - "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" - "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n" - "-----END CERTIFICATE-----\n"; - -uint8_t* jpg; + R"***(-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- +)***"; +void failed() +{ + if(callbackOnImage) { callbackOnImage(nullptr, requestBand, requestOdt); } + progressHimawari = false; +} void himawari_task(void*) { @@ -79,72 +144,131 @@ void himawari_task(void*) if(WiFi.status() != WL_CONNECTED) { WB2_LOGE("Failed to connect WiFi"); - if(callbackOnImage) { callbackOnImage(nullptr); } - progressHimawari = false; + failed(); continue; } - char url[128]; - snprintf(url ,sizeof(url), HIMAWARI_URI_FORMAT); - + // Get image + size_t jpgsz{}, off{}; HTTPClient http; WiFiClientSecure client; + client.setCACert(root_ca_ECC); do { - client.setCACert(root_ca_ECC); + char url[128]; + snprintf(url ,sizeof(url), HIMAWARI_URI_FORMAT, + areaTable[gob::to_underlying(requestArea)], + areaTable[gob::to_underlying(requestArea)], + bandTable[gob::to_underlying(requestBand)], + requestHour, requestMinute); + url[sizeof(url)-1] = '\0'; + WB2_LOGI("Connect to [%s]", url); + int8_t gtry = 3; int httpcode = 0; - // https GET do { - http.begin(client, url); + if(!http.begin(client, url)) + { + WB2_LOGE("Failed to begin"); + continue; + } httpcode = http.GET(); - if(httpcode == HTTP_CODE_OK) { break; } - WB2_LOGD("Failed to GET() %d", httpcode); - http.end(); + if(httpcode >= 0) { break; } + // HTTPClient internal error, to retry. client.stop(); + http.end(); + delay(100); }while(gtry--); - if(httpcode != HTTP_CODE_OK) { break; } + if(httpcode != HTTP_CODE_OK) + { + WB2_LOGE("Failed to GET %d", httpcode); + failed(); + break; + } + + size_t szTmp = jpgsz = http.getSize(); + WB2_LOGD("jpgsz:%zu ava:%zu", jpgsz, client.available()); - size_t sz = http.getSize(); - WB2_LOGD("jpgsz:%zu", sz); - jpg = (uint8_t*)malloc(sz); + jpg = static_cast(malloc(jpgsz)); if(!jpg) { - WB2_LOGD("Failed to allocate"); + WB2_LOGE("Failed to allocate"); + failed(); break; } - client.readBytes(jpg, sz); - WB2_LOGD("av:%d" ,client.available()); + + gtry = 8; + do + { + while(http.connected() && client.available()) + { + size_t read = std::min(blockSize, szTmp); + while(read) + { + auto len = client.readBytes(jpg + off, read); + read -= len; + off += len; + WB2_LOGD("len:%zu off:%zu ava:%zu", len, off, client.available()); + delay(50); // Insert appropriate delay to continue reading the stream. + } + szTmp -= std::min(blockSize, szTmp); + if(callbackOnProgress) { callbackOnProgress(off, jpgsz); } + delay(50); + } + WB2_LOGD("http:%d", http.connected()); + if(off < jpgsz) { WB2_LOGD("Not enough read"); delay(200); } + }while(off < jpgsz && gtry--); + + WB2_LOGD("off:%zu/%zu", off, jpgsz); }while(0); - http.end(); - client.stop(); + client.stop(); + http.end(); + WB2_LOGD("WiFi disconnect"); WiFi.disconnect(true); WiFi.mode(WIFI_OFF); - if(callbackOnImage) { callbackOnImage(jpg); } + if(callbackOnImage) { callbackOnImage((off == jpgsz) ? jpg : nullptr, requestBand, requestOdt); } progressHimawari = false; } } -// -} +bool request(const LocalDateTime& ldt, const himawari::Area area, const himawari::Band band) +{ + if(himawari::busy()) { return false; } + if(jpg) {free(jpg); jpg = nullptr; } + // Himawari images are generated every 10 minutes. + // Latest is more than 20~30 minutes ago. + auto ldt2 = LocalDateTime::ofEpochSecond((ldt.toEpochSecond(ZoneOffset::UTC) - ADJUST_GET_TIME) / 600 * 600, ZoneOffset::UTC); + WB2_LOGI("%s", ldt2.toString().c_str()); + + requestBand = band; + requestArea = area; + requestHour = ldt2.hour(); + requestMinute = ldt2.minute(); + progressHimawari = true; + xTaskNotifyGive(himawariTask); + return true; +} +// +} namespace himawari { -bool initialize(const UBaseType_t priority, const BaseType_t core, image_callback f) +bool initialize(const UBaseType_t priority, const BaseType_t core, image_callback ic, progress_callback pc) { if(!himawariTask) { xTaskCreateUniversal(himawari_task, "himawari_task", 8 * 1024, nullptr, priority, &himawariTask, core); - callbackOnImage = f; + callbackOnImage = ic; + callbackOnProgress = pc; } return himawariTask != nullptr; } @@ -154,15 +278,19 @@ bool busy() return progressHimawari; } -bool request() + +bool request(const goblib::datetime::OffsetDateTime& odt, const Area area, const Band band) { - if(busy()) { return false; } + // Convert to local date-time in UTC. + auto ldt = odt.withOffsetSameEpoch(ZoneOffset::UTC).toLocalDateTime(); + auto ldt2 = LocalDateTime::ofEpochSecond((ldt.toEpochSecond(ZoneOffset::UTC) - ADJUST_GET_TIME) / 600 * 600, ZoneOffset::UTC); - progressHimawari = true; - xTaskNotifyGive(himawariTask); - return true; + requestOdt = OffsetDateTime::of(ldt2, ZoneOffset::UTC).withOffsetSameEpoch(odt.offset()); + + WB2_LOGI("%s => %s", odt.toString().c_str(), ldt.toString().c_str()); + WB2_LOGI("odt:%s", requestOdt.toString().c_str()); + return ::request(ldt, area, band); } - // } #endif diff --git a/src/himawari/himawari_task.hpp b/src/himawari/himawari_task.hpp index f6514f8..bdd6705 100644 --- a/src/himawari/himawari_task.hpp +++ b/src/himawari/himawari_task.hpp @@ -2,18 +2,22 @@ Request image of Weather Satellite "Himawari" M5Stack Core2 only */ -#ifndef HIMAWARI_HPP -#define HIMAWARI_HPP +#ifdef ARDUINO_M5STACK_Core2 +# ifndef HIMAWARI_TASK_HPP +# define HIMAWARI_TASK_HPP -# ifdef ARDUINO_M5STACK_Core2 +#include "himawari.hpp" +#include namespace himawari { -using image_callback = void(*)(const uint8_t* p); +using image_callback = void(*)(const uint8_t* p, const Band band, const goblib::datetime::OffsetDateTime& odt); +using progress_callback = void(*)(const size_t readed, const size_t size); -bool initialize(const UBaseType_t priority, const BaseType_t core, image_callback f); +bool initialize(const UBaseType_t priority, const BaseType_t core, image_callback ic, progress_callback pc); bool busy(); -bool request(); + +bool request(const goblib::datetime::OffsetDateTime& odt, const Area = Area::Japan, const Band = Band::B13); // odt with ZoneOffset // } diff --git a/src/jma/jma_definition.cpp b/src/jma/jma_definition.cpp index 1747edb..91f984e 100644 --- a/src/jma/jma_definition.cpp +++ b/src/jma/jma_definition.cpp @@ -754,33 +754,6 @@ const std::map iconTable = namespace jma { -// DigiCert Global Root CA of www.jma.go.jp. -// Exxpire at Mon, 10 Nov 2031 00:00:00 GMT. -PROGMEM const char root_ca_JMA[] = - "-----BEGIN CERTIFICATE-----" "\n" - "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh" "\n" - "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3" "\n" - "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD" "\n" - "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT" "\n" - "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j" "\n" - "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG" "\n" - "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB" "\n" - "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97" "\n" - "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt" "\n" - "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P" "\n" - "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4" "\n" - "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO" "\n" - "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR" "\n" - "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw" "\n" - "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr" "\n" - "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg" "\n" - "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF" "\n" - "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls" "\n" - "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk" "\n" - "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=" "\n" - "-----END CERTIFICATE-----" "\n" - ; - const char* weatherCodeToString(const weathercode_t wc) { return weatherCodeTable.count(wc) == 1 ? weatherCodeTable.at(wc) : ""; diff --git a/src/jma/jma_definition.hpp b/src/jma/jma_definition.hpp index b294a74..ef4811f 100644 --- a/src/jma/jma_definition.hpp +++ b/src/jma/jma_definition.hpp @@ -12,9 +12,6 @@ using weathercode_t = uint16_t; const char* weatherCodeToString(const weathercode_t wc); const char* officesCodeToString(const officecode_t oc); int16_t weatherCodeToIcon(const weathercode_t wc); - -extern const char root_ca_JMA[]; - // } #endif diff --git a/src/jma/jma_forecast.cpp b/src/jma/jma_forecast.cpp index e0196ce..d12771d 100644 --- a/src/jma/jma_forecast.cpp +++ b/src/jma/jma_forecast.cpp @@ -1,51 +1,10 @@ #include "jma_forecast.hpp" +#include "utility.hpp" #include #include #include -namespace -{ -// Exists T::toString()? -template struct has_toString -{ - template static std::true_type check(U*); - static std::false_type check(...); - static T* _cls; - static const bool value = decltype(check(_cls))::value; -}; - -// Like join function of Ruby. (For Integral, Floating-point, and String) -template::value || std::is_integral::value || std::is_same::value, std::nullptr_t>::type = nullptr> -String join(const std::vector& v, const char* separator = ", ") -{ - - return !v.empty() ? std::accumulate(++v.cbegin(), v.cend(), String(v[0]), - [&separator](const String& a, const T& b) - { - return a + separator + String(b); - }): String(); -} - - -// Like join function of Ruby. (For classes that has the toString function.) -template::value, std::nullptr_t>::type = nullptr> -String join(const std::vector& v, const char* separator = ", ") -{ - return !v.empty() ? std::accumulate(++v.cbegin(), v.cend(), v[0].toString(), - [&separator](const String& a, const T& b) - { - return a + separator + b.toString(); - }) : String(); -} - -template constexpr typename std::underlying_type::type to_underlying(T e) noexcept -{ - return static_cast::type>(e); -} -// -} - namespace jma { // @@ -60,14 +19,14 @@ Reliability Reliability::parse(const char* s) { if(!s || !s[0] || s[1]) { return Reliability(Rank::MAX); } int v = *s - 'A'; - return Reliability((v >= 0 && v < to_underlying(Rank::MAX)) ? (Rank)v : Rank::MAX); + return Reliability((v >= 0 && v < gob::to_underlying(Rank::MAX)) ? (Rank)v : Rank::MAX); } String Reliability::toString() const { static constexpr char tbl[] = { 'A', 'B', 'C', '-'}; - auto v = to_underlying(_rank); - return String((v < to_underlying(Rank::MAX)) ? tbl[v] : tbl[to_underlying(Rank::MAX)]); + auto v = gob::to_underlying(_rank); + return String((v < gob::to_underlying(Rank::MAX)) ? tbl[v] : tbl[gob::to_underlying(Rank::MAX)]); } // @@ -86,48 +45,48 @@ String Forecast::toString() const String Forecast::TimeSeriesWeather::toString() const { String s; - s = "timeDefine:[" + join(_timeDefines) + "]\n"; - s += join(_areas, "\n"); + s = "timeDefine:[" + gob::join(_timeDefines) + "]\n"; + s += gob::join(_areas, "\n"); return s; } String Forecast::TimeSeriesWeather::Areas::toString() const { String s = _area.toString() + '\n'; - s += "weatherCodes:[" + join(_weatherCodes) + "]\n"; - s += "weathers:[" + join(_weathers) + "]\n"; - s += "winds:[" + join(_winds) + "]\n"; - s += "waves:[" + join(_waves) + "]"; + s += "weatherCodes:[" + gob::join(_weatherCodes) + "]\n"; + s += "weathers:[" + gob::join(_weathers) + "]\n"; + s += "winds:[" + gob::join(_winds) + "]\n"; + s += "waves:[" + gob::join(_waves) + "]"; return s; } String Forecast::TimeSeriesPop::toString() const { String s; - s = "timeDefine:[" + join(_timeDefines) + "]\n"; - s += join(_areas, "\n"); + s = "timeDefine:[" + gob::join(_timeDefines) + "]\n"; + s += gob::join(_areas, "\n"); return s; } String Forecast::TimeSeriesPop::Areas::toString() const { String s = _area.toString() + '\n'; - s += "pops:[" + join(_pops) + "]"; + s += "pops:[" + gob::join(_pops) + "]"; return s; } String Forecast::TimeSeriesTemp::toString() const { String s; - s = "timeDefine:[" + join(_timeDefines) + "]\n"; - s += join(_areas, "\n"); + s = "timeDefine:[" + gob::join(_timeDefines) + "]\n"; + s += gob::join(_areas, "\n"); return s; } String Forecast::TimeSeriesTemp::Areas::toString() const { String s = _area.toString() + '\n'; - s += "temps:[" + join(_temps) + "]"; + s += "temps:[" + gob::join(_temps) + "]"; return s; } @@ -147,43 +106,43 @@ String WeeklyForecast::toString() const String WeeklyForecast::TimeSeriesWeather::toString() const { String s; - s = "timeDefine:[" + join(_timeDefines) + "]\n"; - s += join(_areas, "\n"); + s = "timeDefine:[" + gob::join(_timeDefines) + "]\n"; + s += gob::join(_areas, "\n"); return s; } String WeeklyForecast::TimeSeriesWeather::Areas::toString() const { String s = _area.toString() + '\n'; - s += "weatherCodes:[" + join(_weatherCodes) + "]\n"; - s += "pops:[" + join(_pops) + "]\n"; - s += "reliabilities:[" + join(_reliabilities) + ']'; + s += "weatherCodes:[" + gob::join(_weatherCodes) + "]\n"; + s += "pops:[" + gob::join(_pops) + "]\n"; + s += "reliabilities:[" + gob::join(_reliabilities) + ']'; return s; } String WeeklyForecast::TimeSeriesTemp::toString() const { String s; - s = "timeDefine:[" + join(_timeDefines) + "]\n"; - s += join(_areas, "\n"); + s = "timeDefine:[" + gob::join(_timeDefines) + "]\n"; + s += gob::join(_areas, "\n"); return s; } String WeeklyForecast::TimeSeriesTemp::Areas::toString() const { String s = _area.toString() + '\n'; - s += "tempsMin:[" + join(_tempsMin) + "]\n"; - s += "tempsMinUpper[:" + join(_tempsMinUpper) + "]\n"; - s += "tempsMinLower:[" + join(_tempsMinLower) + "]\n"; - s += "tempsMax:[" + join(_tempsMax) + "]\n"; - s += "tempsMaxUpper:[" + join(_tempsMaxUpper) + "]\n"; - s += "tempsMaxLower:[" + join(_tempsMaxLower) + "]"; + s += "tempsMin:[" + gob::join(_tempsMin) + "]\n"; + s += "tempsMinUpper[:" + gob::join(_tempsMinUpper) + "]\n"; + s += "tempsMinLower:[" + gob::join(_tempsMinLower) + "]\n"; + s += "tempsMax:[" + gob::join(_tempsMax) + "]\n"; + s += "tempsMaxUpper:[" + gob::join(_tempsMaxUpper) + "]\n"; + s += "tempsMaxLower:[" + gob::join(_tempsMaxLower) + "]"; return s; } String WeeklyForecast::TempAverage::toString() const { - String s = join(_areas, "\n"); + String s = gob::join(_areas, "\n"); return s; } @@ -196,7 +155,7 @@ String WeeklyForecast::TempAverage::Areas::toString() const String WeeklyForecast::PrecipAverage::toString() const { - String s = join(_areas, "\n"); + String s = gob::join(_areas, "\n"); return s; } diff --git a/src/jma/jma_task.cpp b/src/jma/jma_task.cpp index 23b7e90..a5e4868 100644 --- a/src/jma/jma_task.cpp +++ b/src/jma/jma_task.cpp @@ -7,14 +7,44 @@ #include "jma_task.hpp" #include "jma_forecast_handler.hpp" #include "wb2/wxbeacon2_log.hpp" +#include "utility.hpp" namespace { // Request JMA forcast by WiFi TaskHandle_t forecastTask; volatile bool progressForecast = false; -jma::forecast_callback callback_on_forecast; +jma::forecast_callback callbackOnForecast; +jma::progress_callback callbackOnProgress; PROGMEM const char JMA_FORECAST_URI_FORMAT[] = "https://www.jma.go.jp/bosai/forecast/data/forecast/%06d.json"; + +// DigiCert Global Root CA of www.jma.go.jp. +// Exxpire at Mon, 10 Nov 2031 00:00:00 GMT. +PROGMEM const char root_ca_JMA[] = + R"***(-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= + -----END CERTIFICATE----- +)***"; + // Cities from which data is obtained. PROGMEM const jma::officecode_t requestTable[] = { @@ -31,6 +61,12 @@ PROGMEM const jma::officecode_t requestTable[] = 471000, // Okinawa }; +void end() +{ + JMAHandler dummy; + callbackOnForecast(0 /* End */ , dummy._forecast, dummy._weeklyForecast); +} + void jma_forecast_task(void*) { for(;;) @@ -59,11 +95,12 @@ void jma_forecast_task(void*) { WB2_LOGE("Failed to connect WiFi"); progressForecast = false; + end(); continue; } // Get each JSON. - for(uint8_t index = 0; index < sizeof(requestTable)/sizeof(requestTable[0]); ++index) + for(uint8_t index = 0; index < gob::size(requestTable); ++index) { char url[128]; snprintf(url, sizeof(url), JMA_FORECAST_URI_FORMAT, requestTable[index]); @@ -73,23 +110,33 @@ void jma_forecast_task(void*) HTTPClient http; WiFiClientSecure client; + client.setCACert(root_ca_JMA); do { - client.setCACert(jma::root_ca_JMA); int8_t gtry = 3; int httpcode = 0; // https GET do { - http.begin(client, url); + if(!http.begin(client, url)) + { + WB2_LOGE("Failed to begin"); + continue; + } httpcode = http.GET(); - if(httpcode == HTTP_CODE_OK) { break; } - WB2_LOGD("Failed to GET() %d", httpcode); - http.end(); + if(httpcode >= 0) { break; } + + // HTTPClient internal error, to retry. client.stop(); + http.end(); + delay(100); }while(gtry--); - if(httpcode != HTTP_CODE_OK) { break; } + if(httpcode != HTTP_CODE_OK) + { + WB2_LOGD("Failed to GET() %d", httpcode); + break; + } // parse JSON JsonStreamingParser parser; @@ -97,23 +144,19 @@ void jma_forecast_task(void*) parser.setHandler(&handler); while(client.available()) { parser.parse(client.read()); } - if(callback_on_forecast) { callback_on_forecast(requestTable[index], handler._forecast, handler._weeklyForecast); } + if(callbackOnForecast) { callbackOnForecast(requestTable[index], handler._forecast, handler._weeklyForecast); } }while(0); - http.end(); client.stop(); + http.end(); + if(callbackOnProgress) { callbackOnProgress(index + 1, gob::size(requestTable)); } + delay(10); } + WB2_LOGD("WiFi disconnect"); WiFi.disconnect(true); WiFi.mode(WIFI_OFF); - - // terminate callback - if(callback_on_forecast) - { - JMAHandler dummy; - callback_on_forecast(0 /* End */ , dummy._forecast, dummy._weeklyForecast); - } - + end(); progressForecast = false; } } @@ -123,12 +166,13 @@ void jma_forecast_task(void*) namespace jma { -bool initializeForecast(const UBaseType_t priority, const BaseType_t core, forecast_callback f) +bool initializeForecast(const UBaseType_t priority, const BaseType_t core, forecast_callback fc, progress_callback pc) { if(!forecastTask) { xTaskCreateUniversal(jma_forecast_task, "forecast_task", 8 * 1024, nullptr, priority, &forecastTask, core); - callback_on_forecast = f; + callbackOnForecast = fc; + callbackOnProgress = pc; } return forecastTask != nullptr; } diff --git a/src/jma/jma_task.hpp b/src/jma/jma_task.hpp index e315c4d..affe184 100644 --- a/src/jma/jma_task.hpp +++ b/src/jma/jma_task.hpp @@ -7,8 +7,9 @@ namespace jma { using forecast_callback = void(*)(const officecode_t oc, const Forecast& fc, const WeeklyForecast& wfc); +using progress_callback = void(*)(const size_t readed, const size_t size); -bool initializeForecast(const UBaseType_t priority, const BaseType_t core, forecast_callback f); +bool initializeForecast(const UBaseType_t priority, const BaseType_t core, forecast_callback fc, progress_callback pc); void finalizeForecast(); bool requestForecast(); diff --git a/src/main.cpp b/src/main.cpp index 94666ce..4e2d2aa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,11 +13,12 @@ #include // hardware RNG #include +#include "utility.hpp" #include "aq_talk.hpp" #include "ponko_avatar.hpp" #include "wni_ticker.hpp" #include "weather_map.hpp" -#include "progress_icon.hpp" +#include "progress.hpp" #include "wb2/wxbeacon2_communication.hpp" #include "wb2/wxbeacon2_log.hpp" #include "jma/jma_task.hpp" @@ -25,7 +26,9 @@ #include "cpu_usage.hpp" #ifdef ARDUINO_M5STACK_Core2 +#include "himawari/himawari.hpp" #include "himawari/himawari_task.hpp" +#include "himawari/himawari_screen.hpp" #endif #include @@ -47,8 +50,8 @@ using goblib::datetime::OffsetDateTime; namespace { -// Automatic request interval for advertise. -constexpr uint16_t AUTO_REQUEST_ADVERTISE_INTERVAL_SEC = 5 * 60; +// Automatic request interval. +constexpr uint16_t AUTO_REQUEST_INTERVAL_SEC = 1 * 60; // NTP serve URL const char* ntpURL[] = @@ -66,22 +69,25 @@ const char* ntpURL[] = Avatar* avatar; Ticker* ticker; WeatherMap* weatherMap; +#ifdef ARDUINO_M5STACK_Core2 +HimawariScreen* himawariScreen; +#endif ProgressIcon* progress; bool forceRender = true; // Force rendering all time_t lastUpdate = -1; time_t voiceEnd = -1; -// For task settings. (piority low:0) -constexpr UBaseType_t advertisePriority = 2; -constexpr BaseType_t advertiseCore = 1; +// For task settings. (piority low:0) [Beware of WDT] +constexpr UBaseType_t advertisePriority = 1; +constexpr BaseType_t advertiseCore = 0; // NimBLE task must be core 0. see also https://gitter.im/NimBLE-Arduino/community?source=orgpage constexpr UBaseType_t forecastPriority = 1; -constexpr BaseType_t forecastCore = 1; +constexpr BaseType_t forecastCore = 0; constexpr UBaseType_t himawariPriority = 1; -constexpr BaseType_t himawariCore = 1; +constexpr BaseType_t himawariCore = 0; -constexpr UBaseType_t aqtalkPriority = 2; +constexpr UBaseType_t aqtalkPriority = 1; constexpr BaseType_t aqtalkCore = 1; constexpr UBaseType_t speakerPriority = 1; @@ -122,15 +128,19 @@ struct Weather }; std::map > forecast; -OffsetDateTime requestDatetime; +OffsetDateTime requestForecastDatetime; bool updatedForecast = false; // #ifdef ARDUINO_M5STACK_Core2 -bool updatedHimawari = false; const uint8_t* himawariImage = nullptr; +himawari::Band himawariBand; +OffsetDateTime himawariDatetime; +bool updatedHimawari = false; #endif + + // Ticker text PROGMEM const char DEFAULT_TICKER_TEXT[] = "WEATHEROID Type A Airi "; PROGMEM const char NOTICE_TICKER_TEXT[] = "Press and hold C to put the WxBeacon2 into the broadcast mode. "; @@ -195,10 +205,35 @@ void configTime() bool canRequest() { #ifdef ARDUINO_M5STACK_Core2 - return !busyAdvertise() && !jma::busyForecast() && !himawari::busy(); + return !himawari::busy() && !updatedHimawari && #else - return !busyAdvertise() && !jma::busyForecast(); + return #endif + !busyAdvertise() && !updatedAdvertise && + !jma::busyForecast() && !updatedForecast; +} + +// -------------------------------- +// Request advertise +void _requestAdvertise() +{ + if(canRequest()) + { + requestAdvertise(); + ticker->setTitle(REQUEST_TICKER_TITLE); + } + else + { + WB2_LOGI("Busy"); + } +} + +// Callback on get advertise. +void callbackOnAdvertise(const bool exists, const WxBeacon2::AdvertiseData& ad) +{ + existsBeacon = exists; + updatedAdvertise = true; + advertiseData = ad; } // Play advertise @@ -207,12 +242,16 @@ void playAdvertiseData(const WxBeacon2::AdvertiseData& data) forceRender = true; avatar->closeup(); weatherMap->hide(); +#ifdef ARDUINO_M5STACK_Core2 + himawariScreen->hide(); +#endif + ticker->setTitle("WxBeacon2"); aq_talk::stopAquesTalk(); auto de = data.getE(); if(!existsBeacon || data.format() != WxBeacon2::ADVFormat::E || !de) { - ticker->setText(existsBeacon ? "ERROR" : NOT_EXISTS_BEACON_TICKER_TEXT); + ticker->setText(existsBeacon ? NOTICE_TICKER_TEXT : NOT_EXISTS_BEACON_TICKER_TEXT); ticker->setColor(Ticker::Color::Purple); return; } @@ -249,27 +288,62 @@ void playAdvertiseData(const WxBeacon2::AdvertiseData& data) (float)de->discomfortIndex(), (float)de->heatstroke() ); - ticker->setTitle("WxBeacon2"); ticker->setLevelWBGT(de->heatstroke()); // Set telop color. ticker->setText(ts.c_str()); } - -// Callback on get advertise. -void callbackOnAdvertise(const bool exists, const WxBeacon2::AdvertiseData& ad) -{ - existsBeacon = exists; - updatedAdvertise = true; - advertiseData = ad; -} - -// Request advertise -void _requestAdvertise() +// -------------------------------- +// Request forecast +void _requestForecast() { if(canRequest()) { - lastUpdate = std::time(nullptr); - requestAdvertise(); +#if 0 + // TEST + forecast.clear(); + OffsetDateTime odt = OffsetDateTime::now(); + requestForecastDatetime = odt; + const jma::officecode_t requestTable[] = + { + 16000, // Sapporo + 40000, // Sendai + 130000, // Tokyo + 150000, // Niigata + 170000, // Kanazawa + 230000, // Nagoya + 270000, // Oosaka + 340000, // Hiroshima + 390000, // Kochi + 400000, // Fukuoka + 471000, // Okinawa + }; + + auto& wv = forecast[odt]; + jma::weathercode_t wc = 200; + for(auto& e : requestTable) + { + wv.push_back({e, wc++, -12, 38}); + } + updatedForecast = true; + return; +#endif + + forecast.clear(); + auto odt = OffsetDateTime::now(); + if(odt.toLocalTime() > LocalTime(17, 0, 0)) + { + auto ldt = odt.toLocalDateTime(); + auto epoch = ldt.toEpochSecond(odt.offset()) + 86400; // next day + ldt = LocalDateTime::ofEpochSecond(epoch, odt.offset()); + odt = OffsetDateTime::of(ldt, odt.offset()); + } + requestForecastDatetime = odt; + WB2_LOGI("request forecast:%s", odt.toString().c_str()); + + jma::requestForecast(); + progress->initRatio(); + progress->showProgress(); + ticker->setTitle(REQUEST_TICKER_TITLE); } else @@ -278,58 +352,22 @@ void _requestAdvertise() } } -// Play forecast -void playForecast() +// Callback on progess +void callbackOnProgressForecast(const size_t readed, const size_t size) { - forceRender = true; - avatar->wipe(72, 32, 0.30f); - weatherMap->setDatetime(requestDatetime); - - if(forecast.empty()) - { - avatar->closeup(); - weatherMap->hide(); - ticker->setTitle("ERROR"); - ticker->setColor(Ticker::Color::Purple); - ticker->setText(DEFAULT_TICKER_TEXT); - return; - } - - String ts; - ts.reserve(256); - auto vs = formatString("no/tenki'o/osirase'simasu ", - requestDatetime.month(), requestDatetime.day()); - - weatherMap->clearIcon(); - for(auto& e : forecast) // each date-time - { - WB2_LOGV("%s:[%s] %zu", requestDatetime.toString().c_str(), e.first.toString().c_str(), e.second.size()); - - if(e.first.toLocalDate() != requestDatetime.toLocalDate()) { continue; } // Skip data. - - auto wv = e.second; - std::sort(wv.begin(), wv.end(), [](const Weather& a, const Weather& b) { return a.oc < b.oc; }); // Ascend officecode_t - for(auto& w : wv) - { - ts += w.toString() + ' '; - vs += formatString("%s %s #", aq_talk::officeCodeToTalk(w.oc), aq_talk::weatherCodeToTalk(w.wc)); - - weatherMap->addIcon(w.oc, w.wc); - } - ts += " "; - } - aq_talk::playAquesTalk(vs.c_str(), 120); - - ticker->setTitle("Weather"); - ticker->setText(ts.c_str()); - ticker->setColor(Ticker::Color::Green); - weatherMap->show(); + float ratio = (float)readed / size; + progress->setRatio(ratio); } // Callback on get forecast. void callbackOnForecast(const jma::officecode_t oc, const jma::Forecast& fc, const jma::WeeklyForecast& wfc) { - if(oc == 0) { updatedForecast = true; return; } + if(oc == 0) + { + progress->hideProgress(); + updatedForecast = true; + return; + } if(fc.existsTopWeatherCodes() && fc.existsTopTemp()) { @@ -371,83 +409,142 @@ void callbackOnForecast(const jma::officecode_t oc, const jma::Forecast& fc, con } } -// Request forecast -void _requestForecast() +// Play forecast +void playForecast() { - if(canRequest()) + forceRender = true; +#ifdef ARDUINO_M5STACK_Core2 + himawariScreen->hide(); +#endif + avatar->wipe(72, 32, 0.30f); + weatherMap->setDatetime(requestForecastDatetime); + + if(forecast.empty()) { -#if 0 - himawari::request(); - ticker->setTitle(REQUEST_TICKER_TITLE); + avatar->closeup(); + weatherMap->hide(); + ticker->setTitle("ERROR"); + ticker->setColor(Ticker::Color::Purple); + ticker->setText(DEFAULT_TICKER_TEXT); return; -#endif - -#if 0 - // TEST - lastUpdate = std::time(nullptr); - forecast.clear(); - OffsetDateTime odt = OffsetDateTime::now(); - requestDatetime = odt; - const jma::officecode_t requestTable[] = - { - 16000, // Sapporo - 40000, // Sendai - 130000, // Tokyo - 150000, // Niigata - 170000, // Kanazawa - 230000, // Nagoya - 270000, // Oosaka - 340000, // Hiroshima - 390000, // Kochi - 400000, // Fukuoka - 471000, // Okinawa - }; + } - auto& wv = forecast[odt]; - jma::weathercode_t wc = 200; - for(auto& e : requestTable) - { - wv.push_back({e, wc++, -12, 38}); - } - updatedForecast = true; - return; -#endif + String ts; + ts.reserve(256); + auto vs = formatString("no/tenki'o/osirase'simasu ", + requestForecastDatetime.month(), requestForecastDatetime.day()); - lastUpdate = std::time(nullptr); - forecast.clear(); - auto odt = OffsetDateTime::now(); - if(odt.toLocalTime() > LocalTime(17, 0, 0)) + weatherMap->clearIcon(); + for(auto& e : forecast) // each date-time + { + WB2_LOGV("%s:[%s] %zu", requestForecastDatetime.toString().c_str(), e.first.toString().c_str(), e.second.size()); + + if(e.first.toLocalDate() != requestForecastDatetime.toLocalDate()) { continue; } // Skip data. + + auto wv = e.second; + std::sort(wv.begin(), wv.end(), [](const Weather& a, const Weather& b) { return a.oc < b.oc; }); // Ascend officecode_t + for(auto& w : wv) { - auto ldt = odt.toLocalDateTime(); - auto epoch = ldt.toEpochSecond(odt.offset()) + 86400; // next day - ldt = LocalDateTime::ofEpochSecond(epoch, odt.offset()); - odt = OffsetDateTime::of(ldt, odt.offset()); + ts += w.toString() + ' '; + vs += formatString("%s %s #", aq_talk::officeCodeToTalk(w.oc), aq_talk::weatherCodeToTalk(w.wc)); + + weatherMap->addIcon(w.oc, w.wc); } - requestDatetime = odt; - WB2_LOGI("request forecast:%s", odt.toString().c_str()); + ts += " "; + } + aq_talk::playAquesTalk(vs.c_str(), 120); - jma::requestForecast(); + ticker->setTitle("Weather"); + ticker->setText(ts.c_str()); + ticker->setColor(Ticker::Color::Green); + weatherMap->show(); +} +// -------------------------------- +// Callback on End of aqtalk. +void callbackOnEndAqTalk() +{ + std::time(&voiceEnd); +} + +// -------------------------------- +// Request himawari image +void _requestHimawari() +{ +#ifdef ARDUINO_M5STACK_Core2 + if(canRequest()) + { +#if 0 + himawari::request(OffsetDateTime::now(), + (himawari::Area)(esp_random() % gob::to_underlying(himawari::Area::Max)), + (himawari::Band)(esp_random() % gob::to_underlying(himawari::Band::Max)) + ); +#else + himawari::request(OffsetDateTime::now(), + himawari::Area::Japan, + (himawari::Band)(esp_random() % gob::to_underlying(himawari::Band::Max)) + ); +#endif + progress->initRatio(); + progress->showProgress(); + progress->setRatio(0.0f); ticker->setTitle(REQUEST_TICKER_TITLE); } else { - WB2_LOGI("Busy"); + WB2_LOGD("busy"); } +#endif } -void callbackOnEndAqTalk() +#ifdef ARDUINO_M5STACK_Core2 +// Callback on progress +void callbackOnProgressHimawari(const size_t readed, const size_t size) { - voiceEnd = std::time(nullptr); + float ratio = (float)readed / size; + progress->setRatio(ratio); } -#ifdef ARDUINO_M5STACK_Core2 -// Request himawari image -void callbackOnImage(const uint8_t* ptr) +// Callback on get himawwri image. +void callbackOnHimawariImage(const uint8_t* ptr, const himawari::Band band, const OffsetDateTime& odt) { + progress->hideProgress(); himawariImage = ptr; + himawariBand = band; + himawariDatetime = odt; updatedHimawari = true; } + +PROGMEM static const char talkHimawari[] = "kisyou'eisei'himawarino 'gazouo 'gorannkudasai"; + +// Draw himawari image +void drawHimawari() +{ + forceRender = true; + weatherMap->hide(); + himawariScreen->set(himawariDatetime, himawariImage); + + if(!himawariImage) + { + himawariScreen->hide(); + avatar->closeup(); + ticker->setTitle("ERROR"); + ticker->setColor(Ticker::Color::Purple); + ticker->setText(DEFAULT_TICKER_TEXT); + return; + } + aq_talk::playAquesTalk(talkHimawari, 120); + himawariScreen->show(); + avatar->wipe(204, 152 , 0.25f); + ticker->setTitle("Satellite"); + String ts = himawari::bandToString(himawariBand) + " "; + ticker->setText(ts.c_str()); + ticker->setColor(Ticker::Color::Green); + + // _requestHimawari(); + +} + #endif PROGMEM static const char t0[] = "minnasa--n,ponnbanwa,weza-roido'taipuei,airi'desu"; @@ -456,7 +553,7 @@ PROGMEM static const char t2[] = "weza-roido'una'na-i wa arimasen"; const char* talkTable[] = { t0, t1, t2 }; void talkRandom() { - auto idx = esp_random() % (sizeof(talkTable)/sizeof(talkTable[0])); + auto idx = esp_random() % gob::size(talkTable); aq_talk::playAquesTalk(talkTable[idx], 110); } // @@ -475,7 +572,7 @@ void setup() esp_log_level_set("NimBLEDevice", (esp_log_level_t)0); esp_log_level_set("NIMBLE_NVS", (esp_log_level_t)0); - // Incrase heap + // Incrase internal heap. esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); // @@ -491,15 +588,16 @@ void setup() scfg.task_pinned_core = speakerCore; M5.Speaker.config(scfg); M5.Speaker.begin(); +#ifdef NDEBUG M5.Speaker.setVolume(bd == m5::board_t::board_M5Stack ? 128 : 64); - // M5.Speaker.setVolume(bd == m5::board_t::board_M5Stack ? 80 : 40); - +#else + M5.Speaker.setVolume(bd == m5::board_t::board_M5Stack ? 80 : 40); +#endif + delay(500); M5.Display.setBrightness(40); M5.Display.clear(); - WB2_LOGV("objects"); - // Avatar,Ticker and WeatherMap avatar = new Avatar(); assert(avatar); @@ -508,19 +606,22 @@ void setup() ticker->setText(DEFAULT_TICKER_TEXT); weatherMap = new WeatherMap(); assert(weatherMap); +#ifdef ARDUINO_M5STACK_Core2 + himawariScreen = new HimawariScreen(); + assert(himawariScreen); +#endif progress = new ProgressIcon(); assert(progress); - - WB2_LOGV("after objects"); + // ConfigTime configTime(); M5.Display.fillScreen(TFT_DARKGREEN); // WxBeacon2 / Forecast / Himawari initilizeAdvertise(advertisePriority, advertiseCore, callbackOnAdvertise); - jma::initializeForecast(forecastPriority, forecastCore, callbackOnForecast); + jma::initializeForecast(forecastPriority, forecastCore, callbackOnForecast, callbackOnProgressForecast); #ifdef ARDUINO_M5STACK_Core2 - himawari::initialize(himawariPriority, himawariCore, callbackOnImage); + himawari::initialize(himawariPriority, himawariCore, callbackOnHimawariImage, callbackOnProgressHimawari); #endif // AquesTalk @@ -615,6 +716,7 @@ void loop() { longPressA = true; _requestForecast(); + //_requestHimawari(); } if(M5.BtnA.wasReleased()) { @@ -625,26 +727,13 @@ void loop() longPressA = false; } - time_t t = time(nullptr); - -#if 0 - // Obtain beaocn data at intervals. - - if(canRequest() && lastUpdate > 0 && std::difftime(t, lastUpdate) >= AUTO_REQUEST_ADVERTISE_INTERVAL_SEC) - { - _requestAdvertise(); - } -#endif - - // Random talking - if(!aq_talk::busy() && voiceEnd > 0 && std::difftime(t, voiceEnd) >= 60) - { - talkRandom(); - } - + time_t now{}; + std::time(&now); + // Play latest advertise data if exists. if(updatedAdvertise) { + std::time(&lastUpdate); updatedAdvertise = false; playAdvertiseData(advertiseData); } @@ -652,9 +741,26 @@ void loop() // Play latest forecast if(updatedForecast) { + std::time(&lastUpdate); updatedForecast = false; playForecast(); } + + // Draw himawari image +#ifdef ARDUINO_M5STACK_Core2 + if(updatedHimawari) + { + std::time(&lastUpdate); + updatedHimawari = false; + drawHimawari(); + } +#endif + + // Random talking + if(!aq_talk::busy() && voiceEnd > 0 && std::difftime(now, voiceEnd) >= 60) + { + talkRandom(); + } // Update avatar->pump(); @@ -663,11 +769,14 @@ void loop() progress->pump(busyAdvertise(), (jma::busyForecast() || himawari::busy())); #else progress->pump(busyAdvertise(), jma::busyForecast()); -#endif +#endif // Rendering { weatherMap->render(&M5.Display, forceRender); +#ifdef ARDUINO_M5STACK_Core2 + himawariScreen->render(&M5.Display, forceRender); +#endif avatar->render(&M5.Display, forceRender); ticker->render(&M5.Display); progress->render(&M5.Display); @@ -693,14 +802,24 @@ void loop() #endif } + +#if 1 + // Auto request + if(canRequest() && lastUpdate > 0 && std::difftime(now, lastUpdate) >= AUTO_REQUEST_INTERVAL_SEC) + { + WB2_LOGI("auto: %lf", std::difftime(now, lastUpdate)); + //_requestAdvertise(); + _requestHimawari(); + } +#endif + // Keep about 30 FPS. auto end = millis(); -#if 0 - if((end - start) >= (1000/30)) +#ifdef M5S_WXBEACON2_DEBUG_INFO + if((end - start) > (1000/30)) { WB2_LOGD("over:%lu", (end - start) - (1000/30)); } #endif - delay((end - start) >= (1000/30) ? 1 : (1000/30) - (end -start)); } diff --git a/src/progress.cpp b/src/progress.cpp new file mode 100644 index 0000000..9d56f23 --- /dev/null +++ b/src/progress.cpp @@ -0,0 +1,69 @@ +/* + Icon indicating access to WiFi or BT in progress. + Progress bar for download. + */ + +#include "progress.hpp" +#include "res/resource.h" + +namespace +{ +#if 0 +constexpr int16_t ICON_X = 284; +constexpr int16_t ICON_Y = 160; +#else +constexpr int16_t ICON_X = 4; +constexpr int16_t ICON_Y = 160; +#endif + +inline int32_t roundTrip(const int32_t c) +{ + // return ( (c & 256) + ( (c & 255) ^ (0 - ((c >> 8) & 1)) ) ); + //return ( (c & 128) + ( (c & 127) ^ (0 - ((c >> 7) & 1)) ) ); + return ( (c & 32) + ( (c & 31) ^ (0 - ((c >> 5) & 1)) ) ); +} + +#if 0 +constexpr int16_t PROGRESS_X = 4; +#else +constexpr int16_t PROGRESS_X = 40; +#endif +constexpr int16_t PROGRESS_Y = 180; +constexpr int16_t PROGRESS_WIDTH = 100; +constexpr int16_t PROGRESS_HEIGHT = 8; +constexpr uint16_t PROGRESS_BG_CLR = TFT_BLACK; +constexpr uint16_t PROGRESS_FG_CLR = TFT_SKYBLUE; +// +} + +ProgressIcon::ProgressIcon() +{ + _btSprite = new LGFX_Sprite(); + assert(_btSprite); + _btSprite->createFromBmp(bt_bmp, bt_bmp_len); + + _wifiSprite = new LGFX_Sprite(); + assert(_wifiSprite); + _wifiSprite->createFromBmp(wifi_bmp, wifi_bmp_len); +} + +void ProgressIcon::render(m5gfx::M5GFX* dst) +{ + auto v = roundTrip(_cnt); + _btSprite->setPaletteColor (1, v * 8, v * 8, v * 8); + _wifiSprite->setPaletteColor(1, v * 8, v * 8, v * 8); + + if(_bt) { _btSprite->pushSprite(dst, ICON_X, ICON_Y, 0); } + if(_wifi) { _wifiSprite->pushSprite(dst, ICON_X, ICON_Y, 0); } + + if(_showProgress && _ratio != _prevRatio) + { + _prevRatio = _ratio; + int16_t wid = _ratio >= 100.0f ? PROGRESS_WIDTH - 2 : (PROGRESS_WIDTH - 2)* _ratio; + dst->drawRect(PROGRESS_X, PROGRESS_Y, PROGRESS_WIDTH, PROGRESS_HEIGHT, TFT_WHITE); + dst->fillRect(PROGRESS_X + 1, PROGRESS_Y + 1, + wid, PROGRESS_HEIGHT - 2, PROGRESS_FG_CLR); + dst->fillRect(PROGRESS_X + 1 + wid, PROGRESS_Y + 1, + PROGRESS_WIDTH - 2 - wid, PROGRESS_HEIGHT - 2, PROGRESS_BG_CLR); + } +} diff --git a/src/progress.hpp b/src/progress.hpp new file mode 100644 index 0000000..5dc9eea --- /dev/null +++ b/src/progress.hpp @@ -0,0 +1,34 @@ +/* + Icon indicating access to WiFi or BT in progress. + Progress bar for download. + */ +#ifndef PROGRESS_HPP +#define PROGRESS_HPP + +#include + +class ProgressIcon +{ + public: + ProgressIcon(); + + inline void pump(const bool bt, const bool wifi) { _bt = bt; _wifi = wifi; ++_cnt; } + + inline void showProgress() { showProgress(true); } + inline void hideProgress() { showProgress(false); } + inline void showProgress(const bool b) { _showProgress = b; } + + inline void initRatio() { _ratio = 0.0f; _prevRatio = -1.0f; } + inline void setRatio(const float ratio) { _ratio = ratio; } + + void render(m5gfx::M5GFX* dst); + + private: + bool _bt{}, _wifi{}, _showProgress{}; + uint16_t _cnt{}; + float _ratio{}, _prevRatio{}; + LGFX_Sprite* _btSprite{}; + LGFX_Sprite* _wifiSprite{}; + +}; +#endif diff --git a/src/progress_icon.cpp b/src/progress_icon.cpp deleted file mode 100644 index 67a8f08..0000000 --- a/src/progress_icon.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - Icon indicating access to WiFi or BT in progress - */ - -#include "progress_icon.hpp" -#include "res/resource.h" - -namespace -{ -constexpr int16_t ICON_X = 284; -constexpr int16_t ICON_Y = 160; - -inline int32_t roundTrip(const int32_t c) -{ - // return ( (c & 256) + ( (c & 255) ^ (0 - ((c >> 8) & 1)) ) ); - return ( (c & 128) + ( (c & 127) ^ (0 - ((c >> 7) & 1)) ) ); -} - -// -} - -ProgressIcon::ProgressIcon() -{ - _btSprite = new LGFX_Sprite(); - assert(_btSprite); - _btSprite->createFromBmp(bt_bmp, bt_bmp_len); - - _wifiSprite = new LGFX_Sprite(); - assert(_wifiSprite); - _wifiSprite->createFromBmp(bt_bmp, bt_bmp_len); -} - - -// { _bt = bt; _wifi = wifi; } - -void ProgressIcon::render(m5gfx::M5GFX* dst) -{ - auto v = roundTrip(_cnt); - _btSprite->setPaletteColor (1, v * 2, v * 2, v * 2); - _wifiSprite->setPaletteColor(1, v * 2, v * 2, v * 2); - - if(_bt) { _btSprite->pushSprite(dst, ICON_X, ICON_Y, 0); } - if(_wifi) { _wifiSprite->pushSprite(dst, ICON_X, ICON_Y, 0); } -} diff --git a/src/progress_icon.hpp b/src/progress_icon.hpp deleted file mode 100644 index 9a45aa8..0000000 --- a/src/progress_icon.hpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - Icon indicating access to WiFi or BT in progress - */ -#ifndef PROGRESS_ICON_HPP -#define PROGRESS_ICON_HPP - -#include - -class ProgressIcon -{ - public: - ProgressIcon(); - - inline void pump(const bool bt, const bool wifi) { _bt = bt; _wifi = wifi; ++_cnt; } - void render(m5gfx::M5GFX* dst); - - private: - bool _bt{}, _wifi{}; - uint16_t _cnt{}; - LGFX_Sprite* _btSprite{}; - LGFX_Sprite* _wifiSprite{}; - -}; -#endif diff --git a/src/utility.hpp b/src/utility.hpp new file mode 100644 index 0000000..64553a5 --- /dev/null +++ b/src/utility.hpp @@ -0,0 +1,62 @@ +/* + Utility templates + */ +#ifndef UTILITY_HPP +#define UTILITY_HPP + +#include +#include +#include +#include +#include + +namespace gob +{ + +// Size of array. +template constexpr auto size(const C& c) -> decltype(c.size()) { return c.size(); } +template constexpr auto size(const T(&)[N]) noexcept -> size_t { return N; } + +// Underlying +template constexpr typename std::underlying_type::type to_underlying(T e) noexcept +{ + return static_cast::type>(e); +} + +// Exists T.toString()? +template struct has_toString +{ + template static std::true_type check(U*); + static std::false_type check(...); + static T* _cls; + static const bool value = decltype(check(_cls))::value; +}; + +/* Like join function of Ruby. (For Integral, Floating-point, and String) + join({1, 2, 3}, "/"); // "1/2/3" + */ +template::value || std::is_integral::value || std::is_same::value, std::nullptr_t>::type = nullptr> +String join(const std::vector& v, const char* separator = ", ") +{ + + return !v.empty() ? std::accumulate(++v.cbegin(), v.cend(), String(v[0]), + [&separator](const String& a, const T& b) + { + return a + separator + String(b); + }): String(); +} + +// Like join function of Ruby. (For classes that has the toString function.) +template::value, std::nullptr_t>::type = nullptr> +String join(const std::vector& v, const char* separator = ", ") +{ + return !v.empty() ? std::accumulate(++v.cbegin(), v.cend(), v[0].toString(), + [&separator](const String& a, const T& b) + { + return a + separator + b.toString(); + }) : String(); +} + +// +} +#endif diff --git a/src/wb2/wxbeacon2_communication.cpp b/src/wb2/wxbeacon2_communication.cpp index 112a441..c1bc437 100644 --- a/src/wb2/wxbeacon2_communication.cpp +++ b/src/wb2/wxbeacon2_communication.cpp @@ -47,7 +47,8 @@ void wb2_advertise_task(void*) ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); WB2_LOGI("Start scanning"); - NimBLEDevice::init(""); + NimBLEDevice::init(""); + delay(100); NimBLEScan* scan = NimBLEDevice::getScan(); WxBeacon2AdvertiseCallbacks cb; scan->setAdvertisedDeviceCallbacks(&cb); @@ -60,14 +61,14 @@ void wb2_advertise_task(void*) while(scan->isScanning()) { delay(100); } wb2address = cb.address(); - if(callback_on_advertise) { callback_on_advertise(cb.detected(), cb.data()); } - scan->stop(); scan->clearResults(); NimBLEDevice::deinit(false); + delay(100); WB2_LOGI("End of scanning. detected :%d", cb.detected()); progressAdvertise = false; + if(callback_on_advertise) { callback_on_advertise(cb.detected(), cb.data()); } } } // From 93951ed68d24a649b8ed8f506631a706cd0ffbcf Mon Sep 17 00:00:00 2001 From: GOB Date: Fri, 23 Dec 2022 22:30:49 +0900 Subject: [PATCH 07/31] Some tweaks --- src/main.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4e2d2aa..e87f884 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -540,11 +540,7 @@ void drawHimawari() String ts = himawari::bandToString(himawariBand) + " "; ticker->setText(ts.c_str()); ticker->setColor(Ticker::Color::Green); - - // _requestHimawari(); - } - #endif PROGMEM static const char t0[] = "minnasa--n,ponnbanwa,weza-roido'taipuei,airi'desu"; @@ -807,7 +803,6 @@ void loop() // Auto request if(canRequest() && lastUpdate > 0 && std::difftime(now, lastUpdate) >= AUTO_REQUEST_INTERVAL_SEC) { - WB2_LOGI("auto: %lf", std::difftime(now, lastUpdate)); //_requestAdvertise(); _requestHimawari(); } From 807eb3e1481cf5e2a1e12ab93dad0a8a621fed78 Mon Sep 17 00:00:00 2001 From: GOB Date: Fri, 23 Dec 2022 22:35:11 +0900 Subject: [PATCH 08/31] Rename some files --- src/main.cpp | 2 +- src/wb2/{wxbeacon2_communication.cpp => wxbeacon2_task.cpp} | 2 +- src/wb2/{wxbeacon2_communication.hpp => wxbeacon2_task.hpp} | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/wb2/{wxbeacon2_communication.cpp => wxbeacon2_task.cpp} (99%) rename src/wb2/{wxbeacon2_communication.hpp => wxbeacon2_task.hpp} (84%) diff --git a/src/main.cpp b/src/main.cpp index e87f884..ba8ae47 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,7 +19,7 @@ #include "wni_ticker.hpp" #include "weather_map.hpp" #include "progress.hpp" -#include "wb2/wxbeacon2_communication.hpp" +#include "wb2/wxbeacon2_task.hpp" #include "wb2/wxbeacon2_log.hpp" #include "jma/jma_task.hpp" #include diff --git a/src/wb2/wxbeacon2_communication.cpp b/src/wb2/wxbeacon2_task.cpp similarity index 99% rename from src/wb2/wxbeacon2_communication.cpp rename to src/wb2/wxbeacon2_task.cpp index c1bc437..5d500d3 100644 --- a/src/wb2/wxbeacon2_communication.cpp +++ b/src/wb2/wxbeacon2_task.cpp @@ -1,7 +1,7 @@ #include #include -#include "wxbeacon2_communication.hpp" +#include "wxbeacon2_task.hpp" #include "wxbeacon2_ble.hpp" #include "wxbeacon2_log.hpp" diff --git a/src/wb2/wxbeacon2_communication.hpp b/src/wb2/wxbeacon2_task.hpp similarity index 84% rename from src/wb2/wxbeacon2_communication.hpp rename to src/wb2/wxbeacon2_task.hpp index 1b57fb4..a606ad4 100644 --- a/src/wb2/wxbeacon2_communication.hpp +++ b/src/wb2/wxbeacon2_task.hpp @@ -1,6 +1,6 @@ -#ifndef WXBEACON2_COMMUNICATION_HPP -#define WXBEACON2_COMMUNICATION_HPP +#ifndef WXBEACON2_TASK_HPP +#define WXBEACON2_TASK_HPP #include "wxbeacon2.hpp" From 893e91e3f8b121c4719a916d6265e65879462b79 Mon Sep 17 00:00:00 2001 From: GOB Date: Sat, 24 Dec 2022 18:47:30 +0900 Subject: [PATCH 09/31] Shuffle the ntp connection targets. Add default ticker title. --- src/main.cpp | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ba8ae47..809d3fd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,7 +10,7 @@ #include #include #include // esp_bt_controller_mem_release -#include // hardware RNG +#include // esp_random() is hardware RNG. (No random seed initialization is required) #include #include "utility.hpp" @@ -54,12 +54,10 @@ namespace constexpr uint16_t AUTO_REQUEST_INTERVAL_SEC = 1 * 60; // NTP serve URL -const char* ntpURL[] = -{ - "ntp.nict.jp", - "ntp.jst.mfeed.ad.jp", - "time.cloudflare.com", -}; +PROGMEM const char ntp0[] = "ntp.nict.jp"; +PROGMEM const char ntp1[] = "ntp.jst.mfeed.ad.jp"; +PROGMEM const char ntp2[] = "time.cloudflare.com"; +const char* ntpURLTable[] = { ntp0, ntp1, ntp2 }; // DON'T USE PROGMEM! (because it will be shuffled later) // For configurate time #ifndef M5S_WXBEACON2_TIMEZONE_LOCATION @@ -139,9 +137,8 @@ OffsetDateTime himawariDatetime; bool updatedHimawari = false; #endif - - // Ticker text +PROGMEM const char DEFAULT_TICKER_TITLE[] = "Ponko"; PROGMEM const char DEFAULT_TICKER_TEXT[] = "WEATHEROID Type A Airi "; PROGMEM const char NOTICE_TICKER_TEXT[] = "Press and hold C to put the WxBeacon2 into the broadcast mode. "; PROGMEM const char NOT_EXISTS_BEACON_TICKER_TEXT[] = "WxBeacon2 IS NOT EXISTS. "; @@ -172,6 +169,15 @@ std::string formatString(const char* fmt, ...) } #endif +struct ESP32RNG +{ + using result_type = uint32_t; + static result_type min() { return 0; } + static result_type max() { return gob::size(ntpURLTable); } + result_type operator()() { return esp_random() % max(); } +}; + + // Configurate Time by NTP. void configTime() { @@ -189,13 +195,15 @@ void configTime() abort(); } + std::shuffle(std::begin(ntpURLTable), std::end(ntpURLTable), ESP32RNG()); auto ptz = goblib::datetime::locationToPOSIX(M5S_WXBEACON2_TIMEZONE_LOCATION); - WB2_LOGI("tz:[%s]", ptz ? ptz : "NONE"); - configTzTime(ptz ? ptz : "", ntpURL[0], ntpURL[1], ntpURL[2]); + WB2_LOGI("tz:[%s] [%s] [%s] [%s]", ptz ? ptz : "NONE", ntpURLTable[0], ntpURLTable[1], ntpURLTable[2]); + + configTzTime(ptz ? ptz : "", ntpURLTable[0], ntpURLTable[1], ntpURLTable[2]); // waiting for time synchronization { std::tm discard{}; - getLocalTime(&discard, 5 * 1000); + getLocalTime(&discard, 10 * 1000); } WiFi.disconnect(true); WiFi.mode(WIFI_OFF); @@ -599,6 +607,7 @@ void setup() assert(avatar); ticker = new Ticker(); assert(ticker); + ticker->setTitle(DEFAULT_TICKER_TITLE); ticker->setText(DEFAULT_TICKER_TEXT); weatherMap = new WeatherMap(); assert(weatherMap); @@ -799,7 +808,7 @@ void loop() } -#if 1 +#if 0 // Auto request if(canRequest() && lastUpdate > 0 && std::difftime(now, lastUpdate) >= AUTO_REQUEST_INTERVAL_SEC) { From a95426e11415681366da1af76cc5cef2b128c5b7 Mon Sep 17 00:00:00 2001 From: GOB Date: Sat, 24 Dec 2022 22:36:13 +0900 Subject: [PATCH 10/31] Fixes lib_deps --- platformio.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platformio.ini b/platformio.ini index 7ed04b2..7a3bf4b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,9 +15,9 @@ board_build.f_cpu = 240000000L ; https://github.com/tanakamasayuki/aquestalk download zip and extract ./lib folder. ;lib_extra_dirs = /lib lib_ldf_mode = deep -lib_deps = m5stack/M5Unified - h2zero/NimBLE-Arduino - https://github.com/mrfaptastic/json-streaming-parser2.git @ ^2.0.3 +lib_deps = m5stack/M5Unified @ ^0.0.7 + h2zero/NimBLE-Arduino @^1.3.8 + https://github.com/mrfaptastic/json-streaming-parser2.git @ ^2.1.0 https://github.com/GOB52/gob_datetime.git @ ^0.1.1 monitor_speed = 115200 From 81e757844a5d610e61cc879ad601ae2164c5d0cd Mon Sep 17 00:00:00 2001 From: GOB Date: Sat, 24 Dec 2022 22:42:43 +0900 Subject: [PATCH 11/31] Fixes reduce width of the progress bar. --- src/main.cpp | 7 +++---- src/progress.cpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 809d3fd..ef1ae77 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -177,12 +177,11 @@ struct ESP32RNG result_type operator()() { return esp_random() % max(); } }; - // Configurate Time by NTP. void configTime() { // WiFi connect - WiFi.begin(); // Connect to credential in Hardware. (ESP32 saves the last Wifi connection) + WiFi.begin(); // Connect to credential in Hardware. (ESP32 saves the last WiFi connection) int tcount = 20; while(tcount-- > 0 && WiFi.status() != WL_CONNECTED) { @@ -286,7 +285,7 @@ void playAdvertiseData(const WxBeacon2::AdvertiseData& data) aq_talk::playAquesTalk(vs.c_str(), 120); // auto ts = formatString("TEMP %3.1fdegC HUM %3.1f%% AL %dlx UV %3.1f PRESURE %4.1fhPa N %3.1fdB DCMFT %3.1f WBGT %3.1f ", - auto ts = formatString("気温:%3.1f度 湿度:%3.1f%% 明度:%dlx UV指数:%3.1f 気圧:%4.1fhPa 騒音:%3.1fdB 不快指数:%3.1f WBGT:%3.1f ", + auto ts = formatString("気温:%3.1f℃ 湿度:%3.1f%% 明度:%dlx UV指数:%3.1f 気圧:%4.1fhPa 騒音:%3.1fdB 不快指数:%3.1f WBGT:%3.1f ", (float)de->temperature(), (float)de->relativeHumidity(), (int)de->ambientLight(), @@ -808,7 +807,7 @@ void loop() } -#if 0 +#if 1 // Auto request if(canRequest() && lastUpdate > 0 && std::difftime(now, lastUpdate) >= AUTO_REQUEST_INTERVAL_SEC) { diff --git a/src/progress.cpp b/src/progress.cpp index 9d56f23..4aa8eff 100644 --- a/src/progress.cpp +++ b/src/progress.cpp @@ -29,7 +29,7 @@ constexpr int16_t PROGRESS_X = 4; constexpr int16_t PROGRESS_X = 40; #endif constexpr int16_t PROGRESS_Y = 180; -constexpr int16_t PROGRESS_WIDTH = 100; +constexpr int16_t PROGRESS_WIDTH = 80; constexpr int16_t PROGRESS_HEIGHT = 8; constexpr uint16_t PROGRESS_BG_CLR = TFT_BLACK; constexpr uint16_t PROGRESS_FG_CLR = TFT_SKYBLUE; From 7d1c68fc2559a7509d74dd5015b64fafd4043292 Mon Sep 17 00:00:00 2001 From: GOB Date: Sat, 24 Dec 2022 23:04:06 +0900 Subject: [PATCH 12/31] Fixes .gitignore and add some resources. --- .gitignore | 10 ++- src/res/bt.cpp | 23 +++++ src/res/jpmap.cpp | 213 ++++++++++++++++++++++++++++++++++++++++++++++ src/res/wifi.cpp | 23 +++++ 4 files changed, 267 insertions(+), 2 deletions(-) create mode 100644 src/res/bt.cpp create mode 100644 src/res/jpmap.cpp create mode 100644 src/res/wifi.cpp diff --git a/.gitignore b/.gitignore index f3f68a4..321579b 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,13 @@ *.app #pio -/.pio +/.pio/ # resources -/src/res/*.cpp +/src/res/* +!/res/resource.h +!/res/u8g2_font_profont22_tr.* +!/res/wifi.cpp +!/res/bt.cpp +!/res/jpmap.cpp + diff --git a/src/res/bt.cpp b/src/res/bt.cpp new file mode 100644 index 0000000..a8957f0 --- /dev/null +++ b/src/res/bt.cpp @@ -0,0 +1,23 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t bt_bmp[] = { + 0x42, 0x4d, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x80, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, + 0xf0, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x61, + 0xce, 0x00, 0x00, 0xf1, 0xcf, 0x00, 0x00, 0x79, 0xce, 0x00, 0x00, 0x3d, + 0xfc, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x07, + 0xf0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, + 0xf0, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x3d, + 0xfc, 0x00, 0x00, 0x79, 0xce, 0x00, 0x00, 0xf1, 0xcf, 0x00, 0x00, 0x61, + 0xce, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x01, + 0xf0, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, + 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +const size_t bt_bmp_len = 190; diff --git a/src/res/jpmap.cpp b/src/res/jpmap.cpp new file mode 100644 index 0000000..7a3ce9e --- /dev/null +++ b/src/res/jpmap.cpp @@ -0,0 +1,213 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t jpmap_bmp[] = { + 0x42, 0x4d, 0x9e, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x78, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x58, 0x88, 0x10, 0x00, 0xa0, 0x50, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x07, 0xf8, + 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xf8, 0x00, + 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x03, 0xe0, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xf8, 0x00, + 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x03, 0xe0, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xf8, 0x00, + 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x03, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xfc, 0x00, + 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0xfc, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xfc, + 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, + 0x03, 0xff +}; +const size_t jpmap_bmp_len = 2462; diff --git a/src/res/wifi.cpp b/src/res/wifi.cpp new file mode 100644 index 0000000..5f2485a --- /dev/null +++ b/src/res/wifi.cpp @@ -0,0 +1,23 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t wifi_bmp[] = { + 0x42, 0x4d, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x80, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0x06, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x1f, + 0xf8, 0x00, 0x04, 0x07, 0xe0, 0x20, 0x07, 0x00, 0x00, 0xf0, 0x07, 0x80, + 0x01, 0xe0, 0x03, 0xe0, 0x07, 0xc0, 0x00, 0xff, 0xff, 0x00, 0xe0, 0x3f, + 0xfc, 0x07, 0x70, 0x07, 0xe0, 0x0e, 0x3c, 0x00, 0x00, 0x3c, 0x1f, 0x00, + 0x00, 0xf8, 0x07, 0xc0, 0x03, 0xf0, 0x03, 0xff, 0xff, 0xc0, 0x00, 0x7f, + 0xfe, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +const size_t wifi_bmp_len = 190; From 789eb8e3bfb10bcdfdf205e1db908df37e07f593 Mon Sep 17 00:00:00 2001 From: GOB Date: Sun, 25 Dec 2022 03:30:13 +0900 Subject: [PATCH 13/31] Make it possible to ticker telop draw a color string. --- .gitignore | 10 ++--- src/aq_talk.cpp | 21 ++------- src/aq_talk.hpp | 1 - src/main.cpp | 27 ++++++++++-- src/utility.cpp | 29 +++++++++++++ src/utility.hpp | 3 ++ src/wni_ticker.cpp | 103 ++++++++++++++++++++++++++++----------------- src/wni_ticker.hpp | 14 +++--- 8 files changed, 137 insertions(+), 71 deletions(-) create mode 100644 src/utility.cpp diff --git a/.gitignore b/.gitignore index 321579b..94dbb9a 100644 --- a/.gitignore +++ b/.gitignore @@ -36,9 +36,9 @@ # resources /src/res/* -!/res/resource.h -!/res/u8g2_font_profont22_tr.* -!/res/wifi.cpp -!/res/bt.cpp -!/res/jpmap.cpp +!/src/res/resource.h +!/src/res/u8g2_font_profont22_tr.* +!/src/res/wifi.cpp +!/src/res/bt.cpp +!/src/res/jpmap.cpp diff --git a/src/aq_talk.cpp b/src/aq_talk.cpp index e786bcd..0787975 100644 --- a/src/aq_talk.cpp +++ b/src/aq_talk.cpp @@ -8,9 +8,9 @@ #include #include #include -#include #include #include +#include "utility.hpp" #include "wb2/wxbeacon2_log.hpp" namespace @@ -296,25 +296,10 @@ TaskHandle_t task_handle = nullptr; volatile bool is_talking = false; volatile uint32_t level = 0; -std::vector koeQueue; +std::vector koeQueue; uint16_t koeSpeed = 100; uint16_t koeLenPause = 256U; -std::vector split(const char* s, const char* separator = ",") -{ - std::vector out; - char dup[strlen(s) + 1]; - snprintf(dup, sizeof(dup), "%s", s); - - auto p = strtok(dup, separator); - if(p) - { - out.emplace_back(p); - while((p = strtok(nullptr, separator))) { out.emplace_back(p); } - } - return out; -} - void calcGainAverage(const int16_t* wav, const size_t len) { uint32_t acc = 0; @@ -410,7 +395,7 @@ bool playAquesTalk(const char *koe, const uint16_t speed, const uint16_t lenPaus // Split and store queue. (CAqTkPicoF_SetKoe has a length limitation) koeQueue.clear(); - koeQueue = split(koe, "#"); + koeQueue = gob::split(koe, '#'); koeSpeed = speed; koeLenPause = lenPause; WB2_LOGV("queue:%zu", koeQueue.size()); diff --git a/src/aq_talk.hpp b/src/aq_talk.hpp index 3e294d0..8dffd43 100644 --- a/src/aq_talk.hpp +++ b/src/aq_talk.hpp @@ -6,7 +6,6 @@ #define AQ_TALK_HPP #include "jma/jma_definition.hpp" -//#include namespace aq_talk { diff --git a/src/main.cpp b/src/main.cpp index ef1ae77..cb7e239 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -123,7 +123,26 @@ struct Weather buf[sizeof(buf)-1] = '\0'; return String(buf); } - + String toColorString() const + { + char buf[128]; + // low == temp means Iinvalid data.(The lowest highest temperature on the day of the announcement is invalid) + if(lowTemp != highTemp) + { + snprintf(buf, sizeof(buf), "#@1[%s] %s #@2%d℃#@3%d℃",// @"#n" Palette NO of text for ticker. + jma::officesCodeToString(oc), + jma::weatherCodeToString(wc), + highTemp, lowTemp); + } + else + { + snprintf(buf, sizeof(buf), "[%s] %s", + jma::officesCodeToString(oc), + jma::weatherCodeToString(wc)); + } + buf[sizeof(buf)-1] = '\0'; + return String(buf); + } }; std::map > forecast; OffsetDateTime requestForecastDatetime; @@ -285,7 +304,7 @@ void playAdvertiseData(const WxBeacon2::AdvertiseData& data) aq_talk::playAquesTalk(vs.c_str(), 120); // auto ts = formatString("TEMP %3.1fdegC HUM %3.1f%% AL %dlx UV %3.1f PRESURE %4.1fhPa N %3.1fdB DCMFT %3.1f WBGT %3.1f ", - auto ts = formatString("気温:%3.1f℃ 湿度:%3.1f%% 明度:%dlx UV指数:%3.1f 気圧:%4.1fhPa 騒音:%3.1fdB 不快指数:%3.1f WBGT:%3.1f ", + auto ts = formatString("気温:#@2%3.1f#@1℃ 湿度#@2:%3.1f#@1%% 明度:#@2%d#@1lx UV指数:#@2%3.1f #@1気圧:#@2%4.1f#@1hPa 騒音:#@2%3.1f#@1dB 不快指数:#@2%3.1f #@1WBGT:#@2%3.1f ", (float)de->temperature(), (float)de->relativeHumidity(), (int)de->ambientLight(), @@ -452,7 +471,7 @@ void playForecast() std::sort(wv.begin(), wv.end(), [](const Weather& a, const Weather& b) { return a.oc < b.oc; }); // Ascend officecode_t for(auto& w : wv) { - ts += w.toString() + ' '; + ts += w.toColorString() + ' '; vs += formatString("%s %s #", aq_talk::officeCodeToTalk(w.oc), aq_talk::weatherCodeToTalk(w.wc)); weatherMap->addIcon(w.oc, w.wc); @@ -577,7 +596,7 @@ void setup() // Incrase internal heap. esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); - + // M5.begin(); auto bd = M5.getBoard(); diff --git a/src/utility.cpp b/src/utility.cpp new file mode 100644 index 0000000..4c26d8e --- /dev/null +++ b/src/utility.cpp @@ -0,0 +1,29 @@ + +#include"utility.hpp" + +#include +#include + +namespace gob +{ +std::vector split(const String& str, const char delimiter) +{ + std::vector out; + int start = 0; + int end = str.indexOf(delimiter); + + while(end >= 0) + { + out.emplace_back(str.substring(start, end)); + start = end + 1; + end = str.indexOf(delimiter, start); + } + out.emplace_back(str.substring(start)); + return out; +} + + + + +// +} diff --git a/src/utility.hpp b/src/utility.hpp index 64553a5..aa82849 100644 --- a/src/utility.hpp +++ b/src/utility.hpp @@ -57,6 +57,9 @@ String join(const std::vector& v, const char* separator = ", ") }) : String(); } +// Solit string +std::vector split(const String& str, const char delimiter = ','); +inline std::vector split(const char* s, const char delimiter = ',') { return split(String(s), delimiter); } // } #endif diff --git a/src/wni_ticker.cpp b/src/wni_ticker.cpp index c963f6f..143f5aa 100644 --- a/src/wni_ticker.cpp +++ b/src/wni_ticker.cpp @@ -5,19 +5,27 @@ #include "gob_datetime.hpp" #include "wb2/wxbeacon2_log.hpp" #include "res/resource.h" +#include "utility.hpp" #include #include - using goblib::datetime::LocalTime; -const uint32_t Ticker::DECOR_FOREGROUND_COLORS[] = +PROGMEM const uint16_t Ticker::DECOR_FOREGROUND_COLORS[] = +{ + ::lgfx::color565( 0, 0, 255), // blue + ::lgfx::color565(188, 188, 0), // yellow + ::lgfx::color565(255, 0, 0), // red + ::lgfx::color565(128, 0, 255), // purple + ::lgfx::color565( 64, 144, 48), // green +}; + +PROGMEM const uint16_t Ticker::TELOP_COLORS[] = { - ::lgfx::LGFXBase::color888( 0, 0, 255), // blue - ::lgfx::LGFXBase::color888(188, 188, 0), // yellow - ::lgfx::LGFXBase::color888(255, 0, 0), // red - ::lgfx::LGFXBase::color888(128, 0, 255), // purple - ::lgfx::LGFXBase::color888( 64, 144, 48), // green + ::lgfx::color565(255, 255, 255), + ::lgfx::color565( 0, 0, 0), + ::lgfx::color565(255, 0, 0), + ::lgfx::color565( 0, 0, 255), }; Ticker::Ticker() @@ -37,11 +45,11 @@ Ticker::Ticker() _telop = new LGFX_Sprite(); assert(_telop); _telop->setPsram(true); - _telop->setColorDepth(1); // 1bpp + _telop->setColorDepth(2); // 2bpp _telop->createSprite(TELOP_WIDTH, TELOP_HEIGHT); - _telop->setBitmapColor(::lgfx::LGFXBase::color24to16(TELOP_FCLR), ::lgfx::LGFXBase::color24to16(TELOP_BCLR)); + auto pal = _telop->getPalette(); + for(auto& e : TELOP_COLORS) { *pal++ = ::lgfx::LGFXBase::color16to24(e); } _telop->setTextColor(1); - // _telop->setFont(&titleFont); _telop->setFont(&tickerFont); // @@ -50,7 +58,7 @@ Ticker::Ticker() _decorRight->setPsram(true); _decorRight->setColorDepth(1); // 1bpp _decorRight->createSprite(DECOR_RIGHT_WIDTH, DECOR_RIGHT_HEIGHT); - _decorRight->setBitmapColor(::lgfx::LGFXBase::color24to16(DECOR_FOREGROUND_COLORS[_color]), ::lgfx::LGFXBase::color24to16(TELOP_BCLR)); + _decorRight->setBitmapColor(DECOR_FOREGROUND_COLORS[_color], BG_COLOR); _decorRight->setTextColor(1); _decorRight->setFont(&fonts::Font0); @@ -60,11 +68,10 @@ Ticker::Ticker() _decorLeft->setPsram(true); _decorLeft->setColorDepth(2); // 4bpp _decorLeft->createSprite(DECOR_LEFT_WIDTH, DECOR_LEFT_HEIGHT); - _decorLeft->setPaletteColor(0, 255,0,255); // 0: transparent color - ::lgfx::rgb888_t rgb(DECOR_FOREGROUND_COLORS[_color]); _decorLeft->setPivot(0,0); //left,top - _decorLeft->setPaletteColor(1, rgb.R8(), rgb.G8(), rgb.B8()); // 1: background color - _decorLeft->setPaletteColor(2, 255, 255, 255); // 2: text color + _decorLeft->setPaletteColor(0, 255,0,255); // 0: transparent color + _decorLeft->setPaletteColor(1, DECOR_FOREGROUND_COLORS[_color]); + _decorLeft->setPaletteColor(2, DECOR_TEXT_COLOR); _decorLeft->setFont(&titleFont); _decorLeft->setTextColor(2); _decorLeft->clear(); @@ -75,7 +82,7 @@ Ticker::Ticker() _logo = new LGFX_Sprite(); assert(_logo); _logo->createFromBmp(logo_bmp, logo_bmp_len); - _logo->setPaletteColor(1, rgb.R8(), rgb.G8(), rgb.B8()); // 1: level color + _logo->setPaletteColor(1, DECOR_FOREGROUND_COLORS[_color]); } Ticker::~Ticker() @@ -89,9 +96,8 @@ Ticker::~Ticker() void Ticker::setColor(const Color c) { _color = c; - ::lgfx::rgb888_t rgb(DECOR_FOREGROUND_COLORS[_color]); - _decorLeft->setPaletteColor (1, rgb.R8(), rgb.G8(), rgb.B8()); - _decorRight->setPaletteColor(1, rgb.R8(), rgb.G8(), rgb.B8()); + _decorLeft->setPaletteColor (1, DECOR_FOREGROUND_COLORS[_color]); + _decorRight->setPaletteColor(1, DECOR_FOREGROUND_COLORS[_color]); } // Set level by WBGT @@ -123,24 +129,20 @@ void Ticker::setText(const char* str) if(!str || !str[0]) { return; } WB2_LOGD("%s", str); + if(strlen(str) >= STRING_LEN) { WB2_LOGE("BufferOver %zu", strlen(str)); } _x = _telop->width(); - _str[0] = '\0'; + strncpy(_str, str, sizeof(_str) - 1); + _str[sizeof(_str) - 1] = '\0'; + + auto tokens = gob::split(str, '#'); _twidth = 0; - - if(str && str[0]) + for(auto& e : tokens) { - strncpy(_str, str, sizeof(_str) - 1); - _str[sizeof(_str) - 1] = '\0'; - _twidth = _telop->textWidth(_str); - } - -#if 0 - _decorLeft->setFont(&weather_font); - _decorLeft->setTextColor(3); - _decorLeft->drawString("0123", 2, 1); -#endif + if(e.length() == 0) { continue; } + _twidth += _telop->textWidth(e.c_str() + (e[0] == '@' && isdigit(e[1])) * 2); // Command of change palette? + } } void Ticker::pump() @@ -149,16 +151,16 @@ void Ticker::pump() _telop->clear(0); if(_str[0]) { - auto bwid = _telop->width(); - _telop->drawString(_str, _x, 0); + auto twid = _telop->width(); + drawTelop(_str, _x, 0); // Connect string if string width greater than width of _telop. - if(_twidth > bwid && (_x + _twidth) < bwid) + if(_twidth > twid && (_x + _twidth) < twid) { - _telop->drawString(_str, _x + _twidth, 0); + drawTelop(_str, _x + _twidth, 0); } // Infinity scroll string. _x -= _speed; - if(_twidth <= bwid) + if(_twidth <= twid) { if(_x < -_twidth) { _x = _telop->width(); } } @@ -167,7 +169,7 @@ void Ticker::pump() if(_x < -_twidth) { _x += _twidth; } } } - + // Localtime _decorRight->clear(); _logo->pushSprite(_decorRight, 0, 0, 0); @@ -189,3 +191,28 @@ void Ticker::render(m5gfx::M5GFX* dst) _decorRight->pushSprite(dst, dst->width() - (_decorRight->width() + GAP), dst->height() - _decorRight->height()); _decorLeft->pushSprite(dst, 0, dst->height() - _decorLeft->height(), 0); } + +void Ticker::drawTelop(const char* str, const int16_t x, const int16_t y) +{ + if(!_str[0] || x >= _telop->width()) { return; } + + int16_t left = x; + _telop->setTextColor(1); + + auto tokens = gob::split(str, '#'); + for(auto& e : tokens) + { + if(left > 320) { break; } + if(e.length() == 0) { continue; } + const char* s = e.c_str(); + if(*s == '@' && isdigit(*(s+1))) { _telop->setTextColor((*(s+1)) - '0'); s += 2; } // Change palette + + auto w = _telop->textWidth(s); + if(left >= 0 || left + w >= 0) + { + _telop->drawString(s, left, y); + } + left += w; + } + +} diff --git a/src/wni_ticker.hpp b/src/wni_ticker.hpp index bfa892d..7009663 100644 --- a/src/wni_ticker.hpp +++ b/src/wni_ticker.hpp @@ -33,7 +33,7 @@ class Ticker void pump(); void render(m5gfx::M5GFX* dst); - constexpr static size_t STRING_LEN = 384; + constexpr static size_t STRING_LEN = 512; constexpr static int16_t GAP = 2; //Decoration left @@ -46,12 +46,16 @@ class Ticker // Telop constexpr static int16_t TELOP_WIDTH = 320 - (DECOR_RIGHT_WIDTH + 2 * GAP + DECOR_LEFT_GAP); constexpr static int16_t TELOP_HEIGHT = 24; // height = fontHeight + (1 + 1) - constexpr static uint32_t TELOP_FCLR = ::lgfx::color888( 0, 0, 0); // palette 1 - constexpr static uint32_t TELOP_BCLR = ::lgfx::color888(255, 255, 255); // palette 0 + constexpr static uint16_t BG_COLOR = ::lgfx::color565(255, 255, 255); + constexpr static uint16_t DECOR_TEXT_COLOR = ::lgfx::color565(255, 255, 255); // Decoration foreground colors for each level. - static const uint32_t DECOR_FOREGROUND_COLORS[]; - + static const uint16_t DECOR_FOREGROUND_COLORS[]; + static const uint16_t TELOP_COLORS[]; + + private: + void drawTelop(const char* str, const int16_t x, const int16_t y); + private: // Telop LGFX_Sprite* _telop; From e6b48580651f446a096a2ab9c36f6a8da7e8cc08 Mon Sep 17 00:00:00 2001 From: GOB Date: Sun, 25 Dec 2022 16:27:32 +0900 Subject: [PATCH 14/31] Raise M5Unified version --- platformio.ini | 2 +- src/utility.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 7a3bf4b..5eec020 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,7 +15,7 @@ board_build.f_cpu = 240000000L ; https://github.com/tanakamasayuki/aquestalk download zip and extract ./lib folder. ;lib_extra_dirs = /lib lib_ldf_mode = deep -lib_deps = m5stack/M5Unified @ ^0.0.7 +lib_deps = m5stack/M5Unified @ ^0.1.0 h2zero/NimBLE-Arduino @^1.3.8 https://github.com/mrfaptastic/json-streaming-parser2.git @ ^2.1.0 https://github.com/GOB52/gob_datetime.git @ ^0.1.1 diff --git a/src/utility.hpp b/src/utility.hpp index aa82849..9b558d4 100644 --- a/src/utility.hpp +++ b/src/utility.hpp @@ -57,7 +57,7 @@ String join(const std::vector& v, const char* separator = ", ") }) : String(); } -// Solit string +// Split string std::vector split(const String& str, const char delimiter = ','); inline std::vector split(const char* s, const char delimiter = ',') { return split(String(s), delimiter); } // From 852439bb852463467a990af590cc00471e4b504e Mon Sep 17 00:00:00 2001 From: GOB Date: Sun, 25 Dec 2022 16:30:10 +0900 Subject: [PATCH 15/31] Fixes stop the M5.Speaker in stop function --- src/aq_talk.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/aq_talk.cpp b/src/aq_talk.cpp index 0787975..6abe9c8 100644 --- a/src/aq_talk.cpp +++ b/src/aq_talk.cpp @@ -384,14 +384,17 @@ void waitAquesTalk(void) void stopAquesTalk(void) { - if (is_talking) { is_talking = false; vTaskDelay(1); } + if (is_talking) + { + M5.Speaker.stop(m5spk_virtual_channel); + is_talking = false; vTaskDelay(1); + } } bool playAquesTalk(const char *koe, const uint16_t speed, const uint16_t lenPause) { stopAquesTalk(); waitAquesTalk(); - // Split and store queue. (CAqTkPicoF_SetKoe has a length limitation) koeQueue.clear(); From 37465f4b146277992aaaa0978cf48b87fd05a7d4 Mon Sep 17 00:00:00 2001 From: GOB Date: Sun, 25 Dec 2022 16:59:14 +0900 Subject: [PATCH 16/31] Fixes optimization of ticker text rendering --- src/main.cpp | 8 ++++---- src/wni_ticker.cpp | 50 +++++++++++++++++++--------------------------- src/wni_ticker.hpp | 7 ++++--- 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index cb7e239..7b8a8c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -304,7 +304,7 @@ void playAdvertiseData(const WxBeacon2::AdvertiseData& data) aq_talk::playAquesTalk(vs.c_str(), 120); // auto ts = formatString("TEMP %3.1fdegC HUM %3.1f%% AL %dlx UV %3.1f PRESURE %4.1fhPa N %3.1fdB DCMFT %3.1f WBGT %3.1f ", - auto ts = formatString("気温:#@2%3.1f#@1℃ 湿度#@2:%3.1f#@1%% 明度:#@2%d#@1lx UV指数:#@2%3.1f #@1気圧:#@2%4.1f#@1hPa 騒音:#@2%3.1f#@1dB 不快指数:#@2%3.1f #@1WBGT:#@2%3.1f ", + auto ts = formatString("#@1気温:#@2%3.1f#@1℃ 湿度#@2:%3.1f#@1%% 明度:#@2%d#@1lx UV指数:#@2%3.1f #@1気圧:#@2%4.1f#@1hPa 騒音:#@2%3.1f#@1dB 不快指数:#@2%3.1f #@1WBGT:#@2%3.1f ", (float)de->temperature(), (float)de->relativeHumidity(), (int)de->ambientLight(), @@ -651,9 +651,6 @@ void setup() auto ret = aq_talk::initialize(aqtalkPriority, aqtalkCore, callbackOnEndAqTalk); WB2_LOGD("aq_talk::setup : %d", ret); - // Get advertise from WxBeacon2. - _requestAdvertise(); - // { goblib::datetime::LocalDateTime ldt = goblib::datetime::LocalDateTime::now(); @@ -669,6 +666,9 @@ void setup() M5.Display.startWrite(); // Occupy DMA Bus cpu_usage::initialize(); + + // Get advertise from WxBeacon2. + _requestAdvertise(); } namespace diff --git a/src/wni_ticker.cpp b/src/wni_ticker.cpp index 143f5aa..a05bc45 100644 --- a/src/wni_ticker.cpp +++ b/src/wni_ticker.cpp @@ -126,23 +126,30 @@ void Ticker::setTitle(const char* title) void Ticker::setText(const char* str) { - if(!str || !str[0]) { return; } - WB2_LOGD("%s", str); - if(strlen(str) >= STRING_LEN) { WB2_LOGE("BufferOver %zu", strlen(str)); } + _str.clear(); _x = _telop->width(); - strncpy(_str, str, sizeof(_str) - 1); - _str[sizeof(_str) - 1] = '\0'; - - auto tokens = gob::split(str, '#'); _twidth = 0; - for(auto& e : tokens) + _str = gob::split(str, '#'); + for(auto& e : _str) { if(e.length() == 0) { continue; } - _twidth += _telop->textWidth(e.c_str() + (e[0] == '@' && isdigit(e[1])) * 2); // Command of change palette? } + if(_twidth > 320) + { + auto allot = 320 - _twidth % 320; + int16_t left = 0; + std::vector append; + for(auto& e : _str) + { + if(left > 320) { break; } + append.push_back(e); + left += _telop->textWidth(e.c_str() + (e[0] == '@' && isdigit(e[1])) * 2); + } + _str.insert(_str.end(), append.begin(), append.end()); + } } void Ticker::pump() @@ -152,13 +159,8 @@ void Ticker::pump() if(_str[0]) { auto twid = _telop->width(); - drawTelop(_str, _x, 0); - // Connect string if string width greater than width of _telop. - if(_twidth > twid && (_x + _twidth) < twid) - { - drawTelop(_str, _x + _twidth, 0); - } - // Infinity scroll string. + drawTelop(_x, 0); + _x -= _speed; if(_twidth <= twid) { @@ -192,27 +194,17 @@ void Ticker::render(m5gfx::M5GFX* dst) _decorLeft->pushSprite(dst, 0, dst->height() - _decorLeft->height(), 0); } -void Ticker::drawTelop(const char* str, const int16_t x, const int16_t y) +void Ticker::drawTelop(const int16_t x, const int16_t y) { - if(!_str[0] || x >= _telop->width()) { return; } - int16_t left = x; _telop->setTextColor(1); - auto tokens = gob::split(str, '#'); - for(auto& e : tokens) + for(auto& e : _str) { if(left > 320) { break; } if(e.length() == 0) { continue; } const char* s = e.c_str(); if(*s == '@' && isdigit(*(s+1))) { _telop->setTextColor((*(s+1)) - '0'); s += 2; } // Change palette - - auto w = _telop->textWidth(s); - if(left >= 0 || left + w >= 0) - { - _telop->drawString(s, left, y); - } - left += w; + left += _telop->drawString(s, left, y); } - } diff --git a/src/wni_ticker.hpp b/src/wni_ticker.hpp index 7009663..6380d3c 100644 --- a/src/wni_ticker.hpp +++ b/src/wni_ticker.hpp @@ -33,7 +33,7 @@ class Ticker void pump(); void render(m5gfx::M5GFX* dst); - constexpr static size_t STRING_LEN = 512; + // constexpr static size_t STRING_LEN = 512; constexpr static int16_t GAP = 2; //Decoration left @@ -54,13 +54,14 @@ class Ticker static const uint16_t TELOP_COLORS[]; private: - void drawTelop(const char* str, const int16_t x, const int16_t y); + void drawTelop(const int16_t x, const int16_t y); private: // Telop LGFX_Sprite* _telop; // gob::Sprite* _telop2; - char _str[STRING_LEN + 1/* \0 */]; + // char _str[STRING_LEN + 1/* \0 */]; + std::vector _str; int16_t _twidth; int16_t _x, _speed; // Decoration From da7f5f1055fca8c1660f6abf7cd4a7abe64539d7 Mon Sep 17 00:00:00 2001 From: GOB Date: Sun, 25 Dec 2022 17:47:44 +0900 Subject: [PATCH 17/31] Fixes bug. Telop text rendering. --- src/.#main.cpp | 1 + src/wni_ticker.cpp | 23 +++++++++++++++-------- src/wni_ticker.hpp | 7 ++----- 3 files changed, 18 insertions(+), 13 deletions(-) create mode 120000 src/.#main.cpp diff --git a/src/.#main.cpp b/src/.#main.cpp new file mode 120000 index 0000000..02d62ec --- /dev/null +++ b/src/.#main.cpp @@ -0,0 +1 @@ +gob@gob-imac.local.28670 \ No newline at end of file diff --git a/src/wni_ticker.cpp b/src/wni_ticker.cpp index a05bc45..41b943a 100644 --- a/src/wni_ticker.cpp +++ b/src/wni_ticker.cpp @@ -114,7 +114,7 @@ void Ticker::setTitle(const char* title) { if(!title || !title[0]) { return; } - WB2_LOGD("%s", title); + WB2_LOGD("[%s]", title); _decorLeft->clear(); // fill 0 @@ -126,45 +126,50 @@ void Ticker::setTitle(const char* title) void Ticker::setText(const char* str) { - WB2_LOGD("%s", str); + WB2_LOGD("[%s]", str); + _telop->clear(0); _str.clear(); _x = _telop->width(); _twidth = 0; + _str = gob::split(str, '#'); for(auto& e : _str) { if(e.length() == 0) { continue; } _twidth += _telop->textWidth(e.c_str() + (e[0] == '@' && isdigit(e[1])) * 2); // Command of change palette? } - if(_twidth > 320) + + auto twid = _telop->width(); + if(_twidth > twid) { - auto allot = 320 - _twidth % 320; + auto allot = twid - _twidth % twid; int16_t left = 0; std::vector append; for(auto& e : _str) { - if(left > 320) { break; } + if(left > twid) { break; } append.push_back(e); left += _telop->textWidth(e.c_str() + (e[0] == '@' && isdigit(e[1])) * 2); } _str.insert(_str.end(), append.begin(), append.end()); } + // WB2_LOGD("twidth:%d telop:%d str:%zu", _twidth, twid, _str.size()); } void Ticker::pump() { // Telop - _telop->clear(0); if(_str[0]) { + _telop->clear(0); auto twid = _telop->width(); drawTelop(_x, 0); _x -= _speed; if(_twidth <= twid) { - if(_x < -_twidth) { _x = _telop->width(); } + if(_x < -_twidth) { _x = twid; } } else { @@ -197,11 +202,13 @@ void Ticker::render(m5gfx::M5GFX* dst) void Ticker::drawTelop(const int16_t x, const int16_t y) { int16_t left = x; + auto twid = _telop->width(); + _telop->setTextColor(1); for(auto& e : _str) { - if(left > 320) { break; } + if(left > twid) { break; } if(e.length() == 0) { continue; } const char* s = e.c_str(); if(*s == '@' && isdigit(*(s+1))) { _telop->setTextColor((*(s+1)) - '0'); s += 2; } // Change palette diff --git a/src/wni_ticker.hpp b/src/wni_ticker.hpp index 6380d3c..b65fd25 100644 --- a/src/wni_ticker.hpp +++ b/src/wni_ticker.hpp @@ -33,9 +33,6 @@ class Ticker void pump(); void render(m5gfx::M5GFX* dst); - // constexpr static size_t STRING_LEN = 512; - constexpr static int16_t GAP = 2; - //Decoration left constexpr static int16_t DECOR_LEFT_WIDTH = 160; constexpr static int16_t DECOR_LEFT_HEIGHT = 48; @@ -44,12 +41,12 @@ class Ticker constexpr static int16_t DECOR_RIGHT_WIDTH = 32; constexpr static int16_t DECOR_RIGHT_HEIGHT = 48; // Telop + constexpr static int16_t GAP = 2; constexpr static int16_t TELOP_WIDTH = 320 - (DECOR_RIGHT_WIDTH + 2 * GAP + DECOR_LEFT_GAP); constexpr static int16_t TELOP_HEIGHT = 24; // height = fontHeight + (1 + 1) - + // Colors constexpr static uint16_t BG_COLOR = ::lgfx::color565(255, 255, 255); constexpr static uint16_t DECOR_TEXT_COLOR = ::lgfx::color565(255, 255, 255); - // Decoration foreground colors for each level. static const uint16_t DECOR_FOREGROUND_COLORS[]; static const uint16_t TELOP_COLORS[]; From ebd662e058224609d93a3887d8951d841dbbe3b2 Mon Sep 17 00:00:00 2001 From: GOB Date: Sun, 25 Dec 2022 23:57:20 +0900 Subject: [PATCH 18/31] Tweaks Add output http error. Add some define symbols --- .gitignore | 3 +++ platformio.ini | 9 ++++++--- src/.#main.cpp | 1 - src/himawari/himawari_task.cpp | 1 + src/jma/jma_task.cpp | 1 + src/main.cpp | 27 ++++++++++++++++++--------- src/wb2/wxbeacon2_ble.cpp | 3 ++- 7 files changed, 31 insertions(+), 14 deletions(-) delete mode 120000 src/.#main.cpp diff --git a/.gitignore b/.gitignore index 94dbb9a..850c6c9 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,9 @@ *.out *.app +#Emacs +\#*# + #pio /.pio/ diff --git a/platformio.ini b/platformio.ini index 5eec020..0764716 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,11 +12,10 @@ board_build.flash_mode = qio board_build.f_flash = 80000000L board_build.f_cpu = 240000000L -; https://github.com/tanakamasayuki/aquestalk download zip and extract ./lib folder. -;lib_extra_dirs = /lib +; https://www.a-quest.com/download.html Download AquesTalk ESP32 and extract ./lib folder. lib_ldf_mode = deep lib_deps = m5stack/M5Unified @ ^0.1.0 - h2zero/NimBLE-Arduino @^1.3.8 + h2zero/NimBLE-Arduino @ ^1.4.0 https://github.com/mrfaptastic/json-streaming-parser2.git @ ^2.1.0 https://github.com/GOB52/gob_datetime.git @ ^0.1.1 @@ -26,8 +25,12 @@ upload_speed = 921600 ; Definition ; M5S_WXBEACON2_TIMEZONE_LOCATION : Your time-zone location string. default as "Asia/Tokyo" (e.g. "Asia/Tokyo" "America/Los_Angeles" "Australia/Lord_Howe") +; M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC : Auto request interval (Unit: second) +; M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC : Auto talk interval (Unit; second) build_flags = -Wall -Wextra -Wreturn-local-addr -Werror=format -Werror=return-local-addr -D M5S_WXBEACON2_TIMEZONE_LOCATION=\"Asia/Tokyo\" + -D M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC=300 + -D M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC=60 -D M5S_WXBEACON2_DEBUG_INFO [release_env] diff --git a/src/.#main.cpp b/src/.#main.cpp deleted file mode 120000 index 02d62ec..0000000 --- a/src/.#main.cpp +++ /dev/null @@ -1 +0,0 @@ -gob@gob-imac.local.28670 \ No newline at end of file diff --git a/src/himawari/himawari_task.cpp b/src/himawari/himawari_task.cpp index 5857b55..e9138d5 100644 --- a/src/himawari/himawari_task.cpp +++ b/src/himawari/himawari_task.cpp @@ -176,6 +176,7 @@ void himawari_task(void*) httpcode = http.GET(); if(httpcode >= 0) { break; } // HTTPClient internal error, to retry. + WB2_LOGE("%s", http.errorToString(httpcode).c_str()); client.stop(); http.end(); delay(100); diff --git a/src/jma/jma_task.cpp b/src/jma/jma_task.cpp index a5e4868..d61c072 100644 --- a/src/jma/jma_task.cpp +++ b/src/jma/jma_task.cpp @@ -127,6 +127,7 @@ void jma_forecast_task(void*) if(httpcode >= 0) { break; } // HTTPClient internal error, to retry. + WB2_LOGE("%s", http.errorToString(httpcode).c_str()); client.stop(); http.end(); delay(100); diff --git a/src/main.cpp b/src/main.cpp index 7b8a8c1..a6a1b06 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,7 +51,18 @@ using goblib::datetime::OffsetDateTime; namespace { // Automatic request interval. -constexpr uint16_t AUTO_REQUEST_INTERVAL_SEC = 1 * 60; +#ifdef M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC +# define AUTO_REQUEST_INTERVAL_SEC (M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC) +#else +# define AUTO_REQUEST_INTERVAL_SEC (5 * 60) +#endif + +// Automatic talk interval +#ifdef M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC +# define AUTO_TALK_INTERVAL_SEC (M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC) +#else +# define AUTO_TALK_INTERVAL_SEC (1 * 60) +#endif // NTP serve URL PROGMEM const char ntp0[] = "ntp.nict.jp"; @@ -494,10 +505,10 @@ void callbackOnEndAqTalk() } // -------------------------------- +#ifdef ARDUINO_M5STACK_Core2 // Request himawari image void _requestHimawari() { -#ifdef ARDUINO_M5STACK_Core2 if(canRequest()) { #if 0 @@ -520,10 +531,8 @@ void _requestHimawari() { WB2_LOGD("busy"); } -#endif } -#ifdef ARDUINO_M5STACK_Core2 // Callback on progress void callbackOnProgressHimawari(const size_t readed, const size_t size) { @@ -739,7 +748,6 @@ void loop() { longPressA = true; _requestForecast(); - //_requestHimawari(); } if(M5.BtnA.wasReleased()) { @@ -780,7 +788,7 @@ void loop() #endif // Random talking - if(!aq_talk::busy() && voiceEnd > 0 && std::difftime(now, voiceEnd) >= 60) + if(!aq_talk::busy() && voiceEnd > 0 && std::difftime(now, voiceEnd) >= M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC) { talkRandom(); } @@ -826,14 +834,15 @@ void loop() } -#if 1 // Auto request if(canRequest() && lastUpdate > 0 && std::difftime(now, lastUpdate) >= AUTO_REQUEST_INTERVAL_SEC) { - //_requestAdvertise(); +#ifdef ARDUINO_M5STACK_Core2 _requestHimawari(); - } +#else + _requestAdvertise(); #endif + } // Keep about 30 FPS. auto end = millis(); diff --git a/src/wb2/wxbeacon2_ble.cpp b/src/wb2/wxbeacon2_ble.cpp index 0b0bbe9..a19b709 100644 --- a/src/wb2/wxbeacon2_ble.cpp +++ b/src/wb2/wxbeacon2_ble.cpp @@ -216,11 +216,12 @@ void WxBeacon2AdvertiseCallbacks::onResult(NimBLEAdvertisedDevice* device) detected = (c->_companyID == WxBeacon2::COMPANY_ID); } - WB2_LOGI("WxBeacon2 %s detected", detected ? "" : "NOT"); + WB2_LOGI("WxBeacon2 detected? %d", detected); if(detected) { _address = device->getAddress(); + WB2_LOGI("address: %s",_address.toString().c_str()); NimBLEDevice::getScan()->stop(); } } From 2251f1ff379df53ad5e5874d77f37ed84104c4c6 Mon Sep 17 00:00:00 2001 From: GOB Date: Mon, 26 Dec 2022 00:04:40 +0900 Subject: [PATCH 19/31] Update documents --- .gitignore | 3 + README.md | 209 ++++++++++++++++++++++++++++++++++------------- doc/forecast.jpg | Bin 0 -> 81988 bytes doc/himawari.jpg | Bin 0 -> 86995 bytes doc/progress.jpg | Bin 0 -> 49777 bytes doc/w406.png | Bin 0 -> 434 bytes 6 files changed, 154 insertions(+), 58 deletions(-) create mode 100644 doc/forecast.jpg create mode 100644 doc/himawari.jpg create mode 100644 doc/progress.jpg create mode 100644 doc/w406.png diff --git a/.gitignore b/.gitignore index 850c6c9..5d1fc3f 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,9 @@ #pio /.pio/ +# Doxygen +/doc/html + # resources /src/res/* !/src/res/resource.h diff --git a/README.md b/README.md index 2b72b8e..e817e5c 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,112 @@ # M5S_WxBeacon2 - https://user-images.githubusercontent.com/26270227/186464005-bfc6b1c4-3f5c-4e7f-b2bc-fb4b9d4b0df4.mp4 -定期的に WxBeacon2 から情報を取得し、ティッカーに表示、ポン子ちゃんアバターが喋ります。 +forecast himawari +* WxBeacon2 から情報を取得し、ティッカーに表示、ポン子ちゃんアバターがアナウンスします。 +* 気象庁の天気予報 JSON データを取得し、全国の天気を表示、ポン子ちゃんアバターがアナウンスします。 +* **(Core2 のみ)** 気象庁の気象衛星ひまわりの画像を取得し表示します。 ## 概要 [株式会社ウェザーニューズ](https://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A7%E3%82%B6%E3%83%BC%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%BA)(以下 WNI )による 24 時間お天気番組[ウェザーニュースLiVE](https://weathernews.jp/web910/) とリンクしたアプリケーション [ウェザーニュース](https://weathernews.jp/app/) では サンクスポイント 2000 pt以上取得すると[ウェザービーコン2](https://weathernews.jp/smart/wxbeacon2/)(以下 WxBeacon2 ) をゲットできます。(別途[有償購入](https://weathernews.jp/sorashop/)も可能) -WxBeacon2 +WxBeacon2 ponko + -M5Stack Basic / Gray / Core2 を使って WxBeacon2 から情報を取得し、 [AquesTalk ESP32](https://www.a-quest.com/products/aquestalk_esp32.html) にて喋らせるアプリケーションです。
+M5Stack Basic, Gray, Core2 にて WxBeacon2 や気象庁からデータを取得し、 +[AquesTalk ESP32](https://www.a-quest.com/products/aquestalk_esp32.html) で喋らせるアプリケーションです。 どうせならウェザーニュースLiVE のマスコット、ポン子こと [WEATHEROID TypeA Airi](https://twitter.com/typea_airi) ちゃんに喋らせようという事で、アバターはポン子ちゃんとなっております。 -ponko ## 必要なもの -### M5Stack -M5Stack Basic,Gray,Core2 のいずれか。 +* M5Stack +M5Stack Basic, Gray, Core2 のいずれか。 + +* WxBeacon2 +実体は [OMRON 2JCIE-BL01](https://components.omron.com/jp-ja/products/sensors/2JCIE-BL) です。 +WxBeacon2 でなく当該製品でも動作すると思われます(手元に無いので未確認)。 -### WxBeacon2 -実体は [OMRON 2JCIE-BL01](https://components.omron.com/jp-ja/products/sensors/2JCIE-BL) です。ですので、WxBeacon2 でなく当該製品でも動作すると思われます(手元に無いので未確認)。 +* Wi-Fi接続可能な機器 +ルータやモバイル Wi-Fi 等。 ## コンパイル ### 依存ライブラリ -* [M5Unified](https://github.com/m5stack/M5Unified) 0.0.7 or later -* [M5GFX](https://github.com/m5stack/M5GFX) 0.0.20 or later +* [M5Unified](https://github.com/m5stack/M5Unified) 0.1.1 or later +* [M5GFX](https://github.com/m5stack/M5GFX) 0.1.1 or later * [NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino) 1.4.0 or later -* [AquesTalk ESP32](https://www.a-quest.com/products/aquestalk_esp32.html) 2.21 or later +* [json-streaming-parser2]( https://github.com/mrfaptastic/json-streaming-parser2.git ) 2.1.0 or later +* [gob_datetime]( https://github.com/GOB52/gob_datetime.git) 0.1.1 or later +* [AquesTalk ESP32](https://www.a-quest.com/products/aquestalk_esp32.html) 2.21 or later +AquesTalk ESP32 は [こちら](https://www.a-quest.com/download.html) よりダウンロード後、プロジェクトの lib フォルダ(無ければ作成)に展開してください。 -### 画像ソース -**権利上の問題でポン子ちゃんの画像などは当リポジトリには含まれません。**
+ +### 画像リソース +**権利上の問題でポン子ちゃんの画像などは当リポジトリには含まれません。** 自分で以下の条件を満たす画像をソースファイルとして共にコンパイルする必要があります。 -#### フォーマット +#### 画像フォーマット Basic,Gray での動作の都合上、メモリ使用料削減の為に 4bpp,1bpp を扱います。 -[Windows Bitmap](https://ja.wikipedia.org/wiki/Windows_bitmap) Version 3 (BITMAPINFOHEADER.biSize == 40) format であること。 +[Windows Bitmap](https://ja.wikipedia.org/wiki/Windows_bitmap) の場合は Version 3 (BITMAPINFOHEADER.biSize == 40) format である必要があります。 + +**顔、閉じた口、開いた口は同じパレット配列でなければなりません。** +16色 Bitmap のパレットの並び替えは、拙作 [reorder_palette.py](https://github.com/GOB52/bitmap_tools/blob/master/reorder_palette.py) が使用できます。 + 画像は作成の際の位置イメージです。 -* 顔
+* 顔 Windows bitmap 320 px x 240 px 4 bpp (16色) パレット 0 番は透過色。口とパレット構成を合わせる為、顔にも透過色が必要。 ![face](./doc/ponko_face.png) -* 閉じた口
+* 閉じた口 Windows bitmap 48 px x 32 px 4 bpp (16色) パレット 0 番は透過色。顔に透過色を用いて上書きされる。 ![close](./doc/ponko_mouth_close.png) -* 開いた口
+* 開いた口 Windows bitmap 48 px x 32 px 4 bpp (16色) パレット 0 番は透過色。顔に透過色を用いて上書きされる。 ![open](./doc/ponko_mouth_open.png) -* WNI ロゴ
+ +* WNI ロゴ Windows bitmap 32 px x 32 px 1 bpp (2色) パレット 0 番は透過色。ティッカーに透過色を用いて上書きされる。 ![logo](./doc/logo.png) -**顔、閉じた口、開いた口は同じパレット配列でなければなりません。**
-16色 Bitmap のパレットの並び替えは、拙作 [reorder_palette.py](https://github.com/GOB52/bitmap_tools/blob/master/reorder_palette.py) が使用できます。 +* 天気アイコン (30種類) +PNG 32 px x 24 px 2 bpp (4色) パレットは自由、透過無し。 +![icons](./doc/w406.png) +https://weathernews.jp/s/topics/img/wxicon/ を参考にすると良いでしょう。 + +| リソース名 |内容| +---|--- +|w100| 晴 | +|w101|晴時々曇| +|w102|晴一時雨| +|w104|晴一時雪| +|w110|晴後時々曇| +|w112|晴後一時雨| +|w115|晴後一時雪| +|w200|曇| +|w201|曇時々晴| +|w202|曇一時雨| +|w204|曇一時雪| +|w210|曇後時々晴| +|w212|曇後一時雨| +|w215|曇後一時雪| +|w300|雨| +|w301|雨時々晴| +|w302|雨時々止む| +|w303|雨時々雪| +|w308|雨で暴風を伴う| +|w311|雨後晴| +|w313|雨後曇| +|w314|雨後時々雪| +|w400|雪| +|w401|雪時々晴| +|w402|雪時々止む| +|w403|雪時々雨| +|w406|風雪強い| +|w411|雪後晴| +|w413|雪後曇| +|w414|雪後雨| #### ソースファイル化 @@ -66,14 +117,16 @@ xxd -i ponko_face.bmp ./src/res/ponko_face.cpp ``` xxd で C形式に変換します。出力場所は ./src/res が良いでしょう。 -出力したソースを修正します。 +出力したソースを修正します。 +ヒープを空ける為、画像リソースは **PROGMEM として Flash の領域におきます**。 ```cpp +#include // PROGMEM を使う為 #include "resource.h" // 宣言 //unsigned char ponko_face_bmp[] = { -const uint8_t ponko_face_bmp[] = { +PROGMEM const uint8_t ponko_face_bmp[] = { 0x42, 0x4d, 0x76, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, . @@ -85,60 +138,71 @@ const size_t ponko_face_bmp_len = 38518; ``` -#### 参考 : 各リソースの長さ(フォーマット他条件が一致していれば違っても良い) +詳しくは [各リソースの定義](src/res/resource.h) を参照してください。 -|xxd -i source| \_bmp\_len| -|---|---| -|ponk\_face.cpp| 38518 | -|ponko\_mouth\_close.cpp| 886 | -|ponko\_mouth\_open.cpp| 886 | -|logo.cpp| 190 | +### 動作設定 -### 動作制御 -./src/main.cpp の上部にいくつかの設定項目があります。 +* タイムゾーン設定 +コンパイル時のオプション **M5S_WXBEACON2_TIMEZONE_LOCATION** (文字列) で指定します。 +デフォルトは **"Asia/Tokyo"** です。(M5Stack 内部では POSIX 表記を用いて設定されます) -```cpp +* データ自動取得間隔の設定 +コンパイル時のオプション **M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC** (数値)で指定します。 +デフォルトは 300 (5分間隔) です。 +(Core2 ではひまわりの画像取得のインターバルとなります) -// Settings -namespace -{ -// Auto talking interval time (Unit:second) [自動で WxBeacon2 からデータを取得して喋る頻度] -constexpr uint16_t TALKING_INTERVAL_SEC = 60 * 3; -// Measurement interval time (Unit:second) for broadcast mode [WxBeacon2 のデータ更新頻度] -constexpr uint16_t MEASUREMENT_INTERVAL_BROADCAST_SEC = 60 * 3; -// turnon LED when got advertise data. [WxBeacon2 のデータを取得できたら LED を光らせるか?] -constexpr bool TURNON_LED = false; -} +* ランダムお喋り間隔の設定 +コンパイル時のオプション **M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC** (数値)で指定します。 +デフォルトは 60 (1分間隔) です。 -``` -### WiFi SSID password +### Wi-Fi SSID password -時刻取得の為、起動時に WiFi 接続で NTP サーバーへの接続を行います。
-時刻の表示並びに、 WxBeacon2 のモードを出荷時に戻す際に、蓄積データの基準時刻を書き込む必要がある為です。
-前もって接続する WiFi の SSID とパスワードをハードに書き込む必要があります。(Wifi.begin() を引数なしで呼ぶと保存されている情報を元に接続します)
-SmartConfig 等を利用して SSID とパスワード書き込むか、 WiFi.begin(ssid, password); として一旦接続させるかして、ハードに情報を保存してください。
+指定したタイムゾーンでの時刻取得の為、起動時に Wi-Fi 接続で NTP サーバーへの接続を行います。 +(時刻の表示並びに、 WxBeacon2 のモードを出荷時に戻す際に、蓄積データの基準時刻を書き込む必要がある為) +前もって接続する Wi-Fi の SSID とパスワードをハードに書き込む必要があります。(WiFi.begin() を引数なしで呼ぶと保存されている情報を元に接続します) +SmartConfig 等を利用して SSID とパスワード書き込むか、 WiFi.begin(ssid, password); として一旦接続させるかして、ハードに情報を保存してください。 @tnkmasayuki さんによる記事 [Lang-ship](https://lang-ship.com/blog/work/esp32-wi-fi-setting/) が参考になるでしょう。 +### AquesTalk ESP32 ライセンス +評価版では諸々の制限があります。ライセンスを取得した場合は、 src/aq_talk.cpp のライセンス部分を書き換えてください。 + +```cpp +bool initialize(const UBaseType_t priority, const BaseType_t core, aq_talk_callback f) +{ + if(!task_handle) + { + xTaskCreateUniversal(talk_task, "aq_talk_task", 4 * 1024, nullptr, priority, &task_handle, core); + callbackOnEnd = f; + return task_handle + && CAqTkPicoF_Init(workbuf, LEN_FRAME, "XXX-XXX-XXX") == 0; // ここにライセンスコード + } + return true; +} +``` ## 動作 -WxBeacon2 は通常(出荷時状態)、計測データを内部に蓄積しますが、このアプリケーションでは蓄積モードではなく、ブロードキャストモードを利用します。後述の操作方法(\*1)より、ブロードキャストモードに変更する必要があります。
-**なおモードを変更した場合、蓄積したデータは全て失われる点、ウェザーニュースアプリとの連携ができなくなる点には注意です。**
+WxBeacon2 は通常(出荷時状態)、計測データを内部に蓄積しますが、このアプリケーションでは蓄積モードではなく、ブロードキャストモードを利用します。後述の操作方法(\*1)より、ブロードキャストモードに変更する必要があります。 +**なおモードを変更した場合、蓄積したデータは全て失われる点、ウェザーニュースアプリとの連携ができなくなる点には注意です。** **後述の操作方法(\*2)によって出荷時に状態を戻し、再びウェザーニュースアプリとの連携を取ることができるようになります。** -モードがブロードキャストモードではない場合は、ティッカーが紫色となり、ティッカーにその旨表示されます。。
-ブロードキャストモードであれば、起動時にデータを取得、ティッカーに表示してポン子ちゃんが喋ります。その際のティッカーの色は WBGT (熱中症危険度) のレベルに応じて青、黄、赤のいずれかの色となります。以降は定期的にデータを取得して表示と喋りを行います。 +モードがブロードキャストモードではない場合は、ティッカーが紫色となり、ティッカーにその旨表示されます。。 +ブロードキャストモードであれば、起動時にデータを取得、ティッカーに表示してポン子ちゃんが喋ります。その際のティッカーの色は WBGT (熱中症危険度) のレベルに応じて青、黄、赤のいずれかの色となります。 ## 操作方法 |ボタン| 長押し | 短押し | |---|---|---| -|A | | 強制的にWxBeacon2のデータを取得して喋る| +|A | 全国の天気を取得して喋る | WxBeacon2のデータを取得して喋る| |B | (\*2)WxBeacon2 を出荷時の状態へ戻す | | |C | (\*1)WxBeacon2 をブロードキャストモードに変更する | ティッカー表示の ON/OFF | +各通信は排他的に動作するので、通信が動作中はボタンを押しても動作しません。 +通信中は画面左下に Wi-Fi か BT マークが点滅表示されています。 +progress + C 長押しでブロードキャストモードに上手くならなかった場合は、 B 長押しで出荷時に戻して再度試してください。 ## WxBeacon2 と M5Stack との NumBLE によるやり取り @@ -146,6 +210,35 @@ C 長押しでブロードキャストモードに上手くならなかった場 ## 謝辞 -* 各ライブラリの作成者関係者の方々、助言や示唆を頂いた方々には毎度大変お世話になっております。
-* 毎日楽しい番組を送ってくださる WNI のスタッフ、[気象予報士、キャスター](https://weathernews.jp/wnl/caster/index.html)他の皆様、作業中ラジオ的に楽しんでおります。
-* 元祖 Vtuber ポン子ちゃんを生み出した皆様、マネージャーの[山岸キャスター](https://twitter.com/airin0609)、木曜日の深夜がいつも楽しみです。
+* 各ライブラリの作成者関係者の方々、助言や示唆を頂いた方々には毎度大変お世話になっております。 +* 気象庁 JSON 、気象衛星ひまわり画像取得に関しての先人の皆様方の情報を参考にしました。 +* 毎日楽しい番組を送ってくださる WNI のスタッフ、[気象予報士、キャスター](https://weathernews.jp/wnl/caster/index.html)他の皆様、作業中ラジオ的に楽しんでおります。 +* 元祖 Vtuber ポン子ちゃんを生み出した皆様、マネージャーの[山岸キャスター](https://twitter.com/airin0609)、木曜日の深夜がいつも楽しみです。 + + +## 権利、規約等 + +### 気象庁 トゥルーカラー再現画像の利用規約に基づく表記 + +#### 日本語 +>(1) トゥルーカラー再現画像の説明 +>トゥルーカラー再現画像は、ひまわり8号・9号の可視3バンド(バンド1、2、3)、近赤外1バンド(バンド4)及び赤外1バンド(バンド13)を利用し、人間の目で見たような色を再現した衛星画像です。本画像は、衛星によって観測された画像を人間の目で見たように再現する手法(参考文献[1])によって作成されています。この色の再現過程において緑色を調節するために、Millerらによる手法(参考文献[2])の応用として、バンド2、3、4が使用されています。また、画像をより鮮明にするために、大気分子により太陽光が散乱される影響を除去するための手法(レイリー散乱補正)(参考文献[2])が利用されています。 +> +>(2) 謝辞 +>トゥルーカラー再現画像は、気象庁気象衛星センターと米国海洋大気庁衛星部門GOES-Rアルゴリズムワーキンググループ画像チーム(NOAA/NESDIS/STAR GOES-R Algorithm Working Group imagery team)との協力により開発されました。また、レイリー散乱補正のためのソフトウェアは、NOAA/NESDISとコロラド州立大学との共同研究施設(Cooperative Institute for Research in the Atmosphere: CIRA)から気象庁気象衛星センターに提供されました。関係機関に感謝いたします。 +> +>(3) 参考文献 +>[1] Murata, H., K. Saitoh, Y. Sumida, 2018: True color imagery rendering for Himawari-8 with a color reproduction approach based on the CIE XYZ color system. J. Meteor. Soc. Japan., doi: 10.2151/jmsj.2018-049. +>[2] Miller, S., T. Schmit, C. Seaman, D. Lindsey, M. Gunshor, R. Kohrs, Y. Sumida, and D. Hillger, 2016: A Sight for Sore Eyes - The Return of True Color to Geostationary Satellites. Bull. Amer. Meteor. Soc. doi: 10.1175/BAMS-D-15-00154.1 + +#### English +>1) True Color Reproduction imagery +>True Color Reproduction (TCR) technology enables the display of earth images taken from space in a way that is familiar to the human eye. The imagery consists of data from three visible bands (Band 1, 2 and 3), one near-infrared band (Band 4) and one infrared band (Band 13). To reproduce colors as seen by the human eye, RGB signals observed by AHI are converted into CIE XYZ values and reconverted into RGB signals for output devices compliant with sRGB (an international standard for RGB color space) (Murata et al., 2018). In this process, as an alternative to the bi-spectral hybrid green method outlined by Miller et al. (2016), the green band is optimally adjusted using Band 2, 3 and 4. To make the imagery more vivid, atmospheric correction (Rayleigh correction, Miller et al., 2016) is also applied to AHI Bands 1-4. Software for this purpose was provided by the Cooperative Institute for Research in the Atmosphere (CIRA) established by NOAA/NESDIS and Colorado State University in United States of America. +> +>2) Acknowledgement +>The imagery was developed on the basis of collaboration between the JMA Meteorological Satellite Center and the NOAA/NESDIS/STAR GOES-R Algorithm Working Group imagery team. We would like to acknowledge them for the collaboration and their permission to use the software. +> +>3) Reference +>Murata, H., K. Saitoh, Y. Sumida, 2018: True color imagery rendering for Himawari-8 with a color reproduction approach based on the CIE XYZ color system. J. Meteor. Soc. Japan. doi: 10.2151/jmsj. 2018-049 +>Miller, S., T. Schmit, C. Seaman, D. Lindsey, M. Gunshor, R. Kohrs, Y. Sumida, and D. Hillger, 2016: A Sight for Sore Eyes - The Return of True Color to Geostationary Satellites. Bull. Amer. Meteor. Soc. doi: 10.1175/BAMS-D-15-00154.1 + diff --git a/doc/forecast.jpg b/doc/forecast.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fac98b8681045cbd3de968dd3c3e3d82e568544d GIT binary patch literal 81988 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 literal 0 HcmV?d00001 diff --git a/doc/himawari.jpg b/doc/himawari.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d2d442962afb3109c1836dc1550865619bdc014d GIT binary patch literal 86995 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 &%EqO8h{Bp~QrTm! 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 aAQuv)NhLETrilrE3;G8HNv4)av;Wz|Is@eZ literal 0 HcmV?d00001 diff --git a/doc/progress.jpg b/doc/progress.jpg new file mode 100644 index 0000000000000000000000000000000000000000..43c178058909156615e08d6212f6acf73913fb1a GIT binary patch literal 49777 zcmb5UbyQT}7dLz-fT3II96F=~C1>cNV*p7hl`aYCp}U3_hJy-)4C_vf5{bN_w-R9fmNbpQkc0MP9P{96E200{Vh z^uIggmY{^t{}GIkkbsaFMnXaiBPJ#xqa-6Cr646HCZ{H+proRrrXnGup{1dsy?v(o zpAgXhYC@o}+lo}A#H6>}|3~`Q15m?2C!hcbh#CM>gCNwPfBgX4t({N^=zsS9{{#j= z5CSM65saARw)_#*?JER)tC@g^kc5Dg004m@)Bu!#kduf;97$_v2jlXNpre<_D89q3 zZ1lGG>s`2{z0VXe0}rp1aU}NLibHhf(Xac`DynMg&wZmx`p}M96{kZQauLx>C>z;%-{FQ!O2HyB zc&Dbz`%Y#YZlE=|Pnjws?+`b1Ih6rF`0434RF{B0fmz|MyzD~Zle^$n{=TLks`zJ zn0^6CNun|X<_rON{AQ&334H=ln4Uqg!Zz6chbD(c^)VeV90DjO$DjG{A;9yq#2#iB z{e@W|LC3!J-?v&=wX$fMRoTk?DrSi*sC{He6Ask4REUf~dRu`RNCOvd7oD`160}`b@#Gp3Nul~*y=L&$%59@8LHuMvp1^< z?+Sbodi?t28)PKT8`Eb6j(eNa;Q7W9CKrl7dq?gVA;1a8pjc(9hhj~cPzuruL4^o= zi9I6Lo6SR;3Yb)(+KA=3>8J}7@kxQLjFar6mpay^+ zn~4)u?W4qC`~{a$E%+YWK+VF+K!x46KYVZ;Wv9C#)i8S6ak`)g1dQU9M?m2TFx6Cd zJbb##&ye-7GIyjfsu>Ir5I~DRUu3e!K;QLifkb7iAk|WYk5)A0DjN;Rz+-p16@EyMtB4(dtm?#86!}wq7M!*8+BI&p& zf0mAdrohJIWh0PcNp=!i;HkkKX86Q(mob3Z&}60`+~fx!R-?Z(V=xFaBSktuHJ-;g zYF=&7ca==lt2rqhxDX?Fg*-nKqAV)!3D5ZEepcEgNoV$R-0lze4xHdy|0mAictS0-jSq%8@ zDpeJ6O855xfTo-aBuTr2Ap0g}PKASEwVc5Ik?|Y){0f^G_*{Bc4Qx*e*bzW$LMfuz zPVZ7jw{blTw7ouYr@pKILMNl`7)N9jX{6PvG=n4DoCne#;XrVN;u|MW_PZZ6nsmUJ z;fCf06k{LE1Smg5=p$S3j)eRI9Azk_6h=@YJdZ{`MH9r*pKj#nM=NfSJ}8K!YG>)h z>KLs*q;<%X?;0dNR5_*`-qDI+8KJ@2hr0vf(Zd@Fdzvbm3soHB5eTw*bQblhR%uO3 zg?I%qh~qqOJB$uMmce;UCN1d#PC&TYAVBhhEYX=05luI(^mM((@2LnfQr6l z!C;Q83_}b??RBey(3cs2?(ANV$9- zHZpG6^v8iWNg}vk{gMJi;Q$(%dx&7TN)<$}P9fPHJ*9x`3jqT8GS)0!{lPL#32fQV z(3SQ%UEw5nwN5TAI6Y2>OBH4K(?1{ZrG~Z>n_k7Kx_F7~1XK@68@IY(6_a&KJ#2Pf3=8QCSS0Q$1ZqrkEV9Be9p2N5q$ zh@sZhIj+nWmt$W*P-Ct=?hgi9uTsV3^571_ zGJ;x;wgpe-JO}sNM^F^Q$$S4!LPFD#?2-s54M|}9VoLuw8skL<9pQc}H$VmkvPP)K zuiO^d~UHt{gyF8dA;xMB6IPqk_{s)CIOVg5OgG=oo|g z?=4Y*Crf7lln^h#D9%b3ud@um`bY4xpaJ!1!+(hU|8XK)puAR=D`3SV)oI<5y-? zth*dwE5N58>vEin~U^5eOjbH@sd;F_I(Efq+vBN>@YMDkiQ( za+~L9M*IVACqXP0VJ@ckYd$@43&n|);3B%`0w}X+8KK}829V!KVlMd+dNI~dZz3J) z0g59!I?8?n5Tzfdx=!I{G9XquuHK)fP}M^$0FN{zdMkHm08FKug2~t_h+KeYiDhN? za>6wyp&HrgrsY%_lbL@fL4V^j4|P;CjfSCd=r)0rR>|39%t4*(SCk-!UljDhU=B=@ zWRQ9ITyIsn3N!MH=3TZhT?Sl3D-eXglWL!hLCztH!O-BuEh8*l@ga>&QHpL9TnIY! z(!4yKdIJqlAi^a|K=so7sQ@`zLg#gmw+p5e?h8;f^$76NPW~@fOXk$pG#V1v_fD2Wez%{sEeRu?%Ea_|M(!lQ~DBOWwO!c%A-{lvC z6op+*_0YWN5hO|eQerhXx5Wl9@S}4viR+~SX zKW5awa4;2FHUf@dFF&Y3rZ)Kqi%-&(z7@Z8wo6K%L=y=>PZ$4`D!plkQo#i{QoCm0 z{{XvVS<~DIs`_FDft4$wDe<}VFcTI{8C5+2ei*T&9F4x#%b8>0e%f{@Ofk$i^f6~H zmY@s^DDFh^FK|#>CVENH9#n-^UrM>B_pb93lGR=estNZ)q43}7NI4QoDuTi3@jF>% z)NeE3c%LX5<`a|{^i=8zAzU`G{}>D%DX7Q^xBbKbo+sl!XsCQq+4+Y|?D{ks+h8l3 zFB8@qOXVksGHSQ?FKqI-jv}KT&#pG)@XeepTpx;+jom;3Sk+8*2?hsjm7=#16;wc( zPBsXg?(^^xP7efoP9<}Ufs|^tdCB1!HZLVLH7;)cD# z?~P?hbq+XAXxnQ?y}11!YB_$%#fi!3R~0(6?Mq>4;4&c#0=z^)jKayUFeb$43zAeu zJ}zIyR9jO-#B8!et5`;+BUQ-)!mv#fi$pMf)l3m&q8} zNE`u4bi_;|`*A6>s5!Hh_U+ZK#$n~o`aMHB)y+54{AYUha}-D0%fG6Ff)3|wDl*c} z1Iy-hSUyQgARb9wvj+TRtH_{ztv)4SrZihE*Q51RpqAtxaNAh=1CqZ5<%ybVJ8*Z- zcj11Inl5hn*0+2_1D|sr7ShPhm6LiRB2mk^S6xEytpU!8Zkd^iKU_Jjt{1HeUD2g( zOl(V6Sdc3(OgADrtQHZ($(^WO)y`d)t%;)25d<7z^Z8RQ)Ti6@znrmH+Sp+4@3zJk zmNx6w7u+o7>mdH#2087LqVM5tAC3@g!i$XLD-T0HK2VCeUw#kI7tVF}L4Ag~d|MV= z{ZqeEU-=n2Ofz)lUL@y$aED_h!#HcJSJ8K)%Nixlv*buKy5BA+2%{Tik!;of$BK^6 z?B7S^t-o&t3O2OvD|M_L-?MqJ>QPp766|o@;BdKp*}%Ei%c6yU6Mo+vI9Qp^Xb`r_TfLk;=0&{CtTb5kJ?qmfp6K`z-5d94@gGoo zn>DlhPg7bNI5gh3$Q<=Bk6QS2%TwyyA)P@pA0L|L=}*l^tT(#T&cWsb01s(t=G6t z)sIvzdjs_QrM;kaS$E9Ru!f<7K~XsGz*1;|C?~Sbh@*<-S_xUN%@=w z6XwuBil(Daom6p5C$tVBSY2&`(0-D?`?z$zoyD)~{5_uPvfVgeF6iF|)|TjfeKL;@ zuIKaYYBC%|#Csfu&FOy0PcAi`IpLNawt=kw01`QsQ>f6NoN35~eDEk=#bD}WP!wy} zG=rghZY#wlOv+#R{_x_TR|63ut1NpOjyzULS5NEpM*7*cLMudnfxD}yu*zb68imUr zQl}}-8UNsXGjG(R=Jv0g_Qg)&E`N$X2%dRur~abz&%5hG(p~8@3azBT$Yo3#RHxx3 zX!n)!fr!MX4qfO@yIt5&)1P9Fj6_@HvbT2AJ)>B&rlrbt5qIv@_XkpZj1ldlG@=PDzh6g1>q%5sp)1-GgrnaVXpl)OjlZc^ z91hBf({K9F%3M@>vNJ~42}|m@)z;7)ovATwyzgIBeNAeG(10l{ZILnOk-Zfh6dTzDj?n(r}2ao z|3+!>o^@|hETCZbA%MRoQoYQ&Y~jDnqZWivGzUa z6JhQQ*CigM7stOCT1PF2vWI9KUX7csPR*d6)ywDK-vgb;!INr6D;-&t%?C^Je zopBo3H{GV^Zr^C%pYsUyg>UbVU{aDpTtb_bcqnSr+YZ9Ty-?4&y+Zy04_wr&2USk9 zk3Y<;mHB698qf1da|ZgnCEV}{x*SaAe3J3v3lin+y@})!40WV%v)&i=WS$y={5f-nfPe(kXC#@ zR(9NTDLMUxh+8ux=SAo1M{k<^WE5DvXl`Mq_gx0sJQmZ#wpDD$f|?TIywcZAj$)!d z{smoC!?yMz5sC3bq>-{;oN-Xopz%W#mz+UlYhIL5&yg%zrtsRS$JT2dGRJn3e}_sP zjV+5rl*dY|qiDDG)ENn5NfQ*dKk+nEjt2&5DupuGMavKK6_=8w589qdsxv^^mcp6D zhWC{>_Z9<6$;2WB7jA#x%9+bm3QnJ>rr}>>MXD|yBxL}!M5Ardsl%B&2zWnYm&hXh z*hwBeTV!mn+uYfews_;t8vto%7o2D+?_U4ZUW1iC&znIFnz#KjG_L$Pl6U_@vVW=e z!(*R?pQYcqg4e-?i^8KC&GSqT2Kzxg6bIt}$_fT?FmIGpiarN@R%~7T{ zAho}NAW_u?5J7Mv zGMx;}-$QE8@iiiu(n1V^Meeno;s^`Q<|e^#zwMBcbXe9tSOD|;TQeX_B->8=t(k+o zHjZHnLCmQPGkSJ_gC!>GoSx!T8>M2eB;sg3IF3Y3uOWt~0=RFXDFL~Rrv6EY&Mmev z>1~~v9*>d;@s=Eiybds2w{8y=A;4y|pVlWUwz$?P zl6Vy}ADY=#7xxWEiG}RQL~2LSXS3Nq%_Zk<29%`SoIvfJXE*{mKO7Y8P-g%Zll4T9 zzH-7LGP|Z#=*|-J5lT)whCL*@V(hJ<+aMJ69s(971^foXioPSDWm&~ShIu;(P*>(9 zKWH1279Io0pXCD%)8zn1z-_k?1p#V^+OUFckh>T^kd;-T@WT-mHH8CM<8cH{Ll!{z zopaT@1>fJN}6%-4TMD6Mp>bogjwV6)4R`DJ_31lLuM{wTgcgXkS^Q(tD7KP`l z$d_axLIIv^O#gSWDH3<8!S<zQEa^J;gB4_$NZ;f1>6w42(D;z1`nZKs-mf#_*(=i!gyi zP>2&qkeG^N@C4}WDFfpO6gn>qz&Ik7kL9x%20tlamkN~rY^)g&-$B6Gy0<~JawLGL zy)-If13|uEcROy)K+tQKEUmN$TmkamgsA=FJn3ka|_9upOYvm?QgJrtLz zP2D{R|MO{3@7ygSNX6%Z8TeL(BQycC|KN3E_{elyZ@Cl^b6xX4>%_qvOh9M~_-@&x z_((y=B$2ru5+5mV1lqH(V)o-AYBa?m(feH{8LCgXjmGZf?|hmLnusHW{#V8td|rhr2WUA6@ZrKR zkYA_)vK^D++dbr0g2AestwGY5U(|AF3>xU@KSYqoh$BdHCSepO?m$pbhybSSGawRQ zQnp0k*i4nkFULJIRjK+kr%L74DnBxn2~9dW7>6D(Dy=%ovBJTc!3 z97WPe1a!8Pa18De!Uzd^#~+;%%z?A-P(Ri2M~uwjVlFR~NpbmNm_WFi_|d(eUwgciZk^aQB??EF zT7jVllx`hIWDp79zEyz-egqnT6$0jSVGNQ}>107CI08a`kO3H&xIqI|AoBjH9+F(x z;m7a=1er8%aWm#fzS`ZEKecm;q100rO6S?F>KvcuF95L>#OPRGc;Z#nm-niq{Q2`wO}~MSgVz* z5PJfAkm@mkzh6&P(CkRT5 zH$vftv!*hb-CQ0avya7*T&WPDb=#;#H5D?&VxJ;`QZjRg^72|-DJ+Lzr6z#Rjuex` zOO#jMV)OG(=pdPZYWz}Gz74Uh4NZqeIWl47p7+$q{#1@i&^gPypr2~Y??k@Bj}#`0 z+e=|GB@(?0FADLwy+XUnE+ zl(=ZKsr}$rJ=cBMJH3HRGCu0Hd;-?o4JL_2y>jC2GOhbemz76InQci&R^4eX=t?*PrQFibD0}PzMo^PDIMNg+`+k715tDg@mL6-bpAATok){xm9 zo>jl+UsRRll>F--Faw(}zvd1;;%l@BD^cCn`SZ*5TgB=(Vrey{Gq~nuSc8r9KhIOZC=wt?EzJ=rju%pQ2^F zx#ZL=I=DXW3f4O%h! zF^^}R(n0JC-Gh;j@N@Jx72|Wt-K`7NLb~_NOI1ZG#@6Jh;G~O|$7P&-W5_=Zvo5YB zRT-gX22w{KdOSQ#)gE>5M%=kc&cw3O@Oc09w^9n|6>tnBpY zfF{!FM)pm(Jlj_cmG~szyQ)Kp$M}GhFfPeHT{guDalWvV@9M+#VTY$c1D(^6{~+9R zYqn(f-9V%DO>rFQNxtLtqoqqDzi0GWG7aCK{h~MjaL4xZTc5!Jkb8o_wVidV-s1f1 zfNX7!qwzP<$9YU~>kV+~s~K^d2oaM12J9HAW?fs(#eWBRGA;3L%(`RmL~Ci*6B#(+ z-M1eO1T*V08`fI1{3rQRkt5xow&`0wYwz3PJaNVB#x!1gmfGiA^K~|$cO`#wA0q_+ z1~Xv!#ATuZOq(q(q&Wl#=0))QiJU9x6&9@0$>7o^O>HV-~v-ek#rt+ajD5ZB< zZ`nWftZo>t1i~4{1{ic-tzSr$URHZ1U6hUR7+KjqG4Gn{W3}t2ofP1KU!U^xkLnp7 zscU(;u6K1$=D%kcXdc)s{GbxxwB?M<=I0NI{jO%Fz8j7-4Yz>f zx0Hb7&L?ji@&@ljU$2|IEeehvM=5)6q(lD!izYP>geC&*e1fJmF$j`$(w80?Mr3It z9J%umjs$RBWIxuPld}O)FjDB!=rEy;{?$wKDr5SnIt4}j!jWPBsH#GSBgrsQzc_;{FhQZn|V;QrK%O%3- zi8>XDt46g$s8Zhb2S;Dk7%l3FRrBP;-DyOko&@`z>GCnspf~>k{G?570vp;C)N)jr zhVx%t%9W-NYeMcCuc_4gsg)g>vBBo473&#iXiMRV2VCB5JaB_$2EIFpOCDVTaS7O! zP{8!@zzMZ|4&ykhL$)gvM8eg5K`J15Pf^V7NgnB-6&K-tZFsh`Y!2i5Oc`00U%nXw zqQ)$X3(6&3YQm^OoXwxb#GZuw7!KlP?4b3qndEwLXh_G z+{tj-o2aIlrf>N8%YwTx+u5=~`!;XCDn-0DGwxz-jhlBRsQUeL?Ue8d!rsbtx&>DyBl2xm9KlBvAA2h*9MZX#NRYSE>y@+7-mnm%ha z&uB1Jj2_I=2~;DqgSa7m4$so`aAAks*x}9^VxkaLs4(HRmLg@)y#;enRp;`m$R*^+oq&q=*fH zpSL>^f=Yrj%Ps-*bl)k7^X{~KE!Nem+>{R0_+&%6tLqxrw?{@(=ks~K)$8+29bLJW z&T-+RotA#aI+uU|Jb&Lo6OSf!@@y_Y#|hYbbZ^dnP5K%3tQp3o^5xN{;FP zqo7nH*?75=`s)D;Kj)gM9NPQLE`|*|!G*7eZT*~nj0Nslb4II|-G!l)v0Kp~#XmoO z`!*;p9nj!e`IIU%OJWG?eO}@NKPuiQ3`lq&%uX%NFa|B3Y~0kX=j>G~LkY^oV}u$~ zIo&o?H}@1yv!1P=J{gT!{#wWI7Q8fqnv{4oojaGL~1Q^xHLz9Pe5H!x%In(W#@DLcBXEvEC=^??vVkuU-O-sM|oqS z4jDfAIYjAGxx0d>kn{;P=0l@C&<|>GDnOGM!J{# zEiOxaX#nX|M0|FoFjS_}Y1!SMRXgw?c?d%hw=wD7*+*ff?oOKuSddYf(~zqf>x^1hcU<9O-CjL1lKP&d34cM)l=UI@$V@?Y z`9C)QKd}Rk)?TFf&&1@5iw+0!vNK?Uv^!rTobXNSL zhFI=jyz%-wVG6Wr#*U>so2BQ@tyhxq@mW~+vH6fU_n`Riw@G}V9jz=&nXOHk;D7ip z=#0OnA8k_i1pWbp-_&#NabLYwKm8aw$@e5fN%pAXLrYMdxoaD9F40u;U&#_mlmVeV zZzZ)(O&7Z9J@uB^P}ChY1*1Su}*P=D; zqU7~>e0`Q~XN=XIu4xO-0>k(|i%rRZ>Q}z9Tinh!9eC(*+6;5%Bc|A@g0XU$lb3TA zJlfC0jUT4gOopg*uFhnvnsJ}WR1P4V#+;o=Kq4(gUp3)?ke~Z=mFdm6D3XH|6KnO( z9}V9K$KpfGTc+BQu*vRmqW8=Bd$O?B27engM&F4nG&TGE1H{vOe(Y8uP8!T&n1)c! zuR@jjUb$Ik_u6|%=#A$5CvYi}HoGT;KAbcYQNOuMzj#0^BlgyJ=O8-OuSfkr>U!es zWL`)?twjvVkKg1|*NUeAN4e@v2A25B)wT9hCzIdXlYhWcz7v;WsSE zju|pNngP?@cY*lIY>jX~KA&<1UE7JJ)ue(BE9oTX*;1oq9+`1NvvO}!St0|QU*BwY zwWV*~k+#`?F9ElQt2Ob}%zy-#)vUdZ0`O~gdJh&3WDUz1M-SXKgYIeUrr!Srk*j<2 zkk8BXrCF+#e8mBYmA2z`9*VUj*mQokN$S$+tERq*bF_~|yy+113-=ppg ziM89SbIFrF3xq3{^R!O%a*h;qR{7rlGCd{4dpLiQ^4fDnxz2rIbdZ8`z=P)LiAU+6 zLIS?X+H%9{#?H5Lv_OA{N6?V3)qBHQv>>d(sg;!|PXj7L&!=Pc+u=_=d^FFN%D2 za+~#TURXVtdC^(%`u4CPI(M-@FvvK?CC6;Cmi}+jnzBsJ?_$y01Y-Mz-gT_VVFP39 zi?(TxdXc(#Ax%SIsH#ybdP#;mrj}lN+bSKoLl3{vYWvH+RG59A{}K~_BGujIaFHAR znQnvd&&aVtgQ98xQBd<+>XDiSHW1vmYCRo3VA{i^vL0GGn|Z|YYBq}J(HU}%i2Q|& zK~97=e_os%(I0)5$HN^sP^6YNyrb7 z*@I0}&21gCSKp_9E>5twZ(VD!9~)n%%D;z4pVTKW5L)U7`Xdv((lo|&|v z5%=Q4;b%uNYw)*dbm~0zar<7T&T;)yv8VmomwYS635?lyE11k)W;>QS4A)eb zv-kKUrZ_idp+Ddfrd@p*x`TFV3q#@20dE*H2}eCb&QKJ;yu6 z=h4zLiF4lixep^&A7*fz(GOMxJc5o>r&~^nwWy7pp%wGvOTSoBL^=vMd=ZF=Yww zwE5@%FcIak2(B1?dVDvR<*gTd_lA?(v= zvVoWXkiYe-CX|(7Ov37p>?zIQ>f5@MOPR;IPk)_Q(bL~mNhIa_lK<3|XS!^qMSDkR z?8|fcJg(oIuRq$=%!}bj=ctYW0@kz6yrPIh_3-oFiYf7a~Z9Yk$(1VmujnA&heoHf@C7O9G zLDM!jPTSTHDdn7eFFgi@h%PopK9&;t25ALQ^@VUh?%fD26dud1Rpfmp;@)US8Jo0U z?r_l$hyDF3`sProWuwGvN2}>B8{;=Gn{gHb{NIS&>7dg<0BOc;W;J>ldur{`*{GE{ zuFZc^AiJz}rT*0Hzec3JSp7!c=vISTWXMxX=OJ|2`7sc5B}AeSEHKvcGE?Nl@yY2W z&hr6v-{M4yYr@?C^PdIpith=`bhTOny-<41G*P@peU0Vk-a7gZ*qDI!bM@cl-Gx#W zazxkwl+9+o{U%*_6hAk@bHTn(a;Y1WyG$ut(O~6?WR6j-4-5{=19{YGlTK zXrDHB6-pwao6l|6jyDw8MQkkwO}AevcQn1WU(Q%KQIkzIbnP8)<{5f7k<)VXJh9XN zv=#rUrJANG-4;u75wiRD^!wsRah|VIH{{k6yulKdFxR;Mo_)!6R_Y$*nGI0e! z68^E+6jt{~1OK3>wQ1o`Kyg2=*=Ja1B!W=OZg^X_h(0lcZE_aDd!p1lJ_Ss?z{RePE>YAsO>vq(xYiSKi{o%a|9QRvK6TfQwwe(vkOn zqsu1Nn!UWOG7J^8f1aEk|9zCbwrIrCIxLShsxp8^UG8}ctcu@I8tga^y_uHT@;o)l z9QAzs4``}ZHXqbWF-c{IKU9CGJv2`gH^pLHyrrBi-@_Jn(C|gO8f7^mDq&~V$Py@H zZCK^~(3;76+!EfghU6@znJ;O+@MUdwMt?t6GGtql2xOkOi*POIZ7IjKy|$xd(*Ant>_JL6O-=sa2OoaqQ7_Iaj_AI4hz9{hdMBNduDx!W2~?$@-_&)I2G$(C zIAebJp=9G>QZ@mYt{uvB!LFb7_v;N=$K&W)3k?CH(bACjp7$>qTkg5P_y_Q@<8|pa z4tgLL#?zx+Y-c<5JeP&`m2`UkMG{~{S`4_AGAG{go^v+`#8 z2bjq&Wq!2?8(p1Pc<3_4J}jL}tYsQ54cpee-EuWuGHG^6txVN-X=;yA;G$$XvUEvv zIAC}tyxcbW^xKoX)+SMbZ>-s}?=RGYPU`jQ`6tK9KDVTJ%cOi=DU|Lz+K`!ld!=?` zavP8zy!7adPKQHi6$oq%+fbgF(q|rZ?0>!yp;r83#&<;dZN59b?rgVu%8Gyaxg$*| z#SJaJ$D9&-+S-)VhAUShtTeoM!l)AarSd`r6gBERCbY@S#`+2MNGo<#eO1WXbVfN) zFlN1y=D%*z2(^@nhj*Ore3L-qgWm<^mXwQZqZ?S*d2NXF-zPk|v+d3)QklU)-X2mF zE!NIz(NOj-g)+soCErtX-ScQ}wJT;`TerBFWz4h(OO%&COr*m*-z%k0g*y*}BOWLI=`yeP##phuL(-mjIk*AfxAay z_=9+wf~(%d<*_H)7CzUh9=m!mCo8`)rJQWIZ)5kTpLMa{;z@pu+^ONBv()EDnN=s; zU+}eBJ)~25>K&?kSJ0z+!>4}YbZ_CyJ%+;7I0+Yy%%$S=MCM#$o%H^F1FHVhrD9QP zc`r9v4dH>L+Ln;xzx`AV(;GGpvq3!C*~=B};(N$*_5G7r96J??+0*9nnfp{Ki;a%& zdXlhS>zAFR0P|1J4&3rA+80$ke9Ch7=<`&xyBq%SA3rnfZuIPjqqiRH)Ln^MdDITy z<@0+n(C?x>rYpMa$Pp7 z%!S9zCg+M_5+74gzSl)5#kb&TNiAo?sh)}5VygLNHryw2H!+^g$XW6A+c**ezvq@Y zcC5NDi%yy;WA5!Nz;2Yqap|e0W9do-RZ};G@2|OkmPi(j^3%O)?ww2QC`@ohRr4Pw z)S!IK>eW=U8I@XEG9IbTaT=8d)$BY?e);n;a<$BSX=sKj)ntLxsL6Q*y~ z6kNY{#o!`$9%NcIuicY_Ko#r^ji@HRT9v15`90g1pe;nC)s(EU8_Lf`57U94>>Stb zG-xXEp;xeow^r`|fRtb&&3{1a1B#09C7J%iX20$AyI2I-1vBw=%;i z9MkpIX1kb8O`L7Cyw4P#p{llAs__~Ue_npAn|JA!tA2NveV^{Lvt zVttQUBpz_Oy3v;HV+`uMev<_#a0zuz7g+dHC#UM0)ia%GdlEaINGtZu4n$j8yvfOP zQ#LBV)IQ@g=t*8}Q#a#>2eHi%WQ;OyK$WpirSJ2cav3^v35|zlU(h6t`O4BXIK~i1 z8ER=ipnH}R=$d*Z*WZ{Rvf(F^@tioLi0QOH0^~$lPos{{|^ZY;lfm(=R=1eIpld>T7o{sHEDLfXZ!rzZ(=1b1Bu=sA% z!Pty6y7*#ek)m%{>iFLJNZl$>gfr&X2V=T}}zJMPCR$Pm2)J-NI*#uPBCH z&3Nrv3%-=6N#1F+hwlhC?&37BUEW_zeflp2|7As`R>LtKTK!hBnP_&l2%c?nB;os1 z^QX0k;(e=*`EP8fnz0`m>W{IAKxUHS)8?8D?4fPr=nv6fPTCF1lMOYjY1zIOrf)rK zhI~VE)b-Rn23xf$7vE?2l}(+)-;qRIIn(yi>?U6Imh4)gSUy?6xuuU1(#g!CT$9|_ z{{fk^Qd=EMO1&nE)~JFyV3U84=tY$y^yaQIB`St?Eotb$C2NE-vHX`L-9dVJJ z6r(t_|1ibD8Nwm@jeXdvmm+DDKSD3@nU$hy*$3i<`119qPZ?D=-2VInrb}-)AAO^w z3jf4I*`HQs1;SITor=VQugj%p4tPkPI5HTLN`QXvG{49xe}J!-4=Jp!R5vUqy2l`Q zP&WCO{IPwf@b{x%prH;WT^VNub41fieN*)Y>I6QQvM#Roh zi$yVDH#i0f)nyb6Q6v-2xqCOaRk~eH`ha>-7=kt_sbQpZMJLq1@10;5e{nCP(!I;T zkp|<^X32kdbhkpxUFW~~IWfzYCuB_#U%3GAyXURq;@){4&k{q6^`0put@1w6oe)p* z`9wjDj}Bf=HVggg$5k^(I`YL&fgB$o*%RlzVKdNnTu7L3sPE-PtWbS$hcFX05}Zbm zb65Y_DQ$yzM8EZN+f-mq4znOX+tar$R(-FhGke`-C2N-ORup%<8G}<8Gif&$!!Cv{ z2V>7#7l%##vck&TneN5BM!FAOx$^`qVvvtCuTM8w-A%sLvwiwPK;Lv(FxT6X%HZ0} z$P{>fYNT=40J1doWN-}oS%0^=L5JlaekRE0bLZ6r>z-?X$!HuMQY(JH*>2=d&4b{? z?rd$f4>pVq*f;g#o+i~#1SIc>?f)fzBIhptZA~Q)juAtH^?pgX$R*gS!l{7FC2XOi z#7mRZ5Xll55>#42kOuP0<&@g($tG76l9oAveh)TgOFJr%iJ+(9Fyg_=P-j^JtQmt$Fr5grzL) zk(Vdt>H$88IQgdZz5nXYMj4oxRW<+j=kUjEZ#w>ilz;WD`d&A@J-amaTBOspzh&wr zsg^1>n`!bxeb=@6xzn8@LYnKswg;o5cgtt#GAA>+u)BNXVO-(Ue+s>HJ$oof?;71L zM?wd8D>@o}4Lpfk^!48&%Dpc2RewF1f8F&or^Wb=*&WTcqtP-RH7!B~=|+voMi(2) zYR&cgmM;F&eGkpqLp?Uu@r-RMjIQGU0KK%oF%DMGb^ifmua#&Nw#xoamr6}o>i)Pd zSJm7p?cV8e@dI?2G26v%-1@5XRplDr8|Rr~QU=f8QF9D#*@chU2Gs|C?A?WtX!Xv` zHZ-vvR*jUySK99gF!zeNWG%P*JN(qkN;PNBcOVzYQ1m6w_^{oA49KdYz!|x@Jmjl#jVE;D~n8tWr1#mkv5dslS6uRYbkl^=|rG$if6YW5r+TeS`9O&ATRR56Qw)gR;^gVKJ;Dac$~ zYRe2=(>Av^0^JF?Z~__yE=srZisgEWq$64l$2=Vdi;axF;(jBG*i60CIuBL7ny|;V zm0sK>w!&Lk>=hq{7Im$=IjtN?uLQ1W)t@w(-}Dc&KB~>|^^C4_h&d6OytnZ}nkh;U zq9gz#_SYG8uiLwqPq*}^gL`eH)vIgVljP(&vl)Gb(+p^A4z$VT_=9tFrhsW+a&Odu zvQh_Gt>vXU5~=EI#}M`~E6~h4F@IS>e!Xmt3S=-^_T^VO96n`Dl`MrQAo3^)9$dz} z_p9horF^SUSW-r=`V}E&<6FvS9a_1RL{})W&Q5QZ@`VbBsFMOYXU>m zu_3jBw^Bmz_XG{#AH-LG(35K7NU{r)ov0FI*Re&JK2R!+k9u-s&FD6I>^1jZPBK#eDhY5^P+60RBewtXfN1JsM{{SG}njY};uAt@H z8xOv;I-a2HXtunYs~dk;RY%yVYZGXfkhgIyv?W^; z(mMRBnxoX$TcW0pj;4u0!NLcH{jx(z;-doHA+&u~$q5Ift#$PuMpm6&HWhwR;(c90 zG%nRMf|C(lfytSeVm`OBC#Q~%pV}2oZ^19&lc(hyr?k7yTIvlf`%5WWF(FAa(i|~f zLBqMK-^uE9KiSiNvF;CHemdIgjTqjR%U&d8ED{iqqqzdK`klW!(UE0aW7yAIwoF$#}@5PN{rnTOE%_80U92nvJ;h^MmPi?&GhUyE;n^~t7 z!PRMWX>4h}Pc2_yuy_^m7Y~HSi)4Key5Il+r75-VUf1@2UUjXhRIKvwk3Q=P3Y~WU z0A_hEPbl(=_ROA2B6i#7QcMO+(^5~^GC7k&+6^7w*_PKKlCahoykZu+yNhNL$V#DH zks)tr^th-D!Dnloz?S-`nw{Kw9It7%uGGe^I+Cxdf?c<~+*hC#-J= ztx^6BSW5Z(F9o|UEpb9G@iXX04D_aRO>pMJP37|oy1r`EHmj1DP**HWSCL*_LRYS& z7t@ozv7;(h-IwI@71si_j}Q3KsWs*1v9-2q=&n4|uOt<$t8ktAKmdbYiT9liMvWR! zj~pDuOB%NI=T*z(<@j8_Q&MoVTi<4HmveTU@`{{NVn-uzW3YdU@v8{${5g zxoeI(VmFK=?bfW1f~ggE7(F%yYDHmC0Ra>MXzew9E@p)%uUmaE6}b84P*8vpI(|F+tIl=X*HYzC z!P)4Rv5f~;+_=qT?XuR4T3K17Ex)v40=asL^{jc+jonBpaW)pz-M;C~pFBOXN&Z!u zN|VbNwmsi3eS25c-3z)pTq(bU!g|(ltElc@xxuTmIO4|wpYqL!{{Z(5{{X})n#(Y2 z_8dPFJt6I7!bRkGW2d$LF5X_o+VZ>-H&Z0<_Z{oT?kC&6oj=_5Z8Q6}ia!YR7YewU zoZ*J4wbVF!rMKa%7ZM4DC&<;c;Hy({BLw1<&#ZpW{?ocEi@0lchDED7dgG0cx4`&IjEY5pJCTxmTZ`Y&>? zHl&p{sSTczPj7`~TG=}9FTrg}v81qkAn8(4_uJdRgO(%Niv*wd#?nqHv1_0n(l zXPt-H5#%e@(dHvT6(#b3boHew`xa(KPX=3f>(^2oZrNoj8yM?a>e{WOUL_*8G`yYj z**4zx+c~IhQ+kYj%l1vG-PcTe=~B9R{i^15tyaxdgp*)iI=*y}dZuO!|nyqlFMx@t}RSvtm;P<)2&YXSHF*ORb-MqGZo^DW;818nh7B((UQas}#Qi5lfuX=$u90ClT#LYo0@FaHs z0A?G7rzxrJ&`2xBwy6d-4iJBBY^~qXwCuW3r%|SN?Hi&q8pJxgSIcZPc}mIZe5%&5 z%J@A3GmDne(O3rm5K>ko>>yV^ebctug-!D|cDlvIs>Dm{FKaF*UEC$B zYkMAIc9it4e^StFZ0YWwv26N^<~|v>vF$U&g2GMNwMxK&%8r7(hW`Lfv8#6F6`Zpo zk6T~SSc^3r=e6e*Z1M|Y*5c6!Kmt5E^*sxswCdKesW@_EF0jgJ`)w@u{NYc2UPi!D4y*LEcT0Q!di z0OA!@f586$fRExw(yWFK$5!xZoF&pyv^$Pc3Qv&)SB&auLh4grC#UHWZj?`yT8kKP zdCUAdh$hP6#t9wyR7G1(PEb-tU3{vH*!WM7)HeFl7{;HeolT z9!zSLT{eA<;a+Pyj?=bQ+K(V_mRd*W4^g#fFKpunlRDbr&0y(_U9kEBn{XNEJBrdd zMsI^<80|(vQdPXv+sA|vabXR~6Etm$miEI9z6kE`S+s1e#R&pJeCbi0I@LDhbrhnq zah^7umaNjZ*0vdYoN`jip;qdJbnWX~d09rD8Hq~fH70y-)+o5Q)R`M=o7ZmKX5na4 zu98%u4^utsb3rcJ!H;s*@{sS=vQk(^KafRiT4TsO3Tb z00xDpG|qQcWRZr`xYuv5989IA;$U?oorQWGTG6FX>v%XiaFtnXiMl7*#~VP(@PCN9V;Jsw>k?VFw-V#6 zJPAnoRuyW~PwHf+q}*FmZJK&=cj_dn_4Dy@U&g3)8{pQel8i9f8t?9Ro2N-i&F&aOj_EkOCGnuB>3_P{1+ZzvN4L>{$CVvx#GfCVG1 z2$oLA?7rz%vC7*mT%r6*q{l!UNAaztuN40P=5>8B{=3h??yVh{(VA-l&84#Hq_<^0@ElsHyZzVi$>+ao>qB$FJd(rh zK8EhCoj}-12!=N3DB;!u&^&d?adm-5}YvPi5_1 zY1PX$Q#-zyo+-4>JiCPyz%|7kJ9slJcDE;~p7fg<)#y5@veT zDs9=64auW^(-t=o^p3l8`q8XJ@w6dw{E-|%9BP8Z&SZza=TXANrBXw+vt5O z3e@9PqU5rTDOBXsuC83Uc~3a0QjK~=8cN;@9>&I;6juZrdDYxGeJqmBd*bII<5u~qjX?q>+t%8z(d5GmQde@F$Qk3h; zC#Pw(BTk%87HU2W@o!M)@;SfAi>AJvaO3=?#>X!)nEO=d$;BvO$f;T~sQETd5%8ml z8be#-vw3Y6>h0NeB~tT#=$^l7vnk1?;Ki*d%=%l4)OP8^SzI*BXe&ZeTP~(k_|~IP zr&4L*7h29Rk~aGc+AWgXqW0WK1`EmlHNz@baF^j{T&^wZMA>ZhejKEIBL39|H$FOR zWe8l#JjIwZofPW?Iiniw#WLCSiP-`ZUlhsI0p1pbNn+IMAP(yw&g>7BL?P^LH!OT*)rB0`l=We(5 zdEz#$)p;F2-_(}qy?st4A4?(uJ4`37T|$iG95hO;-6>1SNS|d+A}GSLSRj3Fm;K7i zbSIAnEbgNh8qNRw#b9sdAKS7)q6%8Xgb>7P}{2flPphso;`b9(kfu)-FkrT~&=y#D}F z)oIw&P;ooET2ikk`vIsi860XJ!@G6Ob7W;Cby9!utsbLI+|ySy*9^*`9M24*)7Xtk zsjk;;ja!Q-5~5DRwGDRZskCJ%{aC??#0*Af6{0mJBQ90WEy|J=xFDfhiqz^g5^=$- z)@e!>@_0NnK}Z0>F<7x#ndNe7S;-km5_*B!r<7KrH!&w*W+^s_sE&XTk`?lrh6&(s zKr!By0|ONu<9e);h#~}#W|}6E(YOn#u)1Sh{VzRp^m|K-C#}@ykx@w>@YZb^;-CD@ z=7V;vu3qnhw>z%*ZjwONUhe1Z3d*6HwG?CJox9gahW?{fqBci}TWD@oOk6uJO%2_ZwY)`|U(YBHs=FZVan z`$Msk%JwwAHSxEGS)LN+^sWae<=yr3jVZok&?b6)_3Ir4(idGh{;$Eo^=DFBYS2oV z<5zkgI`ug&(IThd=PS5ET{lp0Y4 zdKjzeRkpT|YAqu!mAsP7A^^c=mG*HLr{Qk1`>KAjjFudi{Y%xod}C`2Y25if?hhb- z7OsB^kFBAc%1i#Fm92f*+QUwk)XV!icP4%ojvw7i*4nkTO@Guq9ag^sE7psPC(0c| zjJ(pfN|I8fk>(EKvJ&pY3&D=#B=Gn)t6nVe0@0T3t+VeXw#O$^QT^U2o)p{3{V!>G7WBfqms!Kg33OpTwn^IqS$j)gQv7pn`I)B0%)T=MdBgGynE(z6HWAJd*J2b`Yi9J@ow81<{ z;)9zVQI{b90MZ(l{g}QA-lbjsa8ADBYQddNm>~H)suc9a@E>_q{X{2N@e$by)H!lJ zUsv&|tDQ1G1YP|{=0KfG#03aeb1T1NaIfQ1_1a?hMQ-|Q^AVihx>4URlUMy=U&fcO z(>_p@?4RZX>m6!;_MS|G{{T*}<4^BhHau=b9p5?JM)TUT<+U|&cYNX%u}Yp%1bT^~ zYdU;=&`R@n89J}BwT1P!6>Xh%*-1~)oCKeUs9tK8w^TM!ehlpGV^k@sPvwKv#8z1b_xw) zq7I(Q`=V}|8plszaY5^At8nGX@f=Z522FES`;(SEjg7iaO~}$X{Bf7sTPEeL(j0r} zgeW0Xv=Lg{$R!kOb$P|ml3xeSWl1ESf~kv19z!kL-UjM6q@Lm8OX(Zo)|22ixQam| zymh2lF;aPi_3SA&G=U@#V8uY18bI5w)FMb3f_&-4;g+sBLL`7e?kjDh%lx>1D0yc! zyCpX+rUuF)z5bF;k}gtYMP5}oB$*{9fLf$^iitGxMzBcfRmqY|ETz;I%YMO00)62h zeR17I6(o+or?`_i9@|HH^Fy#@otT?(=RIi>kAoWQ%EWAZsz_4sKsr>4#}gyH02Kg8 z&>X^k6_siJsv%SGv$yDk5r%4d_xr2dbXEQ`JgZ!P-)7F9mAXrNI7HJJ$v?zePyUPTQ`I0zKH3|E4vj^v`wex$hV8MER_VR z8yv~?iqlc*opR=!YR04F>FVg(Y$n#!W*skdtFdouYiP8VgM^mA<@7Z=-9@fcp3dXp zGN|dAZa)etEiO{tK~|1hTOLIzD&QTAkMHIS_oIDTb1QpxQ|tqLS2ZALaysLK{#V z&7^s4L)0!G<|IfPXc_R+9}0`Vs{O+l7lx94!eh=UdfLA%7)3253Q-9GB20=sZCCC% z##4Am!&YAug$C7h*jHduL8h*1zjkHEPpu`D6JXQ2Yb&blp1Z($mbSp>3%!q^N8`6&O~m{5D2n|K+)g;j zWi2A&UzFQ;1Fm$fj}h!wdzWdJ-Adc$K4u_R^F+CHrzuJBX6f2>YIh1pv9bI}u+#Y) zi(EdmVI{&>;S?yS1K*aqD~Va%B{{B6>JY0*WPH~V^v*)Ww|lIu*LJfG^CZZgn@-+U z&fisoYBanX3Q^j(NDIc9#Np0j?^LwaqhsDsCJ;S$fm-UbdBP_YJ=C63H=L&p^)@R{4M_dE7QjeT$U!Acf+yZRC(s&&NcPB2Mz2a8$r_j{ zBb@9zRX>Z9R;8BW#RWsi(rl7LC=`%SUrI!PC!1l`m?4b)p+Ry%Ou>O9O+&-e=)w=hgA(w|qkh$7LS6_* z!YV~$&;bbePz0>*vGLeeUBCK~E35b!+_YefD^>1VLdCpKDAoS}+%scuconmh+F3NS zd>t1~+o8N`Yf2!VraISxbyd`*c_eD)^2^+KD!#V>1rp+aXs%Z|_A+fU>O}S}qCnI5 zX32mp%*Xbt=ia(;`_(7%eT&c${{XUL^Xzop6r4vTyKh}QP+&NceZVWV>3CW=#x))h zEpk-;=*e*mV>v>8VPSx4FL};}6B`qf9{!=dBfqX+-h&P&jV%;Pu(wERkNZj|UX+bGv z7usnz5w4t(2OV^VjX2Fed!y{s{#zJIu2@O;l#mEgRC%UBf(2y8GToEYEv=&(Nl6m$ z7mWHF52i9!xepS?`3@KcV#tdS{3j{O!BA_2df0vju4Y%Vc|#xsqn5 zbp+|tiufUI7{=kZ~ZceYaD)|)tL=ZqA}t8Q%tt&?jUz)XEe3eu<#=r zZ*lZ=xOOi809_;XeQ8yLrqoI&q*sJopM+BYNhUhGRsz=K=AG@-x3>t+v+VsHjMkd>D6ouB?bl z!3+Vk)QZBO2kat%C1Cz>K77KnZ5C=ormx^JVBXulZphm}c}6jeso|q_b6&=@+f!IG)t<^XdS7D60Ui)-QnZjye)W@cQu=MU)5>KL zsbLuLG;6k4yQO4Ta^hHNwJA#@#7riBb*|~2pTAn1YEBqgGBqu3&0Dxer?KFVY9+Sk z8gpf*610HIK}qHtAa}35`fe^dbvQpMA1(C^>CWj(a0IZBI? zEu+EGa(p4Uv%(v@e2SHF+BwvoQ3r07PEuxUZQ#~+oYKvp4B(hp(Z!y^YQHRaBfVR0WxP%8@QUV(DK;;qt06z6xBGlP*o??+%thlkH^nP6_j!pZXoke0(dt~<))2f{{4|5+$abpj`Y(>tB z*1?u?c22zWe@9V5T;?hu9$*OosO$t7sku7y#7IJurza+LODv9G6@q78WkRl6zgia6 ztIjKtv@9LB5H?UMB*xTKjv=-ABN%siDfo%28?w#mOrzmT#Itg{mtJXmg()O*gCA$! zh#r-St41lomEGOaw1jsfP}7`H)0n$0L4kV3YO%Pye(kS(g6VL~DN(qX+N+&qwJ(EK z_1kDwa$e;ld-5j04SOlfyc-&K|cz}w0Nx-`puKz?7KxW<^DkBUsqQK(Z*ry+kyj=O4DU*Q;_yeWbRt&10_B<81U) zTCuYt4GgsycSQ5`+*3lAf*xO5kyum!L!{I|me@0Iq~>-_A2&L(S8+QHNp zBi)X*u+!*8SB4P^n#Ju-B_oRJJKL;=X729w^}6$p5~ZxkHS|`U6&pye*r`-?IhnF) zeXIc|Zf&c_`o|Ew;KQB^nA%R&$oQ5>uh_WJ%8g5p^6}Cq=UFzt>KQiMqgpvWl5oEh zrIBrIm%h7X-6q|z1B3|MsI2O;?Y<9Mu~C#Glcij0Ek1@89Ld|1#_0-~tT{&?UQN8^ z7LlMM8)=ffa@!cnQ}m_trD0o-SgtEqsVz$5vk7=QT{;x4X?G-uvN*-y?v1tgE1;mM zMq)>Ot5;^K*Jw7pBn?m7s z`Dd2i>QpJzaBsoGxb>~AGuoEi;&H!CLkumy5nB=rMDm!Lg(>|?Lwen$cCFsVR}8ZF zoDU1Jwi%b)UFEIvUsE3MAsq7_dkV~z#Cw~WL^XR!DSck&R?q9K7PH9WFnEV<1FpW) zjTY2|skJ1Cl{t4N@Hpz0(wb0Ze-OQyu6UWRj$>9^B--0q2H54k0PwxB#O{FBo6$hUP2mePe>AT&r27DptNeCjn}I`ucmc6(^I zwB-KJUd#IXhxyCfolS3wbvKQKCFZV4T0ofsQ?!#mD$10jvuO&Os#M9>@thdc3_Yse zc(mg;_C6bFZst`9O1{x4>%VQQ3gSu>)<&wvjPlPK*y;SHF{U(zPaYF*V|t+LsU<5Z z3n!@Gi`q+HB2rPAX_bdkBpm^i{cg+ z7lUTgH+6Y>(@IMs-PbwLmXd!|jmZE4dR4QyjFDWmn|Q@xm>g5pc%4YAMB(pll*>u} ziEafUJvIq}1HEf1;!h~j>zb82nn^{P2mpuxRc++t)>tJmFgjFsa!qpiGHfiKzr13_ zh%VeZmXHbkB@hSVXi9l$crBq$RqFQP?(lYndn{^JQh{}-Y+G?j1f(FIS^3tcwx@4O zuWxtkcT{=~`cP9|>m;vxD`%}r6MLvFoADFOl3F{DF}+t;TDPVBxjZu3UuXA~Q=8-i z?7w&c3)ME@{{Zlh@v5oyHI*5xJmAS+XIJx*_$jWvj&CzJ?k$~Q&|1Mz0iLivHS0Pb z+7+F|A!|>_?z$G@%9E)h%{j~~*gVDVBH+uGZ>^OOBbcPb*QrLNYEz8T@^MvdT`@m7yYMWb`zr+6{E)MU#Mg>q%m zYG_jM2W_fFV~@Uo2pOobCbSarJya`UW6emI_5T0^JIc8$8 zbd%e?Y`De^Q!<;#-Zp@QKD4BC0bMIuTTG=8*6c~jpdltT($GPx(ROKU~+)b}|0|7C*tVqxekxR-#rq+%e$=Z!;Cm>U}LwQJ-;@&Wp}W z)O9X7Ds3nR;UP*r2K1ju(xDepCS9!=D$#O1*=>Dj zyBjC%^(C4D?a|Di6oQi-A}f!tr`MHd6u3vI+T2p51eup*b7l0ljn1jF+<`ij_Cbhf2)a~idxVqNPNbnRtM4Ed+U4PvLbgP(T6 zZMwm}aJJwQ6ep;!c(UmGRcjelT%H4|P1n1Vi{RBxtGxY0$?ipFN29GHCXIWB=2+nK z?_b`A9|`3nq*pW4x&^+UOMFOFPM-%+;dd)~^ANBAA@K&dt2sUF%G2eF@#OYyHy?MX zbwe1i`>8{vGE>+^W+j}n)#+izDCydtgq9Zg7azsE__<*m+ZpDLwT$Y@Tp6_KMwE_C zXM@h(Hdflg0#7gJ70O8!MQhqt-|8~Tc6BSsxE8q0Ii0pQE^XQK$r~-4G9zOLK{a zoRK16q=DX(ZSXv?(i9I#qY@fYeptutPp4R?hE08ZG2#UG?@@2ynCOnAR56j3T6JNp z{yFjb7i^!oX{#wYs89H2!%UC)bl>iepm=;O#qu3p)q-6`_(~aZO6X(uSDxBf%Du$n zQFFT|({a3~3rJ7?>9T4~5dEvz?7hN;%XVlDsi}ZWK&v%970|D~eDFt3)hS#>(vJr_ z%;~$OUtC>Yy4{;gauNZNzVIuRqtcf*)0Id(ESt)j?X9X%e6)yg*t;uCwY%!e1w!^n zN%y2gel^&1mrGaEH3(I!E;48}y>{O2)y5~!jx5`FJVw+l1ds*uk?FPB?GsX*Q$F+PulGIErtSlFLR-wvm6Uw@Sv0sy-JB zDQCuCh_BtWxNkfjuhL%4+)7>@v5{{Xi+Qq8S-HFCQ4l@gSqn^W9cN>=N!Zu_0Eo_v z(wu10?^jsMl{#r8`CDIhROOY7@fNVxIm%e@`wZ%>P0F=S)gEz)&9>JZ{{U_?SoYi!$;Pxrkbpf_8)UM*DBpxl8{5_^Gp{aVY8fWT#7v zN_A8u_*u+j3W;ImEKTKM@tiJ#%l;hhr$REk)FTR<#Z@B=4n2D1p{?)M`KR4P&puO7_Zhn#MNHH8bZq%BPHRjBd_fjB}#aKjFVr zP7h4Jr&G@Er0UWhSzkO=UFK9vWl{iQcX;NZlz2Bdu)o#hZu{_BqB( zAFLmr*ERGVgT)B{00zpR`e@I?>E&b)UU7V==pgT0*0gF z-|LBElC@QYoh538g(2mnq{ty#gH=nd{{ZW&_|e)x|qCUF4Mfi%eiR7W3ts?b@@kO;mHWrxPm&1gx8c=OA}=5 zlJCbS(j5VJqVV>D^5W^H@0OJFseNKQRz*y_;Pv|_O+q;~`<-{CTen)ivuV$E0tZ!k zRy^Y44aR=x&GKnh)>iqu)Z?uZ+d<_QWF5z?a2k?&oy(-32Nd2O)hsgDbVj3D z<}u)5?8~m>nBL<*?G^pnscP1%o%|Qaq4g=ft|mpdvi`fca3QPgVN$vdbx-W8A*s-+ z_S2SG8oe2PY@DXJId*>scc*hVSX=a@KWegt^7KBnnYm$ba&_(93XTuS4ltJT7OOi1 zzS;YfD#oR;s4rtC#mYAn?U^J%m=a;ZgR0~gh%- zJJORTnU3plHuJ1<)c#K@BH7YMy93s|ODCe?76249ksYIYGBUmK`NI`rD)$97GzF%c z(|O%roU+qeYZ&%JC6IJAZ*I^MwM3Fh*(m@LR7eR(B#;3$iGP1>rdv+#?rId^vfK9m z0L{M%E?dG$wq)7a*VHS<*48dllfp~?09+;Ix58Y$4^?8g2f?3b%oVP$_JqtcnasHB zrpps*R^_Y9Y^7*Q8s$pfR3rr{-d0D95V7`FuNS%NEq|?UWnM5#~8+%}~;@ZPlSWZulT(J+SMoYtZdbitp`1m?| zgjzn&3yEQmqOkq@DK9pU4Jk*2!)oxE@W@aAmr_7R$=xS!)1PCsE-R}2L0(m7DP^cO zljXO%ZEu$4jJ2_@d2bBB*1puMQl#i;v{g7IgygwgB(}vpvD?lQ-k%&UQ8OG|;)bWQ zv|aA6$QM!%FVOjIiiwHl@IraI2$_xJsjsGV53+uV(rG!;(`n0oGu%$EjQH-k?eosu zXN>0y9tW>|q;+PaUND{YNbSxxHBZhw_SAQH<92b*F_)e1N$?wqTt`{XUn%6K;G{0@ z{lzWCKmZa+QJS;4?mhh5a!bs`%9>w;LSO;&l?Ymb3K?vn3{A*h-u5);V48_xH8I+7H zce8&I^l7_)Olkz*FtZC5R|;uM0(nUQ?-G9VTpwD?PuHoz-&?|?j&|>iWsKuE%6QHe zapw!*vfhrhqDFGj?y6GVjorD*8OCv)t!Ei{&y2s4jO$Hxr>=gky}o%XwO_u)(@9#6 z@}F<6~R2nARehIJz_dn z7jyP=sp!`pv!`xaX?T;wo-p?1EwfT<#FS&cpP&UNzO6-f~eki+-X{TIFRZ$?YQ+gJqX497`=AscJA1I+H|puX1r)<%pYeTpZ#} z!)SS(D|VzUAxR{la|7RXRZ_U87mdc|mWy*n{bOQ$d2{>_trA$(9;Nlu(6lu3((e|n~_Y0L1j zPp9u_$1{cv7WT&L9eC}H<0@(P6j0(7)hZQ{8OiuGb!bYIu_IL03jEtZkVMz7^k3C& zz^N`u%`?7D9zbtdePRC7lFHr=v7#L zqjaK`r0lBpOHPNJ=&7^7bqROwXE^+ox>s1+ep6y$m_JNr4F3RJRPOpVt+l-7pM=M! zFY;;s04x6hiS&~Nj&mr$FW9{3eWWFa5?})r^VF=WR=b>M?IY>?TClgYgtNvCmr&^I z=0-m1{$94WOgP(n6Sl&QM@Xwqzj9p10cWUFtrrS^CX1HAWgf^pyH?Geup^hmS17JN zS|+7^Qhl7Io(=qUD_dn4)W&c=8x4@N$+2+eQrM*{5(9+Du8XGnb5gduPQGx>R;{b) z_3hrkg3#Z2A5(ZM0md4cP-eIcjxW356pWc;J%-C~a0xj6is{k>YE>Izs1 zJi-Y+wXmhps@+Oi&jtmwWUH+EGusxNPT`gIBOLSkoh?2sP?tvCLPXbvYoBF$h28w? zQd~Ea=q(qmZLKY1O0TlO{{YHQ3`@=ZCszfbwGE_fCwf+YWf%18M!iSi&aKxrlcg$j zi$r@v=uAFl<0p;OK_$e5ByF%AE7d6U<;*E4!FW9GzN-qA9Hs6SL)w!`(Q*C*`Wx_;O6gY zDwW$tmbS*g7_6+A$~gzYN{=s1x2ojJ6*NTkusa`>RM{_ci^TDqWgaMIaz`{ji~h|b64kYbuOjJy^zV|9WLBlI!7|q5C8*YqyPX& z03-ka00Ca%VPkEkTf)-P3KZb5lJ@@q&A%>c=he&#-Uz!S2A*(o?CzV;V%g; z65()T*iX`$^ich^ztgt&;-YHqwa0&k_qo#xmFcwS*XPG zDO9Hm*C`&!vAWbc-wpMevTfir;!G#QAucH+%=YPAU0QLrsk3fmb(Cf5DQ|}nCAGHT z+ZGC9?=O+LT##PzR%iX8x6Z1RuH!CNKj;Zk$JET7F@m|qwB~Du`o+upbjp=wcIPqW zpV438y=Zmn^V{`6p{F18WOBYTYRnd@C{wtRYn!%NZRL-2s1B)6@A0lHF;m|Ja+=l6 zwa50{exsBrJI8N2y{2~jk3qiAJX_zSb1FIDK*^m4_n^!Hm?iHGJT0Os>2ymhIztmE%8mb zJghz&+bJh~#mzfv!r0XKw6*kXfaP^f5z41XDoVkf`O`fFd$LTbv_E5-^?KE%qTaXM zqs&yZl@!!mUmR?f78}pigp!Hrzi&MyX>D4ERB38Gi=HOojjp3kahhse_hXjaV~oMc zw<+`ItMIRawO_&E5OM9`+_cdD0467X_2V5_oG%P%xR!u{&{rOBlOKAsUpcDIIYmBWOTBTVk8QO2D#>O#Dt_+M_mU*X^ZY`0?$YxZJ<6Hipr>oMe zoowLK>yJ;ByY1ld7Zux%A!k#|1YHtG$XBjgHzb_ApDgQ`jpa?gGIGsg07GZI^si&+ zrzJtAjcq1WX|owLb96Pa>gYTYVoc?mHI&D~U_o<~a%aYtm$u8795{*?(#*lzB4r;`}V;InL?3Xpi^B zV(Q8II<0%B{{Xg|cMW_VX^j=(W_X!FXwwo(@1pS8aA(b7^`k1h64{tgRQ`mPzvP=h0R6|-w5wkwk$DNr{e z2HVvViuf`kC-O*=qIV?x>NtsJ<{D5`PUq)U%LLPGl_=#*9n4ipBHXdi($-=ick`s# zG>H_#Oe7{xpIWWRvN0H289wh?j^gBqowoyXxan2NlGu4603^xYyipy`xbBkzJgV4{ zD;+QtlDT@yy7qvnE(lH)(y zi;R=!jvJcyamN{v<1jl{y{{*V8JO@*<5Bv;wz^u1yI3)AH+EZRcfhGgvA0@!gn}#F zEgtGA9#4I?HJdxn3iy9P=dz4lrWLRo0l>1Vb z(sq{prgR1&rQ_`Md3PS#$_2;Kz0y0GismPw+*DiYROH|N=SrK~2;~}sm6MO{XsB-3!T7l>2MCCCXu0&9C63apKTw4)WvCwJMuNLwh@H-x^qeTxith8j{-Io710qzNJqx=j2>op`_4-G$z> z)EB)&7;U8YFL(7$YI{?{PikLRhPOrI509h%+G^Nny*H+GwCZlFPh<99O)74l=Nz{k z?q5%o_RVK8=b!68X8spxEOYtX&VMQyLFPZ7LVN!JX1=bku1?01f%EpAr`uf137R#P z*8uTIEhjsEw0SD^zwXx$s#aQz`-a+GGXo)7m)ZFdIXj|!jzI(WR+e_IOMxz#f-{g7=LSg;7ctMJ4*_M_TmJ*RA z`RVelO)Vl6s&^Va30=>&sbsm#{{VzXgqK!jq@^m{N%2UJ!m>3DJ~uH*BO1=E?WHU- zuL13S!@ecw?KHj}2p2bw1SLVmNUJQgI6{-mNopFEO{dg(1z*skyvcGZ0`DMhY zPQ+GiD_Ra}o(*j4RH;p-&zsz4)pr(rO3quQ0F>NGB!5&_q1be78BtYVx#c>%Kgpl+ za~zgd<0Rm5)3=p(8g82#3Rp(I5W$Mut}@_TYaou|vTp5RcMX#8PDr}7)mN6yhSYie zNUmDvq%A8yq^Gorj$oWJdd@J4PSU-QU}VP^ktvGc7%0>>FAO7RKKFF zJ_EL6-s)TXv;=c<0p(j=Kc}rMvhm6$sTE;mYAR9QcbeYQjw8o{)Uan_)*HxLxiAv) z6i<{WRz9H~{j}*v;iD$e?5zpElzkq@=5)401&p|FR#`TqYJ|9z6S0p<__wJ(&ow)Z zQl&~c<+gn@q4iyrt)wZ`$AdfTtvc%1X75^A7LcF}b8I~;9?R_WS@kfTY_yEqo~_gS zPB6wx>uxJ)JQjUd_L_qp;u6?GLV++V*=)2s%X(e7#PbWiPMyVfJeHXsXe=H|+*zkl zsc96d(zJq? z!N+PdRV%iRV%ubbMQnE%D3!D(VN<0&v2%>Ah6uUZ5DaAOjFQ>KP`Zft1R*WF(M%DlSCSKyuPRCPhKASUhT-h_4z) zW)k<3YDfylKH2!ysI3e-)R2z3?ECEloZy~tvhrWZX^exQ5(b(H`^Zo&w4B`R$J zAzVI@*V>OwSB{a@wAyJ$6JJ!Y-F&(F;6(J%_-D{H1s7ZSBB~dZO%}%^Kz*2 zlLije?R_n;>AK|AZ91}?SDbLyEiA?2QO+JRmVB-cDc7`X{TVt}^qd> z&Kt*v$Cv%N)N^P?W z*rqm$uU6CTwHkQJG_|1T$+_vBb!&^u+1}jRtcI2f{uRa2>4;FNx-ub3lTukdd8hcp zfz=qhTZ=tEeCutrhWuip+iHSGx>X#|K?Wu(L)3kB)BPPMM^U<6)SKz@fUnvPT) zlUsX^3FkS&ZF+xCeVuDvTL{+E?cZs%x5@2?EvD0a$wjBTVv|_LGSYM!?~1y27VCCd zTgI{Jba;*1psB}JnF3YmAjd#p^&-4p>rv{Tw%YQs(_z@tBT*?$@Y+i&f7SKLV{)et zrZSW_%ZSuo&taoQaMoitw9wdp@6{FFRdH{Zfo)v2!YK64%;0g;@J! zTHDyXLIlZDxs-d8w_5rirutsPr7R()>9~v|%Y1H>pP5Pf$^QV+B$7%gCG+P~Yxf;h zs83SV=enf0OT=Rp;xS&)S@GqzN>wG}tKM3{S5&RxY5aZVG4pk?_aX*L^pLeGB z{LK_;mp1lXoOL>L+1M}t05d{>>|J=)8_?-R<9aue>O98?HQ+s*5+m{rvU^IOKfa^) z1t{~q0_qIM26hii`#oiHjANS67Qnu+o@EEXPt2;Z?sRH&sk(}5C6u-3)U2R-F`r~U z1ggc0mNcd%XnmmM{Uu)Pjlq@eUPGyCw^r9KoIE4Z>@BVCX(`TFGcA3Q_#D1g9nyG2 zv`m?NpZ@?lR$ArVX|3hgHdb(hsTp!z=-+4F2IxIf)^8i7@XWtzu4bHV@|6Se=C0O- z@^Jdu$XBV}o-@KbhNR+dJ0Xi+HMeXUZAc+YRmxSgR&A9jTunM_D=4kpQiJpCe68b} z+jEMU*BNmxAiN<-GL!C(hP}g0gN39b{NVF_PD*z&lKC_<(zXV;bc3;=VMNmKA#K=D zG(VQqBEW)oiKN&M$?qCKf=VQSC?t%80FxtcDote*jG8Q2%HCk&><^mNHB-xiS9$v~Ewu)qfflygm^%aX*m8Qy@&7g~9We75r*_n0ywh()k@3 z3-dqEAO8TfSMjL!;=PMIj9?V9RH9T#-9*VWXA1~3pCqV3=#js3RJK_dnN6^f*phz= zsj~EphS*SzqH+Okx#j$8Sr4W78#P3|SZlkxM!#0$xT%)+g#d|a4a@@(b)cEiMxkw;_ zPmrotRMCFK)uJ|LJ&Sc~$srlbMSwdde|<&uB{$(0#>yaGdlqV>0peyF9#GvU)KLXu zkCI6~{7%EpxO0BQ;-*r1RM&z9YW~sq)X@YWfAKWXm`UCyhQwZJO<}4uK3%N#kpQ_QWB}$}Ql24SMm?+6&QBi-H@0W+=bLe)zYIUPY z(ADkZR+~yPYlh?ES&PhM+Wfyne6J6WTxs4G>D_gMw9VplEweU?2g689cBD^Y5TFlF zSgk*&`$*8{;cay)s!3({6w=0cUG7u)+OYWLGyidf z?k<`B?Lqyg^}Ao_{{Z3C{{ZSLe`VihzJB)q0QVF>`Ud=#;bt;T<;pKSU$ZWkIU}$1 zKt#`fExXhzb?0AdU+89@-#Cg{&;J0apBVP}=h$ndKFPEX_qTqde~<1;rrde|0B)8u zmH7PQ>G2{@t~hst4Y!HY&0ILh@fmbli4I93Tyx(97~go>Iz?+MF0j@d-l2Oq#(zws zz2V0RKcXK-8sV-o^Pf2{pIZH!bi`o|9>G?e7U)egEy|sUf;o?=nE(;C^^>J^mY-!f)vubeUq6RA%6onO8k2E+<$Q77 zMfTaR>hPVtf{nE~d&e@Vjks%j!dY)A#u1cou`U~Wi?%}H<-c%};?|gxd8W+bSl zVzX#!+J$&;-pehmJCeayozu=>a~D`^#@jC1tf56CW9wKoHSIx5ZuTnn{h8pvWwfyR zUuY!@L6oQnswJ=A&RbmgBTh0;d9x>o8nw2ANX)ttkpKwTRt&D?IkzrZwT7o(8)G33 zAnNV^0LyQUwi{F^vv}Yl=T|#jF{f8s_@NQU2FYb);T^F za_O?AK`B&7uXX!2+jU3#oU;bC?O3(R$lrPUr`L0E>fCk1%%v#FQS+~5j1(G*@N4BK zJjs#3nW+_zKn?`b7(hnxOOQi#F-;bRk+}1u#1{Vm8bE?VNF!-YGE=d_JweHENITl4^$!(th0EJZ|=)}osy@4G&)oi*b%Vn8V z`PEY484*Tu8J~42j`dbcc9~Z8@RA6F-l>xQnroSVu>S2PtJ>oOXJNck;|Nh5Bv_Jq`^KtSz-QBX2W6gHKv$3%w?g zto@K8e>|VtLrEByi!@pGABHyAr+7V#ZzGp-!7A|K#>^07rD?C)&(vtB;ZkPbo6?MG zEPg8x<LOV1C9*@a(JmwO2*x1 z&Z)W6Xi6;&*;7kvMv}&i&|EXq?_~1$w(<$_{1mCw1@lSwYM5Klpp;~cC|XjtO{861 zXnhH(aoFs=mYlV>4!8kI8vrN~(2Bmjg|z;vYuIX)D~f!hn`kZ=T3_)OFKjUU`0GoB zAt0hs1nxJjex0VqaeL8*tWvmqaCN;m!TlqNvb?@;6=30A%8-=Y0m_j*1oZe;;u>Wr zQ#KT=sm0|Q?ziD@4;sy5GOpU$+N`(``&R1(3mu71n5;*q(v3`{Rdr`iD+a}u(|C(K zW2(jJyan(>Uz_A@J|cu|x1CP*jw$ern9!z?&Ugi##oFsklMY}TVM}!LGFyU!JqMI| zQqro&vf~76t)&Wg4=Cn*cgfo3IE#FXJbD>hE*6wfj#9HbO>)-_)w*zsF|}u!nZc~& zxNEENcob?|tUHOYUsng{&vGf(v7NMc)G;aB)s#0c1|F8tneAbF^b8%6pLQijpijn~ zD;kxl_bHI0LRDq9K1@u`p2}b{j$!h)tGBvoT&h9uX$VUEjx%ef8@<*u;JPtH z=xF&*rB>SbE{aB5OceplBB^Z`#Uy68Yyc6w{uKu_y^9jhv6juEy3J8KiTfE)kL+2o zXbNUT)e@5UFN_m2ZR~`OVYgFMxvzrN1j~GFvQYa=07zO-<5*W|cAGLbDB$`5s`T3R zX9sZB?X6{LVTA;wPc(o(3h}*0glpY5@N{W+C?r?rI3=diFb&w-wo5Jq-6ViHfJ~CF zTE_ISa>%7mFu^7F3pBm%oXWb@qbPl4YGEy;OalN4Rc&D=uv;2yW(rJC46zpOV(lHU z{NonNapI)zRIP;6<7}WsP)PVHnC6jN6D9c>(2xnKA}p>~+BIq*yoep>6A3a8N(4xr zl)${wN+UmHM1M+?_|;XU;J28!uWbg;qnO?zD=EV}EilcKg~rQn1)vxly|%6^Q`9AM zEwJ`Dx!p=M+DAaZai;4Ng0ja9d+T=D)GwGM^c3mpt_?+^P`#-dN-Z0`?;UiWO_e=! zg>YQBk9>qEN}{J${upltZ>~~`i(Hi$9y4H{wSNhya0`Wsfzo*F=AW_+G>eqWE$;))D<#hM=|d;k3C8dPhu&B{5g2!!oYh(S_ZEy^EiiBZ2P6up-q)?{3+Abmuu=p zbgvRlO%=J$Ea>cpO4j6Qh}^a z_^ZS$PP9umHd<{Awy^hw3`_&^2v0N1z2Uuzy19)$-*!zN`(1z6`@Tu9|RJNzvNXDS5 z!ds$>-BFm-8n-^ZL3?EQbxM)>rFJvrSdGp#dyR4z9m><)By9OEChJ_TlTMLcjlyjJ zf;=@5^4ha6F6!MuMo6|bYHZmQajkoT%sY%gZxeX16gEw|&+HZKpJo+RDt})e{{V)T z;@Y!(Bc7*B>IFzn3nG8&u77sDqt{YV<)a(ZR`?A%S5lb&05@`n{-o#kX?pq}D4(aV z@Ho<1q?j6OEAbXi{{VKEuc7jX>Fd8@ROr1}pa|0We^2Hv{{VKEt+)L^?Cw4TPKVYi zASX&@N%XOI`?ViiZ~BI;?mh{J5B0fFACftr{{VvL_i8Uuw*6$)jepWio*e6CPREQ*Xt*fMP|tJ`U{`JqV+3p)C$7m^pm&44k8oEofDfU z(#e0qqxY4!>Mf3+ar#Ny;Xe`9J>3nPpZ-mC32OG=sI_U=AEe7?gS<^}LUb-@{{Yn$ zRZCa4OYs*+PPlLImI&aV6ZuCjgv?1BgKlb%zO4TMQI+>)b@@!TI3>kW08WIlTmm571Xn8%qmr260(Y8XG2L{{X8W#;SV7r|K_`pI_jyXMlWHabk2%KmpKlfi+aM zi$(d1<6&Rmvt!xYi=3fJ(RZL8$^ce8waZ8OjF{L~_$;lxojAIAf6V)kJjnv9dd;K! z#lDWR;{~m!vtJh6SOZGDC(S@sJhi(|)LRQF7VLX7@nKM($)yPHRx2J_<*&4ig=EVF zdp7Yh!G|v{uz?LSpAlrQ?18zgO8U(zwA>MNY~Q)*9Ua6La4%x9nSOSxo5!|-Vn;Yg z-Yd>8Yr+*|&5bE-`bqTn6R?WP=58;ZJ_%aYY6y}_wyaoO!NVluEYAiOV~H5%FYw97 zxy-`?E(a_HN#2w$VJ1z_4+h((wT1^!Y8!Fl(*J-JyDIq>07{u6Qr8tUqTRy%XSog z4vVoD>{wi2G$pIZY~XE_qt!kVWi>>sX?zm&v3|q?*M~n#3?~h2Rr*82Op3OhjV0j~ z%GN8`*%zaFS{LZQ2?jIn#8;v(^l_Fr9MJjiW z!lN4+ER5|V@Lp)Ey#=do&8r%A*g%j?vXTD)5UalJr2UG!5nN#2m&45%gq1G`XaL{( zG>H5u!%n3qh^|XzX9dm*wP84T%cZpG^el~uMYvF`)uTA9%fSxR5r?QTI$IfQ^rmoa zHqu0rt8jMsMP}IO*4Go;j!4dpG_!+RXE}$wmhd_ui`Au2rL7?;{gt$RF=<9$-e|>9 zhq5;9EoY`P=~FkFUfRy(vkGnkfj*m7lKVxaZ1YbI85Yn}c$(z8xxnbFH59ppX;3}x zR)LDtx^$lkCgz@(3ac_k9p)EEy=q;@<5@BGxmw(Q6&jRaxk$Q(kqFh>G*PvAhFXP| zGfOpg_>J60Ce7cIxwXG^&hl5#v zquW7dgUTeDhi+B%|?dE)` zyQ<$Tq88L=aEt6e3wd;QsEkf-mSV~*sc6^gDNO0Ni8W+^6yKzFOsDm4O@qL`tLQU zudMG^Xi${^n73ElB<)rzlE;!RDu+T9l+uPQoe*Z{)jbH2rm} z^LCgtTw3F88VXPfQF0V_>^*4S-?=;_jrUF7zmddSU0pS9g}B;P%F?-j+wi3+G!*$C zP-m<(?U1~_PyxpSO{cn)fA2L7@8q1Ll3Q%nD(OwO&Ff{yKFTD5OiV=^o(QaD$JMu& zRvLQl=EY$zr7+n(Wd8u;RZd)&sBSohUs-CaoPEWG%d8I>wFoL%Bt>Q0eN#kSb|!Sq z52tXsoe_(3C5>h06u=5mPrN&ItXsQvDw4@mKB$poxGAFVrA%8nYGeNZMy;pJ)&%Tg z{{RU!1ZsIdXU9@Pu{n^iHzCmn;42n-eEo;D7d$lKo>NR@ZZC6Q2}+U3*h;yH^{thq zCrUVER8P+!6W6U;ycaSj2<0Ys^s6F4mB)1-jaWo++|U6C0)P!9nhM!}qfBZGKsP18 zJ{#6O*ZNGuz2bvDoNyY^PT*QlBtuBuDjGihikn&Q9N`go~ajPoI3xc|BoCjECGEU^(9zCiSmmvGD0~6?C zsDfECWSd6c!aT-AWSea+TCDRzfJ2ERe^V8oPisab19`t>FnaZA{)_k$$UoRM5CT zXe0@(Jm}WjnLZ54ZVBVuk1>(9N==&#ho4x81MJOeQ)qZc|n!nTuUT!^udeEY23;H*KxPfcKJtB<)h3;}#Az zJRCb9yPU3l7`-indetRon3w!DC{LnHRkYl&DeaF8>>6V2+(T^RE^wmRN&;8om6abe zDHBPouOunH+Z$QxYpi9<7~Fn6hu^t?6zVyEow`V>V*@62a=aS-hLP2nES1KiKUS=i zl@`Uh*hg=Ar5Bfi5>l2KwrQO}y+w(-UBgIe#)(3L1P+~P)rL70DM==dRjJavdM+Qb zv%6UFJ?9Z|$^i5QRTS0-waJybFE6OGnvI97FzXf!EG24o@RFn7Y5Z#Hei;d74I{i{ zmQuSSQ6HQV0qAzxslk(mnLcPKSi6wg`AKYmW+JO-l(U12<}nt;hc5D~x=?LIrEYVC z{HCXZyp`H(6{jq+R_f=%Af>j}6$)CUp4}@l(c);75xDhgHl{miy z+B0fdlNTsdoA?>|kp@RY@~A|%OojCxQ$1?M;Hj1U&uXxUK*69Gs4KwB_6J_R- zd8Tu=uDrffC18?zRz1>kh7pNYS0^Qpl)Y*ia*-Ys>GCg%ohZ?gE{@>3FvfC9f7 zb)e>osWzV{J}hD0zjfQI%N4e@7(ZALMJUtYl&0K?wB^N)BRU;9D|FjPh`;6|@2r|p z!CidG9ibY#PA z=t)0~Z)j^6hRLk|03<3>mU4?tIc=mcEv?mR%UheJ59wXHN|ir-Yjqp>T`Waly4Doq zSx#uIeHAmY&4m9k2ZsQJxv(Y37JPT%h>K2)|ia&EXyWru3eCo!wBkGw|e z4LV>j(Xza-MrFREA<1qA2y)kb#0Za(>^0tNl8C(sw&#H_%p1vsavcyk}MI> z*ms4+&a$+2Xwq2VI;A+PjXR*n;@F}o!H0P6{>oh%x9^KwN# zoZ?o4yk*u-rN@GkzdL{fQk+|56qAZIo4l4etxz)9eQkxdYnYOrWGtEZ?L=bm(F&4# zk#N?k$G?zj=Ox4pLyfj%BzS53MM^MgI3+2!BC}lQuvuKCrRFDF;#gBE1gNYii1_VF znrVer*`JWscJE`>!QxgdDa7)qr7ihWOS{@G0PV9HlJGDQ6Zwv~lT{h6yQ{b$)q?FB)b;?cVz5C`{3z|zLvw7VUa#RTz1^~`b!Ih&m{2NG zT2DHo*R@S4;7csO$?;o)Su2(viqgqMD3vWa50XXlt06(m(62c#s=TCou@Bop)PR*)Zl)Bx$ASPUMM zK?x#O)=)x{NFdCLIFi6Mm4gkDRO@vn)%{{ZKW z{{H~i6?`VJUBF|F+)&v+mN&#lbp!jUDJ+svMCjwM6q^7iSl!spM$22 z=x~BaiCkCW0+sJ-%!voFbkW>Ql1Xqc9rYP+paeiY^(Yy901U>DRivjrASzp57^;Olq1gF}kZ$Ts8U3{oy@H zE-IU;B3-mHbxxvj{!yE}m4)VZ@N`r71({{UEMavH%Gob$P4Ge|B07{8)))jj5iZdwFPX|fG{VA((pQO4^Ln|xT6S` z*1_O8Qu~5@lxq{eDKjf>LT9KqF{;ul1(riE2RJsS6X=({L$Wwh;XWT0mAz3X{G@M zb>C`06rG7Q06}|gKo2Lepa%;+lmKDPy2SuET+jg*V{yOAfDJAJ1pqm8L5cuLbKO34 z0K7rcXaT~+&;fXdv7iGEC=HLofFy0D87kP&0RR%9NRc~=0G%ov$$$X#rS44zM=6oF zdSr$}6B9+cS^VMg(3FIabkhaFg1mBH zeQNPa)OvXe2jzg~DNU#ZK9>ijMCc``UnL(8UzqM zr~$#+fE+8%fC`#m5Ian5QW!w`Z9s>h2Loe34h%&Dz+n3AKnOtEfe$-LJJ17ycAx_0 zJiNbrPy@kDpMwa3zjw_4|$*h<&)_^8J1SceM6K89m$FS$h#g{?~}0DG`$Hdvkv$F7=Eh+2o=y)59K zazs+gijIG}mU0+oRkMuS5e^@S>r3h+qRYl_>>O?svJXwiT94FNk(-Zm7F-KbpaZ#$ z>Z$H%vKWcAv7N)P$N|y_9fwN8l_@hSHDZfgMxw+mU@hVV_Z@2yXP z)S}+)xf^n*?^SkMYd?bEkOh>I&ycW#Ex}INJv3Mz$gARLlnz14Y z4<>+UeN6fZ1sAZE-Ot52sdRg@VY?~AMsT5_BRAS5I`ygQTE-lwF zAlqD_B%w)-$Q=l$yd`au$NWLkm%2Mr-e9sQD7mzBwy;wZ9TYwyvT4gGz^e}1!ZmZs zoxz^-p@MTk_xb%(_*-pzLWZKsiV5X(xT?m z*j+9o!)D{dSsQq3RL`76N4(iTMv^?^$BqW)I76OAhEthsyYDvQlgdc-tjbc#Fe}p7 z&RK92ZU~913JFVa*D**DKn&2G#U=}q%FPO2C9@xG)pCRJs5gXL80DU>;Fq#WxPgvh z^<;+D2fjq9XSoBgtU1-ev8QgIle=TT!RLrlz_@*0AL|5wX)3LjJ9w^HurdA)Z7k}6 zO5NlmVtIdsKkg7}f-Ein0KvDU3HR>Sk=&Jlep^(rGQQ;m%%lDeT^QH_tCtVOfAXca zp=Wl~bbo`dNGSWxxCrQcPQQgcv-b||sx$3>!SAFRfV+qhyefD5sW^kLZ2tfYIp-L? zl5RLzh&rQATuXM!3QB|c=ps5VJKv-2g-J)_Q`iONPT(b{%CwQBHIVbtT` zuiSCodQ&7M^`HlnK9m4bXaNJfngCO@P$m@wM@;@S47tWhDLd?HC5yqo>D2`kgE2eO zEP>H+hm{FP1Q^^JMofGg1(H&*C(ED|B1pc(q$SBGYK!tn-SJK#z?6Xlru30=HajE~ ztOA{qii zY$zL9F07J-09FAL=TKr%Hw_||Udr1c2po!73XZiDxg#o$5oeM=!kdI<(&GzvZiJ?O z*WFq4yc*k?In#?ibld^D9_C5#&b*y zTOd-Bu4PHw#bZ^tY|6K?R97eGF;GDOZCU8&+)PWT+kcf>ycL+0IQT2~6*5BUy#N7gm?=*{3X2*|MFjKiSBGg~lDM8R6iKxFMjoT0cQlEQcNf#q)u@JOI^Fu60ec)RJ z+`O)0ByR#^YK29@Molhc&z!#7_ zTRgyXx$>j~6*}{UDM*>viU*t)Hpo&yN{Hw3pp;%qR@qbpjmYW+LmZR$HhmTrGnQ@c zR9qVm-%`PkU8fd#uly>BDYn6xfTAQu-77MmgI`gu)K8kuAcUQy)be0p7Fq-m%R71W zqalMk7OP}9OUWfs01+aQB)BZ>Kk}WjllFX6#QbU!Wwe(k*bihU66S%hNJ;*PLaQ6x z+SOm$JtuE)5K__Td)5BfH1kwcXKD_u)t3HirOQTW+mRk%e7j(5N0J#J_`NBdQ^e2d4B3d zkX^)30`s5;_)r3%2j6kG-#`wZv^SGKbpvk&?m9iy4>+huX7hpArCa$@UJI%4Z@9!Q zNk|FoCYmxZZCKQV0Rm|9OxP_6Q-j^uR3DMx+p#53kPMG15hQL{#HC?9d4(x?E=PUf zT2_Z&Q7Qw?KMI9MmSxi6pEkX;Tn=&HP^l`B;vf=w^fi$W28#2Vtn>1OtIDk~@((DP zn4mIF!S}*O-jtZvgVNs2GMt)r0CNt#Dv6sLL)|#SfYKM}BB^H7vr3Zua)?kh9|I=k zP=u(+6az+8veMW*#EGD38MxSD`6uUfN*Y7u{->0E}w&4QD%}pY@O11fs!POk%lWog%v`2Py{3?x1}=^ zy#QR})=k~92Y(Sed2djWZ67DsKVyuD{Drh(B1&5We$|Qjjl8+0dS=k6YYsdiAnjM0 z+R=C|QsNc%R1H|3Og5VG6)X#ZQGtCzpfM&Yc*y*4Q|ku&O)r#3ovWYl(q?9!*L3i= z3~(2j9PU=$($u=N+^b-j<=oahxn}ARQG1!`9UsDsqlLHbl!h9K=H-L`06J2JQIAsT zLQLqb=@V?)S`G&QA86J)rqM#aKQ|L3iRe75F&f91z zAs;c;n1UXI<3I~;-Dm+%XrKih{{UqGE%u-SNrOO{Ymc}H0!aY+)LAIAb<^1!bSQYM zjl^$JUJGL^9U~Qzu~T72;UjHkB>?T?lwzn>lBF(qvOp`XqHW* z3zM))2Q|WE`p}6*o0cOljY%KQP$$h*8F?>@M`zG{L(|$v33GdYc-S1IfKR0+vdg19 zA2Yq8wRNVk;zmzDy_21x>_nX$Az$AQ$?r>xs5yKN_wd#YFLs!fWSc*b`W7680vPhhH8 zEKHru#yuYTuUS5v!i)wozbxgPf zB|wda=CbMdHJ3j{G>-+QR1l>SLX%Q342vWb%0VOIC;~fzl&nIxngN+s4wmj&a(4;_ zqaxZz(_dr0A!BVc^|htN;u2s23EXX1(vBIpr-?xInbz2slMLkB2|w1RV%N1#!GHN#r(%A!WBux$;{(x2z5)EN)4hJQWBu_%cpI{*kS=w8 z2`$4pMhet6_lDI6BHDH{&miLUCNXW1ahPFbpLCUhQiO$C)v2PJi8}93V04~A*K%wr z#~4x&gsc)t5m21)U1@IPHqSl#Eo0Sts&DVq&|6n7t$UIP6V!RtDp_V_)SWt6J#vI4 zw1gob05$`)Wu?a^f=*N9awdskhEL3S*hN(zCDIu~nFO7|8&!pG$z0+J6$Ye5ya7!j zyo#hSy93xzERE36Jd1L6pfWh}pkw@c&;s000j0$!p`Z+wubyx0EQ$#xW;3XAO&(Ej zu387U%4b&Pn*@uM4Y%CTMO9{6b>3|-6LhcljT{y#tj%MIdX1tvZr3BXF{1(9W_w&; z)oiF1uNSv&ZnR*Us>w1OV%AwpMOizNbqG-9Bq+>KDOJg)zV|xH)UIVKa--DKOri4f zK%x{p=??;#8|}PM83`r~k+*7Md>43KNq>fUFWI16`C-ScUuf8EyQM%M ztx?)uu32Kwv~I0vf?ibr0BVh-)zOwcrgd2ZoyDEHb44wHu9-T0rgd6C{OW)med>D& zdZQs8)LNYbl`C+MMR%iUdb2*u+QU>Zq50Qj4#tNZhpWMGJ+k#`EtcC3+yyBx30w+F zibS36QN*>@zt8KenzEUj#Vu1Q6Cpnep45ywm0Z~cqENebTvp;KF~rMcCJIE!?@=6x zF4{@}BXu2#si%?|0U&??B=_63J-G!ea&$cx#SG4uWi8rWx`iO@LX9jLRPGu&4X?Du zx=I35eEFS$=QSOr-lduB`%3W$m`+9L^XD{eCF&WSZ|xPtN7c%5k0gI=(s3HNW^;UX z;yTP6v%`MMs^1<-s?C;`++yM*s5W?W&S?r zQtBn4yw+vs8lQM6M98Y8S1g*z=nf5Jt@O4^)!TE(gpiUw4_T#dcxiI zu9!u`3kz+)6qO{%AlAk$O=RZUag&22r-nxd<~?6z&r{l}kCP%qC_J#4+N>&mM|qI& zBt+B69Av>;N;Phu&oi7XO@DME&sC5B(wDMrq!F4bc@(DtekPXA3l&sv*lk^JY?P@FCP!{+ zTX@N0p5LhN+$7_sHI`9?&D|uh3^wQ^^L~fSROwf7crb3QRZp%bd$Gt_Wf@J*I_;a5 zmLw^qg#-6id@81C=SidUE_X2yBeg+!Es+zWxa(6zPsq)>Qed5`SP?HXPDG97j4%M& zvZ&qxJprebA-;%+3FaSl901=!2lRwdlmhw?j1 zXRh)(({)&tCQ1C8W}tsDgXlWcd#rty7xHJDG0R{`_;jgv1=(bY;ih>oK7@TXqqrS` zoZ-fGXZ--c?-d^NCD>yQ9Olvg0H`Q!D{4znOn&}ZdF z@azx#oMr*$78CFkcSEqoJUYzDG?mc39(wxz11pl7RShqqqu#Bu0SFr6nfF{KXx?_L?$S(RzuH6ZAs^prg1oO`{>b zF{ySU&0zc}-c3P*?vm81Nl(!fL~loN5pG~TCVLRe5gvX=5nnPSc>RHYn-+@Fmb$!rPTJ*jRAQW#K!yivS+2~nqYBTGt< z(FG@JH;-v*)vmBg07Gg9JnAk;HkS4dYbF?t!lTZSY!Q~q_4U9dw^ThjsW4_!KgtVg z9Pg;dVy&tTWR~V!+hz6TvI1IrkoqXqZk9ev}0Znct)WQdl6Ozj=&XsP)kw*r0GG!jMSt;L{B%3yb=lH8)=&g#lXzKJpMr<6-2)vLJj2JL`qp%x6i zW3(-@JHZt$2C!$et2rNHjtM4=)>mLo{Dz=duw@Uchz1+`>4pOzKnJ69Kwxrl#XO`p z_)-iEp^pdbqwu2vfrzjIIT83$z`+9@KV=_%7y)wQ$LP2CQIr6WtHJ1xN-}^%W60eI z{3=4gqaU&4YYo9l*hbrsUD4+RQ~{Htw#)7&ler$YDmF;2-W~m9+hJ9Q2da|o%f!!z(5J< zQvsHdw%w=!IFaQ*06>$lpa&@u3{V502%rLix5j`EkvxZP^;-iZ0G@z!6pJI^x5uF> zD3RWT4B721+vP}u5IfLHCAF=iJgG2deCREYg4W8-l{>#S-8Y~hTC;4_jfvQIrzB05 zO-TQry=XX8ziGn=<>m~4LfK#YdiZBsL`+jzu!S5Cs=F&6Zg%Z5ca|dU?=A`6O>2Y^83K_taSMWG5MD7Cpje%+!T|#xl>F z`Y!%-2+I1h$fyql3G$$lAL{#0^&)}bX7RRaFj}a;A%NPjwGI@9giwIX80$1{mOy*@ UGDylO;`l93JAnn8IsV@S0QBqBzyJUM literal 0 HcmV?d00001 diff --git a/doc/w406.png b/doc/w406.png new file mode 100644 index 0000000000000000000000000000000000000000..24a64ffd85d45bdfb73605cb86bdaba060ce5108 GIT binary patch literal 434 zcmeAS@N?(olHy`uVBq!ia0vp^3P3Eu$P6SG&dn_cQY`6?zK#qG8~eHcB(ehe3dtTp zz6=aiY77hwEes65fI+R3G@qx8$*e^HKhvc5SEr|9|eN!^Fs7 zchsoSqyOp>paWD(Tq8 Date: Mon, 26 Dec 2022 19:21:28 +0900 Subject: [PATCH 20/31] Remove unuse file --- src/gob_sprite.hpp | 80 ---------------------------------------------- 1 file changed, 80 deletions(-) delete mode 100644 src/gob_sprite.hpp diff --git a/src/gob_sprite.hpp b/src/gob_sprite.hpp deleted file mode 100644 index 0b9756f..0000000 --- a/src/gob_sprite.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - LGFX_Sprite extension - Support partial transfer (without affine transformation) - */ -#ifndef GOB_SPRITE_HPP -#define GOB_SPRITE_HPP - -#include - -namespace gob -{ - -class Sprite : public lgfx::LGFX_Sprite -{ - public: - Sprite(LovyanGFX* parent) : LGFX_Sprite(parent) {} - Sprite() : LGFX_Sprite() {} - - /*! - @brief partial transfer from LGFX_Sprite to LovyanGFX - @param dst Target - @param dx Destination x-coordinate - @param dy Destination y-coordinate - @param width Width to transfer - @param height Height to transfer - @param sx Source x-coordinate - @param sy Source y-coordinate - @param transp Transparent color or palette index - */ - template - void pushPartial(LovyanGFX* dst, - const int32_t dx, const int32_t dy, - const int32_t width, const int32_t height, - const int32_t sx, const int32_t sy, - const T& transp) - { - push_partial(dst, dx, dy, width, height, sx, sy, _write_conv.convert(transp) & _write_conv.colormask); - } - - /*! - @brief partial transfer from LGFX_Sprite to LovyanGFX without transparention - @param dst Target - @param dx Destination x-coordinate - @param dy Destination y-coordinate - @param width Width to transfer - @param height Height to transfer - @param sx Source x-coordinate - @param sy Source y-coordinate - */ - void pushPartial(LovyanGFX* dst, - const int32_t dx, const int32_t dy, - const int32_t width, const int32_t height, - const int32_t sx, const int32_t sy) - { - push_partial(dst, dx, dy, width, height, sx, sy); - } - - protected: - /* - @note Partial transfer is implemented by clipping destination and then shifting coordinate and pushing. - */ - void push_partial(LovyanGFX* dst, - const int32_t dx, const int32_t dy, - const int32_t width, const int32_t height, - const int32_t sx, const int32_t sy, - const uint32_t transp = ::lgfx::pixelcopy_t::NON_TRANSP) - { - std::int32_t cx,cy,cw,ch; - dst->getClipRect(&cx,&cy,&cw,&ch); - dst->setClipRect(dx, dy, width, height); - - ::lgfx::pixelcopy_t p(_img, dst->getColorDepth(), getColorDepth(), dst->hasPalette(), _palette, transp); - dst->pushImage(dx - sx, dy - sy, this->width(), this->height(), &p, _panel_sprite.getSpriteBuffer()->use_dma()); - - dst->setClipRect(cx, cy, cw, ch); - } -}; -// -} -#endif From 049b8753ff34536c52f354f9ebfbc546f3ef9079 Mon Sep 17 00:00:00 2001 From: GOB Date: Wed, 11 Jan 2023 00:23:38 +0900 Subject: [PATCH 21/31] Fixes FILE_PATTERNS --- doc/Doxyfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/Doxyfile b/doc/Doxyfile index 5e5fa88..58e68e5 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -900,8 +900,8 @@ INPUT_ENCODING = UTF-8 # comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, # *.vhdl, *.ucf, *.qsf and *.ice. -FILE_PATTERNS = wxbeacon2*.cpp \ - wxbeacon2*.hpp +FILE_PATTERNS = wxbeacon2.* \ + wxbeacon2_ble.* # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. From 819a7aa4f155270a01432af7026b06eb4d33d668 Mon Sep 17 00:00:00 2001 From: GOB Date: Wed, 11 Jan 2023 01:51:05 +0900 Subject: [PATCH 22/31] Change JSON parser from JSP2 to gob_json --- platformio.ini | 34 ++- src/jma/jma_forecast_handler.cpp | 384 ++++++++++++------------------- src/jma/jma_forecast_handler.hpp | 195 +++++----------- src/jma/jma_task.cpp | 5 +- 4 files changed, 228 insertions(+), 390 deletions(-) diff --git a/platformio.ini b/platformio.ini index 0764716..8aa62ac 100644 --- a/platformio.ini +++ b/platformio.ini @@ -14,9 +14,9 @@ board_build.f_cpu = 240000000L ; https://www.a-quest.com/download.html Download AquesTalk ESP32 and extract ./lib folder. lib_ldf_mode = deep -lib_deps = m5stack/M5Unified @ ^0.1.0 +lib_deps = https://github.com/M5Stack/M5Unified.git @ ^0.1.2 h2zero/NimBLE-Arduino @ ^1.4.0 - https://github.com/mrfaptastic/json-streaming-parser2.git @ ^2.1.0 + https://github.com/GOB52/gob_json.git @ ^0.0.3 https://github.com/GOB52/gob_datetime.git @ ^0.1.1 monitor_speed = 115200 @@ -32,7 +32,9 @@ build_flags = -Wall -Wextra -Wreturn-local-addr -Werror=format -Werror=return-lo -D M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC=300 -D M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC=60 -D M5S_WXBEACON2_DEBUG_INFO + -D GOB_JSON_LOG_LEVEL=5 +;Choose build type [release_env] build_type = release build_flags = ${env.build_flags} @@ -57,57 +59,51 @@ build_flags = ${env.build_flags} -DWB2_LOG_LEVEL=5 -DMYNEWT_VAL_BLE_HS_LOG_LVL=0 +; Choose board [core2_env] +board = m5stack-core2 build_flags = ${env.build_flags} -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue [m5s_env] -;board_build.partitions = no_ota.csv +board = m5stack-core-esp32 board_build.partitions = min_spiffs.csv ;----------------------------------------------------------------------- ; M5Stack Core2 +[env:core2_master] +extends=release_env, core2_env +build_flags = ${env.build_flags} + -D NDEBUG + [env:core2_release] extends=release_env, core2_env -board = m5stack-core2 [env:core2_log] extends=log_env, core2_env -board = m5stack-core2 [env:core2_debug] extends=debug_env, core2_env -board = m5stack-core2 -[env:core2_master] -extends=release_env, core2_env -board = m5stack-core2 +; M5Stack BASIC +[env:basic_master] +extends=release_env, m5s_env build_flags = ${env.build_flags} -D NDEBUG -; M5Stack BASIC [env:basic_release] extends=release_env, m5s_env -board = m5stack-core-esp32 [env:basic_map] extends=release_env, m5s_env -board = m5stack-core-esp32 build_flags = ${env.build_flags} -Wl,-Map,output.map [env:basic_log] extends=log_env, m5s_env -board = m5stack-core-esp32 [env:basic_debug] extends=debug_env, m5s_env -board = m5stack-core-esp32 -[env:basic_master] -extends=release_env, m5s_env -board = m5stack-core-esp32 -build_flags = ${env.build_flags} - -D NDEBUG diff --git a/src/jma/jma_forecast_handler.cpp b/src/jma/jma_forecast_handler.cpp index 94aa584..baa5e42 100644 --- a/src/jma/jma_forecast_handler.cpp +++ b/src/jma/jma_forecast_handler.cpp @@ -1,122 +1,90 @@ -#include +#include #include "jma_forecast_handler.hpp" #include "wb2/wxbeacon2_log.hpp" -namespace -{ -#ifndef NDEBUG -String fullpath(ElementPath& path) -{ - char buf[256] = ""; - path.toString(buf); - return String(buf); -} -#endif -// -} - -void JMAHandler::startObject(ElementPath path) -{ - // Delegate processing to object. - auto obj = currentObject(); - if(obj) +using goblib::json::ElementPath; +using goblib::json::ElementValue; +using goblib::json::ElementBase; +using goblib::json::Element; +using Delegater = goblib::json::DelegateHandler::Delegater; +using goblib::datetime::OffsetDateTime; + +// Custom helper for specific types. +template struct CustomElement : public Element +{ + CustomElement(const char*k, T* vp) : Element(k, vp) {} + virtual void store(const ElementValue& ev, const int index = -1) override { _store(ev, index); } + + // OffsetDateTime + template::value, std::nullptr_t>::type = nullptr> + void _store(const ElementValue& ev, const int) { *(this->value) = OffsetDateTime::parse(ev.getString()); } + // vector + template::value && std::is_same::value, std::nullptr_t>::type = nullptr> + void _store(const ElementValue& ev, const int) { this->value->emplace_back(ev.getString()); } + // vector + template::value && std::is_same::value, std::nullptr_t>::type = nullptr> + void _store(const ElementValue& ev, const int) { this->value->emplace_back(ev.getString()); } +}; + +// Handler +void JMAHandler::startObject(const ElementPath& path) +{ + // WB2_LOGV("%s:index:%d count:%d", path.toString().c_str(), path.getIndex(), path.getCount()); + Delegater* obj = nullptr; + // pushDelegater if top level object in top array. + if(path.getCount() == 1) { - auto nobj = obj->startObject(path); - if(!nobj) { WB2_LOGD("NullObj:%s", fullpath(path).c_str()); } - assert(nobj); - _objects.push(nobj); - return; - } - - Object* nobj = nullptr; - switch(path.getIndex()) - { - case 0: nobj = new Forecast(_forecast); break; - case 1: nobj = new WeeklyForecast(_weeklyForecast); break; - } - if(!nobj) { WB2_LOGD("NullObj:%s", fullpath(path).c_str()); nobj = new Object(); } - _objects.push(nobj); -} - -void JMAHandler::endObject(ElementPath path) -{ - // Delegate processing to object. - auto obj = currentObject(); - if(obj) - { - obj->endObject(path); - delete _objects.top(); - _objects.pop(); + switch(path.getIndex()) + { + case 0: obj = new Forecast(_forecast); break; + case 1: obj = new WeeklyForecast(_weeklyForecast); break; + } + if(obj) { pushDelegater(obj); return; } + WB2_LOGE("Missing object"); } -} - -void JMAHandler::startArray(ElementPath path) -{ - // Delegate processing to object. - auto obj = currentObject(); - if(obj) { obj->startArray(path); } -} - -void JMAHandler::endArray(ElementPath path) -{ - // Delegate processing to object. - auto obj = currentObject(); - if(obj) { obj->endArray(path); } -} - -void JMAHandler::value(ElementPath path, ElementValue value) -{ - // Delegate processing to object. - auto obj = currentObject(); - if(obj) { obj->value(path, value); } -} - -void JMAHandler::endDocument() -{ - // WB2_LOGD("End of Document: objects %zu", _objects.size()); + DelegateHandler::startObject(path); } // Area -void JMAHandler::Area::value(ElementPath& path, ElementValue& value) +void JMAHandler::Area::value(const ElementPath& path, const ElementValue& value) { Element e_name { "name", &_v._name }; Element e_code { "code", &_v._code }; ElementBase* elements[] = { &e_name, &e_code }; - for(auto& e : elements) - { - if(e->key == path.getKey()) { e->store(value); return; } - - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) { if(*e == path.getKey()) { e->store(value); return; } } } // ForeeCast -JMAHandler::Object* JMAHandler::Forecast::startObject(ElementPath& path) +Delegater* JMAHandler::Forecast::startObject(const ElementPath& path) { - Object* obj = nullptr; + // WB2_LOGV("%s:index:%d count:%d", path.toString().c_str(), path.getIndex(), path.getCount()); + Delegater* obj = nullptr; switch(path.getIndex()) { case 0: obj = new TimeSeriesWeather(_v._tsWeather); break; case 1: obj = new TimeSeriesPop(_v._tsPop); break; case 2: obj = new TimeSeriesTemp(_v._tsTemp); break; } - return obj ? obj : new Object(); + return obj ? obj : Delegater::startObject(path); } -void JMAHandler::Forecast::value(ElementPath& path, ElementValue& value) +void JMAHandler::Forecast::value(const ElementPath& path, const ElementValue& value) { - Element e_publishingOffice { "publishingOffice", &_v._publishingOffice }; - Element e_reportDatetime { "reportDatetime", &_v._reportDatetime }; + Element e_publishingOffice { "publishingOffice", &_v._publishingOffice }; + CustomElement e_reportDatetime { "reportDatetime", &_v._reportDatetime }; ElementBase* elements[] = { &e_publishingOffice, &e_reportDatetime }; - for(auto& e : elements) - { - if(e->key == path.getKey()) { e->store(value); return; } - - } + WB2_LOGV("[%s] %d <%s>", path.toString().c_str(), value.isString(), value.getString()); + for(auto& e : elements) { if(*e == path.getKey()) { e->store(value); return; } } + WB2_LOGE("oops!"); } // Forecast::TimeSeriesWeather -JMAHandler::Object* JMAHandler::Forecast::TimeSeriesWeather::startObject(ElementPath& path) +Delegater* JMAHandler::Forecast::TimeSeriesWeather::startObject(const ElementPath& path) { auto parent = path.getParent(); if(parent && String("areas") == parent->getKey()) @@ -124,33 +92,30 @@ JMAHandler::Object* JMAHandler::Forecast::TimeSeriesWeather::startObject(Element _v._areas.emplace_back(); return new TimeSeriesWeather::Areas(_v._areas.back()); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::Forecast::TimeSeriesWeather::value(ElementPath& path, ElementValue& value) +void JMAHandler::Forecast::TimeSeriesWeather::value(const ElementPath& path, const ElementValue& value) { auto parent = path.getParent(); if(!parent) { return; } - Element e_td { "timeDefines", &_v._timeDefines }; + CustomElement e_td { "timeDefines", &_v._timeDefines }; ElementBase* elements[] = { &e_td }; - for(auto& e : elements) - { - if(e->key == parent->getKey()) { e->store(value); return; } - - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) { if(*e == parent->getKey()) { e->store(value); return; } } } // Forecast::TimeSeriesWeather::Areas -JMAHandler::Object* JMAHandler::Forecast::TimeSeriesWeather::Areas::startObject(ElementPath& path) +Delegater* JMAHandler::Forecast::TimeSeriesWeather::Areas::startObject(const ElementPath& path) { if(String("area") == path.getKey()) { return new JMAHandler::Area(_v._area); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::Forecast::TimeSeriesWeather::Areas::value(ElementPath& path, ElementValue& value) +void JMAHandler::Forecast::TimeSeriesWeather::Areas::value(const ElementPath& path, const ElementValue& value) { auto parent = path.getParent(); if(!parent) { return; } @@ -161,15 +126,12 @@ void JMAHandler::Forecast::TimeSeriesWeather::Areas::value(ElementPath& path, El // Element e_waves { "waves", &_v._waves }; // ElementBase* elements[] = { &e_codes, &e_weathers, &e_winds, &e_waves }; ElementBase* elements[] = { &e_codes }; - for(auto& e : elements) - { - if(e->key == parent->getKey()) { e->store(value); return; } - - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) {if(*e == parent->getKey()) { e->store(value); return; }} } // Forecast::TimeSeriesPop -JMAHandler::Object* JMAHandler::Forecast::TimeSeriesPop::startObject(ElementPath& path) +Delegater* JMAHandler::Forecast::TimeSeriesPop::startObject(const ElementPath& path) { auto parent = path.getParent(); if(parent && String("areas") == parent->getKey()) @@ -177,48 +139,42 @@ JMAHandler::Object* JMAHandler::Forecast::TimeSeriesPop::startObject(ElementPath _v._areas.emplace_back(); return new TimeSeriesPop::Areas(_v._areas.back()); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::Forecast::TimeSeriesPop::value(ElementPath& path, ElementValue& value) +void JMAHandler::Forecast::TimeSeriesPop::value(const ElementPath& path, const ElementValue& value) { auto parent = path.getParent(); if(!parent) { return; } - Element e_td { "timeDefines", &_v._timeDefines }; + CustomElement e_td { "timeDefines", &_v._timeDefines }; ElementBase* elements[] = { &e_td }; - for(auto& e : elements) - { - if(e->key == parent->getKey()) { e->store(value); return; } - - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) { if(*e == parent->getKey()) { e->store(value); return; } } } // Forecast::TimeSeriesPop::Areas -JMAHandler::Object* JMAHandler::Forecast::TimeSeriesPop::Areas::startObject(ElementPath& path) +Delegater* JMAHandler::Forecast::TimeSeriesPop::Areas::startObject(const ElementPath& path) { if(String("area") == path.getKey()) { return new JMAHandler::Area(_v._area); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::Forecast::TimeSeriesPop::Areas::value(ElementPath& path, ElementValue& value) +void JMAHandler::Forecast::TimeSeriesPop::Areas::value(const ElementPath& path, const ElementValue& value) { auto parent = path.getParent(); if(!parent) { return; } Element e_pops { "pops", &_v._pops }; ElementBase* elements[] = { &e_pops }; - for(auto& e : elements) - { - if(e->key == parent->getKey()) { e->store(value); return; } - - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) { if(*e == parent->getKey()) { e->store(value); return; } } } // Forecast::TimeSeriesTemp -JMAHandler::Object* JMAHandler::Forecast::TimeSeriesTemp::startObject(ElementPath& path) +Delegater* JMAHandler::Forecast::TimeSeriesTemp::startObject(const ElementPath& path) { auto parent = path.getParent(); if(parent && String("areas") == parent->getKey()) @@ -226,50 +182,44 @@ JMAHandler::Object* JMAHandler::Forecast::TimeSeriesTemp::startObject(ElementPat _v._areas.emplace_back(); return new TimeSeriesTemp::Areas(_v._areas.back()); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::Forecast::TimeSeriesTemp::value(ElementPath& path, ElementValue& value) +void JMAHandler::Forecast::TimeSeriesTemp::value(const ElementPath& path, const ElementValue& value) { auto parent = path.getParent(); if(!parent) { return; } - Element e_td { "timeDefines", &_v._timeDefines }; + CustomElement e_td { "timeDefines", &_v._timeDefines }; ElementBase* elements[] = { &e_td }; - for(auto& e : elements) - { - if(e->key == parent->getKey()) { e->store(value); return; } - - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) { if(*e == parent->getKey()) { e->store(value); return; } } } // Forecast::TimeSeriesTemp::Areas -JMAHandler::Object* JMAHandler::Forecast::TimeSeriesTemp::Areas::startObject(ElementPath& path) +Delegater* JMAHandler::Forecast::TimeSeriesTemp::Areas::startObject(const ElementPath& path) { if(String("area") == path.getKey()) { return new JMAHandler::Area(_v._area); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::Forecast::TimeSeriesTemp::Areas::value(ElementPath& path, ElementValue& value) +void JMAHandler::Forecast::TimeSeriesTemp::Areas::value(const ElementPath& path, const ElementValue& value) { auto parent = path.getParent(); if(!parent) { return; } Element e_temps { "temps", &_v._temps }; ElementBase* elements[] = { &e_temps }; - for(auto& e : elements) - { - if(e->key == parent->getKey()) { e->store(value); return; } - - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) { if(*e == parent->getKey()) { e->store(value); return; } } } // WeeklyForeeCast -JMAHandler::Object* JMAHandler::WeeklyForecast::startObject(ElementPath& path) +Delegater* JMAHandler::WeeklyForecast::startObject(const ElementPath& path) { - Object* obj = nullptr; + Delegater* obj = nullptr; auto parent = path.getParent(); if(String("timeSeries") == parent->getKey()) @@ -288,22 +238,20 @@ JMAHandler::Object* JMAHandler::WeeklyForecast::startObject(ElementPath& path) { obj = new PrecipAverage(_v._precipAverage); } - return obj ? obj : new Object(); + return obj ? obj : Delegater::startObject(path); } -void JMAHandler::WeeklyForecast::value(ElementPath& path, ElementValue& value) +void JMAHandler::WeeklyForecast::value(const ElementPath& path, const ElementValue& value) { Element e_publishingOffice { "publishingOffice", &_v._publishingOffice }; - Element e_reportDatetime { "reportDatetime", &_v._reportDatetime }; + CustomElement e_reportDatetime { "reportDatetime", &_v._reportDatetime }; ElementBase* elements[] = { &e_publishingOffice, &e_reportDatetime }; - for(auto& e : elements) - { - if(e->key == path.getKey()) { e->store(value); return; } - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) { if(*e == path.getKey()) { e->store(value); return; } } } // WeeklyForecast::TimeSeriesWeather -JMAHandler::Object* JMAHandler::WeeklyForecast::TimeSeriesWeather::startObject(ElementPath& path) +Delegater* JMAHandler::WeeklyForecast::TimeSeriesWeather::startObject(const ElementPath& path) { auto parent = path.getParent(); if(parent && String("areas") == parent->getKey()) @@ -311,50 +259,44 @@ JMAHandler::Object* JMAHandler::WeeklyForecast::TimeSeriesWeather::startObject(E _v._areas.emplace_back(); return new TimeSeriesWeather::Areas(_v._areas.back()); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::WeeklyForecast::TimeSeriesWeather::value(ElementPath& path, ElementValue& value) +void JMAHandler::WeeklyForecast::TimeSeriesWeather::value(const ElementPath& path, const ElementValue& value) { auto parent = path.getParent(); if(!parent) { return; } - Element e_td { "timeDefines", &_v._timeDefines }; + CustomElement e_td { "timeDefines", &_v._timeDefines }; ElementBase* elements[] = { &e_td }; - for(auto& e : elements) - { - if(e->key == parent->getKey()) { e->store(value); return; } - - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) { if(*e == parent->getKey()) { e->store(value); return; } } } // WeeklyForecast::TimeSeriesWeather::Areas -JMAHandler::Object* JMAHandler::WeeklyForecast::TimeSeriesWeather::Areas::startObject(ElementPath& path) +Delegater* JMAHandler::WeeklyForecast::TimeSeriesWeather::Areas::startObject(const ElementPath& path) { if(String("area") == path.getKey()) { return new JMAHandler::Area(_v._area); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::WeeklyForecast::TimeSeriesWeather::Areas::value(ElementPath& path, ElementValue& value) +void JMAHandler::WeeklyForecast::TimeSeriesWeather::Areas::value(const ElementPath& path, const ElementValue& value) { auto parent = path.getParent(); if(!parent) { return; } Element e_codes { "weatherCodes", &_v._weatherCodes }; Element e_pops { "pops", &_v._pops }; - Element e_reliabilities { "reliabilities", &_v._reliabilities }; + CustomElement e_reliabilities { "reliabilities", &_v._reliabilities }; ElementBase* elements[] = { &e_codes, &e_pops, &e_reliabilities }; - for(auto& e : elements) - { - if(e->key == parent->getKey()) { e->store(value); return; } - - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) {if(*e == parent->getKey()) { e->store(value); return; } } } // WeeklyForecast::TimeSeriesTemp -JMAHandler::Object* JMAHandler::WeeklyForecast::TimeSeriesTemp::startObject(ElementPath& path) +Delegater* JMAHandler::WeeklyForecast::TimeSeriesTemp::startObject(const ElementPath& path) { auto parent = path.getParent(); if(parent && String("areas") == parent->getKey()) @@ -362,33 +304,30 @@ JMAHandler::Object* JMAHandler::WeeklyForecast::TimeSeriesTemp::startObject(Elem _v._areas.emplace_back(); return new TimeSeriesTemp::Areas(_v._areas.back()); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::WeeklyForecast::TimeSeriesTemp::value(ElementPath& path, ElementValue& value) +void JMAHandler::WeeklyForecast::TimeSeriesTemp::value(const ElementPath& path, const ElementValue& value) { auto parent = path.getParent(); if(!parent) { return; } - Element e_td { "timeDefines", &_v._timeDefines }; + CustomElement e_td { "timeDefines", &_v._timeDefines }; ElementBase* elements[] = { &e_td }; - for(auto& e : elements) - { - if(e->key == parent->getKey()) { e->store(value); return; } - - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) { if(*e == parent->getKey()) { e->store(value); return; } } } // WeeklyForecast::TimeSeriesTemp::Areas -JMAHandler::Object* JMAHandler::WeeklyForecast::TimeSeriesTemp::Areas::startObject(ElementPath& path) +Delegater* JMAHandler::WeeklyForecast::TimeSeriesTemp::Areas::startObject(const ElementPath& path) { if(String("area") == path.getKey()) { return new JMAHandler::Area(_v._area); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::WeeklyForecast::TimeSeriesTemp::Areas::value(ElementPath& path, ElementValue& value) +void JMAHandler::WeeklyForecast::TimeSeriesTemp::Areas::value(const ElementPath& path, const ElementValue& value) { auto parent = path.getParent(); if(!parent) { return; } @@ -400,15 +339,12 @@ void JMAHandler::WeeklyForecast::TimeSeriesTemp::Areas::value(ElementPath& path, Element e_tempsMaxU { "tempsMaxUpper", &_v._tempsMaxUpper }; Element e_tempsMaxL { "tempsMaxLower", &_v._tempsMaxLower }; ElementBase* elements[] = { &e_tempsMin, &e_tempsMinU, &e_tempsMinL, &e_tempsMax, &e_tempsMaxU, &e_tempsMaxL }; - for(auto& e : elements) - { - if(e->key == parent->getKey()) { e->store(value); return; } - - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) { if(*e == parent->getKey()) { e->store(value); return; } } } // WeeklyForecast::TempAverage -JMAHandler::Object* JMAHandler::WeeklyForecast::TempAverage::startObject(ElementPath& path) +Delegater* JMAHandler::WeeklyForecast::TempAverage::startObject(const ElementPath& path) { auto parent = path.getParent(); if(parent && String("areas") == parent->getKey()) @@ -416,24 +352,25 @@ JMAHandler::Object* JMAHandler::WeeklyForecast::TempAverage::startObject(Element _v._areas.emplace_back(); return new TempAverage::Areas(_v._areas.back()); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::WeeklyForecast::TempAverage::value(ElementPath& path, ElementValue& value) +void JMAHandler::WeeklyForecast::TempAverage::value(const ElementPath& path, const ElementValue& value) { + // No value is obtained. } // WeeklyForecast::TempAverage::Areas -JMAHandler::Object* JMAHandler::WeeklyForecast::TempAverage::Areas::startObject(ElementPath& path) +Delegater* JMAHandler::WeeklyForecast::TempAverage::Areas::startObject(const ElementPath& path) { if(String("area") == path.getKey()) { return new JMAHandler::Area(_v._area); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::WeeklyForecast::TempAverage::Areas::value(ElementPath& path, ElementValue& value) +void JMAHandler::WeeklyForecast::TempAverage::Areas::value(const ElementPath& path, const ElementValue& value) { auto parent = path.getParent(); if(!parent) { return; } @@ -441,15 +378,12 @@ void JMAHandler::WeeklyForecast::TempAverage::Areas::value(ElementPath& path, El Element e_min { "min", &_v._min }; Element e_max { "max", &_v._max }; ElementBase* elements[] = { &e_min, &e_max }; - for(auto& e : elements) - { - if(e->key == parent->getKey()) { e->store(value); return; } - - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) { if(*e == parent->getKey()) { e->store(value); return; } } } // WeeklyForecast::PrecipAverage -JMAHandler::Object* JMAHandler::WeeklyForecast::PrecipAverage::startObject(ElementPath& path) +Delegater* JMAHandler::WeeklyForecast::PrecipAverage::startObject(const ElementPath& path) { auto parent = path.getParent(); if(parent && String("areas") == parent->getKey()) @@ -457,24 +391,24 @@ JMAHandler::Object* JMAHandler::WeeklyForecast::PrecipAverage::startObject(Eleme _v._areas.emplace_back(); return new PrecipAverage::Areas(_v._areas.back()); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::WeeklyForecast::PrecipAverage::value(ElementPath& path, ElementValue& value) +void JMAHandler::WeeklyForecast::PrecipAverage::value(const ElementPath& path, const ElementValue& value) { } // WeeklyForecast::PrecipAverage::Areas -JMAHandler::Object* JMAHandler::WeeklyForecast::PrecipAverage::Areas::startObject(ElementPath& path) +Delegater* JMAHandler::WeeklyForecast::PrecipAverage::Areas::startObject(const ElementPath& path) { if(String("area") == path.getKey()) { return new JMAHandler::Area(_v._area); } - return new Object(); + return Delegater::startObject(path); } -void JMAHandler::WeeklyForecast::PrecipAverage::Areas::value(ElementPath& path, ElementValue& value) +void JMAHandler::WeeklyForecast::PrecipAverage::Areas::value(const ElementPath& path, const ElementValue& value) { auto parent = path.getParent(); if(!parent) { return; } @@ -482,44 +416,26 @@ void JMAHandler::WeeklyForecast::PrecipAverage::Areas::value(ElementPath& path, Element e_min { "min", &_v._min }; Element e_max { "max", &_v._max }; ElementBase* elements[] = { &e_min, &e_max }; - for(auto& e : elements) - { - if(e->key == parent->getKey()) { e->store(value); return; } - - } + // WB2_LOGV("[%s] <%s>", path.toString().c_str(), value.toString().c_str()); + for(auto& e : elements) { if(*e == parent->getKey()) { e->store(value); return; } } } #if 0 +namespace +{ +const char jma_json[] = +R"***( +[{"publishingOffice":"金沢地方気象台","reportDatetime":"2023-01-10T11:00:00+09:00","timeSeries":[{"timeDefines":["2023-01-10T11:00:00+09:00","2023-01-11T00:00:00+09:00","2023-01-12T00:00:00+09:00"],"areas":[{"area":{"name":"加賀","code":"170010"},"weatherCodes":["200","101","101"],"weathers":["くもり 所により 夕方 まで 雨か雪","晴れ 昼前 から 夕方 くもり","晴れ 時々 くもり"],"winds":["北の風 海上 では 北西の風 やや強く","南の風 海上 では 南西の風 やや強く","南の風 後 南西の風"],"waves":["3メートル うねり を伴う","2メートル 後 1.5メートル","1.5メートル 後 1メートル"]},{"area":{"name":"能登","code":"170020"},"weatherCodes":["200","111","201"],"weathers":["くもり 所により 夕方 まで 雨か雪","晴れ 昼前 から くもり","くもり 時々 晴れ"],"winds":["北西の風 やや強く 後 西の風","南の風 海上 では 南西の風 やや強く","南の風"],"waves":["4メートル 後 3メートル うねり を伴う","2.5メートル 後 2メートル","2メートル"]}]},{"timeDefines":["2023-01-10T12:00:00+09:00","2023-01-10T18:00:00+09:00","2023-01-11T00:00:00+09:00","2023-01-11T06:00:00+09:00","2023-01-11T12:00:00+09:00","2023-01-11T18:00:00+09:00"],"areas":[{"area":{"name":"加賀","code":"170010"},"pops":["30","10","0","10","10","0"]},{"area":{"name":"能登","code":"170020"},"pops":["30","10","10","20","20","10"]}]},{"timeDefines":["2023-01-10T09:00:00+09:00","2023-01-10T00:00:00+09:00","2023-01-11T00:00:00+09:00","2023-01-11T09:00:00+09:00"],"areas":[{"area":{"name":"金沢","code":"56227"},"temps":["6","6","0","9"]},{"area":{"name":"輪島","code":"56052"},"temps":["4","5","0","9"]}]}]},{"publishingOffice":"金沢地方気象台","reportDatetime":"2023-01-10T11:00:00+09:00","timeSeries":[{"timeDefines":["2023-01-11T00:00:00+09:00","2023-01-12T00:00:00+09:00","2023-01-13T00:00:00+09:00","2023-01-14T00:00:00+09:00","2023-01-15T00:00:00+09:00","2023-01-16T00:00:00+09:00","2023-01-17T00:00:00+09:00"],"areas":[{"area":{"name":"石川県","code":"170000"},"weatherCodes":["101","101","201","203","202","206","206"],"pops":["","20","40","70","60","50","50"],"reliabilities":["","","C","A","B","C","C"]}]},{"timeDefines":["2023-01-11T00:00:00+09:00","2023-01-12T00:00:00+09:00","2023-01-13T00:00:00+09:00","2023-01-14T00:00:00+09:00","2023-01-15T00:00:00+09:00","2023-01-16T00:00:00+09:00","2023-01-17T00:00:00+09:00"],"areas":[{"area":{"name":"金沢","code":"56227"},"tempsMin":["","2","4","7","4","3","4"],"tempsMinUpper":["","5","5","9","6","5","6"],"tempsMinLower":["","1","2","3","1","1","2"],"tempsMax":["","14","16","16","9","8","8"],"tempsMaxUpper":["","16","18","18","13","11","11"],"tempsMaxLower":["","13","15","14","7","6","6"]}]}],"tempAverage":{"areas":[{"area":{"name":"金沢","code":"56227"},"min":"1.2","max":"7.1"}]},"precipAverage":{"areas":[{"area":{"name":"金沢","code":"56227"},"min":"39.9","max":"67.2"}]}}] +)***"; +// +} void test_json() { - auto mem = esp_get_free_heap_size(); - WB2_LOGD("before:%u", mem); - - { - JsonStreamingParser parser; - JMAHandler handler; - parser.setHandler(&handler); - - - for(auto& e : test) - { - parser.parse(e); - } - printf("--------------------\n"); - printf("%s\n", handler._forecast.toString().c_str()); - printf("--------------------\n"); - printf("%s\n", handler._weeklyForecast.toString().c_str()); - } - - auto mem2 = esp_get_free_heap_size(); - WB2_LOGD("after:%u diff:%d", mem2, mem2 - mem); - - { - JsonStreamingParser parser; - JMAHandler handler; - parser.setHandler(&handler); - } - auto mem3 = esp_get_free_heap_size(); - WB2_LOGD("after:%u diff:%d", mem3, mem3 - mem2); + JMAHandler handler; + goblib::json::StreamingParser parser(&handler); + for(auto& e : jma_json) { parser.parse(e); } + WB2_LOGD("%s", handler._forecast.toString().c_str()); + WB2_LOGD("%s", handler._weeklyForecast.toString().c_str()); + } #endif diff --git a/src/jma/jma_forecast_handler.hpp b/src/jma/jma_forecast_handler.hpp index d654350..c856bf3 100644 --- a/src/jma/jma_forecast_handler.hpp +++ b/src/jma/jma_forecast_handler.hpp @@ -1,267 +1,194 @@ #ifndef JMA_FORECAST_PARSER_HPP #define JMA_FORECAST_PARSER_HPP -#include +#include +#include +#include #include "jma_forecast.hpp" -#include -#include - -template struct is_std_vector { static const bool value=false; }; -template struct is_std_vector > { static const bool value=true; }; - -// Store functions for each type. (SFINAE) -struct ElementBase +// JSON handler for JMA forecast +class JMAHandler : public goblib::json::DelegateHandler { - ElementBase(const char* s) : key(s) {} - virtual void store(ElementValue& s) = 0; - String key; -}; - -template struct Element : public ElementBase -{ - T* value; // Pointer of store target. - Element(const char* key, T* p) : ElementBase(key), value(p) { assert(p); } - virtual void store(ElementValue& ev) override { _store(ev); } // _store function is called based on the type of T. (SFINAE) - - // Integral - template::value && std::is_integral::value, std::nullptr_t>::type = nullptr> - void _store(ElementValue& ev) { *value = ev.isInt() ? ev.getInt() : String(ev.getString()).toInt(); } - // Floating-point - template::value, std::nullptr_t>::type = nullptr> - void _store(ElementValue& ev) { *value = ev.isFloat() ? ev.getFloat() : String(ev.getString()).toFloat(); } - // String - template::value, std::nullptr_t>::type = nullptr> - void _store(ElementValue& ev) { *value = ev.getString(); } - // Boolean - template::value, std::nullptr_t>::type = nullptr> - void _store(ElementValue& ev) { *value = ev.isBool() ? ev.getBool() : (String("true") == ev.getString()); } - // OffsetDateTime - template::value, std::nullptr_t>::type = nullptr> - void _store(ElementValue& ev) { *value = OffsetDateTime::parse(ev.getString()); } - // vector - template::value && std::is_integral::value, std::nullptr_t>::type = nullptr> - void _store(ElementValue& ev) { value->emplace_back(ev.isInt() ? ev.getInt() : String(ev.getString()).toInt()); } - // vector - template::value && std::is_same::value, std::nullptr_t>::type = nullptr> - void _store(ElementValue& ev) { value->emplace_back(ev.getString()); } - // vector - template::value && std::is_same::value, std::nullptr_t>::type = nullptr> - void _store(ElementValue& ev) { value->emplace_back(ev.getString()); } - // vector - template::value && std::is_same::value, std::nullptr_t>::type = nullptr> - void _store(ElementValue& ev) { value->emplace_back(ev.getString()); } -}; + using ElementPath = goblib::json::ElementPath; + using ElementValue = goblib::json::ElementValue; -// -class JMAHandler : public JsonHandler -{ public: - struct Object // interface class. - { - virtual ~Object(){} - virtual Object* startObject(ElementPath& path) { return new Object(); } - virtual void endObject(ElementPath& path) {} - virtual void startArray(ElementPath& path) {} - virtual void endArray(ElementPath& path) {} - virtual void value(ElementPath& path, ElementValue& value) {} - }; - // - class Area : public Object + class Area : public Delegater { public: Area(jma::Area& target) : _v(target) {} - virtual void value(ElementPath& path, ElementValue& value) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::Area& _v; }; // - class Forecast : public Object + class Forecast : public Delegater { // - class TimeSeriesWeather : public Object + class TimeSeriesWeather : public Delegater { // - class Areas : public Object + class Areas : public Delegater { public: Areas(jma::Forecast::TimeSeriesWeather::Areas& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::Forecast::TimeSeriesWeather::Areas& _v; }; public: TimeSeriesWeather(jma::Forecast::TimeSeriesWeather& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::Forecast::TimeSeriesWeather& _v; }; // - class TimeSeriesPop : public Object + class TimeSeriesPop : public Delegater { public: - class Areas : public Object + class Areas : public Delegater { public: Areas(jma::Forecast::TimeSeriesPop::Areas& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::Forecast::TimeSeriesPop::Areas& _v; }; TimeSeriesPop(jma::Forecast::TimeSeriesPop& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::Forecast::TimeSeriesPop& _v; }; // - class TimeSeriesTemp : public Object + class TimeSeriesTemp : public Delegater { public: - class Areas : public Object + class Areas : public Delegater { public: Areas(jma::Forecast::TimeSeriesTemp::Areas& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::Forecast::TimeSeriesTemp::Areas& _v; }; TimeSeriesTemp(jma::Forecast::TimeSeriesTemp& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::Forecast::TimeSeriesTemp& _v; }; public: Forecast(jma::Forecast& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::Forecast& _v; }; // - class WeeklyForecast : public Object + class WeeklyForecast : public Delegater { // - class TimeSeriesWeather : public Object + class TimeSeriesWeather : public Delegater { // - class Areas : public Object + class Areas : public Delegater { public: Areas(jma::WeeklyForecast::TimeSeriesWeather::Areas& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::WeeklyForecast::TimeSeriesWeather::Areas& _v; }; public: TimeSeriesWeather(jma::WeeklyForecast::TimeSeriesWeather& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::WeeklyForecast::TimeSeriesWeather& _v; }; // - class TimeSeriesTemp : public Object + class TimeSeriesTemp : public Delegater { public: - class Areas : public Object + class Areas : public Delegater { public: Areas(jma::WeeklyForecast::TimeSeriesTemp::Areas& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::WeeklyForecast::TimeSeriesTemp::Areas& _v; }; TimeSeriesTemp(jma::WeeklyForecast::TimeSeriesTemp& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::WeeklyForecast::TimeSeriesTemp& _v; }; // - class TempAverage : public Object + class TempAverage : public Delegater { public: - class Areas : public Object + class Areas : public Delegater { public: Areas(jma::WeeklyForecast::TempAverage::Areas& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::WeeklyForecast::TempAverage::Areas& _v; }; TempAverage(jma::WeeklyForecast::TempAverage& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::WeeklyForecast::TempAverage& _v; }; // - class PrecipAverage : public Object + class PrecipAverage : public Delegater { public: - class Areas : public Object + class Areas : public Delegater { public: Areas(jma::WeeklyForecast::PrecipAverage::Areas& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::WeeklyForecast::PrecipAverage::Areas& _v; }; PrecipAverage(jma::WeeklyForecast::PrecipAverage& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::WeeklyForecast::PrecipAverage& _v; }; public: WeeklyForecast(jma::WeeklyForecast& target) : _v(target) {} - virtual Object* startObject(ElementPath& path) override; - virtual void value(ElementPath& path, ElementValue& value) override; + virtual Delegater* startObject(const ElementPath& path) override; + virtual void value(const ElementPath& path, const ElementValue& value) override; private: jma::WeeklyForecast& _v; }; public: - // JsonHandler overrides - void startDocument() override {} - void endDocument() override; - void startObject(ElementPath path) override; - void endObject(ElementPath path) override; - void startArray(ElementPath path) override; - void endArray(ElementPath path) override; - void whitespace(char /*c*/) override {} - void value(ElementPath path, ElementValue value) override; + void startObject(const ElementPath& path) override; jma::Forecast _forecast{}; jma::WeeklyForecast _weeklyForecast{}; - - private: - Object* currentObject() const { return !_objects.empty() ? _objects.top() : nullptr; } - std::stack _objects; }; +#if 0 +void test_json(); +#endif -//void test_json(); #endif diff --git a/src/jma/jma_task.cpp b/src/jma/jma_task.cpp index d61c072..a35f1ae 100644 --- a/src/jma/jma_task.cpp +++ b/src/jma/jma_task.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include "jma_task.hpp" #include "jma_forecast_handler.hpp" #include "wb2/wxbeacon2_log.hpp" @@ -140,9 +140,8 @@ void jma_forecast_task(void*) } // parse JSON - JsonStreamingParser parser; JMAHandler handler; - parser.setHandler(&handler); + goblib::json::StreamingParser parser(&handler); while(client.available()) { parser.parse(client.read()); } if(callbackOnForecast) { callbackOnForecast(requestTable[index], handler._forecast, handler._weeklyForecast); } From 485340197e652fec25b76c780820b57446c1a9fc Mon Sep 17 00:00:00 2001 From: GOB Date: Wed, 11 Jan 2023 02:04:37 +0900 Subject: [PATCH 23/31] Fixes detect button event --- README.md | 2 +- src/main.cpp | 113 ++++++++++++++++++++++++--------------------------- 2 files changed, 53 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index e817e5c..e477ec0 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,7 @@ WxBeacon2 は通常(出荷時状態)、計測データを内部に蓄積しま ## 操作方法 -|ボタン| 長押し | 短押し | +|ボタン| 長押し(1.5秒以上) | 短押し離し | |---|---|---| |A | 全国の天気を取得して喋る | WxBeacon2のデータを取得して喋る| |B | (\*2)WxBeacon2 を出荷時の状態へ戻す | | diff --git a/src/main.cpp b/src/main.cpp index a6a1b06..23ce7ed 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,6 +25,9 @@ #include #include "cpu_usage.hpp" +#include +#include + #ifdef ARDUINO_M5STACK_Core2 #include "himawari/himawari.hpp" #include "himawari/himawari_task.hpp" @@ -147,7 +150,7 @@ struct Weather } else { - snprintf(buf, sizeof(buf), "[%s] %s", + snprintf(buf, sizeof(buf), "#@1[%s] %s", jma::officesCodeToString(oc), jma::weatherCodeToString(wc)); } @@ -405,7 +408,7 @@ void callbackOnForecast(const jma::officecode_t oc, const jma::Forecast& fc, con updatedForecast = true; return; } - + if(fc.existsTopWeatherCodes() && fc.existsTopTemp()) { auto& wcodes = fc.TopWeatherCodes(); @@ -671,6 +674,8 @@ void setup() WB2_LOGI("PSRAM:size:%u free:%u", ESP.getPsramSize(), ESP.getFreePsram()); WB2_LOGI("ESP-IDF Version %d.%d.%d", (ESP_IDF_VERSION>>16) & 0xFF, (ESP_IDF_VERSION>>8)&0xFF, ESP_IDF_VERSION & 0xFF); + WB2_LOGI("gob_datetime Version %s", GOBLIB_DATETIME_VERSION_STRING); + WB2_LOGI("gob_json Version %s", GOB_JSON_VERSION_STRING); } M5.Display.startWrite(); // Occupy DMA Bus @@ -678,11 +683,11 @@ void setup() // Get advertise from WxBeacon2. _requestAdvertise(); -} -namespace -{ -bool longPressA{false}, longPressB{false},longPressC{false}; + // Setting for hold time(ms) + M5.BtnA.setHoldThresh(1500); + M5.BtnB.setHoldThresh(1500); + M5.BtnC.setHoldThresh(1500); } // Main loop @@ -691,71 +696,57 @@ void loop() auto start = millis(); M5.update(); - // WARNING : If the beacon mode is changed, all data stored in WxBeacon2 will be lost. - // WARNING : After the mode change, Abort system. - /* - C button - long press : Set beacon mode to GeneralBroadcaster2 for this application. - press : show/hide ticker - */ - if(!longPressC && M5.BtnC.pressedFor(1000) && canRequest()) - { - longPressC = true; - WB2_LOGI("Set beacon mode to broadcast mode"); - auto b = changeBeaconMode(); - WB2_LOGI("Result : %d", b); - abort(); - } - if(M5.BtnC.wasReleased()) + if(canRequest()) { - if(!longPressC) + // WARNING : If the beacon mode is changed, all data stored in WxBeacon2 will be lost. + // WARNING : After the mode change, Abort system. + /* + C button + long press : Set beacon mode to GeneralBroadcaster2 for this application. + click : show/hide ticker + */ + if(M5.BtnC.wasHold()) + { + WB2_LOGI("Set beacon mode to broadcast mode"); + auto b = changeBeaconMode(); + WB2_LOGI("Result : %d", b); + abort(); + } + else if(M5.BtnC.wasClicked()) { ticker->show(!ticker->isShow()); forceRender = true; } - longPressC = false; - } - - /* - B button - long press : Set default setting for WNI aplication. - press : (none) - */ - if(!longPressB && M5.BtnB.pressedFor(1000) && canRequest()) - { - longPressB = true; - WB2_LOGI("Set default settings"); - aq_talk::stopAquesTalk(); - auto b = changeDefaultSetting(); - WB2_LOGI("Result : %d", b); - abort(); - } - if(M5.BtnB.wasReleased()) - { - if(!longPressB) + /* + B button + long press : Set default setting for WNI aplication. + click : (none) + */ + if(M5.BtnB.wasHold()) { - // nop + WB2_LOGI("Set default settings"); + aq_talk::stopAquesTalk(); + auto b = changeDefaultSetting(); + WB2_LOGI("Result : %d", b); + abort(); } - longPressB = false; - } - - /* - A button - long press : Obtain forecast force. - press : Obtain beacon datat force. - */ - if(!longPressA && M5.BtnA.pressedFor(1000)) - { - longPressA = true; - _requestForecast(); - } - if(M5.BtnA.wasReleased()) - { - if(!longPressA) + else if(M5.BtnB.wasClicked()) + { + /* Nop */ + } + /* + A button + long press : Obtain forecast force. + click : Obtain beacon datat force. + */ + if(M5.BtnA.wasHold()) + { + _requestForecast(); + } + else if(M5.BtnA.wasClicked()) { _requestAdvertise(); } - longPressA = false; } time_t now{}; From 7dec7012f236ce18244ebc9e5d82c808943f1535 Mon Sep 17 00:00:00 2001 From: GOB Date: Sat, 28 Jan 2023 16:56:34 +0900 Subject: [PATCH 24/31] Fixes M5Timer is useed for processing at intervals --- platformio.ini | 81 +++++++++++++++++++++++++--------------------- src/main.cpp | 87 +++++++++++++++++++++++++++++++------------------- 2 files changed, 99 insertions(+), 69 deletions(-) diff --git a/platformio.ini b/platformio.ini index 8aa62ac..267bb07 100644 --- a/platformio.ini +++ b/platformio.ini @@ -14,7 +14,8 @@ board_build.f_cpu = 240000000L ; https://www.a-quest.com/download.html Download AquesTalk ESP32 and extract ./lib folder. lib_ldf_mode = deep -lib_deps = https://github.com/M5Stack/M5Unified.git @ ^0.1.2 +lib_deps = https://github.com/M5Stack/M5Unified.git#develop + ;https://github.com/M5Stack/M5Unified.git @ ^0.1.2 h2zero/NimBLE-Arduino @ ^1.4.0 https://github.com/GOB52/gob_json.git @ ^0.0.3 https://github.com/GOB52/gob_datetime.git @ ^0.1.1 @@ -29,32 +30,30 @@ upload_speed = 921600 ; M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC : Auto talk interval (Unit; second) build_flags = -Wall -Wextra -Wreturn-local-addr -Werror=format -Werror=return-local-addr -D M5S_WXBEACON2_TIMEZONE_LOCATION=\"Asia/Tokyo\" - -D M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC=300 - -D M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC=60 + -D M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC=60 + -D M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC=30 -D M5S_WXBEACON2_DEBUG_INFO -D GOB_JSON_LOG_LEVEL=5 - -;Choose build type -[release_env] -build_type = release -build_flags = ${env.build_flags} - -DCORE_DEBUG_LEVEL=1 + + ;-D M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC=300 + ; -D M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC=60 + +; -------------------------------- +;Choose build options +[option_release] +build_flags = -DCORE_DEBUG_LEVEL=1 -DLOG_LOCAL_LEVEL=4 -DWB2_LOG_LEVEL=5 -DMYNEWT_VAL_BLE_HS_LOG_LVL=5 - -[log_env] -build_type = release -build_flags = ${env.build_flags} - -DCORE_DEBUG_LEVEL=5 + +[option_log] +build_flags = -DCORE_DEBUG_LEVEL=5 -DLOG_LOCAL_LEVEL=5 -DWB2_LOG_LEVEL=5 -DMYNEWT_VAL_BLE_HS_LOG_LVL=0 -[debug_env] -build_type = debug -build_flags = ${env.build_flags} - -DCORE_DEBUG_LEVEL=5 +[option_debug] +build_flags = -DCORE_DEBUG_LEVEL=5 -DLOG_LOCAL_LEVEL=5 -DWB2_LOG_LEVEL=5 -DMYNEWT_VAL_BLE_HS_LOG_LVL=0 @@ -62,48 +61,56 @@ build_flags = ${env.build_flags} ; Choose board [core2_env] board = m5stack-core2 -build_flags = ${env.build_flags} - -DBOARD_HAS_PSRAM - -mfix-esp32-psram-cache-issue [m5s_env] board = m5stack-core-esp32 -board_build.partitions = min_spiffs.csv ;----------------------------------------------------------------------- ; M5Stack Core2 [env:core2_master] -extends=release_env, core2_env -build_flags = ${env.build_flags} - -D NDEBUG +extends = core2_env +build_type=release +build_flags=${env.build_flags} ${option_release.build_flags} -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue -D NDEBUG [env:core2_release] -extends=release_env, core2_env +extends = core2_env +build_type=release +build_flags=${env.build_flags} ${option_release.build_flags} -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue [env:core2_log] -extends=log_env, core2_env +extends = core2_env +build_type=release +build_flags=${env.build_flags} ${option_log.build_flags} -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue [env:core2_debug] -extends=debug_env, core2_env +extends = core2_env +build_type=debug +build_flags=${env.build_flags} ${option_debug.build_flags} -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ; M5Stack BASIC [env:basic_master] -extends=release_env, m5s_env -build_flags = ${env.build_flags} - -D NDEBUG +extends = m5s_env +build_type=release +build_flags=${env.build_flags} ${option_release.build_flags} -D NDEBUG [env:basic_release] -extends=release_env, m5s_env +extends = m5s_env +build_type=release +build_flags=${env.build_flags} ${option_release.build_flags} [env:basic_map] -extends=release_env, m5s_env -build_flags = ${env.build_flags} - -Wl,-Map,output.map +extends = m5s_env +build_type=release +build_flags=${env.build_flags} ${option_release.build_flags} -Wl,-Map,output.map [env:basic_log] -extends=log_env, m5s_env +extends = m5s_env +build_type=release +build_flags=${env.build_flags} ${option_log.build_flags} -D NDEBUG [env:basic_debug] -extends=debug_env, m5s_env +extends = m5s_env +build_type=debug +build_flags=${env.build_flags} ${option_debug.build_flags} -D NDEBUG diff --git a/src/main.cpp b/src/main.cpp index 23ce7ed..57fc27c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,7 @@ */ #include #include +#include #include #include // esp_bt_controller_mem_release #include // esp_random() is hardware RNG. (No random seed initialization is required) @@ -86,8 +87,6 @@ HimawariScreen* himawariScreen; #endif ProgressIcon* progress; bool forceRender = true; // Force rendering all -time_t lastUpdate = -1; -time_t voiceEnd = -1; // For task settings. (piority low:0) [Beware of WDT] constexpr UBaseType_t advertisePriority = 1; @@ -109,6 +108,8 @@ constexpr BaseType_t speakerCore = 0; bool existsBeacon = false; WxBeacon2::AdvertiseData advertiseData; bool updatedAdvertise = false; +M5Timer timer; +int_fast8_t requestTimerId{-1}, talkTimerId{-1}; // struct Weather @@ -500,13 +501,6 @@ void playForecast() weatherMap->show(); } -// -------------------------------- -// Callback on End of aqtalk. -void callbackOnEndAqTalk() -{ - std::time(&voiceEnd); -} - // -------------------------------- #ifdef ARDUINO_M5STACK_Core2 // Request himawari image @@ -587,9 +581,46 @@ PROGMEM static const char t2[] = "weza-roido'una'na-i wa arimasen"; const char* talkTable[] = { t0, t1, t2 }; void talkRandom() { - auto idx = esp_random() % gob::size(talkTable); - aq_talk::playAquesTalk(talkTable[idx], 110); + if(!aq_talk::busy()) + { + auto idx = esp_random() % gob::size(talkTable); + aq_talk::playAquesTalk(talkTable[idx], 110); + } } + +// -------------------------------- +// Callback on End of aqtalk. +void callbackOnEndAqTalk() +{ + timer.restartTimer(talkTimerId); + WB2_LOGV("restart talkRandom timer"); +} + +// -------------------------------- +// Timer +void timerCallbackRequest() +{ + if(canRequest()) + { +#ifdef ARDUINO_M5STACK_Core2 + _requestHimawari(); +#else + _requestAdvertise(); +#endif + return; + } + // Retry + requestTimerId = timer.setTimeout(1000 /*ms*/, timerCallbackRequest); + WB2_LOGI("Retry timercallback %d", requestTimerId); +} + +void resetRequestTimer() +{ + timer.deleteTimer(requestTimerId); + requestTimerId = timer.setTimeout(M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC * 1000 /*ms*/, timerCallbackRequest); + WB2_LOGV("Reset request timer %d", requestTimerId); +} + // } @@ -684,6 +715,10 @@ void setup() // Get advertise from WxBeacon2. _requestAdvertise(); + // Timer callback + requestTimerId = timer.setTimeout(M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC * 1000 /*ms*/, timerCallbackRequest); + talkTimerId = timer.setInterval(M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC * 1000 /*ms*/, talkRandom); + // Setting for hold time(ms) M5.BtnA.setHoldThresh(1500); M5.BtnB.setHoldThresh(1500); @@ -737,7 +772,7 @@ void loop() /* A button long press : Obtain forecast force. - click : Obtain beacon datat force. + click : Obtain beacon data force. */ if(M5.BtnA.wasHold()) { @@ -755,7 +790,7 @@ void loop() // Play latest advertise data if exists. if(updatedAdvertise) { - std::time(&lastUpdate); + resetRequestTimer(); updatedAdvertise = false; playAdvertiseData(advertiseData); } @@ -763,7 +798,7 @@ void loop() // Play latest forecast if(updatedForecast) { - std::time(&lastUpdate); + resetRequestTimer(); updatedForecast = false; playForecast(); } @@ -772,18 +807,12 @@ void loop() #ifdef ARDUINO_M5STACK_Core2 if(updatedHimawari) { - std::time(&lastUpdate); + resetRequestTimer(); updatedHimawari = false; drawHimawari(); } #endif - // Random talking - if(!aq_talk::busy() && voiceEnd > 0 && std::difftime(now, voiceEnd) >= M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC) - { - talkRandom(); - } - // Update avatar->pump(); ticker->pump(); @@ -820,21 +849,15 @@ void loop() heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL)); M5.Display.setCursor(128, 136); M5.Display.printf("c0:%03.1f c1:%03.1f", cpu_usage::cpu0(), cpu_usage::cpu1()); - cpu_usage::reset(); -#endif - } - + M5.Display.setCursor(128, 144); + M5.Display.printf("tmR:%02d tmT:%02d tmA:%02d", requestTimerId, talkTimerId, timer.getNumAvailableTimers()); - // Auto request - if(canRequest() && lastUpdate > 0 && std::difftime(now, lastUpdate) >= AUTO_REQUEST_INTERVAL_SEC) - { -#ifdef ARDUINO_M5STACK_Core2 - _requestHimawari(); -#else - _requestAdvertise(); + cpu_usage::reset(); #endif } + timer.run(); + // Keep about 30 FPS. auto end = millis(); #ifdef M5S_WXBEACON2_DEBUG_INFO From f10082eec97f6bef5b662b6b03f7a668ab0bff2f Mon Sep 17 00:00:00 2001 From: GOB Date: Sat, 28 Jan 2023 17:15:25 +0900 Subject: [PATCH 25/31] Fixes increased himawari jpg data reading interval --- src/himawari/himawari_task.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/himawari/himawari_task.cpp b/src/himawari/himawari_task.cpp index e9138d5..a437f53 100644 --- a/src/himawari/himawari_task.cpp +++ b/src/himawari/himawari_task.cpp @@ -200,7 +200,7 @@ void himawari_task(void*) break; } - gtry = 8; + gtry = 16; do { while(http.connected() && client.available()) @@ -212,14 +212,14 @@ void himawari_task(void*) read -= len; off += len; WB2_LOGD("len:%zu off:%zu ava:%zu", len, off, client.available()); - delay(50); // Insert appropriate delay to continue reading the stream. + delay(100); // Insert appropriate delay to continue reading the stream. } szTmp -= std::min(blockSize, szTmp); if(callbackOnProgress) { callbackOnProgress(off, jpgsz); } - delay(50); + delay(100); } WB2_LOGD("http:%d", http.connected()); - if(off < jpgsz) { WB2_LOGD("Not enough read"); delay(200); } + if(off < jpgsz) { WB2_LOGD("Not enough read"); delay(500); } }while(off < jpgsz && gtry--); WB2_LOGD("off:%zu/%zu", off, jpgsz); From cea01a557f6f27dd0e7d6119900ddfaaeccd1d3a Mon Sep 17 00:00:00 2001 From: GOB Date: Sat, 28 Jan 2023 22:51:20 +0900 Subject: [PATCH 26/31] Add dummy resources --- .gitignore | 5 + README.md | 55 +- platformio.ini | 10 +- src/res/dummy_face.cpp | 3217 ++++++++++++++++++++++++++++++++++++++++ src/res/dummy_logo.cpp | 29 + src/res/dummy_mc.cpp | 81 + src/res/dummy_mo.cpp | 81 + src/res/w100.cpp | 40 + src/res/w101.cpp | 44 + src/res/w102.cpp | 44 + src/res/w104.cpp | 43 + src/res/w110.cpp | 43 + src/res/w112.cpp | 43 + src/res/w115.cpp | 43 + src/res/w200.cpp | 35 + src/res/w201.cpp | 44 + src/res/w202.cpp | 43 + src/res/w204.cpp | 43 + src/res/w210.cpp | 43 + src/res/w212.cpp | 43 + src/res/w215.cpp | 43 + src/res/w300.cpp | 40 + src/res/w301.cpp | 44 + src/res/w302.cpp | 43 + src/res/w303.cpp | 43 + src/res/w308.cpp | 40 + src/res/w311.cpp | 44 + src/res/w313.cpp | 43 + src/res/w314.cpp | 43 + src/res/w400.cpp | 43 + src/res/w401.cpp | 43 + src/res/w402.cpp | 42 + src/res/w403.cpp | 43 + src/res/w406.cpp | 44 + src/res/w411.cpp | 43 + src/res/w413.cpp | 42 + src/res/w414.cpp | 43 + 37 files changed, 4705 insertions(+), 50 deletions(-) create mode 100644 src/res/dummy_face.cpp create mode 100644 src/res/dummy_logo.cpp create mode 100644 src/res/dummy_mc.cpp create mode 100644 src/res/dummy_mo.cpp create mode 100644 src/res/w100.cpp create mode 100644 src/res/w101.cpp create mode 100644 src/res/w102.cpp create mode 100644 src/res/w104.cpp create mode 100644 src/res/w110.cpp create mode 100644 src/res/w112.cpp create mode 100644 src/res/w115.cpp create mode 100644 src/res/w200.cpp create mode 100644 src/res/w201.cpp create mode 100644 src/res/w202.cpp create mode 100644 src/res/w204.cpp create mode 100644 src/res/w210.cpp create mode 100644 src/res/w212.cpp create mode 100644 src/res/w215.cpp create mode 100644 src/res/w300.cpp create mode 100644 src/res/w301.cpp create mode 100644 src/res/w302.cpp create mode 100644 src/res/w303.cpp create mode 100644 src/res/w308.cpp create mode 100644 src/res/w311.cpp create mode 100644 src/res/w313.cpp create mode 100644 src/res/w314.cpp create mode 100644 src/res/w400.cpp create mode 100644 src/res/w401.cpp create mode 100644 src/res/w402.cpp create mode 100644 src/res/w403.cpp create mode 100644 src/res/w406.cpp create mode 100644 src/res/w411.cpp create mode 100644 src/res/w413.cpp create mode 100644 src/res/w414.cpp diff --git a/.gitignore b/.gitignore index 5d1fc3f..f31bdd6 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,9 @@ !/src/res/wifi.cpp !/src/res/bt.cpp !/src/res/jpmap.cpp +!/src/res/dummy_face.cpp +!/src/res/dummy_mo.cpp +!/src/res/dummy_mc.cpp +!/src/res/dummy_logo.cpp +!/src/res/w???.cpp diff --git a/README.md b/README.md index e477ec0..fd8504c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ https://user-images.githubusercontent.com/26270227/186464005-bfc6b1c4-3f5c-4e7f- M5Stack Basic, Gray, Core2 にて WxBeacon2 や気象庁からデータを取得し、 [AquesTalk ESP32](https://www.a-quest.com/products/aquestalk_esp32.html) で喋らせるアプリケーションです。 -どうせならウェザーニュースLiVE のマスコット、ポン子こと [WEATHEROID TypeA Airi](https://twitter.com/typea_airi) ちゃんに喋らせようという事で、アバターはポン子ちゃんとなっております。 +どうせならウェザーニュースLiVE のマスコット、ポン子こと [WEATHEROID TypeA Airi](https://twitter.com/typea_airi) ちゃんに喋らせようという事で、アバターポン子ちゃんを作りました。 ## 必要なもの @@ -34,18 +34,22 @@ WxBeacon2 でなく当該製品でも動作すると思われます(手元に無 ## コンパイル ### 依存ライブラリ -* [M5Unified](https://github.com/m5stack/M5Unified) 0.1.1 or later -* [M5GFX](https://github.com/m5stack/M5GFX) 0.1.1 or later +* [M5Unified](https://github.com/m5stack/M5Unified) 0.1.2#develop or later <-- リリース後書き換え +* [M5GFX](https://github.com/m5stack/M5GFX) 0.1.2 or later * [NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino) 1.4.0 or later -* [json-streaming-parser2]( https://github.com/mrfaptastic/json-streaming-parser2.git ) 2.1.0 or later -* [gob_datetime]( https://github.com/GOB52/gob_datetime.git) 0.1.1 or later +* [gob_json](https://github.com/GOB52/gob_json.git) 0.0.3 or later +* [gob_datetime](https://github.com/GOB52/gob_datetime.git) 0.1.1 or later * [AquesTalk ESP32](https://www.a-quest.com/products/aquestalk_esp32.html) 2.21 or later AquesTalk ESP32 は [こちら](https://www.a-quest.com/download.html) よりダウンロード後、プロジェクトの lib フォルダ(無ければ作成)に展開してください。 ### 画像リソース +初期状態ではダミーとして私が作った顔とロゴが使用されます。 +dummy + **権利上の問題でポン子ちゃんの画像などは当リポジトリには含まれません。** -自分で以下の条件を満たす画像をソースファイルとして共にコンパイルする必要があります。 +ポン子ちゃんや他の画像を使いたい場合、自分で以下の条件を満たす画像を作成し、ソースファイルとして共にコンパイルする必要があります。 + #### 画像フォーマット Basic,Gray での動作の都合上、メモリ使用料削減の為に 4bpp,1bpp を扱います。 @@ -70,45 +74,6 @@ Windows bitmap 48 px x 32 px 4 bpp (16色) パレット 0 番は透過色。顔 Windows bitmap 32 px x 32 px 1 bpp (2色) パレット 0 番は透過色。ティッカーに透過色を用いて上書きされる。 ![logo](./doc/logo.png) -* 天気アイコン (30種類) -PNG 32 px x 24 px 2 bpp (4色) パレットは自由、透過無し。 -![icons](./doc/w406.png) -https://weathernews.jp/s/topics/img/wxicon/ を参考にすると良いでしょう。 - -| リソース名 |内容| ----|--- -|w100| 晴 | -|w101|晴時々曇| -|w102|晴一時雨| -|w104|晴一時雪| -|w110|晴後時々曇| -|w112|晴後一時雨| -|w115|晴後一時雪| -|w200|曇| -|w201|曇時々晴| -|w202|曇一時雨| -|w204|曇一時雪| -|w210|曇後時々晴| -|w212|曇後一時雨| -|w215|曇後一時雪| -|w300|雨| -|w301|雨時々晴| -|w302|雨時々止む| -|w303|雨時々雪| -|w308|雨で暴風を伴う| -|w311|雨後晴| -|w313|雨後曇| -|w314|雨後時々雪| -|w400|雪| -|w401|雪時々晴| -|w402|雪時々止む| -|w403|雪時々雨| -|w406|風雪強い| -|w411|雪後晴| -|w413|雪後曇| -|w414|雪後雨| - - #### ソースファイル化 全てのリソースについて行ってください。 ponko_face.bmp における例を示します。 diff --git a/platformio.ini b/platformio.ini index 267bb07..97ec83d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,6 +11,7 @@ framework = arduino board_build.flash_mode = qio board_build.f_flash = 80000000L board_build.f_cpu = 240000000L +board_build.partitions = min_spiffs.csv ; https://www.a-quest.com/download.html Download AquesTalk ESP32 and extract ./lib folder. lib_ldf_mode = deep @@ -24,19 +25,18 @@ monitor_speed = 115200 monitor_filters = esp32_exception_decoder, time upload_speed = 921600 + ; Definition ; M5S_WXBEACON2_TIMEZONE_LOCATION : Your time-zone location string. default as "Asia/Tokyo" (e.g. "Asia/Tokyo" "America/Los_Angeles" "Australia/Lord_Howe") ; M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC : Auto request interval (Unit: second) ; M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC : Auto talk interval (Unit; second) build_flags = -Wall -Wextra -Wreturn-local-addr -Werror=format -Werror=return-local-addr -D M5S_WXBEACON2_TIMEZONE_LOCATION=\"Asia/Tokyo\" - -D M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC=60 - -D M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC=30 + -D M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC=300 + -D M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC=60 -D M5S_WXBEACON2_DEBUG_INFO -D GOB_JSON_LOG_LEVEL=5 - - ;-D M5S_WXBEACON2_AUTO_REQUEST_INTERVAL_SEC=300 - ; -D M5S_WXBEACON2_AUTO_TALK_INTERVAL_SEC=60 +;300,60 ; -------------------------------- ;Choose build options diff --git a/src/res/dummy_face.cpp b/src/res/dummy_face.cpp new file mode 100644 index 0000000..dc7cf86 --- /dev/null +++ b/src/res/dummy_face.cpp @@ -0,0 +1,3217 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t ponko_face_bmp[] = { + 0x42, 0x4d, 0x76, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x55, 0x55, 0x55, 0x00, 0x80, 0x80, 0x80, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, + 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, + 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, + 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x24, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x42, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 +}; +const size_t ponko_face_bmp_len = 38518; diff --git a/src/res/dummy_logo.cpp b/src/res/dummy_logo.cpp new file mode 100644 index 0000000..ef92ab8 --- /dev/null +++ b/src/res/dummy_logo.cpp @@ -0,0 +1,29 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t logo_bmp[] = { + 0x42, 0x4d, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, + 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x42, 0x47, + 0x52, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x03, 0xc0, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0x03, 0xff, 0xe0, 0x00, 0x3f, + 0xff, 0xe0, 0x03, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, + 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x71, 0xe2, 0x08, 0x08, 0x71, 0xe2, + 0x08, 0x00, 0x31, 0xe3, 0xc8, 0x00, 0x31, 0xe3, 0xcf, 0xf0, 0x31, 0x22, + 0x0f, 0xf0, 0x31, 0x22, 0x0f, 0xf0, 0x11, 0x22, 0x7f, 0xc0, 0x11, 0x22, + 0x7c, 0x00, 0x11, 0x22, 0x0c, 0x04, 0x11, 0x22, 0x08, 0x7c, 0x01, 0x23, + 0xf8, 0xfe, 0x01, 0x23, 0xf8, 0xfe, 0x00, 0x03, 0xf8, 0xfe, 0x00, 0x03, + 0xf8, 0x03, 0x00, 0x03, 0xf8, 0x03, 0x01, 0xe3, 0xfc, 0x03, 0x07, 0xff, + 0xff, 0xff, 0x07, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xe0, 0x03, 0xff, + 0xfe, 0x00, 0x03, 0xff, 0xe0, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x01, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +const size_t logo_bmp_len = 258; diff --git a/src/res/dummy_mc.cpp b/src/res/dummy_mc.cpp new file mode 100644 index 0000000..6886483 --- /dev/null +++ b/src/res/dummy_mc.cpp @@ -0,0 +1,81 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t ponko_mouth_close_bmp[] = { + 0x42, 0x4d, 0x76, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x55, 0x55, 0x55, 0x00, 0x80, 0x80, 0x80, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, + 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, + 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, + 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 +}; +const size_t ponko_mouth_close_bmp_len = 886; diff --git a/src/res/dummy_mo.cpp b/src/res/dummy_mo.cpp new file mode 100644 index 0000000..fee33e9 --- /dev/null +++ b/src/res/dummy_mo.cpp @@ -0,0 +1,81 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t ponko_mouth_open_bmp[] = { + 0x42, 0x4d, 0x76, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x55, 0x55, 0x55, 0x00, 0x80, 0x80, 0x80, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, + 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, + 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, + 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x34, 0x34, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x44, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x44, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x00, 0x00, 0x00, 0x44, + 0x44, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x00, 0x00, 0x44, + 0x44, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x00, 0x00, 0x44, + 0x44, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x00, 0x00, 0x44, + 0x44, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x00, 0x00, 0x44, + 0x44, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x00, 0x00, 0x44, + 0x44, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x00, 0x00, 0x44, + 0x44, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x00, 0x00, 0x44, + 0x44, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x44, 0x44, 0x00, 0x44, 0x44, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 +}; +const size_t ponko_mouth_open_bmp_len = 886; diff --git a/src/res/w100.cpp b/src/res/w100.cpp new file mode 100644 index 0000000..c7b06f0 --- /dev/null +++ b/src/res/w100.cpp @@ -0,0 +1,40 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w100_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x01, 0x03, 0x00, 0x00, 0x00, 0xa1, 0x9d, 0x6d, 0x77, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xff, 0xaa, 0x00, 0xbf, + 0xb2, 0xb3, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x00, + 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, + 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x24, 0xc9, 0x0b, 0x54, 0x4b, 0x00, + 0x00, 0x00, 0x48, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, + 0x01, 0xfb, 0xff, 0xff, 0xff, 0x30, 0xd4, 0xff, 0xff, 0xff, 0x0f, 0x4a, + 0xfc, 0xab, 0x07, 0x12, 0xf3, 0x2a, 0x81, 0x44, 0x5f, 0x21, 0x90, 0x38, + 0xfe, 0x18, 0x48, 0xbc, 0x2b, 0x07, 0x12, 0x7f, 0xec, 0x81, 0xc4, 0x0f, + 0x79, 0x20, 0x21, 0xc0, 0x01, 0x23, 0xc0, 0x5c, 0xb0, 0x04, 0x58, 0x09, + 0x58, 0x31, 0x58, 0x1b, 0xd8, 0x00, 0xb0, 0x51, 0x70, 0x93, 0xc1, 0x16, + 0x81, 0x00, 0x00, 0x8b, 0x53, 0x3e, 0x47, 0xdd, 0xc3, 0xf0, 0x13, 0x00, + 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, + 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x35, 0x3a, + 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, 0x0c, 0x82, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, + 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, + 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x34, + 0x3a, 0x33, 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xd2, 0xeb, 0x91, + 0xf9, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, + 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, + 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x36, 0x2b, 0x30, 0x30, 0x3a, 0x30, + 0x30, 0xb5, 0xa7, 0x05, 0x18, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, + 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w100_png_len = 389; diff --git a/src/res/w101.cpp b/src/res/w101.cpp new file mode 100644 index 0000000..f481977 --- /dev/null +++ b/src/res/w101.cpp @@ -0,0 +1,44 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w101_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xff, 0xaa, 0x00, 0xaa, + 0xaa, 0xaa, 0x16, 0x06, 0x43, 0x85, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x24, 0xc9, 0x0b, + 0x54, 0x4b, 0x00, 0x00, 0x00, 0x73, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x4d, 0xcf, 0x31, 0x0e, 0x80, 0x20, 0x0c, 0x05, 0xd0, 0x6f, 0x02, 0x89, + 0xa3, 0x8b, 0x77, 0x30, 0x9e, 0xc2, 0xae, 0x4c, 0x84, 0xd0, 0xfb, 0x18, + 0x4f, 0xe2, 0x48, 0x38, 0xa5, 0x6d, 0x05, 0xb1, 0xd3, 0x0b, 0x7c, 0x7e, + 0x03, 0xd0, 0xc7, 0xb3, 0x4d, 0xc4, 0xca, 0xa4, 0xc8, 0x3f, 0x78, 0xca, + 0xab, 0x61, 0xe2, 0xf8, 0x82, 0x28, 0xb6, 0x0c, 0x5a, 0xc6, 0x2c, 0xb3, + 0x2c, 0x70, 0xae, 0xd6, 0x32, 0xa0, 0x57, 0xd9, 0x20, 0xe1, 0x54, 0xaf, + 0xa2, 0xcf, 0x29, 0x55, 0x14, 0x2d, 0x3c, 0x52, 0xc1, 0xa6, 0x2b, 0x62, + 0x30, 0xc8, 0xd2, 0x70, 0x77, 0x9c, 0x98, 0x05, 0xcc, 0x3b, 0x1a, 0x36, + 0x8c, 0x13, 0x2d, 0x64, 0x29, 0x96, 0x66, 0xff, 0xe2, 0xfe, 0x7e, 0xf3, + 0x00, 0x45, 0x3c, 0x2f, 0x60, 0xa0, 0xa0, 0x5f, 0x89, 0x00, 0x00, 0x00, + 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, + 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, + 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, + 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, + 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, + 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, + 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xd2, 0xeb, 0x91, 0xf9, 0x00, + 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, + 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, + 0x32, 0x39, 0x3a, 0x33, 0x36, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb5, + 0xa7, 0x05, 0x18, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, + 0x42, 0x60, 0x82 +}; +const size_t w101_png_len = 435; diff --git a/src/res/w102.cpp b/src/res/w102.cpp new file mode 100644 index 0000000..5d9b93c --- /dev/null +++ b/src/res/w102.cpp @@ -0,0 +1,44 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w102_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xff, 0xaa, 0x00, 0x00, + 0x55, 0xff, 0x4a, 0xcc, 0xc3, 0x3a, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x24, 0xc9, 0x0b, + 0x54, 0x4b, 0x00, 0x00, 0x00, 0x73, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x4d, 0xcf, 0x3b, 0x0a, 0x80, 0x30, 0x10, 0x04, 0xd0, 0x11, 0x0c, 0x58, + 0xda, 0x78, 0x87, 0xe0, 0x29, 0xdc, 0xd6, 0x4a, 0x42, 0x72, 0x1f, 0xb1, + 0xf4, 0x14, 0x62, 0x15, 0xf6, 0x94, 0x66, 0xc7, 0xf8, 0x99, 0xea, 0xb1, + 0xd9, 0x0f, 0x01, 0x9e, 0xb8, 0xc4, 0x2c, 0x18, 0x92, 0x18, 0xe2, 0x0f, + 0x4e, 0x96, 0x1b, 0x4d, 0x9a, 0x6e, 0x88, 0x48, 0xed, 0x41, 0xed, 0xa1, + 0x4b, 0xfa, 0x1e, 0x6d, 0xab, 0x9a, 0x3f, 0xd8, 0x53, 0xd4, 0x2d, 0xb3, + 0x39, 0x28, 0x32, 0xc7, 0x43, 0x86, 0xe7, 0xc2, 0xb0, 0x1a, 0xca, 0x89, + 0x19, 0xe8, 0x78, 0x74, 0x66, 0xc5, 0xc0, 0xf1, 0xb2, 0x7f, 0xdc, 0x7d, + 0xc5, 0x5b, 0xf1, 0x27, 0x11, 0xd5, 0xe0, 0x0c, 0xaa, 0xc7, 0xfb, 0x9b, + 0x0b, 0xa6, 0xd2, 0x32, 0x7d, 0xd5, 0x85, 0xde, 0x44, 0x00, 0x00, 0x00, + 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, + 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, + 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, + 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, + 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, + 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, + 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xd2, 0xeb, 0x91, 0xf9, 0x00, + 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, + 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, + 0x32, 0x39, 0x3a, 0x33, 0x36, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb5, + 0xa7, 0x05, 0x18, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, + 0x42, 0x60, 0x82 +}; +const size_t w102_png_len = 435; diff --git a/src/res/w104.cpp b/src/res/w104.cpp new file mode 100644 index 0000000..239668b --- /dev/null +++ b/src/res/w104.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w104_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xff, 0xaa, 0x00, 0xaa, + 0xaa, 0xff, 0x0d, 0x07, 0xe6, 0xfe, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x24, 0xc9, 0x0b, + 0x54, 0x4b, 0x00, 0x00, 0x00, 0x6b, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x65, 0xcf, 0x3d, 0x0e, 0x80, 0x20, 0x0c, 0x05, 0xe0, 0x6a, 0x60, 0x71, + 0x62, 0xf1, 0x12, 0x9e, 0xc2, 0xae, 0x4c, 0xc4, 0xd0, 0xfb, 0x78, 0x14, + 0xc6, 0xa6, 0xa7, 0x94, 0xb6, 0xf8, 0x93, 0xf8, 0xa6, 0x2f, 0xf0, 0x4a, + 0x03, 0xc0, 0x9d, 0x48, 0x96, 0x02, 0x2b, 0xa1, 0xa2, 0x7e, 0x10, 0xb1, + 0x38, 0x26, 0xda, 0x1d, 0x88, 0x38, 0x3a, 0x30, 0x3a, 0xe6, 0x9e, 0x94, + 0x20, 0x04, 0x11, 0x7e, 0xa1, 0x57, 0x95, 0x17, 0xb6, 0xf2, 0xd1, 0x66, + 0xb6, 0x71, 0x47, 0x7f, 0xd0, 0xd1, 0x57, 0x64, 0xef, 0x20, 0x65, 0x3b, + 0x51, 0x9c, 0xa0, 0x20, 0xda, 0xfe, 0xf0, 0x0e, 0x55, 0xd1, 0xa9, 0xa8, + 0x10, 0x69, 0xcf, 0x6f, 0x2e, 0xfc, 0x52, 0x32, 0xf1, 0x86, 0xd6, 0x92, + 0x7d, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, + 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, + 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, + 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, + 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, + 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, + 0x32, 0x34, 0x3a, 0x33, 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xd2, + 0xeb, 0x91, 0xf9, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, + 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x36, 0x2b, 0x30, 0x30, + 0x3a, 0x30, 0x30, 0xb5, 0xa7, 0x05, 0x18, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w104_png_len = 427; diff --git a/src/res/w110.cpp b/src/res/w110.cpp new file mode 100644 index 0000000..6548d02 --- /dev/null +++ b/src/res/w110.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w110_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xff, 0xaa, 0x00, 0xaa, + 0xaa, 0xaa, 0x16, 0x06, 0x43, 0x85, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x24, 0xc9, 0x0b, + 0x54, 0x4b, 0x00, 0x00, 0x00, 0x67, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x63, 0x60, 0x80, 0x01, 0xd6, 0xd0, 0x50, 0xad, 0x55, 0xab, 0x56, 0x2d, + 0x60, 0x10, 0x85, 0x30, 0x56, 0x80, 0x18, 0x5e, 0x18, 0x8c, 0x20, 0x28, + 0x83, 0x15, 0xca, 0x60, 0x65, 0x65, 0x59, 0xb5, 0x82, 0x09, 0xc8, 0x70, + 0x0c, 0x11, 0x01, 0x6a, 0x06, 0x4b, 0x85, 0x6a, 0x2d, 0x60, 0xd0, 0x60, + 0x10, 0x0d, 0x61, 0x84, 0x30, 0x44, 0x04, 0x18, 0x1c, 0xbd, 0x1a, 0x60, + 0x0c, 0x06, 0xa8, 0x94, 0x06, 0x03, 0x03, 0x07, 0x58, 0xb1, 0x02, 0x98, + 0x01, 0xd4, 0xbe, 0x00, 0xcc, 0x00, 0x1a, 0xb8, 0x02, 0xac, 0x06, 0x6e, + 0x05, 0xc2, 0x52, 0x2c, 0xee, 0x81, 0x38, 0x15, 0xee, 0x78, 0x18, 0x00, + 0x00, 0x96, 0x8b, 0x39, 0x9d, 0x27, 0xed, 0xf7, 0x33, 0x00, 0x00, 0x00, + 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, + 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, + 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, + 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, + 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, + 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, + 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xd2, 0xeb, 0x91, 0xf9, 0x00, + 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, + 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, + 0x32, 0x39, 0x3a, 0x33, 0x36, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb5, + 0xa7, 0x05, 0x18, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, + 0x42, 0x60, 0x82 +}; +const size_t w110_png_len = 423; diff --git a/src/res/w112.cpp b/src/res/w112.cpp new file mode 100644 index 0000000..a2029a3 --- /dev/null +++ b/src/res/w112.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w112_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xff, 0xaa, 0x00, 0x00, + 0x55, 0xff, 0x4a, 0xcc, 0xc3, 0x3a, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x24, 0xc9, 0x0b, + 0x54, 0x4b, 0x00, 0x00, 0x00, 0x6d, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x65, 0x8e, 0xb1, 0x0d, 0xc0, 0x20, 0x0c, 0x04, 0x1d, 0x29, 0x96, 0x52, + 0xa6, 0x80, 0x1d, 0x22, 0xb6, 0xa0, 0x8b, 0x28, 0x11, 0xde, 0x27, 0x35, + 0x53, 0x50, 0x22, 0x4f, 0x19, 0x1b, 0x87, 0x34, 0x7c, 0x75, 0xd2, 0xbf, + 0xdf, 0x0f, 0x30, 0x85, 0x44, 0x81, 0x99, 0x1b, 0x78, 0x83, 0xae, 0x90, + 0x16, 0xc8, 0x12, 0x51, 0x40, 0x81, 0xe7, 0x02, 0x8f, 0xb8, 0x33, 0x83, + 0x40, 0x2c, 0x4e, 0x12, 0x87, 0x5a, 0x14, 0x9a, 0x42, 0xd9, 0x28, 0x68, + 0xb3, 0x3b, 0x21, 0xde, 0x13, 0x12, 0x68, 0x58, 0x2d, 0x2b, 0x94, 0x70, + 0xad, 0xdf, 0xf9, 0x80, 0x51, 0x68, 0x56, 0xee, 0xa2, 0xf1, 0x74, 0xc2, + 0xba, 0xc7, 0xa6, 0xfe, 0xe3, 0xa7, 0x5e, 0xc7, 0x55, 0x3c, 0x7b, 0x44, + 0x75, 0x3e, 0x6f, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, + 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, + 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, + 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, + 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, + 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, + 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, + 0x30, 0xd2, 0xeb, 0x91, 0xf9, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, + 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x36, 0x2b, + 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb5, 0xa7, 0x05, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w112_png_len = 429; diff --git a/src/res/w115.cpp b/src/res/w115.cpp new file mode 100644 index 0000000..6ab4d7f --- /dev/null +++ b/src/res/w115.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w115_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xff, 0xaa, 0x00, 0xaa, + 0xaa, 0xff, 0x0d, 0x07, 0xe6, 0xfe, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x24, 0xc9, 0x0b, + 0x54, 0x4b, 0x00, 0x00, 0x00, 0x6d, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x6d, 0x8e, 0xbb, 0x0d, 0x80, 0x30, 0x0c, 0x44, 0x0d, 0xc2, 0x0d, 0x15, + 0x45, 0xb2, 0x03, 0xca, 0x16, 0x69, 0x53, 0x46, 0xf1, 0x3e, 0x8c, 0x92, + 0x32, 0xf2, 0x94, 0xf8, 0x43, 0x68, 0xc0, 0xd5, 0x93, 0x7d, 0xe7, 0x3b, + 0x80, 0x39, 0x48, 0x94, 0x98, 0xb9, 0x43, 0x74, 0x18, 0x0a, 0xe5, 0x03, + 0x95, 0xc7, 0xae, 0x80, 0x95, 0xfb, 0x2a, 0x80, 0xb8, 0xf1, 0x05, 0x02, + 0xb9, 0x05, 0x07, 0x42, 0x4a, 0x06, 0x6d, 0xa1, 0xa4, 0x9a, 0x70, 0x40, + 0x2e, 0xea, 0x32, 0x30, 0x97, 0x9e, 0x5e, 0x31, 0xc0, 0x29, 0x7f, 0xc4, + 0xae, 0x10, 0xa2, 0x3c, 0xb4, 0x8d, 0x46, 0xb8, 0x86, 0x9e, 0xac, 0xbf, + 0x3e, 0x5e, 0xf5, 0x2d, 0x3f, 0xe7, 0x06, 0xe8, 0x30, 0x3a, 0x7a, 0xb4, + 0x50, 0xcc, 0xb5, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, + 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, + 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, + 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, + 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, + 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, + 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, + 0x30, 0xd2, 0xeb, 0x91, 0xf9, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, + 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x36, 0x2b, + 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb5, 0xa7, 0x05, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w115_png_len = 429; diff --git a/src/res/w200.cpp b/src/res/w200.cpp new file mode 100644 index 0000000..33e9e8b --- /dev/null +++ b/src/res/w200.cpp @@ -0,0 +1,35 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w200_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x88, 0xb8, 0x49, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x02, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x03, 0x33, + 0x84, 0x72, 0x88, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, + 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x24, 0xc9, 0x0b, 0x54, 0x4b, 0x00, 0x00, + 0x00, 0x4f, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x75, 0xcf, 0xb1, 0x0d, + 0xc0, 0x30, 0x08, 0x04, 0x40, 0xf6, 0x1f, 0x25, 0x14, 0x6c, 0x90, 0xec, + 0xc3, 0x08, 0x14, 0x7e, 0xfb, 0x8d, 0x89, 0x62, 0x4b, 0xf9, 0xea, 0x0a, + 0x5e, 0x80, 0x60, 0x45, 0xe2, 0x9a, 0x31, 0xf1, 0x84, 0xee, 0xb8, 0x17, + 0x14, 0x9e, 0x30, 0x44, 0xe2, 0x41, 0x2b, 0x20, 0x81, 0x5f, 0xd8, 0x80, + 0x13, 0x63, 0x16, 0x41, 0x70, 0x77, 0xfb, 0xc2, 0x36, 0x78, 0x81, 0x75, + 0x65, 0xe9, 0x3c, 0x6c, 0xe2, 0x3d, 0xbe, 0xde, 0xe9, 0xf5, 0x15, 0x9c, + 0x44, 0x62, 0xea, 0x30, 0xbf, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, + 0x31, 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, + 0x30, 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, + 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, + 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, + 0x54, 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, 0x31, 0x2b, 0x30, 0x30, + 0x3a, 0x30, 0x30, 0xd2, 0xeb, 0x91, 0xf9, 0x00, 0x00, 0x00, 0x28, 0x74, + 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, + 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, + 0x36, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb5, 0xa7, 0x05, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w200_png_len = 335; diff --git a/src/res/w201.cpp b/src/res/w201.cpp new file mode 100644 index 0000000..08b4b40 --- /dev/null +++ b/src/res/w201.cpp @@ -0,0 +1,44 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w201_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0xff, + 0xaa, 0x00, 0x34, 0xe7, 0x85, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x24, 0xc9, 0x0b, + 0x54, 0x4b, 0x00, 0x00, 0x00, 0x72, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x6d, 0xcf, 0x3d, 0x0a, 0x80, 0x30, 0x0c, 0x05, 0xe0, 0x67, 0x41, 0x90, + 0x4e, 0x22, 0x75, 0x77, 0x2c, 0x3d, 0x85, 0xa3, 0x38, 0x15, 0xa9, 0x97, + 0xf2, 0x14, 0x8e, 0x21, 0xa7, 0x34, 0x89, 0xb4, 0x38, 0x98, 0xe9, 0x23, + 0x3f, 0xaf, 0x14, 0xa8, 0xd5, 0x9f, 0x56, 0x19, 0xf3, 0x8b, 0xf2, 0x45, + 0xae, 0xb0, 0x35, 0x41, 0x41, 0xf7, 0x03, 0xcd, 0x11, 0xa0, 0x30, 0x13, + 0xe6, 0x15, 0x08, 0x06, 0xe9, 0x86, 0x94, 0x22, 0x82, 0x60, 0xf2, 0x31, + 0x62, 0x54, 0x5c, 0x44, 0x86, 0x83, 0x3c, 0xe9, 0xa8, 0xdb, 0x6f, 0x47, + 0xf6, 0xe8, 0xb6, 0xb8, 0xc1, 0xd0, 0x3a, 0x49, 0x77, 0x0c, 0x7a, 0x65, + 0xd0, 0x1c, 0x41, 0x61, 0x4d, 0xee, 0x15, 0xcc, 0x77, 0xfb, 0xcd, 0x03, + 0xea, 0x17, 0x2c, 0x73, 0xaf, 0xc2, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x25, + 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, + 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, 0x2b, + 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, 0x00, + 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, + 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, + 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, 0x31, + 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xd2, 0xeb, 0x91, 0xf9, 0x00, 0x00, + 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, + 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, + 0x39, 0x3a, 0x33, 0x36, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb5, 0xa7, + 0x05, 0x18, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, + 0x60, 0x82 +}; +const size_t w201_png_len = 434; diff --git a/src/res/w202.cpp b/src/res/w202.cpp new file mode 100644 index 0000000..16c4ef7 --- /dev/null +++ b/src/res/w202.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w202_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x00, + 0x55, 0xff, 0x34, 0x59, 0xa3, 0x1f, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x24, 0xc9, 0x0b, + 0x54, 0x4b, 0x00, 0x00, 0x00, 0x6b, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x6d, 0xcf, 0x3d, 0x0a, 0xc0, 0x20, 0x0c, 0x06, 0xd0, 0xcf, 0xa1, 0xd0, + 0xb1, 0x14, 0xbd, 0x83, 0x78, 0x8a, 0xce, 0x4e, 0x52, 0xec, 0x7d, 0xa4, + 0x27, 0x91, 0x4e, 0x92, 0x53, 0x36, 0x89, 0x28, 0x1d, 0x9a, 0xe9, 0x91, + 0x5f, 0x02, 0x8c, 0x70, 0x97, 0x46, 0x1a, 0xc8, 0x5f, 0xa4, 0x01, 0x2c, + 0x1d, 0x19, 0xe6, 0x07, 0xba, 0x27, 0x01, 0x99, 0xa8, 0xc1, 0x1d, 0x03, + 0x9c, 0xb5, 0x84, 0x06, 0xcb, 0xd8, 0x05, 0x9b, 0xa0, 0xc2, 0x2b, 0xce, + 0xc2, 0xe0, 0x92, 0x89, 0x60, 0xc8, 0xd1, 0x58, 0xb8, 0x47, 0xa1, 0xe3, + 0x8c, 0x70, 0xaf, 0xbd, 0x14, 0x66, 0xc6, 0x3f, 0x8a, 0x4c, 0x82, 0x45, + 0x40, 0x54, 0xe7, 0x37, 0x2f, 0x62, 0x62, 0x2e, 0xe1, 0xbc, 0x18, 0x37, + 0x17, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, + 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, + 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, + 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, + 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, + 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, + 0x32, 0x34, 0x3a, 0x33, 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xd2, + 0xeb, 0x91, 0xf9, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, + 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x36, 0x2b, 0x30, 0x30, + 0x3a, 0x30, 0x30, 0xb5, 0xa7, 0x05, 0x18, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w202_png_len = 427; diff --git a/src/res/w204.cpp b/src/res/w204.cpp new file mode 100644 index 0000000..5f125f8 --- /dev/null +++ b/src/res/w204.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w204_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xff, 0x73, 0x92, 0x86, 0xdb, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x24, 0xc9, 0x0b, + 0x54, 0x4b, 0x00, 0x00, 0x00, 0x68, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x65, 0xcf, 0x31, 0x0e, 0x80, 0x20, 0x0c, 0x05, 0xd0, 0x8f, 0x09, 0x8b, + 0x93, 0x31, 0x70, 0x09, 0x4f, 0xe1, 0xcc, 0x44, 0x0c, 0xde, 0xc7, 0xa3, + 0x30, 0x36, 0x3d, 0xa5, 0x6d, 0x11, 0x25, 0xb1, 0xd3, 0xcb, 0xe7, 0xd3, + 0xa4, 0x40, 0x1f, 0x7f, 0xda, 0x64, 0xc4, 0x86, 0x32, 0x22, 0x77, 0x58, + 0x28, 0x28, 0xd6, 0x37, 0xb8, 0x0f, 0xba, 0x27, 0x66, 0xa0, 0x30, 0x13, + 0xe2, 0xde, 0x21, 0x69, 0xa0, 0x99, 0x10, 0x04, 0x6b, 0x9d, 0x08, 0xcb, + 0x88, 0x43, 0x21, 0x4f, 0x2e, 0x69, 0x47, 0xf7, 0x27, 0x4d, 0x0c, 0x17, + 0x1a, 0xb6, 0x3f, 0x9e, 0x4e, 0x61, 0xfd, 0xe5, 0x15, 0xcc, 0xf5, 0xbd, + 0xe6, 0x06, 0xe7, 0xee, 0x2f, 0xeb, 0x4a, 0x5c, 0x95, 0x51, 0x00, 0x00, + 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, + 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, + 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, + 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, + 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, + 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, + 0x33, 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xd2, 0xeb, 0x91, 0xf9, + 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, + 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, + 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, + 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x36, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, + 0xb5, 0xa7, 0x05, 0x18, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, + 0xae, 0x42, 0x60, 0x82 +}; +const size_t w204_png_len = 424; diff --git a/src/res/w210.cpp b/src/res/w210.cpp new file mode 100644 index 0000000..3ed08c9 --- /dev/null +++ b/src/res/w210.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w210_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0xff, + 0xaa, 0x00, 0x34, 0xe7, 0x85, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x6b, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x65, 0xce, 0x31, 0x0e, 0xc0, 0x20, 0x08, 0x05, 0x50, 0x6a, 0x62, 0xd2, + 0x74, 0xea, 0x50, 0xf6, 0x8e, 0xc4, 0xa3, 0x38, 0x99, 0x46, 0xef, 0xe3, + 0x51, 0x1c, 0x09, 0xa7, 0x2c, 0x4a, 0xac, 0x43, 0x99, 0x5e, 0x04, 0xe4, + 0x03, 0xcc, 0xf2, 0xa5, 0x44, 0x11, 0x69, 0x80, 0x06, 0xee, 0x78, 0x7e, + 0xc8, 0xc2, 0xc1, 0xd0, 0x38, 0xec, 0x0a, 0x28, 0x37, 0x91, 0x22, 0x03, + 0x52, 0x60, 0x02, 0x4c, 0x80, 0xb1, 0x1d, 0x6c, 0xa8, 0x6e, 0xc0, 0xa7, + 0xea, 0x74, 0x06, 0x16, 0xb6, 0xd1, 0xba, 0x3a, 0xfa, 0xf0, 0xa9, 0xad, + 0xb1, 0xae, 0x2f, 0x68, 0x1f, 0xae, 0x13, 0xeb, 0xe8, 0x3f, 0x8f, 0x45, + 0xfd, 0xc2, 0xcf, 0x7a, 0x01, 0x43, 0xd4, 0x37, 0x17, 0x09, 0xcb, 0xf9, + 0x80, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, + 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, + 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, + 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, + 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, + 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, + 0x32, 0x34, 0x3a, 0x33, 0x31, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xd2, + 0xeb, 0x91, 0xf9, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, + 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x37, 0x2b, 0x30, 0x30, + 0x3a, 0x30, 0x30, 0x13, 0xd0, 0x0e, 0xac, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w210_png_len = 427; diff --git a/src/res/w212.cpp b/src/res/w212.cpp new file mode 100644 index 0000000..5d1747b --- /dev/null +++ b/src/res/w212.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w212_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0x00, + 0x55, 0xff, 0x34, 0x59, 0xa3, 0x1f, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x6e, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x65, 0xce, 0x31, 0x0a, 0xc0, 0x20, 0x10, 0x04, 0xc0, 0x0d, 0x44, 0x48, + 0x99, 0x42, 0xff, 0x20, 0xfe, 0x22, 0x5d, 0xb0, 0x0a, 0x41, 0xff, 0x93, + 0xda, 0x57, 0x58, 0xca, 0xbd, 0x32, 0xab, 0xa2, 0x10, 0xb2, 0xd5, 0x70, + 0x1c, 0x77, 0x0b, 0x8c, 0xa8, 0x18, 0x9d, 0x88, 0x64, 0x98, 0x8e, 0x52, + 0xe1, 0x7f, 0xb8, 0xb9, 0x52, 0x71, 0x10, 0x8f, 0x25, 0x10, 0x44, 0xb0, + 0xc1, 0x04, 0x68, 0x6e, 0x10, 0x17, 0x8c, 0xcb, 0x3c, 0xd8, 0x80, 0x0e, + 0x75, 0x36, 0xf0, 0x8b, 0x07, 0x6c, 0x83, 0xab, 0x07, 0x35, 0xb0, 0xb8, + 0x94, 0x2c, 0x76, 0x60, 0x95, 0x0a, 0x4e, 0xf4, 0xfc, 0x55, 0x98, 0x0f, + 0xfe, 0x7d, 0x7a, 0xd5, 0x59, 0x7e, 0xe4, 0x05, 0x11, 0x7f, 0x3a, 0x6b, + 0xf2, 0xb5, 0x05, 0x36, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, + 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, + 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, + 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, + 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, + 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, + 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, 0x31, 0x2b, 0x30, 0x30, 0x3a, + 0x30, 0x30, 0xd2, 0xeb, 0x91, 0xf9, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, + 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, + 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x37, + 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x13, 0xd0, 0x0e, 0xac, 0x00, 0x00, + 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w212_png_len = 430; diff --git a/src/res/w215.cpp b/src/res/w215.cpp new file mode 100644 index 0000000..e1ea03f --- /dev/null +++ b/src/res/w215.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w215_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xff, 0x73, 0x92, 0x86, 0xdb, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x69, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x6d, 0xce, 0x31, 0x0e, 0x80, 0x20, 0x0c, 0x05, 0xd0, 0xaf, 0x91, 0xc5, + 0xc9, 0x01, 0xee, 0x60, 0xb8, 0x85, 0x2b, 0x13, 0x21, 0x70, 0x1f, 0x8f, + 0xc2, 0x48, 0x7a, 0x4a, 0x69, 0x2b, 0x2c, 0xda, 0xe9, 0x85, 0x96, 0xfc, + 0x0f, 0x8c, 0x31, 0xa5, 0x78, 0x22, 0xaa, 0x70, 0x8a, 0xc6, 0x08, 0x1f, + 0x24, 0x6a, 0x3b, 0xe3, 0x4a, 0x54, 0x57, 0x06, 0x32, 0xdd, 0xe8, 0xc8, + 0xb0, 0x8a, 0x08, 0xe7, 0x27, 0xe4, 0x26, 0xc2, 0x04, 0xf9, 0xd5, 0x53, + 0x82, 0xac, 0x80, 0xc5, 0x03, 0x27, 0xec, 0xc0, 0x01, 0x6c, 0xf4, 0xbe, + 0x58, 0x81, 0x64, 0xc9, 0x31, 0x43, 0xb3, 0x7e, 0xfa, 0x68, 0xd5, 0x59, + 0x7e, 0xcc, 0x03, 0xeb, 0xc8, 0x37, 0x99, 0x0a, 0x97, 0x6b, 0xcf, 0x00, + 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, + 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x35, 0x3a, + 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, 0x0c, 0x82, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, + 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, + 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x34, + 0x3a, 0x33, 0x32, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xe3, 0x03, 0x8b, + 0x64, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, + 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, + 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x37, 0x2b, 0x30, 0x30, 0x3a, 0x30, + 0x30, 0x13, 0xd0, 0x0e, 0xac, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, + 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w215_png_len = 425; diff --git a/src/res/w300.cpp b/src/res/w300.cpp new file mode 100644 index 0000000..ed94f8b --- /dev/null +++ b/src/res/w300.cpp @@ -0,0 +1,40 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w300_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x01, 0x03, 0x00, 0x00, 0x00, 0xa1, 0x9d, 0x6d, 0x77, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x55, 0xff, 0xbf, + 0x0c, 0x95, 0xe2, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x00, + 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, + 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, 0x64, 0xdd, 0x00, + 0x00, 0x00, 0x47, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, + 0x01, 0xfb, 0xff, 0xff, 0xff, 0x30, 0xd4, 0xff, 0xff, 0xff, 0x0f, 0x48, + 0xb4, 0x83, 0x08, 0x66, 0x20, 0xf1, 0x8f, 0x11, 0x48, 0xfc, 0x01, 0x11, + 0x0f, 0x18, 0x80, 0xc4, 0x01, 0x10, 0xd1, 0xc0, 0x50, 0x07, 0x84, 0x0c, + 0x76, 0x0c, 0x35, 0x20, 0x02, 0xc8, 0xaa, 0x83, 0x6a, 0x3b, 0x73, 0x06, + 0x85, 0x00, 0x8b, 0x19, 0x1b, 0xa3, 0x10, 0x20, 0x31, 0xb0, 0x45, 0x20, + 0x00, 0x00, 0xa5, 0x97, 0x36, 0x48, 0x27, 0xcc, 0xec, 0x47, 0x00, 0x00, + 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, + 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, + 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, + 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, + 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, + 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, + 0x33, 0x32, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xe3, 0x03, 0x8b, 0x64, + 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, + 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, + 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, + 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x37, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, + 0x13, 0xd0, 0x0e, 0xac, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, + 0xae, 0x42, 0x60, 0x82 +}; +const size_t w300_png_len = 388; diff --git a/src/res/w301.cpp b/src/res/w301.cpp new file mode 100644 index 0000000..095aa9a --- /dev/null +++ b/src/res/w301.cpp @@ -0,0 +1,44 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w301_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x55, 0xff, 0xff, + 0xaa, 0x00, 0xba, 0xd7, 0x8f, 0x99, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x72, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x4d, 0xcf, 0x31, 0x0a, 0xc0, 0x20, 0x0c, 0x05, 0xd0, 0x54, 0x10, 0x4a, + 0x67, 0xdd, 0x3b, 0x8a, 0xa7, 0x70, 0x29, 0x94, 0x4e, 0x2a, 0xf6, 0x52, + 0x3d, 0x85, 0xa3, 0xe4, 0x94, 0x35, 0x89, 0x96, 0x06, 0x02, 0x0f, 0x93, + 0x7c, 0x10, 0x60, 0x96, 0xbe, 0xb9, 0x22, 0x58, 0x41, 0xf9, 0x23, 0xea, + 0x81, 0xb0, 0x0c, 0x00, 0x08, 0xc2, 0x44, 0x8f, 0xa0, 0x06, 0x43, 0x8d, + 0xd8, 0x18, 0x85, 0x40, 0x39, 0xc5, 0x7b, 0x07, 0x36, 0x1d, 0x26, 0x6f, + 0x6e, 0xe0, 0x69, 0x32, 0xca, 0x6d, 0xeb, 0x30, 0xe9, 0xb8, 0xaa, 0x12, + 0x9c, 0xbb, 0x5a, 0x79, 0x24, 0x2f, 0x1d, 0x9e, 0x77, 0x08, 0xf3, 0xca, + 0x73, 0x4e, 0x0f, 0x46, 0x4a, 0xd6, 0x04, 0xc4, 0xfa, 0xfd, 0xe6, 0x05, + 0xea, 0x61, 0x2f, 0x91, 0x36, 0xbb, 0x42, 0x8c, 0x00, 0x00, 0x00, 0x25, + 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, + 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, 0x2b, + 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, 0x00, + 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, + 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, + 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, 0x32, + 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xe3, 0x03, 0x8b, 0x64, 0x00, 0x00, + 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, + 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, + 0x39, 0x3a, 0x33, 0x37, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x13, 0xd0, + 0x0e, 0xac, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, + 0x60, 0x82 +}; +const size_t w301_png_len = 434; diff --git a/src/res/w302.cpp b/src/res/w302.cpp new file mode 100644 index 0000000..af39aad --- /dev/null +++ b/src/res/w302.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w302_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x55, 0xff, 0xaa, + 0xaa, 0xaa, 0xe6, 0xa3, 0x29, 0x34, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x6e, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x4d, 0xcf, 0x3b, 0x0a, 0x80, 0x30, 0x0c, 0x06, 0xe0, 0x5f, 0xb1, 0x20, + 0x4e, 0x0e, 0xe9, 0x1d, 0x8a, 0xa7, 0x70, 0x71, 0x71, 0x6a, 0x4b, 0xbd, + 0x8f, 0x47, 0x71, 0x94, 0x9e, 0x52, 0xf3, 0xf0, 0x91, 0x21, 0x7c, 0x24, + 0xe4, 0x87, 0x00, 0x4f, 0xb9, 0x4d, 0x2a, 0xc2, 0x2b, 0xca, 0x1f, 0xc5, + 0x19, 0x62, 0x63, 0x98, 0xa1, 0x88, 0x30, 0xcc, 0x80, 0xe7, 0x1c, 0x6e, + 0x5d, 0xad, 0x27, 0xc6, 0x07, 0x74, 0x83, 0x18, 0x1c, 0x98, 0xeb, 0x70, + 0x23, 0x2d, 0x94, 0xcf, 0xd6, 0x70, 0x40, 0x57, 0xab, 0x80, 0xd2, 0xb2, + 0xee, 0x1f, 0x82, 0xac, 0x26, 0xa0, 0x17, 0x04, 0x7c, 0x13, 0xb9, 0x2a, + 0x95, 0x93, 0x9d, 0xe2, 0x78, 0xbf, 0xb9, 0x00, 0x33, 0xd2, 0x2f, 0x9e, + 0x1a, 0x44, 0xb8, 0x85, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, + 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, + 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, + 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, + 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, + 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, + 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, 0x32, 0x2b, 0x30, 0x30, 0x3a, + 0x30, 0x30, 0xe3, 0x03, 0x8b, 0x64, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, + 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, + 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x37, + 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x13, 0xd0, 0x0e, 0xac, 0x00, 0x00, + 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w302_png_len = 430; diff --git a/src/res/w303.cpp b/src/res/w303.cpp new file mode 100644 index 0000000..d77da69 --- /dev/null +++ b/src/res/w303.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w303_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x55, 0xff, 0xaa, + 0xaa, 0xff, 0xfd, 0xa2, 0x8c, 0x4f, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x6c, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x63, 0x60, 0x80, 0x01, 0xd6, 0x50, 0x30, 0x08, 0x60, 0x10, 0x85, 0x30, + 0x42, 0xb0, 0x32, 0x02, 0x58, 0xa1, 0x0c, 0x07, 0x46, 0x28, 0x83, 0x81, + 0x01, 0xc2, 0x70, 0x00, 0x32, 0x40, 0xe6, 0x88, 0x02, 0xb1, 0xc8, 0xaa, + 0x55, 0x2b, 0x18, 0x44, 0x80, 0x0c, 0x16, 0x10, 0x43, 0x00, 0x24, 0xb2, + 0x82, 0x0b, 0x22, 0x12, 0xb4, 0x80, 0x69, 0x05, 0xd8, 0x40, 0x08, 0x23, + 0xd0, 0x55, 0x04, 0xce, 0xf0, 0x02, 0xa9, 0x01, 0x49, 0x79, 0x81, 0x45, + 0x44, 0x02, 0x5d, 0xbd, 0x1a, 0x18, 0x20, 0x0c, 0x2d, 0x30, 0x03, 0x28, + 0x85, 0x60, 0x40, 0xcd, 0x09, 0x59, 0x05, 0xd2, 0xc5, 0x0a, 0x62, 0xac, + 0x5a, 0xb5, 0x00, 0xee, 0x1b, 0x00, 0x7b, 0x80, 0x31, 0x65, 0x50, 0x27, + 0x92, 0xce, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, + 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, + 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, + 0x32, 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, + 0x31, 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, + 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, + 0x3a, 0x32, 0x34, 0x3a, 0x33, 0x32, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, + 0xe3, 0x03, 0x8b, 0x64, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, + 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, + 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x37, 0x2b, 0x30, + 0x30, 0x3a, 0x30, 0x30, 0x13, 0xd0, 0x0e, 0xac, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w303_png_len = 428; diff --git a/src/res/w308.cpp b/src/res/w308.cpp new file mode 100644 index 0000000..31bafac --- /dev/null +++ b/src/res/w308.cpp @@ -0,0 +1,40 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w308_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x01, 0x03, 0x00, 0x00, 0x00, 0xa1, 0x9d, 0x6d, 0x77, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x55, 0xaa, 0xa4, + 0x0d, 0x30, 0x99, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x00, + 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, + 0x07, 0xe6, 0x0c, 0x16, 0x09, 0x10, 0x19, 0x9d, 0x33, 0x36, 0x63, 0x00, + 0x00, 0x00, 0x46, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, + 0x01, 0xfb, 0xff, 0xff, 0xff, 0x30, 0xd4, 0xff, 0x3f, 0xff, 0x0f, 0x48, + 0x30, 0x03, 0x89, 0x7f, 0x8c, 0x40, 0xe2, 0x0f, 0x03, 0x90, 0x68, 0x00, + 0x11, 0x0c, 0x0c, 0x76, 0x0c, 0x35, 0x20, 0xa2, 0x8e, 0x01, 0x88, 0xea, + 0xff, 0xff, 0xff, 0x07, 0x25, 0x8c, 0x8d, 0x81, 0x62, 0x69, 0x69, 0x75, + 0x0c, 0x75, 0xef, 0xde, 0xfd, 0x23, 0x46, 0x02, 0x6c, 0x11, 0x08, 0x00, + 0x00, 0x40, 0xd9, 0x37, 0x0a, 0x39, 0xc5, 0x43, 0x25, 0x00, 0x00, 0x00, + 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, + 0x2d, 0x32, 0x32, 0x54, 0x30, 0x39, 0x3a, 0x31, 0x35, 0x3a, 0x33, 0x32, + 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xd9, 0xa1, 0x2f, 0xc7, 0x00, 0x00, + 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, + 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, + 0x32, 0x2d, 0x32, 0x32, 0x54, 0x30, 0x39, 0x3a, 0x31, 0x35, 0x3a, 0x33, + 0x32, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xa8, 0xfc, 0x97, 0x7b, 0x00, + 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, + 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x32, 0x54, 0x30, 0x39, 0x3a, + 0x31, 0x36, 0x3a, 0x32, 0x35, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x1d, + 0xd3, 0x33, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, + 0x42, 0x60, 0x82 +}; +const size_t w308_png_len = 387; diff --git a/src/res/w311.cpp b/src/res/w311.cpp new file mode 100644 index 0000000..acdaebe --- /dev/null +++ b/src/res/w311.cpp @@ -0,0 +1,44 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w311_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x55, 0xff, 0xff, + 0xaa, 0x00, 0xba, 0xd7, 0x8f, 0x99, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x77, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x65, 0x8e, 0x3b, 0x0e, 0x80, 0x30, 0x0c, 0x43, 0x0d, 0x02, 0x09, 0x31, + 0x31, 0x34, 0x77, 0xa8, 0x72, 0x0a, 0x18, 0x58, 0xd8, 0x40, 0xcd, 0x7d, + 0x38, 0x4a, 0xc7, 0xaa, 0xa7, 0x24, 0xfd, 0x31, 0x80, 0xa7, 0x27, 0xd9, + 0x71, 0x0c, 0x34, 0x8d, 0x22, 0x1c, 0x63, 0xf4, 0xa0, 0x02, 0x21, 0xc1, + 0xf1, 0x85, 0xed, 0x8a, 0x81, 0x13, 0xe0, 0xf2, 0x81, 0x27, 0x90, 0x83, + 0xf1, 0xd6, 0x66, 0x18, 0xd4, 0xb1, 0xa0, 0x15, 0x23, 0xfb, 0x59, 0x33, + 0x40, 0xc7, 0x77, 0x1f, 0xb0, 0x28, 0xac, 0x77, 0x3f, 0xc1, 0x40, 0xdd, + 0x04, 0x5a, 0x28, 0xd9, 0xa2, 0x9d, 0xa8, 0x84, 0x77, 0x32, 0xe5, 0x5c, + 0xc4, 0xe5, 0x42, 0xe3, 0xce, 0xf2, 0x22, 0x41, 0x7d, 0xfa, 0xdf, 0x53, + 0xa7, 0xbe, 0xe3, 0x9b, 0x1e, 0x9f, 0x9d, 0x38, 0xfe, 0xd2, 0xeb, 0xdf, + 0x75, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, + 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, + 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, + 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, + 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, + 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, + 0x32, 0x34, 0x3a, 0x33, 0x32, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xe3, + 0x03, 0x8b, 0x64, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, + 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x37, 0x2b, 0x30, 0x30, + 0x3a, 0x30, 0x30, 0x13, 0xd0, 0x0e, 0xac, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w311_png_len = 439; diff --git a/src/res/w313.cpp b/src/res/w313.cpp new file mode 100644 index 0000000..025388d --- /dev/null +++ b/src/res/w313.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w313_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x55, 0xff, 0xaa, + 0xaa, 0xaa, 0xe6, 0xa3, 0x29, 0x34, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x6b, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x6d, 0xce, 0xbb, 0x0d, 0x80, 0x30, 0x0c, 0x04, 0xd0, 0x03, 0x29, 0x12, + 0x03, 0xc4, 0x3b, 0x44, 0x99, 0x02, 0x0a, 0x9a, 0x74, 0xa0, 0x78, 0x1f, + 0x46, 0x49, 0x19, 0x79, 0x4a, 0xf2, 0x71, 0x52, 0x20, 0x5c, 0x3d, 0x59, + 0xd6, 0xf9, 0x80, 0x31, 0x86, 0xd9, 0x8b, 0x48, 0x02, 0x75, 0xe4, 0x8a, + 0xf0, 0xc5, 0x71, 0x2b, 0xa0, 0x88, 0xb0, 0x22, 0xab, 0x22, 0xa3, 0x60, + 0x87, 0xf1, 0x09, 0x0e, 0x04, 0x2c, 0x0d, 0xb6, 0x20, 0x3c, 0x7d, 0x43, + 0x01, 0xd8, 0x6a, 0x20, 0xbb, 0x86, 0x93, 0x68, 0xc0, 0x26, 0xd4, 0x1b, + 0xe6, 0x98, 0x51, 0x72, 0x6c, 0xbc, 0xfa, 0x8b, 0x89, 0xbf, 0x3e, 0x5a, + 0x75, 0x96, 0x1f, 0xf3, 0x02, 0x42, 0x55, 0x39, 0x9f, 0x4b, 0x6f, 0x67, + 0xae, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, + 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, + 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, + 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, + 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, + 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, + 0x32, 0x34, 0x3a, 0x33, 0x32, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xe3, + 0x03, 0x8b, 0x64, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, + 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x37, 0x2b, 0x30, 0x30, + 0x3a, 0x30, 0x30, 0x13, 0xd0, 0x0e, 0xac, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w313_png_len = 427; diff --git a/src/res/w314.cpp b/src/res/w314.cpp new file mode 100644 index 0000000..6ef237e --- /dev/null +++ b/src/res/w314.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w314_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x55, 0xff, 0xaa, + 0xaa, 0xff, 0xfd, 0xa2, 0x8c, 0x4f, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x6e, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x65, 0xce, 0x31, 0x0e, 0x80, 0x20, 0x0c, 0x05, 0xd0, 0x1f, 0x13, 0x17, + 0x66, 0xb8, 0x83, 0xe1, 0x14, 0x3a, 0xb8, 0xb0, 0x49, 0xe8, 0x7d, 0x3c, + 0x0a, 0x23, 0xe9, 0x29, 0x85, 0x0f, 0x18, 0x13, 0x3b, 0xbd, 0xa1, 0xbf, + 0xfd, 0xc0, 0x9c, 0x55, 0xc4, 0xab, 0x6a, 0x86, 0xeb, 0x28, 0x0d, 0x66, + 0x22, 0x0c, 0x1c, 0x51, 0x8b, 0x69, 0x40, 0xd4, 0xbc, 0x54, 0x24, 0x58, + 0xbd, 0xf1, 0xc5, 0x8e, 0xd5, 0x13, 0xf5, 0xa6, 0x6f, 0x3b, 0xb6, 0x22, + 0x30, 0x05, 0xb8, 0xc0, 0x94, 0xd4, 0x1f, 0xdc, 0x39, 0x9d, 0xf5, 0xc0, + 0x46, 0x28, 0x21, 0x92, 0x08, 0x9b, 0xae, 0xc8, 0x83, 0xc4, 0x48, 0x85, + 0x5f, 0xb1, 0x5e, 0xf5, 0x2d, 0x3f, 0xe7, 0x01, 0x4a, 0xbd, 0x39, 0x9e, + 0x97, 0x78, 0x83, 0x47, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, + 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, + 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, + 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, + 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, + 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, + 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, 0x32, 0x2b, 0x30, 0x30, 0x3a, + 0x30, 0x30, 0xe3, 0x03, 0x8b, 0x64, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, + 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, + 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x37, + 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x13, 0xd0, 0x0e, 0xac, 0x00, 0x00, + 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w314_png_len = 430; diff --git a/src/res/w400.cpp b/src/res/w400.cpp new file mode 100644 index 0000000..1c7b962 --- /dev/null +++ b/src/res/w400.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w400_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x01, 0x03, 0x00, 0x00, 0x00, 0xa1, 0x9d, 0x6d, 0x77, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xff, 0xf8, + 0xc7, 0xb0, 0x26, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x00, + 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, + 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, 0x64, 0xdd, 0x00, + 0x00, 0x00, 0x6b, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, + 0x01, 0xfb, 0xff, 0xff, 0xff, 0x30, 0x64, 0xff, 0xff, 0x7f, 0x8d, 0xa1, + 0xe8, 0x8f, 0xbd, 0x1f, 0x83, 0xe3, 0x0f, 0xf9, 0x26, 0x86, 0x84, 0x0f, + 0xfc, 0x6c, 0x0c, 0xc1, 0x0f, 0xd8, 0x4f, 0x31, 0x94, 0x3e, 0x60, 0x5f, + 0xc7, 0x50, 0xff, 0x80, 0xfd, 0x1f, 0x43, 0xfd, 0x07, 0x7e, 0x20, 0xf1, + 0x43, 0x1e, 0x48, 0xfc, 0xb1, 0x87, 0xb1, 0xc0, 0x62, 0x60, 0xd9, 0x03, + 0xcc, 0xff, 0x18, 0x4a, 0x0f, 0x30, 0xaf, 0x63, 0x08, 0x3e, 0xc0, 0x7c, + 0x8a, 0x21, 0xe1, 0x00, 0x33, 0x1b, 0x83, 0xe3, 0x03, 0xf6, 0x26, 0x86, + 0xa2, 0x0f, 0xfc, 0x7e, 0x0c, 0xd9, 0x3f, 0xe4, 0xaf, 0x41, 0x2c, 0x02, + 0x01, 0x00, 0xe9, 0x6e, 0x31, 0x8a, 0x08, 0x88, 0x03, 0x62, 0x00, 0x00, + 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, + 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, + 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, + 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, + 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, + 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, + 0x33, 0x32, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xe3, 0x03, 0x8b, 0x64, + 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, + 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, + 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, + 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x37, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, + 0x13, 0xd0, 0x0e, 0xac, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, + 0xae, 0x42, 0x60, 0x82 +}; +const size_t w400_png_len = 424; diff --git a/src/res/w401.cpp b/src/res/w401.cpp new file mode 100644 index 0000000..d9286c1 --- /dev/null +++ b/src/res/w401.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w401_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xff, 0xff, + 0xaa, 0x00, 0xc8, 0x34, 0x7a, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x70, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x5d, 0x8f, 0x3d, 0x0a, 0x80, 0x30, 0x0c, 0x85, 0x63, 0xa1, 0x20, 0xdd, + 0xdd, 0x1d, 0x4b, 0x4e, 0xe1, 0x28, 0x4e, 0x52, 0xe2, 0xa5, 0x3c, 0x45, + 0xc7, 0x92, 0x53, 0x9a, 0xbe, 0xa8, 0x88, 0x99, 0x3e, 0x92, 0xf7, 0x43, + 0x88, 0x9e, 0x89, 0x07, 0x66, 0xa7, 0xc9, 0x41, 0x3e, 0x20, 0x74, 0x83, + 0x5f, 0x0d, 0x16, 0xe8, 0xff, 0xd0, 0x73, 0x3a, 0x88, 0x6a, 0x83, 0xd8, + 0xc1, 0xec, 0xc2, 0x9c, 0xb1, 0x29, 0x29, 0x67, 0x68, 0xca, 0xd9, 0xec, + 0x44, 0x34, 0x94, 0x96, 0x1c, 0xb6, 0x1a, 0x1c, 0xd6, 0x39, 0x8c, 0xd0, + 0xf8, 0xc6, 0x5c, 0x0c, 0x8d, 0xe5, 0x30, 0x5c, 0xd6, 0xc8, 0xc8, 0xb1, + 0x66, 0xed, 0xc9, 0xb1, 0x83, 0x6a, 0x7d, 0xbf, 0xb9, 0x00, 0x09, 0xa4, + 0x2b, 0xcb, 0xb3, 0x0d, 0xa7, 0x43, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, + 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, + 0x54, 0x31, 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, + 0x3a, 0x30, 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, + 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, + 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, + 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, 0x32, 0x2b, 0x30, + 0x30, 0x3a, 0x30, 0x30, 0xe3, 0x03, 0x8b, 0x64, 0x00, 0x00, 0x00, 0x28, + 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, + 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, + 0x33, 0x37, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x13, 0xd0, 0x0e, 0xac, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w401_png_len = 432; diff --git a/src/res/w402.cpp b/src/res/w402.cpp new file mode 100644 index 0000000..896fd0b --- /dev/null +++ b/src/res/w402.cpp @@ -0,0 +1,42 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w402_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xff, 0xaa, + 0xaa, 0xaa, 0x94, 0x40, 0xdc, 0x30, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x64, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x6d, 0xcf, 0x31, 0x0a, 0x80, 0x30, 0x0c, 0x05, 0xd0, 0xaf, 0xd0, 0xc5, + 0xdd, 0x3b, 0x94, 0x9e, 0xc2, 0xb9, 0x93, 0x48, 0x72, 0x1f, 0x8f, 0xd2, + 0xb1, 0xf4, 0x94, 0x26, 0xfd, 0x55, 0x44, 0xcc, 0xf4, 0x08, 0x3f, 0x1f, + 0x02, 0xdc, 0x13, 0xb4, 0xcf, 0x8e, 0x95, 0x90, 0x37, 0xa6, 0x01, 0xc1, + 0x00, 0x63, 0xbf, 0xf0, 0x8c, 0x17, 0xfa, 0x95, 0xb4, 0x56, 0xfb, 0x86, + 0xb0, 0x8c, 0xb4, 0xc5, 0xb0, 0x21, 0x1c, 0x75, 0x1e, 0x28, 0xf8, 0x20, + 0x9f, 0x60, 0x38, 0x03, 0xb1, 0x9f, 0x13, 0x56, 0x18, 0x09, 0xd5, 0x04, + 0xcf, 0xa8, 0x17, 0x5b, 0x73, 0x20, 0xca, 0xf3, 0xcd, 0x05, 0x2e, 0x4d, + 0x2e, 0x26, 0x8a, 0x0d, 0x74, 0xec, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, + 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, + 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x32, 0x2b, 0x30, 0x30, + 0x3a, 0x30, 0x30, 0x67, 0xa0, 0xb8, 0x68, 0x00, 0x00, 0x00, 0x25, 0x74, + 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, + 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, + 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x32, 0x2b, 0x30, + 0x30, 0x3a, 0x30, 0x30, 0x16, 0xfd, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x28, + 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, + 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, + 0x33, 0x37, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x13, 0xd0, 0x0e, 0xac, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w402_png_len = 420; diff --git a/src/res/w403.cpp b/src/res/w403.cpp new file mode 100644 index 0000000..299d67f --- /dev/null +++ b/src/res/w403.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w403_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xff, 0x00, + 0x55, 0xff, 0xc8, 0x8a, 0x5c, 0x8f, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x6b, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x5d, 0xcf, 0xc1, 0x09, 0xc0, 0x20, 0x0c, 0x05, 0xd0, 0xdf, 0x83, 0xd0, + 0x05, 0xba, 0x83, 0x38, 0x85, 0x67, 0x4f, 0x45, 0xd2, 0x7d, 0x3c, 0x77, + 0x0a, 0xf1, 0x24, 0x99, 0xb2, 0x26, 0xd1, 0x52, 0x9a, 0xd3, 0x43, 0xbf, + 0x3f, 0x08, 0xac, 0x71, 0x97, 0xce, 0x89, 0xc3, 0x40, 0x1f, 0x10, 0x26, + 0xec, 0x76, 0x20, 0x6a, 0xfe, 0x0f, 0xe9, 0x11, 0x10, 0x73, 0xd7, 0xb0, + 0x61, 0x3c, 0x27, 0x2e, 0x76, 0x92, 0x19, 0x5e, 0x33, 0xb9, 0x0b, 0x80, + 0x2d, 0xd7, 0x89, 0x04, 0xec, 0x86, 0x32, 0x33, 0x69, 0xf5, 0x84, 0x76, + 0x7b, 0xed, 0x31, 0x8c, 0x8d, 0xc1, 0xb7, 0x2e, 0x20, 0x16, 0x38, 0x01, + 0x73, 0x7d, 0x7f, 0xf3, 0x00, 0x47, 0x82, 0x2d, 0x6f, 0x68, 0x39, 0xd6, + 0x46, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, + 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, + 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xb3, 0x31, + 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, + 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, + 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, + 0x32, 0x34, 0x3a, 0x33, 0x32, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xe3, + 0x03, 0x8b, 0x64, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, + 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x37, 0x2b, 0x30, 0x30, + 0x3a, 0x30, 0x30, 0x13, 0xd0, 0x0e, 0xac, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w403_png_len = 427; diff --git a/src/res/w406.cpp b/src/res/w406.cpp new file mode 100644 index 0000000..f2ab2bd --- /dev/null +++ b/src/res/w406.cpp @@ -0,0 +1,44 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w406_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x01, 0x03, 0x00, 0x00, 0x00, 0xa1, 0x9d, 0x6d, 0x77, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x55, 0xaa, 0xa4, + 0x0d, 0x30, 0x99, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x00, + 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, + 0x07, 0xe6, 0x0c, 0x16, 0x09, 0x10, 0x20, 0xc2, 0x36, 0xbe, 0x6b, 0x00, + 0x00, 0x00, 0x75, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, + 0x01, 0xfb, 0xff, 0xff, 0xff, 0x30, 0xd4, 0xff, 0xff, 0xff, 0x0f, 0x48, + 0xfc, 0xfb, 0xc7, 0x50, 0xfe, 0xc7, 0xa6, 0x8e, 0x21, 0xf9, 0x87, 0xc4, + 0x3f, 0x06, 0xf7, 0x0f, 0x9c, 0xff, 0x18, 0xfc, 0x0b, 0xf8, 0xdf, 0x31, + 0xd4, 0x19, 0xf0, 0x1f, 0x63, 0xa8, 0x29, 0xe0, 0xef, 0x63, 0xa8, 0xf9, + 0x21, 0x3f, 0x8f, 0xa1, 0xfe, 0x8f, 0x3d, 0x50, 0xf1, 0x0f, 0x79, 0x20, + 0xf1, 0x81, 0x7f, 0x1f, 0x43, 0xf9, 0x03, 0x76, 0x39, 0x86, 0xe4, 0x03, + 0x4c, 0x76, 0x0c, 0xee, 0x07, 0x98, 0xea, 0x18, 0xfc, 0x0f, 0x30, 0xff, + 0x63, 0xa8, 0x7b, 0xc0, 0xfe, 0x0e, 0xa4, 0xe3, 0x18, 0x43, 0xc5, 0x0f, + 0xf9, 0x3e, 0x86, 0xca, 0xff, 0xff, 0xe7, 0x41, 0x2c, 0x02, 0x01, 0x00, + 0x3e, 0xc5, 0x32, 0x81, 0x48, 0x8f, 0xd5, 0xa4, 0x00, 0x00, 0x00, 0x25, + 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, + 0x32, 0x32, 0x54, 0x30, 0x39, 0x3a, 0x31, 0x35, 0x3a, 0x33, 0x37, 0x2b, + 0x30, 0x30, 0x3a, 0x30, 0x30, 0x8b, 0x99, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, + 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, + 0x2d, 0x32, 0x32, 0x54, 0x30, 0x39, 0x3a, 0x31, 0x35, 0x3a, 0x33, 0x37, + 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0xfa, 0xc4, 0xb8, 0xdc, 0x00, 0x00, + 0x00, 0x28, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, + 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x32, 0x54, 0x30, 0x39, 0x3a, 0x31, + 0x36, 0x3a, 0x33, 0x32, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x14, 0xde, + 0x0d, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, + 0x60, 0x82 +}; +const size_t w406_png_len = 434; diff --git a/src/res/w411.cpp b/src/res/w411.cpp new file mode 100644 index 0000000..05d2640 --- /dev/null +++ b/src/res/w411.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w411_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xff, 0xff, + 0xaa, 0x00, 0xc8, 0x34, 0x7a, 0x9d, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x6d, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x65, 0x8e, 0xb1, 0x0d, 0xc0, 0x20, 0x0c, 0x04, 0x3f, 0x48, 0x48, 0x28, + 0x75, 0xd8, 0x01, 0x79, 0x0a, 0xea, 0x54, 0x11, 0xc2, 0xfb, 0x30, 0x8a, + 0x4b, 0xc4, 0x94, 0x01, 0x1c, 0x52, 0x24, 0xae, 0x4e, 0xfe, 0xb7, 0xff, + 0x81, 0x35, 0x96, 0x99, 0x5a, 0x6b, 0x02, 0xaf, 0x50, 0x07, 0x9c, 0x1f, + 0xc8, 0x36, 0xb5, 0x4a, 0x1d, 0xae, 0x2d, 0x49, 0x25, 0x07, 0x1f, 0x91, + 0x25, 0x04, 0x85, 0xae, 0x84, 0x01, 0x4c, 0xb2, 0x4f, 0x0f, 0x53, 0x31, + 0xf3, 0x8a, 0x63, 0x31, 0x6e, 0x6e, 0x14, 0x86, 0x67, 0x4a, 0x80, 0x57, + 0x33, 0x70, 0xe8, 0x79, 0x87, 0xf5, 0xf0, 0x89, 0xe8, 0x59, 0x1a, 0xfa, + 0xef, 0xb3, 0xaa, 0xbe, 0xe5, 0xd7, 0xdc, 0xe9, 0x0f, 0x38, 0x9f, 0xce, + 0xb1, 0xa3, 0x73, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, + 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, + 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, + 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, + 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, + 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, + 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, 0x32, 0x2b, 0x30, 0x30, 0x3a, 0x30, + 0x30, 0xe3, 0x03, 0x8b, 0x64, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, + 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x37, 0x2b, + 0x30, 0x30, 0x3a, 0x30, 0x30, 0x13, 0xd0, 0x0e, 0xac, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w411_png_len = 429; diff --git a/src/res/w413.cpp b/src/res/w413.cpp new file mode 100644 index 0000000..42ade24 --- /dev/null +++ b/src/res/w413.cpp @@ -0,0 +1,42 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w413_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xff, 0xaa, + 0xaa, 0xaa, 0x94, 0x40, 0xdc, 0x30, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x61, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x65, 0xce, 0xc1, 0x09, 0x80, 0x30, 0x0c, 0x05, 0xd0, 0xaf, 0x50, 0x70, + 0x00, 0xbb, 0x43, 0xe9, 0x14, 0x9e, 0x73, 0x12, 0x69, 0xf6, 0xe9, 0x28, + 0x39, 0x96, 0x4c, 0xa9, 0xb5, 0x89, 0x87, 0xfa, 0x4f, 0x8f, 0xf0, 0x21, + 0x1f, 0xf0, 0x04, 0xe6, 0xac, 0xaa, 0x82, 0x38, 0xd0, 0x3a, 0x68, 0x42, + 0x09, 0xd7, 0xc0, 0xb9, 0x18, 0x0e, 0x14, 0xd5, 0xd5, 0xd0, 0xf0, 0x82, + 0xb3, 0x20, 0xf5, 0x8e, 0xa1, 0x04, 0xa6, 0x6a, 0x17, 0x42, 0xc7, 0xd3, + 0x49, 0xc0, 0x86, 0x08, 0x44, 0xc7, 0x2e, 0x8e, 0x66, 0x9d, 0xf9, 0xd7, + 0x7f, 0x8f, 0x4f, 0xfd, 0xc6, 0x7b, 0x6e, 0x64, 0x2c, 0x38, 0xab, 0xd3, + 0x3e, 0x05, 0xa4, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, + 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, + 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, + 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, + 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, + 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, + 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, 0x32, 0x2b, 0x30, 0x30, 0x3a, 0x30, + 0x30, 0xe3, 0x03, 0x8b, 0x64, 0x00, 0x00, 0x00, 0x28, 0x74, 0x45, 0x58, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, + 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x37, 0x2b, + 0x30, 0x30, 0x3a, 0x30, 0x30, 0x13, 0xd0, 0x0e, 0xac, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w413_png_len = 417; diff --git a/src/res/w414.cpp b/src/res/w414.cpp new file mode 100644 index 0000000..e81aaf8 --- /dev/null +++ b/src/res/w414.cpp @@ -0,0 +1,43 @@ + +#include "resource.h" +#include + +PROGMEM const uint8_t w414_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x02, 0x03, 0x00, 0x00, 0x00, 0xe6, 0x3d, 0x17, 0xa7, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, + 0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, + 0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, + 0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, + 0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, + 0x09, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xff, 0x00, + 0x55, 0xff, 0xc8, 0x8a, 0x5c, 0x8f, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xe6, 0x0c, 0x14, 0x10, 0x1d, 0x25, 0xbe, 0x0c, + 0x64, 0xdd, 0x00, 0x00, 0x00, 0x6f, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x65, 0xce, 0x31, 0x0e, 0x80, 0x20, 0x0c, 0x05, 0xd0, 0xcf, 0x40, 0xe2, + 0x01, 0xf4, 0x0e, 0x84, 0x53, 0x30, 0x1a, 0x26, 0x42, 0xec, 0x7d, 0x9c, + 0x39, 0x05, 0x23, 0xe9, 0x29, 0x6d, 0x41, 0x18, 0xb4, 0xd3, 0x4b, 0x29, + 0xed, 0x07, 0x66, 0x59, 0x22, 0xcf, 0xcc, 0x15, 0xc7, 0x40, 0x53, 0xc4, + 0x0f, 0x2e, 0x9b, 0x65, 0x44, 0x90, 0x8c, 0xe0, 0x76, 0x38, 0x02, 0x2e, + 0x66, 0xbc, 0x68, 0xd8, 0x14, 0xe4, 0xab, 0x22, 0x19, 0xf2, 0xba, 0x59, + 0x7e, 0xd1, 0xd9, 0x21, 0x9d, 0x88, 0x31, 0xac, 0x37, 0x64, 0x8f, 0x34, + 0x7d, 0x29, 0x4e, 0xb1, 0xf3, 0x42, 0x7f, 0x0a, 0xc8, 0x4d, 0xaa, 0xdf, + 0x1a, 0xf8, 0xe7, 0x99, 0x51, 0x57, 0xf8, 0x59, 0x0f, 0x8c, 0xd8, 0x3b, + 0x77, 0x47, 0xb3, 0xb6, 0xb2, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, 0x54, + 0x31, 0x36, 0x3a, 0x32, 0x35, 0x3a, 0x32, 0x39, 0x2b, 0x30, 0x30, 0x3a, + 0x30, 0x30, 0xb3, 0x31, 0x0c, 0x82, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, + 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, + 0x79, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, 0x32, 0x2d, 0x32, 0x30, + 0x54, 0x31, 0x36, 0x3a, 0x32, 0x34, 0x3a, 0x33, 0x32, 0x2b, 0x30, 0x30, + 0x3a, 0x30, 0x30, 0xe3, 0x03, 0x8b, 0x64, 0x00, 0x00, 0x00, 0x28, 0x74, + 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x31, + 0x32, 0x2d, 0x32, 0x30, 0x54, 0x31, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, + 0x37, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x13, 0xd0, 0x0e, 0xac, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +const size_t w414_png_len = 431; From 6fa6482144e1a3ebd7e7a62540f01f530b50a62e Mon Sep 17 00:00:00 2001 From: GOB Date: Sun, 29 Jan 2023 00:04:31 +0900 Subject: [PATCH 27/31] Add file for README.md --- doc/dummy.jpg | Bin 0 -> 67307 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/dummy.jpg diff --git a/doc/dummy.jpg b/doc/dummy.jpg new file mode 100644 index 0000000000000000000000000000000000000000..632e91f6b6f592d4ee84738232d309b5c474fcf4 GIT binary patch literal 67307 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

8@_m~ht*Mz+Sx=2s3V|lM9wZ=3N)j}% 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 WtOM?n!W{3vqxZ!{M1>kjU;o)@f|uO@ literal 0 HcmV?d00001 From 3f8b2640c5af559a1df8ec5b89c1816d903f9a02 Mon Sep 17 00:00:00 2001 From: GOB Date: Fri, 3 Feb 2023 15:29:32 +0900 Subject: [PATCH 28/31] Fixes change parameter for deinit --- src/wb2/wxbeacon2_task.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wb2/wxbeacon2_task.cpp b/src/wb2/wxbeacon2_task.cpp index 5d500d3..9609703 100644 --- a/src/wb2/wxbeacon2_task.cpp +++ b/src/wb2/wxbeacon2_task.cpp @@ -32,7 +32,7 @@ struct ScopedWB2Client ~ScopedWB2Client() { _client.disconnect(); - NimBLEDevice::deinit(false); + NimBLEDevice::deinit(true); } WxBeacon2Client& client() { return _client; } private: @@ -63,7 +63,7 @@ void wb2_advertise_task(void*) wb2address = cb.address(); scan->stop(); scan->clearResults(); - NimBLEDevice::deinit(false); + NimBLEDevice::deinit(true); delay(100); WB2_LOGI("End of scanning. detected :%d", cb.detected()); From f04463fb13f037c24bd1f2d61769af8a8ddc9c36 Mon Sep 17 00:00:00 2001 From: GOB Date: Sat, 4 Feb 2023 17:41:35 +0900 Subject: [PATCH 29/31] Fixes make dummy resources a weak symbol --- src/res/dummy_face.cpp | 4 ++-- src/res/dummy_logo.cpp | 4 ++-- src/res/dummy_mc.cpp | 4 ++-- src/res/dummy_mo.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/res/dummy_face.cpp b/src/res/dummy_face.cpp index dc7cf86..1508a09 100644 --- a/src/res/dummy_face.cpp +++ b/src/res/dummy_face.cpp @@ -2,7 +2,7 @@ #include "resource.h" #include -PROGMEM const uint8_t ponko_face_bmp[] = { +extern PROGMEM const uint8_t ponko_face_bmp[] __attribute__((weak)) = { 0x42, 0x4d, 0x76, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, @@ -3214,4 +3214,4 @@ PROGMEM const uint8_t ponko_face_bmp[] = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }; -const size_t ponko_face_bmp_len = 38518; +extern const size_t ponko_face_bmp_len __attribute__((weak)) = 38518; diff --git a/src/res/dummy_logo.cpp b/src/res/dummy_logo.cpp index ef92ab8..5c2a729 100644 --- a/src/res/dummy_logo.cpp +++ b/src/res/dummy_logo.cpp @@ -2,7 +2,7 @@ #include "resource.h" #include -PROGMEM const uint8_t logo_bmp[] = { +extern PROGMEM const uint8_t logo_bmp[] __attribute__((weak)) = { 0x42, 0x4d, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, @@ -26,4 +26,4 @@ PROGMEM const uint8_t logo_bmp[] = { 0xfe, 0x00, 0x03, 0xff, 0xe0, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const size_t logo_bmp_len = 258; +extern const size_t logo_bmp_len __attribute__((weak)) = 258; diff --git a/src/res/dummy_mc.cpp b/src/res/dummy_mc.cpp index 6886483..5a87219 100644 --- a/src/res/dummy_mc.cpp +++ b/src/res/dummy_mc.cpp @@ -2,7 +2,7 @@ #include "resource.h" #include -PROGMEM const uint8_t ponko_mouth_close_bmp[] = { +extern PROGMEM const uint8_t ponko_mouth_close_bmp[] __attribute__((weak)) = { 0x42, 0x4d, 0x76, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, @@ -78,4 +78,4 @@ PROGMEM const uint8_t ponko_mouth_close_bmp[] = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }; -const size_t ponko_mouth_close_bmp_len = 886; +extern const size_t ponko_mouth_close_bmp_len __attribute__((weak)) = 886; diff --git a/src/res/dummy_mo.cpp b/src/res/dummy_mo.cpp index fee33e9..0ba83b9 100644 --- a/src/res/dummy_mo.cpp +++ b/src/res/dummy_mo.cpp @@ -2,7 +2,7 @@ #include "resource.h" #include -PROGMEM const uint8_t ponko_mouth_open_bmp[] = { +extern PROGMEM const uint8_t ponko_mouth_open_bmp[] __attribute__((weak)) = { 0x42, 0x4d, 0x76, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, @@ -78,4 +78,4 @@ PROGMEM const uint8_t ponko_mouth_open_bmp[] = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }; -const size_t ponko_mouth_open_bmp_len = 886; +extern const size_t ponko_mouth_open_bmp_len __attribute__((weak)) = 886; From 2371a4f7e4660d1baf74db3b377fab45d5c81424 Mon Sep 17 00:00:00 2001 From: GOB Date: Sat, 4 Feb 2023 17:42:34 +0900 Subject: [PATCH 30/31] Fixes add description of dummy resources --- README.md | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index fd8504c..0e206db 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,21 @@ https://user-images.githubusercontent.com/26270227/186464005-bfc6b1c4-3f5c-4e7f-b2bc-fb4b9d4b0df4.mp4 -forecast himawari +|天気予報|気象衛星ひまわり画像| +|---|---| +|forecast| himawari| + * WxBeacon2 から情報を取得し、ティッカーに表示、ポン子ちゃんアバターがアナウンスします。 * 気象庁の天気予報 JSON データを取得し、全国の天気を表示、ポン子ちゃんアバターがアナウンスします。 -* **(Core2 のみ)** 気象庁の気象衛星ひまわりの画像を取得し表示します。 +* **(Core2 のみ)** 気象衛星ひまわりの画像を取得し表示します。 ## 概要 [株式会社ウェザーニューズ](https://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A7%E3%82%B6%E3%83%BC%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%BA)(以下 WNI )による 24 時間お天気番組[ウェザーニュースLiVE](https://weathernews.jp/web910/) とリンクしたアプリケーション [ウェザーニュース](https://weathernews.jp/app/) では サンクスポイント 2000 pt以上取得すると[ウェザービーコン2](https://weathernews.jp/smart/wxbeacon2/)(以下 WxBeacon2 ) をゲットできます。(別途[有償購入](https://weathernews.jp/sorashop/)も可能) -WxBeacon2 ponko +|WxBeacon2|WEATHEROID TypeA Airi ちゃん| +|---|---| +|WxBeacon2| ponko| M5Stack Basic, Gray, Core2 にて WxBeacon2 や気象庁からデータを取得し、 @@ -24,17 +29,17 @@ M5Stack Basic, Gray, Core2 にて WxBeacon2 や気象庁からデータを取得 * M5Stack M5Stack Basic, Gray, Core2 のいずれか。 -* WxBeacon2 -実体は [OMRON 2JCIE-BL01](https://components.omron.com/jp-ja/products/sensors/2JCIE-BL) です。 -WxBeacon2 でなく当該製品でも動作すると思われます(手元に無いので未確認)。 - * Wi-Fi接続可能な機器 ルータやモバイル Wi-Fi 等。 +* (持っていれば) WxBeacon2 +実体は [OMRON 2JCIE-BL01](https://components.omron.com/jp-ja/products/sensors/2JCIE-BL) です。 +WxBeacon2 でなく当該製品でも動作すると思われます(手元に無いので未確認)。 + ## コンパイル ### 依存ライブラリ -* [M5Unified](https://github.com/m5stack/M5Unified) 0.1.2#develop or later <-- リリース後書き換え +* [M5Unified](https://github.com/m5stack/M5Unified) 0.1.3 or later * [M5GFX](https://github.com/m5stack/M5GFX) 0.1.2 or later * [NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino) 1.4.0 or later * [gob_json](https://github.com/GOB52/gob_json.git) 0.0.3 or later @@ -42,14 +47,14 @@ WxBeacon2 でなく当該製品でも動作すると思われます(手元に無 * [AquesTalk ESP32](https://www.a-quest.com/products/aquestalk_esp32.html) 2.21 or later AquesTalk ESP32 は [こちら](https://www.a-quest.com/download.html) よりダウンロード後、プロジェクトの lib フォルダ(無ければ作成)に展開してください。 - ### 画像リソース 初期状態ではダミーとして私が作った顔とロゴが使用されます。 dummy **権利上の問題でポン子ちゃんの画像などは当リポジトリには含まれません。** ポン子ちゃんや他の画像を使いたい場合、自分で以下の条件を満たす画像を作成し、ソースファイルとして共にコンパイルする必要があります。 - +ダミーリソースは全て weak symbol として定義されているので、ダミーリソースのソースファイルは削除する必要はありません。 +自作した同名シンボルが存在すればそちらが使用されます。 #### 画像フォーマット Basic,Gray での動作の都合上、メモリ使用料削減の為に 4bpp,1bpp を扱います。 @@ -158,23 +163,26 @@ WxBeacon2 は通常(出荷時状態)、計測データを内部に蓄積しま ## 操作方法 -|ボタン| 長押し(1.5秒以上) | 短押し離し | +|ボタン| 長押し(1.5秒以上) | クリック | |---|---|---| -|A | 全国の天気を取得して喋る | WxBeacon2のデータを取得して喋る| -|B | (\*2)WxBeacon2 を出荷時の状態へ戻す | | -|C | (\*1)WxBeacon2 をブロードキャストモードに変更する | ティッカー表示の ON/OFF | +|A | 全国の天気を取得して喋る [Wi-Fi 通信] | WxBeacon2のデータを取得して喋る[BLE 通信]| +|B | (\*2)WxBeacon2 を出荷時の状態へ戻す [BLE 通信] | | +|C | (\*1)WxBeacon2 をブロードキャストモードに変更する [BLE 通信] | ティッカー表示の ON/OFF | -各通信は排他的に動作するので、通信が動作中はボタンを押しても動作しません。 +各通信は排他的に動作するので、通信動作させるボタンは通信中は動作しません。 通信中は画面左下に Wi-Fi か BT マークが点滅表示されています。 progress C 長押しでブロードキャストモードに上手くならなかった場合は、 B 長押しで出荷時に戻して再度試してください。 -## WxBeacon2 と M5Stack との NumBLE によるやり取り +## Zenn の記事 +- WxBeacon2 と M5Stack との NumBLE によるやり取り こちらで[記事](https://zenn.dev/gob/articles/wxbeacon2_000_bbc2e4106f701c)にしました。 +- 気象庁天気予報 JSON と ひまわり画像に関して +こちらで[記事](https://zenn.dev/gob/articles/wxbeacon2_001_961ea4d226fc24)にしました。 -## 謝辞 +## 謝辞 * 各ライブラリの作成者関係者の方々、助言や示唆を頂いた方々には毎度大変お世話になっております。 * 気象庁 JSON 、気象衛星ひまわり画像取得に関しての先人の皆様方の情報を参考にしました。 * 毎日楽しい番組を送ってくださる WNI のスタッフ、[気象予報士、キャスター](https://weathernews.jp/wnl/caster/index.html)他の皆様、作業中ラジオ的に楽しんでおります。 From 6e828f686479d2fa67d1d4b5d8f1a4c7b028391b Mon Sep 17 00:00:00 2001 From: GOB Date: Mon, 6 Feb 2023 12:28:21 +0900 Subject: [PATCH 31/31] Increase the version 0.1.3 of M5Unified on depend --- README.md | 3 +-- platformio.ini | 9 ++++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0e206db..b070edf 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,7 @@ WxBeacon2 でなく当該製品でも動作すると思われます(手元に無 ## コンパイル ### 依存ライブラリ -* [M5Unified](https://github.com/m5stack/M5Unified) 0.1.3 or later -* [M5GFX](https://github.com/m5stack/M5GFX) 0.1.2 or later +* [M5Unified](https://github.com/m5stack/M5Unified) 0.1.3 or later (depends on [M5GFX](https://github.com/m5stack/M5GFX) 0.1.3 or later) * [NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino) 1.4.0 or later * [gob_json](https://github.com/GOB52/gob_json.git) 0.0.3 or later * [gob_datetime](https://github.com/GOB52/gob_datetime.git) 0.1.1 or later diff --git a/platformio.ini b/platformio.ini index 97ec83d..ece1700 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,12 +11,10 @@ framework = arduino board_build.flash_mode = qio board_build.f_flash = 80000000L board_build.f_cpu = 240000000L -board_build.partitions = min_spiffs.csv ; https://www.a-quest.com/download.html Download AquesTalk ESP32 and extract ./lib folder. lib_ldf_mode = deep -lib_deps = https://github.com/M5Stack/M5Unified.git#develop - ;https://github.com/M5Stack/M5Unified.git @ ^0.1.2 +lib_deps = https://github.com/M5Stack/M5Unified.git @ ^0.1.3 h2zero/NimBLE-Arduino @ ^1.4.0 https://github.com/GOB52/gob_json.git @ ^0.0.3 https://github.com/GOB52/gob_datetime.git @ ^0.1.1 @@ -64,6 +62,7 @@ board = m5stack-core2 [m5s_env] board = m5stack-core-esp32 +board_build.partitions = min_spiffs.csv ;----------------------------------------------------------------------- ; M5Stack Core2 @@ -106,11 +105,11 @@ build_flags=${env.build_flags} ${option_release.build_flags} -Wl,-Map,output.map [env:basic_log] extends = m5s_env build_type=release -build_flags=${env.build_flags} ${option_log.build_flags} -D NDEBUG +build_flags=${env.build_flags} ${option_log.build_flags} [env:basic_debug] extends = m5s_env build_type=debug -build_flags=${env.build_flags} ${option_debug.build_flags} -D NDEBUG +build_flags=${env.build_flags} ${option_debug.build_flags}