From 65496fbb2938429912afe3ea6e0f13496b59f1fd Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 31 Aug 2024 17:22:30 +0200 Subject: [PATCH 001/130] WebUI improvements --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 21a7192..4c5d961 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 21a7192e6da4dbd38b49dba7d2840d09cf8a5073 +Subproject commit 4c5d9616212b27e3f05c35370f0befcf2c5a04b2 From 9c67f769d395e21e6091ecc0f5c8639e4f40d26d Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 31 Aug 2024 18:06:42 +0200 Subject: [PATCH 002/130] WebUI improvements for small screens --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 4c5d961..645c0f7 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 4c5d9616212b27e3f05c35370f0befcf2c5a04b2 +Subproject commit 645c0f7d494f2c5ef01c4f065aeac923cf9ff4ef From 478c951ffb95f5dc8153836031159d420cebba3d Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 31 Aug 2024 23:11:48 +0200 Subject: [PATCH 003/130] Improved multi-currency support, improved WebUI checks --- data | 2 +- lib/btclock/data_handler.cpp | 7 +- lib/btclock/data_handler.hpp | 7 +- src/fonts/antonio-semibold90.h | 237 ++++++++++++++++++++++++++++++++- src/lib/defaults.hpp | 3 + src/lib/epd.cpp | 2 +- src/lib/price_notify.cpp | 2 + src/lib/shared.hpp | 14 -- src/lib/webserver.cpp | 6 +- 9 files changed, 249 insertions(+), 31 deletions(-) diff --git a/data b/data index 645c0f7..e21b989 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 645c0f7d494f2c5ef01c4f065aeac923cf9ff4ef +Subproject commit e21b9895a7c93f62565ffa2cd1d6c085b9b74035 diff --git a/lib/btclock/data_handler.cpp b/lib/btclock/data_handler.cpp index 6592807..56cc6e4 100644 --- a/lib/btclock/data_handler.cpp +++ b/lib/btclock/data_handler.cpp @@ -12,10 +12,10 @@ char getCurrencySymbol(char input) return '['; break; case CURRENCY_GBP: - return '\\'; + return ']'; break; case CURRENCY_JPY: - return ']'; + return '^'; break; case CURRENCY_AUD: case CURRENCY_CAD: @@ -43,9 +43,6 @@ std::string getCurrencyCode(char input) case CURRENCY_AUD: return "AUD"; break; - case CURRENCY_CHF: - return "CHF"; - break; case CURRENCY_CAD: return "CAD"; break; diff --git a/lib/btclock/data_handler.hpp b/lib/btclock/data_handler.hpp index 226758f..6ccb49a 100644 --- a/lib/btclock/data_handler.hpp +++ b/lib/btclock/data_handler.hpp @@ -7,10 +7,9 @@ const char CURRENCY_USD = '$'; const char CURRENCY_EUR = '['; -const char CURRENCY_GBP = '\\'; -const char CURRENCY_JPY = ']'; -const char CURRENCY_AUD = '^'; -const char CURRENCY_CHF = '_'; +const char CURRENCY_GBP = ']'; +const char CURRENCY_JPY = '^'; +const char CURRENCY_AUD = '_'; const char CURRENCY_CAD = '`'; std::array parsePriceData(std::uint32_t price, char currency, bool useSuffixFormat = false); diff --git a/src/fonts/antonio-semibold90.h b/src/fonts/antonio-semibold90.h index b55d5df..4ad6ab3 100644 --- a/src/fonts/antonio-semibold90.h +++ b/src/fonts/antonio-semibold90.h @@ -5029,7 +5029,231 @@ const uint8_t Antonio_SemiBold90pt7bBitmaps[] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, - 0x00}; + 0x00, + + // Pound sign (start 60325) + 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xE0, + 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x80, 0x0F, + 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xE0, 0x00, + 0x0F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xE0, + 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xC0, + 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, + 0xF0, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, + 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, + 0xFF, 0xFC, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0xFF, + 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x1F, 0xFF, 0xF8, 0x00, 0x00, + 0x07, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, + 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFC, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xFF, + 0xE0, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x07, 0xFF, 0xFE, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x1F, + 0xFF, 0xF0, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x03, 0xFF, + 0xFF, 0x80, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x7F, 0xFF, 0xF0, 0x00, 0x00, + 0x0F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x01, + 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x3F, 0xFF, 0xF8, 0x00, + 0x00, 0x07, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, + 0x80, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFE, + 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, + 0xFF, 0xC0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, + 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, + 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, + 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFE, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x7F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xFF, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, + 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, + 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, + 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, + 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, + 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, + + // yen-sign (start 61607) + 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, + 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE3, + 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x1F, + 0xFF, 0xFE, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x1F, + 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x3F, 0xFF, 0xFC, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x03, 0xFF, + 0xFF, 0xC0, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0xFF, + 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xE0, 0x00, + 0x00, 0x1F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, + 0xF8, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, + 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x07, 0xFF, 0xFF, 0x00, 0x00, + 0x03, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFE, + 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, + 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, + 0x7F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xC0, + 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, + 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, + 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xF8, 0x00, + 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFF, + 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x01, 0xFF, + 0xFF, 0x80, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, + 0x1F, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xF8, + 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, + 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, + 0xFF, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xC0, + 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFE, + 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x07, + 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, + 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xC0, + 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x3F, + 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x0F, + 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x1F, 0xFF, 0xF8, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x01, 0xFF, + 0xFF, 0xC0, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x81, 0xFF, + 0xFF, 0x80, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x07, 0xFF, 0xFF, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x0F, 0xFF, + 0xFE, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x3F, 0xFF, + 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x7F, 0xFF, 0xE0, 0x00, 0x00, + 0x00, 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, + 0xF3, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF7, 0xFF, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xEF, 0xFF, 0xFC, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xDF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, + 0x07, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, + 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x3F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, + 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, + 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, + 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFC, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, + 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, + 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, + 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, + 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, + 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, + 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 + }; const GFXglyph Antonio_SemiBold90pt7bGlyphs[] PROGMEM = { {0, 1, 1, 38, 0, 0}, // 0x20 ' ' @@ -5090,11 +5314,16 @@ const GFXglyph Antonio_SemiBold90pt7bGlyphs[] PROGMEM = { {53398, 108, 151, 116, 4, 106}, // 0x57 'W' {55437, 64, 151, 72, 4, 106}, // 0x58 'X' {56645, 71, 151, 73, 1, 106}, // 0x59 'Y' - {57986, 52, 151, 61, 6, 106}, - {58968, 70, 155, 84, 5, 104}}; // 0x5A 'Z' + {57986, 52, 151, 61, 6, 106}, // 0x5A 'Z' + {58968, 70, 155, 84, 5, 104}, // Euro-sign as [ + {0, 0, 0, 0, 0, 0}, // Skip backslash + {60325, 67, 153, 82, 7, 104 }, // Pound-sign as ] + {61607, 71, 151, 73, 1, 106 }, // Yen-sign as ^ + + }; const GFXfont Antonio_SemiBold90pt7b PROGMEM = { (uint8_t *)Antonio_SemiBold90pt7bBitmaps, - (GFXglyph *)Antonio_SemiBold90pt7bGlyphs, 0x20, 0x5B, 228}; + (GFXglyph *)Antonio_SemiBold90pt7bGlyphs, 0x20, 0x5E, 231}; // Approx. 60745 bytes diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index f9e19b5..2659df0 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -16,6 +16,9 @@ #define DEFAULT_SUFFIX_PRICE false #define DEFAULT_DISABLE_LEDS false #define DEFAULT_OWN_DATA_SOURCE true +#define DEFAULT_STAGING_SOURCE false +#define DEFAULT_V2_SOURCE_CURRENCY CURRENCY_USD + #define DEFAULT_TIME_OFFSET_SECONDS 3600 diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index bc6a614..cc44c7e 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -252,7 +252,7 @@ void prepareDisplayUpdateTask(void *pvParameters) bool updatePartial = true; - if (strstr(epdContent[epdIndex].c_str(), "/") != NULL) + if (epdContent[epdIndex].length() > 1 && strstr(epdContent[epdIndex].c_str(), "/") != NULL) { String top = epdContent[epdIndex].substring( 0, epdContent[epdIndex].indexOf("/")); diff --git a/src/lib/price_notify.cpp b/src/lib/price_notify.cpp index 66381fb..062062a 100644 --- a/src/lib/price_notify.cpp +++ b/src/lib/price_notify.cpp @@ -1,6 +1,8 @@ #include "price_notify.hpp" const char *wsOwnServerPrice = "wss://ws.btclock.dev/ws?assets=bitcoin"; +const char *wsOwnServerV2 = "wss://ws-staging.btclock.dev/api/v2/ws"; + const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin"; // const char* coinCapWsCert = R"(-----BEGIN CERTIFICATE----- diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index f3a21cc..4a2ca68 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -48,20 +48,6 @@ const PROGMEM int screens[SCREEN_COUNT] = { const int usPerSecond = 1000000; const int usPerMinute = 60 * usPerSecond; -struct SpiRamAllocator : ArduinoJson::Allocator { - void* allocate(size_t size) override { - return heap_caps_malloc(size, MALLOC_CAP_SPIRAM); - } - - void deallocate(void* pointer) override { - heap_caps_free(pointer); - } - - void* reallocate(void* ptr, size_t new_size) override { - return heap_caps_realloc(ptr, new_size, MALLOC_CAP_SPIRAM); - } -}; - struct ScreenMapping { int value; const char* name; diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 47565b7..0d516f1 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -455,7 +455,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) } } - String uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout"}; + String uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout", "srcV2Currency"}; for (String setting : uintSettings) { @@ -478,7 +478,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) String boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd", "mdnsEnabled", "otaEnabled", "stealFocus", "mcapBigChar", "useSatsSymbol", "useBlkCountdown", - "suffixPrice", "disableLeds", "ownDataSource", "flAlwaysOn", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", "nostrZapNotify"}; + "suffixPrice", "disableLeds", "ownDataSource", "flAlwaysOn", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", "nostrZapNotify", "stagingSource"}; for (String setting : boolSettings) { @@ -597,6 +597,8 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["ip"] = WiFi.localIP(); root["txPower"] = WiFi.getTxPower(); root["ownDataSource"] = preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE); + root["stagingSource"] = preferences.getBool("stagingSource", DEFAULT_STAGING_SOURCE); + root["srcV2Currency"] = preferences.getChar("srcV2Currency", DEFAULT_V2_SOURCE_CURRENCY); root["nostrPubKey"] = preferences.getString("nostrPubKey", DEFAULT_NOSTR_NPUB); root["nostrRelay"] = preferences.getString("nostrRelay", DEFAULT_NOSTR_RELAY); From a31a42511f016fdf8420347e44483f1459606b65 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 2 Sep 2024 22:44:23 +0200 Subject: [PATCH 004/130] Fix disabled screen skipping --- data | 2 +- src/lib/defaults.hpp | 1 + src/lib/led_handler.cpp | 11 +++++++++++ src/lib/screen_handler.cpp | 9 +++++---- src/lib/webserver.cpp | 27 ++++++++++++++++++++++++++- src/lib/webserver.hpp | 4 ++++ 6 files changed, 48 insertions(+), 6 deletions(-) diff --git a/data b/data index e21b989..2c7f7f6 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit e21b9895a7c93f62565ffa2cd1d6c085b9b74035 +Subproject commit 2c7f7f667ccb10271db072a4b4e6bf8fd4912f2b diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index 2659df0..8e16eb8 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -15,6 +15,7 @@ #define DEFAULT_USE_BLOCK_COUNTDOWN true #define DEFAULT_SUFFIX_PRICE false #define DEFAULT_DISABLE_LEDS false +#define DEFAULT_DISABLE_FL false #define DEFAULT_OWN_DATA_SOURCE true #define DEFAULT_STAGING_SOURCE false #define DEFAULT_V2_SOURCE_CURRENCY CURRENCY_USD diff --git a/src/lib/led_handler.cpp b/src/lib/led_handler.cpp index e124ea1..0d780a6 100644 --- a/src/lib/led_handler.cpp +++ b/src/lib/led_handler.cpp @@ -13,6 +13,9 @@ bool flInTransition = false; void frontlightFlash(int flDelayTime) { + if (preferences.getBool("flDisable", DEFAULT_DISABLE_FL)) + return; + if (frontlightOn) { frontlightFadeOutAll(flDelayTime, true); @@ -65,6 +68,8 @@ void frontlightFadeInAll(int flDelayTime) void frontlightFadeInAll(int flDelayTime, bool staggered) { + if (preferences.getBool("flDisable", DEFAULT_DISABLE_FL)) + return; if (frontlightIsOn()) return; if (flInTransition) @@ -115,6 +120,8 @@ void frontlightFadeOutAll(int flDelayTime) void frontlightFadeOutAll(int flDelayTime, bool staggered) { + if (preferences.getBool("flDisable", DEFAULT_DISABLE_FL)) + return; if (!frontlightIsOn()) return; if (flInTransition) @@ -179,6 +186,8 @@ bool frontlightIsOn() void frontlightFadeIn(uint num, int flDelayTime) { + if (preferences.getBool("flDisable", DEFAULT_DISABLE_FL)) + return; for (int dutyCycle = 0; dutyCycle <= preferences.getUInt("flMaxBrightness"); dutyCycle += 5) { flArray.setPWM(num, 0, dutyCycle); @@ -188,6 +197,8 @@ void frontlightFadeIn(uint num, int flDelayTime) void frontlightFadeOut(uint num, int flDelayTime) { + if (preferences.getBool("flDisable", DEFAULT_DISABLE_FL)) + return; if (!frontlightIsOn()) return; diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 269d2a7..9335020 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -282,7 +282,7 @@ void nextScreen() { newCurrentScreen = screenMappings.front().value; } - String key = "screen" + String(screenMappings[currentIndex - 1].value) + "Visible"; + String key = "screen" + String(newCurrentScreen) + "Visible"; while (!preferences.getBool(key.c_str(), true)) { currentIndex = findScreenIndexByValue(newCurrentScreen); @@ -294,7 +294,7 @@ void nextScreen() { key = "screen" + String(newCurrentScreen) + "Visible"; } - + setCurrentScreen(newCurrentScreen); } @@ -326,8 +326,9 @@ void previousScreen() { } void showSystemStatusScreen() { - std::array sysStatusEpdContent = {"", "", "", "", - "", "", ""}; + std::array sysStatusEpdContent; + std::fill(sysStatusEpdContent.begin(), sysStatusEpdContent.end(), ""); + String ipAddr = WiFi.localIP().toString(); String subNet = WiFi.subnetMask().toString(); diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 0d516f1..352983d 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -37,6 +37,9 @@ void setupWebserver() server.on("/api/show/screen", HTTP_GET, onApiShowScreen); server.on("/api/show/text", HTTP_GET, onApiShowText); + server.on("/api/screen/next", HTTP_GET, onApiScreenNext); + server.on("/api/screen/previous", HTTP_GET, onApiScreenPrevious); + AsyncCallbackJsonWebHandler *settingsPatchHandler = new AsyncCallbackJsonWebHandler("/api/json/settings", onApiSettingsPatch); server.addHandler(settingsPatchHandler); @@ -373,6 +376,27 @@ void onApiShowScreen(AsyncWebServerRequest *request) request->send(200); } +/** + * @Api + * @Path("/api/screen/next") + */ +void onApiScreenNext(AsyncWebServerRequest *request) +{ + nextScreen(); + request->send(200); +} + +/** + * @Api + * @Path("/api/screen/previous") + */ +void onApiScreenPrevious(AsyncWebServerRequest *request) +{ + previousScreen(); + + request->send(200); +} + void onApiShowText(AsyncWebServerRequest *request) { if (request->hasParam("t")) @@ -478,7 +502,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) String boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd", "mdnsEnabled", "otaEnabled", "stealFocus", "mcapBigChar", "useSatsSymbol", "useBlkCountdown", - "suffixPrice", "disableLeds", "ownDataSource", "flAlwaysOn", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", "nostrZapNotify", "stagingSource"}; + "suffixPrice", "disableLeds", "ownDataSource", "flAlwaysOn", "flDisable", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", "nostrZapNotify", "stagingSource"}; for (String setting : boolSettings) { @@ -611,6 +635,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) #ifdef HAS_FRONTLIGHT root["hasFrontlight"] = true; + root["flDisable"] = preferences.getBool("flDisable", DEFAULT_DISABLE_FL); root["flMaxBrightness"] = preferences.getUInt("flMaxBrightness", DEFAULT_FL_MAX_BRIGHTNESS); root["flAlwaysOn"] = preferences.getBool("flAlwaysOn", DEFAULT_FL_ALWAYS_ON); root["flEffectDelay"] = preferences.getUInt("flEffectDelay", DEFAULT_FL_EFFECT_DELAY); diff --git a/src/lib/webserver.hpp b/src/lib/webserver.hpp index 3d16b35..b47d115 100644 --- a/src/lib/webserver.hpp +++ b/src/lib/webserver.hpp @@ -25,6 +25,10 @@ void onApiStatus(AsyncWebServerRequest *request); void onApiSystemStatus(AsyncWebServerRequest *request); void onApiSetWifiTxPower(AsyncWebServerRequest *request); + +void onApiScreenNext(AsyncWebServerRequest *request); +void onApiScreenPrevious(AsyncWebServerRequest *request); + void onApiShowScreen(AsyncWebServerRequest *request); void onApiShowText(AsyncWebServerRequest *request); void onApiIdentify(AsyncWebServerRequest *request); From 6cf464c3e36d67adb131df3e7add3aa37c93f055 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 2 Sep 2024 23:04:23 +0200 Subject: [PATCH 005/130] Dependency upgrade and cleanup --- platformio.ini | 3 +- src/lib/improv.cpp | 143 --------------------------------------------- src/lib/improv.hpp | 86 --------------------------- 3 files changed, 1 insertion(+), 231 deletions(-) delete mode 100644 src/lib/improv.cpp delete mode 100644 src/lib/improv.hpp diff --git a/platformio.ini b/platformio.ini index 2321a84..14799cf 100644 --- a/platformio.ini +++ b/platformio.ini @@ -33,8 +33,7 @@ build_unflags = lib_deps = https://github.com/joltwallet/esp_littlefs.git bblanchon/ArduinoJson@^7.1.0 - esphome/Improv@^1.2.3 - mathieucarbou/ESP Async WebServer@2.10.8 + mathieucarbou/ESPAsyncWebServer @ 3.2.0 adafruit/Adafruit BusIO@^1.16.1 adafruit/Adafruit MCP23017 Arduino Library@^2.3.2 adafruit/Adafruit NeoPixel@^1.12.3 diff --git a/src/lib/improv.cpp b/src/lib/improv.cpp deleted file mode 100644 index 3de3ef5..0000000 --- a/src/lib/improv.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "improv.h" - -namespace improv { - -ImprovCommand parse_improv_data(const std::vector &data, - bool check_checksum) { - return parse_improv_data(data.data(), data.size(), check_checksum); -} - -ImprovCommand parse_improv_data(const uint8_t *data, size_t length, - bool check_checksum) { - ImprovCommand improv_command; - Command command = (Command)data[0]; - uint8_t data_length = data[1]; - - if (data_length != length - 2 - check_checksum) { - improv_command.command = UNKNOWN; - return improv_command; - } - - if (check_checksum) { - uint8_t checksum = data[length - 1]; - - uint32_t calculated_checksum = 0; - for (uint8_t i = 0; i < length - 1; i++) { - calculated_checksum += data[i]; - } - - if ((uint8_t)calculated_checksum != checksum) { - improv_command.command = BAD_CHECKSUM; - return improv_command; - } - } - - if (command == WIFI_SETTINGS) { - uint8_t ssid_length = data[2]; - uint8_t ssid_start = 3; - size_t ssid_end = ssid_start + ssid_length; - - uint8_t pass_length = data[ssid_end]; - size_t pass_start = ssid_end + 1; - size_t pass_end = pass_start + pass_length; - - std::string ssid(data + ssid_start, data + ssid_end); - std::string password(data + pass_start, data + pass_end); - return {.command = command, .ssid = ssid, .password = password}; - } - - improv_command.command = command; - return improv_command; -} - -bool parse_improv_serial_byte(size_t position, uint8_t byte, - const uint8_t *buffer, - std::function &&callback, - std::function &&on_error) { - if (position == 0) return byte == 'I'; - if (position == 1) return byte == 'M'; - if (position == 2) return byte == 'P'; - if (position == 3) return byte == 'R'; - if (position == 4) return byte == 'O'; - if (position == 5) return byte == 'V'; - - if (position == 6) return byte == IMPROV_SERIAL_VERSION; - - if (position <= 8) return true; - - uint8_t type = buffer[7]; - uint8_t data_len = buffer[8]; - - if (position <= 8 + data_len) return true; - - if (position == 8 + data_len + 1) { - uint8_t checksum = 0x00; - for (size_t i = 0; i < position; i++) checksum += buffer[i]; - - if (checksum != byte) { - on_error(ERROR_INVALID_RPC); - return false; - } - - if (type == TYPE_RPC) { - auto command = parse_improv_data(&buffer[9], data_len, false); - return callback(command); - } - } - - return false; -} - -std::vector build_rpc_response(Command command, - const std::vector &datum, - bool add_checksum) { - std::vector out; - uint32_t length = 0; - out.push_back(command); - for (const auto &str : datum) { - uint8_t len = str.length(); - length += len + 1; - out.push_back(len); - out.insert(out.end(), str.begin(), str.end()); - } - out.insert(out.begin() + 1, length); - - if (add_checksum) { - uint32_t calculated_checksum = 0; - - for (uint8_t byte : out) { - calculated_checksum += byte; - } - out.push_back(calculated_checksum); - } - return out; -} - -#ifdef ARDUINO -std::vector build_rpc_response(Command command, - const std::vector &datum, - bool add_checksum) { - std::vector out; - uint32_t length = 0; - out.push_back(command); - for (const auto &str : datum) { - uint8_t len = str.length(); - length += len; - out.push_back(len); - out.insert(out.end(), str.begin(), str.end()); - } - out.insert(out.begin() + 1, length); - - if (add_checksum) { - uint32_t calculated_checksum = 0; - - for (uint8_t byte : out) { - calculated_checksum += byte; - } - out.push_back(calculated_checksum); - } - return out; -} -#endif // ARDUINO - -} // namespace improv \ No newline at end of file diff --git a/src/lib/improv.hpp b/src/lib/improv.hpp deleted file mode 100644 index 1c9453d..0000000 --- a/src/lib/improv.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once - -#ifdef ARDUINO -#include -#endif // ARDUINO - -#include -#include -#include -#include - -namespace improv { - -static const char *const SERVICE_UUID = "00467768-6228-2272-4663-277478268000"; -static const char *const STATUS_UUID = "00467768-6228-2272-4663-277478268001"; -static const char *const ERROR_UUID = "00467768-6228-2272-4663-277478268002"; -static const char *const RPC_COMMAND_UUID = - "00467768-6228-2272-4663-277478268003"; -static const char *const RPC_RESULT_UUID = - "00467768-6228-2272-4663-277478268004"; -static const char *const CAPABILITIES_UUID = - "00467768-6228-2272-4663-277478268005"; - -enum Error : uint8_t { - ERROR_NONE = 0x00, - ERROR_INVALID_RPC = 0x01, - ERROR_UNKNOWN_RPC = 0x02, - ERROR_UNABLE_TO_CONNECT = 0x03, - ERROR_NOT_AUTHORIZED = 0x04, - ERROR_UNKNOWN = 0xFF, -}; - -enum State : uint8_t { - STATE_STOPPED = 0x00, - STATE_AWAITING_AUTHORIZATION = 0x01, - STATE_AUTHORIZED = 0x02, - STATE_PROVISIONING = 0x03, - STATE_PROVISIONED = 0x04, -}; - -enum Command : uint8_t { - UNKNOWN = 0x00, - WIFI_SETTINGS = 0x01, - IDENTIFY = 0x02, - GET_CURRENT_STATE = 0x02, - GET_DEVICE_INFO = 0x03, - GET_WIFI_NETWORKS = 0x04, - BAD_CHECKSUM = 0xFF, -}; - -static const uint8_t CAPABILITY_IDENTIFY = 0x01; -static const uint8_t IMPROV_SERIAL_VERSION = 1; - -enum ImprovSerialType : uint8_t { - TYPE_CURRENT_STATE = 0x01, - TYPE_ERROR_STATE = 0x02, - TYPE_RPC = 0x03, - TYPE_RPC_RESPONSE = 0x04 -}; - -struct ImprovCommand { - Command command; - std::string ssid; - std::string password; -}; - -ImprovCommand parse_improv_data(const std::vector &data, - bool check_checksum = true); -ImprovCommand parse_improv_data(const uint8_t *data, size_t length, - bool check_checksum = true); - -bool parse_improv_serial_byte(size_t position, uint8_t byte, - const uint8_t *buffer, - std::function &&callback, - std::function &&on_error); - -std::vector build_rpc_response(Command command, - const std::vector &datum, - bool add_checksum = true); -#ifdef ARDUINO -std::vector build_rpc_response(Command command, - const std::vector &datum, - bool add_checksum = true); -#endif // ARDUINO - -} // namespace improv \ No newline at end of file From 00ac808731d3c8b249cf6f13172f81697e173c72 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 2 Sep 2024 23:28:09 +0200 Subject: [PATCH 006/130] Fix GitHub action --- .github/workflows/tagging.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tagging.yml b/.github/workflows/tagging.yml index 109fdaa..d0fe113 100644 --- a/.github/workflows/tagging.yml +++ b/.github/workflows/tagging.yml @@ -22,6 +22,7 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: + include-hidden-files: true retention-days: 1 name: prepared-outputs path: .pio/**/*.bin From a4ff5a2f7506e18567c39a17d6395bdb2c9a6437 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Tue, 3 Sep 2024 01:36:44 +0200 Subject: [PATCH 007/130] Add WebUI authentication --- data | 2 +- src/lib/defaults.hpp | 6 +++++- src/lib/webserver.cpp | 48 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/data b/data index 2c7f7f6..34b09a2 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 2c7f7f667ccb10271db072a4b4e6bf8fd4912f2b +Subproject commit 34b09a2d1134d48d7733a3d11a9e6f3f15d080a9 diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index 8e16eb8..ac95653 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -54,4 +54,8 @@ #define DEFAULT_BITAXE_HOSTNAME "bitaxe1" #define DEFAULT_ZAP_NOTIFY_ENABLED false -#define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422" \ No newline at end of file +#define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422" + +#define DEFAULT_HTTP_AUTH_ENABLED false +#define DEFAULT_HTTP_AUTH_USERNAME "btclock" +#define DEFAULT_HTTP_AUTH_PASSWORD "satoshi" \ No newline at end of file diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 352983d..f735877 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -10,14 +10,23 @@ void setupWebserver() { client->send("welcome", NULL, millis(), 1000); }); server.addHandler(&events); + // server.ad. // server.serveStatic("/css", LittleFS, "/css/"); - server.serveStatic("/fonts", LittleFS, "/fonts/"); - server.serveStatic("/build", LittleFS, "/build"); - server.serveStatic("/swagger.json", LittleFS, "/swagger.json"); - server.serveStatic("/api.html", LittleFS, "/api.html"); - server.serveStatic("/fs_hash.txt", LittleFS, "/fs_hash.txt"); + // server.serveStatic("/fonts", LittleFS, "/fonts/"); + // server.serveStatic("/build", LittleFS, "/build"); + // server.serveStatic("/swagger.json", LittleFS, "/swagger.json"); + // server.serveStatic("/api.html", LittleFS, "/api.html"); + // server.serveStatic("/fs_hash.txt", LittleFS, "/fs_hash.txt"); - server.on("/", HTTP_GET, onIndex); + AsyncStaticWebHandler &staticHandler = server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html"); + + if (preferences.getBool("httpAuthEnabled", DEFAULT_HTTP_AUTH_ENABLED)) + { + staticHandler.setAuthentication( + preferences.getString("httpAuthUser", DEFAULT_HTTP_AUTH_USERNAME), + preferences.getString("httpAuthPass", DEFAULT_HTTP_AUTH_PASSWORD)); + } + // server.on("/", HTTP_GET, onIndex); server.on("/api/status", HTTP_GET, onApiStatus); server.on("/api/system_status", HTTP_GET, onApiSystemStatus); @@ -437,6 +446,15 @@ void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json) void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) { + if ( + preferences.getBool("httpAuthEnabled", DEFAULT_HTTP_AUTH_ENABLED) && + !request->authenticate( + preferences.getString("httpAuthUser", DEFAULT_HTTP_AUTH_USERNAME).c_str(), + preferences.getString("httpAuthPass", DEFAULT_HTTP_AUTH_PASSWORD).c_str())) + { + return request->requestAuthentication(); + } + JsonObject settings = json.as(); bool settingsChanged = true; @@ -502,7 +520,10 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) String boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd", "mdnsEnabled", "otaEnabled", "stealFocus", "mcapBigChar", "useSatsSymbol", "useBlkCountdown", - "suffixPrice", "disableLeds", "ownDataSource", "flAlwaysOn", "flDisable", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", "nostrZapNotify", "stagingSource"}; + "suffixPrice", "disableLeds", "ownDataSource", + "flAlwaysOn", "flDisable", "flFlashOnUpd", + "mempoolSecure", "useNostr", "bitaxeEnabled", + "nostrZapNotify", "stagingSource", "httpAuthEnabled"}; for (String setting : boolSettings) { @@ -587,6 +608,15 @@ void onApiIdentify(AsyncWebServerRequest *request) */ void onApiSettingsGet(AsyncWebServerRequest *request) { + if ( + preferences.getBool("httpAuthEnabled", DEFAULT_HTTP_AUTH_ENABLED) && + !request->authenticate( + preferences.getString("httpAuthUser", DEFAULT_HTTP_AUTH_USERNAME).c_str(), + preferences.getString("httpAuthPass", DEFAULT_HTTP_AUTH_PASSWORD).c_str())) + { + return request->requestAuthentication(); + } + JsonDocument root; root["numScreens"] = NUM_SCREENS; root["fgColor"] = getFgColor(); @@ -633,6 +663,10 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["bitaxeEnabled"] = preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED); root["bitaxeHostname"] = preferences.getString("bitaxeHostname", DEFAULT_BITAXE_HOSTNAME); + root["httpAuthEnabled"] = preferences.getBool("httpAuthEnabled", DEFAULT_HTTP_AUTH_ENABLED); + root["httpAuthUser"] = preferences.getString("httpAuthUser", DEFAULT_HTTP_AUTH_USERNAME); + root["httpAuthPass"] = preferences.getString("httpAuthPass", DEFAULT_HTTP_AUTH_PASSWORD); + #ifdef HAS_FRONTLIGHT root["hasFrontlight"] = true; root["flDisable"] = preferences.getBool("flDisable", DEFAULT_DISABLE_FL); From c276d32807acfe280f07f7cd7a56fecbed66ecdd Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 5 Sep 2024 14:00:15 +0200 Subject: [PATCH 008/130] Implement multi-currency support with MsgPack --- data | 2 +- lib/btclock/data_handler.cpp | 38 ++-- lib/btclock/data_handler.hpp | 10 +- src/lib/config.cpp | 350 +++++++++++++---------------------- src/lib/config.hpp | 10 + src/lib/defaults.hpp | 4 +- src/lib/nostr_notify.cpp | 2 +- src/lib/price_fetch.cpp | 4 +- src/lib/price_notify.cpp | 77 +++----- src/lib/price_notify.hpp | 9 +- src/lib/screen_handler.cpp | 76 ++++++-- src/lib/screen_handler.hpp | 3 + src/lib/shared.hpp | 25 ++- src/lib/v2_notify.cpp | 142 ++++++++++++++ src/lib/v2_notify.hpp | 24 +++ src/lib/webserver.cpp | 288 ++++++---------------------- src/lib/webserver.hpp | 3 +- src/main.cpp | 2 +- 18 files changed, 528 insertions(+), 541 deletions(-) create mode 100644 src/lib/v2_notify.cpp create mode 100644 src/lib/v2_notify.hpp diff --git a/data b/data index 34b09a2..2fffb3e 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 34b09a2d1134d48d7733a3d11a9e6f3f15d080a9 +Subproject commit 2fffb3ef0284b4262ca97a81eb979259186604e5 diff --git a/lib/btclock/data_handler.cpp b/lib/btclock/data_handler.cpp index 56cc6e4..0905e8a 100644 --- a/lib/btclock/data_handler.cpp +++ b/lib/btclock/data_handler.cpp @@ -32,25 +32,41 @@ std::string getCurrencyCode(char input) switch (input) { case CURRENCY_EUR: - return "EUR"; + return CURRENCY_CODE_EUR; break; case CURRENCY_GBP: - return "GBP"; + return CURRENCY_CODE_GBP; break; case CURRENCY_JPY: - return "YEN"; + return CURRENCY_CODE_JPY; break; case CURRENCY_AUD: - return "AUD"; + return CURRENCY_CODE_AUD; break; case CURRENCY_CAD: - return "CAD"; + return CURRENCY_CODE_CAD; break; default: - return "USD"; + return CURRENCY_CODE_USD; } } +char getCurrencyChar(const std::string& input) +{ + if (input == "EUR") + return CURRENCY_EUR; + else if (input == "GBP") + return CURRENCY_GBP; + else if (input == "JPY") + return CURRENCY_JPY; + else if (input == "AUD") + return CURRENCY_AUD; + else if (input == "CAD") + return CURRENCY_CAD; + else + return CURRENCY_USD; // Assuming USD is the default for unknown inputs +} + std::array parsePriceData(std::uint32_t price, char currencySymbol, bool useSuffixFormat) { std::array ret; @@ -205,14 +221,8 @@ std::array parseMarketCap(std::uint32_t blockHeight, s std::uint32_t firstIndex = 0; double supply = getSupplyAtBlock(blockHeight); int64_t marketCap = static_cast(supply * double(price)); - if (currencySymbol == '[') - { - ret[0] = "EUR/MCAP"; - } - else - { - ret[0] = "USD/MCAP"; - } + + ret[0] = getCurrencyCode(currencySymbol) + "/MCAP"; if (bigChars) { diff --git a/lib/btclock/data_handler.hpp b/lib/btclock/data_handler.hpp index 6ccb49a..2d563a4 100644 --- a/lib/btclock/data_handler.hpp +++ b/lib/btclock/data_handler.hpp @@ -12,6 +12,13 @@ const char CURRENCY_JPY = '^'; const char CURRENCY_AUD = '_'; const char CURRENCY_CAD = '`'; +const std::string CURRENCY_CODE_USD = "USD"; +const std::string CURRENCY_CODE_EUR = "EUR"; +const std::string CURRENCY_CODE_GBP = "GBP"; +const std::string CURRENCY_CODE_JPY = "JPY"; +const std::string CURRENCY_CODE_AUD = "AUD"; +const std::string CURRENCY_CODE_CAD = "CAD"; + std::array parsePriceData(std::uint32_t price, char currency, bool useSuffixFormat = false); std::array parseSatsPerCurrency(std::uint32_t price, char currencySymbol, bool withSatsSymbol); std::array parseBlockHeight(std::uint32_t blockHeight); @@ -20,4 +27,5 @@ std::array parseMarketCap(std::uint32_t blockHeight, s std::array parseBlockFees(std::uint16_t blockFees); char getCurrencySymbol(char input); -std::string getCurrencyCode(char input); \ No newline at end of file +std::string getCurrencyCode(char input); +char getCurrencyChar(const std::string& input); \ No newline at end of file diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 54c70e0..7a19abe 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -66,7 +66,6 @@ void setup() setupWebserver(); - // setupWifi(); syncTime(); finishSetup(); @@ -268,24 +267,43 @@ void setupPreferences() setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR)); setBgColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR)); setBlockHeight(preferences.getUInt("blockHeight", INITIAL_BLOCK_HEIGHT)); - setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE)); + setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD); + + if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) + setCurrentCurrency(preferences.getUChar("lastCurrency", CURRENCY_USD)); + else + setCurrentCurrency(CURRENCY_USD); + addScreenMapping(SCREEN_BLOCK_HEIGHT, "Block Height"); - addScreenMapping(SCREEN_MSCW_TIME, "Sats per dollar"); - addScreenMapping(SCREEN_BTC_TICKER, "Ticker"); + addScreenMapping(SCREEN_TIME, "Time"); addScreenMapping(SCREEN_HALVING_COUNTDOWN, "Halving countdown"); - addScreenMapping(SCREEN_MARKET_CAP, "Market Cap"); addScreenMapping(SCREEN_BLOCK_FEE_RATE, "Block Fee Rate"); + addScreenMapping(SCREEN_SATS_PER_CURRENCY, "Sats per dollar"); + addScreenMapping(SCREEN_BTC_TICKER, "Ticker"); + addScreenMapping(SCREEN_MARKET_CAP, "Market Cap"); + + + // addScreenMapping(SCREEN_SATS_PER_CURRENCY_USD, "Sats per USD"); + // addScreenMapping(SCREEN_BTC_TICKER_USD, "Ticker USD"); + // addScreenMapping(SCREEN_MARKET_CAP_USD, "Market Cap USD"); + + // addScreenMapping(SCREEN_SATS_PER_CURRENCY_EUR, "Sats per EUR"); + // addScreenMapping(SCREEN_BTC_TICKER_EUR, "Ticker EUR"); + // addScreenMapping(SCREEN_MARKET_CAP_EUR, "Market Cap EUR"); + // screenNameMap[SCREEN_BLOCK_HEIGHT] = "Block Height"; // screenNameMap[SCREEN_BLOCK_FEE_RATE] = "Block Fee Rate"; - // screenNameMap[SCREEN_MSCW_TIME] = "Sats per dollar"; + // screenNameMap[SCREEN_SATS_PER_CURRENCY] = "Sats per dollar"; // screenNameMap[SCREEN_BTC_TICKER] = "Ticker"; // screenNameMap[SCREEN_TIME] = "Time"; // screenNameMap[SCREEN_HALVING_COUNTDOWN] = "Halving countdown"; // screenNameMap[SCREEN_MARKET_CAP] = "Market Cap"; + //addCurrencyMappings(getActiveCurrencies()); + if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED)) { addScreenMapping(SCREEN_BITAXE_HASHRATE, "BitAxe Hashrate"); @@ -293,16 +311,74 @@ void setupPreferences() } } +// void addCurrencyMappings(const std::vector& currencies) +// { +// for (const auto& currency : currencies) +// { +// int satsPerCurrencyScreen; +// int btcTickerScreen; +// int marketCapScreen; + +// // Determine the corresponding screen IDs based on the currency code +// if (currency == "USD") +// { +// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_USD; +// btcTickerScreen = SCREEN_BTC_TICKER_USD; +// marketCapScreen = SCREEN_MARKET_CAP_USD; +// } +// else if (currency == "EUR") +// { +// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_EUR; +// btcTickerScreen = SCREEN_BTC_TICKER_EUR; +// marketCapScreen = SCREEN_MARKET_CAP_EUR; +// } +// else if (currency == "GBP") +// { +// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_GBP; +// btcTickerScreen = SCREEN_BTC_TICKER_GBP; +// marketCapScreen = SCREEN_MARKET_CAP_GBP; +// } +// else if (currency == "JPY") +// { +// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_JPY; +// btcTickerScreen = SCREEN_BTC_TICKER_JPY; +// marketCapScreen = SCREEN_MARKET_CAP_JPY; +// } +// else if (currency == "AUD") +// { +// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_AUD; +// btcTickerScreen = SCREEN_BTC_TICKER_AUD; +// marketCapScreen = SCREEN_MARKET_CAP_AUD; +// } +// else if (currency == "CAD") +// { +// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_CAD; +// btcTickerScreen = SCREEN_BTC_TICKER_CAD; +// marketCapScreen = SCREEN_MARKET_CAP_CAD; +// } +// else +// { +// continue; // Unknown currency, skip it +// } + +// // Create the string locally to ensure it persists +// std::string satsPerCurrencyString = "Sats per " + currency; +// std::string btcTickerString = "Ticker " + currency; +// std::string marketCapString = "Market Cap " + currency; + +// // Pass the c_str() to the function +// addScreenMapping(satsPerCurrencyScreen, satsPerCurrencyString.c_str()); +// addScreenMapping(btcTickerScreen, btcTickerString.c_str()); +// addScreenMapping(marketCapScreen, marketCapString.c_str()); +// } +// } + void setupWebsocketClients(void *pvParameters) { - setupBlockNotify(); - - if (preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE)) - { - setupPriceFetchTask(); - } - else - { + if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) { + setupV2Notify(); + } else { + setupBlockNotify(); setupPriceNotify(); } @@ -453,218 +529,6 @@ void setupHardware() #endif } - -#ifdef IMPROV_ENABLED -void improvGetAvailableWifiNetworks() -{ - int networkNum = WiFi.scanNetworks(); - - for (int id = 0; id < networkNum; ++id) - { - std::vector data = improv::build_rpc_response( - improv::GET_WIFI_NETWORKS, - {WiFi.SSID(id), String(WiFi.RSSI(id)), - (WiFi.encryptionType(id) == WIFI_AUTH_OPEN ? "NO" : "YES")}, - false); - improv_send_response(data); - } - // final response - std::vector data = improv::build_rpc_response( - improv::GET_WIFI_NETWORKS, std::vector{}, false); - improv_send_response(data); -} - -bool improv_connectWifi(std::string ssid, std::string password) -{ - uint8_t count = 0; - - WiFi.begin(ssid.c_str(), password.c_str()); - - while (WiFi.status() != WL_CONNECTED) - { - blinkDelay(500, 2); - - if (count > MAX_ATTEMPTS_WIFI_CONNECTION) - { - WiFi.disconnect(); - return false; - } - count++; - } - - return true; -} - -void onImprovErrorCallback(improv::Error err) -{ - blinkDelayColor(100, 1, 255, 0, 0); - // pixels.setPixelColor(0, pixels.Color(255, 0, 0)); - // pixels.setPixelColor(1, pixels.Color(255, 0, 0)); - // pixels.setPixelColor(2, pixels.Color(255, 0, 0)); - // pixels.setPixelColor(3, pixels.Color(255, 0, 0)); - // pixels.show(); - // vTaskDelay(pdMS_TO_TICKS(100)); - - // pixels.clear(); - // pixels.show(); - // vTaskDelay(pdMS_TO_TICKS(100)); -} - -std::vector getLocalUrl() -{ - return {// URL where user can finish onboarding or use device - // Recommended to use website hosted by device - String("http://" + WiFi.localIP().toString()).c_str()}; -} - -bool onImprovCommandCallback(improv::ImprovCommand cmd) -{ - switch (cmd.command) - { - case improv::Command::GET_CURRENT_STATE: - { - if ((WiFi.status() == WL_CONNECTED)) - { - improv_set_state(improv::State::STATE_PROVISIONED); - std::vector data = improv::build_rpc_response( - improv::GET_CURRENT_STATE, getLocalUrl(), false); - improv_send_response(data); - } - else - { - improv_set_state(improv::State::STATE_AUTHORIZED); - } - - break; - } - - case improv::Command::WIFI_SETTINGS: - { - if (cmd.ssid.length() == 0) - { - improv_set_error(improv::Error::ERROR_INVALID_RPC); - break; - } - - improv_set_state(improv::STATE_PROVISIONING); - queueLedEffect(LED_EFFECT_WIFI_CONNECTING); - - if (improv_connectWifi(cmd.ssid, cmd.password)) - { - queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS); - - // std::array epdContent = {"S", "U", "C", "C", - // "E", "S", "S"}; setEpdContent(epdContent); - - preferences.putBool("wifiConfigured", true); - - improv_set_state(improv::STATE_PROVISIONED); - std::vector data = improv::build_rpc_response( - improv::WIFI_SETTINGS, getLocalUrl(), false); - improv_send_response(data); - - delay(2500); - ESP.restart(); - setupWebserver(); - } - else - { - queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR); - - improv_set_state(improv::STATE_STOPPED); - improv_set_error(improv::Error::ERROR_UNABLE_TO_CONNECT); - } - - break; - } - - case improv::Command::GET_DEVICE_INFO: - { - std::vector infos = {// Firmware name - "BTClock", - // Firmware version - "1.0.0", - // Hardware chip/variant - "ESP32S3", - // Device name - "BTClock"}; - std::vector data = - improv::build_rpc_response(improv::GET_DEVICE_INFO, infos, false); - improv_send_response(data); - break; - } - - case improv::Command::GET_WIFI_NETWORKS: - { - improvGetAvailableWifiNetworks(); - // std::array epdContent = {"W", "E", "B", "W", "I", - // "F", "I"}; setEpdContent(epdContent); - break; - } - - default: - { - improv_set_error(improv::ERROR_UNKNOWN_RPC); - return false; - } - } - - return true; -} - -void improv_set_state(improv::State state) -{ - std::vector data = {'I', 'M', 'P', 'R', 'O', 'V'}; - data.resize(11); - data[6] = improv::IMPROV_SERIAL_VERSION; - data[7] = improv::TYPE_CURRENT_STATE; - data[8] = 1; - data[9] = state; - - uint8_t checksum = 0x00; - for (uint8_t d : data) - checksum += d; - data[10] = checksum; - - Serial.write(data.data(), data.size()); -} - -void improv_send_response(std::vector &response) -{ - std::vector data = {'I', 'M', 'P', 'R', 'O', 'V'}; - data.resize(9); - data[6] = improv::IMPROV_SERIAL_VERSION; - data[7] = improv::TYPE_RPC_RESPONSE; - data[8] = response.size(); - data.insert(data.end(), response.begin(), response.end()); - - uint8_t checksum = 0x00; - for (uint8_t d : data) - checksum += d; - data.push_back(checksum); - - Serial.write(data.data(), data.size()); -} - -void improv_set_error(improv::Error error) -{ - std::vector data = {'I', 'M', 'P', 'R', 'O', 'V'}; - data.resize(11); - data[6] = improv::IMPROV_SERIAL_VERSION; - data[7] = improv::TYPE_ERROR_STATE; - data[8] = 1; - data[9] = error; - - uint8_t checksum = 0x00; - for (uint8_t d : data) - checksum += d; - data[10] = checksum; - - Serial.write(data.data(), data.size()); -} - -#endif - void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { static bool first_connect = true; @@ -842,3 +706,37 @@ int findScreenIndexByValue(int value) } return -1; // Return -1 if value is not found } + +std::vector getAvailableCurrencies() +{ + return {CURRENCY_CODE_USD, CURRENCY_CODE_EUR, CURRENCY_CODE_GBP, CURRENCY_CODE_JPY, CURRENCY_CODE_AUD, CURRENCY_CODE_CAD}; +} + +std::vector getActiveCurrencies() +{ + std::vector result; + + // Convert Arduino String to std::string + std::string stdString = preferences.getString("actCurrencies", DEFAULT_ACTIVE_CURRENCIES).c_str(); + + // Use a stringstream to split the string + std::stringstream ss(stdString); + std::string item; + + // Split the string by comma and add each part to the vector + while (std::getline(ss, item, ',')) + { + result.push_back(item); + } + return result; +} + +bool isActiveCurrency(std::string ¤cy) +{ + std::vector ac = getActiveCurrencies(); + if (std::find(ac.begin(), ac.end(), currency) != ac.end()) + { + return true; + } + return false; +} \ No newline at end of file diff --git a/src/lib/config.hpp b/src/lib/config.hpp index 6888154..8b7434a 100644 --- a/src/lib/config.hpp +++ b/src/lib/config.hpp @@ -19,6 +19,8 @@ #include "lib/nostr_notify.hpp" #include "lib/bitaxe_fetch.hpp" +#include "lib/v2_notify.hpp" + #include "lib/price_notify.hpp" #include "lib/screen_handler.hpp" #include "lib/shared.hpp" @@ -64,6 +66,11 @@ std::vector getLocalUrl(); // void improv_set_state(improv::State state); // void improv_send_response(std::vector &response); // void improv_set_error(improv::Error error); +//void addCurrencyMappings(const std::vector& currencies); +std::vector getActiveCurrencies(); +std::vector getAvailableCurrencies(); + +bool isActiveCurrency(std::string ¤cy); void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info); String getHwRev(); @@ -71,4 +78,7 @@ bool isWhiteVersion(); String getFsRev(); void addScreenMapping(int value, const char* name); +// void addScreenMapping(int value, const String& name); +// void addScreenMapping(int value, const std::string& name); + int findScreenIndexByValue(int value); \ No newline at end of file diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index ac95653..39e7406 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -58,4 +58,6 @@ #define DEFAULT_HTTP_AUTH_ENABLED false #define DEFAULT_HTTP_AUTH_USERNAME "btclock" -#define DEFAULT_HTTP_AUTH_PASSWORD "satoshi" \ No newline at end of file +#define DEFAULT_HTTP_AUTH_PASSWORD "satoshi" + +#define DEFAULT_ACTIVE_CURRENCIES "USD,EUR,JPY" \ No newline at end of file diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index b0adfd3..f9ac019 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -168,7 +168,7 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even { if (typeValue.equals("priceUsd")) { - processNewPrice(obj["content"].as()); + processNewPrice(obj["content"].as(), CURRENCY_USD); } else if (typeValue.equals("blockHeight")) { diff --git a/src/lib/price_fetch.cpp b/src/lib/price_fetch.cpp index d5e6e10..d2ddf67 100644 --- a/src/lib/price_fetch.cpp +++ b/src/lib/price_fetch.cpp @@ -29,9 +29,9 @@ void taskPriceFetch(void *pvParameters) { // usdPrice = doc["bitcoin"]["usd"]; eurPrice = doc["bitcoin"]["eur"].as(); - setPrice(eurPrice); + setPrice(eurPrice, CURRENCY_EUR); if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER || - getCurrentScreen() == SCREEN_MSCW_TIME || + getCurrentScreen() == SCREEN_SATS_PER_CURRENCY || getCurrentScreen() == SCREEN_MARKET_CAP)) { WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0}; xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); diff --git a/src/lib/price_notify.cpp b/src/lib/price_notify.cpp index 062062a..f5ad972 100644 --- a/src/lib/price_notify.cpp +++ b/src/lib/price_notify.cpp @@ -5,36 +5,6 @@ const char *wsOwnServerV2 = "wss://ws-staging.btclock.dev/api/v2/ws"; const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin"; -// const char* coinCapWsCert = R"(-----BEGIN CERTIFICATE----- -// MIIFMjCCBNmgAwIBAgIQBtgXvFyc28MsvQ1HjCnXJTAKBggqhkjOPQQDAjBKMQsw -// CQYDVQQGEwJVUzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEgMB4GA1UEAxMX -// Q2xvdWRmbGFyZSBJbmMgRUNDIENBLTMwHhcNMjMwNTEwMDAwMDAwWhcNMjQwNTA5 -// MjM1OTU5WjB1MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQG -// A1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEe -// MBwGA1UEAxMVc25pLmNsb3VkZmxhcmVzc2wuY29tMFkwEwYHKoZIzj0CAQYIKoZI -// zj0DAQcDQgAEpvFIXzQKHuqTo+IE6c6sB4p0PMXK1KsseEGf2UN/CNRhG5hO7lr8 -// JtXrPZkawWBysZxOsEoetkPrDHMugCLfXKOCA3QwggNwMB8GA1UdIwQYMBaAFKXO -// N+rrsHUOlGeItEX62SQQh5YfMB0GA1UdDgQWBBShsZDJohaR1a5E0Qj7yblZjKDC -// gDA6BgNVHREEMzAxggwqLmNvaW5jYXAuaW+CCmNvaW5jYXAuaW+CFXNuaS5jbG91 -// ZGZsYXJlc3NsLmNvbTAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUH -// AwEGCCsGAQUFBwMCMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj -// ZXJ0LmNvbS9DbG91ZGZsYXJlSW5jRUNDQ0EtMy5jcmwwN6A1oDOGMWh0dHA6Ly9j -// cmw0LmRpZ2ljZXJ0LmNvbS9DbG91ZGZsYXJlSW5jRUNDQ0EtMy5jcmwwPgYDVR0g -// BDcwNTAzBgZngQwBAgIwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2Vy -// dC5jb20vQ1BTMHYGCCsGAQUFBwEBBGowaDAkBggrBgEFBQcwAYYYaHR0cDovL29j -// c3AuZGlnaWNlcnQuY29tMEAGCCsGAQUFBzAChjRodHRwOi8vY2FjZXJ0cy5kaWdp -// Y2VydC5jb20vQ2xvdWRmbGFyZUluY0VDQ0NBLTMuY3J0MAwGA1UdEwEB/wQCMAAw -// ggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB1AO7N0GTV2xrOxVy3nbTNE6Iyh0Z8 -// vOzew1FIWUZxH7WbAAABiAPnoRAAAAQDAEYwRAIgAP2W09OozuhmKeKKMsaVBcae -// o+nPHF1WUWk0i387YYYCIDIM1Wll7/4O3GNx2/Fx9bC6pi69Uya4pLxsCfW3fZMe -// AHYASLDja9qmRzQP5WoC+p0w6xxSActW3SyB2bu/qznYhHMAAAGIA+eg+QAABAMA -// RzBFAiEAuNpSqrbx47gYBgBMz5M6q0CnV/WMJqWQOxYFKrwfwVACIH3nCs4bKToT -// e+MiBrqSDaekixk4kPFEQESO9qHCkWY5AHcA2ra/az+1tiKfm8K7XGvocJFxbLtR -// hIU0vaQ9MEjX+6sAAAGIA+eg1gAABAMASDBGAiEAolCFl2IfbOHUPAOxoi4BLclS -// v9FVXb7LwIvTuCfyrEQCIQDcvehwhV9XGopKGl17F2LYYKI7hvlO3RmpPZQJt1da -// MDAKBggqhkjOPQQDAgNHADBEAiAXRWZ/JVMsfpSFFTHQHUSqRnQ/7cCOWx+9svIy -// mYnFZQIgHMEG0Cm7O4cn5KUzKOsTwwK+2U15s/jPUQi2n2IDTEM= -// -----END CERTIFICATE-----)"; // WebsocketsClient client; esp_websocket_client_handle_t clientPrice = NULL; @@ -42,6 +12,8 @@ esp_websocket_client_config_t config; uint currentPrice = 50000; unsigned long int lastPriceUpdate; bool priceNotifyInit = false; +std::map currencyMap; +std::map lastUpdateMap; void setupPriceNotify() { @@ -100,48 +72,59 @@ void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data) { if (currentPrice != doc["bitcoin"].as()) { - processNewPrice(doc["bitcoin"].as()); + processNewPrice(doc["bitcoin"].as(), CURRENCY_USD); } } } -void processNewPrice(uint newPrice) +void processNewPrice(uint newPrice, char currency) { uint minSecPriceUpd = preferences.getUInt( "minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE); uint currentTime = esp_timer_get_time() / 1000000; - if (lastPriceUpdate == 0 || - (currentTime - lastPriceUpdate) > minSecPriceUpd) + if (lastUpdateMap.find(currency) == lastUpdateMap.end()|| + (currentTime - lastUpdateMap[currency]) > minSecPriceUpd) { // const unsigned long oldPrice = currentPrice; - currentPrice = newPrice; - if (lastPriceUpdate == 0 || - (currentTime - lastPriceUpdate) > 120) - { - preferences.putUInt("lastPrice", currentPrice); - } - lastPriceUpdate = currentTime; + currencyMap[currency] = newPrice; + // if (lastUpdateMap[currency] == 0 || + // (currentTime - lastUpdateMap[currency]) > 120) + // { + // preferences.putUInt("lastPrice", currentPrice); + // } + lastUpdateMap[currency] = currentTime; // if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) { if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER || - getCurrentScreen() == SCREEN_MSCW_TIME || + getCurrentScreen() == SCREEN_SATS_PER_CURRENCY || getCurrentScreen() == SCREEN_MARKET_CAP)) { - WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0}; + WorkItem priceUpdate = {TASK_PRICE_UPDATE, currency}; xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); } //} } } -uint getLastPriceUpdate() +uint getLastPriceUpdate(char currency) { - return lastPriceUpdate; + if (lastUpdateMap.find(currency) == lastUpdateMap.end()) { + return 0; + } + + return lastUpdateMap[currency]; } -uint getPrice() { return currentPrice; } +uint getPrice(char currency) { + if (currencyMap.find(currency) == currencyMap.end()) { + return 0; + } + return currencyMap[currency]; +} -void setPrice(uint newPrice) { currentPrice = newPrice; } +void setPrice(uint newPrice, char currency) { + currencyMap[currency] = newPrice; +} bool isPriceNotifyConnected() { diff --git a/src/lib/price_notify.hpp b/src/lib/price_notify.hpp index 485b096..541f899 100644 --- a/src/lib/price_notify.hpp +++ b/src/lib/price_notify.hpp @@ -14,14 +14,15 @@ void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data); void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data); -uint getPrice(); -void setPrice(uint newPrice); +uint getPrice(char currency); +void setPrice(uint newPrice, char currency); -void processNewPrice(uint newPrice); +//void processNewPrice(uint newPrice); +void processNewPrice(uint newPrice, char currency); bool isPriceNotifyConnected(); void stopPriceNotify(); void restartPriceNotify(); bool getPriceNotifyInit(); -uint getLastPriceUpdate(); \ No newline at end of file +uint getLastPriceUpdate(char currency); \ No newline at end of file diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 9335020..95a8682 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -16,6 +16,7 @@ std::string priceString; QueueHandle_t workQueue = NULL; uint currentScreen; +uint currentCurrency = CURRENCY_USD; void workerTask(void *pvParameters) { WorkItem receivedItem; @@ -40,18 +41,19 @@ void workerTask(void *pvParameters) { } break; case TASK_PRICE_UPDATE: { - uint price = getPrice(); - u_char priceSymbol = '$'; - if (preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE)) { - priceSymbol = '['; - } + uint currency = getCurrentCurrency(); + uint price = getPrice(currency); + // u_char priceSymbol = '$'; + // if (preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE)) { + // priceSymbol = '['; + // } if (getCurrentScreen() == SCREEN_BTC_TICKER) { - taskEpdContent = parsePriceData(price, priceSymbol, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE)); - } else if (getCurrentScreen() == SCREEN_MSCW_TIME) { - taskEpdContent = parseSatsPerCurrency(price, priceSymbol, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); + taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE)); + } else if (getCurrentScreen() == SCREEN_SATS_PER_CURRENCY) { + taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); } else { taskEpdContent = - parseMarketCap(getBlockHeight(), price, priceSymbol, + parseMarketCap(getBlockHeight(), price, currency, preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR)); } @@ -152,7 +154,7 @@ void setupTasks() { xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY, &workerTaskHandle); - xTaskCreate(taskScreenRotate, "rotateScreen", 2048, NULL, tskIDLE_PRIORITY, + xTaskCreate(taskScreenRotate, "rotateScreen", 4096, NULL, tskIDLE_PRIORITY, &taskScreenRotateTaskHandle); waitUntilNoneBusy(); @@ -242,7 +244,7 @@ void setCurrentScreen(uint newScreen) { break; } case SCREEN_MARKET_CAP: - case SCREEN_MSCW_TIME: + case SCREEN_SATS_PER_CURRENCY: case SCREEN_BTC_TICKER: { WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0}; xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); @@ -270,10 +272,36 @@ void setCurrentScreen(uint newScreen) { if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle); } +bool isCurrencySpecific(uint screen) { + switch (screen) { + case SCREEN_BTC_TICKER: + case SCREEN_SATS_PER_CURRENCY: + case SCREEN_MARKET_CAP: + return true; + default: + return false; + } +} + void nextScreen() { int currentIndex = findScreenIndexByValue(getCurrentScreen()); std::vector screenMappings = getScreenNameMap(); + if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE) && isCurrencySpecific(getCurrentScreen())) { + std::vector ac = getActiveCurrencies(); + std::string curCode = getCurrencyCode(getCurrentCurrency()); + if (getCurrencyCode(getCurrentCurrency()) != ac.back()) { + auto it = std::find(ac.begin(), ac.end(), curCode); + if (it != ac.end()) { + size_t index = std::distance(ac.begin(), it); + setCurrentCurrency(getCurrencyChar(ac.at(index+1))); + setCurrentScreen(getCurrentScreen()); + return; + } + } + setCurrentCurrency(getCurrencyChar(ac.front())); + } + int newCurrentScreen; if (currentIndex < screenMappings.size() - 1) { @@ -302,6 +330,23 @@ void previousScreen() { int currentIndex = findScreenIndexByValue(getCurrentScreen()); std::vector screenMappings = getScreenNameMap(); + if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE) && isCurrencySpecific(getCurrentScreen())) { + std::vector ac = getActiveCurrencies(); + std::string curCode = getCurrencyCode(getCurrentCurrency()); + if (getCurrencyCode(getCurrentCurrency()) != ac.front()) { + auto it = std::find(ac.begin(), ac.end(), curCode); + if (it != ac.end()) { + size_t index = std::distance(ac.begin(), it); + setCurrentCurrency(getCurrencyChar(ac.at(index-1))); + setCurrentScreen(getCurrentScreen()); + return; + } + } + setCurrentCurrency(getCurrencyChar(ac.back())); + + } + + int newCurrentScreen; if (currentIndex > 0) { @@ -352,4 +397,13 @@ void showSystemStatusScreen() { (int)round(ESP.getHeapSize() / 1024); setCurrentScreen(SCREEN_CUSTOM); setEpdContent(sysStatusEpdContent); +} + +void setCurrentCurrency(char currency) { + currentCurrency = currency; + preferences.putUChar("lastCurrency", currency); +} + +uint getCurrentCurrency() { + return currentCurrency; } \ No newline at end of file diff --git a/src/lib/screen_handler.hpp b/src/lib/screen_handler.hpp index a3ecaf8..a5c8f8e 100644 --- a/src/lib/screen_handler.hpp +++ b/src/lib/screen_handler.hpp @@ -60,3 +60,6 @@ void setTimerActive(bool status); void toggleTimerActive(); void setupTasks(); +void setCurrentCurrency(char currency); + +uint getCurrentCurrency(); \ No newline at end of file diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index 4a2ca68..5c111df 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -29,12 +29,29 @@ extern std::mutex mcpMutex; #endif const PROGMEM int SCREEN_BLOCK_HEIGHT = 0; -const PROGMEM int SCREEN_MSCW_TIME = 1; -const PROGMEM int SCREEN_BTC_TICKER = 2; + const PROGMEM int SCREEN_TIME = 3; const PROGMEM int SCREEN_HALVING_COUNTDOWN = 4; -const PROGMEM int SCREEN_MARKET_CAP = 5; const PROGMEM int SCREEN_BLOCK_FEE_RATE = 6; + +const PROGMEM int SCREEN_SATS_PER_CURRENCY = 10; + +const PROGMEM int SCREEN_BTC_TICKER = 20; +// const PROGMEM int SCREEN_BTC_TICKER_USD = 20; +// const PROGMEM int SCREEN_BTC_TICKER_EUR = 21; +// const PROGMEM int SCREEN_BTC_TICKER_GBP = 22; +// const PROGMEM int SCREEN_BTC_TICKER_JPY = 23; +// const PROGMEM int SCREEN_BTC_TICKER_AUD = 24; +// const PROGMEM int SCREEN_BTC_TICKER_CAD = 25; + +const PROGMEM int SCREEN_MARKET_CAP = 30; +// const PROGMEM int SCREEN_MARKET_CAP_USD = 30; +// const PROGMEM int SCREEN_MARKET_CAP_EUR = 31; +// const PROGMEM int SCREEN_MARKET_CAP_GBP = 32; +// const PROGMEM int SCREEN_MARKET_CAP_JPY = 33; +// const PROGMEM int SCREEN_MARKET_CAP_AUD = 34; +// const PROGMEM int SCREEN_MARKET_CAP_CAD = 35; + const PROGMEM int SCREEN_BITAXE_HASHRATE = 80; const PROGMEM int SCREEN_BITAXE_BESTDIFF = 81; @@ -42,7 +59,7 @@ const PROGMEM int SCREEN_COUNTDOWN = 98; const PROGMEM int SCREEN_CUSTOM = 99; const int SCREEN_COUNT = 7; const PROGMEM int screens[SCREEN_COUNT] = { - SCREEN_BLOCK_HEIGHT, SCREEN_MSCW_TIME, SCREEN_BTC_TICKER, + SCREEN_BLOCK_HEIGHT, SCREEN_SATS_PER_CURRENCY, SCREEN_BTC_TICKER, SCREEN_TIME, SCREEN_HALVING_COUNTDOWN, SCREEN_MARKET_CAP, SCREEN_BLOCK_FEE_RATE}; const int usPerSecond = 1000000; diff --git a/src/lib/v2_notify.cpp b/src/lib/v2_notify.cpp new file mode 100644 index 0000000..a2f9744 --- /dev/null +++ b/src/lib/v2_notify.cpp @@ -0,0 +1,142 @@ +#include "v2_notify.hpp" + +WebSocketsClient webSocket; +TaskHandle_t v2NotifyTaskHandle; + +void setupV2Notify() +{ + String hostname = "ws.btclock.dev"; + if ( preferences.getBool("stagingSource", DEFAULT_STAGING_SOURCE)) { + Serial.println(F("Connecting to V2 staging source")); + hostname = "ws-staging.btclock.dev"; + } + + webSocket.beginSSL(hostname, 443, "/api/v2/ws"); + webSocket.onEvent(onWebsocketV2Event); + webSocket.setReconnectInterval(5000); + webSocket.enableHeartbeat(15000, 3000, 2); + + setupV2NotifyTask(); +} + +void onWebsocketV2Event(WStype_t type, uint8_t * payload, size_t length) { + switch(type) { + case WStype_DISCONNECTED: + Serial.printf("[WSc] Disconnected!\n"); + break; + case WStype_CONNECTED: + { + Serial.printf("[WSc] Connected to url: %s\n", payload); + + JsonDocument response; + + response["type"] = "subscribe"; + response["eventType"] = "blockfee"; + size_t responseLength = measureMsgPack(response); + uint8_t* buffer = new uint8_t[responseLength]; + serializeMsgPack(response, buffer, responseLength); + webSocket.sendBIN(buffer, responseLength); + delete[] buffer; + + buffer = new uint8_t[responseLength]; + + response["type"] = "subscribe"; + response["eventType"] = "blockheight"; + responseLength = measureMsgPack(response); + buffer = new uint8_t[responseLength]; + serializeMsgPack(response, buffer, responseLength); + webSocket.sendBIN(buffer, responseLength); + + delete[] buffer; + + buffer = new uint8_t[responseLength]; + + response["type"] = "subscribe"; + response["eventType"] = "price"; + + JsonArray currenciesArray = response["currencies"].to(); + + for (const auto &str : getActiveCurrencies()) + { + currenciesArray.add(str); + } + +// response["currencies"] = currenciesArray; + responseLength = measureMsgPack(response); + buffer = new uint8_t[responseLength]; + serializeMsgPack(response, buffer, responseLength); + webSocket.sendBIN(buffer, responseLength); + break; + } + case WStype_TEXT: + Serial.printf("[WSc] get text: %s\n", payload); + + // send message to server + // webSocket.sendTXT("message here"); + break; + case WStype_BIN: + { + JsonDocument doc; + DeserializationError error = deserializeMsgPack(doc, payload, length); + + handleV2Message(doc); + break; + } + case WStype_ERROR: + case WStype_FRAGMENT_TEXT_START: + case WStype_FRAGMENT_BIN_START: + case WStype_FRAGMENT: + case WStype_PING: + case WStype_PONG: + case WStype_FRAGMENT_FIN: + break; + } +} + +void handleV2Message(JsonDocument doc) { + if (doc.containsKey("blockheight")) + { + uint newBlockHeight = doc["blockheight"].as(); + + if (newBlockHeight == getBlockHeight()) { + return; + } + + processNewBlock(newBlockHeight); + } + else if (doc.containsKey("blockfee")) + { + uint medianFee = doc["blockfee"].as(); + + processNewBlockFee(medianFee); + } else if (doc.containsKey("price")) + { + + // Iterate through the key-value pairs of the "price" object + for (JsonPair kv : doc["price"].as()) { + const char* currency = kv.key().c_str(); + uint newPrice = kv.value().as(); + + processNewPrice(newPrice, getCurrencyChar(currency)); + + } + } +} + +void taskV2Notify(void *pvParameters) { + for(;;) { + webSocket.loop(); + vTaskDelay(10 / portTICK_PERIOD_MS); + } +} + +void setupV2NotifyTask() { + xTaskCreate(taskV2Notify, "v2Notify", (6 * 1024), NULL, tskIDLE_PRIORITY, + &v2NotifyTaskHandle); + +} + +bool isV2NotifyConnected() +{ + return webSocket.isConnected(); +} diff --git a/src/lib/v2_notify.hpp b/src/lib/v2_notify.hpp new file mode 100644 index 0000000..d3e4907 --- /dev/null +++ b/src/lib/v2_notify.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include +#include "block_notify.hpp" +#include + +#include "lib/screen_handler.hpp" + +extern TaskHandle_t v2NotifyTaskHandle; + +void setupV2NotifyTask(); +void taskV2Notify(void *pvParameters); + +void setupV2Notify(); +void onWebsocketV2Event(WStype_t type, uint8_t * payload, size_t length); +void handleV2Message(JsonDocument doc); + +bool isV2NotifyConnected(); +// void stopV2Notify(); +// void restartV2Notify(); +// bool getPriceNotifyInit(); +// uint getLastPriceUpdate(); \ No newline at end of file diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index f735877..97441d4 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -41,9 +41,10 @@ void setupWebserver() server.on("/api/action/timer_restart", HTTP_GET, onApiActionTimerRestart); server.on("/api/settings", HTTP_GET, onApiSettingsGet); - server.on("/api/settings", HTTP_POST, onApiSettingsPost); server.on("/api/show/screen", HTTP_GET, onApiShowScreen); + server.on("/api/show/currency", HTTP_GET, onApiShowCurrency); + server.on("/api/show/text", HTTP_GET, onApiShowText); server.on("/api/screen/next", HTTP_GET, onApiScreenNext); @@ -88,6 +89,8 @@ void setupWebserver() } server.on("/api/restart", HTTP_GET, onApiRestart); + server.addRewrite( + new OneParamRewrite("/api/show/currency/{c}", "/api/show/currency?c={c}")); server.addRewrite(new OneParamRewrite("/api/lights/color/{color}", "/api/lights/color?c={color}")); server.addRewrite( @@ -241,10 +244,12 @@ JsonDocument getStatusObject() JsonObject conStatus = root["connectionStatus"].to(); conStatus["price"] = isPriceNotifyConnected(); conStatus["blocks"] = isBlockNotifyConnected(); + conStatus["V2"] = isV2NotifyConnected(); + conStatus["nostr"] = nostrConnected(); root["rssi"] = WiFi.RSSI(); - + root["currency"] = getCurrencyCode(getCurrentCurrency()); #ifdef HAS_FRONTLIGHT std::vector statuses = frontlightGetStatus(); uint16_t arr[NUM_SCREENS]; @@ -548,6 +553,23 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) } } + if (settings.containsKey("actCurrencies")) + { + String actCurrencies; + + for (JsonVariant cur : settings["actCurrencies"].as()) + { + if (!actCurrencies.isEmpty()) + { + actCurrencies += ","; + } + actCurrencies += cur.as(); + } + + preferences.putString("actCurrencies", actCurrencies.c_str()); + Serial.printf("Set actCurrencies: %s\n", actCurrencies); + } + if (settings.containsKey("txPower")) { int txPower = settings["txPower"].as(); @@ -696,6 +718,18 @@ void onApiSettingsGet(AsyncWebServerRequest *request) #endif JsonArray screens = root["screens"].to(); + JsonArray actCurrencies = root["actCurrencies"].to(); + for (const auto &str : getActiveCurrencies()) + { + actCurrencies.add(str); + } + + JsonArray availableCurrencies = root["availableCurrencies"].to(); + for (const auto &str : getAvailableCurrencies()) + { + availableCurrencies.add(str); + } + std::vector screenNameMap = getScreenNameMap(); for (int i = 0; i < screenNameMap.size(); i++) @@ -703,7 +737,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) JsonObject o = screens.add(); String key = "screen" + String(screenNameMap.at(i).value) + "Visible"; o["id"] = screenNameMap.at(i).value; - o["name"] = screenNameMap.at(i).name; + o["name"] = String(screenNameMap.at(i).name); o["enabled"] = preferences.getBool(key.c_str(), true); } @@ -740,230 +774,6 @@ bool processEpdColorSettings(AsyncWebServerRequest *request) return settingsChanged; } -void onApiSettingsPost(AsyncWebServerRequest *request) -{ - // bool settingsChanged = false; - - // settingsChanged = processEpdColorSettings(request); - - // int headers = request->headers(); - // int i; - // for (i = 0; i < headers; i++) - // { - // AsyncWebHeader *h = request->getHeader(i); - // Serial.printf("HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str()); - // } - - // int params = request->params(); - // for (int i = 0; i < params; i++) - // { - // const AsyncWebParameter *p = request->getParam(i); - // if (p->isFile()) - // { // p->isPost() is also true - // Serial.printf("FILE[%s]: %s, size: %u\n", p->name().c_str(), - // p->value().c_str(), p->size()); - // } - // else if (p->isPost()) - // { - // Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); - // } - // else - // { - // Serial.printf("GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); - // } - // } - - // if (request->hasParam("fetchEurPrice", true)) - // { - // const AsyncWebParameter *fetchEurPrice = request->getParam("fetchEurPrice", true); - - // preferences.putBool("fetchEurPrice", fetchEurPrice->value().toInt()); - // settingsChanged = true; - // } - // else - // { - // preferences.putBool("fetchEurPrice", 0); - // settingsChanged = true; - // } - - // if (request->hasParam("ledTestOnPower", true)) - // { - // const AsyncWebParameter *ledTestOnPower = - // request->getParam("ledTestOnPower", true); - - // preferences.putBool("ledTestOnPower", ledTestOnPower->value().toInt()); - // settingsChanged = true; - // } - // else - // { - // preferences.putBool("ledTestOnPower", 0); - // settingsChanged = true; - // } - - // if (request->hasParam("ledFlashOnUpd", true)) - // { - // const AsyncWebParameter *ledFlashOnUpdate = - // request->getParam("ledFlashOnUpd", true); - - // preferences.putBool("ledFlashOnUpd", ledFlashOnUpdate->value().toInt()); - // settingsChanged = true; - // } - // else - // { - // preferences.putBool("ledFlashOnUpd", 0); - // settingsChanged = true; - // } - - // if (request->hasParam("mdnsEnabled", true)) - // { - // const AsyncWebParameter *mdnsEnabled = request->getParam("mdnsEnabled", true); - - // preferences.putBool("mdnsEnabled", mdnsEnabled->value().toInt()); - // settingsChanged = true; - // } - // else - // { - // preferences.putBool("mdnsEnabled", 0); - // settingsChanged = true; - // } - - // if (request->hasParam("otaEnabled", true)) - // { - // const AsyncWebParameter *otaEnabled = request->getParam("otaEnabled", true); - - // preferences.putBool("otaEnabled", otaEnabled->value().toInt()); - // settingsChanged = true; - // } - // else - // { - // preferences.putBool("otaEnabled", 0); - // settingsChanged = true; - // } - - // if (request->hasParam("stealFocus", false)) - // { - // const AsyncWebParameter *stealFocusOnBlock = - // request->getParam("stealFocus", false); - - // preferences.putBool("stealFocus", stealFocusOnBlock->value().toInt()); - // settingsChanged = true; - // } - // else - // { - // preferences.putBool("stealFocus", 0); - // settingsChanged = true; - // } - - // if (request->hasParam("mcapBigChar", true)) - // { - // const AsyncWebParameter *mcapBigChar = request->getParam("mcapBigChar", true); - - // preferences.putBool("mcapBigChar", mcapBigChar->value().toInt()); - // settingsChanged = true; - // } - // else - // { - // preferences.putBool("mcapBigChar", 0); - // settingsChanged = true; - // } - - // if (request->hasParam("mempoolInstance", true)) - // { - // const AsyncWebParameter *mempoolInstance = - // request->getParam("mempoolInstance", true); - - // preferences.putString("mempoolInstance", mempoolInstance->value().c_str()); - // settingsChanged = true; - // } - - // if (request->hasParam("hostnamePrefix", true)) - // { - // const AsyncWebParameter *hostnamePrefix = - // request->getParam("hostnamePrefix", true); - - // preferences.putString("hostnamePrefix", hostnamePrefix->value().c_str()); - // settingsChanged = true; - // } - - // if (request->hasParam("ledBrightness", true)) - // { - // const AsyncWebParameter *ledBrightness = request->getParam("ledBrightness", true); - - // preferences.putUInt("ledBrightness", ledBrightness->value().toInt()); - // settingsChanged = true; - // } - - // if (request->hasParam("fullRefreshMin", true)) - // { - // const AsyncWebParameter *fullRefreshMin = - // request->getParam("fullRefreshMin", true); - - // preferences.putUInt("fullRefreshMin", fullRefreshMin->value().toInt()); - // settingsChanged = true; - // } - - // if (request->hasParam("wpTimeout", true)) - // { - // const AsyncWebParameter *wpTimeout = request->getParam("wpTimeout", true); - - // preferences.putUInt("wpTimeout", wpTimeout->value().toInt()); - // settingsChanged = true; - // } - - // std::vector screenNameMap = getScreenNameMap(); - - // if (request->hasParam("screens")) - // { - // const AsyncWebParameter *screenParam = request->getParam("screens", true); - - // Serial.printf(screenParam->value().c_str()); - // } - - // for (int i = 0; i < screenNameMap.size(); i++) - // { - // String key = "screen[" + String(i) + "]"; - // String prefKey = "screen" + String(i) + "Visible"; - // bool visible = false; - // if (request->hasParam(key, true)) - // { - // const AsyncWebParameter *screenParam = request->getParam(key, true); - // visible = screenParam->value().toInt(); - // } - - // preferences.putBool(prefKey.c_str(), visible); - // } - - // if (request->hasParam("tzOffset", true)) - // { - // const AsyncWebParameter *p = request->getParam("tzOffset", true); - // int tzOffsetSeconds = p->value().toInt() * 60; - // preferences.putInt("gmtOffset", tzOffsetSeconds); - // settingsChanged = true; - // } - - // if (request->hasParam("minSecPriceUpd", true)) - // { - // const AsyncWebParameter *p = request->getParam("minSecPriceUpd", true); - // int minSecPriceUpd = p->value().toInt(); - // preferences.putUInt("minSecPriceUpd", minSecPriceUpd); - // settingsChanged = true; - // } - - // if (request->hasParam("timePerScreen", true)) - // { - // const AsyncWebParameter *p = request->getParam("timePerScreen", true); - // uint timerSeconds = p->value().toInt() * 60; - // preferences.putUInt("timerSeconds", timerSeconds); - // settingsChanged = true; - // } - - // request->send(200); - // if (settingsChanged) - // { - // queueLedEffect(LED_FLASH_SUCCESS); - // } -} - void onApiSystemStatus(AsyncWebServerRequest *request) { AsyncResponseStream *response = @@ -1209,6 +1019,30 @@ void eventSourceTask(void *pvParameters) } } +void onApiShowCurrency(AsyncWebServerRequest *request) +{ + if (request->hasParam("c")) + { + const AsyncWebParameter *p = request->getParam("c"); + std::string currency = p->value().c_str(); + + if (!isActiveCurrency(currency)) + { + request->send(404); + return; + } + + char curChar = getCurrencyChar(currency); + + setCurrentCurrency(curChar); + setCurrentScreen(getCurrentScreen()); + + request->send(200); + return; + } + request->send(404); +} + #ifdef HAS_FRONTLIGHT void onApiFrontlightOn(AsyncWebServerRequest *request) { diff --git a/src/lib/webserver.hpp b/src/lib/webserver.hpp index b47d115..3f71ac9 100644 --- a/src/lib/webserver.hpp +++ b/src/lib/webserver.hpp @@ -30,6 +30,8 @@ void onApiScreenNext(AsyncWebServerRequest *request); void onApiScreenPrevious(AsyncWebServerRequest *request); void onApiShowScreen(AsyncWebServerRequest *request); +void onApiShowCurrency(AsyncWebServerRequest *request); + void onApiShowText(AsyncWebServerRequest *request); void onApiIdentify(AsyncWebServerRequest *request); @@ -38,7 +40,6 @@ void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json); void onApiActionPause(AsyncWebServerRequest *request); void onApiActionTimerRestart(AsyncWebServerRequest *request); void onApiSettingsGet(AsyncWebServerRequest *request); -void onApiSettingsPost(AsyncWebServerRequest *request); void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json); void onApiFullRefresh(AsyncWebServerRequest *request); diff --git a/src/main.cpp b/src/main.cpp index ef8594e..0839e9d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -134,7 +134,7 @@ extern "C" void app_main() } // if more than 5 price updates are missed, there is probably something wrong, reconnect - if ((getLastPriceUpdate() - currentUptime) > (preferences.getUInt("minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE) * 5)) + if ((getLastPriceUpdate(CURRENCY_USD) - currentUptime) > (preferences.getUInt("minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE) * 5)) { Serial.println(F("Detected 5 missed price updates... restarting price handler.")); From 849e5ce4392de328a126eafe1e383bd6284f0804 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 9 Sep 2024 15:13:41 +0200 Subject: [PATCH 009/130] Finish V2 MsgPack WebSocket API implementation --- data | 2 +- dependencies.lock | 2 +- src/lib/block_notify.cpp | 2 +- src/lib/screen_handler.cpp | 9 +++++---- src/lib/v2_notify.cpp | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/data b/data index 2fffb3e..1fa62ca 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 2fffb3ef0284b4262ca97a81eb979259186604e5 +Subproject commit 1fa62ca88dc9cf85109712082e2b0d3916d03323 diff --git a/dependencies.lock b/dependencies.lock index 6400884..f47f33d 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -4,6 +4,6 @@ dependencies: source: type: idf version: 4.4.7 -manifest_hash: 615d994fdba8799111cf7825a85adb23ca6a2ae02b2335b53fde1188ff862f23 +manifest_hash: 3117ab97df715ceaa7b9cacfc3cc7071408d26f122740eea130b5286dc5cd988 target: esp32s3 version: 1.0.0 diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index dad6ad1..19f1893 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -2,7 +2,7 @@ char *wsServer; esp_websocket_client_handle_t blockNotifyClient = NULL; -uint currentBlockHeight = 840000; +uint currentBlockHeight = 860000; uint blockMedianFee = 1; bool blockNotifyInit = false; unsigned long int lastBlockUpdate; diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 95a8682..13e93b5 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -8,14 +8,13 @@ TaskHandle_t workerTaskHandle; esp_timer_handle_t screenRotateTimer; esp_timer_handle_t minuteTimer; -std::array taskEpdContent = {"", "", "", "", - "", "", ""}; +std::array taskEpdContent = {}; std::string priceString; #define WORK_QUEUE_SIZE 10 QueueHandle_t workQueue = NULL; -uint currentScreen; +uint currentScreen = SCREEN_BLOCK_HEIGHT; uint currentCurrency = CURRENCY_USD; void workerTask(void *pvParameters) { @@ -158,7 +157,9 @@ void setupTasks() { &taskScreenRotateTaskHandle); waitUntilNoneBusy(); - setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)); + + if (findScreenIndexByValue(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)) != -1) + setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)); } void setupTimeUpdateTimer(void *pvParameters) { diff --git a/src/lib/v2_notify.cpp b/src/lib/v2_notify.cpp index a2f9744..e23c0af 100644 --- a/src/lib/v2_notify.cpp +++ b/src/lib/v2_notify.cpp @@ -15,7 +15,7 @@ void setupV2Notify() webSocket.onEvent(onWebsocketV2Event); webSocket.setReconnectInterval(5000); webSocket.enableHeartbeat(15000, 3000, 2); - + setupV2NotifyTask(); } From f42cd250fee73c26d5ce52ad9dc1a9c24ebd724d Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 9 Sep 2024 16:52:23 +0200 Subject: [PATCH 010/130] Add some tests for multi-currency --- test/test_datahandler/test_main.cpp | 137 +++++++++++++++++----------- 1 file changed, 86 insertions(+), 51 deletions(-) diff --git a/test/test_datahandler/test_main.cpp b/test/test_datahandler/test_main.cpp index 2c9ffb2..14f3a93 100644 --- a/test/test_datahandler/test_main.cpp +++ b/test/test_datahandler/test_main.cpp @@ -1,102 +1,135 @@ #include #include -void setUp(void) { +void setUp(void) +{ // set stuff up here } -void tearDown(void) { +void tearDown(void) +{ // clean stuff up here } -void test_CorrectSatsPerDollarConversion(void) { - std::array output = parseSatsPerCurrency(37253, '$', false); +void test_CorrectSatsPerDollarConversion(void) +{ + std::array output = parseSatsPerCurrency(37253, CURRENCY_USD, false); TEST_ASSERT_EQUAL_STRING("MSCW/TIME", output[0].c_str()); - TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS-4].c_str()); - TEST_ASSERT_EQUAL_STRING("6", output[NUM_SCREENS-3].c_str()); - TEST_ASSERT_EQUAL_STRING("8", output[NUM_SCREENS-2].c_str()); - TEST_ASSERT_EQUAL_STRING("4", output[NUM_SCREENS-1].c_str()); + TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS - 4].c_str()); + TEST_ASSERT_EQUAL_STRING("6", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("8", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("4", output[NUM_SCREENS - 1].c_str()); } +void test_CorrectSatsPerPoundConversion(void) +{ + std::array output = parseSatsPerCurrency(37253, CURRENCY_GBP, false); + TEST_ASSERT_EQUAL_STRING("SATS/GBP", output[0].c_str()); + TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS - 4].c_str()); + TEST_ASSERT_EQUAL_STRING("6", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("8", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("4", output[NUM_SCREENS - 1].c_str()); +} -void test_SixCharacterBlockHeight(void) { +void test_SixCharacterBlockHeight(void) +{ std::array output = parseBlockHeight(999999); TEST_ASSERT_EQUAL_STRING("BLOCK/HEIGHT", output[0].c_str()); TEST_ASSERT_EQUAL_STRING("9", output[1].c_str()); } -void test_SevenCharacterBlockHeight(void) { +void test_SevenCharacterBlockHeight(void) +{ std::array output = parseBlockHeight(1000000); TEST_ASSERT_EQUAL_STRING("1", output[0].c_str()); TEST_ASSERT_EQUAL_STRING("0", output[1].c_str()); } -void test_FeeRateDisplay(void) { +void test_FeeRateDisplay(void) +{ uint testValue = 21; std::array output = parseBlockFees(static_cast(testValue)); TEST_ASSERT_EQUAL_STRING("FEE/RATE", output[0].c_str()); - TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS-3].c_str()); - TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS-2].c_str()); - TEST_ASSERT_EQUAL_STRING("sat/vB", output[NUM_SCREENS-1].c_str()); + TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("sat/vB", output[NUM_SCREENS - 1].c_str()); } - -void test_PriceOf100kusd(void) { +void test_PriceOf100kusd(void) +{ std::array output = parsePriceData(100000, '$'); TEST_ASSERT_EQUAL_STRING("$", output[0].c_str()); TEST_ASSERT_EQUAL_STRING("1", output[1].c_str()); } -void test_PriceOf1MillionUsd(void) { +void test_PriceOf1MillionUsd(void) +{ std::array output = parsePriceData(1000000, '$'); TEST_ASSERT_EQUAL_STRING("BTC/USD", output[0].c_str()); - - TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS-5].c_str()); - TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS-4].c_str()); - TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-3].c_str()); - TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-2].c_str()); - TEST_ASSERT_EQUAL_STRING("M", output[NUM_SCREENS-1].c_str()); + + TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS - 5].c_str()); + TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS - 4].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("M", output[NUM_SCREENS - 1].c_str()); } -void test_McapLowerUsd(void) { +void test_McapLowerUsd(void) +{ std::array output = parseMarketCap(810000, 26000, '$', true); TEST_ASSERT_EQUAL_STRING("USD/MCAP", output[0].c_str()); -// TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS-6].c_str()); - TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS-5].c_str()); - TEST_ASSERT_EQUAL_STRING("5", output[NUM_SCREENS-4].c_str()); - TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-3].c_str()); - TEST_ASSERT_EQUAL_STRING("7", output[NUM_SCREENS-2].c_str()); - TEST_ASSERT_EQUAL_STRING("B", output[NUM_SCREENS-1].c_str()); + // TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS-6].c_str()); + TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS - 5].c_str()); + TEST_ASSERT_EQUAL_STRING("5", output[NUM_SCREENS - 4].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("7", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("B", output[NUM_SCREENS - 1].c_str()); } -void test_Mcap1TrillionUsd(void) { +void test_Mcap1TrillionUsd(void) +{ std::array output = parseMarketCap(831000, 52000, '$', true); TEST_ASSERT_EQUAL_STRING("USD/MCAP", output[0].c_str()); - TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS-6].c_str()); - TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS-5].c_str()); - TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS-4].c_str()); - TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-3].c_str()); - TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS-2].c_str()); - TEST_ASSERT_EQUAL_STRING("T", output[NUM_SCREENS-1].c_str()); + TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS - 6].c_str()); + TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS - 5].c_str()); + TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS - 4].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("T", output[NUM_SCREENS - 1].c_str()); } -void test_Mcap1TrillionEur(void) { - std::array output = parseMarketCap(831000, 52000, '[', true); +void test_Mcap1TrillionEur(void) +{ + std::array output = parseMarketCap(831000, 52000, CURRENCY_EUR, true); TEST_ASSERT_EQUAL_STRING("EUR/MCAP", output[0].c_str()); - TEST_ASSERT_EQUAL_STRING("[", output[NUM_SCREENS-6].c_str()); - TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS-5].c_str()); - TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS-4].c_str()); - TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS-3].c_str()); - TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS-2].c_str()); - TEST_ASSERT_EQUAL_STRING("T", output[NUM_SCREENS-1].c_str()); + TEST_ASSERT_TRUE(CURRENCY_EUR == output[NUM_SCREENS - 6].c_str()[0]); + TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS - 5].c_str()); + TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS - 4].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("T", output[NUM_SCREENS - 1].c_str()); +} + +void test_Mcap1TrillionJpy(void) +{ + std::array output = parseMarketCap(831000, 52000, CURRENCY_JPY, true); + TEST_ASSERT_EQUAL_STRING("JPY/MCAP", output[0].c_str()); + TEST_ASSERT_TRUE(CURRENCY_JPY == output[NUM_SCREENS - 6].c_str()[0]); + TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS - 5].c_str()); + TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS - 4].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("2", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("T", output[NUM_SCREENS - 1].c_str()); } // not needed when using generate_test_runner.rb -int runUnityTests(void) { +int runUnityTests(void) +{ UNITY_BEGIN(); RUN_TEST(test_CorrectSatsPerDollarConversion); + RUN_TEST(test_CorrectSatsPerPoundConversion); RUN_TEST(test_SixCharacterBlockHeight); RUN_TEST(test_SevenCharacterBlockHeight); RUN_TEST(test_FeeRateDisplay); @@ -104,15 +137,17 @@ int runUnityTests(void) { RUN_TEST(test_McapLowerUsd); RUN_TEST(test_Mcap1TrillionUsd); RUN_TEST(test_Mcap1TrillionEur); - //RUN_TEST(test_Mcap1MillionEur); + RUN_TEST(test_Mcap1TrillionJpy); return UNITY_END(); } -int main(void) { - return runUnityTests(); +int main(void) +{ + return runUnityTests(); } -extern "C" void app_main() { - runUnityTests(); +extern "C" void app_main() +{ + runUnityTests(); } From 7a1ce54248793fabde03a18d4259cfebd1206198 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Tue, 10 Sep 2024 10:21:02 +0200 Subject: [PATCH 011/130] Fix WebUI credentials not being saved --- src/lib/webserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 97441d4..bad307f 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -490,7 +490,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) settings["timePerScreen"].as() * 60); } - String strSettings[] = {"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "nostrZapPubkey"}; + String strSettings[] = {"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "nostrZapPubkey", "httpAuthUser", "httpAuthPass"}; for (String setting : strSettings) { From 5425ea7fbfafa66a3c83e047f30b250e7abbc089 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Tue, 10 Sep 2024 11:12:14 +0200 Subject: [PATCH 012/130] Improve setup-WiFi password generation --- src/lib/config.cpp | 34 ++++++++++++++++++++++++---------- src/lib/config.hpp | 5 +++-- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 7a19abe..4acc5d3 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -62,7 +62,7 @@ void setup() } } - tryImprovSetup(); + setupWifi(); setupWebserver(); @@ -105,7 +105,7 @@ void setup() forceFullRefresh(); } -void tryImprovSetup() +void setupWifi() { WiFi.onEvent(WiFiEvent); WiFi.setAutoConnect(true); @@ -140,10 +140,10 @@ void tryImprovSetup() String softAP_SSID = String("BTClock" + String(mac[5], 16) + String(mac[1], 16)); WiFi.setHostname(softAP_SSID.c_str()); - String softAP_password = + String softAP_password = replaceAmbiguousChars( base64::encode(String(mac[2], 16) + String(mac[4], 16) + String(mac[5], 16) + String(mac[1], 16)) - .substring(2, 10); + .substring(2, 10)); wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", DEFAULT_WP_TIMEOUT)); wm.setWiFiAutoReconnect(false); @@ -274,9 +274,8 @@ void setupPreferences() else setCurrentCurrency(CURRENCY_USD); - addScreenMapping(SCREEN_BLOCK_HEIGHT, "Block Height"); - + addScreenMapping(SCREEN_TIME, "Time"); addScreenMapping(SCREEN_HALVING_COUNTDOWN, "Halving countdown"); addScreenMapping(SCREEN_BLOCK_FEE_RATE, "Block Fee Rate"); @@ -285,7 +284,6 @@ void setupPreferences() addScreenMapping(SCREEN_BTC_TICKER, "Ticker"); addScreenMapping(SCREEN_MARKET_CAP, "Market Cap"); - // addScreenMapping(SCREEN_SATS_PER_CURRENCY_USD, "Sats per USD"); // addScreenMapping(SCREEN_BTC_TICKER_USD, "Ticker USD"); // addScreenMapping(SCREEN_MARKET_CAP_USD, "Market Cap USD"); @@ -302,7 +300,7 @@ void setupPreferences() // screenNameMap[SCREEN_HALVING_COUNTDOWN] = "Halving countdown"; // screenNameMap[SCREEN_MARKET_CAP] = "Market Cap"; - //addCurrencyMappings(getActiveCurrencies()); + // addCurrencyMappings(getActiveCurrencies()); if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED)) { @@ -311,6 +309,19 @@ void setupPreferences() } } +String replaceAmbiguousChars(String input) +{ + const char *ambiguous = "1IlO0"; + const char *replacements = "LKQM8"; + + for (int i = 0; i < strlen(ambiguous); i++) + { + input.replace(ambiguous[i], replacements[i]); + } + + return input; +} + // void addCurrencyMappings(const std::vector& currencies) // { // for (const auto& currency : currencies) @@ -375,9 +386,12 @@ void setupPreferences() void setupWebsocketClients(void *pvParameters) { - if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) { + if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) + { setupV2Notify(); - } else { + } + else + { setupBlockNotify(); setupPriceNotify(); } diff --git a/src/lib/config.hpp b/src/lib/config.hpp index 8b7434a..e615431 100644 --- a/src/lib/config.hpp +++ b/src/lib/config.hpp @@ -44,7 +44,7 @@ uint getLastTimeSync(); void setupPreferences(); void setupWebsocketClients(void *pvParameters); void setupHardware(); -void tryImprovSetup(); +void setupWifi(); void setupTimers(); void finishSetup(); void setupMcp(); @@ -81,4 +81,5 @@ void addScreenMapping(int value, const char* name); // void addScreenMapping(int value, const String& name); // void addScreenMapping(int value, const std::string& name); -int findScreenIndexByValue(int value); \ No newline at end of file +int findScreenIndexByValue(int value); +String replaceAmbiguousChars(String input); \ No newline at end of file From 1f2110fc5a4e458acf5935c72300c262e8718a8f Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 11 Sep 2024 03:23:41 +0200 Subject: [PATCH 013/130] Make zap notify more lightning like, verify SSL certificates, remove price fetch code --- README.md | 7 +- data | 2 +- sdkconfig.defaults | 8 +- src/lib/block_notify.cpp | 95 ++++++++++----------- src/lib/config.cpp | 12 +++ src/lib/config.hpp | 3 +- src/lib/led_handler.cpp | 36 +++++++- src/lib/led_handler.hpp | 1 + src/lib/ota.cpp | 90 ++++++++++---------- src/lib/ota.hpp | 2 +- src/lib/price_fetch.cpp | 57 ------------- src/lib/price_fetch.hpp | 10 --- src/lib/price_notify.cpp | 89 ++++++++++++++++++-- src/lib/price_notify.hpp | 2 + src/lib/screen_handler.cpp | 3 - src/lib/screen_handler.hpp | 1 - src/lib/shared.cpp | 76 +++++++++++++++-- src/lib/shared.hpp | 12 ++- src/lib/v2_notify.cpp | 6 +- src/lib/webserver.cpp | 165 ++++++++++++++++++++++++++++++++++++- src/lib/webserver.hpp | 7 ++ 21 files changed, 494 insertions(+), 190 deletions(-) delete mode 100644 src/lib/price_fetch.cpp delete mode 100644 src/lib/price_fetch.hpp diff --git a/README.md b/README.md index 9e22ee3..5dfc0ad 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,16 @@ Biggest differences with v2 are: - Added market capitalization screen - LED flash on new block (and focus to block height screen on new block) +New features: +- BitAxe integration +- Zap notifier +- + "Steal focus on new block" means that when a new block is mined, the display will switch to the block height screen if it's not on it already. Most [information](https://github.com/btclock/btclock_v2/wiki) about BTClock v2 is still valid for this version. -**NOTE**: The software assumes that the hardware is run in a controlled private network. The Web UI and the OTA update mechanism are not password protected and accessible to anyone in the network. Also, since the device only fetches numbers through WebSockets it will skip server certificate verification to save resources. +**NOTE**: The software assumes that the hardware is run in a controlled private network. ~~The Web UI and the OTA update mechanism are not password protected and accessible to anyone in the network. Also, since the device only fetches numbers through WebSockets it will skip server certificate verification to save resources.~~ Since 3.2.0 the WebUI is password protectable and all certificates are verified. OTA update mechanism is not password-protected. ## Building diff --git a/data b/data index 1fa62ca..1c2d8dc 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 1fa62ca88dc9cf85109712082e2b0d3916d03323 +Subproject commit 1c2d8dcdd0efd846f39b0f24977c982a96f16392 diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 09888de..ffb944e 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -7,8 +7,8 @@ CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y #CONFIG_FREERTOS_USE_TRACE_FACILITY=y #CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y #CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=n -CONFIG_ESP_TLS_INSECURE=y -CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y +#CONFIG_ESP_TLS_INSECURE=y +#CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y CONFIG_HEAP_CORRUPTION_DETECTION=CONFIG_HEAP_POISONING_LIGHT CONFIG_HEAP_POISONING_LIGHT=y @@ -50,4 +50,6 @@ CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120 CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n CONFIG_SPIRAM_CACHE_WORKAROUND=y CONFIG_COMPILER_OPTIMIZATION_PERF=y -CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y \ No newline at end of file +CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y +CONFIG_MBEDTLS_SSL_SERVER_VERIFY=n +CONFIG_MBEDTLS_SSL_VERIFY_CLIENT_CERTIFICATE=n \ No newline at end of file diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index 19f1893..bf5d337 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -7,49 +7,42 @@ uint blockMedianFee = 1; bool blockNotifyInit = false; unsigned long int lastBlockUpdate; -// const char *mempoolWsCert = R"(-----BEGIN CERTIFICATE----- -// MIIHfTCCBmWgAwIBAgIRANFX3mhqRYDt1NFuENoSyaAwDQYJKoZIhvcNAQELBQAw -// gZUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO -// BgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDE9MDsGA1UE -// AxM0U2VjdGlnbyBSU0EgT3JnYW5pemF0aW9uIFZhbGlkYXRpb24gU2VjdXJlIFNl -// cnZlciBDQTAeFw0yMzA3MjQwMDAwMDBaFw0yNDA4MjIyMzU5NTlaMFcxCzAJBgNV -// BAYTAkpQMQ4wDAYDVQQIEwVUb2t5bzEgMB4GA1UEChMXTUVNUE9PTCBTUEFDRSBD -// Ty4sIExURC4xFjAUBgNVBAMTDW1lbXBvb2wuc3BhY2UwggEiMA0GCSqGSIb3DQEB -// AQUAA4IBDwAwggEKAoIBAQCqmiPRWgo58d25R0biQjAksXMq5ciH7z7ZQo2w2AbB -// rHxpnlIry74b9S4wRY5UJeYmd6ZwA76NdSioDvxTJc29bLplY+Ftmfc4ET0zYb2k -// Fi86z7GOWb6Ezor/qez9uMM9cxd021Bvcs0/2OrL6Sgp66u9keDZv9NyvFPpXfuR -// tdV2r4HF57VJqZn105PN4k80kNWgDbae8aw+BuUNvQYKEe71yfB7Bh6zSh9pCSfM -// I6pIJdQzoada2uY1dQMoJeIq8qKNKqAPKGsH5McemUT5ZIKU/tjk3nfX0pz/sQa4 -// CN7tLH6UeUlctei92GFd6Xtn7RbKLhDUbc4Sq02Cc9iXAgMBAAGjggQDMIID/zAf -// BgNVHSMEGDAWgBQX2dYlJ2f5McJJQ9kwNkSMbKlP6zAdBgNVHQ4EFgQUXkxoddJ6 -// rKobsbmDdtuCK1ywXuIwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYD -// VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEoGA1UdIARDMEEwNQYMKwYBBAGy -// MQECAQMEMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgG -// BmeBDAECAjBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLnNlY3RpZ28uY29t -// L1NlY3RpZ29SU0FPcmdhbml6YXRpb25WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0Eu -// Y3JsMIGKBggrBgEFBQcBAQR+MHwwVQYIKwYBBQUHMAKGSWh0dHA6Ly9jcnQuc2Vj -// dGlnby5jb20vU2VjdGlnb1JTQU9yZ2FuaXphdGlvblZhbGlkYXRpb25TZWN1cmVT -// ZXJ2ZXJDQS5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29t -// MIIBgAYKKwYBBAHWeQIEAgSCAXAEggFsAWoAdwB2/4g/Crb7lVHCYcz1h7o0tKTN -// uyncaEIKn+ZnTFo6dAAAAYmc9m/gAAAEAwBIMEYCIQD8XOozx411S/bnZambGjTB -// yTcr2fCmggUfQLSmqksD5gIhAIjiEMg0o1VSuQW31gWzfzL6idCkIZeSKN104cdp -// xa4SAHcA2ra/az+1tiKfm8K7XGvocJFxbLtRhIU0vaQ9MEjX+6sAAAGJnPZwPwAA -// BAMASDBGAiEA2sPTZTzvxewzQ8vk36+BWAKuJS7AvJ5W3clvfwCa8OUCIQC74ekT -// Ged2fqQE4sVy74aS6HRA2ihC9VLtNrASJx1YjQB2AO7N0GTV2xrOxVy3nbTNE6Iy -// h0Z8vOzew1FIWUZxH7WbAAABiZz2cA8AAAQDAEcwRQIgEklH7wYCFuuJIFUHX5PY -// /vZ3bDoxOp+061PT3caa+rICIQC0abgfGlBKiHxp47JZxnW3wcVqWdiYX4ViLm9H -// xfx4ljCBxgYDVR0RBIG+MIG7gg1tZW1wb29sLnNwYWNlghMqLmZtdC5tZW1wb29s -// LnNwYWNlghMqLmZyYS5tZW1wb29sLnNwYWNlgg8qLm1lbXBvb2wuc3BhY2WCEyou -// dGs3Lm1lbXBvb2wuc3BhY2WCEyoudmExLm1lbXBvb2wuc3BhY2WCDGJpc3EubWFy -// a2V0c4IKYmlzcS5uaW5qYYIObGlxdWlkLm5ldHdvcmuCDGxpcXVpZC5wbGFjZYIN -// bWVtcG9vbC5uaW5qYTANBgkqhkiG9w0BAQsFAAOCAQEAFvOSRnlHDfq9C8acjZEG -// 5XIqjNYigyWyjOvx83of6Z3PBKkAZB5D/UHBPp+jBDJiEb/QXC7Z7Y7kpuvnoVib -// b4jDc0RjGEsxL+3F7cSw26m3wILJhhHooGZRmFY4GOAeCZtYCOTzJsiZvFpDoQjU -// hTBxtaps05z0Ly9/eYvkXnjnBNROZJVR+KYHlq4TIoGNc4q4KvpfHv2I/vhS2M1e -// bECNNPEyRxHGKdXXO3huocE7aVKpy+JDR6cWwDu6hpdc1j/SCDqdTDFQ7McHOrqA -// fpPh4FcfePMh7Mqxtg2pSs5pXPtiP0ZjLgxd7HbAXct8Y+/jGk+k3sx3SeYXVimr -// ew== -// -----END CERTIFICATE-----)"; +const char *mempoolWsCert = R"EOF( +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- +)EOF"; void setupBlockNotify() { @@ -103,13 +96,18 @@ void setupBlockNotify() esp_websocket_client_config_t config = { // .uri = "wss://mempool.space/api/v1/ws", - // .task_stack = (6*1024), - // .cert_pem = mempoolWsCert, - .user_agent = USER_AGENT, + .task_stack = (6*1024), + .user_agent = USER_AGENT }; + if (preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE)) { + config.cert_pem = mempoolWsCert; + } + config.uri = mempoolUri.c_str(); + Serial.printf("Connecting to %s\r\n", preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE)); + blockNotifyClient = esp_websocket_client_init(&config); esp_websocket_register_events(blockNotifyClient, WEBSOCKET_EVENT_ANY, onWebsocketBlockEvent, blockNotifyClient); @@ -302,7 +300,10 @@ int getBlockFetch() { try { WiFiClientSecure client; - client.setInsecure(); + + if (preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE)) { + client.setCACert(mempoolWsCert); + } String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 4acc5d3..c295b93 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -753,4 +753,16 @@ bool isActiveCurrency(std::string ¤cy) return true; } return false; +} + +const char* getFirmwareFilename() { + if (HW_REV == "REV_B_EPD_2_13") { + return "btclock_rev_b_213epd_firmware.bin"; + } else if (HW_REV == "REV_A_EPD_2_13") { + return "lolin_s3_mini_213epd_firmware.bin"; + } else if (HW_REV == "REV_A_EPD_2_9") { + return "lolin_s3_mini_29epd_firmware.bin"; + } else { + return ""; + } } \ No newline at end of file diff --git a/src/lib/config.hpp b/src/lib/config.hpp index e615431..e8fcffa 100644 --- a/src/lib/config.hpp +++ b/src/lib/config.hpp @@ -82,4 +82,5 @@ void addScreenMapping(int value, const char* name); // void addScreenMapping(int value, const std::string& name); int findScreenIndexByValue(int value); -String replaceAmbiguousChars(String input); \ No newline at end of file +String replaceAmbiguousChars(String input); +const char* getFirmwareFilename(); \ No newline at end of file diff --git a/src/lib/led_handler.cpp b/src/lib/led_handler.cpp index 0d780a6..1b6756e 100644 --- a/src/lib/led_handler.cpp +++ b/src/lib/led_handler.cpp @@ -298,9 +298,14 @@ void ledTask(void *parameter) } } #endif - blinkDelayColor(250, 3, 142, 48, 235); - // blinkDelayTwoColor(250, 3, pixels.Color(142, 48, 235), - // pixels.Color(169, 21, 255)); + for (int flash = 0; flash < random(7, 10); flash++) + { + lightningStrike(); + delay(random(50, 150)); + } + // blinkDelayColor(250, 3, 142, 48, 235); + // blinkDelayTwoColor(250, 3, pixels.Color(142, 48, 235), + // pixels.Color(169, 21, 255)); #ifdef HAS_FRONTLIGHT if (preferences.getBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE)) { @@ -668,4 +673,29 @@ void ledTheaterChaseRainbow(int wait) } } +void lightningStrike() +{ + uint32_t PURPLE = pixels.Color(128, 0, 128); + uint32_t YELLOW = pixels.Color(255, 226, 41); + + // Randomly choose which LEDs to light up + for (int i = 0; i < pixels.numPixels(); i++) + { + if (random(2) == 0) + { // 50% chance for each LED + pixels.setPixelColor(i, YELLOW); + } + else + { + pixels.setPixelColor(i, PURPLE); + } + } + pixels.show(); + + delay(random(10, 50)); // Flash duration + + // Return to purple background + // setAllPixels(PURPLE); +} + Adafruit_NeoPixel getPixels() { return pixels; } diff --git a/src/lib/led_handler.hpp b/src/lib/led_handler.hpp index 898b121..b86475e 100644 --- a/src/lib/led_handler.hpp +++ b/src/lib/led_handler.hpp @@ -61,6 +61,7 @@ void ledRainbow(int wait); void ledTheaterChaseRainbow(int wait); void ledTheaterChase(uint32_t color, int wait); Adafruit_NeoPixel getPixels(); +void lightningStrike(); #ifdef HAS_FRONTLIGHT void frontlightFlash(int flDelayTime); diff --git a/src/lib/ota.cpp b/src/lib/ota.cpp index c457a01..709de61 100644 --- a/src/lib/ota.cpp +++ b/src/lib/ota.cpp @@ -70,62 +70,62 @@ void handleOTATask(void *parameter) { } } -void downloadUpdate() { - WiFiClientSecure client; - client.setInsecure(); - HTTPClient http; - http.setUserAgent(USER_AGENT); +// void downloadUpdate() { +// WiFiClientSecure client; +// client.setInsecure(); +// HTTPClient http; +// http.setUserAgent(USER_AGENT); - // Send HTTP request to CoinGecko API - http.useHTTP10(true); +// // Send HTTP request to CoinGecko API +// http.useHTTP10(true); - http.begin(client, - "https://api.github.com/repos/btclock/btclock_v3/releases/latest"); - int httpCode = http.GET(); +// http.begin(client, +// "https://api.github.com/repos/btclock/btclock_v3/releases/latest"); +// int httpCode = http.GET(); - if (httpCode == 200) { - // WiFiClient * stream = http->getStreamPtr(); +// if (httpCode == 200) { +// // WiFiClient * stream = http->getStreamPtr(); - JsonDocument filter; +// JsonDocument filter; - JsonObject filter_assets_0 = filter["assets"].add(); - filter_assets_0["name"] = true; - filter_assets_0["browser_download_url"] = true; +// JsonObject filter_assets_0 = filter["assets"].add(); +// filter_assets_0["name"] = true; +// filter_assets_0["browser_download_url"] = true; - JsonDocument doc; +// JsonDocument doc; - DeserializationError error = deserializeJson( - doc, http.getStream(), DeserializationOption::Filter(filter)); +// DeserializationError error = deserializeJson( +// doc, http.getStream(), DeserializationOption::Filter(filter)); - if (error) { - Serial.print("deserializeJson() failed: "); - Serial.println(error.c_str()); - return; - } +// if (error) { +// Serial.print("deserializeJson() failed: "); +// Serial.println(error.c_str()); +// return; +// } - String downloadUrl; - for (JsonObject asset : doc["assets"].as()) { - if (asset["name"].as().compareTo("firmware.bin") == 0) { - downloadUrl = asset["browser_download_url"].as(); - break; - } - } +// String downloadUrl; +// for (JsonObject asset : doc["assets"].as()) { +// if (asset["name"].as().compareTo("firmware.bin") == 0) { +// downloadUrl = asset["browser_download_url"].as(); +// break; +// } +// } - Serial.printf("Download update from %s", downloadUrl); +// Serial.printf("Download update from %s", downloadUrl); - // esp_http_client_config_t config = { - // .url = CONFIG_FIRMWARE_UPGRADE_URL, - // }; - // esp_https_ota_config_t ota_config = { - // .http_config = &config, - // }; - // esp_err_t ret = esp_https_ota(&ota_config); - // if (ret == ESP_OK) - // { - // esp_restart(); - // } - } -} +// // esp_http_client_config_t config = { +// // .url = CONFIG_FIRMWARE_UPGRADE_URL, +// // }; +// // esp_https_ota_config_t ota_config = { +// // .http_config = &config, +// // }; +// // esp_err_t ret = esp_https_ota(&ota_config); +// // if (ret == ESP_OK) +// // { +// // esp_restart(); +// // } +// } +// } void onOTAError(ota_error_t error) { Serial.println(F("\nOTA update error, restarting")); diff --git a/src/lib/ota.hpp b/src/lib/ota.hpp index 42f28cc..a3c4ef6 100644 --- a/src/lib/ota.hpp +++ b/src/lib/ota.hpp @@ -8,7 +8,7 @@ void setupOTA(); void onOTAStart(); void handleOTATask(void *parameter); void onOTAProgress(unsigned int progress, unsigned int total); -void downloadUpdate(); +// void downloadUpdate(); void onOTAError(ota_error_t error); void onOTAComplete(); diff --git a/src/lib/price_fetch.cpp b/src/lib/price_fetch.cpp deleted file mode 100644 index d2ddf67..0000000 --- a/src/lib/price_fetch.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "price_fetch.hpp" - -const PROGMEM char *cgApiUrl = - "https://api.coingecko.com/api/v3/simple/" - "price?ids=bitcoin&vs_currencies=usd%2Ceur"; - -TaskHandle_t priceFetchTaskHandle; - -void taskPriceFetch(void *pvParameters) { - WiFiClientSecure *client = new WiFiClientSecure; - client->setInsecure(); - for (;;) { - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - - HTTPClient *http = new HTTPClient(); - http->setUserAgent(USER_AGENT); - - // Send HTTP request to CoinGecko API - http->begin(*client, cgApiUrl); - - int httpCode = http->GET(); - - // Parse JSON response and extract average price - uint usdPrice, eurPrice; - if (httpCode == 200) { - String payload = http->getString(); - JsonDocument doc; - deserializeJson(doc, payload); - // usdPrice = doc["bitcoin"]["usd"]; - eurPrice = doc["bitcoin"]["eur"].as(); - - setPrice(eurPrice, CURRENCY_EUR); - if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER || - getCurrentScreen() == SCREEN_SATS_PER_CURRENCY || - getCurrentScreen() == SCREEN_MARKET_CAP)) { - WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0}; - xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); - } - - preferences.putUInt("lastPrice", eurPrice); - } else { - Serial.print( - F("Error retrieving BTC/USD price (CoinGecko). HTTP status code: ")); - Serial.println(httpCode); - if (httpCode == -1) { - WiFi.reconnect(); - } - } - } -} - -void setupPriceFetchTask() { - xTaskCreate(taskPriceFetch, "priceFetch", (6 * 1024), NULL, tskIDLE_PRIORITY, - &priceFetchTaskHandle); - - xTaskNotifyGive(priceFetchTaskHandle); -} \ No newline at end of file diff --git a/src/lib/price_fetch.hpp b/src/lib/price_fetch.hpp deleted file mode 100644 index 7016dda..0000000 --- a/src/lib/price_fetch.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include - -#include "lib/config.hpp" -#include "lib/shared.hpp" - -extern TaskHandle_t priceFetchTaskHandle; - -void setupPriceFetchTask(); -void taskPriceFetch(void *pvParameters); \ No newline at end of file diff --git a/src/lib/price_notify.cpp b/src/lib/price_notify.cpp index f5ad972..d6a1e71 100644 --- a/src/lib/price_notify.cpp +++ b/src/lib/price_notify.cpp @@ -5,6 +5,39 @@ const char *wsOwnServerV2 = "wss://ws-staging.btclock.dev/api/v2/ws"; const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin"; +const char* coincapWsCert = R"EOF( +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- +)EOF"; // WebsocketsClient client; esp_websocket_client_handle_t clientPrice = NULL; @@ -14,6 +47,7 @@ unsigned long int lastPriceUpdate; bool priceNotifyInit = false; std::map currencyMap; std::map lastUpdateMap; +WebSocketsClient priceNotifyWs; void setupPriceNotify() { @@ -26,14 +60,51 @@ void setupPriceNotify() { config = {.uri = wsServerPrice, .user_agent = USER_AGENT}; + config.cert_pem = coincapWsCert; + config.task_stack = (6*1024); } clientPrice = esp_websocket_client_init(&config); esp_websocket_register_events(clientPrice, WEBSOCKET_EVENT_ANY, onWebsocketPriceEvent, clientPrice); esp_websocket_client_start(clientPrice); + + // priceNotifyWs.beginSSL("ws.coincap.io", 443, "/prices?assets=bitcoin"); + // priceNotifyWs.onEvent(onWebsocketPriceEvent); + // priceNotifyWs.setReconnectInterval(5000); + // priceNotifyWs.enableHeartbeat(15000, 3000, 2); } + +// void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length) { +// switch(type) { +// case WStype_DISCONNECTED: +// Serial.printf("[WSc] Disconnected!\n"); +// break; +// case WStype_CONNECTED: +// { +// Serial.printf("[WSc] Connected to url: %s\n", payload); + + +// break; +// } +// case WStype_TEXT: +// String message = String((char*)payload); +// onWebsocketPriceMessage(message); +// break; +// case WStype_BIN: +// break; +// case WStype_ERROR: +// case WStype_FRAGMENT_TEXT_START: +// case WStype_FRAGMENT_BIN_START: +// case WStype_FRAGMENT: +// case WStype_PING: +// case WStype_PONG: +// case WStype_FRAGMENT_FIN: +// break; +// } +// } + void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { @@ -83,7 +154,7 @@ void processNewPrice(uint newPrice, char currency) "minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE); uint currentTime = esp_timer_get_time() / 1000000; - if (lastUpdateMap.find(currency) == lastUpdateMap.end()|| + if (lastUpdateMap.find(currency) == lastUpdateMap.end() || (currentTime - lastUpdateMap[currency]) > minSecPriceUpd) { // const unsigned long oldPrice = currentPrice; @@ -108,22 +179,26 @@ void processNewPrice(uint newPrice, char currency) uint getLastPriceUpdate(char currency) { - if (lastUpdateMap.find(currency) == lastUpdateMap.end()) { + if (lastUpdateMap.find(currency) == lastUpdateMap.end()) + { return 0; } return lastUpdateMap[currency]; } -uint getPrice(char currency) { - if (currencyMap.find(currency) == currencyMap.end()) { +uint getPrice(char currency) +{ + if (currencyMap.find(currency) == currencyMap.end()) + { return 0; } - return currencyMap[currency]; + return currencyMap[currency]; } -void setPrice(uint newPrice, char currency) { - currencyMap[currency] = newPrice; +void setPrice(uint newPrice, char currency) +{ + currencyMap[currency] = newPrice; } bool isPriceNotifyConnected() diff --git a/src/lib/price_notify.hpp b/src/lib/price_notify.hpp index 541f899..4aad356 100644 --- a/src/lib/price_notify.hpp +++ b/src/lib/price_notify.hpp @@ -12,6 +12,8 @@ void setupPriceNotify(); void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data); +//void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length); + void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data); uint getPrice(char currency); diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 13e93b5..091a6e0 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -126,9 +126,6 @@ void IRAM_ATTR minuteTimerISR(void *arg) { // vTaskNotifyGiveFromISR(timeUpdateTaskHandle, &xHigherPriorityTaskWoken); WorkItem timeUpdate = {TASK_TIME_UPDATE, 0}; xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken); - if (priceFetchTaskHandle != NULL) { - vTaskNotifyGiveFromISR(priceFetchTaskHandle, &xHigherPriorityTaskWoken); - } if (bitaxeFetchTaskHandle != NULL) { vTaskNotifyGiveFromISR(bitaxeFetchTaskHandle, &xHigherPriorityTaskWoken); diff --git a/src/lib/screen_handler.hpp b/src/lib/screen_handler.hpp index a5c8f8e..91e824a 100644 --- a/src/lib/screen_handler.hpp +++ b/src/lib/screen_handler.hpp @@ -8,7 +8,6 @@ #include #include "lib/epd.hpp" -#include "lib/price_fetch.hpp" #include "lib/shared.hpp" // extern TaskHandle_t priceUpdateTaskHandle; diff --git a/src/lib/shared.cpp b/src/lib/shared.cpp index e6acfab..8a6b470 100644 --- a/src/lib/shared.cpp +++ b/src/lib/shared.cpp @@ -1,10 +1,74 @@ #include "shared.hpp" +const char *github_root_ca = + "-----BEGIN CERTIFICATE-----\n" + "MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL\n" + "MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl\n" + "eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT\n" + "JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx\n" + "MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT\n" + "Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg\n" + "VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm\n" + "aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo\n" + "I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng\n" + "o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G\n" + "A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD\n" + "VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB\n" + "zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW\n" + "RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=\n" + "-----END CERTIFICATE-----\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh\n" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" + "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\n" + "MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT\n" + "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" + "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG\n" + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI\n" + "2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx\n" + "1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ\n" + "q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz\n" + "tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ\n" + "vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP\n" + "BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV\n" + "5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY\n" + "1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4\n" + "NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG\n" + "Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91\n" + "8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe\n" + "pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\n" + "MrY=\n" + "-----END CERTIFICATE-----\n"; + #ifdef TEST_SCREENS -uint8_t input_buffer[3 * input_buffer_pixels]; // up to depth 24 -uint8_t output_row_mono_buffer[max_row_width / 8]; // buffer for at least one row of b/w bits -uint8_t output_row_color_buffer[max_row_width / 8]; // buffer for at least one row of color bits -uint8_t mono_palette_buffer[max_palette_pixels / 8]; // palette buffer for depth <= 8 b/w +uint8_t input_buffer[3 * input_buffer_pixels]; // up to depth 24 +uint8_t output_row_mono_buffer[max_row_width / 8]; // buffer for at least one row of b/w bits +uint8_t output_row_color_buffer[max_row_width / 8]; // buffer for at least one row of color bits +uint8_t mono_palette_buffer[max_palette_pixels / 8]; // palette buffer for depth <= 8 b/w uint8_t color_palette_buffer[max_palette_pixels / 8]; // palette buffer for depth <= 8 c/w -uint16_t rgb_palette_buffer[max_palette_pixels]; // palette buffer for depth <= 8 for buffered graphics, needed for 7-color display -#endif \ No newline at end of file +uint16_t rgb_palette_buffer[max_palette_pixels]; // palette buffer for depth <= 8 for buffered graphics, needed for 7-color display +#endif + +// Function to calculate SHA-256 hash +String calculateSHA256(uint8_t *data, size_t len) +{ + byte shaResult[32]; + mbedtls_md_context_t ctx; + mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256; + + mbedtls_md_init(&ctx); + mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0); + mbedtls_md_starts(&ctx); + mbedtls_md_update(&ctx, data, len); + mbedtls_md_finish(&ctx, shaResult); + mbedtls_md_free(&ctx); + + char sha256_str[65]; + for (int i = 0; i < 32; i++) + { + sprintf(sha256_str + (i * 2), "%02x", shaResult[i]); + } + sha256_str[64] = 0; + + return String(sha256_str); +} diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index 5c111df..26c4c95 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -65,7 +66,16 @@ const PROGMEM int screens[SCREEN_COUNT] = { const int usPerSecond = 1000000; const int usPerMinute = 60 * usPerSecond; +extern const char *github_root_ca; + +const PROGMEM char UPDATE_FIRMWARE = 0; +const PROGMEM char UPDATE_WEBUI = 1; + + struct ScreenMapping { int value; const char* name; -}; \ No newline at end of file +}; + +String calculateSHA256(uint8_t* data, size_t len); + diff --git a/src/lib/v2_notify.cpp b/src/lib/v2_notify.cpp index e23c0af..13d302d 100644 --- a/src/lib/v2_notify.cpp +++ b/src/lib/v2_notify.cpp @@ -9,7 +9,9 @@ void setupV2Notify() if ( preferences.getBool("stagingSource", DEFAULT_STAGING_SOURCE)) { Serial.println(F("Connecting to V2 staging source")); hostname = "ws-staging.btclock.dev"; - } + } else { + Serial.println(F("Connecting to V2 source")); + } webSocket.beginSSL(hostname, 443, "/api/v2/ws"); webSocket.onEvent(onWebsocketV2Event); @@ -120,7 +122,7 @@ void handleV2Message(JsonDocument doc) { processNewPrice(newPrice, getCurrencyChar(currency)); } - } + } } void taskV2Notify(void *pvParameters) { diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index bad307f..392e6c7 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -86,6 +86,8 @@ void setupWebserver() { server.on("/upload/firmware", HTTP_POST, onFirmwareUpdate, asyncFirmwareUpdateHandler); server.on("/upload/webui", HTTP_POST, onFirmwareUpdate, asyncWebuiUpdateHandler); + // server.on("/update/webui", HTTP_GET, onUpdateWebUi); + // server.on("/update/firmware", HTTP_GET, onUpdateFirmware); } server.on("/api/restart", HTTP_GET, onApiRestart); @@ -662,7 +664,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["mcapBigChar"] = preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR); root["mdnsEnabled"] = preferences.getBool("mdnsEnabled", DEFAULT_MDNS_ENABLED); root["otaEnabled"] = preferences.getBool("otaEnabled", DEFAULT_OTA_ENABLED); - root["fetchEurPrice"] = preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE); + // root["fetchEurPrice"] = preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE); root["useSatsSymbol"] = preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL); root["useBlkCountdown"] = preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN); root["suffixPrice"] = preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE); @@ -1043,6 +1045,167 @@ void onApiShowCurrency(AsyncWebServerRequest *request) request->send(404); } +String getLatestRelease(const String &fileToDownload) +{ + + // const char *fileToDownload = "littlefs.bin"; + + String releaseUrl = "https://api.github.com/repos/btclock/btclock_v3/releases/latest"; + WiFiClientSecure client; + client.setCACert(github_root_ca); + HTTPClient http; + http.begin(client, releaseUrl); + http.setUserAgent(USER_AGENT); + + int httpCode = http.GET(); + + String downloadUrl = ""; + + if (httpCode > 0) + { + String payload = http.getString(); + + JsonDocument doc; + deserializeJson(doc, payload); + + JsonArray assets = doc["assets"]; + + for (JsonObject asset : assets) + { + if (asset["name"] == fileToDownload) + { + downloadUrl = asset["browser_download_url"].as(); + break; + } + } + Serial.printf("Latest release URL: %s\r\n", downloadUrl.c_str()); + } + return downloadUrl; +} + +void onUpdateWebUi(AsyncWebServerRequest *request) +{ + request->send(downloadUpdateHandler(UPDATE_WEBUI)); +} + +void onUpdateFirmware(AsyncWebServerRequest *request) +{ + request->send(downloadUpdateHandler(UPDATE_FIRMWARE)); +} + +int downloadUpdateHandler(char updateType) +{ + WiFiClientSecure client; + client.setCACert(github_root_ca); + HTTPClient http; + http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); + + String latestRelease = ""; + + switch (updateType) + { + case UPDATE_FIRMWARE: + latestRelease = getLatestRelease(getFirmwareFilename()); + break; + case UPDATE_WEBUI: + latestRelease = getLatestRelease("littlefs.bin"); + break; + } + + if (latestRelease.equals("")) + { + return 503; + } + + http.begin(client, latestRelease); + http.setUserAgent(USER_AGENT); + + int httpCode = http.GET(); + if (httpCode == HTTP_CODE_OK) + { + int contentLength = http.getSize(); + if (contentLength > 0) + { + uint8_t *buffer = (uint8_t *)malloc(contentLength); + if (buffer) + { + WiFiClient *stream = http.getStreamPtr(); + size_t written = stream->readBytes(buffer, contentLength); + + if (written == contentLength) + { + String calculated_sha256 = calculateSHA256(buffer, contentLength); + Serial.print("Checksum is "); + Serial.println(calculated_sha256); + if (true) + { + Serial.println("Checksum verified. Proceeding with update."); + + Update.onProgress(onOTAProgress); + + int updateType = U_FLASH; + + switch (updateType) + { + case UPDATE_WEBUI: + updateType = U_SPIFFS; + break; + default: + { + updateType = U_FLASH; + } + } + + if (Update.begin(contentLength, updateType)) + { + Update.write(buffer, contentLength); + if (Update.end()) + { + Serial.println("Update complete. Rebooting."); + ESP.restart(); + } + else + { + Serial.println("Error in update process."); + } + } + else + { + Serial.println("Not enough space to begin OTA"); + } + } + else + { + Serial.println("Checksum mismatch. Aborting update."); + } + } + else + { + Serial.println("Error downloading firmware"); + } + free(buffer); + } + else + { + Serial.println("Not enough memory to allocate buffer"); + } + } + else + { + Serial.println("Invalid content length"); + } + } + else + { + Serial.print(httpCode); + Serial.println("Error on HTTP request"); + return 503; + } + http.end(); + + return 200; +} + #ifdef HAS_FRONTLIGHT void onApiFrontlightOn(AsyncWebServerRequest *request) { diff --git a/src/lib/webserver.hpp b/src/lib/webserver.hpp index 3f71ac9..546930a 100644 --- a/src/lib/webserver.hpp +++ b/src/lib/webserver.hpp @@ -21,10 +21,17 @@ void stopWebServer(); void setupWebserver(); bool processEpdColorSettings(AsyncWebServerRequest *request); + + void onApiStatus(AsyncWebServerRequest *request); void onApiSystemStatus(AsyncWebServerRequest *request); void onApiSetWifiTxPower(AsyncWebServerRequest *request); +void onUpdateWebUi(AsyncWebServerRequest *request); +void onUpdateFirmware(AsyncWebServerRequest *request); +int downloadUpdateHandler(char updateType); + +String getLatestRelease(const String& fileToDownload); void onApiScreenNext(AsyncWebServerRequest *request); void onApiScreenPrevious(AsyncWebServerRequest *request); From 5d5b09f56c66809cd7501cb2e7ac34b996292adb Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 11 Sep 2024 17:40:44 +0200 Subject: [PATCH 014/130] Prepare for automatic OTA updates --- .github/workflows/tagging.yml | 5 +- src/lib/ota.cpp | 384 ++++++++++++++++++++++++++++------ src/lib/ota.hpp | 18 +- src/lib/shared.cpp | 37 ++++ src/lib/shared.hpp | 3 +- src/lib/webserver.cpp | 187 +++-------------- src/lib/webserver.hpp | 2 - 7 files changed, 409 insertions(+), 227 deletions(-) diff --git a/.github/workflows/tagging.yml b/.github/workflows/tagging.yml index d0fe113..1418356 100644 --- a/.github/workflows/tagging.yml +++ b/.github/workflows/tagging.yml @@ -56,7 +56,10 @@ jobs: run: mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && esptool.py --chip ${{ matrix.chip.version }} merge_bin -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin --flash_mode dio 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin 0xe000 .pio/boot_app0.bin 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin 0x369000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin - name: Create checksum for merged binary - run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.sha256 + run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin.sha256 + + - name: Create checksum for littlefs partition + run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin.sha256 - name: Copy all artifacts to output folder run: cp .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin .pio/boot_app0.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }} diff --git a/src/lib/ota.cpp b/src/lib/ota.cpp index 709de61..92838db 100644 --- a/src/lib/ota.cpp +++ b/src/lib/ota.cpp @@ -2,9 +2,12 @@ TaskHandle_t taskOtaHandle = NULL; bool isOtaUpdating = false; +QueueHandle_t otaQueue; -void setupOTA() { - if (preferences.getBool("otaEnabled", DEFAULT_OTA_ENABLED)) { +void setupOTA() +{ + if (preferences.getBool("otaEnabled", DEFAULT_OTA_ENABLED)) + { ArduinoOTA.onStart(onOTAStart); ArduinoOTA.onProgress(onOTAProgress); @@ -16,31 +19,38 @@ void setupOTA() { ArduinoOTA.setRebootOnSuccess(false); ArduinoOTA.begin(); // downloadUpdate(); + otaQueue = xQueueCreate(1, sizeof(UpdateMessage)); - xTaskCreate(handleOTATask, "handleOTA", 4096, NULL, tskIDLE_PRIORITY, + xTaskCreate(handleOTATask, "handleOTA", 8192, NULL, 20, &taskOtaHandle); } } -void onOTAProgress(unsigned int progress, unsigned int total) { +void onOTAProgress(unsigned int progress, unsigned int total) +{ uint percentage = progress / (total / 100); pixels.fill(pixels.Color(0, 255, 0)); - if (percentage < 100) { + if (percentage < 100) + { pixels.setPixelColor(0, pixels.Color(0, 0, 0)); } - if (percentage < 75) { + if (percentage < 75) + { pixels.setPixelColor(1, pixels.Color(0, 0, 0)); } - if (percentage < 50) { + if (percentage < 50) + { pixels.setPixelColor(2, pixels.Color(0, 0, 0)); } - if (percentage < 25) { + if (percentage < 25) + { pixels.setPixelColor(3, pixels.Color(0, 0, 0)); } pixels.show(); } -void onOTAStart() { +void onOTAStart() +{ forceFullRefresh(); std::array epdContent = {"U", "P", "D", "A", "T", "E", "!"}; @@ -58,76 +68,296 @@ void onOTAStart() { vTaskSuspend(ledTaskHandle); vTaskSuspend(buttonTaskHandle); - stopWebServer(); + // stopWebServer(); stopBlockNotify(); stopPriceNotify(); } -void handleOTATask(void *parameter) { - for (;;) { - ArduinoOTA.handle(); // Allow OTA updates to occur +void handleOTATask(void *parameter) +{ + UpdateMessage msg; + + for (;;) + { + if (xQueueReceive(otaQueue, &msg, 0) == pdTRUE) + { + int result = downloadUpdateHandler(msg.updateType); + } + + ArduinoOTA.handle(); // Allow OTA updates to occur vTaskDelay(pdMS_TO_TICKS(2000)); } } -// void downloadUpdate() { -// WiFiClientSecure client; -// client.setInsecure(); -// HTTPClient http; -// http.setUserAgent(USER_AGENT); +String getLatestRelease(const String &fileToDownload) +{ + String releaseUrl = "https://api.github.com/repos/btclock/btclock_v3/releases/latest"; + WiFiClientSecure client; + client.setCACert(github_root_ca); + HTTPClient http; + http.begin(client, releaseUrl); + http.setUserAgent(USER_AGENT); -// // Send HTTP request to CoinGecko API -// http.useHTTP10(true); + int httpCode = http.GET(); -// http.begin(client, -// "https://api.github.com/repos/btclock/btclock_v3/releases/latest"); -// int httpCode = http.GET(); + String downloadUrl = ""; -// if (httpCode == 200) { -// // WiFiClient * stream = http->getStreamPtr(); + if (httpCode > 0) + { + String payload = http.getString(); -// JsonDocument filter; + JsonDocument doc; + deserializeJson(doc, payload); -// JsonObject filter_assets_0 = filter["assets"].add(); -// filter_assets_0["name"] = true; -// filter_assets_0["browser_download_url"] = true; + JsonArray assets = doc["assets"]; -// JsonDocument doc; + for (JsonObject asset : assets) + { + if (asset["name"] == fileToDownload) + { + downloadUrl = asset["browser_download_url"].as(); + break; + } + } + Serial.printf("Latest release URL: %s\r\n", downloadUrl.c_str()); + } + return downloadUrl; +} -// DeserializationError error = deserializeJson( -// doc, http.getStream(), DeserializationOption::Filter(filter)); +int downloadUpdateHandler(char updateType) +{ + WiFiClientSecure client; + client.setCACert(github_root_ca); + HTTPClient http; + http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); -// if (error) { -// Serial.print("deserializeJson() failed: "); -// Serial.println(error.c_str()); -// return; -// } + String latestRelease = ""; -// String downloadUrl; -// for (JsonObject asset : doc["assets"].as()) { -// if (asset["name"].as().compareTo("firmware.bin") == 0) { -// downloadUrl = asset["browser_download_url"].as(); -// break; -// } -// } + switch (updateType) + { + case UPDATE_FIRMWARE: + { + latestRelease = getLatestRelease(getFirmwareFilename()); + } + break; + case UPDATE_WEBUI: + { + latestRelease = getLatestRelease("littlefs.bin"); + updateWebUi(latestRelease, U_SPIFFS); + return 0; + } + break; + } -// Serial.printf("Download update from %s", downloadUrl); + if (latestRelease.isEmpty()) + { + return 503; + } + // First, download the expected SHA256 + String expectedSHA256 = downloadSHA256(getFirmwareFilename()); + if (expectedSHA256.isEmpty()) + { + Serial.println("Failed to get SHA256 checksum. Aborting update."); + return false; + } -// // esp_http_client_config_t config = { -// // .url = CONFIG_FIRMWARE_UPGRADE_URL, -// // }; -// // esp_https_ota_config_t ota_config = { -// // .http_config = &config, -// // }; -// // esp_err_t ret = esp_https_ota(&ota_config); -// // if (ret == ESP_OK) -// // { -// // esp_restart(); -// // } -// } -// } + http.begin(client, latestRelease); + http.setUserAgent(USER_AGENT); -void onOTAError(ota_error_t error) { + int httpCode = http.GET(); + if (httpCode == HTTP_CODE_OK) + { + int contentLength = http.getSize(); + if (contentLength > 0) + { + // Allocate memory to store the firmware + uint8_t *firmware = (uint8_t *)malloc(contentLength); + if (!firmware) + { + Serial.println(F("Not enough memory to store firmware")); + return false; + } + + WiFiClient *stream = http.getStreamPtr(); + size_t bytesRead = 0; + while (bytesRead < contentLength) + { + size_t available = stream->available(); + if (available) + { + size_t readBytes = stream->readBytes(firmware + bytesRead, available); + bytesRead += readBytes; + } + yield(); // Allow background tasks to run + } + + if (bytesRead != contentLength) + { + Serial.println("Failed to read entire firmware"); + free(firmware); + return false; + } + + // Calculate SHA256 + String calculated_sha256 = calculateSHA256(firmware, contentLength); + + Serial.print("Calculated checksum: "); + Serial.println(calculated_sha256); + Serial.print("Expected checksum: "); + Serial.println(expectedSHA256); + + if (calculated_sha256 != expectedSHA256) + { + Serial.println("Checksum mismatch. Aborting update."); + free(firmware); + return false; + } + + Update.onProgress(onOTAProgress); + + int updateType = (updateType == UPDATE_WEBUI) ? U_SPIFFS : U_FLASH; + + if (Update.begin(contentLength, updateType)) + { + size_t written = Update.writeStream(*stream); + + if (written == contentLength) + { + Serial.println("Written : " + String(written) + " successfully"); + } + else + { + Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?"); + } + + if (Update.end()) + { + Serial.println("OTA done!"); + if (Update.isFinished()) + { + Serial.println("Update successfully completed. Rebooting."); + ESP.restart(); + } + else + { + Serial.println("Update not finished? Something went wrong!"); + } + } + else + { + Serial.println("Error Occurred. Error #: " + String(Update.getError())); + } + } + else + { + Serial.println("Not enough space to begin OTA"); + } + } + else + { + Serial.println("Invalid content length"); + } + } + else + { + Serial.printf("HTTP error: %d\n", httpCode); + return 503; + } + http.end(); + + return 200; +} + +void updateWebUi(String latestRelease, int command) +{ + WiFiClientSecure client; + client.setCACert(github_root_ca); + HTTPClient http; + http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); + http.begin(client, latestRelease); + http.setUserAgent(USER_AGENT); + + int httpCode = http.GET(); + if (httpCode == HTTP_CODE_OK) + { + int contentLength = http.getSize(); + if (contentLength > 0) + { + uint8_t *buffer = (uint8_t *)malloc(contentLength); + if (buffer) + { + WiFiClient *stream = http.getStreamPtr(); + size_t written = stream->readBytes(buffer, contentLength); + + if (written == contentLength) + { + String expectedSHA256 = ""; + if (command == U_FLASH) + { + expectedSHA256 = downloadSHA256(getFirmwareFilename()); + Serial.print("Expected checksum: "); + Serial.println(expectedSHA256); + } + + String calculated_sha256 = calculateSHA256(buffer, contentLength); + Serial.print("Checksum is "); + Serial.println(calculated_sha256); + if ((command == U_FLASH && expectedSHA256.equals(calculated_sha256)) || command == U_SPIFFS) + { + Serial.println("Checksum verified. Proceeding with update."); + + Update.onProgress(onOTAProgress); + + if (Update.begin(contentLength, command)) + { + onOTAStart(); + + Update.write(buffer, contentLength); + if (Update.end()) + { + Serial.println("Update complete. Rebooting."); + ESP.restart(); + } + else + { + Serial.println("Error in update process."); + } + } + else + { + Serial.println("Not enough space to begin OTA"); + } + } + else + { + Serial.println("Checksum mismatch. Aborting update."); + } + } + else + { + Serial.println("Error downloading firmware"); + } + free(buffer); + } + else + { + Serial.println("Not enough memory to allocate buffer"); + } + } + else + { + Serial.println("Invalid content length"); + } + } + else + { + Serial.print(httpCode); + Serial.println("Error on HTTP request"); + } +} + +void onOTAError(ota_error_t error) +{ Serial.println(F("\nOTA update error, restarting")); Wire.end(); SPI.end(); @@ -136,7 +366,8 @@ void onOTAError(ota_error_t error) { ESP.restart(); } -void onOTAComplete() { +void onOTAComplete() +{ Serial.println(F("\nOTA update finished")); Wire.end(); SPI.end(); @@ -144,6 +375,37 @@ void onOTAComplete() { ESP.restart(); } -bool getIsOTAUpdating() { +bool getIsOTAUpdating() +{ return isOtaUpdating; +} + +String downloadSHA256(const String &filename) +{ + String sha256Url = getLatestRelease(filename + ".sha256"); + if (sha256Url.isEmpty()) + { + Serial.println("Failed to get SHA256 file URL"); + return ""; + } + + WiFiClientSecure client; + client.setCACert(github_root_ca); + HTTPClient http; + http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); + http.begin(client, sha256Url); + http.setUserAgent(USER_AGENT); + + int httpCode = http.GET(); + if (httpCode == HTTP_CODE_OK) + { + String sha256 = http.getString(); + sha256.trim(); // Remove any whitespace or newline characters + return sha256; + } + else + { + Serial.printf("Failed to download SHA256 file. HTTP error: %d\n", httpCode); + return ""; + } } \ No newline at end of file diff --git a/src/lib/ota.hpp b/src/lib/ota.hpp index a3c4ef6..fd29473 100644 --- a/src/lib/ota.hpp +++ b/src/lib/ota.hpp @@ -1,9 +1,20 @@ +#pragma once + #include #include #include "lib/config.hpp" #include "lib/shared.hpp" +#ifndef UPDATE_MESSAGE_HPP +#define UPDATE_MESSAGE_HPP +typedef struct { + char updateType; +} UpdateMessage; +#endif + +extern QueueHandle_t otaQueue; + void setupOTA(); void onOTAStart(); void handleOTATask(void *parameter); @@ -11,5 +22,10 @@ void onOTAProgress(unsigned int progress, unsigned int total); // void downloadUpdate(); void onOTAError(ota_error_t error); void onOTAComplete(); +int downloadUpdateHandler(char updateType); +String getLatestRelease(const String& fileToDownload); -bool getIsOTAUpdating(); \ No newline at end of file +bool getIsOTAUpdating(); + +void updateWebUi(String latestRelease, int command); +String downloadSHA256(const String& filename); \ No newline at end of file diff --git a/src/lib/shared.cpp b/src/lib/shared.cpp index 8a6b470..597d803 100644 --- a/src/lib/shared.cpp +++ b/src/lib/shared.cpp @@ -72,3 +72,40 @@ String calculateSHA256(uint8_t *data, size_t len) return String(sha256_str); } + +String calculateSHA256(WiFiClient *stream, size_t contentLength) { + mbedtls_md_context_t ctx; + mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256; + + mbedtls_md_init(&ctx); + mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0); + mbedtls_md_starts(&ctx); + + uint8_t buff[1024]; + size_t bytesRead = 0; + + while (bytesRead < contentLength) { + size_t toRead = min((size_t)(contentLength - bytesRead), sizeof(buff)); + size_t readBytes = stream->readBytes(buff, toRead); + + if (readBytes == 0) { + break; + } + + mbedtls_md_update(&ctx, buff, readBytes); + bytesRead += readBytes; + } + + byte shaResult[32]; + mbedtls_md_finish(&ctx, shaResult); + mbedtls_md_free(&ctx); + + String result = ""; + for (int i = 0; i < sizeof(shaResult); i++) { + char str[3]; + sprintf(str, "%02x", (int)shaResult[i]); + result += str; + } + + return result; +} \ No newline at end of file diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index 26c4c95..dba240c 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -78,4 +79,4 @@ struct ScreenMapping { }; String calculateSHA256(uint8_t* data, size_t len); - +String calculateSHA256(WiFiClient *stream, size_t contentLength); \ No newline at end of file diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 392e6c7..a789e75 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -142,6 +142,32 @@ void onFirmwareUpdate(AsyncWebServerRequest *request) request->send(response); } +void onUpdateWebUi(AsyncWebServerRequest *request) +{ + UpdateMessage msg = {UPDATE_WEBUI}; + if (xQueueSend(otaQueue, &msg, 0) == pdTRUE) + { + request->send(200, "text/plain", "WebUI update triggered"); + } + else + { + request->send(503, "text/plain", "Update already in progress"); + } +} + +void onUpdateFirmware(AsyncWebServerRequest *request) +{ + UpdateMessage msg = {UPDATE_FIRMWARE}; + if (xQueueSend(otaQueue, &msg, 0) == pdTRUE) + { + request->send(200, "text/plain", "Firmware update triggered"); + } + else + { + request->send(503, "text/plain", "Update already in progress"); + } +} + void asyncWebuiUpdateHandler(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { asyncFileUpdateHandler(request, filename, index, data, len, final, U_SPIFFS); @@ -1045,167 +1071,6 @@ void onApiShowCurrency(AsyncWebServerRequest *request) request->send(404); } -String getLatestRelease(const String &fileToDownload) -{ - - // const char *fileToDownload = "littlefs.bin"; - - String releaseUrl = "https://api.github.com/repos/btclock/btclock_v3/releases/latest"; - WiFiClientSecure client; - client.setCACert(github_root_ca); - HTTPClient http; - http.begin(client, releaseUrl); - http.setUserAgent(USER_AGENT); - - int httpCode = http.GET(); - - String downloadUrl = ""; - - if (httpCode > 0) - { - String payload = http.getString(); - - JsonDocument doc; - deserializeJson(doc, payload); - - JsonArray assets = doc["assets"]; - - for (JsonObject asset : assets) - { - if (asset["name"] == fileToDownload) - { - downloadUrl = asset["browser_download_url"].as(); - break; - } - } - Serial.printf("Latest release URL: %s\r\n", downloadUrl.c_str()); - } - return downloadUrl; -} - -void onUpdateWebUi(AsyncWebServerRequest *request) -{ - request->send(downloadUpdateHandler(UPDATE_WEBUI)); -} - -void onUpdateFirmware(AsyncWebServerRequest *request) -{ - request->send(downloadUpdateHandler(UPDATE_FIRMWARE)); -} - -int downloadUpdateHandler(char updateType) -{ - WiFiClientSecure client; - client.setCACert(github_root_ca); - HTTPClient http; - http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); - - String latestRelease = ""; - - switch (updateType) - { - case UPDATE_FIRMWARE: - latestRelease = getLatestRelease(getFirmwareFilename()); - break; - case UPDATE_WEBUI: - latestRelease = getLatestRelease("littlefs.bin"); - break; - } - - if (latestRelease.equals("")) - { - return 503; - } - - http.begin(client, latestRelease); - http.setUserAgent(USER_AGENT); - - int httpCode = http.GET(); - if (httpCode == HTTP_CODE_OK) - { - int contentLength = http.getSize(); - if (contentLength > 0) - { - uint8_t *buffer = (uint8_t *)malloc(contentLength); - if (buffer) - { - WiFiClient *stream = http.getStreamPtr(); - size_t written = stream->readBytes(buffer, contentLength); - - if (written == contentLength) - { - String calculated_sha256 = calculateSHA256(buffer, contentLength); - Serial.print("Checksum is "); - Serial.println(calculated_sha256); - if (true) - { - Serial.println("Checksum verified. Proceeding with update."); - - Update.onProgress(onOTAProgress); - - int updateType = U_FLASH; - - switch (updateType) - { - case UPDATE_WEBUI: - updateType = U_SPIFFS; - break; - default: - { - updateType = U_FLASH; - } - } - - if (Update.begin(contentLength, updateType)) - { - Update.write(buffer, contentLength); - if (Update.end()) - { - Serial.println("Update complete. Rebooting."); - ESP.restart(); - } - else - { - Serial.println("Error in update process."); - } - } - else - { - Serial.println("Not enough space to begin OTA"); - } - } - else - { - Serial.println("Checksum mismatch. Aborting update."); - } - } - else - { - Serial.println("Error downloading firmware"); - } - free(buffer); - } - else - { - Serial.println("Not enough memory to allocate buffer"); - } - } - else - { - Serial.println("Invalid content length"); - } - } - else - { - Serial.print(httpCode); - Serial.println("Error on HTTP request"); - return 503; - } - http.end(); - - return 200; -} - #ifdef HAS_FRONTLIGHT void onApiFrontlightOn(AsyncWebServerRequest *request) { diff --git a/src/lib/webserver.hpp b/src/lib/webserver.hpp index 546930a..9f47d02 100644 --- a/src/lib/webserver.hpp +++ b/src/lib/webserver.hpp @@ -29,9 +29,7 @@ void onApiSetWifiTxPower(AsyncWebServerRequest *request); void onUpdateWebUi(AsyncWebServerRequest *request); void onUpdateFirmware(AsyncWebServerRequest *request); -int downloadUpdateHandler(char updateType); -String getLatestRelease(const String& fileToDownload); void onApiScreenNext(AsyncWebServerRequest *request); void onApiScreenPrevious(AsyncWebServerRequest *request); From 283469dc4c0e8d66e2ea2759a9f791cc7ad74b24 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 11 Sep 2024 18:07:34 +0200 Subject: [PATCH 015/130] Fix github action --- .github/workflows/tagging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tagging.yml b/.github/workflows/tagging.yml index 1418356..2e232b6 100644 --- a/.github/workflows/tagging.yml +++ b/.github/workflows/tagging.yml @@ -59,7 +59,7 @@ jobs: run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin.sha256 - name: Create checksum for littlefs partition - run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin.sha256 + run: shasum -a 256 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin.sha256 - name: Copy all artifacts to output folder run: cp .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin .pio/boot_app0.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }} From d00c216126406c11d08c9c1e1a6422a2bea9bc52 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 11 Sep 2024 18:56:06 +0200 Subject: [PATCH 016/130] GitHub Workflow addition --- .github/workflows/tagging.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/tagging.yml b/.github/workflows/tagging.yml index 2e232b6..825d100 100644 --- a/.github/workflows/tagging.yml +++ b/.github/workflows/tagging.yml @@ -55,6 +55,9 @@ jobs: - name: Create merged firmware binary run: mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && esptool.py --chip ${{ matrix.chip.version }} merge_bin -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin --flash_mode dio 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin 0xe000 .pio/boot_app0.bin 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin 0x369000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin + - name: Create checksum for firmware + run: shasum -a 256 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}_firmware.bin.sha256 + - name: Create checksum for merged binary run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin.sha256 From 023ff29131436ba2a94503a3c2052c7c184a7e76 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 11 Sep 2024 20:27:40 +0200 Subject: [PATCH 017/130] Add single-click auto-update functionality --- data | 2 +- src/lib/ota.cpp | 77 +++++++++++++++++++++++++++++-------------- src/lib/ota.hpp | 10 ++++-- src/lib/shared.hpp | 7 ++-- src/lib/webserver.cpp | 24 +++----------- src/lib/webserver.hpp | 5 +-- 6 files changed, 72 insertions(+), 53 deletions(-) diff --git a/data b/data index 1c2d8dc..6c40b54 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 1c2d8dcdd0efd846f39b0f24977c982a96f16392 +Subproject commit 6c40b54273b7f7c7d6c2624d3c2a066435f27756 diff --git a/src/lib/ota.cpp b/src/lib/ota.cpp index 92838db..3a391ca 100644 --- a/src/lib/ota.cpp +++ b/src/lib/ota.cpp @@ -4,6 +4,8 @@ TaskHandle_t taskOtaHandle = NULL; bool isOtaUpdating = false; QueueHandle_t otaQueue; + + void setupOTA() { if (preferences.getBool("otaEnabled", DEFAULT_OTA_ENABLED)) @@ -65,7 +67,7 @@ void onOTAStart() vTaskSuspend(workerTaskHandle); vTaskSuspend(taskScreenRotateTaskHandle); - vTaskSuspend(ledTaskHandle); +// vTaskSuspend(ledTaskHandle); vTaskSuspend(buttonTaskHandle); // stopWebServer(); @@ -81,7 +83,18 @@ void handleOTATask(void *parameter) { if (xQueueReceive(otaQueue, &msg, 0) == pdTRUE) { - int result = downloadUpdateHandler(msg.updateType); + if (msg.updateType == UPDATE_ALL) { + int resultWebUi = downloadUpdateHandler(UPDATE_WEBUI); + int resultFw = downloadUpdateHandler(UPDATE_FIRMWARE); + + if (resultWebUi == 0 && resultFw == 0) { + ESP.restart(); + } else { + queueLedEffect(LED_FLASH_ERROR); + vTaskDelay(pdMS_TO_TICKS(3000)); + ESP.restart(); + } + } } ArduinoOTA.handle(); // Allow OTA updates to occur @@ -89,7 +102,7 @@ void handleOTATask(void *parameter) } } -String getLatestRelease(const String &fileToDownload) +ReleaseInfo getLatestRelease(const String &fileToDownload) { String releaseUrl = "https://api.github.com/repos/btclock/btclock_v3/releases/latest"; WiFiClientSecure client; @@ -100,7 +113,7 @@ String getLatestRelease(const String &fileToDownload) int httpCode = http.GET(); - String downloadUrl = ""; + ReleaseInfo info = {"", ""}; if (httpCode > 0) { @@ -113,15 +126,26 @@ String getLatestRelease(const String &fileToDownload) for (JsonObject asset : assets) { - if (asset["name"] == fileToDownload) + String assetName = asset["name"].as(); + if (assetName == fileToDownload) + { + info.fileUrl = asset["browser_download_url"].as(); + } + else if (assetName == fileToDownload + ".sha256") + { + info.checksumUrl = asset["browser_download_url"].as(); + } + + if (!info.fileUrl.isEmpty() && !info.checksumUrl.isEmpty()) { - downloadUrl = asset["browser_download_url"].as(); break; } } - Serial.printf("Latest release URL: %s\r\n", downloadUrl.c_str()); + Serial.printf("Latest release URL: %s\r\n", info.fileUrl.c_str()); + Serial.printf("Checksum URL: %s\r\n", info.checksumUrl.c_str()); } - return downloadUrl; + http.end(); + return info; } int downloadUpdateHandler(char updateType) @@ -131,7 +155,7 @@ int downloadUpdateHandler(char updateType) HTTPClient http; http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); - String latestRelease = ""; + ReleaseInfo latestRelease; switch (updateType) { @@ -143,25 +167,22 @@ int downloadUpdateHandler(char updateType) case UPDATE_WEBUI: { latestRelease = getLatestRelease("littlefs.bin"); - updateWebUi(latestRelease, U_SPIFFS); - return 0; + // updateWebUi(latestRelease.fileUrl, U_SPIFFS); + // return 0; } break; } - if (latestRelease.isEmpty()) - { - return 503; - } + // First, download the expected SHA256 - String expectedSHA256 = downloadSHA256(getFirmwareFilename()); + String expectedSHA256 = downloadSHA256(latestRelease.checksumUrl); if (expectedSHA256.isEmpty()) { Serial.println("Failed to get SHA256 checksum. Aborting update."); return false; } - http.begin(client, latestRelease); + http.begin(client, latestRelease.fileUrl); http.setUserAgent(USER_AGENT); int httpCode = http.GET(); @@ -215,19 +236,21 @@ int downloadUpdateHandler(char updateType) Update.onProgress(onOTAProgress); - int updateType = (updateType == UPDATE_WEBUI) ? U_SPIFFS : U_FLASH; - if (Update.begin(contentLength, updateType)) { - size_t written = Update.writeStream(*stream); + onOTAStart(); + size_t written = Update.write(firmware, contentLength); if (written == contentLength) { Serial.println("Written : " + String(written) + " successfully"); + free(firmware); } else { Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?"); + free(firmware); + return 503; } if (Update.end()) @@ -236,26 +259,33 @@ int downloadUpdateHandler(char updateType) if (Update.isFinished()) { Serial.println("Update successfully completed. Rebooting."); - ESP.restart(); +// ESP.restart(); } else { Serial.println("Update not finished? Something went wrong!"); + free(firmware); + return 503; } } else { Serial.println("Error Occurred. Error #: " + String(Update.getError())); + free(firmware); + return 503; } } else { Serial.println("Not enough space to begin OTA"); + free(firmware); + return 503; } } else { Serial.println("Invalid content length"); + return 503; } } else @@ -265,7 +295,7 @@ int downloadUpdateHandler(char updateType) } http.end(); - return 200; + return 0; } void updateWebUi(String latestRelease, int command) @@ -380,9 +410,8 @@ bool getIsOTAUpdating() return isOtaUpdating; } -String downloadSHA256(const String &filename) +String downloadSHA256(const String &sha256Url) { - String sha256Url = getLatestRelease(filename + ".sha256"); if (sha256Url.isEmpty()) { Serial.println("Failed to get SHA256 file URL"); diff --git a/src/lib/ota.hpp b/src/lib/ota.hpp index fd29473..516f9a1 100644 --- a/src/lib/ota.hpp +++ b/src/lib/ota.hpp @@ -15,6 +15,11 @@ typedef struct { extern QueueHandle_t otaQueue; +struct ReleaseInfo { + String fileUrl; + String checksumUrl; +}; + void setupOTA(); void onOTAStart(); void handleOTATask(void *parameter); @@ -23,9 +28,10 @@ void onOTAProgress(unsigned int progress, unsigned int total); void onOTAError(ota_error_t error); void onOTAComplete(); int downloadUpdateHandler(char updateType); -String getLatestRelease(const String& fileToDownload); +ReleaseInfo getLatestRelease(const String& fileToDownload); bool getIsOTAUpdating(); void updateWebUi(String latestRelease, int command); -String downloadSHA256(const String& filename); \ No newline at end of file +String downloadSHA256(const String& filename); + diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index dba240c..68a64b6 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -69,9 +70,9 @@ const int usPerMinute = 60 * usPerSecond; extern const char *github_root_ca; -const PROGMEM char UPDATE_FIRMWARE = 0; -const PROGMEM char UPDATE_WEBUI = 1; - +const PROGMEM char UPDATE_FIRMWARE = U_FLASH; +const PROGMEM char UPDATE_WEBUI = U_SPIFFS; +const PROGMEM char UPDATE_ALL = 99; struct ScreenMapping { int value; diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index a789e75..3d8b6da 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -86,8 +86,7 @@ void setupWebserver() { server.on("/upload/firmware", HTTP_POST, onFirmwareUpdate, asyncFirmwareUpdateHandler); server.on("/upload/webui", HTTP_POST, onFirmwareUpdate, asyncWebuiUpdateHandler); - // server.on("/update/webui", HTTP_GET, onUpdateWebUi); - // server.on("/update/firmware", HTTP_GET, onUpdateFirmware); + server.on("/api/firmware/auto_update", HTTP_GET, onAutoUpdateFirmware); } server.on("/api/restart", HTTP_GET, onApiRestart); @@ -142,29 +141,16 @@ void onFirmwareUpdate(AsyncWebServerRequest *request) request->send(response); } -void onUpdateWebUi(AsyncWebServerRequest *request) +void onAutoUpdateFirmware(AsyncWebServerRequest *request) { - UpdateMessage msg = {UPDATE_WEBUI}; + UpdateMessage msg = {UPDATE_ALL}; if (xQueueSend(otaQueue, &msg, 0) == pdTRUE) { - request->send(200, "text/plain", "WebUI update triggered"); + request->send(200, "application/json", "{\"msg\":\"Firmware update triggered\"}"); } else { - request->send(503, "text/plain", "Update already in progress"); - } -} - -void onUpdateFirmware(AsyncWebServerRequest *request) -{ - UpdateMessage msg = {UPDATE_FIRMWARE}; - if (xQueueSend(otaQueue, &msg, 0) == pdTRUE) - { - request->send(200, "text/plain", "Firmware update triggered"); - } - else - { - request->send(503, "text/plain", "Update already in progress"); + request->send(503,"application/json", "{\"msg\":\"Update already in progress\"}"); } } diff --git a/src/lib/webserver.hpp b/src/lib/webserver.hpp index 9f47d02..8c49011 100644 --- a/src/lib/webserver.hpp +++ b/src/lib/webserver.hpp @@ -26,10 +26,6 @@ bool processEpdColorSettings(AsyncWebServerRequest *request); void onApiStatus(AsyncWebServerRequest *request); void onApiSystemStatus(AsyncWebServerRequest *request); void onApiSetWifiTxPower(AsyncWebServerRequest *request); -void onUpdateWebUi(AsyncWebServerRequest *request); -void onUpdateFirmware(AsyncWebServerRequest *request); - - void onApiScreenNext(AsyncWebServerRequest *request); void onApiScreenPrevious(AsyncWebServerRequest *request); @@ -58,6 +54,7 @@ void onFirmwareUpdate(AsyncWebServerRequest *request); void asyncFirmwareUpdateHandler(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); void asyncFileUpdateHandler(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final, int command); void asyncWebuiUpdateHandler(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); +void onAutoUpdateFirmware(AsyncWebServerRequest *request); void onIndex(AsyncWebServerRequest *request); void onNotFound(AsyncWebServerRequest *request); From 18bac7dcc7edbcb417a17815f28c342aef0efb14 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 12 Sep 2024 02:18:44 +0200 Subject: [PATCH 018/130] Remove old settings from sdkconfig and add optimizations --- dependencies.lock | 2 +- sdkconfig.defaults | 13 +++---------- src/lib/led_handler.cpp | 4 ++-- src/lib/ota.cpp | 2 ++ 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/dependencies.lock b/dependencies.lock index f47f33d..2cb885d 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -4,6 +4,6 @@ dependencies: source: type: idf version: 4.4.7 -manifest_hash: 3117ab97df715ceaa7b9cacfc3cc7071408d26f122740eea130b5286dc5cd988 +manifest_hash: 841ba2a95f4b32d39636bf4fdf07c48a2052f71c9728a5b7f263083a3b430a4f target: esp32s3 version: 1.0.0 diff --git a/sdkconfig.defaults b/sdkconfig.defaults index ffb944e..ab761ec 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -16,18 +16,14 @@ CONFIG_HEAP_POISONING_LIGHT=y CONFIG_ESP32S3_SPIRAM_SUPPORT=y CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y CONFIG_BOOTLOADER_LOG_LEVEL=0 -CONFIG_LOG_BOOTLOADER_LEVEL_NONE=y CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y CONFIG_ESP32S3_SPIRAM_SUPPORT=y CONFIG_LOG_DEFAULT_LEVEL_NONE=y CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_LOG_MAXIMUM_LEVEL=0 -CONFIG_LOG_BOOTLOADER_LEVEL_NONE=y -CONFIG_LOG_BOOTLOADER_LEVEL=0 -CONFIG_CXX_EXCEPTIONS=y CONFIG_COMPILER_CXX_EXCEPTIONS=y #CONFIG_BOOTLOADER_WDT_ENABLE=n -#CONFIG_TASK_WDT=n +#CONFIG_ESP_TASK_WDT=n #Required for BTClock #CONFIG_SPIRAM_MODE_OCT=y @@ -42,14 +38,11 @@ CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=12 CONFIG_ESP32_WIFI_RX_BA_WIN=6 CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120 -CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240 CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y CONFIG_RTC_CLK_CAL_CYCLES=576 CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120 CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n CONFIG_SPIRAM_CACHE_WORKAROUND=y -CONFIG_COMPILER_OPTIMIZATION_PERF=y -CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y -CONFIG_MBEDTLS_SSL_SERVER_VERIFY=n -CONFIG_MBEDTLS_SSL_VERIFY_CLIENT_CERTIFICATE=n \ No newline at end of file +CONFIG_COMPILER_OPTIMIZATION_PERF=y +CONFIG_NEWLIB_NANO_FORMAT=y \ No newline at end of file diff --git a/src/lib/led_handler.cpp b/src/lib/led_handler.cpp index 1b6756e..8dccf82 100644 --- a/src/lib/led_handler.cpp +++ b/src/lib/led_handler.cpp @@ -323,6 +323,8 @@ void ledTask(void *parameter) break; } case LED_FLASH_UPDATE: + blinkDelayTwoColor(250, 3, pixels.Color(0, 230, 0), + pixels.Color(230, 230, 0)); break; case LED_FLASH_BLOCK_NOTIFY: { @@ -574,7 +576,6 @@ void saveLedState() { int pixelColor = pixels.getPixelColor(i); char key[12]; - snprintf(key, 12, "%s%d", "ledColor_", i); preferences.putUInt(key, pixelColor); } @@ -586,7 +587,6 @@ void restoreLedState() for (int i = 0; i < pixels.numPixels(); i++) { char key[12]; - snprintf(key, 12, "%s%d", "ledColor_", i); uint pixelColor = preferences.getUInt(key, pixels.Color(0, 0, 0)); pixels.setPixelColor(i, pixelColor); } diff --git a/src/lib/ota.cpp b/src/lib/ota.cpp index 3a391ca..d4b11a6 100644 --- a/src/lib/ota.cpp +++ b/src/lib/ota.cpp @@ -84,7 +84,9 @@ void handleOTATask(void *parameter) if (xQueueReceive(otaQueue, &msg, 0) == pdTRUE) { if (msg.updateType == UPDATE_ALL) { + queueLedEffect(LED_FLASH_UPDATE); int resultWebUi = downloadUpdateHandler(UPDATE_WEBUI); + queueLedEffect(LED_FLASH_UPDATE); int resultFw = downloadUpdateHandler(UPDATE_FIRMWARE); if (resultWebUi == 0 && resultFw == 0) { From 630943ec5482d2c1137462640d51cf6c23c18f46 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 12 Sep 2024 02:22:29 +0200 Subject: [PATCH 019/130] Bring back snprintf for ledstate --- src/lib/led_handler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/led_handler.cpp b/src/lib/led_handler.cpp index 8dccf82..a40097b 100644 --- a/src/lib/led_handler.cpp +++ b/src/lib/led_handler.cpp @@ -576,6 +576,7 @@ void saveLedState() { int pixelColor = pixels.getPixelColor(i); char key[12]; + snprintf(key, 12, "%s%d", "ledColor_", i); preferences.putUInt(key, pixelColor); } @@ -587,6 +588,7 @@ void restoreLedState() for (int i = 0; i < pixels.numPixels(); i++) { char key[12]; + snprintf(key, 12, "%s%d", "ledColor_", i); uint pixelColor = preferences.getUInt(key, pixels.Color(0, 0, 0)); pixels.setPixelColor(i, pixelColor); } From 5dd47c227529bc05b4b756e334d78db310d380eb Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 16 Sep 2024 21:50:28 +0200 Subject: [PATCH 020/130] Fixes for Rev. B black PCB --- data | 2 +- sdkconfig.defaults | 2 +- src/fonts/fonts.hpp | 2 +- src/lib/config.cpp | 23 ++++++++++++++++++++++- src/lib/config.hpp | 2 +- src/lib/led_handler.cpp | 10 +++++----- src/lib/nostr_notify.cpp | 7 +++++-- src/lib/webserver.cpp | 2 +- 8 files changed, 37 insertions(+), 13 deletions(-) diff --git a/data b/data index 6c40b54..761c7f2 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 6c40b54273b7f7c7d6c2624d3c2a066435f27756 +Subproject commit 761c7f2991d347e97e77470ea3bf5511d7a7e507 diff --git a/sdkconfig.defaults b/sdkconfig.defaults index ab761ec..59b2ec3 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -44,5 +44,5 @@ CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120 CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n CONFIG_SPIRAM_CACHE_WORKAROUND=y -CONFIG_COMPILER_OPTIMIZATION_PERF=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_NEWLIB_NANO_FORMAT=y \ No newline at end of file diff --git a/src/fonts/fonts.hpp b/src/fonts/fonts.hpp index 1c12d49..099c4e0 100644 --- a/src/fonts/fonts.hpp +++ b/src/fonts/fonts.hpp @@ -1,7 +1,7 @@ #pragma once #include "antonio-semibold20.h" -#include "antonio-semibold30.h" +//#include "antonio-semibold30.h" #include "antonio-semibold40.h" #include "antonio-semibold90.h" #include "sats-symbol.h" diff --git a/src/lib/config.cpp b/src/lib/config.cpp index c295b93..cc50719 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -58,6 +58,9 @@ void setup() { preferences.clear(); queueLedEffect(LED_EFFECT_WIFI_ERASE_SETTINGS); + nvs_flash_erase(); + delay(1000); + ESP.restart(); } } @@ -229,6 +232,9 @@ void setupWifi() // esp_task_wdt_deinit(); // esp_task_wdt_reset(); } + + + setFgColor(preferences.getUInt("fgColor", isWhiteVersion() ? GxEPD_BLACK : GxEPD_WHITE)); setBgColor(preferences.getUInt("bgColor", isWhiteVersion() ? GxEPD_WHITE : GxEPD_BLACK)); } @@ -274,6 +280,16 @@ void setupPreferences() else setCurrentCurrency(CURRENCY_USD); + if (!preferences.isKey("flDisable")) { + preferences.putBool("flDisable", isWhiteVersion() ? false : true); + } + + if (!preferences.isKey("fgColor")) { + preferences.putUInt("fgColor", isWhiteVersion() ? GxEPD_BLACK : GxEPD_WHITE); + preferences.putUInt("bgColor", isWhiteVersion() ? GxEPD_WHITE : GxEPD_BLACK); + } + + addScreenMapping(SCREEN_BLOCK_HEIGHT, "Block Height"); addScreenMapping(SCREEN_TIME, "Time"); @@ -455,6 +471,10 @@ void setupHardware() Serial.println(F("An Error has occurred while mounting LittleFS")); } + if (HW_REV == "REV_B_EPD_2_13" && !isWhiteVersion()) { + Serial.println(F("Black Rev B")); + } + if (!LittleFS.open("/index.html.gz", "r")) { Serial.println(F("Error loading WebUI")); @@ -509,7 +529,7 @@ void setupHardware() } #ifdef IS_HW_REV_B - pinMode(39, INPUT_PULLUP); + pinMode(39, INPUT_PULLDOWN); #endif @@ -690,6 +710,7 @@ String getHwRev() bool isWhiteVersion() { #ifdef IS_HW_REV_B + pinMode(39, INPUT_PULLDOWN); return digitalRead(39); #else return false; diff --git a/src/lib/config.hpp b/src/lib/config.hpp index e8fcffa..8c9da90 100644 --- a/src/lib/config.hpp +++ b/src/lib/config.hpp @@ -7,7 +7,7 @@ #include #include #include - +#include #include #include "lib/block_notify.hpp" diff --git a/src/lib/led_handler.cpp b/src/lib/led_handler.cpp index a40097b..4f882e0 100644 --- a/src/lib/led_handler.cpp +++ b/src/lib/led_handler.cpp @@ -13,7 +13,7 @@ bool flInTransition = false; void frontlightFlash(int flDelayTime) { - if (preferences.getBool("flDisable", DEFAULT_DISABLE_FL)) + if (preferences.getBool("flDisable")) return; if (frontlightOn) @@ -68,7 +68,7 @@ void frontlightFadeInAll(int flDelayTime) void frontlightFadeInAll(int flDelayTime, bool staggered) { - if (preferences.getBool("flDisable", DEFAULT_DISABLE_FL)) + if (preferences.getBool("flDisable")) return; if (frontlightIsOn()) return; @@ -120,7 +120,7 @@ void frontlightFadeOutAll(int flDelayTime) void frontlightFadeOutAll(int flDelayTime, bool staggered) { - if (preferences.getBool("flDisable", DEFAULT_DISABLE_FL)) + if (preferences.getBool("flDisable")) return; if (!frontlightIsOn()) return; @@ -186,7 +186,7 @@ bool frontlightIsOn() void frontlightFadeIn(uint num, int flDelayTime) { - if (preferences.getBool("flDisable", DEFAULT_DISABLE_FL)) + if (preferences.getBool("flDisable")) return; for (int dutyCycle = 0; dutyCycle <= preferences.getUInt("flMaxBrightness"); dutyCycle += 5) { @@ -197,7 +197,7 @@ void frontlightFadeIn(uint num, int flDelayTime) void frontlightFadeOut(uint num, int flDelayTime) { - if (preferences.getBool("flDisable", DEFAULT_DISABLE_FL)) + if (preferences.getBool("flDisable")) return; if (!frontlightIsOn()) return; diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index f9ac019..2e044bb 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -76,7 +76,8 @@ void setupNostrNotify(bool asDatasource, bool zapNotify) }else if(status==nostr::ConnectionStatus::ERROR){ sstatus = "ERROR"; } - Serial.println("[ Nostr ] Connection status changed: " + sstatus); }); + //Serial.println("[ Nostr ] Connection status changed: " + sstatus); + }); } } catch (const std::exception &e) @@ -204,9 +205,11 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event) if (strcmp(key, "bolt11") == 0) { - Serial.println(F("Got a zap")); + Serial.print(F("Got a zap of ")); int64_t satsAmount = getAmountInSatoshis(std::string(value)); + Serial.print(satsAmount); + Serial.println(F(" sats")); std::array textEpdContent = parseZapNotify(satsAmount, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 3d8b6da..801c286 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -705,7 +705,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) #ifdef HAS_FRONTLIGHT root["hasFrontlight"] = true; - root["flDisable"] = preferences.getBool("flDisable", DEFAULT_DISABLE_FL); + root["flDisable"] = preferences.getBool("flDisable"); root["flMaxBrightness"] = preferences.getUInt("flMaxBrightness", DEFAULT_FL_MAX_BRIGHTNESS); root["flAlwaysOn"] = preferences.getBool("flAlwaysOn", DEFAULT_FL_ALWAYS_ON); root["flEffectDelay"] = preferences.getUInt("flEffectDelay", DEFAULT_FL_EFFECT_DELAY); From ff50acf913da8d8220ea79e110415dd6d18c521d Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 18 Sep 2024 02:00:10 +0200 Subject: [PATCH 021/130] Fix WebUI currency converter, reorganize some code --- data | 2 +- src/lib/block_notify.hpp | 1 + src/lib/button_handler.hpp | 1 + src/lib/config.cpp | 4 +- src/lib/nostr_notify.hpp | 1 + src/lib/ota.hpp | 1 + src/lib/screen_handler.cpp | 92 +------------------ src/lib/screen_handler.hpp | 12 +-- src/lib/timers.cpp | 86 ++++++++++++++++++ src/lib/timers.hpp | 22 +++++ src/lib/v2_notify.cpp | 180 ++++++++++++++++++++----------------- src/lib/v2_notify.hpp | 16 ++-- src/lib/webserver.cpp | 3 +- src/main.cpp | 2 +- 14 files changed, 228 insertions(+), 195 deletions(-) create mode 100644 src/lib/timers.cpp create mode 100644 src/lib/timers.hpp diff --git a/data b/data index 761c7f2..7d82b1e 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 761c7f2991d347e97e77470ea3bf5511d7a7e507 +Subproject commit 7d82b1e1a9014e80f725478333774f4d53e22134 diff --git a/src/lib/block_notify.hpp b/src/lib/block_notify.hpp index 0af7196..d5565eb 100644 --- a/src/lib/block_notify.hpp +++ b/src/lib/block_notify.hpp @@ -11,6 +11,7 @@ #include "lib/led_handler.hpp" #include "lib/screen_handler.hpp" +#include "lib/timers.hpp" #include "lib/shared.hpp" // using namespace websockets; diff --git a/src/lib/button_handler.hpp b/src/lib/button_handler.hpp index 03e1b36..9f28d33 100644 --- a/src/lib/button_handler.hpp +++ b/src/lib/button_handler.hpp @@ -4,6 +4,7 @@ #include "lib/screen_handler.hpp" #include "lib/shared.hpp" +#include "lib/timers.hpp" extern TaskHandle_t buttonTaskHandle; diff --git a/src/lib/config.cpp b/src/lib/config.cpp index cc50719..2898a31 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -404,7 +404,7 @@ void setupWebsocketClients(void *pvParameters) { if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) { - setupV2Notify(); + V2Notify::setupV2Notify(); } else { @@ -553,7 +553,7 @@ void setupHardware() { Serial.println(F("Found BH1750")); hasLuxSensor = true; - bh1750.begin(BH1750::CONTINUOUS_LOW_RES_MODE, 0x5C); + bh1750.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x5C); } else { diff --git a/src/lib/nostr_notify.hpp b/src/lib/nostr_notify.hpp index d64e3e9..045574d 100644 --- a/src/lib/nostr_notify.hpp +++ b/src/lib/nostr_notify.hpp @@ -12,6 +12,7 @@ #include "price_notify.hpp" #include "block_notify.hpp" +#include "lib/timers.hpp" void setupNostrNotify(bool asDatasource, bool zapNotify); diff --git a/src/lib/ota.hpp b/src/lib/ota.hpp index 516f9a1..44704f6 100644 --- a/src/lib/ota.hpp +++ b/src/lib/ota.hpp @@ -5,6 +5,7 @@ #include "lib/config.hpp" #include "lib/shared.hpp" +#include "lib/timers.hpp" #ifndef UPDATE_MESSAGE_HPP #define UPDATE_MESSAGE_HPP diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 091a6e0..d1c6165 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -5,8 +5,7 @@ // TaskHandle_t timeUpdateTaskHandle; TaskHandle_t taskScreenRotateTaskHandle; TaskHandle_t workerTaskHandle; -esp_timer_handle_t screenRotateTimer; -esp_timer_handle_t minuteTimer; + std::array taskEpdContent = {}; std::string priceString; @@ -23,8 +22,6 @@ void workerTask(void *pvParameters) { while (1) { // Wait for a work item to be available in the queue if (xQueueReceive(workQueue, &receivedItem, portMAX_DELAY)) { - uint firstIndex = 0; - // Process the work item based on its type switch (receivedItem.type) { case TASK_BITAXE_UPDATE: { @@ -42,10 +39,7 @@ void workerTask(void *pvParameters) { case TASK_PRICE_UPDATE: { uint currency = getCurrentCurrency(); uint price = getPrice(currency); - // u_char priceSymbol = '$'; - // if (preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE)) { - // priceSymbol = '['; - // } + if (getCurrentScreen() == SCREEN_BTC_TICKER) { taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE)); } else if (getCurrentScreen() == SCREEN_SATS_PER_CURRENCY) { @@ -121,29 +115,6 @@ void taskScreenRotate(void *pvParameters) { } } -void IRAM_ATTR minuteTimerISR(void *arg) { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - // vTaskNotifyGiveFromISR(timeUpdateTaskHandle, &xHigherPriorityTaskWoken); - WorkItem timeUpdate = {TASK_TIME_UPDATE, 0}; - xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken); - - if (bitaxeFetchTaskHandle != NULL) { - vTaskNotifyGiveFromISR(bitaxeFetchTaskHandle, &xHigherPriorityTaskWoken); - } - - if (xHigherPriorityTaskWoken == pdTRUE) { - portYIELD_FROM_ISR(); - } -} - -void IRAM_ATTR screenRotateTimerISR(void *arg) { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - vTaskNotifyGiveFromISR(taskScreenRotateTaskHandle, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken == pdTRUE) { - portYIELD_FROM_ISR(); - } -} - void setupTasks() { workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem)); @@ -159,65 +130,6 @@ void setupTasks() { setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)); } -void setupTimeUpdateTimer(void *pvParameters) { - const esp_timer_create_args_t minuteTimerConfig = { - .callback = &minuteTimerISR, .name = "minute_timer"}; - - esp_timer_create(&minuteTimerConfig, &minuteTimer); - - time_t currentTime; - struct tm timeinfo; - time(¤tTime); - localtime_r(¤tTime, &timeinfo); - uint32_t secondsUntilNextMinute = 60 - timeinfo.tm_sec; - - if (secondsUntilNextMinute > 0) - vTaskDelay(pdMS_TO_TICKS((secondsUntilNextMinute * 1000))); - - esp_timer_start_periodic(minuteTimer, usPerMinute); - - WorkItem timeUpdate = {TASK_TIME_UPDATE, 0}; - xQueueSend(workQueue, &timeUpdate, portMAX_DELAY); - // xTaskNotifyGive(timeUpdateTaskHandle); - - vTaskDelete(NULL); -} - -void setupScreenRotateTimer(void *pvParameters) { - const esp_timer_create_args_t screenRotateTimerConfig = { - .callback = &screenRotateTimerISR, .name = "screen_rotate_timer"}; - - esp_timer_create(&screenRotateTimerConfig, &screenRotateTimer); - - if (preferences.getBool("timerActive", DEFAULT_TIMER_ACTIVE)) { - esp_timer_start_periodic(screenRotateTimer, - getTimerSeconds() * usPerSecond); - } - - vTaskDelete(NULL); -} - -uint getTimerSeconds() { return preferences.getUInt("timerSeconds", DEFAULT_TIMER_SECONDS); } - -bool isTimerActive() { return esp_timer_is_active(screenRotateTimer); } - -void setTimerActive(bool status) { - if (status) { - esp_timer_start_periodic(screenRotateTimer, - getTimerSeconds() * usPerSecond); - queueLedEffect(LED_EFFECT_START_TIMER); - preferences.putBool("timerActive", true); - } else { - esp_timer_stop(screenRotateTimer); - queueLedEffect(LED_EFFECT_PAUSE_TIMER); - preferences.putBool("timerActive", false); - } - - if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle); -} - -void toggleTimerActive() { setTimerActive(!isTimerActive()); } - uint getCurrentScreen() { return currentScreen; } void setCurrentScreen(uint newScreen) { diff --git a/src/lib/screen_handler.hpp b/src/lib/screen_handler.hpp index 91e824a..6c99a7c 100644 --- a/src/lib/screen_handler.hpp +++ b/src/lib/screen_handler.hpp @@ -16,9 +16,6 @@ extern TaskHandle_t workerTaskHandle; extern TaskHandle_t taskScreenRotateTaskHandle; -extern esp_timer_handle_t screenRotateTimer; -extern esp_timer_handle_t minuteTimer; - extern QueueHandle_t workQueue; typedef enum { @@ -42,21 +39,14 @@ void previousScreen(); void showSystemStatusScreen(); -void setupTimeUpdateTimer(void *pvParameters); -void setupScreenRotateTimer(void *pvParameters); -void IRAM_ATTR minuteTimerISR(void *arg); -void IRAM_ATTR screenRotateTimerISR(void *arg); // void taskPriceUpdate(void *pvParameters); // void taskBlockUpdate(void *pvParameters); // void taskTimeUpdate(void *pvParameters); void taskScreenRotate(void *pvParameters); -uint getTimerSeconds(); -bool isTimerActive(); -void setTimerActive(bool status); -void toggleTimerActive(); + void setupTasks(); void setCurrentCurrency(char currency); diff --git a/src/lib/timers.cpp b/src/lib/timers.cpp new file mode 100644 index 0000000..d84d358 --- /dev/null +++ b/src/lib/timers.cpp @@ -0,0 +1,86 @@ +#include "timers.hpp" + +esp_timer_handle_t screenRotateTimer; +esp_timer_handle_t minuteTimer; + +void setupTimeUpdateTimer(void *pvParameters) { + const esp_timer_create_args_t minuteTimerConfig = { + .callback = &minuteTimerISR, .name = "minute_timer"}; + + esp_timer_create(&minuteTimerConfig, &minuteTimer); + + time_t currentTime; + struct tm timeinfo; + time(¤tTime); + localtime_r(¤tTime, &timeinfo); + uint32_t secondsUntilNextMinute = 60 - timeinfo.tm_sec; + + if (secondsUntilNextMinute > 0) + vTaskDelay(pdMS_TO_TICKS((secondsUntilNextMinute * 1000))); + + esp_timer_start_periodic(minuteTimer, usPerMinute); + + WorkItem timeUpdate = {TASK_TIME_UPDATE, 0}; + xQueueSend(workQueue, &timeUpdate, portMAX_DELAY); + // xTaskNotifyGive(timeUpdateTaskHandle); + + vTaskDelete(NULL); +} + +void setupScreenRotateTimer(void *pvParameters) { + const esp_timer_create_args_t screenRotateTimerConfig = { + .callback = &screenRotateTimerISR, .name = "screen_rotate_timer"}; + + esp_timer_create(&screenRotateTimerConfig, &screenRotateTimer); + + if (preferences.getBool("timerActive", DEFAULT_TIMER_ACTIVE)) { + esp_timer_start_periodic(screenRotateTimer, + getTimerSeconds() * usPerSecond); + } + + vTaskDelete(NULL); +} + +uint getTimerSeconds() { return preferences.getUInt("timerSeconds", DEFAULT_TIMER_SECONDS); } + +bool isTimerActive() { return esp_timer_is_active(screenRotateTimer); } + +void setTimerActive(bool status) { + if (status) { + esp_timer_start_periodic(screenRotateTimer, + getTimerSeconds() * usPerSecond); + queueLedEffect(LED_EFFECT_START_TIMER); + preferences.putBool("timerActive", true); + } else { + esp_timer_stop(screenRotateTimer); + queueLedEffect(LED_EFFECT_PAUSE_TIMER); + preferences.putBool("timerActive", false); + } + + if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle); +} + +void toggleTimerActive() { setTimerActive(!isTimerActive()); } + +void IRAM_ATTR minuteTimerISR(void *arg) { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // vTaskNotifyGiveFromISR(timeUpdateTaskHandle, &xHigherPriorityTaskWoken); + WorkItem timeUpdate = {TASK_TIME_UPDATE, 0}; + xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken); + + if (bitaxeFetchTaskHandle != NULL) { + vTaskNotifyGiveFromISR(bitaxeFetchTaskHandle, &xHigherPriorityTaskWoken); + } + + if (xHigherPriorityTaskWoken == pdTRUE) { + portYIELD_FROM_ISR(); + } +} + +void IRAM_ATTR screenRotateTimerISR(void *arg) { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + vTaskNotifyGiveFromISR(taskScreenRotateTaskHandle, &xHigherPriorityTaskWoken); + if (xHigherPriorityTaskWoken == pdTRUE) { + portYIELD_FROM_ISR(); + } +} \ No newline at end of file diff --git a/src/lib/timers.hpp b/src/lib/timers.hpp new file mode 100644 index 0000000..e543a9f --- /dev/null +++ b/src/lib/timers.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +#include "lib/shared.hpp" +#include "lib/screen_handler.hpp" + +extern esp_timer_handle_t screenRotateTimer; +extern esp_timer_handle_t minuteTimer; + +void setupTimeUpdateTimer(void *pvParameters); +void setupScreenRotateTimer(void *pvParameters); + +void IRAM_ATTR minuteTimerISR(void *arg); +void IRAM_ATTR screenRotateTimerISR(void *arg); + +uint getTimerSeconds(); +bool isTimerActive(); +void setTimerActive(bool status); +void toggleTimerActive(); \ No newline at end of file diff --git a/src/lib/v2_notify.cpp b/src/lib/v2_notify.cpp index 13d302d..33104a5 100644 --- a/src/lib/v2_notify.cpp +++ b/src/lib/v2_notify.cpp @@ -1,41 +1,51 @@ #include "v2_notify.hpp" -WebSocketsClient webSocket; -TaskHandle_t v2NotifyTaskHandle; +using namespace V2Notify; -void setupV2Notify() +namespace V2Notify { - String hostname = "ws.btclock.dev"; - if ( preferences.getBool("stagingSource", DEFAULT_STAGING_SOURCE)) { - Serial.println(F("Connecting to V2 staging source")); - hostname = "ws-staging.btclock.dev"; - } else { - Serial.println(F("Connecting to V2 source")); + WebSocketsClient webSocket; + + TaskHandle_t v2NotifyTaskHandle; + + void setupV2Notify() + { + String hostname = "ws.btclock.dev"; + if (preferences.getBool("stagingSource", DEFAULT_STAGING_SOURCE)) + { + Serial.println(F("Connecting to V2 staging source")); + hostname = "ws-staging.btclock.dev"; + } + else + { + Serial.println(F("Connecting to V2 source")); + } + + webSocket.beginSSL(hostname, 443, "/api/v2/ws"); + webSocket.onEvent(V2Notify::onWebsocketV2Event); + webSocket.setReconnectInterval(5000); + webSocket.enableHeartbeat(15000, 3000, 2); + + V2Notify::setupV2NotifyTask(); } - webSocket.beginSSL(hostname, 443, "/api/v2/ws"); - webSocket.onEvent(onWebsocketV2Event); - webSocket.setReconnectInterval(5000); - webSocket.enableHeartbeat(15000, 3000, 2); - - setupV2NotifyTask(); -} - -void onWebsocketV2Event(WStype_t type, uint8_t * payload, size_t length) { - switch(type) { - case WStype_DISCONNECTED: - Serial.printf("[WSc] Disconnected!\n"); - break; - case WStype_CONNECTED: + void onWebsocketV2Event(WStype_t type, uint8_t *payload, size_t length) + { + switch (type) { - Serial.printf("[WSc] Connected to url: %s\n", payload); + case WStype_DISCONNECTED: + Serial.printf("[WSc] Disconnected!\n"); + break; + case WStype_CONNECTED: + { + Serial.printf("[WSc] Connected to url: %s\n", payload); JsonDocument response; response["type"] = "subscribe"; response["eventType"] = "blockfee"; size_t responseLength = measureMsgPack(response); - uint8_t* buffer = new uint8_t[responseLength]; + uint8_t *buffer = new uint8_t[responseLength]; serializeMsgPack(response, buffer, responseLength); webSocket.sendBIN(buffer, responseLength); delete[] buffer; @@ -62,83 +72,89 @@ void onWebsocketV2Event(WStype_t type, uint8_t * payload, size_t length) { { currenciesArray.add(str); } - -// response["currencies"] = currenciesArray; + + // response["currencies"] = currenciesArray; responseLength = measureMsgPack(response); buffer = new uint8_t[responseLength]; serializeMsgPack(response, buffer, responseLength); webSocket.sendBIN(buffer, responseLength); - break; + break; } - case WStype_TEXT: - Serial.printf("[WSc] get text: %s\n", payload); + case WStype_TEXT: + Serial.printf("[WSc] get text: %s\n", payload); - // send message to server - // webSocket.sendTXT("message here"); - break; - case WStype_BIN: + // send message to server + // webSocket.sendTXT("message here"); + break; + case WStype_BIN: { JsonDocument doc; DeserializationError error = deserializeMsgPack(doc, payload, length); - handleV2Message(doc); - break; + V2Notify::handleV2Message(doc); + break; } - case WStype_ERROR: - case WStype_FRAGMENT_TEXT_START: - case WStype_FRAGMENT_BIN_START: - case WStype_FRAGMENT: + case WStype_ERROR: + case WStype_FRAGMENT_TEXT_START: + case WStype_FRAGMENT_BIN_START: + case WStype_FRAGMENT: case WStype_PING: case WStype_PONG: - case WStype_FRAGMENT_FIN: - break; - } -} - -void handleV2Message(JsonDocument doc) { - if (doc.containsKey("blockheight")) - { - uint newBlockHeight = doc["blockheight"].as(); - - if (newBlockHeight == getBlockHeight()) { - return; + case WStype_FRAGMENT_FIN: + break; + } } - processNewBlock(newBlockHeight); - } - else if (doc.containsKey("blockfee")) - { - uint medianFee = doc["blockfee"].as(); + void handleV2Message(JsonDocument doc) + { + if (doc.containsKey("blockheight")) + { + uint newBlockHeight = doc["blockheight"].as(); - processNewBlockFee(medianFee); - } else if (doc.containsKey("price")) - { + if (newBlockHeight == getBlockHeight()) + { + return; + } - // Iterate through the key-value pairs of the "price" object - for (JsonPair kv : doc["price"].as()) { - const char* currency = kv.key().c_str(); - uint newPrice = kv.value().as(); - - processNewPrice(newPrice, getCurrencyChar(currency)); + processNewBlock(newBlockHeight); + } + else if (doc.containsKey("blockfee")) + { + uint medianFee = doc["blockfee"].as(); + processNewBlockFee(medianFee); + } + else if (doc.containsKey("price")) + { + + // Iterate through the key-value pairs of the "price" object + for (JsonPair kv : doc["price"].as()) + { + const char *currency = kv.key().c_str(); + uint newPrice = kv.value().as(); + + processNewPrice(newPrice, getCurrencyChar(currency)); + } + } } - } -} -void taskV2Notify(void *pvParameters) { - for(;;) { - webSocket.loop(); - vTaskDelay(10 / portTICK_PERIOD_MS); + void taskV2Notify(void *pvParameters) + { + for (;;) + { + webSocket.loop(); + vTaskDelay(10 / portTICK_PERIOD_MS); + } } -} -void setupV2NotifyTask() { - xTaskCreate(taskV2Notify, "v2Notify", (6 * 1024), NULL, tskIDLE_PRIORITY, - &v2NotifyTaskHandle); + void setupV2NotifyTask() + { + xTaskCreate(V2Notify::taskV2Notify, "v2Notify", (6 * 1024), NULL, tskIDLE_PRIORITY, + &V2Notify::v2NotifyTaskHandle); + } -} - -bool isV2NotifyConnected() -{ - return webSocket.isConnected(); -} + bool isV2NotifyConnected() + { + return webSocket.isConnected(); + } +} \ No newline at end of file diff --git a/src/lib/v2_notify.hpp b/src/lib/v2_notify.hpp index d3e4907..21a74ba 100644 --- a/src/lib/v2_notify.hpp +++ b/src/lib/v2_notify.hpp @@ -8,16 +8,18 @@ #include "lib/screen_handler.hpp" -extern TaskHandle_t v2NotifyTaskHandle; +namespace V2Notify { + extern TaskHandle_t v2NotifyTaskHandle; -void setupV2NotifyTask(); -void taskV2Notify(void *pvParameters); + void setupV2NotifyTask(); + void taskV2Notify(void *pvParameters); -void setupV2Notify(); -void onWebsocketV2Event(WStype_t type, uint8_t * payload, size_t length); -void handleV2Message(JsonDocument doc); + void setupV2Notify(); + void onWebsocketV2Event(WStype_t type, uint8_t * payload, size_t length); + void handleV2Message(JsonDocument doc); -bool isV2NotifyConnected(); + bool isV2NotifyConnected(); +} // void stopV2Notify(); // void restartV2Notify(); // bool getPriceNotifyInit(); diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 801c286..88c40e4 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -256,9 +256,10 @@ JsonDocument getStatusObject() // root["espPsramSize"] = ESP.getPsramSize(); JsonObject conStatus = root["connectionStatus"].to(); + conStatus["price"] = isPriceNotifyConnected(); conStatus["blocks"] = isBlockNotifyConnected(); - conStatus["V2"] = isV2NotifyConnected(); + conStatus["V2"] = V2Notify::isV2NotifyConnected(); conStatus["nostr"] = nostrConnected(); diff --git a/src/main.cpp b/src/main.cpp index 0839e9d..908f155 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,7 +51,7 @@ extern "C" void app_main() if (hasLightLevel()) { if (preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE) != 0) { - if (hasLightLevel() && getLightLevel() == 0) + if (hasLightLevel() && getLightLevel() <= 2) { if (frontlightIsOn()) { frontlightFadeOutAll(); From 41bf2480ce8923a15883714bb4536991023a86ad Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 18 Sep 2024 02:40:24 +0200 Subject: [PATCH 022/130] Dependency updates and fix URL rewrites --- platformio.ini | 4 ++-- src/lib/webserver.cpp | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 14799cf..13b8e5f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,7 +15,7 @@ default_envs = lolin_s3_mini_213epd, lolin_s3_mini_29epd, btclock_rev_b_213epd [btclock_base] -platform = espressif32 @ ^6.6.0 +platform = espressif32 @ ^6.8.1 framework = arduino, espidf monitor_speed = 115200 monitor_filters = esp32_exception_decoder, colorize @@ -33,7 +33,7 @@ build_unflags = lib_deps = https://github.com/joltwallet/esp_littlefs.git bblanchon/ArduinoJson@^7.1.0 - mathieucarbou/ESPAsyncWebServer @ 3.2.0 + mathieucarbou/ESPAsyncWebServer @ 3.3.1 adafruit/Adafruit BusIO@^1.16.1 adafruit/Adafruit MCP23017 Arduino Library@^2.3.2 adafruit/Adafruit NeoPixel@^1.12.3 diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 88c40e4..738f4f5 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -20,6 +20,10 @@ void setupWebserver() AsyncStaticWebHandler &staticHandler = server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html"); + + server.rewrite("/convert", "/"); + server.rewrite("/api", "/"); + if (preferences.getBool("httpAuthEnabled", DEFAULT_HTTP_AUTH_ENABLED)) { staticHandler.setAuthentication( From ff0d8f5a0aa29224ee2f322178c5481301571479 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 21 Sep 2024 15:58:07 +0200 Subject: [PATCH 023/130] Make BTClock v8 board working again --- .github/workflows/tagging.yml | 52 ++++++++++++++++++------ boards/{btclock.json => btclock_v8.json} | 6 +-- data | 2 +- partition_16mb.csv | 2 +- platformio.ini | 16 ++++++-- src/lib/button_handler.cpp | 20 +++++++-- src/lib/config.cpp | 14 +++---- src/lib/epd.cpp | 15 ++++--- src/lib/shared.hpp | 2 +- 9 files changed, 91 insertions(+), 38 deletions(-) rename boards/{btclock.json => btclock_v8.json} (92%) diff --git a/.github/workflows/tagging.yml b/.github/workflows/tagging.yml index 825d100..13e2a3c 100644 --- a/.github/workflows/tagging.yml +++ b/.github/workflows/tagging.yml @@ -1,9 +1,9 @@ name: BTClock CI -on: +on: push: tags: - - '*' + - "*" jobs: build: @@ -40,10 +40,14 @@ jobs: version: esp32s3 - name: btclock_rev_b version: esp32s3 + - name: btclock_v8 + version: esp32s3 epd_variant: [213epd, 29epd] exclude: - - chip: btclock_rev_b - epd_variant: 29epd + - chip: btclock_rev_b + epd_variant: 29epd + - chip: btclock_v8 + epd_variant: 29epd steps: - uses: actions/download-artifact@v4 with: @@ -51,13 +55,37 @@ jobs: path: .pio - name: Install esptools.py run: pip install --upgrade esptool - + # - name: Create merged firmware binary + # run: mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && esptool.py --chip ${{ matrix.chip.version }} merge_bin -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin --flash_mode dio 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin 0xe000 .pio/boot_app0.bin 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin 0x369000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin - name: Create merged firmware binary - run: mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && esptool.py --chip ${{ matrix.chip.version }} merge_bin -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin --flash_mode dio 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin 0xe000 .pio/boot_app0.bin 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin 0x369000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin + run: | + if [ "${{ matrix.chip.name }}" == "btclock_v8" ]; then + mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && \ + esptool.py --chip ${{ matrix.chip.version }} merge_bin \ + -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \ + --flash_mode qio \ + 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin \ + 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \ + 0xe000 .pio/boot_app0.bin \ + 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \ + 0x810000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin; + else + # Original command for other cases + mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && \ + esptool.py --chip ${{ matrix.chip.version }} merge_bin \ + -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \ + --flash_mode dio \ + 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin \ + 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \ + 0xe000 .pio/boot_app0.bin \ + 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \ + 0x369000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin + # Adjust the offset for littlefs or other files as needed for the original case + fi - name: Create checksum for firmware run: shasum -a 256 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}_firmware.bin.sha256 - + - name: Create checksum for merged binary run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin.sha256 @@ -91,10 +119,10 @@ jobs: merge-multiple: false - name: Write commit hash to file run: echo $GITHUB_SHA > commit.txt - + - name: Write build date to file run: echo "$(date -u +'%Y-%m-%dT%H:%M:%SZ')" > date.txt - + - name: Create release uses: ncipollo/release-action@v1 with: @@ -117,8 +145,8 @@ jobs: with: source-directory: . target-directory: firmware_v3/ - destination-github-username: 'btclock' - destination-repository-name: 'web-flasher' + destination-github-username: "btclock" + destination-repository-name: "web-flasher" target-branch: main user-name: ${{github.actor}} - user-email: ${{github.actor}}@users.noreply.github.com \ No newline at end of file + user-email: ${{github.actor}}@users.noreply.github.com diff --git a/boards/btclock.json b/boards/btclock_v8.json similarity index 92% rename from boards/btclock.json rename to boards/btclock_v8.json index bee4064..b30bd19 100644 --- a/boards/btclock.json +++ b/boards/btclock_v8.json @@ -10,7 +10,7 @@ "-DBOARD_HAS_PSRAM", "-DARDUINO_BTCLOCK", "-DARDUINO_ESP32S3_DEV", - "-DIS_BTCLOCK_S3", + "-DIS_BTCLOCK_V8", "-DARDUINO_USB_MODE=1", "-DARDUINO_RUNNING_CORE=1", "-DARDUINO_EVENT_RUNNING_CORE=1", @@ -20,8 +20,8 @@ "f_flash": "80000000L", "flash_mode": "qio", "psram_type": "opi", - "espidf": { - "sdkconfig_path": "boards" + "esp-idf": { + "sdkconfig_path": "boards/sdkconfig.btclock_v8" }, "hwids": [ [ diff --git a/data b/data index 7d82b1e..95aa9d6 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 7d82b1e1a9014e80f725478333774f4d53e22134 +Subproject commit 95aa9d67d17dde32dab3216810e7b4e4086feb03 diff --git a/partition_16mb.csv b/partition_16mb.csv index 80df02b..a32b7ca 100644 --- a/partition_16mb.csv +++ b/partition_16mb.csv @@ -3,5 +3,5 @@ nvs, data, nvs, 36K, 20K, otadata, data, ota, 56K, 8K, app0, app, ota_0, 64K, 4096K, app1, app, ota_1, , 4096K, -spiffs, data, spiffs, , 3072K, +spiffs, data, spiffs, , 400K, coredump, data, coredump,, 64K, diff --git a/platformio.ini b/platformio.ini index 13b8e5f..30e03ec 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] data_dir = data/build_gz -default_envs = lolin_s3_mini_213epd, lolin_s3_mini_29epd, btclock_rev_b_213epd +default_envs = lolin_s3_mini_213epd, lolin_s3_mini_29epd, btclock_rev_b_213epd, btclock_v8_213epd [env] @@ -120,10 +120,11 @@ build_flags = -D VERSION_EPD_2_9 -D HW_REV=\"REV_B_EPD_2_9\" -[env:btclock_s3] +[env:btclock_v8] extends = btclock_base -board = btclock +board = btclock_v8 board_build.partitions = partition_16mb.csv +board_build.flash_mode = qio test_framework = unity build_flags = ${btclock_base.build_flags} @@ -145,6 +146,15 @@ build_flags = build_unflags = ${btclock_base.build_unflags} +[env:btclock_v8_213epd] +extends = env:btclock_v8 +test_framework = unity +build_flags = + ${env:btclock_v8.build_flags} + -D USE_QR + -D VERSION_EPD_2_13 + -D HW_REV=\"REV_V8_EPD_2_13\" + [env:native_test_only] platform = native test_framework = unity diff --git a/src/lib/button_handler.cpp b/src/lib/button_handler.cpp index 7b27a64..437090d 100644 --- a/src/lib/button_handler.cpp +++ b/src/lib/button_handler.cpp @@ -4,6 +4,18 @@ TaskHandle_t buttonTaskHandle = NULL; const TickType_t debounceDelay = pdMS_TO_TICKS(50); TickType_t lastDebounceTime = 0; +#ifdef IS_BTCLOCK_V8 +#define BTN_1 0 +#define BTN_2 1 +#define BTN_3 2 +#define BTN_4 3 +#else +#define BTN_1 3 +#define BTN_2 2 +#define BTN_3 1 +#define BTN_4 0 +#endif + void buttonTask(void *parameter) { while (1) { ulTaskNotifyTake(pdTRUE, portMAX_DELAY); @@ -17,16 +29,16 @@ void buttonTask(void *parameter) { uint pin = mcp1.getLastInterruptPin(); switch (pin) { - case 3: + case BTN_1: toggleTimerActive(); break; - case 2: + case BTN_2: nextScreen(); break; - case 1: + case BTN_3: previousScreen(); break; - case 0: + case BTN_4: showSystemStatusScreen(); break; } diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 2898a31..17805c0 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -4,7 +4,7 @@ Preferences preferences; Adafruit_MCP23X17 mcp1; -#ifdef IS_BTCLOCK_S3 +#ifdef IS_BTCLOCK_V8 Adafruit_MCP23X17 mcp2; #endif @@ -439,12 +439,12 @@ std::vector getScreenNameMap() { return screenMappings; } void setupMcp() { -#ifdef IS_BTCLOCK_S3 +#ifdef IS_BTCLOCK_V8 const int mcp1AddrPins[] = {MCP1_A0_PIN, MCP1_A1_PIN, MCP1_A2_PIN}; const int mcp1AddrValues[] = {LOW, LOW, LOW}; const int mcp2AddrPins[] = {MCP2_A0_PIN, MCP2_A1_PIN, MCP2_A2_PIN}; - const int mcp2AddrValues[] = {LOW, LOW, HIGH}; + const int mcp2AddrValues[] = {HIGH, LOW, LOW}; pinMode(MCP_RESET_PIN, OUTPUT); digitalWrite(MCP_RESET_PIN, HIGH); @@ -505,7 +505,7 @@ void setupHardware() if (!mcp1.begin_I2C(0x20)) { - Serial.println(F("Error MCP23017")); + Serial.println(F("Error MCP23017 1")); // while (1) // ; @@ -520,7 +520,7 @@ void setupHardware() mcp1.pinMode(i, INPUT_PULLUP); mcp1.setupInterruptPin(i, LOW); } -#ifndef IS_BTCLOCK_S3 +#ifndef IS_BTCLOCK_V8 for (int i = 8; i <= 14; i++) { mcp1.pinMode(i, OUTPUT); @@ -533,10 +533,10 @@ void setupHardware() #endif -#ifdef IS_BTCLOCK_S3 +#ifdef IS_BTCLOCK_V8 if (!mcp2.begin_I2C(0x21)) { - Serial.println(F("Error MCP23017")); + Serial.println(F("Error MCP23017 2")); // while (1) // ; diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index cc44c7e..7688fc8 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -30,7 +30,7 @@ MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = { }; Native_Pin EPD_DC = Native_Pin(14); -#elif IS_BTCLOCK_S3 +#elif IS_BTCLOCK_V8 Native_Pin EPD_DC = Native_Pin(38); MCP23X17_Pin EPD_BUSY[NUM_SCREENS] = { @@ -104,8 +104,8 @@ GxEPD2_BW displays[NUM_SCREENS] = { EPD_CLASS(&EPD_CS[4], &EPD_DC, &EPD_RESET_MPD[4], &EPD_BUSY[4]), EPD_CLASS(&EPD_CS[5], &EPD_DC, &EPD_RESET_MPD[5], &EPD_BUSY[5]), EPD_CLASS(&EPD_CS[6], &EPD_DC, &EPD_RESET_MPD[6], &EPD_BUSY[6]), -#ifdef IS_BTCLOCK_S3 - EPD_CLASS(&EPD_CS[7], &EPD_DC, &EPD_RESET_MPD[6], &EPD_BUSY[7]), +#ifdef IS_BTCLOCK_V8 + EPD_CLASS(&EPD_CS[7], &EPD_DC, &EPD_RESET_MPD[7], &EPD_BUSY[7]), #endif }; @@ -170,7 +170,7 @@ void setupDisplays() updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem)); - xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", 2048, NULL, 11, NULL); + xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", 4096, NULL, 11, NULL); for (uint i = 0; i < NUM_SCREENS; i++) { @@ -180,7 +180,7 @@ void setupDisplays() int *taskParam = new int; *taskParam = i; - xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), 2048, taskParam, + xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), 4096, taskParam, 11, &tasks[i]); // create task } @@ -194,8 +194,11 @@ void setupDisplays() } else { - + #ifdef IS_BTCLOCK_V8 + epdContent = {"B", "T", "C", "L", "O", "C", "K", "v8"}; + #else epdContent = {"B", "T", "C", "L", "O", "C", "K"}; + #endif } setEpdContent(epdContent); diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index 68a64b6..a381c7f 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -17,7 +17,7 @@ #include "defaults.hpp" extern Adafruit_MCP23X17 mcp1; -#ifdef IS_BTCLOCK_S3 +#ifdef IS_BTCLOCK_V8 extern Adafruit_MCP23X17 mcp2; #endif extern Preferences preferences; From 8b72f2f6b300d09ab1bdf758269cd5b3fab19ddd Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 21 Sep 2024 18:25:13 +0200 Subject: [PATCH 024/130] Fix merged binary for v8 --- .github/workflows/tagging.yml | 8 +- boards/sdkconfig.btclock_v8 | 1598 +++++++++++++++++++++++++++++++++ 2 files changed, 1603 insertions(+), 3 deletions(-) create mode 100644 boards/sdkconfig.btclock_v8 diff --git a/.github/workflows/tagging.yml b/.github/workflows/tagging.yml index 13e2a3c..2964234 100644 --- a/.github/workflows/tagging.yml +++ b/.github/workflows/tagging.yml @@ -63,10 +63,12 @@ jobs: mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && \ esptool.py --chip ${{ matrix.chip.version }} merge_bin \ -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \ - --flash_mode qio \ + --flash_mode dio \ + --flash_freq 80m \ + --flash_size 16MB \ 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin \ 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \ - 0xe000 .pio/boot_app0.bin \ + 0xe000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/ota_data_initial.bin \ 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \ 0x810000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin; else @@ -77,7 +79,7 @@ jobs: --flash_mode dio \ 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin \ 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \ - 0xe000 .pio/boot_app0.bin \ + 0xe000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/ota_data_initial.bin \ 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \ 0x369000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin # Adjust the offset for littlefs or other files as needed for the original case diff --git a/boards/sdkconfig.btclock_v8 b/boards/sdkconfig.btclock_v8 new file mode 100644 index 0000000..0c3b34e --- /dev/null +++ b/boards/sdkconfig.btclock_v8 @@ -0,0 +1,1598 @@ +# +# Automatically generated file. DO NOT EDIT. +# Espressif IoT Development Framework (ESP-IDF) Project Configuration +# +CONFIG_IDF_CMAKE=y +CONFIG_IDF_TARGET_ARCH_XTENSA=y +CONFIG_IDF_TARGET="esp32s3" +CONFIG_IDF_TARGET_ESP32S3=y +CONFIG_IDF_FIRMWARE_CHIP_ID=0x0009 + +# +# SDK tool configuration +# +CONFIG_SDK_TOOLPREFIX="xtensa-esp32s3-elf-" +# CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set +# end of SDK tool configuration + +# +# Build type +# +CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y +# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set +CONFIG_APP_BUILD_GENERATE_BINARIES=y +CONFIG_APP_BUILD_BOOTLOADER=y +CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y +# end of Build type + +# +# Application manager +# +CONFIG_APP_COMPILE_TIME_DATE=y +# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set +# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set +# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 +# end of Application manager + +# +# Bootloader config +# +CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x0 +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set +CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y +# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_INFO is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set +CONFIG_BOOTLOADER_LOG_LEVEL=0 + +# +# Serial Flash Configurations +# +# CONFIG_BOOTLOADER_FLASH_DC_AWARE is not set +CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y +# end of Serial Flash Configurations + +CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y +# CONFIG_BOOTLOADER_FACTORY_RESET is not set +# CONFIG_BOOTLOADER_APP_TEST is not set +CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y +CONFIG_BOOTLOADER_WDT_ENABLE=y +# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set +CONFIG_BOOTLOADER_WDT_TIME_MS=9000 +# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 +# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +# end of Bootloader config + +# +# Security features +# +CONFIG_SECURE_BOOT_SUPPORTS_RSA=y +CONFIG_SECURE_TARGET_HAS_SECURE_ROM_DL_MODE=y +# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set +# CONFIG_SECURE_BOOT is not set +# CONFIG_SECURE_FLASH_ENC_ENABLED is not set +# end of Security features + +# +# Boot ROM Behavior +# +CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y +# CONFIG_BOOT_ROM_LOG_ALWAYS_OFF is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_HIGH is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_LOW is not set +# end of Boot ROM Behavior + +# +# Serial flasher config +# +CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200 +# CONFIG_ESPTOOLPY_NO_STUB is not set +# CONFIG_ESPTOOLPY_OCT_FLASH is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y +# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y +CONFIG_ESPTOOLPY_FLASHMODE="dio" +CONFIG_ESPTOOLPY_S3_STR=y +# CONFIG_ESPTOOLPY_FLASHFREQ_120M is not set +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set +CONFIG_ESPTOOLPY_FLASHFREQ="80m" +# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE="2MB" +CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y +CONFIG_ESPTOOLPY_BEFORE_RESET=y +# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +CONFIG_ESPTOOLPY_BEFORE="default_reset" +CONFIG_ESPTOOLPY_AFTER_RESET=y +# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +CONFIG_ESPTOOLPY_AFTER="hard_reset" +# CONFIG_ESPTOOLPY_MONITOR_BAUD_CONSOLE is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set +CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y +# CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set +# CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set +CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200 +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +# end of Serial flasher config + +# +# Partition Table +# +CONFIG_PARTITION_TABLE_SINGLE_APP=y +# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +# CONFIG_PARTITION_TABLE_CUSTOM is not set +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# Arduino Configuration +# +CONFIG_ARDUINO_VARIANT="esp32s3" +CONFIG_ENABLE_ARDUINO_DEPENDS=y +# CONFIG_AUTOSTART_ARDUINO is not set +# CONFIG_ARDUINO_RUN_CORE0 is not set +CONFIG_ARDUINO_RUN_CORE1=y +# CONFIG_ARDUINO_RUN_NO_AFFINITY is not set +CONFIG_ARDUINO_RUNNING_CORE=1 +CONFIG_ARDUINO_LOOP_STACK_SIZE=8192 +# CONFIG_ARDUINO_EVENT_RUN_CORE0 is not set +CONFIG_ARDUINO_EVENT_RUN_CORE1=y +# CONFIG_ARDUINO_EVENT_RUN_NO_AFFINITY is not set +CONFIG_ARDUINO_EVENT_RUNNING_CORE=1 +# CONFIG_ARDUINO_SERIAL_EVENT_RUN_CORE0 is not set +# CONFIG_ARDUINO_SERIAL_EVENT_RUN_CORE1 is not set +CONFIG_ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY=y +CONFIG_ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE=-1 +CONFIG_ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE=2048 +CONFIG_ARDUINO_SERIAL_EVENT_TASK_PRIORITY=24 +CONFIG_ARDUINO_UDP_RUN_CORE0=y +# CONFIG_ARDUINO_UDP_RUN_CORE1 is not set +# CONFIG_ARDUINO_UDP_RUN_NO_AFFINITY is not set +CONFIG_ARDUINO_UDP_RUNNING_CORE=0 +CONFIG_ARDUINO_UDP_TASK_PRIORITY=3 +# CONFIG_ARDUINO_ISR_IRAM is not set +# CONFIG_DISABLE_HAL_LOCKS is not set + +# +# Debug Log Configuration +# +# CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_NONE is not set +CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_ERROR=y +# CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_WARN is not set +# CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_INFO is not set +# CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL=1 +# CONFIG_ARDUHAL_LOG_COLORS is not set +# CONFIG_ARDUHAL_ESP_LOG is not set +# end of Debug Log Configuration + +CONFIG_ARDUHAL_PARTITION_SCHEME_DEFAULT=y +# CONFIG_ARDUHAL_PARTITION_SCHEME_MINIMAL is not set +# CONFIG_ARDUHAL_PARTITION_SCHEME_NO_OTA is not set +# CONFIG_ARDUHAL_PARTITION_SCHEME_HUGE_APP is not set +# CONFIG_ARDUHAL_PARTITION_SCHEME_MIN_SPIFFS is not set +CONFIG_ARDUHAL_PARTITION_SCHEME="default" +# CONFIG_ARDUINO_SELECTIVE_COMPILATION is not set +# end of Arduino Configuration + +# +# Compiler options +# +# CONFIG_COMPILER_OPTIMIZATION_DEFAULT is not set +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_COMPILER_OPTIMIZATION_PERF is not set +# CONFIG_COMPILER_OPTIMIZATION_NONE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +CONFIG_COMPILER_CXX_EXCEPTIONS=y +CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0 +# CONFIG_COMPILER_CXX_RTTI is not set +CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y +# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set +# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set +# CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set +# CONFIG_COMPILER_DUMP_RTL_FILES is not set +# end of Compiler options + +# +# Component config +# + +# +# Application Level Tracing +# +# CONFIG_APPTRACE_DEST_JTAG is not set +CONFIG_APPTRACE_DEST_NONE=y +CONFIG_APPTRACE_LOCK_ENABLE=y +# end of Application Level Tracing + +# +# ESP-ASIO +# +# CONFIG_ASIO_SSL_SUPPORT is not set +# end of ESP-ASIO + +# +# Bluetooth +# +# CONFIG_BT_ENABLED is not set +# end of Bluetooth + +# +# CoAP Configuration +# +CONFIG_COAP_MBEDTLS_PSK=y +# CONFIG_COAP_MBEDTLS_PKI is not set +# CONFIG_COAP_MBEDTLS_DEBUG is not set +CONFIG_COAP_LOG_DEFAULT_LEVEL=0 +# end of CoAP Configuration + +# +# Driver configurations +# + +# +# ADC configuration +# +# CONFIG_ADC_FORCE_XPD_FSM is not set +CONFIG_ADC_DISABLE_DAC=y +# CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3 is not set +# end of ADC configuration + +# +# MCPWM configuration +# +# CONFIG_MCPWM_ISR_IN_IRAM is not set +# end of MCPWM configuration + +# +# SPI configuration +# +# CONFIG_SPI_MASTER_IN_IRAM is not set +CONFIG_SPI_MASTER_ISR_IN_IRAM=y +# CONFIG_SPI_SLAVE_IN_IRAM is not set +CONFIG_SPI_SLAVE_ISR_IN_IRAM=y +# end of SPI configuration + +# +# TWAI configuration +# +# CONFIG_TWAI_ISR_IN_IRAM is not set +# CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM is not set +# end of TWAI configuration + +# +# UART configuration +# +# CONFIG_UART_ISR_IN_IRAM is not set +# end of UART configuration + +# +# GDMA Configuration +# +# CONFIG_GDMA_CTRL_FUNC_IN_IRAM is not set +# CONFIG_GDMA_ISR_IRAM_SAFE is not set +# end of GDMA Configuration +# end of Driver configurations + +# +# eFuse Bit Manager +# +# CONFIG_EFUSE_CUSTOM_TABLE is not set +# CONFIG_EFUSE_VIRTUAL is not set +CONFIG_EFUSE_MAX_BLK_LEN=256 +# end of eFuse Bit Manager + +# +# ESP-TLS +# +CONFIG_ESP_TLS_USING_MBEDTLS=y +CONFIG_ESP_TLS_USE_DS_PERIPHERAL=y +# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set +# CONFIG_ESP_TLS_SERVER is not set +# CONFIG_ESP_TLS_PSK_VERIFICATION is not set +# CONFIG_ESP_TLS_INSECURE is not set +# end of ESP-TLS + +# +# ESP32S3-Specific +# +CONFIG_ESP32S3_REV_MIN_0=y +# CONFIG_ESP32S3_REV_MIN_1 is not set +# CONFIG_ESP32S3_REV_MIN_2 is not set +CONFIG_ESP32S3_REV_MIN_FULL=0 +CONFIG_ESP_REV_MIN_FULL=0 +CONFIG_ESP32S3_REV_MAX_FULL_STR_OPT=y +CONFIG_ESP32S3_REV_MAX_FULL=99 +CONFIG_ESP_REV_MAX_FULL=99 +# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_80 is not set +CONFIG_ESP32S3_DEFAULT_CPU_FREQ_160=y +# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240 is not set +CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=160 + +# +# Cache config +# +CONFIG_ESP32S3_INSTRUCTION_CACHE_16KB=y +# CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB is not set +CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE=0x4000 +# CONFIG_ESP32S3_INSTRUCTION_CACHE_4WAYS is not set +CONFIG_ESP32S3_INSTRUCTION_CACHE_8WAYS=y +CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS=8 +# CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_16B is not set +CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_32B=y +CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_SIZE=32 +# CONFIG_ESP32S3_INSTRUCTION_CACHE_WRAP is not set +# CONFIG_ESP32S3_DATA_CACHE_16KB is not set +CONFIG_ESP32S3_DATA_CACHE_32KB=y +# CONFIG_ESP32S3_DATA_CACHE_64KB is not set +CONFIG_ESP32S3_DATA_CACHE_SIZE=0x8000 +# CONFIG_ESP32S3_DATA_CACHE_4WAYS is not set +CONFIG_ESP32S3_DATA_CACHE_8WAYS=y +CONFIG_ESP32S3_DCACHE_ASSOCIATED_WAYS=8 +# CONFIG_ESP32S3_DATA_CACHE_LINE_16B is not set +CONFIG_ESP32S3_DATA_CACHE_LINE_32B=y +# CONFIG_ESP32S3_DATA_CACHE_LINE_64B is not set +CONFIG_ESP32S3_DATA_CACHE_LINE_SIZE=32 +# CONFIG_ESP32S3_DATA_CACHE_WRAP is not set +# end of Cache config + +CONFIG_ESP32S3_SPIRAM_SUPPORT=y + +# +# SPI RAM config +# +# CONFIG_SPIRAM_MODE_QUAD is not set +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_TYPE_AUTO=y +# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set +CONFIG_SPIRAM_SIZE=-1 +CONFIG_SPIRAM_CLK_IO=30 +CONFIG_SPIRAM_CS_IO=26 +# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set +# CONFIG_SPIRAM_RODATA is not set +# CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY is not set +# CONFIG_SPIRAM_SPEED_80M is not set +CONFIG_SPIRAM_SPEED_40M=y +CONFIG_SPIRAM=y +CONFIG_SPIRAM_BOOT_INIT=y +# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set +# CONFIG_SPIRAM_USE_MEMMAP is not set +# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set +CONFIG_SPIRAM_USE_MALLOC=y +CONFIG_SPIRAM_MEMTEST=y +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384 +CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y +CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768 +# end of SPI RAM config + +# CONFIG_ESP32S3_TRAX is not set +CONFIG_ESP32S3_TRACEMEM_RESERVE_DRAM=0x0 +# CONFIG_ESP32S3_ULP_COPROC_ENABLED is not set +CONFIG_ESP32S3_ULP_COPROC_RESERVE_MEM=0 +CONFIG_ESP32S3_DEBUG_OCDAWARE=y +CONFIG_ESP32S3_BROWNOUT_DET=y +CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_7=y +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_1 is not set +CONFIG_ESP32S3_BROWNOUT_DET_LVL=7 +CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC_FRC1=y +# CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC is not set +# CONFIG_ESP32S3_TIME_SYSCALL_USE_FRC1 is not set +# CONFIG_ESP32S3_TIME_SYSCALL_USE_NONE is not set +CONFIG_ESP32S3_RTC_CLK_SRC_INT_RC=y +# CONFIG_ESP32S3_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_ESP32S3_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_ESP32S3_RTC_CLK_SRC_INT_8MD256 is not set +CONFIG_ESP32S3_RTC_CLK_CAL_CYCLES=1024 +CONFIG_ESP32S3_DEEP_SLEEP_WAKEUP_DELAY=2000 +# CONFIG_ESP32S3_NO_BLOBS is not set +# CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM is not set +# CONFIG_ESP32S3_USE_FIXED_STATIC_RAM_SIZE is not set +# end of ESP32S3-Specific + +# +# ADC-Calibration +# +# end of ADC-Calibration + +# +# Common ESP-related +# +CONFIG_ESP_ERR_TO_NAME_LOOKUP=y +# end of Common ESP-related + +# +# Ethernet +# +CONFIG_ETH_ENABLED=y +CONFIG_ETH_USE_SPI_ETHERNET=y +# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set +# CONFIG_ETH_SPI_ETHERNET_W5500 is not set +# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set +# CONFIG_ETH_USE_OPENETH is not set +# end of Ethernet + +# +# Event Loop Library +# +# CONFIG_ESP_EVENT_LOOP_PROFILING is not set +CONFIG_ESP_EVENT_POST_FROM_ISR=y +CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y +# end of Event Loop Library + +# +# GDB Stub +# +# end of GDB Stub + +# +# ESP HTTP client +# +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y +# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set +CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH=y +# end of ESP HTTP client + +# +# HTTP Server +# +CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_URI_LEN=512 +CONFIG_HTTPD_ERR_RESP_NO_DELAY=y +CONFIG_HTTPD_PURGE_BUF_LEN=32 +# CONFIG_HTTPD_LOG_PURGE_DATA is not set +# CONFIG_HTTPD_WS_SUPPORT is not set +# end of HTTP Server + +# +# ESP HTTPS OTA +# +# CONFIG_OTA_ALLOW_HTTP is not set +# end of ESP HTTPS OTA + +# +# ESP HTTPS server +# +# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set +# end of ESP HTTPS server + +# +# Hardware Settings +# + +# +# MAC Config +# +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y +# CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES_TWO is not set +CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES=4 +# end of MAC Config + +# +# Sleep Config +# +CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y +CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y +CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND=y +CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y +CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU=y +CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y +# end of Sleep Config + +# +# RTC Clock Config +# +CONFIG_RTC_CLOCK_BBPLL_POWER_ON_WITH_USB=y +# end of RTC Clock Config +# end of Hardware Settings + +# +# IPC (Inter-Processor Call) +# +CONFIG_ESP_IPC_TASK_STACK_SIZE=1536 +CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y +CONFIG_ESP_IPC_ISR_ENABLE=y +# end of IPC (Inter-Processor Call) + +# +# LCD and Touch Panel +# + +# +# LCD Touch Drivers are maintained in the IDF Component Registry +# + +# +# LCD Peripheral Configuration +# +CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE=32 +# CONFIG_LCD_RGB_ISR_IRAM_SAFE is not set +# end of LCD Peripheral Configuration +# end of LCD and Touch Panel + +# +# ESP NETIF Adapter +# +CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 +CONFIG_ESP_NETIF_TCPIP_LWIP=y +# CONFIG_ESP_NETIF_LOOPBACK is not set +CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y +# end of ESP NETIF Adapter + +# +# PHY +# +CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP_PHY_MAX_TX_POWER=20 +# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set +CONFIG_ESP_PHY_ENABLE_USB=y +CONFIG_ESP_PHY_RF_CAL_PARTIAL=y +# CONFIG_ESP_PHY_RF_CAL_NONE is not set +# CONFIG_ESP_PHY_RF_CAL_FULL is not set +CONFIG_ESP_PHY_CALIBRATION_MODE=0 +# end of PHY + +# +# Power Management +# +# CONFIG_PM_ENABLE is not set +CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y +CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP=y +# end of Power Management + +# +# ESP Ringbuf +# +# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH is not set +# end of ESP Ringbuf + +# +# ESP System Settings +# +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set +CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y +# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set +# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set +CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y +CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y + +# +# Memory protection +# +# end of Memory protection + +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y +# CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1 is not set +# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_USB_CDC is not set +# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set +# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_NONE is not set +# CONFIG_ESP_CONSOLE_SECONDARY_NONE is not set +CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y +CONFIG_ESP_CONSOLE_UART=y +CONFIG_ESP_CONSOLE_MULTIPLE_UART=y +CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_INT_WDT=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 +CONFIG_ESP_INT_WDT_CHECK_CPU1=y +CONFIG_ESP_TASK_WDT=y +# CONFIG_ESP_TASK_WDT_PANIC is not set +CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y +CONFIG_ESP_SYSTEM_BBPLL_RECALIB=y +# end of ESP System Settings + +# +# High resolution timer (esp_timer) +# +# CONFIG_ESP_TIMER_PROFILING is not set +CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y +CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y +CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1 +# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set +CONFIG_ESP_TIMER_IMPL_SYSTIMER=y +# end of High resolution timer (esp_timer) + +# +# Wi-Fi +# +CONFIG_ESP32_WIFI_ENABLED=y +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=6 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=12 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16 +CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32 +CONFIG_ESP_WIFI_STATIC_RX_MGMT_BUFFER=y +# CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUFFER is not set +CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF=0 +CONFIG_ESP_WIFI_RX_MGMT_BUF_NUM_DEF=5 +# CONFIG_ESP32_WIFI_CSI_ENABLED is not set +CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP32_WIFI_TX_BA_WIN=6 +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_RX_BA_WIN=6 +# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set +CONFIG_ESP32_WIFI_NVS_ENABLED=y +CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y +# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set +CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 +CONFIG_ESP32_WIFI_IRAM_OPT=y +CONFIG_ESP32_WIFI_RX_IRAM_OPT=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y +# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set +# CONFIG_ESP_WIFI_FTM_ENABLE is not set +# CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set +# CONFIG_ESP_WIFI_GCMP_SUPPORT is not set +# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y +# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set +CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7 +# end of Wi-Fi + +# +# Core dump +# +# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set +# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set +CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y +# end of Core dump + +# +# FAT Filesystem support +# +# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set +CONFIG_FATFS_CODEPAGE_437=y +# CONFIG_FATFS_CODEPAGE_720 is not set +# CONFIG_FATFS_CODEPAGE_737 is not set +# CONFIG_FATFS_CODEPAGE_771 is not set +# CONFIG_FATFS_CODEPAGE_775 is not set +# CONFIG_FATFS_CODEPAGE_850 is not set +# CONFIG_FATFS_CODEPAGE_852 is not set +# CONFIG_FATFS_CODEPAGE_855 is not set +# CONFIG_FATFS_CODEPAGE_857 is not set +# CONFIG_FATFS_CODEPAGE_860 is not set +# CONFIG_FATFS_CODEPAGE_861 is not set +# CONFIG_FATFS_CODEPAGE_862 is not set +# CONFIG_FATFS_CODEPAGE_863 is not set +# CONFIG_FATFS_CODEPAGE_864 is not set +# CONFIG_FATFS_CODEPAGE_865 is not set +# CONFIG_FATFS_CODEPAGE_866 is not set +# CONFIG_FATFS_CODEPAGE_869 is not set +# CONFIG_FATFS_CODEPAGE_932 is not set +# CONFIG_FATFS_CODEPAGE_936 is not set +# CONFIG_FATFS_CODEPAGE_949 is not set +# CONFIG_FATFS_CODEPAGE_950 is not set +CONFIG_FATFS_CODEPAGE=437 +CONFIG_FATFS_LFN_NONE=y +# CONFIG_FATFS_LFN_HEAP is not set +# CONFIG_FATFS_LFN_STACK is not set +CONFIG_FATFS_FS_LOCK=0 +CONFIG_FATFS_TIMEOUT_MS=10000 +CONFIG_FATFS_PER_FILE_CACHE=y +CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y +# CONFIG_FATFS_USE_FASTSEEK is not set +# end of FAT Filesystem support + +# +# Modbus configuration +# +CONFIG_FMB_COMM_MODE_TCP_EN=y +CONFIG_FMB_TCP_PORT_DEFAULT=502 +CONFIG_FMB_TCP_PORT_MAX_CONN=5 +CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20 +CONFIG_FMB_COMM_MODE_RTU_EN=y +CONFIG_FMB_COMM_MODE_ASCII_EN=y +CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150 +CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200 +CONFIG_FMB_QUEUE_LENGTH=20 +CONFIG_FMB_PORT_TASK_STACK_SIZE=4096 +CONFIG_FMB_SERIAL_BUF_SIZE=256 +CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB=8 +CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS=1000 +CONFIG_FMB_PORT_TASK_PRIO=10 +# CONFIG_FMB_PORT_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_FMB_PORT_TASK_AFFINITY_CPU0=y +# CONFIG_FMB_PORT_TASK_AFFINITY_CPU1 is not set +CONFIG_FMB_PORT_TASK_AFFINITY=0x0 +CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT=y +CONFIG_FMB_CONTROLLER_SLAVE_ID=0x00112233 +CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20 +CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20 +CONFIG_FMB_CONTROLLER_STACK_SIZE=4096 +CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20 +# CONFIG_FMB_TIMER_PORT_ENABLED is not set +# CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD is not set +# end of Modbus configuration + +# +# FreeRTOS +# +# CONFIG_FREERTOS_UNICORE is not set +CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y +CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y +# CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set +CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y +CONFIG_FREERTOS_HZ=1000 +CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y +CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y +CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 +CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y +# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set +# CONFIG_FREERTOS_ASSERT_DISABLE is not set +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 +CONFIG_FREERTOS_ISR_STACKSIZE=1536 +# CONFIG_FREERTOS_LEGACY_HOOKS is not set +CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y +# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set +CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120 +CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 +CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 +# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set +# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set +CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y +# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set +# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set +CONFIG_FREERTOS_DEBUG_OCDAWARE=y +CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y +# CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH is not set +# end of FreeRTOS + +# +# Hardware Abstraction Layer (HAL) and Low Level (LL) +# +CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y +# CONFIG_HAL_ASSERTION_DISABLE is not set +# CONFIG_HAL_ASSERTION_SILIENT is not set +# CONFIG_HAL_ASSERTION_ENABLE is not set +CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 +# end of Hardware Abstraction Layer (HAL) and Low Level (LL) + +# +# Heap memory debugging +# +# CONFIG_HEAP_POISONING_DISABLED is not set +CONFIG_HEAP_POISONING_LIGHT=y +# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set +CONFIG_HEAP_TRACING_OFF=y +# CONFIG_HEAP_TRACING_STANDALONE is not set +# CONFIG_HEAP_TRACING_TOHOST is not set +# CONFIG_HEAP_TASK_TRACKING is not set +# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set +# end of Heap memory debugging + +# +# jsmn +# +# CONFIG_JSMN_PARENT_LINKS is not set +# CONFIG_JSMN_STRICT is not set +# end of jsmn + +# +# libsodium +# +# end of libsodium + +# +# Log output +# +CONFIG_LOG_DEFAULT_LEVEL_NONE=y +# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=0 +CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y +# CONFIG_LOG_MAXIMUM_LEVEL_ERROR is not set +# CONFIG_LOG_MAXIMUM_LEVEL_WARN is not set +# CONFIG_LOG_MAXIMUM_LEVEL_INFO is not set +# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +CONFIG_LOG_MAXIMUM_LEVEL=0 +CONFIG_LOG_COLORS=y +CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y +# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set +# end of Log output + +# +# LWIP +# +CONFIG_LWIP_LOCAL_HOSTNAME="espressif" +# CONFIG_LWIP_NETIF_API is not set +CONFIG_LWIP_TCPIP_TASK_PRIO=18 +# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set +# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +# CONFIG_LWIP_L2_TO_L3_COPY is not set +# CONFIG_LWIP_IRAM_OPTIMIZATION is not set +CONFIG_LWIP_TIMERS_ONDEMAND=y +CONFIG_LWIP_MAX_SOCKETS=10 +# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set +# CONFIG_LWIP_SO_LINGER is not set +CONFIG_LWIP_SO_REUSE=y +CONFIG_LWIP_SO_REUSE_RXTOALL=y +CONFIG_LWIP_SO_RCVBUF=y +# CONFIG_LWIP_NETBUF_RECVINFO is not set +CONFIG_LWIP_IP_DEFAULT_TTL=64 +CONFIG_LWIP_IP4_FRAG=y +CONFIG_LWIP_IP6_FRAG=y +# CONFIG_LWIP_IP4_REASSEMBLY is not set +# CONFIG_LWIP_IP6_REASSEMBLY is not set +# CONFIG_LWIP_IP_FORWARD is not set +# CONFIG_LWIP_STATS is not set +# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set +CONFIG_LWIP_ESP_GRATUITOUS_ARP=y +CONFIG_LWIP_GARP_TMR_INTERVAL=60 +CONFIG_LWIP_ESP_MLDV6_REPORT=y +CONFIG_LWIP_MLDV6_TMR_INTERVAL=40 +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 +CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y +# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set +CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y +# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set +CONFIG_LWIP_DHCP_OPTIONS_LEN=68 +CONFIG_LWIP_DHCP_COARSE_TIMER_SECS=1 + +# +# DHCP server +# +CONFIG_LWIP_DHCPS=y +CONFIG_LWIP_DHCPS_LEASE_UNIT=60 +CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 +# end of DHCP server + +# CONFIG_LWIP_AUTOIP is not set +CONFIG_LWIP_IPV6=y +# CONFIG_LWIP_IPV6_AUTOCONFIG is not set +CONFIG_LWIP_IPV6_NUM_ADDRESSES=3 +# CONFIG_LWIP_IPV6_FORWARD is not set +# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=y +CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 + +# +# TCP +# +CONFIG_LWIP_MAX_ACTIVE_TCP=16 +CONFIG_LWIP_MAX_LISTENING_TCP=16 +CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y +CONFIG_LWIP_TCP_MAXRTX=12 +CONFIG_LWIP_TCP_SYNMAXRTX=12 +CONFIG_LWIP_TCP_MSS=1440 +CONFIG_LWIP_TCP_TMR_INTERVAL=250 +CONFIG_LWIP_TCP_MSL=60000 +CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000 +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5760 +CONFIG_LWIP_TCP_WND_DEFAULT=5760 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 +CONFIG_LWIP_TCP_QUEUE_OOSEQ=y +CONFIG_LWIP_TCP_OOSEQ_TIMEOUT=6 +CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=0 +# CONFIG_LWIP_TCP_SACK_OUT is not set +# CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set +CONFIG_LWIP_TCP_OVERSIZE_MSS=y +# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set +# CONFIG_LWIP_WND_SCALE is not set +CONFIG_LWIP_TCP_RTO_TIME=1500 +# end of TCP + +# +# UDP +# +CONFIG_LWIP_MAX_UDP_PCBS=16 +CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 +# end of UDP + +# +# Checksums +# +# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set +# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set +CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y +# end of Checksums + +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_LWIP_PPP_SUPPORT is not set +CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 +CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 +# CONFIG_LWIP_SLIP_SUPPORT is not set + +# +# ICMP +# +CONFIG_LWIP_ICMP=y +# CONFIG_LWIP_MULTICAST_PING is not set +# CONFIG_LWIP_BROADCAST_PING is not set +# end of ICMP + +# +# LWIP RAW API +# +CONFIG_LWIP_MAX_RAW_PCBS=16 +# end of LWIP RAW API + +# +# SNTP +# +CONFIG_LWIP_SNTP_MAX_SERVERS=1 +# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set +CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 +# end of SNTP + +# +# DNS +# +CONFIG_LWIP_DNS_MAX_SERVERS=3 +# CONFIG_LWIP_FALLBACK_DNS_SERVER_SUPPORT is not set +# end of DNS + +CONFIG_LWIP_ESP_LWIP_ASSERT=y + +# +# Hooks +# +# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set +CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y +# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y +# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set +CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y +# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set +# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set +CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set +# end of Hooks + +# CONFIG_LWIP_DEBUG is not set +# end of LWIP + +# +# mbedTLS +# +CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set +# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set +# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set +# CONFIG_MBEDTLS_DEBUG is not set + +# +# mbedTLS v2.28.x related +# +# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set +# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set +# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set +CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y +# end of mbedTLS v2.28.x related + +# +# Certificate Bundle +# +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set +# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 +# end of Certificate Bundle + +# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set +# CONFIG_MBEDTLS_CMAC_C is not set +CONFIG_MBEDTLS_HARDWARE_AES=y +CONFIG_MBEDTLS_AES_USE_INTERRUPT=y +CONFIG_MBEDTLS_HARDWARE_MPI=y +CONFIG_MBEDTLS_HARDWARE_SHA=y +CONFIG_MBEDTLS_ROM_MD5=y +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set +CONFIG_MBEDTLS_HAVE_TIME=y +# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y +CONFIG_MBEDTLS_SHA512_C=y +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set +# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set +# CONFIG_MBEDTLS_TLS_DISABLED is not set +CONFIG_MBEDTLS_TLS_SERVER=y +CONFIG_MBEDTLS_TLS_CLIENT=y +CONFIG_MBEDTLS_TLS_ENABLED=y + +# +# TLS Key Exchange Methods +# +CONFIG_MBEDTLS_PSK_MODES=y +CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_PSK=y +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_PSK=y +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y +# end of TLS Key Exchange Methods + +CONFIG_MBEDTLS_SSL_RENEGOTIATION=y +# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set +CONFIG_MBEDTLS_SSL_PROTO_TLS1=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set +# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set +CONFIG_MBEDTLS_SSL_ALPN=y +CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y +CONFIG_MBEDTLS_X509_CHECK_KEY_USAGE=y +CONFIG_MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE=y +CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y + +# +# Symmetric Ciphers +# +CONFIG_MBEDTLS_AES_C=y +# CONFIG_MBEDTLS_CAMELLIA_C is not set +# CONFIG_MBEDTLS_DES_C is not set +CONFIG_MBEDTLS_RC4_DISABLED=y +# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set +# CONFIG_MBEDTLS_RC4_ENABLED is not set +# CONFIG_MBEDTLS_BLOWFISH_C is not set +# CONFIG_MBEDTLS_XTEA_C is not set +CONFIG_MBEDTLS_CCM_C=y +CONFIG_MBEDTLS_GCM_C=y +# CONFIG_MBEDTLS_NIST_KW_C is not set +# end of Symmetric Ciphers + +# CONFIG_MBEDTLS_RIPEMD160_C is not set + +# +# Certificates +# +CONFIG_MBEDTLS_PEM_PARSE_C=y +CONFIG_MBEDTLS_PEM_WRITE_C=y +CONFIG_MBEDTLS_X509_CRL_PARSE_C=y +CONFIG_MBEDTLS_X509_CSR_PARSE_C=y +# end of Certificates + +CONFIG_MBEDTLS_ECP_C=y +CONFIG_MBEDTLS_ECDH_C=y +CONFIG_MBEDTLS_ECDSA_C=y +# CONFIG_MBEDTLS_ECJPAKE_C is not set +CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y +CONFIG_MBEDTLS_ECP_NIST_OPTIM=y +# CONFIG_MBEDTLS_POLY1305_C is not set +# CONFIG_MBEDTLS_CHACHA20_C is not set +# CONFIG_MBEDTLS_HKDF_C is not set +# CONFIG_MBEDTLS_THREADING_C is not set +# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set +# CONFIG_MBEDTLS_SECURITY_RISKS is not set +# end of mbedTLS + +# +# mDNS +# +CONFIG_MDNS_MAX_SERVICES=10 +CONFIG_MDNS_TASK_PRIORITY=1 +CONFIG_MDNS_TASK_STACK_SIZE=4096 +# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_MDNS_TASK_AFFINITY_CPU0=y +# CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set +CONFIG_MDNS_TASK_AFFINITY=0x0 +CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000 +# CONFIG_MDNS_STRICT_MODE is not set +CONFIG_MDNS_TIMER_PERIOD_MS=100 +# CONFIG_MDNS_NETWORKING_SOCKET is not set +CONFIG_MDNS_MULTIPLE_INSTANCE=y +# end of mDNS + +# +# ESP-MQTT Configurations +# +CONFIG_MQTT_PROTOCOL_311=y +CONFIG_MQTT_TRANSPORT_SSL=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y +# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set +# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set +# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set +# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set +# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set +# CONFIG_MQTT_CUSTOM_OUTBOX is not set +# end of ESP-MQTT Configurations + +# +# Newlib +# +CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set +CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y +CONFIG_NEWLIB_NANO_FORMAT=y +# end of Newlib + +# +# NVS +# +# CONFIG_NVS_ASSERT_ERROR_CHECK is not set +# end of NVS + +# +# OpenSSL +# +# CONFIG_OPENSSL_DEBUG is not set +CONFIG_OPENSSL_ERROR_STACK=y +# CONFIG_OPENSSL_ASSERT_DO_NOTHING is not set +CONFIG_OPENSSL_ASSERT_EXIT=y +# end of OpenSSL + +# +# OpenThread +# +# CONFIG_OPENTHREAD_ENABLED is not set +# end of OpenThread + +# +# PThreads +# +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_PTHREAD_STACK_MIN=768 +CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y +# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set +# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set +CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" +# end of PThreads + +# +# Main Flash configuration +# + +# +# Optional and Experimental Features (READ DOCS FIRST) +# + +# +# Features here require specific hardware (READ DOCS FIRST!) +# +# CONFIG_SPI_FLASH_HPM_ENA is not set +CONFIG_SPI_FLASH_HPM_AUTO=y +# CONFIG_SPI_FLASH_HPM_DIS is not set +CONFIG_SPI_FLASH_HPM_ON=y +CONFIG_SPI_FLASH_HPM_DC_AUTO=y +# CONFIG_SPI_FLASH_HPM_DC_DISABLE is not set +# end of Optional and Experimental Features (READ DOCS FIRST) +# end of Main Flash configuration + +# +# SPI Flash driver +# +# CONFIG_SPI_FLASH_VERIFY_WRITE is not set +# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set +CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y +# CONFIG_SPI_FLASH_ROM_IMPL is not set +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set +# CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set +# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set +# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set +CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y +CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 +CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 +CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 +# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set +# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set +# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set + +# +# Auto-detect flash chips +# +CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP=y +# end of Auto-detect flash chips + +CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y +# end of SPI Flash driver + +# +# SPIFFS Configuration +# +CONFIG_SPIFFS_MAX_PARTITIONS=3 + +# +# SPIFFS Cache Configuration +# +CONFIG_SPIFFS_CACHE=y +CONFIG_SPIFFS_CACHE_WR=y +# CONFIG_SPIFFS_CACHE_STATS is not set +# end of SPIFFS Cache Configuration + +CONFIG_SPIFFS_PAGE_CHECK=y +CONFIG_SPIFFS_GC_MAX_RUNS=10 +# CONFIG_SPIFFS_GC_STATS is not set +CONFIG_SPIFFS_PAGE_SIZE=256 +CONFIG_SPIFFS_OBJ_NAME_LEN=32 +# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set +CONFIG_SPIFFS_USE_MAGIC=y +CONFIG_SPIFFS_USE_MAGIC_LENGTH=y +CONFIG_SPIFFS_META_LENGTH=4 +CONFIG_SPIFFS_USE_MTIME=y + +# +# Debug Configuration +# +# CONFIG_SPIFFS_DBG is not set +# CONFIG_SPIFFS_API_DBG is not set +# CONFIG_SPIFFS_GC_DBG is not set +# CONFIG_SPIFFS_CACHE_DBG is not set +# CONFIG_SPIFFS_CHECK_DBG is not set +# CONFIG_SPIFFS_TEST_VISUALISATION is not set +# end of Debug Configuration +# end of SPIFFS Configuration + +# +# TCP Transport +# + +# +# Websocket +# +CONFIG_WS_TRANSPORT=y +CONFIG_WS_BUFFER_SIZE=1024 +# end of Websocket +# end of TCP Transport + +# +# TinyUSB Stack +# +# CONFIG_TINYUSB is not set +# end of TinyUSB Stack + +# +# Unity unit testing library +# +CONFIG_UNITY_ENABLE_FLOAT=y +CONFIG_UNITY_ENABLE_DOUBLE=y +# CONFIG_UNITY_ENABLE_64BIT is not set +# CONFIG_UNITY_ENABLE_COLOR is not set +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y +# CONFIG_UNITY_ENABLE_FIXTURE is not set +# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set +# end of Unity unit testing library + +# +# USB-OTG +# +CONFIG_USB_OTG_SUPPORTED=y +CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE=256 +CONFIG_USB_HOST_HW_BUFFER_BIAS_BALANCED=y +# CONFIG_USB_HOST_HW_BUFFER_BIAS_IN is not set +# CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT is not set + +# +# Root Hub configuration +# +CONFIG_USB_HOST_DEBOUNCE_DELAY_MS=250 +CONFIG_USB_HOST_RESET_HOLD_MS=30 +CONFIG_USB_HOST_RESET_RECOVERY_MS=30 +CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS=10 +# end of Root Hub configuration +# end of USB-OTG + +# +# Virtual file system +# +CONFIG_VFS_SUPPORT_IO=y +CONFIG_VFS_SUPPORT_DIR=y +CONFIG_VFS_SUPPORT_SELECT=y +CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_VFS_SUPPORT_TERMIOS=y + +# +# Host File System I/O (Semihosting) +# +CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# end of Host File System I/O (Semihosting) +# end of Virtual file system + +# +# Wear Levelling +# +# CONFIG_WL_SECTOR_SIZE_512 is not set +CONFIG_WL_SECTOR_SIZE_4096=y +CONFIG_WL_SECTOR_SIZE=4096 +# end of Wear Levelling + +# +# Wi-Fi Provisioning Manager +# +CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 +CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 +# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set +# end of Wi-Fi Provisioning Manager + +# +# Supplicant +# +CONFIG_WPA_MBEDTLS_CRYPTO=y +# CONFIG_WPA_WAPI_PSK is not set +# CONFIG_WPA_SUITE_B_192 is not set +# CONFIG_WPA_DEBUG_PRINT is not set +# CONFIG_WPA_TESTING_OPTIONS is not set +# CONFIG_WPA_WPS_STRICT is not set +# CONFIG_WPA_11KV_SUPPORT is not set +# CONFIG_WPA_MBO_SUPPORT is not set +# CONFIG_WPA_DPP_SUPPORT is not set +# end of Supplicant + +# +# LittleFS +# +# CONFIG_LITTLEFS_SDMMC_SUPPORT is not set +CONFIG_LITTLEFS_MAX_PARTITIONS=3 +CONFIG_LITTLEFS_PAGE_SIZE=256 +CONFIG_LITTLEFS_OBJ_NAME_LEN=64 +CONFIG_LITTLEFS_READ_SIZE=128 +CONFIG_LITTLEFS_WRITE_SIZE=128 +CONFIG_LITTLEFS_LOOKAHEAD_SIZE=128 +CONFIG_LITTLEFS_CACHE_SIZE=512 +CONFIG_LITTLEFS_BLOCK_CYCLES=512 +CONFIG_LITTLEFS_USE_MTIME=y +# CONFIG_LITTLEFS_USE_ONLY_HASH is not set +# CONFIG_LITTLEFS_HUMAN_READABLE is not set +CONFIG_LITTLEFS_MTIME_USE_SECONDS=y +# CONFIG_LITTLEFS_MTIME_USE_NONCE is not set +# CONFIG_LITTLEFS_SPIFFS_COMPAT is not set +# CONFIG_LITTLEFS_FLUSH_FILE_EVERY_WRITE is not set +# CONFIG_LITTLEFS_FCNTL_GET_PATH is not set +# CONFIG_LITTLEFS_MULTIVERSION is not set +# CONFIG_LITTLEFS_MALLOC_STRATEGY_DISABLE is not set +CONFIG_LITTLEFS_MALLOC_STRATEGY_DEFAULT=y +# CONFIG_LITTLEFS_MALLOC_STRATEGY_INTERNAL is not set +CONFIG_LITTLEFS_ASSERTS=y +# end of LittleFS +# end of Component config + +# +# Compatibility options +# +# CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set +# end of Compatibility options + +# Deprecated options for backward compatibility +CONFIG_TOOLPREFIX="xtensa-esp32s3-elf-" +CONFIG_LOG_BOOTLOADER_LEVEL_NONE=y +# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_INFO is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set +CONFIG_LOG_BOOTLOADER_LEVEL=0 +# CONFIG_APP_ROLLBACK_ENABLE is not set +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +# CONFIG_FLASHMODE_QIO is not set +# CONFIG_FLASHMODE_QOUT is not set +CONFIG_FLASHMODE_DIO=y +# CONFIG_FLASHMODE_DOUT is not set +# CONFIG_MONITOR_BAUD_9600B is not set +# CONFIG_MONITOR_BAUD_57600B is not set +CONFIG_MONITOR_BAUD_115200B=y +# CONFIG_MONITOR_BAUD_230400B is not set +# CONFIG_MONITOR_BAUD_921600B is not set +# CONFIG_MONITOR_BAUD_2MB is not set +# CONFIG_MONITOR_BAUD_OTHER is not set +CONFIG_MONITOR_BAUD_OTHER_VAL=115200 +CONFIG_MONITOR_BAUD=115200 +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set +CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y +CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2 +CONFIG_CXX_EXCEPTIONS=y +CONFIG_CXX_EXCEPTIONS_EMG_POOL_SIZE=0 +CONFIG_STACK_CHECK_NONE=y +# CONFIG_STACK_CHECK_NORM is not set +# CONFIG_STACK_CHECK_STRONG is not set +# CONFIG_STACK_CHECK_ALL is not set +# CONFIG_WARN_WRITE_STRINGS is not set +# CONFIG_DISABLE_GCC8_WARNINGS is not set +# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set +CONFIG_ESP32_APPTRACE_DEST_NONE=y +CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y +CONFIG_ADC2_DISABLE_DAC=y +CONFIG_DEFAULT_PSRAM_CLK_IO=30 +CONFIG_DEFAULT_PSRAM_CS_IO=26 +# CONFIG_EVENT_LOOP_PROFILING is not set +CONFIG_POST_EVENTS_FROM_ISR=y +CONFIG_POST_EVENTS_FROM_IRAM_ISR=y +CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND=y +CONFIG_IPC_TASK_STACK_SIZE=1536 +CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP32_PHY_MAX_TX_POWER=20 +# CONFIG_ESP32_REDUCE_PHY_TX_POWER is not set +CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU=y +# CONFIG_ESP32S2_PANIC_PRINT_HALT is not set +CONFIG_ESP32S2_PANIC_PRINT_REBOOT=y +# CONFIG_ESP32S2_PANIC_SILENT_REBOOT is not set +# CONFIG_ESP32S2_PANIC_GDBSTUB is not set +CONFIG_ESP32S2_ALLOW_RTC_FAST_MEM_AS_HEAP=y +CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART=y +CONFIG_CONSOLE_UART_NUM=0 +CONFIG_CONSOLE_UART_BAUDRATE=115200 +CONFIG_INT_WDT=y +CONFIG_INT_WDT_TIMEOUT_MS=300 +CONFIG_INT_WDT_CHECK_CPU1=y +CONFIG_TASK_WDT=y +# CONFIG_TASK_WDT_PANIC is not set +CONFIG_TASK_WDT_TIMEOUT_S=5 +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y +# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set +CONFIG_TIMER_TASK_STACK_SIZE=3584 +# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y +CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150 +CONFIG_MB_MASTER_DELAY_MS_CONVERT=200 +CONFIG_MB_QUEUE_LENGTH=20 +CONFIG_MB_SERIAL_TASK_STACK_SIZE=4096 +CONFIG_MB_SERIAL_BUF_SIZE=256 +CONFIG_MB_SERIAL_TASK_PRIO=10 +CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT=y +CONFIG_MB_CONTROLLER_SLAVE_ID=0x00112233 +CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20 +CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20 +CONFIG_MB_CONTROLLER_STACK_SIZE=4096 +CONFIG_MB_EVENT_QUEUE_TIMEOUT=20 +# CONFIG_MB_TIMER_PORT_ENABLED is not set +# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set +CONFIG_TIMER_TASK_PRIORITY=1 +CONFIG_TIMER_TASK_STACK_DEPTH=3120 +CONFIG_TIMER_QUEUE_LENGTH=10 +# CONFIG_L2_TO_L3_COPY is not set +# CONFIG_USE_ONLY_LWIP_SELECT is not set +CONFIG_ESP_GRATUITOUS_ARP=y +CONFIG_GARP_TMR_INTERVAL=60 +CONFIG_TCPIP_RECVMBOX_SIZE=32 +CONFIG_TCP_MAXRTX=12 +CONFIG_TCP_SYNMAXRTX=12 +CONFIG_TCP_MSS=1440 +CONFIG_TCP_MSL=60000 +CONFIG_TCP_SND_BUF_DEFAULT=5760 +CONFIG_TCP_WND_DEFAULT=5760 +CONFIG_TCP_RECVMBOX_SIZE=6 +CONFIG_TCP_QUEUE_OOSEQ=y +# CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set +CONFIG_TCP_OVERSIZE_MSS=y +# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_TCP_OVERSIZE_DISABLE is not set +CONFIG_UDP_RECVMBOX_SIZE=6 +CONFIG_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_PPP_SUPPORT is not set +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_ESP32_PTHREAD_STACK_MIN=768 +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set +# CONFIG_USB_ENABLED is not set +CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_SUPPORT_TERMIOS=y +CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# End of deprecated options From e8a9e253f7afe73c21bd27b91a95ebb97a93e129 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 21 Sep 2024 18:40:44 +0200 Subject: [PATCH 025/130] Fix matrix expansion --- .github/workflows/tagging.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tagging.yml b/.github/workflows/tagging.yml index 2964234..8f64608 100644 --- a/.github/workflows/tagging.yml +++ b/.github/workflows/tagging.yml @@ -44,9 +44,9 @@ jobs: version: esp32s3 epd_variant: [213epd, 29epd] exclude: - - chip: btclock_rev_b + - chip: {name: btclock_rev_b, version: esp32s3} epd_variant: 29epd - - chip: btclock_v8 + - chip: {name: btclock_v8, version: esp32s3} epd_variant: 29epd steps: - uses: actions/download-artifact@v4 From 85579e98cf89493e9f72b09644c2f9d1bff5096f Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 28 Sep 2024 00:03:18 +0200 Subject: [PATCH 026/130] Bugfixes for stack size and market cap with small chars, write tests for the small char mcap --- lib/btclock/data_handler.cpp | 4 +- lib/btclock/utils.cpp | 3 +- sdkconfig.defaults | 2 +- src/fonts/antonio-semibold40.h | 88 ++++++++++++++++++++++++++--- src/lib/epd.cpp | 12 +++- src/lib/webserver.cpp | 3 +- test/test_datahandler/test_main.cpp | 65 +++++++++++++++++++++ 7 files changed, 162 insertions(+), 15 deletions(-) diff --git a/lib/btclock/data_handler.cpp b/lib/btclock/data_handler.cpp index 0905e8a..7b63db6 100644 --- a/lib/btclock/data_handler.cpp +++ b/lib/btclock/data_handler.cpp @@ -220,7 +220,7 @@ std::array parseMarketCap(std::uint32_t blockHeight, s std::array ret; std::uint32_t firstIndex = 0; double supply = getSupplyAtBlock(blockHeight); - int64_t marketCap = static_cast(supply * double(price)); + uint64_t marketCap = static_cast(supply * double(price)); ret[0] = getCurrencyCode(currencySymbol) + "/MCAP"; @@ -256,7 +256,7 @@ std::array parseMarketCap(std::uint32_t blockHeight, s ret[i] = ""; } - ret[NUM_SCREENS - groups - 1] = " $ "; + ret[NUM_SCREENS - groups - 1] = std::string(" ") + currencySymbol + " "; for (std::uint32_t i = 0; i < groups; i++) { ret[(NUM_SCREENS - groups + i)] = stringValue.substr(i * 3, 3).c_str(); diff --git a/lib/btclock/utils.cpp b/lib/btclock/utils.cpp index c419603..53212e4 100644 --- a/lib/btclock/utils.cpp +++ b/lib/btclock/utils.cpp @@ -68,7 +68,8 @@ std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters) } else { - sprintf(result, "%llu", (unsigned long long)num); + snprintf(result, sizeof(result), "%llu", (unsigned long long)num); +// sprintf(result, "%llu", (unsigned long long)num); return result; } diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 59b2ec3..3294889 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -45,4 +45,4 @@ CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120 CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n CONFIG_SPIRAM_CACHE_WORKAROUND=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y -CONFIG_NEWLIB_NANO_FORMAT=y \ No newline at end of file +#CONFIG_NEWLIB_NANO_FORMAT=y \ No newline at end of file diff --git a/src/fonts/antonio-semibold40.h b/src/fonts/antonio-semibold40.h index 0f8ea5f..13725f9 100644 --- a/src/fonts/antonio-semibold40.h +++ b/src/fonts/antonio-semibold40.h @@ -1526,7 +1526,78 @@ const uint8_t Antonio_SemiBold40pt7bBitmaps[] PROGMEM = { 0x3F, 0xE0, 0x3F, 0xE0, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0x80, - 0x00}; + 0x00, + // euro + 0x00, 0x07, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0x00, + 0x07, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xFF, 0x00, + 0xFF, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xFE, 0x07, 0xFE, 0x07, 0xFC, 0x0F, + 0xF8, 0x0F, 0xF8, 0x1F, 0xF0, 0x0F, 0xF8, 0x3F, 0xE0, 0x1F, 0xF0, 0xFF, + 0x80, 0x3F, 0xE1, 0xFF, 0x00, 0x7F, 0xC3, 0xFE, 0x00, 0xFF, 0x87, 0xFC, + 0x00, 0xFF, 0x0F, 0xF8, 0x01, 0xFE, 0x1F, 0xF0, 0x03, 0xFC, 0x3F, 0xE0, + 0x07, 0xF8, 0x7F, 0xC0, 0x0F, 0xF0, 0xFF, 0x80, 0x1F, 0xE1, 0xFF, 0x00, + 0x3F, 0xC3, 0xFE, 0x00, 0x7F, 0x87, 0xFC, 0x00, 0xFF, 0x0F, 0xF8, 0x01, + 0xFE, 0x1F, 0xF0, 0x03, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xFF, 0x80, + 0x0F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFC, 0x00, + 0x07, 0xFC, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, + 0x3F, 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0x00, 0x1F, + 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x0F, + 0xF8, 0x00, 0x00, 0x1F, 0xF0, 0x03, 0xFC, 0x3F, 0xE0, 0x07, 0xF8, 0x7F, + 0xC0, 0x0F, 0xF0, 0xFF, 0x80, 0x1F, 0xE1, 0xFF, 0x00, 0x3F, 0xC3, 0xFE, + 0x00, 0x7F, 0x87, 0xFC, 0x00, 0xFF, 0x0F, 0xF8, 0x01, 0xFE, 0x1F, 0xF0, + 0x03, 0xFC, 0x3F, 0xE0, 0x07, 0xF8, 0x7F, 0xC0, 0x0F, 0xF0, 0xFF, 0x80, + 0x1F, 0xE1, 0xFF, 0x00, 0x7F, 0xC3, 0xFE, 0x00, 0xFF, 0x87, 0xFC, 0x01, + 0xFF, 0x0F, 0xF8, 0x03, 0xFE, 0x0F, 0xF8, 0x07, 0xFC, 0x1F, 0xF0, 0x0F, + 0xF0, 0x3F, 0xE0, 0x3F, 0xE0, 0x3F, 0xE0, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, + 0x80, 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xF0, + 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xF8, 0x00, + 0x00, 0x3F, 0x80, 0x00, + // pound + 0x00, 0x0F, 0xFC, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFC, 0x00, + 0x7F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xC0, 0x7F, + 0xFF, 0xFF, 0x83, 0xFF, 0x03, 0xFE, 0x0F, 0xF8, 0x07, 0xF8, 0x3F, 0xC0, + 0x1F, 0xE1, 0xFF, 0x00, 0x3F, 0xC7, 0xFC, 0x00, 0xFF, 0x1F, 0xE0, 0x03, + 0xFC, 0x7F, 0x80, 0x0F, 0xF1, 0xFE, 0x00, 0x3F, 0xC7, 0xF8, 0x00, 0xFF, + 0x1F, 0xF0, 0x03, 0xFC, 0x7F, 0xC0, 0x0F, 0xF1, 0xFF, 0x00, 0x3F, 0xC3, + 0xFC, 0x00, 0xFF, 0x0F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0xFF, + 0x80, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x1F, 0xF0, + 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x03, 0xFC, 0x00, + 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x3F, 0xFF, 0xFF, 0xF8, + 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xFE, 0x3F, + 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFE, 0x00, 0x00, 0x0F, + 0xF8, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x01, 0xFE, + 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x7F, 0xC0, + 0x00, 0x01, 0xFF, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x1F, 0xF0, 0x00, + 0x00, 0x7F, 0xC0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, + 0x1F, 0xF0, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x0F, + 0xF8, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x0F, 0xF8, + 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x1F, 0xF0, 0x00, + 0x01, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, + 0x7F, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xDF, + 0xFF, 0xFF, 0xFF, + // yen + 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x07, 0xFB, 0xFE, 0x00, 0x1F, 0xF3, + 0xFC, 0x00, 0x3F, 0xE7, 0xFC, 0x00, 0x7F, 0xCF, 0xF8, 0x00, 0xFF, 0x0F, + 0xF0, 0x03, 0xFE, 0x1F, 0xE0, 0x07, 0xFC, 0x3F, 0xE0, 0x0F, 0xF0, 0x7F, + 0xC0, 0x1F, 0xE0, 0x7F, 0x80, 0x7F, 0xC0, 0xFF, 0x80, 0xFF, 0x81, 0xFF, + 0x01, 0xFE, 0x01, 0xFE, 0x03, 0xFC, 0x03, 0xFC, 0x07, 0xF8, 0x07, 0xFC, + 0x1F, 0xF0, 0x0F, 0xF8, 0x3F, 0xC0, 0x0F, 0xF0, 0x7F, 0x80, 0x1F, 0xE0, + 0xFF, 0x00, 0x3F, 0xE3, 0xFC, 0x00, 0x3F, 0xC7, 0xF8, 0x00, 0x7F, 0x8F, + 0xF0, 0x00, 0xFF, 0x9F, 0xE0, 0x00, 0xFF, 0x7F, 0x80, 0x01, 0xFE, 0xFF, + 0x00, 0x03, 0xFD, 0xFE, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF0, + 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0x00, + 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x7F, 0xFC, 0x00, 0x00, 0xFF, 0xF8, 0x00, + 0x00, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0x80, 0x07, + 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0xF8, 0x3F, + 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xE0, 0x00, 0x7F, 0xC0, 0x00, 0x00, + 0xFF, 0x80, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x07, + 0xFC, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, + 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, + 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x0F, 0xF8, + 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x7F, 0xC0, + 0x00, 0x00, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x03, 0xFE, 0x00, + 0x00, 0x07, 0xFC, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x1F, 0xF0, 0x00, + 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x7F, 0xC0, 0x00 + }; const GFXglyph Antonio_SemiBold40pt7bGlyphs[] PROGMEM = { {0, 1, 1, 17, 0, 0}, // 0x20 ' ' @@ -1588,10 +1659,10 @@ const GFXglyph Antonio_SemiBold40pt7bGlyphs[] PROGMEM = { {10963, 28, 67, 32, 2, -66}, // 0x58 'X' {11198, 31, 67, 32, 1, -66}, // 0x59 'Y' {11458, 23, 67, 27, 3, -66}, // 0x5A 'Z' - {11651, 17, 70, 26, 6, -66}, // 0x5B '[' - {11800, 24, 67, 30, 3, -66}, // 0x5C '\' - {12001, 16, 70, 26, 4, -66}, // 0x5D ']' - {12141, 29, 35, 37, 4, -66}, // 0x5E '^' + {18021, 31, 69, 37, 2, -67}, // 0x5B '[' --> euro { 18290, 31, 69, 37, 2, -67 } was {11651, 17, 70, 26, 6, -66} + {11800, 24, 67, 30, 3, -66}, // 0x5C '\' + {18557, 30, 68, 36, 3, -67 }, // 0x5D ']' --> pound { 0, 30, 68, 36, 3, -67 } was {12001, 16, 70, 26, 4, -66} + {18812, 31, 67, 32, 1, -66 }, // 0x5E '^' --> yen { 0, 31, 67, 32, 1, -66 } was {12141, 29, 35, 37, 4, -66 {12268, 25, 7, 29, 2, 2}, // 0x5F '_' {12290, 12, 15, 16, 2, -77}, // 0x60 '`' {12313, 27, 59, 36, 4, -57}, // 0x61 'a' @@ -1623,10 +1694,13 @@ const GFXglyph Antonio_SemiBold40pt7bGlyphs[] PROGMEM = { {17509, 20, 75, 27, 4, -67}, // 0x7B '{' {17697, 9, 75, 21, 6, -70}, // 0x7C '|' {17782, 19, 75, 27, 4, -67}, // 0x7D '}' - {17961, 34, 14, 43, 4, -44}, {18021, 31, 69, 37, 2, -67}}; // 0x7E '~' + {17961, 34, 14, 43, 4, -44}}; // 0x7E '~' + + +//, {18021, 31, 69, 37, 2, -67} const GFXfont Antonio_SemiBold40pt7b PROGMEM = { (uint8_t *)Antonio_SemiBold40pt7bBitmaps, - (GFXglyph *)Antonio_SemiBold40pt7bGlyphs, 0x20, 0x7E, 101}; + (GFXglyph *)Antonio_SemiBold40pt7bGlyphs, 0x20, 0x7E, 100}; // Approx. 18961 bytes diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 7688fc8..a301f17 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -132,6 +132,12 @@ std::mutex epdMutex[NUM_SCREENS]; uint8_t qrcode[800]; +#ifdef IS_BTCLOCK_V8 +#define EPD_TASK_STACK_SIZE 4096 +#else +#define EPD_TASK_STACK_SIZE 2048 +#endif + void forceFullRefresh() { for (uint i = 0; i < NUM_SCREENS; i++) @@ -170,7 +176,7 @@ void setupDisplays() updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem)); - xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", 4096, NULL, 11, NULL); + xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", EPD_TASK_STACK_SIZE, NULL, 11, NULL); for (uint i = 0; i < NUM_SCREENS; i++) { @@ -180,7 +186,7 @@ void setupDisplays() int *taskParam = new int; *taskParam = i; - xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), 4096, taskParam, + xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), EPD_TASK_STACK_SIZE, taskParam, 11, &tasks[i]); // create task } @@ -190,7 +196,7 @@ void setupDisplays() setFgColor(GxEPD_BLACK); setBgColor(GxEPD_WHITE); - epdContent = {" ", " ", " ", " ", " ", " ", " "}; + epdContent.fill(""); } else { diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 738f4f5..d5dba86 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -300,7 +300,8 @@ JsonDocument getLedStatusObject() uint green = (pixColor >> 8) & 0xFF; uint blue = pixColor & 0xFF; char hexColor[8]; - sprintf(hexColor, "#%02X%02X%02X", red, green, blue); + snprintf(hexColor, sizeof(hexColor), "#%02X%02X%02X", red, green, blue); + JsonObject object = colors.add(); object["red"] = red; diff --git a/test/test_datahandler/test_main.cpp b/test/test_datahandler/test_main.cpp index 14f3a93..29d337f 100644 --- a/test/test_datahandler/test_main.cpp +++ b/test/test_datahandler/test_main.cpp @@ -1,6 +1,18 @@ #include #include +template +std::string joinArrayWithBrackets(const std::array& arr, const std::string& separator = " ") { + std::ostringstream result; + for (size_t i = 0; i < N; ++i) { + if (i > 0) { + result << separator; + } + result << '[' << arr[i] << ']'; + } + return result.str(); +} + void setUp(void) { // set stuff up here @@ -100,6 +112,24 @@ void test_Mcap1TrillionUsd(void) TEST_ASSERT_EQUAL_STRING("T", output[NUM_SCREENS - 1].c_str()); } +void test_Mcap1TrillionUsdSmallChars(void) +{ + std::array output = parseMarketCap(831000, 52000, '$', false); + TEST_ASSERT_EQUAL_STRING("USD/MCAP", output[0].c_str()); + + std::string joined = joinArrayWithBrackets(output); + + + + TEST_ASSERT_EQUAL_STRING_MESSAGE(" $ ", output[NUM_SCREENS - 6].c_str(), joined.c_str()); + + TEST_ASSERT_EQUAL_STRING_MESSAGE(" 1", output[NUM_SCREENS - 5].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("020", output[NUM_SCREENS - 4].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("825", output[NUM_SCREENS - 3].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("000", output[NUM_SCREENS - 2].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("000", output[NUM_SCREENS - 1].c_str(), joined.c_str()); +} + void test_Mcap1TrillionEur(void) { std::array output = parseMarketCap(831000, 52000, CURRENCY_EUR, true); @@ -112,6 +142,23 @@ void test_Mcap1TrillionEur(void) TEST_ASSERT_EQUAL_STRING("T", output[NUM_SCREENS - 1].c_str()); } +void test_Mcap1TrillionEurSmallChars(void) +{ + std::array output = parseMarketCap(831000, 52000, CURRENCY_EUR, false); + TEST_ASSERT_EQUAL_STRING("EUR/MCAP", output[0].c_str()); + + std::string joined = joinArrayWithBrackets(output); + + char result[4]; + snprintf(result, sizeof(result), " %c ", CURRENCY_EUR); + TEST_ASSERT_EQUAL_STRING(result, output[NUM_SCREENS - 6].c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE(" 1", output[NUM_SCREENS - 5].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("020", output[NUM_SCREENS - 4].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("825", output[NUM_SCREENS - 3].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("000", output[NUM_SCREENS - 2].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("000", output[NUM_SCREENS - 1].c_str(), joined.c_str()); +} + void test_Mcap1TrillionJpy(void) { std::array output = parseMarketCap(831000, 52000, CURRENCY_JPY, true); @@ -124,6 +171,21 @@ void test_Mcap1TrillionJpy(void) TEST_ASSERT_EQUAL_STRING("T", output[NUM_SCREENS - 1].c_str()); } +void test_Mcap1TrillionJpySmallChars(void) +{ + std::array output = parseMarketCap(831000, 52000, CURRENCY_JPY, false); + TEST_ASSERT_EQUAL_STRING("JPY/MCAP", output[0].c_str()); + + char result[4]; + snprintf(result, sizeof(result), " %c ", CURRENCY_JPY); + TEST_ASSERT_EQUAL_STRING(result, output[NUM_SCREENS - 6].c_str()); + TEST_ASSERT_EQUAL_STRING(" 1", output[NUM_SCREENS - 5].c_str()); + TEST_ASSERT_EQUAL_STRING("020", output[NUM_SCREENS - 4].c_str()); + TEST_ASSERT_EQUAL_STRING("825", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("000", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("000", output[NUM_SCREENS - 1].c_str()); +} + // not needed when using generate_test_runner.rb int runUnityTests(void) { @@ -136,8 +198,11 @@ int runUnityTests(void) RUN_TEST(test_PriceOf100kusd); RUN_TEST(test_McapLowerUsd); RUN_TEST(test_Mcap1TrillionUsd); + RUN_TEST(test_Mcap1TrillionUsdSmallChars); RUN_TEST(test_Mcap1TrillionEur); + RUN_TEST(test_Mcap1TrillionEurSmallChars); RUN_TEST(test_Mcap1TrillionJpy); + RUN_TEST(test_Mcap1TrillionJpySmallChars); return UNITY_END(); } From b0ec0685a1d26502193e67ef56224351c6f01272 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 3 Oct 2024 00:26:14 +0200 Subject: [PATCH 027/130] Bugfix for too short WiFi-setup passwords --- data | 2 +- platformio.ini | 6 +++--- src/lib/config.cpp | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/data b/data index 95aa9d6..9867988 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 95aa9d67d17dde32dab3216810e7b4e4086feb03 +Subproject commit 9867988a095a09a693aa2dc567605d15cfe4ceb1 diff --git a/platformio.ini b/platformio.ini index 30e03ec..59f20fb 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,7 +15,7 @@ default_envs = lolin_s3_mini_213epd, lolin_s3_mini_29epd, btclock_rev_b_213epd, [btclock_base] -platform = espressif32 @ ^6.8.1 +platform = espressif32 @ ^6.9.0 framework = arduino, espidf monitor_speed = 115200 monitor_filters = esp32_exception_decoder, colorize @@ -32,8 +32,8 @@ build_unflags = -fno-exceptions lib_deps = https://github.com/joltwallet/esp_littlefs.git - bblanchon/ArduinoJson@^7.1.0 - mathieucarbou/ESPAsyncWebServer @ 3.3.1 + bblanchon/ArduinoJson@^7.2.0 + mathieucarbou/ESPAsyncWebServer @ 3.3.7 adafruit/Adafruit BusIO@^1.16.1 adafruit/Adafruit MCP23017 Arduino Library@^2.3.2 adafruit/Adafruit NeoPixel@^1.12.3 diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 17805c0..d20a9d3 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -145,7 +145,7 @@ void setupWifi() WiFi.setHostname(softAP_SSID.c_str()); String softAP_password = replaceAmbiguousChars( base64::encode(String(mac[2], 16) + String(mac[4], 16) + - String(mac[5], 16) + String(mac[1], 16)) + String(mac[5], 16) + String(mac[1], 16) + String(mac[3], 16)) .substring(2, 10)); wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", DEFAULT_WP_TIMEOUT)); @@ -155,10 +155,10 @@ void setupWifi() wm.setAPCallback([&](WiFiManager *wifiManager) { - // Serial.printf("Entered config mode:ip=%s, ssid='%s', pass='%s'\n", - // WiFi.softAPIP().toString().c_str(), - // wifiManager->getConfigPortalSSID().c_str(), - // softAP_password.c_str()); + Serial.printf("Entered config mode:ip=%s, ssid='%s', pass='%s'\n", + WiFi.softAPIP().toString().c_str(), + wifiManager->getConfigPortalSSID().c_str(), + softAP_password.c_str()); // delay(6000); setFgColor(GxEPD_BLACK); setBgColor(GxEPD_WHITE); From a614bd15dbe8f95a9fbb00b3cf99c8d6ecb5a47b Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 23 Oct 2024 00:43:53 +0200 Subject: [PATCH 028/130] Restore Nostr Zap subscription after loss of connection --- data | 2 +- src/lib/nostr_notify.cpp | 76 +++++++++++++++++++++++++++------------- src/lib/nostr_notify.hpp | 5 ++- 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/data b/data index 9867988..384b431 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 9867988a095a09a693aa2dc567605d15cfe4ceb1 +Subproject commit 384b4317c4b58afd981f410a9b732700e733b00b diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index 2e044bb..237eabe 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -4,16 +4,20 @@ std::vector pools; nostr::Transport *transport; TaskHandle_t nostrTaskHandle = NULL; boolean nostrIsConnected = false; +boolean nostrIsSubscribed = false; +boolean nostrIsSubscribing = true; + +String subIdZap; void setupNostrNotify(bool asDatasource, bool zapNotify) { nostr::esp32::ESP32Platform::initNostr(false); - time_t now; - time(&now); - struct tm *utcTimeInfo; - utcTimeInfo = gmtime(&now); - time_t utcNow = mktime(utcTimeInfo); - time_t timestamp60MinutesAgo = utcNow - 3600; + // time_t now; + // time(&now); + // struct tm *utcTimeInfo; + // utcTimeInfo = gmtime(&now); + // time_t utcNow = mktime(utcTimeInfo); + // time_t timestamp60MinutesAgo = utcNow - 3600; try { @@ -27,20 +31,7 @@ void setupNostrNotify(bool asDatasource, bool zapNotify) if (zapNotify) { - String subIdZap = pool->subscribeMany( - {relay}, - { - { - {"kinds", {"9735"}}, - {"limit", {"1"}}, - {"since", {String(timestamp60MinutesAgo)}}, - {"#p", {preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY)}}, - }, - }, - handleNostrZapCallback, - onNostrSubscriptionClosed, - onNostrSubscriptionEose); - Serial.println("[ Nostr ] Subscribing to Zap Notifications"); + subscribeZaps(pool, relay, 60); } if (asDatasource) @@ -50,7 +41,7 @@ void setupNostrNotify(bool asDatasource, bool zapNotify) {// First filter { {"kinds", {"1"}}, - {"since", {String(timestamp60MinutesAgo)}}, + {"since", {String(getMinutesAgo(60))}}, {"authors", {pubKey}}, }}, handleNostrEventCallback, @@ -72,11 +63,12 @@ void setupNostrNotify(bool asDatasource, bool zapNotify) sstatus="CONNECTED"; }else if(status==nostr::ConnectionStatus::DISCONNECTED){ nostrIsConnected = false; + nostrIsSubscribed = false; sstatus="DISCONNECTED"; }else if(status==nostr::ConnectionStatus::ERROR){ sstatus = "ERROR"; } - //Serial.println("[ Nostr ] Connection status changed: " + sstatus); + Serial.println("[ Nostr ] Connection status changed: " + sstatus); }); } } @@ -88,8 +80,10 @@ void setupNostrNotify(bool asDatasource, bool zapNotify) void nostrTask(void *pvParameters) { - int blockFetch = getBlockFetch(); - processNewBlock(blockFetch); + if(preferences.getBool("useNostr", DEFAULT_USE_NOSTR)) { + int blockFetch = getBlockFetch(); + processNewBlock(blockFetch); + } while (1) { @@ -98,6 +92,10 @@ void nostrTask(void *pvParameters) // Run internal loop: refresh relays, complete pending connections, send // pending messages pool->loop(); + if (!nostrIsSubscribed && !nostrIsSubscribing) { + Serial.println(F("Not subscribed")); + subscribeZaps(pool, preferences.getString("nostrRelay"), 1); + } } vTaskDelay(pdMS_TO_TICKS(100)); } @@ -125,6 +123,8 @@ void onNostrSubscriptionEose(const String &subId) // This is the callback that will be called when the subscription is // EOSE Serial.println("[ Nostr ] Subscription EOSE: " + subId); + nostrIsSubscribing = false; + nostrIsSubscribed = true; } void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *event) @@ -183,6 +183,34 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even } } +time_t getMinutesAgo(int min) { + time_t now; + time(&now); + return now - (min * 60); +} + +void subscribeZaps(nostr::NostrPool *pool, const String &relay, int minutesAgo) { + if (subIdZap) { + pool->closeSubscription(subIdZap); + } + nostrIsSubscribing = true; + + subIdZap = pool->subscribeMany( + {relay}, + { + { + {"kinds", {"9735"}}, + {"limit", {"1"}}, + {"since", {String(getMinutesAgo(minutesAgo))}}, + {"#p", {preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY)}}, + }, + }, + handleNostrZapCallback, + onNostrSubscriptionClosed, + onNostrSubscriptionEose); + Serial.println("[ Nostr ] Subscribing to Zap Notifications since " + String(getMinutesAgo(minutesAgo))); +} + void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event) { // Received events callback, we can access the event content with // event->getContent() Here you should handle the event, for this diff --git a/src/lib/nostr_notify.hpp b/src/lib/nostr_notify.hpp index 045574d..ebbe2cb 100644 --- a/src/lib/nostr_notify.hpp +++ b/src/lib/nostr_notify.hpp @@ -24,4 +24,7 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event); void onNostrSubscriptionClosed(const String &subId, const String &reason); -void onNostrSubscriptionEose(const String &subId); \ No newline at end of file +void onNostrSubscriptionEose(const String &subId); + +time_t getMinutesAgo(int min); +void subscribeZaps(nostr::NostrPool *pool, const String &relay, int minutesAgo); \ No newline at end of file From 82dd70a38ddf9a8337d4f9c33b079fe2754989eb Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 25 Nov 2024 23:54:02 +0100 Subject: [PATCH 029/130] Use CA bundle instead of single certificates, make auto update URL configurable --- .gitignore | 3 +- .gitmodules | 2 +- ci/Dockerfile | 15 ++++++ partition.csv | 4 +- platformio.ini | 1 + src/lib/block_notify.cpp | 2 +- src/lib/config.cpp | 4 ++ src/lib/defaults.hpp | 4 +- src/lib/ota.cpp | 13 +++-- src/lib/price_notify.cpp | 47 +++------------- src/lib/shared.cpp | 113 +++++++++++++++++++++++++-------------- src/lib/shared.hpp | 7 ++- src/lib/webserver.cpp | 3 +- x509_crt_bundle | Bin 0 -> 63694 bytes 14 files changed, 126 insertions(+), 92 deletions(-) create mode 100644 ci/Dockerfile create mode 100644 x509_crt_bundle diff --git a/.gitignore b/.gitignore index e5f0444..b6395ed 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ data/.yarn data/node_modules node_modules .DS_Store -*.bin \ No newline at end of file +*.bin +ci/cache \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index f921d34..d8b183a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "data"] path = data - url = https://github.com/btclock/webui.git + url = https://git.btclock.dev/btclock/webui.git diff --git a/ci/Dockerfile b/ci/Dockerfile new file mode 100644 index 0000000..795d695 --- /dev/null +++ b/ci/Dockerfile @@ -0,0 +1,15 @@ +# Use the official Python 3.9 image as the base +FROM python:3.9-slim + +# Set the working directory +WORKDIR /workspace + +RUN apt-get update && apt-get install -y git + +# Install PlatformIO +RUN pip install platformio + +WORKDIR /usr/src + +CMD ["platformio", "run"] + diff --git a/partition.csv b/partition.csv index 4ca1357..318b4f0 100644 --- a/partition.csv +++ b/partition.csv @@ -1,7 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 36K, 20K, otadata, data, ota, 56K, 8K, -app0, app, ota_0, 64K, 1700K, -app1, app, ota_1, , 1700K, +app0, app, ota_0, 64K, 1740K, +app1, app, ota_1, , 1740K, spiffs, data, spiffs, , 400K, coredump, data, coredump,, 64K, diff --git a/platformio.ini b/platformio.ini index 59f20fb..25e7d9c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -21,6 +21,7 @@ monitor_speed = 115200 monitor_filters = esp32_exception_decoder, colorize board_build.filesystem = littlefs extra_scripts = post:scripts/extra_script.py +board_build.embed_files = x509_crt_bundle build_flags = !python scripts/git_rev.py -DLAST_BUILD_TIME=$UNIX_TIME diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index bf5d337..b86d497 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -302,7 +302,7 @@ int getBlockFetch() WiFiClientSecure client; if (preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE)) { - client.setCACert(mempoolWsCert); + client.setCACertBundle(rootca_crt_bundle_start); } String mempoolInstance = diff --git a/src/lib/config.cpp b/src/lib/config.cpp index d20a9d3..8f954b2 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -284,6 +284,10 @@ void setupPreferences() preferences.putBool("flDisable", isWhiteVersion() ? false : true); } + if (!preferences.isKey("gitReleaseUrl")) { + preferences.putString("gitReleaseUrl", DEFAULT_GIT_RELEASE_URL); + } + if (!preferences.isKey("fgColor")) { preferences.putUInt("fgColor", isWhiteVersion() ? GxEPD_BLACK : GxEPD_WHITE); preferences.putUInt("bgColor", isWhiteVersion() ? GxEPD_WHITE : GxEPD_BLACK); diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index 39e7406..dd222a5 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -60,4 +60,6 @@ #define DEFAULT_HTTP_AUTH_USERNAME "btclock" #define DEFAULT_HTTP_AUTH_PASSWORD "satoshi" -#define DEFAULT_ACTIVE_CURRENCIES "USD,EUR,JPY" \ No newline at end of file +#define DEFAULT_ACTIVE_CURRENCIES "USD,EUR,JPY" + +#define DEFAULT_GIT_RELEASE_URL "https://git.btclock.dev/api/v1/repos/btclock/btclock_v3/releases/latest" diff --git a/src/lib/ota.cpp b/src/lib/ota.cpp index d4b11a6..1800f76 100644 --- a/src/lib/ota.cpp +++ b/src/lib/ota.cpp @@ -106,9 +106,12 @@ void handleOTATask(void *parameter) ReleaseInfo getLatestRelease(const String &fileToDownload) { - String releaseUrl = "https://api.github.com/repos/btclock/btclock_v3/releases/latest"; + String releaseUrl = preferences.getString("gitReleaseUrl"); WiFiClientSecure client; - client.setCACert(github_root_ca); +// client.setCACert(isrg_root_x1cert); + client.setCACertBundle(rootca_crt_bundle_start); + + HTTPClient http; http.begin(client, releaseUrl); http.setUserAgent(USER_AGENT); @@ -153,7 +156,7 @@ ReleaseInfo getLatestRelease(const String &fileToDownload) int downloadUpdateHandler(char updateType) { WiFiClientSecure client; - client.setCACert(github_root_ca); + client.setCACertBundle(rootca_crt_bundle_start); HTTPClient http; http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); @@ -303,7 +306,7 @@ int downloadUpdateHandler(char updateType) void updateWebUi(String latestRelease, int command) { WiFiClientSecure client; - client.setCACert(github_root_ca); + client.setCACertBundle(rootca_crt_bundle_start); HTTPClient http; http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); http.begin(client, latestRelease); @@ -421,7 +424,7 @@ String downloadSHA256(const String &sha256Url) } WiFiClientSecure client; - client.setCACert(github_root_ca); + client.setCACertBundle(rootca_crt_bundle_start); HTTPClient http; http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); http.begin(client, sha256Url); diff --git a/src/lib/price_notify.cpp b/src/lib/price_notify.cpp index d6a1e71..f995de8 100644 --- a/src/lib/price_notify.cpp +++ b/src/lib/price_notify.cpp @@ -5,40 +5,6 @@ const char *wsOwnServerV2 = "wss://ws-staging.btclock.dev/api/v2/ws"; const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin"; -const char* coincapWsCert = R"EOF( ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- -)EOF"; - // WebsocketsClient client; esp_websocket_client_handle_t clientPrice = NULL; esp_websocket_client_config_t config; @@ -60,7 +26,8 @@ void setupPriceNotify() { config = {.uri = wsServerPrice, .user_agent = USER_AGENT}; - config.cert_pem = coincapWsCert; + config.cert_pem = isrg_root_x1cert; + config.task_stack = (6*1024); } @@ -159,11 +126,11 @@ void processNewPrice(uint newPrice, char currency) { // const unsigned long oldPrice = currentPrice; currencyMap[currency] = newPrice; - // if (lastUpdateMap[currency] == 0 || - // (currentTime - lastUpdateMap[currency]) > 120) - // { - // preferences.putUInt("lastPrice", currentPrice); - // } + if (currency == CURRENCY_USD && ( lastUpdateMap[currency] == 0 || + (currentTime - lastUpdateMap[currency]) > 120)) + { + preferences.putUInt("lastPrice", currentPrice); + } lastUpdateMap[currency] = currentTime; // if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) { if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER || diff --git a/src/lib/shared.cpp b/src/lib/shared.cpp index 597d803..20bf6d4 100644 --- a/src/lib/shared.cpp +++ b/src/lib/shared.cpp @@ -1,44 +1,79 @@ #include "shared.hpp" -const char *github_root_ca = - "-----BEGIN CERTIFICATE-----\n" - "MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL\n" - "MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl\n" - "eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT\n" - "JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx\n" - "MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT\n" - "Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg\n" - "VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm\n" - "aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo\n" - "I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng\n" - "o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G\n" - "A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD\n" - "VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB\n" - "zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW\n" - "RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=\n" - "-----END CERTIFICATE-----\n" - "-----BEGIN CERTIFICATE-----\n" - "MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh\n" - "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" - "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\n" - "MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT\n" - "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" - "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG\n" - "9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI\n" - "2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx\n" - "1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ\n" - "q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz\n" - "tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ\n" - "vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP\n" - "BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV\n" - "5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY\n" - "1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4\n" - "NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG\n" - "Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91\n" - "8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe\n" - "pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\n" - "MrY=\n" - "-----END CERTIFICATE-----\n"; +// const char *github_root_ca = +// "-----BEGIN CERTIFICATE-----\n" +// "MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL\n" +// "MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl\n" +// "eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT\n" +// "JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx\n" +// "MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT\n" +// "Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg\n" +// "VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm\n" +// "aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo\n" +// "I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng\n" +// "o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G\n" +// "A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD\n" +// "VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB\n" +// "zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW\n" +// "RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=\n" +// "-----END CERTIFICATE-----\n" +// "-----BEGIN CERTIFICATE-----\n" +// "MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh\n" +// "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" +// "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\n" +// "MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT\n" +// "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" +// "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG\n" +// "9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI\n" +// "2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx\n" +// "1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ\n" +// "q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz\n" +// "tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ\n" +// "vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP\n" +// "BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV\n" +// "5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY\n" +// "1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4\n" +// "NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG\n" +// "Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91\n" +// "8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe\n" +// "pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\n" +// "MrY=\n" +// "-----END CERTIFICATE-----\n"; + +const char* isrg_root_x1cert = R"EOF( +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- +)EOF"; + #ifdef TEST_SCREENS uint8_t input_buffer[3 * input_buffer_pixels]; // up to depth 24 diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index a381c7f..19d1df0 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -9,6 +9,7 @@ #include #include #include +#include "esp_crt_bundle.h" #include #include @@ -68,7 +69,11 @@ const PROGMEM int screens[SCREEN_COUNT] = { const int usPerSecond = 1000000; const int usPerMinute = 60 * usPerSecond; -extern const char *github_root_ca; +// extern const char *github_root_ca; +extern const char *isrg_root_x1cert; + +extern const uint8_t rootca_crt_bundle_start[] asm("_binary_x509_crt_bundle_start"); + const PROGMEM char UPDATE_FIRMWARE = U_FLASH; const PROGMEM char UPDATE_WEBUI = U_SPIFFS; diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index d5dba86..7a6d28d 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -510,7 +510,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) settings["timePerScreen"].as() * 60); } - String strSettings[] = {"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "nostrZapPubkey", "httpAuthUser", "httpAuthPass"}; + String strSettings[] = {"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl"}; for (String setting : strSettings) { @@ -701,6 +701,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["nostrZapNotify"] = preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED); root["nostrZapPubkey"] = preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY); + root["gitReleaseUrl"] = preferences.getString("gitReleaseUrl", DEFAULT_GIT_RELEASE_URL); root["bitaxeEnabled"] = preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED); root["bitaxeHostname"] = preferences.getString("bitaxeHostname", DEFAULT_BITAXE_HOSTNAME); diff --git a/x509_crt_bundle b/x509_crt_bundle new file mode 100644 index 0000000000000000000000000000000000000000..77d8ea3e85b3c2b257ffe256f6231d116a0cc7b8 GIT binary patch literal 63694 zcmb@uWmsM5vMr3e2KR-#ThQR{?!jGxTX1&??oM!bcMtBa!6mo^F5T($&N=t=m;If) zfABo4n(N1UYmTZKHLB(W3ISpRCSzb>gk^w+096KqKmid^V0^=X^v4GnIA|eLGb>jc z2Qzy{WCp}PY@l#Zf<|@@W+v8p48Fib4Db-pRDoiFxA4Hgz~DfjzQBk;uXY#^UtnOM zLDP$&xw#q^M>1dhUs)tSK#}Hh2jO6S^MOQs8;v!M{2W;OZBhpxKVi(<@(UN^r}}SM z6GicFJn~aUEe8EnLYa%c5}_%gpO0c3tG++Tfk}d1+kT&Bvm&+~0E?zk(41K+whdi< zd&RV-!_toHqAj5L1%W6^I(puN39|;4#=Il)9V&7N0KplxjwcQ(=#~_JwpthH*oKON z)S8MH(*T3?9j_1o{f2Civ>aTb_NxKSWjMN`r`97fHdL30ekM`lMR$bR$^)kw#5xEl zFc2^h2M8GhJ0mK?n;$NPRWh|SjMn!v!VX1mH`=L~a0ABkW0Lcp{3*MS zNLE+u4ZC|ET@SPvxEj2w@tq~CW1T?34$eLjowh7iXyphtV{t3rx>#VYR* zHmPFAfuMR`yD#&(iApqSmyC=sgj9X2Y{tUIgCce&yESc$pEr)(pu@&IQw!0C z3H;sJUk*t4I$V37xYhHSb@N2dy@(+KYZ^Mz)I__3I}uZ{g;Kw7SjVnwAYo>iHmjDv z4D|SLOYQ=W`@Hm0k@g(-`oxlh!`>TxP@$4|Y=d`Ym0L8cg*9|5$uz8ex5Msq>LLH+ z&B;>|W)Ydw3WX#R0C(C8-I?~p#`{*hMG?G3+jL-N&=LJzh(_2ghUkpc#Z-tZuQX56 zXT3E}{HZ$~(2cGk-0FId38us@F2C2-b=d@%NiXTJ5nYyiyc?f|xhO$k!E^m#4?knTPr zY+!+_uB-#`G+dRr7_7VY1hrb~XG@1jM(%DCUYRwuRP04&1!;K`ORqok&P?zl{M?h8BXDrK8oK0KbM%WSa0rC?&HL(T^BRx>kl>CQQBSJH z*#}b>R_PxQ<9vnK+h0OhSn(IUiE9YU$O!`!>G81ETJbgC6*wxSXZV}4?X7dWbKIp}9*xjKMrX-060mt#mKl4Xf}@+nn>awWjSk*V{hUT_QHx5gXF|O3ESF%#1Kq zs!h3}Nj=A0EPe6(W}c4S+<-p4W_i&pK=h~VXvs^Nj{(9;DU;x2{FQamc+Bm+po63z zyFM&)T|v_-k&BhmZ}yh*4vxf1DRQtAA5R0{Z$Jx4OB;4>!fON(wU*)JK9kjj93g9f5Hm|>4)L(O!k_{ep4%|UA%3FU1qm!D@48J z96YQS=7XKCl1*>b2zBor{DJ99L1+V~vjp8_s`Dn;nt|IRmc<4kG1#Q8PJ@XDc#qhx z>#**`O)J;to1EU_>1E_S`?BTlN~r7zZ{B~eMSpNuN=s$spns?Y$U#`TO?X!q+*cfn zVnxZlg={NU(Ctl)+;7znuIU$p336GyOJ_%Mvna z(IDxo4)v5?FM$lzEPI&A>{2XR%Y0iZpa%M$y8chOFZ znzGwc`w(o>qba34aM9GUGZ0w1rR+kk0Y1KE8tfbJqv-`w3QmWD=?!3$ayQBwvr`4) z0SD{{!=B|@@zP=`@5%uhR>AR$ER71-g3*;7mf%hGE)9nhJDl8a6!l*uzPY!vf)~AE z*}gP%(5K-664#)3W)f-%S~VgEvE^ElxFuK`yCqbPmPI@+_ub62SQMUaIe#B?!cD^w zxb$xA*iQM#HMeYe^EDQYiXfrFq9;cCY3hjO`xVutUYbsP0{+OQyPy%bHpR#JCHxG9##AWG9bHnsX-%MNmW`Bxq{$Z$Z zq1cMR-iM1T$%5k}bAF#pV5B#OslKqPhmaax4g0PM)RFNT5Eqck|NfV;FgU%^*1vxl zIJFNL5D}<85ZF{nD7$Q~BK&h#sJrB6cM(a0O8pyJoMk9m!YQDAgSHg%$8!#A?L(gY zA)n%0O+b>cHv01SeI%>xw2key_x}2q9}JnZMo8#CGzVu>WjWsYl8Kh;OC{^#%;5$x0_U; zwbvkuRcF5kE>L0=4IFU`QVL%Yc0*9`U8;)t9Y_b#ejo!CR95~Nh2k2#Xh8YAttZ46SE5AgJ?b1eNIg# zUDCNE>fyNFp`x4aC+M{-?!z?)2A80p>g)QP+#wj3|BI>}~+D9?p>V2cwefK?E z0iF0uV?uX0WKC+Y+S3sZ?i%fft;AS{?2zqN<a?F(SBDdsTX)9> z(kGA4bPyz>A;=8Mnig4UA)B3yXi8P1Jgy+)=6ygCv~wZFXWb@L?{U5=iZ~Wmx(bY# z+Cm-ZwsDw!xvJ<<;TtGZ$bsIm2^0+_IHDle_5)Oa4OyzBgo#}Lh+Cf53j8a~6lDK~ z848raYg48uE-Ldk%utYing9y2vP!T0#BXbG19Ow-AgM%T-Eu7jPO)nA{v^?~Ve|B- z{h880Jw9_?RZ}H@=~i z18d<$y-)6~Dq9XFJc@?$^}b}t72J#VEmx)xKhc~oLVAnv93`chDssqwT?ysTGZD;O z|8d@7eZ_xL5W$fno0N~@&}9UHhK?gWJj@y$m!8ZQX=~dk4hF1K=T=+u4ryzm*-i3s zjU5OGTa#jYD$SmkDJUs>NS=Ovt(3V&_J^B!U){{jh|hrggDIo&JJ{F*lmBbg@k|W=lB4wL>nqDIA1ZEM9EU zrq-18Z_lH=qWf+M-6WB$S4D77zTd67?DWao4lRzphK?%nM$3(R&%{6O*ZIz%_SF|D zld3LP$=y`y8mhaQje|DWz_$$i)?=nW!2BY;xfngdoq(BO5@%%8S> zyXyMV4WTV_)srB}2XGRo^&D(11ut${Ly$Hyj+L|7iE@I#z-dH1YH^$NDUB(H8#X^( z=f#00H+=}G+Y>vCkb7EO8?}K%ScSDq_hvwcjDJUg@V(DbR&mZDrIv&)5+r8asV@~@ z*&)q^us-@Rr{o?jd%DDyX*;h>bQ&Hi*bBMt-BkNfaO z`L!b!wY1UKvjm7T{mCqUn>YLRsBJ!;k%5!v`j9Nyi~!#!rxY=D69wt<$8e4GnBqY6 zNfl9dnP3p%QJ>sXhJ4C#X^XYU%7xGI9R5^OFd5D|>v)fGGcMe>>vrt?DJzP&9042D zt9@qTgwDN0gjn;1W>3j2u9FJwd?=#Qjf-S+-gJwR8-iJ+UJ1D%pPopGN(~+uec9-A|QtHl?2LlkI2A*kdr&=Zlwf-jxLq%~rIHqgeEH?oKuL(;1< zdArh9cLny^u;+_ltCelj)Ec>F=>9@~`KG$ZI0Y?hW4sFXMYWn_!yER&k2NQf-kT8* zOvLpz4Px<7RYEcW;hZ2!0Q&U~Raq|1Xu|m}GFBzP@xVLL<1>v8Nw=;tE(|#>{RKox zi52Px>sI^NvEu=`eg1^`B2TM@1H7ovx+b;QW{Fs8IF;|-M^NWFl-4-7a1~LXLdurg zax(~rL$Hq5>w2({(4Sq{q~@$AcrkFJF)YZMAKmCXkZ~~)Xzf9xvUXXsG`6H1@oYCa z-YUBAjrx6>hsj9Sj0)Y^-4NRms}>!Tp>m{h|3-8()D9h!pz0PJTzdMU^nQhM8xEK2 zjf~J-p-d&&;N>EAVvOnGS%e70l!~xg3O5|0Un4ka563uH9!p4r>l=E}zOO}zW={pq zCUxuX7j8yqJ9;Wce*x{4Rs0IH*Usgqz=Z<+hnS^jW^L)ph|Pfcqj^F8+xDY>5oY`+ zX0c{-=Y_j|axWSbSe4fqdgq(yeHb+;p+n^nY+4Acj~YYbrj?P4;Sm~0$bu<{gS0lm zE=e|krR#mb(x!{W#y3Y91kD}ecGHSNys9n(rZYYWf{Urx#kjBpI1q~1aRU19G4lWS zrz`wkL7HHjAvjzu*_o{0dnD>yMS(YWCqltZ4Us*e!=OZhUhFkJEN1>y+14q48?fs`LU;rQ2t)0Cg$s6gEgKRN zB>0DkE5_(h`My9h*J|WooxXDzr7`h>4v@4dp~91GmopI^E89ue54a-lMLx9z*F425m&+U@T7cC_c^19?sONDX%XK*kWh(j9jRM& z#R!R6(+hEk{k+W-&@K~@C#gO{-RBZ%t26<^o*cd_ez>7zmxl~N4;$X4*t&@2_JBF~z|w?MgEuHeK)%fOc!Iw7D^+Yk(#7sREQ zFqVrRb!l9TQ8l2u(Ip5DcbclHYXhMbq)C3yhn$hd+|{tlstWE!{sjXNj{9`+xWq^) zesT@#UntvkBhyWh_HepU0r|*`>_#XHONdm@$5}$e36>U?>K|yAGF6!0Tk9B8L{0o7 zMg(7zG5;^g_?27yR4h?o1%(xq{@@k>MSezH2JAng1QrG5ztfA?to+-A+}Y=d72_e~ z;1KkTz?HDF0E|9*Y7p}k*5(Trj2ZUF?(GWS$iR7>DAl8BLiO()>;eq!a)ohPe=#?3h)W_Hpl6 zYKVLt8+bVDJ(g@U&nx{tN+Ew1TT59|!kQwr(+ky4HhO24xs!HIIjwcyk4~CF+ym(1 zL45a?ukzVf=xwnEcBqAc+S^*R>3U={cYLMOaBQMdyTo_I>ZwCS{#}r=qh4F8!*4#c z6c}BaIU2OZKjI{g?R>7dnUwjw7-~y0#>Uf{(0gH7RK7b7Z%qMTiBLBz@9u)y1EBYM zL{;8IPX0a%lbr#wt^fXrRg$LBZl9M&wv?uYE^sT?DQfo<)p&l%pjLz=#LF9zQkM}_ zNY;&_^{|5qG+Fcz&9<9}e)aO;0EDiPBLb5?;m8*&b~b7kW4{=AYMvK)XD9vaV-sFp zAHNNiA~^yAx8xFo4u1^i3wW;e+cdoz)}&C*>SJzf_II99vEz$xPz{%mK+yPKWP6Wr zbB7+1Z$%C^F&C>EnP^8);p7(ljQmcUw8lrkHKZP}5-sMmQKq}KlvHfw-aqrNu3l$`Zr_w{a=WCoE}VP0WieB& zL;y6)X>GoKT4eiRZaN+*pBtcQ0+xkDVxvvr+m)!gAV!H&zu6umy&eFkh?#;TCD3K&> zOhnjTNQLph!3*^Pcj?kpP0yxjTF9LnkjmPXa=hhZv*D_K*gC8;(~scpmSnmHiFouAI= zVxz$$Xz88Z&jdSITT&M8?F(tXO{kty$dJ8{iZ+F&Z@gQ9IG{`6l`otm>V+wMD`r`9 z|Kd>+sJh)e7vSRDEO;p9b+gb;Y=z%3$!4jhb#a=9rG$MAI_0#t8Q#WSGc6{$HF)P0 z``Jk(O~8mZ55Ef%R6~TeG4Zltwpy9+ta(KWDDe?Bo}9U3Ur;s{^IX6V2?85HTXYtO zeW!M%EgjE?#h>q1ZmL~F>rH-uP3SeV3H&Vhpm5Oqf`Tf4bl;4ONDK&nrZPB4IZ5$9 z%)gTQKR*6zCMK--+tij?RMMd*kyt^WXq@8kequ4<`}o$5@fiVuD08<^?t01^L7mbn z+D9{1WSf>jxJYwM{Dr7R^j0J>Hm!4mnrICz688Drxe;jFrVC&@|4NT#Y45S8X`7+D zrFsP4DdB+6IHsR@_OFC2+p@byK-dq9|g}H^zATp$rROKh-phS%p z07M1~rFgH6(=RZ_>63i4)eo2_>ahNyJlBu(aBd(m=u=^TXee`{ zE;|x$BCj$QG_kVzz;2u8nL`NU@Tk5Qi72 zDDRHW1f$E-V@cDt^xz)G8orDD@te0TX*-i%GrMZ3A0K8e5mFsvcA6FFuskQP$272> znjvl;6+TNQgRS1(*M`aE%IJrj2a!DZ33LTL%+gX)Y1q0Mn$MH#8o)1q5x=Z0(djv*02czNkX}3udgAcK)zUg{Rc4ecclneQTuD^t! zbuyrn(iW!kFRm&4iZ;Ptfb-ha{FTIDP*DDCX#`Eptn~nbHgq&n4u*7$=nSYoSSP&G zA35)*V*XpWwJCqpn{LDd(+AHgw`}-O%YP^ds)O_{S_3zXtI{~kQmg=%sCkwz_LRAr zSbZq6Rc$FOV*=|Ny?TGRfkty?E^K8@idHjn}46&gKm>~|lOQ_Fx9yvD(rp4lGKI?>DZpA)16J(W@0v1_KRx+|QF<1MHvy{1N^D4U9qPO*P5mhU!rJo9;*G1(Pyo)-?v~$3fGKC z^0W^-ofxK_7FUltYJvL>uKfu<7<$wp>TlC1AW-3(g2Y zP0ZD)N%cQ1Dq~5ifI60L0^C`eu=5NJv!i!y|DokOi{k( z1xIb`s8O$7h-CK9jaDeG0g2bWhm$hBKb^&Zzq3`XBi*4qHPWt_JmtoK)e!8<4?HBv z*aC-KVG(!}GsodjF2(P={H;K2vL^MCx%jf6vrp#wD&5Io52T++vMc_boFR?UZv8no z<+$pP2+j2Jh`XxONwAI%t``O2cK#IIH5~vy7{fNOFsI$hw)U&!`U{=4z?Va3k zIGYfO!4%s8T)>T>)2vjsuARvi1#|ugVt&<8PII+fG@)UQoJ9?L) z=k`KWs0X({u5G`B?6O)@>|4ST%NLP?ABo+qRt-N`Ldl;sU|I?dlWp4fhd}u3hL%=t zQT8{H)K~~1U*!vSO9}3NU<iCDwGQ1>I7iNJ#m?HbSM+f+ZR}rOG0|A%3VF`2MC3FzH`Jxy%hrMA> zEKh_c?(nmdzGxVdBBYqAHdWio;}*P z#JsveH`hghVrnm~=PzWkxyC-M6++EQ__z#AM(KOppLFD8+_pJqtVgjQ@2A+yNvKLx zL5V2f#T~sGD3%;MBDYr%Tp9l({+2OvaJI3tFtaxKt-oviN0~9`EaEIJ^c1p=a>rfc zq;})HlSh;dg^Z$147VV*wb;dP=u`du@oB&5rZdQl`Uh;$jN@lKvz0JAvkEP+CSdch z?Yki?%!+24n}sbtwQ!cZYRq2E*|wxa6I-M-1Um%5;lFRnpnWJ&q+V%p;{7BA1r?5; zLyS9PUPjcM3`}QbG}2CDtV|-wCsc(qzu6toxrX$P=cMuJ;(}OlrNb!EX7QfSHo~JV ze&$PimJT`b+V_G9G6W#XBW{s%9^H<2a#Jg0{PG#7>;ho9A5=f%1f9@6xSxi@Y!?}a zV2$wKuL`m0jc+-N40_yL#rm*)UuLvT7;cwB`d@B4)J{93_VBm87!B=3c!QPETI$% zxTNBtQv!^VI1#Kq*)O4G%l;&kw1X7JEcLLNCO+1Q)P@w~RM!EAtmrTu=u zdj`{AgLJUcErM~U{XK8#B|}^zZI5}6B;od5vnDmJ8*BHR$#aRZT$mMwF7?^GZqLA{ z)(EzkORu|SWR%`CXQ!_61`u-}w<2M`E%3c2m99AUC^1_DqGJpr$oNpn^{9RgnBB_l z_c|8HC2;ovM?wd8VD{e*p0$#~uk9-=YCXqhv_Pn(I5w-}<7owg=4Wf71sg0;F4k6W zdhbHsO*&r3_QcGF22VsEuUM^xbQ{?wgu#P;PwUV`FO6M3e0Kd@-;s2@@>K6fNtG3i3k(+#fS zo&5ZiyM$LcSw*b0F63l&!oSc}O;oRlyUvQYlI={zxI=rrySqHN@v`eZ4{MP1!kmrR zOoN7Ym{>EFQ`i12JOLj&3ePf6kG(0-o_RhoA%ob%H&4oED|@oprC-%_B)*X7ddk%#`~BhxF|y{&>qe(z&q;*6CTdFXAjNbA)Uujy_GO#=V>7( zR%m^&SahU?406#&F2e1*BRtLjFyNSf%NR#h1<;k!_L8QjrB9zv1~LUXB#dhI(Suo* z;niat#$y}7_{u;e8B1CtVoVnR2-v_|*zPhI+FPLw?~<{{j`T{pjS2`F8rmA7p1yyG zg3U5%2hLF+x7|aebb6^$aTTT}$Z%8I&!uEF%>$N2%%fvJ!|B+LLi%i1qNe&)DR6M; zQgexBNjuV-JC}Fq(RX+Cn^rYAvrQ=5mkAV^mktRy7O8?B!ZtZD<)f;W^haTQL$ozz z;BXM9x{>U60%ooBZKi_gDj`(tdNJP%%4Ir7P>tf)C1WAZz$OOMf|p_4eJZMWsCtb! zUFuI)ysM_BlhZg)Ei^1@A{u7Dq;vLE9CMI`P8eZjFK(y!gtp=lymCdtRUc*fqDY2prNi(nD~_b4u*1J zMK%TjrFAVnZ#^uzy)>0M_^i&S0;iuyaqwo~G!eD3@1u*t;Q1G8XI=k-11cxLi5f5l z!>0r6unl{IMf2D=ahcjOiGbc*B8DgE6H_Alf?zmhLbbk4&P=M+;mzocMf(y<@5X&t z!%tah;aD#@dIh!A%Xkd27tW4#PmfnGTg)!}+XjweJ=i4G0tgSVaoon_G zp=g{H6A!cXES?y#n;_V0Ke$pyNM|1 z|1yi(SQ`GZnMnKZh`_xME|qh8wm0V+ByCT8&hF`FK@H#^l0C zsTypa&T=L?2|!3BP!ghuQT8a*fO16#APW77sax6-sJ)a&!@5)n5cG`@S9w%I?U%|u zt(tvsJq5x6tc!xu{ty1k3N)7p2 zYiq#otfhD50!L~qPK5aShBd;Mrl>!DK5Z}9g(*hJUk6ucP#z%CW-?DqG(cG%T6Se~ z58#yOQwX^y`I_!r|4i5GsY&idX)4^(Z@NKSiHPh$<#?n~B7vuDq?>aASiM*7K zUp));)hb9?^7#jNTH)n}K|v9rGzjADUGzID>`=`R@^?WITq4OR1kNF0^#MpG93l@z zprc@K-Hguwes$pzDv>cjPmx-_Yr$DPTc*|?5og@1MpxRU@@FL8<;5zAHuq&7OM35; zoVoL3>T$!#mW* zPVQK@VKm$^{mV2mEl8eSrH9sC2 zW9>w1ulKXx2Sq{o<#Z(JfL_QqX0yhPN zG_Vv>nF#j*1sXVV;ZXFjz1o|4?1=(?xwJJekp1KX6p-WLCs=nng*0MQVhF+GSb9bO zluExlw4Zsz_eduwA*|lNQPGs0x#T58C;!* zXRtcmMFXuG!jY|fV8Y@IXT770r$9P|VxhB%SJdDU!t@?KBa_C>K$nl8pt9a2Dp@H3 zO09ecqE#Op1iho;Gcjm=9Ac}rW%tNzK?~f$O&7=`;hOO(Mu~&K*|`Hf>D8fyvS##h z`npaK4BulJmc`@kux{|$QdiVm`K;Frx8LbJx|E+VvjzD?-~=wM#bt@dML^Lt#Z=kZ zrN1O@&=X27r(KQ)GW8s}E%}KLt(CD)Y)~zZn%n3*mqNcek7 z14eaQxCNW;dM1y@J#EDTPqe2N$B){_cQ+Wg#{(8vBbV;y)R6g$maa-pmg%?!)(8i# zaG#0IbJuYg7&EJs+@H-yjEh%{CUP<)QXmN}e4>_n)gRV~I>FMmi#6Fk?eny`Wv9bB zRlyFVe;-f!4AFf@m7DFC)j(>O53>Cu@Wo#dC;Cg&{BxxtWFYvVfnolu(kPl)IvLsh z+qI_mBFJmnh4J?7&|OcmVC%qbEBjX&+h)nAe0w}C>!fl})$+IOg7g?X1cP5pk-A*U zu|TPj9%x+sZuXl@o0PwS2^DhOKY@keU*t%W-|M+IH|*x1)F0{bPFPOvJwE81;MHbi zv1(?=j+~3fJ_o>n^X@IeZppT+#Irxe95AsGO%ia*kO!n!qQx;S>A{Oi>k5>|ithVq z$f+HKhBawtudF6Z5U`oFi0$~*vmc3ZRv?;0VLqtmfRH%*t2r^1V)$UYsFU7%VxoZwMMx4x+0ft>#$71Qq9 zwZDVJkV&snxtQU4_@s3u-X>%e6n=7=?Sa%n{;lX60*BYRQQ&2F4ly6B{jy}iS9^%? zuB?MD^-__CJ^H(G+cXiYre3s&x2~YVVrRYD^H8Tj97KWD@Q7-Hx3)!Mbl(r>2>tfKJ=}h3me5${!;tbZ7W@dD zIz?=v(TO)<5YRGJc@ecxDlGC+Y@%E1>}gKGjjiAY#skS60PjCR-~@APj=FBQ&GJ!I zMg^GH^`e-P%ktqa%1U~Wb-ny(h2+##xGtQ-)_KNrA96~+E}moi^1=!c!N@<0>)Iy>#ZW_XdV!=p}ab5u5XN+&M|uTCDoq(64kQ0 zJ`$+}l@F{aq#(qHps9yX$dqnk(noOvAEYZxX638A0l>huZcqi$UNReJko-Xv=J`5d zkK=OHDM}SRAKkP@3nCeZQ^rhx%W_7%kmsh(Sgk0UJ1@-z1adDO+dsbKBcm7TmC(wd72DNNot?76ie>O?Yd%ETa}QSz5w*VgO?`K*Jr-(oeMqGOkY0~G!y`o@!Y+&C8JEFE|7r4 zUuC^t4=K2iMc1jY9M|86kU}yF`{|6%U!Kn0cQeA$QJo1$QhFQ&7N1QA7)v}qKHqfKng)tJvDKNwh?U6kSF6xUr~*}#83 zI|%W1Zw7Abl1s`;F1*)|ybHx&ohQT5p?(2Ghcnu(Q-ICx*j#$$tQTk<1yl7snakiD zjH`3UZAF7qQ$DOehBnfn&1OkF@_Q@pTrFuo&2KeWq26JzLH~2AdZoog41gbf7?!Aw zjfthvkEKI^qLH1GnSs%(>?9@lb50J50xPPd_`~V{#*R-tGDsNycD8dW*GfkmZ$o?` zA9wb5-+K=x2w&Tqn{cnk{pD73y2QlXaLIe>o2vUS{&-dQeTi#lP2X}4THl1|6c#I# z+!2$HWbKS4*YryEj|5<_O!PVvy` zZj4Vs2epieolAFjy9I}~G>@xe%~eEILRMxlUifx(uG1A*Sz;m7EqIb)3xo1hy5_}E zlp%VN?S6)OPT1!*jZ-}J;|!)oOMtH4a0{n%oJ%_@R56T7kTosmN$mEI>TKofgw<-h z394bWEX9=b^52jei=74>Ft;isS1{F4){s)wirw374jbO?`65N^r+0@2KfE;#eKNQQ zzIXZVuI2pT6!dVsUWMQquUgwib~Xn*d4vwr5(!(^*B7c>GF^HYBS|@mmB&OXLv>*! zGy(FZ_=|Y$Vdh7_Nf3>iwcjxw)m zj6&mg=`y ztgE+O>B_~^V_bQk?9N~wtkQ4J1H3h}#S}6*`Wj9tO3y}|Oi`QG%YZGD33`d}GN0|7 zH)u2~cECDh?Xs|0lJ+@FkK;+*owE1LngX!eLc*WRPS_6ZTVMRPMm)NvzDU$WfM ze_HR-oUqn8r(>Y=eR^oE#efmp4NmP#wOFeht_3|`x{7WzGQ8E2D%j5hbS+}{VsfI^Mk`ew`ul$7u-SimRE~1w-dyvxy)#6FoSeTn=GtYiho^F?(Cy| zm#W?>g^D9ec~In6IC*F!$6%?}hJP0S&C;st2*+`%dU~j3(3xo}sw|aVkU|=8~Skgw@1M z>pLkzR_dDC*Faggsr@dA5z#NHgT=KK$nqRIi;pH{vzo~1Oer{Rv(1|MLnEYSipu0# z8^dfP!FrGQ4HF}$=#SF{QfsmKGh6G|5K3!w>5{dd7>a$qtYWXo+r!I#IM}U6C&Y5C z-V1?sG#s8SX@%~>%zl|s$`0WEj!FVr9WGs%#nT_V^uFw^iL_bF>S3~$^R3$7hQu&v9C4ope9Yl<;wtKI6kVYD8XIG7 ze^6z|kx7}ElQjKaM=j6@G27n=Vsa&HXuy6j+?;;5w`3A86iDK=8x#Ab8~gvBZ2a7Q zM?w3)CL4?Z(cf#$S?zL2kq6%_`D($^0-6|yS7>*Ti@>;Xl)JvFG2oHZ_M8Q*h0|&i}dikaV9`k@ED*#WiW|S_SD-IcR&y<1yFOf`heFhP! z$iv;fvsZI!xIu`9uR9+feYo$J+U*HsfQi8HWIgIzZ$U`wj0oBeej8x&z&lW~fszJ} znKb_Cx+=EziFkT^wwGLdBZE5?DmP4()Gnx(3CzTiCK|#l$uK?&d|3Cppp)Qug4is9ytx^}=x?q*G8`OC95^R!hOC~Jv z%4XLui`-uatm`_uje)24?6Xw08i>V2PP9YW zNO(KbLd4O*nf+9I^VcagYWVaFAy7Cww%tmZ)H5c0UtB>hziW+yK11sv zSE=aS=EAAFWeAe`F)(!wJF@JB0L^PQ9{oc9KP%sC@4rV$7;w-v@AJ zerBS98->Q3&WO}*l}bA8!!~t4RxCI`WzAh5^Uj15d&IrE=#Xf9m<_j;7$7Kn=1-~d z)BfhKa+a?u_=U18yhOR9_fZpgm6$MF4Jfi_!W`uUW%~`a_ln70eDxSUku}vF|ID{x zRLF=>gVl?#L+CWtwgkBqdbkde>1WQVP; zSbA-DUVt=iw91Kf1MDw$kg7<_XJcDXy5KfAmTEav>q=OQ?FhO2Sidr^yAfJ9GC_IZ zF~y)s=-Z8NJ7>4fBI7s#n?P;w!}c7ZS>NShE#{O|Y>_LdP=kchppx8o2!M2u4faQE zSikj9q}@G9s);u+^}1)hS`Y5iWsU9pXojm7k3Mm<23x@kh9qpHCik{N?3;Q$`ZsR) zXpsI7biifYX!HMJ%rXBvn5!8nhsIlQBMvZyF^2#4BJ*{y{ zcRL8fDY0N&et=b!s_4tdcI6J0dMRBeU6Wb#Wr7u28(t1C&9z4N<0>$eWD0piM}O;i zB)B#0AknQ4V-K?`UZXly2@{ZR%e|I6(#doQ%mEO@VVzX0sXFcZWai6@UPmF4y>=J^ zeInQhE)p7etuES*V*^Zx)bzb*ieeav19}*RZ9J{4jL*T98sr_z%LBm7WBOF@y1C{n z!vs5Vpq-vDrI@;@jdKB=PdlWvO~sd9VU!ru4-ioVnRh{ERS0K2Ay`L;xOz`+mZ2+i zps*Qa&2Ls`lsHPra+wbueU@m)5M_5jC(qClaV(RWtZ%?RcFf%VQ&XJQs{$B#Ej$VaqmC;W7%;2>Tb&wwM=ugIlD zUsQS4h8V1nKm*1uUc%Aqx~h4DEp@%3W#eyeXv=^(Ai*9Sy*)a_eTCPe$^E;B&XN?+_}iwBB=^=ej7R#XBADEzB+ z1~4%&G5izF=^q)On0)lVPB{}m1#AjhSUZ+IQG@!=IDI0WSLfn4vcTVCp=xosdGlr8 z>TAgkx6C^ssIW0~+mVjgiU2b<~2B4UKFUOhxr&xVSTh6or(La~mP~ zKCSnp%bYV4_f9cg<5sRSV`%rCSB2i6H8r3PQ%ZCr7I`@uiBmC{Tp8ZZVLLDNbSLTw zxQmwoNxVuKzut>ivi6r`0fT~}Xk_4MXY}KK2-?_vu(A77?_Hy;Bm9?d{Qil_ zl02W?__6C7)W~kx;h8O$c(pYCP55L!5)6(QX5)kQO}`3#t&qtl5>36D4P<0~Ts-UZ z#+JLaLZ9XWvHncFw)V&(e%{8o6H4rv$SF`f&@(G|6I|7Kh_d0q>t}=tV^T4&1X%6d zX7nB?*-4Q*RIP7=I>5 zzUH<y~v>%Na360nBqrKShfHJ<07a;bQaYv<6H0TlMhM*pEl?y(A0yPTYlhQ z>Xlnc{K73?eg3Zpti%nCtbc6tlQWS1@G}12w%0w_pBrKS0?=>gONDY+YwwbIW|&1T zY~=NPtBYi#OhUB%7Zq3GC>H0>U&`YJ?UL{7v_FP+32ZXTIZXP%e;i9CED_u)Ez=3K zzJv}X&|qrIIf}dA*Md2INt&v#t*KSalnFYEZEZW2Wnu`H#L!XgRqVb2NsL(3r|uvj z(2rQ}X{3}Ccj5k|8%*?+yu>!xoijtD1Z2W$ZQlW+cAmGoTbV=VHoU=>kA;5yz2U6< z9pAN;2H5v6EW;!#4#YUx%qVZPdx1%B7*;{FGdE^M+iH(+vRlN(7cwZBBnA}b$N$zOr`yRmZNGcgo^`?u>(CAW^qN?n zLxH*}dwYq15t_x+A*SB({D^xlel&?c(Mggf?&Ikf!Y5 zQq{a^{Q<05HmljR$Nh!z+@6Ogj;aclA0g{mI@rjN-y;q>HiINzmN2Py`khs zr2l-P^xt?ox`LH%q0~~@48nF7#gwE*c43rI^zK6UZAb{{LEE8@h$8fg*0sj|tuPhH z5u@HbC9~9*fsZiko`}s%Nt<|y6;T5#LvIrbpPqP_(EYNIf*Af5F3t_`9U%t3<3?8(fh0z z)1upbe(B3SGhp_*&77Im2kfy@YbGssOABwiNWf9Yea88WL#cTP1{3E^vN(OP2 zxncn)x_$U6KLUWWv$in%pjtMXj!E}Gb)*R_*3@+OEt#%kb*A%64C+}qK>VqU4^3Phs##UDX30&QVur47Be-3C$swSevZe9ZZHa5PQrr^rj6j5B zdp53i(evK;62Vnm`{C*@bS-wQpYsoiUN}AM=%Mqv%r3?x1wdQQ zfJi%bpdLN4-}|3yqh^Cu!t6gCM{QceRKKXvGlnv+g5WSpRPQ)tejHpPe}|0}Z2K0v zFx3e!gChtWC}Y`o?$zxIcm|oelry{Lm)pGT1%HIe=XE-y+rV)~v8y2~L)6#qYO>Rk zFT{Hj46zO1-MFu6B8Jq;-U|r3S;Gfoy-}(%s&9`-TS3`}vuUJRF|i&DN2&`z4Fkfm z^>>R&ikZPCYiGr0fLuT|;3Aj$DHbCOusiABVmrSQJqaDrw>S=sf^9@?@FRX35n9<; zn>pIp1E|J7knZ1(R#Zw>fM4nd+Wii2|3n`tr%@@x!9Dq!5S8VELp5y>6(B8~gOI5y zT%ztF&vbhj9_HG+YEjYJvmPgm-yXvTQx1>5%kOZr+&tMRzcK93>A+^~5{95|Kss7L zIi_^qxYgk)I;QK%TkUY(fmI(C8_WzBO`fxj24=wXvEtZMdn7+xuA1$d-(YC$*(}Nw zK7r-)NK*vVkmM?TbmG7W!J|qd({d#4m)C89GzP21MG4c76bUG&1IclV)aatoNd7q- z#5v@uIR{T25#(9}VZ?l8 zf~$y$>531^+crQp`1UFVd_m=lYrTtw<^}aGaxBn8#XsbJpb7)&alJGR>)du{sj|UI z#BmXSH!}!fA2qJ{X$2#YP+}#SY&wRNN)+D=vSKY~dwa$LrbgRy=B2MFg&C*yUg;y> z!NQT99o6}s8r}ha5^*oV4EqFGRPZOv%Z(xtxGP5vKbi^a*D<;DZ#YH1cz_|QX#3(_ z9OP^#?7KMRe+3#@lGTvgqKXoFNRUE9O3Vpy*T%5Wj zdm%GBe~M3v&IhKW z={=I$M^(g!zsM3WCw38w&m=3#RaQZwVtp0HLI96a9+C9Xvt)i8h?1u*UG zJgOqr={UF3RwBan{(SKNcH{p6%~R5m|3LFZf1`OhCw)sZ13<^p0N@J#8-Tu^IR4>- zSjC>G1@t|c^Y%G!7^l0$YkJCvca=rm^cICK&H<$LrEdk`UK}W^HM`%m7{K+wX8vOETbK&!HLFiP@o(Xf708 znuLTO1BO`$->Orm+E|H+=?zJ(D^6A@vR@HNs={7 z$jW25Fv9L~wl0Qcizo6s{K9giWVtBQ_mJvqM-37*TL<|DY3@@f`}A8 z4Bukp_F2Lb+Sa%4UMKE5SD9JWNw7b%(zzA`)qL!w%=+p;5`c&Uy!(%a_cJkvMu8VH zGco(7%ki2}+}ePK{uhS_1^3q*gi2C?hPWa>6CFFt57QH6{$nOtGjTcShLryJVElG> zWOlpd@GXxyb0kf}?pnnyr1Usl`WGmelvYdCB}|D%*HRAl!hEq(8vDU-#vt4l`$v1>I{4dpU5^Bo5L4`lJbqPEjpL5j*q9ikMBmrlg88g&X0qKMjfFj(CP@*9OT>&>sy%@8ls=BY?|A1P_=uI660`Os$|SnWm0O6T%E zGk;kZ*XEB3x;=Aolf9b2#s@fZWHOH7&{^?LNX>3Z2Y1k5h` zE~gWfkKn!WEG(4B-1)?$n6nCp;BY-O68pyp6ibM@jPakGcsYQ_llcwf$jH*;(cyf@ zIIyS!PHwi}0tvq&H9H$4Jqsfv1M9E+2NV|L*V}^Mqs(n zmXcMx?(;aT=kb|Dvjd&c#VoCVz4xcxtBexe+v&6PSjVt!+{98%-~GBv`rusohkoyD zn@B~MnWRo-##kOqTBn(^Ao1aZ3MB~31qhUPn$Mf0Sn3@wKfbkdix!eIeHpLQSc7y% z!LOIgKTN_h+j+(yhbZH785DOIFdf+<+5QGt29kRPH7p+b!xx8p82LRENX$Fsl-U6Mb!$jU45}`b9I0S&j;!BZ=OOZFe%y&rb8j!>@MNEufbXq~l}?vqn8= z&eeg<8{irt-+G6$;jryMtEO-t6Yb?*!J@B*A2LP0r^E$9!+2-vKV_SV`C=5wbav1} zVYEjiYNhUCLDd0&Kb{?|eR_>;tyb~S3^&KSCu$qVw(LCT_Wl~((AX?fTs~(D4bucd z!e`d9PP&G1L+?PVZ9f@-VIEJCi$()jAqMJv{mZ)r2tI>ir0u6})(lhy-pj3#bG^99 zM-z*Ah4OaO5=^+^0)6Ni`8-Y^m6j(-IidJS~8n&cp4%wg$9=u* zinJeTDvxI0f58~MouviyWht-8#8Z&06eOBSoj@p)Ix34Gc(Ly>xqY6hnpn zB39f-Kf0p;OuWnTH_x^xKnGPIiGVMkQkU!a8SLta)} zp5jzS6a_~!(f7tQ$QR*-f>&bDZimx%Cp+=oTV9le&|uYgHSq%3WyS_dE{S^puX{a0 zm`whvcDMjl_=`a&%%CGkxmJ$Awvz zb2Z*x;i!xA=J3wLLXGe+rF`(gw8p7v8R~EV9D|+M6g}=Iy1=;uB?`ntU7~GHnx5Y=3vVwL+^rz{*STq2qncw#%C=ktdfs z>@2n~N2&H}RITx<93Kzec6Gc24B6dDS*~B6&eDENNJcU)OJbgL0`}dgxD3#XfWz1E z3{KSMuQ&+)a-(%d69Ud7MclkZK)I?QV#t0WFt(ThTT|(hWca@0GM9!R0kRTfoo*Qj zGf^u0t>h}0m0~XU17zt;FRS0dcESrRa=$47j@$*sL$^>}G2H?CSh*F@D1Y8+0acA< z^L?bG)j;wVI;oORT~)$Dq68aZ=#Yt1L)baU;Kh{7BB=+$|> z)3OfnjCLT|=DBl>NwP!+_?l6Ro!Y{7E(mY6bcj;R{73Gz=iZU%;BfO-5IPxaNPNw_ zFTuRF>!`=0Kjb7l7~X2UDvzzc-VBgD&pD4vCC->ewP8_eCD2w!YjP;;^tAEN-$%C; z)iAn%M@kb}e6(7bd*4y(l~=jSt74OV`*j;x>=D8TS+%~1L{<~Dd&7>Bq~W@@moUVWN+r^MyO!q zV5DbnU`i-zZ{uY9t4j!q0xPblAo|1p)c$OGWqU6jE>T%8(lV%2$#H|*RvOmXq9d%i zc2u)mubsMbp03QTzXHjUFRz&fSqjC~R~bB_B3rZ*OnsqGBl4bPh zMwBYq85U$`CSh!B8RgAo+g?UN3~{mDvEy65B^lL_;vEl~IW3yxnIcA_xW`s53vJ_1 zGbyeb;pH1j_WR}e09m7&LNDb#2phAN#q`UI=~)9(A5o z(yNz)NCg_XQhWp=*(r4e9P-vdoEcvB1<2s8>PI~Cu4pizQST;b!K-;ZByc4iz>y#N zzHG>$cnZcj)(koBMiKzOn4p`{v}37-{MboH_eQM2k25*nOE)Yhm%?x4W2-+HPL4k) zfA$>s8BSOIX`yEjr%0g~Wyp$is&hMmc^)@b)B)Rt;o1Nd95ng!_3{>)zzp#OnbxM; z6XvdMNSVyeVmL?NDw(|XbBo~>qu@{MAP?~1zk9v^4W`HNPtE7iwAoBwf9OLfi3@ZI zo;TwzrE4bOaCngQE9mzc;i$`7cDg+ug%glMBfmhbUsIyverW3LW!M1S!1u#s3!fKW zfHt?@0dlzqk@q5AfVNK6bXh;W<3D6yaT+p(geCX_qyVV)$o=NR|GC=ptL^|x^v~5E zKs)+BD)^+F1u)ruq-~(fifr`+8*kHZNqO{3nsSFWNo0fiiYSvn?2z(q35|Le`~k~> zxFIqbsD+EWG~4oi&h3?C+3ASkQV0)4BLdVk(<bg)D8QAv4cng#y8|2)llp?SZv_oA}mZKLQ4Oi`PN5=I25q)+{!7>pw!h*8WKbYt=09Qu;v)BfMg8!FO`_{vCvNkjLdv->U z|IcFpH8oE@(^gd{=$@*1uvX4tw36+H_fp4Urxz5SSI@_k8~ghoH4TYVQ*B;zkebPZ zr;x79;+os_rF!9~uX=9>6+OfHnCdHc7 zgnEA=GKEM+O$?sWV`;G>Q^`<0?&wf?WElUj7}-TK|E}<2;Z{4GB2wj2~+J<9TT{7$i6lbc*gGps(T=xprfDn!4@d#v zb^fz|nEAi)5B~#l6cvU~y!X;--)EmBy2*s8pY_0xBC1-|1UJ!%)wV(9nqRTkXlr7+~ZE-v-1)01}0I zw)Qs0Mh<{q0gA+e;v$6nEDS7+Omr-4e@wxK5-lRX+}xk#FmL!sEp2ow%zM=%4uELa z2vYXQnpY3uYLTb9B4L}Ut5(zz3T%fX?5u0%gT~TcA#Ll=GuW{$g2CFAaLaomK&~5r zzu9k(x9Ozt>!@9luk7S%E@PE=Gjt}&0{^n4y*t3=u~6=^YPXMeidy}hJG4xqnF2^L zOY-5v9jZSpE5TqatIzyf>d!q*8$3);CYLdDhS)MoPC@>A7TgTG4kws)beH_ zMCLS^+cX7}+VES3(g-Bk-`14AMryPJ%q)D9_1E zyyL2n{c!PAK{*Yc?)D;kSe3r^{XlfJ$t5Ow9LIy`!lY{=J;6sRSRJjDGJ{Z!mxRs> z>yITe`NYNP+B;-nUZxbeyJ3w>NX;13Dd{LLMXr0d7BVA!`lB4JG^+RPuS$VaHAiGUT7-42HG7L+EQ2Lv3f5p2^^^k4nTdNQ_%dfN-TZ z&0vM#^bHl(V<+jy5z0mTjC&JH_mejBe~s_|8sGna#s>ggzk5D8DSC1`((geZmO#>8 z&)f!(GK;(G>j7erJD{lpSQlmX?WON)q<+E!P*?;-4So@E0EO|#h5^7>&>z%@ z6-tis)s5-xCJxnRFToO5-qm?H1Gz-NjC&OZjgZQ36LJT_&Z&Lcy`;oUUz#i@Jw8xe zxs0Aek${cn>b_i>iiC^hSgERdW?Sq2NUh`B1kx&zj)PF!-PLIVy1Ih%p1Y=U4G6!G zNwhij;0Xq`l_g*ajznAWL&H|hN?&!e}rjWq2^2%P!d>KV5+VO|z; zt+Z{^*t|VwXk3AB04|xhy?EU-XF^8j$N=!+9()*d;%-fT@aMT(a4NVYK3lGjrA`{} zXQk6Ypr<6$j3q@NF^tMGEkl4-h(k9v4QEVR=-u?VnuqvD-d zJ;zkQkg+p06Cmq=H9r-`@WUITy0lab?92)r2N8tlJn78j~}sEPPbwNqwa?05Xr=)PF6e50&UZVz7%Q*K3E0WIP9|u7oD>7 zkAyhkH(NqHr&;h|9O@O@dG_JuT#N6c)p5;b>s=vTgWKReBDGD>L3UA8LdlS>e99?| zF(>GX5e|9tIl0j;4-IS3(+O$B)=`!^4KGIMQH4C~sX54e;O-5K+Df0K^FRslq60$S zr3OeSuWSaf-*JwkA|QbxdoP?aQ@g=`qNG7br z{YIi<3h#Wjwnz#IB4am#n(jI%leM`SNRbQ5r5$2c-Ql1p%%Jq#rb1+)z2z0)cU@H=;)FtrxwsG>K)z>u8ud zj2&o$YJW`uZUbVGanjOG*`nDY7sYRD7hEmf09F)`%TQ5%Y=IG8UG-$S866Q)m?Snf zAU%8mF|K0{El`Dz??M}ywG#^u@c>RdMY>5Z@5Qi!@B?xx0WgokZ@)uBpM1dCg z#)x&W)N|JR^&)^tBxL4bWL_}_*(^K4ar^HQ-Yw6h&H*+Bg#FfW_A8en$wGH&O@K;*HnG&sB zQEtPuebdyw5ggu+ZPnpSAT-I!SPv04#X3t;W742RxeHTFaVm+!Qm{biTsqjJ1O1ly zWz+NpEqk9gjpwHBL2LPq1`*5Q!43L+&CTc@r;ejf;KW_Q(=hED?73?|$x3cOqH35^9r4V-m>hof6eRPKMg`VY zIs+IvpQ-@Z$l6mMFCbw3ONT{W9%X`mw;~d(10GDZNc5xt#~7b=LfLa)e3^ApK%|#V zMwl<0xRt|}M=XB#Md!r<4YAzvU1zmfU7g^4zw3UjxsLkyFitJm+0qDBe8jPR`esgHEu%%}Rje za32kAB$xx|c>@8g%;;4K*LZnVo+qH{$$}K&q1^+T9^sb$!}` z+#&m+jSEmL)wBL468Sgi{;tXZz~iO>KP2Fl53Cz&%6XLyWs5NFl$z59Btg57SAAQFXi?z z?t_xAl){Wc361!A^k}0_8}C~7kTl`UtGxgU#fGX7g6F%X=uGG$YJT3TGfawOboJLv z;@E`{^MxT(p!V(zTVG72tzRb^c?_xFoo}rk)4jeQ5h?94II!_yp<;4Cj`vv~A}T0LF_~naPSSMH#}cCs#)Y_dOePd}I0c`= zsmjW2z_FbUF>BJ8W4qK}c@^&3ezWJ@_+~IcR;PfviO^!)V)Y6RptgNkZA^nm{xwO% zBN06c7>nA{+J{{Y!q6Ys-@jWrc9o$o_yg-c`dBfwX$ACKBM#fnv@&Tcr6Edc$v~VM z-yK_FI16p&Qyc(ffW4nC;|EWWZ%70SDe6YSyNs-2t z!Gzn-$8q9*vmRWx$#yvs<`zZG#!eSe0kNr*AL_)Oz=YoQIT8HbPYVPfpWiJIP&fOz z783>q+Q{m=k`tgC@N3i_8U@Bk+R4z=9sq}|4StKjKR^02Gy|Fjf`2Z0j2{#=ouz<} zERYjPTsSbv2dE%kWy!uq{&a_uN;WZm>xS*9gXhNnpm}2(xe=>yz5VJ|$$t@VdO#zP zSG&I+@|dS%EVZIkMSzn1mF--6od-)<=~su9(RsWu|GayuXf##}TvE{$P70Mc^O{a` zj&$y;&LlQ9@NitDPusPPT7h`}Pp&#J!lsyFc_I!>oKFY?&dvRp7vPgY7lB8+O^Xa= z${}O<^)Z#QrQT>HiC=k737OE>p!<5jgx!1!9^0mh@+#irUWFg)>DJY zEfeE$+|_X$F{Q-6uw3!`~B3&!zH*x!O`vp)dMc5wa@Mb<$n4keHSrv;y>E*w0f z$tApMnSd~+1WM65dd!2>vB_36hFIPJ-L1T;oS*c?02bAxNU_+QA?3V3)AMV}PD?C7 z3CO_RY0s}jrYB#{6*7I|qQ`$+0u8_ssQq>XfSMl_9mRJyj6y7-XRBxZZ_f9Z3dK+U z&9BW2C@4R8^xtpIw<7?+)<0i^N0;I}+-PvlVW~96a1B)954+Lmlk2KeM2H_S9@k6f z2nx2BJ+BYf8$p-i)gHC%JtKH^fK43H5v^;1`rB0emjGISiJr7QNzHZ(9zK`5HhjRGqErN*8Kv0 zV`TXYkijB;uTTNja{tHaz$hlW5w?2O7ejRTi1?QYp8nIl?4&EOC+Mp0<`+tH1$_L5 zjz%??;Tx!rgkNA(FV+mtVJO&>FGtE`gw?~`W(1^4JFgK_yqT(*g5aTJFLKO{Rl&`+ zk%A_)$|P~G?OS@ijrV$`hI|6$TuKH+JX?t`W9Kt?7InbDbF$^cK^S(x3;YICl4Fut z+c7J7GsNR;_pV7|`Yyk~sdHs#InP(_g8^?~N>>GBsCNBwUWN`wS5F+1d^DD7*8gy; zsA1^gnS7TkmVuB^UVwRNenxU$1;vL^t)AV#rH1Lpt={;*B}ze7<$puUBB6W+(vh@5us) zao}syjzZOD4!tt4h`3K>52wojZG{za_43lx6c##u4`)W=;M}g*AnRM(-tTsYaW_u~UxbG>oUQCG?w&Ix1c$zf0lE)1#uA76uU zB(=`aw#{3n?^^l|~_(fL_)LBvxCAsvLW5-fY#Pa%9Hir7xOLa&3 zC7(w+tHqT~^UVjHpH>L)1ixFMxbSbesDPfOqnVYBz0q$WQqWD`$o|Jf*H6V7z&PVy zA0+(y?eB*8M}M3P)=XTI%&oddYM)x?Hbb$sxtHKuRryIXl8PeLa6Mb=s1gd?YMGp7 zOg~5esWxN@`GDa#MwJ z-Q-`cN?rwrr6%GQnKbgk&R*XtpwM>V%-Y(XMs*+$K@6vEE)FreyUg7jHl3LY35cOg zb##3w*VcWi&j){~U4>K!nNi0~Hn_?&*ocPp(yE4VzX<$tFauhy9l)dWjCN$!a?8$Q z?=LFTu-XqBoE!6s>(6hr8B692QBA28^wynDnQv@0{Bo03+U% zK?Ty$D`eR0KTiQrR{#AJ{(GS0Z&9Y7pyXeB2ZH~oo$;8bSMEWIh_~NBOjizZ`L?D? zz%GHkWm@4=MaAuT5_2qz2z+qDyC!yx{pR(FrvXTQu4ZK$|6KEX{mQqYAhup&y%L}H ziIs?@n#x~x&ihp zS~(C3$^sT+C<)R0YBYiVq0#hbEs9Tr_TtxcYfzp=d~emJYdKaw>LJ9*S(|Y&cLCN@ zM&p=B5gqC~q0<8rw$yo4(bT-$(>1H(uRXc!1a-xW*2B#Y5{l^9Bx>rl?GUGz!MEM!XLxk3z%^`uB_Z^7(&F8md zq9>D~?1DY(Yn%M-N)Cic)Rs#ZGmyDEO$#>V4-r^2(dZkd8vV6vE!z0K zRiT`Oko1V4^}32e9#LATLup6#HWJ!~>O3|*m`q>@>S6mm@v#(#3aTW~2vtyR zxvBhKBc!9@iTa8@yQaX?SJ?1G9R-=;dtip3R(C!4G19!3q`tT1v@53aASJuN?pnFW zXw3dHoK;&s9q;WvQPO?LMvX)h(mummhRi8Y8U|v1xH<7#wWE!;fl>#o4u`Ef+ zrHfx8-lQts3ncJI)yc*F9~Vpq;O7394DnAL&p+2bC(zgxsuXHI_Nx2!XepF)2paiH z_Ma!VEVCrd`Appse>7s}+?+sYSNkO!a)Oi+_%+M6u)hbY(cB8G^yHd1Yzb!%S{sK- zzJ`snnL?3!)4+jws+Ph8HM9jYIuv5Sg!vE$1Q4s}wzsM*Z}@>pV@Ppto1$`cOpjMn zWgr%WE6uVV_FdqWL`?QB`fOwl`+9t%Ede=i_yeD|fj^f&C3cF%_?o&o=YtLUJi(&` z;(?4GI!7rPtm0YO?8{0EP`OTOF7#C)CNgZN`yU6P3-Acqzj=iJl&tl$?+*h@Wb`*z z>sM3mU+V*ZECg)6LO6c69Kz^iGFnF9#UW#rK23{yVc<9nOk~dbB|r{Rl2j8)(2^*_ zd|(#zO4lrE-Dl@rYf>4n zfr7^Hq~qBt3J+c7ZNuIm`pXktBXKhYX@3?QO?vCcEQNJw^wpvlJo{J_Wv+&ZEFKYh z@g?WSHX#%dI^HC%h532&V@|eDR5MBNO*p%d;y$dDw=S;ZN=KR^>AAk}F@l|QnmVW- zGxOiQ6y;NIw`Z$nv1ENtnbd+;hb}R@?x+S6c2@!_Z&UnQx4U`6l}kTW^hBg!*qd*1 z>I4Z9kNQ@*k8B$_3Zv89ZoWhs8;P+>;9B1jb8Z~Ul*h;ND}I!IS)Rc%Q~?38 z06)G>N*K@lEia$DTV)<_>{L4U3$#2$VCotM=fVWI8u!$DNJLj8n@vFMMtFtoNckBz znLlNnD0nXc!W_EBT-4d33r$pSL?B z8%T_|(xaW2l8acV!cya#(ho<%s%~C|zR{?sjUcdcds(1h+8w~WW&F+n{+0ABR`re> zYXNb(($D1@dH|Q8^RJfps|pVb^>P~ptkm88blNPHYD&M@aP`(2~StVO5ZmPoBdQy!=9Ptb(85NtOf-u0y)&N zU^sG}9*sOWgDPO*v%&Q-q)J&Tf)&L-1H} z-$ZRVze<(6$x?b2igqTMV(9BGfoOlYZ@(z>iq!|vq?l&TjY}0Y)YYoKV|eBStB~e1 zzwQ5YLh@)a{23vf4el8F;Rzu*la7AXQo-mp{B0ZYCaxOj#~7SY$RAF@004jVemjc) z947qCT0v2W|ACM43krSXr2GTT;6t8`E+}YsEB)m(#(Sy&r_#@l+^W{|2JJgwp|O!~ z-+$T{wH}H_9zfYBNWV66B(OxR-rL?ku?l2J5vtOD9C1cm&}_}=yPXr*R&`#9?qV*I z4BRyyV%MNb-j6C-N_BSM+)^cg*X?BnljgYS+_ z7(iTgv)*lNya56q=ekj)n=7Q}Oq=YYtxW@@RKl%rX5g@gs7%5*MT*kme+F|~#aKwOasF$GxbqI@#E~1#R z@w#vNQ$V?%t`iEpOUPKS}&ObU;5(|@#JWd z%p3NtujF_wNPhI2lD{!-hY;CzqaZd>Vm zx#U+XB)5%f{4eaAL%;;q zx1Fyv021|I128BUfBnV3HzWVx__jDVk?hwBKTPMU7R%*C!MH>Z=HwkCk0ojXLlKSu z#}&xXH7H&S_Lu>wrf(2Ovj#v)hF9_7sU1l;IDy; zg+hpG3`I_uvy(Y(qFZFg0@|~SC8WG~#$|OZowc(hSz|I*h3mj1SS& zX_A1 zO@BaDXK_sj6+A{nv9w<+4=KpDs1qDBSs{4_#m(K~0Wt(cA^qQiETHuUV9EZ7LKLFP z{4%11Lb8A#-_|{gi--&ID+v?wD=Ue~Du^qo|DBlsz1mGw2+(}{UJ3g4F+v6A|EvwS zn2UZo;OOX*cESk93E{2$P^TN^9E2?3rDDtz;&)_k0G|=Q%JdpUUcMXaQC%ru@XVq{ zs&ao%M2oF2r+@}Y^`jqJ&ig2<$`lFc^Mg=Z0~xoT20#GTsygQfp(-ol$USs}KGfm( z^myXSRmPNtT@pg-p_1blL~y_y>hGgdP9eixZ+%$ac}kX6{^|1Yq}=B^h}+)%An#sX zrr;nUf|%WHlln!}NJ~s3|21kSNl|xMs<2Q^_5AD6K8h_l#PT=8evufMEM7@FA*q$p zOi-7vn>36mD>2eC@SW2ojOqE;dGC86PH^hIu|-&}4GlOyv15|#nmD1(I;qC8wziq$ zkjkC2kU~WF+5#I|IU8@rEL%f%==suA)6hoP7EE$-)x>OD*Y|MRo?FHyL5+%fVRl?J zXCTalmqXTTAdJDliWYq4X>9fCPh-x~OXA>n!Wf}SbfJtT!e2~qCNwb}hihG*BY-kb z-5PPQ`#|f3?AxG7C!#H>l!9O~m^W}v*y(qejMNmTV!2)KG&1UEGTO+53SQ9+5^G zQWS8jl{lx4mV4j?!1d4(T;P0QLqAaIOR~Z%sdhUbLYmsvnFHriKu{p)%RtNXZp$oE zMORn0uP}|X?W+Fhlw$6{5I>11gh;dQcL5o&@px$XsoK5siYPOOVuD-K)0xJJmjJEsccYI z`!hgpad;_CdnGc;cd0%mnJ?O{+qJ*Gs;ABzlMNK{-NFp(2O4m%kSjkP#2DKWWj}s~ z`DHK%O6wS4Pa>(AmU0|WCoNawMGktQR7Sq`7xNn8AG&smvP@P#khNsXvezN0VO+m_ zBNAnJ-Dwu$ob1f4t|j0c9GYb2E_S++gNy@MbUd^siN6bPP`)#B5*y2r!My^sE&M99 zK2->d%DW@Jc1q9cfN`;RT@nmv#0xi}JL;OKx*DmW+2?#V!uB=4ZgG_XrceU5v%dFN z-^%+v!+gfcP{_^Jh8@8Vn2q@^z?%s1uta#(N))d`EkDC6$cs9*k(So;JFU5w>b&C} zY?ypr>2Ttf^yzo$=5Z~-2CXBspf#te>J9PkX~wVYTo5L+DP~o>4kn#np#EBf z(Li9&B9o87Ym^+jOlhr^^AxfHv*z>p9opu>Fvsi`at;dhLS%&wGI!Ps@E7%O@{HKP zgj4Wyb#)zk`Sa}carAo$Y;>>%+Cb!u3d>0_%^zGri==&gyYEUg9gw5EP_OKz!xG|54OTg_7I6Y_xO(I?mW$PcNgHjd=Y=Gc4lTxS*?72xSGb9uj`a5O%128IsM;qG~^nFtme9@qL zYloayzCs!wQhYgfMaWLBrVD%HyHtdhz@W!fS4AEW7PgWJ4eO8L9u-|0w(F+&hCYDu zD?%~@i}T3ZDpz67iTORzxq{w$CgD86R@LGYrr{K_rp~PzCUcAEXg15Oh0jbS8&4-r zcLd|&0xjkfIYLc=|6I4VP=_9KBKnj1`*3Hg`Li5JII3qD`=t!siO6W?K3C;n!tC+S zR?q|Dp7hC#mc;wP6AT(TA5r{}j@U8MQ#kCickVtc&SKCzl?Qqem-7OP1broU8>m{^ zR>kP?#)Yq}jm=l7X{}B=DlRx}=q=<0NUc6+Cmy`e!E}-RaXbD`9ms!xR2O&2X%%=` z?8QUkm@aP2@#&R(Gs~3t>qOTR3uh{Pshgn3ogPE;yk6dYB8H`ENx*<%Y{!!3hlmDh zg_TBpf~?!cwI)`kH%e-q#+bs_zgYfaDHp*T0Gl}8FbujeWR;C7g%i4Z1XQWuSrKDd z#fCDukNlzos1lb7Y01TwC9QnSEqKMxb_dGQR@tl~*EF+zwcf4fJl&Q;`Lg6WLGNOa z&jxR@Ev|Vwgt9rk-Cje*j+1xhViNj^{3Q2yF{J`@I!d?UJT|+kH8hlfZnQg}MxU`9 z9mGXQWA`mISAh_XTO%)6%bTp=O`Hn($kD^scQ;Q~ryQQe;oBw&^glT)CV+a$|A`y& z&uA5Ex206b=xDT&SMB~?m1>a?H8|S&3CuI1V`iPcf{w8_!RHkmVKL@RHLs@V6Xio?eBB(nf&SkwkrCwt>x1?YP`X7A7 zpQ_~0C}`4V2KF`%HpY&CY2LqOJXz?NzPV#i6zad<|5g6^jm}_1_!pB5FeV15#QXyw zpK0L+5pd#1AsO`r3j&d+H7|Ut4`Vd)btoO*M#5M=2Xrw#=B^&SD#Cirb9C7)pLVQy z%#QYRUJ3c30hn>h&E0t%BKYQ8a)D2Mrk6W70lE^Q6-RCeoMUHSg|2{IJAh08fc)Q1 z@qgwk0z^-K`m?`kkpJZ?{z-FdNV6@TF@ho?1|2$~RaCz-^dg02T_k!i@5t5MMl{Cs zhRj5c5idLce&e%XZUBfXu-1DqK0igomiB&5)989X>d%)(6C+kwBMG-2r4sRF@N1HS zc)^gdDAB(DhRp0>51;ofYw8K);@OPk-e8C{)d$w$)?w_;38ybqlU5G(*h-Y^epszp zJbd7sRkd&79T==$leD-Yu>|b^Z%ybQb>KAiHT;BKN^>g;ehyKe=5Xc8sM()=Pez$t zn;H`lGtJ@0NFtDLwFPA}xiSSa$W~T9_0(|ENvqyOJ$Q zd_NOf_Hj%!NmSV*N_fD8JRkwrl>nKy$=d>P40xUHVABr!;G*fR8e!Ot&{`QRk&V~@{os=GT?^<{j^E&);q$n|BB=n$(OvljMX#E6t!bQ5Mc0-j1&z(Z|5mw04xn&S^f4uuqzz zrQTFG?3yT5g<0dmxpiSQ^*K&OGEW^MJC2EB6`jdR=KO7Kf1*qo7Mg;@6PK-%?Pvv6 z30f*6S8+{v@u=YA)fe06qj4n8_%Rs<^l1`4N|%}nF5uUeM=7tv7iG+ntFNQ@D;Zq% z=HPU??{fHJ@!nwU*zz#%<}`HaZ?JBp&5j%yU@|hW%50~fN>m&Acfen9t$MxLNt{`18(@$nFN2QU#L6;ue6^Z1ciZym0etWa0kueww+a#cb$mBz^DE z@EwLPqqVk#R>~lLaBVtv$E-C9Gl}+knhy8L+_iJp7oKKUI9ve}3$TToxh0$MbD=EY zl5gnL0^qgHemfCK1^S-?8PKqJGW;sS3WNg6isCZDii(7CQv6CHvI^4Q!xYW0atkOd z#gEVZOUd*v=lyNK@UIB<$NaT^<}B__9bYJP30$O*W`0ICG@Bp|)CaB~1i@?bmv4TvbW?_Ao^l-~NT-E%J4+#165W(5@Y zBx4~9$nSx~3iAo|5K@xE+>w`7|`m{i)j7Y&(z0a z1r``7N^QXspNh1>qz(|Rl;%#(_RjUuhkY%MxR0&~=<>=X2T_i~fPn`a<<&ZjIjW2$ zduHiD^!FVDV3(yusDB`ID*zz0_{}K)7d`hM2u1%43rX@|8>x}6$S`l8_GRMvxBa2I-Je zq(rGZQCN$$_x8B`^!RA znUR}9< zf(e|WCk%Ua9;+T}lM41c4s%K$#yWgvwX}u!UFAxkQiO#ZNRpNvW4owNF49K)`=_54 zFM0{ZBtB3!!hmMwKPEU8qGy!7qAFX7C?ly+2gHP^#wLhRFL8;xk%5L;>p#r^6J9{V`ZLpp^`3TR*B*SJU@m1#wXbnX4tyaj3hODjS$hDqrpQJOD zZa+3fs;7sjiVj#zOt6WifP4L7omOKL+Zr0VK>rr-iqK+y%bTjhc zWohTCuup5VWPYAMTj2S#esKOIlpkbxB>~pf!1hUFVj*Kg6Mzly7eiZMfbyOTM#|R7 z*}~c7Hc$kte-pZA0{}qss1lIacG8rxG1+#r=5rn#b{BD+TO8<0c?pFFc-zDef)jSQPE$oHAjAOy;j2E79dhl0!va@b_E4vBXo@t9AH_&6a}l>%-` z$7?J;Fzln`ihZ)O;*otD6`e%1><<;4Z92%)hVa>2ZrWr9kiMgE=lCyspkFFCwTXsJ@KQ z+_rTDl$|oYAcZ~-z?5N6NmprR9N5sB>y0M3Oi8_<%L}kNq#=rd*LTp-DHryn4)-4f z&rKZ&%Y+w%6=Gf3dg^gio@(E&g*=TG;=t%?aT)hvf!=oPDD4#2D$@=l%HvRm>JnV`?>vB5S`#sU^FK!yxCI%vFJu8uZUD~f*# zD9vC#zaU)$2a&YTg{5%EP%${>)G6cK^#?IVZ)DZ`0Kf1`3>ude_FS%}04(3)Z7PJED~h>+`0r_(uTw-1dFm*gpwkJq;TjNlI2sZV8PkUq59f%*!CYFk zRV&hHT@^}Vi%-W1K97S7(lcj1-#b8@An5T<#a2_N1TaL4b(8H6uiu?OpzrcFHVWmpANfSlLxy6+4=eS0tp#J+b&=ns>pOGf#R*jy&M2^lKGV&QHfu zHV*MV#&sq6`ki?}=L$wjZRg$l3!Kl_p*CUS5xS^^)Gh|K!ZCatKC-`+bA;t<NEzq?qrn6TXBatue*0rHijZ=acdt z7YZ}a+-Z~z0!=5|VM5DGZ9&gul_Qi%9byxuhT0GHi#u0X4j76TrD=Uwz1z_MTp?!( zoXNYlrn-qi9ogiBp}M$=@WiM?Ld~}DN}LTcgFoeB2b7D=17rk_0l(|$fkT7VkWvB2 z0Nn5A;=rTfC`hRQ(~jbHF198=`DDawP3#<<04DeC>ELKYKkvDF?_ZjrC4~QuU}mxE z@ukUVrjsiN)(9`WIX|bIR&k}sQ#PRJdXAI72n)cVu*73-F4TVfn06LfK1=IMrPhY~ zGz%&1s>)ERn2x7HS?OeQ!_1_m82LGcm4&A|&gHPqIDmG$wTwZ<@?z zNmGgX1lE^s?6jX%TG=-An|xgz5E4hCb{K6Wz3lhbm;Y+F{5Gh}$)venIL6{^(v`p` zqo6?}Ldnc=X0os$QB}|h{A~AR@0v>ZnLq|9UR52RA3C%wgTmJ-I84M=QxOgyQW5t~ z!H`o~>iL+LWr(jKLc<7y*LPH=()uF7jotQEaHMUU8Le1No+gx8yp6^C93XjD5o-rj zS^s;25xEu2F9L0{JBsZ+$d1@8vtOF3!`IxUb1@67RLK^UZgx*#$vWXlvIZ?F1N;%k z+bftioC9nJ$mgP5GQKQ~zRZz%?1Ncg95>E2SsCi4kDY|9h{w)>Y}vCohbEU76UVXD zs?8h^;sDfHb`SO-aK7Ky)-<@yC(X-u8q3t?*?~y>=Dp@m)A0>t!bK2(v7)L^9r7+awFRFyci2-mhVZv# z^rKmsh*?$U@|&ml(PDOpLZ!+S=@kdC+d!Y@pxGxihli>A>72LH@vh2hgf&kzCVn35 zJ)38Crpn(^4L=oP9@wP7eIKx5KhHzm3@mR=ZBjcm88bkt4wq_(V1yhG5~K2pHCIG+ zyM(V*8GM(5AC#Nfn1PgRfIJ>}K8B zEqW#Ir5nWd`pgLt5z)m_*T+qaB7{>~YIz@~>dVCUVmq7Z{X{lO&YH;&|$PeQbNeXSzZ@T9wm4f)Ck6<1-n+up<)3#l-{X!52IJZmzJ_ZWDj zXz=!MrX?{nHo5yc*%I_cu9tQ&0Sy=TsA~2YmqW(Y<8QT|hifZfv9?KMxetQ$D_02L zaKx_W5_<3{mKZ~AW7G=NiE+H(sPs9K?DXw+xlWE2i^VO#b)>=-yz7N@0un$uJlvXU z%qUFAKm8dPVHXoadjN3i_WdqIK>Qim1{nWju)L$}G(!EBDjjOCy$MB31A@jx!()?s>Ue%)) zI*K7lSQuB|{WZLFQN@&CYg@M2 zns69zyx%Y3{yLQ1fD|A#6GEMp{o-idz%9k!4NC54|0R-!L10$R78WCJwJw-;I4SQt z6iAwaFf{CA#h{s1Hag01wVPqt?d5zTs;)!T&PK0#m9o8eARfRKyFFMjkVWcFhHwZl z;_`B;^vWV~_iidY0wnMs2RPkxtQjI817#KzXH{>CJmLofs*AX(#nrFlE(whG7kYtqk5se z5|x@q8WL$BUNHw}q)uy`HY~P;HNi7_UUsj7+h@zQZ&2(Q?Jdqm) zmxFc~sj!3`&k@mrQ?>&Imyd}A@dARX$AeY>56k(!%m@whPR@TR?D!iD+hg=G&Gk=q zZ8+kyknMhw%fxdZlIwLA^i7ZE9bDrR(roruLBmFeVgCf?9!7Vdu_fKz7i~ zihYS+TILz`1B)8rMBXjXaYM=L=nK{%pO~oHCLcjjO)ggCd!j*61-2bXr35i>5u;Ge_iGs-rQt>HULO8dv%O+2ChD7IYGIWT^4vK zjY{$iAJS}xmq3}4SWzsQHs>#p5X6@FR34UhDoo0b)pK4NdDg8WOGoC6Ix zk~Q&{0?6@fWZr7)QHdNAxQDQ`bmRTeHHaW3X4F)(pr<$xbp&m$*N!?}!2{!dLd%ea zxl=)L3h>7(0%%_%XXz?K7n;LHNC_Y*p*bpZ)0lpQ+(@HI}CD$U^ur;2EMWm z>W|bq8_X8gTJ@yRQwL^K)Gx~JoN?;$00I8!MOSU;7`J?{Yc0EE?N9U58)$xdKG>xa z!pwK=<1h%Q5{>{vAVn*&9MH5k2jVQi@!mFtMu1i^v^KSKG-1YN!v0|aAfNz=4(&|r zfJpO4hT{&{z!9*8goGYI763^3>gWnAmv#DWnxjoHds>VZgw&vpSD!YTSWbG}E^1EL!%1=~ZqQZ50 zRIwVY&4;TUlRQ0MS{(Tt7?Kn9LLtliC?!rjh_cu9?fMWqU8Ekg2_T?d@=amyTTlB1S;T_+k)kPOpyL1#(qn+_$wF{vn^8W$|rr2 zsZSM+HJC(VBCzNYLoftWo#Q~(6eHCLfhUplw1hsf?;sO~y^nG)JWA#1o>9d0p*FG= zv$C-ePx$-&{kmwJ2{!1(<{l{DcVdbAgT95NE3iBM-;X6GKzx8O`u}d_z+lU7GYsF5 zKjhMS5027Y@0$hZZ!_REJzHHrt;pN|F0C8ir6FO3{mjbs=qh1@5BVKtCcJ5<`io4g zz~Eu^&qtV7AV#Mou&N&cSn@)RD+=Pt#dv)UwnlmumHG=bU_O`D1II$M2csV^1q>w* z-hiVMJVKJeS!tHv4*}dfIo2}+gU<+2GraQPJh)!N0jamkRy1;P=6&_OkNkO!tp`c( zIbrsC)rWZI5?TU?o7d7196P~zth85a(`sy9IC;|My;X%1^#j=nVS63PEm7YH=179b zoO>boEQ_cUhV~k?SFiQSi`ky`b&#rN;H98+a;E$6g;>8v77XzMJJA7Cpc*W9$U^4s zW4%TpXWzYS>Nen;^TM90Dw=R{19v1D;O->)Ot;BU^gWZVPD%W#0(^Scz3KN^1_n-~0jEB*dLAenk^eY;^&a?cxvD zy67k|;M4j74a9Ab+A-&znT@P6=!7~IcJ@n-jm|S&%(ll)OV8oXUm07rBt5s}2TsCK zOItcc45xs&B*)Dsw-|h9GvKwRsh?cB_nD!uWd=`^mv-m~r!T>Z(imsta);u4z#+{y z;hN1XNIrG%vf2%n)xOCz-}L~`X%F``ViyS-@e6f0c{*$P%Bzud*rpuTgV3KR)DH-x zJ`YYPP~G3Pf5V~SsM%V00G#dql7{?A75BI8x<7l#|3Tl&1Dv1PIa>W4$A107JJ+%4 z-C;j^=&2Q`{Hm=WbdwFGuJ2cE`f9CSCH;~-mVCp|I$PwBaVD_j^BD_`Y-}!FOB44V zP|Z?aW@%2Zafopls*l9_JkU8qa!$b7cZFW{DXoH}a3B<$Pm+dcQjWkP24``Jjpt<^p++g4du`DB zo|fwGVP;j*k2MX&3qO-3?~miOTR0rLh#^eYNd z%jS4mBRIkg+PS}kLXV|O)Sx(~hf`p&1kFk{pqTirKy^?xL{Y5ho77K9`2(@k_kpDT zn^?-m#PZV`rM<_}Kc@ZuYZLvyg41GDiMSNJi_e{c(1FDAUzh@NpvI1#hZr6KDM|)F zx_Wm-KvY8(uZWgG8ib5=7VR-vmWWa(hq|HrV2BJcp_TZ&b)Z$&**T+@-)GG+AWGNa zFlgCpK^?RmX1^I2g{1}w1j4Dm--FfvPw&$|>k5ClPk}Dh?_$=i-`vi(ru-00GD7f@ zOw0sGxCvcAy+2>*m__vu=~xxTZ#4>U63e8`r+GG}>dvM4$;<=^(o#-*Y+`EWhs7!J$pIn>5gjkhHN3uw6P0j-`ExX)k*>6 z7)&XH8K`LNZ^aakN@ylV$IPPf#M>m8rWhQ@x{c?zjon3kWQ@teLm1cusAZKSX$soc z;;F(L+qHqXxlLJi^Aaq%qet<18W>$`Q6rls+}j}Oo8{~3ti8F+l@!wbe5+@eGz&vz zJotH`i{egtI7a4T8XIu|!p*|dhlVR1xqPO%x+mD5!uq4J#HdqQT)>z=QB(9;fo;_q ziTQG1Xpx$SPx3FxQ@%MAL}-!28kEbaCLD#*`f!#oqT!Ny`aJ~K%&q!u(ly&+>$bA` zX7#3v=ZsK1H9EYxbqEN;?~WAtS*xXGW-r)P%H4QL$W zZuUKo#0^OD=xk9$wU|ZH5|8BGqxeqRU-!npO&BEaeEOP+p?6&TY%|8?>S(BOG*o*C z>XAWnAbY)@*^ex&D5DrIH3crr#!BOio4X+#fxwgcm(8lG%!~{y55CQ2 zqCpASS{XVT-aEW-Xph9`Rb9-0JXB)B62w9bDh&5iir~@E?=Ssul7NQj?c{;`vIKB6 zg8R#VDL4QUrvWLZU4Pk-5|cvxw)YVsY+hR|DmXc=UCx^G|$gE z^9W>(rn07Ai7(=}xOS{djB2CJZ@;cKmE3;(Qd%Jd&f9udj>QkI$^$mdLMFw3jbR_m zK8fh+RD5_~G2oxi>i_ccZ!=B6<^S%i=9nIa*E@QCg6%gRpAh+=*O?#0Dg7ndzZtz% z;-eteF<+;fm}5Re+|o<#Nn(eAmMj99WVl}DCjOag@*1?wG=WWkQ+ojddOe z|H)~^-s-X+)Ci5xwkhnYO!D@#*2gx~b!MIPJ_pn8fUyzoy0J<(0o&ym-jt)4950sO~gnRU$sL&GWbx z4sJtQbJ3q&Ml=x>&g^yejW!7Mc>B;dfy*q`Barhb>(C4+`Y)f?x1hdvo1$r7Dne&E zgjCJjIWvtUsC--`nO-6$GK|h;$aQ0hvtBG^sfFA)jUI~4MC7bbP7Pb&kQ3&ygr>!OPU;P_2CU zST1|EiOUN=GnXvmC=fHH7}HB64MV%WoGt!((ue{Z7%tfB`1U1EW3SW$F>=9?$Qti%#nT^m+3s)=4oDtZU%0fO{j`TIgwTT>x$eso@k+4-#{@3GV zT$U0gAd}hEMda6r0tEz36G|QMdGn>5pVbt}AOYeDYzp+zWj&LRamHf?APpU$og_9R za8O$z9Z}1w4=zaG=CJ!5IRHD*b)zQS25d?Hw(g{`A;?&ab@- zKfxnl{(19X!1b;Q4;%qsmHu|LkP0v+`x9P&@&Wvu2lrcX0qINe^glYqZ_ewSeEGN-8t34RPAQ;Q{{YO((~BN&x~b9c z9d-a_(09`}Fg>cI{u}Qbr3B6tY&j&UIFY;Cw$1IYxRT|@dsE^Si@QXtNxiuwc9e~# zQ4{p)nUjPeFI)=bT zyd@^>&mnS_iP|Efg^w`sH$gSJQ@(6LQN>D2Y_Tqa;3EZAW&UYmfHwKX$aw zw7bTQnbT+Qsj_49YLir0)8d+$&2Y=i3gHLW!-*8lnYznG{eL1Zpf31LPPf%1;n0Z0 zj;wse!?o1Ab&hPRq5ksyq43I{TbR0D+DlaeIfRI_i4pq~<=WWO>c92zh-LNy{~#%c?r}-4XXI2?l;xyp^x%W~Zg!8?xi&5V5c;9AB4EBBDw> zI43ggM!*W4YM;S`DVD(MkSeQFJQ#Prucs?l4pCAaXL)U3f-^y8W6h>P2BZ4e%ATIK zEUG<%wJ323%Ipcw*?77#$M*NScg#G}ljx~sy||~k`rn}&yby_|0|~2tak?b`t*pg8 z)*%r7k_B3oW~v;m(7RF7OV(g zjKnYHQ=F&1HnuNID<5DL^tMT|%|;Uaw2GGTLRk4_t4pvmT_F-dLLGK}6kXxSg^okx z{QmVvpV$pXf~rE7(AoOzO`efdY4OoO9PjpQRQyC6>66*s*K({3!CZnaKImS4s40rQ zLS_xG{0vp|t>uYUGLWEm`kPp{uiMqA=)n96a85H9)l|TfJ)tFUQZG0n$htI#6dxJK z6c^#X3BnEerr%ttXqz_%H#FtoLsWq0b*f@ZqCZHxHR+{WKK-sob`uhG?m*+RgVg=< zdmmX~;&H8|66ol&=^fPUZ@7UM0eFpXl22TrSVg2>-N4s=zl(te-}*!k!SKK75#DiE zfFm&cU61fbP0#PWqSz+@!PRNG_L-U;@p-FVR*Cnr-@LusTIu-?7u;4uUe7hbYM38r z@V^>`5enR<5+Wm7cf=S4#l6t8C#@RH;#wc+mhX9PL(${eTs=>j0T;64&jERT=-{y5 ziN9laZDd;fQV$4t&?T<6haAHv#46=X;OdYVYw>jQD-%7*B%G_VCFo;^lPBGm3e|rMLTR zL>ELe)|8GPIwu#B0>vVEH@F@-30|g8a8R2yu{HSTAjoAzrwU3edAaUKzZ3NG>16wS5tnKv6* zaNzry;`BJ&tjBb|ZuKS&vmf(M+^W?EgT`69+{$xf4L=OSsFdx8U1Ds!MBK{4eKsr` z+klS2XOteo2?b(`x}oW+rP2Z<$ zA2Ly@i7GNIp^6QEHc!pA9)ENxRgH)Agkv91rP^R=E&jdXo}8BzHP6y{o*_MDlsm9AebHPGjuOGiwx zaeYMfbOZ3lS31Q#Yo(Lf$B(u)s$Gx=C1i9kC*+Ai-V{@S&7AEhGAaaXvc7_$*5Sst z_>ye`o|cazCsy=qUTczu_%X+ZqCEm>k(=KxV)Jn1EEF2zeSzY=*OwnvA2K+= z$}`8u5qaUkA40e7Gy|tmYLbStcY+K76Hy9|g=2D}MNSgUMpt!aPJn7N5kZJP-xZs` zMjAZjf!J!fva`RB)hvu>R!n{%7WnwGqu*=Fi2wUhH~qxbB;cpGLT*j1zz3!lP+WHv zJ}_v|LXH+5zzI3`eI!7Nc@<+jXJ;o9Ak)nssTDL73A-QNwYReTYi}+1gWlSIAX<9Z zl|M5G}u(SOkn-U4rkd!$F4}*zGKYc)=s?#e#SYVoK5%ZDI2y3I)46v?_VejVzSNAq{aw{iEoLM3P9COS%1DB2jna7wza0)@5cg!Ep_L3G=&< z(H&yh4>l4ZX9H8G1dXrZv8NHRt^AlC2I`$P`E5bP#vtP@-S*Rx27U3%;VwLIUf4Y; zW*rOh>J^Ef@(R7x20{15E|6%j5>HrJI62svnI6axn8Lo((r{>mLh``jM!y_}bWfBG zj|P8xBQQIrY-r(e9~=g9gWkRhw2pzTw?DFCz^*8Q;yv-m55DY~YqDSo!}H=y0agW^P`U_ByRkLB816*&P@Y3KE3x&$R9+qKo{}3nT`*XvF-A2iRA8gM5S2fvG##eYk$VWx4A+ z4Qi~6?<4irEPKa#L*ITGWUKB~I@|%DYbf0f+UHOa(zNx;omu4c4tq35~;d@qe69=&=_~<1*o9nih zvxOVa$>v3@j2hIgb~{?E>mrYlqF-*LSzDx@yGb&MO_i-8@`@Q;vLq={wwQGeFw|M? ziud*szp5kxEJ?yN<;fQv1&VV7?R^~bmlQFRcce+vX_dvJiqIkPtSL#E`?R7I*a<5x zZ^NJZJrQf(i&aC2H(KcczD}ot&KP%Dqfek^N4G1jLM(MHSBtEssYsn~#IE>8>S^0y z;mt`y*$&4=Q^N^7_qUHC!i3?oL4#;t=9*W-4H}}T)JxF`(&4rp_C}CC@D(LxOSbZU zt*AvLk!?ru-&f~3o5)$yuCIb1QBL$ru=p4w3-}TbPH*oFwi{`NK@FVm);zPUXsIUt z_Ej#Gp|AaDXHGHQ<6?Z3HG_&EviXB@tq{n44njc-hkrmoJ zAmG!Z%19r2Tdg!-Ah8*w^7GV2-tO422d5Tj7Ti@u!63j$SzBA!+F3lz>H~*=7#o_| z{ZTB2fc+!h^32c`KrCrzZDL_-=JXG?0Rq*ZxBSkQ1N&!N4(!&J0|VM}V4xt4x=K_s zyd2NR0)|@&THk+YC>ep{U)9}QEQW2=0OQ{>He5bJ4lpjy{aWfY=Cxf7UjYLGtLgim znkFnE6bsw$AgrpU?hz6Fw7yynn(kQ79+Y}`*mWsO#+6PdWUuX~knpB3@C?VtA#vrg z;I9|6!l(vwpGzU{k0P(xh${G5R!wfdf>Qx)ib;-lwQaeavU;*57&h(6s1Ny(&IaXp zyQ=NEsO)%h-u1YnzX){t4hsKiB(A16k@?dP5Fm6($0F4}DLBq^=}vRlZ9=_l?sF$b z??f7_Dc_I`e&bW_Ws<1w=WnoF+y3ZpuO}R-K=JyT`yH`u^EqbBdxWAIJZslSt54m< z`BjJg3N>IksPR(KViEeL>F_TgKf)yP0mK(Sy|-ACiw&icXM^V-L7!{>P^b8^?AavF z^gM1@pFAF=%WM_Qm-0ZSMiiv?p@%`y7>-`qpNEdZ44Y0Ynh~PlT{IvXl1l zS@MmZd@@}lX@C?oenfK2O5p4mL3heU{c2(x&o79+n{QpN@(S0k2>{LWbYEDE;$n85 z+_CEnq>{wFb=^zTNID(Tj&FEtTEaNBhs@3qwXf7St_D8d{$u?X<|7BJ;Uy>qNg;1` z>D=(6ei=_86dSX8m=xJf6r6Hlzr~9<$jNiXfwqmZ-ghr%Ff+EWVk@59k<&)rs+xb; zw0FZnV9?;?0ndn~0l;E(_j{WM8V&yE3&bL~b7}tU-oK@cQ3Dq1sVb|fs1o0$u$dW{ z=zjViRxw>_rF>{NQRW@Soxrs~GFoE*wOq)#Il zUM;)|2XBBx-`5!aq${xYxO({OWQ6-lZlDi+@~C0gm()e_c;gaZrra9)wcc#j^y9Y- zIx3a=)!r<=5p3)3?jZl_?EZ(phX0Pj@k0e*JwfVRfTOo z2TN}PyEq)4HN;o6e>T#w_+_GU+LMC{g;rvotEYtDA?2Gwr1B^5Sl@qFOq^^p7o1>O)!e7H60-j zdmq$LDUip7JO`G!hbo)sb!-J$q=y+e)L^#u5iMg#J77Y#`at_;Y165cl!qSVExVdC ztkkU3Q(WKYPqvhvBOOzCS^zVyMjJ_4p7c3GLJxSfx2+dR^(oikrzj8KatW*TR zZao!d5W$tLIV6|R{0>2wFi9aUt>|C1)aF)yX@;@duMtFuY&^YV)C5FThFzT=Di{cI zt_CF9q9fU4d}skg<p=(jOLu6pla;{p0u6k_kACuHmBdQO5^WL{EvM_takF4mU zoLd!3>5Qem7|U5V)`oShRX19daVAKbq?m+(&>T%cLfTro?A#}c`|{IRcmb?}_mBUp z?Cy;Pw0|}h(4ha(SOAiA-Jk~NP zO9jJCfy+IT96;n(PYD}47Q@s9mxfgO6r$wo6Ym$Kd1-JFktKUqT;!%-^sb}IqlMfv zU=4<;iY6j#j;F;Yk5Ym-0k1&PZjW!uU$?;j?D6Gc;`+G}SpFo$_#-^{-#y1u2;5yX z-{jX$+i;TgW5QG_i3A2mvWU@asJZ))y?MV{xpErMJuxUu)6)U*t76pjJq!ItE)ueB zfv5a3Zq;FZmL5^w?yOI0uI?CDy_~kr8GUc$f?^%Fi6Du=lIQ7*a0&Gr@>dD=DuMGs z&gh+HnGojO%Q1pl1k&;&BJn)i>eC?hgUX*gz00|`TbRFzoxL*{LDK}I^&4W7SZ-X3 z1K5C#(8cHHZ!ZO7OL>{f=W^Q=)qY}QXhH;UU|p8jtF($HpGzC|9}^R2NwN=J0z;A# z39hqtYBt$56e{hXR9y~b>?Nt97|POAHP5xhzzPOa$43Ps1$BZ{fMs|sY-nu$T}JgRX+2Vc#w6f z{qn~`!$k8}-l*E3fyj+-^ix-lPy_wsp!k{8yIB;HNEbywJWNW7O zPOBS%?c1Dyy9@&WoZ%Lo@O9n`R^m_A1x3j!j+n<3YL>sFln=;Z|A2l%bW`nT(!+roAl#k)=U9W!pXiR|&br{OMpEv2ND5tv z;Xsv9rpkBNOMIx!@>fCKtc;S>Wfs9&kLvL-PLiQ!k`IzM!qMX$PL6x+3%ZxFavmA} zfjoupd7aPaxi3me-t-iG7Mg}DrIrmePf#E{6kAz>+87rdr)CH+B{n2Xi3LuQx+`Kp zJzgVwn4BVFht8FUO??mQ;BL2|qCY}3S1MkA{j4W14k?=>l9^PZ0~Th__N!akOu%Ij zajFzf9jbWcg_s&3^N;yeB9`KmZ#1vUbK+#4@JN4EH1e@CXd5hPItePMu}WuASMo?p79t zCY{w*#8iJZ{qNz38n``Ke{63Ay8Gt|IU3r!1K;qYus{On5K|M2cgH*b<*~m_h<1_b zIkm~ypm%1UtS86Wjx&i7@_sU#Gg-ln@Eu?p2wW%bSU=&Oc%hH$rET+;Ng;^xEQ?60 zr6(0G?g;tRS0sqTSSixuwf&{X)AuoH2c6>9LH4@y$Dnbfm-0+SKC6_*+Xp7RuNwMU zjju7|Zr(Ip%@nq`zYu}1o6^kBR39ZHvUjgo;8H~dxXfV)y#TGy+dqr`a#LnfiHM!0fz z1?R*nB@?S?t1SWh#6w6?iF`*+Mb|_yt(bDE%y0Dash{a2?PSTRKaM$QFB5dQaMa9v z_w*1>w}eyI^0I(0_Jbv}_URA@slMI(ZytP6z#z_jFCrQuuz2Ry=(-Eaa4~V*?pSy< zrrQ)9umbV+8iOssnNdVhg&4@fVqt51N7e`A;52e4b_AFL9B*eI{K)hFcq=BAF*OjJ znVt~;_1S+W?(SayFZ(%udkX3j>qLaV_t?OVQ>0xm?K%i7wQ8&`H6${4yx3t3eHy=1syoL2PKe_Y0TS6 z5{)nxB<4;>X>S5#`pfv2WEbN66a`=-fz9db=q7%y`vK4W+LC{IL zmMrKdmC(_Im>zYV|z8wV1#pS@fKX9z>4uSP{CR{0+O zAk}02I{ew~90-zc6Z5loo%yx5%DU=-a37RkBHUM>-l5|8Ym4qI z3mag?ztt`8o27*{z|n&EHdJTfVFPgf@s|)ocP7Jq6)HT!A62M8l)KHh0*RK~fmBy= z07ol;hs7WL{Rl+&)vABR#=lRAwRS3y0I5V6Y^18^0e^}O9a!#D;ROtVSiLqD;cArm z+Sy|g&i8^r)lZp=3tC3zLol>!=+IlnMA;$l0=^arL9`QJzf1)|@@f)Ucgvn(x*W* zFHqkgBweK!nP>=g46kLsaoInyOB!H65LN3Q_^u0u<5E<~~vf9OHWj9k-BlZ#}}JbNmai(q~~}0cD>-7sV&1O5dJVX@@3AQ_0S^NZ{Z80zXU_|wp5 z8EWr0I(=p=O-h2%LlU)iQ=bnB2obWi2qUM)&Mg@YkFWMsErfzpK9z*7yTjE zpLz~B=o#1+N^A&Z3j+=#_W-Ig7hv(IovpR|AM}1`)PF}y0Uz`?Y8IM;>Kqp`5vH^ba^x6+{523~)Y8un zM2zrF@Ak{Ls2Y^`x#o;;p{!O`}QYpPkcBXg!gxWFnK#wCU~`lY&f z3YIQZy*1hnKia-?ui}PRTT@KIWI@wmbW`tm_oDhpYlHG-7THYC{%9I`!1~a;F0t;Y zWDh7S8kDReI9o{`yM;*<9O19A&~Hyw^warIu;{idO66H(jh^k+f81WF^_O8L{WZ{l1oFRu^~@{kpE`uwi8cDpCX-~FfvS4o&-zZY5hE3U4kd$zTW_NJ;lEJxZQ- z?fCq<_6d42`>Y!YyYgp|)&H9D#pPi>Aa2C~noGsGjSEzh>hpxfxo;An`ns`xd! zCLTXF1}MklRi?(c`)ut+gUo3a?>c?V3jmWyy4H?SHO$>(lwo=kN$TS0^_aKs?2Gdx zzGp6^+NWkY9+tM3&rCB*E#gR^i43`u+BRP*3_|_i`2+TrgrIKx(Bun!$vLLvrfy%`f5Hm zHvKi0!gO+usHPN< zLqv?7?z;Eh-TEeP|I?_(%<{Ll`afx~|I+pbqMDeK_M5QXzDZL|w5^LE@g3-m#=B*2O!8Q95iw#3J8H0AtQs=QSz;!-wGlhYovQD zgPVoZWh5IGJZeyj^F^Ykc{{{csbhu{DJ literal 0 HcmV?d00001 From 1ccd5f18fbd5f427c6edd6ca641ed132211e223b Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Tue, 26 Nov 2024 00:03:07 +0100 Subject: [PATCH 030/130] Update WebUI --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 384b431..5066032 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 384b4317c4b58afd981f410a9b732700e733b00b +Subproject commit 5066032a55b5436ec5c888cf0eb91bdc9e71bea0 From 9f3351f85bdd8c8e0d892db3d2030f737b107065 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Tue, 26 Nov 2024 18:07:47 +0100 Subject: [PATCH 031/130] Add Forgejo CI action Remove report action Fix release step Add platformio and node_modules cache Try with less targets Disable more Restore all variants Remove verbose and feature branch run --- .forgejo/workflows/push.yaml | 171 +++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 .forgejo/workflows/push.yaml diff --git a/.forgejo/workflows/push.yaml b/.forgejo/workflows/push.yaml new file mode 100644 index 0000000..81fdc06 --- /dev/null +++ b/.forgejo/workflows/push.yaml @@ -0,0 +1,171 @@ +on: + push: + tags: + - "*" + workflow_dispatch: + +jobs: + build: + runs-on: docker + container: + image: ghcr.io/catthehacker/ubuntu:js-22.04 + permissions: + contents: write + checks: write + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: actions/setup-node@v4 + with: + node-version: lts/* + cache: yarn + cache-dependency-path: '**/yarn.lock' + - uses: actions/cache@v4 + with: + path: | + ~/.cache/pip + ~/.platformio/.cache + ~/data/node_modules + .pio + data/node_modules + key: ${{ runner.os }}-pio + - uses: actions/setup-python@v5 + with: + python-version: '3.9' + cache: 'pip' + - name: Get current date + id: dateAndTime + shell: bash + run: echo "dateAndTime=$(date +'%Y-%m-%d-%H:%M')" >> $GITHUB_OUTPUT + - name: Install PlatformIO Core + shell: bash + run: pip install --upgrade platformio + - name: Run unit tests + shell: bash + run: mkdir -p junit-reports && pio test -e native_test_only --junit-output-path junit-reports/ + - name: Build BTClock firmware + shell: bash + run: pio run + - name: Build BTClock filesystem + shell: bash + run: pio run --target buildfs + - name: Copy bootloader to output folder + run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin .pio + - name: Upload artifacts + uses: https://code.forgejo.org/forgejo/upload-artifact@v4 + with: + include-hidden-files: true + retention-days: 1 + name: prepared-outputs + path: .pio/**/*.bin + merge: + runs-on: docker + container: + image: ghcr.io/catthehacker/ubuntu:js-22.04 + permissions: + contents: write + checks: write + needs: build + continue-on-error: true + strategy: + matrix: + chip: + - name: lolin_s3_mini + version: esp32s3 + - name: btclock_rev_b + version: esp32s3 + - name: btclock_v8 + version: esp32s3 + epd_variant: [213epd, 29epd] + exclude: + - chip: {name: btclock_rev_b, version: esp32s3} + epd_variant: 29epd + - chip: {name: btclock_v8, version: esp32s3} + epd_variant: 29epd + steps: + - uses: https://code.forgejo.org/forgejo/download-artifact@v4 + with: + name: prepared-outputs + path: .pio + - name: Install esptools.py + run: pip install --upgrade esptool + - name: Create merged firmware binary + run: | + if [ "${{ matrix.chip.name }}" == "btclock_v8" ]; then + mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && \ + esptool.py --chip ${{ matrix.chip.version }} merge_bin \ + -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \ + --flash_mode dio \ + --flash_freq 80m \ + --flash_size 16MB \ + 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin \ + 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \ + 0xe000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/ota_data_initial.bin \ + 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \ + 0x810000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin; + else + # Original command for other cases + mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && \ + esptool.py --chip ${{ matrix.chip.version }} merge_bin \ + -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \ + --flash_mode dio \ + 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin \ + 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \ + 0xe000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/ota_data_initial.bin \ + 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \ + 0x369000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin + # Adjust the offset for littlefs or other files as needed for the original case + fi + + - name: Create checksum for firmware + run: shasum -a 256 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}_firmware.bin.sha256 + + - name: Create checksum for merged binary + run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin.sha256 + + - name: Create checksum for littlefs partition + run: shasum -a 256 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin.sha256 + + - name: Copy all artifacts to output folder + run: cp .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin .pio/boot_app0.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }} + + - name: Create OTA binary file + run: mv ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}_firmware.bin + - name: Upload artifacts + uses: https://code.forgejo.org/forgejo/upload-artifact@v4 + with: + name: build-${{ matrix.chip.name }}-${{ matrix.epd_variant }} + path: | + ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin + ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.sha256 + release: + runs-on: docker + permissions: + contents: write + checks: write + needs: merge + steps: + - name: Download matrix outputs + uses: https://code.forgejo.org/forgejo/download-artifact@v4 + with: + pattern: build-* + merge-multiple: false + path: temp + - name: Copy files + run: | + mkdir -p release + find temp -type f \( -name "*.bin" -o -name "*.sha256" \) -exec cp -f {} release/ \; + - name: Create release + uses: https://code.forgejo.org/actions/forgejo-release@v2.4.0 + with: + url: 'https://git.btclock.dev' + repo: '${{ github.repository }}' + direction: upload + tag: '${{ github.ref_name }}' + sha: '${{ github.sha }}' + release-dir: release + token: ${{ secrets.TOKEN }} + override: ${{ github.ref_type != 'tag' && github.ref_name != 'main' }} + prerelease: ${{ github.ref_type != 'tag' && github.ref_name != 'main' }} + release-notes-assistant: false \ No newline at end of file From 3b47c81cfe06028fdc12e583e4d36b23b710a2b9 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Tue, 26 Nov 2024 20:50:32 +0100 Subject: [PATCH 032/130] Webserver dependency update and testing new CI flow --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 25e7d9c..021a03d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -34,7 +34,7 @@ build_unflags = lib_deps = https://github.com/joltwallet/esp_littlefs.git bblanchon/ArduinoJson@^7.2.0 - mathieucarbou/ESPAsyncWebServer @ 3.3.7 + mathieucarbou/ESPAsyncWebServer @ 3.3.23 adafruit/Adafruit BusIO@^1.16.1 adafruit/Adafruit MCP23017 Arduino Library@^2.3.2 adafruit/Adafruit NeoPixel@^1.12.3 From 239297c26d586aad885c1598947baca4eebd4950 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Tue, 26 Nov 2024 21:48:28 +0100 Subject: [PATCH 033/130] Add own badges to README --- .forgejo/workflows/push.yaml | 2 ++ README.md | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/push.yaml b/.forgejo/workflows/push.yaml index 81fdc06..b48a34e 100644 --- a/.forgejo/workflows/push.yaml +++ b/.forgejo/workflows/push.yaml @@ -1,3 +1,5 @@ +name: 'BTClock CI' + on: push: tags: diff --git a/README.md b/README.md index 5dfc0ad..81890b4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # BTClock v3 -[![BTClock CI](https://github.com/btclock/btclock_v3/actions/workflows/tagging.yml/badge.svg)](https://github.com/btclock/btclock_v3/actions/workflows/tagging.yml) +[![Latest release](https://git.btclock.dev/btclock/btclock_v3/badges/release.svg)](https://git.btclock.dev/btclock/btclock_v3/releases/latest) + +[![BTClock CI](https://git.btclock.dev/btclock/btclock_v3/badges/workflows/push.yaml/badge.svg)](https://git.btclock.dev/btclock/btclock_v3/actions?workflow=push.yaml&actor=0&status=0) Software for the BTClock project. From d37307cccfea6b35dfb149b6e3d5248d9a8460b3 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 27 Nov 2024 11:33:12 +0100 Subject: [PATCH 034/130] Add Mow mode notation and setting --- data | 2 +- lib/btclock/data_handler.cpp | 4 +- lib/btclock/data_handler.hpp | 2 +- lib/btclock/utils.cpp | 25 ++++++++--- lib/btclock/utils.hpp | 1 + src/lib/defaults.hpp | 2 + src/lib/epd.cpp | 70 +++++++++++++++++++++++++++-- src/lib/screen_handler.cpp | 2 +- src/lib/webserver.cpp | 2 + test/test_datahandler/test_main.cpp | 29 ++++++++++++ 10 files changed, 124 insertions(+), 15 deletions(-) diff --git a/data b/data index 5066032..d74e9da 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 5066032a55b5436ec5c888cf0eb91bdc9e71bea0 +Subproject commit d74e9dab60772ef11f9b033cfe982d216a9c95ee diff --git a/lib/btclock/data_handler.cpp b/lib/btclock/data_handler.cpp index 7b63db6..3209811 100644 --- a/lib/btclock/data_handler.cpp +++ b/lib/btclock/data_handler.cpp @@ -67,13 +67,13 @@ char getCurrencyChar(const std::string& input) return CURRENCY_USD; // Assuming USD is the default for unknown inputs } -std::array parsePriceData(std::uint32_t price, char currencySymbol, bool useSuffixFormat) +std::array parsePriceData(std::uint32_t price, char currencySymbol, bool useSuffixFormat, bool mowMode) { std::array ret; std::string priceString; if (std::to_string(price).length() >= NUM_SCREENS || useSuffixFormat) { - priceString = getCurrencySymbol(currencySymbol) + formatNumberWithSuffix(price, NUM_SCREENS - 2); + priceString = getCurrencySymbol(currencySymbol) + formatNumberWithSuffix(price, NUM_SCREENS - 2, mowMode); } else { diff --git a/lib/btclock/data_handler.hpp b/lib/btclock/data_handler.hpp index 2d563a4..f8e237c 100644 --- a/lib/btclock/data_handler.hpp +++ b/lib/btclock/data_handler.hpp @@ -19,7 +19,7 @@ const std::string CURRENCY_CODE_JPY = "JPY"; const std::string CURRENCY_CODE_AUD = "AUD"; const std::string CURRENCY_CODE_CAD = "CAD"; -std::array parsePriceData(std::uint32_t price, char currency, bool useSuffixFormat = false); +std::array parsePriceData(std::uint32_t price, char currency, bool useSuffixFormat = false, bool mowMode = false); std::array parseSatsPerCurrency(std::uint32_t price, char currencySymbol, bool withSatsSymbol); std::array parseBlockHeight(std::uint32_t blockHeight); std::array parseHalvingCountdown(std::uint32_t blockHeight, bool asBlocks); diff --git a/lib/btclock/utils.cpp b/lib/btclock/utils.cpp index 53212e4..9056d14 100644 --- a/lib/btclock/utils.cpp +++ b/lib/btclock/utils.cpp @@ -28,7 +28,12 @@ double getSupplyAtBlock(std::uint32_t blockNr) return totalBitcoinInCirculation; } -std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters) +std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters) +{ + return formatNumberWithSuffix(num, numCharacters, false); +} + +std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters, bool mowMode) { static char result[20]; // Adjust size as needed const long long quadrillion = 1000000000000000LL; @@ -56,30 +61,36 @@ std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters) numDouble /= billion; suffix = 'B'; } - else if (num >= million || numDigits > 6) + else if (num >= million || numDigits > 6 || (mowMode && num >= thousand)) { numDouble /= million; suffix = 'M'; } - else if (num >= thousand || numDigits > 3) + else if (!mowMode && (num >= thousand || numDigits > 3)) { numDouble /= thousand; suffix = 'K'; } - else + else if (!mowMode) { snprintf(result, sizeof(result), "%llu", (unsigned long long)num); -// sprintf(result, "%llu", (unsigned long long)num); return result; } + else // mowMode is true and num < 1000 + { + numDouble /= million; + suffix = 'M'; + } // Add suffix int len = snprintf(result, sizeof(result), "%.0f%c", numDouble, suffix); - // If there's room, add decimal places + // If there's room, add more decimal places if (len < numCharacters) { - snprintf(result, sizeof(result), "%.*f%c", numCharacters - len - 1, numDouble, suffix); + int restLen = mowMode ? numCharacters - len : numCharacters - len - 1; + + snprintf(result, sizeof(result), "%.*f%c", restLen, numDouble, suffix); } return result; diff --git a/lib/btclock/utils.hpp b/lib/btclock/utils.hpp index b166cae..cf4a107 100644 --- a/lib/btclock/utils.hpp +++ b/lib/btclock/utils.hpp @@ -11,4 +11,5 @@ int modulo(int x,int N); double getSupplyAtBlock(std::uint32_t blockNr); std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters = 4); +std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters, bool mowMode); int64_t getAmountInSatoshis(std::string bolt11); \ No newline at end of file diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index dd222a5..c665b3b 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -18,6 +18,8 @@ #define DEFAULT_DISABLE_FL false #define DEFAULT_OWN_DATA_SOURCE true #define DEFAULT_STAGING_SOURCE false +#define DEFAULT_MOW_MODE false + #define DEFAULT_V2_SOURCE_CURRENCY CURRENCY_USD diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index a301f17..eac002c 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -283,7 +283,10 @@ void prepareDisplayUpdateTask(void *pvParameters) } else { - if (epdContent[epdIndex].length() > 1 && epdContent[epdIndex].indexOf(".") == -1) + if (epdContent[epdIndex].length() == 2) { + showChars(epdIndex, epdContent[epdIndex], updatePartial, &FONT_BIG); + } + else if (epdContent[epdIndex].length() > 1 && epdContent[epdIndex].indexOf(".") == -1) { if (epdContent[epdIndex].equals("STS")) { @@ -407,6 +410,32 @@ void splitText(const uint dispNum, const String &top, const String &bottom, displays[dispNum].print(bottom); } +// void showChars(const uint dispNum, const String &chars, bool partial, +// const GFXfont *font) +// { +// displays[dispNum].setRotation(2); +// displays[dispNum].setFont(font); +// displays[dispNum].setTextColor(getFgColor()); +// int16_t tbx, tby; +// uint16_t tbw, tbh; + +// displays[dispNum].getTextBounds(chars, 0, 0, &tbx, &tby, &tbw, &tbh); + +// // center the bounding box by transposition of the origin: +// uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx; +// uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby; + +// displays[dispNum].fillScreen(getBgColor()); + +// displays[dispNum].setCursor(x, y); +// displays[dispNum].print(chars); + +// // displays[dispNum].setCursor(10, 3); +// // displays[dispNum].setFont(&FONT_SMALL); +// // displays[dispNum].setTextColor(getFgColor()); +// // displays[dispNum].println("Y = " + y); +// } + void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font) { @@ -466,6 +495,18 @@ void showDigit(const uint dispNum, char chr, bool partial, // displays[dispNum].println("Y = " + y); } +int16_t calculateDescent(const GFXfont *font) { + int16_t maxDescent = 0; + for (uint16_t i = font->first; i <= font->last; i++) { + GFXglyph *glyph = &font->glyph[i - font->first]; + int16_t descent = glyph->yOffset; + if (descent > maxDescent) { + maxDescent = descent; + } + } + return maxDescent; +} + void showChars(const uint dispNum, const String &chars, bool partial, const GFXfont *font) { @@ -475,12 +516,35 @@ void showChars(const uint dispNum, const String &chars, bool partial, int16_t tbx, tby; uint16_t tbw, tbh; displays[dispNum].getTextBounds(chars, 0, 0, &tbx, &tby, &tbw, &tbh); + + int16_t descent = calculateDescent(font); + // center the bounding box by transposition of the origin: uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx; uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby; displays[dispNum].fillScreen(getBgColor()); - displays[dispNum].setCursor(x, y); - displays[dispNum].print(chars); + // displays[dispNum].setCursor(x, y); + // displays[dispNum].print(chars); + + for (int i = 0; i < chars.length(); i++) { + char c = chars[i]; + if (c == '.' || c == ',') { + // For the dot, calculate its specific descent + GFXglyph *dotGlyph = &font->glyph[c -font->first]; + int16_t dotDescent = dotGlyph->yOffset; + + // Draw the dot with adjusted y-position + displays[dispNum].setCursor(x, y + dotDescent + dotGlyph->height); + displays[dispNum].print(c); + } else { + // For other characters, use the original y-position + displays[dispNum].setCursor(x, y); + displays[dispNum].print(c); + } + + // Move x-position for the next character + x += font->glyph[c - font->first].xAdvance; + } } int getBgColor() { return bgColor; } diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index d1c6165..47ac609 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -41,7 +41,7 @@ void workerTask(void *pvParameters) { uint price = getPrice(currency); if (getCurrentScreen() == SCREEN_BTC_TICKER) { - taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE)); + taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE), preferences.getBool("mowMode", DEFAULT_MOW_MODE)); } else if (getCurrentScreen() == SCREEN_SATS_PER_CURRENCY) { taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); } else { diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 7a6d28d..c4ad256 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -546,6 +546,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) "mdnsEnabled", "otaEnabled", "stealFocus", "mcapBigChar", "useSatsSymbol", "useBlkCountdown", "suffixPrice", "disableLeds", "ownDataSource", + "mowMode", "flAlwaysOn", "flDisable", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", "nostrZapNotify", "stagingSource", "httpAuthEnabled"}; @@ -687,6 +688,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["useBlkCountdown"] = preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN); root["suffixPrice"] = preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE); root["disableLeds"] = preferences.getBool("disableLeds", DEFAULT_DISABLE_LEDS); + root["mowMode"] = preferences.getBool("mowMode", DEFAULT_MOW_MODE); root["hostnamePrefix"] = preferences.getString("hostnamePrefix", DEFAULT_HOSTNAME_PREFIX); root["hostname"] = getMyHostname(); diff --git a/test/test_datahandler/test_main.cpp b/test/test_datahandler/test_main.cpp index 29d337f..218408c 100644 --- a/test/test_datahandler/test_main.cpp +++ b/test/test_datahandler/test_main.cpp @@ -86,6 +86,33 @@ void test_PriceOf1MillionUsd(void) TEST_ASSERT_EQUAL_STRING("M", output[NUM_SCREENS - 1].c_str()); } +void test_PriceSuffixMode(void) +{ + std::array output = parsePriceData(93000, '$', true, false); + TEST_ASSERT_EQUAL_STRING("BTC/USD", output[0].c_str()); + + TEST_ASSERT_EQUAL_STRING("9", output[NUM_SCREENS - 5].c_str()); + TEST_ASSERT_EQUAL_STRING("3", output[NUM_SCREENS - 4].c_str()); + TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("K", output[NUM_SCREENS - 1].c_str()); +} + +void test_PriceSuffixModeMow(void) +{ + std::array output = parsePriceData(93000, '$', true, true); + + std::string joined = joinArrayWithBrackets(output); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("$", output[0].c_str(), joined.c_str()); + + TEST_ASSERT_EQUAL_STRING_MESSAGE(".", output[NUM_SCREENS - 5].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("0", output[NUM_SCREENS - 4].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("9", output[NUM_SCREENS - 3].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("3", output[NUM_SCREENS - 2].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("M", output[NUM_SCREENS - 1].c_str(), joined.c_str()); +} + void test_McapLowerUsd(void) { std::array output = parseMarketCap(810000, 26000, '$', true); @@ -203,6 +230,8 @@ int runUnityTests(void) RUN_TEST(test_Mcap1TrillionEurSmallChars); RUN_TEST(test_Mcap1TrillionJpy); RUN_TEST(test_Mcap1TrillionJpySmallChars); + RUN_TEST(test_PriceSuffixMode); + RUN_TEST(test_PriceSuffixModeMow); return UNITY_END(); } From 2951055f68473dfca060d46c56347628edf81da7 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 27 Nov 2024 11:41:58 +0100 Subject: [PATCH 035/130] Add requirements.txt for CI --- requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a91b030 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +platformio \ No newline at end of file From 4cda081d05e76351cce434b9d6a14298bedb8dcd Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 28 Nov 2024 18:22:07 +0100 Subject: [PATCH 036/130] Add suffix compact mode, added extra zap notify settings, WebUI cleanup --- .forgejo/workflows/push.yaml | 2 +- data | 2 +- dependencies.lock | 2 +- lib/btclock/data_handler.cpp | 40 +++++++++++++++++++++++++---- lib/btclock/data_handler.hpp | 3 ++- partition.csv | 6 ++--- platformio.ini | 4 +-- src/lib/defaults.hpp | 3 +++ src/lib/epd.cpp | 2 +- src/lib/led_handler.cpp | 4 +-- src/lib/nostr_notify.cpp | 5 +++- src/lib/screen_handler.cpp | 5 +++- src/lib/webserver.cpp | 7 ++++- test/test_datahandler/test_main.cpp | 16 ++++++++++++ 14 files changed, 81 insertions(+), 20 deletions(-) diff --git a/.forgejo/workflows/push.yaml b/.forgejo/workflows/push.yaml index b48a34e..5121d24 100644 --- a/.forgejo/workflows/push.yaml +++ b/.forgejo/workflows/push.yaml @@ -116,7 +116,7 @@ jobs: 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \ 0xe000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/ota_data_initial.bin \ 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \ - 0x369000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin + 0x370000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin # Adjust the offset for littlefs or other files as needed for the original case fi diff --git a/data b/data index d74e9da..de99a22 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit d74e9dab60772ef11f9b033cfe982d216a9c95ee +Subproject commit de99a221d688949da0d95e2f9df2da5ba77f5c0d diff --git a/dependencies.lock b/dependencies.lock index 2cb885d..c338e6c 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -4,6 +4,6 @@ dependencies: source: type: idf version: 4.4.7 -manifest_hash: 841ba2a95f4b32d39636bf4fdf07c48a2052f71c9728a5b7f263083a3b430a4f +manifest_hash: cd2f3ee15e776d949eb4ea4eddc8f39b30c2a7905050850eed01ab4928143cff target: esp32s3 version: 1.0.0 diff --git a/lib/btclock/data_handler.cpp b/lib/btclock/data_handler.cpp index 3209811..c1f1d1f 100644 --- a/lib/btclock/data_handler.cpp +++ b/lib/btclock/data_handler.cpp @@ -67,7 +67,7 @@ char getCurrencyChar(const std::string& input) return CURRENCY_USD; // Assuming USD is the default for unknown inputs } -std::array parsePriceData(std::uint32_t price, char currencySymbol, bool useSuffixFormat, bool mowMode) +std::array parsePriceData(std::uint32_t price, char currencySymbol, bool useSuffixFormat, bool mowMode, bool shareDot) { std::array ret; std::string priceString; @@ -80,7 +80,7 @@ std::array parsePriceData(std::uint32_t price, char cu priceString = getCurrencySymbol(currencySymbol) + std::to_string(price); } std::uint32_t firstIndex = 0; - if (priceString.length() < (NUM_SCREENS)) + if ((shareDot && priceString.length() <= (NUM_SCREENS)) || priceString.length() < (NUM_SCREENS)) { priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); @@ -89,11 +89,41 @@ std::array parsePriceData(std::uint32_t price, char cu firstIndex = 1; } - - for (std::uint32_t i = firstIndex; i < NUM_SCREENS; i++) + + if (shareDot) { - ret[i] = priceString[i]; + std::vector tempArray; + size_t dotPosition = priceString.find('.'); + if (dotPosition != std::string::npos && dotPosition > 0) + { + for (size_t i = 0; i < priceString.length(); ++i) + { + if (i == dotPosition - 1) + { + tempArray.push_back(std::string(1, priceString[i]) + "."); + ++i; // Skip the dot in the next iteration + } + else + { + tempArray.push_back(std::string(1, priceString[i])); + } + } + + // Copy from tempArray to ret + for (std::uint32_t i = firstIndex; i < NUM_SCREENS && i - firstIndex < tempArray.size(); ++i) + { + ret[i] = tempArray[i - firstIndex]; + } + } } + else + { + for (std::uint32_t i = firstIndex; i < NUM_SCREENS; i++) + { + ret[i] = std::string(1, priceString[i]); + } + } + return ret; } diff --git a/lib/btclock/data_handler.hpp b/lib/btclock/data_handler.hpp index f8e237c..4dda86b 100644 --- a/lib/btclock/data_handler.hpp +++ b/lib/btclock/data_handler.hpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "utils.hpp" @@ -19,7 +20,7 @@ const std::string CURRENCY_CODE_JPY = "JPY"; const std::string CURRENCY_CODE_AUD = "AUD"; const std::string CURRENCY_CODE_CAD = "CAD"; -std::array parsePriceData(std::uint32_t price, char currency, bool useSuffixFormat = false, bool mowMode = false); +std::array parsePriceData(std::uint32_t price, char currency, bool useSuffixFormat = false, bool mowMode = false, bool shareDot = false); std::array parseSatsPerCurrency(std::uint32_t price, char currencySymbol, bool withSatsSymbol); std::array parseBlockHeight(std::uint32_t blockHeight); std::array parseHalvingCountdown(std::uint32_t blockHeight, bool asBlocks); diff --git a/partition.csv b/partition.csv index 318b4f0..778b9f2 100644 --- a/partition.csv +++ b/partition.csv @@ -1,7 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 36K, 20K, otadata, data, ota, 56K, 8K, -app0, app, ota_0, 64K, 1740K, -app1, app, ota_1, , 1740K, -spiffs, data, spiffs, , 400K, +app0, app, ota_0, 64K, 1760K, +app1, app, ota_1, , 1760K, +spiffs, data, spiffs, , 410K, coredump, data, coredump,, 64K, diff --git a/platformio.ini b/platformio.ini index 021a03d..7b0d229 100644 --- a/platformio.ini +++ b/platformio.ini @@ -33,9 +33,9 @@ build_unflags = -fno-exceptions lib_deps = https://github.com/joltwallet/esp_littlefs.git - bblanchon/ArduinoJson@^7.2.0 + bblanchon/ArduinoJson@^7.2.1 mathieucarbou/ESPAsyncWebServer @ 3.3.23 - adafruit/Adafruit BusIO@^1.16.1 + adafruit/Adafruit BusIO@^1.16.2 adafruit/Adafruit MCP23017 Arduino Library@^2.3.2 adafruit/Adafruit NeoPixel@^1.12.3 https://github.com/dsbaars/universal_pin diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index c665b3b..8af3b5b 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -19,6 +19,7 @@ #define DEFAULT_OWN_DATA_SOURCE true #define DEFAULT_STAGING_SOURCE false #define DEFAULT_MOW_MODE false +#define DEFAULT_SUFFIX_SHARE_DOT false #define DEFAULT_V2_SOURCE_CURRENCY CURRENCY_USD @@ -57,6 +58,8 @@ #define DEFAULT_ZAP_NOTIFY_ENABLED false #define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422" +#define DEFAULT_LED_FLASH_ON_ZAP true +#define DEFAULT_FL_FLASH_ON_ZAP true #define DEFAULT_HTTP_AUTH_ENABLED false #define DEFAULT_HTTP_AUTH_USERNAME "btclock" diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index eac002c..1c04725 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -534,7 +534,7 @@ void showChars(const uint dispNum, const String &chars, bool partial, int16_t dotDescent = dotGlyph->yOffset; // Draw the dot with adjusted y-position - displays[dispNum].setCursor(x, y + dotDescent + dotGlyph->height); + displays[dispNum].setCursor(x, y + dotDescent + dotGlyph->height + 8); displays[dispNum].print(c); } else { // For other characters, use the original y-position diff --git a/src/lib/led_handler.cpp b/src/lib/led_handler.cpp index 4f882e0..338c3c3 100644 --- a/src/lib/led_handler.cpp +++ b/src/lib/led_handler.cpp @@ -285,7 +285,7 @@ void ledTask(void *parameter) #ifdef HAS_FRONTLIGHT bool frontlightWasOn = false; - if (preferences.getBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE)) + if (preferences.getBool("flFlashOnZap", DEFAULT_FL_FLASH_ON_ZAP)) { if (frontlightOn) { @@ -307,7 +307,7 @@ void ledTask(void *parameter) // blinkDelayTwoColor(250, 3, pixels.Color(142, 48, 235), // pixels.Color(169, 21, 255)); #ifdef HAS_FRONTLIGHT - if (preferences.getBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE)) + if (preferences.getBool("flFlashOnZap", DEFAULT_FL_FLASH_ON_ZAP)) { vTaskDelay(pdMS_TO_TICKS(10)); if (frontlightWasOn) diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index 237eabe..bad593d 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -252,7 +252,10 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event) setEpdContent(textEpdContent); vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250)); - queueLedEffect(LED_EFFECT_NOSTR_ZAP); + if (preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP)) + { + queueLedEffect(LED_EFFECT_NOSTR_ZAP); + } if (timerPeriod > 0) { esp_timer_start_periodic(screenRotateTimer, diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 47ac609..1f2b4a4 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -41,7 +41,10 @@ void workerTask(void *pvParameters) { uint price = getPrice(currency); if (getCurrentScreen() == SCREEN_BTC_TICKER) { - taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE), preferences.getBool("mowMode", DEFAULT_MOW_MODE)); + taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE), + preferences.getBool("mowMode", DEFAULT_MOW_MODE), + preferences.getBool("suffixShareDot", DEFAULT_SUFFIX_SHARE_DOT) + ); } else if (getCurrentScreen() == SCREEN_SATS_PER_CURRENCY) { taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); } else { diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index c4ad256..777fe0b 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -546,7 +546,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) "mdnsEnabled", "otaEnabled", "stealFocus", "mcapBigChar", "useSatsSymbol", "useBlkCountdown", "suffixPrice", "disableLeds", "ownDataSource", - "mowMode", + "mowMode", "suffixShareDot", "flAlwaysOn", "flDisable", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", "nostrZapNotify", "stagingSource", "httpAuthEnabled"}; @@ -689,6 +689,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["suffixPrice"] = preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE); root["disableLeds"] = preferences.getBool("disableLeds", DEFAULT_DISABLE_LEDS); root["mowMode"] = preferences.getBool("mowMode", DEFAULT_MOW_MODE); + root["suffixShareDot"] = preferences.getBool("suffixShareDot", DEFAULT_SUFFIX_SHARE_DOT); root["hostnamePrefix"] = preferences.getString("hostnamePrefix", DEFAULT_HOSTNAME_PREFIX); root["hostname"] = getMyHostname(); @@ -703,6 +704,8 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["nostrZapNotify"] = preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED); root["nostrZapPubkey"] = preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY); + root["ledFlashOnZap"] = preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP); + root["gitReleaseUrl"] = preferences.getString("gitReleaseUrl", DEFAULT_GIT_RELEASE_URL); root["bitaxeEnabled"] = preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED); @@ -719,6 +722,8 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["flAlwaysOn"] = preferences.getBool("flAlwaysOn", DEFAULT_FL_ALWAYS_ON); root["flEffectDelay"] = preferences.getUInt("flEffectDelay", DEFAULT_FL_EFFECT_DELAY); root["flFlashOnUpd"] = preferences.getBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE); + root["flFlashOnZap"] = preferences.getBool("flFlashOnZap", DEFAULT_FL_FLASH_ON_ZAP); + root["hasLightLevel"] = hasLightLevel(); root["luxLightToggle"] = preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE); #else diff --git a/test/test_datahandler/test_main.cpp b/test/test_datahandler/test_main.cpp index 218408c..f2ad64c 100644 --- a/test/test_datahandler/test_main.cpp +++ b/test/test_datahandler/test_main.cpp @@ -113,6 +113,21 @@ void test_PriceSuffixModeMow(void) TEST_ASSERT_EQUAL_STRING_MESSAGE("M", output[NUM_SCREENS - 1].c_str(), joined.c_str()); } +void test_PriceSuffixModeMowCompact(void) +{ + std::array output = parsePriceData(93000, '$', true, true, true); + + std::string joined = joinArrayWithBrackets(output); + + TEST_ASSERT_EQUAL_STRING("BTC/USD", output[0].c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("$", output[NUM_SCREENS - 6].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("0.", output[NUM_SCREENS - 5].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("0", output[NUM_SCREENS - 4].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("9", output[NUM_SCREENS - 3].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("3", output[NUM_SCREENS - 2].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("M", output[NUM_SCREENS - 1].c_str(), joined.c_str()); +} + void test_McapLowerUsd(void) { std::array output = parseMarketCap(810000, 26000, '$', true); @@ -232,6 +247,7 @@ int runUnityTests(void) RUN_TEST(test_Mcap1TrillionJpySmallChars); RUN_TEST(test_PriceSuffixMode); RUN_TEST(test_PriceSuffixModeMow); + RUN_TEST(test_PriceSuffixModeMowCompact); return UNITY_END(); } From 031b506fedc536e130fb8a5e874b59e3cb051864 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 28 Nov 2024 19:21:15 +0100 Subject: [PATCH 037/130] Fix partition tables for bigger flash sizes --- partition_16mb.csv | 2 +- partition_8mb.csv | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/partition_16mb.csv b/partition_16mb.csv index a32b7ca..e26e145 100644 --- a/partition_16mb.csv +++ b/partition_16mb.csv @@ -3,5 +3,5 @@ nvs, data, nvs, 36K, 20K, otadata, data, ota, 56K, 8K, app0, app, ota_0, 64K, 4096K, app1, app, ota_1, , 4096K, -spiffs, data, spiffs, , 400K, +spiffs, data, spiffs, , 410K, coredump, data, coredump,, 64K, diff --git a/partition_8mb.csv b/partition_8mb.csv index 4ca1357..778b9f2 100644 --- a/partition_8mb.csv +++ b/partition_8mb.csv @@ -1,7 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 36K, 20K, otadata, data, ota, 56K, 8K, -app0, app, ota_0, 64K, 1700K, -app1, app, ota_1, , 1700K, -spiffs, data, spiffs, , 400K, +app0, app, ota_0, 64K, 1760K, +app1, app, ota_1, , 1760K, +spiffs, data, spiffs, , 410K, coredump, data, coredump,, 64K, From 981895d3157df20b16a1c7eddba9d61e27277803 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Fri, 29 Nov 2024 01:22:07 +0100 Subject: [PATCH 038/130] Convert partition table to hex, update WebUI --- data | 2 +- partition.csv | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/data b/data index de99a22..f0fa58b 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit de99a221d688949da0d95e2f9df2da5ba77f5c0d +Subproject commit f0fa58b5ea60f695aeaae9ddd7138cbb3686e96a diff --git a/partition.csv b/partition.csv index 778b9f2..80714ea 100644 --- a/partition.csv +++ b/partition.csv @@ -1,7 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags -nvs, data, nvs, 36K, 20K, -otadata, data, ota, 56K, 8K, -app0, app, ota_0, 64K, 1760K, -app1, app, ota_1, , 1760K, -spiffs, data, spiffs, , 410K, -coredump, data, coredump,, 64K, +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x1b8000, +app1, app, ota_1, , 0x1b8000, +spiffs, data, spiffs, , 0x66800, +coredump, data, coredump,, 0x10000, \ No newline at end of file From 41b5fcf1c1938c4bac7e9cea53395c07e39ffaec Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 5 Dec 2024 04:32:32 +0100 Subject: [PATCH 039/130] Bugfix for suffix compact mode --- lib/btclock/data_handler.cpp | 9 +++++---- maintainers.yaml | 20 ++++++++++++++++++++ test/test_datahandler/test_main.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 maintainers.yaml diff --git a/lib/btclock/data_handler.cpp b/lib/btclock/data_handler.cpp index c1f1d1f..80e2328 100644 --- a/lib/btclock/data_handler.cpp +++ b/lib/btclock/data_handler.cpp @@ -90,10 +90,11 @@ std::array parsePriceData(std::uint32_t price, char cu firstIndex = 1; } - if (shareDot) + size_t dotPosition = priceString.find('.'); + + if (shareDot && dotPosition != std::string::npos && dotPosition > 0) { std::vector tempArray; - size_t dotPosition = priceString.find('.'); if (dotPosition != std::string::npos && dotPosition > 0) { for (size_t i = 0; i < priceString.length(); ++i) @@ -322,9 +323,9 @@ emscripten::val parseBlockHeightArray(std::uint32_t blockHeight) return arrayToStringArray(parseBlockHeight(blockHeight)); } -emscripten::val parsePriceDataArray(std::uint32_t price, const std::string ¤cySymbol, bool useSuffixFormat = false) +emscripten::val parsePriceDataArray(std::uint32_t price, const std::string ¤cySymbol, bool useSuffixFormat = false, bool mowMode = false, bool shareDot = false) { - return arrayToStringArray(parsePriceData(price, currencySymbol[0], useSuffixFormat)); + return arrayToStringArray(parsePriceData(price, currencySymbol[0], useSuffixFormat, mowMode, shareDot)); } emscripten::val parseHalvingCountdownArray(std::uint32_t blockHeight, bool asBlocks) diff --git a/maintainers.yaml b/maintainers.yaml new file mode 100644 index 0000000..8176c63 --- /dev/null +++ b/maintainers.yaml @@ -0,0 +1,20 @@ +identifier: BTClock +maintainers: +- npub1k5f85zx0xdskyayqpfpc0zq6n7vwqjuuxugkayk72fgynp34cs3qfcvqg2 +relays: +- wss://relay.noderunners.network/ +- wss://nostr.sathoarder.com/ +- wss://offchain.pub/ +- wss://nostr3.daedaluslabs.io/ +- wss://nostr4.daedaluslabs.io/ +- wss://nostr.dbtc.link/ +- wss://purplepag.es/ +- wss://nos.lol/ +- wss://nostr1.daedaluslabs.io/ +- wss://nostr.noderunners.network/ +- wss://nostr.lnbitcoin.cz/ +- wss://relay.primal.net/ +- wss://relay.damus.io +- wss://nostr-relay.derekross.me/ +- wss://nostr2.azzamo.net/ +- wss://nostr2.daedaluslabs.io/ diff --git a/test/test_datahandler/test_main.cpp b/test/test_datahandler/test_main.cpp index f2ad64c..6314f34 100644 --- a/test/test_datahandler/test_main.cpp +++ b/test/test_datahandler/test_main.cpp @@ -98,6 +98,30 @@ void test_PriceSuffixMode(void) TEST_ASSERT_EQUAL_STRING("K", output[NUM_SCREENS - 1].c_str()); } +void test_PriceSuffixModeCompact1(void) +{ + std::array output = parsePriceData(100000, '$', true, false, true); + TEST_ASSERT_EQUAL_STRING("BTC/USD", output[0].c_str()); + + TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS - 5].c_str()); + TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS - 4].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("K", output[NUM_SCREENS - 1].c_str()); +} + +void test_PriceSuffixModeCompact2(void) +{ + std::array output = parsePriceData(1000000, '$', true, false, true); + TEST_ASSERT_EQUAL_STRING("BTC/USD", output[0].c_str()); + + TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS - 5].c_str()); + TEST_ASSERT_EQUAL_STRING("1.", output[NUM_SCREENS - 4].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("M", output[NUM_SCREENS - 1].c_str()); +} + void test_PriceSuffixModeMow(void) { std::array output = parsePriceData(93000, '$', true, true); @@ -246,6 +270,8 @@ int runUnityTests(void) RUN_TEST(test_Mcap1TrillionJpy); RUN_TEST(test_Mcap1TrillionJpySmallChars); RUN_TEST(test_PriceSuffixMode); + RUN_TEST(test_PriceSuffixModeCompact1); + RUN_TEST(test_PriceSuffixModeCompact2); RUN_TEST(test_PriceSuffixModeMow); RUN_TEST(test_PriceSuffixModeMowCompact); From f0f591a16f7c5a9409be5cf83d9fa5d0476c9da6 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 5 Dec 2024 05:21:14 +0100 Subject: [PATCH 040/130] Make better use of the screens in compact suffix mode --- lib/btclock/data_handler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/btclock/data_handler.cpp b/lib/btclock/data_handler.cpp index 80e2328..60b0ef1 100644 --- a/lib/btclock/data_handler.cpp +++ b/lib/btclock/data_handler.cpp @@ -73,7 +73,8 @@ std::array parsePriceData(std::uint32_t price, char cu std::string priceString; if (std::to_string(price).length() >= NUM_SCREENS || useSuffixFormat) { - priceString = getCurrencySymbol(currencySymbol) + formatNumberWithSuffix(price, NUM_SCREENS - 2, mowMode); + int numScreens = shareDot && !mowMode ? NUM_SCREENS - 1 : NUM_SCREENS - 2; + priceString = getCurrencySymbol(currencySymbol) + formatNumberWithSuffix(price, numScreens, mowMode); } else { From 33c06c86a1394a3a8e608b5e65f4755edf63e315 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 5 Dec 2024 18:22:59 +0100 Subject: [PATCH 041/130] Prepare sats per dollar for 1B amounts --- lib/btclock/data_handler.cpp | 21 +++++++++++-- test/test_datahandler/test_main.cpp | 47 +++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/lib/btclock/data_handler.cpp b/lib/btclock/data_handler.cpp index 60b0ef1..b489bb8 100644 --- a/lib/btclock/data_handler.cpp +++ b/lib/btclock/data_handler.cpp @@ -139,9 +139,26 @@ std::array parseSatsPerCurrency(std::uint32_t price,ch if (priceString.length() < (NUM_SCREENS)) { - priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); + // Check if price is greater than 1 billion + if (price >= 100000000) + { + double satsPerCurrency = (1.0 / static_cast(price)) * 1e8; // Calculate satoshis + std::ostringstream oss; + oss << std::fixed << std::setprecision(3) << satsPerCurrency; // Format with 3 decimal places + priceString = oss.str(); + } + else + { + priceString = std::to_string(static_cast(round(1.0 / static_cast(price) * 1e8))); // Default formatting + } - if (currencySymbol != CURRENCY_USD) + // Pad the string with spaces if necessary + if (priceString.length() < NUM_SCREENS) + { + priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); + } + + if (currencySymbol != CURRENCY_USD || price >= 100000000) // no time anymore when earlier than 1 ret[0] = "SATS/" + getCurrencyCode(currencySymbol); else ret[0] = "MSCW/TIME"; diff --git a/test/test_datahandler/test_main.cpp b/test/test_datahandler/test_main.cpp index 6314f34..b09c9b1 100644 --- a/test/test_datahandler/test_main.cpp +++ b/test/test_datahandler/test_main.cpp @@ -33,6 +33,17 @@ void test_CorrectSatsPerDollarConversion(void) TEST_ASSERT_EQUAL_STRING("4", output[NUM_SCREENS - 1].c_str()); } +void test_SatsPerDollarAfter1B(void) +{ + std::array output = parseSatsPerCurrency(120000000, CURRENCY_USD, false); + TEST_ASSERT_EQUAL_STRING("SATS/USD", output[0].c_str()); + TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 5].c_str()); + TEST_ASSERT_EQUAL_STRING(".", output[NUM_SCREENS - 4].c_str()); + TEST_ASSERT_EQUAL_STRING("8", output[NUM_SCREENS - 3].c_str()); + TEST_ASSERT_EQUAL_STRING("3", output[NUM_SCREENS - 2].c_str()); + TEST_ASSERT_EQUAL_STRING("3", output[NUM_SCREENS - 1].c_str()); +} + void test_CorrectSatsPerPoundConversion(void) { std::array output = parseSatsPerCurrency(37253, CURRENCY_GBP, false); @@ -101,25 +112,33 @@ void test_PriceSuffixMode(void) void test_PriceSuffixModeCompact1(void) { std::array output = parsePriceData(100000, '$', true, false, true); - TEST_ASSERT_EQUAL_STRING("BTC/USD", output[0].c_str()); - TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS - 5].c_str()); - TEST_ASSERT_EQUAL_STRING("1", output[NUM_SCREENS - 4].c_str()); - TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 3].c_str()); - TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 2].c_str()); - TEST_ASSERT_EQUAL_STRING("K", output[NUM_SCREENS - 1].c_str()); + std::string joined = joinArrayWithBrackets(output); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("BTC/USD", output[0].c_str(), joined.c_str()); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("$", output[NUM_SCREENS - 6].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("1", output[NUM_SCREENS - 5].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("0", output[NUM_SCREENS - 4].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("0.", output[NUM_SCREENS - 3].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("0", output[NUM_SCREENS - 2].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("K", output[NUM_SCREENS - 1].c_str(), joined.c_str()); } void test_PriceSuffixModeCompact2(void) { std::array output = parsePriceData(1000000, '$', true, false, true); - TEST_ASSERT_EQUAL_STRING("BTC/USD", output[0].c_str()); - TEST_ASSERT_EQUAL_STRING("$", output[NUM_SCREENS - 5].c_str()); - TEST_ASSERT_EQUAL_STRING("1.", output[NUM_SCREENS - 4].c_str()); - TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 3].c_str()); - TEST_ASSERT_EQUAL_STRING("0", output[NUM_SCREENS - 2].c_str()); - TEST_ASSERT_EQUAL_STRING("M", output[NUM_SCREENS - 1].c_str()); + std::string joined = joinArrayWithBrackets(output); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("BTC/USD", output[0].c_str(), joined.c_str()); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("$", output[NUM_SCREENS - 6].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("1.", output[NUM_SCREENS - 5].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("0", output[NUM_SCREENS - 4].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("0", output[NUM_SCREENS - 3].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("0", output[NUM_SCREENS - 2].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("M", output[NUM_SCREENS - 1].c_str(), joined.c_str()); } void test_PriceSuffixModeMow(void) @@ -143,7 +162,8 @@ void test_PriceSuffixModeMowCompact(void) std::string joined = joinArrayWithBrackets(output); - TEST_ASSERT_EQUAL_STRING("BTC/USD", output[0].c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("BTC/USD", output[0].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("$", output[NUM_SCREENS - 6].c_str(), joined.c_str()); TEST_ASSERT_EQUAL_STRING_MESSAGE("0.", output[NUM_SCREENS - 5].c_str(), joined.c_str()); TEST_ASSERT_EQUAL_STRING_MESSAGE("0", output[NUM_SCREENS - 4].c_str(), joined.c_str()); @@ -258,6 +278,7 @@ int runUnityTests(void) UNITY_BEGIN(); RUN_TEST(test_CorrectSatsPerDollarConversion); RUN_TEST(test_CorrectSatsPerPoundConversion); + RUN_TEST(test_SatsPerDollarAfter1B); RUN_TEST(test_SixCharacterBlockHeight); RUN_TEST(test_SevenCharacterBlockHeight); RUN_TEST(test_FeeRateDisplay); From d6604d28d66a4e8458a8f412fff5a13c92c2599a Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 5 Dec 2024 18:28:46 +0100 Subject: [PATCH 042/130] Update some initial values --- src/lib/block_notify.cpp | 2 +- src/lib/price_notify.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index b86d497..c4db06e 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -2,7 +2,7 @@ char *wsServer; esp_websocket_client_handle_t blockNotifyClient = NULL; -uint currentBlockHeight = 860000; +uint currentBlockHeight = 873400; uint blockMedianFee = 1; bool blockNotifyInit = false; unsigned long int lastBlockUpdate; diff --git a/src/lib/price_notify.cpp b/src/lib/price_notify.cpp index f995de8..ab5192b 100644 --- a/src/lib/price_notify.cpp +++ b/src/lib/price_notify.cpp @@ -8,7 +8,7 @@ const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin"; // WebsocketsClient client; esp_websocket_client_handle_t clientPrice = NULL; esp_websocket_client_config_t config; -uint currentPrice = 50000; +uint currentPrice = 90000; unsigned long int lastPriceUpdate; bool priceNotifyInit = false; std::map currencyMap; From 132aa835cd8492900b9af9bc89f6cd1e25ad4635 Mon Sep 17 00:00:00 2001 From: kdmukai Date: Mon, 9 Dec 2024 15:58:39 -0600 Subject: [PATCH 043/130] Mow Units no rounding! --- lib/btclock/data_handler.cpp | 11 +++++++++-- lib/btclock/utils.cpp | 24 +++++++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/btclock/data_handler.cpp b/lib/btclock/data_handler.cpp index b489bb8..eaf4538 100644 --- a/lib/btclock/data_handler.cpp +++ b/lib/btclock/data_handler.cpp @@ -73,7 +73,7 @@ std::array parsePriceData(std::uint32_t price, char cu std::string priceString; if (std::to_string(price).length() >= NUM_SCREENS || useSuffixFormat) { - int numScreens = shareDot && !mowMode ? NUM_SCREENS - 1 : NUM_SCREENS - 2; + int numScreens = shareDot || mowMode ? NUM_SCREENS - 1 : NUM_SCREENS - 2; priceString = getCurrencySymbol(currencySymbol) + formatNumberWithSuffix(price, numScreens, mowMode); } else @@ -85,7 +85,14 @@ std::array parsePriceData(std::uint32_t price, char cu { priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' '); - ret[0] = "BTC/" + getCurrencyCode(currencySymbol); + if (mowMode) + { + ret[0] = "MOW/UNITS"; + } + else + { + ret[0] = "BTC/" + getCurrencyCode(currencySymbol); + } firstIndex = 1; diff --git a/lib/btclock/utils.cpp b/lib/btclock/utils.cpp index 9056d14..45dfdd2 100644 --- a/lib/btclock/utils.cpp +++ b/lib/btclock/utils.cpp @@ -1,4 +1,5 @@ #include "utils.hpp" +#include int modulo(int x, int N) { @@ -83,14 +84,31 @@ std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters, bool mo } // Add suffix - int len = snprintf(result, sizeof(result), "%.0f%c", numDouble, suffix); + int len; + + // Mow Mode always uses string truncation to avoid rounding + std::string mowAsString = std::to_string(numDouble); + if (mowMode) { + // Default to one decimal place + len = snprintf(result, sizeof(result), "%s%c", mowAsString.substr(0, mowAsString.find(".") + 2).c_str(), suffix); + } + else + { + len = snprintf(result, sizeof(result), "%.0f%c", numDouble, suffix); + } // If there's room, add more decimal places if (len < numCharacters) { int restLen = mowMode ? numCharacters - len : numCharacters - len - 1; - - snprintf(result, sizeof(result), "%.*f%c", restLen, numDouble, suffix); + + if (mowMode) { + snprintf(result, sizeof(result), "%s%c", mowAsString.substr(0, mowAsString.find(".") + 2 + restLen).c_str(), suffix); + } + else + { + snprintf(result, sizeof(result), "%.*f%c", restLen, numDouble, suffix); + } } return result; From 9ada991ab15f7aa90060c8692da8554852617d7b Mon Sep 17 00:00:00 2001 From: kdmukai Date: Mon, 9 Dec 2024 16:05:55 -0600 Subject: [PATCH 044/130] Update utils.cpp --- lib/btclock/utils.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/btclock/utils.cpp b/lib/btclock/utils.cpp index 45dfdd2..0e19962 100644 --- a/lib/btclock/utils.cpp +++ b/lib/btclock/utils.cpp @@ -1,5 +1,4 @@ #include "utils.hpp" -#include int modulo(int x, int N) { From 2a116d97ed88333296949c6b84529bbb303827f3 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Tue, 10 Dec 2024 15:13:17 +0100 Subject: [PATCH 045/130] Add frontlight off when dark setting --- data | 2 +- src/lib/defaults.hpp | 2 ++ src/lib/webserver.cpp | 4 +++- src/main.cpp | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/data b/data index f0fa58b..25e91b2 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit f0fa58b5ea60f695aeaae9ddd7138cbb3686e96a +Subproject commit 25e91b2086936e7c6ef09e917c6efd371293fd7e diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index 8af3b5b..ada5531 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -45,6 +45,8 @@ #define DEFAULT_FL_EFFECT_DELAY 15 #define DEFAULT_LUX_LIGHT_TOGGLE 128 +#define DEFAULT_FL_OFF_WHEN_DARK true + #define DEFAULT_FL_ALWAYS_ON false #define DEFAULT_FL_FLASH_ON_UPDATE false diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 777fe0b..b901379 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -546,7 +546,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) "mdnsEnabled", "otaEnabled", "stealFocus", "mcapBigChar", "useSatsSymbol", "useBlkCountdown", "suffixPrice", "disableLeds", "ownDataSource", - "mowMode", "suffixShareDot", + "mowMode", "suffixShareDot", "flOffWhenDark", "flAlwaysOn", "flDisable", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", "nostrZapNotify", "stagingSource", "httpAuthEnabled"}; @@ -726,6 +726,8 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["hasLightLevel"] = hasLightLevel(); root["luxLightToggle"] = preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE); + root["flOffWhenDark"] = preferences.getBool("flOffWhenDark", DEFAULT_FL_OFF_WHEN_DARK); + #else root["hasFrontlight"] = false; root["hasLightLevel"] = false; diff --git a/src/main.cpp b/src/main.cpp index 908f155..b9d2ae7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,7 +51,7 @@ extern "C" void app_main() if (hasLightLevel()) { if (preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE) != 0) { - if (hasLightLevel() && getLightLevel() <= 2) + if (hasLightLevel() && getLightLevel() <= 1 && preferences.getBool("flOffWhenDark", DEFAULT_FL_OFF_WHEN_DARK)) { if (frontlightIsOn()) { frontlightFadeOutAll(); From dbf2c53083c05187d5e6f152d5e2ba32a3fd16a1 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Tue, 10 Dec 2024 15:18:04 +0100 Subject: [PATCH 046/130] Adapted tests for Mow Units --- test/test_datahandler/test_main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_datahandler/test_main.cpp b/test/test_datahandler/test_main.cpp index b09c9b1..24118e4 100644 --- a/test/test_datahandler/test_main.cpp +++ b/test/test_datahandler/test_main.cpp @@ -143,7 +143,7 @@ void test_PriceSuffixModeCompact2(void) void test_PriceSuffixModeMow(void) { - std::array output = parsePriceData(93000, '$', true, true); + std::array output = parsePriceData(93600, '$', true, true); std::string joined = joinArrayWithBrackets(output); @@ -158,11 +158,11 @@ void test_PriceSuffixModeMow(void) void test_PriceSuffixModeMowCompact(void) { - std::array output = parsePriceData(93000, '$', true, true, true); + std::array output = parsePriceData(93600, '$', true, true, true); std::string joined = joinArrayWithBrackets(output); - TEST_ASSERT_EQUAL_STRING_MESSAGE("BTC/USD", output[0].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("MOW/UNITS", output[0].c_str(), joined.c_str()); TEST_ASSERT_EQUAL_STRING_MESSAGE("$", output[NUM_SCREENS - 6].c_str(), joined.c_str()); TEST_ASSERT_EQUAL_STRING_MESSAGE("0.", output[NUM_SCREENS - 5].c_str(), joined.c_str()); From 34b77ea1056e2d7fa8c3df0795b666c6b2d07d84 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 12 Dec 2024 23:12:59 +0100 Subject: [PATCH 047/130] Update WebUI --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 25e91b2..653a39d 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 25e91b2086936e7c6ef09e917c6efd371293fd7e +Subproject commit 653a39d0a339bcf3ac3365eacd2e5e8136ecf4c6 From db0ec01c869bb2485308943a679b98a036272b05 Mon Sep 17 00:00:00 2001 From: kdmukai Date: Tue, 17 Dec 2024 08:53:00 -0600 Subject: [PATCH 048/130] Add bitaxe logo --- lib/btclock/bitaxe_handler.cpp | 4 +- src/icons/icons.cpp | 260 ++++++++++++++++++++++++++++++++- src/lib/epd.cpp | 6 +- 3 files changed, 264 insertions(+), 6 deletions(-) diff --git a/lib/btclock/bitaxe_handler.cpp b/lib/btclock/bitaxe_handler.cpp index cbc71ec..c18b7de 100644 --- a/lib/btclock/bitaxe_handler.cpp +++ b/lib/btclock/bitaxe_handler.cpp @@ -24,7 +24,7 @@ std::array parseBitaxeHashRate(std::string text) } ret[NUM_SCREENS - 1] = "GH/S"; - ret[0] = "BIT/AXE"; + ret[0] = "mdi:bitaxe"; return ret; } @@ -37,7 +37,7 @@ std::array parseBitaxeBestDiff(std::string text) if (text.length() < NUM_SCREENS) { text.insert(text.begin(), NUM_SCREENS - text.length(), ' '); - ret[0] = "BIT/AXE"; + ret[0] = "mdi:bitaxe"; ret[1] = "mdi:rocket"; firstIndex = 2; } diff --git a/src/icons/icons.cpp b/src/icons/icons.cpp index 3254740..ca69f63 100644 --- a/src/icons/icons.cpp +++ b/src/icons/icons.cpp @@ -1015,11 +1015,267 @@ const unsigned char epd_icons_flash [] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 }; +// 'bitaxe_logo', 122x250px +const unsigned char epd_icons_bitaxe_logo [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xcf, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xfc, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0x83, 0xff, 0xff, 0xf7, 0xf0, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xf1, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xf8, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xcf, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xe7, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xe7, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x07, 0xf9, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x07, 0xf8, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xff, 0x8f, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0x8f, 0xf7, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe2, 0x00, 0x00, 0x01, 0x00, 0x00, 0x20, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x11, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xbf, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xbf, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0x9f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xfb, 0xf0, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xf7, 0xf8, 0x3f, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xf1, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0x83, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xef, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x3f, 0xff, 0xcf, 0xff, 0xff, 0x83, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x1f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x0f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xbf, 0xff, 0x01, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x7f, 0xc1, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x81, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xfd, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xfb, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xf3, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xe7, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0x8f, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x82, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + + // Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 8032) -const int epd_icons_allArray_LEN = 4; +const int epd_icons_allArray_LEN = 5; const unsigned char* epd_icons_allArray[epd_icons_allArray_LEN] = { epd_icons_pickaxe, epd_icons_rocket_launch, epd_icons_lightning, - epd_icons_flash + epd_icons_flash, + epd_icons_bitaxe_logo }; diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 1c04725..3ef06e6 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -603,10 +603,12 @@ void renderIcon(const uint dispNum, const String &text, bool partial) if (text.endsWith("rocket")) { iconIndex = 1; } - - if (text.endsWith("lnbolt")) { + else if (text.endsWith("lnbolt")) { iconIndex = 3; } + else if (text.endsWith("bitaxe")) { + iconIndex = 4; + } displays[dispNum].drawInvertedBitmap(0,0, epd_icons_allArray[iconIndex], 122, 250, getFgColor()); From 4a52fc0bf22c050a440eca7aa885cf18bcd42f10 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 18 Dec 2024 00:50:20 +0100 Subject: [PATCH 049/130] Add vertical screen description option --- data | 2 +- src/lib/defaults.hpp | 1 + src/lib/epd.cpp | 6 +++++- src/lib/webserver.cpp | 3 +++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/data b/data index 653a39d..266a99b 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 653a39d0a339bcf3ac3365eacd2e5e8136ecf4c6 +Subproject commit 266a99be96189bea92e0ef593f930bb92d3b5b20 diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index ada5531..11df69a 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -70,3 +70,4 @@ #define DEFAULT_ACTIVE_CURRENCIES "USD,EUR,JPY" #define DEFAULT_GIT_RELEASE_URL "https://git.btclock.dev/api/v1/repos/btclock/btclock_v3/releases/latest" +#define DEFAULT_VERTICAL_DESC true diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 1c04725..986b9cc 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -373,7 +373,11 @@ extern "C" void updateDisplay(void *pvParameters) noexcept void splitText(const uint dispNum, const String &top, const String &bottom, bool partial) { - displays[dispNum].setRotation(2); + if(preferences.getBool("verticalDesc", DEFAULT_VERTICAL_DESC) && dispNum == 0) { + displays[dispNum].setRotation(1); + } else { + displays[dispNum].setRotation(2); + } displays[dispNum].setFont(&FONT_SMALL); displays[dispNum].setTextColor(getFgColor()); diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index b901379..11b9024 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -549,6 +549,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) "mowMode", "suffixShareDot", "flOffWhenDark", "flAlwaysOn", "flDisable", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", + "verticalDesc", "nostrZapNotify", "stagingSource", "httpAuthEnabled"}; for (String setting : boolSettings) @@ -689,6 +690,8 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["suffixPrice"] = preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE); root["disableLeds"] = preferences.getBool("disableLeds", DEFAULT_DISABLE_LEDS); root["mowMode"] = preferences.getBool("mowMode", DEFAULT_MOW_MODE); + root["verticalDesc"] = preferences.getBool("verticalDesc", DEFAULT_VERTICAL_DESC); + root["suffixShareDot"] = preferences.getBool("suffixShareDot", DEFAULT_SUFFIX_SHARE_DOT); root["hostnamePrefix"] = preferences.getString("hostnamePrefix", DEFAULT_HOSTNAME_PREFIX); From 83d293c58e46f7698fd484bda35c7130a568014c Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 18 Dec 2024 01:32:11 +0100 Subject: [PATCH 050/130] Add bitaxe logo to WebUI --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 266a99b..85b9b17 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 266a99be96189bea92e0ef593f930bb92d3b5b20 +Subproject commit 85b9b17506f89696b89ab6f6e6ed231b7a8f6e91 From af4c46665912b444bdaa056bbab6c060a767220e Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 18 Dec 2024 19:47:03 +0100 Subject: [PATCH 051/130] Switch to leaner MCP23017 library, create new aligned partition tables --- .forgejo/workflows/push.yaml | 26 +++++++++++++------ partition.csv | 4 +-- partition_16mb.csv | 12 ++++----- partition_8mb.csv | 12 ++++----- platformio.ini | 14 +++++------ scripts/pre_script.py | 7 ++++++ src/lib/button_handler.cpp | 23 ++++++++--------- src/lib/config.cpp | 48 ++++++++++++++++++++++++++---------- src/lib/config.hpp | 6 +++-- src/lib/epd.cpp | 11 ++++++++- src/lib/epd.hpp | 1 + src/lib/shared.cpp | 10 +++++++- src/lib/shared.hpp | 12 ++++++--- 13 files changed, 127 insertions(+), 59 deletions(-) create mode 100644 scripts/pre_script.py diff --git a/.forgejo/workflows/push.yaml b/.forgejo/workflows/push.yaml index 5121d24..6ccb926 100644 --- a/.forgejo/workflows/push.yaml +++ b/.forgejo/workflows/push.yaml @@ -95,7 +95,6 @@ jobs: - name: Create merged firmware binary run: | if [ "${{ matrix.chip.name }}" == "btclock_v8" ]; then - mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && \ esptool.py --chip ${{ matrix.chip.version }} merge_bin \ -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \ --flash_mode dio \ @@ -105,7 +104,19 @@ jobs: 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \ 0xe000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/ota_data_initial.bin \ 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \ - 0x810000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin; + 0xDF0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs_16MB.bin + elif [ "${{ matrix.chip.name }}" == "btclock_rev_b" ]; then + mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && \ + esptool.py --chip ${{ matrix.chip.version }} merge_bin \ + -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \ + --flash_mode dio \ + --flash_freq 80m \ + --flash_size 8MB \ + 0x0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/bootloader.bin \ + 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \ + 0xe000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/ota_data_initial.bin \ + 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \ + 0x6F0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs_8MB.bin; else # Original command for other cases mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && \ @@ -116,7 +127,7 @@ jobs: 0x8000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/partitions.bin \ 0xe000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/ota_data_initial.bin \ 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \ - 0x370000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin + 0x380000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs_4MB.bin # Adjust the offset for littlefs or other files as needed for the original case fi @@ -127,10 +138,11 @@ jobs: run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin.sha256 - name: Create checksum for littlefs partition - run: shasum -a 256 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs.bin.sha256 - - - name: Copy all artifacts to output folder - run: cp .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin .pio/boot_app0.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }} + run: | + fs_file=$(find .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }} -name "littlefs*.bin") + shasum -a 256 "$fs_file" | awk '{print $1}' > "${fs_file}.sha256" + - name: Copy all artifacts to output folder + run: cp .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin .pio/boot_app0.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }} - name: Create OTA binary file run: mv ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}_firmware.bin diff --git a/partition.csv b/partition.csv index 80714ea..eedbf5b 100644 --- a/partition.csv +++ b/partition.csv @@ -3,5 +3,5 @@ nvs, data, nvs, 0x9000, 0x5000, otadata, data, ota, 0xe000, 0x2000, app0, app, ota_0, 0x10000, 0x1b8000, app1, app, ota_1, , 0x1b8000, -spiffs, data, spiffs, , 0x66800, -coredump, data, coredump,, 0x10000, \ No newline at end of file +spiffs, data, spiffs, , 0x66C00, +coredump, data, coredump,, 0x10000, diff --git a/partition_16mb.csv b/partition_16mb.csv index e26e145..7e58611 100644 --- a/partition_16mb.csv +++ b/partition_16mb.csv @@ -1,7 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags -nvs, data, nvs, 36K, 20K, -otadata, data, ota, 56K, 8K, -app0, app, ota_0, 64K, 4096K, -app1, app, ota_1, , 4096K, -spiffs, data, spiffs, , 410K, -coredump, data, coredump,, 64K, +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x6F0000, +app1, app, ota_1, , 0x6F0000, +spiffs, data, spiffs, , 0x200000, +coredump, data, coredump,, 0x10000, \ No newline at end of file diff --git a/partition_8mb.csv b/partition_8mb.csv index 778b9f2..025f649 100644 --- a/partition_8mb.csv +++ b/partition_8mb.csv @@ -1,7 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags -nvs, data, nvs, 36K, 20K, -otadata, data, ota, 56K, 8K, -app0, app, ota_0, 64K, 1760K, -app1, app, ota_1, , 1760K, -spiffs, data, spiffs, , 410K, -coredump, data, coredump,, 64K, +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x370000, +app1, app, ota_1, , 0x370000, +spiffs, data, spiffs, , 0xCD000, +coredump, data, coredump,, 0x10000, \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 7b0d229..d2abb92 100644 --- a/platformio.ini +++ b/platformio.ini @@ -20,8 +20,9 @@ framework = arduino, espidf monitor_speed = 115200 monitor_filters = esp32_exception_decoder, colorize board_build.filesystem = littlefs -extra_scripts = post:scripts/extra_script.py -board_build.embed_files = x509_crt_bundle +extra_scripts = pre:scripts/pre_script.py, post:scripts/extra_script.py +board_build.embed_files = + x509_crt_bundle build_flags = !python scripts/git_rev.py -DLAST_BUILD_TIME=$UNIX_TIME @@ -35,14 +36,13 @@ lib_deps = https://github.com/joltwallet/esp_littlefs.git bblanchon/ArduinoJson@^7.2.1 mathieucarbou/ESPAsyncWebServer @ 3.3.23 - adafruit/Adafruit BusIO@^1.16.2 - adafruit/Adafruit MCP23017 Arduino Library@^2.3.2 + robtillaart/MCP23017@^0.8.0 adafruit/Adafruit NeoPixel@^1.12.3 - https://github.com/dsbaars/universal_pin + https://github.com/dsbaars/universal_pin#feature/mcp23017_rt https://github.com/dsbaars/GxEPD2#universal_pin https://github.com/tzapu/WiFiManager.git#v2.0.17 rblb/Nostrduino@1.2.8 - + [env:lolin_s3_mini] extends = btclock_base board = lolin_s3_mini @@ -64,7 +64,7 @@ build_unflags = [env:btclock_rev_b] extends = btclock_base board = btclock_rev_b -board_build.partitions = partition.csv +board_build.partitions = partition_8mb.csv build_flags = ${btclock_base.build_flags} -D MCP_INT_PIN=8 diff --git a/scripts/pre_script.py b/scripts/pre_script.py new file mode 100644 index 0000000..45d6bea --- /dev/null +++ b/scripts/pre_script.py @@ -0,0 +1,7 @@ +Import("env") + +flash_size = env.BoardConfig().get("upload.flash_size", "4MB") +fs_image_name = f"littlefs_{flash_size}" +env.Replace(ESP32_FS_IMAGE_NAME=fs_image_name) +env.Replace(ESP8266_FS_IMAGE_NAME=fs_image_name) + diff --git a/src/lib/button_handler.cpp b/src/lib/button_handler.cpp index 437090d..72f1eaa 100644 --- a/src/lib/button_handler.cpp +++ b/src/lib/button_handler.cpp @@ -5,15 +5,15 @@ const TickType_t debounceDelay = pdMS_TO_TICKS(50); TickType_t lastDebounceTime = 0; #ifdef IS_BTCLOCK_V8 -#define BTN_1 0 -#define BTN_2 1 -#define BTN_3 2 -#define BTN_4 3 +#define BTN_1 256 +#define BTN_2 512 +#define BTN_3 1024 +#define BTN_4 2048 #else -#define BTN_1 3 -#define BTN_2 2 -#define BTN_3 1 -#define BTN_4 0 +#define BTN_1 2048 +#define BTN_2 1024 +#define BTN_3 512 +#define BTN_4 256 #endif void buttonTask(void *parameter) { @@ -22,11 +22,12 @@ void buttonTask(void *parameter) { std::lock_guard lock(mcpMutex); TickType_t currentTime = xTaskGetTickCount(); + if ((currentTime - lastDebounceTime) >= debounceDelay) { lastDebounceTime = currentTime; if (!digitalRead(MCP_INT_PIN)) { - uint pin = mcp1.getLastInterruptPin(); + uint pin = mcp1.getInterruptFlagRegister(); switch (pin) { case BTN_1: @@ -43,12 +44,12 @@ void buttonTask(void *parameter) { break; } } - mcp1.clearInterrupts(); + mcp1.getInterruptCaptureRegister(); } else { } // Very ugly, but for some reason this is necessary while (!digitalRead(MCP_INT_PIN)) { - mcp1.clearInterrupts(); + mcp1.getInterruptCaptureRegister(); } } } diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 8f954b2..e9912a9 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -2,10 +2,12 @@ #define MAX_ATTEMPTS_WIFI_CONNECTION 20 +// zlib_turbo zt; + Preferences preferences; -Adafruit_MCP23X17 mcp1; +MCP23017 mcp1(0x20); #ifdef IS_BTCLOCK_V8 -Adafruit_MCP23X17 mcp2; +MCP23017 mcp2(0x21); #endif #ifdef HAS_FRONTLIGHT @@ -35,7 +37,7 @@ void setup() } { std::lock_guard lockMcp(mcpMutex); - if (mcp1.digitalRead(3) == LOW) + if (mcp1.read1(3) == LOW) { preferences.putBool("wifiConfigured", false); preferences.remove("txPower"); @@ -46,7 +48,7 @@ void setup() } { - if (mcp1.digitalRead(0) == LOW) + if (mcp1.read1(0) == LOW) { // Then loop forever to prevent anything else from writing to the screen while (true) @@ -54,7 +56,7 @@ void setup() delay(1000); } } - else if (mcp1.digitalRead(1) == LOW) + else if (mcp1.read1(1) == LOW) { preferences.clear(); queueLedEffect(LED_EFFECT_WIFI_ERASE_SETTINGS); @@ -66,6 +68,7 @@ void setup() } setupWifi(); + // loadIcons(); setupWebserver(); @@ -106,6 +109,7 @@ void setup() #endif forceFullRefresh(); + } void setupWifi() @@ -132,7 +136,7 @@ void setupWifi() bool buttonPress = false; { std::lock_guard lockMcp(mcpMutex); - buttonPress = (mcp1.digitalRead(2) == LOW); + buttonPress = (mcp1.read1(2) == LOW); } { @@ -507,7 +511,7 @@ void setupHardware() Wire.begin(I2C_SDA_PIN, I2C_SCK_PIN, 400000); - if (!mcp1.begin_I2C(0x20)) + if (!mcp1.begin()) { Serial.println(F("Error MCP23017 1")); @@ -517,17 +521,20 @@ void setupHardware() else { pinMode(MCP_INT_PIN, INPUT_PULLUP); - mcp1.setupInterrupts(false, false, LOW); +// mcp1.setupInterrupts(false, false, LOW); + mcp1.enableControlRegister(MCP23x17_IOCR_ODR); + + mcp1.mirrorInterrupts(true); for (int i = 0; i < 4; i++) { - mcp1.pinMode(i, INPUT_PULLUP); - mcp1.setupInterruptPin(i, LOW); + mcp1.pinMode1(i, INPUT_PULLUP); + mcp1.enableInterrupt(i, LOW); } #ifndef IS_BTCLOCK_V8 for (int i = 8; i <= 14; i++) { - mcp1.pinMode(i, OUTPUT); + mcp1.pinMode1(i, OUTPUT); } #endif } @@ -538,7 +545,7 @@ void setupHardware() #endif #ifdef IS_BTCLOCK_V8 - if (!mcp2.begin_I2C(0x21)) + if (!mcp2.begin()) { Serial.println(F("Error MCP23017 2")); @@ -790,4 +797,19 @@ const char* getFirmwareFilename() { } else { return ""; } -} \ No newline at end of file +} + +// void loadIcons() { +// size_t ocean_logo_size = 886; + +// int iUncompSize = zt.gzip_info((uint8_t *)epd_compress_bitaxe, ocean_logo_size); +// Serial.printf("uncompressed size = %d\n", iUncompSize); + +// uint8_t *pUncompressed; +// pUncompressed = (uint8_t *)malloc(iUncompSize+4); +// int rc = zt.gunzip((uint8_t *)epd_compress_bitaxe, ocean_logo_size, pUncompressed); + +// if (rc == ZT_SUCCESS) { +// Serial.println("Decode success"); +// } +// } \ No newline at end of file diff --git a/src/lib/config.hpp b/src/lib/config.hpp index 8c9da90..53abe17 100644 --- a/src/lib/config.hpp +++ b/src/lib/config.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include @@ -83,4 +83,6 @@ void addScreenMapping(int value, const char* name); int findScreenIndexByValue(int value); String replaceAmbiguousChars(String input); -const char* getFirmwareFilename(); \ No newline at end of file +const char* getFirmwareFilename(); + +// void loadIcons(); \ No newline at end of file diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 1e27eae..2b30f26 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -191,7 +191,7 @@ void setupDisplays() } // Hold lower button to enable "storage mode" (prevents burn-in of ePaper displays) - if (mcp1.digitalRead(0) == LOW) + if (mcp1.read1(0) == LOW) { setFgColor(GxEPD_BLACK); setBgColor(GxEPD_WHITE); @@ -614,10 +614,19 @@ void renderIcon(const uint dispNum, const String &text, bool partial) iconIndex = 4; } + + + displays[dispNum].drawInvertedBitmap(0,0, epd_icons_allArray[iconIndex], 122, 250, getFgColor()); + +// displays[dispNum].drawInvertedBitmap(0,0, getOceanIcon(), 122, 250, getFgColor()); + + } + + void renderQr(const uint dispNum, const String &text, bool partial) { #ifdef USE_QR diff --git a/src/lib/epd.hpp b/src/lib/epd.hpp index 749f940..1194cf1 100644 --- a/src/lib/epd.hpp +++ b/src/lib/epd.hpp @@ -4,6 +4,7 @@ #include #include + #include #include #include diff --git a/src/lib/shared.cpp b/src/lib/shared.cpp index 20bf6d4..3422ff8 100644 --- a/src/lib/shared.cpp +++ b/src/lib/shared.cpp @@ -143,4 +143,12 @@ String calculateSHA256(WiFiClient *stream, size_t contentLength) { } return result; -} \ No newline at end of file +} + +// uint8_t* getOceanIcon() { +// zlib_turbo zt; +// int iUncompSize = zt.gzip_info((uint8_t *)ocean_logo_comp, ocean_logo_size); +// uint8_t *pUncompressed; +// pUncompressed = (uint8_t *)malloc(iUncompSize+4); +// zt.gunzip((uint8_t *)ocean_logo_comp, ocean_logo_size, pUncompressed); +// } \ No newline at end of file diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index 19d1df0..4753764 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -1,6 +1,7 @@ #pragma once -#include +#include "MCP23017.h" +// #include #include #include #include @@ -17,9 +18,9 @@ #include "defaults.hpp" -extern Adafruit_MCP23X17 mcp1; +extern MCP23017 mcp1; #ifdef IS_BTCLOCK_V8 -extern Adafruit_MCP23X17 mcp2; +extern MCP23017 mcp2; #endif extern Preferences preferences; extern std::mutex mcpMutex; @@ -73,7 +74,12 @@ const int usPerMinute = 60 * usPerSecond; extern const char *isrg_root_x1cert; extern const uint8_t rootca_crt_bundle_start[] asm("_binary_x509_crt_bundle_start"); +// extern const uint8_t ocean_logo_comp[] asm("_binary_ocean_gz_start"); +// extern const uint8_t ocean_logo_comp_end[] asm("_binary_ocean_gz_end"); +// uint8_t* getOceanIcon(); + +// const size_t ocean_logo_size = ocean_logo_comp_end - ocean_logo_comp; const PROGMEM char UPDATE_FIRMWARE = U_FLASH; const PROGMEM char UPDATE_WEBUI = U_SPIFFS; From de8fe2e26eed61918f8133c614860a26d6291f9a Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 18 Dec 2024 20:41:42 +0100 Subject: [PATCH 052/130] Fix preaction script --- scripts/extra_script.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/scripts/extra_script.py b/scripts/extra_script.py index d7e4b31..8451978 100644 --- a/scripts/extra_script.py +++ b/scripts/extra_script.py @@ -5,6 +5,9 @@ from shutil import copyfileobj, rmtree from pathlib import Path import subprocess + + + revision = ( subprocess.check_output(["git", "rev-parse", "HEAD"]) .strip() @@ -43,5 +46,15 @@ def before_buildfs(source, target, env): output_directory = 'data/build_gz' process_directory(input_directory, output_directory) +flash_size = env.BoardConfig().get("upload.flash_size", "4MB") +fs_image_name = f"littlefs_{flash_size}" +env.Replace(ESP32_FS_IMAGE_NAME=fs_image_name) +env.Replace(ESP8266_FS_IMAGE_NAME=fs_image_name) + os.environ["PUBLIC_BASE_URL"] = "" -env.AddPreAction("$BUILD_DIR/littlefs.bin", before_buildfs) +fs_name = env.get("ESP32_FS_IMAGE_NAME", "littlefs.bin") +# Or alternatively: +# fs_name = env.get("FSTOOLNAME", "littlefs.bin") + +# Use the variable in the pre-action +env.AddPreAction(f"$BUILD_DIR/{fs_name}.bin", before_buildfs) From 0dcde59fb4e2d3ac939886689b23e9b2c77b1ab1 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 18 Dec 2024 21:40:18 +0100 Subject: [PATCH 053/130] Fix workflow --- .forgejo/workflows/push.yaml | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/.forgejo/workflows/push.yaml b/.forgejo/workflows/push.yaml index 6ccb926..02458ae 100644 --- a/.forgejo/workflows/push.yaml +++ b/.forgejo/workflows/push.yaml @@ -1,4 +1,4 @@ -name: 'BTClock CI' +name: "BTClock CI" on: push: @@ -22,7 +22,7 @@ jobs: with: node-version: lts/* cache: yarn - cache-dependency-path: '**/yarn.lock' + cache-dependency-path: "**/yarn.lock" - uses: actions/cache@v4 with: path: | @@ -34,8 +34,8 @@ jobs: key: ${{ runner.os }}-pio - uses: actions/setup-python@v5 with: - python-version: '3.9' - cache: 'pip' + python-version: "3.9" + cache: "pip" - name: Get current date id: dateAndTime shell: bash @@ -48,7 +48,7 @@ jobs: run: mkdir -p junit-reports && pio test -e native_test_only --junit-output-path junit-reports/ - name: Build BTClock firmware shell: bash - run: pio run + run: pio run - name: Build BTClock filesystem shell: bash run: pio run --target buildfs @@ -81,9 +81,9 @@ jobs: version: esp32s3 epd_variant: [213epd, 29epd] exclude: - - chip: {name: btclock_rev_b, version: esp32s3} + - chip: { name: btclock_rev_b, version: esp32s3 } epd_variant: 29epd - - chip: {name: btclock_v8, version: esp32s3} + - chip: { name: btclock_v8, version: esp32s3 } epd_variant: 29epd steps: - uses: https://code.forgejo.org/forgejo/download-artifact@v4 @@ -93,7 +93,9 @@ jobs: - name: Install esptools.py run: pip install --upgrade esptool - name: Create merged firmware binary + shell: bash run: | + mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} if [ "${{ matrix.chip.name }}" == "btclock_v8" ]; then esptool.py --chip ${{ matrix.chip.version }} merge_bin \ -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \ @@ -106,7 +108,6 @@ jobs: 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \ 0xDF0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs_16MB.bin elif [ "${{ matrix.chip.name }}" == "btclock_rev_b" ]; then - mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && \ esptool.py --chip ${{ matrix.chip.version }} merge_bin \ -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \ --flash_mode dio \ @@ -118,8 +119,6 @@ jobs: 0x10000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin \ 0x6F0000 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/littlefs_8MB.bin; else - # Original command for other cases - mkdir -p ${{ matrix.chip.name }}_${{ matrix.epd_variant }} && \ esptool.py --chip ${{ matrix.chip.version }} merge_bin \ -o ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin \ --flash_mode dio \ @@ -132,17 +131,20 @@ jobs: fi - name: Create checksum for firmware + shell: bash run: shasum -a 256 .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}_firmware.bin.sha256 - name: Create checksum for merged binary + shell: bash run: shasum -a 256 ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin | awk '{print $1}' > ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}.bin.sha256 - name: Create checksum for littlefs partition + shell: bash run: | fs_file=$(find .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }} -name "littlefs*.bin") shasum -a 256 "$fs_file" | awk '{print $1}' > "${fs_file}.sha256" - - name: Copy all artifacts to output folder - run: cp .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin .pio/boot_app0.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }} + - name: Copy all artifacts to output folder + run: cp .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin .pio/boot_app0.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }} - name: Create OTA binary file run: mv ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/firmware.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${{ matrix.chip.name }}_${{ matrix.epd_variant }}_firmware.bin @@ -173,13 +175,13 @@ jobs: - name: Create release uses: https://code.forgejo.org/actions/forgejo-release@v2.4.0 with: - url: 'https://git.btclock.dev' - repo: '${{ github.repository }}' + url: "https://git.btclock.dev" + repo: "${{ github.repository }}" direction: upload - tag: '${{ github.ref_name }}' - sha: '${{ github.sha }}' + tag: "${{ github.ref_name }}" + sha: "${{ github.sha }}" release-dir: release token: ${{ secrets.TOKEN }} override: ${{ github.ref_type != 'tag' && github.ref_name != 'main' }} prerelease: ${{ github.ref_type != 'tag' && github.ref_name != 'main' }} - release-notes-assistant: false \ No newline at end of file + release-notes-assistant: false From c989169ff46581785e10132db04d980264713571 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 18 Dec 2024 22:20:40 +0100 Subject: [PATCH 054/130] Fix workflow and auto updater webui filenames --- .forgejo/workflows/push.yaml | 2 +- src/lib/config.cpp | 13 +++++++++++++ src/lib/config.hpp | 2 +- src/lib/ota.cpp | 3 +-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/.forgejo/workflows/push.yaml b/.forgejo/workflows/push.yaml index 02458ae..b95439c 100644 --- a/.forgejo/workflows/push.yaml +++ b/.forgejo/workflows/push.yaml @@ -142,7 +142,7 @@ jobs: shell: bash run: | fs_file=$(find .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }} -name "littlefs*.bin") - shasum -a 256 "$fs_file" | awk '{print $1}' > "${fs_file}.sha256" + shasum -a 256 "$fs_file" | awk '{print $1}' > "${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${fs_file}.sha256" - name: Copy all artifacts to output folder run: cp .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin .pio/boot_app0.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }} diff --git a/src/lib/config.cpp b/src/lib/config.cpp index e9912a9..1dac009 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -799,6 +799,19 @@ const char* getFirmwareFilename() { } } +const char* getWebUiFilename() { + if (HW_REV == "REV_B_EPD_2_13") { + return "littlefs_8MB.bin"; + } else if (HW_REV == "REV_A_EPD_2_13") { + return "littlefs_4MB.bin"; + } else if (HW_REV == "REV_A_EPD_2_9") { + return "littlefs_4MB.bin"; + } else { + return "littlefs_4MB.bin"; + } +} + + // void loadIcons() { // size_t ocean_logo_size = 886; diff --git a/src/lib/config.hpp b/src/lib/config.hpp index 53abe17..51aef87 100644 --- a/src/lib/config.hpp +++ b/src/lib/config.hpp @@ -84,5 +84,5 @@ void addScreenMapping(int value, const char* name); int findScreenIndexByValue(int value); String replaceAmbiguousChars(String input); const char* getFirmwareFilename(); - +const char* getWebUiFilename(); // void loadIcons(); \ No newline at end of file diff --git a/src/lib/ota.cpp b/src/lib/ota.cpp index 1800f76..05c45e1 100644 --- a/src/lib/ota.cpp +++ b/src/lib/ota.cpp @@ -171,14 +171,13 @@ int downloadUpdateHandler(char updateType) break; case UPDATE_WEBUI: { - latestRelease = getLatestRelease("littlefs.bin"); + latestRelease = getLatestRelease(getWebUiFilename()); // updateWebUi(latestRelease.fileUrl, U_SPIFFS); // return 0; } break; } - // First, download the expected SHA256 String expectedSHA256 = downloadSHA256(latestRelease.checksumUrl); if (expectedSHA256.isEmpty()) From ae2e6656dfaef3cf762c86057b3716871b0fb850 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 18 Dec 2024 22:52:50 +0100 Subject: [PATCH 055/130] Fix LittleFS sha256 generation --- .forgejo/workflows/push.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/push.yaml b/.forgejo/workflows/push.yaml index b95439c..219205f 100644 --- a/.forgejo/workflows/push.yaml +++ b/.forgejo/workflows/push.yaml @@ -142,7 +142,10 @@ jobs: shell: bash run: | fs_file=$(find .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }} -name "littlefs*.bin") - shasum -a 256 "$fs_file" | awk '{print $1}' > "${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${fs_file}.sha256" + echo $fs_file + fs_name=$(basename "$fs_file") + shasum -a 256 "$fs_file" | awk '{print $1}' > "${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${fs_name}.sha256" + cat "${{ matrix.chip.name }}_${{ matrix.epd_variant }}/${fs_name}.sha256" - name: Copy all artifacts to output folder run: cp .pio/build/${{ matrix.chip.name }}_${{ matrix.epd_variant }}/*.bin .pio/boot_app0.bin ${{ matrix.chip.name }}_${{ matrix.epd_variant }} From 1bd465b33acdb241389cdde1dcdcdcdb8c55789d Mon Sep 17 00:00:00 2001 From: kdmukai Date: Tue, 17 Dec 2024 20:17:21 -0600 Subject: [PATCH 056/130] rebuilt with larger partitions --- lib/btclock/mining_pool_stats_handler.cpp | 66 +++ lib/btclock/mining_pool_stats_handler.hpp | 4 + partition_8mb.csv | 2 +- platformio.ini | 1 + src/icons/icons.cpp | 516 +++++++++++++++++++++- src/lib/config.cpp | 10 + src/lib/config.hpp | 1 + src/lib/defaults.hpp | 7 + src/lib/epd.cpp | 6 + src/lib/mining_pool_stats_fetch.cpp | 120 +++++ src/lib/mining_pool_stats_fetch.hpp | 15 + src/lib/screen_handler.cpp | 24 +- src/lib/screen_handler.hpp | 4 +- src/lib/shared.hpp | 2 + src/lib/timers.cpp | 4 + src/lib/webserver.cpp | 8 +- 16 files changed, 782 insertions(+), 8 deletions(-) create mode 100644 lib/btclock/mining_pool_stats_handler.cpp create mode 100644 lib/btclock/mining_pool_stats_handler.hpp create mode 100644 src/lib/mining_pool_stats_fetch.cpp create mode 100644 src/lib/mining_pool_stats_fetch.hpp diff --git a/lib/btclock/mining_pool_stats_handler.cpp b/lib/btclock/mining_pool_stats_handler.cpp new file mode 100644 index 0000000..17eb4c8 --- /dev/null +++ b/lib/btclock/mining_pool_stats_handler.cpp @@ -0,0 +1,66 @@ +#include "mining_pool_stats_handler.hpp" +#include + +std::array parseMiningPoolStatsHashRate(std::string miningPoolName, std::string text) +{ + std::array ret; + ret.fill(""); // Initialize all elements to empty strings + std::string hashrate; + std::string label; + + if (text.length() > 21) { + // We are massively future-proof!! + label = "ZH/S"; + hashrate = text.substr(0, text.length() - 21); + } else if (text.length() > 18) { + label = "EH/S"; + hashrate = text.substr(0, text.length() - 18); + } else if (text.length() > 15) { + label = "PH/S"; + hashrate = text.substr(0, text.length() - 15); + } else if (text.length() > 12) { + label = "TH/S"; + hashrate = text.substr(0, text.length() - 12); + } else if (text.length() > 9) { + label = "GH/S"; + hashrate = text.substr(0, text.length() - 9); + } else if (text.length() > 6) { + label = "MH/S"; + hashrate = text.substr(0, text.length() - 6); + } else if (text.length() > 3) { + label = "KH/S"; + hashrate = text.substr(0, text.length() - 3); + } else { + label = "H/S"; + hashrate = text; + } + + std::size_t textLength = hashrate.length(); + + // Calculate the position where the digits should start + // Account for the position of the mining pool logo and the hashrate label + std::size_t startIndex = NUM_SCREENS - 1 - textLength; + + std::cout << "miningPoolName: " << miningPoolName << std::endl; + + // Insert the mining pool logo icon just before the digits + if (startIndex > 0) + { + if (miningPoolName == "ocean") { + ret[startIndex - 1] = "mdi:braiins_logo"; + } else if (miningPoolName == "braiins") { + ret[startIndex - 1] = "mdi:braiins_logo"; + } + } + + // Place the digits + for (std::size_t i = 0; i < textLength; ++i) + { + ret[startIndex + i] = hashrate.substr(i, 1); + } + + ret[NUM_SCREENS - 1] = label; + ret[0] = "POOL/STATS"; + + return ret; +} \ No newline at end of file diff --git a/lib/btclock/mining_pool_stats_handler.hpp b/lib/btclock/mining_pool_stats_handler.hpp new file mode 100644 index 0000000..b79d8f9 --- /dev/null +++ b/lib/btclock/mining_pool_stats_handler.hpp @@ -0,0 +1,4 @@ +#include +#include + +std::array parseMiningPoolStatsHashRate(std::string miningPoolName, std::string text); \ No newline at end of file diff --git a/partition_8mb.csv b/partition_8mb.csv index 025f649..e0584ae 100644 --- a/partition_8mb.csv +++ b/partition_8mb.csv @@ -4,4 +4,4 @@ otadata, data, ota, 0xe000, 0x2000, app0, app, ota_0, 0x10000, 0x370000, app1, app, ota_1, , 0x370000, spiffs, data, spiffs, , 0xCD000, -coredump, data, coredump,, 0x10000, \ No newline at end of file +coredump, data, coredump,, 0x10000, diff --git a/platformio.ini b/platformio.ini index d2abb92..125ad96 100644 --- a/platformio.ini +++ b/platformio.ini @@ -96,6 +96,7 @@ build_flags = [env:btclock_rev_b_213epd] extends = env:btclock_rev_b +board_build.partitions = partition_8mb.csv test_framework = unity build_flags = ${env:btclock_rev_b.build_flags} diff --git a/src/icons/icons.cpp b/src/icons/icons.cpp index ca69f63..d80fde1 100644 --- a/src/icons/icons.cpp +++ b/src/icons/icons.cpp @@ -1270,12 +1270,524 @@ const unsigned char epd_icons_bitaxe_logo [] PROGMEM = { }; +// 'ocean_logo', 122x250px +const unsigned char epd_icons_ocean_logo [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x78, 0x00, 0x1f, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xfc, 0x00, 0x3f, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0x00, 0x7f, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x00, 0x7f, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xc0, + 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xc0, + 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xc0, + 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xc0, + 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xc0, + 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xc0, + 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xc0, + 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xc0, + 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xc0, + 0xff, 0x80, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xc0, + 0xff, 0x80, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xc0, + 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xc0, + 0xff, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x3f, 0xc0, + 0xff, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x1f, 0xc0, + 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x1f, 0xc0, + 0xfe, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xc0, + 0xfe, 0x00, 0x00, 0x03, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xc0, + 0xfe, 0x00, 0x00, 0x01, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xc0, + 0xfe, 0x00, 0x00, 0x01, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0x00, 0x1f, 0xc0, + 0xfe, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf0, 0xff, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x1f, 0xc0, + 0xfe, 0x00, 0x78, 0x00, 0x7f, 0xff, 0xf1, 0xff, 0xfc, 0x00, 0x03, 0xff, 0xff, 0xc0, 0x1f, 0xc0, + 0xfe, 0x00, 0xfc, 0x00, 0x3f, 0xff, 0xf1, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xff, 0xc0, 0x1f, 0xc0, + 0xff, 0x00, 0xff, 0x00, 0x1f, 0xff, 0xf1, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xc0, + 0xff, 0x01, 0xff, 0x80, 0x1f, 0xff, 0xf3, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xc0, + 0xff, 0x01, 0xff, 0xc0, 0x0f, 0xff, 0xe3, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xc0, + 0xff, 0x01, 0xff, 0xe0, 0x07, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xc0, + 0xff, 0x81, 0xff, 0xf8, 0x03, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xc0, + 0xff, 0x81, 0xff, 0xfc, 0x01, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xc0, + 0xff, 0x83, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xc0, + 0xff, 0xc3, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xc0, + 0xff, 0xc3, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xc0, + 0xff, 0xe3, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xc0, + 0xff, 0xe3, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xc0, + 0xff, 0xf3, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfc, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xf9, 0xff, 0xc0, + 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xf9, 0xff, 0xc0, + 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0xf0, 0xff, 0xc0, + 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xf0, 0xff, 0xc0, + 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xf0, 0x7f, 0xc0, + 0xff, 0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0x7f, 0xc0, + 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xf0, 0x07, 0xff, 0xf0, 0x7f, 0xc0, + 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xf8, 0x03, 0xff, 0xf0, 0x3f, 0xc0, + 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xf8, 0x01, 0xff, 0xe0, 0x3f, 0xc0, + 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xf1, 0xff, 0xfc, 0x00, 0xff, 0xe0, 0x3f, 0xc0, + 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xf1, 0xff, 0xfe, 0x00, 0x3f, 0xe0, 0x1f, 0xc0, + 0xff, 0x00, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xf1, 0xff, 0xff, 0x00, 0x1f, 0xe0, 0x1f, 0xc0, + 0xfe, 0x00, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xf1, 0xff, 0xff, 0x80, 0x0f, 0xc0, 0x1f, 0xc0, + 0xfe, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x07, 0xff, 0xe1, 0xff, 0xff, 0x80, 0x07, 0x80, 0x1f, 0xc0, + 0xfe, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xe3, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x1f, 0xc0, + 0xfe, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xc0, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xc0, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xc0, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xc0, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x1f, 0xc0, + 0xff, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xc0, + 0xff, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xc0, + 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x80, 0x00, 0x3f, 0xc0, + 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x80, 0x00, 0x3f, 0xc0, + 0xff, 0x80, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xc0, + 0xff, 0x80, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xc0, + 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xc0, + 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xc0, + 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xc0, + 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xc0, + 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xc0, + 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xc0, + 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xc0, 0x0f, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0x80, 0x0f, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0x80, 0x0f, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x07, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + + +// 'braiins_pool', 122x250px +const unsigned char epd_icons_braiins_logo [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xe0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xc0, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xc0, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xc0, 0x38, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0x7c, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x00, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x01, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x01, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf0, 0x1f, 0x01, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf0, 0x0c, 0x01, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf0, 0x00, 0x01, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf8, 0x00, 0x03, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf8, 0x00, 0x03, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xfc, 0x00, 0x07, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xc0, + 0xff, 0xfe, 0x00, 0x0f, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0x00, 0x1f, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x3f, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0x00, 0x00, 0x01, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x03, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x03, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x03, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x03, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x07, 0xff, 0x81, 0xff, 0xe0, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x07, 0xfe, 0x00, 0x7f, 0xe0, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xf8, 0x00, 0x1f, 0xf0, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x00, 0x0f, 0xf0, 0x00, 0x0f, 0xf0, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x0f, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x07, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xc0, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x03, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x07, 0xc0, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x06, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x03, 0xff, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x03, 0xff, 0x00, 0x07, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x03, 0xff, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xfc, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x03, 0xff, 0x00, 0x07, 0xff, 0x00, 0xff, 0xe0, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x03, 0xff, 0x00, 0x0f, 0xfc, 0x00, 0x3f, 0xe0, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0x00, 0x0f, 0xf8, 0x00, 0x1f, 0xf0, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xf0, 0x00, 0x0f, 0xf0, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x07, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x07, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x03, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xc0, 0x00, 0x03, 0xf0, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x07, 0x80, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0x00, 0x07, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x07, 0xff, 0xff, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xfc, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x03, 0xff, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xfc, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xfe, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xf3, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0x00, 0x0f, 0xff, 0xc3, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xfe, 0x00, 0x07, 0xff, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xfc, 0x00, 0x03, 0xfc, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xf8, 0x00, 0x01, 0xf0, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xf0, 0x00, 0x00, 0xc0, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x1f, 0x80, 0x00, 0x07, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xc0, 0x00, 0x1f, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xe0, 0x00, 0x7f, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xe0, 0x01, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xe0, 0x0f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xe0, 0x3f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xe0, 0x7f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xe0, 0x7f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xe0, 0x7f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xe0, 0x7f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xe0, 0x7f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0xc0, 0x3f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x00, 0xfc, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xfc, 0x00, 0x38, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf8, 0x00, 0x10, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x7c, 0x03, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x1e, 0x00, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + + // Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 8032) -const int epd_icons_allArray_LEN = 5; +const int epd_icons_allArray_LEN = 7; const unsigned char* epd_icons_allArray[epd_icons_allArray_LEN] = { epd_icons_pickaxe, epd_icons_rocket_launch, epd_icons_lightning, epd_icons_flash, - epd_icons_bitaxe_logo + epd_icons_bitaxe_logo, + epd_icons_ocean_logo, + epd_icons_braiins_logo }; diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 1dac009..f764b54 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -95,6 +95,11 @@ void setup() setupBitaxeFetchTask(); } + if (preferences.getBool("miningPoolStatsEnabled", DEFAULT_MINING_POOL_STATS_ENABLED)) + { + setupMiningPoolStatsFetchTask(); + } + setupButtonTask(); setupOTA(); @@ -331,6 +336,11 @@ void setupPreferences() addScreenMapping(SCREEN_BITAXE_HASHRATE, "BitAxe Hashrate"); addScreenMapping(SCREEN_BITAXE_BESTDIFF, "BitAxe Best Difficulty"); } + + if (preferences.getBool("miningPoolStatsEnabled", DEFAULT_MINING_POOL_STATS_ENABLED)) + { + addScreenMapping(SCREEN_MINING_POOL_STATS_HASHRATE, "Mining Pool Hashrate"); + } } String replaceAmbiguousChars(String input) diff --git a/src/lib/config.hpp b/src/lib/config.hpp index 51aef87..87dd4d6 100644 --- a/src/lib/config.hpp +++ b/src/lib/config.hpp @@ -18,6 +18,7 @@ #include "lib/ota.hpp" #include "lib/nostr_notify.hpp" #include "lib/bitaxe_fetch.hpp" +#include "lib/mining_pool_stats_fetch.hpp" #include "lib/v2_notify.hpp" diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index 11df69a..8380f46 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -58,6 +58,13 @@ #define DEFAULT_BITAXE_ENABLED false #define DEFAULT_BITAXE_HOSTNAME "bitaxe1" +#define MINING_POOL_NAME_OCEAN "ocean" +#define MINING_POOL_NAME_BRAIINS "braiins" + +#define DEFAULT_MINING_POOL_STATS_ENABLED true +#define DEFAULT_MINING_POOL_NAME MINING_POOL_NAME_OCEAN +#define DEFAULT_MINING_POOL_USER "38Qkkei3SuF1Eo45BaYmRHUneRD54yyTFy" // Random actual Ocean hasher + #define DEFAULT_ZAP_NOTIFY_ENABLED false #define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422" #define DEFAULT_LED_FLASH_ON_ZAP true diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 2b30f26..5281087 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -613,6 +613,12 @@ void renderIcon(const uint dispNum, const String &text, bool partial) else if (text.endsWith("bitaxe")) { iconIndex = 4; } + else if (text.endsWith("ocean_logo")) { + iconIndex = 5; + } + else if (text.endsWith("braiins_logo")) { + iconIndex = 6; + } diff --git a/src/lib/mining_pool_stats_fetch.cpp b/src/lib/mining_pool_stats_fetch.cpp new file mode 100644 index 0000000..6fd3914 --- /dev/null +++ b/src/lib/mining_pool_stats_fetch.cpp @@ -0,0 +1,120 @@ +#include "mining_pool_stats_fetch.hpp" + +TaskHandle_t miningPoolStatsFetchTaskHandle; + +std::string miningPoolStatsHashrate; +std::string miningPoolStatsBestDiff; + +std::string getMiningPoolStatsHashRate() +{ + return miningPoolStatsHashrate; +} + + +void taskMiningPoolStatsFetch(void *pvParameters) +{ + for (;;) + { + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + HTTPClient http; + http.setUserAgent(USER_AGENT); + String miningPoolStatsApiUrl; + + // TODO: Remove when webui gets proper update + Serial.println("FORCING miningPoolUser"); + preferences.putString("miningPoolName", MINING_POOL_NAME_OCEAN); + + Serial.println("miningPoolName: \"" + preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) + "\""); + Serial.println("miningPoolUser: \"" + preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER) + "\""); + + std::string httpHeaderKey = ""; + std::string httpHeaderValue; + if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_OCEAN) { + miningPoolStatsApiUrl = "https://api.ocean.xyz/v1/statsnap/" + preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER); + Serial.println(miningPoolStatsApiUrl); + + } + else if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_BRAIINS) { + miningPoolStatsApiUrl = "https://pool.braiins.com/accounts/profile/json/btc/"; + httpHeaderKey = "Pool-Auth-Token"; + httpHeaderValue = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str(); + Serial.println(miningPoolStatsApiUrl); + } + else + { + Serial.println("Unknown mining pool: \"" + preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) + "\""); + continue; + } + + http.begin(miningPoolStatsApiUrl.c_str()); + + if (httpHeaderKey.length() > 0) { + http.addHeader(httpHeaderKey.c_str(), httpHeaderValue.c_str()); + } + + int httpCode = http.GET(); + + if (httpCode == 200) + { + String payload = http.getString(); + JsonDocument doc; + deserializeJson(doc, payload); + + Serial.println(doc.as()); + + if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_OCEAN) { + Serial.println(doc["result"].as()); + Serial.println(doc["result"]["hashrate_300s"].as()); + miningPoolStatsHashrate = doc["result"]["hashrate_300s"].as(); + } + else if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_BRAIINS) { + // Reports hashrate in specific hashrate units (e.g. Gh/s); we want raw total hashes per second. + std::string hashrateUnit = doc["btc"]["hash_rate_unit"].as(); + Serial.println(doc["btc"]["hash_rate_unit"].as()); + int multiplier = 0; + if (hashrateUnit == "Zh/s") { + multiplier = 21; + } else if (hashrateUnit == "Eh/s") { + multiplier = 18; + } else if (hashrateUnit == "Ph/s") { + multiplier = 15; + } else if (hashrateUnit == "Th/s") { + multiplier = 12; + } else if (hashrateUnit == "Gh/s") { + multiplier = 9; + } else if (hashrateUnit == "Mh/s") { + multiplier = 6; + } else if (hashrateUnit == "Kh/s") { + multiplier = 3; + } + + // Add zeroes to pad to a full h/s output + miningPoolStatsHashrate = std::to_string(static_cast(std::round(doc["btc"]["hash_rate_5m"].as()))) + std::string(multiplier, '0'); + Serial.println(miningPoolStatsHashrate.c_str()); + } + + // if (workQueue != nullptr && (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || getCurrentScreen() == SCREEN_MINING_POOL_STATS_BESTDIFF)) + if (workQueue != nullptr && (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE)) + { + WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0}; + xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); + } + } + else + { + Serial.print( + F("Error retrieving mining pool data. HTTP status code: ")); + Serial.println(httpCode); + Serial.println(miningPoolStatsApiUrl); + } + } +} + +void setupMiningPoolStatsFetchTask() +{ + xTaskCreate(taskMiningPoolStatsFetch, "miningPoolStatsFetch", (6 * 1024), NULL, tskIDLE_PRIORITY, + &miningPoolStatsFetchTaskHandle); + + xTaskNotifyGive(miningPoolStatsFetchTaskHandle); +} \ No newline at end of file diff --git a/src/lib/mining_pool_stats_fetch.hpp b/src/lib/mining_pool_stats_fetch.hpp new file mode 100644 index 0000000..f06207b --- /dev/null +++ b/src/lib/mining_pool_stats_fetch.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#include "lib/config.hpp" +#include "lib/shared.hpp" + +extern TaskHandle_t miningPoolStatsFetchTaskHandle; + +void setupMiningPoolStatsFetchTask(); +void taskMiningPoolStatsFetch(void *pvParameters); + +std::string getMiningPoolStatsHashRate(); +// std::string getMiningPoolStatsBestDiff(); \ No newline at end of file diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 1f2b4a4..5d8c41c 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -33,9 +33,19 @@ void workerTask(void *pvParameters) { parseBitaxeBestDiff(getBitaxeBestDiff()); } setEpdContent(taskEpdContent); - + break; + } + case TASK_MINING_POOL_STATS_UPDATE: { + if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) { + taskEpdContent = + parseMiningPoolStatsHashRate(preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(), getMiningPoolStatsHashRate()); + // } else if (getCurrentScreen() == SCREEN_BITAXE_BESTDIFF) { + // taskEpdContent = + // parseBitaxeBestDiff(getBitaxeBestDiff()); + } + setEpdContent(taskEpdContent); + break; } - break; case TASK_PRICE_UPDATE: { uint currency = getCurrentCurrency(); uint price = getPrice(currency); @@ -179,6 +189,16 @@ void setCurrentScreen(uint newScreen) { return; } break; + } + case SCREEN_MINING_POOL_STATS_HASHRATE: { + if (preferences.getBool("miningPoolStatsEnabled", DEFAULT_MINING_POOL_STATS_ENABLED)) { + WorkItem miningPoolStatsUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0}; + xQueueSend(workQueue, &miningPoolStatsUpdate, portMAX_DELAY); + } else { + setCurrentScreen(SCREEN_BLOCK_HEIGHT); + return; + } + break; } } diff --git a/src/lib/screen_handler.hpp b/src/lib/screen_handler.hpp index 6c99a7c..ee658c9 100644 --- a/src/lib/screen_handler.hpp +++ b/src/lib/screen_handler.hpp @@ -6,6 +6,7 @@ #include #include +#include #include "lib/epd.hpp" #include "lib/shared.hpp" @@ -23,7 +24,8 @@ typedef enum { TASK_BLOCK_UPDATE, TASK_FEE_UPDATE, TASK_TIME_UPDATE, - TASK_BITAXE_UPDATE + TASK_BITAXE_UPDATE, + TASK_MINING_POOL_STATS_UPDATE } TaskType; typedef struct { diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index 4753764..5fc2c2b 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -60,6 +60,8 @@ const PROGMEM int SCREEN_MARKET_CAP = 30; const PROGMEM int SCREEN_BITAXE_HASHRATE = 80; const PROGMEM int SCREEN_BITAXE_BESTDIFF = 81; +const PROGMEM int SCREEN_MINING_POOL_STATS_HASHRATE = 85; + const PROGMEM int SCREEN_COUNTDOWN = 98; const PROGMEM int SCREEN_CUSTOM = 99; const int SCREEN_COUNT = 7; diff --git a/src/lib/timers.cpp b/src/lib/timers.cpp index d84d358..2fdb71c 100644 --- a/src/lib/timers.cpp +++ b/src/lib/timers.cpp @@ -72,6 +72,10 @@ void IRAM_ATTR minuteTimerISR(void *arg) { vTaskNotifyGiveFromISR(bitaxeFetchTaskHandle, &xHigherPriorityTaskWoken); } + if (miningPoolStatsFetchTaskHandle != NULL) { + vTaskNotifyGiveFromISR(miningPoolStatsFetchTaskHandle, &xHigherPriorityTaskWoken); + } + if (xHigherPriorityTaskWoken == pdTRUE) { portYIELD_FROM_ISR(); } diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 11b9024..0a55ff8 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -510,7 +510,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) settings["timePerScreen"].as() * 60); } - String strSettings[] = {"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl"}; + String strSettings[] = {"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl"}; for (String setting : strSettings) { @@ -549,7 +549,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) "mowMode", "suffixShareDot", "flOffWhenDark", "flAlwaysOn", "flDisable", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", - "verticalDesc", + "miningPoolStatsEnabled", "verticalDesc", "nostrZapNotify", "stagingSource", "httpAuthEnabled"}; for (String setting : boolSettings) @@ -714,6 +714,10 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["bitaxeEnabled"] = preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED); root["bitaxeHostname"] = preferences.getString("bitaxeHostname", DEFAULT_BITAXE_HOSTNAME); + root["miningPoolStatsEnabled"] = preferences.getBool("miningPoolStatsEnabled", DEFAULT_MINING_POOL_STATS_ENABLED); + root["miningPoolName"] = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME); + root["miningPoolUser"] = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER); + root["httpAuthEnabled"] = preferences.getBool("httpAuthEnabled", DEFAULT_HTTP_AUTH_ENABLED); root["httpAuthUser"] = preferences.getString("httpAuthUser", DEFAULT_HTTP_AUTH_USERNAME); root["httpAuthPass"] = preferences.getString("httpAuthPass", DEFAULT_HTTP_AUTH_PASSWORD); From 2bc5984f6ffb28f8ff1830ad44479bdea71838d2 Mon Sep 17 00:00:00 2001 From: kdmukai Date: Wed, 18 Dec 2024 15:58:12 -0600 Subject: [PATCH 057/130] Add mining pool daily/expected earnings --- lib/btclock/mining_pool_stats_handler.cpp | 84 ++++++++++++++++++++--- lib/btclock/mining_pool_stats_handler.hpp | 3 +- src/lib/config.cpp | 1 + src/lib/defaults.hpp | 2 +- src/lib/mining_pool_stats_fetch.cpp | 26 +++---- src/lib/mining_pool_stats_fetch.hpp | 2 +- src/lib/screen_handler.cpp | 9 +-- src/lib/shared.hpp | 1 + 8 files changed, 95 insertions(+), 33 deletions(-) diff --git a/lib/btclock/mining_pool_stats_handler.cpp b/lib/btclock/mining_pool_stats_handler.cpp index 17eb4c8..6802e42 100644 --- a/lib/btclock/mining_pool_stats_handler.cpp +++ b/lib/btclock/mining_pool_stats_handler.cpp @@ -41,16 +41,10 @@ std::array parseMiningPoolStatsHashRate(std::string mi // Account for the position of the mining pool logo and the hashrate label std::size_t startIndex = NUM_SCREENS - 1 - textLength; - std::cout << "miningPoolName: " << miningPoolName << std::endl; - - // Insert the mining pool logo icon just before the digits + // Insert the pickaxe icon just before the digits if (startIndex > 0) { - if (miningPoolName == "ocean") { - ret[startIndex - 1] = "mdi:braiins_logo"; - } else if (miningPoolName == "braiins") { - ret[startIndex - 1] = "mdi:braiins_logo"; - } + ret[startIndex - 1] = "mdi:pickaxe"; } // Place the digits @@ -60,7 +54,79 @@ std::array parseMiningPoolStatsHashRate(std::string mi } ret[NUM_SCREENS - 1] = label; - ret[0] = "POOL/STATS"; + + // Set the mining pool logo + if (miningPoolName == "ocean") { + ret[0] = "mdi:ocean_logo"; + } else if (miningPoolName == "braiins") { + ret[0] = "mdi:braiins_logo"; + } + + return ret; +} + + +std::array parseMiningPoolStatsDailyEarnings(std::string miningPoolName, int sats) +{ + std::array ret; + ret.fill(""); // Initialize all elements to empty strings + std::string satsDisplay = std::to_string(sats); + std::string label; + + if (miningPoolName == "braiins") { + // fpps guarantees payout; report current daily earnings + label = "sats/earned"; + } else { + // TIDES can only estimate earnings on the next block Ocean finds + label = "sats/block"; + } + + if (sats >= 100000000) { + // A whale mining 1+ BTC per day! No decimal points; whales scoff at such things. + label = "BTC" + label.substr(4); + satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 8); + } else if (sats >= 10000000) { + // 10.0M to 99.9M you get one decimal point + satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 6) + "." + satsDisplay[2] + "M"; + } else if (sats >= 1000000) { + // 1.00M to 9.99M you get two decimal points + satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 6) + "." + satsDisplay.substr(2, 2) + "M"; + } else if (sats >= 100000) { + // 100K to 999K you get no extra precision + satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 3) + "K"; + } else if (sats >= 10000) { + // 10.0K to 99.9K you get one decimal point + satsDisplay = satsDisplay.substr(0, satsDisplay.length() - 3) + "." + satsDisplay[2] + "K"; + } else { + // Pleb miner! 4 digit or fewer sats will fit as-is. no-op. + } + + std::size_t textLength = satsDisplay.length(); + + // Calculate the position where the digits should start + // Account for the position of the mining pool logo + std::size_t startIndex = NUM_SCREENS - 1 - textLength; + + // Insert the pickaxe icon just before the digits if there's room + if (startIndex > 0) + { + ret[startIndex - 1] = "mdi:pickaxe"; + } + + // Place the digits + for (std::size_t i = 0; i < textLength; ++i) + { + ret[startIndex + i] = satsDisplay.substr(i, 1); + } + + ret[NUM_SCREENS - 1] = label; + + // Set the mining pool logo + if (miningPoolName == "ocean") { + ret[0] = "mdi:ocean_logo"; + } else if (miningPoolName == "braiins") { + ret[0] = "mdi:braiins_logo"; + } return ret; } \ No newline at end of file diff --git a/lib/btclock/mining_pool_stats_handler.hpp b/lib/btclock/mining_pool_stats_handler.hpp index b79d8f9..495c7db 100644 --- a/lib/btclock/mining_pool_stats_handler.hpp +++ b/lib/btclock/mining_pool_stats_handler.hpp @@ -1,4 +1,5 @@ #include #include -std::array parseMiningPoolStatsHashRate(std::string miningPoolName, std::string text); \ No newline at end of file +std::array parseMiningPoolStatsHashRate(std::string miningPoolName, std::string text); +std::array parseMiningPoolStatsDailyEarnings(std::string miningPoolName, int sats); diff --git a/src/lib/config.cpp b/src/lib/config.cpp index f764b54..d8e71ef 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -340,6 +340,7 @@ void setupPreferences() if (preferences.getBool("miningPoolStatsEnabled", DEFAULT_MINING_POOL_STATS_ENABLED)) { addScreenMapping(SCREEN_MINING_POOL_STATS_HASHRATE, "Mining Pool Hashrate"); + addScreenMapping(SCREEN_MINING_POOL_STATS_EARNINGS, "Mining Pool Earnings"); } } diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index 8380f46..3d28829 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -61,7 +61,7 @@ #define MINING_POOL_NAME_OCEAN "ocean" #define MINING_POOL_NAME_BRAIINS "braiins" -#define DEFAULT_MINING_POOL_STATS_ENABLED true +#define DEFAULT_MINING_POOL_STATS_ENABLED false #define DEFAULT_MINING_POOL_NAME MINING_POOL_NAME_OCEAN #define DEFAULT_MINING_POOL_USER "38Qkkei3SuF1Eo45BaYmRHUneRD54yyTFy" // Random actual Ocean hasher diff --git a/src/lib/mining_pool_stats_fetch.cpp b/src/lib/mining_pool_stats_fetch.cpp index 6fd3914..9de1cd7 100644 --- a/src/lib/mining_pool_stats_fetch.cpp +++ b/src/lib/mining_pool_stats_fetch.cpp @@ -3,13 +3,17 @@ TaskHandle_t miningPoolStatsFetchTaskHandle; std::string miningPoolStatsHashrate; -std::string miningPoolStatsBestDiff; +int miningPoolStatsDailyEarnings; std::string getMiningPoolStatsHashRate() { return miningPoolStatsHashrate; } +int getMiningPoolStatsDailyEarnings() +{ + return miningPoolStatsDailyEarnings; +} void taskMiningPoolStatsFetch(void *pvParameters) { @@ -21,25 +25,15 @@ void taskMiningPoolStatsFetch(void *pvParameters) http.setUserAgent(USER_AGENT); String miningPoolStatsApiUrl; - // TODO: Remove when webui gets proper update - Serial.println("FORCING miningPoolUser"); - preferences.putString("miningPoolName", MINING_POOL_NAME_OCEAN); - - Serial.println("miningPoolName: \"" + preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) + "\""); - Serial.println("miningPoolUser: \"" + preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER) + "\""); - std::string httpHeaderKey = ""; std::string httpHeaderValue; if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_OCEAN) { miningPoolStatsApiUrl = "https://api.ocean.xyz/v1/statsnap/" + preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER); - Serial.println(miningPoolStatsApiUrl); - } else if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_BRAIINS) { miningPoolStatsApiUrl = "https://pool.braiins.com/accounts/profile/json/btc/"; httpHeaderKey = "Pool-Auth-Token"; httpHeaderValue = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str(); - Serial.println(miningPoolStatsApiUrl); } else { @@ -64,14 +58,12 @@ void taskMiningPoolStatsFetch(void *pvParameters) Serial.println(doc.as()); if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_OCEAN) { - Serial.println(doc["result"].as()); - Serial.println(doc["result"]["hashrate_300s"].as()); miningPoolStatsHashrate = doc["result"]["hashrate_300s"].as(); + miningPoolStatsDailyEarnings = int(doc["result"]["estimated_earn_next_block"].as() * 100000000); } else if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_BRAIINS) { // Reports hashrate in specific hashrate units (e.g. Gh/s); we want raw total hashes per second. std::string hashrateUnit = doc["btc"]["hash_rate_unit"].as(); - Serial.println(doc["btc"]["hash_rate_unit"].as()); int multiplier = 0; if (hashrateUnit == "Zh/s") { multiplier = 21; @@ -91,11 +83,11 @@ void taskMiningPoolStatsFetch(void *pvParameters) // Add zeroes to pad to a full h/s output miningPoolStatsHashrate = std::to_string(static_cast(std::round(doc["btc"]["hash_rate_5m"].as()))) + std::string(multiplier, '0'); - Serial.println(miningPoolStatsHashrate.c_str()); + + miningPoolStatsDailyEarnings = int(doc["btc"]["today_reward"].as() * 100000000); } - // if (workQueue != nullptr && (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || getCurrentScreen() == SCREEN_MINING_POOL_STATS_BESTDIFF)) - if (workQueue != nullptr && (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE)) + if (workQueue != nullptr && (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS)) { WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0}; xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); diff --git a/src/lib/mining_pool_stats_fetch.hpp b/src/lib/mining_pool_stats_fetch.hpp index f06207b..bae5267 100644 --- a/src/lib/mining_pool_stats_fetch.hpp +++ b/src/lib/mining_pool_stats_fetch.hpp @@ -12,4 +12,4 @@ void setupMiningPoolStatsFetchTask(); void taskMiningPoolStatsFetch(void *pvParameters); std::string getMiningPoolStatsHashRate(); -// std::string getMiningPoolStatsBestDiff(); \ No newline at end of file +int getMiningPoolStatsDailyEarnings(); diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 5d8c41c..84f91d6 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -39,9 +39,9 @@ void workerTask(void *pvParameters) { if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) { taskEpdContent = parseMiningPoolStatsHashRate(preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(), getMiningPoolStatsHashRate()); - // } else if (getCurrentScreen() == SCREEN_BITAXE_BESTDIFF) { - // taskEpdContent = - // parseBitaxeBestDiff(getBitaxeBestDiff()); + } else if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS) { + taskEpdContent = + parseMiningPoolStatsDailyEarnings(preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(), getMiningPoolStatsDailyEarnings()); } setEpdContent(taskEpdContent); break; @@ -190,7 +190,8 @@ void setCurrentScreen(uint newScreen) { } break; } - case SCREEN_MINING_POOL_STATS_HASHRATE: { + case SCREEN_MINING_POOL_STATS_HASHRATE: + case SCREEN_MINING_POOL_STATS_EARNINGS: { if (preferences.getBool("miningPoolStatsEnabled", DEFAULT_MINING_POOL_STATS_ENABLED)) { WorkItem miningPoolStatsUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0}; xQueueSend(workQueue, &miningPoolStatsUpdate, portMAX_DELAY); diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index 5fc2c2b..22e40b2 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -61,6 +61,7 @@ const PROGMEM int SCREEN_BITAXE_HASHRATE = 80; const PROGMEM int SCREEN_BITAXE_BESTDIFF = 81; const PROGMEM int SCREEN_MINING_POOL_STATS_HASHRATE = 85; +const PROGMEM int SCREEN_MINING_POOL_STATS_EARNINGS = 86; const PROGMEM int SCREEN_COUNTDOWN = 98; const PROGMEM int SCREEN_CUSTOM = 99; From e175b5f2f5389c57eef6a5fd22d7082459a5c70d Mon Sep 17 00:00:00 2001 From: kdmukai Date: Wed, 18 Dec 2024 16:00:47 -0600 Subject: [PATCH 058/130] syncing to my forked webui submodule --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index d8b183a..e44bd8c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "data"] path = data - url = https://git.btclock.dev/btclock/webui.git + url = https://git.btclock.dev/kdmukai/webui.git From fabc6c1d28ffb8db5f5a64c97a23e006cdc88690 Mon Sep 17 00:00:00 2001 From: kdmukai Date: Wed, 18 Dec 2024 17:07:44 -0600 Subject: [PATCH 059/130] bugfix for long preferences key --- src/lib/config.cpp | 4 ++-- src/lib/screen_handler.cpp | 2 +- src/lib/webserver.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/config.cpp b/src/lib/config.cpp index d8e71ef..8c387ba 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -95,7 +95,7 @@ void setup() setupBitaxeFetchTask(); } - if (preferences.getBool("miningPoolStatsEnabled", DEFAULT_MINING_POOL_STATS_ENABLED)) + if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) { setupMiningPoolStatsFetchTask(); } @@ -337,7 +337,7 @@ void setupPreferences() addScreenMapping(SCREEN_BITAXE_BESTDIFF, "BitAxe Best Difficulty"); } - if (preferences.getBool("miningPoolStatsEnabled", DEFAULT_MINING_POOL_STATS_ENABLED)) + if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) { addScreenMapping(SCREEN_MINING_POOL_STATS_HASHRATE, "Mining Pool Hashrate"); addScreenMapping(SCREEN_MINING_POOL_STATS_EARNINGS, "Mining Pool Earnings"); diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 84f91d6..6c4357c 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -192,7 +192,7 @@ void setCurrentScreen(uint newScreen) { } case SCREEN_MINING_POOL_STATS_HASHRATE: case SCREEN_MINING_POOL_STATS_EARNINGS: { - if (preferences.getBool("miningPoolStatsEnabled", DEFAULT_MINING_POOL_STATS_ENABLED)) { + if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) { WorkItem miningPoolStatsUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0}; xQueueSend(workQueue, &miningPoolStatsUpdate, portMAX_DELAY); } else { diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 0a55ff8..4dc0c1e 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -549,7 +549,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) "mowMode", "suffixShareDot", "flOffWhenDark", "flAlwaysOn", "flDisable", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", - "miningPoolStatsEnabled", "verticalDesc", + "miningPoolStats", "verticalDesc", "nostrZapNotify", "stagingSource", "httpAuthEnabled"}; for (String setting : boolSettings) @@ -714,7 +714,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["bitaxeEnabled"] = preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED); root["bitaxeHostname"] = preferences.getString("bitaxeHostname", DEFAULT_BITAXE_HOSTNAME); - root["miningPoolStatsEnabled"] = preferences.getBool("miningPoolStatsEnabled", DEFAULT_MINING_POOL_STATS_ENABLED); + root["miningPoolStats"] = preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED); root["miningPoolName"] = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME); root["miningPoolUser"] = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER); From c3af0b4d368fdd58bffa94eb5b4fb9a93405589a Mon Sep 17 00:00:00 2001 From: kdmukai Date: Wed, 18 Dec 2024 17:08:32 -0600 Subject: [PATCH 060/130] Docs update; info on mining pool stats config --- README.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 81890b4..367a38d 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Biggest differences with v2 are: New features: - BitAxe integration - Zap notifier -- +- Braiins Pool and Ocean mining stats integration "Steal focus on new block" means that when a new block is mined, the display will switch to the block height screen if it's not on it already. @@ -27,4 +27,27 @@ Most [information](https://github.com/btclock/btclock_v2/wiki) about BTClock v2 ## Building -Use PlatformIO to build it yourself. Make sure you fetch the [WebUI](https://github.com/btclock/webui) submodule. \ No newline at end of file +Use PlatformIO to build it yourself. Make sure you fetch the [WebUI](https://github.com/btclock/webui) submodule. + + +## Braiins Pool and Ocean integration +Enable mining pool stats by accessing your btclock's web UI (point a web browser at the device's IP address). + +Under Settings -> Extra Features: toggle Enable Mining Pool Stats. + +New options will appear. Select your mining pool and enter your pool username (Ocean) or api key (Braiins). + + +### Braiins Pool integration +Create an API key based on the steps [here](https://academy.braiins.com/en/braiins-pool/monitoring/#api-configuration). + +The key's permissions should be: +* Web Access: no +* API Access: yes +* Access Permissions: Read-only + +Copy the token that is created for the new key. Enter this as your "Mining Pool username or api key" in the btclock web UI. + + +### Ocean integration +Your "Mining Pool username" is just the onchain withdrawal address that you specify when pointing your miners at Ocean. From 72e5ee6580928bb4aa166f84af22336d4a756145 Mon Sep 17 00:00:00 2001 From: kdmukai Date: Wed, 18 Dec 2024 21:05:39 -0600 Subject: [PATCH 061/130] README update --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 367a38d..71d3319 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,10 @@ Under Settings -> Extra Features: toggle Enable Mining Pool Stats. New options will appear. Select your mining pool and enter your pool username (Ocean) or api key (Braiins). +The Mining Pool Earnings screen displays: +* Braiins: Today's mining reward thus far +* Ocean: Your estimated earnings if the pool were to find a block right now + ### Braiins Pool integration Create an API key based on the steps [here](https://academy.braiins.com/en/braiins-pool/monitoring/#api-configuration). From be224d1f91d7e961fdef38e8c448003d8351fa0d Mon Sep 17 00:00:00 2001 From: kdmukai Date: Wed, 18 Dec 2024 21:06:45 -0600 Subject: [PATCH 062/130] Restoring .gitmodule link to main webui repo --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index e44bd8c..d8b183a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "data"] path = data - url = https://git.btclock.dev/kdmukai/webui.git + url = https://git.btclock.dev/btclock/webui.git From e758659a4acd58e64e1a80149f22cf0e50b222e3 Mon Sep 17 00:00:00 2001 From: kdmukai Date: Wed, 18 Dec 2024 21:31:05 -0600 Subject: [PATCH 063/130] Remove platformio edit --- platformio.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 125ad96..d2abb92 100644 --- a/platformio.ini +++ b/platformio.ini @@ -96,7 +96,6 @@ build_flags = [env:btclock_rev_b_213epd] extends = env:btclock_rev_b -board_build.partitions = partition_8mb.csv test_framework = unity build_flags = ${env:btclock_rev_b.build_flags} From 8f9307d1e4de2b92fbc38f16e6599f495a50754b Mon Sep 17 00:00:00 2001 From: kdmukai Date: Wed, 18 Dec 2024 21:34:52 -0600 Subject: [PATCH 064/130] Remove whitespace --- partition_8mb.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/partition_8mb.csv b/partition_8mb.csv index e0584ae..025f649 100644 --- a/partition_8mb.csv +++ b/partition_8mb.csv @@ -4,4 +4,4 @@ otadata, data, ota, 0xe000, 0x2000, app0, app, ota_0, 0x10000, 0x370000, app1, app, ota_1, , 0x370000, spiffs, data, spiffs, , 0xCD000, -coredump, data, coredump,, 0x10000, +coredump, data, coredump,, 0x10000, \ No newline at end of file From 01ef6daf9f41b17ffcde80aca0f4729e73690976 Mon Sep 17 00:00:00 2001 From: kdmukai Date: Thu, 19 Dec 2024 13:53:16 -0600 Subject: [PATCH 065/130] Update screen id consts --- src/lib/shared.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index 22e40b2..8027519 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -60,8 +60,8 @@ const PROGMEM int SCREEN_MARKET_CAP = 30; const PROGMEM int SCREEN_BITAXE_HASHRATE = 80; const PROGMEM int SCREEN_BITAXE_BESTDIFF = 81; -const PROGMEM int SCREEN_MINING_POOL_STATS_HASHRATE = 85; -const PROGMEM int SCREEN_MINING_POOL_STATS_EARNINGS = 86; +const PROGMEM int SCREEN_MINING_POOL_STATS_HASHRATE = 70; +const PROGMEM int SCREEN_MINING_POOL_STATS_EARNINGS = 71; const PROGMEM int SCREEN_COUNTDOWN = 98; const PROGMEM int SCREEN_CUSTOM = 99; From f9aa593f0b39b6889c041288c982b39932730cb6 Mon Sep 17 00:00:00 2001 From: kdmukai Date: Thu, 19 Dec 2024 13:54:28 -0600 Subject: [PATCH 066/130] Removed pool name consts; reduce Preferences hits --- src/lib/defaults.hpp | 5 +---- src/lib/mining_pool_stats_fetch.cpp | 15 ++++++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index 3d28829..7ca89fb 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -58,11 +58,8 @@ #define DEFAULT_BITAXE_ENABLED false #define DEFAULT_BITAXE_HOSTNAME "bitaxe1" -#define MINING_POOL_NAME_OCEAN "ocean" -#define MINING_POOL_NAME_BRAIINS "braiins" - #define DEFAULT_MINING_POOL_STATS_ENABLED false -#define DEFAULT_MINING_POOL_NAME MINING_POOL_NAME_OCEAN +#define DEFAULT_MINING_POOL_NAME "ocean" #define DEFAULT_MINING_POOL_USER "38Qkkei3SuF1Eo45BaYmRHUneRD54yyTFy" // Random actual Ocean hasher #define DEFAULT_ZAP_NOTIFY_ENABLED false diff --git a/src/lib/mining_pool_stats_fetch.cpp b/src/lib/mining_pool_stats_fetch.cpp index 9de1cd7..3d440af 100644 --- a/src/lib/mining_pool_stats_fetch.cpp +++ b/src/lib/mining_pool_stats_fetch.cpp @@ -2,6 +2,7 @@ TaskHandle_t miningPoolStatsFetchTaskHandle; +std::string miningPoolName; std::string miningPoolStatsHashrate; int miningPoolStatsDailyEarnings; @@ -25,19 +26,21 @@ void taskMiningPoolStatsFetch(void *pvParameters) http.setUserAgent(USER_AGENT); String miningPoolStatsApiUrl; + miningPoolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); + std::string httpHeaderKey = ""; std::string httpHeaderValue; - if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_OCEAN) { + if (miningPoolName == "ocean") { miningPoolStatsApiUrl = "https://api.ocean.xyz/v1/statsnap/" + preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER); } - else if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_BRAIINS) { + else if (miningPoolName == "braiins") { miningPoolStatsApiUrl = "https://pool.braiins.com/accounts/profile/json/btc/"; httpHeaderKey = "Pool-Auth-Token"; httpHeaderValue = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str(); } else { - Serial.println("Unknown mining pool: \"" + preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) + "\""); + // Unknown mining pool / missing implementation continue; } @@ -55,13 +58,11 @@ void taskMiningPoolStatsFetch(void *pvParameters) JsonDocument doc; deserializeJson(doc, payload); - Serial.println(doc.as()); - - if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_OCEAN) { + if (miningPoolName == "ocean") { miningPoolStatsHashrate = doc["result"]["hashrate_300s"].as(); miningPoolStatsDailyEarnings = int(doc["result"]["estimated_earn_next_block"].as() * 100000000); } - else if (preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME) == MINING_POOL_NAME_BRAIINS) { + else if (miningPoolName == "braiins") { // Reports hashrate in specific hashrate units (e.g. Gh/s); we want raw total hashes per second. std::string hashrateUnit = doc["btc"]["hash_rate_unit"].as(); int multiplier = 0; From 814cd234a9b4824ca4f0cf9a57f74cc37b865054 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Fri, 20 Dec 2024 01:08:03 +0100 Subject: [PATCH 067/130] Big refactor of mining pool support, optimization of existing icons --- lib/btclock/mining_pool_stats_handler.cpp | 29 +- lib/btclock/mining_pool_stats_handler.hpp | 4 +- src/icons/icons.cpp | 1508 +++++------------ src/lib/config.cpp | 4 +- src/lib/epd.cpp | 29 +- src/lib/epd.hpp | 1 + src/lib/mining_pool/braiins/brains_pool.cpp | 32 + src/lib/mining_pool/braiins/brains_pool.hpp | 18 + src/lib/mining_pool/logo_data.hpp | 10 + src/lib/mining_pool/mining_pool_interface.hpp | 21 + .../noderunners/noderunners_pool.cpp | 39 + .../noderunners/noderunners_pool.hpp | 20 + src/lib/mining_pool/ocean/ocean_pool.cpp | 26 + src/lib/mining_pool/ocean/ocean_pool.hpp | 15 + src/lib/mining_pool/pool_factory.cpp | 20 + src/lib/mining_pool/pool_factory.hpp | 35 + src/lib/mining_pool/pool_stats.hpp | 10 + src/lib/mining_pool_stats_fetch.cpp | 86 +- src/lib/mining_pool_stats_fetch.hpp | 4 + src/lib/screen_handler.cpp | 4 +- src/lib/shared.hpp | 30 +- src/lib/webserver.cpp | 16 +- src/lib/webserver.hpp | 1 + 23 files changed, 772 insertions(+), 1190 deletions(-) create mode 100644 src/lib/mining_pool/braiins/brains_pool.cpp create mode 100644 src/lib/mining_pool/braiins/brains_pool.hpp create mode 100644 src/lib/mining_pool/logo_data.hpp create mode 100644 src/lib/mining_pool/mining_pool_interface.hpp create mode 100644 src/lib/mining_pool/noderunners/noderunners_pool.cpp create mode 100644 src/lib/mining_pool/noderunners/noderunners_pool.hpp create mode 100644 src/lib/mining_pool/ocean/ocean_pool.cpp create mode 100644 src/lib/mining_pool/ocean/ocean_pool.hpp create mode 100644 src/lib/mining_pool/pool_factory.cpp create mode 100644 src/lib/mining_pool/pool_factory.hpp create mode 100644 src/lib/mining_pool/pool_stats.hpp diff --git a/lib/btclock/mining_pool_stats_handler.cpp b/lib/btclock/mining_pool_stats_handler.cpp index 6802e42..445b912 100644 --- a/lib/btclock/mining_pool_stats_handler.cpp +++ b/lib/btclock/mining_pool_stats_handler.cpp @@ -1,7 +1,7 @@ #include "mining_pool_stats_handler.hpp" #include -std::array parseMiningPoolStatsHashRate(std::string miningPoolName, std::string text) +std::array parseMiningPoolStatsHashRate(std::string text) { std::array ret; ret.fill(""); // Initialize all elements to empty strings @@ -55,31 +55,19 @@ std::array parseMiningPoolStatsHashRate(std::string mi ret[NUM_SCREENS - 1] = label; - // Set the mining pool logo - if (miningPoolName == "ocean") { - ret[0] = "mdi:ocean_logo"; - } else if (miningPoolName == "braiins") { - ret[0] = "mdi:braiins_logo"; - } + + ret[0] = "mdi:miningpool"; + return ret; } -std::array parseMiningPoolStatsDailyEarnings(std::string miningPoolName, int sats) +std::array parseMiningPoolStatsDailyEarnings(int sats, std::string label) { std::array ret; ret.fill(""); // Initialize all elements to empty strings std::string satsDisplay = std::to_string(sats); - std::string label; - - if (miningPoolName == "braiins") { - // fpps guarantees payout; report current daily earnings - label = "sats/earned"; - } else { - // TIDES can only estimate earnings on the next block Ocean finds - label = "sats/block"; - } if (sats >= 100000000) { // A whale mining 1+ BTC per day! No decimal points; whales scoff at such things. @@ -121,12 +109,7 @@ std::array parseMiningPoolStatsDailyEarnings(std::stri ret[NUM_SCREENS - 1] = label; - // Set the mining pool logo - if (miningPoolName == "ocean") { - ret[0] = "mdi:ocean_logo"; - } else if (miningPoolName == "braiins") { - ret[0] = "mdi:braiins_logo"; - } + ret[0] = "mdi:miningpool"; return ret; } \ No newline at end of file diff --git a/lib/btclock/mining_pool_stats_handler.hpp b/lib/btclock/mining_pool_stats_handler.hpp index 495c7db..d9aaadd 100644 --- a/lib/btclock/mining_pool_stats_handler.hpp +++ b/lib/btclock/mining_pool_stats_handler.hpp @@ -1,5 +1,5 @@ #include #include -std::array parseMiningPoolStatsHashRate(std::string miningPoolName, std::string text); -std::array parseMiningPoolStatsDailyEarnings(std::string miningPoolName, int sats); +std::array parseMiningPoolStatsHashRate(std::string text); +std::array parseMiningPoolStatsDailyEarnings(int sats, std::string label); diff --git a/src/icons/icons.cpp b/src/icons/icons.cpp index d80fde1..5fd6c1a 100644 --- a/src/icons/icons.cpp +++ b/src/icons/icons.cpp @@ -1,578 +1,7 @@ #include "icons.h" -// 'pickaxe', 122x250px -const unsigned char epd_icons_pickaxe [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x71, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x20, 0xe1, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xf0, 0x00, 0x00, 0x7f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xf8, 0xc0, 0x00, 0x7f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0x00, 0x07, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 -}; -// 'rocket-launch', 122x250px -const unsigned char epd_icons_rocket_launch [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x03, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x03, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x7f, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x03, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xe0, 0x00, 0x03, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xe0, 0x00, 0x07, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x01, 0xff, 0xff, 0xe0, 0x00, 0x07, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x01, 0xff, 0xff, 0xe0, 0x00, 0x07, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf9, 0xfc, 0x00, 0x00, 0x01, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xe1, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x83, 0xf0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfe, 0x03, 0xf0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x1f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf8, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x7f, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xfe, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xf8, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xc0, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xfe, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xe7, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc3, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x83, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x03, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x0f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x3f, 0x9f, 0xe0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x7f, 0x0f, 0xf0, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0xfe, 0x07, 0xf8, 0x00, 0x00, 0x0f, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x01, 0xfc, 0x03, 0xfc, 0x00, 0x00, 0x3f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xfe, 0x03, 0xf8, 0x01, 0xfe, 0x00, 0x00, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xfc, 0x07, 0xf0, 0x00, 0xff, 0x00, 0x03, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf8, 0x0f, 0xe0, 0x00, 0x7f, 0x80, 0x0f, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf0, 0x1f, 0xc0, 0x00, 0x7f, 0xe0, 0x7f, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xc0, 0x7f, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xc0, 0xfe, 0x00, 0x03, 0xfb, 0xff, 0xfe, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xc1, 0xfc, 0x00, 0x07, 0xf0, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xc3, 0xf8, 0x00, 0x0f, 0xe0, 0x3f, 0xe0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xc7, 0xf0, 0x00, 0x1f, 0xc0, 0x7f, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xcf, 0xe0, 0x00, 0x3f, 0x80, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xdf, 0xc0, 0x00, 0x7f, 0x01, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0xfe, 0x03, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x00, 0x01, 0xfc, 0x07, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xfe, 0x00, 0x03, 0xf8, 0x0f, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xfc, 0x00, 0x07, 0xf0, 0x1f, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf8, 0x00, 0x0f, 0xe0, 0x3f, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0x1f, 0xc0, 0x7f, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x3f, 0x80, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xc0, 0x00, 0x7f, 0x01, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xc0, 0x00, 0xfe, 0x03, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xc0, 0x01, 0xfc, 0x07, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xc0, 0x03, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xc0, 0x07, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xc0, 0x0f, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xc0, 0x1f, 0xc0, 0x7f, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 -}; - -const unsigned char epd_icons_lightning [] PROGMEM = { - // 'lightning-bolt, 122x250px - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +// 'lightning-bolt', 122x122px +const unsigned char epd_icons_lightning_bolt [] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, @@ -694,6 +123,10 @@ const unsigned char epd_icons_lightning [] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; +// 'rocket-launch', 122x122px +const unsigned char epd_icons_rocket_launch [] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, @@ -702,32 +135,89 @@ const unsigned char epd_icons_lightning [] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf1, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc1, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x03, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x03, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x0f, 0x80, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xfe, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf8, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x80, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x80, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf8, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x81, 0xff, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xfe, 0x07, 0xe7, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xfc, 0x0f, 0xc3, 0xf0, 0x00, 0x00, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf8, 0x1f, 0x81, 0xf8, 0x00, 0x03, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf0, 0x3f, 0x00, 0xfc, 0x00, 0x0f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x7e, 0x00, 0x7e, 0x00, 0x3f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xc0, 0xfc, 0x00, 0x3f, 0x80, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x81, 0xf8, 0x00, 0x7f, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x03, 0xf0, 0x00, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x07, 0xe0, 0x01, 0xf3, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x0f, 0xc0, 0x03, 0xe0, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x1f, 0x80, 0x07, 0xc0, 0xff, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x3f, 0x00, 0x0f, 0x81, 0xff, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x7e, 0x00, 0x1f, 0x03, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xfc, 0x00, 0x3e, 0x07, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf8, 0x00, 0x7c, 0x0f, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf0, 0x00, 0xf8, 0x1f, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x01, 0xf0, 0x3f, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xc0, 0x03, 0xe0, 0x7f, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x80, 0x07, 0xc0, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x00, 0x0f, 0x81, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x00, 0x1f, 0x03, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x00, 0x3e, 0x07, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x00, 0x7c, 0x0f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x00, 0xf8, 0x1f, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x01, 0xf0, 0x3f, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, @@ -760,227 +250,98 @@ const unsigned char epd_icons_lightning [] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 }; - -// 'flash', 122x250px -const unsigned char epd_icons_flash [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +// 'pickaxe', 122x122px +const unsigned char epd_icons_pickaxe [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x31, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xfd, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, @@ -1270,262 +631,135 @@ const unsigned char epd_icons_bitaxe_logo [] PROGMEM = { }; -// 'ocean_logo', 122x250px +// // 'ocean_logo', 122x250px const unsigned char epd_icons_ocean_logo [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x78, 0x00, 0x1f, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xfc, 0x00, 0x3f, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xfe, 0x00, 0x7f, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x00, 0x7f, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xc0, - 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xc0, - 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xc0, - 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xc0, - 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xc0, - 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xc0, - 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xc0, - 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xc0, - 0xff, 0x80, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xc0, - 0xff, 0x80, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xc0, - 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xc0, - 0xff, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x3f, 0xc0, - 0xff, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x1f, 0xc0, - 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x1f, 0xc0, - 0xfe, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xc0, - 0xfe, 0x00, 0x00, 0x03, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xc0, - 0xfe, 0x00, 0x00, 0x01, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xc0, - 0xfe, 0x00, 0x00, 0x01, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0x00, 0x1f, 0xc0, - 0xfe, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf0, 0xff, 0xff, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x1f, 0xc0, - 0xfe, 0x00, 0x78, 0x00, 0x7f, 0xff, 0xf1, 0xff, 0xfc, 0x00, 0x03, 0xff, 0xff, 0xc0, 0x1f, 0xc0, - 0xfe, 0x00, 0xfc, 0x00, 0x3f, 0xff, 0xf1, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xff, 0xc0, 0x1f, 0xc0, - 0xff, 0x00, 0xff, 0x00, 0x1f, 0xff, 0xf1, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xc0, - 0xff, 0x01, 0xff, 0x80, 0x1f, 0xff, 0xf3, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xc0, - 0xff, 0x01, 0xff, 0xc0, 0x0f, 0xff, 0xe3, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xc0, - 0xff, 0x01, 0xff, 0xe0, 0x07, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xc0, - 0xff, 0x81, 0xff, 0xf8, 0x03, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xc0, - 0xff, 0x81, 0xff, 0xfc, 0x01, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xc0, - 0xff, 0x83, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xc0, - 0xff, 0xc3, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xc0, - 0xff, 0xc3, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xc0, - 0xff, 0xe3, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xc0, - 0xff, 0xe3, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xc0, - 0xff, 0xf3, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfc, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xf9, 0xff, 0xc0, - 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xf9, 0xff, 0xc0, - 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0xf0, 0xff, 0xc0, - 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xf0, 0xff, 0xc0, - 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xf0, 0x7f, 0xc0, - 0xff, 0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0x7f, 0xc0, - 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xf0, 0x07, 0xff, 0xf0, 0x7f, 0xc0, - 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xf8, 0x03, 0xff, 0xf0, 0x3f, 0xc0, - 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xf8, 0x01, 0xff, 0xe0, 0x3f, 0xc0, - 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xf1, 0xff, 0xfc, 0x00, 0xff, 0xe0, 0x3f, 0xc0, - 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xf1, 0xff, 0xfe, 0x00, 0x3f, 0xe0, 0x1f, 0xc0, - 0xff, 0x00, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xf1, 0xff, 0xff, 0x00, 0x1f, 0xe0, 0x1f, 0xc0, - 0xfe, 0x00, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xf1, 0xff, 0xff, 0x80, 0x0f, 0xc0, 0x1f, 0xc0, - 0xfe, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x07, 0xff, 0xe1, 0xff, 0xff, 0x80, 0x07, 0x80, 0x1f, 0xc0, - 0xfe, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xe3, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x1f, 0xc0, - 0xfe, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xc0, - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xc0, - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xc0, - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xc0, - 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x1f, 0xc0, - 0xff, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xc0, - 0xff, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xc0, - 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x80, 0x00, 0x3f, 0xc0, - 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x80, 0x00, 0x3f, 0xc0, - 0xff, 0x80, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xc0, - 0xff, 0x80, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xc0, - 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xc0, - 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xc0, - 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xc0, - 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xc0, - 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xc0, - 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xc0, 0x0f, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0x80, 0x0f, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0x80, 0x0f, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x07, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +// 'ocean_logo', 122x122px +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x20, 0x00, 0x0f, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xfe, 0x03, 0xfc, 0x00, 0x3f, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xfc, 0x00, 0x7f, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xfe, 0x00, 0x7f, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xc0, +0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xc0, +0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xc0, +0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xc0, +0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xc0, +0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xc0, +0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xc0, +0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xc0, +0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xc0, +0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xc0, +0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xc0, +0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x1f, 0xc0, +0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x1f, 0xc0, +0xfc, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xc0, +0xfc, 0x00, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xc0, +0xfc, 0x00, 0x01, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xc0, +0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, +0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x07, 0xc0, +0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xc0, +0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x07, 0xc0, +0xf8, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, +0xf8, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x03, 0x00, 0x07, 0xc0, +0xf8, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xe0, 0x07, 0xc0, +0xf8, 0x00, 0x00, 0x03, 0xff, 0xff, 0xe1, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xf0, 0x07, 0xc0, +0xf8, 0x03, 0xe0, 0x01, 0xff, 0xff, 0xe3, 0xff, 0xfc, 0x00, 0x03, 0xff, 0xff, 0xf0, 0x07, 0xc0, +0xf8, 0x07, 0xf8, 0x00, 0xff, 0xff, 0xe3, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x07, 0xc0, +0xf8, 0x07, 0xfc, 0x00, 0x7f, 0xff, 0xe3, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xc0, +0xf8, 0x07, 0xfe, 0x00, 0x3f, 0xff, 0xe7, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xc0, +0xf8, 0x07, 0xff, 0x80, 0x1f, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xc0, +0xfc, 0x0f, 0xff, 0xc0, 0x0f, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0f, 0xc0, +0xfc, 0x0f, 0xff, 0xe0, 0x0f, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0f, 0xc0, +0xfc, 0x0f, 0xff, 0xf8, 0x07, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0f, 0xc0, +0xfe, 0x0f, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xc0, +0xfe, 0x1f, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xc0, +0xff, 0x1f, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xc0, +0xff, 0x1f, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xc0, +0xff, 0x9f, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xc0, +0xff, 0xdf, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xdf, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xfe, 0xff, 0xc0, +0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xfe, 0x7f, 0xc0, +0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xfe, 0x7f, 0xc0, +0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xfe, 0x3f, 0xc0, +0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xfc, 0x1f, 0xc0, +0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xfc, 0x1f, 0xc0, +0xfc, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xfc, 0x1f, 0xc0, +0xfc, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfc, 0x01, 0xff, 0xfc, 0x0f, 0xc0, +0xfc, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfc, 0x00, 0xff, 0xfc, 0x0f, 0xc0, +0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfe, 0x00, 0x7f, 0xf8, 0x07, 0xc0, +0xf8, 0x07, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xf9, 0xff, 0xff, 0x00, 0x1f, 0xf8, 0x07, 0xc0, +0xf8, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xf1, 0xff, 0xff, 0x80, 0x0f, 0xf8, 0x07, 0xc0, +0xf8, 0x07, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xf1, 0xff, 0xff, 0xc0, 0x07, 0xf0, 0x07, 0xc0, +0xf8, 0x03, 0xff, 0xff, 0xf0, 0x00, 0x0f, 0xff, 0xf1, 0xff, 0xff, 0xe0, 0x01, 0xf0, 0x07, 0xc0, +0xf8, 0x03, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xff, 0xe3, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x07, 0xc0, +0xf8, 0x01, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x07, 0xc0, +0xf8, 0x00, 0x30, 0x00, 0x00, 0x07, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x07, 0xc0, +0xf8, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x07, 0xc0, +0xf8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xc0, +0xf8, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x00, 0x00, 0x07, 0xc0, +0xf8, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x80, 0x00, 0x07, 0xc0, +0xf8, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x07, 0xc0, +0xfc, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x0f, 0xc0, +0xfc, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xc0, +0xfc, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x0f, 0xc0, +0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xc0, +0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xc0, +0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xc0, +0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xc0, +0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xc0, +0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xc0, +0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xc0, +0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xc0, +0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xc0, +0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xc0, +0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xc0, +0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xc0, +0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0x80, 0x1f, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0x80, 0x0f, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xfe, 0x03, 0xff, 0x00, 0x0f, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3c, 0x00, 0x03, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 }; -// 'braiins_pool', 122x250px +// // 'braiins_pool', 122x250px const unsigned char epd_icons_braiins_logo [] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, @@ -1779,15 +1013,139 @@ const unsigned char epd_icons_braiins_logo [] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 }; +const unsigned char epd_icons_noderunners_logo [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x01, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x01, 0xff, 0x00, 0x01, 0xfb, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x01, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0x80, 0x01, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x01, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x01, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x01, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xdf, 0xf0, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xdf, 0xf0, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xcf, 0xf8, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xcf, 0xfc, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xc7, 0xfe, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe7, 0xfe, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe3, 0xff, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe1, 0xff, 0x81, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe1, 0xff, 0x81, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0xff, 0xc1, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0x7f, 0xe1, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0x3f, 0xe1, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0x3f, 0xf1, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0x1f, 0xf9, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0x0f, 0xf9, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0x0f, 0xfd, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xe0, 0x07, 0xfd, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xe0, 0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xe0, 0x03, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xe0, 0x01, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe1, 0xc0, 0x00, 0x3f, 0xe0, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe7, 0xf0, 0x00, 0x3f, 0xe0, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x07, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x07, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; // Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 8032) const int epd_icons_allArray_LEN = 7; const unsigned char* epd_icons_allArray[epd_icons_allArray_LEN] = { epd_icons_pickaxe, epd_icons_rocket_launch, - epd_icons_lightning, - epd_icons_flash, + epd_icons_lightning_bolt, epd_icons_bitaxe_logo, epd_icons_ocean_logo, - epd_icons_braiins_logo + epd_icons_braiins_logo, + epd_icons_noderunners_logo }; diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 8c387ba..d7f403f 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -340,7 +340,9 @@ void setupPreferences() if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) { addScreenMapping(SCREEN_MINING_POOL_STATS_HASHRATE, "Mining Pool Hashrate"); - addScreenMapping(SCREEN_MINING_POOL_STATS_EARNINGS, "Mining Pool Earnings"); + if (getMiningPool()->supportsDailyEarnings()) { + addScreenMapping(SCREEN_MINING_POOL_STATS_EARNINGS, "Mining Pool Earnings"); + } } } diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 5281087..062fc74 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -604,26 +604,36 @@ void renderIcon(const uint dispNum, const String &text, bool partial) displays[dispNum].setTextColor(getFgColor()); uint iconIndex = 0; + uint width = 122; + uint height = 122; if (text.endsWith("rocket")) { iconIndex = 1; } else if (text.endsWith("lnbolt")) { - iconIndex = 3; + iconIndex = 2; } else if (text.endsWith("bitaxe")) { - iconIndex = 4; + width = 122; + height = 250; + iconIndex = 3; } - else if (text.endsWith("ocean_logo")) { - iconIndex = 5; - } - else if (text.endsWith("braiins_logo")) { - iconIndex = 6; + else if (text.endsWith("miningpool")) { + LogoData logo = getMiningPoolLogo(); + + int x_offset = (displays[dispNum].width() - logo.width) / 2; + int y_offset = (displays[dispNum].height() - logo.height) / 2; + // Close the file + + displays[dispNum].drawInvertedBitmap(x_offset,y_offset, logo.data, logo.width, logo.height, getFgColor()); + return; } - + + int x_offset = (displays[dispNum].width() - width) / 2; + int y_offset = (displays[dispNum].height() - height) / 2; - displays[dispNum].drawInvertedBitmap(0,0, epd_icons_allArray[iconIndex], 122, 250, getFgColor()); + displays[dispNum].drawInvertedBitmap(x_offset,y_offset, epd_icons_allArray[iconIndex], width, height, getFgColor()); // displays[dispNum].drawInvertedBitmap(0,0, getOceanIcon(), 122, 250, getFgColor()); @@ -633,6 +643,7 @@ void renderIcon(const uint dispNum, const String &text, bool partial) + void renderQr(const uint dispNum, const String &text, bool partial) { #ifdef USE_QR diff --git a/src/lib/epd.hpp b/src/lib/epd.hpp index 1194cf1..79be979 100644 --- a/src/lib/epd.hpp +++ b/src/lib/epd.hpp @@ -14,6 +14,7 @@ #include "lib/config.hpp" #include "lib/shared.hpp" #include "icons/icons.h" +#include "mining_pool_stats_fetch.hpp" #ifdef USE_QR #include "qrcodegen.h" diff --git a/src/lib/mining_pool/braiins/brains_pool.cpp b/src/lib/mining_pool/braiins/brains_pool.cpp new file mode 100644 index 0000000..5418829 --- /dev/null +++ b/src/lib/mining_pool/braiins/brains_pool.cpp @@ -0,0 +1,32 @@ +#include "brains_pool.hpp" + +void BraiinsPool::prepareRequest(HTTPClient& http) const { + http.addHeader("Pool-Auth-Token", poolUser.c_str()); +} + +std::string BraiinsPool::getApiUrl() const { + return "https://pool.braiins.com/accounts/profile/json/btc/"; +} + +PoolStats BraiinsPool::parseResponse(const JsonDocument &doc) const +{ + std::string unit = doc["btc"]["hash_rate_unit"].as(); + + static const std::unordered_map multipliers = { + {"Zh/s", 21}, {"Eh/s", 18}, {"Ph/s", 15}, {"Th/s", 12}, {"Gh/s", 9}, {"Mh/s", 6}, {"Kh/s", 3}}; + + int multiplier = multipliers.at(unit); + float hashValue = doc["btc"]["hash_rate_5m"].as(); + + return PoolStats{ + .hashrate = std::to_string(static_cast(std::round(hashValue))) + std::string(multiplier, '0'), + .dailyEarnings = static_cast(doc["btc"]["today_reward"].as() * 100000000)}; +} + +LogoData BraiinsPool::getLogo() const { + return LogoData{ + .data = epd_icons_allArray[5], + .width = 122, + .height = 250 + }; +} \ No newline at end of file diff --git a/src/lib/mining_pool/braiins/brains_pool.hpp b/src/lib/mining_pool/braiins/brains_pool.hpp new file mode 100644 index 0000000..ea2c0e0 --- /dev/null +++ b/src/lib/mining_pool/braiins/brains_pool.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "lib/mining_pool/mining_pool_interface.hpp" +#include + +class BraiinsPool : public MiningPoolInterface +{ +public: + void setPoolUser(const std::string &user) override { poolUser = user; } + void prepareRequest(HTTPClient &http) const override; + std::string getApiUrl() const override; + PoolStats parseResponse(const JsonDocument &doc) const override; + LogoData getLogo() const override; + bool supportsDailyEarnings() const override { return true; } + std::string getDailyEarningsLabel() const override { return "sats/earned"; } +private: + static int getHashrateMultiplier(const std::string &unit); +}; \ No newline at end of file diff --git a/src/lib/mining_pool/logo_data.hpp b/src/lib/mining_pool/logo_data.hpp new file mode 100644 index 0000000..7cd0819 --- /dev/null +++ b/src/lib/mining_pool/logo_data.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +struct LogoData { + const uint8_t* data; + size_t width; + size_t height; +}; diff --git a/src/lib/mining_pool/mining_pool_interface.hpp b/src/lib/mining_pool/mining_pool_interface.hpp new file mode 100644 index 0000000..1df84b9 --- /dev/null +++ b/src/lib/mining_pool/mining_pool_interface.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include "pool_stats.hpp" +#include "logo_data.hpp" + +class MiningPoolInterface { +public: + virtual ~MiningPoolInterface() = default; + virtual void setPoolUser(const std::string& user) = 0; + virtual void prepareRequest(HTTPClient& http) const = 0; + virtual std::string getApiUrl() const = 0; + virtual PoolStats parseResponse(const JsonDocument& doc) const = 0; + virtual LogoData getLogo() const = 0; + virtual bool supportsDailyEarnings() const = 0; + virtual std::string getDailyEarningsLabel() const = 0; + +protected: + std::string poolUser; +}; \ No newline at end of file diff --git a/src/lib/mining_pool/noderunners/noderunners_pool.cpp b/src/lib/mining_pool/noderunners/noderunners_pool.cpp new file mode 100644 index 0000000..22ee112 --- /dev/null +++ b/src/lib/mining_pool/noderunners/noderunners_pool.cpp @@ -0,0 +1,39 @@ +// src/noderunners/noderunners_pool.cpp +#include "noderunners_pool.hpp" + +void NodeRunnersPool::prepareRequest(HTTPClient& http) const { + // Empty as NodeRunners doesn't need special headers +} + +std::string NodeRunnersPool::getApiUrl() const { + return "https://pool.noderunners.network/api/v1/users/" + poolUser; +} + +PoolStats NodeRunnersPool::parseResponse(const JsonDocument& doc) const { + std::string hashrateStr = doc["hashrate1m"].as(); + char unit = hashrateStr.back(); + std::string value = hashrateStr.substr(0, hashrateStr.size() - 1); + + int multiplier = getHashrateMultiplier(unit); + + return PoolStats{ + .hashrate = value + std::string(multiplier, '0'), + .dailyEarnings = std::nullopt + }; +} + +LogoData NodeRunnersPool::getLogo() const { + return LogoData { + .data = epd_icons_allArray[6], + .width = 122, + .height = 122 + }; +} + +int NodeRunnersPool::getHashrateMultiplier(char unit) { + static const std::unordered_map multipliers = { + {'Z', 21}, {'E', 18}, {'P', 15}, {'T', 12}, + {'G', 9}, {'M', 6}, {'K', 3} + }; + return multipliers.at(unit); +} diff --git a/src/lib/mining_pool/noderunners/noderunners_pool.hpp b/src/lib/mining_pool/noderunners/noderunners_pool.hpp new file mode 100644 index 0000000..ea1b0a2 --- /dev/null +++ b/src/lib/mining_pool/noderunners/noderunners_pool.hpp @@ -0,0 +1,20 @@ + +#pragma once + +#include "lib/mining_pool/mining_pool_interface.hpp" +#include + +class NodeRunnersPool : public MiningPoolInterface { +public: + void setPoolUser(const std::string& user) override { poolUser = user; } + + void prepareRequest(HTTPClient& http) const override; + std::string getApiUrl() const override; + PoolStats parseResponse(const JsonDocument& doc) const override; + LogoData getLogo() const override; + bool supportsDailyEarnings() const override { return false; } + std::string getDailyEarningsLabel() const override { return ""; } + +private: + static int getHashrateMultiplier(char unit); +}; \ No newline at end of file diff --git a/src/lib/mining_pool/ocean/ocean_pool.cpp b/src/lib/mining_pool/ocean/ocean_pool.cpp new file mode 100644 index 0000000..f66ad5c --- /dev/null +++ b/src/lib/mining_pool/ocean/ocean_pool.cpp @@ -0,0 +1,26 @@ +#include "ocean_pool.hpp" + +void OceanPool::prepareRequest(HTTPClient& http) const { + // Empty as Ocean doesn't need special headers +} + +std::string OceanPool::getApiUrl() const { + return "https://api.ocean.xyz/v1/statsnap/" + poolUser; +} + +PoolStats OceanPool::parseResponse(const JsonDocument& doc) const { + return PoolStats{ + .hashrate = doc["result"]["hashrate_300s"].as(), + .dailyEarnings = static_cast( + doc["result"]["estimated_earn_next_block"].as() * 100000000 + ) + }; +} + +LogoData OceanPool::getLogo() const { + return LogoData{ + .data = epd_icons_allArray[4], + .width = 122, + .height = 122 + }; +} \ No newline at end of file diff --git a/src/lib/mining_pool/ocean/ocean_pool.hpp b/src/lib/mining_pool/ocean/ocean_pool.hpp new file mode 100644 index 0000000..3756579 --- /dev/null +++ b/src/lib/mining_pool/ocean/ocean_pool.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "lib/mining_pool/mining_pool_interface.hpp" +#include + +class OceanPool : public MiningPoolInterface { +public: + void setPoolUser(const std::string& user) override { poolUser = user; } + void prepareRequest(HTTPClient& http) const override; + std::string getApiUrl() const override; + PoolStats parseResponse(const JsonDocument& doc) const override; + LogoData getLogo() const override; + bool supportsDailyEarnings() const override { return true; } + std::string getDailyEarningsLabel() const override { return "sats/block"; } +}; \ No newline at end of file diff --git a/src/lib/mining_pool/pool_factory.cpp b/src/lib/mining_pool/pool_factory.cpp new file mode 100644 index 0000000..0a786a9 --- /dev/null +++ b/src/lib/mining_pool/pool_factory.cpp @@ -0,0 +1,20 @@ +#include "pool_factory.hpp" + + +const char* PoolFactory::MINING_POOL_NAME_OCEAN = "ocean"; +const char* PoolFactory::MINING_POOL_NAME_NODERUNNERS = "noderunners"; +const char* PoolFactory::MINING_POOL_NAME_BRAIINS = "braiins"; + +std::unique_ptr PoolFactory::createPool(const std::string& poolName) { + static const std::unordered_map()>> poolFactories = { + {MINING_POOL_NAME_OCEAN, []() { return std::make_unique(); }}, + {MINING_POOL_NAME_NODERUNNERS, []() { return std::make_unique(); }}, + {MINING_POOL_NAME_BRAIINS, []() { return std::make_unique(); }} + }; + + auto it = poolFactories.find(poolName); + if (it == poolFactories.end()) { + return nullptr; + } + return it->second(); +} \ No newline at end of file diff --git a/src/lib/mining_pool/pool_factory.hpp b/src/lib/mining_pool/pool_factory.hpp new file mode 100644 index 0000000..92cba72 --- /dev/null +++ b/src/lib/mining_pool/pool_factory.hpp @@ -0,0 +1,35 @@ +#pragma once +#include "mining_pool_interface.hpp" +#include +#include +#include "noderunners/noderunners_pool.hpp" +#include "braiins/brains_pool.hpp" +#include "ocean/ocean_pool.hpp" + +class PoolFactory { + public: + static std::unique_ptr createPool(const std::string& poolName); + static std::vector getAvailablePools() { + return { + MINING_POOL_NAME_OCEAN, + MINING_POOL_NAME_NODERUNNERS, + MINING_POOL_NAME_BRAIINS + }; + } + + static std::string getAvailablePoolsAsString() { + const auto pools = getAvailablePools(); + std::string result; + for (size_t i = 0; i < pools.size(); ++i) { + result += pools[i]; + if (i < pools.size() - 1) { + result += ", "; + } + } + return result; + } + private: + static const char* MINING_POOL_NAME_OCEAN; + static const char* MINING_POOL_NAME_NODERUNNERS; + static const char* MINING_POOL_NAME_BRAIINS; +}; \ No newline at end of file diff --git a/src/lib/mining_pool/pool_stats.hpp b/src/lib/mining_pool/pool_stats.hpp new file mode 100644 index 0000000..842310a --- /dev/null +++ b/src/lib/mining_pool/pool_stats.hpp @@ -0,0 +1,10 @@ + +#pragma once + +#include +#include + +struct PoolStats { + std::string hashrate; + std::optional dailyEarnings; +}; diff --git a/src/lib/mining_pool_stats_fetch.cpp b/src/lib/mining_pool_stats_fetch.cpp index 3d440af..b263edb 100644 --- a/src/lib/mining_pool_stats_fetch.cpp +++ b/src/lib/mining_pool_stats_fetch.cpp @@ -24,68 +24,38 @@ void taskMiningPoolStatsFetch(void *pvParameters) HTTPClient http; http.setUserAgent(USER_AGENT); - String miningPoolStatsApiUrl; - miningPoolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); + std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); + std::string poolUser = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str(); - std::string httpHeaderKey = ""; - std::string httpHeaderValue; - if (miningPoolName == "ocean") { - miningPoolStatsApiUrl = "https://api.ocean.xyz/v1/statsnap/" + preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER); - } - else if (miningPoolName == "braiins") { - miningPoolStatsApiUrl = "https://pool.braiins.com/accounts/profile/json/btc/"; - httpHeaderKey = "Pool-Auth-Token"; - httpHeaderValue = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str(); - } - else + auto poolInterface = PoolFactory::createPool(poolName); + if (!poolInterface) { - // Unknown mining pool / missing implementation + Serial.println("Unknown mining pool: \"" + String(poolName.c_str()) + "\""); continue; } - http.begin(miningPoolStatsApiUrl.c_str()); - - if (httpHeaderKey.length() > 0) { - http.addHeader(httpHeaderKey.c_str(), httpHeaderValue.c_str()); - } - + poolInterface->setPoolUser(poolUser); + std::string apiUrl = poolInterface->getApiUrl(); + http.begin(apiUrl.c_str()); + poolInterface->prepareRequest(http); int httpCode = http.GET(); - if (httpCode == 200) { String payload = http.getString(); JsonDocument doc; deserializeJson(doc, payload); - if (miningPoolName == "ocean") { - miningPoolStatsHashrate = doc["result"]["hashrate_300s"].as(); - miningPoolStatsDailyEarnings = int(doc["result"]["estimated_earn_next_block"].as() * 100000000); + PoolStats stats = poolInterface->parseResponse(doc); + miningPoolStatsHashrate = stats.hashrate; + + if (stats.dailyEarnings) + { + miningPoolStatsDailyEarnings = *stats.dailyEarnings; } - else if (miningPoolName == "braiins") { - // Reports hashrate in specific hashrate units (e.g. Gh/s); we want raw total hashes per second. - std::string hashrateUnit = doc["btc"]["hash_rate_unit"].as(); - int multiplier = 0; - if (hashrateUnit == "Zh/s") { - multiplier = 21; - } else if (hashrateUnit == "Eh/s") { - multiplier = 18; - } else if (hashrateUnit == "Ph/s") { - multiplier = 15; - } else if (hashrateUnit == "Th/s") { - multiplier = 12; - } else if (hashrateUnit == "Gh/s") { - multiplier = 9; - } else if (hashrateUnit == "Mh/s") { - multiplier = 6; - } else if (hashrateUnit == "Kh/s") { - multiplier = 3; - } - - // Add zeroes to pad to a full h/s output - miningPoolStatsHashrate = std::to_string(static_cast(std::round(doc["btc"]["hash_rate_5m"].as()))) + std::string(multiplier, '0'); - - miningPoolStatsDailyEarnings = int(doc["btc"]["today_reward"].as() * 100000000); + else + { + miningPoolStatsDailyEarnings = 0; // or any other default value } if (workQueue != nullptr && (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS)) @@ -99,7 +69,6 @@ void taskMiningPoolStatsFetch(void *pvParameters) Serial.print( F("Error retrieving mining pool data. HTTP status code: ")); Serial.println(httpCode); - Serial.println(miningPoolStatsApiUrl); } } } @@ -110,4 +79,21 @@ void setupMiningPoolStatsFetchTask() &miningPoolStatsFetchTaskHandle); xTaskNotifyGive(miningPoolStatsFetchTaskHandle); -} \ No newline at end of file +} + +std::unique_ptr& getMiningPool() +{ + static std::unique_ptr currentMiningPool; + + if (!currentMiningPool) { + std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); + currentMiningPool = PoolFactory::createPool(poolName); + } + + return currentMiningPool; +} + +LogoData getMiningPoolLogo() +{ + return getMiningPool()->getLogo(); +} diff --git a/src/lib/mining_pool_stats_fetch.hpp b/src/lib/mining_pool_stats_fetch.hpp index bae5267..7a84454 100644 --- a/src/lib/mining_pool_stats_fetch.hpp +++ b/src/lib/mining_pool_stats_fetch.hpp @@ -2,6 +2,7 @@ #include #include +#include "mining_pool/pool_factory.hpp" #include "lib/config.hpp" #include "lib/shared.hpp" @@ -13,3 +14,6 @@ void taskMiningPoolStatsFetch(void *pvParameters); std::string getMiningPoolStatsHashRate(); int getMiningPoolStatsDailyEarnings(); + +std::unique_ptr& getMiningPool(); +LogoData getMiningPoolLogo(); \ No newline at end of file diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 6c4357c..d4043fa 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -38,10 +38,10 @@ void workerTask(void *pvParameters) { case TASK_MINING_POOL_STATS_UPDATE: { if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) { taskEpdContent = - parseMiningPoolStatsHashRate(preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(), getMiningPoolStatsHashRate()); + parseMiningPoolStatsHashRate(getMiningPoolStatsHashRate()); } else if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS) { taskEpdContent = - parseMiningPoolStatsDailyEarnings(preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(), getMiningPoolStatsDailyEarnings()); + parseMiningPoolStatsDailyEarnings(getMiningPoolStatsDailyEarnings(), getMiningPool()->getDailyEarningsLabel()); } setEpdContent(taskEpdContent); break; diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index 8027519..9fd7455 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -42,26 +42,15 @@ const PROGMEM int SCREEN_BLOCK_FEE_RATE = 6; const PROGMEM int SCREEN_SATS_PER_CURRENCY = 10; const PROGMEM int SCREEN_BTC_TICKER = 20; -// const PROGMEM int SCREEN_BTC_TICKER_USD = 20; -// const PROGMEM int SCREEN_BTC_TICKER_EUR = 21; -// const PROGMEM int SCREEN_BTC_TICKER_GBP = 22; -// const PROGMEM int SCREEN_BTC_TICKER_JPY = 23; -// const PROGMEM int SCREEN_BTC_TICKER_AUD = 24; -// const PROGMEM int SCREEN_BTC_TICKER_CAD = 25; const PROGMEM int SCREEN_MARKET_CAP = 30; -// const PROGMEM int SCREEN_MARKET_CAP_USD = 30; -// const PROGMEM int SCREEN_MARKET_CAP_EUR = 31; -// const PROGMEM int SCREEN_MARKET_CAP_GBP = 32; -// const PROGMEM int SCREEN_MARKET_CAP_JPY = 33; -// const PROGMEM int SCREEN_MARKET_CAP_AUD = 34; -// const PROGMEM int SCREEN_MARKET_CAP_CAD = 35; + +const PROGMEM int SCREEN_MINING_POOL_STATS_HASHRATE = 70; +const PROGMEM int SCREEN_MINING_POOL_STATS_EARNINGS = 71; const PROGMEM int SCREEN_BITAXE_HASHRATE = 80; const PROGMEM int SCREEN_BITAXE_BESTDIFF = 81; -const PROGMEM int SCREEN_MINING_POOL_STATS_HASHRATE = 70; -const PROGMEM int SCREEN_MINING_POOL_STATS_EARNINGS = 71; const PROGMEM int SCREEN_COUNTDOWN = 98; const PROGMEM int SCREEN_CUSTOM = 99; @@ -94,4 +83,15 @@ struct ScreenMapping { }; String calculateSHA256(uint8_t* data, size_t len); -String calculateSHA256(WiFiClient *stream, size_t contentLength); \ No newline at end of file +String calculateSHA256(WiFiClient *stream, size_t contentLength); + +namespace ArduinoJson { + template + struct Converter> { + static void toJson(const std::vector& src, JsonVariant dst) { + JsonArray array = dst.to(); + for (T item : src) + array.add(item); + } + }; +} \ No newline at end of file diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 4dc0c1e..8b031d6 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -717,11 +717,10 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["miningPoolStats"] = preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED); root["miningPoolName"] = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME); root["miningPoolUser"] = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER); - + root["availablePools"] = PoolFactory::getAvailablePools(); root["httpAuthEnabled"] = preferences.getBool("httpAuthEnabled", DEFAULT_HTTP_AUTH_ENABLED); root["httpAuthUser"] = preferences.getString("httpAuthUser", DEFAULT_HTTP_AUTH_USERNAME); root["httpAuthPass"] = preferences.getString("httpAuthPass", DEFAULT_HTTP_AUTH_PASSWORD); - #ifdef HAS_FRONTLIGHT root["hasFrontlight"] = true; root["flDisable"] = preferences.getBool("flDisable"); @@ -755,17 +754,8 @@ void onApiSettingsGet(AsyncWebServerRequest *request) #endif JsonArray screens = root["screens"].to(); - JsonArray actCurrencies = root["actCurrencies"].to(); - for (const auto &str : getActiveCurrencies()) - { - actCurrencies.add(str); - } - - JsonArray availableCurrencies = root["availableCurrencies"].to(); - for (const auto &str : getAvailableCurrencies()) - { - availableCurrencies.add(str); - } + root["actCurrencies"] = getActiveCurrencies(); + root["availableCurrencies"] = getAvailableCurrencies(); std::vector screenNameMap = getScreenNameMap(); diff --git a/src/lib/webserver.hpp b/src/lib/webserver.hpp index 8c49011..6817baf 100644 --- a/src/lib/webserver.hpp +++ b/src/lib/webserver.hpp @@ -14,6 +14,7 @@ #include "lib/price_notify.hpp" #include "lib/screen_handler.hpp" #include "webserver/OneParamRewrite.hpp" +#include "lib/mining_pool/pool_factory.hpp" extern TaskHandle_t eventSourceTaskHandle; From f613c7e9a1f4671807f1abce2475e0a7fd9d183d Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Fri, 20 Dec 2024 01:33:10 +0100 Subject: [PATCH 068/130] Update WebUI --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 85b9b17..dfe703d 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 85b9b17506f89696b89ab6f6e6ed231b7a8f6e91 +Subproject commit dfe703d67683f92313bea5080df4d3f6fa4ef26d From aeee5238b3e53b743ae00c6148dd4ca440a85bac Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Fri, 20 Dec 2024 04:00:09 +0100 Subject: [PATCH 069/130] Improve mining pool interface, added GoBrrr pool, Public Pool and Satoshi Radio pool --- lib/btclock/mining_pool_stats_handler.hpp | 5 - src/icons/icons.cpp | 131 +++++++++++++++++- src/lib/mining_pool/braiins/brains_pool.hpp | 2 + .../mining_pool/gobrrr_pool/gobrrr_pool.cpp | 14 ++ .../mining_pool/gobrrr_pool/gobrrr_pool.hpp | 15 ++ src/lib/mining_pool/mining_pool_interface.hpp | 2 + .../mining_pool_stats_handler.cpp | 17 ++- .../mining_pool/mining_pool_stats_handler.hpp | 8 ++ .../noderunners/noderunners_pool.cpp | 13 +- .../noderunners/noderunners_pool.hpp | 6 +- src/lib/mining_pool/ocean/ocean_pool.hpp | 3 + src/lib/mining_pool/pool_factory.cpp | 11 +- src/lib/mining_pool/pool_factory.hpp | 11 +- .../mining_pool/public_pool/public_pool.cpp | 21 +++ .../mining_pool/public_pool/public_pool.hpp | 15 ++ .../satoshi_radio/satoshi_radio_pool.cpp | 6 + .../satoshi_radio/satoshi_radio_pool.hpp | 14 ++ src/lib/screen_handler.cpp | 4 +- src/lib/screen_handler.hpp | 2 +- 19 files changed, 274 insertions(+), 26 deletions(-) delete mode 100644 lib/btclock/mining_pool_stats_handler.hpp create mode 100644 src/lib/mining_pool/gobrrr_pool/gobrrr_pool.cpp create mode 100644 src/lib/mining_pool/gobrrr_pool/gobrrr_pool.hpp rename {lib/btclock => src/lib/mining_pool}/mining_pool_stats_handler.cpp (90%) create mode 100644 src/lib/mining_pool/mining_pool_stats_handler.hpp create mode 100644 src/lib/mining_pool/public_pool/public_pool.cpp create mode 100644 src/lib/mining_pool/public_pool/public_pool.hpp create mode 100644 src/lib/mining_pool/satoshi_radio/satoshi_radio_pool.cpp create mode 100644 src/lib/mining_pool/satoshi_radio/satoshi_radio_pool.hpp diff --git a/lib/btclock/mining_pool_stats_handler.hpp b/lib/btclock/mining_pool_stats_handler.hpp deleted file mode 100644 index d9aaadd..0000000 --- a/lib/btclock/mining_pool_stats_handler.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#include -#include - -std::array parseMiningPoolStatsHashRate(std::string text); -std::array parseMiningPoolStatsDailyEarnings(int sats, std::string label); diff --git a/src/icons/icons.cpp b/src/icons/icons.cpp index 5fd6c1a..91aee98 100644 --- a/src/icons/icons.cpp +++ b/src/icons/icons.cpp @@ -1138,8 +1138,134 @@ const unsigned char epd_icons_noderunners_logo [] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 }; +// 'gobrrr', 122x122px +const unsigned char epd_icons_gobrrr_logo [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x10, 0x48, 0x84, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x24, 0x84, 0x20, 0x21, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x82, 0x25, 0x19, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x28, 0x18, 0x20, 0x41, 0x4c, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x83, 0x21, 0x88, 0x84, 0x21, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x8c, 0x48, 0x24, 0x09, 0x24, 0x82, 0x60, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x21, 0x08, 0x80, 0x61, 0x08, 0x18, 0x0a, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfc, 0x02, 0x22, 0x19, 0x04, 0x42, 0x41, 0x88, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x98, 0x82, 0x42, 0x1b, 0x11, 0x04, 0x21, 0x23, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe2, 0x20, 0x50, 0x42, 0xff, 0xe4, 0x64, 0x24, 0x83, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xc8, 0x46, 0x14, 0x93, 0xff, 0xf8, 0x01, 0x84, 0x28, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x03, 0x10, 0x81, 0x0f, 0xff, 0xfe, 0x98, 0x11, 0x08, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x24, 0x01, 0x24, 0x5f, 0xff, 0xff, 0x02, 0x42, 0x42, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfc, 0x88, 0xa9, 0x04, 0x3f, 0xff, 0xff, 0x90, 0x48, 0x21, 0x0f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x42, 0x22, 0x51, 0xbf, 0xf3, 0xff, 0xc5, 0x09, 0x0c, 0x47, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf3, 0x10, 0x40, 0x00, 0x7f, 0xc0, 0x7f, 0xc4, 0x21, 0x10, 0x93, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x25, 0x14, 0xaa, 0xff, 0x0c, 0x1f, 0xc8, 0x84, 0x42, 0x09, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe4, 0x80, 0x04, 0x82, 0xfe, 0x21, 0x0f, 0x82, 0x50, 0x88, 0x63, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x84, 0x4a, 0xc8, 0x11, 0xfc, 0x81, 0x27, 0x21, 0x06, 0x23, 0x00, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x91, 0x10, 0x02, 0x45, 0xfc, 0x18, 0x42, 0x18, 0x3f, 0xf0, 0x18, 0x7f, 0xff, 0xc0, + 0xff, 0xff, 0x10, 0x91, 0x31, 0x13, 0xf9, 0x42, 0x10, 0x82, 0x7f, 0xfc, 0x82, 0x3f, 0xff, 0xc0, + 0xff, 0xfe, 0x46, 0x04, 0x04, 0x43, 0xf8, 0x04, 0x8c, 0x21, 0xff, 0xfe, 0x62, 0x1f, 0xff, 0xc0, + 0xff, 0xfc, 0x00, 0x62, 0x42, 0x13, 0xf8, 0xb0, 0x41, 0x0c, 0xff, 0xff, 0x08, 0xcf, 0xff, 0xc0, + 0xff, 0xfc, 0xa9, 0x08, 0x98, 0x8b, 0xf2, 0x03, 0x10, 0xc3, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xc0, + 0xff, 0xf8, 0x81, 0x04, 0x80, 0x8b, 0xf2, 0x48, 0x26, 0x13, 0xf8, 0x3f, 0xd5, 0x27, 0xff, 0xc0, + 0xff, 0xf2, 0x14, 0x61, 0x24, 0x23, 0xf0, 0x88, 0x80, 0x17, 0xf0, 0x0f, 0xc4, 0x23, 0xff, 0xc0, + 0xff, 0xf0, 0x44, 0x08, 0x05, 0x27, 0xf4, 0x22, 0x17, 0xe7, 0xe5, 0x27, 0xe0, 0x8b, 0xff, 0xc0, + 0xff, 0xe4, 0x41, 0x86, 0x50, 0x43, 0xf1, 0x04, 0x47, 0xf7, 0xc1, 0x0f, 0xe9, 0x01, 0xff, 0xc0, + 0xff, 0xc3, 0x18, 0x30, 0x42, 0x13, 0xf9, 0x31, 0x27, 0xf7, 0xd0, 0x43, 0xe1, 0x31, 0xff, 0xc0, + 0xff, 0xd0, 0x02, 0x01, 0x08, 0x8b, 0xf8, 0x00, 0x8f, 0xef, 0xc6, 0x33, 0xe4, 0x04, 0xff, 0xc0, + 0xff, 0xc4, 0xa0, 0xc9, 0x22, 0x23, 0xfa, 0x4c, 0x17, 0xef, 0xc0, 0x87, 0xf0, 0xc4, 0xff, 0xc0, + 0xff, 0x88, 0x8c, 0x08, 0x21, 0x05, 0xfc, 0x41, 0x47, 0xf7, 0xc8, 0x03, 0xe2, 0x10, 0x7f, 0xc0, + 0xff, 0x82, 0x11, 0x22, 0x0c, 0x51, 0xfc, 0x10, 0x27, 0xe7, 0xc9, 0x5b, 0xe8, 0x12, 0x7f, 0xc0, + 0xff, 0x24, 0x41, 0x22, 0xc0, 0x83, 0xfe, 0x86, 0x0f, 0xf7, 0xc2, 0x07, 0xe3, 0x42, 0x3f, 0xc0, + 0xff, 0x09, 0x08, 0x78, 0x3a, 0x28, 0xff, 0x20, 0xc3, 0xf7, 0xe2, 0x27, 0xe0, 0x08, 0xbf, 0xc0, + 0xfe, 0x40, 0x92, 0x79, 0x38, 0x40, 0xff, 0x88, 0x1f, 0xe7, 0xf0, 0x8f, 0xcc, 0xa1, 0x1f, 0xc0, + 0xfe, 0x14, 0x27, 0xff, 0xfd, 0x14, 0x7f, 0xe3, 0x3f, 0xf3, 0xf4, 0x9f, 0xc0, 0x24, 0x5f, 0xc0, + 0xfe, 0x21, 0x0f, 0xff, 0xff, 0xc1, 0x3f, 0xff, 0xff, 0xf3, 0xfe, 0x7f, 0x93, 0x04, 0x1f, 0xc0, + 0xfc, 0x88, 0xcf, 0xff, 0xff, 0xf2, 0x1f, 0xff, 0xff, 0xf1, 0xff, 0xff, 0x84, 0x49, 0x2f, 0xc0, + 0xfc, 0x46, 0x0f, 0xff, 0xff, 0xf8, 0x8f, 0xff, 0xff, 0xf0, 0xff, 0xfe, 0x20, 0x40, 0x8f, 0xc0, + 0xfc, 0x10, 0x27, 0xff, 0xff, 0xfc, 0xa7, 0xff, 0xfe, 0xf2, 0x7f, 0xfe, 0x29, 0x12, 0x1f, 0xc0, + 0xf9, 0x81, 0x27, 0xf0, 0x2f, 0xfe, 0x01, 0xff, 0xf8, 0x12, 0x3f, 0xf8, 0x82, 0x12, 0x47, 0xc0, + 0xf8, 0x29, 0x0f, 0xe2, 0x01, 0xff, 0x18, 0x7f, 0xc1, 0x00, 0x87, 0x80, 0x12, 0x40, 0x47, 0xc0, + 0xfa, 0x22, 0x4f, 0xe8, 0xc4, 0xff, 0x22, 0x00, 0x04, 0x4c, 0x10, 0x25, 0x40, 0x4c, 0x17, 0xc0, + 0xf8, 0x84, 0x17, 0xe1, 0x10, 0xff, 0x00, 0x80, 0x24, 0x41, 0x40, 0x04, 0x19, 0x01, 0x87, 0xc0, + 0xf1, 0x11, 0x27, 0xe4, 0x12, 0x7f, 0x4c, 0x24, 0x91, 0x11, 0x0c, 0xd0, 0x81, 0x30, 0x27, 0xc0, + 0xf4, 0x40, 0x8f, 0xe4, 0x82, 0x7f, 0x11, 0x12, 0x01, 0x12, 0x21, 0x02, 0x44, 0x06, 0x23, 0xc0, + 0xf0, 0x8c, 0x07, 0xe0, 0xa4, 0xff, 0x13, 0x12, 0x64, 0xc2, 0x42, 0x32, 0x30, 0xc0, 0x8b, 0xc0, + 0xf2, 0x21, 0x67, 0xea, 0x08, 0xff, 0x7f, 0x4f, 0xcf, 0xe5, 0xfb, 0xf8, 0xfe, 0x18, 0x43, 0xc0, + 0xf2, 0x10, 0x0f, 0xe0, 0x42, 0xfe, 0x3f, 0xbf, 0xcf, 0xef, 0xfb, 0xf9, 0xfe, 0x03, 0x13, 0xc0, + 0xf0, 0xc6, 0x27, 0xe5, 0x17, 0xfe, 0xbf, 0xff, 0xef, 0xff, 0xf3, 0xff, 0xfc, 0xa0, 0x27, 0xc0, + 0xf1, 0x00, 0x87, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xcf, 0xff, 0xf3, 0xff, 0xfe, 0x0c, 0x83, 0xc0, + 0xf2, 0x28, 0x97, 0xff, 0xff, 0xf9, 0x3f, 0xff, 0xcf, 0xff, 0xf9, 0xff, 0xfc, 0x40, 0x4b, 0xc0, + 0xf0, 0x82, 0x17, 0xff, 0xff, 0xf2, 0x1f, 0xff, 0xc7, 0xff, 0xf1, 0xff, 0xfd, 0x23, 0x13, 0xc0, + 0xe4, 0x12, 0x47, 0xff, 0xff, 0xf8, 0x9f, 0xf3, 0x97, 0xfc, 0xf3, 0xff, 0x5c, 0x24, 0x13, 0xc0, + 0xf1, 0x48, 0x4f, 0xff, 0xff, 0xfc, 0x7f, 0xc0, 0x07, 0xf0, 0x01, 0xfc, 0x00, 0x84, 0x83, 0xc0, + 0xf1, 0x01, 0x07, 0xff, 0xff, 0xff, 0x1f, 0xc8, 0x67, 0xf3, 0x0d, 0xfc, 0x82, 0x10, 0x63, 0xc0, + 0xe4, 0x31, 0x27, 0xe0, 0x03, 0xff, 0x1f, 0xc6, 0x0f, 0xf0, 0x41, 0xfc, 0x52, 0x43, 0x09, 0xc0, + 0xf0, 0x84, 0x27, 0xe0, 0x08, 0xff, 0x3f, 0x90, 0x87, 0xe4, 0x21, 0xfc, 0x44, 0x48, 0x0b, 0xc0, + 0xf2, 0x08, 0x8f, 0xec, 0xc0, 0x7f, 0x9f, 0x80, 0x97, 0xf1, 0x8d, 0xf9, 0x09, 0x08, 0xa3, 0xc0, + 0xf1, 0x48, 0x87, 0xe1, 0x14, 0x7f, 0x9f, 0xcc, 0x27, 0xe4, 0x11, 0xfc, 0x20, 0x22, 0x07, 0xc0, + 0xf0, 0x42, 0x37, 0xe1, 0x05, 0x3f, 0x9f, 0x91, 0x27, 0xe0, 0x41, 0xfc, 0x84, 0x84, 0x53, 0xc0, + 0xf2, 0x12, 0x07, 0xe8, 0x60, 0x7f, 0x9f, 0x81, 0x07, 0xf3, 0x09, 0xf8, 0x92, 0x51, 0x03, 0xc0, + 0xf2, 0x20, 0xcf, 0xe2, 0x09, 0x7f, 0x9f, 0xc8, 0x4f, 0xf0, 0x25, 0xfc, 0x10, 0x02, 0x2b, 0xc0, + 0xf0, 0x89, 0x07, 0xe4, 0x84, 0x7f, 0x9f, 0x92, 0x27, 0xe4, 0x91, 0xfc, 0x45, 0x88, 0x83, 0xc0, + 0xf9, 0x08, 0x37, 0xe0, 0x30, 0xff, 0x9f, 0x84, 0x87, 0xe4, 0x83, 0xf9, 0x20, 0x24, 0x4f, 0xc0, + 0xf8, 0x62, 0x0f, 0xea, 0x43, 0xff, 0x3f, 0xc0, 0x4f, 0xf0, 0x28, 0x99, 0x08, 0x91, 0x07, 0xc0, + 0xf8, 0x82, 0x4f, 0xf2, 0x4f, 0xff, 0x1f, 0x99, 0x17, 0xf2, 0x4f, 0xef, 0x8a, 0x02, 0x37, 0xc0, + 0xf9, 0x10, 0x87, 0xff, 0xff, 0xfe, 0x5f, 0xc1, 0x07, 0xe2, 0x1f, 0xff, 0xa0, 0xa4, 0x87, 0xc0, + 0xf8, 0x44, 0x9f, 0xff, 0xff, 0xfe, 0x1f, 0xc4, 0x67, 0xf0, 0x8f, 0xff, 0x84, 0x10, 0x47, 0xc0, + 0xfc, 0x12, 0x0f, 0xff, 0xff, 0xfc, 0x9f, 0x90, 0x8f, 0xf4, 0x4f, 0xff, 0x91, 0x42, 0x1f, 0xc0, + 0xfd, 0x20, 0x67, 0xff, 0xff, 0xf8, 0x5f, 0xc6, 0x07, 0xf1, 0x1f, 0xff, 0x91, 0x09, 0x8f, 0xc0, + 0xfc, 0x49, 0x0f, 0xff, 0xff, 0xe1, 0x1f, 0xc0, 0x57, 0xf0, 0x8f, 0xff, 0x84, 0x24, 0x2f, 0xc0, + 0xfc, 0x42, 0x0f, 0xfb, 0x7e, 0x04, 0x3f, 0x19, 0x07, 0xc6, 0x2f, 0xff, 0xa4, 0x90, 0x0f, 0xc0, + 0xfe, 0x10, 0xa0, 0x78, 0x78, 0x90, 0x80, 0x01, 0x20, 0x00, 0x0f, 0xff, 0x88, 0x42, 0xdf, 0xc0, + 0xfe, 0x84, 0x80, 0x38, 0x38, 0x86, 0x00, 0xc4, 0x20, 0x29, 0x40, 0x00, 0x42, 0x08, 0x1f, 0xc0, + 0xfe, 0x24, 0x12, 0x02, 0x02, 0x20, 0x64, 0x10, 0x8c, 0x81, 0x13, 0xfc, 0x11, 0x89, 0x3f, 0xc0, + 0xff, 0x11, 0x24, 0xc2, 0x90, 0x22, 0x09, 0x26, 0x10, 0x94, 0x24, 0xf9, 0x88, 0x21, 0x3f, 0xc0, + 0xff, 0x41, 0x21, 0x10, 0x85, 0x89, 0x88, 0x20, 0x42, 0x10, 0x80, 0xf2, 0x22, 0x24, 0x3f, 0xc0, + 0xff, 0x8c, 0x08, 0x11, 0x24, 0x08, 0x22, 0x89, 0x22, 0x42, 0x4a, 0x64, 0x10, 0x84, 0xff, 0xc0, + 0xff, 0x80, 0xc4, 0x88, 0x10, 0x42, 0x02, 0x08, 0x88, 0x49, 0x10, 0x09, 0x44, 0x90, 0x7f, 0xc0, + 0xff, 0xd2, 0x17, 0xef, 0xdf, 0xff, 0xfd, 0xf6, 0xff, 0xff, 0xff, 0xc0, 0x08, 0x12, 0xff, 0xc0, + 0xff, 0xc2, 0x1b, 0x76, 0xed, 0xb5, 0xb7, 0x77, 0x66, 0xb6, 0x6d, 0xe4, 0xa3, 0x02, 0xff, 0xc0, + 0xff, 0xe8, 0xdb, 0x5b, 0x36, 0x6d, 0xb6, 0xd9, 0xbb, 0xad, 0xb6, 0x64, 0x20, 0x61, 0xff, 0xc0, + 0xff, 0xe0, 0x1d, 0xdb, 0xdb, 0xce, 0x6d, 0xbe, 0xdb, 0x6d, 0xb7, 0xb1, 0x0c, 0x0d, 0xff, 0xc0, + 0xff, 0xf5, 0x06, 0xdc, 0xdb, 0x73, 0xdb, 0x66, 0xdc, 0xdb, 0x6d, 0x81, 0x11, 0x83, 0xff, 0xc0, + 0xff, 0xf1, 0x20, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x48, 0x40, 0x33, 0xff, 0xc0, + 0xff, 0xf8, 0x25, 0x26, 0xac, 0x89, 0x2c, 0xb3, 0x26, 0x26, 0x9a, 0x4c, 0xca, 0x07, 0xff, 0xc0, + 0xff, 0xfc, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xf7, 0xbc, 0x8f, 0xff, 0xc0, + 0xff, 0xfc, 0x9a, 0xd9, 0x53, 0x66, 0xd3, 0x4c, 0xd9, 0x99, 0x6d, 0xb6, 0xe6, 0x3f, 0xff, 0xc0, + 0xff, 0xfe, 0x1b, 0x6f, 0x7d, 0xbb, 0x7d, 0xf7, 0x6e, 0xef, 0x6d, 0xbb, 0x7a, 0x1f, 0xff, 0xc0, + 0xff, 0xff, 0x4d, 0xb3, 0xa6, 0xdb, 0x4d, 0x37, 0x6e, 0xed, 0xb6, 0xcd, 0x98, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x26, 0xdc, 0xfb, 0x6d, 0xf7, 0xd9, 0xb3, 0x35, 0xb6, 0xf6, 0xec, 0x3f, 0xff, 0xc0, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe4, 0x22, 0x04, 0x92, 0x08, 0x24, 0x48, 0x88, 0x49, 0x09, 0x11, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe2, 0x48, 0x90, 0x00, 0x82, 0x04, 0x84, 0x92, 0x00, 0x40, 0x45, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x84, 0x93, 0x29, 0x31, 0x90, 0x91, 0x11, 0x96, 0x14, 0x87, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf9, 0x21, 0x00, 0x44, 0x04, 0x22, 0x10, 0x44, 0x10, 0x91, 0x2f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x08, 0x4c, 0x44, 0x90, 0x22, 0x46, 0x00, 0x40, 0x82, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x92, 0x21, 0x10, 0x84, 0x88, 0x40, 0xaa, 0x4a, 0x24, 0x9f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x81, 0x01, 0x02, 0x22, 0x09, 0x18, 0x21, 0x08, 0x20, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xcc, 0x54, 0x62, 0x28, 0xc1, 0x03, 0x04, 0x21, 0x8a, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x84, 0x08, 0x81, 0x14, 0x60, 0x48, 0x84, 0x0b, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf8, 0x89, 0x08, 0x44, 0x10, 0x0c, 0x22, 0x50, 0x67, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x20, 0xc3, 0x12, 0x43, 0x01, 0x84, 0x06, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x06, 0x10, 0x20, 0x88, 0x60, 0x11, 0x20, 0xbf, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xd0, 0x11, 0x24, 0x20, 0x8c, 0x48, 0x91, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf1, 0x44, 0x43, 0x0c, 0x01, 0x02, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x08, 0x90, 0x41, 0x31, 0x30, 0x6f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x22, 0x04, 0x31, 0x04, 0x05, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0x21, 0x84, 0x42, 0x45, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x28, 0x04, 0x48, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x51, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + // Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 8032) -const int epd_icons_allArray_LEN = 7; +const int epd_icons_allArray_LEN = 8; const unsigned char* epd_icons_allArray[epd_icons_allArray_LEN] = { epd_icons_pickaxe, epd_icons_rocket_launch, @@ -1147,5 +1273,6 @@ const unsigned char* epd_icons_allArray[epd_icons_allArray_LEN] = { epd_icons_bitaxe_logo, epd_icons_ocean_logo, epd_icons_braiins_logo, - epd_icons_noderunners_logo + epd_icons_noderunners_logo, + epd_icons_gobrrr_logo }; diff --git a/src/lib/mining_pool/braiins/brains_pool.hpp b/src/lib/mining_pool/braiins/brains_pool.hpp index ea2c0e0..a002c58 100644 --- a/src/lib/mining_pool/braiins/brains_pool.hpp +++ b/src/lib/mining_pool/braiins/brains_pool.hpp @@ -12,6 +12,8 @@ public: PoolStats parseResponse(const JsonDocument &doc) const override; LogoData getLogo() const override; bool supportsDailyEarnings() const override { return true; } + bool hasLogo() const override { return true; } + std::string getDisplayLabel() const override { return "BRAIINS/POOL"; } // Fallback if needed std::string getDailyEarningsLabel() const override { return "sats/earned"; } private: static int getHashrateMultiplier(const std::string &unit); diff --git a/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.cpp b/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.cpp new file mode 100644 index 0000000..90cd420 --- /dev/null +++ b/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.cpp @@ -0,0 +1,14 @@ +// src/noderunners/noderunners_pool.cpp +#include "gobrrr_pool.hpp" + +std::string GoBrrrPool::getApiUrl() const { + return "https://pool.gobrrr.me/api/client/" + poolUser; +} + +LogoData GoBrrrPool::getLogo() const { + return LogoData { + .data = epd_icons_allArray[7], + .width = 122, + .height = 122 + }; +} diff --git a/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.hpp b/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.hpp new file mode 100644 index 0000000..c50fe83 --- /dev/null +++ b/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.hpp @@ -0,0 +1,15 @@ + +#pragma once + +#include "lib/mining_pool/mining_pool_interface.hpp" +#include "lib/mining_pool/public_pool/public_pool.hpp" + +#include + +class GoBrrrPool : public PublicPool { +public: + std::string getApiUrl() const override; + bool hasLogo() const override { return true; } + std::string getDisplayLabel() const override { return "GOBRRR/POOL"; } + LogoData getLogo() const override; +}; \ No newline at end of file diff --git a/src/lib/mining_pool/mining_pool_interface.hpp b/src/lib/mining_pool/mining_pool_interface.hpp index 1df84b9..63bb53f 100644 --- a/src/lib/mining_pool/mining_pool_interface.hpp +++ b/src/lib/mining_pool/mining_pool_interface.hpp @@ -12,7 +12,9 @@ public: virtual void prepareRequest(HTTPClient& http) const = 0; virtual std::string getApiUrl() const = 0; virtual PoolStats parseResponse(const JsonDocument& doc) const = 0; + virtual bool hasLogo() const = 0; virtual LogoData getLogo() const = 0; + virtual std::string getDisplayLabel() const = 0; virtual bool supportsDailyEarnings() const = 0; virtual std::string getDailyEarningsLabel() const = 0; diff --git a/lib/btclock/mining_pool_stats_handler.cpp b/src/lib/mining_pool/mining_pool_stats_handler.cpp similarity index 90% rename from lib/btclock/mining_pool_stats_handler.cpp rename to src/lib/mining_pool/mining_pool_stats_handler.cpp index 445b912..4eb8007 100644 --- a/lib/btclock/mining_pool_stats_handler.cpp +++ b/src/lib/mining_pool/mining_pool_stats_handler.cpp @@ -1,7 +1,7 @@ #include "mining_pool_stats_handler.hpp" #include -std::array parseMiningPoolStatsHashRate(std::string text) +std::array parseMiningPoolStatsHashRate(std::string text, const MiningPoolInterface& pool) { std::array ret; ret.fill(""); // Initialize all elements to empty strings @@ -55,15 +55,18 @@ std::array parseMiningPoolStatsHashRate(std::string te ret[NUM_SCREENS - 1] = label; - - ret[0] = "mdi:miningpool"; + if (pool.hasLogo()) { + ret[0] = "mdi:miningpool"; + } else { + ret[0] = pool.getDisplayLabel(); + } return ret; } -std::array parseMiningPoolStatsDailyEarnings(int sats, std::string label) +std::array parseMiningPoolStatsDailyEarnings(int sats, std::string label, const MiningPoolInterface& pool) { std::array ret; ret.fill(""); // Initialize all elements to empty strings @@ -109,7 +112,11 @@ std::array parseMiningPoolStatsDailyEarnings(int sats, ret[NUM_SCREENS - 1] = label; - ret[0] = "mdi:miningpool"; + if (pool.hasLogo()) { + ret[0] = "mdi:miningpool"; + } else { + ret[0] = pool.getDisplayLabel(); + } return ret; } \ No newline at end of file diff --git a/src/lib/mining_pool/mining_pool_stats_handler.hpp b/src/lib/mining_pool/mining_pool_stats_handler.hpp new file mode 100644 index 0000000..a284bc7 --- /dev/null +++ b/src/lib/mining_pool/mining_pool_stats_handler.hpp @@ -0,0 +1,8 @@ +#include +#include +#ifndef UNITY_TEST +#include "lib/mining_pool/mining_pool_interface.hpp" +#endif + +std::array parseMiningPoolStatsHashRate(std::string text, const MiningPoolInterface& pool); +std::array parseMiningPoolStatsDailyEarnings(int sats, std::string label, const MiningPoolInterface& pool); diff --git a/src/lib/mining_pool/noderunners/noderunners_pool.cpp b/src/lib/mining_pool/noderunners/noderunners_pool.cpp index 22ee112..495ffd9 100644 --- a/src/lib/mining_pool/noderunners/noderunners_pool.cpp +++ b/src/lib/mining_pool/noderunners/noderunners_pool.cpp @@ -1,15 +1,15 @@ // src/noderunners/noderunners_pool.cpp #include "noderunners_pool.hpp" -void NodeRunnersPool::prepareRequest(HTTPClient& http) const { +void NoderunnersPool::prepareRequest(HTTPClient& http) const { // Empty as NodeRunners doesn't need special headers } -std::string NodeRunnersPool::getApiUrl() const { +std::string NoderunnersPool::getApiUrl() const { return "https://pool.noderunners.network/api/v1/users/" + poolUser; } -PoolStats NodeRunnersPool::parseResponse(const JsonDocument& doc) const { +PoolStats NoderunnersPool::parseResponse(const JsonDocument& doc) const { std::string hashrateStr = doc["hashrate1m"].as(); char unit = hashrateStr.back(); std::string value = hashrateStr.substr(0, hashrateStr.size() - 1); @@ -22,7 +22,7 @@ PoolStats NodeRunnersPool::parseResponse(const JsonDocument& doc) const { }; } -LogoData NodeRunnersPool::getLogo() const { +LogoData NoderunnersPool::getLogo() const { return LogoData { .data = epd_icons_allArray[6], .width = 122, @@ -30,7 +30,10 @@ LogoData NodeRunnersPool::getLogo() const { }; } -int NodeRunnersPool::getHashrateMultiplier(char unit) { +int NoderunnersPool::getHashrateMultiplier(char unit) { + if (unit == '0') + return 0; + static const std::unordered_map multipliers = { {'Z', 21}, {'E', 18}, {'P', 15}, {'T', 12}, {'G', 9}, {'M', 6}, {'K', 3} diff --git a/src/lib/mining_pool/noderunners/noderunners_pool.hpp b/src/lib/mining_pool/noderunners/noderunners_pool.hpp index ea1b0a2..c6cb25c 100644 --- a/src/lib/mining_pool/noderunners/noderunners_pool.hpp +++ b/src/lib/mining_pool/noderunners/noderunners_pool.hpp @@ -4,7 +4,7 @@ #include "lib/mining_pool/mining_pool_interface.hpp" #include -class NodeRunnersPool : public MiningPoolInterface { +class NoderunnersPool : public MiningPoolInterface { public: void setPoolUser(const std::string& user) override { poolUser = user; } @@ -14,7 +14,9 @@ public: LogoData getLogo() const override; bool supportsDailyEarnings() const override { return false; } std::string getDailyEarningsLabel() const override { return ""; } + bool hasLogo() const override { return true; } + std::string getDisplayLabel() const override { return "NODE/RUNNERS"; } // Fallback if needed -private: +protected: static int getHashrateMultiplier(char unit); }; \ No newline at end of file diff --git a/src/lib/mining_pool/ocean/ocean_pool.hpp b/src/lib/mining_pool/ocean/ocean_pool.hpp index 3756579..2773915 100644 --- a/src/lib/mining_pool/ocean/ocean_pool.hpp +++ b/src/lib/mining_pool/ocean/ocean_pool.hpp @@ -10,6 +10,9 @@ public: std::string getApiUrl() const override; PoolStats parseResponse(const JsonDocument& doc) const override; LogoData getLogo() const override; + bool hasLogo() const override { return true; } + std::string getDisplayLabel() const override { return "OCEAN/POOL"; } // Fallback if needed bool supportsDailyEarnings() const override { return true; } std::string getDailyEarningsLabel() const override { return "sats/block"; } + }; \ No newline at end of file diff --git a/src/lib/mining_pool/pool_factory.cpp b/src/lib/mining_pool/pool_factory.cpp index 0a786a9..d3073e1 100644 --- a/src/lib/mining_pool/pool_factory.cpp +++ b/src/lib/mining_pool/pool_factory.cpp @@ -1,15 +1,20 @@ #include "pool_factory.hpp" - const char* PoolFactory::MINING_POOL_NAME_OCEAN = "ocean"; const char* PoolFactory::MINING_POOL_NAME_NODERUNNERS = "noderunners"; const char* PoolFactory::MINING_POOL_NAME_BRAIINS = "braiins"; +const char* PoolFactory::MINING_POOL_NAME_SATOSHI_RADIO = "satoshi_radio"; +const char* PoolFactory::MINING_POOL_NAME_PUBLIC_POOL = "public_pool"; +const char* PoolFactory::MINING_POOL_NAME_GOBRRR_POOL = "gobrrr_pool"; std::unique_ptr PoolFactory::createPool(const std::string& poolName) { static const std::unordered_map()>> poolFactories = { {MINING_POOL_NAME_OCEAN, []() { return std::make_unique(); }}, - {MINING_POOL_NAME_NODERUNNERS, []() { return std::make_unique(); }}, - {MINING_POOL_NAME_BRAIINS, []() { return std::make_unique(); }} + {MINING_POOL_NAME_NODERUNNERS, []() { return std::make_unique(); }}, + {MINING_POOL_NAME_BRAIINS, []() { return std::make_unique(); }}, + {MINING_POOL_NAME_SATOSHI_RADIO, []() { return std::make_unique(); }}, + {MINING_POOL_NAME_PUBLIC_POOL, []() { return std::make_unique(); }}, + {MINING_POOL_NAME_GOBRRR_POOL, []() { return std::make_unique(); }} }; auto it = poolFactories.find(poolName); diff --git a/src/lib/mining_pool/pool_factory.hpp b/src/lib/mining_pool/pool_factory.hpp index 92cba72..a8e4861 100644 --- a/src/lib/mining_pool/pool_factory.hpp +++ b/src/lib/mining_pool/pool_factory.hpp @@ -5,6 +5,9 @@ #include "noderunners/noderunners_pool.hpp" #include "braiins/brains_pool.hpp" #include "ocean/ocean_pool.hpp" +#include "satoshi_radio/satoshi_radio_pool.hpp" +#include "public_pool/public_pool.hpp" +#include "gobrrr_pool/gobrrr_pool.hpp" class PoolFactory { public: @@ -13,7 +16,10 @@ class PoolFactory { return { MINING_POOL_NAME_OCEAN, MINING_POOL_NAME_NODERUNNERS, - MINING_POOL_NAME_BRAIINS + MINING_POOL_NAME_SATOSHI_RADIO, + MINING_POOL_NAME_BRAIINS, + MINING_POOL_NAME_PUBLIC_POOL, + MINING_POOL_NAME_GOBRRR_POOL }; } @@ -32,4 +38,7 @@ class PoolFactory { static const char* MINING_POOL_NAME_OCEAN; static const char* MINING_POOL_NAME_NODERUNNERS; static const char* MINING_POOL_NAME_BRAIINS; + static const char* MINING_POOL_NAME_SATOSHI_RADIO; + static const char* MINING_POOL_NAME_PUBLIC_POOL; + static const char* MINING_POOL_NAME_GOBRRR_POOL; }; \ No newline at end of file diff --git a/src/lib/mining_pool/public_pool/public_pool.cpp b/src/lib/mining_pool/public_pool/public_pool.cpp new file mode 100644 index 0000000..9a5d56f --- /dev/null +++ b/src/lib/mining_pool/public_pool/public_pool.cpp @@ -0,0 +1,21 @@ +// src/noderunners/noderunners_pool.cpp +#include "public_pool.hpp" + +std::string PublicPool::getApiUrl() const { + return "https://public-pool.io:40557/api/client/" + poolUser; +} + +PoolStats PublicPool::parseResponse(const JsonDocument& doc) const { + uint64_t totalHashrate = 0; + + for (JsonVariantConst worker : doc["workers"].as()) { + totalHashrate += static_cast(std::llround(worker["hashRate"].as())); + } + + + + return PoolStats{ + .hashrate = std::to_string(totalHashrate), + .dailyEarnings = std::nullopt // Public Pool doesn't support daily earnings + }; +} \ No newline at end of file diff --git a/src/lib/mining_pool/public_pool/public_pool.hpp b/src/lib/mining_pool/public_pool/public_pool.hpp new file mode 100644 index 0000000..e2fdaed --- /dev/null +++ b/src/lib/mining_pool/public_pool/public_pool.hpp @@ -0,0 +1,15 @@ + +#pragma once + +#include "lib/mining_pool/mining_pool_interface.hpp" +#include "lib/mining_pool/noderunners/noderunners_pool.hpp" + +#include + +class PublicPool : public NoderunnersPool { +public: + std::string getApiUrl() const override; + bool hasLogo() const override { return false; } + std::string getDisplayLabel() const override { return "PUBLIC/POOL"; } + PoolStats parseResponse(const JsonDocument& doc) const override; +}; \ No newline at end of file diff --git a/src/lib/mining_pool/satoshi_radio/satoshi_radio_pool.cpp b/src/lib/mining_pool/satoshi_radio/satoshi_radio_pool.cpp new file mode 100644 index 0000000..5b8f4a3 --- /dev/null +++ b/src/lib/mining_pool/satoshi_radio/satoshi_radio_pool.cpp @@ -0,0 +1,6 @@ +// src/noderunners/noderunners_pool.cpp +#include "satoshi_radio_pool.hpp" + +std::string SatoshiRadioPool::getApiUrl() const { + return "https://pool.satoshiradio.nl/api/v1/users/" + poolUser; +} diff --git a/src/lib/mining_pool/satoshi_radio/satoshi_radio_pool.hpp b/src/lib/mining_pool/satoshi_radio/satoshi_radio_pool.hpp new file mode 100644 index 0000000..d809fb1 --- /dev/null +++ b/src/lib/mining_pool/satoshi_radio/satoshi_radio_pool.hpp @@ -0,0 +1,14 @@ + +#pragma once + +#include "lib/mining_pool/mining_pool_interface.hpp" +#include "lib/mining_pool/noderunners/noderunners_pool.hpp" + +#include + +class SatoshiRadioPool : public NoderunnersPool { +public: + std::string getApiUrl() const override; + bool hasLogo() const override { return false; } + std::string getDisplayLabel() const override { return "SATOSHI/RADIO"; } // Fallback if needed +}; \ No newline at end of file diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index d4043fa..ea55e02 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -38,10 +38,10 @@ void workerTask(void *pvParameters) { case TASK_MINING_POOL_STATS_UPDATE: { if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) { taskEpdContent = - parseMiningPoolStatsHashRate(getMiningPoolStatsHashRate()); + parseMiningPoolStatsHashRate(getMiningPoolStatsHashRate(), *getMiningPool()); } else if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS) { taskEpdContent = - parseMiningPoolStatsDailyEarnings(getMiningPoolStatsDailyEarnings(), getMiningPool()->getDailyEarningsLabel()); + parseMiningPoolStatsDailyEarnings(getMiningPoolStatsDailyEarnings(), getMiningPool()->getDailyEarningsLabel(), *getMiningPool()); } setEpdContent(taskEpdContent); break; diff --git a/src/lib/screen_handler.hpp b/src/lib/screen_handler.hpp index ee658c9..fcdf2ba 100644 --- a/src/lib/screen_handler.hpp +++ b/src/lib/screen_handler.hpp @@ -6,7 +6,7 @@ #include #include -#include +#include "lib/mining_pool/mining_pool_stats_handler.hpp" #include "lib/epd.hpp" #include "lib/shared.hpp" From e8a7b221cbd579fe8745da282e914b580caf2d53 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Fri, 20 Dec 2024 04:07:46 +0100 Subject: [PATCH 070/130] Update WebUI for new mining pools --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index dfe703d..fd328d4 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit dfe703d67683f92313bea5080df4d3f6fa4ef26d +Subproject commit fd328d4f05345eaa73cf27d05bb542eaa6915cdb From 7bcb24bab0a7c8ba8d5bcdba5a91a07834ad9a38 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Fri, 20 Dec 2024 14:11:26 +0100 Subject: [PATCH 071/130] Mining pool bugfixes, improvements and icon optimizations --- lib/btclock/utils.cpp | 79 ++ lib/btclock/utils.hpp | 6 +- platformio.ini | 4 +- src/icons/icons.cpp | 727 ++++++------------ src/lib/config.cpp | 78 -- src/lib/epd.cpp | 4 +- src/lib/mining_pool/braiins/brains_pool.cpp | 4 +- src/lib/mining_pool/braiins/brains_pool.hpp | 3 +- .../mining_pool/mining_pool_stats_handler.cpp | 39 +- .../mining_pool/mining_pool_stats_handler.hpp | 5 +- .../noderunners/noderunners_pool.cpp | 19 +- .../noderunners/noderunners_pool.hpp | 4 +- src/lib/mining_pool_stats_fetch.cpp | 1 + test/test_mining_pool/test_main.cpp | 75 ++ 14 files changed, 411 insertions(+), 637 deletions(-) create mode 100644 test/test_mining_pool/test_main.cpp diff --git a/lib/btclock/utils.cpp b/lib/btclock/utils.cpp index 0e19962..d5c8027 100644 --- a/lib/btclock/utils.cpp +++ b/lib/btclock/utils.cpp @@ -164,3 +164,82 @@ int64_t getAmountInSatoshis(std::string bolt11) { return satoshis; } + +void parseHashrateString(const std::string& hashrate, std::string& label, std::string& output, unsigned int maxCharacters) { + // Handle empty string or "0" cases + if (hashrate.empty() || hashrate == "0") { + label = "H/S"; + output = "0"; + return; + } + + size_t suffixLength = 0; + if (hashrate.length() > 21) { + label = "ZH/S"; + suffixLength = 21; + } else if (hashrate.length() > 18) { + label = "EH/S"; + suffixLength = 18; + } else if (hashrate.length() > 15) { + label = "PH/S"; + suffixLength = 15; + } else if (hashrate.length() > 12) { + label = "TH/S"; + suffixLength = 12; + } else if (hashrate.length() > 9) { + label = "GH/S"; + suffixLength = 9; + } else if (hashrate.length() > 6) { + label = "MH/S"; + suffixLength = 6; + } else if (hashrate.length() > 3) { + label = "KH/S"; + suffixLength = 3; + } else { + label = "H/S"; + suffixLength = 0; + } + + double value = std::stod(hashrate) / std::pow(10, suffixLength); + + // Calculate integer part length + int integerPartLength = std::to_string(static_cast(value)).length(); + + // Calculate remaining space for decimals + int remainingSpace = maxCharacters - integerPartLength; + + char buffer[32]; + if (remainingSpace <= 0) + { + // No space for decimals, just round to integer + snprintf(buffer, sizeof(buffer), "%.0f", value); + } + else + { + // Space for decimal point and some decimals + snprintf(buffer, sizeof(buffer), "%.*f", remainingSpace - 1, value); + } + + // Remove trailing zeros and decimal point if necessary + output = buffer; + if (output.find('.') != std::string::npos) + { + output = output.substr(0, output.find_last_not_of('0') + 1); + if (output.back() == '.') + { + output.pop_back(); + } + } + +} + +int getHashrateMultiplier(char unit) { + if (unit == '0') + return 0; + + static const std::unordered_map multipliers = { + {'Z', 21}, {'E', 18}, {'P', 15}, {'T', 12}, + {'G', 9}, {'M', 6}, {'K', 3} + }; + return multipliers.at(unit); +} diff --git a/lib/btclock/utils.hpp b/lib/btclock/utils.hpp index cf4a107..44df032 100644 --- a/lib/btclock/utils.hpp +++ b/lib/btclock/utils.hpp @@ -5,6 +5,8 @@ #include #include #include +#include + int modulo(int x,int N); @@ -12,4 +14,6 @@ double getSupplyAtBlock(std::uint32_t blockNr); std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters = 4); std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters, bool mowMode); -int64_t getAmountInSatoshis(std::string bolt11); \ No newline at end of file +int64_t getAmountInSatoshis(std::string bolt11); +void parseHashrateString(const std::string& hashrate, std::string& label, std::string& output, unsigned int maxCharacters); +int getHashrateMultiplier(char unit); \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index d2abb92..81d4a49 100644 --- a/platformio.ini +++ b/platformio.ini @@ -164,4 +164,6 @@ build_flags = -D MCP_INT_PIN=8 -D NEOPIXEL_PIN=34 -D NEOPIXEL_COUNT=4 - -D NUM_SCREENS=7 \ No newline at end of file + -D NUM_SCREENS=7 + -D UNITY_TEST + -std=gnu++17 diff --git a/src/icons/icons.cpp b/src/icons/icons.cpp index 91aee98..55854f8 100644 --- a/src/icons/icons.cpp +++ b/src/icons/icons.cpp @@ -376,258 +376,160 @@ const unsigned char epd_icons_pickaxe [] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 }; -// 'bitaxe_logo', 122x250px const unsigned char epd_icons_bitaxe_logo [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xcf, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xfc, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0x83, 0xff, 0xff, 0xf7, 0xf0, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xf1, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xf8, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xcf, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xe7, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xe7, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x07, 0xf9, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x07, 0xf8, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xff, 0x8f, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0x8f, 0xf7, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe2, 0x00, 0x00, 0x01, 0x00, 0x00, 0x20, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x11, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xbf, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xbf, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0x9f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xfb, 0xf0, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xf7, 0xf8, 0x3f, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xf1, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0x83, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xef, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x3f, 0xff, 0xcf, 0xff, 0xff, 0x83, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x1f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x0f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xbf, 0xff, 0x01, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x7f, 0xc1, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x81, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xfd, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xfb, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xf3, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xe7, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0x8f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x82, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 + // 'bitaxe_dark copy', 88x220px + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3e, 0xff, 0xff, 0xfd, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0xff, 0xff, 0xfe, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xff, 0x00, + 0x07, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, + 0xf0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x00, 0x07, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x03, 0xff, + 0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0xe0, 0x07, 0xf8, 0x7f, 0xff, 0xfd, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xfe, + 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0x07, + 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xcf, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0x80, 0x0f, + 0xff, 0xe7, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xf3, 0xff, 0xff, 0xf0, + 0x01, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xf3, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xf0, + 0x1f, 0xff, 0xf9, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xfd, 0xff, 0xff, + 0xe0, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xfd, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xfe, + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xfe, 0x7f, + 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xfc, 0x7f, 0xff, 0xff, + 0xff, 0xfc, 0x00, 0x00, 0x7f, 0x3f, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x0f, 0xff, + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, + 0x1f, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xf0, 0x03, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x0f, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xfc, 0xff, 0xff, + 0xff, 0xff, 0xfc, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, + 0x00, 0x3f, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x01, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, + 0xe0, 0x0f, 0xff, 0xf1, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xf9, 0xfc, + 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xfd, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0x3f, + 0xff, 0xf8, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xf7, 0xff, 0xff, 0xfc, 0x3f, 0xff, + 0xff, 0xff, 0xe0, 0x07, 0xff, 0xf3, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, + 0xf3, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xf3, 0xff, 0xff, 0xf8, 0x01, + 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xf9, 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0x80, 0x1f, + 0xff, 0xf9, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xfc, 0xff, 0xff, 0xf0, + 0x03, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xfe, 0x3f, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xf8, + 0x3f, 0xff, 0x7e, 0x1f, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xfc, 0xff, 0x03, 0xff, + 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, + 0xff, 0x80, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xe0, + 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff, + 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, + 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, + 0xff, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x7f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, + 0xff, 0x83, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xf8, 0x7f, + 0xff, 0xf9, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0xff, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xe0, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0xff, 0xc0, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x1f, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xff, 0xc0, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x3f, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xf0, 0x7f, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1f, 0xff, 0xf9, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, + 0xff, 0xf0, 0x1f, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xfd, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff, + 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, + 0xef, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xfc, 0x00, + 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, + 0x00, 0x07, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x03, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, + 0xff, 0xe0, 0x07, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xe0, 0x07, 0xff, 0xff, + 0x80, 0x1f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xc0, 0x07, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xf8, + 0x0f, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x07, 0xff, 0x80, 0x0f, 0xff, + 0xff, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x03, 0xff, 0x80, 0x1f, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, + 0xf0, 0x01, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xf0, 0x01, 0xff, 0xf0, 0x1f, + 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x7f, 0xff, + 0xff, 0xe0, 0x03, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xfe, 0x00, 0x7f, 0xff, 0x80, 0x03, 0xff, + 0xff, 0xff, 0xf8, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, + 0x00, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xe0, 0x1f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0x01, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xfc, + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfe, 0x03, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, + 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, + 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, + 0xbf, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0x9f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xe7, 0xff, 0xff, 0xe7, 0xfd, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xfc, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff }; @@ -761,256 +663,79 @@ const unsigned char epd_icons_ocean_logo [] PROGMEM = { // // 'braiins_pool', 122x250px const unsigned char epd_icons_braiins_logo [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xe0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xc0, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xc0, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xc0, 0x38, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0x7c, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x00, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x01, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x01, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf0, 0x1f, 0x01, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf0, 0x0c, 0x01, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0x01, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf8, 0x00, 0x03, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf8, 0x00, 0x03, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xfc, 0x00, 0x07, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xc0, - 0xff, 0xfe, 0x00, 0x0f, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0x00, 0x1f, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x3f, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0x00, 0x00, 0x01, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x03, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfc, 0x00, 0x03, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x00, 0x00, 0x03, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x00, 0x00, 0x03, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x07, 0xff, 0x81, 0xff, 0xe0, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x07, 0xfe, 0x00, 0x7f, 0xe0, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xf8, 0x00, 0x1f, 0xf0, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x00, 0x0f, 0xf0, 0x00, 0x0f, 0xf0, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x0f, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x07, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xc0, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x03, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x07, 0xc0, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x06, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf0, 0x00, 0x03, 0xff, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x00, 0x00, 0x03, 0xff, 0x00, 0x07, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0x00, 0x03, 0xff, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xfc, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x03, 0xff, 0x00, 0x07, 0xff, 0x00, 0xff, 0xe0, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x03, 0xff, 0x00, 0x0f, 0xfc, 0x00, 0x3f, 0xe0, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0x00, 0x0f, 0xf8, 0x00, 0x1f, 0xf0, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf8, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xf0, 0x00, 0x0f, 0xf0, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x07, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x07, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x00, 0x00, 0x03, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0x3f, 0x80, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xfc, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0x00, 0x03, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xc0, 0x00, 0x03, 0xf0, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x07, 0x80, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0x00, 0x07, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x07, 0xff, 0xff, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xfc, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf0, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x03, 0xff, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xfc, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xfe, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xf3, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0x00, 0x0f, 0xff, 0xc3, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xfe, 0x00, 0x07, 0xff, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xfc, 0x00, 0x03, 0xfc, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xf8, 0x00, 0x01, 0xf0, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0x00, 0xc0, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x1f, 0x80, 0x00, 0x07, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xc0, 0x00, 0x1f, 0xff, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xe0, 0x00, 0x7f, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xe0, 0x01, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xe0, 0x0f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xe0, 0x3f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xe0, 0x7f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xe0, 0x7f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xe0, 0x7f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xe0, 0x7f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xe0, 0x7f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0xc0, 0x3f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x00, 0xfc, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xfc, 0x00, 0x38, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf8, 0x00, 0x10, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x7c, 0x03, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x1e, 0x00, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x3f, 0x80, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +// 'braiins-vector-logo', 37x230px + 0xff, 0xff, 0xf8, 0x0f, 0xf8, 0xff, 0xff, 0xe0, 0x01, 0xf8, 0x01, 0xff, 0xc0, 0x00, 0xf8, 0x01, + 0xff, 0x80, 0x00, 0x78, 0x01, 0xff, 0x00, 0x00, 0x38, 0x01, 0xff, 0x00, 0x00, 0x18, 0x01, 0xfe, + 0x00, 0x00, 0x18, 0x01, 0xfe, 0x00, 0x00, 0x18, 0x01, 0xfe, 0x01, 0xf0, 0x08, 0x01, 0xfc, 0x03, + 0xf8, 0x08, 0x01, 0xfc, 0x03, 0xf8, 0x08, 0x01, 0xfc, 0x07, 0xf8, 0x08, 0x01, 0xfc, 0x07, 0xfc, + 0x08, 0x01, 0xfc, 0x07, 0xfc, 0x08, 0x01, 0xfc, 0x07, 0xfc, 0x08, 0x01, 0xf8, 0x07, 0xf8, 0x08, + 0x00, 0xf8, 0x07, 0xf8, 0x08, 0x80, 0xf0, 0x07, 0xf8, 0x08, 0x80, 0x00, 0x0f, 0xf0, 0x08, 0x80, + 0x00, 0x0f, 0xf0, 0x08, 0xc0, 0x00, 0x0f, 0xe0, 0x18, 0xc0, 0x00, 0x1f, 0xc0, 0x18, 0xe0, 0x00, + 0x3f, 0xc0, 0x38, 0xf0, 0x00, 0x3f, 0xe0, 0x38, 0xf8, 0x00, 0xff, 0xf0, 0x78, 0xfe, 0x03, 0xff, + 0xf8, 0xf8, 0xff, 0xff, 0xff, 0xfd, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0x00, + 0x08, 0xff, 0xff, 0xfc, 0x00, 0x08, 0xff, 0xff, 0xf0, 0x00, 0x38, 0xff, 0xff, 0xc0, 0x00, 0xf8, + 0xff, 0xff, 0x00, 0x03, 0xf8, 0xff, 0xfc, 0x00, 0x07, 0xf8, 0xff, 0xf0, 0x00, 0x1f, 0xf8, 0xff, + 0xc0, 0x00, 0x7f, 0xf8, 0xff, 0x80, 0x01, 0xff, 0xf8, 0xfe, 0x00, 0x03, 0xff, 0xf8, 0xf8, 0x00, + 0x0f, 0xff, 0xf8, 0xf0, 0x00, 0x3f, 0xff, 0xf8, 0xc0, 0x00, 0xff, 0xff, 0xf8, 0x00, 0x03, 0xff, + 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, + 0x08, 0xff, 0xff, 0xff, 0x80, 0x08, 0xff, 0xff, 0xfc, 0x00, 0x08, 0xff, 0xff, 0xc0, 0x00, 0x08, + 0xff, 0xfe, 0x00, 0x00, 0x08, 0xff, 0xf0, 0x00, 0x00, 0x08, 0xff, 0x00, 0x00, 0x00, 0x08, 0xf8, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, + 0x03, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, + 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf0, 0x08, 0xff, + 0xff, 0xff, 0x80, 0x08, 0xff, 0xff, 0xf8, 0x00, 0x08, 0xff, 0xff, 0xc0, 0x00, 0x08, 0xff, 0xfe, + 0x00, 0x00, 0x08, 0xff, 0xf0, 0x00, 0x00, 0x08, 0xff, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x03, 0xff, + 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, + 0x00, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf0, 0x08, 0xff, 0xff, 0xff, + 0x00, 0x08, 0xff, 0xff, 0xf8, 0x00, 0x08, 0xff, 0xff, 0xc0, 0x00, 0x08, 0xff, 0xfe, 0x00, 0x00, + 0x08, 0xff, 0xe0, 0x00, 0x00, 0x08, 0xff, 0x00, 0x00, 0x00, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x08, + 0x80, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x07, 0xff, 0xf8, 0x00, + 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x00, 0xff, + 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x00, 0x07, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, + 0xf8, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0xe0, 0x00, 0x00, 0x03, 0xf8, 0xfc, 0x00, 0x00, 0x00, 0x08, + 0xff, 0xc0, 0x00, 0x00, 0x08, 0xff, 0xf8, 0x00, 0x00, 0x08, 0xff, 0xff, 0x00, 0x00, 0x08, 0xff, + 0xff, 0xf0, 0x00, 0x08, 0xff, 0xff, 0xfe, 0x00, 0x08, 0xff, 0xff, 0xff, 0xc0, 0x08, 0xff, 0xff, + 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xe8, + 0xfe, 0x00, 0xff, 0xff, 0x88, 0xf0, 0x00, 0x3f, 0xfe, 0x08, 0xe0, 0x00, 0x1f, 0xf8, 0x08, 0xc0, + 0x00, 0x0f, 0xe0, 0x08, 0xc0, 0x00, 0x07, 0x80, 0x08, 0x80, 0x00, 0x06, 0x00, 0x08, 0x80, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xfe, 0x00, 0x00, 0x38, 0x01, 0xff, 0x00, + 0x00, 0xf8, 0x01, 0xff, 0x00, 0x03, 0xf8, 0x01, 0xff, 0x00, 0x0f, 0xf8, 0x01, 0xff, 0x00, 0x3f, + 0xf8, 0x01, 0xff, 0x00, 0xff, 0xf8, 0x01, 0xff, 0x01, 0xff, 0xf8, 0x01, 0xff, 0x01, 0xff, 0xf8, + 0x01, 0xff, 0x01, 0xff, 0xf8, 0x01, 0xff, 0x01, 0xff, 0xf8, 0x01, 0xff, 0x01, 0xff, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xbf, 0xf8, 0xff, 0xff, + 0xf8, 0x03, 0xf8, 0xf8, 0x07, 0xf0, 0x00, 0xf8, 0xf0, 0x01, 0xe0, 0x00, 0x78, 0xc0, 0x00, 0xc0, + 0x00, 0x38, 0xc0, 0x00, 0x80, 0x00, 0x18, 0x80, 0x00, 0x00, 0x00, 0x18, 0x80, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0xf0, 0x08, 0x00, 0xfc, 0x07, 0xf8, 0x08, + 0x01, 0xfc, 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, 0xf8, 0x08, 0x01, + 0xfe, 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, 0xf8, 0x08, 0x01, 0xfe, + 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, + 0xf8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x03, + 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xf8 }; const unsigned char epd_icons_noderunners_logo [] PROGMEM = { diff --git a/src/lib/config.cpp b/src/lib/config.cpp index d7f403f..04e9a60 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -359,68 +359,6 @@ String replaceAmbiguousChars(String input) return input; } -// void addCurrencyMappings(const std::vector& currencies) -// { -// for (const auto& currency : currencies) -// { -// int satsPerCurrencyScreen; -// int btcTickerScreen; -// int marketCapScreen; - -// // Determine the corresponding screen IDs based on the currency code -// if (currency == "USD") -// { -// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_USD; -// btcTickerScreen = SCREEN_BTC_TICKER_USD; -// marketCapScreen = SCREEN_MARKET_CAP_USD; -// } -// else if (currency == "EUR") -// { -// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_EUR; -// btcTickerScreen = SCREEN_BTC_TICKER_EUR; -// marketCapScreen = SCREEN_MARKET_CAP_EUR; -// } -// else if (currency == "GBP") -// { -// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_GBP; -// btcTickerScreen = SCREEN_BTC_TICKER_GBP; -// marketCapScreen = SCREEN_MARKET_CAP_GBP; -// } -// else if (currency == "JPY") -// { -// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_JPY; -// btcTickerScreen = SCREEN_BTC_TICKER_JPY; -// marketCapScreen = SCREEN_MARKET_CAP_JPY; -// } -// else if (currency == "AUD") -// { -// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_AUD; -// btcTickerScreen = SCREEN_BTC_TICKER_AUD; -// marketCapScreen = SCREEN_MARKET_CAP_AUD; -// } -// else if (currency == "CAD") -// { -// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_CAD; -// btcTickerScreen = SCREEN_BTC_TICKER_CAD; -// marketCapScreen = SCREEN_MARKET_CAP_CAD; -// } -// else -// { -// continue; // Unknown currency, skip it -// } - -// // Create the string locally to ensure it persists -// std::string satsPerCurrencyString = "Sats per " + currency; -// std::string btcTickerString = "Ticker " + currency; -// std::string marketCapString = "Market Cap " + currency; - -// // Pass the c_str() to the function -// addScreenMapping(satsPerCurrencyScreen, satsPerCurrencyString.c_str()); -// addScreenMapping(btcTickerScreen, btcTickerString.c_str()); -// addScreenMapping(marketCapScreen, marketCapString.c_str()); -// } -// } - void setupWebsocketClients(void *pvParameters) { if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) @@ -823,19 +761,3 @@ const char* getWebUiFilename() { return "littlefs_4MB.bin"; } } - - -// void loadIcons() { -// size_t ocean_logo_size = 886; - -// int iUncompSize = zt.gzip_info((uint8_t *)epd_compress_bitaxe, ocean_logo_size); -// Serial.printf("uncompressed size = %d\n", iUncompSize); - -// uint8_t *pUncompressed; -// pUncompressed = (uint8_t *)malloc(iUncompSize+4); -// int rc = zt.gunzip((uint8_t *)epd_compress_bitaxe, ocean_logo_size, pUncompressed); - -// if (rc == ZT_SUCCESS) { -// Serial.println("Decode success"); -// } -// } \ No newline at end of file diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 062fc74..b91e75c 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -613,8 +613,8 @@ void renderIcon(const uint dispNum, const String &text, bool partial) iconIndex = 2; } else if (text.endsWith("bitaxe")) { - width = 122; - height = 250; + width = 88; + height = 220; iconIndex = 3; } else if (text.endsWith("miningpool")) { diff --git a/src/lib/mining_pool/braiins/brains_pool.cpp b/src/lib/mining_pool/braiins/brains_pool.cpp index 5418829..93f9d37 100644 --- a/src/lib/mining_pool/braiins/brains_pool.cpp +++ b/src/lib/mining_pool/braiins/brains_pool.cpp @@ -26,7 +26,7 @@ PoolStats BraiinsPool::parseResponse(const JsonDocument &doc) const LogoData BraiinsPool::getLogo() const { return LogoData{ .data = epd_icons_allArray[5], - .width = 122, - .height = 250 + .width = 37, + .height = 230 }; } \ No newline at end of file diff --git a/src/lib/mining_pool/braiins/brains_pool.hpp b/src/lib/mining_pool/braiins/brains_pool.hpp index a002c58..e9354e5 100644 --- a/src/lib/mining_pool/braiins/brains_pool.hpp +++ b/src/lib/mining_pool/braiins/brains_pool.hpp @@ -2,6 +2,7 @@ #include "lib/mining_pool/mining_pool_interface.hpp" #include +#include class BraiinsPool : public MiningPoolInterface { @@ -15,6 +16,4 @@ public: bool hasLogo() const override { return true; } std::string getDisplayLabel() const override { return "BRAIINS/POOL"; } // Fallback if needed std::string getDailyEarningsLabel() const override { return "sats/earned"; } -private: - static int getHashrateMultiplier(const std::string &unit); }; \ No newline at end of file diff --git a/src/lib/mining_pool/mining_pool_stats_handler.cpp b/src/lib/mining_pool/mining_pool_stats_handler.cpp index 4eb8007..ffd9885 100644 --- a/src/lib/mining_pool/mining_pool_stats_handler.cpp +++ b/src/lib/mining_pool/mining_pool_stats_handler.cpp @@ -1,46 +1,19 @@ #include "mining_pool_stats_handler.hpp" -#include -std::array parseMiningPoolStatsHashRate(std::string text, const MiningPoolInterface& pool) +std::array parseMiningPoolStatsHashRate(const std::string& hashrate, const MiningPoolInterface& pool) { std::array ret; ret.fill(""); // Initialize all elements to empty strings - std::string hashrate; std::string label; + std::string output; - if (text.length() > 21) { - // We are massively future-proof!! - label = "ZH/S"; - hashrate = text.substr(0, text.length() - 21); - } else if (text.length() > 18) { - label = "EH/S"; - hashrate = text.substr(0, text.length() - 18); - } else if (text.length() > 15) { - label = "PH/S"; - hashrate = text.substr(0, text.length() - 15); - } else if (text.length() > 12) { - label = "TH/S"; - hashrate = text.substr(0, text.length() - 12); - } else if (text.length() > 9) { - label = "GH/S"; - hashrate = text.substr(0, text.length() - 9); - } else if (text.length() > 6) { - label = "MH/S"; - hashrate = text.substr(0, text.length() - 6); - } else if (text.length() > 3) { - label = "KH/S"; - hashrate = text.substr(0, text.length() - 3); - } else { - label = "H/S"; - hashrate = text; - } - - std::size_t textLength = hashrate.length(); + parseHashrateString(hashrate, label, output, 4); + std::size_t textLength = output.length(); // Calculate the position where the digits should start // Account for the position of the mining pool logo and the hashrate label std::size_t startIndex = NUM_SCREENS - 1 - textLength; - + // Insert the pickaxe icon just before the digits if (startIndex > 0) { @@ -50,7 +23,7 @@ std::array parseMiningPoolStatsHashRate(std::string te // Place the digits for (std::size_t i = 0; i < textLength; ++i) { - ret[startIndex + i] = hashrate.substr(i, 1); + ret[startIndex + i] = output.substr(i, 1); } ret[NUM_SCREENS - 1] = label; diff --git a/src/lib/mining_pool/mining_pool_stats_handler.hpp b/src/lib/mining_pool/mining_pool_stats_handler.hpp index a284bc7..dcbc1db 100644 --- a/src/lib/mining_pool/mining_pool_stats_handler.hpp +++ b/src/lib/mining_pool/mining_pool_stats_handler.hpp @@ -1,8 +1,11 @@ #include #include +#include +#include + #ifndef UNITY_TEST #include "lib/mining_pool/mining_pool_interface.hpp" #endif -std::array parseMiningPoolStatsHashRate(std::string text, const MiningPoolInterface& pool); +std::array parseMiningPoolStatsHashRate(const std::string& hashrate, const MiningPoolInterface& pool); std::array parseMiningPoolStatsDailyEarnings(int sats, std::string label, const MiningPoolInterface& pool); diff --git a/src/lib/mining_pool/noderunners/noderunners_pool.cpp b/src/lib/mining_pool/noderunners/noderunners_pool.cpp index 495ffd9..0f55180 100644 --- a/src/lib/mining_pool/noderunners/noderunners_pool.cpp +++ b/src/lib/mining_pool/noderunners/noderunners_pool.cpp @@ -15,9 +15,13 @@ PoolStats NoderunnersPool::parseResponse(const JsonDocument& doc) const { std::string value = hashrateStr.substr(0, hashrateStr.size() - 1); int multiplier = getHashrateMultiplier(unit); + double hashrate = std::stod(value) * std::pow(10, multiplier); + + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%.0f", hashrate); return PoolStats{ - .hashrate = value + std::string(multiplier, '0'), + .hashrate = buffer, .dailyEarnings = std::nullopt }; } @@ -28,15 +32,4 @@ LogoData NoderunnersPool::getLogo() const { .width = 122, .height = 122 }; -} - -int NoderunnersPool::getHashrateMultiplier(char unit) { - if (unit == '0') - return 0; - - static const std::unordered_map multipliers = { - {'Z', 21}, {'E', 18}, {'P', 15}, {'T', 12}, - {'G', 9}, {'M', 6}, {'K', 3} - }; - return multipliers.at(unit); -} +} \ No newline at end of file diff --git a/src/lib/mining_pool/noderunners/noderunners_pool.hpp b/src/lib/mining_pool/noderunners/noderunners_pool.hpp index c6cb25c..5ecce53 100644 --- a/src/lib/mining_pool/noderunners/noderunners_pool.hpp +++ b/src/lib/mining_pool/noderunners/noderunners_pool.hpp @@ -3,6 +3,7 @@ #include "lib/mining_pool/mining_pool_interface.hpp" #include +#include class NoderunnersPool : public MiningPoolInterface { public: @@ -16,7 +17,4 @@ public: std::string getDailyEarningsLabel() const override { return ""; } bool hasLogo() const override { return true; } std::string getDisplayLabel() const override { return "NODE/RUNNERS"; } // Fallback if needed - -protected: - static int getHashrateMultiplier(char unit); }; \ No newline at end of file diff --git a/src/lib/mining_pool_stats_fetch.cpp b/src/lib/mining_pool_stats_fetch.cpp index b263edb..2f9c10b 100644 --- a/src/lib/mining_pool_stats_fetch.cpp +++ b/src/lib/mining_pool_stats_fetch.cpp @@ -47,6 +47,7 @@ void taskMiningPoolStatsFetch(void *pvParameters) deserializeJson(doc, payload); PoolStats stats = poolInterface->parseResponse(doc); + miningPoolStatsHashrate = stats.hashrate; if (stats.dailyEarnings) diff --git a/test/test_mining_pool/test_main.cpp b/test/test_mining_pool/test_main.cpp new file mode 100644 index 0000000..f028aba --- /dev/null +++ b/test/test_mining_pool/test_main.cpp @@ -0,0 +1,75 @@ +#include +#include + +void test_parseMiningPoolStatsHashRate1dot34TH(void) +{ + std::string hashrate; + std::string label; + std::string output; + + parseHashrateString("1340000000000", label, output, 4); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("TH/S", label.c_str(), label.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("1.34", output.c_str(), output.c_str()); +} + +void test_parseMiningPoolStatsHashRate645GH(void) +{ + std::string hashrate = "645000000000"; + std::string label; + std::string output; + + parseHashrateString(hashrate, label, output, 4); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("GH/S", label.c_str(), label.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("645", output.c_str(), output.c_str()); +} + +void test_parseMiningPoolStatsHashRateEmpty(void) +{ + std::string hashrate = ""; + std::string label; + std::string output; + + parseHashrateString(hashrate, label, output, 4); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("H/S", label.c_str(), label.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("0", output.c_str(), output.c_str()); +} + +void test_parseMiningPoolStatsHashRateZero(void) +{ + std::string hashrate = "0"; + std::string label; + std::string output; + + parseHashrateString(hashrate, label, output, 4); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("H/S", label.c_str(), label.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("0", output.c_str(), output.c_str()); +} + + + + +// not needed when using generate_test_runner.rb +int runUnityTests(void) +{ + UNITY_BEGIN(); + RUN_TEST(test_parseMiningPoolStatsHashRate1dot34TH); + RUN_TEST(test_parseMiningPoolStatsHashRate645GH); + RUN_TEST(test_parseMiningPoolStatsHashRateZero); + RUN_TEST(test_parseMiningPoolStatsHashRateEmpty); + + return UNITY_END(); +} + +int main(void) +{ + return runUnityTests(); +} + +extern "C" void app_main() +{ + runUnityTests(); +} From fb70d435a9e97e66aefc5d8320fe4d05d57c3f6f Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Fri, 20 Dec 2024 23:02:54 +0100 Subject: [PATCH 072/130] Get mining pool logos by download --- platformio.ini | 227 +++++---- scripts/extra_script.py | 69 ++- src/icons/icons.cpp | 465 +----------------- src/lib/block_notify.cpp | 56 +-- src/lib/config.cpp | 8 +- src/lib/config.hpp | 1 - src/lib/defaults.hpp | 2 + src/lib/epd.cpp | 18 +- src/lib/epd.hpp | 2 +- src/lib/mining_pool/braiins/brains_pool.cpp | 14 +- src/lib/mining_pool/braiins/brains_pool.hpp | 16 +- .../mining_pool/gobrrr_pool/gobrrr_pool.cpp | 10 +- .../mining_pool/gobrrr_pool/gobrrr_pool.hpp | 17 +- src/lib/mining_pool/logo_data.hpp | 3 +- src/lib/mining_pool/mining_pool_interface.cpp | 18 + src/lib/mining_pool/mining_pool_interface.hpp | 14 +- .../noderunners/noderunners_pool.cpp | 8 - .../noderunners/noderunners_pool.hpp | 17 +- src/lib/mining_pool/ocean/ocean_pool.cpp | 8 - src/lib/mining_pool/ocean/ocean_pool.hpp | 17 +- src/lib/mining_pool/pool_factory.cpp | 109 ++++ src/lib/mining_pool/pool_factory.hpp | 12 + src/lib/mining_pool_stats_fetch.cpp | 51 +- src/lib/shared.cpp | 30 +- src/lib/shared.hpp | 16 +- src/lib/webserver.cpp | 7 +- 26 files changed, 547 insertions(+), 668 deletions(-) create mode 100644 src/lib/mining_pool/mining_pool_interface.cpp diff --git a/platformio.ini b/platformio.ini index 81d4a49..be29cbe 100644 --- a/platformio.ini +++ b/platformio.ini @@ -7,119 +7,137 @@ ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html + [platformio] data_dir = data/build_gz default_envs = lolin_s3_mini_213epd, lolin_s3_mini_29epd, btclock_rev_b_213epd, btclock_v8_213epd [env] - [btclock_base] platform = espressif32 @ ^6.9.0 -framework = arduino, espidf +framework = arduino, espidf monitor_speed = 115200 monitor_filters = esp32_exception_decoder, colorize board_build.filesystem = littlefs extra_scripts = pre:scripts/pre_script.py, post:scripts/extra_script.py +platform_packages = + earlephilhower/tool-mklittlefs-rp2040-earlephilhower board_build.embed_files = - x509_crt_bundle -build_flags = - !python scripts/git_rev.py - -DLAST_BUILD_TIME=$UNIX_TIME - -DARDUINO_USB_CDC_ON_BOOT - -DCORE_DEBUG_LEVEL=0 - -fexceptions + x509_crt_bundle +build_flags = + !python scripts/git_rev.py + -DLAST_BUILD_TIME=$UNIX_TIME + -DARDUINO_USB_CDC_ON_BOOT + -DCORE_DEBUG_LEVEL=0 + -fexceptions build_unflags = - -Werror=all - -fno-exceptions + -Werror=all + -fno-exceptions lib_deps = - https://github.com/joltwallet/esp_littlefs.git - bblanchon/ArduinoJson@^7.2.1 - mathieucarbou/ESPAsyncWebServer @ 3.3.23 - robtillaart/MCP23017@^0.8.0 - adafruit/Adafruit NeoPixel@^1.12.3 - https://github.com/dsbaars/universal_pin#feature/mcp23017_rt - https://github.com/dsbaars/GxEPD2#universal_pin - https://github.com/tzapu/WiFiManager.git#v2.0.17 - rblb/Nostrduino@1.2.8 + https://github.com/joltwallet/esp_littlefs.git + bblanchon/ArduinoJson@^7.2.1 + mathieucarbou/ESPAsyncWebServer @ 3.3.23 + robtillaart/MCP23017@^0.8.0 + adafruit/Adafruit NeoPixel@^1.12.3 + https://github.com/dsbaars/universal_pin#feature/mcp23017_rt + https://github.com/dsbaars/GxEPD2#universal_pin + https://github.com/tzapu/WiFiManager.git#v2.0.17 + rblb/Nostrduino@1.2.8 [env:lolin_s3_mini] extends = btclock_base board = lolin_s3_mini board_build.partitions = partition.csv -build_flags = - ${btclock_base.build_flags} - -D MCP_INT_PIN=8 - -D NEOPIXEL_PIN=34 - -D NEOPIXEL_COUNT=4 - -D NUM_SCREENS=7 - -D I2C_SDA_PIN=35 - -D I2C_SCK_PIN=36 - -DARDUINO_USB_CDC_ON_BOOT=1 - -D IS_HW_REV_A +build_flags = + ${btclock_base.build_flags} + -D MCP_INT_PIN=8 + -D NEOPIXEL_PIN=34 + -D NEOPIXEL_COUNT=4 + -D NUM_SCREENS=7 + -D I2C_SDA_PIN=35 + -D I2C_SCK_PIN=36 + -DARDUINO_USB_CDC_ON_BOOT=1 + -D IS_HW_REV_A build_unflags = - ${btclock_base.build_unflags} - + ${btclock_base.build_unflags} +platform_packages = + platformio/tool-mklittlefs@^1.203.210628 + earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 [env:btclock_rev_b] extends = btclock_base board = btclock_rev_b board_build.partitions = partition_8mb.csv -build_flags = - ${btclock_base.build_flags} - -D MCP_INT_PIN=8 - -D NEOPIXEL_PIN=15 - -D NEOPIXEL_COUNT=4 - -D NUM_SCREENS=7 - -D I2C_SDA_PIN=35 - -D I2C_SCK_PIN=36 - -D HAS_FRONTLIGHT - -D PCA_OE_PIN=45 - -D PCA_I2C_ADDR=0x42 - -D IS_HW_REV_B +build_flags = + ${btclock_base.build_flags} + -D MCP_INT_PIN=8 + -D NEOPIXEL_PIN=15 + -D NEOPIXEL_COUNT=4 + -D NUM_SCREENS=7 + -D I2C_SDA_PIN=35 + -D I2C_SCK_PIN=36 + -D HAS_FRONTLIGHT + -D PCA_OE_PIN=45 + -D PCA_I2C_ADDR=0x42 + -D IS_HW_REV_B lib_deps = - ${btclock_base.lib_deps} - robtillaart/PCA9685@^0.7.1 - claws/BH1750@^1.3.0 + ${btclock_base.lib_deps} + robtillaart/PCA9685@^0.7.1 + claws/BH1750@^1.3.0 build_unflags = - ${btclock_base.build_unflags} + ${btclock_base.build_unflags} +platform_packages = + platformio/tool-mklittlefs@^1.203.210628 + earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 [env:lolin_s3_mini_213epd] extends = env:lolin_s3_mini test_framework = unity -build_flags = - ${env:lolin_s3_mini.build_flags} - -D USE_QR - -D VERSION_EPD_2_13 - -D HW_REV=\"REV_A_EPD_2_13\" - +build_flags = + ${env:lolin_s3_mini.build_flags} + -D USE_QR + -D VERSION_EPD_2_13 + -D HW_REV=\"REV_A_EPD_2_13\" +platform_packages = + platformio/tool-mklittlefs@^1.203.210628 + earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 [env:btclock_rev_b_213epd] extends = env:btclock_rev_b test_framework = unity -build_flags = - ${env:btclock_rev_b.build_flags} - -D USE_QR - -D VERSION_EPD_2_13 - -D HW_REV=\"REV_B_EPD_2_13\" +build_flags = + ${env:btclock_rev_b.build_flags} + -D USE_QR + -D VERSION_EPD_2_13 + -D HW_REV=\"REV_B_EPD_2_13\" +platform_packages = + platformio/tool-mklittlefs@^1.203.210628 + earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 [env:lolin_s3_mini_29epd] extends = env:lolin_s3_mini test_framework = unity -build_flags = - ${env:lolin_s3_mini.build_flags} - -D USE_QR - -D VERSION_EPD_2_9 - -D HW_REV=\"REV_A_EPD_2_9\" +build_flags = + ${env:lolin_s3_mini.build_flags} + -D USE_QR + -D VERSION_EPD_2_9 + -D HW_REV=\"REV_A_EPD_2_9\" +platform_packages = + platformio/tool-mklittlefs@^1.203.210628 + earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 [env:btclock_rev_b_29epd] extends = env:btclock_rev_b test_framework = unity -build_flags = - ${env:btclock_rev_b.build_flags} - -D USE_QR - -D VERSION_EPD_2_9 - -D HW_REV=\"REV_B_EPD_2_9\" +build_flags = + ${env:btclock_rev_b.build_flags} + -D USE_QR + -D VERSION_EPD_2_9 + -D HW_REV=\"REV_B_EPD_2_9\" +platform_packages = + platformio/tool-mklittlefs@^1.203.210628 + earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 [env:btclock_v8] extends = btclock_base @@ -127,43 +145,52 @@ board = btclock_v8 board_build.partitions = partition_16mb.csv board_build.flash_mode = qio test_framework = unity -build_flags = - ${btclock_base.build_flags} - -D MCP_INT_PIN=4 - -D NEOPIXEL_PIN=5 - -D NEOPIXEL_COUNT=4 - -D NUM_SCREENS=8 - -D SPI_SDA_PIN=11 - -D SPI_SCK_PIN=12 - -D I2C_SDA_PIN=1 - -D I2C_SCK_PIN=2 - -D MCP_RESET_PIN=21 - -D MCP1_A0_PIN=6 - -D MCP1_A1_PIN=7 - -D MCP1_A2_PIN=8 - -D MCP2_A0_PIN=9 - -D MCP2_A1_PIN=10 - -D MCP2_A2_PIN=14 +build_flags = + ${btclock_base.build_flags} + -D MCP_INT_PIN=4 + -D NEOPIXEL_PIN=5 + -D NEOPIXEL_COUNT=4 + -D NUM_SCREENS=8 + -D SPI_SDA_PIN=11 + -D SPI_SCK_PIN=12 + -D I2C_SDA_PIN=1 + -D I2C_SCK_PIN=2 + -D MCP_RESET_PIN=21 + -D MCP1_A0_PIN=6 + -D MCP1_A1_PIN=7 + -D MCP1_A2_PIN=8 + -D MCP2_A0_PIN=9 + -D MCP2_A1_PIN=10 + -D MCP2_A2_PIN=14 build_unflags = - ${btclock_base.build_unflags} + ${btclock_base.build_unflags} +platform_packages = + platformio/tool-mklittlefs@^1.203.210628 + earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 [env:btclock_v8_213epd] extends = env:btclock_v8 test_framework = unity -build_flags = - ${env:btclock_v8.build_flags} - -D USE_QR - -D VERSION_EPD_2_13 - -D HW_REV=\"REV_V8_EPD_2_13\" +build_flags = + ${env:btclock_v8.build_flags} + -D USE_QR + -D VERSION_EPD_2_13 + -D HW_REV=\"REV_V8_EPD_2_13\" +platform_packages = + platformio/tool-mklittlefs@^1.203.210628 + earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 [env:native_test_only] platform = native test_framework = unity -build_flags = - ${btclock_base.build_flags} - -D MCP_INT_PIN=8 - -D NEOPIXEL_PIN=34 - -D NEOPIXEL_COUNT=4 - -D NUM_SCREENS=7 - -D UNITY_TEST - -std=gnu++17 +build_flags = + ${btclock_base.build_flags} + -D MCP_INT_PIN=8 + -D NEOPIXEL_PIN=34 + -D NEOPIXEL_COUNT=4 + -D NUM_SCREENS=7 + -D UNITY_TEST + -std=gnu++17 +platform_packages = + platformio/tool-mklittlefs@^1.203.210628 + earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 diff --git a/scripts/extra_script.py b/scripts/extra_script.py index 8451978..ebc94e9 100644 --- a/scripts/extra_script.py +++ b/scripts/extra_script.py @@ -1,7 +1,7 @@ Import("env") import os import gzip -from shutil import copyfileobj, rmtree +from shutil import copyfileobj, rmtree, copyfile, copytree from pathlib import Path import subprocess @@ -29,7 +29,7 @@ def process_directory(input_dir, output_dir): Path(output_root).mkdir(parents=True, exist_ok=True) for file in files: - # if file.endswith(('.html', '.css', '.js')): +# if not file.endswith(('.bin')): input_file_path = os.path.join(root, file) output_file_path = os.path.join(output_root, file + '.gz') gzip_file(input_file_path, output_file_path) @@ -41,11 +41,72 @@ def process_directory(input_dir, output_dir): # Build web interface before building FS def before_buildfs(source, target, env): + env.Execute("cd data && yarn && yarn postinstall && yarn build") input_directory = 'data/dist' output_directory = 'data/build_gz' +# copytree("assets", "data/dist/assets") + process_directory(input_directory, output_directory) +def get_fs_partition_size(env): + import csv + + # Get partition table path - first try custom, then default + board_config = env.BoardConfig() + partition_table = board_config.get("build.partitions", "default.csv") + + # Handle default partition table path + if partition_table == "default.csv" or partition_table == "huge_app.csv": + partition_table = os.path.join(env.PioPlatform().get_package_dir("framework-arduinoespressif32"), + "tools", "partitions", partition_table) + + # Parse CSV to find spiffs/littlefs partition + with open(partition_table, 'r') as f: + for row in csv.reader(f): + if len(row) < 5: + continue + # Remove comments and whitespace + row = [cell.strip().split('#')[0] for cell in row] + # Check if this is a spiffs or littlefs partition + if row[0].startswith(('spiffs', 'littlefs')): + # Size is in hex format + return int(row[4], 16) + return 0 + +def get_littlefs_used_size(binary_path): + mklittlefs_path = os.path.join(env.PioPlatform().get_package_dir("tool-mklittlefs-rp2040-earlephilhower"), "mklittlefs") + + try: + result = subprocess.run([mklittlefs_path, '-l', binary_path], capture_output=True, text=True) + + if result.returncode == 0: + # Parse the output to sum up file sizes + total_size = 0 + for line in result.stdout.splitlines(): + if line.strip() and not line.startswith('') and not line.startswith('Creation'): + # Each line format: size filename + size = line.split()[0] + total_size += int(size) + return total_size + except Exception as e: + print(f"Error getting filesystem size: {e}") + return 0 + + +def after_littlefs(source, target, env): + binary_path = str(target[0]) + partition_size = get_fs_partition_size(env) + used_size = get_littlefs_used_size(binary_path) + + percentage = (used_size / partition_size) * 100 + bar_width = 50 + filled = int(bar_width * percentage / 100) + bar = '=' * filled + '-' * (bar_width - filled) + + print(f"\nLittleFS Actual Usage: [{bar}] {percentage:.1f}% ({used_size}/{partition_size} bytes)") + + flash_size = env.BoardConfig().get("upload.flash_size", "4MB") fs_image_name = f"littlefs_{flash_size}" env.Replace(ESP32_FS_IMAGE_NAME=fs_image_name) @@ -58,3 +119,7 @@ fs_name = env.get("ESP32_FS_IMAGE_NAME", "littlefs.bin") # Use the variable in the pre-action env.AddPreAction(f"$BUILD_DIR/{fs_name}.bin", before_buildfs) +env.AddPostAction(f"$BUILD_DIR/{fs_name}.bin", after_littlefs) +# LittleFS Actual Usage: [==============================--------------------] 60.4% (254165/420864 bytes) +# LittleFS Actual Usage: [==============================--------------------] 60.2% (253476/420864 bytes) +# 372736 used \ No newline at end of file diff --git a/src/icons/icons.cpp b/src/icons/icons.cpp index 55854f8..d9ae65c 100644 --- a/src/icons/icons.cpp +++ b/src/icons/icons.cpp @@ -532,472 +532,11 @@ const unsigned char epd_icons_bitaxe_logo [] PROGMEM = { 0xff, 0xff, 0xff, 0xff }; - -// // 'ocean_logo', 122x250px -const unsigned char epd_icons_ocean_logo [] PROGMEM = { -// 'ocean_logo', 122x122px -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x20, 0x00, 0x0f, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xfe, 0x03, 0xfc, 0x00, 0x3f, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xfc, 0x00, 0x7f, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xfe, 0x00, 0x7f, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xc0, -0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xc0, -0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xc0, -0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xc0, -0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xc0, -0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xc0, -0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xc0, -0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xc0, -0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xc0, -0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xc0, -0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xc0, -0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x1f, 0xc0, -0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x1f, 0xc0, -0xfc, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xc0, -0xfc, 0x00, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xc0, -0xfc, 0x00, 0x01, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xc0, -0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, -0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x07, 0xc0, -0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xc0, -0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x07, 0xc0, -0xf8, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, -0xf8, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x03, 0x00, 0x07, 0xc0, -0xf8, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xe0, 0x07, 0xc0, -0xf8, 0x00, 0x00, 0x03, 0xff, 0xff, 0xe1, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xf0, 0x07, 0xc0, -0xf8, 0x03, 0xe0, 0x01, 0xff, 0xff, 0xe3, 0xff, 0xfc, 0x00, 0x03, 0xff, 0xff, 0xf0, 0x07, 0xc0, -0xf8, 0x07, 0xf8, 0x00, 0xff, 0xff, 0xe3, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x07, 0xc0, -0xf8, 0x07, 0xfc, 0x00, 0x7f, 0xff, 0xe3, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xc0, -0xf8, 0x07, 0xfe, 0x00, 0x3f, 0xff, 0xe7, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xc0, -0xf8, 0x07, 0xff, 0x80, 0x1f, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xc0, -0xfc, 0x0f, 0xff, 0xc0, 0x0f, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0f, 0xc0, -0xfc, 0x0f, 0xff, 0xe0, 0x0f, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0f, 0xc0, -0xfc, 0x0f, 0xff, 0xf8, 0x07, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0f, 0xc0, -0xfe, 0x0f, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xc0, -0xfe, 0x1f, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xc0, -0xff, 0x1f, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xc0, -0xff, 0x1f, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xc0, -0xff, 0x9f, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xc0, -0xff, 0xdf, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xdf, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xfe, 0xff, 0xc0, -0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xfe, 0x7f, 0xc0, -0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xfe, 0x7f, 0xc0, -0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xfe, 0x3f, 0xc0, -0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xfc, 0x1f, 0xc0, -0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xfc, 0x1f, 0xc0, -0xfc, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xfc, 0x1f, 0xc0, -0xfc, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfc, 0x01, 0xff, 0xfc, 0x0f, 0xc0, -0xfc, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfc, 0x00, 0xff, 0xfc, 0x0f, 0xc0, -0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xfe, 0x00, 0x7f, 0xf8, 0x07, 0xc0, -0xf8, 0x07, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xf9, 0xff, 0xff, 0x00, 0x1f, 0xf8, 0x07, 0xc0, -0xf8, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xf1, 0xff, 0xff, 0x80, 0x0f, 0xf8, 0x07, 0xc0, -0xf8, 0x07, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xf1, 0xff, 0xff, 0xc0, 0x07, 0xf0, 0x07, 0xc0, -0xf8, 0x03, 0xff, 0xff, 0xf0, 0x00, 0x0f, 0xff, 0xf1, 0xff, 0xff, 0xe0, 0x01, 0xf0, 0x07, 0xc0, -0xf8, 0x03, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xff, 0xe3, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x07, 0xc0, -0xf8, 0x01, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x07, 0xc0, -0xf8, 0x00, 0x30, 0x00, 0x00, 0x07, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x07, 0xc0, -0xf8, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x07, 0xc0, -0xf8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xc0, -0xf8, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x00, 0x00, 0x07, 0xc0, -0xf8, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x80, 0x00, 0x07, 0xc0, -0xf8, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x07, 0xc0, -0xfc, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x0f, 0xc0, -0xfc, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xc0, -0xfc, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x0f, 0xc0, -0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xc0, -0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xc0, -0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xc0, -0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xc0, -0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x7f, 0xc0, -0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xc0, -0xff, 0xe0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xc0, -0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xc0, -0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xc0, -0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xc0, -0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xc0, -0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xc0, -0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0x80, 0x1f, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0x80, 0x0f, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xfe, 0x03, 0xff, 0x00, 0x0f, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3c, 0x00, 0x03, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 -}; - - -// // 'braiins_pool', 122x250px -const unsigned char epd_icons_braiins_logo [] PROGMEM = { -// 'braiins-vector-logo', 37x230px - 0xff, 0xff, 0xf8, 0x0f, 0xf8, 0xff, 0xff, 0xe0, 0x01, 0xf8, 0x01, 0xff, 0xc0, 0x00, 0xf8, 0x01, - 0xff, 0x80, 0x00, 0x78, 0x01, 0xff, 0x00, 0x00, 0x38, 0x01, 0xff, 0x00, 0x00, 0x18, 0x01, 0xfe, - 0x00, 0x00, 0x18, 0x01, 0xfe, 0x00, 0x00, 0x18, 0x01, 0xfe, 0x01, 0xf0, 0x08, 0x01, 0xfc, 0x03, - 0xf8, 0x08, 0x01, 0xfc, 0x03, 0xf8, 0x08, 0x01, 0xfc, 0x07, 0xf8, 0x08, 0x01, 0xfc, 0x07, 0xfc, - 0x08, 0x01, 0xfc, 0x07, 0xfc, 0x08, 0x01, 0xfc, 0x07, 0xfc, 0x08, 0x01, 0xf8, 0x07, 0xf8, 0x08, - 0x00, 0xf8, 0x07, 0xf8, 0x08, 0x80, 0xf0, 0x07, 0xf8, 0x08, 0x80, 0x00, 0x0f, 0xf0, 0x08, 0x80, - 0x00, 0x0f, 0xf0, 0x08, 0xc0, 0x00, 0x0f, 0xe0, 0x18, 0xc0, 0x00, 0x1f, 0xc0, 0x18, 0xe0, 0x00, - 0x3f, 0xc0, 0x38, 0xf0, 0x00, 0x3f, 0xe0, 0x38, 0xf8, 0x00, 0xff, 0xf0, 0x78, 0xfe, 0x03, 0xff, - 0xf8, 0xf8, 0xff, 0xff, 0xff, 0xfd, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, - 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0x00, - 0x08, 0xff, 0xff, 0xfc, 0x00, 0x08, 0xff, 0xff, 0xf0, 0x00, 0x38, 0xff, 0xff, 0xc0, 0x00, 0xf8, - 0xff, 0xff, 0x00, 0x03, 0xf8, 0xff, 0xfc, 0x00, 0x07, 0xf8, 0xff, 0xf0, 0x00, 0x1f, 0xf8, 0xff, - 0xc0, 0x00, 0x7f, 0xf8, 0xff, 0x80, 0x01, 0xff, 0xf8, 0xfe, 0x00, 0x03, 0xff, 0xf8, 0xf8, 0x00, - 0x0f, 0xff, 0xf8, 0xf0, 0x00, 0x3f, 0xff, 0xf8, 0xc0, 0x00, 0xff, 0xff, 0xf8, 0x00, 0x03, 0xff, - 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, - 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, - 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf8, - 0x08, 0xff, 0xff, 0xff, 0x80, 0x08, 0xff, 0xff, 0xfc, 0x00, 0x08, 0xff, 0xff, 0xc0, 0x00, 0x08, - 0xff, 0xfe, 0x00, 0x00, 0x08, 0xff, 0xf0, 0x00, 0x00, 0x08, 0xff, 0x00, 0x00, 0x00, 0x08, 0xf8, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, - 0x03, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, - 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, - 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf0, 0x08, 0xff, - 0xff, 0xff, 0x80, 0x08, 0xff, 0xff, 0xf8, 0x00, 0x08, 0xff, 0xff, 0xc0, 0x00, 0x08, 0xff, 0xfe, - 0x00, 0x00, 0x08, 0xff, 0xf0, 0x00, 0x00, 0x08, 0xff, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x00, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x03, 0xff, - 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, - 0x00, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, - 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf0, 0x08, 0xff, 0xff, 0xff, - 0x00, 0x08, 0xff, 0xff, 0xf8, 0x00, 0x08, 0xff, 0xff, 0xc0, 0x00, 0x08, 0xff, 0xfe, 0x00, 0x00, - 0x08, 0xff, 0xe0, 0x00, 0x00, 0x08, 0xff, 0x00, 0x00, 0x00, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x08, - 0x80, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x07, 0xff, 0xf8, 0x00, - 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x00, 0xff, - 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x00, 0x07, 0xff, - 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, - 0xf8, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0xe0, 0x00, 0x00, 0x03, 0xf8, 0xfc, 0x00, 0x00, 0x00, 0x08, - 0xff, 0xc0, 0x00, 0x00, 0x08, 0xff, 0xf8, 0x00, 0x00, 0x08, 0xff, 0xff, 0x00, 0x00, 0x08, 0xff, - 0xff, 0xf0, 0x00, 0x08, 0xff, 0xff, 0xfe, 0x00, 0x08, 0xff, 0xff, 0xff, 0xc0, 0x08, 0xff, 0xff, - 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, - 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, - 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xe8, - 0xfe, 0x00, 0xff, 0xff, 0x88, 0xf0, 0x00, 0x3f, 0xfe, 0x08, 0xe0, 0x00, 0x1f, 0xf8, 0x08, 0xc0, - 0x00, 0x0f, 0xe0, 0x08, 0xc0, 0x00, 0x07, 0x80, 0x08, 0x80, 0x00, 0x06, 0x00, 0x08, 0x80, 0x00, - 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xfe, 0x00, 0x00, 0x38, 0x01, 0xff, 0x00, - 0x00, 0xf8, 0x01, 0xff, 0x00, 0x03, 0xf8, 0x01, 0xff, 0x00, 0x0f, 0xf8, 0x01, 0xff, 0x00, 0x3f, - 0xf8, 0x01, 0xff, 0x00, 0xff, 0xf8, 0x01, 0xff, 0x01, 0xff, 0xf8, 0x01, 0xff, 0x01, 0xff, 0xf8, - 0x01, 0xff, 0x01, 0xff, 0xf8, 0x01, 0xff, 0x01, 0xff, 0xf8, 0x01, 0xff, 0x01, 0xff, 0xf8, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, - 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xbf, 0xf8, 0xff, 0xff, - 0xf8, 0x03, 0xf8, 0xf8, 0x07, 0xf0, 0x00, 0xf8, 0xf0, 0x01, 0xe0, 0x00, 0x78, 0xc0, 0x00, 0xc0, - 0x00, 0x38, 0xc0, 0x00, 0x80, 0x00, 0x18, 0x80, 0x00, 0x00, 0x00, 0x18, 0x80, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0xf0, 0x08, 0x00, 0xfc, 0x07, 0xf8, 0x08, - 0x01, 0xfc, 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, 0xf8, 0x08, 0x01, - 0xfe, 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, 0xf8, 0x08, 0x01, 0xfe, - 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, 0xf8, 0x08, 0x01, 0xfe, 0x07, - 0xf8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x03, - 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xf8 -}; - -const unsigned char epd_icons_noderunners_logo [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x01, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x01, 0xff, 0x00, 0x01, 0xfb, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x01, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0x80, 0x01, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x01, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x01, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x01, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xdf, 0xf0, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xdf, 0xf0, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xcf, 0xf8, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xcf, 0xfc, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xc7, 0xfe, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe7, 0xfe, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe3, 0xff, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe1, 0xff, 0x81, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe1, 0xff, 0x81, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0xff, 0xc1, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0x7f, 0xe1, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0x3f, 0xe1, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0x3f, 0xf1, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0x1f, 0xf9, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0x0f, 0xf9, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xe0, 0x0f, 0xfd, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xe0, 0x07, 0xfd, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xe0, 0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xe0, 0x03, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xe0, 0x01, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0xff, 0xff, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe1, 0xc0, 0x00, 0x3f, 0xe0, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe7, 0xf0, 0x00, 0x3f, 0xe0, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x07, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x07, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 -}; - -// 'gobrrr', 122x122px -const unsigned char epd_icons_gobrrr_logo [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x10, 0x48, 0x84, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x24, 0x84, 0x20, 0x21, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x82, 0x25, 0x19, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x28, 0x18, 0x20, 0x41, 0x4c, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xe0, 0x83, 0x21, 0x88, 0x84, 0x21, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x8c, 0x48, 0x24, 0x09, 0x24, 0x82, 0x60, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x21, 0x08, 0x80, 0x61, 0x08, 0x18, 0x0a, 0x3f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfc, 0x02, 0x22, 0x19, 0x04, 0x42, 0x41, 0x88, 0x0f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf0, 0x98, 0x82, 0x42, 0x1b, 0x11, 0x04, 0x21, 0x23, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xe2, 0x20, 0x50, 0x42, 0xff, 0xe4, 0x64, 0x24, 0x83, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xc8, 0x46, 0x14, 0x93, 0xff, 0xf8, 0x01, 0x84, 0x28, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x03, 0x10, 0x81, 0x0f, 0xff, 0xfe, 0x98, 0x11, 0x08, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x24, 0x01, 0x24, 0x5f, 0xff, 0xff, 0x02, 0x42, 0x42, 0x3f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfc, 0x88, 0xa9, 0x04, 0x3f, 0xff, 0xff, 0x90, 0x48, 0x21, 0x0f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x42, 0x22, 0x51, 0xbf, 0xf3, 0xff, 0xc5, 0x09, 0x0c, 0x47, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf3, 0x10, 0x40, 0x00, 0x7f, 0xc0, 0x7f, 0xc4, 0x21, 0x10, 0x93, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe0, 0x25, 0x14, 0xaa, 0xff, 0x0c, 0x1f, 0xc8, 0x84, 0x42, 0x09, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe4, 0x80, 0x04, 0x82, 0xfe, 0x21, 0x0f, 0x82, 0x50, 0x88, 0x63, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x84, 0x4a, 0xc8, 0x11, 0xfc, 0x81, 0x27, 0x21, 0x06, 0x23, 0x00, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x91, 0x10, 0x02, 0x45, 0xfc, 0x18, 0x42, 0x18, 0x3f, 0xf0, 0x18, 0x7f, 0xff, 0xc0, - 0xff, 0xff, 0x10, 0x91, 0x31, 0x13, 0xf9, 0x42, 0x10, 0x82, 0x7f, 0xfc, 0x82, 0x3f, 0xff, 0xc0, - 0xff, 0xfe, 0x46, 0x04, 0x04, 0x43, 0xf8, 0x04, 0x8c, 0x21, 0xff, 0xfe, 0x62, 0x1f, 0xff, 0xc0, - 0xff, 0xfc, 0x00, 0x62, 0x42, 0x13, 0xf8, 0xb0, 0x41, 0x0c, 0xff, 0xff, 0x08, 0xcf, 0xff, 0xc0, - 0xff, 0xfc, 0xa9, 0x08, 0x98, 0x8b, 0xf2, 0x03, 0x10, 0xc3, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xc0, - 0xff, 0xf8, 0x81, 0x04, 0x80, 0x8b, 0xf2, 0x48, 0x26, 0x13, 0xf8, 0x3f, 0xd5, 0x27, 0xff, 0xc0, - 0xff, 0xf2, 0x14, 0x61, 0x24, 0x23, 0xf0, 0x88, 0x80, 0x17, 0xf0, 0x0f, 0xc4, 0x23, 0xff, 0xc0, - 0xff, 0xf0, 0x44, 0x08, 0x05, 0x27, 0xf4, 0x22, 0x17, 0xe7, 0xe5, 0x27, 0xe0, 0x8b, 0xff, 0xc0, - 0xff, 0xe4, 0x41, 0x86, 0x50, 0x43, 0xf1, 0x04, 0x47, 0xf7, 0xc1, 0x0f, 0xe9, 0x01, 0xff, 0xc0, - 0xff, 0xc3, 0x18, 0x30, 0x42, 0x13, 0xf9, 0x31, 0x27, 0xf7, 0xd0, 0x43, 0xe1, 0x31, 0xff, 0xc0, - 0xff, 0xd0, 0x02, 0x01, 0x08, 0x8b, 0xf8, 0x00, 0x8f, 0xef, 0xc6, 0x33, 0xe4, 0x04, 0xff, 0xc0, - 0xff, 0xc4, 0xa0, 0xc9, 0x22, 0x23, 0xfa, 0x4c, 0x17, 0xef, 0xc0, 0x87, 0xf0, 0xc4, 0xff, 0xc0, - 0xff, 0x88, 0x8c, 0x08, 0x21, 0x05, 0xfc, 0x41, 0x47, 0xf7, 0xc8, 0x03, 0xe2, 0x10, 0x7f, 0xc0, - 0xff, 0x82, 0x11, 0x22, 0x0c, 0x51, 0xfc, 0x10, 0x27, 0xe7, 0xc9, 0x5b, 0xe8, 0x12, 0x7f, 0xc0, - 0xff, 0x24, 0x41, 0x22, 0xc0, 0x83, 0xfe, 0x86, 0x0f, 0xf7, 0xc2, 0x07, 0xe3, 0x42, 0x3f, 0xc0, - 0xff, 0x09, 0x08, 0x78, 0x3a, 0x28, 0xff, 0x20, 0xc3, 0xf7, 0xe2, 0x27, 0xe0, 0x08, 0xbf, 0xc0, - 0xfe, 0x40, 0x92, 0x79, 0x38, 0x40, 0xff, 0x88, 0x1f, 0xe7, 0xf0, 0x8f, 0xcc, 0xa1, 0x1f, 0xc0, - 0xfe, 0x14, 0x27, 0xff, 0xfd, 0x14, 0x7f, 0xe3, 0x3f, 0xf3, 0xf4, 0x9f, 0xc0, 0x24, 0x5f, 0xc0, - 0xfe, 0x21, 0x0f, 0xff, 0xff, 0xc1, 0x3f, 0xff, 0xff, 0xf3, 0xfe, 0x7f, 0x93, 0x04, 0x1f, 0xc0, - 0xfc, 0x88, 0xcf, 0xff, 0xff, 0xf2, 0x1f, 0xff, 0xff, 0xf1, 0xff, 0xff, 0x84, 0x49, 0x2f, 0xc0, - 0xfc, 0x46, 0x0f, 0xff, 0xff, 0xf8, 0x8f, 0xff, 0xff, 0xf0, 0xff, 0xfe, 0x20, 0x40, 0x8f, 0xc0, - 0xfc, 0x10, 0x27, 0xff, 0xff, 0xfc, 0xa7, 0xff, 0xfe, 0xf2, 0x7f, 0xfe, 0x29, 0x12, 0x1f, 0xc0, - 0xf9, 0x81, 0x27, 0xf0, 0x2f, 0xfe, 0x01, 0xff, 0xf8, 0x12, 0x3f, 0xf8, 0x82, 0x12, 0x47, 0xc0, - 0xf8, 0x29, 0x0f, 0xe2, 0x01, 0xff, 0x18, 0x7f, 0xc1, 0x00, 0x87, 0x80, 0x12, 0x40, 0x47, 0xc0, - 0xfa, 0x22, 0x4f, 0xe8, 0xc4, 0xff, 0x22, 0x00, 0x04, 0x4c, 0x10, 0x25, 0x40, 0x4c, 0x17, 0xc0, - 0xf8, 0x84, 0x17, 0xe1, 0x10, 0xff, 0x00, 0x80, 0x24, 0x41, 0x40, 0x04, 0x19, 0x01, 0x87, 0xc0, - 0xf1, 0x11, 0x27, 0xe4, 0x12, 0x7f, 0x4c, 0x24, 0x91, 0x11, 0x0c, 0xd0, 0x81, 0x30, 0x27, 0xc0, - 0xf4, 0x40, 0x8f, 0xe4, 0x82, 0x7f, 0x11, 0x12, 0x01, 0x12, 0x21, 0x02, 0x44, 0x06, 0x23, 0xc0, - 0xf0, 0x8c, 0x07, 0xe0, 0xa4, 0xff, 0x13, 0x12, 0x64, 0xc2, 0x42, 0x32, 0x30, 0xc0, 0x8b, 0xc0, - 0xf2, 0x21, 0x67, 0xea, 0x08, 0xff, 0x7f, 0x4f, 0xcf, 0xe5, 0xfb, 0xf8, 0xfe, 0x18, 0x43, 0xc0, - 0xf2, 0x10, 0x0f, 0xe0, 0x42, 0xfe, 0x3f, 0xbf, 0xcf, 0xef, 0xfb, 0xf9, 0xfe, 0x03, 0x13, 0xc0, - 0xf0, 0xc6, 0x27, 0xe5, 0x17, 0xfe, 0xbf, 0xff, 0xef, 0xff, 0xf3, 0xff, 0xfc, 0xa0, 0x27, 0xc0, - 0xf1, 0x00, 0x87, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xcf, 0xff, 0xf3, 0xff, 0xfe, 0x0c, 0x83, 0xc0, - 0xf2, 0x28, 0x97, 0xff, 0xff, 0xf9, 0x3f, 0xff, 0xcf, 0xff, 0xf9, 0xff, 0xfc, 0x40, 0x4b, 0xc0, - 0xf0, 0x82, 0x17, 0xff, 0xff, 0xf2, 0x1f, 0xff, 0xc7, 0xff, 0xf1, 0xff, 0xfd, 0x23, 0x13, 0xc0, - 0xe4, 0x12, 0x47, 0xff, 0xff, 0xf8, 0x9f, 0xf3, 0x97, 0xfc, 0xf3, 0xff, 0x5c, 0x24, 0x13, 0xc0, - 0xf1, 0x48, 0x4f, 0xff, 0xff, 0xfc, 0x7f, 0xc0, 0x07, 0xf0, 0x01, 0xfc, 0x00, 0x84, 0x83, 0xc0, - 0xf1, 0x01, 0x07, 0xff, 0xff, 0xff, 0x1f, 0xc8, 0x67, 0xf3, 0x0d, 0xfc, 0x82, 0x10, 0x63, 0xc0, - 0xe4, 0x31, 0x27, 0xe0, 0x03, 0xff, 0x1f, 0xc6, 0x0f, 0xf0, 0x41, 0xfc, 0x52, 0x43, 0x09, 0xc0, - 0xf0, 0x84, 0x27, 0xe0, 0x08, 0xff, 0x3f, 0x90, 0x87, 0xe4, 0x21, 0xfc, 0x44, 0x48, 0x0b, 0xc0, - 0xf2, 0x08, 0x8f, 0xec, 0xc0, 0x7f, 0x9f, 0x80, 0x97, 0xf1, 0x8d, 0xf9, 0x09, 0x08, 0xa3, 0xc0, - 0xf1, 0x48, 0x87, 0xe1, 0x14, 0x7f, 0x9f, 0xcc, 0x27, 0xe4, 0x11, 0xfc, 0x20, 0x22, 0x07, 0xc0, - 0xf0, 0x42, 0x37, 0xe1, 0x05, 0x3f, 0x9f, 0x91, 0x27, 0xe0, 0x41, 0xfc, 0x84, 0x84, 0x53, 0xc0, - 0xf2, 0x12, 0x07, 0xe8, 0x60, 0x7f, 0x9f, 0x81, 0x07, 0xf3, 0x09, 0xf8, 0x92, 0x51, 0x03, 0xc0, - 0xf2, 0x20, 0xcf, 0xe2, 0x09, 0x7f, 0x9f, 0xc8, 0x4f, 0xf0, 0x25, 0xfc, 0x10, 0x02, 0x2b, 0xc0, - 0xf0, 0x89, 0x07, 0xe4, 0x84, 0x7f, 0x9f, 0x92, 0x27, 0xe4, 0x91, 0xfc, 0x45, 0x88, 0x83, 0xc0, - 0xf9, 0x08, 0x37, 0xe0, 0x30, 0xff, 0x9f, 0x84, 0x87, 0xe4, 0x83, 0xf9, 0x20, 0x24, 0x4f, 0xc0, - 0xf8, 0x62, 0x0f, 0xea, 0x43, 0xff, 0x3f, 0xc0, 0x4f, 0xf0, 0x28, 0x99, 0x08, 0x91, 0x07, 0xc0, - 0xf8, 0x82, 0x4f, 0xf2, 0x4f, 0xff, 0x1f, 0x99, 0x17, 0xf2, 0x4f, 0xef, 0x8a, 0x02, 0x37, 0xc0, - 0xf9, 0x10, 0x87, 0xff, 0xff, 0xfe, 0x5f, 0xc1, 0x07, 0xe2, 0x1f, 0xff, 0xa0, 0xa4, 0x87, 0xc0, - 0xf8, 0x44, 0x9f, 0xff, 0xff, 0xfe, 0x1f, 0xc4, 0x67, 0xf0, 0x8f, 0xff, 0x84, 0x10, 0x47, 0xc0, - 0xfc, 0x12, 0x0f, 0xff, 0xff, 0xfc, 0x9f, 0x90, 0x8f, 0xf4, 0x4f, 0xff, 0x91, 0x42, 0x1f, 0xc0, - 0xfd, 0x20, 0x67, 0xff, 0xff, 0xf8, 0x5f, 0xc6, 0x07, 0xf1, 0x1f, 0xff, 0x91, 0x09, 0x8f, 0xc0, - 0xfc, 0x49, 0x0f, 0xff, 0xff, 0xe1, 0x1f, 0xc0, 0x57, 0xf0, 0x8f, 0xff, 0x84, 0x24, 0x2f, 0xc0, - 0xfc, 0x42, 0x0f, 0xfb, 0x7e, 0x04, 0x3f, 0x19, 0x07, 0xc6, 0x2f, 0xff, 0xa4, 0x90, 0x0f, 0xc0, - 0xfe, 0x10, 0xa0, 0x78, 0x78, 0x90, 0x80, 0x01, 0x20, 0x00, 0x0f, 0xff, 0x88, 0x42, 0xdf, 0xc0, - 0xfe, 0x84, 0x80, 0x38, 0x38, 0x86, 0x00, 0xc4, 0x20, 0x29, 0x40, 0x00, 0x42, 0x08, 0x1f, 0xc0, - 0xfe, 0x24, 0x12, 0x02, 0x02, 0x20, 0x64, 0x10, 0x8c, 0x81, 0x13, 0xfc, 0x11, 0x89, 0x3f, 0xc0, - 0xff, 0x11, 0x24, 0xc2, 0x90, 0x22, 0x09, 0x26, 0x10, 0x94, 0x24, 0xf9, 0x88, 0x21, 0x3f, 0xc0, - 0xff, 0x41, 0x21, 0x10, 0x85, 0x89, 0x88, 0x20, 0x42, 0x10, 0x80, 0xf2, 0x22, 0x24, 0x3f, 0xc0, - 0xff, 0x8c, 0x08, 0x11, 0x24, 0x08, 0x22, 0x89, 0x22, 0x42, 0x4a, 0x64, 0x10, 0x84, 0xff, 0xc0, - 0xff, 0x80, 0xc4, 0x88, 0x10, 0x42, 0x02, 0x08, 0x88, 0x49, 0x10, 0x09, 0x44, 0x90, 0x7f, 0xc0, - 0xff, 0xd2, 0x17, 0xef, 0xdf, 0xff, 0xfd, 0xf6, 0xff, 0xff, 0xff, 0xc0, 0x08, 0x12, 0xff, 0xc0, - 0xff, 0xc2, 0x1b, 0x76, 0xed, 0xb5, 0xb7, 0x77, 0x66, 0xb6, 0x6d, 0xe4, 0xa3, 0x02, 0xff, 0xc0, - 0xff, 0xe8, 0xdb, 0x5b, 0x36, 0x6d, 0xb6, 0xd9, 0xbb, 0xad, 0xb6, 0x64, 0x20, 0x61, 0xff, 0xc0, - 0xff, 0xe0, 0x1d, 0xdb, 0xdb, 0xce, 0x6d, 0xbe, 0xdb, 0x6d, 0xb7, 0xb1, 0x0c, 0x0d, 0xff, 0xc0, - 0xff, 0xf5, 0x06, 0xdc, 0xdb, 0x73, 0xdb, 0x66, 0xdc, 0xdb, 0x6d, 0x81, 0x11, 0x83, 0xff, 0xc0, - 0xff, 0xf1, 0x20, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x48, 0x40, 0x33, 0xff, 0xc0, - 0xff, 0xf8, 0x25, 0x26, 0xac, 0x89, 0x2c, 0xb3, 0x26, 0x26, 0x9a, 0x4c, 0xca, 0x07, 0xff, 0xc0, - 0xff, 0xfc, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xf7, 0xbc, 0x8f, 0xff, 0xc0, - 0xff, 0xfc, 0x9a, 0xd9, 0x53, 0x66, 0xd3, 0x4c, 0xd9, 0x99, 0x6d, 0xb6, 0xe6, 0x3f, 0xff, 0xc0, - 0xff, 0xfe, 0x1b, 0x6f, 0x7d, 0xbb, 0x7d, 0xf7, 0x6e, 0xef, 0x6d, 0xbb, 0x7a, 0x1f, 0xff, 0xc0, - 0xff, 0xff, 0x4d, 0xb3, 0xa6, 0xdb, 0x4d, 0x37, 0x6e, 0xed, 0xb6, 0xcd, 0x98, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0x26, 0xdc, 0xfb, 0x6d, 0xf7, 0xd9, 0xb3, 0x35, 0xb6, 0xf6, 0xec, 0x3f, 0xff, 0xc0, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe4, 0x22, 0x04, 0x92, 0x08, 0x24, 0x48, 0x88, 0x49, 0x09, 0x11, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xe2, 0x48, 0x90, 0x00, 0x82, 0x04, 0x84, 0x92, 0x00, 0x40, 0x45, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf8, 0x84, 0x93, 0x29, 0x31, 0x90, 0x91, 0x11, 0x96, 0x14, 0x87, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xf9, 0x21, 0x00, 0x44, 0x04, 0x22, 0x10, 0x44, 0x10, 0x91, 0x2f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x08, 0x4c, 0x44, 0x90, 0x22, 0x46, 0x00, 0x40, 0x82, 0x1f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xfe, 0x92, 0x21, 0x10, 0x84, 0x88, 0x40, 0xaa, 0x4a, 0x24, 0x9f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x81, 0x01, 0x02, 0x22, 0x09, 0x18, 0x21, 0x08, 0x20, 0x7f, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xcc, 0x54, 0x62, 0x28, 0xc1, 0x03, 0x04, 0x21, 0x8a, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf0, 0x84, 0x08, 0x81, 0x14, 0x60, 0x48, 0x84, 0x0b, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xf8, 0x89, 0x08, 0x44, 0x10, 0x0c, 0x22, 0x50, 0x67, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xfe, 0x20, 0xc3, 0x12, 0x43, 0x01, 0x84, 0x06, 0x1f, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0x06, 0x10, 0x20, 0x88, 0x60, 0x11, 0x20, 0xbf, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xd0, 0x11, 0x24, 0x20, 0x8c, 0x48, 0x91, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xf1, 0x44, 0x43, 0x0c, 0x01, 0x02, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x08, 0x90, 0x41, 0x31, 0x30, 0x6f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x22, 0x04, 0x31, 0x04, 0x05, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0x21, 0x84, 0x42, 0x45, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x28, 0x04, 0x48, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x51, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 -}; - // Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 8032) -const int epd_icons_allArray_LEN = 8; +const int epd_icons_allArray_LEN = 4; const unsigned char* epd_icons_allArray[epd_icons_allArray_LEN] = { epd_icons_pickaxe, epd_icons_rocket_launch, epd_icons_lightning_bolt, - epd_icons_bitaxe_logo, - epd_icons_ocean_logo, - epd_icons_braiins_logo, - epd_icons_noderunners_logo, - epd_icons_gobrrr_logo + epd_icons_bitaxe_logo }; diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index c4db06e..48989bd 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -296,45 +296,27 @@ void restartBlockNotify() } -int getBlockFetch() -{ - try { - WiFiClientSecure client; +int getBlockFetch() { + try { + String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); + const String protocol = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE) ? "https" : "http"; + String url = protocol + "://" + mempoolInstance + "/api/blocks/tip/height"; - if (preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE)) { - client.setCACertBundle(rootca_crt_bundle_start); + HTTPClient* http = HttpHelper::begin(url); + Serial.println("Fetching block height from " + url); + int httpCode = http->GET(); + + if (httpCode > 0 && httpCode == HTTP_CODE_OK) { + String blockHeightStr = http->getString(); + HttpHelper::end(http); + return blockHeightStr.toInt(); + } + HttpHelper::end(http); + Serial.println("HTTP code" + String(httpCode)); + } catch (...) { + Serial.println(F("An exception occurred while trying to get the latest block")); } - - String mempoolInstance = - preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); - - // Get current block height through regular API - HTTPClient http; - - const String protocol = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE) ? "https" : "http"; - - if (preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE)) - http.begin(client, protocol + "://" + mempoolInstance + "/api/blocks/tip/height"); - else - http.begin(protocol + "://" + mempoolInstance + "/api/blocks/tip/height"); - - Serial.println("Fetching block height from " + protocol + "://" + mempoolInstance + "/api/blocks/tip/height"); - int httpCode = http.GET(); - - if (httpCode > 0 && httpCode == HTTP_CODE_OK) - { - String blockHeightStr = http.getString(); - return blockHeightStr.toInt(); - } else { - Serial.println("HTTP code" + String(httpCode)); - return 0; - } - } - catch (...) { - Serial.println(F("An exception occured while trying to get the latest block")); - } - - return 2203; // B-T-C + return 2203; // B-T-C } uint getLastBlockUpdate() diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 04e9a60..9feb9a9 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -439,15 +439,19 @@ void setupHardware() Serial.println(F("Error loading WebUI")); } - // if (!LittleFS.exists("/qr.txt")) // { // File f = LittleFS.open("/qr.txt", "w"); // if(f) { - + // if (f.print("Hello")) { + // Serial.println(F("Written QR to FS")); + // Serial.printf("\nLittleFS free: %zu\n", LittleFS.totalBytes() - LittleFS.usedBytes()); + // } // } else { // Serial.println(F("Can't write QR to FS")); // } + + // f.close(); // } setupLeds(); diff --git a/src/lib/config.hpp b/src/lib/config.hpp index 87dd4d6..2c001cd 100644 --- a/src/lib/config.hpp +++ b/src/lib/config.hpp @@ -33,7 +33,6 @@ #define NTP_SERVER "pool.ntp.org" #define DEFAULT_TIME_OFFSET_SECONDS 3600 -#define USER_AGENT "BTClock/3.0" #ifndef MCP_DEV_ADDR #define MCP_DEV_ADDR 0x20 #endif diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index 7ca89fb..d880f2d 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -75,3 +75,5 @@ #define DEFAULT_GIT_RELEASE_URL "https://git.btclock.dev/api/v1/repos/btclock/btclock_v3/releases/latest" #define DEFAULT_VERTICAL_DESC true + +#define DEFAULT_MINING_POOL_LOGOS_URL "https://git.btclock.dev/btclock/mining-pool-logos/raw/branch/main" diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index b91e75c..260f772 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -176,7 +176,7 @@ void setupDisplays() updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem)); - xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", EPD_TASK_STACK_SIZE, NULL, 11, NULL); + xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", EPD_TASK_STACK_SIZE*2, NULL, 11, NULL); for (uint i = 0; i < NUM_SCREENS; i++) { @@ -275,7 +275,10 @@ void prepareDisplayUpdateTask(void *pvParameters) } else if (epdContent[epdIndex].startsWith(F("mdi"))) { - renderIcon(epdIndex, epdContent[epdIndex], updatePartial); + bool updated = renderIcon(epdIndex, epdContent[epdIndex], updatePartial); + if (!updated) { + continue; + } } else if (epdContent[epdIndex].length() > 5) { @@ -594,7 +597,7 @@ void renderText(const uint dispNum, const String &text, bool partial) } } -void renderIcon(const uint dispNum, const String &text, bool partial) +bool renderIcon(const uint dispNum, const String &text, bool partial) { displays[dispNum].setRotation(2); @@ -620,12 +623,17 @@ void renderIcon(const uint dispNum, const String &text, bool partial) else if (text.endsWith("miningpool")) { LogoData logo = getMiningPoolLogo(); + if (logo.size == 0) { + Serial.println("No logo found"); + return false; + } + int x_offset = (displays[dispNum].width() - logo.width) / 2; int y_offset = (displays[dispNum].height() - logo.height) / 2; // Close the file displays[dispNum].drawInvertedBitmap(x_offset,y_offset, logo.data, logo.width, logo.height, getFgColor()); - return; + return true; } @@ -635,7 +643,7 @@ void renderIcon(const uint dispNum, const String &text, bool partial) displays[dispNum].drawInvertedBitmap(x_offset,y_offset, epd_icons_allArray[iconIndex], width, height, getFgColor()); - + return true; // displays[dispNum].drawInvertedBitmap(0,0, getOceanIcon(), 122, 250, getFgColor()); diff --git a/src/lib/epd.hpp b/src/lib/epd.hpp index 79be979..c267047 100644 --- a/src/lib/epd.hpp +++ b/src/lib/epd.hpp @@ -45,7 +45,7 @@ int getFgColor(); void setBgColor(int color); void setFgColor(int color); -void renderIcon(const uint dispNum, const String &text, bool partial); +bool renderIcon(const uint dispNum, const String &text, bool partial); void renderText(const uint dispNum, const String &text, bool partial); void renderQr(const uint dispNum, const String &text, bool partial); diff --git a/src/lib/mining_pool/braiins/brains_pool.cpp b/src/lib/mining_pool/braiins/brains_pool.cpp index 93f9d37..47b6e61 100644 --- a/src/lib/mining_pool/braiins/brains_pool.cpp +++ b/src/lib/mining_pool/braiins/brains_pool.cpp @@ -10,6 +10,13 @@ std::string BraiinsPool::getApiUrl() const { PoolStats BraiinsPool::parseResponse(const JsonDocument &doc) const { + if (doc["btc"].isNull()) { + return PoolStats{ + .hashrate = "0", + .dailyEarnings = 0 + }; + } + std::string unit = doc["btc"]["hash_rate_unit"].as(); static const std::unordered_map multipliers = { @@ -23,10 +30,3 @@ PoolStats BraiinsPool::parseResponse(const JsonDocument &doc) const .dailyEarnings = static_cast(doc["btc"]["today_reward"].as() * 100000000)}; } -LogoData BraiinsPool::getLogo() const { - return LogoData{ - .data = epd_icons_allArray[5], - .width = 37, - .height = 230 - }; -} \ No newline at end of file diff --git a/src/lib/mining_pool/braiins/brains_pool.hpp b/src/lib/mining_pool/braiins/brains_pool.hpp index e9354e5..d79f66b 100644 --- a/src/lib/mining_pool/braiins/brains_pool.hpp +++ b/src/lib/mining_pool/braiins/brains_pool.hpp @@ -11,9 +11,23 @@ public: void prepareRequest(HTTPClient &http) const override; std::string getApiUrl() const override; PoolStats parseResponse(const JsonDocument &doc) const override; - LogoData getLogo() const override; bool supportsDailyEarnings() const override { return true; } bool hasLogo() const override { return true; } std::string getDisplayLabel() const override { return "BRAIINS/POOL"; } // Fallback if needed std::string getDailyEarningsLabel() const override { return "sats/earned"; } + std::string getLogoFilename() const override { + return "braiins.bin"; + } + + std::string getPoolName() const override { + return "braiins"; + } + + int getLogoWidth() const override { + return 37; + } + + int getLogoHeight() const override { + return 230; + } }; \ No newline at end of file diff --git a/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.cpp b/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.cpp index 90cd420..0186fec 100644 --- a/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.cpp +++ b/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.cpp @@ -3,12 +3,4 @@ std::string GoBrrrPool::getApiUrl() const { return "https://pool.gobrrr.me/api/client/" + poolUser; -} - -LogoData GoBrrrPool::getLogo() const { - return LogoData { - .data = epd_icons_allArray[7], - .width = 122, - .height = 122 - }; -} +} \ No newline at end of file diff --git a/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.hpp b/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.hpp index c50fe83..8c9ffb8 100644 --- a/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.hpp +++ b/src/lib/mining_pool/gobrrr_pool/gobrrr_pool.hpp @@ -11,5 +11,20 @@ public: std::string getApiUrl() const override; bool hasLogo() const override { return true; } std::string getDisplayLabel() const override { return "GOBRRR/POOL"; } - LogoData getLogo() const override; + + std::string getLogoFilename() const override { + return "gobrrr.bin"; + } + + std::string getPoolName() const override { + return "gobrrr_pool"; + } + + int getLogoWidth() const override { + return 122; + } + + int getLogoHeight() const override { + return 122; + } }; \ No newline at end of file diff --git a/src/lib/mining_pool/logo_data.hpp b/src/lib/mining_pool/logo_data.hpp index 7cd0819..75dcb35 100644 --- a/src/lib/mining_pool/logo_data.hpp +++ b/src/lib/mining_pool/logo_data.hpp @@ -6,5 +6,6 @@ struct LogoData { const uint8_t* data; size_t width; - size_t height; + size_t height; + size_t size; }; diff --git a/src/lib/mining_pool/mining_pool_interface.cpp b/src/lib/mining_pool/mining_pool_interface.cpp new file mode 100644 index 0000000..ced6cb9 --- /dev/null +++ b/src/lib/mining_pool/mining_pool_interface.cpp @@ -0,0 +1,18 @@ +#include "mining_pool_interface.hpp" +#include "pool_factory.hpp" + +LogoData MiningPoolInterface::getLogo() const { + if (!hasLogo()) { + return LogoData{nullptr, 0, 0, 0}; + } + + // Check if logo exists + String logoPath = String(PoolFactory::getLogosDir()) + "/" + String(getPoolName().c_str()) + "_logo.bin"; + + if (!LittleFS.exists(logoPath)) { + return LogoData{nullptr, 0, 0, 0}; + } + + // Now load the logo (whether it was just downloaded or already existed) + return PoolFactory::loadLogoFromFS(getPoolName(), this); +} \ No newline at end of file diff --git a/src/lib/mining_pool/mining_pool_interface.hpp b/src/lib/mining_pool/mining_pool_interface.hpp index 63bb53f..28383a3 100644 --- a/src/lib/mining_pool/mining_pool_interface.hpp +++ b/src/lib/mining_pool/mining_pool_interface.hpp @@ -4,6 +4,7 @@ #include #include "pool_stats.hpp" #include "logo_data.hpp" +#include "lib/shared.hpp" class MiningPoolInterface { public: @@ -13,10 +14,21 @@ public: virtual std::string getApiUrl() const = 0; virtual PoolStats parseResponse(const JsonDocument& doc) const = 0; virtual bool hasLogo() const = 0; - virtual LogoData getLogo() const = 0; + virtual LogoData getLogo() const; virtual std::string getDisplayLabel() const = 0; virtual bool supportsDailyEarnings() const = 0; virtual std::string getDailyEarningsLabel() const = 0; + virtual std::string getLogoFilename() const { return ""; } + virtual std::string getPoolName() const = 0; + virtual int getLogoWidth() const { return 0; } + virtual int getLogoHeight() const { return 0; } + std::string getLogoUrl() const { + if (!hasLogo() || getLogoFilename().empty()) { + return ""; + } + std::string baseUrl = preferences.getString("poolLogosUrl", DEFAULT_MINING_POOL_LOGOS_URL).c_str(); + return baseUrl + "/" + getLogoFilename().c_str(); + } protected: std::string poolUser; diff --git a/src/lib/mining_pool/noderunners/noderunners_pool.cpp b/src/lib/mining_pool/noderunners/noderunners_pool.cpp index 0f55180..da34e38 100644 --- a/src/lib/mining_pool/noderunners/noderunners_pool.cpp +++ b/src/lib/mining_pool/noderunners/noderunners_pool.cpp @@ -24,12 +24,4 @@ PoolStats NoderunnersPool::parseResponse(const JsonDocument& doc) const { .hashrate = buffer, .dailyEarnings = std::nullopt }; -} - -LogoData NoderunnersPool::getLogo() const { - return LogoData { - .data = epd_icons_allArray[6], - .width = 122, - .height = 122 - }; } \ No newline at end of file diff --git a/src/lib/mining_pool/noderunners/noderunners_pool.hpp b/src/lib/mining_pool/noderunners/noderunners_pool.hpp index 5ecce53..562ff50 100644 --- a/src/lib/mining_pool/noderunners/noderunners_pool.hpp +++ b/src/lib/mining_pool/noderunners/noderunners_pool.hpp @@ -1,4 +1,3 @@ - #pragma once #include "lib/mining_pool/mining_pool_interface.hpp" @@ -12,9 +11,23 @@ public: void prepareRequest(HTTPClient& http) const override; std::string getApiUrl() const override; PoolStats parseResponse(const JsonDocument& doc) const override; - LogoData getLogo() const override; bool supportsDailyEarnings() const override { return false; } std::string getDailyEarningsLabel() const override { return ""; } bool hasLogo() const override { return true; } std::string getDisplayLabel() const override { return "NODE/RUNNERS"; } // Fallback if needed + std::string getLogoFilename() const override { + return "noderunners.bin"; + } + + std::string getPoolName() const override { + return "noderunners"; + } + + int getLogoWidth() const override { + return 122; + } + + int getLogoHeight() const override { + return 122; + } }; \ No newline at end of file diff --git a/src/lib/mining_pool/ocean/ocean_pool.cpp b/src/lib/mining_pool/ocean/ocean_pool.cpp index f66ad5c..f6050af 100644 --- a/src/lib/mining_pool/ocean/ocean_pool.cpp +++ b/src/lib/mining_pool/ocean/ocean_pool.cpp @@ -16,11 +16,3 @@ PoolStats OceanPool::parseResponse(const JsonDocument& doc) const { ) }; } - -LogoData OceanPool::getLogo() const { - return LogoData{ - .data = epd_icons_allArray[4], - .width = 122, - .height = 122 - }; -} \ No newline at end of file diff --git a/src/lib/mining_pool/ocean/ocean_pool.hpp b/src/lib/mining_pool/ocean/ocean_pool.hpp index 2773915..3ede176 100644 --- a/src/lib/mining_pool/ocean/ocean_pool.hpp +++ b/src/lib/mining_pool/ocean/ocean_pool.hpp @@ -9,10 +9,23 @@ public: void prepareRequest(HTTPClient& http) const override; std::string getApiUrl() const override; PoolStats parseResponse(const JsonDocument& doc) const override; - LogoData getLogo() const override; bool hasLogo() const override { return true; } std::string getDisplayLabel() const override { return "OCEAN/POOL"; } // Fallback if needed bool supportsDailyEarnings() const override { return true; } std::string getDailyEarningsLabel() const override { return "sats/block"; } - + std::string getLogoFilename() const override { + return "ocean.bin"; + } + + std::string getPoolName() const override { + return "ocean"; + } + + int getLogoWidth() const override { + return 122; + } + + int getLogoHeight() const override { + return 122; + } }; \ No newline at end of file diff --git a/src/lib/mining_pool/pool_factory.cpp b/src/lib/mining_pool/pool_factory.cpp index d3073e1..150793a 100644 --- a/src/lib/mining_pool/pool_factory.cpp +++ b/src/lib/mining_pool/pool_factory.cpp @@ -6,6 +6,7 @@ const char* PoolFactory::MINING_POOL_NAME_BRAIINS = "braiins"; const char* PoolFactory::MINING_POOL_NAME_SATOSHI_RADIO = "satoshi_radio"; const char* PoolFactory::MINING_POOL_NAME_PUBLIC_POOL = "public_pool"; const char* PoolFactory::MINING_POOL_NAME_GOBRRR_POOL = "gobrrr_pool"; +const char* PoolFactory::LOGOS_DIR = "/logos"; std::unique_ptr PoolFactory::createPool(const std::string& poolName) { static const std::unordered_map()>> poolFactories = { @@ -22,4 +23,112 @@ std::unique_ptr PoolFactory::createPool(const std::string& return nullptr; } return it->second(); +} + +void PoolFactory::downloadPoolLogo(const std::string& poolName, const MiningPoolInterface* poolInterface) +{ + const int MAX_RETRIES = 5; + const int RETRY_DELAY_MS = 1000; // 1 second between retries + + if (!poolInterface || !poolInterface->hasLogo()) { + Serial.println(F("No pool interface or logo")); + return; + } + + // Ensure logos directory exists + if (!LittleFS.exists(LOGOS_DIR)) { + LittleFS.mkdir(LOGOS_DIR); + } + + String logoPath = String(LOGOS_DIR) + "/" + String(poolName.c_str()) + "_logo.bin"; + + // Only download if the logo doesn't exist + if (!LittleFS.exists(logoPath)) { + // Clean up logos directory first + File root = LittleFS.open(LOGOS_DIR, "r"); + if (root) { + File file = root.openNextFile(); + while (file) { + String path = file.path(); + file.close(); + LittleFS.remove(path); + file = root.openNextFile(); + } + root.close(); + } + + // Download new logo with retries + std::string logoUrl = poolInterface->getLogoUrl(); + if (!logoUrl.empty()) { + for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) { + Serial.printf("Downloading pool logo (attempt %d of %d)...\n", attempt, MAX_RETRIES); + + HTTPClient http; + http.setUserAgent(USER_AGENT); + http.begin(logoUrl.c_str()); + int httpCode = http.GET(); + + if (httpCode == 200) { + File file = LittleFS.open(logoPath, "w"); + if (file) { + http.writeToStream(&file); + file.close(); + Serial.println(F("Logo downloaded successfully")); + http.end(); + return; // Success! + } + } + + http.end(); + + if (attempt < MAX_RETRIES) { + Serial.printf("Failed to download logo, HTTP code: %d. Retrying...\n", httpCode); + vTaskDelay(pdMS_TO_TICKS(RETRY_DELAY_MS)); + } else { + Serial.printf("Failed to download logo after %d attempts\n", MAX_RETRIES); + } + } + } + } else { + Serial.println(F("Logo already exists")); + } +} + +LogoData PoolFactory::loadLogoFromFS(const std::string& poolName, const MiningPoolInterface* poolInterface) +{ + // Initialize with dimensions from the pool interface + LogoData logo = {nullptr, + 0, + 0, + 0}; + + String logoPath = String(LOGOS_DIR) + "/" + String(poolName.c_str()) + "_logo.bin"; + if (!LittleFS.exists(logoPath)) { + return logo; + } + + // Only set dimensions if file exists + logo.width = static_cast(poolInterface->getLogoWidth()); + logo.height = static_cast(poolInterface->getLogoHeight()); + + File file = LittleFS.open(logoPath, "r"); + if (!file) { + return logo; + } + + size_t size = file.size(); + uint8_t* buffer = new uint8_t[size]; + + + if (file.read(buffer, size) == size) { + logo.data = buffer; + logo.size = size; + } else { + delete[] buffer; + logo.data = nullptr; + logo.size = 0; + } + + file.close(); + return logo; } \ No newline at end of file diff --git a/src/lib/mining_pool/pool_factory.hpp b/src/lib/mining_pool/pool_factory.hpp index a8e4861..96231c9 100644 --- a/src/lib/mining_pool/pool_factory.hpp +++ b/src/lib/mining_pool/pool_factory.hpp @@ -2,15 +2,22 @@ #include "mining_pool_interface.hpp" #include #include +#include "lib/shared.hpp" +#include "lib/config.hpp" + #include "noderunners/noderunners_pool.hpp" #include "braiins/brains_pool.hpp" #include "ocean/ocean_pool.hpp" #include "satoshi_radio/satoshi_radio_pool.hpp" #include "public_pool/public_pool.hpp" #include "gobrrr_pool/gobrrr_pool.hpp" +#include +#include + class PoolFactory { public: + static const char* getLogosDir() { return LOGOS_DIR; } static std::unique_ptr createPool(const std::string& poolName); static std::vector getAvailablePools() { return { @@ -34,6 +41,10 @@ class PoolFactory { } return result; } + + static void downloadPoolLogo(const std::string& poolName, const MiningPoolInterface* poolInterface); + static LogoData loadLogoFromFS(const std::string& poolName, const MiningPoolInterface* poolInterface); + private: static const char* MINING_POOL_NAME_OCEAN; static const char* MINING_POOL_NAME_NODERUNNERS; @@ -41,4 +52,5 @@ class PoolFactory { static const char* MINING_POOL_NAME_SATOSHI_RADIO; static const char* MINING_POOL_NAME_PUBLIC_POOL; static const char* MINING_POOL_NAME_GOBRRR_POOL; + static const char* LOGOS_DIR; }; \ No newline at end of file diff --git a/src/lib/mining_pool_stats_fetch.cpp b/src/lib/mining_pool_stats_fetch.cpp index 2f9c10b..3f870bb 100644 --- a/src/lib/mining_pool_stats_fetch.cpp +++ b/src/lib/mining_pool_stats_fetch.cpp @@ -18,6 +18,12 @@ int getMiningPoolStatsDailyEarnings() void taskMiningPoolStatsFetch(void *pvParameters) { + std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); + auto poolInterface = PoolFactory::createPool(poolName); + + std::string poolUser = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str(); + + // Main stats fetching loop for (;;) { ulTaskNotifyTake(pdTRUE, portMAX_DELAY); @@ -25,16 +31,8 @@ void taskMiningPoolStatsFetch(void *pvParameters) HTTPClient http; http.setUserAgent(USER_AGENT); - std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); - std::string poolUser = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str(); - - auto poolInterface = PoolFactory::createPool(poolName); - if (!poolInterface) - { - Serial.println("Unknown mining pool: \"" + String(poolName.c_str()) + "\""); - continue; - } + poolInterface->setPoolUser(poolUser); std::string apiUrl = poolInterface->getApiUrl(); http.begin(apiUrl.c_str()); @@ -74,12 +72,36 @@ void taskMiningPoolStatsFetch(void *pvParameters) } } -void setupMiningPoolStatsFetchTask() -{ - xTaskCreate(taskMiningPoolStatsFetch, "miningPoolStatsFetch", (6 * 1024), NULL, tskIDLE_PRIORITY, - &miningPoolStatsFetchTaskHandle); +void downloadMiningPoolLogoTask(void *pvParameters) { + std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); + auto poolInterface = PoolFactory::createPool(poolName); + PoolFactory::downloadPoolLogo(poolName, poolInterface.get()); + + // If we're on the mining pool stats screen, trigger a display update + if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) { + WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0}; + xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); + } xTaskNotifyGive(miningPoolStatsFetchTaskHandle); + vTaskDelete(NULL); +} + +void setupMiningPoolStatsFetchTask() +{ + xTaskCreate(downloadMiningPoolLogoTask, + "logoDownload", + (6 * 1024), + NULL, + 12, + NULL); + + xTaskCreate(taskMiningPoolStatsFetch, + "miningPoolStatsFetch", + (6 * 1024), + NULL, + tskIDLE_PRIORITY, + &miningPoolStatsFetchTaskHandle); } std::unique_ptr& getMiningPool() @@ -96,5 +118,6 @@ std::unique_ptr& getMiningPool() LogoData getMiningPoolLogo() { - return getMiningPool()->getLogo(); + LogoData logo = getMiningPool()->getLogo(); + return logo; } diff --git a/src/lib/shared.cpp b/src/lib/shared.cpp index 3422ff8..a776750 100644 --- a/src/lib/shared.cpp +++ b/src/lib/shared.cpp @@ -151,4 +151,32 @@ String calculateSHA256(WiFiClient *stream, size_t contentLength) { // uint8_t *pUncompressed; // pUncompressed = (uint8_t *)malloc(iUncompSize+4); // zt.gunzip((uint8_t *)ocean_logo_comp, ocean_logo_size, pUncompressed); -// } \ No newline at end of file +// } + +WiFiClientSecure HttpHelper::secureClient; +WiFiClient HttpHelper::insecureClient; +bool HttpHelper::certBundleSet = false; + +HTTPClient* HttpHelper::begin(const String& url) { + HTTPClient* http = new HTTPClient(); + + if (url.startsWith("https://")) { + if (!certBundleSet) { + secureClient.setCACertBundle(rootca_crt_bundle_start); + certBundleSet = true; + } + http->begin(secureClient, url); + } else { + http->begin(insecureClient, url); + } + + http->setUserAgent(USER_AGENT); + return http; +} + +void HttpHelper::end(HTTPClient* http) { + if (http) { + http->end(); + delete http; + } +} \ No newline at end of file diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index 9fd7455..adbbe5e 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -12,12 +12,15 @@ #include #include "esp_crt_bundle.h" #include +#include #include #include #include "defaults.hpp" +#define USER_AGENT "BTClock/3.0" + extern MCP23017 mcp1; #ifdef IS_BTCLOCK_V8 extern MCP23017 mcp2; @@ -94,4 +97,15 @@ namespace ArduinoJson { array.add(item); } }; -} \ No newline at end of file +} + +class HttpHelper { +public: + static HTTPClient* begin(const String& url); + static void end(HTTPClient* http); + +private: + static WiFiClientSecure secureClient; + static bool certBundleSet; + static WiFiClient insecureClient; +}; \ No newline at end of file diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 8b031d6..eddc2f9 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -510,7 +510,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) settings["timePerScreen"].as() * 60); } - String strSettings[] = {"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl"}; + String strSettings[] = {"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl"}; for (String setting : strSettings) { @@ -768,6 +768,8 @@ void onApiSettingsGet(AsyncWebServerRequest *request) o["enabled"] = preferences.getBool(key.c_str(), true); } + root["poolLogosUrl"] = preferences.getString("poolLogosUrl", DEFAULT_MINING_POOL_LOGOS_URL); + AsyncResponseStream *response = request->beginResponseStream("application/json"); serializeJson(root, *response); @@ -812,6 +814,9 @@ void onApiSystemStatus(AsyncWebServerRequest *request) root["espHeapSize"] = ESP.getHeapSize(); root["espFreePsram"] = ESP.getFreePsram(); root["espPsramSize"] = ESP.getPsramSize(); + root["fsUsedBytes"] = LittleFS.usedBytes(); + root["fsTotalBytes"] = LittleFS.totalBytes(); + root["rssi"] = WiFi.RSSI(); root["txPower"] = WiFi.getTxPower(); From 46c0f3a22bdb37cdf1f80e3d16416bb03ab9c50f Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 21 Dec 2024 00:01:27 +0100 Subject: [PATCH 073/130] Improve webserver functionality --- src/lib/webserver.cpp | 279 ++++++++++++++++-------------------------- src/lib/webserver.hpp | 3 +- 2 files changed, 107 insertions(+), 175 deletions(-) diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index eddc2f9..ee9a701 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -1,26 +1,37 @@ #include "webserver.hpp" +static const char* JSON_CONTENT = "application/json"; + +static const char *const PROGMEM strSettings[] = { + "hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl"}; + +static const char *const PROGMEM uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout", "srcV2Currency"}; + +static const char *const PROGMEM boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd", + "mdnsEnabled", "otaEnabled", "stealFocus", + "mcapBigChar", "useSatsSymbol", "useBlkCountdown", + "suffixPrice", "disableLeds", "ownDataSource", + "mowMode", "suffixShareDot", "flOffWhenDark", + "flAlwaysOn", "flDisable", "flFlashOnUpd", + "mempoolSecure", "useNostr", "bitaxeEnabled", + "miningPoolStats", "verticalDesc", + "nostrZapNotify", "stagingSource", "httpAuthEnabled"}; + AsyncWebServer server(80); AsyncEventSource events("/events"); TaskHandle_t eventSourceTaskHandle; +#define HTTP_OK 200 +#define HTTP_BAD_REQUEST 400 + void setupWebserver() { events.onConnect([](AsyncEventSourceClient *client) { client->send("welcome", NULL, millis(), 1000); }); server.addHandler(&events); - // server.ad. - // server.serveStatic("/css", LittleFS, "/css/"); - // server.serveStatic("/fonts", LittleFS, "/fonts/"); - // server.serveStatic("/build", LittleFS, "/build"); - // server.serveStatic("/swagger.json", LittleFS, "/swagger.json"); - // server.serveStatic("/api.html", LittleFS, "/api.html"); - // server.serveStatic("/fs_hash.txt", LittleFS, "/fs_hash.txt"); - AsyncStaticWebHandler &staticHandler = server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html"); - server.rewrite("/convert", "/"); server.rewrite("/api", "/"); @@ -31,7 +42,6 @@ void setupWebserver() preferences.getString("httpAuthPass", DEFAULT_HTTP_AUTH_PASSWORD)); } // server.on("/", HTTP_GET, onIndex); - server.on("/api/status", HTTP_GET, onApiStatus); server.on("/api/system_status", HTTP_GET, onApiSystemStatus); server.on("/api/wifi_set_tx_power", HTTP_GET, onApiSetWifiTxPower); @@ -51,8 +61,8 @@ void setupWebserver() server.on("/api/show/text", HTTP_GET, onApiShowText); - server.on("/api/screen/next", HTTP_GET, onApiScreenNext); - server.on("/api/screen/previous", HTTP_GET, onApiScreenPrevious); + server.on("/api/screen/next", HTTP_GET, onApiScreenControl); + server.on("/api/screen/previous", HTTP_GET, onApiScreenControl); AsyncCallbackJsonWebHandler *settingsPatchHandler = new AsyncCallbackJsonWebHandler("/api/json/settings", onApiSettingsPatch); @@ -212,36 +222,6 @@ void asyncFileUpdateHandler(AsyncWebServerRequest *request, String filename, siz void asyncFirmwareUpdateHandler(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { asyncFileUpdateHandler(request, filename, index, data, len, final, U_FLASH); - - // if (!index) - // { - // Serial.printf("Update Start: %s\n", filename.c_str()); - - // // Update.runAsync(true); - // if (!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)) - // { - // Update.printError(Serial); - // } - // } - // if (!Update.hasError()) - // { - // if (Update.write(data, len) != len) - // { - // Update.printError(Serial); - // } - // } - // if (final) - // { - // if (Update.end(true)) - // { - // Serial.printf("Update Success: %uB\n", index + len); - // onApiRestart(request); - // } - // else - // { - // Update.printError(Serial); - // } - // } } JsonDocument getStatusObject() @@ -260,7 +240,7 @@ JsonDocument getStatusObject() // root["espPsramSize"] = ESP.getPsramSize(); JsonObject conStatus = root["connectionStatus"].to(); - + conStatus["price"] = isPriceNotifyConnected(); conStatus["blocks"] = isBlockNotifyConnected(); conStatus["V2"] = V2Notify::isV2NotifyConnected(); @@ -313,25 +293,26 @@ JsonDocument getLedStatusObject() return root; } -void eventSourceUpdate() -{ - if (!events.count()) - return; - JsonDocument root = getStatusObject(); - JsonArray data = root["data"].to(); +void eventSourceUpdate() { + if (!events.count()) return; + + JsonDocument doc = getStatusObject(); + doc["leds"] = getLedStatusObject()["data"]; - root["leds"] = getLedStatusObject()["data"]; + // Get current EPD content directly as array + std::array epdContent = getCurrentEpdContent(); + + // Add EPD content arrays + JsonArray data = doc["data"].to(); + + // Copy array elements directly + for(const auto& content : epdContent) { + data.add(content); + } - String epdContent[NUM_SCREENS]; - std::array retEpdContent = getCurrentEpdContent(); - std::copy(std::begin(retEpdContent), std::end(retEpdContent), epdContent); - - copyArray(epdContent, data); - - String bufString; - serializeJson(root, bufString); - - events.send(bufString.c_str(), "status"); + String buffer; + serializeJson(doc, buffer); + events.send(buffer.c_str(), "status"); } /** @@ -341,21 +322,22 @@ void eventSourceUpdate() void onApiStatus(AsyncWebServerRequest *request) { AsyncResponseStream *response = - request->beginResponseStream("application/json"); + request->beginResponseStream(JSON_CONTENT); JsonDocument root = getStatusObject(); + + // Get current EPD content directly as array + std::array epdContent = getCurrentEpdContent(); + + // Add EPD content arrays JsonArray data = root["data"].to(); - JsonArray rendered = root["rendered"].to(); - String epdContent[NUM_SCREENS]; + + // Copy array elements directly + for(const auto& content : epdContent) { + data.add(content); + } root["leds"] = getLedStatusObject()["data"]; - - std::array retEpdContent = getCurrentEpdContent(); - - std::copy(std::begin(retEpdContent), std::end(retEpdContent), epdContent); - - copyArray(epdContent, data); - copyArray(epdContent, rendered); serializeJson(root, *response); request->send(response); @@ -368,7 +350,7 @@ void onApiStatus(AsyncWebServerRequest *request) void onApiActionPause(AsyncWebServerRequest *request) { setTimerActive(false); - request->send(200); + request->send(HTTP_OK); }; /** @@ -378,7 +360,7 @@ void onApiActionPause(AsyncWebServerRequest *request) void onApiActionTimerRestart(AsyncWebServerRequest *request) { setTimerActive(true); - request->send(200); + request->send(HTTP_OK); } /** @@ -392,7 +374,7 @@ void onApiFullRefresh(AsyncWebServerRequest *request) setEpdContent(newEpdContent, true); - request->send(200); + request->send(HTTP_OK); } /** @@ -407,28 +389,21 @@ void onApiShowScreen(AsyncWebServerRequest *request) uint currentScreen = p->value().toInt(); setCurrentScreen(currentScreen); } - request->send(200); + request->send(HTTP_OK); } /** * @Api * @Path("/api/screen/next") */ -void onApiScreenNext(AsyncWebServerRequest *request) -{ - nextScreen(); - request->send(200); -} - -/** - * @Api - * @Path("/api/screen/previous") - */ -void onApiScreenPrevious(AsyncWebServerRequest *request) -{ - previousScreen(); - - request->send(200); +void onApiScreenControl(AsyncWebServerRequest *request) { + const String& action = request->url(); + if (action.endsWith("/next")) { + nextScreen(); + } else if (action.endsWith("/previous")) { + previousScreen(); + } + request->send(HTTP_OK); } void onApiShowText(AsyncWebServerRequest *request) @@ -448,7 +423,7 @@ void onApiShowText(AsyncWebServerRequest *request) setEpdContent(textEpdContent); } setCurrentScreen(SCREEN_CUSTOM); - request->send(200); + request->send(HTTP_OK); } void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json) @@ -466,7 +441,7 @@ void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json) setEpdContent(epdContent); setCurrentScreen(SCREEN_CUSTOM); - request->send(200); + request->send(HTTP_OK); } void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) @@ -487,18 +462,20 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) if (settings.containsKey("fgColor")) { String fgColor = settings["fgColor"].as(); - preferences.putUInt("fgColor", strtol(fgColor.c_str(), NULL, 16)); - setFgColor(int(strtol(fgColor.c_str(), NULL, 16))); + uint32_t color = strtol(fgColor.c_str(), NULL, 16); + preferences.putUInt("fgColor", color); + setFgColor(color); Serial.print(F("Setting foreground color to ")); - Serial.println(strtol(fgColor.c_str(), NULL, 16)); + Serial.println(color); settingsChanged = true; } if (settings.containsKey("bgColor")) { String bgColor = settings["bgColor"].as(); - preferences.putUInt("bgColor", strtol(bgColor.c_str(), NULL, 16)); - setBgColor(int(strtol(bgColor.c_str(), NULL, 16))); + uint32_t color = strtol(bgColor.c_str(), NULL, 16); + preferences.putUInt("bgColor", color); + setBgColor(color); Serial.print(F("Setting background color to ")); Serial.println(bgColor.c_str()); settingsChanged = true; @@ -510,8 +487,6 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) settings["timePerScreen"].as() * 60); } - String strSettings[] = {"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl"}; - for (String setting : strSettings) { if (settings.containsKey(setting)) @@ -522,7 +497,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) } } - String uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout", "srcV2Currency"}; + for (String setting : uintSettings) { @@ -542,16 +517,6 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) gmtOffset, settings["tzOffset"].as(), written); } - String boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd", - "mdnsEnabled", "otaEnabled", "stealFocus", - "mcapBigChar", "useSatsSymbol", "useBlkCountdown", - "suffixPrice", "disableLeds", "ownDataSource", - "mowMode", "suffixShareDot", "flOffWhenDark", - "flAlwaysOn", "flDisable", "flFlashOnUpd", - "mempoolSecure", "useNostr", "bitaxeEnabled", - "miningPoolStats", "verticalDesc", - "nostrZapNotify", "stagingSource", "httpAuthEnabled"}; - for (String setting : boolSettings) { if (settings.containsKey(setting)) @@ -619,7 +584,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) } } - request->send(200); + request->send(HTTP_OK); if (settingsChanged) { queueLedEffect(LED_FLASH_SUCCESS); @@ -628,7 +593,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) void onApiRestart(AsyncWebServerRequest *request) { - request->send(200); + request->send(HTTP_OK); if (events.count()) events.send("closing"); @@ -642,7 +607,7 @@ void onApiIdentify(AsyncWebServerRequest *request) { queueLedEffect(LED_FLASH_IDENTIFY); - request->send(200); + request->send(HTTP_OK); } /** @@ -771,7 +736,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["poolLogosUrl"] = preferences.getString("poolLogosUrl", DEFAULT_MINING_POOL_LOGOS_URL); AsyncResponseStream *response = - request->beginResponseStream("application/json"); + request->beginResponseStream(JSON_CONTENT); serializeJson(root, *response); request->send(response); @@ -783,8 +748,9 @@ bool processEpdColorSettings(AsyncWebServerRequest *request) if (request->hasParam("fgColor", true)) { const AsyncWebParameter *fgColor = request->getParam("fgColor", true); - preferences.putUInt("fgColor", strtol(fgColor->value().c_str(), NULL, 16)); - setFgColor(int(strtol(fgColor->value().c_str(), NULL, 16))); + uint32_t color = strtol(fgColor->value().c_str(), NULL, 16); + preferences.putUInt("fgColor", color); + setFgColor(color); // Serial.print(F("Setting foreground color to ")); // Serial.println(fgColor->value().c_str()); settingsChanged = true; @@ -793,8 +759,9 @@ bool processEpdColorSettings(AsyncWebServerRequest *request) { const AsyncWebParameter *bgColor = request->getParam("bgColor", true); - preferences.putUInt("bgColor", strtol(bgColor->value().c_str(), NULL, 16)); - setBgColor(int(strtol(bgColor->value().c_str(), NULL, 16))); + uint32_t color = strtol(bgColor->value().c_str(), NULL, 16); + preferences.putUInt("bgColor", color); + setBgColor(color); // Serial.print(F("Setting background color to ")); // Serial.println(bgColor->value().c_str()); settingsChanged = true; @@ -806,7 +773,7 @@ bool processEpdColorSettings(AsyncWebServerRequest *request) void onApiSystemStatus(AsyncWebServerRequest *request) { AsyncResponseStream *response = - request->beginResponseStream("application/json"); + request->beginResponseStream(JSON_CONTENT); JsonDocument root; @@ -848,19 +815,19 @@ void onApiSetWifiTxPower(AsyncWebServerRequest *request) if (WiFi.setTxPower(static_cast(txPower))) { preferences.putInt("txPower", txPower); - request->send(200, "application/json", "{\"setTxPower\": \"ok\"}"); + request->send(HTTP_OK, "application/json", "{\"setTxPower\": \"ok\"}"); return; } } } - return request->send(400); + return request->send(HTTP_BAD_REQUEST); } void onApiLightsStatus(AsyncWebServerRequest *request) { AsyncResponseStream *response = - request->beginResponseStream("application/json"); + request->beginResponseStream(JSON_CONTENT); serializeJson(getLedStatusObject()["data"], *response); @@ -870,7 +837,7 @@ void onApiLightsStatus(AsyncWebServerRequest *request) void onApiStopDataSources(AsyncWebServerRequest *request) { AsyncResponseStream *response = - request->beginResponseStream("application/json"); + request->beginResponseStream(JSON_CONTENT); stopPriceNotify(); stopBlockNotify(); @@ -881,7 +848,7 @@ void onApiStopDataSources(AsyncWebServerRequest *request) void onApiRestartDataSources(AsyncWebServerRequest *request) { AsyncResponseStream *response = - request->beginResponseStream("application/json"); + request->beginResponseStream(JSON_CONTENT); restartPriceNotify(); restartBlockNotify(); @@ -894,7 +861,7 @@ void onApiRestartDataSources(AsyncWebServerRequest *request) void onApiLightsOff(AsyncWebServerRequest *request) { setLights(0, 0, 0); - request->send(200); + request->send(HTTP_OK); } void onApiLightsSetColor(AsyncWebServerRequest *request) @@ -902,7 +869,7 @@ void onApiLightsSetColor(AsyncWebServerRequest *request) if (request->hasParam("c")) { AsyncResponseStream *response = - request->beginResponseStream("application/json"); + request->beginResponseStream(JSON_CONTENT); String rgbColor = request->getParam("c")->value(); @@ -926,7 +893,7 @@ void onApiLightsSetColor(AsyncWebServerRequest *request) } else { - request->send(400); + request->send(HTTP_BAD_REQUEST); } } @@ -943,7 +910,7 @@ void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json) } Serial.printf("Invalid values for LED set %d\n", lights.size()); - request->send(400); + request->send(HTTP_BAD_REQUEST); return; } @@ -964,14 +931,14 @@ void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json) &green, &blue) == 3) { Serial.printf("Invalid hex for LED %d\n", i); - request->send(400); + request->send(HTTP_BAD_REQUEST); return; } } else { Serial.printf("No valid color for LED %d\n", i); - request->send(400); + request->send(HTTP_BAD_REQUEST); return; } @@ -982,7 +949,7 @@ void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json) pixels.show(); saveLedState(); - request->send(200); + request->send(HTTP_OK); } void onIndex(AsyncWebServerRequest *request) @@ -992,48 +959,14 @@ void onIndex(AsyncWebServerRequest *request) void onNotFound(AsyncWebServerRequest *request) { - // Serial.printf("NotFound, URL[%s]\n", request->url()); - - // Serial.printf("NotFound, METHOD[%s]\n", request->methodToString()); - - // int headers = request->headers(); - // int i; - // for (i = 0; i < headers; i++) - // { - // AsyncWebHeader *h = request->getHeader(i); - // Serial.printf("NotFound HEADER[%s]: %s\n", h->name().c_str(), - // h->value().c_str()); - // } - - // int params = request->params(); - // for (int i = 0; i < params; i++) - // { - // const AsyncWebParameter *p = request->getParam(i); - // if (p->isFile()) - // { // p->isPost() is also true - // Serial.printf("NotFound FILE[%s]: %s, size: %u\n", - // p->name().c_str(), p->value().c_str(), p->size()); - // } - // else if (p->isPost()) - // { - // Serial.printf("NotFound POST[%s]: %s\n", p->name().c_str(), - // p->value().c_str()); - // } - // else - // { - // Serial.printf("NotFound GET[%s]: %s\n", p->name().c_str(), - // p->value().c_str()); - // } - // } - - // Access-Control-Request-Method == POST might be better + // Access-Control-Request-Method == POST might be better if (request->method() == HTTP_OPTIONS || request->hasHeader("Sec-Fetch-Mode")) { // Serial.printf("NotFound, Return[%d]\n", 200); - request->send(200); + request->send(HTTP_OK); } else { @@ -1069,7 +1002,7 @@ void onApiShowCurrency(AsyncWebServerRequest *request) setCurrentCurrency(curChar); setCurrentScreen(getCurrentScreen()); - request->send(200); + request->send(HTTP_OK); return; } request->send(404); @@ -1080,13 +1013,13 @@ void onApiFrontlightOn(AsyncWebServerRequest *request) { frontlightFadeInAll(); - request->send(200); + request->send(HTTP_OK); } void onApiFrontlightStatus(AsyncWebServerRequest *request) { AsyncResponseStream *response = - request->beginResponseStream("application/json"); + request->beginResponseStream(JSON_CONTENT); JsonDocument root; @@ -1105,7 +1038,7 @@ void onApiFrontlightFlash(AsyncWebServerRequest *request) { frontlightFlash(preferences.getUInt("flEffectDelay")); - request->send(200); + request->send(HTTP_OK); } void onApiFrontlightSetBrightness(AsyncWebServerRequest *request) @@ -1113,11 +1046,11 @@ void onApiFrontlightSetBrightness(AsyncWebServerRequest *request) if (request->hasParam("b")) { frontlightSetBrightness(request->getParam("b")->value().toInt()); - request->send(200); + request->send(HTTP_OK); } else { - request->send(400); + request->send(HTTP_BAD_REQUEST); } } @@ -1125,6 +1058,6 @@ void onApiFrontlightOff(AsyncWebServerRequest *request) { frontlightFadeOutAll(); - request->send(200); + request->send(HTTP_OK); } #endif \ No newline at end of file diff --git a/src/lib/webserver.hpp b/src/lib/webserver.hpp index 6817baf..45fa854 100644 --- a/src/lib/webserver.hpp +++ b/src/lib/webserver.hpp @@ -28,8 +28,7 @@ void onApiStatus(AsyncWebServerRequest *request); void onApiSystemStatus(AsyncWebServerRequest *request); void onApiSetWifiTxPower(AsyncWebServerRequest *request); -void onApiScreenNext(AsyncWebServerRequest *request); -void onApiScreenPrevious(AsyncWebServerRequest *request); +void onApiScreenControl(AsyncWebServerRequest *request); void onApiShowScreen(AsyncWebServerRequest *request); void onApiShowCurrency(AsyncWebServerRequest *request); From 753838b122fbf7d00faa0ddbea6d3ebd2a0e8c62 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 21 Dec 2024 00:15:08 +0100 Subject: [PATCH 074/130] Switch to new ArduinoJson methods --- src/lib/webserver.cpp | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index ee9a701..f1810cc 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -275,7 +275,6 @@ JsonDocument getLedStatusObject() for (uint i = 0; i < pixels.numPixels(); i++) { uint32_t pixColor = pixels.getPixelColor(pixels.numPixels() - i - 1); - uint alpha = (pixColor >> 24) & 0xFF; uint red = (pixColor >> 16) & 0xFF; uint green = (pixColor >> 8) & 0xFF; uint blue = pixColor & 0xFF; @@ -459,7 +458,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) bool settingsChanged = true; - if (settings.containsKey("fgColor")) + if (settings["fgColor"].is()) { String fgColor = settings["fgColor"].as(); uint32_t color = strtol(fgColor.c_str(), NULL, 16); @@ -469,7 +468,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) Serial.println(color); settingsChanged = true; } - if (settings.containsKey("bgColor")) + if (settings["bgColor"].is()) { String bgColor = settings["bgColor"].as(); @@ -481,7 +480,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) settingsChanged = true; } - if (settings.containsKey("timePerScreen")) + if (settings["timePerScreen"].is()) { preferences.putUInt("timerSeconds", settings["timePerScreen"].as() * 60); @@ -489,11 +488,11 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) for (String setting : strSettings) { - if (settings.containsKey(setting)) + if (settings[setting].is()) { preferences.putString(setting.c_str(), settings[setting].as()); Serial.printf("Setting %s to %s\r\n", setting.c_str(), - settings[setting].as()); + settings[setting].as().c_str()); } } @@ -501,7 +500,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) for (String setting : uintSettings) { - if (settings.containsKey(setting)) + if (settings[setting].is()) { preferences.putUInt(setting.c_str(), settings[setting].as()); Serial.printf("Setting %s to %d\r\n", setting.c_str(), @@ -509,7 +508,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) } } - if (settings.containsKey("tzOffset")) + if (settings["tzOffset"].is()) { int gmtOffset = settings["tzOffset"].as() * 60; size_t written = preferences.putInt("gmtOffset", gmtOffset); @@ -519,15 +518,15 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) for (String setting : boolSettings) { - if (settings.containsKey(setting)) + if (settings[setting].is()) { - preferences.putBool(setting.c_str(), settings[setting].as()); + preferences.putBool(setting.c_str(), settings[setting].as()); Serial.printf("Setting %s to %d\r\n", setting.c_str(), - settings[setting].as()); + settings[setting].as()); } } - if (settings.containsKey("screens")) + if (settings["screens"].is()) { for (JsonVariant screen : settings["screens"].as()) { @@ -535,12 +534,12 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) uint id = s["id"].as(); String key = "screen[" + String(id) + "]"; String prefKey = "screen" + String(id) + "Visible"; - bool visible = s["enabled"].as(); + bool visible = s["enabled"].as(); preferences.putBool(prefKey.c_str(), visible); } } - if (settings.containsKey("actCurrencies")) + if (settings["actCurrencies"].is()) { String actCurrencies; @@ -554,10 +553,10 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) } preferences.putString("actCurrencies", actCurrencies.c_str()); - Serial.printf("Set actCurrencies: %s\n", actCurrencies); + Serial.printf("Set actCurrencies: %s\n", actCurrencies.c_str()); } - if (settings.containsKey("txPower")) + if (settings["txPower"].is()) { int txPower = settings["txPower"].as(); @@ -918,14 +917,14 @@ void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json) { unsigned int red, green, blue; - if (lights[i].containsKey("red") && lights[i].containsKey("green") && - lights[i].containsKey("blue")) + if (lights[i]["red"].is() && lights[i]["green"].is() && + lights[i]["blue"].is()) { red = lights[i]["red"].as(); green = lights[i]["green"].as(); blue = lights[i]["blue"].as(); } - else if (lights[i].containsKey("hex")) + else if (lights[i]["hex"].is()) { if (!sscanf(lights[i]["hex"].as().c_str(), "#%02X%02X%02X", &red, &green, &blue) == 3) From 03dbb8add68d8b361b434462d7deb9b84731aa76 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 21 Dec 2024 00:50:57 +0100 Subject: [PATCH 075/130] Small improvements for epd --- src/lib/epd.cpp | 141 ++++++++++++++---------------------------------- 1 file changed, 40 insertions(+), 101 deletions(-) diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 260f772..9b5bfd1 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -138,6 +138,9 @@ uint8_t qrcode[800]; #define EPD_TASK_STACK_SIZE 2048 #endif +#define BUSY_TIMEOUT_COUNT 200 +#define BUSY_RETRY_DELAY pdMS_TO_TICKS(10) + void forceFullRefresh() { for (uint i = 0; i < NUM_SCREENS; i++) @@ -417,89 +420,36 @@ void splitText(const uint dispNum, const String &top, const String &bottom, displays[dispNum].print(bottom); } -// void showChars(const uint dispNum, const String &chars, bool partial, -// const GFXfont *font) -// { -// displays[dispNum].setRotation(2); -// displays[dispNum].setFont(font); -// displays[dispNum].setTextColor(getFgColor()); -// int16_t tbx, tby; -// uint16_t tbw, tbh; +// Consolidate common display setup code into a helper function +void setupDisplay(const uint dispNum, const GFXfont *font) { + displays[dispNum].setRotation(2); + displays[dispNum].setFont(font); + displays[dispNum].setTextColor(getFgColor()); + displays[dispNum].fillScreen(getBgColor()); +} -// displays[dispNum].getTextBounds(chars, 0, 0, &tbx, &tby, &tbw, &tbh); +void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font) { + String str(chr); + if (chr == '.') { + str = "!"; + } + + setupDisplay(dispNum, font); + + int16_t tbx, tby; + uint16_t tbw, tbh; + displays[dispNum].getTextBounds(str, 0, 0, &tbx, &tby, &tbw, &tbh); -// // center the bounding box by transposition of the origin: -// uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx; -// uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby; + uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx; + uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby; -// displays[dispNum].fillScreen(getBgColor()); + displays[dispNum].setCursor(x, y); + displays[dispNum].print(str); -// displays[dispNum].setCursor(x, y); -// displays[dispNum].print(chars); - -// // displays[dispNum].setCursor(10, 3); -// // displays[dispNum].setFont(&FONT_SMALL); -// // displays[dispNum].setTextColor(getFgColor()); -// // displays[dispNum].println("Y = " + y); -// } - -void showDigit(const uint dispNum, char chr, bool partial, - const GFXfont *font) -{ - String str(chr); - - if (chr == '.') - { - str = "!"; - } - displays[dispNum].setRotation(2); - displays[dispNum].setFont(font); - displays[dispNum].setTextColor(getFgColor()); - int16_t tbx, tby; - uint16_t tbw, tbh; - - displays[dispNum].getTextBounds(str, 0, 0, &tbx, &tby, &tbw, &tbh); - - // center the bounding box by transposition of the origin: - uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx; - uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby; - - // if (str.equals(".")) - // { - // // int16_t yAdvance = font->yAdvance; - // // uint8_t charIndex = 46 - font->first; - // // GFXglyph *glyph = (&font->glyph)[charIndex]; - // int16_t tbx2, tby2; - // uint16_t tbw2, tbh2; - // displays[dispNum].getTextBounds(".!", 0, 0, &tbx2, &tby2, &tbw2, &tbh2); - - // y = ((displays[dispNum].height() - tbh2) / 2) - tby2; - // // Serial.print("yAdvance"); - // // Serial.println(yAdvance); - // // if (glyph != nullptr) { - // // Serial.print("height"); - // // Serial.println(glyph->height); - // // Serial.print("yOffset"); - // // Serial.println(glyph->yOffset); - // // } - - // // y = 250-99+18+19; - // } - - displays[dispNum].fillScreen(getBgColor()); - - displays[dispNum].setCursor(x, y); - displays[dispNum].print(str); - - if (chr == '.') - { - displays[dispNum].fillRect(x, y, displays[dispNum].width(), round(displays[dispNum].height() * 0.9), getBgColor()); - } - - // displays[dispNum].setCursor(10, 3); - // displays[dispNum].setFont(&FONT_SMALL); - // displays[dispNum].setTextColor(getFgColor()); - // displays[dispNum].println("Y = " + y); + if (chr == '.') { + displays[dispNum].fillRect(x, y, displays[dispNum].width(), + round(displays[dispNum].height() * 0.9), getBgColor()); + } } int16_t calculateDescent(const GFXfont *font) { @@ -517,21 +467,16 @@ int16_t calculateDescent(const GFXfont *font) { void showChars(const uint dispNum, const String &chars, bool partial, const GFXfont *font) { - displays[dispNum].setRotation(2); - displays[dispNum].setFont(font); - displays[dispNum].setTextColor(getFgColor()); + setupDisplay(dispNum, font); + + int16_t tbx, tby; uint16_t tbw, tbh; displays[dispNum].getTextBounds(chars, 0, 0, &tbx, &tby, &tbw, &tbh); - int16_t descent = calculateDescent(font); - // center the bounding box by transposition of the origin: uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx; uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby; - displays[dispNum].fillScreen(getBgColor()); - // displays[dispNum].setCursor(x, y); - // displays[dispNum].print(chars); for (int i = 0; i < chars.length(); i++) { char c = chars[i]; @@ -603,8 +548,8 @@ bool renderIcon(const uint dispNum, const String &text, bool partial) displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), displays[dispNum].height()); - displays[dispNum].fillScreen(getBgColor()); - displays[dispNum].setTextColor(getFgColor()); + displays[dispNum].fillScreen(getBgColor()); + displays[dispNum].setTextColor(getFgColor()); uint iconIndex = 0; uint width = 122; @@ -649,9 +594,6 @@ bool renderIcon(const uint dispNum, const String &text, bool partial) } - - - void renderQr(const uint dispNum, const String &text, bool partial) { #ifdef USE_QR @@ -695,15 +637,12 @@ void waitUntilNoneBusy() while (EPD_BUSY[i].digitalRead()) { count++; - vTaskDelay(10); - if (count == 200) - { - // displays[i].init(0, false); - vTaskDelay(100); - } - else if (count > 205) - { - Serial.printf("Busy timeout %d", i); + vTaskDelay(BUSY_RETRY_DELAY); + + if (count == BUSY_TIMEOUT_COUNT) { + vTaskDelay(pdMS_TO_TICKS(100)); + } else if (count > BUSY_TIMEOUT_COUNT + 5) { + log_e("Display %d busy timeout", i); break; } } From 9889e983eca45b9808eac76aedc73683bcce2967 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 21 Dec 2024 00:51:26 +0100 Subject: [PATCH 076/130] Update WebUI --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index fd328d4..924be8f 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit fd328d4f05345eaa73cf27d05bb542eaa6915cdb +Subproject commit 924be8fc2eb02fe384a20b53da1a9fa3d8db8a05 From 8a818c66a063e9c2e8fe4eab86841e902fb76cfa Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 21 Dec 2024 01:15:59 +0100 Subject: [PATCH 077/130] Update readme --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 71d3319..1962434 100644 --- a/README.md +++ b/README.md @@ -16,21 +16,21 @@ Biggest differences with v2 are: New features: - BitAxe integration -- Zap notifier -- Braiins Pool and Ocean mining stats integration +- Nostr Zap notifier +- Multiple mining pool stats integrations "Steal focus on new block" means that when a new block is mined, the display will switch to the block height screen if it's not on it already. -Most [information](https://github.com/btclock/btclock_v2/wiki) about BTClock v2 is still valid for this version. +See the [docs](https://git.btclock.dev/btclock/docs) repo for more information and building instructions. **NOTE**: The software assumes that the hardware is run in a controlled private network. ~~The Web UI and the OTA update mechanism are not password protected and accessible to anyone in the network. Also, since the device only fetches numbers through WebSockets it will skip server certificate verification to save resources.~~ Since 3.2.0 the WebUI is password protectable and all certificates are verified. OTA update mechanism is not password-protected. ## Building -Use PlatformIO to build it yourself. Make sure you fetch the [WebUI](https://github.com/btclock/webui) submodule. +Use PlatformIO to build it yourself. Make sure you fetch the [WebUI](https://git.btclock.dev/btclock/webui) submodule. -## Braiins Pool and Ocean integration +## Mining pool stats Enable mining pool stats by accessing your btclock's web UI (point a web browser at the device's IP address). Under Settings -> Extra Features: toggle Enable Mining Pool Stats. @@ -41,6 +41,8 @@ The Mining Pool Earnings screen displays: * Braiins: Today's mining reward thus far * Ocean: Your estimated earnings if the pool were to find a block right now +For solo mining pools, there are no earning estimations. Your username is the onchain withdrawal address, without the worker name. + ### Braiins Pool integration Create an API key based on the steps [here](https://academy.braiins.com/en/braiins-pool/monitoring/#api-configuration). From 4fdd6b6b4fe7387e7e6a99d855c31c3d2bb98c77 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 21 Dec 2024 17:36:07 +0100 Subject: [PATCH 078/130] Fix button handling --- src/lib/button_handler.cpp | 58 +++++++++++++++++++++++--------------- src/lib/button_handler.hpp | 7 +++++ src/lib/config.cpp | 46 +++++++++++++++--------------- 3 files changed, 66 insertions(+), 45 deletions(-) diff --git a/src/lib/button_handler.cpp b/src/lib/button_handler.cpp index 72f1eaa..c2f2a21 100644 --- a/src/lib/button_handler.cpp +++ b/src/lib/button_handler.cpp @@ -19,41 +19,52 @@ TickType_t lastDebounceTime = 0; void buttonTask(void *parameter) { while (1) { ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - std::lock_guard lock(mcpMutex); - + TickType_t currentTime = xTaskGetTickCount(); - + if ((currentTime - lastDebounceTime) >= debounceDelay) { lastDebounceTime = currentTime; - + + std::lock_guard lock(mcpMutex); + if (!digitalRead(MCP_INT_PIN)) { - uint pin = mcp1.getInterruptFlagRegister(); - - switch (pin) { - case BTN_1: - toggleTimerActive(); - break; - case BTN_2: - nextScreen(); - break; - case BTN_3: - previousScreen(); - break; - case BTN_4: - showSystemStatusScreen(); - break; - } + uint16_t intFlags = mcp1.getInterruptFlagRegister(); + uint16_t intCap = mcp1.getInterruptCaptureRegister(); + + // Check each button individually + if (intFlags & BTN_1) handleButton1(); + if (intFlags & BTN_2) handleButton2(); + if (intFlags & BTN_3) handleButton3(); + if (intFlags & BTN_4) handleButton4(); } - mcp1.getInterruptCaptureRegister(); - } else { } - // Very ugly, but for some reason this is necessary + + // Clear interrupt state while (!digitalRead(MCP_INT_PIN)) { + std::lock_guard lock(mcpMutex); mcp1.getInterruptCaptureRegister(); + delay(1); // Small delay to prevent tight loop } } } +// Helper functions to handle each button +void handleButton1() { + toggleTimerActive(); +} + +void handleButton2() { + nextScreen(); +} + +void handleButton3() { + previousScreen(); +} + +void handleButton4() { + showSystemStatusScreen(); +} + void IRAM_ATTR handleButtonInterrupt() { BaseType_t xHigherPriorityTaskWoken = pdFALSE; xTaskNotifyFromISR(buttonTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken); @@ -67,4 +78,5 @@ void setupButtonTask() { &buttonTaskHandle); // Create the FreeRTOS task // Use interrupt instead of task attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, CHANGE); + Serial.printf("Button task created\n"); } diff --git a/src/lib/button_handler.hpp b/src/lib/button_handler.hpp index 9f28d33..ed8ae38 100644 --- a/src/lib/button_handler.hpp +++ b/src/lib/button_handler.hpp @@ -8,6 +8,13 @@ extern TaskHandle_t buttonTaskHandle; +// Task and setup functions void buttonTask(void *pvParameters); void IRAM_ATTR handleButtonInterrupt(); void setupButtonTask(); + +// Individual button handlers +void handleButton1(); +void handleButton2(); +void handleButton3(); +void handleButton4(); diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 9feb9a9..08f645e 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -466,32 +466,34 @@ void setupHardware() Wire.begin(I2C_SDA_PIN, I2C_SCK_PIN, 400000); - if (!mcp1.begin()) - { + if (!mcp1.begin()) { Serial.println(F("Error MCP23017 1")); - - // while (1) - // ; - } - else - { + } else { pinMode(MCP_INT_PIN, INPUT_PULLUP); -// mcp1.setupInterrupts(false, false, LOW); - mcp1.enableControlRegister(MCP23x17_IOCR_ODR); - - mcp1.mirrorInterrupts(true); - - for (int i = 0; i < 4; i++) - { - mcp1.pinMode1(i, INPUT_PULLUP); - mcp1.enableInterrupt(i, LOW); + + // Enable mirrored interrupts (both INTA and INTB pins signal any interrupt) + if (!mcp1.mirrorInterrupts(true)) { + Serial.println(F("Error setting up mirrored interrupts")); } -#ifndef IS_BTCLOCK_V8 - for (int i = 8; i <= 14; i++) - { - mcp1.pinMode1(i, OUTPUT); + + // Configure all 4 button pins as inputs with pullups and interrupts + for (int i = 0; i < 4; i++) { + if (!mcp1.pinMode1(i, INPUT_PULLUP)) { + Serial.printf("Error setting pin %d to input pull up\n", i); + } + // Enable interrupt on CHANGE for each pin + if (!mcp1.enableInterrupt(i, CHANGE)) { + Serial.printf("Error enabling interrupt for pin %d\n", i); + } } -#endif + + // Set interrupt pins as open drain with active-low polarity + if (!mcp1.setInterruptPolarity(2)) { // 2 = Open drain + Serial.println(F("Error setting interrupt polarity")); + } + + // Clear any pending interrupts + mcp1.getInterruptCaptureRegister(); } #ifdef IS_HW_REV_B From c44626cb42b8341aedd4d4cc3d4259acb53e6131 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 21 Dec 2024 17:46:10 +0100 Subject: [PATCH 079/130] Unclutter main.cpp --- src/main.cpp | 252 ++++++++++++++++++++++++--------------------------- 1 file changed, 116 insertions(+), 136 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index b9d2ae7..845de01 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,152 +22,132 @@ uint wifiLostConnection; uint priceNotifyLostConnection = 0; uint blockNotifyLostConnection = 0; -// char ptrTaskList[1500]; -extern "C" void app_main() -{ +int64_t getUptime() { + return esp_timer_get_time() / 1000000; +} + +void handlePriceNotifyDisconnection() { + if (priceNotifyLostConnection == 0) { + priceNotifyLostConnection = getUptime(); + Serial.println(F("Lost price notification connection, trying to reconnect...")); + } + + if ((getUptime() - priceNotifyLostConnection) > 300) { // 5 minutes timeout + Serial.println(F("Price notification connection lost for 5 minutes, restarting handler...")); + restartPriceNotify(); + priceNotifyLostConnection = 0; + } +} + +void handleBlockNotifyDisconnection() { + if (blockNotifyLostConnection == 0) { + blockNotifyLostConnection = getUptime(); + Serial.println(F("Lost block notification connection, trying to reconnect...")); + } + + if ((getUptime() - blockNotifyLostConnection) > 300) { // 5 minutes timeout + Serial.println(F("Block notification connection lost for 5 minutes, restarting handler...")); + restartBlockNotify(); + blockNotifyLostConnection = 0; + } +} + +void handleFrontlight() { +#ifdef HAS_FRONTLIGHT + if (hasLightLevel() && preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE) != 0) { + uint lightLevel = getLightLevel(); + uint luxThreshold = preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE); + + if (lightLevel <= 1 && preferences.getBool("flOffWhenDark", DEFAULT_FL_OFF_WHEN_DARK)) { + if (frontlightIsOn()) frontlightFadeOutAll(); + } else if (lightLevel < luxThreshold && !frontlightIsOn()) { + frontlightFadeInAll(); + } else if (frontlightIsOn() && lightLevel > luxThreshold) { + frontlightFadeOutAll(); + } + } +#endif +} + +void checkWiFiConnection() { + if (!WiFi.isConnected()) { + if (!wifiLostConnection) { + wifiLostConnection = getUptime(); + Serial.println(F("Lost WiFi connection, trying to reconnect...")); + } + if ((getUptime() - wifiLostConnection) > 600) { + Serial.println(F("Still no connection after 10 minutes, restarting...")); + delay(2000); + ESP.restart(); + } + WiFi.begin(); + } else if (wifiLostConnection) { + wifiLostConnection = 0; + Serial.println(F("Connection restored, reset timer.")); + } +} + +void checkMissedBlocks() { + Serial.println(F("Long time (45 min) since last block, checking if I missed anything...")); + int currentBlock = getBlockFetch(); + if (currentBlock != -1) { + if (currentBlock != getBlockHeight()) { + Serial.println(F("Detected stuck block height... restarting block handler.")); + restartBlockNotify(); + } + setLastBlockUpdate(getUptime()); + } +} + + +void monitorDataConnections() { + // Price notification monitoring + if (getPriceNotifyInit() && !preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE) && !isPriceNotifyConnected()) { + handlePriceNotifyDisconnection(); + } else if (priceNotifyLostConnection > 0 && isPriceNotifyConnected()) { + priceNotifyLostConnection = 0; + } + + // Block notification monitoring + if (getBlockNotifyInit() && !isBlockNotifyConnected()) { + handleBlockNotifyDisconnection(); + } else if (blockNotifyLostConnection > 0 && isBlockNotifyConnected()) { + blockNotifyLostConnection = 0; + } + + // Check for missed price updates + if ((getLastPriceUpdate(CURRENCY_USD) - getUptime()) > (preferences.getUInt("minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE) * 5)) { + Serial.println(F("Detected 5 missed price updates... restarting price handler.")); + restartPriceNotify(); + priceNotifyLostConnection = 0; + } + + // Check for missed blocks + if ((getLastBlockUpdate() - getUptime()) > 45 * 60) { + checkMissedBlocks(); + } +} + +extern "C" void app_main() { initArduino(); - Serial.begin(115200); setup(); - while (true) - { - // vTaskList(ptrTaskList); - // Serial.println(F("**********************************")); - // Serial.println(F("Task State Prio Stack Num")); - // Serial.println(F("**********************************")); - // Serial.print(ptrTaskList); - // Serial.println(F("**********************************")); - if (eventSourceTaskHandle != NULL) + while (true) { + if (eventSourceTaskHandle != NULL) { xTaskNotifyGive(eventSourceTaskHandle); + } - int64_t currentUptime = esp_timer_get_time() / 1000000; - ; - - if (!getIsOTAUpdating()) - { -#ifdef HAS_FRONTLIGHT - if (hasLightLevel()) { - if (preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE) != 0) - { - if (hasLightLevel() && getLightLevel() <= 1 && preferences.getBool("flOffWhenDark", DEFAULT_FL_OFF_WHEN_DARK)) - { - if (frontlightIsOn()) { - frontlightFadeOutAll(); - } - } - else if (hasLightLevel() && getLightLevel() < preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE) && !frontlightIsOn()) - { - frontlightFadeInAll(); - } - else if (frontlightIsOn() && getLightLevel() > preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE)) - { - frontlightFadeOutAll(); - } - } - } -#endif + if (!getIsOTAUpdating()) { + handleFrontlight(); + checkWiFiConnection(); + monitorDataConnections(); - if (!WiFi.isConnected()) - { - if (!wifiLostConnection) - { - wifiLostConnection = currentUptime; - Serial.println(F("Lost WiFi connection, trying to reconnect...")); - } - - if ((currentUptime - wifiLostConnection) > 600) - { - Serial.println(F("Still no connection after 10 minutes, restarting...")); - delay(2000); - ESP.restart(); - } - - WiFi.begin(); - } - else if (wifiLostConnection) - { - wifiLostConnection = 0; - Serial.println(F("Connection restored, reset timer.")); - } - - if (getPriceNotifyInit() && !preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE) && !isPriceNotifyConnected()) - { - priceNotifyLostConnection++; - Serial.println(F("Lost price data connection...")); - queueLedEffect(LED_DATA_PRICE_ERROR); - - // if price WS connection does not come back after 6*5 seconds, destroy and recreate - if (priceNotifyLostConnection > 6) - { - Serial.println(F("Restarting price handler...")); - - restartPriceNotify(); - // setupPriceNotify(); - priceNotifyLostConnection = 0; - } - } - else if (priceNotifyLostConnection > 0 && isPriceNotifyConnected()) - { - priceNotifyLostConnection = 0; - } - - if (getBlockNotifyInit() && !isBlockNotifyConnected()) - { - blockNotifyLostConnection++; - Serial.println(F("Lost block data connection...")); - queueLedEffect(LED_DATA_BLOCK_ERROR); - // if mempool WS connection does not come back after 6*5 seconds, destroy and recreate - if (blockNotifyLostConnection > 6) - { - Serial.println(F("Restarting block handler...")); - - restartBlockNotify(); - // setupBlockNotify(); - blockNotifyLostConnection = 0; - } - } - else if (blockNotifyLostConnection > 0 && isBlockNotifyConnected()) - { - blockNotifyLostConnection = 0; - } - - // if more than 5 price updates are missed, there is probably something wrong, reconnect - if ((getLastPriceUpdate(CURRENCY_USD) - currentUptime) > (preferences.getUInt("minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE) * 5)) - { - Serial.println(F("Detected 5 missed price updates... restarting price handler.")); - - restartPriceNotify(); - // setupPriceNotify(); - - priceNotifyLostConnection = 0; - } - - // If after 45 minutes no mempool blocks, check the rest API - if ((getLastBlockUpdate() - currentUptime) > 45 * 60) - { - Serial.println(F("Long time (45 min) since last block, checking if I missed anything...")); - int currentBlock = getBlockFetch(); - if (currentBlock != -1) - { - if (currentBlock != getBlockHeight()) - { - Serial.println(F("Detected stuck block height... restarting block handler.")); - // Mempool source stuck, restart - restartBlockNotify(); - // setupBlockNotify(); - } - // set last block update so it doesn't fetch for 45 minutes - setLastBlockUpdate(currentUptime); - } - } - - if (currentUptime - getLastTimeSync() > 24 * 60 * 60) - { + if (getUptime() - getLastTimeSync() > 24 * 60 * 60) { Serial.println(F("Last time update is longer than 24 hours ago, sync again")); syncTime(); - }; + } } vTaskDelay(pdMS_TO_TICKS(5000)); From 957a947bc5e81565b9fb7fa422c347897ec7b50b Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 21 Dec 2024 17:53:35 +0100 Subject: [PATCH 080/130] More clean-up and bugfixes --- src/lib/bitaxe_fetch.cpp | 2 +- src/lib/button_handler.cpp | 1 - src/lib/epd.cpp | 19 ------------------- src/lib/epd.hpp | 1 - src/lib/mining_pool_stats_fetch.cpp | 2 +- 5 files changed, 2 insertions(+), 23 deletions(-) diff --git a/src/lib/bitaxe_fetch.cpp b/src/lib/bitaxe_fetch.cpp index cfb7635..71ab90e 100644 --- a/src/lib/bitaxe_fetch.cpp +++ b/src/lib/bitaxe_fetch.cpp @@ -54,7 +54,7 @@ void taskBitaxeFetch(void *pvParameters) void setupBitaxeFetchTask() { - xTaskCreate(taskBitaxeFetch, "bitaxeFetch", (6 * 1024), NULL, tskIDLE_PRIORITY, + xTaskCreate(taskBitaxeFetch, "bitaxeFetch", (3 * 1024), NULL, tskIDLE_PRIORITY, &bitaxeFetchTaskHandle); xTaskNotifyGive(bitaxeFetchTaskHandle); diff --git a/src/lib/button_handler.cpp b/src/lib/button_handler.cpp index c2f2a21..61e6c6d 100644 --- a/src/lib/button_handler.cpp +++ b/src/lib/button_handler.cpp @@ -78,5 +78,4 @@ void setupButtonTask() { &buttonTaskHandle); // Create the FreeRTOS task // Use interrupt instead of task attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, CHANGE); - Serial.printf("Button task created\n"); } diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 9b5bfd1..528db1d 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -149,25 +149,6 @@ void forceFullRefresh() } } -void refreshFromMemory() -{ - for (uint i = 0; i < NUM_SCREENS; i++) - { - int *taskParam = new int; - *taskParam = i; - - xTaskCreate( - [](void *pvParameters) - { - const int epdIndex = *(int *)pvParameters; - delete (int *)pvParameters; - displays[epdIndex].refresh(false); - vTaskDelete(NULL); - }, - "PrepareUpd", 4096, taskParam, tskIDLE_PRIORITY, NULL); - } -} - void setupDisplays() { std::lock_guard lockMcp(mcpMutex); diff --git a/src/lib/epd.hpp b/src/lib/epd.hpp index c267047..35fcdd3 100644 --- a/src/lib/epd.hpp +++ b/src/lib/epd.hpp @@ -26,7 +26,6 @@ typedef struct { } UpdateDisplayTaskItem; void forceFullRefresh(); -void refreshFromMemory(); void setupDisplays(); void splitText(const uint dispNum, const String &top, const String &bottom, diff --git a/src/lib/mining_pool_stats_fetch.cpp b/src/lib/mining_pool_stats_fetch.cpp index 3f870bb..b8fed5c 100644 --- a/src/lib/mining_pool_stats_fetch.cpp +++ b/src/lib/mining_pool_stats_fetch.cpp @@ -93,7 +93,7 @@ void setupMiningPoolStatsFetchTask() "logoDownload", (6 * 1024), NULL, - 12, + tskIDLE_PRIORITY, NULL); xTaskCreate(taskMiningPoolStatsFetch, From 66c662e1fdf5ccfa072aac951a9fe8fd6abdffbd Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 26 Dec 2024 21:43:50 +0100 Subject: [PATCH 081/130] Use own nostrduino fork, improve nostr code, WebUI update --- data | 2 +- platformio.ini | 8 +- src/lib/nostr_notify.cpp | 223 ++++++++++++++++++++++----------------- 3 files changed, 132 insertions(+), 101 deletions(-) diff --git a/data b/data index 924be8f..65b6df5 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 924be8fc2eb02fe384a20b53da1a9fa3d8db8a05 +Subproject commit 65b6df5d92f3f936e823a5c1413681aee85ab0c5 diff --git a/platformio.ini b/platformio.ini index be29cbe..90f1cc0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -43,7 +43,7 @@ lib_deps = https://github.com/dsbaars/universal_pin#feature/mcp23017_rt https://github.com/dsbaars/GxEPD2#universal_pin https://github.com/tzapu/WiFiManager.git#v2.0.17 - rblb/Nostrduino@1.2.8 + https://github.com/dsbaars/nostrduino#feature/fix-btclock [env:lolin_s3_mini] extends = btclock_base @@ -71,7 +71,11 @@ board = btclock_rev_b board_build.partitions = partition_8mb.csv build_flags = ${btclock_base.build_flags} - -D MCP_INT_PIN=8 + -D MCP_INT_PIN=8docker run --rm -e RENOVATE_TOKEN -e LOG_LEVEL=debug \ + -e "RENOVATE_REPOSITORIES=[\"your-repo-name\"]" \ + renovate/renovate \ + --platform local \ + --dry-run -D NEOPIXEL_PIN=15 -D NEOPIXEL_COUNT=4 -D NUM_SCREENS=7 diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index bad593d..d19002c 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -27,8 +27,8 @@ void setupNostrNotify(bool asDatasource, bool zapNotify) String pubKey = preferences.getString("nostrPubKey"); pools.push_back(pool); - std::vector>> filters; - + std::vector *relays = pool->getConnectedRelays(); + if (zapNotify) { subscribeZaps(pool, relay, 60); @@ -46,31 +46,29 @@ void setupNostrNotify(bool asDatasource, bool zapNotify) }}, handleNostrEventCallback, onNostrSubscriptionClosed, - onNostrSubscriptionEose); + onNostrSubscriptionEose + ); - Serial.println("[ Nostr ] Subscribing to Nostr Data Feed"); + Serial.println(F("[ Nostr ] Subscribing to Nostr Data Feed")); } - std::vector *relays = pool->getConnectedRelays(); for (nostr::NostrRelay *relay : *relays) { Serial.println("[ Nostr ] Registering to connection events of: " + relay->getUrl()); - relay->getConnection()->addConnectionStatusListener([&](const nostr::ConnectionStatus &status) - { - String sstatus="UNKNOWN"; - if(status==nostr::ConnectionStatus::CONNECTED){ - nostrIsConnected = true; - sstatus="CONNECTED"; - }else if(status==nostr::ConnectionStatus::DISCONNECTED){ - nostrIsConnected = false; + relay->getConnection()->addConnectionStatusListener([](const nostr::ConnectionStatus &status) + { + static const char* STATUS_STRINGS[] = {"UNKNOWN", "CONNECTED", "DISCONNECTED", "ERROR"}; + int statusIndex = static_cast(status); + + nostrIsConnected = (status == nostr::ConnectionStatus::CONNECTED); + if (!nostrIsConnected) { nostrIsSubscribed = false; - sstatus="DISCONNECTED"; - }else if(status==nostr::ConnectionStatus::ERROR){ - sstatus = "ERROR"; } - Serial.println("[ Nostr ] Connection status changed: " + sstatus); - }); + + Serial.println("[ Nostr ] Connection status changed: " + String(STATUS_STRINGS[statusIndex])); + }); } + } catch (const std::exception &e) { @@ -103,7 +101,7 @@ void nostrTask(void *pvParameters) void setupNostrTask() { - xTaskCreate(nostrTask, "nostrTask", 16384, NULL, 10, &nostrTaskHandle); + xTaskCreate(nostrTask, "nostrTask", 8192, NULL, 10, &nostrTaskHandle); } boolean nostrConnected() @@ -129,55 +127,57 @@ void onNostrSubscriptionEose(const String &subId) void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *event) { - // Received events callback, we can access the event content with - // event->getContent() Here you should handle the event, for this - // test we will just serialize it and print to console JsonDocument doc; JsonArray arr = doc["data"].to(); event->toSendableEvent(arr); - // Access the second element which is the object + + // Early return if array is invalid + if (arr.size() < 2 || !arr[1].is()) { + return; + } + JsonObject obj = arr[1].as(); JsonArray tags = obj["tags"].as(); + if (!tags) { + return; + } - // Flag to check if the tag was found - bool tagFound = false; - uint medianFee = 0; + // Use direct value access instead of multiple comparisons String typeValue; - - // Iterate over the tags array - for (JsonArray tag : tags) - { - // Check if the tag is an array with two elements - if (tag.size() == 2) - { - const char *key = tag[0]; - const char *value = tag[1]; - - // Check if the key is "type" and the value is "priceUsd" - if (strcmp(key, "type") == 0 && (strcmp(value, "priceUsd") == 0 || strcmp(value, "blockHeight") == 0)) - { - typeValue = value; - tagFound = true; - } - else if (strcmp(key, "medianFee") == 0) - { - medianFee = tag[1].as(); - } + uint medianFee = 0; + + for (JsonArray tag : tags) { + if (tag.size() != 2) continue; + + const char *key = tag[0]; + if (!key) continue; + + // Use switch for better performance on string comparisons + switch (key[0]) { + case 't': // type + if (strcmp(key, "type") == 0) { + const char *value = tag[1]; + if (value) typeValue = value; + } + break; + case 'm': // medianFee + if (strcmp(key, "medianFee") == 0) { + medianFee = tag[1].as(); + } + break; } } - if (tagFound) - { - if (typeValue.equals("priceUsd")) - { + + // Process the data + if (!typeValue.isEmpty()) { + if (typeValue == "priceUsd") { processNewPrice(obj["content"].as(), CURRENCY_USD); } - else if (typeValue.equals("blockHeight")) - { + else if (typeValue == "blockHeight") { processNewBlock(obj["content"].as()); } - if (medianFee != 0) - { + if (medianFee != 0) { processNewBlockFee(medianFee); } } @@ -202,7 +202,27 @@ void subscribeZaps(nostr::NostrPool *pool, const String &relay, int minutesAgo) {"kinds", {"9735"}}, {"limit", {"1"}}, {"since", {String(getMinutesAgo(minutesAgo))}}, - {"#p", {preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY)}}, + {"#p", {preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY) }}, + // {"#p", [&]() { + // std::initializer_list pubkeys; + // String pubkeysStr = preferences.getString("nostrZapPubkeys", ""); + // if (pubkeysStr.length() > 0) { + // // Assuming pubkeys are comma-separated + // char* str = strdup(pubkeysStr.c_str()); + // char* token = strtok(str, ","); + // std::vector keys; + // while (token != NULL) { + // keys.push_back(String(token)); + // token = strtok(NULL, ","); + // } + // free(str); + // return std::initializer_list(keys.begin(), keys.end()); + // } + // // Return default if no pubkeys found + // return std::initializer_list{ + // preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY) + // }; + // }()}, }, }, handleNostrZapCallback, @@ -212,56 +232,63 @@ void subscribeZaps(nostr::NostrPool *pool, const String &relay, int minutesAgo) } void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event) { - // Received events callback, we can access the event content with - // event->getContent() Here you should handle the event, for this - // test we will just serialize it and print to console JsonDocument doc; JsonArray arr = doc["data"].to(); event->toSendableEvent(arr); - // Access the second element which is the object + + // Early return if invalid + if (arr.size() < 2 || !arr[1].is()) { + return; + } + JsonObject obj = arr[1].as(); JsonArray tags = obj["tags"].as(); + if (!tags) { + return; + } - // Iterate over the tags array - for (JsonArray tag : tags) - { - // Check if the tag is an array with two elements - if (tag.size() == 2) - { - const char *key = tag[0]; - const char *value = tag[1]; + uint64_t zapAmount = 0; + String zapPubkey; + + for (JsonArray tag : tags) { + if (tag.size() != 2) continue; + + const char *key = tag[0]; + const char *value = tag[1]; + if (!key || !value) continue; - if (strcmp(key, "bolt11") == 0) - { - Serial.print(F("Got a zap of ")); - - int64_t satsAmount = getAmountInSatoshis(std::string(value)); - Serial.print(satsAmount); - Serial.println(F(" sats")); - - std::array textEpdContent = parseZapNotify(satsAmount, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); - - uint64_t timerPeriod = 0; - if (isTimerActive()) - { - // store timer periode before making inactive to prevent artifacts - timerPeriod = getTimerSeconds(); - esp_timer_stop(screenRotateTimer); - } - setCurrentScreen(SCREEN_CUSTOM); - - setEpdContent(textEpdContent); - vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250)); - if (preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP)) - { - queueLedEffect(LED_EFFECT_NOSTR_ZAP); - } - if (timerPeriod > 0) - { - esp_timer_start_periodic(screenRotateTimer, - timerPeriod * usPerSecond); - } - } + if (key[0] == 'b' && strcmp(key, "bolt11") == 0) { + zapAmount = getAmountInSatoshis(std::string(value)); + } + else if (key[0] == 'p' && strcmp(key, "p") == 0) { + zapPubkey = value; } } + + if (zapAmount == 0) return; + + std::array textEpdContent = parseZapNotify(zapAmount, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); + + Serial.printf("Got a zap of %llu sats for %s\n", zapAmount, zapPubkey.c_str()); + + uint64_t timerPeriod = 0; + if (isTimerActive()) + { + // store timer periode before making inactive to prevent artifacts + timerPeriod = getTimerSeconds(); + esp_timer_stop(screenRotateTimer); + } + setCurrentScreen(SCREEN_CUSTOM); + + setEpdContent(textEpdContent); + vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250)); + if (preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP)) + { + queueLedEffect(LED_EFFECT_NOSTR_ZAP); + } + if (timerPeriod > 0) + { + esp_timer_start_periodic(screenRotateTimer, + timerPeriod * usPerSecond); + } } \ No newline at end of file From 698c3a3a437d9e97e9855b60175975639813d3c9 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 26 Dec 2024 22:20:30 +0100 Subject: [PATCH 082/130] More code optimizations, remove unnecessary checks --- src/lib/led_handler.cpp | 21 +++++++++------------ src/lib/led_handler.hpp | 2 +- src/lib/nostr_notify.cpp | 4 +--- src/lib/v2_notify.cpp | 8 +++++--- src/main.cpp | 9 ++++++++- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/lib/led_handler.cpp b/src/lib/led_handler.cpp index 338c3c3..c2c56f4 100644 --- a/src/lib/led_handler.cpp +++ b/src/lib/led_handler.cpp @@ -6,7 +6,7 @@ Adafruit_NeoPixel pixels(NEOPIXEL_COUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800); uint ledTaskParams; #ifdef HAS_FRONTLIGHT -#define FL_FADE_STEP 25 +constexpr uint16_t FL_FADE_STEP = 25; bool frontlightOn = false; bool flInTransition = false; @@ -68,18 +68,15 @@ void frontlightFadeInAll(int flDelayTime) void frontlightFadeInAll(int flDelayTime, bool staggered) { - if (preferences.getBool("flDisable")) - return; - if (frontlightIsOn()) - return; - if (flInTransition) + if (preferences.getBool("flDisable") || frontlightIsOn() || flInTransition) return; flInTransition = true; + const int maxBrightness = preferences.getUInt("flMaxBrightness"); + if (staggered) { - int maxBrightness = preferences.getUInt("flMaxBrightness"); int step = FL_FADE_STEP; int staggerDelay = flDelayTime / NUM_SCREENS; @@ -100,7 +97,7 @@ void frontlightFadeInAll(int flDelayTime, bool staggered) } else { - for (int dutyCycle = 0; dutyCycle <= preferences.getUInt("flMaxBrightness"); dutyCycle += FL_FADE_STEP) + for (int dutyCycle = 0; dutyCycle <= maxBrightness; dutyCycle += FL_FADE_STEP) { for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) { @@ -179,7 +176,7 @@ std::vector frontlightGetStatus() return statuses; } -bool frontlightIsOn() +inline bool frontlightIsOn() { return frontlightOn; } @@ -225,7 +222,7 @@ void ledTask(void *parameter) continue; } - uint32_t oldLights[NEOPIXEL_COUNT]; + std::array oldLights; // get current state for (int i = 0; i < NEOPIXEL_COUNT; i++) @@ -498,7 +495,7 @@ void blinkDelay(int d, int times) pixels.show(); } -void blinkDelayColor(int d, int times, uint r, uint g, uint b) +void blinkDelayColor(int d, int times, uint r, uint g, uint b) { for (int j = 0; j < times; j++) { @@ -518,7 +515,7 @@ void blinkDelayColor(int d, int times, uint r, uint g, uint b) pixels.show(); } -void blinkDelayTwoColor(int d, int times, uint32_t c1, uint32_t c2) +void blinkDelayTwoColor(int d, int times, const uint32_t& c1, const uint32_t& c2) { for (int j = 0; j < times; j++) { diff --git a/src/lib/led_handler.hpp b/src/lib/led_handler.hpp index b86475e..98d8834 100644 --- a/src/lib/led_handler.hpp +++ b/src/lib/led_handler.hpp @@ -49,7 +49,7 @@ void setupLeds(); void setupLedTask(); void blinkDelay(int d, int times); void blinkDelayColor(int d, int times, uint r, uint g, uint b); -void blinkDelayTwoColor(int d, int times, uint32_t c1, uint32_t c2); +void blinkDelayTwoColor(int d, int times, const uint32_t& c1, const uint32_t& c2); void clearLeds(); void saveLedState(); void restoreLedState(); diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index d19002c..a919e0e 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -63,9 +63,7 @@ void setupNostrNotify(bool asDatasource, bool zapNotify) nostrIsConnected = (status == nostr::ConnectionStatus::CONNECTED); if (!nostrIsConnected) { nostrIsSubscribed = false; - } - - Serial.println("[ Nostr ] Connection status changed: " + String(STATUS_STRINGS[statusIndex])); + } }); } diff --git a/src/lib/v2_notify.cpp b/src/lib/v2_notify.cpp index 33104a5..e0b5966 100644 --- a/src/lib/v2_notify.cpp +++ b/src/lib/v2_notify.cpp @@ -34,11 +34,12 @@ namespace V2Notify switch (type) { case WStype_DISCONNECTED: - Serial.printf("[WSc] Disconnected!\n"); + Serial.print(F("[WSc] Disconnected!\n")); break; case WStype_CONNECTED: { - Serial.printf("[WSc] Connected to url: %s\n", payload); + Serial.print(F("[WSc] Connected to url:")); + Serial.println((char *)payload); JsonDocument response; @@ -81,7 +82,8 @@ namespace V2Notify break; } case WStype_TEXT: - Serial.printf("[WSc] get text: %s\n", payload); + Serial.print(F("[WSc] get text: ")); + Serial.println((char *)payload); // send message to server // webSocket.sendTXT("message here"); diff --git a/src/main.cpp b/src/main.cpp index 845de01..ea24213 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -102,6 +102,7 @@ void checkMissedBlocks() { void monitorDataConnections() { + // Price notification monitoring if (getPriceNotifyInit() && !preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE) && !isPriceNotifyConnected()) { handlePriceNotifyDisconnection(); @@ -134,6 +135,9 @@ extern "C" void app_main() { Serial.begin(115200); setup(); + bool ownDataSource = preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE); + + while (true) { if (eventSourceTaskHandle != NULL) { xTaskNotifyGive(eventSourceTaskHandle); @@ -142,7 +146,10 @@ extern "C" void app_main() { if (!getIsOTAUpdating()) { handleFrontlight(); checkWiFiConnection(); - monitorDataConnections(); + + if (!ownDataSource) { + monitorDataConnections(); + } if (getUptime() - getLastTimeSync() > 24 * 60 * 60) { Serial.println(F("Last time update is longer than 24 hours ago, sync again")); From 17fef80253137d39c08156fd04f4988ee43b8f0f Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 26 Dec 2024 23:08:46 +0100 Subject: [PATCH 083/130] Make ScreenHandler class, fix button handling --- src/lib/bitaxe_fetch.cpp | 2 +- src/lib/block_notify.cpp | 4 +- src/lib/button_handler.cpp | 160 +++++--- src/lib/button_handler.hpp | 34 ++ src/lib/config.cpp | 6 +- src/lib/mining_pool_stats_fetch.cpp | 4 +- src/lib/nostr_notify.cpp | 2 +- src/lib/price_notify.cpp | 6 +- src/lib/screen_handler.cpp | 614 +++++++++++++--------------- src/lib/screen_handler.hpp | 44 +- src/lib/webserver.cpp | 18 +- 11 files changed, 484 insertions(+), 410 deletions(-) diff --git a/src/lib/bitaxe_fetch.cpp b/src/lib/bitaxe_fetch.cpp index 71ab90e..f439cb4 100644 --- a/src/lib/bitaxe_fetch.cpp +++ b/src/lib/bitaxe_fetch.cpp @@ -36,7 +36,7 @@ void taskBitaxeFetch(void *pvParameters) bitaxeHashrate = std::to_string(static_cast(std::round(doc["hashRate"].as()))); bitaxeBestDiff = doc["bestDiff"].as(); - if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BITAXE_HASHRATE || getCurrentScreen() == SCREEN_BITAXE_BESTDIFF)) + if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_BESTDIFF)) { WorkItem priceUpdate = {TASK_BITAXE_UPDATE, 0}; xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index 48989bd..e41fc4b 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -200,7 +200,7 @@ void processNewBlock(uint newBlockHeight) { xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); // xTaskNotifyGive(blockUpdateTaskHandle); - if (getCurrentScreen() != SCREEN_BLOCK_HEIGHT && + if (ScreenHandler::getCurrentScreen() != SCREEN_BLOCK_HEIGHT && preferences.getBool("stealFocus", DEFAULT_STEAL_FOCUS)) { uint64_t timerPeriod = 0; @@ -210,7 +210,7 @@ void processNewBlock(uint newBlockHeight) { timerPeriod = getTimerSeconds(); esp_timer_stop(screenRotateTimer); } - setCurrentScreen(SCREEN_BLOCK_HEIGHT); + ScreenHandler::setCurrentScreen(SCREEN_BLOCK_HEIGHT); if (timerPeriod > 0) { esp_timer_start_periodic(screenRotateTimer, diff --git a/src/lib/button_handler.cpp b/src/lib/button_handler.cpp index 61e6c6d..ff7e259 100644 --- a/src/lib/button_handler.cpp +++ b/src/lib/button_handler.cpp @@ -1,8 +1,7 @@ #include "button_handler.hpp" TaskHandle_t buttonTaskHandle = NULL; -const TickType_t debounceDelay = pdMS_TO_TICKS(50); -TickType_t lastDebounceTime = 0; +ButtonState buttonStates[4]; #ifdef IS_BTCLOCK_V8 #define BTN_1 256 @@ -17,65 +16,134 @@ TickType_t lastDebounceTime = 0; #endif void buttonTask(void *parameter) { - while (1) { - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - + while (1) { + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + TickType_t currentTime = xTaskGetTickCount(); + + std::lock_guard lock(mcpMutex); + + if (!digitalRead(MCP_INT_PIN)) { + uint16_t intFlags = mcp1.getInterruptFlagRegister(); + uint16_t intCap = mcp1.getInterruptCaptureRegister(); + + // Check button states + if (intFlags & BTN_1) handleButtonPress(0); + if (intFlags & BTN_2) handleButtonPress(1); + if (intFlags & BTN_3) handleButtonPress(2); + if (intFlags & BTN_4) handleButtonPress(3); + + // Check for button releases + for (int i = 0; i < 4; i++) { + if (buttonStates[i].isPressed) { + bool currentlyPressed = false; + switch (i) { + case 0: currentlyPressed = (intCap & BTN_1); break; + case 1: currentlyPressed = (intCap & BTN_2); break; + case 2: currentlyPressed = (intCap & BTN_3); break; + case 3: currentlyPressed = (intCap & BTN_4); break; + } + if (!currentlyPressed) { + handleButtonRelease(i); + } + } + } + + // Check for long press on pressed buttons + for (int i = 0; i < 4; i++) { + if (buttonStates[i].isPressed && !buttonStates[i].longPressHandled) { + if ((currentTime - buttonStates[i].pressStartTime) >= longPressDelay) { + handleLongPress(i); + buttonStates[i].longPressHandled = true; + } + } + } + } + + // Clear interrupt state + while (!digitalRead(MCP_INT_PIN)) { + mcp1.getInterruptCaptureRegister(); + delay(1); + } + } +} + +void handleButtonPress(int buttonIndex) { TickType_t currentTime = xTaskGetTickCount(); + ButtonState &state = buttonStates[buttonIndex]; - if ((currentTime - lastDebounceTime) >= debounceDelay) { - lastDebounceTime = currentTime; - - std::lock_guard lock(mcpMutex); - - if (!digitalRead(MCP_INT_PIN)) { - uint16_t intFlags = mcp1.getInterruptFlagRegister(); - uint16_t intCap = mcp1.getInterruptCaptureRegister(); - - // Check each button individually - if (intFlags & BTN_1) handleButton1(); - if (intFlags & BTN_2) handleButton2(); - if (intFlags & BTN_3) handleButton3(); - if (intFlags & BTN_4) handleButton4(); - } + if ((currentTime - state.lastPressTime) >= debounceDelay) { + state.isPressed = true; + state.pressStartTime = currentTime; + state.longPressHandled = false; + + // Check for double click + if ((currentTime - state.lastPressTime) <= doubleClickDelay) { + state.clickCount++; + if (state.clickCount == 2) { + handleDoubleClick(buttonIndex); + state.clickCount = 0; + } + } else { + state.clickCount = 1; + } + + state.lastPressTime = currentTime; } +} + +void handleButtonRelease(int buttonIndex) { + TickType_t currentTime = xTaskGetTickCount(); + ButtonState &state = buttonStates[buttonIndex]; - // Clear interrupt state - while (!digitalRead(MCP_INT_PIN)) { - std::lock_guard lock(mcpMutex); - mcp1.getInterruptCaptureRegister(); - delay(1); // Small delay to prevent tight loop + state.isPressed = false; + + // If this wasn't a long press or double click, handle as single click + if (!state.longPressHandled && state.clickCount == 1 && + (currentTime - state.pressStartTime) < longPressDelay) { + handleSingleClick(buttonIndex); + state.clickCount = 0; } - } } -// Helper functions to handle each button -void handleButton1() { - toggleTimerActive(); +// Button action handlers +void handleSingleClick(int buttonIndex) { + switch (buttonIndex) { + case 0: + toggleTimerActive(); + break; + case 1: + Serial.println("Button 2 single click"); + ScreenHandler::nextScreen(); + break; + case 2: + Serial.println("Button 3 single click"); + ScreenHandler::previousScreen(); + break; + case 3: + ScreenHandler::showSystemStatusScreen(); + break; + } } -void handleButton2() { - nextScreen(); +void handleDoubleClick(int buttonIndex) { + Serial.printf("Button %d double clicked\n", buttonIndex + 1); } -void handleButton3() { - previousScreen(); -} - -void handleButton4() { - showSystemStatusScreen(); +void handleLongPress(int buttonIndex) { + Serial.printf("Button %d long press detected\n", buttonIndex + 1); } void IRAM_ATTR handleButtonInterrupt() { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xTaskNotifyFromISR(buttonTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken == pdTRUE) { - portYIELD_FROM_ISR(); - } + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xTaskNotifyFromISR(buttonTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken); + if (xHigherPriorityTaskWoken == pdTRUE) { + portYIELD_FROM_ISR(); + } } void setupButtonTask() { - xTaskCreate(buttonTask, "ButtonTask", 3072, NULL, tskIDLE_PRIORITY, - &buttonTaskHandle); // Create the FreeRTOS task - // Use interrupt instead of task - attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, CHANGE); + xTaskCreate(buttonTask, "ButtonTask", 3072, NULL, tskIDLE_PRIORITY, + &buttonTaskHandle); + attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, FALLING); } diff --git a/src/lib/button_handler.hpp b/src/lib/button_handler.hpp index ed8ae38..f3f41a1 100644 --- a/src/lib/button_handler.hpp +++ b/src/lib/button_handler.hpp @@ -18,3 +18,37 @@ void handleButton1(); void handleButton2(); void handleButton3(); void handleButton4(); + +// New features +const TickType_t debounceDelay = pdMS_TO_TICKS(50); +const TickType_t doubleClickDelay = pdMS_TO_TICKS(300); // Maximum time between clicks for double click +const TickType_t longPressDelay = pdMS_TO_TICKS(1000); // Time to hold for long press + +// Track timing for each button +struct ButtonState { + TickType_t lastPressTime = 0; + TickType_t pressStartTime = 0; + bool isPressed = false; + uint8_t clickCount = 0; + bool longPressHandled = false; +}; + +extern ButtonState buttonStates[4]; + +#ifdef IS_BTCLOCK_V8 +#define BTN_1 256 +#define BTN_2 512 +#define BTN_3 1024 +#define BTN_4 2048 +#else +#define BTN_1 2048 +#define BTN_2 1024 +#define BTN_3 512 +#define BTN_4 256 +#endif + +void handleButtonPress(int buttonIndex); +void handleButtonRelease(int buttonIndex); +void handleSingleClick(int buttonIndex); +void handleDoubleClick(int buttonIndex); +void handleLongPress(int buttonIndex); diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 08f645e..4ae7e4b 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -285,9 +285,9 @@ void setupPreferences() setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD); if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) - setCurrentCurrency(preferences.getUChar("lastCurrency", CURRENCY_USD)); + ScreenHandler::setCurrentCurrency(preferences.getUChar("lastCurrency", CURRENCY_USD)); else - setCurrentCurrency(CURRENCY_USD); + ScreenHandler::setCurrentCurrency(CURRENCY_USD); if (!preferences.isKey("flDisable")) { preferences.putBool("flDisable", isWhiteVersion() ? false : true); @@ -482,7 +482,7 @@ void setupHardware() Serial.printf("Error setting pin %d to input pull up\n", i); } // Enable interrupt on CHANGE for each pin - if (!mcp1.enableInterrupt(i, CHANGE)) { + if (!mcp1.enableInterrupt(i, FALLING)) { Serial.printf("Error enabling interrupt for pin %d\n", i); } } diff --git a/src/lib/mining_pool_stats_fetch.cpp b/src/lib/mining_pool_stats_fetch.cpp index b8fed5c..9687e03 100644 --- a/src/lib/mining_pool_stats_fetch.cpp +++ b/src/lib/mining_pool_stats_fetch.cpp @@ -57,7 +57,7 @@ void taskMiningPoolStatsFetch(void *pvParameters) miningPoolStatsDailyEarnings = 0; // or any other default value } - if (workQueue != nullptr && (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS)) + if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS)) { WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0}; xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); @@ -78,7 +78,7 @@ void downloadMiningPoolLogoTask(void *pvParameters) { PoolFactory::downloadPoolLogo(poolName, poolInterface.get()); // If we're on the mining pool stats screen, trigger a display update - if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) { + if (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) { WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0}; xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); } diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index a919e0e..20bdd01 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -276,7 +276,7 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event) timerPeriod = getTimerSeconds(); esp_timer_stop(screenRotateTimer); } - setCurrentScreen(SCREEN_CUSTOM); + ScreenHandler::setCurrentScreen(SCREEN_CUSTOM); setEpdContent(textEpdContent); vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250)); diff --git a/src/lib/price_notify.cpp b/src/lib/price_notify.cpp index ab5192b..780f651 100644 --- a/src/lib/price_notify.cpp +++ b/src/lib/price_notify.cpp @@ -133,9 +133,9 @@ void processNewPrice(uint newPrice, char currency) } lastUpdateMap[currency] = currentTime; // if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) { - if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER || - getCurrentScreen() == SCREEN_SATS_PER_CURRENCY || - getCurrentScreen() == SCREEN_MARKET_CAP)) + if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BTC_TICKER || + ScreenHandler::getCurrentScreen() == SCREEN_SATS_PER_CURRENCY || + ScreenHandler::getCurrentScreen() == SCREEN_MARKET_CAP)) { WorkItem priceUpdate = {TASK_PRICE_UPDATE, currency}; xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index ea55e02..8c7213c 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -1,343 +1,315 @@ #include "screen_handler.hpp" -// TaskHandle_t priceUpdateTaskHandle; -// TaskHandle_t blockUpdateTaskHandle; -// TaskHandle_t timeUpdateTaskHandle; TaskHandle_t taskScreenRotateTaskHandle; TaskHandle_t workerTaskHandle; - - -std::array taskEpdContent = {}; -std::string priceString; - -#define WORK_QUEUE_SIZE 10 QueueHandle_t workQueue = NULL; -uint currentScreen = SCREEN_BLOCK_HEIGHT; -uint currentCurrency = CURRENCY_USD; +// Initialize static members +uint ScreenHandler::currentScreen = SCREEN_BLOCK_HEIGHT; +uint ScreenHandler::currentCurrency = CURRENCY_USD; -void workerTask(void *pvParameters) { - WorkItem receivedItem; +std::array taskEpdContent = {}; - while (1) { - // Wait for a work item to be available in the queue - if (xQueueReceive(workQueue, &receivedItem, portMAX_DELAY)) { - // Process the work item based on its type - switch (receivedItem.type) { - case TASK_BITAXE_UPDATE: { - if (getCurrentScreen() == SCREEN_BITAXE_HASHRATE) { - taskEpdContent = - parseBitaxeHashRate(getBitAxeHashRate()); - } else if (getCurrentScreen() == SCREEN_BITAXE_BESTDIFF) { - taskEpdContent = - parseBitaxeBestDiff(getBitaxeBestDiff()); - } - setEpdContent(taskEpdContent); - break; - } - case TASK_MINING_POOL_STATS_UPDATE: { - if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) { - taskEpdContent = - parseMiningPoolStatsHashRate(getMiningPoolStatsHashRate(), *getMiningPool()); - } else if (getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS) { - taskEpdContent = - parseMiningPoolStatsDailyEarnings(getMiningPoolStatsDailyEarnings(), getMiningPool()->getDailyEarningsLabel(), *getMiningPool()); - } - setEpdContent(taskEpdContent); - break; - } - case TASK_PRICE_UPDATE: { - uint currency = getCurrentCurrency(); - uint price = getPrice(currency); - - if (getCurrentScreen() == SCREEN_BTC_TICKER) { - taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE), - preferences.getBool("mowMode", DEFAULT_MOW_MODE), - preferences.getBool("suffixShareDot", DEFAULT_SUFFIX_SHARE_DOT) - ); - } else if (getCurrentScreen() == SCREEN_SATS_PER_CURRENCY) { - taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); - } else { - taskEpdContent = - parseMarketCap(getBlockHeight(), price, currency, - preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR)); - } - - setEpdContent(taskEpdContent); - break; - } - case TASK_FEE_UPDATE: { - if (getCurrentScreen() == SCREEN_BLOCK_FEE_RATE) { - taskEpdContent = parseBlockFees(static_cast(getBlockMedianFee())); - setEpdContent(taskEpdContent); - } - break; - } - case TASK_BLOCK_UPDATE: { - if (getCurrentScreen() != SCREEN_HALVING_COUNTDOWN) { - taskEpdContent = parseBlockHeight(getBlockHeight()); - } else { - taskEpdContent = parseHalvingCountdown(getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN)); - } - - if (getCurrentScreen() == SCREEN_HALVING_COUNTDOWN || - getCurrentScreen() == SCREEN_BLOCK_HEIGHT) { - setEpdContent(taskEpdContent); - } - break; - } - case TASK_TIME_UPDATE: { - if (getCurrentScreen() == SCREEN_TIME) { - time_t currentTime; - struct tm timeinfo; - time(¤tTime); - localtime_r(¤tTime, &timeinfo); - std::string timeString; - - String minute = String(timeinfo.tm_min); - if (minute.length() < 2) { - minute = "0" + minute; - } - - timeString = - std::to_string(timeinfo.tm_hour) + ":" + minute.c_str(); - timeString.insert(timeString.begin(), - NUM_SCREENS - timeString.length(), ' '); - taskEpdContent[0] = std::to_string(timeinfo.tm_mday) + "/" + - std::to_string(timeinfo.tm_mon + 1); - - for (uint i = 1; i < NUM_SCREENS; i++) { - taskEpdContent[i] = timeString[i]; - } - setEpdContent(taskEpdContent); - } - - break; - } - // Add more cases for additional task types - } +// Convert existing functions to static member functions +void ScreenHandler::setCurrentScreen(uint newScreen) { + if (newScreen != SCREEN_CUSTOM) { + preferences.putUInt("currentScreen", newScreen); + } + currentScreen = newScreen; + + switch (currentScreen) { + case SCREEN_TIME: { + WorkItem timeUpdate = {TASK_TIME_UPDATE, 0}; + xQueueSend(workQueue, &timeUpdate, portMAX_DELAY); + break; + } + case SCREEN_HALVING_COUNTDOWN: + case SCREEN_BLOCK_HEIGHT: { + WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0}; + xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); + break; + } + case SCREEN_MARKET_CAP: + case SCREEN_SATS_PER_CURRENCY: + case SCREEN_BTC_TICKER: { + WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0}; + xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); + break; + } + case SCREEN_BLOCK_FEE_RATE: { + WorkItem blockUpdate = {TASK_FEE_UPDATE, 0}; + xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); + break; + } + case SCREEN_BITAXE_BESTDIFF: + case SCREEN_BITAXE_HASHRATE: { + if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED)) { + WorkItem bitaxeUpdate = {TASK_BITAXE_UPDATE, 0}; + xQueueSend(workQueue, &bitaxeUpdate, portMAX_DELAY); + } else { + setCurrentScreen(SCREEN_BLOCK_HEIGHT); + return; + } + break; + } + case SCREEN_MINING_POOL_STATS_HASHRATE: + case SCREEN_MINING_POOL_STATS_EARNINGS: { + if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) { + WorkItem miningPoolStatsUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0}; + xQueueSend(workQueue, &miningPoolStatsUpdate, portMAX_DELAY); + } else { + setCurrentScreen(SCREEN_BLOCK_HEIGHT); + return; + } + break; + } + } + + if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle); +} + +void ScreenHandler::setCurrentCurrency(char currency) { + currentCurrency = currency; + preferences.putUChar("lastCurrency", currency); +} + +bool ScreenHandler::isCurrencySpecific(uint screen) { + switch (screen) { + case SCREEN_BTC_TICKER: + case SCREEN_SATS_PER_CURRENCY: + case SCREEN_MARKET_CAP: + return true; + default: + return false; + } +} + +bool ScreenHandler::handleCurrencyRotation(bool forward) { + if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE) && isCurrencySpecific(getCurrentScreen())) { + std::vector ac = getActiveCurrencies(); + if (ac.empty()) return false; + + std::string curCode = getCurrencyCode(getCurrentCurrency()); + auto it = std::find(ac.begin(), ac.end(), curCode); + + if (it == ac.end()) { + // Current currency not found in active currencies - initialize based on direction + setCurrentCurrency(getCurrencyChar(forward ? ac.front() : ac.back())); + setCurrentScreen(getCurrentScreen()); + return true; + } else if (forward && curCode != ac.back()) { + // Moving forward and not at last currency + setCurrentCurrency(getCurrencyChar(ac.at(std::distance(ac.begin(), it) + 1))); + setCurrentScreen(getCurrentScreen()); + return true; + } else if (!forward && curCode != ac.front()) { + // Moving backward and not at first currency + setCurrentCurrency(getCurrencyChar(ac.at(std::distance(ac.begin(), it) - 1))); + setCurrentScreen(getCurrentScreen()); + return true; + } + return false; + } + return false; +} + +int ScreenHandler::findNextVisibleScreen(int currentScreen, bool forward) { + std::vector screenMappings = getScreenNameMap(); + int newScreen; + + if (forward) { + newScreen = (currentScreen < screenMappings.size() - 1) ? + screenMappings[currentScreen + 1].value : screenMappings.front().value; + } else { + newScreen = (currentScreen > 0) ? + screenMappings[currentScreen - 1].value : screenMappings.back().value; + } + + String key = "screen" + String(newScreen) + "Visible"; + while (!preferences.getBool(key.c_str(), true)) { + currentScreen = findScreenIndexByValue(newScreen); + if (forward) { + newScreen = (currentScreen < screenMappings.size() - 1) ? + screenMappings[currentScreen + 1].value : screenMappings.front().value; + } else { + newScreen = (currentScreen > 0) ? + screenMappings[currentScreen - 1].value : screenMappings.back().value; + } + key = "screen" + String(newScreen) + "Visible"; + } + + return newScreen; +} + +void ScreenHandler::nextScreen() { + if (handleCurrencyRotation(true)) return; + int currentIndex = findScreenIndexByValue(getCurrentScreen()); + setCurrentScreen(findNextVisibleScreen(currentIndex, true)); +} + +void ScreenHandler::previousScreen() { + if (handleCurrencyRotation(false)) return; + int currentIndex = findScreenIndexByValue(getCurrentScreen()); + setCurrentScreen(findNextVisibleScreen(currentIndex, false)); +} + +void ScreenHandler::showSystemStatusScreen() { + std::array sysStatusEpdContent; + std::fill(sysStatusEpdContent.begin(), sysStatusEpdContent.end(), ""); + + String ipAddr = WiFi.localIP().toString(); + String subNet = WiFi.subnetMask().toString(); + + sysStatusEpdContent[0] = "IP/Subnet"; + + int ipAddrPos = 0; + int subnetPos = 0; + for (int i = 0; i < 4; i++) { + sysStatusEpdContent[1 + i] = ipAddr.substring(0, ipAddr.indexOf('.')) + + "/" + subNet.substring(0, subNet.indexOf('.')); + ipAddrPos = ipAddr.indexOf('.') + 1; + subnetPos = subNet.indexOf('.') + 1; + ipAddr = ipAddr.substring(ipAddrPos); + subNet = subNet.substring(subnetPos); + } + sysStatusEpdContent[NUM_SCREENS - 2] = "RAM/Status"; + + sysStatusEpdContent[NUM_SCREENS - 1] = + String((int)round(ESP.getFreeHeap() / 1024)) + "/" + + (int)round(ESP.getHeapSize() / 1024); + setCurrentScreen(SCREEN_CUSTOM); + setEpdContent(sysStatusEpdContent); +} + +// Keep these as free functions +void workerTask(void *pvParameters) { + WorkItem receivedItem; + + while (1) { + if (xQueueReceive(workQueue, &receivedItem, portMAX_DELAY)) { + uint currentScreenValue = ScreenHandler::getCurrentScreen(); + + switch (receivedItem.type) { + case TASK_BITAXE_UPDATE: { + if (currentScreenValue != SCREEN_BITAXE_HASHRATE && + currentScreenValue != SCREEN_BITAXE_BESTDIFF) break; + + taskEpdContent = (currentScreenValue == SCREEN_BITAXE_HASHRATE) ? + parseBitaxeHashRate(getBitAxeHashRate()) : + parseBitaxeBestDiff(getBitaxeBestDiff()); + setEpdContent(taskEpdContent); + break; + } + + case TASK_MINING_POOL_STATS_UPDATE: { + if (currentScreenValue != SCREEN_MINING_POOL_STATS_HASHRATE && + currentScreenValue != SCREEN_MINING_POOL_STATS_EARNINGS) break; + + taskEpdContent = (currentScreenValue == SCREEN_MINING_POOL_STATS_HASHRATE) ? + parseMiningPoolStatsHashRate(getMiningPoolStatsHashRate(), *getMiningPool()) : + parseMiningPoolStatsDailyEarnings(getMiningPoolStatsDailyEarnings(), + getMiningPool()->getDailyEarningsLabel(), *getMiningPool()); + setEpdContent(taskEpdContent); + break; + } + + case TASK_PRICE_UPDATE: { + uint currency = ScreenHandler::getCurrentCurrency(); + uint price = getPrice(currency); + + if (currentScreenValue == SCREEN_BTC_TICKER) { + taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE), + preferences.getBool("mowMode", DEFAULT_MOW_MODE), + preferences.getBool("suffixShareDot", DEFAULT_SUFFIX_SHARE_DOT) + ); + } else if (currentScreenValue == SCREEN_SATS_PER_CURRENCY) { + taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); + } else { + taskEpdContent = + parseMarketCap(getBlockHeight(), price, currency, + preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR)); + } + + setEpdContent(taskEpdContent); + break; + } + case TASK_FEE_UPDATE: { + if (currentScreenValue == SCREEN_BLOCK_FEE_RATE) { + taskEpdContent = parseBlockFees(static_cast(getBlockMedianFee())); + setEpdContent(taskEpdContent); + } + break; + } + case TASK_BLOCK_UPDATE: { + if (currentScreenValue != SCREEN_HALVING_COUNTDOWN) { + taskEpdContent = parseBlockHeight(getBlockHeight()); + } else { + taskEpdContent = parseHalvingCountdown(getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN)); + } + + if (currentScreenValue == SCREEN_HALVING_COUNTDOWN || + currentScreenValue == SCREEN_BLOCK_HEIGHT) { + setEpdContent(taskEpdContent); + } + break; + } + case TASK_TIME_UPDATE: { + if (currentScreenValue == SCREEN_TIME) { + time_t currentTime; + struct tm timeinfo; + time(¤tTime); + localtime_r(¤tTime, &timeinfo); + std::string timeString; + + String minute = String(timeinfo.tm_min); + if (minute.length() < 2) { + minute = "0" + minute; + } + + timeString = + std::to_string(timeinfo.tm_hour) + ":" + minute.c_str(); + timeString.insert(timeString.begin(), + NUM_SCREENS - timeString.length(), ' '); + taskEpdContent[0] = std::to_string(timeinfo.tm_mday) + "/" + + std::to_string(timeinfo.tm_mon + 1); + + for (uint i = 1; i < NUM_SCREENS; i++) { + taskEpdContent[i] = timeString[i]; + } + setEpdContent(taskEpdContent); + } + + break; + } + // Add more cases for additional task types + } + } } - } } void taskScreenRotate(void *pvParameters) { - for (;;) { - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - - nextScreen(); - } + for (;;) { + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + ScreenHandler::nextScreen(); + } } void setupTasks() { - workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem)); + workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem)); - xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY, - &workerTaskHandle); + xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY, + &workerTaskHandle); - xTaskCreate(taskScreenRotate, "rotateScreen", 4096, NULL, tskIDLE_PRIORITY, - &taskScreenRotateTaskHandle); + xTaskCreate(taskScreenRotate, "rotateScreen", 4096, NULL, tskIDLE_PRIORITY, + &taskScreenRotateTaskHandle); - waitUntilNoneBusy(); + waitUntilNoneBusy(); - if (findScreenIndexByValue(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)) != -1) - setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)); + if (findScreenIndexByValue(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)) != -1) + ScreenHandler::setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)); } -uint getCurrentScreen() { return currentScreen; } - -void setCurrentScreen(uint newScreen) { - if (newScreen != SCREEN_CUSTOM) { - preferences.putUInt("currentScreen", newScreen); - } - - currentScreen = newScreen; - - switch (currentScreen) { - case SCREEN_TIME: { - WorkItem timeUpdate = {TASK_TIME_UPDATE, 0}; - xQueueSend(workQueue, &timeUpdate, portMAX_DELAY); - // xTaskNotifyGive(timeUpdateTaskHandle); - break; - } - case SCREEN_HALVING_COUNTDOWN: - case SCREEN_BLOCK_HEIGHT: { - WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0}; - xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); - // xTaskNotifyGive(blockUpdateTaskHandle); - break; - } - case SCREEN_MARKET_CAP: - case SCREEN_SATS_PER_CURRENCY: - case SCREEN_BTC_TICKER: { - WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0}; - xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); - // xTaskNotifyGive(priceUpdateTaskHandle); - break; - } - case SCREEN_BLOCK_FEE_RATE: { - WorkItem blockUpdate = {TASK_FEE_UPDATE, 0}; - xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); - break; - } - case SCREEN_BITAXE_BESTDIFF: - case SCREEN_BITAXE_HASHRATE: { - if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED)) { - WorkItem bitaxeUpdate = {TASK_BITAXE_UPDATE, 0}; - xQueueSend(workQueue, &bitaxeUpdate, portMAX_DELAY); - } else { - setCurrentScreen(SCREEN_BLOCK_HEIGHT); - return; - } - break; - } - case SCREEN_MINING_POOL_STATS_HASHRATE: - case SCREEN_MINING_POOL_STATS_EARNINGS: { - if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) { - WorkItem miningPoolStatsUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0}; - xQueueSend(workQueue, &miningPoolStatsUpdate, portMAX_DELAY); - } else { - setCurrentScreen(SCREEN_BLOCK_HEIGHT); - return; - } - break; - } - } - - if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle); -} - -bool isCurrencySpecific(uint screen) { - switch (screen) { - case SCREEN_BTC_TICKER: - case SCREEN_SATS_PER_CURRENCY: - case SCREEN_MARKET_CAP: - return true; - default: - return false; - } -} - -void nextScreen() { - int currentIndex = findScreenIndexByValue(getCurrentScreen()); - std::vector screenMappings = getScreenNameMap(); - - if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE) && isCurrencySpecific(getCurrentScreen())) { - std::vector ac = getActiveCurrencies(); - std::string curCode = getCurrencyCode(getCurrentCurrency()); - if (getCurrencyCode(getCurrentCurrency()) != ac.back()) { - auto it = std::find(ac.begin(), ac.end(), curCode); - if (it != ac.end()) { - size_t index = std::distance(ac.begin(), it); - setCurrentCurrency(getCurrencyChar(ac.at(index+1))); - setCurrentScreen(getCurrentScreen()); - return; - } - } - setCurrentCurrency(getCurrencyChar(ac.front())); - } - - int newCurrentScreen; - - if (currentIndex < screenMappings.size() - 1) { - newCurrentScreen = (screenMappings[currentIndex + 1].value); - } else { - newCurrentScreen = screenMappings.front().value; - } - - String key = "screen" + String(newCurrentScreen) + "Visible"; - - while (!preferences.getBool(key.c_str(), true)) { - currentIndex = findScreenIndexByValue(newCurrentScreen); - if (currentIndex < screenMappings.size() - 1) { - newCurrentScreen = (screenMappings[currentIndex + 1].value); - } else { - newCurrentScreen = screenMappings.front().value; - } - - key = "screen" + String(newCurrentScreen) + "Visible"; - } - - setCurrentScreen(newCurrentScreen); -} - -void previousScreen() { - int currentIndex = findScreenIndexByValue(getCurrentScreen()); - std::vector screenMappings = getScreenNameMap(); - - if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE) && isCurrencySpecific(getCurrentScreen())) { - std::vector ac = getActiveCurrencies(); - std::string curCode = getCurrencyCode(getCurrentCurrency()); - if (getCurrencyCode(getCurrentCurrency()) != ac.front()) { - auto it = std::find(ac.begin(), ac.end(), curCode); - if (it != ac.end()) { - size_t index = std::distance(ac.begin(), it); - setCurrentCurrency(getCurrencyChar(ac.at(index-1))); - setCurrentScreen(getCurrentScreen()); - return; - } - } - setCurrentCurrency(getCurrencyChar(ac.back())); - - } - - - int newCurrentScreen; - - if (currentIndex > 0) { - newCurrentScreen = screenMappings[currentIndex - 1].value; - } else { - newCurrentScreen = screenMappings.back().value; - } - - String key = "screen" + String(newCurrentScreen) + "Visible"; - - while (!preferences.getBool(key.c_str(), true)) { - int currentIndex = findScreenIndexByValue(newCurrentScreen); - if (currentIndex > 0) { - newCurrentScreen = screenMappings[currentIndex - 1].value; - } else { - newCurrentScreen = screenMappings.back().value; - } - - key = "screen" + String(newCurrentScreen) + "Visible"; - } - setCurrentScreen(newCurrentScreen); -} - -void showSystemStatusScreen() { - std::array sysStatusEpdContent; - std::fill(sysStatusEpdContent.begin(), sysStatusEpdContent.end(), ""); - - - String ipAddr = WiFi.localIP().toString(); - String subNet = WiFi.subnetMask().toString(); - - sysStatusEpdContent[0] = "IP/Subnet"; - - int ipAddrPos = 0; - int subnetPos = 0; - for (int i = 0; i < 4; i++) { - sysStatusEpdContent[1 + i] = ipAddr.substring(0, ipAddr.indexOf('.')) + - "/" + subNet.substring(0, subNet.indexOf('.')); - ipAddrPos = ipAddr.indexOf('.') + 1; - subnetPos = subNet.indexOf('.') + 1; - ipAddr = ipAddr.substring(ipAddrPos); - subNet = subNet.substring(subnetPos); - } - sysStatusEpdContent[NUM_SCREENS - 2] = "RAM/Status"; - - sysStatusEpdContent[NUM_SCREENS - 1] = - String((int)round(ESP.getFreeHeap() / 1024)) + "/" + - (int)round(ESP.getHeapSize() / 1024); - setCurrentScreen(SCREEN_CUSTOM); - setEpdContent(sysStatusEpdContent); -} - -void setCurrentCurrency(char currency) { - currentCurrency = currency; - preferences.putUChar("lastCurrency", currency); -} - -uint getCurrentCurrency() { - return currentCurrency; +void cleanup() { + vQueueDelete(workQueue); + // Add any other cleanup needed } \ No newline at end of file diff --git a/src/lib/screen_handler.hpp b/src/lib/screen_handler.hpp index fcdf2ba..914af09 100644 --- a/src/lib/screen_handler.hpp +++ b/src/lib/screen_handler.hpp @@ -11,12 +11,10 @@ #include "lib/epd.hpp" #include "lib/shared.hpp" -// extern TaskHandle_t priceUpdateTaskHandle; -// extern TaskHandle_t blockUpdateTaskHandle; -// extern TaskHandle_t timeUpdateTaskHandle; +#define WORK_QUEUE_SIZE 10 + extern TaskHandle_t workerTaskHandle; extern TaskHandle_t taskScreenRotateTaskHandle; - extern QueueHandle_t workQueue; typedef enum { @@ -33,24 +31,26 @@ typedef struct { char data; } WorkItem; +class ScreenHandler { +private: + static uint currentScreen; + static uint currentCurrency; + +public: + static uint getCurrentScreen() { return currentScreen; } + static uint getCurrentCurrency() { return currentCurrency; } + static void setCurrentScreen(uint newScreen); + static void setCurrentCurrency(char currency); + static void nextScreen(); + static void previousScreen(); + static void showSystemStatusScreen(); + static bool isCurrencySpecific(uint screen); + static bool handleCurrencyRotation(bool forward); + static int findNextVisibleScreen(int currentScreen, bool forward); +}; + +// Keep as free functions since they deal with FreeRTOS tasks void workerTask(void *pvParameters); -uint getCurrentScreen(); -void setCurrentScreen(uint newScreen); -void nextScreen(); -void previousScreen(); - -void showSystemStatusScreen(); - - - -// void taskPriceUpdate(void *pvParameters); -// void taskBlockUpdate(void *pvParameters); -// void taskTimeUpdate(void *pvParameters); void taskScreenRotate(void *pvParameters); - - - void setupTasks(); -void setCurrentCurrency(char currency); - -uint getCurrentCurrency(); \ No newline at end of file +void cleanup(); \ No newline at end of file diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index f1810cc..4a8a8f5 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -228,7 +228,7 @@ JsonDocument getStatusObject() { JsonDocument root; - root["currentScreen"] = getCurrentScreen(); + root["currentScreen"] = ScreenHandler::getCurrentScreen(); root["numScreens"] = NUM_SCREENS; root["timerRunning"] = isTimerActive(); root["espUptime"] = esp_timer_get_time() / 1000000; @@ -248,7 +248,7 @@ JsonDocument getStatusObject() conStatus["nostr"] = nostrConnected(); root["rssi"] = WiFi.RSSI(); - root["currency"] = getCurrencyCode(getCurrentCurrency()); + root["currency"] = getCurrencyCode(ScreenHandler::getCurrentCurrency()); #ifdef HAS_FRONTLIGHT std::vector statuses = frontlightGetStatus(); uint16_t arr[NUM_SCREENS]; @@ -386,7 +386,7 @@ void onApiShowScreen(AsyncWebServerRequest *request) { const AsyncWebParameter *p = request->getParam("s"); uint currentScreen = p->value().toInt(); - setCurrentScreen(currentScreen); + ScreenHandler::setCurrentScreen(currentScreen); } request->send(HTTP_OK); } @@ -398,9 +398,9 @@ void onApiShowScreen(AsyncWebServerRequest *request) void onApiScreenControl(AsyncWebServerRequest *request) { const String& action = request->url(); if (action.endsWith("/next")) { - nextScreen(); + ScreenHandler::nextScreen(); } else if (action.endsWith("/previous")) { - previousScreen(); + ScreenHandler::previousScreen(); } request->send(HTTP_OK); } @@ -421,7 +421,7 @@ void onApiShowText(AsyncWebServerRequest *request) setEpdContent(textEpdContent); } - setCurrentScreen(SCREEN_CUSTOM); + ScreenHandler::setCurrentScreen(SCREEN_CUSTOM); request->send(HTTP_OK); } @@ -439,7 +439,7 @@ void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json) setEpdContent(epdContent); - setCurrentScreen(SCREEN_CUSTOM); + ScreenHandler::setCurrentScreen(SCREEN_CUSTOM); request->send(HTTP_OK); } @@ -998,8 +998,8 @@ void onApiShowCurrency(AsyncWebServerRequest *request) char curChar = getCurrencyChar(currency); - setCurrentCurrency(curChar); - setCurrentScreen(getCurrentScreen()); + ScreenHandler::setCurrentCurrency(curChar); + ScreenHandler::setCurrentScreen(ScreenHandler::getCurrentScreen()); request->send(HTTP_OK); return; From cff6131fc4df948376b8d037bf2adf20e0318430 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Fri, 27 Dec 2024 00:05:45 +0100 Subject: [PATCH 084/130] Update WebUI and convert ButtonHandler to class --- data | 2 +- src/lib/button_handler.cpp | 63 +++++++--------------------------- src/lib/button_handler.hpp | 70 +++++++++++++++++++------------------- src/lib/config.cpp | 4 +-- src/lib/ota.cpp | 7 ++-- 5 files changed, 53 insertions(+), 93 deletions(-) diff --git a/data b/data index 65b6df5..2ce53eb 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 65b6df5d92f3f936e823a5c1413681aee85ab0c5 +Subproject commit 2ce53eb499e00a990be5cb0ea078e146f467ceb4 diff --git a/src/lib/button_handler.cpp b/src/lib/button_handler.cpp index ff7e259..bd4204d 100644 --- a/src/lib/button_handler.cpp +++ b/src/lib/button_handler.cpp @@ -1,7 +1,8 @@ #include "button_handler.hpp" -TaskHandle_t buttonTaskHandle = NULL; -ButtonState buttonStates[4]; +// Initialize static members +TaskHandle_t ButtonHandler::buttonTaskHandle = NULL; +ButtonState ButtonHandler::buttonStates[4] = {}; #ifdef IS_BTCLOCK_V8 #define BTN_1 256 @@ -15,7 +16,7 @@ ButtonState buttonStates[4]; #define BTN_4 256 #endif -void buttonTask(void *parameter) { +void ButtonHandler::buttonTask(void *parameter) { while (1) { ulTaskNotifyTake(pdTRUE, portMAX_DELAY); @@ -48,16 +49,6 @@ void buttonTask(void *parameter) { } } } - - // Check for long press on pressed buttons - for (int i = 0; i < 4; i++) { - if (buttonStates[i].isPressed && !buttonStates[i].longPressHandled) { - if ((currentTime - buttonStates[i].pressStartTime) >= longPressDelay) { - handleLongPress(i); - buttonStates[i].longPressHandled = true; - } - } - } } // Clear interrupt state @@ -68,56 +59,34 @@ void buttonTask(void *parameter) { } } -void handleButtonPress(int buttonIndex) { +void ButtonHandler::handleButtonPress(int buttonIndex) { TickType_t currentTime = xTaskGetTickCount(); ButtonState &state = buttonStates[buttonIndex]; if ((currentTime - state.lastPressTime) >= debounceDelay) { state.isPressed = true; - state.pressStartTime = currentTime; - state.longPressHandled = false; - - // Check for double click - if ((currentTime - state.lastPressTime) <= doubleClickDelay) { - state.clickCount++; - if (state.clickCount == 2) { - handleDoubleClick(buttonIndex); - state.clickCount = 0; - } - } else { - state.clickCount = 1; - } - state.lastPressTime = currentTime; } } -void handleButtonRelease(int buttonIndex) { - TickType_t currentTime = xTaskGetTickCount(); +void ButtonHandler::handleButtonRelease(int buttonIndex) { ButtonState &state = buttonStates[buttonIndex]; - state.isPressed = false; + if (!state.isPressed) return; // Ignore if button wasn't pressed - // If this wasn't a long press or double click, handle as single click - if (!state.longPressHandled && state.clickCount == 1 && - (currentTime - state.pressStartTime) < longPressDelay) { - handleSingleClick(buttonIndex); - state.clickCount = 0; - } + state.isPressed = false; + handleSingleClick(buttonIndex); } -// Button action handlers -void handleSingleClick(int buttonIndex) { +void ButtonHandler::handleSingleClick(int buttonIndex) { switch (buttonIndex) { case 0: toggleTimerActive(); break; case 1: - Serial.println("Button 2 single click"); ScreenHandler::nextScreen(); break; case 2: - Serial.println("Button 3 single click"); ScreenHandler::previousScreen(); break; case 3: @@ -126,15 +95,7 @@ void handleSingleClick(int buttonIndex) { } } -void handleDoubleClick(int buttonIndex) { - Serial.printf("Button %d double clicked\n", buttonIndex + 1); -} - -void handleLongPress(int buttonIndex) { - Serial.printf("Button %d long press detected\n", buttonIndex + 1); -} - -void IRAM_ATTR handleButtonInterrupt() { +void IRAM_ATTR ButtonHandler::handleButtonInterrupt() { BaseType_t xHigherPriorityTaskWoken = pdFALSE; xTaskNotifyFromISR(buttonTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken); if (xHigherPriorityTaskWoken == pdTRUE) { @@ -142,7 +103,7 @@ void IRAM_ATTR handleButtonInterrupt() { } } -void setupButtonTask() { +void ButtonHandler::setup() { xTaskCreate(buttonTask, "ButtonTask", 3072, NULL, tskIDLE_PRIORITY, &buttonTaskHandle); attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, FALLING); diff --git a/src/lib/button_handler.hpp b/src/lib/button_handler.hpp index f3f41a1..17fab6b 100644 --- a/src/lib/button_handler.hpp +++ b/src/lib/button_handler.hpp @@ -6,24 +6,6 @@ #include "lib/shared.hpp" #include "lib/timers.hpp" -extern TaskHandle_t buttonTaskHandle; - -// Task and setup functions -void buttonTask(void *pvParameters); -void IRAM_ATTR handleButtonInterrupt(); -void setupButtonTask(); - -// Individual button handlers -void handleButton1(); -void handleButton2(); -void handleButton3(); -void handleButton4(); - -// New features -const TickType_t debounceDelay = pdMS_TO_TICKS(50); -const TickType_t doubleClickDelay = pdMS_TO_TICKS(300); // Maximum time between clicks for double click -const TickType_t longPressDelay = pdMS_TO_TICKS(1000); // Time to hold for long press - // Track timing for each button struct ButtonState { TickType_t lastPressTime = 0; @@ -33,22 +15,40 @@ struct ButtonState { bool longPressHandled = false; }; -extern ButtonState buttonStates[4]; +class ButtonHandler { +private: + static const TickType_t debounceDelay = pdMS_TO_TICKS(50); + static const TickType_t doubleClickDelay = pdMS_TO_TICKS(1000); // Maximum time between clicks for double click + static const TickType_t longPressDelay = pdMS_TO_TICKS(1500); // Time to hold for long press -#ifdef IS_BTCLOCK_V8 -#define BTN_1 256 -#define BTN_2 512 -#define BTN_3 1024 -#define BTN_4 2048 -#else -#define BTN_1 2048 -#define BTN_2 1024 -#define BTN_3 512 -#define BTN_4 256 -#endif + static ButtonState buttonStates[4]; + static TaskHandle_t buttonTaskHandle; -void handleButtonPress(int buttonIndex); -void handleButtonRelease(int buttonIndex); -void handleSingleClick(int buttonIndex); -void handleDoubleClick(int buttonIndex); -void handleLongPress(int buttonIndex); + // Button handlers + static void handleButtonPress(int buttonIndex); + static void handleButtonRelease(int buttonIndex); + static void handleSingleClick(int buttonIndex); + static void handleDoubleClick(int buttonIndex); + static void handleLongPress(int buttonIndex); + + // Task function + static void buttonTask(void *pvParameters); + +public: + static void setup(); + static void IRAM_ATTR handleButtonInterrupt(); + static void suspendTask() { if (buttonTaskHandle != NULL) vTaskSuspend(buttonTaskHandle); } + static void resumeTask() { if (buttonTaskHandle != NULL) vTaskResume(buttonTaskHandle); } + + #ifdef IS_BTCLOCK_V8 + static const uint16_t BTN_1 = 256; + static const uint16_t BTN_2 = 512; + static const uint16_t BTN_3 = 1024; + static const uint16_t BTN_4 = 2048; + #else + static const uint16_t BTN_1 = 2048; + static const uint16_t BTN_2 = 1024; + static const uint16_t BTN_3 = 512; + static const uint16_t BTN_4 = 256; + #endif +}; diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 4ae7e4b..4c7303c 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -100,7 +100,7 @@ void setup() setupMiningPoolStatsFetchTask(); } - setupButtonTask(); + ButtonHandler::setup(); setupOTA(); waitUntilNoneBusy(); @@ -482,7 +482,7 @@ void setupHardware() Serial.printf("Error setting pin %d to input pull up\n", i); } // Enable interrupt on CHANGE for each pin - if (!mcp1.enableInterrupt(i, FALLING)) { + if (!mcp1.enableInterrupt(i, CHANGE)) { Serial.printf("Error enabling interrupt for pin %d\n", i); } } diff --git a/src/lib/ota.cpp b/src/lib/ota.cpp index 05c45e1..0d6a57f 100644 --- a/src/lib/ota.cpp +++ b/src/lib/ota.cpp @@ -64,11 +64,10 @@ void onOTAStart() // Stop or suspend all tasks // vTaskSuspend(priceUpdateTaskHandle); // vTaskSuspend(blockUpdateTaskHandle); - vTaskSuspend(workerTaskHandle); vTaskSuspend(taskScreenRotateTaskHandle); - -// vTaskSuspend(ledTaskHandle); - vTaskSuspend(buttonTaskHandle); + vTaskSuspend(workerTaskHandle); + vTaskSuspend(eventSourceTaskHandle); + ButtonHandler::suspendTask(); // stopWebServer(); stopBlockNotify(); From 10fe5b505354ec9e0b048c6ab89fd690eae11a20 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Fri, 27 Dec 2024 00:41:41 +0100 Subject: [PATCH 085/130] Fix function definition and rev.b definition --- platformio.ini | 6 +----- src/lib/led_handler.cpp | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/platformio.ini b/platformio.ini index 90f1cc0..0dcacd0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -71,11 +71,7 @@ board = btclock_rev_b board_build.partitions = partition_8mb.csv build_flags = ${btclock_base.build_flags} - -D MCP_INT_PIN=8docker run --rm -e RENOVATE_TOKEN -e LOG_LEVEL=debug \ - -e "RENOVATE_REPOSITORIES=[\"your-repo-name\"]" \ - renovate/renovate \ - --platform local \ - --dry-run + -D MCP_INT_PIN=8 -D NEOPIXEL_PIN=15 -D NEOPIXEL_COUNT=4 -D NUM_SCREENS=7 diff --git a/src/lib/led_handler.cpp b/src/lib/led_handler.cpp index c2c56f4..42ef5e5 100644 --- a/src/lib/led_handler.cpp +++ b/src/lib/led_handler.cpp @@ -176,7 +176,7 @@ std::vector frontlightGetStatus() return statuses; } -inline bool frontlightIsOn() +bool frontlightIsOn() { return frontlightOn; } From 4140b05a7dbaf662f507b91fa691d36933b04f05 Mon Sep 17 00:00:00 2001 From: Ticktock Depbot Date: Fri, 27 Dec 2024 08:28:10 +0000 Subject: [PATCH 086/130] Add renovate.json --- renovate.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..5db72dd --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ] +} From b7ff9d810123efefa67d79c676e163d236c83993 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 28 Dec 2024 13:40:08 +0100 Subject: [PATCH 087/130] Better handling of unexpected pool stats responses, add CKPool --- src/lib/mining_pool/braiins/brains_pool.cpp | 47 +++++++++------ src/lib/mining_pool/ckpool/ckpool.cpp | 47 +++++++++++++++ src/lib/mining_pool/ckpool/ckpool.hpp | 25 ++++++++ src/lib/mining_pool/ckpool/eu_ckpool.hpp | 16 ++++++ .../noderunners/noderunners_pool.cpp | 57 +++++++++++++------ src/lib/mining_pool/ocean/ocean_pool.cpp | 31 ++++++---- src/lib/mining_pool/pool_factory.cpp | 6 +- src/lib/mining_pool/pool_factory.hpp | 8 ++- .../mining_pool/public_pool/public_pool.cpp | 27 ++++++--- .../satoshi_radio/satoshi_radio_pool.cpp | 3 +- 10 files changed, 210 insertions(+), 57 deletions(-) create mode 100644 src/lib/mining_pool/ckpool/ckpool.cpp create mode 100644 src/lib/mining_pool/ckpool/ckpool.hpp create mode 100644 src/lib/mining_pool/ckpool/eu_ckpool.hpp diff --git a/src/lib/mining_pool/braiins/brains_pool.cpp b/src/lib/mining_pool/braiins/brains_pool.cpp index 47b6e61..6449b29 100644 --- a/src/lib/mining_pool/braiins/brains_pool.cpp +++ b/src/lib/mining_pool/braiins/brains_pool.cpp @@ -1,32 +1,43 @@ #include "brains_pool.hpp" -void BraiinsPool::prepareRequest(HTTPClient& http) const { +void BraiinsPool::prepareRequest(HTTPClient &http) const +{ http.addHeader("Pool-Auth-Token", poolUser.c_str()); } -std::string BraiinsPool::getApiUrl() const { +std::string BraiinsPool::getApiUrl() const +{ return "https://pool.braiins.com/accounts/profile/json/btc/"; } PoolStats BraiinsPool::parseResponse(const JsonDocument &doc) const { - if (doc["btc"].isNull()) { + try + { + if (doc["btc"].isNull()) + { + return PoolStats{ + .hashrate = "0", + .dailyEarnings = 0}; + } + + std::string unit = doc["btc"]["hash_rate_unit"].as(); + + static const std::unordered_map multipliers = { + {"Zh/s", 21}, {"Eh/s", 18}, {"Ph/s", 15}, {"Th/s", 12}, {"Gh/s", 9}, {"Mh/s", 6}, {"Kh/s", 3}}; + + int multiplier = multipliers.at(unit); + float hashValue = doc["btc"]["hash_rate_5m"].as(); + + return PoolStats{ + .hashrate = std::to_string(static_cast(std::round(hashValue))) + std::string(multiplier, '0'), + .dailyEarnings = static_cast(doc["btc"]["today_reward"].as() * 100000000)}; + } + catch (const std::exception &e) + { + Serial.printf("Error parsing %s response: %s\n", getPoolName().c_str(), e.what()); return PoolStats{ .hashrate = "0", - .dailyEarnings = 0 - }; + .dailyEarnings = std::nullopt}; } - - std::string unit = doc["btc"]["hash_rate_unit"].as(); - - static const std::unordered_map multipliers = { - {"Zh/s", 21}, {"Eh/s", 18}, {"Ph/s", 15}, {"Th/s", 12}, {"Gh/s", 9}, {"Mh/s", 6}, {"Kh/s", 3}}; - - int multiplier = multipliers.at(unit); - float hashValue = doc["btc"]["hash_rate_5m"].as(); - - return PoolStats{ - .hashrate = std::to_string(static_cast(std::round(hashValue))) + std::string(multiplier, '0'), - .dailyEarnings = static_cast(doc["btc"]["today_reward"].as() * 100000000)}; } - diff --git a/src/lib/mining_pool/ckpool/ckpool.cpp b/src/lib/mining_pool/ckpool/ckpool.cpp new file mode 100644 index 0000000..4c17c7d --- /dev/null +++ b/src/lib/mining_pool/ckpool/ckpool.cpp @@ -0,0 +1,47 @@ +#include "ckpool.hpp" + +void CKPool::prepareRequest(HTTPClient &http) const +{ + // Empty as CKPool doesn't need special headers +} + +std::string CKPool::getApiUrl() const +{ + return getBaseUrl() + "/users/" + poolUser; +} + +PoolStats CKPool::parseResponse(const JsonDocument &doc) const +{ + try + { + std::string hashrateStr = doc["hashrate1m"].as(); + + // Special case for "0" + if (hashrateStr == "0") { + return PoolStats{ + .hashrate = "0", + .dailyEarnings = std::nullopt + }; + } + + char unit = hashrateStr.back(); + std::string value = hashrateStr.substr(0, hashrateStr.size() - 1); + + int multiplier = getHashrateMultiplier(unit); + double hashrate = std::stod(value) * std::pow(10, multiplier); + + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%.0f", hashrate); + + return PoolStats{ + .hashrate = buffer, + .dailyEarnings = std::nullopt}; + } + catch (const std::exception &e) + { + Serial.printf("Error parsing %s response: %s\n", getPoolName().c_str(), e.what()); + return PoolStats{ + .hashrate = "0", + .dailyEarnings = std::nullopt}; + } +} \ No newline at end of file diff --git a/src/lib/mining_pool/ckpool/ckpool.hpp b/src/lib/mining_pool/ckpool/ckpool.hpp new file mode 100644 index 0000000..bbf75d1 --- /dev/null +++ b/src/lib/mining_pool/ckpool/ckpool.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "lib/mining_pool/mining_pool_interface.hpp" +#include + +class CKPool : public MiningPoolInterface { +public: + void setPoolUser(const std::string& user) override { poolUser = user; } + + void prepareRequest(HTTPClient& http) const override; + std::string getApiUrl() const override; + PoolStats parseResponse(const JsonDocument& doc) const override; + bool supportsDailyEarnings() const override { return false; } + std::string getDailyEarningsLabel() const override { return ""; } + bool hasLogo() const override { return false; } + std::string getDisplayLabel() const override { return "CK/POOL"; } + std::string getPoolName() const override { + return "ckpool"; + } + +protected: + virtual std::string getBaseUrl() const { + return "https://solo.ckpool.org"; + } +}; \ No newline at end of file diff --git a/src/lib/mining_pool/ckpool/eu_ckpool.hpp b/src/lib/mining_pool/ckpool/eu_ckpool.hpp new file mode 100644 index 0000000..95a9b75 --- /dev/null +++ b/src/lib/mining_pool/ckpool/eu_ckpool.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "ckpool.hpp" + +class EUCKPool : public CKPool { +public: + std::string getDisplayLabel() const override { return "CK/POOL"; } + std::string getPoolName() const override { + return "eu_ckpool"; + } + +protected: + std::string getBaseUrl() const override { + return "https://eusolo.ckpool.org"; + } +}; \ No newline at end of file diff --git a/src/lib/mining_pool/noderunners/noderunners_pool.cpp b/src/lib/mining_pool/noderunners/noderunners_pool.cpp index da34e38..e7e10ca 100644 --- a/src/lib/mining_pool/noderunners/noderunners_pool.cpp +++ b/src/lib/mining_pool/noderunners/noderunners_pool.cpp @@ -1,27 +1,48 @@ // src/noderunners/noderunners_pool.cpp #include "noderunners_pool.hpp" -void NoderunnersPool::prepareRequest(HTTPClient& http) const { - // Empty as NodeRunners doesn't need special headers +void NoderunnersPool::prepareRequest(HTTPClient &http) const +{ + // Empty as Noderunners doesn't need special headers } -std::string NoderunnersPool::getApiUrl() const { +std::string NoderunnersPool::getApiUrl() const +{ return "https://pool.noderunners.network/api/v1/users/" + poolUser; } -PoolStats NoderunnersPool::parseResponse(const JsonDocument& doc) const { - std::string hashrateStr = doc["hashrate1m"].as(); - char unit = hashrateStr.back(); - std::string value = hashrateStr.substr(0, hashrateStr.size() - 1); - - int multiplier = getHashrateMultiplier(unit); - double hashrate = std::stod(value) * std::pow(10, multiplier); - - char buffer[32]; - snprintf(buffer, sizeof(buffer), "%.0f", hashrate); - - return PoolStats{ - .hashrate = buffer, - .dailyEarnings = std::nullopt - }; +PoolStats NoderunnersPool::parseResponse(const JsonDocument &doc) const +{ + try + { + std::string hashrateStr = doc["hashrate1m"].as(); + + // Special case for "0" + if (hashrateStr == "0") { + return PoolStats{ + .hashrate = "0", + .dailyEarnings = std::nullopt + }; + } + + char unit = hashrateStr.back(); + std::string value = hashrateStr.substr(0, hashrateStr.size() - 1); + + int multiplier = getHashrateMultiplier(unit); + double hashrate = std::stod(value) * std::pow(10, multiplier); + + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%.0f", hashrate); + + return PoolStats{ + .hashrate = buffer, + .dailyEarnings = std::nullopt}; + } + catch (const std::exception &e) + { + Serial.printf("Error parsing %s response: %s\n", getPoolName().c_str(), e.what()); + return PoolStats{ + .hashrate = "0", + .dailyEarnings = std::nullopt}; + } } \ No newline at end of file diff --git a/src/lib/mining_pool/ocean/ocean_pool.cpp b/src/lib/mining_pool/ocean/ocean_pool.cpp index f6050af..cf9bf49 100644 --- a/src/lib/mining_pool/ocean/ocean_pool.cpp +++ b/src/lib/mining_pool/ocean/ocean_pool.cpp @@ -1,18 +1,29 @@ #include "ocean_pool.hpp" -void OceanPool::prepareRequest(HTTPClient& http) const { +void OceanPool::prepareRequest(HTTPClient &http) const +{ // Empty as Ocean doesn't need special headers } -std::string OceanPool::getApiUrl() const { +std::string OceanPool::getApiUrl() const +{ return "https://api.ocean.xyz/v1/statsnap/" + poolUser; } -PoolStats OceanPool::parseResponse(const JsonDocument& doc) const { - return PoolStats{ - .hashrate = doc["result"]["hashrate_300s"].as(), - .dailyEarnings = static_cast( - doc["result"]["estimated_earn_next_block"].as() * 100000000 - ) - }; -} +PoolStats OceanPool::parseResponse(const JsonDocument &doc) const +{ + try + { + return PoolStats{ + .hashrate = doc["result"]["hashrate_300s"].as(), + .dailyEarnings = static_cast( + doc["result"]["estimated_earn_next_block"].as() * 100000000)}; + } + catch (const std::exception &e) + { + Serial.printf("Error parsing %s response: %s\n", getPoolName().c_str(), e.what()); + return PoolStats{ + .hashrate = "0", + .dailyEarnings = std::nullopt}; + } +} \ No newline at end of file diff --git a/src/lib/mining_pool/pool_factory.cpp b/src/lib/mining_pool/pool_factory.cpp index 150793a..c353996 100644 --- a/src/lib/mining_pool/pool_factory.cpp +++ b/src/lib/mining_pool/pool_factory.cpp @@ -6,6 +6,8 @@ const char* PoolFactory::MINING_POOL_NAME_BRAIINS = "braiins"; const char* PoolFactory::MINING_POOL_NAME_SATOSHI_RADIO = "satoshi_radio"; const char* PoolFactory::MINING_POOL_NAME_PUBLIC_POOL = "public_pool"; const char* PoolFactory::MINING_POOL_NAME_GOBRRR_POOL = "gobrrr_pool"; +const char* PoolFactory::MINING_POOL_NAME_CKPOOL = "ckpool"; +const char* PoolFactory::MINING_POOL_NAME_EU_CKPOOL = "eu_ckpool"; const char* PoolFactory::LOGOS_DIR = "/logos"; std::unique_ptr PoolFactory::createPool(const std::string& poolName) { @@ -15,7 +17,9 @@ std::unique_ptr PoolFactory::createPool(const std::string& {MINING_POOL_NAME_BRAIINS, []() { return std::make_unique(); }}, {MINING_POOL_NAME_SATOSHI_RADIO, []() { return std::make_unique(); }}, {MINING_POOL_NAME_PUBLIC_POOL, []() { return std::make_unique(); }}, - {MINING_POOL_NAME_GOBRRR_POOL, []() { return std::make_unique(); }} + {MINING_POOL_NAME_GOBRRR_POOL, []() { return std::make_unique(); }}, + {MINING_POOL_NAME_CKPOOL, []() { return std::make_unique(); }}, + {MINING_POOL_NAME_EU_CKPOOL, []() { return std::make_unique(); }} }; auto it = poolFactories.find(poolName); diff --git a/src/lib/mining_pool/pool_factory.hpp b/src/lib/mining_pool/pool_factory.hpp index 96231c9..951dbe5 100644 --- a/src/lib/mining_pool/pool_factory.hpp +++ b/src/lib/mining_pool/pool_factory.hpp @@ -11,6 +11,8 @@ #include "satoshi_radio/satoshi_radio_pool.hpp" #include "public_pool/public_pool.hpp" #include "gobrrr_pool/gobrrr_pool.hpp" +#include "ckpool/ckpool.hpp" +#include "ckpool/eu_ckpool.hpp" #include #include @@ -26,7 +28,9 @@ class PoolFactory { MINING_POOL_NAME_SATOSHI_RADIO, MINING_POOL_NAME_BRAIINS, MINING_POOL_NAME_PUBLIC_POOL, - MINING_POOL_NAME_GOBRRR_POOL + MINING_POOL_NAME_GOBRRR_POOL, + MINING_POOL_NAME_CKPOOL, + MINING_POOL_NAME_EU_CKPOOL }; } @@ -52,5 +56,7 @@ class PoolFactory { static const char* MINING_POOL_NAME_SATOSHI_RADIO; static const char* MINING_POOL_NAME_PUBLIC_POOL; static const char* MINING_POOL_NAME_GOBRRR_POOL; + static const char* MINING_POOL_NAME_CKPOOL; + static const char* MINING_POOL_NAME_EU_CKPOOL; static const char* LOGOS_DIR; }; \ No newline at end of file diff --git a/src/lib/mining_pool/public_pool/public_pool.cpp b/src/lib/mining_pool/public_pool/public_pool.cpp index 9a5d56f..8c7c6e2 100644 --- a/src/lib/mining_pool/public_pool/public_pool.cpp +++ b/src/lib/mining_pool/public_pool/public_pool.cpp @@ -1,21 +1,32 @@ // src/noderunners/noderunners_pool.cpp #include "public_pool.hpp" -std::string PublicPool::getApiUrl() const { +std::string PublicPool::getApiUrl() const +{ return "https://public-pool.io:40557/api/client/" + poolUser; } -PoolStats PublicPool::parseResponse(const JsonDocument& doc) const { +PoolStats PublicPool::parseResponse(const JsonDocument &doc) const +{ uint64_t totalHashrate = 0; - - for (JsonVariantConst worker : doc["workers"].as()) { - totalHashrate += static_cast(std::llround(worker["hashRate"].as())); - } - + try + { + for (JsonVariantConst worker : doc["workers"].as()) + { + totalHashrate += static_cast(std::llround(worker["hashRate"].as())); + } + } + catch (const std::exception &e) + { + Serial.printf("Error parsing %s response: %s\n", getPoolName().c_str(), e.what()); + return PoolStats{ + .hashrate = "0", + .dailyEarnings = std::nullopt}; + } return PoolStats{ .hashrate = std::to_string(totalHashrate), - .dailyEarnings = std::nullopt // Public Pool doesn't support daily earnings + .dailyEarnings = std::nullopt // Public Pool doesn't support daily earnings }; } \ No newline at end of file diff --git a/src/lib/mining_pool/satoshi_radio/satoshi_radio_pool.cpp b/src/lib/mining_pool/satoshi_radio/satoshi_radio_pool.cpp index 5b8f4a3..39fa107 100644 --- a/src/lib/mining_pool/satoshi_radio/satoshi_radio_pool.cpp +++ b/src/lib/mining_pool/satoshi_radio/satoshi_radio_pool.cpp @@ -1,6 +1,7 @@ // src/noderunners/noderunners_pool.cpp #include "satoshi_radio_pool.hpp" -std::string SatoshiRadioPool::getApiUrl() const { +std::string SatoshiRadioPool::getApiUrl() const +{ return "https://pool.satoshiradio.nl/api/v1/users/" + poolUser; } From bc3e5afe51b6592787c38cced638ed33105bf757 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 28 Dec 2024 16:29:34 +0100 Subject: [PATCH 088/130] Add debug log setting and custom endpoint settings --- src/lib/config.cpp | 21 +++++++++++++ src/lib/config.hpp | 2 ++ src/lib/defaults.hpp | 13 +++++++- src/lib/mining_pool_stats_fetch.cpp | 14 +++++++++ src/lib/nostr_notify.cpp | 5 ++- src/lib/v2_notify.cpp | 23 +++++++++++--- src/lib/webserver.cpp | 47 +++++++++++++++-------------- 7 files changed, 95 insertions(+), 30 deletions(-) diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 4c7303c..38fba9e 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -284,6 +284,22 @@ void setupPreferences() setBlockHeight(preferences.getUInt("blockHeight", INITIAL_BLOCK_HEIGHT)); setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD); + if (!preferences.isKey("enableDebugLog")) { + preferences.putBool("enableDebugLog", DEFAULT_ENABLE_DEBUG_LOG); + } + + if (!preferences.isKey("ceEnabled")) { + preferences.putBool("ceEnabled", DEFAULT_CUSTOM_ENDPOINT_ENABLED); + } + + if (!preferences.isKey("ceEndpoint")) { + preferences.putString("ceEndpoint", DEFAULT_CUSTOM_ENDPOINT); + } + + if (!preferences.isKey("ceDisableSSL")) { + preferences.putBool("ceDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); + } + if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) ScreenHandler::setCurrentCurrency(preferences.getUChar("lastCurrency", CURRENCY_USD)); else @@ -767,3 +783,8 @@ const char* getWebUiFilename() { return "littlefs_4MB.bin"; } } + +bool debugLogEnabled() +{ + return preferences.getBool("enableDebugLog", DEFAULT_ENABLE_DEBUG_LOG); +} diff --git a/src/lib/config.hpp b/src/lib/config.hpp index 2c001cd..806497c 100644 --- a/src/lib/config.hpp +++ b/src/lib/config.hpp @@ -77,6 +77,8 @@ String getHwRev(); bool isWhiteVersion(); String getFsRev(); +bool debugLogEnabled(); + void addScreenMapping(int value, const char* name); // void addScreenMapping(int value, const String& name); // void addScreenMapping(int value, const std::string& name); diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index d880f2d..da4d405 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -17,7 +17,9 @@ #define DEFAULT_DISABLE_LEDS false #define DEFAULT_DISABLE_FL false #define DEFAULT_OWN_DATA_SOURCE true -#define DEFAULT_STAGING_SOURCE false +#define DEFAULT_CUSTOM_SOURCE false +#define DEFAULT_CUSTOM_EP "ws-staging.btclock.dev" +#define DEFAULT_CUSTOM_SSL true #define DEFAULT_MOW_MODE false #define DEFAULT_SUFFIX_SHARE_DOT false @@ -77,3 +79,12 @@ #define DEFAULT_VERTICAL_DESC true #define DEFAULT_MINING_POOL_LOGOS_URL "https://git.btclock.dev/btclock/mining-pool-logos/raw/branch/main" + +#define DEFAULT_ENABLE_DEBUG_LOG false + +#define DEFAULT_DISABLE_FL false +#define DEFAULT_OWN_DATA_SOURCE true +#define DEFAULT_CUSTOM_ENDPOINT_ENABLED false +#define DEFAULT_CUSTOM_ENDPOINT "ws-staging.btclock.dev" +#define DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL false +#define DEFAULT_MOW_MODE false diff --git a/src/lib/mining_pool_stats_fetch.cpp b/src/lib/mining_pool_stats_fetch.cpp index 9687e03..a35a00e 100644 --- a/src/lib/mining_pool_stats_fetch.cpp +++ b/src/lib/mining_pool_stats_fetch.cpp @@ -36,6 +36,10 @@ void taskMiningPoolStatsFetch(void *pvParameters) poolInterface->setPoolUser(poolUser); std::string apiUrl = poolInterface->getApiUrl(); http.begin(apiUrl.c_str()); + if (debugLogEnabled()) + { + Serial.printf("Fetching mining pool stats from %s\r\n", apiUrl.c_str()); + } poolInterface->prepareRequest(http); int httpCode = http.GET(); if (httpCode == 200) @@ -44,10 +48,20 @@ void taskMiningPoolStatsFetch(void *pvParameters) JsonDocument doc; deserializeJson(doc, payload); + if (debugLogEnabled()) + { + Serial.printf("Mining pool stats response: %s\r\n", payload.c_str()); + } + PoolStats stats = poolInterface->parseResponse(doc); miningPoolStatsHashrate = stats.hashrate; + if (debugLogEnabled()) + { + Serial.printf("Mining pool stats parsed hashrate: %s\r\n", stats.hashrate.c_str()); + } + if (stats.dailyEarnings) { miningPoolStatsDailyEarnings = *stats.dailyEarnings; diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index 20bdd01..46c6ecf 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -267,7 +267,10 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event) std::array textEpdContent = parseZapNotify(zapAmount, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); - Serial.printf("Got a zap of %llu sats for %s\n", zapAmount, zapPubkey.c_str()); + if (debugLogEnabled()) + { + Serial.printf("Got a zap of %llu sats for %s\n", zapAmount, zapPubkey.c_str()); + } uint64_t timerPeriod = 0; if (isTimerActive()) diff --git a/src/lib/v2_notify.cpp b/src/lib/v2_notify.cpp index e0b5966..5c30ad2 100644 --- a/src/lib/v2_notify.cpp +++ b/src/lib/v2_notify.cpp @@ -8,25 +8,36 @@ namespace V2Notify TaskHandle_t v2NotifyTaskHandle; + String currentHostname; + void setupV2Notify() { String hostname = "ws.btclock.dev"; - if (preferences.getBool("stagingSource", DEFAULT_STAGING_SOURCE)) + if (preferences.getBool("ceEnabled", DEFAULT_CUSTOM_ENDPOINT_ENABLED)) { - Serial.println(F("Connecting to V2 staging source")); - hostname = "ws-staging.btclock.dev"; + Serial.println(F("Connecting to custom source")); + hostname = preferences.getString("ceEndpoint", DEFAULT_CUSTOM_ENDPOINT); + bool useSSL = !preferences.getBool("ceDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); + + if (useSSL) { + webSocket.beginSSL(hostname, 443, "/api/v2/ws"); + } else { + webSocket.begin(hostname, 80, "/api/v2/ws"); + } } else { Serial.println(F("Connecting to V2 source")); + webSocket.beginSSL(hostname, 443, "/api/v2/ws"); } - webSocket.beginSSL(hostname, 443, "/api/v2/ws"); webSocket.onEvent(V2Notify::onWebsocketV2Event); webSocket.setReconnectInterval(5000); webSocket.enableHeartbeat(15000, 3000, 2); V2Notify::setupV2NotifyTask(); + + currentHostname = hostname; } void onWebsocketV2Event(WStype_t type, uint8_t *payload, size_t length) @@ -38,7 +49,9 @@ namespace V2Notify break; case WStype_CONNECTED: { - Serial.print(F("[WSc] Connected to url:")); + Serial.print(F("[WSc] Connected to ")); + Serial.print(currentHostname); + Serial.print(F(": ")); Serial.println((char *)payload); JsonDocument response; diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 4a8a8f5..2571505 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -3,7 +3,7 @@ static const char* JSON_CONTENT = "application/json"; static const char *const PROGMEM strSettings[] = { - "hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl"}; + "hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl", "ceEndpoint"}; static const char *const PROGMEM uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout", "srcV2Currency"}; @@ -15,7 +15,8 @@ static const char *const PROGMEM boolSettings[] = {"fetchEurPrice", "ledTestOnPo "flAlwaysOn", "flDisable", "flFlashOnUpd", "mempoolSecure", "useNostr", "bitaxeEnabled", "miningPoolStats", "verticalDesc", - "nostrZapNotify", "stagingSource", "httpAuthEnabled"}; + "nostrZapNotify", "ceEnabled", "httpAuthEnabled", + "enableDebugLog", "ceDisableSSL"}; AsyncWebServer server(80); AsyncEventSource events("/events"); @@ -458,25 +459,22 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) bool settingsChanged = true; - if (settings["fgColor"].is()) + if (settings["invertedColor"].is()) { - String fgColor = settings["fgColor"].as(); - uint32_t color = strtol(fgColor.c_str(), NULL, 16); - preferences.putUInt("fgColor", color); - setFgColor(color); - Serial.print(F("Setting foreground color to ")); - Serial.println(color); - settingsChanged = true; - } - if (settings["bgColor"].is()) - { - String bgColor = settings["bgColor"].as(); - - uint32_t color = strtol(bgColor.c_str(), NULL, 16); - preferences.putUInt("bgColor", color); - setBgColor(color); - Serial.print(F("Setting background color to ")); - Serial.println(bgColor.c_str()); + bool inverted = settings["invertedColor"].as(); + preferences.putBool("invertedColor", inverted); + if (inverted) { + preferences.putUInt("fgColor", GxEPD_WHITE); + preferences.putUInt("bgColor", GxEPD_BLACK); + setFgColor(GxEPD_WHITE); + setBgColor(GxEPD_BLACK); + } else { + preferences.putUInt("fgColor", GxEPD_BLACK); + preferences.putUInt("bgColor", GxEPD_WHITE); + setFgColor(GxEPD_BLACK); + setBgColor(GxEPD_WHITE); + } + Serial.printf("Setting invertedColor to %d\r\n", inverted); settingsChanged = true; } @@ -627,8 +625,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) JsonDocument root; root["numScreens"] = NUM_SCREENS; - root["fgColor"] = getFgColor(); - root["bgColor"] = getBgColor(); + root["invertedColor"] = preferences.getBool("invertedColor", getFgColor() == GxEPD_WHITE); root["timerSeconds"] = getTimerSeconds(); root["timerRunning"] = isTimerActive(); root["minSecPriceUpd"] = preferences.getUInt( @@ -657,13 +654,13 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["verticalDesc"] = preferences.getBool("verticalDesc", DEFAULT_VERTICAL_DESC); root["suffixShareDot"] = preferences.getBool("suffixShareDot", DEFAULT_SUFFIX_SHARE_DOT); + root["enableDebugLog"] = preferences.getBool("enableDebugLog", DEFAULT_ENABLE_DEBUG_LOG); root["hostnamePrefix"] = preferences.getString("hostnamePrefix", DEFAULT_HOSTNAME_PREFIX); root["hostname"] = getMyHostname(); root["ip"] = WiFi.localIP(); root["txPower"] = WiFi.getTxPower(); root["ownDataSource"] = preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE); - root["stagingSource"] = preferences.getBool("stagingSource", DEFAULT_STAGING_SOURCE); root["srcV2Currency"] = preferences.getChar("srcV2Currency", DEFAULT_V2_SOURCE_CURRENCY); root["nostrPubKey"] = preferences.getString("nostrPubKey", DEFAULT_NOSTR_NPUB); @@ -734,6 +731,10 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["poolLogosUrl"] = preferences.getString("poolLogosUrl", DEFAULT_MINING_POOL_LOGOS_URL); + root["ceEnabled"] = preferences.getBool("ceEnabled", DEFAULT_CUSTOM_ENDPOINT_ENABLED); + root["ceEndpoint"] = preferences.getString("ceEndpoint", DEFAULT_CUSTOM_ENDPOINT); + root["ceDisableSSL"] = preferences.getBool("ceDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); + AsyncResponseStream *response = request->beginResponseStream(JSON_CONTENT); serializeJson(root, *response); From 64e518bf58f89749753167a8b6826e10bb6455c5 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 28 Dec 2024 18:19:31 +0100 Subject: [PATCH 089/130] Improve data source selection, clean up unused preferences --- data | 2 +- src/lib/block_notify.cpp | 5 --- src/lib/config.cpp | 64 ++++++++++++++++++++----------- src/lib/config.hpp | 15 +++++++- src/lib/defaults.hpp | 21 +++++++---- src/lib/epd.cpp | 2 +- src/lib/nostr_notify.cpp | 3 +- src/lib/ota.cpp | 38 +++++++++---------- src/lib/price_notify.cpp | 24 +++--------- src/lib/screen_handler.cpp | 2 +- src/lib/v2_notify.cpp | 2 +- src/lib/webserver.cpp | 77 ++++++++++++++++++++++++++------------ src/main.cpp | 4 +- 13 files changed, 155 insertions(+), 104 deletions(-) diff --git a/data b/data index 2ce53eb..4057e18 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 2ce53eb499e00a990be5cb0ea078e146f467ceb4 +Subproject commit 4057e1875508b47d876478d97cff544213fd63d4 diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index e41fc4b..a1ce1fc 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -82,11 +82,6 @@ void setupBlockNotify() xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); } - if (!preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE) && preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) - { - return; - } - // std::strcpy(wsServer, String("wss://" + mempoolInstance + // "/api/v1/ws").c_str()); diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 38fba9e..5870ec4 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -25,6 +25,23 @@ void addScreenMapping(int value, const char *name) screenMappings.push_back({value, name}); } +void setupDataSource() +{ + DataSourceType dataSource = getDataSource(); + bool zapNotifyEnabled = preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED); + + // Setup Nostr if it's either the data source or zap notifications are enabled + if (dataSource == NOSTR_SOURCE || zapNotifyEnabled) { + setupNostrNotify(dataSource == NOSTR_SOURCE, zapNotifyEnabled); + setupNostrTask(); + } + // Setup other data sources if Nostr is not the data source + if (dataSource != NOSTR_SOURCE) { + xTaskCreate(setupWebsocketClients, "setupWebsocketClients", 8192, NULL, + tskIDLE_PRIORITY, NULL); + } +} + void setup() { setupPreferences(); @@ -78,17 +95,8 @@ void setup() setupTasks(); setupTimers(); - if (preferences.getBool("useNostr", DEFAULT_USE_NOSTR) || preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED)) - { - setupNostrNotify(preferences.getBool("useNostr", DEFAULT_USE_NOSTR), preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED)); - setupNostrTask(); - } - - if (!preferences.getBool("useNostr", DEFAULT_USE_NOSTR)) - { - xTaskCreate(setupWebsocketClients, "setupWebsocketClients", 8192, NULL, - tskIDLE_PRIORITY, NULL); - } + // Setup data sources (includes Nostr zap notifications if enabled) + setupDataSource(); if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED)) { @@ -288,22 +296,26 @@ void setupPreferences() preferences.putBool("enableDebugLog", DEFAULT_ENABLE_DEBUG_LOG); } - if (!preferences.isKey("ceEnabled")) { - preferences.putBool("ceEnabled", DEFAULT_CUSTOM_ENDPOINT_ENABLED); + if (!preferences.isKey("dataSource")) { + preferences.putUChar("dataSource", DEFAULT_DATA_SOURCE); } - if (!preferences.isKey("ceEndpoint")) { - preferences.putString("ceEndpoint", DEFAULT_CUSTOM_ENDPOINT); + // Initialize custom endpoint settings if not set + if (!preferences.isKey("customEndpoint")) { + preferences.putString("customEndpoint", DEFAULT_CUSTOM_ENDPOINT); } - if (!preferences.isKey("ceDisableSSL")) { - preferences.putBool("ceDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); + if (!preferences.isKey("customEndpointDisableSSL")) { + preferences.putBool("customEndpointDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); } - if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) + // Set currency based on data source + DataSourceType dataSource = static_cast(preferences.getUChar("dataSource", DEFAULT_DATA_SOURCE)); + if (dataSource == BTCLOCK_SOURCE || dataSource == CUSTOM_SOURCE) { ScreenHandler::setCurrentCurrency(preferences.getUChar("lastCurrency", CURRENCY_USD)); - else + } else { ScreenHandler::setCurrentCurrency(CURRENCY_USD); + } if (!preferences.isKey("flDisable")) { preferences.putBool("flDisable", isWhiteVersion() ? false : true); @@ -377,11 +389,13 @@ String replaceAmbiguousChars(String input) void setupWebsocketClients(void *pvParameters) { - if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) + DataSourceType dataSource = getDataSource(); + + if (dataSource == BTCLOCK_SOURCE || dataSource == CUSTOM_SOURCE) { V2Notify::setupV2Notify(); } - else + else if (dataSource == THIRD_PARTY_SOURCE) { setupBlockNotify(); setupPriceNotify(); @@ -788,3 +802,11 @@ bool debugLogEnabled() { return preferences.getBool("enableDebugLog", DEFAULT_ENABLE_DEBUG_LOG); } + +DataSourceType getDataSource() { + return static_cast(preferences.getUChar("dataSource", DEFAULT_DATA_SOURCE)); +} + +void setDataSource(DataSourceType source) { + preferences.putUChar("dataSource", static_cast(source)); +} diff --git a/src/lib/config.hpp b/src/lib/config.hpp index 806497c..d8e27b6 100644 --- a/src/lib/config.hpp +++ b/src/lib/config.hpp @@ -31,6 +31,9 @@ #include "BH1750.h" #endif +#include "shared.hpp" +#include "defaults.hpp" + #define NTP_SERVER "pool.ntp.org" #define DEFAULT_TIME_OFFSET_SECONDS 3600 #ifndef MCP_DEV_ADDR @@ -87,4 +90,14 @@ int findScreenIndexByValue(int value); String replaceAmbiguousChars(String input); const char* getFirmwareFilename(); const char* getWebUiFilename(); -// void loadIcons(); \ No newline at end of file +// void loadIcons(); + +extern Preferences preferences; +extern MCP23017 mcp1; +#ifdef IS_BTCLOCK_V8 +extern MCP23017 mcp2; +#endif + +// Expose DataSourceType enum +extern DataSourceType getDataSource(); +extern void setDataSource(DataSourceType source); \ No newline at end of file diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index da4d405..8849817 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -1,4 +1,6 @@ -#define INITIAL_BLOCK_HEIGHT 851500 +#pragma once + +#define INITIAL_BLOCK_HEIGHT 876600 #define INITIAL_LAST_PRICE 50000 #define DEFAULT_TX_POWER 0 @@ -16,16 +18,11 @@ #define DEFAULT_SUFFIX_PRICE false #define DEFAULT_DISABLE_LEDS false #define DEFAULT_DISABLE_FL false -#define DEFAULT_OWN_DATA_SOURCE true -#define DEFAULT_CUSTOM_SOURCE false -#define DEFAULT_CUSTOM_EP "ws-staging.btclock.dev" -#define DEFAULT_CUSTOM_SSL true #define DEFAULT_MOW_MODE false #define DEFAULT_SUFFIX_SHARE_DOT false #define DEFAULT_V2_SOURCE_CURRENCY CURRENCY_USD - #define DEFAULT_TIME_OFFSET_SECONDS 3600 #define DEFAULT_HOSTNAME_PREFIX "btclock" @@ -83,8 +80,16 @@ #define DEFAULT_ENABLE_DEBUG_LOG false #define DEFAULT_DISABLE_FL false -#define DEFAULT_OWN_DATA_SOURCE true -#define DEFAULT_CUSTOM_ENDPOINT_ENABLED false #define DEFAULT_CUSTOM_ENDPOINT "ws-staging.btclock.dev" #define DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL false #define DEFAULT_MOW_MODE false + +// Define data source types +enum DataSourceType { + BTCLOCK_SOURCE = 0, // BTClock's own data source + THIRD_PARTY_SOURCE = 1, // Third party data sources like mempool.space + NOSTR_SOURCE = 2, // Nostr data source + CUSTOM_SOURCE = 3 // Custom data source endpoint +}; + +#define DEFAULT_DATA_SOURCE BTCLOCK_SOURCE diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 528db1d..151b1c0 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -550,7 +550,7 @@ bool renderIcon(const uint dispNum, const String &text, bool partial) LogoData logo = getMiningPoolLogo(); if (logo.size == 0) { - Serial.println("No logo found"); + Serial.println(F("No logo found")); return false; } diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index 46c6ecf..b9a7a46 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -76,7 +76,8 @@ void setupNostrNotify(bool asDatasource, bool zapNotify) void nostrTask(void *pvParameters) { - if(preferences.getBool("useNostr", DEFAULT_USE_NOSTR)) { + DataSourceType dataSource = getDataSource(); + if(dataSource == NOSTR_SOURCE) { int blockFetch = getBlockFetch(); processNewBlock(blockFetch); } diff --git a/src/lib/ota.cpp b/src/lib/ota.cpp index 0d6a57f..9a0a695 100644 --- a/src/lib/ota.cpp +++ b/src/lib/ota.cpp @@ -181,7 +181,7 @@ int downloadUpdateHandler(char updateType) String expectedSHA256 = downloadSHA256(latestRelease.checksumUrl); if (expectedSHA256.isEmpty()) { - Serial.println("Failed to get SHA256 checksum. Aborting update."); + Serial.println(F("Failed to get SHA256 checksum. Aborting update.")); return false; } @@ -217,7 +217,7 @@ int downloadUpdateHandler(char updateType) if (bytesRead != contentLength) { - Serial.println("Failed to read entire firmware"); + Serial.println(F("Failed to read entire firmware")); free(firmware); return false; } @@ -225,14 +225,14 @@ int downloadUpdateHandler(char updateType) // Calculate SHA256 String calculated_sha256 = calculateSHA256(firmware, contentLength); - Serial.print("Calculated checksum: "); + Serial.print(F("Calculated checksum: ")); Serial.println(calculated_sha256); - Serial.print("Expected checksum: "); + Serial.print(F("Expected checksum: ")); Serial.println(expectedSHA256); if (calculated_sha256 != expectedSHA256) { - Serial.println("Checksum mismatch. Aborting update."); + Serial.println(F("Checksum mismatch. Aborting update.")); free(firmware); return false; } @@ -258,15 +258,15 @@ int downloadUpdateHandler(char updateType) if (Update.end()) { - Serial.println("OTA done!"); + Serial.println(F("OTA done!")); if (Update.isFinished()) { - Serial.println("Update successfully completed. Rebooting."); + Serial.println(F("Update successfully completed. Rebooting.")); // ESP.restart(); } else { - Serial.println("Update not finished? Something went wrong!"); + Serial.println(F("Update not finished? Something went wrong!")); free(firmware); return 503; } @@ -280,14 +280,14 @@ int downloadUpdateHandler(char updateType) } else { - Serial.println("Not enough space to begin OTA"); + Serial.println(F("Not enough space to begin OTA")); free(firmware); return 503; } } else { - Serial.println("Invalid content length"); + Serial.println(F("Invalid content length")); return 503; } } @@ -337,7 +337,7 @@ void updateWebUi(String latestRelease, int command) Serial.println(calculated_sha256); if ((command == U_FLASH && expectedSHA256.equals(calculated_sha256)) || command == U_SPIFFS) { - Serial.println("Checksum verified. Proceeding with update."); + Serial.println(F("Checksum verified. Proceeding with update.")); Update.onProgress(onOTAProgress); @@ -348,38 +348,38 @@ void updateWebUi(String latestRelease, int command) Update.write(buffer, contentLength); if (Update.end()) { - Serial.println("Update complete. Rebooting."); + Serial.println(F("Update complete. Rebooting.")); ESP.restart(); } else { - Serial.println("Error in update process."); + Serial.println(F("Error in update process.")); } } else { - Serial.println("Not enough space to begin OTA"); + Serial.println(F("Not enough space to begin OTA")); } } else { - Serial.println("Checksum mismatch. Aborting update."); + Serial.println(F("Checksum mismatch. Aborting update.")); } } else { - Serial.println("Error downloading firmware"); + Serial.println(F("Error downloading firmware")); } free(buffer); } else { - Serial.println("Not enough memory to allocate buffer"); + Serial.println(F("Not enough memory to allocate buffer")); } } else { - Serial.println("Invalid content length"); + Serial.println(F("Invalid content length")); } } else @@ -417,7 +417,7 @@ String downloadSHA256(const String &sha256Url) { if (sha256Url.isEmpty()) { - Serial.println("Failed to get SHA256 file URL"); + Serial.println(F("Failed to get SHA256 file URL")); return ""; } diff --git a/src/lib/price_notify.cpp b/src/lib/price_notify.cpp index 780f651..0d56a90 100644 --- a/src/lib/price_notify.cpp +++ b/src/lib/price_notify.cpp @@ -1,8 +1,5 @@ #include "price_notify.hpp" -const char *wsOwnServerPrice = "wss://ws.btclock.dev/ws?assets=bitcoin"; -const char *wsOwnServerV2 = "wss://ws-staging.btclock.dev/api/v2/ws"; - const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin"; // WebsocketsClient client; @@ -17,19 +14,12 @@ WebSocketsClient priceNotifyWs; void setupPriceNotify() { - if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) - { - config = {.uri = wsOwnServerPrice, - .user_agent = USER_AGENT}; - } - else - { - config = {.uri = wsServerPrice, - .user_agent = USER_AGENT}; - config.cert_pem = isrg_root_x1cert; + config = {.uri = wsServerPrice, + .user_agent = USER_AGENT}; + config.cert_pem = isrg_root_x1cert; + + config.task_stack = (6*1024); - config.task_stack = (6*1024); - } clientPrice = esp_websocket_client_init(&config); esp_websocket_register_events(clientPrice, WEBSOCKET_EVENT_ANY, @@ -86,10 +76,6 @@ void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base, break; case WEBSOCKET_EVENT_DATA: onWebsocketPriceMessage(data); - if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) - { - onWebsocketBlockMessage(data); - } break; case WEBSOCKET_EVENT_ERROR: Serial.println(F("Price WS Connnection error")); diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 8c7213c..44c0fe0 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -85,7 +85,7 @@ bool ScreenHandler::isCurrencySpecific(uint screen) { } bool ScreenHandler::handleCurrencyRotation(bool forward) { - if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE) && isCurrencySpecific(getCurrentScreen())) { + if ((getDataSource() == BTCLOCK_SOURCE || getDataSource() == CUSTOM_SOURCE) && isCurrencySpecific(getCurrentScreen())) { std::vector ac = getActiveCurrencies(); if (ac.empty()) return false; diff --git a/src/lib/v2_notify.cpp b/src/lib/v2_notify.cpp index 5c30ad2..469e6e1 100644 --- a/src/lib/v2_notify.cpp +++ b/src/lib/v2_notify.cpp @@ -13,7 +13,7 @@ namespace V2Notify void setupV2Notify() { String hostname = "ws.btclock.dev"; - if (preferences.getBool("ceEnabled", DEFAULT_CUSTOM_ENDPOINT_ENABLED)) + if (getDataSource() == CUSTOM_SOURCE) { Serial.println(F("Connecting to custom source")); hostname = preferences.getString("ceEndpoint", DEFAULT_CUSTOM_ENDPOINT); diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 2571505..d1ed533 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -5,17 +5,17 @@ static const char* JSON_CONTENT = "application/json"; static const char *const PROGMEM strSettings[] = { "hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl", "ceEndpoint"}; -static const char *const PROGMEM uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout", "srcV2Currency"}; +static const char *const PROGMEM uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout"}; -static const char *const PROGMEM boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd", +static const char *const PROGMEM boolSettings[] = {"ledTestOnPower", "ledFlashOnUpd", "mdnsEnabled", "otaEnabled", "stealFocus", "mcapBigChar", "useSatsSymbol", "useBlkCountdown", - "suffixPrice", "disableLeds", "ownDataSource", + "suffixPrice", "disableLeds", "mowMode", "suffixShareDot", "flOffWhenDark", "flAlwaysOn", "flDisable", "flFlashOnUpd", - "mempoolSecure", "useNostr", "bitaxeEnabled", + "mempoolSecure", "bitaxeEnabled", "miningPoolStats", "verticalDesc", - "nostrZapNotify", "ceEnabled", "httpAuthEnabled", + "nostrZapNotify", "httpAuthEnabled", "enableDebugLog", "ceDisableSSL"}; AsyncWebServer server(80); @@ -581,6 +581,29 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) } } + // Handle data source setting + if (settings["dataSource"].is()) { + uint8_t dataSource = settings["dataSource"].as(); + if (dataSource <= CUSTOM_SOURCE) { // Validate including custom source + preferences.putUChar("dataSource", dataSource); + Serial.printf("Setting dataSource to %d\r\n", dataSource); + settingsChanged = true; + } + } + + // Handle custom endpoint settings + if (settings["customEndpoint"].is()) { + preferences.putString("customEndpoint", settings["customEndpoint"].as()); + Serial.printf("Setting customEndpoint to %s\r\n", settings["customEndpoint"].as().c_str()); + settingsChanged = true; + } + + if (settings["customEndpointDisableSSL"].is()) { + preferences.putBool("customEndpointDisableSSL", settings["customEndpointDisableSSL"].as()); + Serial.printf("Setting customEndpointDisableSSL to %d\r\n", settings["customEndpointDisableSSL"].as()); + settingsChanged = true; + } + request->send(HTTP_OK); if (settingsChanged) { @@ -590,14 +613,17 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) void onApiRestart(AsyncWebServerRequest *request) { + request->onDisconnect([]() { + delay(500); + + noInterrupts(); + esp_restart(); + }); + request->send(HTTP_OK); if (events.count()) events.send("closing"); - - delay(500); - - esp_restart(); } void onApiIdentify(AsyncWebServerRequest *request) @@ -634,10 +660,25 @@ void onApiSettingsGet(AsyncWebServerRequest *request) preferences.getUInt("fullRefreshMin", DEFAULT_MINUTES_FULL_REFRESH); root["wpTimeout"] = preferences.getUInt("wpTimeout", DEFAULT_WP_TIMEOUT); root["tzOffset"] = preferences.getInt("gmtOffset", DEFAULT_TIME_OFFSET_SECONDS) / 60; - root["mempoolInstance"] = - preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); + + // Add data source settings + root["dataSource"] = preferences.getUChar("dataSource", DEFAULT_DATA_SOURCE); + + // Mempool settings (only used for THIRD_PARTY_SOURCE) + root["mempoolInstance"] = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); root["mempoolSecure"] = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE); - root["useNostr"] = preferences.getBool("useNostr", DEFAULT_USE_NOSTR); + + // Nostr settings (used for NOSTR_SOURCE or when zapNotify is enabled) + root["nostrPubKey"] = preferences.getString("nostrPubKey", DEFAULT_NOSTR_NPUB); + root["nostrRelay"] = preferences.getString("nostrRelay", DEFAULT_NOSTR_RELAY); + root["nostrZapNotify"] = preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED); + root["nostrZapPubkey"] = preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY); + root["ledFlashOnZap"] = preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP); + + // Custom endpoint settings (only used for CUSTOM_SOURCE) + root["customEndpoint"] = preferences.getString("customEndpoint", DEFAULT_CUSTOM_ENDPOINT); + root["customEndpointDisableSSL"] = preferences.getBool("customEndpointDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); + root["ledTestOnPower"] = preferences.getBool("ledTestOnPower", DEFAULT_LED_TEST_ON_POWER); root["ledFlashOnUpd"] = preferences.getBool("ledFlashOnUpd", DEFAULT_LED_FLASH_ON_UPD); root["ledBrightness"] = preferences.getUInt("ledBrightness", DEFAULT_LED_BRIGHTNESS); @@ -645,7 +686,6 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["mcapBigChar"] = preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR); root["mdnsEnabled"] = preferences.getBool("mdnsEnabled", DEFAULT_MDNS_ENABLED); root["otaEnabled"] = preferences.getBool("otaEnabled", DEFAULT_OTA_ENABLED); - // root["fetchEurPrice"] = preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE); root["useSatsSymbol"] = preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL); root["useBlkCountdown"] = preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN); root["suffixPrice"] = preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE); @@ -660,15 +700,6 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["hostname"] = getMyHostname(); root["ip"] = WiFi.localIP(); root["txPower"] = WiFi.getTxPower(); - root["ownDataSource"] = preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE); - root["srcV2Currency"] = preferences.getChar("srcV2Currency", DEFAULT_V2_SOURCE_CURRENCY); - - root["nostrPubKey"] = preferences.getString("nostrPubKey", DEFAULT_NOSTR_NPUB); - root["nostrRelay"] = preferences.getString("nostrRelay", DEFAULT_NOSTR_RELAY); - - root["nostrZapNotify"] = preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED); - root["nostrZapPubkey"] = preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY); - root["ledFlashOnZap"] = preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP); root["gitReleaseUrl"] = preferences.getString("gitReleaseUrl", DEFAULT_GIT_RELEASE_URL); @@ -730,8 +761,6 @@ void onApiSettingsGet(AsyncWebServerRequest *request) } root["poolLogosUrl"] = preferences.getString("poolLogosUrl", DEFAULT_MINING_POOL_LOGOS_URL); - - root["ceEnabled"] = preferences.getBool("ceEnabled", DEFAULT_CUSTOM_ENDPOINT_ENABLED); root["ceEndpoint"] = preferences.getString("ceEndpoint", DEFAULT_CUSTOM_ENDPOINT); root["ceDisableSSL"] = preferences.getBool("ceDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); diff --git a/src/main.cpp b/src/main.cpp index ea24213..4943a51 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -135,7 +135,7 @@ extern "C" void app_main() { Serial.begin(115200); setup(); - bool ownDataSource = preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE); + bool thirdPartySource = getDataSource() == THIRD_PARTY_SOURCE; while (true) { @@ -147,7 +147,7 @@ extern "C" void app_main() { handleFrontlight(); checkWiFiConnection(); - if (!ownDataSource) { + if (thirdPartySource) { monitorDataConnections(); } From 833d46fa5ad1c5b54c91000650f07b364991462f Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 29 Dec 2024 01:31:33 +0100 Subject: [PATCH 090/130] Improve WebUI feedback --- data | 2 +- src/lib/ota.cpp | 1 + src/lib/webserver.cpp | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/data b/data index 4057e18..468e105 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 4057e1875508b47d876478d97cff544213fd63d4 +Subproject commit 468e105adfaded0440ff8bba61a8241d54f28cd4 diff --git a/src/lib/ota.cpp b/src/lib/ota.cpp index 9a0a695..c481b72 100644 --- a/src/lib/ota.cpp +++ b/src/lib/ota.cpp @@ -83,6 +83,7 @@ void handleOTATask(void *parameter) if (xQueueReceive(otaQueue, &msg, 0) == pdTRUE) { if (msg.updateType == UPDATE_ALL) { + isOtaUpdating = true; queueLedEffect(LED_FLASH_UPDATE); int resultWebUi = downloadUpdateHandler(UPDATE_WEBUI); queueLedEffect(LED_FLASH_UPDATE); diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index d1ed533..66c6895 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -232,6 +232,7 @@ JsonDocument getStatusObject() root["currentScreen"] = ScreenHandler::getCurrentScreen(); root["numScreens"] = NUM_SCREENS; root["timerRunning"] = isTimerActive(); + root["isOTAUpdating"] = getIsOTAUpdating(); root["espUptime"] = esp_timer_get_time() / 1000000; // root["currentPrice"] = getPrice(); // root["currentBlockHeight"] = getBlockHeight(); From 73a20cf9a74e360257fbbe56b5bcc332d0600cbc Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 29 Dec 2024 17:11:34 +0100 Subject: [PATCH 091/130] Screen handler bugfix for multi currency --- data | 2 +- src/lib/screen_handler.cpp | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/data b/data index 468e105..48e585d 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 468e105adfaded0440ff8bba61a8241d54f28cd4 +Subproject commit 48e585d4ec12bbc441499936d7cbf53d4307b9ec diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 44c0fe0..f837e5e 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -108,6 +108,7 @@ bool ScreenHandler::handleCurrencyRotation(bool forward) { setCurrentScreen(getCurrentScreen()); return true; } + // If we're at the last/first currency of current screen, let nextScreen/previousScreen handle it return false; } return false; @@ -143,14 +144,38 @@ int ScreenHandler::findNextVisibleScreen(int currentScreen, bool forward) { void ScreenHandler::nextScreen() { if (handleCurrencyRotation(true)) return; + int currentIndex = findScreenIndexByValue(getCurrentScreen()); - setCurrentScreen(findNextVisibleScreen(currentIndex, true)); + int nextScreen = findNextVisibleScreen(currentIndex, true); + + // If moving from a currency-specific screen to another currency-specific screen + // reset to first currency + if (isCurrencySpecific(getCurrentScreen()) && isCurrencySpecific(nextScreen)) { + std::vector ac = getActiveCurrencies(); + if (!ac.empty()) { + setCurrentCurrency(getCurrencyChar(ac.front())); + } + } + + setCurrentScreen(nextScreen); } void ScreenHandler::previousScreen() { if (handleCurrencyRotation(false)) return; + int currentIndex = findScreenIndexByValue(getCurrentScreen()); - setCurrentScreen(findNextVisibleScreen(currentIndex, false)); + int prevScreen = findNextVisibleScreen(currentIndex, false); + + // If moving from a currency-specific screen to another currency-specific screen + // reset to last currency + if (isCurrencySpecific(getCurrentScreen()) && isCurrencySpecific(prevScreen)) { + std::vector ac = getActiveCurrencies(); + if (!ac.empty()) { + setCurrentCurrency(getCurrencyChar(ac.back())); + } + } + + setCurrentScreen(prevScreen); } void ScreenHandler::showSystemStatusScreen() { From 90d91ba21617f6194fdd73a87d2cfe728981e151 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 29 Dec 2024 23:28:22 +0100 Subject: [PATCH 092/130] Compress fonts and add Oswald font --- platformio.ini | 1 + src/fonts/antonio-semibold20.h | 578 +-- src/fonts/antonio-semibold40.h | 2109 +++-------- src/fonts/antonio-semibold90.h | 6284 ++++++-------------------------- src/fonts/fonts.hpp | 80 +- src/fonts/oswald-medium20.h | 323 ++ src/fonts/oswald-medium30.h | 497 +++ src/fonts/oswald-medium80.h | 1083 ++++++ src/lib/defaults.hpp | 5 + src/lib/epd.cpp | 741 ++-- src/lib/epd.hpp | 14 +- src/lib/gzip_decompressor.hpp | 49 + src/lib/webserver.cpp | 4 +- 13 files changed, 4197 insertions(+), 7571 deletions(-) create mode 100644 src/fonts/oswald-medium20.h create mode 100644 src/fonts/oswald-medium30.h create mode 100644 src/fonts/oswald-medium80.h create mode 100644 src/lib/gzip_decompressor.hpp diff --git a/platformio.ini b/platformio.ini index 0dcacd0..b65defd 100644 --- a/platformio.ini +++ b/platformio.ini @@ -30,6 +30,7 @@ build_flags = -DLAST_BUILD_TIME=$UNIX_TIME -DARDUINO_USB_CDC_ON_BOOT -DCORE_DEBUG_LEVEL=0 + -D DEFAULT_BOOT_TEXT=\"BTCLOCK\" -fexceptions build_unflags = -Werror=all diff --git a/src/fonts/antonio-semibold20.h b/src/fonts/antonio-semibold20.h index d544b08..be8b1ec 100644 --- a/src/fonts/antonio-semibold20.h +++ b/src/fonts/antonio-semibold20.h @@ -1,384 +1,191 @@ +#pragma once + #include #include +#include "fonts.hpp" -const uint8_t Antonio_SemiBold20pt7bBitmaps[] PROGMEM = { - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x7B, 0xDE, 0xF7, - 0x98, 0xC6, 0x00, 0x03, 0x8F, 0x01, 0xC7, 0x80, 0xE3, 0x80, 0xF1, 0xC0, - 0x70, 0xE0, 0x38, 0x70, 0x1C, 0x78, 0x0E, 0x3C, 0x07, 0x1C, 0x07, 0x8E, - 0x03, 0x87, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x38, 0xE0, 0x3C, - 0x70, 0x1E, 0x38, 0x0E, 0x1C, 0x07, 0x0E, 0x03, 0x8F, 0x0F, 0xFF, 0xF7, - 0xFF, 0xF8, 0xF1, 0xC0, 0x70, 0xE0, 0x38, 0x70, 0x1C, 0x78, 0x0E, 0x3C, - 0x0F, 0x1C, 0x07, 0x8E, 0x03, 0x87, 0x01, 0xC3, 0x80, 0xE3, 0xC0, 0x71, - 0xE0, 0x78, 0xE0, 0x00, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, - 0x1F, 0xC1, 0xFF, 0x9F, 0xFC, 0xFB, 0xF7, 0x87, 0xBC, 0x3D, 0xE1, 0xEF, - 0x0F, 0x78, 0x7B, 0xE3, 0xDF, 0x00, 0x7C, 0x01, 0xF8, 0x0F, 0xE0, 0x3F, - 0x80, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x3E, 0xF0, 0xF7, 0x87, 0xFC, 0x3F, - 0xE1, 0xFF, 0x0F, 0xFC, 0x7B, 0xFF, 0xCF, 0xFE, 0x3F, 0xE0, 0xFE, 0x01, - 0xC0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0x1F, 0x80, 0x01, 0xC0, - 0x07, 0xFE, 0x00, 0x3C, 0x00, 0x7F, 0xE0, 0x03, 0xC0, 0x0F, 0x9F, 0x00, - 0x38, 0x00, 0xF0, 0xF0, 0x07, 0x80, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0xF0, - 0xF0, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0xF0, 0x00, 0xF0, 0xF0, 0x0E, 0x00, - 0x0F, 0x0F, 0x01, 0xE0, 0x00, 0xF0, 0xF0, 0x1C, 0x00, 0x0F, 0x0F, 0x03, - 0xC0, 0x60, 0xF0, 0xF0, 0x3C, 0x3F, 0xCF, 0x0F, 0x03, 0x87, 0xFE, 0xF0, - 0xF0, 0x78, 0xFF, 0xEF, 0x0F, 0x07, 0x8F, 0x0E, 0xF0, 0xF0, 0xF0, 0xF0, - 0xFF, 0x0F, 0x0F, 0x0E, 0x0F, 0xF0, 0xF0, 0xE0, 0xE0, 0xF7, 0xDF, 0x1E, - 0x0E, 0x0F, 0x7F, 0xE1, 0xE0, 0xE0, 0xF3, 0xFC, 0x1C, 0x0E, 0x0F, 0x1F, - 0x83, 0xC0, 0xE0, 0xF0, 0x00, 0x38, 0x0E, 0x0F, 0x00, 0x07, 0x80, 0xE0, - 0xF0, 0x00, 0x78, 0x0E, 0x0F, 0x00, 0x07, 0x00, 0xE0, 0xF0, 0x00, 0xF0, - 0x0E, 0x0F, 0x00, 0x0E, 0x00, 0xE0, 0xF0, 0x01, 0xE0, 0x0F, 0x0F, 0x00, - 0x1E, 0x00, 0xF1, 0xE0, 0x01, 0xC0, 0x0F, 0xFE, 0x00, 0x3C, 0x00, 0x7F, - 0xC0, 0x03, 0x80, 0x03, 0xF8, 0x03, 0xE0, 0x03, 0xFE, 0x00, 0xFF, 0x80, - 0x7C, 0xF0, 0x1E, 0x1C, 0x07, 0x87, 0x01, 0xE1, 0xC0, 0x78, 0x70, 0x1E, - 0x1C, 0x07, 0x8F, 0x00, 0xF3, 0x80, 0x3D, 0xE0, 0x0F, 0x78, 0x01, 0xFC, - 0x00, 0x7E, 0x00, 0x1F, 0x80, 0x07, 0xC0, 0x03, 0xF0, 0x00, 0xFE, 0x08, - 0x7F, 0x86, 0x3F, 0xE3, 0x8F, 0x3C, 0xF7, 0x8F, 0x79, 0xE1, 0xFC, 0x78, - 0x7F, 0x3C, 0x1F, 0x8F, 0x03, 0xE3, 0xC0, 0xF0, 0xF0, 0x3E, 0x1E, 0x1F, - 0x87, 0xFF, 0xF1, 0xFF, 0xFC, 0x3F, 0xE7, 0x87, 0xF1, 0xE0, 0xFF, 0xFF, - 0xF7, 0x76, 0x66, 0x66, 0x3E, 0xFF, 0xFF, 0xCF, 0x1E, 0x3C, 0x78, 0xF1, - 0xE3, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C, - 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xFB, 0xF7, - 0xE1, 0xC0, 0xF1, 0xF3, 0xF1, 0xE3, 0xC7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9, - 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, - 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7B, 0xF7, 0xEF, 0x98, 0x00, - 0x07, 0x00, 0x1C, 0x04, 0x71, 0x39, 0xCE, 0xFB, 0x7D, 0xFF, 0xC1, 0xFC, - 0x03, 0xE0, 0x3F, 0xE3, 0xEF, 0xFF, 0x73, 0x99, 0xC6, 0x07, 0x08, 0x1C, - 0x00, 0x70, 0x00, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, - 0x8C, 0xE7, 0x31, 0x9C, 0xC0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0x00, - 0xF8, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0E, 0x00, 0xF0, 0x07, 0x80, 0x3C, - 0x01, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x38, 0x03, 0xC0, 0x1E, 0x00, - 0xF0, 0x07, 0x80, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x0F, 0x00, 0x78, - 0x03, 0xC0, 0x1E, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x3C, 0x01, - 0xE0, 0x0F, 0x00, 0x78, 0x07, 0x80, 0x00, 0x0F, 0xC1, 0xFF, 0x9F, 0xFC, - 0xFF, 0xF7, 0x8F, 0xFC, 0x3F, 0xE1, 0xFF, 0x0F, 0xF8, 0x7F, 0xC3, 0xFE, - 0x1F, 0xF0, 0xFF, 0x87, 0xFC, 0x3F, 0xE1, 0xFF, 0x0F, 0xF8, 0x7F, 0xC3, - 0xFE, 0x1F, 0xF0, 0xFF, 0x87, 0xFC, 0x3F, 0xE1, 0xFF, 0x0F, 0xF8, 0x7F, - 0xC3, 0xFE, 0x1F, 0xF0, 0xFF, 0x87, 0xBC, 0x7D, 0xF7, 0xEF, 0xFE, 0x3F, - 0xF0, 0xFF, 0x00, 0x03, 0x83, 0xC3, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, - 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC3, - 0xE1, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, - 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC0, 0x0F, 0x81, 0xFF, 0x1F, 0xF8, 0xFF, - 0xEF, 0x8F, 0x7C, 0x7B, 0xC3, 0xDE, 0x1E, 0xF0, 0xFF, 0x87, 0xFC, 0x3F, - 0xE1, 0xEF, 0x0F, 0x78, 0x78, 0x07, 0xC0, 0x3C, 0x03, 0xE0, 0x1E, 0x01, - 0xF0, 0x0F, 0x00, 0xF8, 0x07, 0x80, 0x7C, 0x07, 0xC0, 0x3E, 0x03, 0xE0, - 0x1F, 0x00, 0xF0, 0x07, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0xFE, 0xFF, 0xF7, - 0xFF, 0x80, 0x0F, 0xC0, 0xFF, 0x87, 0xFF, 0x1F, 0xFE, 0x78, 0xFB, 0xE1, - 0xEF, 0x87, 0xBC, 0x1E, 0xF0, 0x7B, 0xC1, 0xE0, 0x07, 0x80, 0x1E, 0x00, - 0x78, 0x03, 0xE0, 0x3F, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0xC0, 0x0F, 0x00, - 0x3E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0xBC, 0x1E, 0xF0, 0x7F, 0xC1, 0xFF, - 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xE1, 0xE7, 0xDF, 0x9F, 0xFC, 0x3F, 0xE0, - 0x7F, 0x00, 0x01, 0xF0, 0x07, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x1F, - 0xC0, 0x7F, 0x01, 0xFC, 0x06, 0xF0, 0x3B, 0xC0, 0xEF, 0x03, 0xBC, 0x1C, - 0xF0, 0x73, 0xC1, 0xCF, 0x0F, 0x3C, 0x38, 0xF0, 0xE3, 0xC7, 0x8F, 0x1C, - 0x3C, 0x70, 0xF1, 0xC3, 0xCF, 0x0F, 0x38, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, - 0x03, 0xC0, 0xFF, 0xEF, 0xFE, 0xFF, 0xEF, 0xFE, 0xF0, 0x0F, 0x00, 0xF0, - 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF3, 0x0F, 0xFC, 0xFF, 0xEF, 0xFE, 0xF9, - 0xEF, 0x1F, 0xF0, 0xF1, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, - 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x1F, 0xFB, - 0xEF, 0xFE, 0x7F, 0xC3, 0xF8, 0x0F, 0xC0, 0xFF, 0x83, 0xFF, 0x1F, 0xFC, - 0x78, 0xF9, 0xE1, 0xEF, 0x87, 0xBE, 0x1E, 0xF8, 0x7B, 0xE1, 0xEF, 0x80, - 0x3E, 0x00, 0xF8, 0x03, 0xEF, 0x8F, 0xFF, 0x3F, 0xFE, 0xFF, 0xFB, 0xE1, - 0xEF, 0x87, 0xBE, 0x1E, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, - 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x79, 0xE1, 0xE7, 0xFF, 0x9F, - 0xFE, 0x3F, 0xF0, 0x7F, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x7C, 0x01, 0xE0, 0x0F, 0x80, 0x3C, 0x00, 0xF0, 0x07, 0xC0, 0x1E, - 0x00, 0x78, 0x03, 0xE0, 0x0F, 0x80, 0x3C, 0x00, 0xF0, 0x07, 0xC0, 0x1E, - 0x00, 0x78, 0x03, 0xE0, 0x0F, 0x80, 0x3C, 0x00, 0xF0, 0x07, 0xC0, 0x1F, - 0x00, 0x7C, 0x01, 0xF0, 0x07, 0x80, 0x1E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, - 0x80, 0x3E, 0x00, 0xF8, 0x00, 0x1F, 0xC1, 0xFF, 0x1F, 0xFC, 0xFB, 0xFF, - 0x8F, 0xFC, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, - 0xFF, 0x87, 0xBC, 0x79, 0xFF, 0xC7, 0xFC, 0x3F, 0xE3, 0xFF, 0x9E, 0x3D, - 0xF1, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, - 0x1F, 0xE0, 0xFF, 0x07, 0xFC, 0x3F, 0xF7, 0xEF, 0xFE, 0x3F, 0xF0, 0xFE, - 0x00, 0x1F, 0x81, 0xFF, 0x1F, 0xFD, 0xFF, 0xEF, 0x8F, 0x78, 0x7F, 0xC3, - 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, - 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0xC7, 0xDF, 0xFE, 0xFF, 0xF3, 0xFF, 0x80, - 0x3C, 0x01, 0xE0, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x0F, - 0xFC, 0x79, 0xF7, 0xCF, 0xFE, 0x3F, 0xE0, 0xFE, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xF3, 0x9C, 0xCE, 0x73, 0x98, - 0x00, 0x20, 0x0C, 0x07, 0x81, 0xF0, 0xFE, 0x3F, 0x9F, 0xC7, 0xF0, 0xF8, - 0x1C, 0x03, 0xE0, 0x7E, 0x07, 0xF0, 0x3F, 0x03, 0xF8, 0x1F, 0x01, 0xE0, - 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xC0, 0x80, 0x18, 0x03, 0x80, 0x7C, 0x0F, 0xC0, 0xFE, 0x07, - 0xF0, 0x7F, 0x03, 0xE0, 0x3C, 0x0F, 0x83, 0xF1, 0xFC, 0xFE, 0x3F, 0x87, - 0xC0, 0xF0, 0x18, 0x02, 0x00, 0x00, 0x1F, 0x87, 0xFC, 0x7F, 0xEF, 0xFE, - 0xF1, 0xEF, 0x1F, 0xF1, 0xFF, 0x1F, 0xF1, 0xFF, 0x1F, 0xF1, 0xFF, 0x1F, - 0x01, 0xF0, 0x1E, 0x01, 0xE0, 0x3E, 0x03, 0xE0, 0xFC, 0x3F, 0x83, 0xF0, - 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x00, 0x3F, 0x80, - 0x00, 0xFF, 0xF0, 0x00, 0xFF, 0xFC, 0x00, 0xF8, 0x0F, 0x00, 0xF0, 0x03, - 0xC0, 0xF0, 0x00, 0xF0, 0xF0, 0x00, 0x38, 0x78, 0x00, 0x1C, 0x38, 0x1F, - 0x87, 0x3C, 0x3F, 0xE3, 0x9E, 0x1E, 0xF1, 0xCE, 0x1C, 0x38, 0xE7, 0x0E, - 0x1C, 0x77, 0x8E, 0x0E, 0x1F, 0xC7, 0x07, 0x0F, 0xE3, 0x83, 0x87, 0xF1, - 0xC1, 0xC3, 0xF8, 0xE0, 0xE1, 0xFC, 0x70, 0x70, 0xFE, 0x38, 0x38, 0x7F, - 0x1C, 0x1C, 0x77, 0x8E, 0x0E, 0x39, 0xC7, 0x07, 0x1C, 0xE3, 0xC7, 0xCE, - 0x70, 0xF6, 0xFE, 0x3C, 0x7F, 0x3F, 0x1E, 0x1F, 0x0F, 0x07, 0x81, 0x00, - 0x03, 0xC0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1F, 0x80, - 0x70, 0x07, 0xFF, 0xF8, 0x00, 0xFF, 0xFE, 0x00, 0x1F, 0xF0, 0x00, 0x07, - 0xC0, 0x07, 0xE0, 0x0F, 0xE0, 0x0F, 0xE0, 0x0F, 0xE0, 0x0F, 0xE0, 0x0F, - 0xE0, 0x0F, 0xF0, 0x0E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E, - 0xF0, 0x1E, 0x70, 0x1E, 0x78, 0x1C, 0x78, 0x3C, 0x78, 0x3C, 0x78, 0x3C, - 0x78, 0x3C, 0x78, 0x3C, 0x3C, 0x3C, 0x3C, 0x7C, 0x3C, 0x78, 0x3C, 0x7F, - 0xFC, 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFE, 0x78, 0x1E, 0xF8, 0x1E, 0xF8, - 0x1E, 0xF0, 0x1E, 0xF0, 0x1F, 0xF0, 0x1F, 0xFF, 0x03, 0xFF, 0x8F, 0xFF, - 0x3F, 0xFC, 0xF0, 0xFB, 0xC3, 0xEF, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xC1, - 0xEF, 0x07, 0xBC, 0x3E, 0xF0, 0xFB, 0xC3, 0xCF, 0xFF, 0x3F, 0xF8, 0xFF, - 0xF3, 0xFF, 0xCF, 0x0F, 0xBC, 0x1E, 0xF0, 0x7B, 0xC1, 0xEF, 0x07, 0xFC, - 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xC3, 0xEF, - 0xFF, 0xBF, 0xFC, 0xFF, 0xE3, 0xFF, 0x00, 0x0F, 0xC0, 0x7F, 0xC3, 0xFF, - 0x9F, 0xFE, 0x7C, 0x79, 0xE1, 0xFF, 0x87, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, - 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, - 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, - 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x1F, 0x78, 0x7D, 0xE1, 0xE7, - 0xEF, 0x8F, 0xFE, 0x3F, 0xF0, 0x3F, 0x80, 0xFF, 0x07, 0xFF, 0x3F, 0xFD, - 0xFF, 0xEF, 0x0F, 0xF8, 0x7F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, - 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, - 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, - 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x7F, 0xFF, 0xDF, 0xFE, 0xFF, - 0xE7, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3C, 0x0F, 0x03, - 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, - 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, - 0xC0, 0xF0, 0x3C, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xF0, - 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, - 0x03, 0xC0, 0xF0, 0x3C, 0x00, 0x0F, 0xE0, 0x7F, 0xC3, 0xFF, 0x9F, 0xFE, - 0x7C, 0x7D, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, - 0xFE, 0x0F, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF9, 0xFF, 0xE7, - 0xFF, 0x9F, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, - 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0x78, 0x3D, 0xE1, 0xF7, 0xEF, 0xCF, - 0xFF, 0x3F, 0xEC, 0x3F, 0x30, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC, 0x1F, - 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, - 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x07, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC, 0x1F, 0xF0, - 0x7F, 0xC1, 0xFF, 0x07, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC, - 0x1F, 0xF0, 0x7F, 0xC1, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xF8, - 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0x00, - 0xF8, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F, - 0x00, 0xF8, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0xF8, 0x7F, 0xC3, 0xFE, - 0x1F, 0xF0, 0xFF, 0x87, 0xFC, 0x3F, 0xE1, 0xEF, 0x0F, 0x78, 0x7B, 0xF7, - 0xCF, 0xFC, 0x7F, 0xE1, 0xFE, 0x00, 0xF0, 0x3D, 0xE0, 0xFB, 0xC1, 0xE7, - 0x83, 0xCF, 0x0F, 0x9E, 0x1E, 0x3C, 0x3C, 0x78, 0xF8, 0xF1, 0xE1, 0xE7, - 0xC3, 0xCF, 0x87, 0x9E, 0x0F, 0x7C, 0x1E, 0xF8, 0x3D, 0xE0, 0x7F, 0xC0, - 0xFF, 0x01, 0xFE, 0x03, 0xFE, 0x07, 0xBC, 0x0F, 0x7C, 0x1E, 0xF8, 0x3C, - 0xF0, 0x79, 0xF0, 0xF1, 0xE1, 0xE3, 0xC3, 0xC7, 0xC7, 0x87, 0x8F, 0x0F, - 0x9E, 0x1F, 0x3C, 0x1E, 0x78, 0x3E, 0xF0, 0x7D, 0xE0, 0x7C, 0xF0, 0x3C, - 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, - 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, - 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x03, - 0xFF, 0xC0, 0x3F, 0xFC, 0x03, 0xFF, 0xC0, 0x3F, 0xFC, 0x03, 0xFF, 0xC0, - 0x7F, 0xFE, 0x07, 0xFF, 0xE0, 0x7F, 0xFE, 0x07, 0xFE, 0xE0, 0x7F, 0xEE, - 0x0F, 0xFE, 0xF0, 0xFF, 0xEF, 0x0E, 0xFE, 0x70, 0xEF, 0xE7, 0x0E, 0xFE, - 0x70, 0xEF, 0xE7, 0x1E, 0xFE, 0x79, 0xCF, 0xE3, 0x9C, 0xFF, 0x39, 0xCF, - 0xF3, 0x9C, 0xFF, 0x3B, 0xCF, 0xF3, 0xF8, 0xFF, 0x1F, 0x8F, 0xF1, 0xF8, - 0xFF, 0x1F, 0x8F, 0xF1, 0xF8, 0xFF, 0x1F, 0x8F, 0xF0, 0xF0, 0xFF, 0x0F, - 0x0F, 0xF0, 0xF0, 0xFF, 0x0F, 0x0F, 0xE0, 0x3F, 0x80, 0xFF, 0x03, 0xFC, - 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFF, 0x0F, 0xFC, 0x3F, 0xF0, 0xFF, - 0xE3, 0xFF, 0x8F, 0xFE, 0x3F, 0xFC, 0xFF, 0xF3, 0xFD, 0xCF, 0xF7, 0xBF, - 0xDE, 0xFF, 0x3B, 0xFC, 0xFF, 0xF3, 0xDF, 0xC7, 0x7F, 0x1F, 0xFC, 0x7F, - 0xF0, 0xFF, 0xC3, 0xFF, 0x0F, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x03, - 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0x70, 0x0F, 0xE0, 0x7F, 0xC3, 0xFF, 0x9F, - 0xFE, 0x7C, 0x7D, 0xE1, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, - 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, - 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, - 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0x78, 0x7D, 0xE1, 0xF7, 0xFF, - 0x8F, 0xFE, 0x3F, 0xF0, 0x3F, 0x80, 0xFF, 0x87, 0xFF, 0x3F, 0xFD, 0xFF, - 0xEF, 0x0F, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, - 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x1F, 0xF0, 0xFF, 0xFF, 0xBF, - 0xFD, 0xFF, 0xCF, 0xF8, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, - 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, - 0x80, 0x00, 0x0F, 0xE0, 0x7F, 0xC3, 0xFF, 0x9F, 0xFE, 0x7C, 0x7D, 0xE1, - 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, - 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, - 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, - 0x83, 0xFE, 0x0F, 0x78, 0x7D, 0xE1, 0xF7, 0xFF, 0x8F, 0xFE, 0x3F, 0xF0, - 0x3F, 0x80, 0x1E, 0x00, 0x3C, 0x00, 0x78, 0x01, 0xE0, 0x03, 0x00, 0xFF, - 0x83, 0xFF, 0x8F, 0xFF, 0x3F, 0xFE, 0xF0, 0xFB, 0xC1, 0xEF, 0x07, 0xBC, - 0x1E, 0xF0, 0x7B, 0xC1, 0xEF, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xC3, 0xEF, - 0x1F, 0x3F, 0xFC, 0xFF, 0xE3, 0xFF, 0xCF, 0x0F, 0xBC, 0x1E, 0xF0, 0x7B, - 0xC1, 0xEF, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xC1, 0xEF, 0x07, 0xBC, 0x1E, - 0xF0, 0x7B, 0xC1, 0xEF, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xC1, 0xF0, 0x0F, - 0xC0, 0xFF, 0xC3, 0xFF, 0x1F, 0xFE, 0x78, 0x79, 0xE1, 0xEF, 0x87, 0xBE, - 0x1F, 0xF8, 0x7D, 0xE1, 0xF7, 0x87, 0xDF, 0x1F, 0x7E, 0x00, 0xFC, 0x01, - 0xF8, 0x03, 0xF0, 0x0F, 0xE0, 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xF9, - 0xE1, 0xF7, 0x87, 0xDE, 0x0F, 0x78, 0x3D, 0xE0, 0xF7, 0x83, 0xDE, 0x0F, - 0x78, 0x3D, 0xE1, 0xF7, 0xEF, 0x8F, 0xFE, 0x3F, 0xF0, 0x3F, 0x80, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, - 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, - 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, - 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, - 0x80, 0xF8, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, - 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, - 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, - 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, - 0x83, 0xFE, 0x0F, 0x78, 0x3D, 0xE1, 0xF7, 0xEF, 0xCF, 0xFE, 0x3F, 0xF8, - 0x7F, 0x80, 0xF0, 0x1F, 0xF0, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF8, 0x1E, - 0x78, 0x1E, 0x78, 0x1E, 0x78, 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0x7C, 0x3C, - 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0x78, - 0x1E, 0x78, 0x1E, 0x78, 0x1E, 0x78, 0x1E, 0x78, 0x1E, 0x70, 0x1E, 0xF0, - 0x0E, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xE0, - 0x0F, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0xF0, 0x3C, - 0x0F, 0xF0, 0x3C, 0x0F, 0xF0, 0x3C, 0x0F, 0xF0, 0x3C, 0x1E, 0xF0, 0x3C, - 0x1E, 0x78, 0x3E, 0x1E, 0x78, 0x7E, 0x1E, 0x78, 0x7E, 0x1E, 0x78, 0x7E, - 0x1E, 0x78, 0x7E, 0x1E, 0x78, 0x7E, 0x1E, 0x78, 0x7E, 0x1E, 0x38, 0x7F, - 0x1C, 0x38, 0xF7, 0x1C, 0x3C, 0xF7, 0x3C, 0x3C, 0xE7, 0x3C, 0x3C, 0xE7, - 0x3C, 0x3C, 0xE7, 0x3C, 0x3C, 0xE7, 0x3C, 0x3C, 0xE7, 0xBC, 0x1D, 0xE3, - 0xB8, 0x1D, 0xC3, 0xB8, 0x1D, 0xC3, 0xB8, 0x1F, 0xC3, 0xB8, 0x1F, 0xC3, - 0xB8, 0x1F, 0xC3, 0xF8, 0x1F, 0xC3, 0xF8, 0x1F, 0xC1, 0xF8, 0x0F, 0x81, - 0xF8, 0x0F, 0x81, 0xF0, 0x0F, 0x81, 0xF0, 0x0F, 0x81, 0xF0, 0x0F, 0x81, - 0xF0, 0x0F, 0x81, 0xF0, 0xF0, 0x3F, 0xC0, 0xF7, 0x07, 0x9E, 0x1E, 0x78, - 0x78, 0xE3, 0xE3, 0xCF, 0x0F, 0x3C, 0x3C, 0xF0, 0x7F, 0x81, 0xFE, 0x07, - 0xF8, 0x0F, 0xE0, 0x3F, 0x00, 0xFC, 0x01, 0xF0, 0x07, 0x80, 0x3E, 0x00, - 0xF8, 0x03, 0xF0, 0x0F, 0xC0, 0x7F, 0x01, 0xFE, 0x07, 0xF8, 0x3F, 0xE0, - 0xF3, 0xC3, 0xCF, 0x0F, 0x3C, 0x78, 0x71, 0xE1, 0xE7, 0x87, 0x9E, 0x0E, - 0xF0, 0x3F, 0xC0, 0xF0, 0xF8, 0x0F, 0x78, 0x1F, 0x78, 0x1E, 0x7C, 0x1E, - 0x3C, 0x1E, 0x3C, 0x3E, 0x3C, 0x3C, 0x3E, 0x3C, 0x1E, 0x3C, 0x1E, 0x78, - 0x1E, 0x78, 0x0F, 0x78, 0x0F, 0x78, 0x0F, 0xF0, 0x0F, 0xF0, 0x07, 0xF0, - 0x07, 0xF0, 0x07, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, - 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, - 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, - 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xFF, 0x01, 0xF0, 0x1E, 0x01, 0xE0, 0x3E, - 0x03, 0xE0, 0x3C, 0x07, 0xC0, 0x7C, 0x07, 0xC0, 0x78, 0x0F, 0x80, 0xF8, - 0x0F, 0x80, 0xF0, 0x1F, 0x01, 0xF0, 0x1E, 0x01, 0xE0, 0x3E, 0x03, 0xE0, - 0x3C, 0x07, 0xC0, 0x7C, 0x07, 0xC0, 0x78, 0x0F, 0x80, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, - 0xFF, 0xFF, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x07, 0x00, 0xF0, 0x1E, 0x03, - 0xC0, 0x78, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x3C, 0x07, 0x80, 0xF0, - 0x1E, 0x01, 0xC0, 0x3C, 0x07, 0x80, 0xF0, 0x0E, 0x01, 0xE0, 0x3C, 0x07, - 0x80, 0xF0, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0x78, 0x0F, 0x01, 0xE0, - 0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, - 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x80, 0x7F, 0x01, 0xFE, 0x03, 0xDC, 0x07, - 0xBC, 0x0E, 0x78, 0x3C, 0xF0, 0x79, 0xE0, 0xF1, 0xE1, 0xE3, 0xC7, 0x87, - 0x8F, 0x0F, 0x1E, 0x0F, 0x3C, 0x1E, 0xF8, 0x3D, 0xE0, 0x7C, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0xF9, 0xE7, 0x8E, 0x38, 0x71, 0xC3, 0x0F, 0xC0, 0xFF, - 0xC3, 0xFF, 0x1F, 0xFE, 0x78, 0x79, 0xE1, 0xEF, 0x87, 0xBE, 0x1E, 0xF8, - 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x7F, 0x0F, 0xFC, 0x7F, 0xF3, 0xE7, 0xDE, - 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, - 0x87, 0xFE, 0x1F, 0xF8, 0x7D, 0xE3, 0xF7, 0xFF, 0xDF, 0xFF, 0x3F, 0x7C, - 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x79, 0xE3, 0xDF, 0x9F, - 0xFE, 0xFF, 0xFF, 0xC7, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, - 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, - 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xFC, - 0x7F, 0xF7, 0xFF, 0xFE, 0xF7, 0xF7, 0x9F, 0x00, 0x0F, 0xC1, 0xFF, 0x8F, - 0xFC, 0xFF, 0xF7, 0x87, 0xBC, 0x3F, 0xE1, 0xFF, 0x0F, 0xF8, 0x7F, 0xC3, - 0xFE, 0x1F, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0x00, 0xF8, 0x07, - 0xC0, 0x3E, 0x1F, 0xF0, 0xFF, 0x87, 0xFC, 0x3F, 0xE1, 0xEF, 0x0F, 0x78, - 0x7B, 0xE7, 0xDF, 0xFC, 0x7F, 0xE1, 0xFE, 0x00, 0x00, 0x7C, 0x01, 0xF0, - 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x7D, 0xF3, 0xFF, 0xDF, 0xFF, 0x7F, 0xFD, - 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, - 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, - 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7D, 0xE1, - 0xF7, 0xDF, 0xDF, 0xFF, 0x3F, 0xFC, 0x7D, 0xF0, 0x0F, 0xC0, 0x7F, 0xC3, - 0xFF, 0x1F, 0xFE, 0x78, 0x79, 0xE1, 0xEF, 0x87, 0xBE, 0x1E, 0xF8, 0x7B, - 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0xF8, 0x03, 0xE0, 0x0F, 0x87, 0xBE, 0x1E, 0xF8, 0x7B, 0xE1, 0xEF, 0x87, - 0x9E, 0x1E, 0x78, 0x79, 0xF3, 0xE7, 0xFF, 0x0F, 0xFC, 0x1F, 0xE0, 0x07, - 0xC3, 0xF1, 0xFC, 0x7C, 0x1E, 0x07, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, - 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, - 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, - 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x80, 0x1F, 0x7C, 0xFF, 0xF7, 0xFF, 0xDF, - 0xFF, 0x78, 0x7D, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, - 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, - 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7D, 0xE1, 0xF7, 0xCF, 0xDF, 0xFF, - 0x3F, 0xFC, 0x7D, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x79, 0xC3, 0xE7, 0xFF, - 0xBF, 0xFC, 0x3F, 0xC0, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, - 0x79, 0xF3, 0xDF, 0xDF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFC, 0x1F, 0xE0, 0xFF, - 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, - 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, - 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xC0, - 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3C, 0x78, 0xF1, 0xE0, 0x00, 0x0F, - 0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9, 0xF3, - 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, - 0xF9, 0xFF, 0xDF, 0xBE, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, - 0xF0, 0x03, 0xC1, 0xFF, 0x07, 0xBC, 0x1E, 0xF0, 0xFB, 0xC3, 0xCF, 0x1F, - 0x3C, 0x78, 0xF1, 0xE3, 0xCF, 0x8F, 0x3C, 0x3D, 0xF0, 0xF7, 0x83, 0xDE, - 0x0F, 0xF8, 0x3F, 0xC0, 0xFF, 0x83, 0xDE, 0x0F, 0x78, 0x3D, 0xF0, 0xF3, - 0xC3, 0xCF, 0x8F, 0x1E, 0x3C, 0x7C, 0xF0, 0xF3, 0xC3, 0xCF, 0x0F, 0xBC, - 0x1E, 0xF0, 0x7F, 0xC0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xE1, - 0xF3, 0xDF, 0xCF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xFC, 0x3F, - 0xC1, 0xE0, 0xFF, 0x07, 0x83, 0xFC, 0x1E, 0x0F, 0xF0, 0x78, 0x3F, 0xC1, - 0xE0, 0xFF, 0x07, 0x83, 0xFC, 0x1E, 0x0F, 0xF0, 0x78, 0x3F, 0xC1, 0xE0, - 0xFF, 0x07, 0x83, 0xFC, 0x1E, 0x0F, 0xF0, 0x78, 0x3F, 0xC1, 0xE0, 0xFF, - 0x07, 0x83, 0xFC, 0x1E, 0x0F, 0xF0, 0x78, 0x3F, 0xC1, 0xE0, 0xFF, 0x07, - 0x83, 0xFC, 0x1E, 0x0F, 0xF0, 0x78, 0x3F, 0xC1, 0xE0, 0xFF, 0x07, 0x83, - 0xFC, 0x1E, 0x0F, 0xF0, 0x78, 0x3C, 0xF3, 0xE7, 0xBF, 0xBF, 0xFF, 0xFF, - 0xFF, 0x87, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, - 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, - 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, - 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0x80, 0x0F, 0xC0, 0x7F, 0x83, 0xFF, 0x1F, - 0xFE, 0x78, 0x79, 0xE1, 0xEF, 0x87, 0xBE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, - 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, - 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xDE, 0x1E, - 0x78, 0x79, 0xF3, 0xE7, 0xFF, 0x0F, 0xFC, 0x1F, 0xE0, 0xF3, 0xC7, 0xBF, - 0xBF, 0xFD, 0xFF, 0xFF, 0x8F, 0xF8, 0x7F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, - 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, - 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, - 0xF8, 0xFF, 0xEF, 0xFF, 0xFD, 0xFF, 0xEF, 0x7E, 0x78, 0x03, 0xC0, 0x1E, - 0x00, 0xF0, 0x07, 0x80, 0x00, 0x1E, 0x7C, 0xFF, 0xF7, 0xFF, 0xDF, 0xFF, - 0x78, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, - 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, - 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0x78, - 0x7D, 0xF7, 0xF7, 0xFF, 0xCF, 0xFF, 0x1F, 0x7C, 0x01, 0xF0, 0x07, 0xC0, - 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0xF3, 0xFB, 0xFF, 0xFF, 0xFF, 0xC7, 0x83, - 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, - 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, - 0x0F, 0x00, 0x1F, 0x83, 0xFE, 0x1F, 0xF9, 0xFF, 0xCF, 0x0F, 0x78, 0x7B, - 0xC3, 0xDE, 0x1E, 0xF0, 0xF7, 0xC7, 0xBE, 0x00, 0xF8, 0x07, 0xE0, 0x1F, - 0x80, 0x7E, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0x80, 0x7D, 0xE1, 0xEF, 0x0F, - 0xF8, 0x7F, 0xC3, 0xFE, 0x1F, 0xF0, 0xF7, 0xEF, 0x9F, 0xFC, 0xFF, 0xC1, - 0xFC, 0x00, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x8F, 0xFF, 0xFF, - 0xFF, 0xCF, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, - 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, - 0xF8, 0x3E, 0x0F, 0x83, 0xF0, 0xFF, 0x1F, 0xC3, 0xF0, 0xF8, 0x3F, 0xE0, - 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, - 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, - 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, - 0x83, 0xFE, 0x0F, 0x78, 0x7D, 0xF3, 0xF7, 0xFF, 0xCF, 0xEF, 0x1F, 0x3C, - 0xF0, 0x7F, 0xC1, 0xEF, 0x07, 0xBC, 0x1E, 0x78, 0x79, 0xE1, 0xE7, 0x87, - 0x9E, 0x1C, 0x78, 0x71, 0xE3, 0xC7, 0x8F, 0x0E, 0x3C, 0x3C, 0xF0, 0xF3, - 0xC3, 0xCE, 0x0F, 0x38, 0x3C, 0xE0, 0xF3, 0x81, 0xDE, 0x07, 0x78, 0x1F, - 0xE0, 0x7F, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, - 0xF0, 0x0F, 0x80, 0xF0, 0x78, 0x7F, 0x87, 0xC3, 0xFC, 0x3E, 0x1F, 0xE1, - 0xF0, 0xF7, 0x0F, 0x87, 0xB8, 0x7C, 0x39, 0xC3, 0xE1, 0xCE, 0x1F, 0x8E, - 0x79, 0xDC, 0x73, 0xCE, 0xE7, 0x9E, 0x77, 0x3C, 0xF3, 0xB9, 0xE3, 0x9D, - 0xCF, 0x1C, 0xE6, 0x70, 0xE7, 0x3B, 0x87, 0x71, 0xDC, 0x3B, 0x8E, 0xE1, - 0xDC, 0x77, 0x0F, 0xE3, 0xB8, 0x7F, 0x1D, 0xC3, 0xF8, 0xFE, 0x0F, 0x83, - 0xE0, 0x7C, 0x1F, 0x03, 0xE0, 0xF8, 0x1F, 0x07, 0xC0, 0xF8, 0x3E, 0x07, - 0xC1, 0xF0, 0x3E, 0x0F, 0x81, 0xE0, 0x7C, 0x00, 0xF0, 0x7B, 0xC1, 0xE7, - 0x87, 0x9E, 0x3C, 0x78, 0xF0, 0xF3, 0xC3, 0xCE, 0x0F, 0x78, 0x1F, 0xE0, - 0x7F, 0x01, 0xFC, 0x03, 0xF0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, - 0x0F, 0x80, 0x7F, 0x01, 0xFC, 0x07, 0xF0, 0x3D, 0xE0, 0xF7, 0x83, 0xDE, - 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xCF, 0x07, 0xBC, 0x1E, 0xF0, 0x7C, 0xF0, - 0x3F, 0xC0, 0xFF, 0x07, 0xFE, 0x1E, 0x78, 0x79, 0xE1, 0xE7, 0x87, 0x9E, - 0x1E, 0x78, 0x79, 0xE1, 0xC3, 0x87, 0x0F, 0x3C, 0x3C, 0xF0, 0xF3, 0xC3, - 0xCF, 0x0F, 0x3C, 0x1C, 0xE0, 0x73, 0x81, 0xCE, 0x07, 0xB8, 0x1F, 0xE0, - 0x7F, 0x80, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, - 0x07, 0x80, 0x1E, 0x00, 0xF8, 0x1F, 0xE0, 0x7F, 0x01, 0xFC, 0x00, 0x7F, - 0xEF, 0xFD, 0xFF, 0xBF, 0xF0, 0x1E, 0x07, 0xC0, 0xF0, 0x1E, 0x07, 0xC0, - 0xF0, 0x1E, 0x03, 0xC0, 0xF8, 0x1E, 0x03, 0xC0, 0xF8, 0x1E, 0x03, 0xC0, - 0xF8, 0x1F, 0x03, 0xC0, 0x78, 0x1F, 0x03, 0xC0, 0x78, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x07, 0xC3, 0xF1, 0xFC, 0x7E, 0x1E, 0x07, 0x81, 0xE0, - 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0xF8, 0x7E, - 0x3F, 0x0F, 0x83, 0xF0, 0xFE, 0x0F, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, - 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0xC1, 0xFC, 0x3F, - 0x07, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF8, 0x3F, 0x0F, - 0xC1, 0xF8, 0x3E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, - 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1F, 0x83, 0xF0, 0x7C, 0x3F, 0x1F, 0xC7, - 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, - 0x78, 0x3E, 0x0F, 0x8F, 0xC3, 0xF0, 0xF8, 0x00, 0x1E, 0x07, 0x9F, 0xF3, - 0xDF, 0xFF, 0xDF, 0xFF, 0xEF, 0xFF, 0xE1, 0x03, 0xE0}; +const uint8_t Antonio_SemiBold20pt7bBitmaps_Gzip[] = { + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xa5, 0x57, + 0x4f, 0x6f, 0xe3, 0xba, 0x11, 0xa7, 0xaa, 0xe2, 0xf1, 0x1d, 0x16, 0xe6, + 0xf5, 0x1d, 0xbc, 0x62, 0x3f, 0xc2, 0xeb, 0xcd, 0x8b, 0x55, 0xac, 0xaf, + 0xf2, 0x4e, 0x7b, 0x76, 0xb0, 0x40, 0x57, 0x46, 0x94, 0x48, 0x81, 0x81, + 0xea, 0x52, 0xac, 0xaf, 0x5b, 0x60, 0x9b, 0x7c, 0x8d, 0x2d, 0x10, 0x6c, + 0x64, 0x08, 0x78, 0xbe, 0x45, 0x5f, 0x60, 0x11, 0x53, 0x10, 0x50, 0x5f, + 0x8a, 0x8a, 0x86, 0x80, 0x4a, 0x41, 0x14, 0xb1, 0x3f, 0xd2, 0x72, 0xfe, + 0x6c, 0xb2, 0xd9, 0xd7, 0x96, 0xa4, 0x39, 0x43, 0x8a, 0x96, 0x86, 0x33, + 0xc3, 0xdf, 0x0c, 0x89, 0xea, 0xcb, 0x1b, 0x5d, 0x08, 0xd3, 0x6c, 0x79, + 0x70, 0x59, 0x7f, 0xf8, 0x95, 0xd8, 0x73, 0x6b, 0x19, 0x15, 0xd1, 0x26, + 0x99, 0x88, 0xd1, 0x64, 0xe8, 0x0f, 0x5c, 0x3a, 0xa4, 0xef, 0xed, 0x98, + 0x9b, 0xe5, 0xed, 0x48, 0xb8, 0x13, 0x67, 0x34, 0x18, 0xd2, 0x81, 0x3d, + 0x67, 0xaa, 0x56, 0xcd, 0xdd, 0x3a, 0x66, 0xd6, 0x59, 0x69, 0x54, 0x24, + 0xfb, 0xc2, 0x17, 0xe4, 0x07, 0xf2, 0xb3, 0x15, 0xbd, 0x20, 0xbf, 0xf0, + 0x85, 0x3a, 0x6d, 0xaf, 0xeb, 0xf8, 0x6c, 0x2f, 0x2f, 0x99, 0x7f, 0x50, + 0xac, 0x48, 0x60, 0x35, 0x4c, 0x78, 0x51, 0x60, 0x49, 0x9a, 0x8c, 0x65, + 0x1d, 0xb7, 0x5e, 0xae, 0x58, 0x7b, 0xa0, 0xb2, 0xce, 0x13, 0x9d, 0x95, + 0x0c, 0xc8, 0xc4, 0x8e, 0x86, 0x84, 0x47, 0x56, 0x42, 0x3b, 0xe2, 0x92, + 0x50, 0xd8, 0x09, 0x3b, 0x25, 0x23, 0x22, 0x25, 0x8d, 0x18, 0x23, 0x13, + 0x30, 0x8c, 0x80, 0x91, 0x60, 0x06, 0x60, 0x2c, 0x01, 0x66, 0x08, 0xc6, + 0x4e, 0x7e, 0x91, 0xd2, 0xf5, 0x32, 0x66, 0xc7, 0x9d, 0x94, 0xbe, 0x2a, + 0x19, 0x9d, 0x0f, 0x24, 0x8a, 0x62, 0x6c, 0xc0, 0xa4, 0x14, 0xa2, 0x5e, + 0x39, 0x03, 0x16, 0xe6, 0x42, 0x54, 0xed, 0x70, 0xc0, 0xf8, 0x2c, 0x11, + 0x92, 0x8c, 0x06, 0x8c, 0xd0, 0x08, 0x8c, 0xaf, 0x19, 0x02, 0x46, 0x82, + 0x19, 0x80, 0xb1, 0x04, 0xbe, 0xe2, 0x90, 0x8d, 0xb0, 0x12, 0x66, 0x24, + 0x49, 0xec, 0xc8, 0x6e, 0x6c, 0x61, 0x77, 0x44, 0x45, 0x81, 0x74, 0x86, + 0x34, 0xb6, 0xf2, 0xc4, 0x9f, 0x80, 0x99, 0x93, 0x2a, 0xda, 0x13, 0xcc, + 0xb7, 0x5a, 0x72, 0x04, 0xd1, 0x69, 0x62, 0x4b, 0xd2, 0xfd, 0x18, 0xfe, + 0xd9, 0x2b, 0xe6, 0x6e, 0x3d, 0x9f, 0xe6, 0xad, 0x1f, 0xba, 0x7c, 0x6e, + 0x17, 0x89, 0x94, 0x63, 0x87, 0xc7, 0x6a, 0xa3, 0x5a, 0x6f, 0x1d, 0x6f, + 0x84, 0x52, 0xf5, 0x9f, 0xde, 0xbc, 0x19, 0x2b, 0x95, 0x39, 0xae, 0xbf, + 0x29, 0x96, 0xf3, 0x27, 0xc8, 0x75, 0x9d, 0x27, 0x9b, 0x0a, 0xc3, 0xec, + 0x74, 0x1c, 0x5c, 0x55, 0xeb, 0x47, 0xe4, 0xa0, 0x2e, 0x3f, 0x40, 0xf2, + 0xe1, 0xef, 0xf7, 0x5f, 0x5d, 0x5c, 0x1f, 0xaa, 0x45, 0x6b, 0x0b, 0xaf, + 0x28, 0xd5, 0xdb, 0xbf, 0xfe, 0x4a, 0x7f, 0x1c, 0x42, 0x5f, 0x50, 0x15, + 0x9a, 0x36, 0xa0, 0xd6, 0x5c, 0xcf, 0xff, 0x65, 0xfd, 0xc7, 0x8f, 0x09, + 0x28, 0x44, 0x20, 0x0d, 0x8d, 0x5c, 0x4b, 0x0c, 0x88, 0xd4, 0x34, 0x71, + 0x34, 0x1d, 0xd9, 0x5b, 0xea, 0x1b, 0xca, 0x88, 0xa6, 0xd0, 0x87, 0xa6, + 0xae, 0xa1, 0x34, 0x22, 0x4c, 0x9b, 0x56, 0xd5, 0x73, 0x63, 0xc0, 0x26, + 0x4c, 0x3b, 0x2e, 0x55, 0xfc, 0xed, 0xc1, 0xd9, 0x61, 0x5d, 0x76, 0x9e, + 0x54, 0xc4, 0x9e, 0xa5, 0x85, 0x96, 0xe6, 0x94, 0xc5, 0x69, 0x2e, 0x9b, + 0x60, 0xcc, 0x9f, 0x62, 0x12, 0x76, 0xac, 0x78, 0xa3, 0xca, 0x79, 0x70, + 0x90, 0x5e, 0x3a, 0xdb, 0x97, 0xc1, 0x83, 0x7c, 0x9a, 0xb8, 0xb6, 0x70, + 0x2c, 0xc8, 0x04, 0xb1, 0x03, 0xb8, 0x90, 0x2d, 0xb8, 0x96, 0x34, 0x00, + 0xed, 0xe0, 0x93, 0x11, 0x4b, 0x54, 0xac, 0x78, 0xe7, 0x5f, 0xe7, 0x65, + 0x7c, 0xe6, 0xc8, 0x83, 0x85, 0xa0, 0x91, 0x03, 0xc1, 0x85, 0x67, 0x35, + 0x54, 0xf0, 0x84, 0x91, 0x31, 0xf1, 0x2d, 0x41, 0xf1, 0x2c, 0x5c, 0x28, + 0x4d, 0x0e, 0xf2, 0xf5, 0xea, 0xb4, 0xf5, 0x44, 0x48, 0xb4, 0x4f, 0x7a, + 0xa4, 0xb5, 0x25, 0x4f, 0x42, 0xab, 0xfd, 0x41, 0xbe, 0x4e, 0x4a, 0xfb, + 0x6c, 0x28, 0xdf, 0x2e, 0x32, 0xe6, 0x8e, 0x24, 0x2c, 0x32, 0x74, 0x27, + 0x9b, 0x34, 0x63, 0x23, 0xb7, 0x3f, 0x41, 0x44, 0xc2, 0x3b, 0xe1, 0x1b, + 0x20, 0xaa, 0xec, 0xd0, 0x7a, 0x0d, 0x33, 0x52, 0xb1, 0x16, 0xc3, 0xab, + 0x92, 0xcb, 0xcd, 0x6e, 0x4a, 0x32, 0xb8, 0xa2, 0x69, 0xfc, 0xba, 0xec, + 0xc2, 0xb4, 0x81, 0xa8, 0x33, 0xc5, 0x5b, 0xff, 0x0a, 0xa2, 0x7e, 0x76, + 0x9a, 0x83, 0xbc, 0x8c, 0xc6, 0xa4, 0xb1, 0xcb, 0xb9, 0xf2, 0x3a, 0x75, + 0xbd, 0x9d, 0x0c, 0x73, 0x15, 0x77, 0x7c, 0x47, 0xa6, 0xf9, 0x5a, 0x9d, + 0x42, 0x8b, 0x61, 0xb4, 0x13, 0x20, 0x80, 0x39, 0x22, 0x08, 0x40, 0x13, + 0xb3, 0xc9, 0x27, 0x78, 0x4e, 0xf4, 0x59, 0x83, 0x0e, 0x1a, 0x3d, 0x85, + 0x0f, 0x10, 0x1c, 0x4a, 0xde, 0x5e, 0x2b, 0x58, 0x6e, 0xd1, 0x31, 0x19, + 0xce, 0x5a, 0x2e, 0x60, 0x9f, 0xa9, 0x5a, 0xb6, 0x5e, 0xa1, 0x4e, 0xf6, + 0x36, 0x8a, 0x36, 0xf7, 0x9e, 0xd0, 0xd6, 0x33, 0x96, 0xeb, 0x08, 0x87, + 0x49, 0x6e, 0x60, 0x12, 0x1f, 0x26, 0xbd, 0x7d, 0xda, 0x2f, 0x5d, 0xae, + 0x3a, 0x55, 0x29, 0xed, 0x48, 0xbb, 0x27, 0xac, 0x9d, 0xd6, 0xe6, 0x50, + 0x13, 0x78, 0x1e, 0x41, 0x31, 0x40, 0xa3, 0x22, 0xcd, 0x12, 0x20, 0x4a, + 0xf5, 0xf1, 0xe2, 0xed, 0x07, 0xf2, 0x87, 0x17, 0xf4, 0x58, 0x76, 0xde, + 0xe9, 0x52, 0x36, 0x43, 0x5b, 0x1c, 0x51, 0xe9, 0xd9, 0x0d, 0xb7, 0xc4, + 0x0b, 0xa2, 0x77, 0xd8, 0xf6, 0xff, 0x4a, 0xa2, 0x9f, 0xec, 0x28, 0x60, + 0x49, 0x47, 0x65, 0x68, 0x0b, 0x97, 0xcd, 0x36, 0x6d, 0xe7, 0xc5, 0x89, + 0xfc, 0xe9, 0x77, 0x78, 0x53, 0xdc, 0x86, 0x65, 0xb7, 0x29, 0xf9, 0x46, + 0xf5, 0xcd, 0x92, 0xf0, 0x55, 0xf8, 0x45, 0xeb, 0xcd, 0xa4, 0x0b, 0x87, + 0x45, 0x33, 0xdf, 0xec, 0x79, 0x3b, 0x21, 0x5e, 0x44, 0x20, 0x12, 0x5e, + 0xdf, 0x30, 0x6d, 0x3a, 0x0d, 0x25, 0x64, 0xe4, 0x93, 0xe1, 0x88, 0xc7, + 0xae, 0x57, 0x9c, 0x38, 0x9b, 0x8b, 0xe1, 0x68, 0x3d, 0x18, 0xbe, 0x7b, + 0x3f, 0xe0, 0x4b, 0xca, 0x8a, 0x59, 0xbc, 0x59, 0xa4, 0x8d, 0xc8, 0xdb, + 0xc9, 0xa4, 0x1b, 0x8d, 0xc2, 0xa1, 0x7e, 0xf0, 0x6a, 0x49, 0x87, 0xc5, + 0xf2, 0x62, 0xf2, 0xef, 0xce, 0x0d, 0x3d, 0x87, 0x33, 0x7a, 0x4c, 0xf0, + 0x62, 0xa0, 0x12, 0xbc, 0x01, 0x10, 0x30, 0xa1, 0xaa, 0x21, 0x0a, 0x2a, + 0x93, 0x84, 0x26, 0x54, 0xb0, 0xbb, 0x2a, 0x07, 0xd2, 0xd9, 0xd5, 0x89, + 0xe3, 0x0f, 0x7d, 0x77, 0x57, 0x51, 0x02, 0x90, 0xb0, 0x45, 0xed, 0xc2, + 0xce, 0x77, 0x1a, 0x54, 0x2c, 0xe3, 0x92, 0x2b, 0x5b, 0xc1, 0x29, 0x5a, + 0x79, 0x9d, 0x96, 0xc6, 0x63, 0x17, 0x20, 0x63, 0x8c, 0x32, 0xe5, 0x35, + 0x50, 0x7b, 0xc6, 0xfa, 0xc9, 0x96, 0xdf, 0x3a, 0x75, 0x5a, 0xaa, 0xf3, + 0x56, 0x15, 0x8a, 0xb0, 0x24, 0x4c, 0xe1, 0x34, 0xc1, 0x54, 0xbb, 0x10, + 0x6b, 0x3c, 0xa1, 0x66, 0x86, 0x18, 0x5f, 0xe8, 0x5d, 0xe2, 0x76, 0x12, + 0x84, 0xfb, 0x87, 0xf9, 0xba, 0x9c, 0xc3, 0xe2, 0x5e, 0xa4, 0xa8, 0xf2, + 0x60, 0x71, 0x1c, 0xe2, 0xc5, 0x23, 0x8b, 0x3f, 0x35, 0x08, 0x15, 0xdc, + 0x60, 0xdd, 0x12, 0x63, 0x69, 0xe9, 0x02, 0x93, 0x6f, 0x3b, 0x33, 0x95, + 0x3c, 0x98, 0x33, 0x8b, 0x1e, 0x2f, 0x35, 0x33, 0xf6, 0xc3, 0xa5, 0xba, + 0x23, 0x4c, 0x6c, 0x77, 0x72, 0x78, 0x4f, 0x5a, 0xd6, 0x6f, 0xe1, 0x4a, + 0xe9, 0x93, 0xc1, 0x1e, 0xec, 0x84, 0xf9, 0x7b, 0x79, 0x5d, 0x42, 0x47, + 0xff, 0xf4, 0x7e, 0x36, 0x7a, 0xe9, 0xd5, 0xf3, 0x80, 0xf4, 0xe5, 0xc9, + 0x67, 0x5b, 0x22, 0xd5, 0xd7, 0x05, 0xd8, 0x93, 0x8c, 0x81, 0x41, 0x06, + 0x75, 0x9e, 0x1c, 0xdc, 0x83, 0x40, 0x1d, 0xf7, 0xea, 0xac, 0x0d, 0xf3, + 0x8e, 0xc8, 0x3d, 0x71, 0xbd, 0x58, 0xcf, 0x32, 0x76, 0xe2, 0xb8, 0xae, + 0xdf, 0x6c, 0xf2, 0x75, 0x9a, 0xc5, 0x27, 0x2c, 0x70, 0x9a, 0x3d, 0x11, + 0x26, 0xca, 0xea, 0xec, 0x8e, 0x9e, 0xe9, 0xa1, 0x2b, 0xa7, 0x72, 0x93, + 0x17, 0xe9, 0x72, 0x19, 0xcf, 0xd9, 0x09, 0x77, 0x1d, 0x7f, 0x2c, 0x0f, + 0x45, 0xf0, 0x48, 0x25, 0x4f, 0x76, 0x46, 0xa1, 0x8d, 0xa5, 0x22, 0xde, + 0xd8, 0x2a, 0xf1, 0xda, 0x5d, 0x17, 0x76, 0x54, 0x09, 0x74, 0x9d, 0x08, + 0xff, 0xc5, 0x3a, 0xa9, 0xca, 0x41, 0x37, 0x29, 0xd7, 0xa6, 0x73, 0xba, + 0x69, 0x56, 0x7c, 0x54, 0xaf, 0xb2, 0xea, 0xa3, 0x7a, 0x9d, 0x55, 0x8d, + 0xe2, 0xf3, 0xcd, 0x6d, 0x67, 0x22, 0xa8, 0xe9, 0x10, 0xb7, 0x95, 0xdd, + 0x6e, 0xb5, 0x8b, 0xf3, 0x0d, 0x34, 0x2f, 0x14, 0x1c, 0xa5, 0x55, 0xd5, + 0x4d, 0x56, 0x9f, 0x5f, 0xaa, 0xd7, 0xe0, 0x56, 0xcb, 0x90, 0xb7, 0xa1, + 0x54, 0x29, 0x16, 0x18, 0x25, 0xe2, 0x0f, 0xd2, 0x4b, 0x26, 0xb7, 0xc6, + 0xcb, 0xef, 0x1b, 0xef, 0x19, 0x02, 0x37, 0xac, 0x55, 0xef, 0x86, 0x71, + 0xef, 0x86, 0x5f, 0x7b, 0x1e, 0x54, 0xac, 0xce, 0x6f, 0x54, 0xd6, 0xf8, + 0x7d, 0xc0, 0x72, 0xfb, 0x28, 0x65, 0x06, 0xe4, 0xff, 0xf9, 0xa6, 0x83, + 0x83, 0x8c, 0x38, 0x61, 0x13, 0x6c, 0x55, 0x03, 0xb2, 0xbc, 0x5e, 0xdc, + 0x9d, 0x3d, 0x73, 0xbe, 0xb8, 0xa7, 0xcf, 0xd7, 0xed, 0xd9, 0x7b, 0x82, + 0x48, 0x20, 0x7c, 0xaa, 0x83, 0xd1, 0x54, 0x83, 0x39, 0x6f, 0xf0, 0xf6, + 0x78, 0xc5, 0x8f, 0x48, 0x6b, 0x35, 0xb6, 0x64, 0x82, 0x47, 0x1e, 0xf2, + 0x85, 0x2b, 0x4c, 0x5e, 0xc2, 0x55, 0x45, 0x3d, 0xbb, 0xdc, 0x7a, 0x6c, + 0xbf, 0x69, 0x53, 0x58, 0xd4, 0xfc, 0xf6, 0xf6, 0x1b, 0x76, 0xf8, 0xd4, + 0x01, 0xe9, 0xbc, 0x26, 0x8c, 0x00, 0x33, 0x06, 0x93, 0x1a, 0xc7, 0xd7, + 0xd5, 0x20, 0x52, 0xe0, 0xf6, 0xc5, 0x0c, 0x9d, 0x5d, 0x9d, 0x38, 0x00, + 0x31, 0xb6, 0xab, 0x00, 0x35, 0xda, 0x57, 0x38, 0xdf, 0xae, 0x39, 0x52, + 0x3b, 0xad, 0xe3, 0x1f, 0x7d, 0xdd, 0x80, 0x9f, 0xa3, 0x7a, 0xe8, 0xd6, + 0xae, 0xbb, 0xbe, 0xdf, 0xce, 0x5e, 0x16, 0x9f, 0x5e, 0xa6, 0xba, 0xf1, + 0xbe, 0x35, 0xba, 0x2d, 0x1a, 0x76, 0x8c, 0x26, 0xef, 0x37, 0x78, 0x53, + 0x4d, 0x4f, 0x1c, 0xdf, 0x2f, 0x0a, 0xc4, 0x65, 0x57, 0x86, 0xc7, 0x1d, + 0xd5, 0x39, 0x25, 0xd4, 0x0a, 0xa3, 0x6b, 0x50, 0x83, 0xde, 0x43, 0x0b, + 0x93, 0x9e, 0xa8, 0x10, 0xad, 0x5d, 0x7f, 0x3f, 0x5f, 0xc7, 0x27, 0x03, + 0xfc, 0x4f, 0x36, 0xcc, 0xe7, 0xbe, 0x13, 0x38, 0xae, 0xe3, 0x8e, 0x5d, + 0x34, 0x30, 0xd8, 0x11, 0xd3, 0x15, 0x7b, 0xa1, 0xba, 0x0a, 0xfb, 0x3b, + 0x35, 0xac, 0x15, 0xda, 0x2e, 0xca, 0xb8, 0x34, 0x41, 0x1a, 0xe2, 0x1b, + 0x03, 0x48, 0xfe, 0x68, 0xf6, 0x0e, 0x34, 0xe4, 0x33, 0x45, 0x3f, 0x76, + 0xec, 0xc4, 0xa7, 0x64, 0x4b, 0x22, 0x4d, 0x5c, 0x4d, 0x2c, 0x43, 0x06, + 0x96, 0xd0, 0x84, 0x19, 0xe2, 0x6b, 0x62, 0x7c, 0xe3, 0x99, 0xa2, 0x1f, + 0x27, 0x70, 0xb0, 0x08, 0x8a, 0xb0, 0xbf, 0xd0, 0xb3, 0x81, 0x0f, 0x4c, + 0x11, 0xc0, 0x14, 0x8d, 0x28, 0x0e, 0x73, 0x35, 0xe4, 0x04, 0x46, 0xac, + 0xab, 0xf5, 0xfb, 0xd1, 0x7e, 0xfa, 0xc0, 0x53, 0x9d, 0xc6, 0xa4, 0xe7, + 0x21, 0x6b, 0xc3, 0x6a, 0x7d, 0xc9, 0xbf, 0x4a, 0x42, 0x0e, 0x8b, 0x5a, + 0xad, 0x94, 0x17, 0xec, 0x8e, 0xdb, 0xb4, 0x58, 0x9d, 0x76, 0x0a, 0xd9, + 0xc3, 0xf3, 0xc1, 0xa1, 0x85, 0xd2, 0xba, 0xba, 0x3e, 0xd5, 0x89, 0xe3, + 0x1c, 0x89, 0x63, 0x7c, 0x76, 0x97, 0x1e, 0xde, 0x03, 0xcf, 0x7b, 0xa8, + 0xb9, 0x5e, 0x19, 0xd4, 0x34, 0xf9, 0x8b, 0x4e, 0x63, 0x0e, 0x2b, 0x7c, + 0x37, 0xbc, 0x79, 0x20, 0xcc, 0x93, 0x04, 0xe7, 0x6c, 0x05, 0x09, 0xdb, + 0x43, 0x69, 0x82, 0xdf, 0xdd, 0xb6, 0x0e, 0xcc, 0x73, 0x63, 0x8e, 0xce, + 0x04, 0xbf, 0x3e, 0xef, 0x8a, 0xe1, 0x4e, 0xd3, 0x6a, 0xad, 0x21, 0x4b, + 0xd0, 0x74, 0xd3, 0x06, 0x0e, 0x9d, 0xeb, 0x45, 0x1b, 0xe1, 0x3b, 0xf4, + 0xf8, 0x5b, 0x5d, 0xc4, 0x03, 0xa5, 0x55, 0x01, 0xd4, 0x78, 0x56, 0x96, + 0x6c, 0x2b, 0x8b, 0xde, 0xc3, 0x34, 0x5d, 0x23, 0x2c, 0xc3, 0x11, 0x77, + 0xba, 0xab, 0x20, 0xa8, 0x52, 0xe9, 0xf7, 0x02, 0x6b, 0x3f, 0x40, 0xca, + 0x4e, 0x1e, 0x86, 0x22, 0x89, 0x3b, 0x82, 0x20, 0xec, 0x1b, 0x77, 0x83, + 0xe0, 0x4a, 0xad, 0x3e, 0xdf, 0x25, 0xa9, 0xdb, 0xd4, 0x00, 0x69, 0x03, + 0xd7, 0x37, 0x8b, 0x6c, 0xee, 0xee, 0x49, 0x0d, 0x3a, 0x8d, 0x87, 0x44, + 0x54, 0x63, 0x8f, 0xc4, 0x71, 0xc1, 0xad, 0x23, 0xd0, 0x54, 0xc3, 0x5a, + 0x98, 0x3c, 0x8e, 0x7d, 0x55, 0x5e, 0xad, 0xb2, 0xd2, 0xb0, 0x0d, 0x12, + 0x48, 0x08, 0x37, 0x6b, 0x1d, 0x26, 0xfd, 0xff, 0x91, 0x75, 0xab, 0xf5, + 0xf9, 0x39, 0xde, 0x15, 0x7f, 0x7f, 0xf3, 0x66, 0x80, 0xfc, 0x3e, 0x9c, + 0xdd, 0x83, 0xd4, 0x6f, 0xba, 0xc1, 0xe5, 0x9d, 0x45, 0xab, 0xe5, 0x39, + 0x82, 0x84, 0x9a, 0x7f, 0x27, 0x8b, 0xc1, 0x6d, 0x43, 0x21, 0xca, 0x1c, + 0xdd, 0x86, 0x0f, 0xa7, 0x37, 0xef, 0x73, 0xae, 0xb6, 0x25, 0xfe, 0x61, + 0x5d, 0xab, 0x4c, 0xf1, 0x9d, 0xa7, 0x5a, 0xb2, 0xba, 0xc6, 0xa6, 0x96, + 0xb3, 0x85, 0xc0, 0x16, 0x1d, 0x46, 0x1f, 0x31, 0x84, 0x23, 0xd3, 0xba, + 0x42, 0xf4, 0xf0, 0xcd, 0xfd, 0xa6, 0x5e, 0x7e, 0x26, 0xfa, 0x7a, 0x12, + 0x1d, 0x99, 0x5b, 0x4a, 0x74, 0x98, 0x97, 0xfd, 0xd1, 0xa8, 0x4b, 0xdc, + 0xb2, 0x16, 0x2d, 0x19, 0xb3, 0x99, 0x68, 0xc6, 0x4c, 0xbb, 0x65, 0x66, + 0xb8, 0x27, 0x3b, 0xdc, 0x2d, 0x52, 0xf9, 0x5f, 0xe0, 0xff, 0x61, 0x05, + 0xb9, 0x4b, 0x0e, 0x10, 0x35, 0x31, 0x0b, 0x5a, 0x05, 0x52, 0x0e, 0xfd, + 0x7d, 0xdc, 0x75, 0x06, 0x80, 0xd6, 0x2a, 0xbd, 0xc0, 0x65, 0x47, 0x54, + 0xc7, 0x97, 0xd4, 0xe7, 0x02, 0x77, 0x22, 0x8a, 0xab, 0x91, 0xb9, 0x21, + 0x01, 0xec, 0xfc, 0x30, 0x4e, 0xdb, 0x31, 0xcf, 0x65, 0xcd, 0xe2, 0x4f, + 0xc1, 0xab, 0x34, 0xbf, 0xe0, 0xef, 0xa7, 0x5f, 0xde, 0x5e, 0xac, 0x4f, + 0xde, 0xb9, 0xd5, 0xdf, 0x8b, 0xbf, 0x65, 0xc3, 0x7f, 0x4c, 0xd6, 0xaf, + 0xe3, 0xfd, 0x2f, 0xaf, 0xdf, 0xe7, 0x5f, 0xde, 0xb1, 0xe2, 0x53, 0xf8, + 0x32, 0x6d, 0x3a, 0x08, 0x1a, 0x70, 0x5b, 0x34, 0x9c, 0x26, 0xcd, 0x98, + 0x2e, 0xe4, 0x98, 0x1d, 0x8b, 0x80, 0x20, 0x58, 0xe2, 0xc3, 0xae, 0x6f, + 0xbe, 0xb8, 0xfd, 0x94, 0xfe, 0x46, 0x9f, 0xa1, 0x9a, 0x0f, 0x9b, 0x00, + 0x69, 0xae, 0xc4, 0x99, 0xf6, 0xe2, 0x00, 0x70, 0xae, 0x68, 0xd7, 0x8b, + 0xac, 0x49, 0x1a, 0x33, 0x23, 0x32, 0x10, 0x7f, 0x28, 0xde, 0x1e, 0x5f, + 0xd0, 0x4f, 0x78, 0x4f, 0xa4, 0xdf, 0xb3, 0x15, 0xd9, 0xdc, 0x81, 0xcc, + 0xab, 0x49, 0x58, 0xde, 0xa8, 0x73, 0xe9, 0xd0, 0x64, 0xfb, 0xb3, 0x93, + 0x66, 0xf7, 0xe3, 0x80, 0x5f, 0xf3, 0x33, 0x18, 0xa1, 0xb1, 0xe0, 0xe8, + 0xe1, 0xb9, 0x6f, 0x8e, 0x3c, 0xa8, 0xb9, 0x63, 0x5f, 0x61, 0xc1, 0xa2, + 0xf5, 0x68, 0xf2, 0xe8, 0xb0, 0x20, 0x0f, 0xf3, 0xd8, 0x02, 0xfb, 0x7c, + 0xb0, 0x9a, 0xcf, 0x64, 0xe0, 0xf1, 0xe5, 0x83, 0x39, 0x58, 0x16, 0x86, + 0x23, 0x0e, 0x3d, 0xad, 0x56, 0xf0, 0xb9, 0x52, 0xe5, 0xb6, 0xf8, 0x0f, + 0x50, 0xdd, 0x7d, 0xcc, 0xa9, 0x11, 0x00, 0x00 +}; const GFXglyph Antonio_SemiBold20pt7bGlyphs[] PROGMEM = { {0, 1, 1, 8, 0, 0}, // 0x20 ' ' @@ -477,8 +284,13 @@ const GFXglyph Antonio_SemiBold20pt7bGlyphs[] PROGMEM = { {4461, 10, 37, 14, 2, -33}, // 0x7D '}' {4508, 17, 6, 21, 2, -21}}; // 0x7E '~' -const GFXfont Antonio_SemiBold20pt7b PROGMEM = { - (uint8_t *)Antonio_SemiBold20pt7bBitmaps, - (GFXglyph *)Antonio_SemiBold20pt7bGlyphs, 0x20, 0x7E, 51}; - -// Approx. 5193 bytes +// Font properties +static constexpr FontData Antonio_SemiBold20pt7b_Properties = { + Antonio_SemiBold20pt7bBitmaps_Gzip, + Antonio_SemiBold20pt7bGlyphs, + sizeof(Antonio_SemiBold20pt7bBitmaps_Gzip), + 4521, // Original size + 0x20, // First char + 0x7E, // Last char + 51 // yAdvance +}; diff --git a/src/fonts/antonio-semibold40.h b/src/fonts/antonio-semibold40.h index 13725f9..3790765 100644 --- a/src/fonts/antonio-semibold40.h +++ b/src/fonts/antonio-semibold40.h @@ -1,1603 +1,488 @@ +#pragma once + #include #include -const uint8_t Antonio_SemiBold40pt7bBitmaps[] PROGMEM = { - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFE, 0x7F, - 0x9F, 0xE7, 0xF9, 0xFE, 0x7F, 0x9F, 0xE7, 0xF9, 0xFE, 0x7F, 0x9F, 0xE7, - 0xF9, 0xFE, 0x7F, 0x9F, 0xE7, 0xF8, 0xFC, 0x3F, 0x0F, 0xC3, 0xF0, 0xFC, - 0x3F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, - 0xC3, 0xF0, 0xFC, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, - 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFB, 0xFE, 0xFF, 0xBF, 0xEF, 0xFB, 0xFE, 0xFF, 0xBF, 0xEF, - 0xF8, 0xFF, 0xFF, 0xEF, 0xFB, 0xFE, 0xFF, 0xBF, 0xEF, 0xFB, 0xFE, 0xFF, - 0x1F, 0xC7, 0xF1, 0xFC, 0x7F, 0x1F, 0xC7, 0xF1, 0xF8, 0x7E, 0x1F, 0x87, - 0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xC1, 0xF0, 0x7C, 0x00, 0x00, 0x07, 0xE0, - 0x3F, 0x80, 0x01, 0xF8, 0x0F, 0xC0, 0x00, 0xFE, 0x03, 0xF0, 0x00, 0x3F, - 0x81, 0xFC, 0x00, 0x0F, 0xE0, 0x7F, 0x00, 0x03, 0xF0, 0x1F, 0xC0, 0x00, - 0xFC, 0x07, 0xF0, 0x00, 0x3F, 0x01, 0xF8, 0x00, 0x1F, 0xC0, 0x7E, 0x00, - 0x07, 0xF0, 0x3F, 0x80, 0x01, 0xFC, 0x0F, 0xE0, 0x00, 0x7E, 0x03, 0xF8, - 0x00, 0x1F, 0x80, 0xFE, 0x00, 0x07, 0xE0, 0x3F, 0x00, 0x03, 0xF8, 0x0F, - 0xC0, 0x00, 0xFE, 0x07, 0xF0, 0x00, 0x3F, 0x81, 0xFC, 0x00, 0x0F, 0xC0, - 0x7F, 0x00, 0x03, 0xF0, 0x1F, 0xC0, 0x00, 0xFC, 0x07, 0xE0, 0x00, 0x7F, - 0x01, 0xF8, 0x00, 0x1F, 0xC0, 0xFE, 0x03, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xF3, - 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xF8, 0x1F, 0xC0, 0x00, 0xFE, 0x07, 0xF0, - 0x00, 0x3F, 0x01, 0xFC, 0x00, 0x0F, 0xC0, 0x7F, 0x00, 0x03, 0xF0, 0x1F, - 0x80, 0x01, 0xFC, 0x07, 0xE0, 0x00, 0x7F, 0x01, 0xF8, 0x00, 0x1F, 0xC0, - 0xFE, 0x00, 0x07, 0xE0, 0x3F, 0x80, 0x01, 0xF8, 0x0F, 0xE0, 0x00, 0x7E, - 0x03, 0xF0, 0x00, 0x3F, 0x80, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xF3, - 0xFF, 0xFF, 0xFF, 0xFC, 0x07, 0xF0, 0x1F, 0x80, 0x01, 0xFC, 0x07, 0xE0, - 0x00, 0x7F, 0x03, 0xF8, 0x00, 0x1F, 0x80, 0xFE, 0x00, 0x07, 0xE0, 0x3F, - 0x80, 0x01, 0xF8, 0x0F, 0xC0, 0x00, 0xFE, 0x03, 0xF0, 0x00, 0x3F, 0x80, - 0xFC, 0x00, 0x0F, 0xE0, 0x7F, 0x00, 0x03, 0xF8, 0x1F, 0xC0, 0x00, 0xFC, - 0x07, 0xF0, 0x00, 0x3F, 0x01, 0xFC, 0x00, 0x1F, 0xC0, 0x7E, 0x00, 0x07, - 0xF0, 0x1F, 0x80, 0x01, 0xFC, 0x0F, 0xE0, 0x00, 0x7F, 0x03, 0xF8, 0x00, - 0x1F, 0x80, 0xFE, 0x00, 0x07, 0xE0, 0x3F, 0x80, 0x01, 0xF8, 0x0F, 0xC0, - 0x00, 0xFE, 0x03, 0xF0, 0x00, 0x3F, 0x81, 0xFC, 0x00, 0x0F, 0xE0, 0x7F, - 0x00, 0x03, 0xF0, 0x1F, 0xC0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, - 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, - 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, - 0x7F, 0xF8, 0x00, 0x7F, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x1F, 0xFF, 0xFC, - 0x0F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xFC, 0x7F, 0xC1, - 0xFF, 0x1F, 0xF0, 0x3F, 0xEF, 0xF8, 0x0F, 0xFB, 0xFE, 0x01, 0xFE, 0xFF, - 0x80, 0x7F, 0xBF, 0xE0, 0x1F, 0xEF, 0xF8, 0x07, 0xFB, 0xFE, 0x01, 0xFE, - 0xFF, 0x80, 0x7F, 0x9F, 0xE0, 0x1F, 0xE7, 0xFC, 0x07, 0xF9, 0xFF, 0x01, - 0xFE, 0x7F, 0xE0, 0x7F, 0x8F, 0xFC, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x7F, - 0xE0, 0x00, 0x1F, 0xFE, 0x00, 0x03, 0xFF, 0xC0, 0x00, 0x7F, 0xF8, 0x00, - 0x1F, 0xFF, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x7F, 0xFC, 0x00, 0x0F, 0xFF, - 0x80, 0x00, 0xFF, 0xF0, 0x00, 0x1F, 0xFC, 0x00, 0x03, 0xFF, 0x80, 0x00, - 0x7F, 0xF0, 0x00, 0x0F, 0xFC, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x7F, 0xE7, - 0xF8, 0x0F, 0xF9, 0xFE, 0x03, 0xFF, 0x7F, 0x80, 0x7F, 0xDF, 0xE0, 0x1F, - 0xF7, 0xF8, 0x07, 0xFD, 0xFE, 0x01, 0xFF, 0x7F, 0x80, 0x3F, 0xDF, 0xE0, - 0x0F, 0xF7, 0xF8, 0x03, 0xFD, 0xFE, 0x01, 0xFF, 0x7F, 0xC0, 0x7F, 0xDF, - 0xF0, 0x1F, 0xF7, 0xFE, 0x0F, 0xFC, 0xFF, 0xC7, 0xFE, 0x3F, 0xFF, 0xFF, - 0x87, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xF8, 0x07, 0xFF, - 0xFC, 0x00, 0xFF, 0xFE, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x3C, 0x00, 0x00, - 0x0F, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x3C, 0x00, - 0x00, 0x0F, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x3C, - 0x00, 0x01, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xE0, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, - 0x07, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xF0, 0x00, - 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x7F, 0xFF, - 0xFE, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x7F, 0xF7, 0xFE, 0x00, 0x00, - 0x0F, 0xE0, 0x00, 0x00, 0x7F, 0x81, 0xFF, 0x00, 0x00, 0x1F, 0xC0, 0x00, - 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, - 0x3F, 0x80, 0x00, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x00, 0x3F, 0x80, 0x00, - 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x7F, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x00, - 0xFE, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x7F, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x01, - 0xFC, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x03, 0xFC, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x7F, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x07, - 0xF0, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x07, 0xF0, 0x03, 0xFF, - 0x80, 0xFF, 0x00, 0x7F, 0x00, 0x0F, 0xF0, 0x0F, 0xFF, 0xE0, 0xFF, 0x00, - 0x7F, 0x00, 0x0F, 0xE0, 0x1F, 0xFF, 0xF0, 0xFF, 0x00, 0x7F, 0x00, 0x0F, - 0xE0, 0x3F, 0xFF, 0xF8, 0xFF, 0x00, 0x7F, 0x00, 0x1F, 0xC0, 0x7F, 0xFF, - 0xFC, 0xFF, 0x00, 0x7F, 0x00, 0x1F, 0xC0, 0x7F, 0xFF, 0xFC, 0xFF, 0x00, - 0x7F, 0x00, 0x3F, 0xC0, 0xFF, 0xEF, 0xFE, 0xFF, 0x00, 0x7F, 0x00, 0x3F, - 0x80, 0xFF, 0x01, 0xFE, 0xFF, 0x00, 0x7F, 0x00, 0x3F, 0x80, 0xFF, 0x01, - 0xFE, 0xFF, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0xFE, 0x00, 0xFE, 0xFF, 0x00, - 0x7F, 0x00, 0x7F, 0x01, 0xFE, 0x00, 0xFE, 0xFF, 0x00, 0x7F, 0x00, 0xFF, - 0x01, 0xFE, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFE, 0x01, 0xFE, 0x00, - 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFE, 0x01, 0xFE, 0x00, 0xFF, 0x7F, 0x00, - 0xFF, 0x01, 0xFC, 0x01, 0xFE, 0x00, 0xFF, 0x7F, 0x81, 0xFE, 0x01, 0xFC, - 0x01, 0xFE, 0x00, 0xFF, 0x7F, 0xFF, 0xFE, 0x03, 0xFC, 0x01, 0xFE, 0x00, - 0xFF, 0x3F, 0xFF, 0xFE, 0x03, 0xF8, 0x01, 0xFE, 0x00, 0xFF, 0x3F, 0xFF, - 0xFC, 0x03, 0xF8, 0x01, 0xFE, 0x00, 0xFF, 0x1F, 0xFF, 0xF8, 0x07, 0xF0, - 0x01, 0xFE, 0x00, 0xFF, 0x0F, 0xFF, 0xF0, 0x07, 0xF0, 0x01, 0xFE, 0x00, - 0xFF, 0x03, 0xFF, 0xE0, 0x0F, 0xF0, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0x7F, - 0x00, 0x0F, 0xE0, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x0F, 0xE0, - 0x01, 0xFE, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x01, 0xFE, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0x00, - 0x00, 0x3F, 0xC0, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0x80, - 0x01, 0xFE, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x01, 0xFE, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0x00, - 0x00, 0x7F, 0x00, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x01, 0xFE, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x01, 0xFE, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0x00, - 0x01, 0xFE, 0x00, 0x01, 0xFE, 0x00, 0xFE, 0x00, 0x00, 0x01, 0xFC, 0x00, - 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFE, 0x01, - 0xFE, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0xFF, 0x01, 0xFE, 0x00, 0x00, - 0x03, 0xF8, 0x00, 0x00, 0xFF, 0x83, 0xFE, 0x00, 0x00, 0x07, 0xF8, 0x00, - 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x7F, 0xFF, - 0xFC, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, - 0x0F, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xE0, 0x00, - 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x07, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F, - 0xF8, 0x00, 0x00, 0x07, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x00, - 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xFF, 0x80, - 0x00, 0xFF, 0xDF, 0xF0, 0x00, 0x3F, 0xE0, 0x7F, 0x00, 0x07, 0xF8, 0x0F, - 0xE0, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0x1F, 0xE0, 0x1F, 0x80, 0x03, 0xFC, - 0x03, 0xF0, 0x00, 0xFF, 0x80, 0x7E, 0x00, 0x1F, 0xF0, 0x0F, 0xC0, 0x01, - 0xFE, 0x01, 0xF8, 0x00, 0x3F, 0xC0, 0x3F, 0x00, 0x07, 0xF8, 0x0F, 0xE0, - 0x00, 0xFF, 0x01, 0xFC, 0x00, 0x1F, 0xE0, 0x3F, 0x80, 0x01, 0xFE, 0x07, - 0xF0, 0x00, 0x3F, 0xC1, 0xFC, 0x00, 0x07, 0xF8, 0x3F, 0x80, 0x00, 0x7F, - 0x8F, 0xE0, 0x00, 0x0F, 0xF3, 0xFC, 0x00, 0x01, 0xFE, 0x7F, 0x00, 0x00, - 0x1F, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0x00, - 0x00, 0x07, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFE, - 0x00, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x0F, - 0xFC, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, - 0x1F, 0xFF, 0x00, 0x10, 0x07, 0xFF, 0xE0, 0x06, 0x01, 0xFF, 0xFE, 0x01, - 0xC0, 0x3F, 0xFF, 0xC0, 0x3C, 0x0F, 0xF3, 0xFC, 0x0F, 0xC3, 0xFE, 0x7F, - 0x83, 0xF8, 0x7F, 0x8F, 0xF0, 0x7F, 0x9F, 0xF0, 0xFF, 0x1F, 0xE3, 0xFC, - 0x1F, 0xE3, 0xF8, 0xFF, 0x81, 0xFE, 0xFF, 0x1F, 0xE0, 0x3F, 0xFF, 0xC3, - 0xFC, 0x07, 0xFF, 0xF0, 0xFF, 0x00, 0x7F, 0xFE, 0x1F, 0xE0, 0x0F, 0xFF, - 0x83, 0xFC, 0x00, 0xFF, 0xF0, 0x7F, 0x80, 0x1F, 0xFC, 0x0F, 0xF0, 0x01, - 0xFF, 0x81, 0xFE, 0x00, 0x3F, 0xE0, 0x3F, 0xC0, 0x07, 0xFC, 0x07, 0xF8, - 0x00, 0xFF, 0x80, 0xFF, 0x00, 0x3F, 0xF0, 0x1F, 0xE0, 0x07, 0xFF, 0x03, - 0xFC, 0x01, 0xFF, 0xE0, 0x7F, 0xC0, 0x7F, 0xFE, 0x0F, 0xFC, 0x1F, 0xFF, - 0xC0, 0xFF, 0xFF, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, - 0xEF, 0xF0, 0x3F, 0xFF, 0xF8, 0xFF, 0x03, 0xFF, 0xFE, 0x1F, 0xE0, 0x3F, - 0xFF, 0x81, 0xFE, 0x01, 0xFF, 0xC0, 0x3F, 0xC0, 0x07, 0xE0, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7E, 0x7E, 0x7E, - 0x7E, 0x7E, 0x7E, 0x3E, 0x3E, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, - 0x00, 0x7C, 0x0F, 0xF0, 0xFF, 0xC7, 0xFF, 0x3F, 0xFC, 0xFF, 0xF7, 0xFF, - 0xDF, 0xF8, 0x7F, 0xC1, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, - 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, - 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, - 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, - 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, - 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, - 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, - 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, - 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x1F, 0xF0, 0x7F, - 0xC1, 0xFF, 0x87, 0xFF, 0xCF, 0xFF, 0x3F, 0xFC, 0x7F, 0xF0, 0xFF, 0xC0, - 0xFF, 0x00, 0x0C, 0xF8, 0x03, 0xFE, 0x0F, 0xFC, 0x3F, 0xF8, 0xFF, 0xF3, - 0xFF, 0xEF, 0xFF, 0x83, 0xFE, 0x07, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, - 0x07, 0xFC, 0x1F, 0xF0, 0x7F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F, - 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, - 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, - 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, - 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, - 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, - 0x0F, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0xFF, - 0x03, 0xFC, 0x0F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC, 0x1F, 0xF0, 0x7F, - 0xC1, 0xFF, 0x0F, 0xFC, 0x7F, 0xEF, 0xFF, 0xBF, 0xFE, 0xFF, 0xF3, 0xFF, - 0x8F, 0xFC, 0x3F, 0xC0, 0xC0, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0xFE, - 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x3F, 0x00, 0x01, 0x00, 0xF8, 0x04, - 0x0C, 0x07, 0xC0, 0xE0, 0xF8, 0x3E, 0x0F, 0x8F, 0xE1, 0xF0, 0xFC, 0x7F, - 0x8F, 0x9F, 0xF7, 0xFF, 0x7D, 0xFF, 0xDF, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, - 0xFF, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x7F, 0xFC, 0x00, 0x00, 0xFF, 0x80, - 0x00, 0x1F, 0xFF, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFC, 0x0F, - 0xFF, 0xFF, 0xF9, 0xFF, 0xDF, 0x7F, 0xF7, 0xF8, 0xF9, 0xFF, 0x1F, 0x87, - 0xC3, 0xF8, 0xF8, 0x3E, 0x0F, 0x83, 0x01, 0xF0, 0x38, 0x10, 0x0F, 0x80, - 0x40, 0x00, 0xFC, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x3F, 0x80, 0x00, - 0x01, 0xFC, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, - 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, - 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, - 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, - 0x00, 0x00, 0x7E, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFC, 0x3E, 0x0F, 0x83, 0xE1, 0xF0, 0x7C, - 0x1F, 0x07, 0xC3, 0xE0, 0xF8, 0x3E, 0x0F, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, - 0xFF, 0x00, 0x00, 0xFE, 0x00, 0x01, 0xFE, 0x00, 0x01, 0xFE, 0x00, 0x01, - 0xFE, 0x00, 0x01, 0xFE, 0x00, 0x03, 0xFC, 0x00, 0x03, 0xFC, 0x00, 0x03, - 0xFC, 0x00, 0x03, 0xFC, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x07, - 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x0F, 0xF0, 0x00, 0x0F, 0xF0, 0x00, 0x0F, - 0xF0, 0x00, 0x0F, 0xF0, 0x00, 0x1F, 0xE0, 0x00, 0x1F, 0xE0, 0x00, 0x1F, - 0xE0, 0x00, 0x1F, 0xE0, 0x00, 0x3F, 0xC0, 0x00, 0x3F, 0xC0, 0x00, 0x3F, - 0xC0, 0x00, 0x3F, 0xC0, 0x00, 0x7F, 0x80, 0x00, 0x7F, 0x80, 0x00, 0x7F, - 0x80, 0x00, 0x7F, 0x80, 0x00, 0x7F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFE, 0x00, 0x01, 0xFE, 0x00, 0x01, 0xFE, - 0x00, 0x01, 0xFE, 0x00, 0x01, 0xFC, 0x00, 0x03, 0xFC, 0x00, 0x03, 0xFC, - 0x00, 0x03, 0xFC, 0x00, 0x03, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, - 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xF0, 0x00, 0x0F, 0xF0, - 0x00, 0x0F, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0xE0, 0x00, 0x1F, 0xE0, - 0x00, 0x1F, 0xE0, 0x00, 0x1F, 0xC0, 0x00, 0x3F, 0xC0, 0x00, 0x3F, 0xC0, - 0x00, 0x3F, 0xC0, 0x00, 0x3F, 0x80, 0x00, 0x7F, 0x80, 0x00, 0x7F, 0x80, - 0x00, 0x7F, 0x80, 0x00, 0x7F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x7F, - 0xFF, 0x00, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xF0, - 0x7F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFC, 0x7F, 0xE0, - 0xFF, 0xCF, 0xF8, 0x0F, 0xF9, 0xFF, 0x01, 0xFF, 0x3F, 0xC0, 0x1F, 0xE7, - 0xF8, 0x03, 0xFC, 0xFF, 0x00, 0x7F, 0xBF, 0xE0, 0x0F, 0xF7, 0xFC, 0x01, - 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, - 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x0F, - 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x07, 0xFF, 0xFE, - 0x00, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x00, 0x7F, - 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, - 0x07, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, - 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, - 0x3F, 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, - 0xF8, 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, - 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, - 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xDF, 0xE0, 0x0F, - 0xF3, 0xFC, 0x01, 0xFE, 0x7F, 0x80, 0x3F, 0xCF, 0xF0, 0x0F, 0xF9, 0xFF, - 0x01, 0xFF, 0x3F, 0xE0, 0x3F, 0xE3, 0xFE, 0x0F, 0xFC, 0x7F, 0xFF, 0xFF, - 0x0F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0x01, 0xFF, - 0xFF, 0xC0, 0x1F, 0xFF, 0xF0, 0x00, 0xFF, 0xF8, 0x00, 0x03, 0xF8, 0x00, - 0x00, 0x0F, 0xE0, 0x03, 0xFC, 0x00, 0x7F, 0x80, 0x1F, 0xF0, 0x0F, 0xFE, - 0x03, 0xFF, 0xC1, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xF8, 0x7F, 0xF8, 0x0F, 0xF8, - 0x01, 0xFF, 0x00, 0x3F, 0xE0, 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xF0, - 0x03, 0xFE, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x3F, 0xE0, - 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xF0, 0x03, 0xFE, 0x00, 0x7F, 0xC0, - 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x3F, 0xE0, 0x07, 0xFC, 0x00, 0xFF, 0x80, - 0x1F, 0xF0, 0x03, 0xFE, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x01, 0xFF, 0x00, - 0x3F, 0xE0, 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xF0, 0x03, 0xFE, 0x00, - 0x7F, 0xC0, 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x3F, 0xE0, 0x07, 0xFC, 0x00, - 0xFF, 0x80, 0x1F, 0xF0, 0x03, 0xFE, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x01, - 0xFF, 0x00, 0x3F, 0xE0, 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xF0, 0x03, - 0xFE, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x3F, 0xE0, 0x07, - 0xFC, 0x00, 0xFF, 0x80, 0x00, 0x7F, 0x80, 0x01, 0xFF, 0xF0, 0x01, 0xFF, - 0xFE, 0x01, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xF0, 0xFF, - 0xFF, 0xF8, 0xFF, 0xFF, 0xFE, 0x7F, 0xC1, 0xFF, 0x3F, 0xE0, 0x7F, 0x9F, - 0xE0, 0x3F, 0xCF, 0xF0, 0x1F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFC, 0x03, 0xFF, - 0xFE, 0x01, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0x80, 0x3F, - 0xFF, 0xC0, 0x1F, 0xFF, 0xE0, 0x0F, 0xFF, 0xF0, 0x07, 0xFF, 0xF8, 0x03, - 0xFF, 0xFC, 0x03, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x80, - 0x7F, 0xBF, 0xC0, 0x3F, 0xC0, 0x00, 0x3F, 0xE0, 0x00, 0x1F, 0xF0, 0x00, - 0x0F, 0xF0, 0x00, 0x0F, 0xF8, 0x00, 0x07, 0xFC, 0x00, 0x07, 0xFC, 0x00, - 0x03, 0xFE, 0x00, 0x03, 0xFE, 0x00, 0x03, 0xFF, 0x00, 0x01, 0xFF, 0x00, - 0x01, 0xFF, 0x80, 0x00, 0xFF, 0x80, 0x00, 0xFF, 0x80, 0x00, 0xFF, 0xC0, - 0x00, 0x7F, 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x3F, 0xE0, 0x00, 0x3F, 0xF0, - 0x00, 0x1F, 0xF0, 0x00, 0x1F, 0xF8, 0x00, 0x0F, 0xF8, 0x00, 0x0F, 0xF8, - 0x00, 0x07, 0xFC, 0x00, 0x07, 0xFC, 0x00, 0x03, 0xFE, 0x00, 0x03, 0xFE, - 0x00, 0x01, 0xFF, 0x00, 0x00, 0xFF, 0x80, 0x00, 0xFF, 0x80, 0x00, 0x7F, - 0xC0, 0x00, 0x3F, 0xE0, 0x00, 0x1F, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x07, - 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFE, - 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, - 0xE0, 0x00, 0x7F, 0xC0, 0x00, 0x7F, 0xFE, 0x00, 0x1F, 0xFF, 0xF0, 0x07, - 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, - 0xE3, 0xFF, 0xFF, 0xFC, 0x7F, 0xE0, 0xFF, 0xCF, 0xF8, 0x0F, 0xF9, 0xFF, - 0x01, 0xFF, 0x3F, 0xC0, 0x1F, 0xEF, 0xF8, 0x03, 0xFF, 0xFF, 0x00, 0x7F, - 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, - 0x07, 0xFF, 0xFE, 0x00, 0xFF, 0x80, 0x00, 0x1F, 0xF0, 0x00, 0x03, 0xFE, - 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x0F, 0xF8, 0x00, 0x01, 0xFE, 0x00, 0x00, - 0x3F, 0xC0, 0x00, 0x0F, 0xF8, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x7F, 0xC0, - 0x00, 0x1F, 0xF8, 0x00, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0x80, 0x03, 0xFF, - 0xE0, 0x00, 0x7F, 0xF0, 0x00, 0x0F, 0xFF, 0x80, 0x01, 0xFF, 0xF8, 0x00, - 0x3F, 0xFF, 0x80, 0x00, 0x3F, 0xF0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x1F, - 0xE0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x07, 0xF8, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x7F, - 0xFF, 0xC0, 0x0F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xE0, - 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF0, 0x03, 0xFF, - 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, - 0x3F, 0xCF, 0xF0, 0x07, 0xF9, 0xFE, 0x01, 0xFF, 0x3F, 0xE0, 0x3F, 0xE7, - 0xFE, 0x0F, 0xF8, 0x7F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, - 0xF8, 0x1F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xE0, 0x00, - 0xFF, 0xF8, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x07, - 0xFC, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x03, 0xFF, - 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x01, 0xFF, 0xC0, - 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x3F, 0xFC, 0x00, 0x00, 0xFF, 0xF0, 0x00, - 0x07, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x7F, 0xFC, 0x00, 0x01, - 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0xFB, - 0xFC, 0x00, 0x07, 0xEF, 0xF0, 0x00, 0x1F, 0xBF, 0xC0, 0x00, 0x7E, 0xFF, - 0x00, 0x03, 0xF3, 0xFC, 0x00, 0x0F, 0xCF, 0xF0, 0x00, 0x3F, 0x3F, 0xC0, - 0x00, 0xF8, 0xFF, 0x00, 0x07, 0xE3, 0xFC, 0x00, 0x1F, 0x8F, 0xF0, 0x00, - 0x7E, 0x3F, 0xC0, 0x03, 0xF0, 0xFF, 0x00, 0x0F, 0xC3, 0xFC, 0x00, 0x3F, - 0x0F, 0xF0, 0x01, 0xFC, 0x3F, 0xC0, 0x07, 0xE0, 0xFF, 0x00, 0x1F, 0x83, - 0xFC, 0x00, 0xFE, 0x0F, 0xF0, 0x03, 0xF8, 0x3F, 0xC0, 0x0F, 0xC0, 0xFF, - 0x00, 0x3F, 0x03, 0xFC, 0x01, 0xFC, 0x0F, 0xF0, 0x07, 0xE0, 0x3F, 0xC0, - 0x1F, 0x80, 0xFF, 0x00, 0xFE, 0x03, 0xFC, 0x03, 0xF8, 0x0F, 0xF0, 0x0F, - 0xC0, 0x3F, 0xC0, 0x7F, 0x00, 0xFF, 0x01, 0xFC, 0x03, 0xFC, 0x07, 0xF0, - 0x0F, 0xF0, 0x3F, 0x80, 0x3F, 0xC0, 0xFF, 0xFF, 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, 0x00, 0x3F, 0xC0, - 0x00, 0x00, 0xFF, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x0F, 0xF0, 0x00, - 0x00, 0x3F, 0xC0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, - 0x0F, 0xF0, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x03, - 0xFC, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x7F, 0xFF, 0xFE, 0x3F, 0xFF, 0xFF, - 0x1F, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, - 0xF1, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFC, 0x7F, 0x80, 0x00, 0x3F, 0xC0, - 0x00, 0x1F, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xF8, 0x00, 0x03, 0xFC, - 0x00, 0x01, 0xFE, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x3F, - 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xF9, 0xFE, 0x03, - 0xFD, 0xFF, 0xC1, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFE, - 0x3F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xCF, 0xFC, 0x7F, 0xE7, 0xFC, 0x1F, - 0xF3, 0xFC, 0x07, 0xF9, 0xFE, 0x03, 0xFC, 0xFF, 0x01, 0xFF, 0x7F, 0x80, - 0xFF, 0x8F, 0x80, 0x7F, 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0x0F, 0xF0, 0x00, - 0x07, 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x01, 0xFE, 0x00, 0x00, 0xFF, 0x00, - 0x00, 0x7F, 0x80, 0x00, 0x3F, 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0x0F, 0xF0, - 0x00, 0x07, 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0xFF, - 0xFF, 0x80, 0x7F, 0xFF, 0xC0, 0x3F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF0, 0x0F, - 0xFF, 0xF8, 0x07, 0xFF, 0xFC, 0x03, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0x01, - 0xFF, 0xFF, 0x80, 0xFF, 0x7F, 0xC0, 0x7F, 0xBF, 0xE0, 0x3F, 0xCF, 0xF8, - 0x3F, 0xE7, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF8, 0x7F, - 0xFF, 0xF8, 0x1F, 0xFF, 0xFC, 0x07, 0xFF, 0xF8, 0x00, 0xFF, 0xF8, 0x00, - 0x07, 0xC0, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x3F, 0xFF, 0x00, 0x1F, 0xFF, - 0xF0, 0x07, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFE, 0x0F, - 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFC, 0x3F, 0xE0, 0x7F, 0x8F, 0xF8, 0x0F, - 0xF9, 0xFF, 0x00, 0xFF, 0x3F, 0xC0, 0x1F, 0xE7, 0xF8, 0x03, 0xFC, 0xFF, - 0x00, 0x7F, 0x9F, 0xE0, 0x0F, 0xF3, 0xFC, 0x01, 0xFE, 0xFF, 0x80, 0x3F, - 0xDF, 0xF0, 0x07, 0xFB, 0xFE, 0x00, 0xFF, 0x7F, 0xC0, 0x1F, 0xEF, 0xF8, - 0x00, 0x01, 0xFF, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x07, 0xFC, 0x00, 0x00, - 0xFF, 0x80, 0x00, 0x1F, 0xF0, 0x00, 0x03, 0xFE, 0x3F, 0xC0, 0x7F, 0xDF, - 0xFE, 0x0F, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFE, 0x3F, 0xFF, 0xFF, 0xE7, - 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0x3F, 0xFB, 0xFF, 0x01, - 0xFF, 0x7F, 0xC0, 0x1F, 0xEF, 0xF8, 0x03, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, - 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF0, 0x03, - 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x00, 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF0, 0x03, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF8, - 0x01, 0xFE, 0xFF, 0x00, 0x3F, 0xDF, 0xE0, 0x07, 0xFB, 0xFC, 0x00, 0xFF, - 0x7F, 0x80, 0x1F, 0xEF, 0xF8, 0x03, 0xFD, 0xFF, 0x00, 0xFF, 0xBF, 0xF0, - 0x1F, 0xE3, 0xFF, 0x07, 0xFC, 0x7F, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xE0, - 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, - 0xF0, 0x00, 0xFF, 0xFC, 0x00, 0x03, 0xFC, 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, 0xF0, 0x00, 0x01, 0xFE, - 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x7F, 0xC0, 0x00, - 0x07, 0xFC, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, - 0x80, 0x00, 0x0F, 0xF0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x1F, 0xF0, 0x00, - 0x01, 0xFE, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x3F, - 0xC0, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x07, 0xFC, 0x00, - 0x00, 0x7F, 0x80, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x0F, - 0xF0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x01, 0xFE, 0x00, - 0x00, 0x3F, 0xE0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x03, - 0xFC, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x7F, 0xC0, - 0x00, 0x0F, 0xFC, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x0F, 0xF8, 0x00, 0x00, - 0xFF, 0x80, 0x00, 0x1F, 0xF8, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x1F, 0xF0, - 0x00, 0x01, 0xFF, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x03, 0xFF, 0x00, 0x00, - 0x3F, 0xF0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x03, 0xFE, - 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x7F, 0xE0, 0x00, - 0x07, 0xFE, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x7F, - 0xC0, 0x00, 0x07, 0xFC, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x0F, 0xFC, 0x00, - 0x00, 0xFF, 0xC0, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x0F, - 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x00, 0x3F, 0xFF, - 0xF0, 0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0x1F, - 0xFF, 0xFF, 0xE3, 0xFF, 0x07, 0xFC, 0x7F, 0xC0, 0x7F, 0xCF, 0xF0, 0x0F, - 0xFB, 0xFE, 0x01, 0xFF, 0x7F, 0xC0, 0x1F, 0xEF, 0xF8, 0x03, 0xFD, 0xFF, - 0x00, 0x7F, 0xBF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x3F, - 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xC0, 0x1F, 0xEF, 0xF8, - 0x03, 0xFD, 0xFF, 0x00, 0x7F, 0xBF, 0xE0, 0x0F, 0xF3, 0xFC, 0x01, 0xFE, - 0x7F, 0x80, 0x7F, 0xCF, 0xF0, 0x0F, 0xF1, 0xFF, 0x01, 0xFE, 0x1F, 0xE0, - 0x7F, 0xC3, 0xFE, 0x1F, 0xF0, 0x3F, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0x80, - 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, - 0xFC, 0x1F, 0xF8, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0xFF, 0x81, 0xFF, 0x1F, - 0xF0, 0x1F, 0xE3, 0xFC, 0x03, 0xFE, 0xFF, 0x80, 0x7F, 0xDF, 0xF0, 0x0F, - 0xFB, 0xFE, 0x00, 0xFF, 0x7F, 0xC0, 0x1F, 0xEF, 0xF8, 0x03, 0xFF, 0xFE, - 0x00, 0x7F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x00, 0x3F, - 0xFF, 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF0, - 0x03, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFE, - 0xFF, 0x80, 0x3F, 0xDF, 0xF0, 0x0F, 0xFB, 0xFE, 0x01, 0xFF, 0x7F, 0xE0, - 0x3F, 0xE7, 0xFC, 0x0F, 0xFC, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xE1, - 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, - 0xF0, 0x00, 0xFF, 0xF8, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x7F, 0xC0, 0x00, - 0x7F, 0xFF, 0x00, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, - 0xF0, 0x3F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFE, 0x7F, - 0xE0, 0xFF, 0xCF, 0xF8, 0x0F, 0xF9, 0xFE, 0x01, 0xFF, 0x3F, 0xC0, 0x1F, - 0xE7, 0xF8, 0x03, 0xFE, 0xFF, 0x00, 0x7F, 0xDF, 0xE0, 0x0F, 0xFF, 0xFC, - 0x01, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0xFF, - 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, - 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x07, 0xFF, - 0xFE, 0x00, 0xFF, 0xFF, 0xC0, 0x1F, 0xF7, 0xF8, 0x03, 0xFE, 0xFF, 0x00, - 0x7F, 0xDF, 0xE0, 0x0F, 0xFB, 0xFC, 0x01, 0xFF, 0x7F, 0x80, 0x3F, 0xEF, - 0xF8, 0x07, 0xFC, 0xFF, 0x81, 0xFF, 0x9F, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, - 0xFE, 0x3F, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0x07, - 0xFF, 0xFF, 0xE0, 0x7F, 0xF7, 0xFC, 0x00, 0xF0, 0xFF, 0x80, 0x00, 0x1F, - 0xF0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x0F, 0xF8, 0x00, - 0x01, 0xFF, 0x7F, 0xC0, 0x3F, 0xEF, 0xF8, 0x07, 0xFD, 0xFF, 0x00, 0xFF, - 0xBF, 0xE0, 0x1F, 0xF7, 0xFC, 0x03, 0xFE, 0xFF, 0x80, 0x7F, 0xDF, 0xF0, - 0x0F, 0xFB, 0xFE, 0x01, 0xFE, 0x3F, 0xC0, 0x3F, 0xC7, 0xF8, 0x07, 0xF8, - 0xFF, 0x00, 0xFF, 0x1F, 0xF0, 0x3F, 0xE3, 0xFE, 0x07, 0xFC, 0x3F, 0xFF, - 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x00, 0xFF, 0xF8, 0x00, 0x01, 0xF8, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 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, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFD, 0xFF, 0x7F, 0xDF, 0xF7, 0xFD, 0xFF, - 0x7F, 0xDF, 0xF7, 0xFD, 0xFF, 0x0F, 0xC3, 0xF0, 0xFC, 0x7E, 0x1F, 0x87, - 0xE1, 0xF0, 0x7C, 0x3F, 0x0F, 0xC3, 0xE0, 0xF8, 0x7E, 0x1F, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x30, 0x00, 0x01, 0xC0, 0x00, 0x1F, 0x00, 0x00, - 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x7F, 0xC0, 0x07, 0xFF, 0x00, 0x3F, 0xFC, - 0x03, 0xFF, 0xF0, 0x1F, 0xFF, 0x81, 0xFF, 0xF8, 0x0F, 0xFF, 0x80, 0xFF, - 0xFC, 0x0F, 0xFF, 0xC0, 0x3F, 0xFE, 0x00, 0xFF, 0xE0, 0x03, 0xFE, 0x00, - 0x0F, 0xF0, 0x00, 0x3F, 0x80, 0x00, 0xFF, 0x80, 0x03, 0xFF, 0x00, 0x0F, - 0xFF, 0x00, 0x3F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0xFF, - 0xFC, 0x00, 0xFF, 0xFC, 0x01, 0xFF, 0xF8, 0x01, 0xFF, 0xF0, 0x01, 0xFF, - 0xC0, 0x03, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x07, 0xF0, 0x00, 0x07, 0xC0, - 0x00, 0x0F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x80, 0x00, - 0x03, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0xFE, 0x00, 0x03, - 0xFE, 0x00, 0x0F, 0xFC, 0x00, 0x3F, 0xFC, 0x00, 0xFF, 0xF8, 0x01, 0xFF, - 0xF8, 0x03, 0xFF, 0xF0, 0x03, 0xFF, 0xF0, 0x07, 0xFF, 0xE0, 0x07, 0xFF, - 0xE0, 0x07, 0xFF, 0xC0, 0x0F, 0xFF, 0x00, 0x0F, 0xFC, 0x00, 0x1F, 0xF0, - 0x00, 0x1F, 0xC0, 0x00, 0x3F, 0x00, 0x03, 0xFC, 0x00, 0x1F, 0xF0, 0x01, - 0xFF, 0xC0, 0x1F, 0xFF, 0x00, 0xFF, 0xFC, 0x0F, 0xFF, 0xC0, 0x7F, 0xFC, - 0x07, 0xFF, 0xE0, 0x7F, 0xFE, 0x03, 0xFF, 0xF0, 0x0F, 0xFF, 0x00, 0x3F, - 0xF8, 0x00, 0xFF, 0x80, 0x03, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0x3E, 0x00, - 0x00, 0xE0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x03, 0xFF, - 0xF0, 0x0F, 0xFF, 0xF8, 0x1F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFC, 0x3F, 0xFF, - 0xFE, 0x3F, 0xFF, 0xFE, 0x7F, 0xFF, 0xFE, 0x7F, 0xC1, 0xFF, 0x7F, 0xC1, - 0xFF, 0x7F, 0x81, 0xFF, 0x7F, 0x81, 0xFF, 0x7F, 0x81, 0xFF, 0xFF, 0x81, - 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x81, - 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x81, - 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x81, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, - 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x03, - 0xFE, 0x00, 0x03, 0xFE, 0x00, 0x03, 0xFE, 0x00, 0x07, 0xFE, 0x00, 0x0F, - 0xFC, 0x00, 0x1F, 0xFC, 0x00, 0x7F, 0xF8, 0x03, 0xFF, 0xF0, 0x07, 0xFF, - 0xE0, 0x07, 0xFF, 0xC0, 0x07, 0xFF, 0x00, 0x07, 0xFC, 0x00, 0x07, 0xF8, - 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, - 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF8, - 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, - 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, - 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xF0, 0x01, 0xFF, - 0x80, 0x00, 0xFF, 0xC0, 0x00, 0x7F, 0xC0, 0x01, 0xFF, 0x00, 0x00, 0x1F, - 0xE0, 0x03, 0xFE, 0x00, 0x00, 0x0F, 0xE0, 0x07, 0xF8, 0x00, 0x00, 0x07, - 0xF0, 0x07, 0xF8, 0x00, 0x00, 0x03, 0xF0, 0x0F, 0xF0, 0x00, 0x00, 0x03, - 0xF8, 0x0F, 0xE0, 0x00, 0x00, 0x01, 0xF8, 0x1F, 0xC0, 0x00, 0x00, 0x00, - 0xFC, 0x1F, 0xC0, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0xC0, 0x07, 0xFE, 0x00, - 0xFC, 0x3F, 0x80, 0x1F, 0xFF, 0xC0, 0x7E, 0x3F, 0x80, 0x3F, 0xFF, 0xF0, - 0x7E, 0x7F, 0x00, 0x7F, 0xFF, 0xF0, 0x7E, 0x7F, 0x00, 0xFF, 0xFF, 0xF0, - 0x7E, 0x7F, 0x00, 0xFE, 0x03, 0xF0, 0x3E, 0x7F, 0x01, 0xFC, 0x03, 0xF0, - 0x3F, 0x7E, 0x01, 0xF8, 0x03, 0xF0, 0x3F, 0xFE, 0x03, 0xF8, 0x03, 0xF0, - 0x3F, 0xFE, 0x03, 0xF0, 0x03, 0xF0, 0x3F, 0xFE, 0x03, 0xF0, 0x03, 0xF0, - 0x3F, 0xFE, 0x03, 0xE0, 0x03, 0xF0, 0x3F, 0xFE, 0x07, 0xE0, 0x03, 0xF0, - 0x3F, 0xFE, 0x07, 0xE0, 0x03, 0xF0, 0x3F, 0xFE, 0x07, 0xE0, 0x03, 0xF0, - 0x3F, 0xFC, 0x07, 0xE0, 0x03, 0xF0, 0x3F, 0xFC, 0x07, 0xE0, 0x03, 0xF0, - 0x3F, 0xFC, 0x07, 0xE0, 0x03, 0xF0, 0x3F, 0xFC, 0x07, 0xE0, 0x03, 0xF0, - 0x3F, 0xFC, 0x07, 0xE0, 0x03, 0xF0, 0x3F, 0xFC, 0x07, 0xE0, 0x03, 0xF0, - 0x3F, 0xFC, 0x07, 0xE0, 0x03, 0xF0, 0x3F, 0xFC, 0x07, 0xE0, 0x03, 0xF0, - 0x3F, 0xFC, 0x07, 0xE0, 0x03, 0xF0, 0x3F, 0xFC, 0x07, 0xE0, 0x03, 0xF0, - 0x3F, 0xFE, 0x07, 0xE0, 0x07, 0xF0, 0x3F, 0xFE, 0x07, 0xE0, 0x07, 0xF0, - 0x3F, 0xFE, 0x07, 0xE0, 0x07, 0xF0, 0x3E, 0xFE, 0x07, 0xE0, 0x07, 0xF0, - 0x7E, 0xFE, 0x07, 0xF0, 0x07, 0xF0, 0x7E, 0xFE, 0x03, 0xF0, 0x0F, 0xF0, - 0x7E, 0x7E, 0x03, 0xF0, 0x1D, 0xF0, 0xFC, 0x7F, 0x01, 0xF8, 0x1D, 0xFD, - 0xFC, 0x7F, 0x01, 0xFF, 0xFC, 0xFF, 0xF8, 0x7F, 0x00, 0xFF, 0xF8, 0xFF, - 0xF8, 0x3F, 0x80, 0xFF, 0xF8, 0x7F, 0xF0, 0x3F, 0x80, 0x7F, 0xF0, 0x3F, - 0xE0, 0x3F, 0x80, 0x3F, 0xE0, 0x1F, 0xC0, 0x1F, 0xC0, 0x0F, 0xC0, 0x00, - 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x01, 0xFF, 0xC0, 0x00, 0x07, - 0x80, 0x00, 0xFF, 0xF8, 0x00, 0x7F, 0xC0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xE0, - 0x00, 0x03, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0x80, - 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0xFF, 0xFC, 0x00, - 0x01, 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xF0, 0x00, - 0x0F, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x7F, 0xBF, 0x80, 0x00, - 0xFF, 0x7F, 0x00, 0x01, 0xFE, 0xFE, 0x00, 0x03, 0xFD, 0xFE, 0x00, 0x07, - 0xF3, 0xFC, 0x00, 0x0F, 0xE7, 0xF8, 0x00, 0x3F, 0xCF, 0xF0, 0x00, 0x7F, - 0x8F, 0xE0, 0x00, 0xFF, 0x1F, 0xC0, 0x01, 0xFE, 0x3F, 0xC0, 0x03, 0xFC, - 0x7F, 0x80, 0x07, 0xF8, 0xFF, 0x00, 0x0F, 0xE1, 0xFE, 0x00, 0x3F, 0xC3, - 0xFC, 0x00, 0x7F, 0x83, 0xF8, 0x00, 0xFF, 0x07, 0xF0, 0x01, 0xFE, 0x0F, - 0xF0, 0x03, 0xFC, 0x1F, 0xE0, 0x07, 0xF8, 0x3F, 0xC0, 0x0F, 0xE0, 0x7F, - 0x80, 0x3F, 0xC0, 0xFF, 0x00, 0x7F, 0x80, 0xFE, 0x00, 0xFF, 0x01, 0xFE, - 0x01, 0xFE, 0x03, 0xFC, 0x03, 0xFC, 0x07, 0xF8, 0x07, 0xF8, 0x0F, 0xF0, - 0x1F, 0xF0, 0x1F, 0xE0, 0x3F, 0xC0, 0x3F, 0xC0, 0x7F, 0x80, 0x3F, 0xC0, - 0xFF, 0x00, 0x7F, 0x81, 0xFE, 0x00, 0xFF, 0x03, 0xFC, 0x01, 0xFE, 0x07, - 0xF8, 0x03, 0xFC, 0x1F, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xF8, 0x7F, - 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, - 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFE, 0x3F, 0xE0, - 0x03, 0xFE, 0x7F, 0x80, 0x03, 0xFC, 0xFF, 0x00, 0x07, 0xF9, 0xFE, 0x00, - 0x0F, 0xF3, 0xFC, 0x00, 0x1F, 0xE7, 0xF8, 0x00, 0x3F, 0xDF, 0xF0, 0x00, - 0x7F, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x00, 0x01, - 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x07, 0xF8, 0xFF, 0xFF, 0xF0, - 0x0F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, - 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xCF, 0xF8, 0x0F, - 0xFC, 0xFF, 0x80, 0x7F, 0xCF, 0xF8, 0x03, 0xFE, 0xFF, 0x80, 0x3F, 0xEF, - 0xF8, 0x03, 0xFE, 0xFF, 0x80, 0x3F, 0xEF, 0xF8, 0x03, 0xFE, 0xFF, 0x80, - 0x3F, 0xEF, 0xF8, 0x03, 0xFE, 0xFF, 0x80, 0x3F, 0xEF, 0xF8, 0x03, 0xFE, - 0xFF, 0x80, 0x3F, 0xEF, 0xF8, 0x03, 0xFE, 0xFF, 0x80, 0x3F, 0xEF, 0xF8, - 0x03, 0xFE, 0xFF, 0x80, 0x3F, 0xCF, 0xF8, 0x03, 0xFC, 0xFF, 0x80, 0x3F, - 0xCF, 0xF8, 0x07, 0xFC, 0xFF, 0x80, 0x7F, 0x8F, 0xFF, 0xFF, 0xF8, 0xFF, - 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, - 0xE0, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xF8, 0xFF, 0x80, 0xFF, 0xCF, - 0xF8, 0x07, 0xFC, 0xFF, 0x80, 0x3F, 0xEF, 0xF8, 0x03, 0xFE, 0xFF, 0x80, - 0x1F, 0xEF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x3F, 0xEF, 0xF8, 0x03, 0xFE, 0xFF, 0x80, 0x7F, 0xEF, - 0xF8, 0x0F, 0xFC, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, - 0xFF, 0x8F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xC0, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x3F, 0xFE, 0x00, 0x1F, - 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFE, - 0x0F, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFC, 0x7F, 0xE0, 0xFF, 0xCF, 0xF8, - 0x0F, 0xFB, 0xFE, 0x01, 0xFF, 0x7F, 0xC0, 0x1F, 0xEF, 0xF8, 0x03, 0xFF, - 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x00, - 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF0, 0x03, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, - 0x80, 0x00, 0x0F, 0xF0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x3F, 0xC0, 0x00, - 0x07, 0xF8, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x03, 0xFC, - 0x00, 0x00, 0x7F, 0x80, 0x00, 0x0F, 0xF0, 0x00, 0x01, 0xFE, 0x00, 0x00, - 0x3F, 0xC0, 0x00, 0x07, 0xF8, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x1F, 0xE0, - 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF0, 0x03, 0xFF, - 0xFE, 0x00, 0x7F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x00, - 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF0, 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, - 0xFF, 0xFF, 0x80, 0x3F, 0xDF, 0xF0, 0x07, 0xF9, 0xFE, 0x01, 0xFF, 0x3F, - 0xE0, 0x3F, 0xE7, 0xFE, 0x0F, 0xFC, 0x7F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, - 0xE0, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xC0, 0x1F, - 0xFF, 0xF0, 0x00, 0xFF, 0xF8, 0x00, 0x03, 0xF8, 0x00, 0xFF, 0xFF, 0xF0, - 0x0F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, - 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xCF, 0xF8, 0x0F, - 0xFC, 0xFF, 0x80, 0x7F, 0xEF, 0xF8, 0x03, 0xFE, 0xFF, 0x80, 0x3F, 0xEF, - 0xF8, 0x03, 0xFE, 0xFF, 0x80, 0x1F, 0xEF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, - 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, - 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFE, 0xFF, 0x80, 0x1F, 0xEF, 0xF8, 0x03, - 0xFE, 0xFF, 0x80, 0x3F, 0xEF, 0xF8, 0x03, 0xFE, 0xFF, 0x80, 0x7F, 0xCF, - 0xF8, 0x0F, 0xFC, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, - 0xFF, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0x80, - 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, - 0xBF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xBF, - 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, - 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, - 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, - 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, - 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, - 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFB, 0xFF, - 0xFF, 0xEF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFE, 0xFF, 0x80, 0x03, 0xFE, 0x00, - 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, - 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, - 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, - 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, - 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, - 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, - 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, - 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, - 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, - 0xFF, 0xFE, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xBF, 0xFF, - 0xFE, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xBF, 0xE0, 0x00, - 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, - 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, - 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, - 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, - 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, - 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, - 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, - 0x00, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x3F, 0xFF, 0x00, 0x1F, 0xFF, 0xF8, - 0x07, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0x0F, 0xFF, - 0xFF, 0xE3, 0xFF, 0xFF, 0xFE, 0x7F, 0xE0, 0x7F, 0xCF, 0xF8, 0x07, 0xFB, - 0xFE, 0x00, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x00, - 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, - 0xE0, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, 0x01, - 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xC0, 0x07, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, - 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x7F, 0x80, 0x00, - 0x0F, 0xF0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x07, 0xF8, - 0x00, 0x00, 0xFF, 0x03, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFC, 0x0F, 0xFF, - 0xFF, 0x81, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xC0, - 0xFF, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xE0, 0x03, 0xFF, - 0xFC, 0x00, 0x7F, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, 0x01, 0xFF, 0xFE, 0x00, - 0x3F, 0xFF, 0xC0, 0x07, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, - 0xE0, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x80, 0x0F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, - 0x80, 0x3F, 0xFF, 0xF0, 0x07, 0xFD, 0xFF, 0x00, 0xFF, 0xBF, 0xE0, 0x3F, - 0xF7, 0xFE, 0x0F, 0xFE, 0x7F, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0xF8, 0xFF, - 0xFF, 0xDF, 0x1F, 0xFF, 0xF3, 0xE1, 0xFF, 0xFE, 0x7C, 0x1F, 0xFF, 0x8F, - 0x80, 0xFF, 0xC0, 0xF0, 0x01, 0x80, 0x00, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, - 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, - 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, - 0x1F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x1F, - 0xF0, 0x00, 0x07, 0xFC, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x7F, 0xC0, 0x00, - 0x1F, 0xF0, 0x00, 0x07, 0xFC, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x7F, 0xC0, - 0x00, 0x1F, 0xF0, 0x00, 0x07, 0xFC, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x7F, - 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x07, 0xFC, 0x00, 0x01, 0xFF, 0x00, 0x00, - 0x7F, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x07, 0xFC, 0x00, 0x01, 0xFF, 0x00, - 0x00, 0x7F, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x07, 0xFC, 0x00, 0x01, 0xFF, - 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x07, 0xFC, 0x00, 0x01, - 0xFF, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x07, 0xFC, 0x00, - 0x01, 0xFF, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x07, 0xFC, - 0x00, 0x01, 0xFF, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x07, - 0xFC, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x1F, 0xFF, 0xF8, - 0x07, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xE0, 0x1F, 0xFF, - 0xF8, 0x07, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xE0, 0x1F, - 0xFF, 0xF8, 0x07, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xE0, - 0x1F, 0xFF, 0xF8, 0x07, 0xFF, 0xFE, 0x01, 0xFF, 0x7F, 0x80, 0x7F, 0xDF, - 0xF0, 0x1F, 0xE7, 0xFC, 0x0F, 0xF9, 0xFF, 0x87, 0xFE, 0x3F, 0xFF, 0xFF, - 0x0F, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xF8, 0x0F, 0xFF, - 0xFC, 0x01, 0xFF, 0xFE, 0x00, 0x1F, 0xFE, 0x00, 0x00, 0xFC, 0x00, 0xFF, - 0x80, 0x0F, 0xFF, 0xFE, 0x00, 0x3F, 0xEF, 0xF8, 0x01, 0xFF, 0x3F, 0xE0, - 0x07, 0xFC, 0xFF, 0x80, 0x1F, 0xF3, 0xFE, 0x00, 0xFF, 0x8F, 0xF8, 0x03, - 0xFE, 0x3F, 0xE0, 0x0F, 0xF8, 0xFF, 0x80, 0x7F, 0xC3, 0xFE, 0x01, 0xFF, - 0x0F, 0xF8, 0x07, 0xFC, 0x3F, 0xE0, 0x3F, 0xE0, 0xFF, 0x80, 0xFF, 0x83, - 0xFE, 0x03, 0xFE, 0x0F, 0xF8, 0x1F, 0xF0, 0x3F, 0xE0, 0x7F, 0xC0, 0xFF, - 0x83, 0xFE, 0x03, 0xFE, 0x0F, 0xF8, 0x0F, 0xF8, 0x3F, 0xE0, 0x3F, 0xE1, - 0xFF, 0x00, 0xFF, 0x87, 0xFC, 0x03, 0xFE, 0x1F, 0xF0, 0x0F, 0xF8, 0xFF, - 0x80, 0x3F, 0xE3, 0xFE, 0x00, 0xFF, 0x8F, 0xF8, 0x03, 0xFE, 0x7F, 0xC0, - 0x0F, 0xF9, 0xFF, 0x00, 0x3F, 0xE7, 0xF8, 0x00, 0xFF, 0xBF, 0xE0, 0x03, - 0xFE, 0xFF, 0x80, 0x0F, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0xFF, - 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, - 0xF8, 0x00, 0xFF, 0xBF, 0xE0, 0x03, 0xFE, 0xFF, 0x80, 0x0F, 0xF9, 0xFF, - 0x00, 0x3F, 0xE7, 0xFC, 0x00, 0xFF, 0x9F, 0xF0, 0x03, 0xFE, 0x3F, 0xE0, - 0x0F, 0xF8, 0xFF, 0x80, 0x3F, 0xE3, 0xFF, 0x00, 0xFF, 0x87, 0xFC, 0x03, - 0xFE, 0x1F, 0xF0, 0x0F, 0xF8, 0x7F, 0xE0, 0x3F, 0xE0, 0xFF, 0x80, 0xFF, - 0x83, 0xFE, 0x03, 0xFE, 0x07, 0xFC, 0x0F, 0xF8, 0x1F, 0xF0, 0x3F, 0xE0, - 0x7F, 0xE0, 0xFF, 0x80, 0xFF, 0x83, 0xFE, 0x03, 0xFE, 0x0F, 0xF8, 0x0F, - 0xFC, 0x3F, 0xE0, 0x1F, 0xF0, 0xFF, 0x80, 0x7F, 0xC3, 0xFE, 0x00, 0xFF, - 0x8F, 0xF8, 0x03, 0xFE, 0x3F, 0xE0, 0x0F, 0xFC, 0xFF, 0x80, 0x1F, 0xF3, - 0xFE, 0x00, 0x7F, 0xCF, 0xF8, 0x01, 0xFF, 0xBF, 0xE0, 0x03, 0xFE, 0xFF, - 0x80, 0x0F, 0xFB, 0xFE, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x7F, 0xC0, 0xFF, - 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, - 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, - 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, - 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, - 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, - 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, - 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, - 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, - 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, - 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, - 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, - 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, - 0x03, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x80, 0x03, - 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0xF0, 0x00, - 0x01, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xFF, - 0xC0, 0x00, 0x1F, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0xF8, 0x00, - 0x07, 0xFF, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0xF8, 0x00, - 0x1F, 0xFF, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, - 0xFF, 0xBF, 0x80, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF, - 0xE0, 0x01, 0xFB, 0xFF, 0xFF, 0xF0, 0x01, 0xFD, 0xFF, 0xFD, 0xF8, 0x00, - 0xFE, 0xFF, 0xFE, 0xFE, 0x00, 0x7F, 0x7F, 0xFF, 0x7F, 0x00, 0x3F, 0xBF, - 0xFF, 0xBF, 0x80, 0x1F, 0x9F, 0xFF, 0xDF, 0xC0, 0x0F, 0xCF, 0xFF, 0xE7, - 0xE0, 0x0F, 0xE7, 0xFF, 0xF3, 0xF8, 0x07, 0xF3, 0xFF, 0xF9, 0xFC, 0x03, - 0xF9, 0xFF, 0xFC, 0xFE, 0x01, 0xF8, 0xFF, 0xFE, 0x7F, 0x00, 0xFC, 0x7F, - 0xFF, 0x1F, 0x80, 0xFE, 0x3F, 0xFF, 0x8F, 0xC0, 0x7F, 0x1F, 0xFF, 0xC7, - 0xF0, 0x3F, 0x8F, 0xFF, 0xE3, 0xF8, 0x1F, 0x87, 0xFF, 0xF1, 0xFC, 0x0F, - 0xC3, 0xFF, 0xF8, 0x7E, 0x07, 0xE1, 0xFF, 0xFC, 0x3F, 0x07, 0xF1, 0xFF, - 0xFE, 0x1F, 0xC3, 0xF8, 0xFF, 0xFF, 0x0F, 0xE1, 0xF8, 0x7F, 0xFF, 0x87, - 0xF0, 0xFC, 0x3F, 0xFF, 0xC1, 0xF8, 0x7E, 0x1F, 0xFF, 0xE0, 0xFC, 0x7F, - 0x0F, 0xFF, 0xF0, 0x7F, 0x3F, 0x87, 0xFF, 0xF8, 0x3F, 0x9F, 0x83, 0xFF, - 0xFC, 0x1F, 0xCF, 0xC1, 0xFF, 0xFE, 0x07, 0xE7, 0xE0, 0xFF, 0xFF, 0x03, - 0xF3, 0xF0, 0x7F, 0xFF, 0x81, 0xFF, 0xF8, 0x3F, 0xFF, 0xC0, 0xFF, 0xF8, - 0x1F, 0xFF, 0xE0, 0x7F, 0xFC, 0x0F, 0xFF, 0xF0, 0x1F, 0xFE, 0x07, 0xFF, - 0xF8, 0x0F, 0xFF, 0x03, 0xFF, 0xFC, 0x07, 0xFF, 0x81, 0xFF, 0xFE, 0x03, - 0xFF, 0xC0, 0xFF, 0xFF, 0x01, 0xFF, 0xC0, 0x7F, 0xFF, 0x80, 0x7F, 0xE0, - 0x3F, 0xFF, 0xC0, 0x3F, 0xF0, 0x1F, 0xFF, 0xE0, 0x1F, 0xF8, 0x0F, 0xFF, - 0xF0, 0x0F, 0xFC, 0x07, 0xFF, 0xF8, 0x07, 0xFC, 0x03, 0xFF, 0xFC, 0x01, - 0xFE, 0x01, 0xFF, 0xFE, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0x80, - 0x7F, 0xFF, 0x80, 0x3F, 0xC0, 0x3F, 0xFF, 0xC0, 0x1F, 0xC0, 0x1F, 0xE0, - 0xFE, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xC0, 0x01, 0xFF, 0xFE, - 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x00, - 0x1F, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0xC0, 0x07, 0xFF, 0xFF, 0x00, 0x3F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, - 0xF8, 0x03, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF8, - 0x07, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xF8, 0x0F, - 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, - 0xFF, 0xC0, 0xFF, 0xFF, 0x7F, 0x07, 0xFF, 0xFB, 0xF8, 0x3F, 0xFF, 0xDF, - 0xC0, 0xFF, 0xFE, 0x7F, 0x07, 0xFF, 0xF3, 0xF8, 0x3F, 0xFF, 0x9F, 0xC1, - 0xFF, 0xFC, 0x7F, 0x0F, 0xFF, 0xE3, 0xF8, 0x7F, 0xFF, 0x1F, 0xC3, 0xFF, - 0xF8, 0x7F, 0x1F, 0xFF, 0xC3, 0xF8, 0xFF, 0xFE, 0x1F, 0xE7, 0xFF, 0xF0, - 0x7F, 0x3F, 0xFF, 0x83, 0xF9, 0xFF, 0xFC, 0x1F, 0xEF, 0xFF, 0xE0, 0x7F, - 0x7F, 0xFF, 0x83, 0xFB, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, - 0xFF, 0x03, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xFE, - 0x03, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xFC, 0x03, - 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xF8, 0x03, 0xFF, - 0xFF, 0xC0, 0x1F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0x00, - 0x1F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xC0, 0x03, 0xFF, 0xFE, 0x00, 0x1F, - 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0x80, 0x03, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, - 0xE0, 0x00, 0x7E, 0x00, 0x7F, 0xE0, 0x00, 0x7F, 0xFF, 0x00, 0x1F, 0xFF, - 0xF8, 0x07, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0x0F, - 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFE, 0x7F, 0xE0, 0x7F, 0xCF, 0xF8, 0x0F, - 0xFB, 0xFE, 0x00, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, - 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x00, 0x1F, - 0xFF, 0xE0, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, - 0x01, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xC0, 0x07, 0xFF, 0xF8, 0x00, 0xFF, - 0xFF, 0x00, 0x1F, 0xFF, 0xE0, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x80, - 0x0F, 0xFF, 0xF0, 0x01, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xC0, 0x07, 0xFF, - 0xF8, 0x00, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xE0, 0x03, 0xFF, 0xFC, 0x00, - 0x7F, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, 0x01, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, - 0xC0, 0x07, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xE0, 0x03, - 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, 0x01, 0xFF, 0xFE, - 0x00, 0x3F, 0xFF, 0xC0, 0x07, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0x00, 0x1F, - 0xFF, 0xE0, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x80, 0x1F, 0xFF, 0xF0, - 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, - 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0xFF, 0xBF, 0xE0, - 0x3F, 0xE7, 0xFE, 0x0F, 0xFC, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xE1, - 0xFF, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, - 0xF0, 0x00, 0xFF, 0xF8, 0x00, 0x03, 0xF8, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, - 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, - 0xFF, 0x8F, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xCF, 0xF8, 0x0F, 0xFC, - 0xFF, 0x80, 0x7F, 0xEF, 0xF8, 0x03, 0xFE, 0xFF, 0x80, 0x3F, 0xEF, 0xF8, - 0x03, 0xFE, 0xFF, 0x80, 0x1F, 0xEF, 0xF8, 0x01, 0xFE, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xEF, 0xF8, 0x01, 0xFE, 0xFF, 0x80, - 0x3F, 0xEF, 0xF8, 0x03, 0xFE, 0xFF, 0x80, 0x3F, 0xEF, 0xF8, 0x07, 0xFE, - 0xFF, 0x80, 0xFF, 0xCF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, - 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFC, - 0x0F, 0xFF, 0xFF, 0x80, 0xFF, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, - 0x80, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x0F, 0xF8, 0x00, - 0x00, 0xFF, 0x80, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x0F, - 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0x80, - 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x0F, 0xF8, 0x00, 0x00, - 0xFF, 0x80, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x0F, 0xF8, - 0x00, 0x00, 0xFF, 0x80, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, - 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x7F, 0xFF, 0x00, 0x1F, 0xFF, - 0xF8, 0x07, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0x0F, - 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFE, 0x7F, 0xE0, 0x7F, 0xCF, 0xF8, 0x0F, - 0xFB, 0xFE, 0x00, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, - 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x00, 0x1F, - 0xFF, 0xE0, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, - 0x01, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xC0, 0x07, 0xFF, 0xF8, 0x00, 0xFF, - 0xFF, 0x00, 0x1F, 0xFF, 0xE0, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x80, - 0x0F, 0xFF, 0xF0, 0x01, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xC0, 0x07, 0xFF, - 0xF8, 0x00, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xE0, 0x03, 0xFF, 0xFC, 0x00, - 0x7F, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, 0x01, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, - 0xC0, 0x07, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xE0, 0x03, - 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, 0x01, 0xFF, 0xFE, - 0x00, 0x3F, 0xFF, 0xC0, 0x07, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0x00, 0x1F, - 0xFF, 0xE0, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x80, 0x1F, 0xFF, 0xF0, - 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, - 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0xFF, 0xBF, 0xE0, - 0x3F, 0xE7, 0xFE, 0x0F, 0xFC, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xE1, - 0xFF, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, - 0xF0, 0x00, 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x0F, 0xF0, 0x00, - 0x00, 0xFF, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x0F, - 0xF0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x01, 0xF0, 0x00, - 0x00, 0x1C, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, - 0xE0, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xCF, - 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xEF, 0xF8, 0x07, 0xFE, 0xFF, 0x80, - 0x3F, 0xEF, 0xF8, 0x03, 0xFE, 0xFF, 0x80, 0x1F, 0xEF, 0xF8, 0x01, 0xFE, - 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xEF, 0xF8, 0x01, 0xFE, 0xFF, 0x80, 0x3F, 0xEF, 0xF8, 0x03, - 0xFE, 0xFF, 0x80, 0x3F, 0xEF, 0xF8, 0x07, 0xFC, 0xFF, 0xFF, 0xFF, 0xCF, - 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, - 0xFF, 0x0F, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xCF, 0xF8, 0x0F, 0xFC, - 0xFF, 0x80, 0x3F, 0xCF, 0xF8, 0x03, 0xFE, 0xFF, 0x80, 0x1F, 0xEF, 0xF8, - 0x01, 0xFE, 0xFF, 0x80, 0x1F, 0xEF, 0xF8, 0x01, 0xFE, 0xFF, 0x80, 0x1F, - 0xEF, 0xF8, 0x01, 0xFE, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, - 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xF0, 0x00, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x00, 0x3F, 0xFF, 0xF0, 0x0F, - 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, - 0xE3, 0xFF, 0xDF, 0xFC, 0x7F, 0xC0, 0xFF, 0x8F, 0xF0, 0x0F, 0xF3, 0xFE, - 0x01, 0xFF, 0x7F, 0xC0, 0x3F, 0xEF, 0xF8, 0x03, 0xFD, 0xFE, 0x00, 0x7F, - 0xBF, 0xC0, 0x0F, 0xF7, 0xF8, 0x01, 0xFE, 0xFF, 0x00, 0x3F, 0xDF, 0xF0, - 0x07, 0xFB, 0xFE, 0x00, 0xFF, 0x7F, 0xC0, 0x1F, 0xEF, 0xF8, 0x03, 0xFC, - 0xFF, 0x80, 0x7F, 0x9F, 0xF8, 0x0F, 0xF3, 0xFF, 0x80, 0x00, 0x3F, 0xF0, - 0x00, 0x07, 0xFF, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x0F, 0xFF, 0x00, 0x00, - 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, - 0x00, 0x01, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0x00, 0x01, 0xFF, 0xF0, 0x00, - 0x1F, 0xFE, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x1F, 0xFE, 0x00, 0x01, 0xFF, - 0xC0, 0x00, 0x1F, 0xFC, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x1F, 0xFB, 0xFE, - 0x03, 0xFF, 0x7F, 0xC0, 0x3F, 0xEF, 0xF8, 0x07, 0xFD, 0xFF, 0x00, 0x7F, - 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, - 0x07, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF8, 0x03, 0xFF, - 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFB, 0xFC, 0x01, 0xFF, 0x7F, 0x80, - 0x3F, 0xEF, 0xF0, 0x07, 0xFD, 0xFF, 0x00, 0xFF, 0x3F, 0xE0, 0x3F, 0xE3, - 0xFE, 0x0F, 0xFC, 0x7F, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, - 0xFC, 0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x00, - 0xFF, 0xF8, 0x00, 0x01, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0xFF, 0x80, 0x01, 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x07, - 0xFC, 0x00, 0x0F, 0xF8, 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xE0, 0x00, 0x7F, - 0xC0, 0x00, 0xFF, 0x80, 0x01, 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x07, 0xFC, - 0x00, 0x0F, 0xF8, 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xE0, 0x00, 0x7F, 0xC0, - 0x00, 0xFF, 0x80, 0x01, 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x07, 0xFC, 0x00, - 0x0F, 0xF8, 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xE0, 0x00, 0x7F, 0xC0, 0x00, - 0xFF, 0x80, 0x01, 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x07, 0xFC, 0x00, 0x0F, - 0xF8, 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xE0, 0x00, 0x7F, 0xC0, 0x00, 0xFF, - 0x80, 0x01, 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x07, 0xFC, 0x00, 0x0F, 0xF8, - 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xE0, 0x00, 0x7F, 0xC0, 0x00, 0xFF, 0x80, - 0x01, 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x07, 0xFC, 0x00, 0x0F, 0xF8, 0x00, - 0x1F, 0xF0, 0x00, 0x3F, 0xE0, 0x00, 0x7F, 0xC0, 0x00, 0xFF, 0x80, 0x01, - 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x07, 0xFC, 0x00, 0x0F, 0xF8, 0x00, 0x1F, - 0xF0, 0x00, 0x3F, 0xE0, 0x00, 0x7F, 0xC0, 0x00, 0xFF, 0x80, 0x01, 0xFF, - 0x00, 0x03, 0xFE, 0x00, 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, - 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, - 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFE, 0xFF, 0x80, 0x1F, 0xEF, 0xF8, 0x01, 0xFE, 0xFF, - 0x80, 0x3F, 0xEF, 0xF8, 0x03, 0xFE, 0x7F, 0xC0, 0x3F, 0xE7, 0xFE, 0x07, - 0xFC, 0x7F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0x81, - 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xC0, 0x01, 0xFF, - 0xF8, 0x00, 0x01, 0xFC, 0x00, 0xFF, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x07, - 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x1F, 0xEF, 0xF8, 0x00, 0x3F, - 0xDF, 0xF0, 0x00, 0x7F, 0x9F, 0xE0, 0x00, 0xFF, 0x3F, 0xC0, 0x01, 0xFE, - 0x7F, 0x80, 0x03, 0xFC, 0xFF, 0x00, 0x0F, 0xF9, 0xFF, 0x00, 0x1F, 0xE3, - 0xFE, 0x00, 0x3F, 0xC3, 0xFC, 0x00, 0x7F, 0x87, 0xF8, 0x00, 0xFF, 0x0F, - 0xF0, 0x01, 0xFE, 0x1F, 0xE0, 0x03, 0xFC, 0x3F, 0xE0, 0x0F, 0xF8, 0x7F, - 0xC0, 0x1F, 0xE0, 0x7F, 0x80, 0x3F, 0xC0, 0xFF, 0x00, 0x7F, 0x81, 0xFE, - 0x00, 0xFF, 0x03, 0xFC, 0x01, 0xFE, 0x07, 0xF8, 0x03, 0xFC, 0x0F, 0xF8, - 0x07, 0xF0, 0x0F, 0xF0, 0x1F, 0xE0, 0x1F, 0xE0, 0x3F, 0xC0, 0x3F, 0xC0, - 0x7F, 0x80, 0x7F, 0x80, 0xFF, 0x00, 0xFF, 0x01, 0xFE, 0x01, 0xFF, 0x03, - 0xFC, 0x03, 0xFE, 0x07, 0xF0, 0x03, 0xFC, 0x0F, 0xE0, 0x07, 0xF8, 0x3F, - 0xC0, 0x0F, 0xF0, 0x7F, 0x80, 0x1F, 0xE0, 0xFF, 0x00, 0x3F, 0xC1, 0xFE, - 0x00, 0x7F, 0xC3, 0xFC, 0x00, 0x7F, 0x87, 0xF0, 0x00, 0xFF, 0x0F, 0xE0, - 0x01, 0xFE, 0x1F, 0xC0, 0x03, 0xFC, 0x7F, 0x80, 0x07, 0xF8, 0xFF, 0x00, - 0x0F, 0xF1, 0xFE, 0x00, 0x0F, 0xF3, 0xFC, 0x00, 0x1F, 0xE7, 0xF0, 0x00, - 0x3F, 0xCF, 0xE0, 0x00, 0x7F, 0x9F, 0xC0, 0x00, 0xFF, 0x3F, 0x80, 0x01, - 0xFE, 0xFF, 0x00, 0x01, 0xFD, 0xFE, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x07, - 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x3F, - 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0xFF, - 0xF8, 0x00, 0x01, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x07, 0xFF, - 0xC0, 0x00, 0x07, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x1F, 0xFE, - 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0xFF, 0xE0, - 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x01, 0xFF, 0xFF, 0x00, 0x0F, 0xF0, 0x01, - 0xFE, 0xFF, 0x00, 0x0F, 0xF0, 0x01, 0xFE, 0xFF, 0x00, 0x0F, 0xF0, 0x01, - 0xFE, 0x7F, 0x80, 0x0F, 0xF0, 0x01, 0xFE, 0x7F, 0x80, 0x0F, 0xF8, 0x01, - 0xFE, 0x7F, 0x80, 0x0F, 0xF8, 0x01, 0xFE, 0x7F, 0x80, 0x1F, 0xF8, 0x01, - 0xFE, 0x7F, 0x80, 0x1F, 0xF8, 0x01, 0xFE, 0x7F, 0x80, 0x1F, 0xF8, 0x01, - 0xFE, 0x7F, 0x80, 0x1F, 0xF8, 0x01, 0xFC, 0x7F, 0x80, 0x1F, 0xF8, 0x03, - 0xFC, 0x3F, 0x80, 0x1F, 0xFC, 0x03, 0xFC, 0x3F, 0xC0, 0x1F, 0xFC, 0x03, - 0xFC, 0x3F, 0xC0, 0x3F, 0xFC, 0x03, 0xFC, 0x3F, 0xC0, 0x3F, 0xFC, 0x03, - 0xFC, 0x3F, 0xC0, 0x3F, 0xFC, 0x03, 0xFC, 0x3F, 0xC0, 0x3F, 0xFC, 0x03, - 0xFC, 0x3F, 0xC0, 0x3F, 0xFC, 0x03, 0xF8, 0x3F, 0xC0, 0x3F, 0xFE, 0x03, - 0xF8, 0x1F, 0xC0, 0x3F, 0xFE, 0x03, 0xF8, 0x1F, 0xC0, 0x7F, 0x7E, 0x03, - 0xF8, 0x1F, 0xC0, 0x7F, 0x7E, 0x07, 0xF8, 0x1F, 0xE0, 0x7F, 0x7E, 0x07, - 0xF8, 0x1F, 0xE0, 0x7F, 0x7E, 0x07, 0xF8, 0x1F, 0xE0, 0x7E, 0x7E, 0x07, - 0xF8, 0x1F, 0xE0, 0x7E, 0x7F, 0x07, 0xF8, 0x0F, 0xE0, 0x7E, 0x7F, 0x07, - 0xF0, 0x0F, 0xE0, 0xFE, 0x3F, 0x07, 0xF0, 0x0F, 0xE0, 0xFE, 0x3F, 0x07, - 0xF0, 0x0F, 0xE0, 0xFE, 0x3F, 0x07, 0xF0, 0x0F, 0xE0, 0xFE, 0x3F, 0x07, - 0xF0, 0x0F, 0xF0, 0xFC, 0x3F, 0x0F, 0xF0, 0x0F, 0xF0, 0xFC, 0x3F, 0x8F, - 0xF0, 0x0F, 0xF0, 0xFC, 0x3F, 0x8F, 0xF0, 0x07, 0xF1, 0xFC, 0x1F, 0x8F, - 0xE0, 0x07, 0xF1, 0xFC, 0x1F, 0x8F, 0xE0, 0x07, 0xF1, 0xFC, 0x1F, 0x8F, - 0xE0, 0x07, 0xF1, 0xF8, 0x1F, 0x8F, 0xE0, 0x07, 0xF1, 0xF8, 0x1F, 0x8F, - 0xE0, 0x07, 0xF1, 0xF8, 0x1F, 0xCF, 0xE0, 0x07, 0xF9, 0xF8, 0x1F, 0xCF, - 0xE0, 0x07, 0xFB, 0xF8, 0x0F, 0xCF, 0xE0, 0x03, 0xFB, 0xF8, 0x0F, 0xDF, - 0xE0, 0x03, 0xFB, 0xF8, 0x0F, 0xDF, 0xC0, 0x03, 0xFB, 0xF0, 0x0F, 0xDF, - 0xC0, 0x03, 0xFB, 0xF0, 0x0F, 0xDF, 0xC0, 0x03, 0xFB, 0xF0, 0x0F, 0xFF, - 0xC0, 0x03, 0xFB, 0xF0, 0x0F, 0xFF, 0xC0, 0x03, 0xFF, 0xF0, 0x07, 0xFF, - 0xC0, 0x03, 0xFF, 0xF0, 0x07, 0xFF, 0xC0, 0x01, 0xFF, 0xF0, 0x07, 0xFF, - 0xC0, 0x01, 0xFF, 0xE0, 0x07, 0xFF, 0xC0, 0x01, 0xFF, 0xE0, 0x07, 0xFF, - 0x80, 0x01, 0xFF, 0xE0, 0x07, 0xFF, 0x80, 0x01, 0xFF, 0xE0, 0x07, 0xFF, - 0x80, 0x01, 0xFF, 0xE0, 0x03, 0xFF, 0x80, 0x01, 0xFF, 0xE0, 0x03, 0xFF, - 0x80, 0x01, 0xFF, 0xE0, 0x03, 0xFF, 0x80, 0x00, 0xFF, 0xC0, 0x03, 0xFF, - 0x80, 0x00, 0xFF, 0xC0, 0x03, 0xFF, 0x80, 0x00, 0xFF, 0xC0, 0x03, 0xFF, - 0x00, 0x00, 0xFF, 0xC0, 0x03, 0xFF, 0x00, 0x00, 0xFF, 0xC0, 0x03, 0xFF, - 0x00, 0x00, 0xFF, 0xC0, 0x01, 0xFF, 0x00, 0x00, 0xFF, 0xC0, 0x01, 0xFF, - 0x00, 0x00, 0xFF, 0x80, 0x01, 0xFF, 0x00, 0xFF, 0x00, 0x1F, 0xFF, 0xF0, - 0x01, 0xFE, 0x7F, 0x00, 0x1F, 0xE7, 0xF8, 0x01, 0xFE, 0x7F, 0x80, 0x3F, - 0xE3, 0xF8, 0x03, 0xFC, 0x3F, 0xC0, 0x3F, 0xC3, 0xFC, 0x03, 0xFC, 0x1F, - 0xC0, 0x7F, 0x81, 0xFE, 0x07, 0xF8, 0x1F, 0xE0, 0x7F, 0x81, 0xFE, 0x07, - 0xF8, 0x0F, 0xE0, 0xFF, 0x00, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x00, - 0x7F, 0x0F, 0xE0, 0x07, 0xF9, 0xFE, 0x00, 0x7F, 0x9F, 0xE0, 0x03, 0xF9, - 0xFE, 0x00, 0x3F, 0xDF, 0xC0, 0x03, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xC0, - 0x01, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0xFF, 0xF8, 0x00, 0x0F, - 0xFF, 0x80, 0x00, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x7F, 0xF0, - 0x00, 0x07, 0xFF, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x07, 0xFE, 0x00, 0x00, - 0x7F, 0xE0, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x0F, 0xFE, - 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0xFF, 0xF0, 0x00, - 0x1F, 0xFF, 0x00, 0x01, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0x00, 0x03, 0xFF, - 0xF8, 0x00, 0x3F, 0xFF, 0x80, 0x03, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xC0, - 0x07, 0xFB, 0xFC, 0x00, 0x7F, 0x9F, 0xC0, 0x07, 0xF9, 0xFE, 0x00, 0xFF, - 0x9F, 0xE0, 0x0F, 0xF0, 0xFE, 0x00, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, - 0x01, 0xFF, 0x07, 0xF0, 0x1F, 0xE0, 0x7F, 0x81, 0xFE, 0x07, 0xF8, 0x1F, - 0xE0, 0x7F, 0x83, 0xFE, 0x03, 0xF8, 0x3F, 0xC0, 0x3F, 0xC3, 0xFC, 0x03, - 0xFC, 0x7F, 0xC0, 0x1F, 0xC7, 0xF8, 0x01, 0xFE, 0x7F, 0x80, 0x1F, 0xE7, - 0xF8, 0x00, 0xFE, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0x00, - 0x07, 0xF0, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x07, 0xFB, 0xFE, 0x00, - 0x1F, 0xF3, 0xFC, 0x00, 0x3F, 0xE7, 0xFC, 0x00, 0x7F, 0xCF, 0xF8, 0x00, - 0xFF, 0x0F, 0xF0, 0x03, 0xFE, 0x1F, 0xE0, 0x07, 0xFC, 0x3F, 0xE0, 0x0F, - 0xF0, 0x7F, 0xC0, 0x1F, 0xE0, 0x7F, 0x80, 0x3F, 0xC0, 0xFF, 0x80, 0xFF, - 0x81, 0xFF, 0x01, 0xFE, 0x01, 0xFE, 0x03, 0xFC, 0x03, 0xFC, 0x07, 0xF8, - 0x07, 0xFC, 0x1F, 0xF0, 0x0F, 0xF8, 0x3F, 0xC0, 0x0F, 0xF0, 0x7F, 0x80, - 0x1F, 0xE0, 0xFF, 0x00, 0x3F, 0xE3, 0xFC, 0x00, 0x3F, 0xC7, 0xF8, 0x00, - 0x7F, 0x8F, 0xF0, 0x00, 0xFF, 0x9F, 0xE0, 0x00, 0xFF, 0x7F, 0x80, 0x01, - 0xFE, 0xFF, 0x00, 0x03, 0xFD, 0xFE, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x07, - 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x1F, - 0xFF, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x7F, 0xFC, 0x00, 0x00, 0xFF, - 0xF8, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x03, 0xFF, - 0x80, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x0F, 0xF8, - 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x7F, 0xC0, - 0x00, 0x00, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x03, 0xFE, 0x00, - 0x00, 0x07, 0xFC, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x1F, 0xF0, 0x00, - 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x00, 0xFF, 0x80, 0x00, - 0x01, 0xFF, 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, - 0x0F, 0xF8, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, - 0x7F, 0xC0, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x03, - 0xFE, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x1F, - 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x7F, 0xFF, - 0xFE, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, - 0xEF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x07, 0xFC, - 0x00, 0x0F, 0xF8, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0xC0, 0x00, 0xFF, 0x80, - 0x01, 0xFF, 0x00, 0x07, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x1F, 0xF0, 0x00, - 0x3F, 0xE0, 0x00, 0xFF, 0xC0, 0x01, 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x07, - 0xFC, 0x00, 0x1F, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0x7F, 0xC0, 0x00, 0xFF, - 0x80, 0x03, 0xFE, 0x00, 0x07, 0xFC, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xF0, - 0x00, 0x7F, 0xC0, 0x00, 0xFF, 0x80, 0x01, 0xFF, 0x00, 0x07, 0xFE, 0x00, - 0x0F, 0xF8, 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0xC0, 0x01, - 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x07, 0xFC, 0x00, 0x1F, 0xF8, 0x00, 0x3F, - 0xE0, 0x00, 0x7F, 0xC0, 0x01, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x07, 0xFC, - 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xF0, 0x00, 0x7F, 0xC0, 0x00, 0xFF, 0x80, - 0x01, 0xFF, 0x00, 0x07, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x1F, 0xF0, 0x00, - 0x3F, 0xE0, 0x00, 0xFF, 0xC0, 0x01, 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x07, - 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0x7F, - 0xFF, 0xFE, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xF0, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x80, 0x7F, 0xC0, 0x3F, 0xE0, 0x1F, 0xF0, - 0x0F, 0xF8, 0x07, 0xFC, 0x03, 0xFE, 0x01, 0xFF, 0x00, 0xFF, 0x80, 0x7F, - 0xC0, 0x3F, 0xE0, 0x1F, 0xF0, 0x0F, 0xF8, 0x07, 0xFC, 0x03, 0xFE, 0x01, - 0xFF, 0x00, 0xFF, 0x80, 0x7F, 0xC0, 0x3F, 0xE0, 0x1F, 0xF0, 0x0F, 0xF8, - 0x07, 0xFC, 0x03, 0xFE, 0x01, 0xFF, 0x00, 0xFF, 0x80, 0x7F, 0xC0, 0x3F, - 0xE0, 0x1F, 0xF0, 0x0F, 0xF8, 0x07, 0xFC, 0x03, 0xFE, 0x01, 0xFF, 0x00, - 0xFF, 0x80, 0x7F, 0xC0, 0x3F, 0xE0, 0x1F, 0xF0, 0x0F, 0xF8, 0x07, 0xFC, - 0x03, 0xFE, 0x01, 0xFF, 0x00, 0xFF, 0x80, 0x7F, 0xC0, 0x3F, 0xE0, 0x1F, - 0xF0, 0x0F, 0xF8, 0x07, 0xFC, 0x03, 0xFE, 0x01, 0xFF, 0x00, 0xFF, 0x80, - 0x7F, 0xC0, 0x3F, 0xE0, 0x1F, 0xF0, 0x0F, 0xF8, 0x07, 0xFC, 0x03, 0xFE, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0x80, - 0x00, 0x7F, 0x80, 0x00, 0x7F, 0x80, 0x00, 0x3F, 0x80, 0x00, 0x3F, 0xC0, - 0x00, 0x3F, 0xC0, 0x00, 0x3F, 0xC0, 0x00, 0x3F, 0xC0, 0x00, 0x1F, 0xE0, - 0x00, 0x1F, 0xE0, 0x00, 0x1F, 0xE0, 0x00, 0x1F, 0xE0, 0x00, 0x0F, 0xE0, - 0x00, 0x0F, 0xF0, 0x00, 0x0F, 0xF0, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xF0, - 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, - 0x00, 0x03, 0xFC, 0x00, 0x03, 0xFC, 0x00, 0x03, 0xFC, 0x00, 0x03, 0xFC, - 0x00, 0x01, 0xFC, 0x00, 0x01, 0xFE, 0x00, 0x01, 0xFE, 0x00, 0x01, 0xFE, - 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0xFF, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x7F, 0x80, 0x00, 0x7F, - 0x80, 0x00, 0x7F, 0x80, 0x00, 0x3F, 0x80, 0x00, 0x3F, 0xC0, 0x00, 0x3F, - 0xC0, 0x00, 0x3F, 0xC0, 0x00, 0x1F, 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0x1F, - 0xE0, 0x00, 0x1F, 0xE0, 0x00, 0x0F, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x0F, - 0xF0, 0x00, 0x0F, 0xF0, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xF8, 0x00, 0x07, - 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x03, 0xF8, 0x00, 0x03, - 0xFC, 0x00, 0x03, 0xFC, 0x00, 0x03, 0xFC, 0x00, 0x01, 0xFC, 0x00, 0x01, - 0xFE, 0x00, 0x01, 0xFE, 0x00, 0x01, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, - 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xF0, - 0x00, 0x03, 0xFF, 0x80, 0x00, 0x3F, 0xFE, 0x00, 0x01, 0xFF, 0xF0, 0x00, - 0x0F, 0xFF, 0x80, 0x00, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x3F, - 0xBF, 0x80, 0x01, 0xFD, 0xFC, 0x00, 0x1F, 0xEF, 0xE0, 0x00, 0xFF, 0x7F, - 0x80, 0x07, 0xF1, 0xFC, 0x00, 0x3F, 0x8F, 0xE0, 0x03, 0xFC, 0x7F, 0x80, - 0x1F, 0xE3, 0xFC, 0x00, 0xFF, 0x1F, 0xE0, 0x07, 0xF0, 0x7F, 0x00, 0x7F, - 0x83, 0xFC, 0x03, 0xFC, 0x1F, 0xE0, 0x1F, 0xE0, 0xFF, 0x00, 0xFF, 0x07, - 0xF8, 0x0F, 0xF0, 0x1F, 0xE0, 0x7F, 0x80, 0xFF, 0x03, 0xFC, 0x07, 0xF8, - 0x1F, 0xE0, 0x3F, 0xC1, 0xFE, 0x00, 0xFF, 0x0F, 0xF0, 0x07, 0xF8, 0x7F, - 0x80, 0x3F, 0xC7, 0xFC, 0x01, 0xFE, 0x3F, 0xE0, 0x0F, 0xF9, 0xFE, 0x00, - 0x3F, 0xCF, 0xF0, 0x01, 0xFE, 0xFF, 0x80, 0x0F, 0xF7, 0xFC, 0x00, 0x7F, - 0xFF, 0xE0, 0x03, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0xFF, 0x8F, 0xF8, 0x7F, 0x87, 0xFC, 0x3F, 0xC3, 0xFC, 0x1F, - 0xC0, 0xFE, 0x0F, 0xE0, 0x7E, 0x07, 0xE0, 0x3F, 0x03, 0xF0, 0x1F, 0x01, - 0xF0, 0x00, 0x7F, 0xE0, 0x00, 0x3F, 0xFF, 0x00, 0x1F, 0xFF, 0xF8, 0x07, - 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, - 0xE1, 0xFF, 0x87, 0xFE, 0x3F, 0xE0, 0x7F, 0xCF, 0xF8, 0x07, 0xF9, 0xFF, - 0x00, 0xFF, 0xBF, 0xE0, 0x1F, 0xF7, 0xFC, 0x03, 0xFE, 0xFF, 0x80, 0x7F, - 0xDF, 0xF0, 0x0F, 0xFB, 0xFE, 0x01, 0xFF, 0x7F, 0xC0, 0x3F, 0xEF, 0xF8, - 0x07, 0xFD, 0xFF, 0x00, 0xFF, 0x80, 0x00, 0x1F, 0xF0, 0x00, 0x03, 0xFE, - 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x7F, 0xF8, 0x00, 0x7F, 0xFF, 0x00, 0x3F, - 0xFF, 0xE0, 0x1F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0x83, 0xFF, 0x9F, 0xF0, - 0xFF, 0xC3, 0xFE, 0x3F, 0xE0, 0x7F, 0xCF, 0xF8, 0x0F, 0xFB, 0xFE, 0x01, - 0xFF, 0x7F, 0xC0, 0x3F, 0xEF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, - 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x0F, - 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x07, 0xFF, 0xFE, - 0x00, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x00, 0x7F, - 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0x7F, 0xC0, 0x3F, 0xEF, 0xF8, - 0x0F, 0xFD, 0xFF, 0x03, 0xFF, 0xBF, 0xFB, 0xFF, 0xF3, 0xFF, 0xFF, 0xFE, - 0x7F, 0xFF, 0xFF, 0xC7, 0xFF, 0xEF, 0xF8, 0xFF, 0xFD, 0xFF, 0x0F, 0xFF, - 0x3F, 0xE0, 0x7F, 0x87, 0xFC, 0x00, 0x80, 0x00, 0x00, 0xFF, 0x80, 0x00, - 0x1F, 0xF0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x0F, 0xF8, - 0x00, 0x01, 0xFF, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x07, 0xFC, 0x00, 0x00, - 0xFF, 0x80, 0x00, 0x1F, 0xF0, 0x00, 0x03, 0xFE, 0x0F, 0xC0, 0x7F, 0xC7, - 0xFE, 0x0F, 0xF9, 0xFF, 0xF1, 0xFF, 0x7F, 0xFE, 0x3F, 0xFF, 0xFF, 0xE7, - 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0x1F, 0xFB, 0xFF, 0x81, - 0xFF, 0x7F, 0xE0, 0x1F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, - 0xF0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x07, - 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x00, 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF0, 0x03, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xF0, 0x03, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xC0, - 0x0F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xE0, 0x07, 0xFF, - 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF0, 0x03, 0xFF, 0xFE, 0x00, - 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, - 0xE0, 0x0F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xF8, 0x07, - 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFE, 0x07, 0xFD, 0xFF, - 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFC, 0xFF, 0xBF, 0xFF, - 0x9F, 0xF3, 0xFF, 0xE3, 0xFE, 0x3F, 0xF8, 0x7F, 0xC3, 0xFE, 0x00, 0x00, - 0x04, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xC0, - 0x7F, 0xFF, 0xF0, 0x1F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, - 0xF1, 0xFF, 0xCF, 0xFE, 0x7F, 0xC0, 0xFF, 0x9F, 0xE0, 0x1F, 0xEF, 0xF8, - 0x07, 0xFB, 0xFE, 0x01, 0xFE, 0xFF, 0x80, 0x7F, 0xFF, 0xE0, 0x1F, 0xFF, - 0xF0, 0x07, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xC0, 0x1F, - 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xC0, - 0x1F, 0xFF, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3F, - 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, - 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, - 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, - 0x00, 0x7F, 0xFF, 0xC0, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, 0xFF, - 0xFF, 0x00, 0x7F, 0xFF, 0xC0, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, - 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF8, 0x07, 0xFB, 0xFE, - 0x01, 0xFE, 0xFF, 0x80, 0x7F, 0x9F, 0xE0, 0x3F, 0xE7, 0xFC, 0x1F, 0xF9, - 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, - 0xE0, 0x3F, 0xFF, 0xF0, 0x07, 0xFF, 0xF8, 0x00, 0x7F, 0xF8, 0x00, 0x01, - 0xE0, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, - 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, - 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x1F, - 0xC3, 0xFC, 0x1F, 0xF8, 0xFF, 0x0F, 0xFF, 0x3F, 0xC7, 0xFF, 0xEF, 0xF3, - 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xDF, 0xF8, 0x7F, - 0xFF, 0xFC, 0x0F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xE0, - 0x1F, 0xFF, 0xF8, 0x07, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, - 0xC0, 0x0F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x00, 0x3F, - 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x00, - 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, - 0x00, 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x00, 0xFF, - 0xFF, 0x00, 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x00, - 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, - 0x00, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x03, 0xFF, - 0xFC, 0x00, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x03, - 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF8, - 0x07, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xC0, 0xFF, 0xDF, 0xFF, 0xFF, 0xF7, - 0xFF, 0xFF, 0xFD, 0xFF, 0xFE, 0xFF, 0x3F, 0xFF, 0xBF, 0xC7, 0xFF, 0xCF, - 0xF1, 0xFF, 0xE3, 0xFC, 0x1F, 0xF0, 0xFF, 0x00, 0xE0, 0x00, 0x00, 0x00, - 0x7F, 0xC0, 0x00, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, - 0x1F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xF1, 0xFF, 0x87, - 0xFE, 0x7F, 0xC0, 0xFF, 0xBF, 0xE0, 0x1F, 0xEF, 0xF8, 0x07, 0xFB, 0xFE, - 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xC0, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, - 0xFC, 0x01, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xC0, 0x1F, 0xFF, 0xF0, 0x07, - 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xC0, 0x1F, 0xFF, 0xF0, - 0x07, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3F, 0xC0, - 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x7F, 0xFF, - 0xC0, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x00, 0x7F, - 0xFF, 0xC0, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x00, - 0x7F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF8, 0x07, 0xFB, 0xFE, 0x01, 0xFE, 0xFF, - 0x80, 0x7F, 0x9F, 0xE0, 0x3F, 0xE7, 0xFC, 0x0F, 0xF9, 0xFF, 0xFF, 0xFC, - 0x3F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, - 0xF0, 0x07, 0xFF, 0xF8, 0x00, 0xFF, 0xF8, 0x00, 0x01, 0xE0, 0x00, 0x00, - 0x7F, 0xE0, 0x0F, 0xFF, 0x01, 0xFF, 0xF0, 0x3F, 0xFF, 0x07, 0xFF, 0xF0, - 0x7F, 0xFF, 0x07, 0xFE, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x00, 0xFF, 0x80, - 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, - 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, - 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, - 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, - 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, - 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, - 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, - 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, - 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, - 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, - 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, - 0x80, 0x00, 0xFC, 0x00, 0x00, 0x7F, 0xE3, 0xFC, 0x1F, 0xFE, 0x7F, 0x87, - 0xFF, 0xEF, 0xF1, 0xFF, 0xFD, 0xFE, 0x3F, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, - 0xF9, 0xFF, 0x87, 0xFF, 0x3F, 0xE0, 0x7F, 0xEF, 0xF8, 0x07, 0xFD, 0xFF, - 0x00, 0xFF, 0xBF, 0xE0, 0x1F, 0xF7, 0xFC, 0x03, 0xFE, 0xFF, 0x00, 0x7F, - 0xDF, 0xE0, 0x0F, 0xFB, 0xFC, 0x00, 0xFF, 0x7F, 0x80, 0x1F, 0xEF, 0xF0, - 0x03, 0xFD, 0xFE, 0x00, 0x7F, 0xBF, 0xC0, 0x0F, 0xF7, 0xF8, 0x01, 0xFE, - 0xFF, 0x00, 0x3F, 0xDF, 0xE0, 0x07, 0xFB, 0xFC, 0x00, 0xFF, 0x7F, 0x80, - 0x1F, 0xEF, 0xF0, 0x03, 0xFD, 0xFE, 0x00, 0x7F, 0xBF, 0xC0, 0x0F, 0xF7, - 0xF8, 0x01, 0xFE, 0xFF, 0x00, 0x3F, 0xDF, 0xE0, 0x07, 0xFB, 0xFC, 0x00, - 0xFF, 0x7F, 0x80, 0x1F, 0xEF, 0xF0, 0x03, 0xFD, 0xFE, 0x00, 0x7F, 0xBF, - 0xC0, 0x0F, 0xF7, 0xF8, 0x01, 0xFE, 0xFF, 0x00, 0x7F, 0xDF, 0xF0, 0x0F, - 0xFB, 0xFE, 0x01, 0xFF, 0x7F, 0xC0, 0x3F, 0xEF, 0xF8, 0x07, 0xFD, 0xFF, - 0x00, 0xFF, 0xBF, 0xF0, 0x1F, 0xF3, 0xFE, 0x07, 0xFE, 0x7F, 0xF3, 0xFF, - 0xCF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xDF, 0xE1, 0xFF, - 0xFB, 0xFC, 0x1F, 0xFE, 0x7F, 0x81, 0xFF, 0x0F, 0xF0, 0x00, 0x01, 0xFE, - 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF8, 0x00, 0x01, 0xFF, 0x00, 0x00, - 0x3F, 0xE2, 0x00, 0x0F, 0xFC, 0x70, 0x01, 0xFF, 0x1F, 0xC0, 0xFF, 0xE7, - 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, - 0xF0, 0x1F, 0xFF, 0xFC, 0x00, 0xFF, 0xFE, 0x00, 0x01, 0xF8, 0x00, 0x00, - 0xFF, 0x80, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x0F, 0xF8, - 0x00, 0x00, 0xFF, 0x80, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, - 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, - 0x81, 0xFC, 0x0F, 0xF8, 0x7F, 0xF0, 0xFF, 0x8F, 0xFF, 0x8F, 0xF9, 0xFF, - 0xFC, 0xFF, 0xBF, 0xFF, 0xCF, 0xFB, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xEF, - 0xFF, 0x9F, 0xFE, 0xFF, 0xE0, 0x3F, 0xEF, 0xFC, 0x03, 0xFF, 0xFF, 0xC0, - 0x1F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, - 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0x7F, 0xDF, - 0xF7, 0xFD, 0xFF, 0x7F, 0xDF, 0xF7, 0xFD, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFB, 0xFE, 0xFF, 0xBF, 0xEF, 0xFB, 0xFE, 0xFF, - 0xBF, 0xEF, 0xFB, 0xFE, 0xFF, 0xBF, 0xEF, 0xFB, 0xFE, 0xFF, 0xBF, 0xEF, - 0xFB, 0xFE, 0xFF, 0xBF, 0xEF, 0xFB, 0xFE, 0xFF, 0xBF, 0xEF, 0xFB, 0xFE, - 0xFF, 0xBF, 0xEF, 0xFB, 0xFE, 0xFF, 0xBF, 0xEF, 0xFB, 0xFE, 0xFF, 0xBF, - 0xEF, 0xFB, 0xFE, 0xFF, 0xBF, 0xEF, 0xFB, 0xFE, 0xFF, 0xBF, 0xEF, 0xFB, - 0xFE, 0xFF, 0xBF, 0xEF, 0xFB, 0xFE, 0xFF, 0xBF, 0xEF, 0xFB, 0xFE, 0xFF, - 0xBF, 0xEF, 0xF8, 0x07, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC, - 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, - 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, - 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, - 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, - 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, - 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, - 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, - 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, - 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0xFF, 0xFB, 0xFF, - 0xEF, 0xFF, 0x3F, 0xFC, 0xFF, 0xE3, 0xFF, 0x07, 0xF0, 0x00, 0xFF, 0x80, - 0x00, 0x03, 0xFE, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x3F, 0xE0, 0x00, - 0x00, 0xFF, 0x80, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, - 0x3F, 0xE0, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x0F, - 0xF8, 0x00, 0x00, 0x3F, 0xE0, 0x03, 0xFE, 0xFF, 0x80, 0x1F, 0xF3, 0xFE, - 0x00, 0x7F, 0xCF, 0xF8, 0x03, 0xFE, 0x3F, 0xE0, 0x0F, 0xF8, 0xFF, 0x80, - 0x3F, 0xC3, 0xFE, 0x01, 0xFF, 0x0F, 0xF8, 0x07, 0xFC, 0x3F, 0xE0, 0x3F, - 0xE0, 0xFF, 0x80, 0xFF, 0x83, 0xFE, 0x03, 0xFC, 0x0F, 0xF8, 0x1F, 0xF0, - 0x3F, 0xE0, 0x7F, 0xC0, 0xFF, 0x83, 0xFE, 0x03, 0xFE, 0x0F, 0xF8, 0x0F, - 0xF8, 0x3F, 0xC0, 0x3F, 0xE1, 0xFF, 0x00, 0xFF, 0x87, 0xFC, 0x03, 0xFE, - 0x3F, 0xE0, 0x0F, 0xF8, 0xFF, 0x80, 0x3F, 0xE3, 0xFC, 0x00, 0xFF, 0x9F, - 0xF0, 0x03, 0xFE, 0x7F, 0x80, 0x0F, 0xFB, 0xFE, 0x00, 0x3F, 0xEF, 0xF8, - 0x00, 0xFF, 0xBF, 0xC0, 0x03, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xF8, 0x00, - 0x3F, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xC0, 0x03, 0xFE, 0xFF, 0x00, 0x0F, - 0xFB, 0xFE, 0x00, 0x3F, 0xE7, 0xF8, 0x00, 0xFF, 0x9F, 0xF0, 0x03, 0xFE, - 0x7F, 0xC0, 0x0F, 0xF8, 0xFF, 0x00, 0x3F, 0xE3, 0xFE, 0x00, 0xFF, 0x87, - 0xF8, 0x03, 0xFE, 0x1F, 0xF0, 0x0F, 0xF8, 0x7F, 0xC0, 0x3F, 0xE0, 0xFF, - 0x80, 0xFF, 0x83, 0xFE, 0x03, 0xFE, 0x07, 0xF8, 0x0F, 0xF8, 0x1F, 0xF0, - 0x3F, 0xE0, 0x7F, 0xC0, 0xFF, 0x80, 0xFF, 0x83, 0xFE, 0x03, 0xFE, 0x0F, - 0xF8, 0x07, 0xF8, 0x3F, 0xE0, 0x1F, 0xF0, 0xFF, 0x80, 0x7F, 0xC3, 0xFE, - 0x00, 0xFF, 0x8F, 0xF8, 0x03, 0xFE, 0x3F, 0xE0, 0x07, 0xFC, 0xFF, 0x80, - 0x1F, 0xF3, 0xFE, 0x00, 0x7F, 0xCF, 0xF8, 0x00, 0xFF, 0xBF, 0xE0, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x01, 0xFC, 0x00, 0xFF, 0x03, - 0xFE, 0x1F, 0xF8, 0x0F, 0xFF, 0x0F, 0xF9, 0xFF, 0xF8, 0x7F, 0xFE, 0x3F, - 0xE7, 0xFF, 0xE3, 0xFF, 0xFC, 0xFF, 0xBF, 0xFF, 0xDF, 0xFF, 0xF3, 0xFF, - 0xFF, 0xFF, 0x7F, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, - 0x7F, 0xFF, 0xCF, 0xFE, 0xFF, 0xE0, 0x7F, 0xF8, 0x0F, 0xFB, 0xFF, 0x00, - 0xFF, 0xC0, 0x3F, 0xFF, 0xFC, 0x03, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x07, - 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0x7F, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFE, 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x7F, 0x80, - 0x1F, 0xFF, 0xF8, 0x01, 0xFE, 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x1F, 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x7F, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFE, 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xF8, 0x01, 0xFF, - 0xFF, 0x80, 0x1F, 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x7F, 0x80, 0x1F, 0xFF, - 0xF8, 0x01, 0xFE, 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x7F, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFE, 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xF8, 0x01, 0xFF, 0xFF, 0x80, - 0x1F, 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x7F, 0x80, 0x1F, 0xFF, 0xF8, 0x01, - 0xFE, 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x7F, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFE, - 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xE0, - 0x07, 0xFF, 0xFE, 0x00, 0x7F, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFE, 0x00, - 0x7F, 0xFF, 0xE0, 0x07, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xE0, 0x07, - 0xFF, 0xFE, 0x00, 0x7F, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFE, 0x00, 0x7F, - 0xFF, 0xE0, 0x07, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xE0, 0x07, 0xFF, - 0xFE, 0x00, 0x7F, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFE, 0x00, 0x7F, 0xFF, - 0xE0, 0x07, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xE0, 0x07, 0xFF, 0xFE, - 0x00, 0x7F, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFE, 0x00, 0x7F, 0xFF, 0xE0, - 0x07, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xE0, 0x07, 0xFF, 0xFE, 0x00, - 0x7F, 0x80, 0x1F, 0xF0, 0x00, 0x01, 0xFC, 0x0F, 0xF8, 0x7F, 0xF0, 0xFF, - 0x8F, 0xFF, 0x8F, 0xF9, 0xFF, 0xFC, 0xFF, 0xBF, 0xFF, 0xCF, 0xFB, 0xFF, - 0xFE, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0x8F, 0xFE, 0xFF, 0xE0, 0x3F, 0xEF, - 0xFC, 0x03, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, - 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, - 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF8, 0x01, 0xFF, 0x00, 0x7F, 0x80, 0x00, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, - 0x80, 0x3F, 0xFF, 0xF0, 0x1F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xC3, 0xFF, - 0xFF, 0xF1, 0xFF, 0x87, 0xFE, 0x7F, 0xC0, 0xFF, 0x9F, 0xE0, 0x3F, 0xEF, - 0xF8, 0x07, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xE0, 0x1F, - 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xC0, - 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, - 0xC0, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x00, 0x7F, - 0xFF, 0xC0, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x00, - 0x7F, 0xFF, 0xC0, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, - 0x00, 0x7F, 0xFF, 0xC0, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, 0xFF, - 0xFF, 0x00, 0x7F, 0xFF, 0xC0, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, - 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xC0, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, - 0x01, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF8, 0x07, 0xFF, - 0xFE, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xDF, 0xF0, 0x3F, 0xE7, 0xFC, 0x0F, - 0xF9, 0xFF, 0xFF, 0xFE, 0x3F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xC1, 0xFF, - 0xFF, 0xE0, 0x3F, 0xFF, 0xF0, 0x07, 0xFF, 0xF8, 0x00, 0x7F, 0xF8, 0x00, - 0x01, 0xE0, 0x00, 0x00, 0x01, 0xF0, 0x1F, 0xF1, 0xFF, 0xC3, 0xFE, 0x7F, - 0xFC, 0x7F, 0xDF, 0xFF, 0x8F, 0xFB, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xBF, - 0xFF, 0xFF, 0xF7, 0xFF, 0x87, 0xFE, 0xFF, 0xE0, 0x7F, 0xDF, 0xF8, 0x07, - 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, - 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x3F, - 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, - 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, - 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xC0, - 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, - 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, - 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, - 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x07, - 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, - 0x00, 0x7F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xC0, 0x3F, - 0xFF, 0xF8, 0x0F, 0xFB, 0xFF, 0x81, 0xFF, 0x7F, 0xFF, 0xFF, 0xEF, 0xFF, - 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xE7, 0xFD, 0xFF, 0xF8, - 0xFF, 0x9F, 0xFE, 0x1F, 0xF1, 0xFF, 0x03, 0xFE, 0x07, 0x00, 0x7F, 0xC0, - 0x00, 0x0F, 0xF8, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x07, - 0xFC, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x1F, 0xF0, 0x00, 0x03, 0xFE, 0x00, - 0x00, 0x7F, 0xC0, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x01, - 0xFF, 0x8F, 0xF1, 0xFF, 0xF3, 0xFC, 0x7F, 0xFE, 0xFF, 0x3F, 0xFF, 0xBF, - 0xDF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFD, 0xFF, 0x8F, 0xFF, 0xFF, 0xC0, - 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xF8, 0x07, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, - 0x80, 0x7F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, 0xFF, - 0xFF, 0x00, 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x00, - 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, - 0x00, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x03, 0xFF, - 0xFC, 0x00, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x03, - 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, - 0x03, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, - 0xF0, 0x03, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xC0, 0x0F, - 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, - 0x1F, 0xFF, 0xF8, 0x07, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, - 0xE0, 0x3F, 0xF7, 0xFC, 0x1F, 0xFD, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, - 0xCF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFB, 0xFC, 0x7F, 0xFE, 0xFF, 0x0F, 0xFF, - 0x3F, 0xC1, 0xFF, 0x8F, 0xF0, 0x0F, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, - 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, - 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, - 0xFF, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x01, 0xFF, 0xF0, 0xFF, 0xFE, 0x3F, - 0xFF, 0xCF, 0xFF, 0xFB, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0xFF, 0xF8, 0x1F, 0xFC, 0x03, 0xFF, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x01, - 0xFF, 0x00, 0x3F, 0xE0, 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xF0, 0x03, - 0xFE, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x3F, 0xE0, 0x07, - 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xF0, 0x03, 0xFE, 0x00, 0x7F, 0xC0, 0x0F, - 0xF8, 0x01, 0xFF, 0x00, 0x3F, 0xE0, 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x1F, - 0xF0, 0x03, 0xFE, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x3F, - 0xE0, 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xF0, 0x03, 0xFE, 0x00, 0x7F, - 0xC0, 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x3F, 0xE0, 0x07, 0xFC, 0x00, 0xFF, - 0x80, 0x1F, 0xF0, 0x03, 0xFE, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x01, 0xFF, - 0x00, 0x3F, 0xE0, 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xF0, 0x00, 0x00, - 0x7F, 0x80, 0x00, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xF0, - 0x1F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xF1, 0xFF, 0xCF, - 0xFC, 0x7F, 0xC0, 0xFF, 0x1F, 0xE0, 0x3F, 0xEF, 0xF8, 0x07, 0xFB, 0xFE, - 0x01, 0xFE, 0xFF, 0x80, 0x7F, 0xBF, 0xE0, 0x1F, 0xEF, 0xF8, 0x07, 0xFB, - 0xFE, 0x01, 0xFE, 0xFF, 0x80, 0x7F, 0x9F, 0xE0, 0x1F, 0xE7, 0xFC, 0x07, - 0xF9, 0xFF, 0x01, 0xFE, 0x7F, 0xE0, 0x00, 0x0F, 0xFC, 0x00, 0x03, 0xFF, - 0x80, 0x00, 0x7F, 0xF0, 0x00, 0x0F, 0xFE, 0x00, 0x03, 0xFF, 0xC0, 0x00, - 0x7F, 0xF8, 0x00, 0x0F, 0xFF, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x3F, 0xFC, - 0x00, 0x07, 0xFF, 0x80, 0x00, 0xFF, 0xF0, 0x00, 0x1F, 0xFE, 0x00, 0x03, - 0xFF, 0x80, 0x00, 0x7F, 0xF0, 0x00, 0x0F, 0xFC, 0x00, 0x01, 0xFF, 0x80, - 0x00, 0x7F, 0xE7, 0xF8, 0x0F, 0xF9, 0xFE, 0x01, 0xFF, 0x7F, 0x80, 0x7F, - 0xDF, 0xE0, 0x1F, 0xF7, 0xF8, 0x07, 0xFD, 0xFE, 0x00, 0xFF, 0x7F, 0x80, - 0x3F, 0xDF, 0xE0, 0x0F, 0xF7, 0xF8, 0x03, 0xFD, 0xFE, 0x01, 0xFF, 0x7F, - 0xC0, 0x7F, 0xDF, 0xF0, 0x1F, 0xF3, 0xFE, 0x0F, 0xFC, 0xFF, 0xFF, 0xFE, - 0x3F, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, - 0xF8, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFC, 0x00, 0x03, 0xF8, 0x00, 0x07, - 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, - 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, - 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, - 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, - 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x07, - 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, - 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, - 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, - 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, - 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x07, - 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, - 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x7F, 0xC0, - 0x07, 0xFC, 0x00, 0x7F, 0xC0, 0x07, 0xFF, 0xF0, 0x7F, 0xFF, 0x07, 0xFF, - 0xF0, 0x7F, 0xFF, 0x03, 0xFF, 0xF0, 0x1F, 0xFF, 0x00, 0xFF, 0xF0, 0xFF, - 0x80, 0x1F, 0xFF, 0xF0, 0x03, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xC0, 0x0F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, - 0x00, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF0, 0x03, 0xFF, 0xFE, 0x00, 0x7F, - 0xFF, 0xC0, 0x0F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xE0, - 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF0, 0x03, 0xFF, - 0xFE, 0x00, 0x7F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x00, - 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xF0, 0x03, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF8, 0x01, - 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, - 0x80, 0x1F, 0xFF, 0xF0, 0x03, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xC0, 0x0F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, - 0x00, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF0, 0x03, 0xFF, 0xFE, 0x00, 0x7F, - 0xFF, 0xC0, 0x0F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, - 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xFC, 0x1F, 0xFD, - 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xEF, 0xF7, 0xFF, 0xFD, 0xFE, 0x7F, 0xFF, - 0x3F, 0xC7, 0xFF, 0xE7, 0xF8, 0xFF, 0xF8, 0xFF, 0x07, 0xFE, 0x1F, 0xE0, - 0x1E, 0x00, 0x00, 0xFF, 0x00, 0x1F, 0xFF, 0xE0, 0x03, 0xFF, 0xFC, 0x00, - 0x7F, 0xFF, 0x80, 0x1F, 0xE7, 0xF8, 0x03, 0xFC, 0xFF, 0x00, 0x7F, 0x9F, - 0xE0, 0x0F, 0xF3, 0xFC, 0x01, 0xFE, 0x7F, 0x80, 0x3F, 0xCF, 0xF0, 0x07, - 0xF9, 0xFE, 0x00, 0xFE, 0x1F, 0xE0, 0x1F, 0xC3, 0xFC, 0x07, 0xF8, 0x7F, - 0x80, 0xFF, 0x0F, 0xF0, 0x1F, 0xE1, 0xFE, 0x03, 0xFC, 0x3F, 0xC0, 0x7F, - 0x87, 0xF8, 0x0F, 0xE0, 0x7F, 0x01, 0xFC, 0x0F, 0xF0, 0x3F, 0x81, 0xFE, - 0x07, 0xF0, 0x3F, 0xC1, 0xFE, 0x07, 0xF8, 0x3F, 0xC0, 0xFF, 0x07, 0xF8, - 0x1F, 0xE0, 0xFE, 0x01, 0xFC, 0x1F, 0xC0, 0x3F, 0xC3, 0xF8, 0x07, 0xF8, - 0x7F, 0x00, 0xFF, 0x0F, 0xE0, 0x1F, 0xE3, 0xFC, 0x03, 0xFC, 0x7F, 0x80, - 0x7F, 0x8F, 0xE0, 0x07, 0xF1, 0xFC, 0x00, 0xFE, 0x3F, 0x80, 0x1F, 0xC7, - 0xF0, 0x03, 0xFC, 0xFE, 0x00, 0x7F, 0x9F, 0xC0, 0x0F, 0xF3, 0xF8, 0x01, - 0xFE, 0x7E, 0x00, 0x1F, 0xCF, 0xC0, 0x03, 0xFB, 0xF8, 0x00, 0x7F, 0x7F, - 0x00, 0x0F, 0xEF, 0xE0, 0x01, 0xFD, 0xFC, 0x00, 0x3F, 0xFF, 0x80, 0x07, - 0xFF, 0xE0, 0x00, 0x7F, 0xFC, 0x00, 0x0F, 0xFF, 0x80, 0x01, 0xFF, 0xF0, - 0x00, 0x3F, 0xFE, 0x00, 0x07, 0xFF, 0xC0, 0x00, 0xFF, 0xF8, 0x00, 0x1F, - 0xFE, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x3F, 0xF8, 0x00, 0x07, 0xFF, 0x00, - 0x00, 0xFF, 0xE0, 0x00, 0xFF, 0x00, 0x7F, 0x80, 0x1F, 0xFF, 0xC0, 0x1F, - 0xE0, 0x07, 0xFF, 0xF0, 0x07, 0xF8, 0x03, 0xFF, 0xFC, 0x01, 0xFE, 0x00, - 0xFF, 0x7F, 0x00, 0xFF, 0xC0, 0x3F, 0xDF, 0xC0, 0x3F, 0xF0, 0x0F, 0xE7, - 0xF0, 0x0F, 0xFC, 0x03, 0xF9, 0xFC, 0x03, 0xFF, 0x00, 0xFE, 0x7F, 0x00, - 0xFF, 0xC0, 0x3F, 0x9F, 0xC0, 0x3F, 0xF0, 0x0F, 0xE7, 0xF8, 0x0F, 0xFE, - 0x03, 0xF9, 0xFE, 0x07, 0xFF, 0x80, 0xFE, 0x3F, 0x81, 0xFF, 0xE0, 0x7F, - 0x8F, 0xE0, 0x7F, 0xF8, 0x1F, 0xC3, 0xF8, 0x1F, 0xBE, 0x07, 0xF0, 0xFE, - 0x07, 0xEF, 0x81, 0xFC, 0x3F, 0x81, 0xFB, 0xE0, 0x7F, 0x0F, 0xE0, 0x7E, - 0xFC, 0x1F, 0xC3, 0xF8, 0x3F, 0xBF, 0x07, 0xF0, 0xFE, 0x0F, 0xCF, 0xC1, - 0xFC, 0x1F, 0xC3, 0xF3, 0xF0, 0x7F, 0x07, 0xF0, 0xFC, 0xFC, 0x1F, 0x81, - 0xFC, 0x3F, 0x1F, 0x0F, 0xE0, 0x7F, 0x0F, 0xC7, 0xC3, 0xF8, 0x1F, 0xC3, - 0xF1, 0xF8, 0xFE, 0x07, 0xF1, 0xF8, 0x7E, 0x3F, 0x81, 0xFC, 0x7E, 0x1F, - 0x8F, 0xE0, 0x7F, 0x1F, 0x87, 0xE3, 0xF8, 0x0F, 0xC7, 0xE1, 0xF8, 0xFE, - 0x03, 0xF1, 0xF8, 0x3E, 0x3F, 0x00, 0xFE, 0x7E, 0x0F, 0x8F, 0xC0, 0x3F, - 0x9F, 0x83, 0xF3, 0xF0, 0x0F, 0xE7, 0xC0, 0xFC, 0xFC, 0x03, 0xFB, 0xF0, - 0x3F, 0x3F, 0x00, 0xFE, 0xFC, 0x0F, 0xDF, 0xC0, 0x3F, 0xBF, 0x03, 0xF7, - 0xF0, 0x07, 0xEF, 0xC0, 0xFD, 0xFC, 0x01, 0xFB, 0xF0, 0x1F, 0x7E, 0x00, - 0x7E, 0xFC, 0x07, 0xFF, 0x80, 0x1F, 0xBE, 0x01, 0xFF, 0xE0, 0x07, 0xFF, - 0x80, 0x7F, 0xF8, 0x01, 0xFF, 0xE0, 0x1F, 0xFE, 0x00, 0x7F, 0xF8, 0x07, - 0xFF, 0x80, 0x1F, 0xFE, 0x01, 0xFF, 0xE0, 0x03, 0xFF, 0x80, 0x7F, 0xF8, - 0x00, 0xFF, 0xC0, 0x0F, 0xFC, 0x00, 0x3F, 0xF0, 0x03, 0xFF, 0x00, 0x0F, - 0xFC, 0x00, 0xFF, 0xC0, 0x03, 0xFF, 0x00, 0x3F, 0xF0, 0x00, 0xFF, 0xC0, - 0x0F, 0xFC, 0x00, 0x3F, 0xF0, 0x03, 0xFF, 0x00, 0x0F, 0xFC, 0x00, 0xFF, - 0xC0, 0x01, 0xFE, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, - 0x1F, 0xE0, 0x01, 0xFE, 0x00, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x01, 0xFE, - 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0x80, 0x1F, 0xF7, 0xF8, 0x01, 0xFE, 0x3F, - 0xC0, 0x1F, 0xE3, 0xFC, 0x01, 0xFC, 0x3F, 0xC0, 0x3F, 0xC1, 0xFE, 0x03, - 0xFC, 0x1F, 0xE0, 0x3F, 0x81, 0xFE, 0x07, 0xF8, 0x0F, 0xF0, 0x7F, 0x80, - 0xFF, 0x07, 0xF0, 0x0F, 0xF0, 0x7F, 0x00, 0x7F, 0x8F, 0xF0, 0x07, 0xF8, - 0xFE, 0x00, 0x7F, 0x8F, 0xE0, 0x03, 0xFD, 0xFE, 0x00, 0x3F, 0xDF, 0xC0, - 0x03, 0xFD, 0xFC, 0x00, 0x1F, 0xFF, 0xC0, 0x01, 0xFF, 0xF8, 0x00, 0x1F, - 0xFF, 0x80, 0x00, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0xFF, 0xF0, - 0x00, 0x07, 0xFF, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x07, 0xFE, 0x00, 0x00, - 0x3F, 0xE0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x07, 0xFE, - 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x07, 0xFE, 0x00, 0x00, 0xFF, 0xF0, 0x00, - 0x0F, 0xFF, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0x80, 0x01, 0xFF, - 0xF8, 0x00, 0x1F, 0xFF, 0x80, 0x03, 0xFF, 0xFC, 0x00, 0x3F, 0xBF, 0xC0, - 0x03, 0xFB, 0xFC, 0x00, 0x7F, 0x9F, 0xE0, 0x07, 0xF9, 0xFE, 0x00, 0x7F, - 0x1F, 0xE0, 0x0F, 0xF0, 0xFF, 0x00, 0xFF, 0x0F, 0xF0, 0x0F, 0xE0, 0xFF, - 0x01, 0xFE, 0x07, 0xF8, 0x1F, 0xE0, 0x7F, 0x81, 0xFC, 0x07, 0xFC, 0x3F, - 0xC0, 0x3F, 0xC3, 0xFC, 0x03, 0xFC, 0x3F, 0xC0, 0x3F, 0xE7, 0xF8, 0x01, - 0xFE, 0x7F, 0x80, 0x1F, 0xE7, 0xF8, 0x01, 0xFF, 0xFF, 0x00, 0x0F, 0xF0, - 0xFF, 0x00, 0x1F, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, - 0x01, 0xFE, 0x7F, 0x80, 0x1F, 0xE7, 0xF8, 0x01, 0xFE, 0x7F, 0x80, 0x1F, - 0xE7, 0xF8, 0x01, 0xFE, 0x7F, 0x80, 0x3F, 0xE7, 0xF8, 0x03, 0xFC, 0x3F, - 0xC0, 0x3F, 0xC3, 0xFC, 0x03, 0xFC, 0x3F, 0xC0, 0x3F, 0xC3, 0xFC, 0x03, - 0xFC, 0x3F, 0xC0, 0x3F, 0xC3, 0xFC, 0x03, 0xF8, 0x1F, 0xC0, 0x7F, 0x81, - 0xFE, 0x07, 0xF8, 0x1F, 0xE0, 0x7F, 0x81, 0xFE, 0x07, 0xF8, 0x1F, 0xE0, - 0x7F, 0x81, 0xFE, 0x07, 0xF0, 0x0F, 0xE0, 0x7F, 0x00, 0xFE, 0x07, 0xF0, - 0x0F, 0xE0, 0x7F, 0x00, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x00, 0xFF, - 0x0F, 0xE0, 0x07, 0xF0, 0xFE, 0x00, 0x7F, 0x0F, 0xE0, 0x07, 0xF0, 0xFE, - 0x00, 0x7F, 0x0F, 0xE0, 0x07, 0xF0, 0xFE, 0x00, 0x7F, 0x8F, 0xC0, 0x03, - 0xF9, 0xFC, 0x00, 0x3F, 0x9F, 0xC0, 0x03, 0xF9, 0xFC, 0x00, 0x3F, 0x9F, - 0xC0, 0x03, 0xF9, 0xFC, 0x00, 0x3F, 0x9F, 0x80, 0x01, 0xF9, 0xF8, 0x00, - 0x1F, 0x9F, 0x80, 0x01, 0xFD, 0xF8, 0x00, 0x1F, 0xDF, 0x80, 0x01, 0xFD, - 0xF8, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0x00, - 0x00, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x0F, - 0xFE, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x7F, 0xE0, - 0x00, 0x07, 0xFE, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x07, 0xFC, 0x00, 0x00, - 0x7F, 0xC0, 0x00, 0x07, 0xFC, 0x00, 0x3F, 0xFF, 0xC0, 0x03, 0xFF, 0xFC, - 0x00, 0x3F, 0xFF, 0x80, 0x03, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0x80, 0x03, - 0xFF, 0xF0, 0x00, 0x3F, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, - 0xDF, 0xFF, 0xFE, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xBF, 0xFF, 0xFD, 0xFF, - 0xFF, 0xE0, 0x01, 0xFF, 0x00, 0x0F, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xFC, - 0x00, 0x3F, 0xE0, 0x01, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x80, 0x07, - 0xFC, 0x00, 0x3F, 0xC0, 0x03, 0xFE, 0x00, 0x1F, 0xF0, 0x00, 0xFF, 0x00, - 0x0F, 0xF8, 0x00, 0x7F, 0xC0, 0x03, 0xFE, 0x00, 0x1F, 0xE0, 0x01, 0xFF, - 0x00, 0x0F, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xFC, 0x00, 0x3F, 0xE0, 0x01, - 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x80, 0x07, 0xFC, 0x00, 0x3F, 0xC0, - 0x03, 0xFE, 0x00, 0x1F, 0xF0, 0x00, 0xFF, 0x80, 0x07, 0xF8, 0x00, 0x7F, - 0xC0, 0x03, 0xFE, 0x00, 0x1F, 0xE0, 0x01, 0xFF, 0x00, 0x0F, 0xF8, 0x00, - 0x7F, 0xC0, 0x07, 0xFC, 0x00, 0x3F, 0xE0, 0x01, 0xFF, 0x00, 0x0F, 0xF0, - 0x00, 0xFF, 0x80, 0x07, 0xFC, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x0F, 0xF0, 0x03, 0xFF, 0x00, 0xFF, 0xF0, 0x1F, 0xFF, 0x01, - 0xFF, 0xF0, 0x1F, 0xFF, 0x03, 0xFF, 0xF0, 0x3F, 0xF0, 0x03, 0xFE, 0x00, - 0x3F, 0xE0, 0x03, 0xFE, 0x00, 0x3F, 0xC0, 0x03, 0xFC, 0x00, 0x3F, 0xC0, - 0x03, 0xFC, 0x00, 0x3F, 0xC0, 0x03, 0xFC, 0x00, 0x3F, 0xC0, 0x03, 0xFC, - 0x00, 0x3F, 0xC0, 0x03, 0xFC, 0x00, 0x3F, 0xC0, 0x03, 0xFC, 0x00, 0x3F, - 0xC0, 0x03, 0xFC, 0x00, 0x3F, 0xC0, 0x03, 0xFC, 0x00, 0x3F, 0xC0, 0x07, - 0xFC, 0x00, 0x7F, 0xC0, 0x07, 0xFC, 0x00, 0x7F, 0xC0, 0x0F, 0xFC, 0x0F, - 0xFF, 0x80, 0xFF, 0xF8, 0x0F, 0xFF, 0x00, 0xFF, 0xC0, 0x0F, 0xF8, 0x00, - 0xFF, 0xE0, 0x0F, 0xFF, 0x00, 0xFF, 0xF8, 0x0F, 0xFF, 0x80, 0x0F, 0xFC, - 0x00, 0x7F, 0xC0, 0x07, 0xFC, 0x00, 0x7F, 0xC0, 0x03, 0xFC, 0x00, 0x3F, - 0xC0, 0x03, 0xFC, 0x00, 0x3F, 0xC0, 0x03, 0xFC, 0x00, 0x3F, 0xC0, 0x03, - 0xFC, 0x00, 0x3F, 0xC0, 0x03, 0xFC, 0x00, 0x3F, 0xC0, 0x03, 0xFC, 0x00, - 0x3F, 0xC0, 0x03, 0xFC, 0x00, 0x3F, 0xC0, 0x03, 0xFC, 0x00, 0x3F, 0xC0, - 0x03, 0xFC, 0x00, 0x3F, 0xC0, 0x03, 0xFE, 0x00, 0x3F, 0xE0, 0x03, 0xFE, - 0x00, 0x3F, 0xF8, 0x03, 0xFF, 0xF0, 0x1F, 0xFF, 0x01, 0xFF, 0xF0, 0x0F, - 0xFF, 0x00, 0x7F, 0xF0, 0x03, 0xFF, 0x00, 0x07, 0xF0, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0x00, - 0x1F, 0xF8, 0x03, 0xFF, 0x80, 0x7F, 0xF8, 0x0F, 0xFF, 0x81, 0xFF, 0xF0, - 0x3F, 0xFE, 0x00, 0x7F, 0xC0, 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xF0, - 0x03, 0xFE, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x3F, 0xE0, - 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xF0, 0x03, 0xFE, 0x00, 0x7F, 0xC0, - 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x3F, 0xE0, 0x07, 0xFC, 0x00, 0xFF, 0x80, - 0x1F, 0xF0, 0x03, 0xFE, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x01, 0xFF, 0x00, - 0x1F, 0xF0, 0x03, 0xFF, 0x00, 0x7F, 0xFC, 0x07, 0xFF, 0x80, 0x7F, 0xF0, - 0x07, 0xFE, 0x00, 0x3F, 0xC0, 0x1F, 0xF8, 0x0F, 0xFF, 0x03, 0xFF, 0xE0, - 0x7F, 0xFC, 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x01, - 0xFF, 0x00, 0x3F, 0xE0, 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xF0, 0x03, - 0xFE, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x3F, 0xE0, 0x07, - 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xF0, 0x03, 0xFE, 0x00, 0x7F, 0xC0, 0x0F, - 0xF8, 0x01, 0xFF, 0x00, 0x3F, 0xE0, 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x3F, - 0xF0, 0x0F, 0xFC, 0x0F, 0xFF, 0x81, 0xFF, 0xF0, 0x3F, 0xFC, 0x07, 0xFF, - 0x80, 0xFF, 0xE0, 0x1F, 0xF0, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x7C, 0x00, 0x07, 0xE0, 0x7F, 0xF0, 0x01, 0xFC, 0x3F, 0xFF, - 0xC0, 0xFF, 0x1F, 0xFF, 0xFE, 0xFF, 0x8F, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, - 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFE, 0x3F, - 0xFF, 0xFF, 0xFF, 0x8F, 0xF0, 0x3F, 0xFF, 0xC0, 0xF8, 0x01, 0xFF, 0xE0, - 0x0E, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x07, 0xFC, - 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, - 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFE, - 0x01, 0xFF, 0xFF, 0xFE, 0x07, 0xFE, 0x07, 0xFC, 0x0F, 0xF8, 0x0F, 0xF8, - 0x1F, 0xF0, 0x0F, 0xF8, 0x3F, 0xE0, 0x1F, 0xF0, 0xFF, 0x80, 0x3F, 0xE1, - 0xFF, 0x00, 0x7F, 0xC3, 0xFE, 0x00, 0xFF, 0x87, 0xFC, 0x00, 0xFF, 0x0F, - 0xF8, 0x01, 0xFE, 0x1F, 0xF0, 0x03, 0xFC, 0x3F, 0xE0, 0x07, 0xF8, 0x7F, - 0xC0, 0x0F, 0xF0, 0xFF, 0x80, 0x1F, 0xE1, 0xFF, 0x00, 0x3F, 0xC3, 0xFE, - 0x00, 0x7F, 0x87, 0xFC, 0x00, 0xFF, 0x0F, 0xF8, 0x01, 0xFE, 0x1F, 0xF0, - 0x03, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, - 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x07, 0xFC, 0x00, - 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, - 0x07, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFE, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x0F, 0xF8, 0x00, 0x00, - 0x1F, 0xF0, 0x03, 0xFC, 0x3F, 0xE0, 0x07, 0xF8, 0x7F, 0xC0, 0x0F, 0xF0, - 0xFF, 0x80, 0x1F, 0xE1, 0xFF, 0x00, 0x3F, 0xC3, 0xFE, 0x00, 0x7F, 0x87, - 0xFC, 0x00, 0xFF, 0x0F, 0xF8, 0x01, 0xFE, 0x1F, 0xF0, 0x03, 0xFC, 0x3F, - 0xE0, 0x07, 0xF8, 0x7F, 0xC0, 0x0F, 0xF0, 0xFF, 0x80, 0x1F, 0xE1, 0xFF, - 0x00, 0x7F, 0xC3, 0xFE, 0x00, 0xFF, 0x87, 0xFC, 0x01, 0xFF, 0x07, 0xF8, - 0x03, 0xFE, 0x0F, 0xF8, 0x07, 0xFC, 0x1F, 0xF0, 0x0F, 0xF0, 0x3F, 0xE0, - 0x3F, 0xE0, 0x3F, 0xE0, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, - 0xFE, 0x00, 0xFF, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, - 0xC0, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0x80, - 0x00, - // euro - 0x00, 0x07, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0x00, - 0x07, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xFE, 0x07, 0xFE, 0x07, 0xFC, 0x0F, - 0xF8, 0x0F, 0xF8, 0x1F, 0xF0, 0x0F, 0xF8, 0x3F, 0xE0, 0x1F, 0xF0, 0xFF, - 0x80, 0x3F, 0xE1, 0xFF, 0x00, 0x7F, 0xC3, 0xFE, 0x00, 0xFF, 0x87, 0xFC, - 0x00, 0xFF, 0x0F, 0xF8, 0x01, 0xFE, 0x1F, 0xF0, 0x03, 0xFC, 0x3F, 0xE0, - 0x07, 0xF8, 0x7F, 0xC0, 0x0F, 0xF0, 0xFF, 0x80, 0x1F, 0xE1, 0xFF, 0x00, - 0x3F, 0xC3, 0xFE, 0x00, 0x7F, 0x87, 0xFC, 0x00, 0xFF, 0x0F, 0xF8, 0x01, - 0xFE, 0x1F, 0xF0, 0x03, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xFF, 0x80, - 0x0F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFC, 0x00, - 0x07, 0xFC, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, - 0x3F, 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0x00, 0x1F, - 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x0F, - 0xF8, 0x00, 0x00, 0x1F, 0xF0, 0x03, 0xFC, 0x3F, 0xE0, 0x07, 0xF8, 0x7F, - 0xC0, 0x0F, 0xF0, 0xFF, 0x80, 0x1F, 0xE1, 0xFF, 0x00, 0x3F, 0xC3, 0xFE, - 0x00, 0x7F, 0x87, 0xFC, 0x00, 0xFF, 0x0F, 0xF8, 0x01, 0xFE, 0x1F, 0xF0, - 0x03, 0xFC, 0x3F, 0xE0, 0x07, 0xF8, 0x7F, 0xC0, 0x0F, 0xF0, 0xFF, 0x80, - 0x1F, 0xE1, 0xFF, 0x00, 0x7F, 0xC3, 0xFE, 0x00, 0xFF, 0x87, 0xFC, 0x01, - 0xFF, 0x0F, 0xF8, 0x03, 0xFE, 0x0F, 0xF8, 0x07, 0xFC, 0x1F, 0xF0, 0x0F, - 0xF0, 0x3F, 0xE0, 0x3F, 0xE0, 0x3F, 0xE0, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, - 0x80, 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xF8, 0x00, - 0x00, 0x3F, 0x80, 0x00, - // pound - 0x00, 0x0F, 0xFC, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFC, 0x00, - 0x7F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xC0, 0x7F, - 0xFF, 0xFF, 0x83, 0xFF, 0x03, 0xFE, 0x0F, 0xF8, 0x07, 0xF8, 0x3F, 0xC0, - 0x1F, 0xE1, 0xFF, 0x00, 0x3F, 0xC7, 0xFC, 0x00, 0xFF, 0x1F, 0xE0, 0x03, - 0xFC, 0x7F, 0x80, 0x0F, 0xF1, 0xFE, 0x00, 0x3F, 0xC7, 0xF8, 0x00, 0xFF, - 0x1F, 0xF0, 0x03, 0xFC, 0x7F, 0xC0, 0x0F, 0xF1, 0xFF, 0x00, 0x3F, 0xC3, - 0xFC, 0x00, 0xFF, 0x0F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0xFF, - 0x80, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x1F, 0xF0, - 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x03, 0xFC, 0x00, - 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x3F, 0xFF, 0xFF, 0xF8, - 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xFE, 0x3F, - 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFE, 0x00, 0x00, 0x0F, - 0xF8, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x01, 0xFE, - 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x7F, 0xC0, - 0x00, 0x01, 0xFF, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x1F, 0xF0, 0x00, - 0x00, 0x7F, 0xC0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, - 0x1F, 0xF0, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x0F, - 0xF8, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x0F, 0xF8, - 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x1F, 0xF0, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, - 0x7F, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xDF, - 0xFF, 0xFF, 0xFF, - // yen - 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x07, 0xFB, 0xFE, 0x00, 0x1F, 0xF3, - 0xFC, 0x00, 0x3F, 0xE7, 0xFC, 0x00, 0x7F, 0xCF, 0xF8, 0x00, 0xFF, 0x0F, - 0xF0, 0x03, 0xFE, 0x1F, 0xE0, 0x07, 0xFC, 0x3F, 0xE0, 0x0F, 0xF0, 0x7F, - 0xC0, 0x1F, 0xE0, 0x7F, 0x80, 0x7F, 0xC0, 0xFF, 0x80, 0xFF, 0x81, 0xFF, - 0x01, 0xFE, 0x01, 0xFE, 0x03, 0xFC, 0x03, 0xFC, 0x07, 0xF8, 0x07, 0xFC, - 0x1F, 0xF0, 0x0F, 0xF8, 0x3F, 0xC0, 0x0F, 0xF0, 0x7F, 0x80, 0x1F, 0xE0, - 0xFF, 0x00, 0x3F, 0xE3, 0xFC, 0x00, 0x3F, 0xC7, 0xF8, 0x00, 0x7F, 0x8F, - 0xF0, 0x00, 0xFF, 0x9F, 0xE0, 0x00, 0xFF, 0x7F, 0x80, 0x01, 0xFE, 0xFF, - 0x00, 0x03, 0xFD, 0xFE, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF0, - 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0x00, - 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x7F, 0xFC, 0x00, 0x00, 0xFF, 0xF8, 0x00, - 0x00, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0x80, 0x07, - 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0xF8, 0x3F, - 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xE0, 0x00, 0x7F, 0xC0, 0x00, 0x00, - 0xFF, 0x80, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x07, - 0xFC, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, - 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, - 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x0F, 0xF8, - 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x7F, 0xC0, - 0x00, 0x00, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x03, 0xFE, 0x00, - 0x00, 0x07, 0xFC, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x1F, 0xF0, 0x00, - 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x7F, 0xC0, 0x00 - }; +const uint8_t Antonio_SemiBold40pt7bBitmaps_Gzip[] = { + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe5, 0x5c, + 0xbd, 0x72, 0xec, 0x3a, 0x72, 0x06, 0x8b, 0x5b, 0x66, 0xb2, 0x65, 0xdc, + 0xd0, 0x81, 0x77, 0xf1, 0x0a, 0x1b, 0x3a, 0xb8, 0x75, 0xe0, 0x47, 0x72, + 0xe8, 0xe0, 0x78, 0x40, 0x95, 0x02, 0x85, 0xf3, 0x08, 0x7a, 0x93, 0x15, + 0x55, 0x0a, 0x14, 0xce, 0x23, 0x0c, 0x65, 0x05, 0x0a, 0x05, 0x95, 0x02, + 0x41, 0x25, 0x0a, 0xed, 0xef, 0x6b, 0x90, 0x1c, 0xce, 0x48, 0x3a, 0xd2, + 0xf9, 0xdd, 0x5b, 0xde, 0x39, 0x73, 0x40, 0x70, 0x48, 0x82, 0x0d, 0xa0, + 0x7f, 0xbe, 0xee, 0x06, 0x64, 0x64, 0xfc, 0x3c, 0xe6, 0x70, 0x7a, 0x73, + 0x50, 0xa4, 0xc1, 0xdb, 0x8b, 0x78, 0x58, 0xfc, 0xb5, 0x39, 0xea, 0xff, + 0x7b, 0x2e, 0xcc, 0xf8, 0xb1, 0x4f, 0x59, 0xce, 0x6e, 0xb5, 0x48, 0x22, + 0xb7, 0xd3, 0x99, 0xbb, 0xbc, 0x1b, 0x02, 0x8a, 0xb4, 0x72, 0x27, 0x57, + 0x2c, 0xce, 0xe3, 0x67, 0x63, 0x9a, 0xde, 0xb7, 0x55, 0xb2, 0x9d, 0xc9, + 0x75, 0x34, 0xfe, 0x68, 0x30, 0xb6, 0x0f, 0xa6, 0x8e, 0xae, 0x33, 0x43, + 0x83, 0x1f, 0xaa, 0x64, 0x5c, 0xb7, 0x32, 0x4d, 0xc4, 0x5d, 0x83, 0xed, + 0xcd, 0xaa, 0xc6, 0x0f, 0x6d, 0xe6, 0x63, 0xa6, 0xd6, 0xc7, 0x9a, 0xf1, + 0xb1, 0x6e, 0x7e, 0xac, 0x37, 0x41, 0x1f, 0xcb, 0x35, 0x3a, 0x33, 0xb0, + 0x47, 0x1e, 0xff, 0x37, 0xf8, 0x7f, 0xcf, 0x1f, 0xea, 0xe4, 0xc6, 0xc7, + 0xaa, 0xf9, 0x31, 0x34, 0xbe, 0x7b, 0x6c, 0xa2, 0x89, 0x6f, 0xc3, 0x5d, + 0xed, 0xf0, 0x7a, 0x3b, 0xcd, 0xfc, 0xd8, 0x8e, 0xa6, 0x45, 0x57, 0xda, + 0xb1, 0x2b, 0x69, 0xee, 0xca, 0x30, 0x76, 0xc5, 0x95, 0xae, 0xbc, 0xfe, + 0xd8, 0x72, 0x04, 0x8c, 0xc3, 0xf8, 0x74, 0xa6, 0x8a, 0xc6, 0x7c, 0x7e, + 0x79, 0x12, 0x92, 0x09, 0xd2, 0x7a, 0x89, 0x4e, 0x06, 0x2b, 0x72, 0x2c, + 0x72, 0x07, 0xaa, 0xc2, 0xb9, 0xb8, 0xe8, 0x6f, 0x13, 0x26, 0xa1, 0xca, + 0xd2, 0x86, 0xb3, 0xde, 0xdd, 0xa6, 0x66, 0x3c, 0x39, 0xed, 0xdd, 0xcd, + 0xd0, 0x3c, 0x4a, 0x95, 0x43, 0x1f, 0xd6, 0x83, 0xa9, 0x05, 0xcd, 0xf4, + 0xc6, 0x65, 0xd4, 0x3a, 0x36, 0xe8, 0x04, 0x35, 0x90, 0x06, 0x22, 0xa4, + 0x35, 0x12, 0x8d, 0xe3, 0x4d, 0xad, 0x09, 0xd1, 0xd8, 0xc1, 0x54, 0xac, + 0xdd, 0x24, 0xfb, 0x88, 0x91, 0x0d, 0x6d, 0xd8, 0xf6, 0xee, 0x21, 0x35, + 0xcf, 0xb9, 0xc2, 0x89, 0xdf, 0xf6, 0xf6, 0x21, 0xd5, 0x7a, 0xd2, 0x85, + 0x6d, 0x74, 0x0f, 0xd9, 0x0e, 0x72, 0x99, 0x31, 0x62, 0x27, 0x22, 0x57, + 0x22, 0xd1, 0x4b, 0x6a, 0x64, 0x30, 0x82, 0x0e, 0x0f, 0xc6, 0xfc, 0x0e, + 0x36, 0x31, 0xa6, 0x46, 0x1f, 0xe3, 0x8b, 0x13, 0xbe, 0x46, 0x3f, 0x0d, + 0x48, 0x31, 0x4d, 0x42, 0x6f, 0x05, 0x05, 0xc6, 0xd0, 0x78, 0xb4, 0xb0, + 0xab, 0x60, 0x10, 0x31, 0x04, 0x79, 0xac, 0x3c, 0x4c, 0x95, 0x23, 0xf4, + 0x8a, 0xa3, 0x27, 0x66, 0x59, 0xf1, 0xed, 0x5e, 0x25, 0x2c, 0x2a, 0xf8, + 0x1e, 0x54, 0xf2, 0x9b, 0x15, 0xcc, 0xe2, 0x41, 0xa5, 0x9e, 0x2b, 0xe9, + 0xb0, 0x42, 0x4a, 0xc7, 0x0a, 0x46, 0x91, 0x15, 0x1b, 0xad, 0xf4, 0x5a, + 0xe9, 0x9d, 0xc4, 0x52, 0xc1, 0xc8, 0xb0, 0xe2, 0xba, 0x00, 0x2e, 0x5b, + 0x56, 0x7c, 0x27, 0xb7, 0x59, 0x2b, 0x2d, 0xa6, 0x6c, 0xaf, 0x12, 0x40, + 0x50, 0xa9, 0x54, 0x63, 0x05, 0x17, 0x8c, 0xb0, 0x83, 0x79, 0xaf, 0xc2, + 0x0b, 0x83, 0x56, 0x8e, 0xf2, 0x58, 0x91, 0x5c, 0x6b, 0xc5, 0xa3, 0x92, + 0x4a, 0x65, 0x28, 0x15, 0x8c, 0x73, 0x13, 0x59, 0xb1, 0x12, 0x4b, 0x05, + 0xdc, 0x60, 0xb5, 0xa2, 0x94, 0x6a, 0xc5, 0xec, 0x2a, 0x6e, 0xae, 0x74, + 0x63, 0xc5, 0xcf, 0x95, 0xf6, 0xb0, 0x12, 0xe6, 0x8a, 0x19, 0x2b, 0x32, + 0x55, 0xf2, 0x61, 0xa5, 0xd2, 0x0a, 0xc6, 0x9c, 0xa3, 0xac, 0x15, 0x8e, + 0x32, 0x3b, 0xa4, 0x83, 0x2b, 0x73, 0xe5, 0x38, 0x17, 0x0e, 0x09, 0x13, + 0x63, 0x68, 0xc5, 0x2a, 0x87, 0xa4, 0xc2, 0x0f, 0x73, 0x05, 0x03, 0x4e, + 0x92, 0xc9, 0x57, 0xdd, 0xa8, 0xaa, 0x20, 0x49, 0x36, 0x95, 0x1f, 0x6a, + 0x3e, 0x28, 0xa8, 0x40, 0x9c, 0xf0, 0x03, 0xd9, 0x7f, 0x0b, 0x79, 0x84, + 0x2c, 0x36, 0x54, 0x05, 0x62, 0x20, 0xbe, 0xbd, 0x6b, 0xeb, 0x01, 0x52, + 0x2a, 0xed, 0xca, 0xb8, 0x68, 0xd1, 0x57, 0x68, 0x0c, 0xdf, 0xf9, 0xf1, + 0x16, 0x4a, 0x38, 0x85, 0x59, 0x95, 0xcb, 0x39, 0x5a, 0x49, 0x60, 0xb1, + 0xb0, 0xee, 0x8d, 0xbd, 0x87, 0xf0, 0xe4, 0x40, 0x12, 0x7a, 0xbc, 0x48, + 0xe9, 0x1d, 0xc9, 0x50, 0x9a, 0xd8, 0x51, 0x32, 0xbd, 0x07, 0x71, 0x90, + 0x33, 0x15, 0x39, 0x23, 0xca, 0xf8, 0xe6, 0x37, 0x48, 0xc1, 0xbf, 0x54, + 0x92, 0xab, 0xce, 0x4b, 0xf7, 0x3b, 0x5a, 0xb2, 0x17, 0x39, 0x1c, 0xa7, + 0xb0, 0x8e, 0xe1, 0x34, 0x8a, 0xbb, 0x1e, 0xdc, 0x75, 0x92, 0x23, 0xa8, + 0x57, 0xf0, 0xd1, 0xc5, 0xd0, 0x28, 0x53, 0x65, 0xd7, 0x5b, 0x39, 0x86, + 0xb0, 0xc5, 0xd0, 0xba, 0x01, 0x13, 0x88, 0x1b, 0xd0, 0xb8, 0xef, 0x9a, + 0x01, 0x83, 0x45, 0x4e, 0xf4, 0xd1, 0xf5, 0x8d, 0x80, 0x0f, 0xa4, 0x87, + 0xbc, 0x42, 0x56, 0x9d, 0x74, 0x54, 0x6a, 0x0e, 0xc5, 0x11, 0x94, 0x36, + 0xc5, 0x15, 0x93, 0x9f, 0xd9, 0x2a, 0x18, 0x47, 0x3a, 0x3c, 0xdb, 0x73, + 0x7c, 0x44, 0x02, 0x3e, 0xab, 0xf2, 0xf9, 0xf4, 0xe9, 0xf7, 0xf2, 0x31, + 0x9f, 0x6d, 0x94, 0x4b, 0xf1, 0x83, 0x3c, 0xc8, 0x36, 0x85, 0xf3, 0x6c, + 0x93, 0xef, 0x31, 0x39, 0x3f, 0xf5, 0xe0, 0x22, 0x94, 0xdd, 0x09, 0x14, + 0xb2, 0x1f, 0x42, 0x04, 0xf9, 0xe6, 0xcf, 0xa9, 0x46, 0x4f, 0x7c, 0x82, + 0x7e, 0xbe, 0xc5, 0x1d, 0xcd, 0xa0, 0x77, 0xe8, 0xa1, 0x43, 0x5f, 0x6d, + 0xf4, 0x3f, 0xf2, 0x30, 0x35, 0x7d, 0x2e, 0x76, 0x08, 0xb7, 0x72, 0x96, + 0xf1, 0xda, 0xf5, 0xe0, 0xbb, 0xae, 0x28, 0x1d, 0x32, 0x26, 0xb9, 0xcf, + 0x54, 0x26, 0xfd, 0xe9, 0xcf, 0x4d, 0xd7, 0xa7, 0x4f, 0x76, 0x7d, 0x15, + 0x87, 0xb0, 0x3e, 0x7d, 0x90, 0xff, 0x91, 0xad, 0x48, 0xc2, 0x60, 0x83, + 0x3b, 0x55, 0xdd, 0x62, 0x52, 0x8a, 0xf2, 0xcd, 0xe4, 0x60, 0xa8, 0xf3, + 0x47, 0xd9, 0x86, 0x87, 0xf4, 0x28, 0xee, 0xe4, 0x22, 0xe1, 0xc9, 0xe3, + 0x2a, 0xfe, 0xc7, 0x6f, 0xb6, 0xfd, 0x4f, 0x33, 0x8c, 0xcd, 0xb6, 0x45, + 0x01, 0xad, 0xde, 0xfc, 0xca, 0x8b, 0xcf, 0x07, 0x6f, 0x8e, 0x03, 0x5e, + 0x77, 0x15, 0x3f, 0xbb, 0xe6, 0x82, 0x34, 0xd7, 0xdd, 0x5e, 0x23, 0x71, + 0x6e, 0xcd, 0x94, 0x6f, 0x1e, 0x85, 0xb5, 0x7c, 0x21, 0xa6, 0xf3, 0x17, + 0xac, 0x36, 0x7f, 0x21, 0x91, 0xf3, 0x17, 0x22, 0x38, 0x7f, 0x7d, 0xb7, + 0xfb, 0x86, 0x76, 0xf1, 0x9d, 0x9a, 0x3f, 0x78, 0xc3, 0xa2, 0xf9, 0x7a, + 0xd1, 0x7c, 0xb3, 0x68, 0xde, 0x2e, 0x9a, 0x77, 0x8b, 0xe6, 0xfd, 0x9b, + 0xcd, 0xab, 0x11, 0x84, 0x44, 0x42, 0x41, 0x40, 0xf0, 0x2b, 0x74, 0x32, + 0x08, 0x54, 0x20, 0xcd, 0xd6, 0x10, 0x7a, 0xd9, 0xc0, 0xe2, 0xe1, 0x57, + 0xdf, 0xb9, 0x9b, 0x54, 0x53, 0x31, 0x9f, 0xc1, 0xd6, 0x41, 0x72, 0xd4, + 0xf8, 0x36, 0x42, 0x6d, 0xdb, 0x41, 0x73, 0x02, 0x25, 0xa0, 0x11, 0x08, + 0xde, 0xaf, 0xba, 0x04, 0x93, 0x7b, 0x0f, 0x45, 0x0e, 0xe3, 0xbb, 0x89, + 0x85, 0xc2, 0xde, 0x5f, 0x43, 0x00, 0x0a, 0xf1, 0x7d, 0x61, 0xb0, 0x4a, + 0x1f, 0x88, 0xd4, 0x26, 0xb5, 0xea, 0x41, 0x8c, 0x1c, 0x94, 0x42, 0xb4, + 0xb0, 0xe1, 0xe7, 0x90, 0xf1, 0xc5, 0xe7, 0x5e, 0x52, 0x48, 0x36, 0x55, + 0x60, 0xca, 0x1e, 0x36, 0x5a, 0x70, 0x57, 0x0d, 0x76, 0xec, 0x7e, 0xe1, + 0x4f, 0x34, 0x12, 0x12, 0xa9, 0xed, 0x94, 0xf2, 0x73, 0xe5, 0x37, 0x10, + 0x99, 0x21, 0x65, 0x50, 0xc5, 0xa7, 0x3d, 0xba, 0x8a, 0xee, 0x63, 0x48, + 0x6a, 0xbd, 0xc7, 0xe8, 0x10, 0x61, 0x6c, 0xd0, 0xc7, 0x9e, 0x46, 0x8b, + 0x43, 0xb3, 0xbb, 0x06, 0xf8, 0xd3, 0x71, 0xe6, 0xc1, 0x08, 0x85, 0x35, + 0x12, 0xc1, 0x07, 0xbe, 0x78, 0x31, 0xbf, 0x30, 0x40, 0xa2, 0x9a, 0x77, + 0xfc, 0x82, 0x07, 0x3b, 0xf2, 0x02, 0x1e, 0xf0, 0x91, 0xcf, 0xb8, 0xc4, + 0x67, 0x0e, 0x1e, 0xab, 0xc4, 0x8c, 0x0f, 0x84, 0xd2, 0x76, 0xcf, 0xb6, + 0xc9, 0x85, 0x22, 0x4f, 0x22, 0xcf, 0x20, 0x97, 0x6a, 0x52, 0xe4, 0x4c, + 0x28, 0xe6, 0xbd, 0x36, 0x9a, 0xf7, 0xb8, 0x2b, 0x63, 0x82, 0xae, 0x0f, + 0xb9, 0xeb, 0xf6, 0x8d, 0x19, 0x6f, 0x49, 0x09, 0xde, 0xcb, 0x76, 0x40, + 0x0a, 0x6d, 0x9f, 0x2f, 0x35, 0xd1, 0xdf, 0x40, 0xa4, 0xb0, 0xf9, 0x56, + 0xa1, 0x5b, 0x24, 0x74, 0xab, 0x30, 0xdd, 0x1e, 0x0f, 0xa2, 0x17, 0xbc, + 0x09, 0x14, 0x8e, 0xcf, 0xd3, 0x56, 0xf2, 0x87, 0xb1, 0x41, 0xe9, 0xac, + 0xa4, 0xaa, 0xa8, 0x21, 0x45, 0x67, 0x98, 0x15, 0x89, 0x07, 0x64, 0x6c, + 0x62, 0xf3, 0x98, 0x95, 0xbb, 0x6e, 0xa0, 0x75, 0x67, 0xd1, 0x00, 0x77, + 0xe5, 0xc2, 0x5d, 0xbd, 0x72, 0x57, 0x34, 0xfa, 0x2e, 0xa2, 0x3b, 0xbc, + 0xd6, 0xa8, 0x49, 0x35, 0x04, 0x90, 0xa4, 0x09, 0x16, 0x04, 0x74, 0xe1, + 0xca, 0xa0, 0x26, 0xaf, 0x51, 0x3b, 0x6b, 0xa8, 0xf9, 0x30, 0xdf, 0xb8, + 0x82, 0x81, 0xc4, 0xe9, 0x13, 0x46, 0xf9, 0x16, 0xa3, 0x7e, 0xd6, 0x99, + 0x15, 0x94, 0x21, 0xac, 0xa6, 0xdd, 0xc0, 0x94, 0xa2, 0xb7, 0x40, 0x48, + 0xcd, 0x35, 0xcc, 0xeb, 0x3a, 0x9a, 0x95, 0xef, 0x6a, 0x18, 0x39, 0x7b, + 0x31, 0x18, 0x0f, 0xd3, 0x36, 0xd0, 0x32, 0x41, 0x76, 0x61, 0xee, 0xb2, + 0x8d, 0x75, 0xf2, 0x9d, 0x85, 0x29, 0xf0, 0x30, 0x6d, 0xd0, 0xd1, 0xc0, + 0xd6, 0x9d, 0x83, 0xb9, 0x03, 0xe2, 0x81, 0xb7, 0x00, 0x8b, 0xed, 0x3b, + 0x05, 0x44, 0x35, 0x10, 0x39, 0x14, 0x79, 0xeb, 0xf7, 0x95, 0xdb, 0xde, + 0x47, 0x95, 0x06, 0x07, 0xab, 0x9e, 0x10, 0xc5, 0x97, 0x4e, 0x31, 0xa7, + 0xc0, 0xba, 0x10, 0xb8, 0xb5, 0xc0, 0x10, 0x72, 0x72, 0xef, 0x94, 0x73, + 0x07, 0x68, 0x1b, 0xdc, 0x39, 0xf3, 0x48, 0x3d, 0xe8, 0x04, 0xb2, 0xef, + 0xcb, 0x0b, 0x80, 0xd4, 0xcf, 0x13, 0xbb, 0xcf, 0x4d, 0x6d, 0x86, 0x70, + 0x33, 0xb8, 0xfb, 0x81, 0x57, 0x07, 0x21, 0xcc, 0x96, 0x75, 0x1b, 0xde, + 0x6f, 0xac, 0x5c, 0x18, 0x25, 0x00, 0xa6, 0x5b, 0x88, 0x35, 0xad, 0xe2, + 0x6f, 0x88, 0x46, 0xad, 0x4c, 0xd8, 0x12, 0xa7, 0x9f, 0x41, 0x9e, 0x92, + 0xbf, 0x51, 0x87, 0xa6, 0xbc, 0x19, 0x93, 0x0a, 0x0c, 0x91, 0x38, 0xa1, + 0x70, 0x36, 0x54, 0x16, 0x96, 0x7a, 0xd1, 0x2b, 0xe7, 0x52, 0x2f, 0x42, + 0x1a, 0xd7, 0xe4, 0x5c, 0xb3, 0xd0, 0x8b, 0xa7, 0x45, 0x21, 0x81, 0x65, + 0xb6, 0x11, 0x2e, 0x07, 0xa0, 0x26, 0x99, 0x5a, 0xb9, 0x02, 0x62, 0xd2, + 0x8c, 0x56, 0x8e, 0xac, 0x87, 0x69, 0xd8, 0x8e, 0x2d, 0xb1, 0xaf, 0x37, + 0xc5, 0xbf, 0xda, 0x8a, 0x7f, 0x62, 0x37, 0x27, 0x51, 0x38, 0x60, 0xca, + 0xfc, 0x36, 0xbf, 0xce, 0x97, 0x00, 0x85, 0xe1, 0x8a, 0x34, 0x60, 0x24, + 0x8c, 0x16, 0x9b, 0x79, 0x06, 0x85, 0x67, 0xd1, 0x5d, 0xc3, 0x56, 0x07, + 0x9d, 0x1c, 0xe8, 0x45, 0xda, 0x57, 0x34, 0x42, 0x85, 0x61, 0x44, 0x6d, + 0xc9, 0x5b, 0x3c, 0x10, 0x8b, 0xb4, 0xed, 0xc4, 0x67, 0x98, 0xa4, 0x90, + 0x5d, 0xb1, 0xa3, 0x74, 0xed, 0xdd, 0xe5, 0xe7, 0xbb, 0xf4, 0xd0, 0x7e, + 0xf9, 0xe6, 0x5e, 0xf9, 0x67, 0xd1, 0x72, 0x19, 0xa4, 0xf1, 0x19, 0x97, + 0xe6, 0x67, 0x46, 0xa1, 0x15, 0x15, 0xae, 0x7a, 0x41, 0x14, 0x06, 0x76, + 0x71, 0xd8, 0x7b, 0xb9, 0x8c, 0xed, 0xed, 0x1d, 0x54, 0xcb, 0x71, 0x00, + 0xa3, 0x9d, 0x6d, 0x9d, 0x23, 0xc3, 0x62, 0x80, 0xba, 0x00, 0x4b, 0xf2, + 0x94, 0xa7, 0x29, 0x78, 0x2e, 0xb6, 0xee, 0x85, 0xfd, 0xd9, 0x5d, 0x2a, + 0xf6, 0x87, 0x4f, 0xdd, 0x01, 0x93, 0xbb, 0x3e, 0x5c, 0x64, 0x47, 0x26, + 0xa9, 0xf5, 0x81, 0x4e, 0xf5, 0xb4, 0xd0, 0x9d, 0x71, 0x49, 0x21, 0x1b, + 0xb0, 0xa5, 0xc3, 0x64, 0x0c, 0x35, 0xbd, 0xd1, 0x2d, 0xdf, 0x65, 0xa6, + 0xe9, 0x7e, 0x67, 0x76, 0x95, 0x8c, 0xc2, 0x5a, 0x85, 0x42, 0x68, 0xa3, + 0xc1, 0x92, 0x6b, 0x66, 0x6d, 0x74, 0x68, 0xeb, 0x42, 0xb7, 0x6f, 0xd4, + 0xfd, 0x74, 0x6f, 0x1e, 0xd5, 0x6e, 0x9e, 0x8c, 0x7a, 0x2e, 0xd6, 0xf4, + 0x6b, 0x6c, 0xf0, 0xc3, 0xfc, 0xd4, 0xd3, 0xa0, 0x0e, 0x30, 0xbc, 0xec, + 0x01, 0xdd, 0x3b, 0x55, 0x61, 0x22, 0x53, 0x5f, 0xaa, 0x40, 0x09, 0x5e, + 0xde, 0x87, 0x87, 0xc1, 0xc4, 0x17, 0x7a, 0x1c, 0x3d, 0xe7, 0x53, 0xca, + 0xa1, 0x70, 0xa5, 0x17, 0x83, 0x52, 0x41, 0x40, 0xfc, 0x65, 0x6a, 0xa0, + 0xf5, 0xe8, 0xcd, 0x5f, 0x03, 0xca, 0xfa, 0xd2, 0x92, 0xd0, 0xf8, 0x51, + 0xb0, 0x3b, 0x5b, 0x3a, 0x0a, 0x07, 0x64, 0x9f, 0x61, 0xdf, 0xf8, 0xd8, + 0xb7, 0x59, 0xfc, 0x8d, 0x0f, 0x08, 0x0b, 0xdb, 0x87, 0xb1, 0x60, 0xb4, + 0x87, 0x71, 0x9b, 0xf8, 0xd9, 0x5b, 0xc0, 0xc2, 0x95, 0xc3, 0x0d, 0x7f, + 0x32, 0xe6, 0x6f, 0xa6, 0xea, 0x18, 0x8b, 0x18, 0x54, 0x05, 0x76, 0x0d, + 0xa6, 0x0e, 0x33, 0x0e, 0x13, 0x7d, 0x44, 0x3a, 0x5b, 0x4a, 0x5a, 0xe7, + 0x31, 0x60, 0x3d, 0xba, 0x6d, 0x19, 0x14, 0x31, 0xb4, 0x52, 0xb4, 0x04, + 0xf8, 0x35, 0xe8, 0x97, 0xf3, 0x8c, 0x11, 0x4c, 0x6a, 0xf7, 0x3b, 0x5c, + 0x24, 0x72, 0x8c, 0xd4, 0x3e, 0xd6, 0x98, 0x3f, 0x1b, 0xf3, 0xdb, 0x4b, + 0x92, 0xfb, 0x03, 0x4a, 0xc3, 0xfe, 0xe5, 0xdc, 0x9a, 0x5a, 0x23, 0x0a, + 0x9f, 0x08, 0xee, 0xf8, 0xe6, 0x81, 0x76, 0x87, 0xaf, 0xc0, 0x7c, 0x82, + 0x9f, 0x30, 0x89, 0xbd, 0x7e, 0x31, 0x88, 0xbc, 0x48, 0x43, 0x0f, 0x6d, + 0xcf, 0x37, 0x3b, 0x12, 0x01, 0xcb, 0xa4, 0x94, 0x07, 0xa8, 0xc2, 0x3e, + 0x80, 0x99, 0x23, 0x09, 0xa6, 0xe3, 0x54, 0x33, 0x62, 0xc4, 0x76, 0x7b, + 0xbe, 0xc2, 0x68, 0x6f, 0xa8, 0x59, 0x1d, 0x3d, 0x27, 0xcc, 0x11, 0xe6, + 0x3d, 0x07, 0x45, 0x2b, 0xfc, 0x1e, 0x8d, 0x5f, 0x79, 0xef, 0x5b, 0x60, + 0xc8, 0xee, 0x3b, 0xc2, 0x93, 0x4c, 0x99, 0x26, 0x7d, 0x80, 0x6c, 0x69, + 0x22, 0x9b, 0x83, 0xdc, 0xec, 0x83, 0xeb, 0xe5, 0xf7, 0xcd, 0xd9, 0x7c, + 0xe3, 0xfe, 0xc5, 0x83, 0x54, 0x20, 0x8a, 0x09, 0xe8, 0x80, 0xaa, 0xd3, + 0x2c, 0xf4, 0x89, 0x21, 0x58, 0x54, 0x37, 0x42, 0xc8, 0x1f, 0x62, 0x35, + 0xe1, 0xa4, 0x82, 0x2b, 0x6a, 0x0d, 0xba, 0x34, 0x1a, 0x9e, 0x61, 0x59, + 0x47, 0x9a, 0xc6, 0x9a, 0xee, 0x30, 0x58, 0x93, 0x7e, 0x90, 0x19, 0x4a, + 0x09, 0x33, 0x9d, 0x51, 0x42, 0xa2, 0xbb, 0x95, 0xa7, 0x24, 0xad, 0x02, + 0xde, 0xc5, 0x52, 0xb4, 0xcc, 0x75, 0xfc, 0x14, 0x60, 0x99, 0xa3, 0x5f, + 0x55, 0x09, 0x65, 0xae, 0x4b, 0x19, 0x17, 0x65, 0xcf, 0xb2, 0x39, 0x2c, + 0x87, 0xef, 0x28, 0xd1, 0x42, 0xb3, 0x57, 0x7e, 0xd2, 0x72, 0x05, 0x17, + 0x9e, 0x25, 0xbb, 0xb3, 0x5a, 0xd5, 0xf1, 0x2f, 0xf0, 0xdb, 0xaa, 0xf4, + 0x97, 0x67, 0x94, 0xb0, 0x54, 0x09, 0x34, 0x27, 0x81, 0x73, 0x8f, 0x1a, + 0x40, 0x04, 0xfe, 0xc3, 0xeb, 0xf7, 0xbd, 0xeb, 0x1c, 0xb0, 0x47, 0xf1, + 0xfe, 0x4a, 0xa0, 0xa1, 0x00, 0x85, 0x12, 0x98, 0x30, 0xe3, 0xec, 0xd4, + 0x3a, 0xca, 0x1c, 0x3d, 0xd3, 0x12, 0x15, 0x35, 0x2d, 0xc5, 0x58, 0x75, + 0x55, 0x89, 0x3e, 0x88, 0x42, 0x25, 0x51, 0xfc, 0x24, 0x1a, 0x08, 0xe0, + 0x2c, 0x10, 0xdf, 0xcd, 0xfc, 0x9e, 0x14, 0x44, 0x55, 0x1a, 0x4c, 0x40, + 0x0b, 0x34, 0x18, 0x04, 0x7b, 0x9c, 0x20, 0xc2, 0x01, 0x1a, 0x7f, 0xa8, + 0x40, 0xc5, 0x59, 0x04, 0x57, 0x34, 0xe2, 0x68, 0xff, 0xac, 0x65, 0x38, + 0xa8, 0xca, 0xe0, 0xac, 0x67, 0xb0, 0x16, 0xd1, 0xd5, 0x0d, 0x60, 0x22, + 0x10, 0x16, 0x63, 0x14, 0xc2, 0x18, 0x0e, 0xa0, 0x15, 0x00, 0x0b, 0xf5, + 0x8e, 0xbd, 0xca, 0xc6, 0x03, 0x62, 0x85, 0x63, 0xf0, 0x3d, 0x63, 0x41, + 0xc0, 0x56, 0x83, 0xc3, 0x4c, 0x03, 0x5f, 0xf5, 0x81, 0xc0, 0x09, 0xb6, + 0x2d, 0x33, 0x12, 0x53, 0x11, 0x5c, 0x0d, 0x0d, 0xb4, 0x95, 0x8d, 0x50, + 0xee, 0x40, 0x5c, 0xb0, 0xee, 0xe5, 0x86, 0x23, 0x46, 0x90, 0xa0, 0xb6, + 0x1b, 0xe0, 0x03, 0x74, 0x2c, 0xf9, 0xa2, 0x12, 0xe9, 0x43, 0x42, 0x0d, + 0xcb, 0x85, 0x68, 0x74, 0x90, 0xe6, 0x27, 0x7b, 0xb0, 0x52, 0x68, 0x09, + 0x23, 0x80, 0x76, 0x34, 0x60, 0xe2, 0x48, 0xdc, 0x96, 0xc8, 0xaa, 0xd7, + 0xb8, 0x8c, 0x50, 0x34, 0xb2, 0xc6, 0x69, 0x40, 0xa0, 0x9a, 0x2f, 0xa0, + 0x37, 0xa2, 0x08, 0xb6, 0xb7, 0x56, 0xb4, 0x45, 0xb5, 0x3e, 0x40, 0x8b, + 0x6e, 0xa8, 0x9d, 0xa9, 0x93, 0x3f, 0x7a, 0xd8, 0x10, 0xc1, 0xf0, 0xd0, + 0xf0, 0xf1, 0xb1, 0x31, 0x3b, 0xa3, 0x85, 0x7e, 0x7a, 0x43, 0x2b, 0xe5, + 0x96, 0xf1, 0x39, 0x58, 0xae, 0x4a, 0xad, 0xd4, 0xb7, 0x1d, 0xc6, 0x56, + 0xc2, 0x6d, 0x52, 0x4b, 0xb6, 0x29, 0x30, 0x68, 0xad, 0x3d, 0xca, 0xa5, + 0x7f, 0xbd, 0x9a, 0x0b, 0xff, 0x25, 0xf7, 0x61, 0x67, 0xb0, 0x97, 0xc6, + 0xea, 0x63, 0xe8, 0x49, 0x61, 0xc9, 0x88, 0x5a, 0x46, 0xd7, 0x60, 0x84, + 0x24, 0xaf, 0x5e, 0xfa, 0x20, 0x1c, 0xdb, 0xb3, 0x99, 0xdb, 0xa5, 0xfb, + 0xb0, 0xe7, 0x9c, 0xe6, 0x7d, 0x83, 0xfd, 0xce, 0x9c, 0xee, 0x4d, 0xd8, + 0x77, 0x0e, 0xfc, 0x0f, 0x3f, 0x14, 0x92, 0x16, 0x04, 0x86, 0xcd, 0x3c, + 0xa7, 0x23, 0x2b, 0xc5, 0xc2, 0x4a, 0x6d, 0xe1, 0x65, 0x38, 0x8a, 0xb7, + 0xf4, 0x10, 0xf3, 0x5c, 0xed, 0x69, 0x4d, 0x32, 0x91, 0x81, 0xff, 0xea, + 0xea, 0x8b, 0xc6, 0x50, 0xfd, 0xe6, 0xc6, 0x4a, 0xf5, 0x55, 0xb0, 0xf0, + 0xaa, 0xbb, 0xf4, 0xad, 0x2f, 0xc8, 0x3f, 0x7a, 0x14, 0xbe, 0x50, 0xdd, + 0xb9, 0x32, 0xf0, 0x82, 0x68, 0x74, 0xc7, 0x10, 0xcf, 0xb5, 0xa2, 0x41, + 0x4c, 0x96, 0xfa, 0x2b, 0x33, 0xe4, 0x9b, 0xf9, 0x99, 0x11, 0x5b, 0x6a, + 0x9c, 0x20, 0xad, 0xd5, 0xc0, 0x04, 0x55, 0xa9, 0x3a, 0x48, 0x52, 0x82, + 0xb9, 0xaf, 0x8a, 0x4a, 0x4d, 0xcc, 0xa7, 0xb3, 0x7d, 0x54, 0x9c, 0xa6, + 0x46, 0x87, 0x2e, 0xbd, 0xdf, 0xe0, 0x7c, 0xe9, 0x40, 0xac, 0x88, 0x3c, + 0x0b, 0x50, 0xf4, 0x0f, 0xd9, 0x02, 0x63, 0x80, 0xb1, 0x32, 0x18, 0x6b, + 0xeb, 0xe4, 0xfe, 0x4a, 0xf2, 0x67, 0x07, 0xcf, 0x50, 0xba, 0x58, 0x11, + 0x60, 0xfd, 0x74, 0x8e, 0x7f, 0xeb, 0xf3, 0x8b, 0xc5, 0x2e, 0xbe, 0x4d, + 0xc9, 0x57, 0x7f, 0x8a, 0x9a, 0x05, 0x10, 0x6c, 0x86, 0x39, 0xac, 0xf2, + 0x0f, 0x39, 0x21, 0x7f, 0x52, 0x2f, 0xc2, 0x71, 0xef, 0xdf, 0x3f, 0x61, + 0x16, 0x2e, 0x3a, 0x38, 0x42, 0x8f, 0x72, 0x42, 0x9f, 0xc3, 0x6a, 0xcc, + 0x0c, 0xbc, 0x97, 0x54, 0xfb, 0x66, 0x4d, 0x2d, 0x30, 0xb0, 0x66, 0xc9, + 0x68, 0xd4, 0x99, 0x0c, 0xb4, 0x61, 0xec, 0xee, 0xc1, 0xed, 0x6b, 0x28, + 0x2a, 0xdf, 0xc3, 0x29, 0x6b, 0xe1, 0xb6, 0x55, 0x62, 0x61, 0xd8, 0xa0, + 0xa4, 0x7b, 0x68, 0xa8, 0xe3, 0x5c, 0x6b, 0x7c, 0x1d, 0x4e, 0x7e, 0x37, + 0x9e, 0x30, 0xea, 0xee, 0xaf, 0xc0, 0x81, 0x27, 0xf0, 0x53, 0x5c, 0xe4, + 0x53, 0xf0, 0x4b, 0x4a, 0x23, 0xa1, 0x63, 0x20, 0xc0, 0xc3, 0x5e, 0x83, + 0x3f, 0xa9, 0xfc, 0xf0, 0x72, 0x3a, 0x98, 0x14, 0x28, 0x4a, 0x53, 0x39, + 0xdd, 0x5d, 0xd5, 0x9b, 0x41, 0xd5, 0x69, 0x9c, 0x08, 0xf0, 0xd7, 0x8b, + 0x96, 0xc3, 0x8e, 0x88, 0x66, 0x18, 0xc9, 0xd8, 0x51, 0x65, 0x41, 0x24, + 0xa6, 0x9e, 0x34, 0xcf, 0x5d, 0x18, 0x7b, 0x04, 0x31, 0xae, 0xa6, 0x77, + 0x3c, 0x65, 0xcd, 0x1a, 0x82, 0xfe, 0x9f, 0xa1, 0x4e, 0x7e, 0x78, 0xf5, + 0xe5, 0xa7, 0x53, 0x74, 0xa7, 0x30, 0x8f, 0x58, 0x5c, 0x41, 0x78, 0x20, + 0x06, 0xf7, 0xa2, 0x58, 0xaf, 0x60, 0xc5, 0x9e, 0x50, 0x51, 0x23, 0x8f, + 0x4c, 0xd4, 0x2a, 0x3c, 0x52, 0x9c, 0xa4, 0xf9, 0x2b, 0x8d, 0x3d, 0xb2, + 0x09, 0xcf, 0x7b, 0x1c, 0xef, 0x71, 0xbc, 0x07, 0x8f, 0x9c, 0xb5, 0x8d, + 0x94, 0xd9, 0x91, 0xbe, 0x82, 0xea, 0x8d, 0xd5, 0xb3, 0x3c, 0x27, 0x93, + 0x05, 0xe8, 0x30, 0x04, 0xc0, 0x44, 0x7f, 0x86, 0x7b, 0xdc, 0xa9, 0x6c, + 0x3b, 0xbb, 0x91, 0x9b, 0xde, 0xde, 0xc8, 0x7d, 0x6a, 0xee, 0xe5, 0x71, + 0xa8, 0x1f, 0x65, 0xc8, 0x55, 0x82, 0xda, 0x34, 0x30, 0xe6, 0xae, 0x05, + 0xdb, 0xad, 0xbb, 0xe0, 0xe4, 0x32, 0xfa, 0xb5, 0x5c, 0x27, 0x77, 0x22, + 0x77, 0x83, 0xbd, 0x90, 0xb4, 0x6a, 0xae, 0xe0, 0x11, 0x35, 0x77, 0x92, + 0xdd, 0x05, 0x14, 0x95, 0xbd, 0x02, 0xf2, 0x3b, 0x89, 0xf0, 0x91, 0xce, + 0xe1, 0x3d, 0x4a, 0x3f, 0x04, 0xa8, 0xbf, 0xe0, 0x4f, 0x00, 0x0a, 0x4f, + 0x8f, 0xe1, 0x3d, 0x6d, 0xce, 0xa1, 0x25, 0x6f, 0x80, 0x0b, 0xea, 0x7b, + 0xa8, 0xe6, 0x23, 0x62, 0xc5, 0x4e, 0x12, 0x6e, 0x0c, 0x50, 0xa3, 0xd1, + 0x41, 0x83, 0x82, 0xa5, 0x6b, 0x06, 0xa7, 0x8e, 0x18, 0x5e, 0xe8, 0x08, + 0x85, 0x3a, 0x68, 0x4a, 0x30, 0x0b, 0x5c, 0x4c, 0x78, 0x9c, 0xbd, 0xc3, + 0x0d, 0xd1, 0x32, 0x7a, 0xd5, 0xc0, 0x07, 0x05, 0xea, 0x24, 0xff, 0x97, + 0x08, 0x71, 0xcb, 0x18, 0x31, 0xf3, 0x67, 0x80, 0xe8, 0x3d, 0xa0, 0xaf, + 0x46, 0x47, 0xbb, 0x4a, 0x87, 0x82, 0x59, 0x74, 0xe5, 0x52, 0xa7, 0x4a, + 0x18, 0xba, 0x98, 0x7a, 0x97, 0x1a, 0xa6, 0xb3, 0x0a, 0x64, 0x68, 0x10, + 0x60, 0x17, 0xd8, 0x12, 0x6d, 0x07, 0x9a, 0x21, 0x0a, 0xa3, 0x1b, 0x8e, + 0xf7, 0x53, 0xd5, 0x83, 0x4a, 0xd2, 0x13, 0x1a, 0x79, 0x02, 0xd5, 0xdb, + 0x0e, 0x43, 0xd3, 0x60, 0xb4, 0xbc, 0x9c, 0x9e, 0x0b, 0xbb, 0x79, 0x8d, + 0x9e, 0x3b, 0x8c, 0x08, 0x06, 0x09, 0x23, 0x91, 0xdd, 0x0d, 0x3b, 0x2e, + 0xc7, 0x18, 0x47, 0x77, 0x8b, 0xfe, 0x05, 0x39, 0x7e, 0xd2, 0xc4, 0x5b, + 0xbf, 0x68, 0x2e, 0x68, 0x0c, 0x05, 0xdd, 0xa2, 0xb8, 0x33, 0x88, 0xd2, + 0xbb, 0x25, 0x31, 0xc4, 0x5e, 0xc4, 0x59, 0xad, 0x53, 0x7b, 0xd1, 0x4f, + 0xf4, 0x6b, 0x57, 0x14, 0x2b, 0xd2, 0x8a, 0xd4, 0x3a, 0xe1, 0xbd, 0x59, + 0xcd, 0xf9, 0x8d, 0x37, 0x8c, 0x9f, 0x7d, 0x7a, 0x35, 0xde, 0xf1, 0x51, + 0x5b, 0xf5, 0x83, 0x2f, 0xbd, 0x84, 0x90, 0x63, 0xd8, 0xe5, 0xac, 0x40, + 0x48, 0x51, 0x64, 0x78, 0x55, 0xb2, 0x95, 0xef, 0x43, 0x48, 0x45, 0x61, + 0x6f, 0x40, 0xc8, 0xfc, 0x55, 0x06, 0xa7, 0x3c, 0xb0, 0xf3, 0x1c, 0x9a, + 0x4c, 0x7f, 0x60, 0x7c, 0xc3, 0xa1, 0xcb, 0xd0, 0x4a, 0x9e, 0x43, 0x7f, + 0x3f, 0xe1, 0x60, 0xfe, 0x49, 0xe6, 0x54, 0x8a, 0x0f, 0xbd, 0x77, 0xa8, + 0xca, 0xba, 0x0e, 0x2e, 0x85, 0xf9, 0x77, 0xb8, 0xd2, 0xa6, 0x48, 0x63, + 0x5f, 0x86, 0x3f, 0xc9, 0xec, 0x48, 0x95, 0x19, 0xfa, 0xfa, 0xe9, 0x7e, + 0x31, 0xcf, 0xfb, 0x13, 0xdc, 0x2d, 0x5e, 0xa4, 0x7c, 0xe5, 0x37, 0x7b, + 0x6f, 0xd8, 0x3f, 0xfc, 0x58, 0xc8, 0xb3, 0x17, 0xbd, 0xad, 0x8b, 0x33, + 0xe8, 0x38, 0xeb, 0xdb, 0x01, 0xa6, 0x6e, 0x1d, 0xed, 0x7d, 0x1e, 0xe3, + 0x8a, 0xf4, 0xf1, 0xc3, 0x59, 0x67, 0x1f, 0xc6, 0xa0, 0xf8, 0x22, 0x22, + 0x4f, 0x57, 0x37, 0x9c, 0x26, 0x7b, 0x5f, 0x32, 0x44, 0x8d, 0x06, 0x76, + 0x34, 0x3d, 0x23, 0xf3, 0xc1, 0x89, 0x66, 0x66, 0xa6, 0x43, 0xd6, 0x68, + 0x83, 0x1e, 0x3a, 0xc6, 0xa3, 0x18, 0x06, 0x72, 0x4f, 0x5c, 0x07, 0x34, + 0xc5, 0x30, 0x5f, 0x4c, 0x6d, 0xf1, 0x0e, 0xa7, 0x59, 0x9f, 0xa2, 0xa4, + 0x05, 0xc6, 0xee, 0x32, 0x95, 0x7b, 0x11, 0xf9, 0x37, 0x82, 0x9a, 0xd3, + 0xa7, 0x65, 0x62, 0x4b, 0xc3, 0x62, 0x03, 0xc5, 0xc0, 0x71, 0x79, 0x06, + 0x41, 0xd3, 0x1f, 0xf2, 0xe7, 0x3f, 0x82, 0x57, 0xfa, 0x7d, 0xde, 0xec, + 0x2c, 0x04, 0x98, 0xe3, 0x9b, 0xac, 0xf9, 0x93, 0x0b, 0x66, 0x7e, 0x8a, + 0xba, 0x29, 0xc6, 0xb1, 0x63, 0xa4, 0xa9, 0x1a, 0x4c, 0x89, 0xcd, 0xd0, + 0x59, 0x21, 0xd8, 0x63, 0xd6, 0x47, 0x43, 0x37, 0xa7, 0x3d, 0xf3, 0x43, + 0xd5, 0x18, 0xd9, 0x21, 0xf0, 0x73, 0xd7, 0x63, 0x5c, 0xe9, 0x04, 0x73, + 0xcc, 0xa5, 0x45, 0xae, 0xaf, 0x07, 0x82, 0x40, 0x70, 0x66, 0xff, 0x4a, + 0xd8, 0x08, 0xa8, 0x34, 0xda, 0xe8, 0xfa, 0x29, 0xae, 0x14, 0x5a, 0xd1, + 0xa0, 0x13, 0x6e, 0x00, 0x3c, 0x8c, 0xb8, 0xa1, 0xc4, 0xa4, 0xb8, 0xd2, + 0xa5, 0x07, 0x9f, 0x9f, 0x83, 0xf1, 0xb4, 0x79, 0x30, 0x12, 0xd7, 0x29, + 0xb9, 0x5d, 0x44, 0xeb, 0x6e, 0x8a, 0x2b, 0x61, 0xb6, 0x36, 0x98, 0xae, + 0x53, 0xcc, 0x17, 0x57, 0xeb, 0x80, 0xf6, 0xe7, 0x31, 0xae, 0x34, 0x86, + 0xcb, 0x9c, 0xe6, 0x23, 0x17, 0x11, 0xb5, 0xa4, 0x52, 0xc0, 0xfc, 0x6a, + 0x33, 0x07, 0xdc, 0xca, 0xba, 0x1d, 0x9f, 0x54, 0x78, 0x0c, 0xbd, 0x60, + 0xc3, 0x95, 0x36, 0x5a, 0xe6, 0x65, 0x19, 0xda, 0xb1, 0x4c, 0xbb, 0xd2, + 0xbd, 0x56, 0x0e, 0x2c, 0x6b, 0xc6, 0x48, 0x07, 0x94, 0x5d, 0x29, 0xfd, + 0xdb, 0x25, 0xfa, 0xcd, 0x30, 0xa9, 0x1b, 0xcb, 0xb0, 0x2a, 0x65, 0x93, + 0x30, 0x92, 0x8b, 0x72, 0x55, 0xca, 0xc0, 0x45, 0x4a, 0x28, 0xa3, 0xed, + 0xb3, 0x7f, 0xb5, 0xe4, 0xaa, 0x4e, 0x2d, 0xd7, 0x63, 0xd9, 0xdc, 0x0d, + 0x6e, 0xdd, 0xef, 0x97, 0x69, 0xaf, 0xdc, 0xf4, 0xcd, 0xa3, 0x96, 0x4f, + 0xc9, 0x6e, 0xfa, 0x1a, 0xe5, 0xb6, 0x94, 0x5d, 0xfd, 0x14, 0xf7, 0x4a, + 0x99, 0x4a, 0x6a, 0x87, 0xb1, 0xac, 0xc6, 0xb2, 0x9f, 0xca, 0xf6, 0xa0, + 0xac, 0xf7, 0x4b, 0xc3, 0x07, 0x97, 0xa5, 0x39, 0x28, 0xab, 0x5d, 0x49, + 0x49, 0xd4, 0xec, 0x0f, 0x17, 0x5e, 0xb9, 0x1b, 0x1d, 0x63, 0x7f, 0x9d, + 0x74, 0xe8, 0x2e, 0x30, 0x82, 0x18, 0xa9, 0xa3, 0xac, 0x83, 0xc4, 0x83, + 0x05, 0xef, 0x08, 0x3b, 0x0f, 0xf6, 0x03, 0x47, 0x3d, 0x66, 0xf2, 0x6e, + 0x8d, 0x83, 0x07, 0xf5, 0x0a, 0xa3, 0x94, 0xd3, 0x9d, 0x68, 0xb4, 0x76, + 0x5c, 0x1c, 0x69, 0x8b, 0xe2, 0x6c, 0x64, 0x2f, 0x0d, 0x37, 0x26, 0xf2, + 0xb2, 0xf2, 0x84, 0x1e, 0x96, 0xda, 0xb4, 0x2e, 0x99, 0xf9, 0x72, 0xe8, + 0x98, 0xa8, 0x04, 0x1f, 0xf2, 0x7d, 0x72, 0xda, 0xdb, 0x98, 0x47, 0x22, + 0x2a, 0x69, 0xe2, 0x48, 0x19, 0x0e, 0x70, 0x7c, 0xd2, 0x48, 0x35, 0xa4, + 0xe4, 0xb2, 0xb0, 0xcb, 0x0d, 0xd1, 0x7a, 0xab, 0x0a, 0x53, 0x4c, 0x13, + 0xd9, 0x32, 0x8e, 0x74, 0x7b, 0xc0, 0xe3, 0x74, 0xaf, 0x80, 0x01, 0xd8, + 0x1a, 0x7c, 0xaa, 0x9e, 0x8e, 0x1d, 0x24, 0x64, 0x92, 0xb0, 0x16, 0x02, + 0xbc, 0x88, 0xdb, 0x0e, 0x74, 0xba, 0x16, 0x22, 0x74, 0x8d, 0xe7, 0x2f, + 0x81, 0x25, 0xd7, 0x91, 0x44, 0x31, 0x91, 0x4a, 0x4e, 0xd6, 0x98, 0xf1, + 0x81, 0x8c, 0x30, 0x85, 0xef, 0xb3, 0x29, 0x0b, 0x98, 0x92, 0x76, 0xb8, + 0xd2, 0xb8, 0x75, 0xab, 0x86, 0x9b, 0x43, 0x41, 0xb8, 0xe2, 0x62, 0x59, + 0xda, 0x16, 0x3a, 0x85, 0x2e, 0x9c, 0x1e, 0x46, 0xc1, 0x7f, 0xf8, 0xe5, + 0xc0, 0x38, 0xd2, 0xb3, 0x86, 0x92, 0x1e, 0x34, 0x9a, 0xb4, 0x15, 0xf5, + 0xb1, 0x66, 0x25, 0x3d, 0x69, 0xe8, 0x26, 0xef, 0xb4, 0xb6, 0xb2, 0x4b, + 0xb9, 0xc9, 0xa5, 0x59, 0x8d, 0xcf, 0x4f, 0xf9, 0x0f, 0x3f, 0x55, 0x7d, + 0xc5, 0x53, 0x13, 0x75, 0x67, 0x5c, 0x27, 0x32, 0x13, 0xfd, 0x22, 0xa0, + 0x81, 0x16, 0xa0, 0x7b, 0x7b, 0xce, 0x0f, 0x7c, 0x9a, 0x5c, 0xfd, 0xa2, + 0x1f, 0xf6, 0x3e, 0x83, 0xe8, 0xba, 0xd8, 0x79, 0xe9, 0x94, 0x6f, 0xf7, + 0x16, 0x6d, 0xb9, 0xc5, 0x6a, 0x2b, 0xdb, 0xef, 0x56, 0x61, 0x35, 0x71, + 0x2f, 0xbb, 0xb4, 0x5c, 0x17, 0x56, 0x0d, 0xbb, 0x05, 0x5d, 0xa6, 0x2c, + 0x5f, 0x98, 0xbf, 0xcb, 0x35, 0x60, 0xcb, 0x37, 0xb9, 0xee, 0xf5, 0xd7, + 0xd8, 0x83, 0xd7, 0xa4, 0x2f, 0xbc, 0xe6, 0x70, 0x6c, 0x7f, 0xed, 0xbf, + 0x83, 0xb7, 0x87, 0xa8, 0x62, 0xe2, 0xf3, 0xb8, 0x00, 0xa6, 0x35, 0xa3, + 0x6c, 0xf9, 0xb3, 0xb6, 0x7a, 0xa6, 0x09, 0x55, 0xc9, 0x83, 0xd6, 0x35, + 0x7e, 0xdd, 0xd3, 0x86, 0x39, 0xc8, 0xa5, 0x40, 0x96, 0x63, 0x30, 0xe1, + 0x98, 0x0a, 0xac, 0xa7, 0xb4, 0x8a, 0xa6, 0x5d, 0x20, 0xd7, 0x42, 0x59, + 0x86, 0x95, 0x3c, 0x57, 0x1d, 0xd2, 0x24, 0x48, 0xfa, 0x25, 0x6c, 0x28, + 0x04, 0x9f, 0x5a, 0x6c, 0x43, 0x6b, 0xd4, 0xda, 0x87, 0xe2, 0x2d, 0xe6, + 0xd7, 0xd0, 0x15, 0xf8, 0x70, 0x9d, 0xc2, 0xc9, 0x00, 0x3d, 0xe3, 0xba, + 0x0c, 0x53, 0xd1, 0xf4, 0xbe, 0x8e, 0x0e, 0x28, 0xfb, 0x30, 0x74, 0xea, + 0xc7, 0x44, 0xfa, 0x09, 0x5a, 0x67, 0xe8, 0xf4, 0xf1, 0x95, 0x0c, 0xf6, + 0x22, 0xb9, 0x3d, 0xe7, 0xbd, 0xcb, 0x1a, 0x73, 0x85, 0xaf, 0xfd, 0xb4, + 0x68, 0xfd, 0x34, 0xca, 0x45, 0x69, 0x66, 0x7e, 0xea, 0xeb, 0x57, 0xc7, + 0xe9, 0xbb, 0xec, 0x33, 0x00, 0xf1, 0xd9, 0x93, 0xa6, 0xdf, 0x03, 0xd3, + 0xef, 0xb7, 0x09, 0x72, 0x65, 0xb9, 0x6e, 0xec, 0x64, 0x30, 0xad, 0x79, + 0xb9, 0x90, 0xea, 0xe5, 0xba, 0x14, 0xdb, 0x85, 0xcb, 0x0c, 0x98, 0x72, + 0x27, 0x61, 0x6f, 0x5d, 0x8a, 0x7b, 0x42, 0xc7, 0x03, 0x89, 0xae, 0xd5, + 0x23, 0x8f, 0x2f, 0x28, 0x7a, 0x67, 0x5d, 0xca, 0x57, 0x5e, 0x3a, 0xe8, + 0xa2, 0x26, 0x4a, 0xbc, 0x8e, 0xbf, 0x19, 0x03, 0xca, 0xd0, 0x18, 0xd4, + 0x1e, 0x0f, 0xa4, 0xf0, 0x4c, 0x4e, 0xef, 0xe5, 0x3a, 0xfb, 0xc4, 0x98, + 0x18, 0xd3, 0xf2, 0xcc, 0x30, 0xb0, 0xb9, 0x2e, 0x30, 0x84, 0x40, 0x5f, + 0xf8, 0x92, 0xeb, 0x91, 0x36, 0x40, 0x72, 0xd0, 0xe8, 0x8b, 0x0d, 0x01, + 0xba, 0x32, 0xa8, 0x29, 0x8e, 0x61, 0x50, 0xa7, 0x6b, 0xef, 0x44, 0xc3, + 0xdb, 0x52, 0x96, 0x9b, 0xbd, 0x7f, 0xf2, 0x4a, 0x03, 0xf3, 0x89, 0x46, + 0x2c, 0xe7, 0x5d, 0x08, 0x30, 0x4f, 0xee, 0xb1, 0x40, 0xc9, 0x12, 0x23, + 0xef, 0x75, 0x20, 0x13, 0xd9, 0xa3, 0x62, 0xde, 0xf4, 0x9d, 0x17, 0xba, + 0x0b, 0x2e, 0x28, 0xc1, 0xd4, 0x62, 0x92, 0xef, 0xcb, 0x1c, 0x61, 0xc6, + 0xb7, 0x49, 0x63, 0xee, 0x2f, 0x02, 0xa6, 0x46, 0x57, 0xa2, 0xc4, 0xba, + 0x04, 0xf4, 0x7f, 0xce, 0xc9, 0xde, 0x4b, 0xe9, 0x98, 0x75, 0x54, 0xef, + 0x0f, 0xd4, 0xec, 0x59, 0xbc, 0x9c, 0x5d, 0xca, 0xe6, 0x4e, 0xae, 0x61, + 0x69, 0xc5, 0xb0, 0x7f, 0x41, 0x27, 0x28, 0x8c, 0xdb, 0x37, 0x38, 0x41, + 0x17, 0x9c, 0xa0, 0x13, 0x4e, 0xd0, 0xbc, 0x63, 0x43, 0x5b, 0x7c, 0x7b, + 0x48, 0x77, 0x27, 0xaf, 0x7c, 0xbe, 0x7f, 0x82, 0xec, 0x6e, 0x82, 0xce, + 0x77, 0x13, 0x24, 0x65, 0x82, 0x02, 0x98, 0xb2, 0x22, 0x23, 0x36, 0xf4, + 0x40, 0x9b, 0xb2, 0x8c, 0x93, 0x61, 0xe6, 0x52, 0x1c, 0x2c, 0x36, 0x89, + 0xf3, 0x85, 0x5f, 0x5e, 0x70, 0xbd, 0x74, 0xc0, 0xb8, 0xe7, 0x70, 0x22, + 0xb7, 0x77, 0xf2, 0x4c, 0xa9, 0xde, 0x70, 0x75, 0xf5, 0x09, 0xf5, 0xc2, + 0xc1, 0xea, 0x9b, 0x71, 0x39, 0x4f, 0x59, 0x3a, 0x16, 0x0f, 0x1d, 0xe8, + 0xdd, 0xaa, 0xb2, 0x8f, 0x5f, 0x7a, 0xa9, 0x0c, 0xcf, 0xa2, 0xbb, 0xcf, + 0x4d, 0x0e, 0xf7, 0x53, 0x40, 0xc1, 0xc9, 0xf6, 0x4a, 0x9e, 0x48, 0xe1, + 0x91, 0xec, 0xd2, 0x48, 0x93, 0x7a, 0xfa, 0x5f, 0x63, 0x87, 0xff, 0xaa, + 0xc4, 0x75, 0xd4, 0x45, 0xbc, 0xdd, 0x2b, 0xab, 0x70, 0xcf, 0x0f, 0x17, + 0x7d, 0x56, 0x1f, 0x8c, 0x17, 0x1d, 0xc1, 0x8f, 0x0a, 0x11, 0xce, 0xf6, + 0xfa, 0x51, 0xf5, 0xc5, 0xe6, 0x49, 0xd7, 0xa8, 0xde, 0xca, 0x69, 0xc6, + 0xd4, 0xde, 0x0e, 0x25, 0xaa, 0x38, 0xfc, 0x31, 0xbc, 0xcf, 0x2f, 0x1e, + 0x76, 0x4b, 0x92, 0xa6, 0x85, 0x4d, 0xbb, 0xdd, 0x66, 0xdf, 0x53, 0xa4, + 0xe5, 0x6e, 0x81, 0xf3, 0xa9, 0x71, 0x5d, 0xe3, 0xf3, 0x93, 0xb7, 0x31, + 0xe8, 0x01, 0xf0, 0xef, 0x96, 0xdb, 0x27, 0xae, 0x01, 0xfc, 0x39, 0x6b, + 0xba, 0xae, 0x26, 0x15, 0x64, 0xfb, 0xa5, 0x53, 0x8d, 0x3b, 0x95, 0xd4, + 0xc7, 0x9c, 0x4b, 0x79, 0x99, 0xcc, 0x99, 0xb2, 0x28, 0x8b, 0x64, 0x4e, + 0x37, 0x27, 0x73, 0xa6, 0x0c, 0xcc, 0x98, 0x90, 0x09, 0x9a, 0x3b, 0x01, + 0xbb, 0x82, 0x57, 0xc7, 0xec, 0x4d, 0xd2, 0x5d, 0x0a, 0x4c, 0x17, 0xd0, + 0xa3, 0xe5, 0x55, 0xa6, 0x7a, 0xf4, 0x66, 0x88, 0x3d, 0x3d, 0x06, 0x58, + 0xac, 0x93, 0x34, 0x66, 0x6f, 0xba, 0x5d, 0xf6, 0x26, 0xcd, 0xef, 0x9d, + 0xb2, 0x37, 0xf0, 0xd5, 0x0f, 0xb3, 0x37, 0xcd, 0x2e, 0x7b, 0xa3, 0x19, + 0xa2, 0x57, 0xf5, 0xd9, 0xb7, 0x7e, 0xa2, 0x06, 0x27, 0x40, 0x19, 0x74, + 0x12, 0x34, 0x5a, 0x82, 0x59, 0xbf, 0xc1, 0x20, 0x53, 0x06, 0xb6, 0xba, + 0x8d, 0x2f, 0x10, 0x89, 0xab, 0x2d, 0x0d, 0xb0, 0x8f, 0xd2, 0x07, 0xe0, + 0x10, 0x0c, 0x4c, 0xc7, 0x3d, 0x51, 0xaa, 0x17, 0x9b, 0x22, 0x15, 0x25, + 0xa4, 0x55, 0xa2, 0x23, 0xfa, 0x73, 0x61, 0xc9, 0xfe, 0x9f, 0xea, 0x67, + 0x8e, 0xe6, 0x1b, 0x8a, 0x64, 0xbd, 0x54, 0x24, 0xff, 0x70, 0x2d, 0xf1, + 0x81, 0x03, 0x3d, 0x8c, 0x37, 0x6d, 0x30, 0x2c, 0xe0, 0xed, 0x5e, 0xba, + 0xf5, 0x5d, 0x1b, 0xfc, 0x23, 0x4e, 0x76, 0x90, 0x85, 0x28, 0x7a, 0xb4, + 0xc1, 0x8b, 0xb4, 0xee, 0x3e, 0x48, 0xaa, 0xa2, 0xbb, 0x03, 0x76, 0x0e, + 0x43, 0xd8, 0xca, 0xfa, 0x09, 0x26, 0x6d, 0x04, 0x84, 0x27, 0xe4, 0xe2, + 0xed, 0x88, 0x15, 0xfb, 0x8f, 0x83, 0xe8, 0x1f, 0x78, 0x29, 0xee, 0x20, + 0xab, 0x55, 0xe4, 0xac, 0xfe, 0xee, 0x73, 0x31, 0x5f, 0x37, 0xcf, 0x30, + 0x64, 0xa7, 0x19, 0xc4, 0x43, 0x43, 0xbc, 0x0d, 0xc5, 0xe7, 0x85, 0xd6, + 0x15, 0x03, 0xfe, 0xeb, 0x3b, 0xb9, 0x1f, 0x82, 0x42, 0xa9, 0x09, 0x57, + 0xad, 0xcb, 0xfa, 0x28, 0x2f, 0xaf, 0x4e, 0xd4, 0xcf, 0x80, 0x79, 0xaf, + 0x4e, 0x14, 0x28, 0x78, 0x18, 0xdc, 0x73, 0x81, 0xa0, 0x1b, 0xae, 0xfe, + 0x7d, 0x22, 0xa1, 0x00, 0xa7, 0xe7, 0x8c, 0xc7, 0x7f, 0x04, 0x41, 0x03, + 0x49, 0x71, 0x9a, 0x37, 0x8c, 0x01, 0x04, 0x2a, 0xa3, 0x2c, 0xc9, 0xa9, + 0xfa, 0xf9, 0x86, 0x2d, 0x34, 0xdf, 0xf1, 0x93, 0x19, 0x65, 0xa2, 0xb8, + 0x38, 0x45, 0x26, 0x4e, 0xd4, 0x71, 0x60, 0x72, 0xc1, 0xa9, 0x4c, 0xbc, + 0xb7, 0xad, 0x98, 0xeb, 0x55, 0xa7, 0x1d, 0xc3, 0xf3, 0xb6, 0x62, 0x2b, + 0x9a, 0x3e, 0xf0, 0x83, 0x86, 0x4e, 0x4b, 0x3e, 0xe1, 0xb5, 0x6d, 0xc5, + 0xd5, 0x72, 0x5b, 0xb1, 0x79, 0x6d, 0x5b, 0xf1, 0xbd, 0xe6, 0x8a, 0xc6, + 0x6d, 0xc5, 0x5d, 0xd9, 0x56, 0xac, 0x29, 0xa6, 0x69, 0x3f, 0x18, 0x63, + 0xbd, 0x2f, 0x0b, 0xf2, 0x5f, 0x5e, 0x16, 0xfd, 0xeb, 0xf7, 0xfd, 0xe0, + 0xa2, 0xc3, 0xc0, 0x72, 0x55, 0x34, 0x31, 0x32, 0x0b, 0x5d, 0x1a, 0x6d, + 0x88, 0x87, 0xbf, 0xcb, 0x3b, 0xfc, 0x49, 0x97, 0xf6, 0xc4, 0x5a, 0x17, + 0xed, 0x17, 0x27, 0xf3, 0xf6, 0x01, 0xb8, 0x39, 0xd0, 0xd9, 0xba, 0x49, + 0x10, 0xdd, 0x26, 0xbb, 0xfe, 0xaf, 0xc6, 0xec, 0x65, 0xf7, 0xf6, 0x37, + 0x80, 0x84, 0x71, 0xcf, 0x90, 0xc1, 0x9d, 0x70, 0xd5, 0x18, 0x8b, 0x00, + 0xb4, 0x75, 0x57, 0x99, 0xc1, 0xd7, 0x70, 0x92, 0x6c, 0x1f, 0xb8, 0x39, + 0xc7, 0x1f, 0xe5, 0x26, 0xfa, 0xf3, 0xcc, 0xf8, 0xbd, 0x30, 0x76, 0x91, + 0xab, 0xc1, 0x75, 0xfe, 0x02, 0x20, 0x21, 0x30, 0x78, 0xcf, 0x7d, 0x02, + 0x03, 0x18, 0x42, 0x63, 0xcf, 0x26, 0xfb, 0xd6, 0x5d, 0xc6, 0x7a, 0x60, + 0x64, 0xb6, 0xb3, 0xf7, 0x30, 0x50, 0x2b, 0xe3, 0x36, 0x5d, 0xfd, 0x84, + 0x71, 0x0e, 0xc6, 0xde, 0xf6, 0x8c, 0x9a, 0x78, 0x69, 0x1b, 0x99, 0xf6, + 0xaf, 0x33, 0xb0, 0xe2, 0xb3, 0x46, 0xec, 0x19, 0xba, 0x2d, 0xb9, 0x2b, + 0x9f, 0x34, 0x5e, 0xab, 0xe1, 0x7a, 0x1a, 0xba, 0x8e, 0xc6, 0x2d, 0x36, + 0x49, 0x57, 0x0c, 0xe8, 0x76, 0xe9, 0xce, 0x6f, 0x3b, 0x1f, 0xed, 0x4d, + 0xb4, 0x43, 0xfd, 0x48, 0x29, 0xcc, 0xfa, 0xe3, 0xa9, 0xfe, 0x98, 0x6c, + 0xae, 0x1f, 0x33, 0xb8, 0x38, 0xfb, 0x23, 0x30, 0xd1, 0x1a, 0x78, 0xc1, + 0x5d, 0x24, 0xf7, 0xf7, 0x26, 0xe6, 0xe6, 0xf6, 0x68, 0xf0, 0x47, 0x4f, + 0x7d, 0xb0, 0xfd, 0x6a, 0xc0, 0x8f, 0xfe, 0x0c, 0x3f, 0xda, 0xcd, 0x39, + 0xea, 0xf7, 0x31, 0x34, 0x71, 0x18, 0x1c, 0x6e, 0x70, 0xe8, 0xbc, 0xbd, + 0xc4, 0x23, 0x17, 0x77, 0x29, 0x37, 0x77, 0x69, 0xe5, 0x8f, 0x86, 0x95, + 0x43, 0x3b, 0xee, 0xe4, 0x3a, 0xd9, 0xcb, 0xab, 0x94, 0xeb, 0xbb, 0xf4, + 0xc9, 0x9b, 0xbc, 0xb2, 0x6b, 0xbc, 0xf4, 0xf8, 0x1e, 0x2f, 0xed, 0x86, + 0xa1, 0x7e, 0x8a, 0x1e, 0x3f, 0x0e, 0x16, 0xb4, 0x9d, 0xd5, 0x0f, 0xb1, + 0xb9, 0xed, 0x9e, 0x87, 0xea, 0x29, 0xba, 0x95, 0x59, 0x0d, 0x20, 0xc7, + 0xfd, 0xbd, 0xc4, 0xcc, 0x03, 0x26, 0xb8, 0x47, 0x57, 0x43, 0xe2, 0x8f, + 0xb9, 0x84, 0xcd, 0x21, 0x81, 0x98, 0x60, 0x8c, 0x4e, 0xac, 0x75, 0xbd, + 0xbb, 0x46, 0xcb, 0x7d, 0x3c, 0xfc, 0x11, 0xfd, 0x67, 0x8c, 0x94, 0x9c, + 0xab, 0x1b, 0xbb, 0x95, 0x8d, 0xf9, 0x63, 0xcf, 0x91, 0xa2, 0x43, 0xe3, + 0x3b, 0xcc, 0x09, 0x77, 0x5c, 0x61, 0xd6, 0x18, 0x80, 0xf2, 0x1a, 0x3a, + 0x8f, 0x98, 0x5e, 0x66, 0x0f, 0x02, 0x43, 0xc6, 0x4d, 0xca, 0x5c, 0x4e, + 0x4c, 0x37, 0x88, 0xa1, 0xf3, 0xe7, 0x97, 0xa1, 0x73, 0x53, 0x36, 0x80, + 0xcd, 0x31, 0x73, 0x5f, 0x56, 0xd1, 0x71, 0xed, 0xdc, 0x6e, 0x23, 0xcb, + 0x32, 0x11, 0xd9, 0x8e, 0x8f, 0x93, 0xd9, 0x3c, 0x30, 0xa9, 0xc6, 0xcc, + 0x4b, 0x8c, 0xde, 0xf5, 0x8c, 0xd8, 0x33, 0x66, 0xde, 0x4b, 0x35, 0x46, + 0xf3, 0x87, 0x66, 0x0a, 0xf1, 0xe3, 0x70, 0x33, 0x05, 0xcb, 0x4b, 0x62, + 0xa6, 0x24, 0x04, 0xa6, 0x2c, 0x57, 0xb9, 0xb0, 0x3b, 0xf8, 0x9b, 0x5d, + 0x7a, 0x60, 0xef, 0x90, 0xf6, 0x93, 0x05, 0xe5, 0x10, 0xf9, 0x77, 0x1a, + 0xc6, 0xc3, 0x98, 0x3a, 0x00, 0xd3, 0x62, 0xce, 0x35, 0x83, 0xb0, 0x38, + 0xac, 0x3b, 0xf0, 0x91, 0x01, 0x03, 0xed, 0x1d, 0xda, 0xea, 0x11, 0xbd, + 0xc2, 0xe1, 0x19, 0x87, 0x6d, 0x39, 0xec, 0x65, 0x60, 0xa7, 0xc3, 0xcb, + 0x4d, 0x3e, 0x73, 0x92, 0xa1, 0x21, 0xc7, 0x6b, 0x7e, 0x62, 0x4e, 0x29, + 0x70, 0x43, 0x82, 0xee, 0xb2, 0x0b, 0xb4, 0x26, 0x5b, 0xea, 0xba, 0x07, + 0x0a, 0xf1, 0x33, 0x17, 0xfa, 0x08, 0x0d, 0x2a, 0x26, 0x18, 0xf7, 0xeb, + 0x09, 0x5d, 0x0d, 0x9e, 0x00, 0xd8, 0x73, 0xea, 0xcb, 0x65, 0x3d, 0x79, + 0xff, 0xde, 0xa2, 0xe0, 0x96, 0xf7, 0x76, 0x2f, 0xee, 0x7d, 0x01, 0xc7, + 0xb9, 0x11, 0xb8, 0xa6, 0x06, 0x74, 0x0c, 0x1f, 0x38, 0x2a, 0x44, 0x4f, + 0x4b, 0x44, 0x47, 0x86, 0x4d, 0x0f, 0x1f, 0x2b, 0x8a, 0x5a, 0x65, 0x61, + 0x07, 0x6e, 0x33, 0x01, 0xb8, 0x27, 0x33, 0x83, 0xcd, 0x7b, 0xd6, 0xb8, + 0xf5, 0xc4, 0xce, 0xb7, 0x7c, 0xb4, 0xd1, 0x7a, 0xec, 0x5c, 0xa1, 0x25, + 0xd5, 0x23, 0x91, 0x96, 0xb1, 0xda, 0x5a, 0x53, 0x2c, 0x3f, 0xe1, 0xc3, + 0x9d, 0x8b, 0x49, 0x45, 0xd4, 0x02, 0x27, 0x45, 0xee, 0x8a, 0xe9, 0xbe, + 0xd1, 0x8c, 0x3b, 0x52, 0xc9, 0x2d, 0x2b, 0x6d, 0x88, 0x0d, 0x47, 0xd3, + 0xe9, 0x8a, 0x29, 0x2e, 0xa0, 0x52, 0xb8, 0xfb, 0x0d, 0x90, 0x00, 0x1a, + 0x6f, 0x28, 0x74, 0xb1, 0x59, 0x28, 0x96, 0x58, 0x97, 0xed, 0x42, 0xff, + 0x66, 0x3e, 0x9b, 0xa6, 0x0f, 0xdc, 0x7d, 0x09, 0x2b, 0xec, 0x18, 0x3a, + 0x16, 0x5d, 0x7b, 0xa2, 0x30, 0x94, 0x99, 0x62, 0x9a, 0x68, 0xe0, 0x1f, + 0x5c, 0xa6, 0x46, 0xfa, 0xd7, 0xb2, 0x11, 0xe2, 0x6f, 0xe3, 0xf6, 0x50, + 0x5d, 0xa1, 0xc6, 0x2c, 0x08, 0x58, 0x9e, 0xe6, 0x88, 0x48, 0x95, 0x68, + 0x2a, 0x37, 0xba, 0xe2, 0x8f, 0x5e, 0xa3, 0x1d, 0x1d, 0x45, 0xba, 0xa9, + 0xea, 0x2c, 0x9e, 0x80, 0x20, 0xe6, 0x4e, 0x41, 0x03, 0x3c, 0x5b, 0x98, + 0x88, 0xce, 0xd2, 0x8e, 0xe2, 0x32, 0x1c, 0x5e, 0x13, 0x16, 0x97, 0x45, + 0xc3, 0x9d, 0xcc, 0x8d, 0xb1, 0xfd, 0xac, 0x7f, 0x2b, 0xe4, 0x20, 0x5b, + 0xd4, 0x1c, 0x5c, 0x0e, 0x92, 0xc6, 0xcb, 0xef, 0x35, 0x7e, 0x70, 0x79, + 0x24, 0xad, 0x82, 0xfd, 0x52, 0xf7, 0x96, 0xb9, 0x34, 0x6e, 0x07, 0xa1, + 0xeb, 0xcd, 0xe5, 0x61, 0xad, 0x28, 0x34, 0xa6, 0xb1, 0x8d, 0xd3, 0x2e, + 0x86, 0xf2, 0x97, 0x1d, 0xda, 0xff, 0xbf, 0x63, 0x61, 0xbf, 0x72, 0x2c, + 0xf8, 0x87, 0x58, 0x14, 0x07, 0x96, 0xd5, 0x03, 0x41, 0xa1, 0x08, 0x30, + 0xb6, 0x3e, 0x75, 0x2c, 0x63, 0xdc, 0xa0, 0x53, 0x12, 0x2e, 0x35, 0x09, + 0x42, 0x5c, 0xc0, 0x7c, 0x3e, 0xf3, 0x94, 0x42, 0x4a, 0x40, 0xc5, 0x9d, + 0xe8, 0xc2, 0x02, 0xb1, 0x71, 0x8e, 0x93, 0x54, 0xe3, 0x5f, 0x07, 0x51, + 0x68, 0xdb, 0x99, 0x79, 0xbb, 0x6e, 0x89, 0xa4, 0xf8, 0x12, 0x51, 0x23, + 0xd7, 0xae, 0x0b, 0xc3, 0xf2, 0xb4, 0x5f, 0xc6, 0x5a, 0xc2, 0xd8, 0xc6, + 0x30, 0xb7, 0x31, 0x6d, 0x71, 0x7e, 0xfd, 0x74, 0xf1, 0x2c, 0xaf, 0xb0, + 0x3a, 0xfe, 0xaa, 0x7b, 0x38, 0x55, 0x17, 0x33, 0x30, 0x4c, 0x98, 0xff, + 0xbc, 0x38, 0xfd, 0x70, 0xf6, 0x36, 0xfc, 0x92, 0xec, 0x6d, 0x53, 0x16, + 0xd0, 0x4d, 0x7b, 0x76, 0xb8, 0xb4, 0xac, 0x7f, 0x23, 0xff, 0x3a, 0x5d, + 0x16, 0x75, 0x51, 0xf9, 0x57, 0x88, 0xe4, 0x1b, 0xb3, 0xb7, 0xff, 0x07, + 0xcb, 0x4b, 0x74, 0x5c, 0x80, 0x4a, 0x00, 0x00 +}; const GFXglyph Antonio_SemiBold40pt7bGlyphs[] PROGMEM = { {0, 1, 1, 17, 0, 0}, // 0x20 ' ' @@ -1633,7 +518,7 @@ const GFXglyph Antonio_SemiBold40pt7bGlyphs[] PROGMEM = { {4810, 22, 38, 28, 3, -47}, // 0x3E '>' {4915, 24, 68, 33, 5, -67}, // 0x3F '?' {5119, 48, 71, 58, 5, -67}, // 0x40 '@' - {5545, 31, 67, 35, 2, -66}, // 0x41 'A' + {5545, 31, 69, 37, 2, -67}, // 0x41 'A' {5805, 28, 67, 36, 5, -66}, // 0x42 'B' {6040, 27, 69, 36, 5, -67}, // 0x43 'C' {6273, 28, 67, 37, 5, -66}, // 0x44 'D' @@ -1699,8 +584,30 @@ const GFXglyph Antonio_SemiBold40pt7bGlyphs[] PROGMEM = { //, {18021, 31, 69, 37, 2, -67} -const GFXfont Antonio_SemiBold40pt7b PROGMEM = { - (uint8_t *)Antonio_SemiBold40pt7bBitmaps, - (GFXglyph *)Antonio_SemiBold40pt7bGlyphs, 0x20, 0x7E, 100}; +// const GFXfont Antonio_SemiBold40pt7b PROGMEM = { +// (uint8_t *)Antonio_SemiBold40pt7bBitmaps, +// (GFXglyph *)Antonio_SemiBold40pt7bGlyphs, 0x20, 0x7E, 100}; // Approx. 18961 bytes + +// // Font metadata structure +// struct FontData { +// const uint8_t* compressedData; +// const GFXglyph* glyphs; +// const size_t compressedSize; +// const size_t originalSize; +// const uint16_t first; +// const uint16_t last; +// const uint8_t yAdvance; +// }; + +// Font properties +static constexpr FontData Antonio_SemiBold40pt7b_Properties = { + Antonio_SemiBold40pt7bBitmaps_Gzip, + Antonio_SemiBold40pt7bGlyphs, + sizeof(Antonio_SemiBold40pt7bBitmaps_Gzip), + 19072, // Original size + 0x20, // First char + 0x7E, // Last char + 100 // yAdvance +}; diff --git a/src/fonts/antonio-semibold90.h b/src/fonts/antonio-semibold90.h index 4ad6ab3..4f57cb4 100644 --- a/src/fonts/antonio-semibold90.h +++ b/src/fonts/antonio-semibold90.h @@ -1,5259 +1,1023 @@ +#pragma once + #include #include +// #include "fonts.hpp" -const uint8_t Antonio_SemiBold90pt7bBitmaps[] PROGMEM = { - 0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, - 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x7F, - 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x7F, 0xFF, - 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, - 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0x8F, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0xFF, - 0xFF, 0xE3, 0xFF, 0xFF, 0x8F, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, - 0xE3, 0xFF, 0xFF, 0x8F, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0xE3, - 0xFF, 0xFF, 0x8F, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0xC1, 0xFF, - 0xFF, 0x07, 0xFF, 0xFC, 0x1F, 0xFF, 0xF0, 0x7F, 0xFF, 0xC1, 0xFF, 0xFF, - 0x07, 0xFF, 0xFC, 0x1F, 0xFF, 0xF0, 0x7F, 0xFF, 0xC1, 0xFF, 0xFF, 0x07, - 0xFF, 0xFC, 0x1F, 0xFF, 0xF0, 0x7F, 0xFF, 0xC1, 0xFF, 0xFF, 0x07, 0xFF, - 0xFC, 0x1F, 0xFF, 0xF0, 0x7F, 0xFF, 0xC0, 0xFF, 0xFE, 0x03, 0xFF, 0xF8, - 0x0F, 0xFF, 0xE0, 0x3F, 0xFF, 0x80, 0xFF, 0xFE, 0x03, 0xFF, 0xF8, 0x0F, - 0xFF, 0xE0, 0x3F, 0xFF, 0x80, 0xFF, 0xFE, 0x03, 0xFF, 0xF8, 0x0F, 0xFF, - 0xE0, 0x3F, 0xFF, 0x80, 0xFF, 0xFE, 0x03, 0xFF, 0xF8, 0x0F, 0xFF, 0xE0, - 0x3F, 0xFF, 0x80, 0xFF, 0xFE, 0x01, 0xFF, 0xF0, 0x07, 0xFF, 0xC0, 0x1F, - 0xFF, 0x00, 0x7F, 0xFC, 0x01, 0xFF, 0xF0, 0x07, 0xFF, 0xC0, 0x1F, 0xFF, - 0x00, 0x7F, 0xFC, 0x01, 0xFF, 0xF0, 0x07, 0xFF, 0xC0, 0x1F, 0xFF, 0x00, - 0x7F, 0xFC, 0x01, 0xFF, 0xF0, 0x07, 0xFF, 0xC0, 0x1F, 0xFF, 0x00, 0x7F, - 0xFC, 0x01, 0xFF, 0xF0, 0x03, 0xFF, 0x80, 0x0F, 0xFE, 0x00, 0x3F, 0xF8, - 0x00, 0xFF, 0xE0, 0x03, 0xFF, 0x80, 0x0F, 0xFE, 0x00, 0x3F, 0xF8, 0x00, - 0xFF, 0xE0, 0x03, 0xFF, 0x80, 0x0F, 0xFE, 0x00, 0x3F, 0xF8, 0x00, 0xFF, - 0xE0, 0x03, 0xFF, 0x80, 0x0F, 0xFE, 0x00, 0x3F, 0xF8, 0x00, 0xFF, 0xE0, - 0x03, 0xFF, 0x80, 0x07, 0xFC, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0xC0, 0x01, - 0xFF, 0x00, 0x07, 0xFC, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0xC0, 0x01, 0xFF, - 0x00, 0x07, 0xFC, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0xC0, 0x01, 0xFF, 0x00, - 0x07, 0xFC, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xDF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, - 0xDF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xDF, - 0xFF, 0xFF, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xDF, 0xFF, - 0xFF, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, - 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFE, 0xFF, 0xFF, 0xF9, 0xFF, - 0xFF, 0xE7, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF9, 0xFF, 0xFF, - 0xC7, 0xFF, 0xFF, 0x1F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF1, 0xFF, 0xFF, 0xC7, - 0xFF, 0xFF, 0x1F, 0xFF, 0xFC, 0x7F, 0xFF, 0xE1, 0xFF, 0xFF, 0x87, 0xFF, - 0xFE, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xE1, 0xFF, 0xFF, 0x87, 0xFF, 0xFE, - 0x1F, 0xFF, 0xF0, 0x7F, 0xFF, 0xC1, 0xFF, 0xFF, 0x07, 0xFF, 0xFC, 0x1F, - 0xFF, 0xF0, 0x3F, 0xFF, 0xC0, 0xFF, 0xFF, 0x03, 0xFF, 0xF8, 0x0F, 0xFF, - 0xE0, 0x3F, 0xFF, 0x80, 0xFF, 0xFE, 0x03, 0xFF, 0xF8, 0x0F, 0xFF, 0xE0, - 0x3F, 0xFF, 0x80, 0xFF, 0xFC, 0x03, 0xFF, 0xF0, 0x0F, 0xFF, 0xC0, 0x3F, - 0xFF, 0x00, 0xFF, 0xFC, 0x03, 0xFF, 0xF0, 0x0F, 0xFF, 0xC0, 0x3F, 0xFE, - 0x00, 0xFF, 0xF8, 0x03, 0xFF, 0xE0, 0x0F, 0xFF, 0x80, 0x3F, 0xFE, 0x00, - 0xFF, 0xF8, 0x03, 0xFF, 0xE0, 0x07, 0xFF, 0x00, 0x1F, 0xFC, 0x00, 0x7F, - 0xF0, 0x01, 0xFF, 0xC0, 0x07, 0xFF, 0x00, 0x1F, 0xFC, 0x00, 0x7F, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xC0, - 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x03, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xC0, - 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x03, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xC0, - 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x03, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xC0, - 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x03, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xC0, - 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x03, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xC0, - 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x03, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, - 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x01, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, - 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x01, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, - 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x01, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, - 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF0, - 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF0, - 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF0, - 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFE, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xF0, - 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x7F, 0xFE, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xF0, - 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x7F, - 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x7F, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xF8, - 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x7F, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xF8, - 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x7F, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0x80, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFC, - 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x3F, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x03, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0x80, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFC, - 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x3F, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x01, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0x80, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFC, - 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x3F, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x01, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0x80, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFC, - 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x3F, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x01, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xC0, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, - 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x3F, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x01, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, - 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x1F, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x01, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, - 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x1F, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, - 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x1F, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0xC0, - 0x7F, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0x00, 0x07, - 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xF0, 0x7F, 0xFF, - 0xF8, 0x00, 0x0F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, - 0xC1, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xFC, 0x3F, 0xFF, 0xF8, 0x00, - 0x03, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xF1, 0xFF, - 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, - 0xFF, 0xC7, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0xFF, 0xFF, 0xE0, - 0x00, 0x03, 0xFF, 0xFF, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xF3, - 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF0, 0x00, 0x01, - 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xF9, 0xFF, 0xFF, - 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, - 0xE3, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF0, 0x00, - 0x01, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xF1, 0xFF, - 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFE, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0xFF, - 0xFF, 0xC3, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xF8, - 0x00, 0x03, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xE1, - 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0x00, 0x01, - 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x8F, 0xFF, 0xFE, - 0x00, 0x01, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xFE, - 0x3F, 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x00, 0x00, - 0x7F, 0xFF, 0xFC, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0x9F, 0xFF, - 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0x80, 0x00, 0x1F, 0xFF, - 0xFE, 0x7F, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0x00, - 0x00, 0x3F, 0xFF, 0xFD, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0xBF, - 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x1F, - 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0xDF, 0xFF, 0xFC, - 0x00, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFF, - 0x7F, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0x00, 0x00, - 0x3F, 0xFF, 0xFD, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0x9F, 0xFF, - 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0x80, 0x00, 0x1F, 0xFF, - 0xFE, 0x7F, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x00, - 0x00, 0x7F, 0xFF, 0xF9, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, 0x3F, - 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0x80, 0x00, 0x7F, - 0xFF, 0xF8, 0x7F, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, - 0x00, 0x03, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF8, - 0x1F, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xF8, 0x3F, - 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, - 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x1F, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x7F, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, - 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, - 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF8, - 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, - 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, - 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x01, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF8, - 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x7E, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, - 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, - 0xFF, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xC0, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0xFF, - 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xC0, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xE0, 0x00, 0x00, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, - 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x03, - 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x01, 0xFF, 0xFE, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0x80, 0x00, - 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, - 0xF0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFE, 0x00, - 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFE, - 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFE, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, - 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xF8, - 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x7F, - 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xE3, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, - 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x3F, - 0xFF, 0xFC, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x07, - 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0x3F, 0xFF, - 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x03, - 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xCF, 0xFF, 0xF8, 0x00, 0x00, 0x3F, - 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, - 0x1F, 0xFF, 0xF3, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, - 0x3F, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFE, 0xFF, - 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, - 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xBF, 0xFF, 0xE0, 0x00, 0x00, - 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFE, 0x00, - 0x00, 0x3F, 0xFF, 0xEF, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, - 0x01, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFB, - 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFE, 0xFF, 0xFF, 0xC0, 0x00, - 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xF0, - 0x00, 0x00, 0xFF, 0xFF, 0x9F, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0x80, - 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, - 0xE7, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xF8, - 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFD, 0xFF, 0xFF, 0x00, - 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, - 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x7F, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFC, - 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, - 0xFF, 0xDF, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, - 0xC0, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xF7, 0xFF, 0xFE, - 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x01, 0xFF, - 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, - 0xF0, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x01, - 0xFF, 0xFF, 0x3F, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x01, 0xFF, - 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xCF, 0xFF, - 0xFC, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x07, - 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xF3, 0xFF, 0xFF, 0x80, 0x03, 0xFF, - 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, - 0x07, 0xFF, 0xFC, 0x7F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x1F, - 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x00, - 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, - 0x00, 0x1F, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFC, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xC0, 0x00, - 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xF0, - 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, - 0xF0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFE, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x7F, 0xFF, - 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, - 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xF0, - 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x01, - 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, - 0x3F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x00, 0x07, - 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFC, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, - 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, - 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xC0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, - 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x01, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, - 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, - 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, - 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x03, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, - 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, - 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x7F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, - 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, - 0xFF, 0xC0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0x80, - 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xF8, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, - 0x01, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x03, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xF0, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x00, 0x07, 0xFF, 0xFE, - 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, - 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, - 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x3F, - 0xFF, 0x80, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFC, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, - 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xC0, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0xC0, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x3F, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFE, 0x03, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFC, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, - 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF1, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF3, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xEF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x08, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x70, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xF0, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x1F, 0xE0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x3F, 0xE0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, - 0xC0, 0x00, 0xFF, 0xFF, 0xE7, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xC0, 0x03, - 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xC0, 0x07, 0xFF, 0xFF, - 0x0F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0x80, 0x1F, 0xFF, 0xFC, 0x1F, 0xFF, - 0xF8, 0x00, 0x7F, 0xFF, 0x80, 0x3F, 0xFF, 0xF8, 0x1F, 0xFF, 0xF8, 0x00, - 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, - 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFC, 0x07, 0xFF, - 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFC, 0x00, - 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xE0, 0x3F, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, - 0xC0, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0x83, 0xFF, - 0xFE, 0x01, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0x8F, 0xFF, 0xFC, 0x03, - 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x1F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFE, - 0x00, 0x07, 0xFF, 0xFE, 0x7F, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x00, 0x07, - 0xFF, 0xFE, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, - 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xC0, 0x07, 0xFF, 0xFE, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFC, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFE, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xF8, - 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xE0, 0x00, 0x7F, - 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x1F, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xF8, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, - 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, - 0xF8, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xF0, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0x80, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0x01, - 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, - 0x80, 0x00, 0x0F, 0xFF, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, - 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x3F, - 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, - 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x83, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, - 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFE, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x1F, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, - 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, - 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, - 0xFF, 0xFF, 0x3F, 0xFF, 0xE7, 0xFF, 0xFC, 0xFF, 0xFF, 0x9F, 0xFF, 0xF3, - 0xFF, 0xFE, 0x7F, 0xFF, 0xCF, 0xFF, 0xF9, 0xFF, 0xFF, 0x3F, 0xFF, 0xC7, - 0xFF, 0xF8, 0x7F, 0xFF, 0x0F, 0xFF, 0xE1, 0xFF, 0xFC, 0x3F, 0xFF, 0x87, - 0xFF, 0xF0, 0xFF, 0xFE, 0x1F, 0xFF, 0xC3, 0xFF, 0xF0, 0x7F, 0xFE, 0x0F, - 0xFF, 0xC1, 0xFF, 0xF8, 0x1F, 0xFF, 0x03, 0xFF, 0xE0, 0x7F, 0xFC, 0x0F, - 0xFF, 0x81, 0xFF, 0xF0, 0x3F, 0xFE, 0x07, 0xFF, 0x80, 0xFF, 0xF0, 0x1F, - 0xFE, 0x03, 0xFF, 0xC0, 0x3F, 0xF8, 0x07, 0xFF, 0x00, 0xFF, 0xE0, 0x1F, - 0xFC, 0x03, 0xFF, 0x80, 0x7F, 0xF0, 0x0F, 0xFC, 0x01, 0xFF, 0x80, 0x3F, - 0xF0, 0x07, 0xFE, 0x00, 0xFF, 0xC0, 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x3F, - 0xE0, 0x07, 0xFC, 0x00, 0xFF, 0x80, 0x1F, 0xE0, 0x03, 0xFC, 0x00, 0x7F, - 0x80, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x3F, 0xFF, - 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xFF, - 0x00, 0x7F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, - 0x03, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, - 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, - 0x1F, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0x80, - 0x3F, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFC, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF8, 0x00, - 0x7F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF8, 0x00, - 0x7F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xF0, 0x00, - 0x7F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xF0, 0x00, - 0x7F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xF0, 0x00, - 0x7F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF8, 0x00, - 0x7F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xF8, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFE, 0x00, - 0x3F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, - 0x1F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, - 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, - 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFF, - 0x00, 0x3F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, - 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xE0, - 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, - 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0xFC, - 0x00, 0xFF, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xFE, - 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFE, - 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFE, - 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xFE, - 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, - 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xF8, - 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xE0, - 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0x80, - 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xF8, 0x00, - 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x80, - 0x01, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x3F, - 0xFE, 0x00, 0x03, 0xC0, 0x03, 0xE0, 0x00, 0x3F, 0xFC, 0x00, 0x07, 0xE0, - 0x07, 0xF0, 0x00, 0x3F, 0xFC, 0x00, 0x0F, 0xE0, 0x07, 0xFC, 0x00, 0x3F, - 0xFC, 0x00, 0x3F, 0xF0, 0x0F, 0xFE, 0x00, 0x3F, 0xFC, 0x00, 0x7F, 0xF0, - 0x0F, 0xFF, 0x00, 0x1F, 0xFC, 0x00, 0xFF, 0xF8, 0x1F, 0xFF, 0xC0, 0x1F, - 0xFC, 0x03, 0xFF, 0xFC, 0x3F, 0xFF, 0xE0, 0x1F, 0xFC, 0x07, 0xFF, 0xFC, - 0x3F, 0xFF, 0xF0, 0x1F, 0xFC, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xFC, 0x1F, - 0xFC, 0x3F, 0xFF, 0xFE, 0x7F, 0xFF, 0xFE, 0x1F, 0xFC, 0x7F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xDF, - 0xFB, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xDF, 0xFB, 0xFF, 0xFF, 0xF8, - 0xFF, 0xFF, 0xFF, 0x9F, 0xF8, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFE, 0x1F, - 0xFC, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFC, 0x1F, 0xFC, 0x3F, 0xFF, 0xFF, - 0x3F, 0xFF, 0xF8, 0x1F, 0xFC, 0x1F, 0xFF, 0xFE, 0x1F, 0xFF, 0xF0, 0x1F, - 0xFC, 0x07, 0xFF, 0xFC, 0x1F, 0xFF, 0xC0, 0x1F, 0xFC, 0x03, 0xFF, 0xFC, - 0x0F, 0xFF, 0x80, 0x1F, 0xFC, 0x01, 0xFF, 0xF8, 0x0F, 0xFF, 0x00, 0x3F, - 0xFC, 0x00, 0x7F, 0xF8, 0x07, 0xFC, 0x00, 0x3F, 0xFC, 0x00, 0x3F, 0xF0, - 0x03, 0xF8, 0x00, 0x3F, 0xFC, 0x00, 0x1F, 0xF0, 0x03, 0xF0, 0x00, 0x3F, - 0xFC, 0x00, 0x0F, 0xE0, 0x01, 0xE0, 0x00, 0x3F, 0xFE, 0x00, 0x03, 0xC0, - 0x01, 0x80, 0x00, 0x3F, 0xFE, 0x00, 0x01, 0xC0, 0x01, 0x00, 0x00, 0x3F, - 0xFE, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 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, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 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, 0xE0, 0x03, 0xFF, - 0xC0, 0x07, 0xFF, 0x80, 0x1F, 0xFF, 0x00, 0x3F, 0xFC, 0x00, 0x7F, 0xF8, - 0x00, 0xFF, 0xF0, 0x01, 0xFF, 0xC0, 0x07, 0xFF, 0x80, 0x0F, 0xFF, 0x00, - 0x1F, 0xFE, 0x00, 0x3F, 0xF8, 0x00, 0xFF, 0xF0, 0x01, 0xFF, 0xE0, 0x03, - 0xFF, 0x80, 0x07, 0xFF, 0x00, 0x0F, 0xFE, 0x00, 0x3F, 0xF8, 0x00, 0x7F, - 0xF0, 0x00, 0xFF, 0xE0, 0x01, 0xFF, 0xC0, 0x03, 0xFF, 0x00, 0x0F, 0xFE, - 0x00, 0x1F, 0xFC, 0x00, 0x3F, 0xF0, 0x00, 0x7F, 0xE0, 0x00, 0xFF, 0xC0, - 0x03, 0xFF, 0x80, 0x07, 0xFE, 0x00, 0x0F, 0xFC, 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, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, - 0xF0, 0xFF, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0x00, - 0x07, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xF8, 0xFF, - 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0xFF, - 0xFF, 0xF3, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF8, - 0x00, 0x03, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xF9, - 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, - 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFD, 0xFF, 0xFF, - 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, - 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0xFF, 0xFF, - 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0x9F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, - 0xF3, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF0, 0x00, - 0x03, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xF9, 0xFF, - 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x01, 0xFF, - 0xFF, 0xE3, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xF8, 0x7F, 0xFF, 0xF8, - 0x00, 0x0F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xE1, - 0xFF, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0x00, 0x1F, - 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x00, - 0x3F, 0xFF, 0xC0, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, - 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, - 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, - 0xE0, 0x00, 0x1F, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, - 0x3F, 0xFF, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0xF8, 0x3F, - 0xFF, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, - 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, - 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF8, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, - 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, - 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x01, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, - 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x03, - 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, - 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, - 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, - 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, - 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF8, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, - 0x01, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, - 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, - 0xFF, 0x03, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xC0, - 0x00, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 0xF0, 0xFF, - 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xF8, 0x7F, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, - 0xFC, 0x3F, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0x1F, 0xFF, 0xFC, 0x00, - 0x03, 0xFF, 0xFF, 0x8F, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xCF, 0xFF, - 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, - 0xF3, 0xFF, 0xFF, 0x80, 0x00, 0x1F, 0xFF, 0xF9, 0xFF, 0xFF, 0xC0, 0x00, - 0x0F, 0xFF, 0xFC, 0xFF, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0x7F, 0xFF, - 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xBF, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, - 0xDF, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0x00, 0x00, - 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFB, 0xFF, 0xFF, - 0x80, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xFB, 0xFF, - 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xFD, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, - 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, - 0x03, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0x9F, 0xFF, - 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, - 0xFF, 0xFC, 0x07, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, - 0xFE, 0x00, 0x0F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, - 0xFC, 0x1F, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, - 0x00, 0x07, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x3F, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, - 0x07, 0xFF, 0xFF, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0xFF, - 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xF9, 0xFF, 0xFF, - 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, - 0xFE, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF3, 0xFF, 0xFF, 0x80, - 0x00, 0x03, 0xFF, 0xFF, 0x9F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFD, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, - 0xFD, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0x9F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xE7, 0xFF, 0xFE, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF9, 0xFF, 0xFF, - 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, - 0xFE, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0x80, - 0x00, 0x07, 0xFF, 0xFF, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xF8, - 0x7F, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0x80, 0x00, - 0x1F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0xFF, - 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, - 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, - 0xFF, 0x87, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xBF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF7, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFE, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xDF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF3, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFE, 0x7F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xCF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xF1, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x1F, 0xFE, 0x3F, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xC7, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xF8, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFE, 0x1F, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xC3, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xF8, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xC1, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0xFF, 0xF8, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xE0, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xF8, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xE0, 0x7F, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x0F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x03, 0xFF, 0xE0, - 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x07, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x03, 0xFF, - 0xE0, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x03, - 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x01, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x00, 0x00, - 0x03, 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x7F, 0xFC, 0x00, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x00, - 0x00, 0x03, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFE, - 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x0F, 0xFF, 0xFC, - 0x00, 0x00, 0x03, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x7F, - 0xFE, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x07, 0xFF, - 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x7F, 0xFE, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x03, - 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, - 0x00, 0x7F, 0xFE, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xC0, - 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xF0, - 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, - 0xC0, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, - 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x0F, - 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x0F, - 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, - 0x0F, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xF8, 0x00, - 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xC0, - 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xF8, - 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, - 0xE0, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x01, 0xFF, - 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x3F, - 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x01, - 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x80, 0x00, - 0x1F, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0x00, - 0x01, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0x80, - 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, - 0x80, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, - 0x80, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0xFF, - 0xFF, 0xC0, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x60, 0x00, 0x00, 0x7F, - 0xFF, 0xE0, 0x1F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0xFF, 0xFF, 0xE0, - 0x00, 0x7F, 0xFF, 0xE3, 0xFF, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xE7, 0xFF, - 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xEF, 0xFF, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, - 0xFE, 0x00, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xF8, - 0x7F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xF8, 0x7F, 0xFF, 0xF8, 0x00, 0x1F, - 0xFF, 0xFC, 0x7F, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF0, - 0x00, 0x1F, 0xFF, 0xFC, 0x7F, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFC, 0x7F, - 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFC, 0x7F, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, - 0xFC, 0x7F, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xE0, 0x00, - 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, - 0xC0, 0x00, 0x0F, 0xFF, 0xFE, 0x0F, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFE, - 0x00, 0x00, 0xC0, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, - 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, - 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, - 0x00, 0x0F, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0xFF, - 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, - 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, - 0x0F, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0xFF, 0xFF, - 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, - 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, - 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFC, 0xFF, 0xFF, 0xE0, - 0x00, 0x0F, 0xFF, 0xFC, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFC, 0xFF, - 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFC, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, - 0xFC, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFC, 0xFF, 0xFF, 0xF8, 0x00, - 0x3F, 0xFF, 0xF8, 0x7F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF8, 0x7F, 0xFF, - 0xFE, 0x00, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xF8, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xFC, 0x07, 0xFF, - 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, - 0xE0, 0x00, 0x7F, 0xFF, 0xF0, 0x3F, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xFF, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF8, 0x00, - 0x03, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xF8, 0x3F, - 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x00, 0x00, 0x1F, - 0xFF, 0xF8, 0x7F, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, - 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, - 0x87, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xF0, 0x00, - 0x01, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0xFF, - 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x1F, - 0xFF, 0xFC, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, - 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, - 0xCF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, - 0xFF, 0xFC, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, - 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, - 0xCF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x3C, 0x00, 0x00, 0x0F, 0xFF, 0xFE, - 0x01, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFC, 0x00, - 0x0F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xE7, 0xFF, - 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, - 0xFE, 0x01, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, - 0xCF, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xFC, 0xFF, 0xFF, 0xF8, 0x00, - 0x01, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, - 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, - 0x00, 0x00, 0x07, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, - 0xEF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, - 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x7F, 0xFF, 0xF0, 0x00, - 0x00, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x7F, - 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xE7, 0xFF, 0xFF, 0x80, 0x00, 0x07, - 0xFF, 0xFE, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, - 0xC0, 0x00, 0x0F, 0xFF, 0xFE, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, - 0xE3, 0xFF, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xFC, 0x3F, 0xFF, 0xFE, 0x00, - 0x03, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFC, 0x1F, - 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, - 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF0, 0x00, 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, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, - 0xFC, 0x00, 0x3F, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, - 0xF8, 0x3F, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xE0, - 0x00, 0x1F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xF0, - 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x80, 0x00, - 0x1F, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF1, 0xFF, - 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, 0x00, 0x00, 0x1F, - 0xFF, 0xFC, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, - 0x80, 0x00, 0x07, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, - 0xF9, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFB, - 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xDF, 0xFF, 0xFC, 0x00, 0x00, - 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, - 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xF8, 0x00, 0x00, 0x3F, - 0xFF, 0xFD, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, - 0xFB, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xDF, 0xFF, 0xFC, 0x00, - 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF7, - 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x00, - 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xCF, 0xFF, - 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, - 0xFF, 0xF1, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0x8F, 0xFF, 0xFE, - 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, - 0xE3, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFC, 0x00, - 0x00, 0x7F, 0xFF, 0xF0, 0x7F, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0x83, - 0xFF, 0xFF, 0x80, 0x00, 0x1F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFC, 0x00, 0x00, - 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0x03, 0xFF, - 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x1F, 0xFF, 0xFC, 0x00, 0x03, 0xFF, - 0xFF, 0x80, 0x7F, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, - 0x80, 0x01, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFC, - 0x00, 0x7F, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xE0, - 0x3F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, - 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, - 0xF8, 0x01, 0xFF, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFE, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xF8, - 0x0F, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xF8, 0x00, - 0x07, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xF8, 0x1F, - 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xE0, 0x00, 0x07, - 0xFF, 0xFF, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x7F, 0xFF, - 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, - 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xF9, 0xFF, 0xFF, 0xE0, - 0x00, 0x03, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFE, - 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xF3, 0xFF, 0xFF, 0x80, 0x00, - 0x03, 0xFF, 0xFF, 0x9F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFD, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, - 0xFD, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, - 0x00, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF3, - 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xE3, 0xFF, - 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0xFF, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, - 0xE0, 0x00, 0x7F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFF, - 0xC0, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, - 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFC, 0x00, 0x7F, - 0xFF, 0xFE, 0x1F, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, - 0xC0, 0x00, 0x7F, 0xFF, 0xF8, 0x7F, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, - 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0x80, 0x00, - 0x1F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xCF, 0xFF, - 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, - 0xFF, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0x00, - 0x00, 0x1F, 0xFF, 0xFD, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x7F, 0xFF, 0xF7, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0xFF, - 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xDF, 0xFF, 0xF8, 0x00, 0x00, 0x3F, - 0xFF, 0xFB, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0x7F, 0xFF, 0xF0, - 0x00, 0x00, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFD, - 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0x9F, 0xFF, 0xFC, 0x00, 0x00, - 0x7F, 0xFF, 0xF3, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xFE, 0x7F, 0xFF, - 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, - 0xF8, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xFF, - 0xF1, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xF8, 0x3F, 0xFF, 0xF8, 0x00, - 0x00, 0x7F, 0xF0, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xE0, 0x00, 0x01, 0xFF, - 0xFF, 0xCF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0x80, - 0x00, 0x07, 0xFF, 0xFF, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xE7, - 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0xFF, 0xFF, 0xC0, 0x00, 0x03, - 0xFF, 0xFF, 0x9F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xF3, 0xFF, 0xFF, - 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, - 0xCF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0x80, 0x00, - 0x07, 0xFF, 0xFF, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xE7, 0xFF, - 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, - 0xFF, 0x9F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xF3, 0xFF, 0xFF, 0x00, - 0x00, 0x0F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0x8F, - 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xF1, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, - 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, - 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x7F, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFF, - 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xC0, 0x00, - 0x3F, 0xFF, 0xF8, 0x3F, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0x07, 0xFF, - 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, - 0xF8, 0x0F, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, - 0x0F, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 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, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, - 0xBF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xBF, - 0xFF, 0xFE, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xBF, 0xFF, - 0xFE, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFE, - 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFE, 0xFF, - 0xFF, 0xFB, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 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, 0xFC, 0x03, 0xFF, 0xF0, - 0x0F, 0xFF, 0x80, 0x3F, 0xFE, 0x01, 0xFF, 0xF8, 0x07, 0xFF, 0xC0, 0x1F, - 0xFF, 0x00, 0x7F, 0xFC, 0x03, 0xFF, 0xF0, 0x0F, 0xFF, 0x80, 0x3F, 0xFE, - 0x00, 0xFF, 0xF8, 0x03, 0xFF, 0xC0, 0x1F, 0xFF, 0x00, 0x7F, 0xFC, 0x01, - 0xFF, 0xF0, 0x07, 0xFF, 0x80, 0x1F, 0xFE, 0x00, 0xFF, 0xF8, 0x03, 0xFF, - 0xC0, 0x0F, 0xFF, 0x00, 0x3F, 0xFC, 0x01, 0xFF, 0xF0, 0x07, 0xFF, 0x80, - 0x1F, 0xFE, 0x00, 0x7F, 0xF8, 0x01, 0xFF, 0xC0, 0x0F, 0xFF, 0x00, 0x3F, - 0xFC, 0x00, 0xFF, 0xE0, 0x03, 0xFF, 0x80, 0x1F, 0xFE, 0x00, 0x7F, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, - 0xC3, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x00, 0x1F, - 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF9, 0xFF, 0xFF, 0xE0, - 0x01, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFF, 0x9F, 0xFF, - 0xFC, 0x00, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xF9, - 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x00, 0x03, 0xFF, - 0xFF, 0x9F, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF0, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x01, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, - 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x03, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFC, 0x00, - 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xF8, 0x00, 0x7F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, - 0x07, 0xFF, 0xE0, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xF0, 0x07, 0xFF, - 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xC0, - 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x1F, - 0xFF, 0x80, 0x7F, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x3F, 0xFE, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0xFF, 0xF8, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xE0, 0x3F, 0xFF, 0xC0, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0x80, 0xFF, 0xFE, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0x03, 0xFF, - 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xE0, 0x00, 0x7F, 0xFC, - 0x1F, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0x80, 0x01, - 0xFF, 0xF0, 0x7F, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x3F, 0xFE, - 0x00, 0x07, 0xFF, 0xC1, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, - 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0x07, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xF0, - 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x7F, 0xFC, 0x1F, 0xFF, 0xC0, 0x00, 0x1F, - 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0x80, 0x01, 0xFF, 0xF8, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x07, 0xFF, 0xE3, 0xFF, - 0xFC, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, - 0x8F, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xE0, 0x00, - 0x3F, 0xFE, 0x3F, 0xFF, 0x80, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x0F, 0xFF, - 0x80, 0x00, 0xFF, 0xF8, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xF0, 0x00, 0x00, - 0x3F, 0xFE, 0x00, 0x03, 0xFF, 0xE3, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xC0, - 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0x9F, 0xFF, 0xE0, 0x00, 0x3F, - 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x3F, 0xFE, 0x7F, 0xFF, 0x80, - 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0xFF, 0xF9, 0xFF, - 0xFE, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x03, 0xFF, - 0xF7, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0x00, - 0x0F, 0xFF, 0xDF, 0xFF, 0xC0, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x03, 0xFF, - 0xE0, 0x00, 0x3F, 0xFF, 0x7F, 0xFF, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x00, - 0x0F, 0xFF, 0x80, 0x00, 0xFF, 0xFD, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xC0, - 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x03, 0xFF, 0xF7, 0xFF, 0xF0, 0x00, 0x1F, - 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xDF, 0xFF, 0xC0, - 0x00, 0x7F, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0x7F, - 0xFF, 0x00, 0x01, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x3F, 0xFE, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0xFF, - 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFC, 0x00, 0x00, - 0x03, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xE0, - 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, - 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x1F, - 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0x80, - 0x00, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0x00, 0x3F, - 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFE, 0x00, 0x00, - 0x00, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xF8, - 0x00, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x03, - 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x0F, 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x03, 0xFF, 0xE0, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x00, 0x0F, - 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0x80, 0x00, - 0x00, 0x3F, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFE, - 0x00, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, - 0xFF, 0xF8, 0x00, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x3F, 0xFE, 0xFF, 0xFF, - 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0xFF, 0xFB, - 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x03, - 0xFF, 0xEF, 0xFF, 0xF0, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xF8, - 0x00, 0x0F, 0xFF, 0xBF, 0xFF, 0xC0, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x03, - 0xFF, 0xE0, 0x00, 0x3F, 0xFE, 0x7F, 0xFF, 0x00, 0x03, 0xFF, 0xE0, 0x00, - 0x00, 0x0F, 0xFF, 0x80, 0x00, 0xFF, 0xF9, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, - 0xC0, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x03, 0xFF, 0xE7, 0xFF, 0xF0, 0x00, - 0x3F, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0x1F, 0xFF, - 0xC0, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x7F, 0xFC, - 0x7F, 0xFF, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x01, - 0xFF, 0xF1, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFE, - 0x00, 0x07, 0xFF, 0xC7, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0x1F, 0xFF, 0xE0, 0x00, 0x7F, 0xFC, 0x00, - 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0x7F, 0xF8, 0x7F, 0xFF, 0x80, 0x01, 0xFF, - 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x03, 0xFF, 0xE0, 0xFF, 0xFE, 0x00, - 0x07, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0x83, 0xFF, - 0xF8, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x3F, 0xFE, - 0x0F, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, - 0xFF, 0xF0, 0x3F, 0xFF, 0xC0, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, - 0xC0, 0x07, 0xFF, 0xC0, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xF0, 0x00, 0x03, - 0xF7, 0xFF, 0x80, 0x1F, 0xFF, 0x03, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xE0, - 0x00, 0x1F, 0xDF, 0xFE, 0x00, 0xFF, 0xF8, 0x07, 0xFF, 0xF0, 0x00, 0x1F, - 0xFF, 0xC0, 0x00, 0x7F, 0x7F, 0xFC, 0x07, 0xFF, 0xE0, 0x1F, 0xFF, 0xC0, - 0x00, 0x3F, 0xFF, 0x00, 0x03, 0xF8, 0xFF, 0xF8, 0x3F, 0xFF, 0x80, 0x7F, - 0xFF, 0x80, 0x00, 0xFF, 0xFE, 0x00, 0x1F, 0xE3, 0xFF, 0xFB, 0xFF, 0xFC, - 0x01, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFE, 0x01, 0xFF, 0x8F, 0xFF, 0xFF, - 0xFF, 0xF0, 0x03, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFC, 0x1F, - 0xFF, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xF0, 0x7F, 0xFF, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x7F, 0xFF, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFC, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0x07, - 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0xF0, - 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, - 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFF, 0xF8, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x00, 0x1F, - 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x00, - 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, - 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF7, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xEF, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xCF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0x9F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x3F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFC, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF9, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE3, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC3, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0x87, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x0F, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x1F, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xF8, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x07, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x0F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xF8, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xF0, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x3F, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xC0, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xFF, 0xFE, - 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x03, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, - 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF0, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x07, - 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xE0, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x07, - 0xFF, 0xFC, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xF8, 0x00, - 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, - 0xFC, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x7F, - 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, - 0xC0, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x03, 0xFF, - 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, - 0x0F, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xF8, - 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, - 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, - 0xFF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, - 0x80, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x1F, - 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, - 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xF8, - 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x03, 0xFF, - 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, - 0x7F, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xC0, - 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, - 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x03, - 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFE, 0x00, - 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xFF, - 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x3F, - 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, - 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, - 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, - 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x07, - 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFC, 0x00, - 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x01, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xF8, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x1F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xC1, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x83, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFE, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x3F, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x7F, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xF1, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xE3, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0x9F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFD, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xFB, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, - 0xFF, 0xC1, 0xFF, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, - 0xC0, 0x00, 0x1F, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x1F, 0xFF, - 0xFF, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFE, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, - 0xF8, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, - 0x00, 0x01, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, - 0xC3, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x80, - 0x00, 0x07, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0x3F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xF8, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xE0, 0x00, - 0x01, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xC7, - 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF8, 0x00, 0x00, - 0x7F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF1, 0xFF, - 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, 0x03, - 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0x8F, 0xFF, - 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x1F, - 0xFF, 0xFE, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x7F, 0xFF, - 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, - 0xFF, 0xE1, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, - 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, - 0xFF, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFE, - 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, - 0xF0, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF0, - 0x00, 0x01, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFF, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0x80, - 0x00, 0x3F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x1F, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFE, 0x00, 0x07, 0xFF, - 0xFF, 0xF0, 0x3F, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, - 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF0, 0x00, 0x01, 0xFF, - 0xFF, 0xE1, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, - 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, - 0xFF, 0x8F, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x1F, 0xFF, 0xFE, - 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, - 0xFE, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, - 0xF3, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x80, - 0x00, 0x01, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xDF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFE, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFD, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF7, - 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xDF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, - 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, - 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, - 0xFF, 0xFD, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, - 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xDF, 0xFF, 0xFE, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x3F, 0xFF, 0xFD, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, - 0xFB, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x80, - 0x00, 0x03, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0x9F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0x1F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xE0, 0x00, - 0x01, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0xC7, - 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x00, 0x00, - 0x3F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xFC, 0x3F, - 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, - 0xFE, 0x00, 0x7F, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, - 0xF8, 0x1F, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFC, - 0x00, 0x03, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, - 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xFC, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0x7F, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xE3, - 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, 0x00, 0x00, - 0x1F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x80, 0x00, 0x03, - 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, - 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, - 0xFF, 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xDF, 0xFF, 0xFC, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xDF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, - 0x00, 0x3F, 0xFF, 0xFD, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF7, - 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, 0x00, 0x00, - 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, - 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x80, 0x00, 0x07, - 0xFF, 0xFF, 0x8F, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0x00, 0x01, 0xFF, - 0xFF, 0xC3, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, - 0x80, 0x00, 0x3F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x7F, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xF0, - 0x00, 0x3F, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xF8, - 0x0F, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xE1, - 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x3F, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0x00, - 0x3F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xFF, 0x8F, - 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xFE, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xF3, 0xFF, - 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, - 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, - 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, - 0xFB, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFB, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, - 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, - 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, - 0xF3, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xC0, 0x00, - 0x07, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0x00, 0x07, - 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xFF, 0x0F, 0xFF, - 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 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, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 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, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x3F, - 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFE, 0x00, 0x3F, - 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 0xFC, 0x1F, 0xFF, - 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFC, 0x00, 0x01, 0xFF, - 0xFF, 0xE3, 0xFF, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, - 0x80, 0x00, 0x0F, 0xFF, 0xFE, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, - 0xF8, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, - 0x00, 0x01, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFE, - 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFD, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xDF, - 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, - 0x1F, 0xFF, 0xFD, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xF7, 0xFF, - 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x3F, - 0xFF, 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xDF, 0xFF, 0xFE, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, - 0xFD, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xF7, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0xFF, 0xFF, 0xDF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFD, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xCF, - 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF3, 0xFF, - 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x80, 0x00, 0x1F, - 0xFF, 0xFF, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x7F, 0xFF, - 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, - 0xFF, 0xC3, 0xFF, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, - 0xE0, 0x07, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, - 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFB, 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFC, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF8, 0x7F, 0xF0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0xC0, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF8, - 0x0F, 0xFC, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xF0, 0x00, 0x1F, - 0xFF, 0xFF, 0xFC, 0x00, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xFF, 0xE0, 0x03, - 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x1F, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF0, 0x00, 0x03, - 0xFF, 0xFF, 0xDF, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, - 0x00, 0x00, 0x3F, 0xFF, 0xFD, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, - 0x7F, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xDF, 0xFF, 0xFC, 0x00, 0x00, - 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xFD, 0xFF, 0xFF, - 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, - 0x8F, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, - 0x7F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFC, 0x3F, 0xFF, - 0xFE, 0x00, 0x0F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFF, - 0xC1, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0x87, - 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x7F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x7F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0x80, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x1F, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xE0, - 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, - 0xFC, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, - 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFE, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x7F, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x80, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, - 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x3F, - 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x0F, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xF8, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, - 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x01, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFE, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF3, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF7, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, - 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x80, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, - 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x03, - 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFE, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x07, - 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xFC, 0x00, - 0x0F, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, - 0xE0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, - 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, - 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFF, - 0xC0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x3F, - 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x01, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, - 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFE, - 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFC, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x80, 0x00, 0x00, 0x0F, 0xFF, - 0xEF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xF8, 0x00, 0x00, 0x01, 0xFF, 0xFE, - 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x80, 0x00, 0x00, 0x1F, 0xFF, 0xCF, - 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xF8, 0x00, 0x00, 0x01, 0xFF, 0xFD, 0xFF, - 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0x80, 0x00, 0x00, 0x1F, 0xFF, 0xDF, 0xFF, - 0xFF, 0xFF, 0xF3, 0xFF, 0xFC, 0x00, 0x00, 0x01, 0xFF, 0xFD, 0xFF, 0xFF, - 0xFF, 0xFF, 0x3F, 0xFF, 0xC0, 0x00, 0x00, 0x1F, 0xFF, 0xDF, 0xFF, 0xFF, - 0xFF, 0xF1, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, - 0xFF, 0x1F, 0xFF, 0xC0, 0x00, 0x00, 0x3F, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, - 0xF1, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, - 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xF1, - 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, - 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, - 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, - 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFE, - 0x00, 0x00, 0x07, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xF0, - 0x00, 0x00, 0x7F, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0x00, - 0x00, 0x0F, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, 0xF0, 0x00, - 0x00, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0x00, 0x00, - 0x0F, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, 0xF0, 0x00, 0x00, - 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0x80, 0x00, 0x0F, - 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xF8, 0x00, 0x00, 0xFF, - 0xFC, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0x80, 0x00, 0x1F, 0xFF, - 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFC, - 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0x80, 0x00, 0x1F, 0xFF, 0xC1, - 0xFF, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFC, 0x1F, - 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0x81, 0xFF, - 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xF8, 0x1F, 0xFF, - 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0x81, 0xFF, 0xFF, - 0xFF, 0xFF, 0x81, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, - 0xFF, 0xF8, 0x1F, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xFF, - 0xF8, 0x0F, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, - 0x0F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, - 0xFF, 0xF0, 0x00, 0x7F, 0xFE, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x7F, - 0xFF, 0x00, 0x07, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, - 0xF0, 0x00, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, - 0x00, 0x0F, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xF0, - 0x00, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0x80, - 0x0F, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xF8, 0x00, - 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0x80, 0x0F, - 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xF8, 0x01, 0xFF, - 0xFC, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0x80, 0x1F, 0xFF, - 0xC0, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFC, 0x01, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xC0, 0x1F, 0xFF, 0x80, - 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFC, 0x01, 0xFF, 0xF8, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xC0, 0x3F, 0xFF, 0x80, 0x3F, - 0xFF, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFC, 0x03, 0xFF, 0xF8, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xE0, 0x3F, 0xFF, 0x80, 0x3F, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0xFF, 0xFE, 0x03, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xE0, 0x3F, 0xFF, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0xFF, 0xFE, 0x03, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x07, 0xFF, 0xE0, 0x7F, 0xFF, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x7F, 0xFF, 0x07, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x07, 0xFF, 0xF0, 0x7F, 0xFE, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x7F, 0xFF, 0x07, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x07, 0xFF, 0xF0, 0x7F, 0xFE, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x3F, 0xFF, 0x0F, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x03, - 0xFF, 0xF8, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x3F, - 0xFF, 0x8F, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x03, 0xFF, - 0xF8, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, - 0x8F, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xF9, - 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xDF, - 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFD, 0xFF, - 0xF8, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xDF, 0xFF, - 0x80, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFD, 0xFF, 0xF8, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xDF, 0xFF, 0x80, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x03, 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x3F, 0xFF, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x03, 0xFF, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x3F, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x03, 0xFF, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x1F, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x01, - 0xFF, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x1F, - 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x01, 0xFF, - 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x1F, 0xFF, - 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, - 0xF8, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFF, - 0x80, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFB, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, - 0xFE, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, - 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xF0, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF9, - 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFE, 0x3F, 0xFF, 0xC0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, - 0x1F, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xF0, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE1, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFC, 0x1F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xF0, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0x81, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, - 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, - 0xFF, 0xF0, 0x1F, 0xFF, 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, - 0xF8, 0x1F, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFE, 0x01, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, - 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xC1, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xE0, 0x7F, 0xFF, 0xFF, 0xFF, 0xE0, 0x0F, - 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x1F, 0xFF, - 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xC3, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x0F, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFC, 0x7F, - 0xFF, 0xFF, 0xFF, 0xE0, 0x01, 0xFF, 0xFE, 0x3F, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xCF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x0F, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFD, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFE, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xE0, 0x7F, - 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, - 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0x83, 0xFF, - 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x1F, - 0xFF, 0xFE, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, - 0xFF, 0xF9, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, - 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, - 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, - 0xFE, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, - 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, - 0xFF, 0xF9, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xF3, 0xFF, 0xFF, - 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, - 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, - 0xFE, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF8, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, - 0xE1, 0xFF, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xE0, - 0x00, 0x0F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xFE, - 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xC0, - 0x01, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xE0, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, - 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, - 0xC0, 0x00, 0x1F, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, - 0xFE, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, - 0x00, 0x01, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, - 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0x3F, 0xFF, 0xFC, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF3, - 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0x00, 0x01, - 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, - 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, - 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, - 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFE, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0x00, - 0x01, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, - 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xEF, 0xFF, - 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x00, 0x1F, - 0xFF, 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF3, 0xFF, 0xFF, - 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0xFF, 0xFF, 0xF0, - 0x00, 0x01, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, - 0x8F, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFF, 0xE3, - 0xFF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x00, 0x07, - 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFE, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xE0, 0x1F, - 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0xFF, - 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, - 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xFF, 0x0F, 0xFF, - 0xFF, 0x80, 0x00, 0x1F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x3F, - 0xFF, 0xFC, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x7F, 0xFF, - 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xF9, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, - 0xFF, 0xF3, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, - 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0x9F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, - 0xFF, 0xF3, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, - 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0x9F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, - 0xFC, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, - 0x00, 0x01, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, - 0xC1, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xC0, - 0x00, 0x1F, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xFC, - 0x0F, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xE0, - 0x07, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xFF, - 0xF0, 0xFF, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xE0, - 0x00, 0x07, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, - 0xC7, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF8, 0x00, - 0x00, 0x3F, 0xFF, 0xFC, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF9, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xC0, 0x00, - 0x01, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xCF, - 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x7F, - 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xF3, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x01, - 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xDF, 0xFF, - 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFD, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, - 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, - 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0x9F, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, - 0xFC, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF9, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, - 0xE7, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF8, 0x00, - 0x00, 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF1, - 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, - 0x03, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFF, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFE, 0x00, 0x00, - 0x7F, 0xFF, 0xF8, 0x3F, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xF0, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xFF, - 0xE0, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xE0, - 0x00, 0x07, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, - 0x87, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x0F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFC, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF8, 0x00, - 0x00, 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF1, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, - 0x01, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0x8F, - 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x7F, - 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xF3, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x80, 0x00, 0x01, - 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x9F, 0xFF, - 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, - 0xFF, 0xFE, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, - 0xFF, 0xF3, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, - 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xDF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, - 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFD, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, - 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xDF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xBF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, - 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFD, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xEF, - 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xDF, 0xFF, 0xFE, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x7F, - 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x3F, 0xFF, 0xFD, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x01, - 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xDF, 0xFF, - 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFD, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, - 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, - 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xDF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xBF, 0xFF, 0xFC, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, - 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFD, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, - 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xDF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x07, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x80, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFE, 0x01, 0xFF, - 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xC0, 0x07, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, - 0xF8, 0x00, 0x1F, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, - 0xF8, 0x3F, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xC0, - 0x00, 0x0F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xF0, - 0xFF, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x80, 0x00, - 0x0F, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xF1, 0xFF, - 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0x8F, 0xFF, 0xFE, 0x00, 0x00, 0x1F, - 0xFF, 0xFC, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, - 0x80, 0x00, 0x03, 0xFF, 0xFF, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, - 0xF8, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x00, - 0x00, 0x07, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xF9, - 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x00, 0x00, - 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF3, 0xFF, - 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0x9F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, - 0xFF, 0xFC, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, - 0xF9, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, - 0x00, 0x0F, 0xFF, 0xFE, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xF3, - 0xFF, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x80, 0x00, - 0x1F, 0xFF, 0xFC, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xE3, 0xFF, - 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, - 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xE0, - 0x00, 0x07, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xC0, 0x00, - 0x07, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x7F, - 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0x80, 0x00, 0x07, - 0xFF, 0xFF, 0xDF, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xBF, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFD, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0x80, 0x00, - 0x03, 0xFF, 0xFF, 0xDF, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, - 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, - 0xFE, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xF1, 0xFF, 0xFF, 0xC0, - 0x00, 0x03, 0xFF, 0xFF, 0x8F, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x7F, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xC0, 0x00, - 0x0F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x7F, - 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xE0, 0x00, 0x7F, - 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, - 0xFF, 0xE7, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, - 0x00, 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, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, - 0xFF, 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xDF, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xBF, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, - 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, - 0xFD, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, - 0xEF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0x9F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFE, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF8, 0x00, - 0x00, 0x7F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0xFF, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xE0, 0x00, - 0x07, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xFF, 0x07, - 0xFF, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xE0, 0x01, - 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xF0, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFD, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xFB, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x8F, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, - 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x7F, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF1, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE1, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFE, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x1F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x3F, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xC0, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x07, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x0F, 0xFF, - 0xFC, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x0F, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0x80, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, - 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x3F, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, - 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x1F, - 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0xC0, - 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, - 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x07, - 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFC, 0x00, - 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, - 0xE0, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x7F, - 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xE0, 0x00, - 0x03, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFE, - 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x03, 0xFF, - 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, - 0x3F, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xC0, - 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, - 0xF8, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x07, - 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFC, 0x00, - 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, - 0xC0, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x7F, - 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, - 0x07, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFC, - 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, - 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, - 0x7F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xE0, - 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, - 0x80, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, - 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xF8, - 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x1F, - 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0x80, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x1F, - 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xE0, 0x00, - 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, - 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x03, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xC0, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, - 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xC0, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xFF, 0xFE, - 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x03, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xF0, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, - 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x7F, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x03, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x07, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFC, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x7F, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xE1, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xC3, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x87, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x0F, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFE, 0x3F, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF9, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xF3, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xE7, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xCF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xDF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xBF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0x7F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF7, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x07, 0xFF, - 0xFE, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xE7, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, - 0x00, 0x07, 0xFF, 0xFE, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE7, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x7F, 0xFF, 0xE0, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE7, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x3F, 0xFF, - 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE3, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, - 0xFE, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xC3, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, - 0x00, 0x0F, 0xFF, 0xFC, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x3F, 0xFF, 0xF0, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x1F, 0xFF, - 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xC1, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, - 0xFC, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x0F, 0xFF, 0xF8, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x1F, 0xFF, 0xF8, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x80, - 0x00, 0x01, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x0F, 0xFF, - 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x80, - 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, - 0xF8, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xE0, 0x00, 0x01, - 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x1F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x03, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFC, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xC0, - 0x00, 0x03, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, - 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFF, 0x00, - 0x7F, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, - 0xF0, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x00, 0x03, - 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x3F, 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xF0, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x00, - 0x7F, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xE0, - 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xE0, 0x03, 0xFF, - 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0xFE, 0x00, - 0x3F, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, - 0xE0, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xF8, 0x00, 0x03, - 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x7F, 0xFF, 0xE0, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x00, 0x00, - 0xFF, 0xFE, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xF0, - 0x00, 0x0F, 0xFF, 0xEF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x01, 0xFF, - 0xFF, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xFC, 0x00, - 0x1F, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xCF, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, - 0xC0, 0x01, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFC, 0xFF, 0xFC, 0x00, 0x07, - 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xCF, 0xFF, 0xC0, - 0x00, 0x7F, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFC, 0xFF, - 0xFC, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, - 0xCF, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0x00, 0x01, - 0xFF, 0xFC, 0x7F, 0xFE, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xF8, - 0x00, 0x1F, 0xFF, 0x87, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0xFF, - 0xFF, 0x80, 0x01, 0xFF, 0xF8, 0x7F, 0xFE, 0x00, 0x0F, 0xFF, 0xF8, 0x00, - 0x0F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0x87, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, - 0x80, 0x00, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xF8, 0x7F, 0xFE, 0x00, 0x0F, - 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0x87, 0xFF, 0xE0, - 0x00, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xF8, 0x7F, - 0xFF, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, - 0x83, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0x80, 0x03, - 0xFF, 0xF0, 0x3F, 0xFF, 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xF8, - 0x00, 0x3F, 0xFF, 0x03, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x7F, - 0xFF, 0xC0, 0x07, 0xFF, 0xF0, 0x3F, 0xFF, 0x00, 0x1F, 0xFF, 0xF0, 0x00, - 0x07, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x03, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, - 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x07, 0xFF, 0xF0, 0x3F, 0xFF, 0x00, 0x1F, - 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x03, 0xFF, 0xF8, - 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x07, 0xFF, 0xF0, 0x1F, - 0xFF, 0x80, 0x1F, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x7F, 0xFE, - 0x01, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x07, - 0xFF, 0xE0, 0x1F, 0xFF, 0x80, 0x1F, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFC, - 0x00, 0xFF, 0xFE, 0x01, 0xFF, 0xF8, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x3F, - 0xFF, 0xC0, 0x0F, 0xFF, 0xE0, 0x1F, 0xFF, 0x80, 0x1F, 0xFF, 0xE0, 0x00, - 0x03, 0xFF, 0xFE, 0x00, 0xFF, 0xFE, 0x01, 0xFF, 0xF8, 0x01, 0xFF, 0xFE, - 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x0F, 0xFF, 0xE0, 0x1F, 0xFF, 0xC0, 0x1F, - 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0xFF, 0xFC, 0x00, 0xFF, 0xFC, - 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x0F, 0xFF, 0xC0, 0x0F, - 0xFF, 0xC0, 0x3F, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0xFF, 0xFC, - 0x00, 0xFF, 0xFC, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x1F, - 0xFF, 0xC0, 0x0F, 0xFF, 0xC0, 0x3F, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFE, - 0x01, 0xFF, 0xFC, 0x00, 0xFF, 0xFC, 0x03, 0xFF, 0xFC, 0x00, 0x00, 0x1F, - 0xFF, 0xE0, 0x1F, 0xFF, 0xC0, 0x0F, 0xFF, 0xC0, 0x3F, 0xFF, 0xC0, 0x00, - 0x01, 0xFF, 0xFE, 0x01, 0xFF, 0xFC, 0x00, 0xFF, 0xFE, 0x03, 0xFF, 0xFC, - 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x1F, 0xFF, 0x80, 0x07, 0xFF, 0xE0, 0x3F, - 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x01, 0xFF, 0xF8, 0x00, 0x7F, 0xFE, - 0x03, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x1F, 0xFF, 0x80, 0x07, - 0xFF, 0xE0, 0x3F, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x03, 0xFF, 0xF8, - 0x00, 0x7F, 0xFE, 0x03, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xF0, 0x3F, - 0xFF, 0x80, 0x07, 0xFF, 0xE0, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, - 0x03, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xF0, 0x3F, 0xFF, 0x80, 0x07, 0xFF, 0xF0, 0x7F, 0xFF, 0x80, 0x00, - 0x00, 0xFF, 0xFF, 0x03, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0x07, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0xF0, 0x3F, 0xFF, 0x00, 0x03, 0xFF, 0xF0, 0x7F, - 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, - 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x7F, 0xFF, 0x00, 0x03, - 0xFF, 0xF0, 0x7F, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0x87, 0xFF, 0xF0, - 0x00, 0x3F, 0xFF, 0x07, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x7F, - 0xFF, 0x00, 0x03, 0xFF, 0xF8, 0x7F, 0xFF, 0x80, 0x00, 0x00, 0x7F, 0xFF, - 0x87, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0x87, 0xFF, 0xF8, 0x00, 0x00, 0x07, - 0xFF, 0xF8, 0x7F, 0xFE, 0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0x87, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0x8F, 0xFF, 0xF0, - 0x00, 0x00, 0x07, 0xFF, 0xF8, 0x7F, 0xFE, 0x00, 0x01, 0xFF, 0xF8, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x8F, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, - 0x8F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xF8, 0xFF, 0xFE, 0x00, 0x01, - 0xFF, 0xF8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xCF, 0xFF, 0xE0, - 0x00, 0x1F, 0xFF, 0xCF, 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xFC, 0xFF, - 0xFE, 0x00, 0x01, 0xFF, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xCF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xCF, 0xFF, 0xF0, 0x00, 0x00, 0x03, - 0xFF, 0xFC, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xCF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xCF, 0xFF, 0xE0, - 0x00, 0x00, 0x03, 0xFF, 0xFD, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFC, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xDF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, - 0xDF, 0xFF, 0xE0, 0x00, 0x00, 0x03, 0xFF, 0xFD, 0xFF, 0xFC, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xDF, 0xFF, 0x80, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x7F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, - 0xFE, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x7F, 0xFF, 0xE0, - 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, - 0xFC, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x3F, 0xFF, 0xF0, - 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, - 0xF8, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x1F, 0xFF, 0xF0, - 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, - 0xF0, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x0F, 0xFF, 0xF8, - 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, - 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, - 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, - 0xC0, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFE, - 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, - 0xC0, 0x01, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, - 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, - 0x80, 0x00, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, - 0x80, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, - 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, - 0xC0, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x07, 0xFF, 0xFE, - 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, - 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, - 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, - 0xF0, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x0F, 0xFF, 0xF8, - 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, - 0xF8, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x1F, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, - 0xFC, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x3F, 0xFF, 0xF0, - 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x07, 0xFF, - 0xFE, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x7F, 0xFF, 0xE0, - 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x7F, 0xFF, 0xC0, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xFF, - 0xFE, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, - 0xFC, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x7F, 0xFF, 0xE0, - 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, - 0xFC, 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x3F, 0xFF, 0xF0, - 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, - 0xF8, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x1F, 0xFF, 0xF0, - 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, - 0xF0, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x0F, 0xFF, 0xF8, - 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, - 0xE0, 0x07, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xFF, 0xFC, - 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, - 0xE0, 0x03, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFE, - 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, - 0xC0, 0x01, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, - 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, - 0x80, 0x01, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, - 0x80, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, - 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, - 0xC0, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x07, 0xFF, 0xFE, - 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, - 0xE0, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFE, - 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, - 0xF0, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x1F, 0xFF, 0xFC, - 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, - 0xF8, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x3F, 0xFF, 0xF8, - 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, - 0xFC, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x7F, 0xFF, 0xF0, - 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, - 0xFE, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x7F, 0xFF, 0xE0, - 0x00, 0x00, 0x03, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0x87, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xF8, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xF0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, - 0xF8, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xF0, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFE, - 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xC0, - 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFE, - 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, - 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, - 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xF0, - 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x03, 0xFF, - 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x01, - 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0x80, - 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x7F, 0xFF, - 0xF0, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, - 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x1F, 0xFF, 0xFC, 0x00, - 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFE, - 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, - 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, - 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xC0, - 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, - 0xFF, 0x80, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x0F, - 0xFF, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xF8, 0x00, - 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, - 0xFC, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x01, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x7F, 0xFF, - 0xF0, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, - 0xF0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0x83, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x07, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFE, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, - 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF1, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF7, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xEF, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xDF, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, - 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFE, 0x00, 0x07, - 0xFF, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xFF, 0x00, - 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, - 0xC0, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, - 0xFF, 0x80, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x7F, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xE0, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x07, - 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xFE, 0x00, - 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, - 0xFC, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, - 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFE, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x03, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, - 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0xFF, - 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xC0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, - 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, - 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x3F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, - 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFE, - 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, - 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x03, - 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, - 0xF8, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0xFF, - 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xE0, 0x00, - 0x1F, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, - 0x00, - - // Pound sign (start 60325) - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x80, 0x0F, - 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xE0, 0x00, - 0x0F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xE0, - 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xC0, - 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x3F, 0xFF, - 0xF0, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, - 0xFF, 0xFC, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x1F, 0xFF, 0xF8, 0x00, 0x00, - 0x07, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, - 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFC, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xFF, - 0xE0, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFC, 0x07, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x1F, - 0xFF, 0xF0, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x03, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x7F, 0xFF, 0xF0, 0x00, 0x00, - 0x0F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x01, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x3F, 0xFF, 0xF8, 0x00, - 0x00, 0x07, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, - 0x80, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFE, - 0x00, 0x00, 0x03, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, - 0xFF, 0xC0, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFE, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - // yen-sign (start 61607) - 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE3, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xFE, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x1F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x3F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0xFF, - 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xE0, 0x00, - 0x00, 0x1F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, - 0xF8, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, - 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x07, 0xFF, 0xFF, 0x00, 0x00, - 0x03, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFE, - 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, - 0x7F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xC0, - 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, - 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, - 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xF8, 0x00, - 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFF, - 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x01, 0xFF, - 0xFF, 0x80, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, - 0x1F, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xF8, - 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, - 0xF0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, - 0xFF, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xC0, - 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFE, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x00, - 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x3F, - 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x0F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x1F, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0xC0, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x81, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFF, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFE, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFE, 0x3F, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x7F, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xF3, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF7, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xEF, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xDF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 - }; +//unsigned int antonio_90_c_len = 6 +const uint8_t Antonio_SemiBold90pt7bBitmaps_Gzip[] = { + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xed, 0x7d, + 0x4b, 0x8e, 0xde, 0x38, 0x97, 0x25, 0x05, 0x15, 0xa0, 0x1e, 0x34, 0xa0, + 0x1d, 0x94, 0x7a, 0x19, 0x35, 0x68, 0xb4, 0x6a, 0x29, 0xbd, 0x84, 0x5a, + 0x40, 0xa3, 0x28, 0xc3, 0x03, 0x0f, 0xbd, 0x04, 0x2f, 0x25, 0x65, 0x78, + 0xe0, 0x61, 0x2c, 0xc1, 0x4a, 0x78, 0xe0, 0x61, 0xca, 0xf0, 0xc0, 0x32, + 0x52, 0x16, 0x5b, 0xbc, 0xe7, 0x1c, 0x92, 0xfa, 0x1e, 0xf1, 0x48, 0xdb, + 0xe9, 0xf0, 0x9f, 0xf1, 0x01, 0x11, 0x94, 0x48, 0xf1, 0xf2, 0x75, 0x79, + 0xdf, 0xa2, 0x5c, 0x08, 0x5f, 0x43, 0xf8, 0x1c, 0xc2, 0xbb, 0x10, 0xfc, + 0xdd, 0x97, 0x4b, 0x08, 0xef, 0x43, 0x78, 0x19, 0xb6, 0xfe, 0x5e, 0x97, + 0xaf, 0x43, 0x68, 0xc2, 0xda, 0x85, 0xd9, 0xdf, 0x7d, 0x39, 0x86, 0xad, + 0x0e, 0x4b, 0x1b, 0xa6, 0x3e, 0x0c, 0xf7, 0xb8, 0xac, 0xc2, 0xdc, 0x84, + 0xb1, 0x0b, 0xce, 0xaf, 0xf7, 0xb9, 0xac, 0xc3, 0xd0, 0x6e, 0xae, 0x5f, + 0x5c, 0x98, 0xee, 0x73, 0xd9, 0xac, 0xae, 0x9b, 0x9d, 0x1f, 0xab, 0xe0, + 0x6e, 0xbf, 0x74, 0xf7, 0xfa, 0x35, 0xf7, 0x9d, 0xdf, 0xb3, 0xcb, 0x31, + 0xf0, 0xf7, 0x5b, 0xd8, 0x42, 0xf8, 0x12, 0xc2, 0x87, 0x10, 0x5e, 0x85, + 0xcd, 0xc7, 0xcb, 0xb7, 0x21, 0x74, 0x61, 0xf5, 0xe1, 0x63, 0xbe, 0xfc, + 0x3d, 0x84, 0x17, 0x61, 0xeb, 0xc2, 0x92, 0x2f, 0xcb, 0x59, 0xee, 0x23, + 0xbc, 0x8b, 0xf3, 0xb9, 0xd6, 0x61, 0x6e, 0xc3, 0xd8, 0x07, 0x97, 0x2e, + 0x37, 0x17, 0x96, 0x3a, 0x4c, 0x6d, 0x18, 0x74, 0xd9, 0x04, 0xd7, 0xad, + 0xce, 0xcf, 0x55, 0x18, 0x75, 0x19, 0x47, 0xb7, 0x83, 0x70, 0x3b, 0x8c, + 0xfd, 0xca, 0x07, 0x57, 0x85, 0x75, 0xbf, 0xd8, 0x01, 0x5b, 0xb6, 0x73, + 0x5d, 0x18, 0x9d, 0xdf, 0xe2, 0x63, 0x7b, 0xc1, 0x0e, 0xd9, 0x66, 0xe3, + 0xae, 0xe7, 0x83, 0x3d, 0xbf, 0x59, 0x36, 0x9e, 0xef, 0xec, 0xf9, 0xfe, + 0x9e, 0xcf, 0xcf, 0x96, 0x6d, 0xcf, 0x3b, 0x7b, 0xbe, 0xba, 0xef, 0xf3, + 0x43, 0xcc, 0xc6, 0xf3, 0x8d, 0x3d, 0xdf, 0xde, 0xf3, 0xf9, 0xd5, 0xb2, + 0xf1, 0x7c, 0x6f, 0xcf, 0xfb, 0x7b, 0x3e, 0x9f, 0x26, 0x63, 0xb3, 0x66, + 0x9d, 0xcd, 0xd2, 0x7d, 0x9e, 0xcf, 0x93, 0x31, 0x5b, 0xb3, 0xce, 0x66, + 0xe9, 0x3e, 0xcf, 0xe7, 0xc9, 0x18, 0xf2, 0xe2, 0x1c, 0x9f, 0xf7, 0x42, + 0xbc, 0x37, 0xba, 0xd8, 0x71, 0x89, 0xbf, 0x59, 0x17, 0x3b, 0x86, 0xf1, + 0xb7, 0xf6, 0xba, 0xfa, 0x3d, 0x15, 0xb6, 0xba, 0x58, 0x6e, 0x05, 0xf6, + 0x97, 0x16, 0xb3, 0xf9, 0xcb, 0x8b, 0xd9, 0xff, 0xd5, 0xc5, 0x7c, 0xd8, + 0xe2, 0x6c, 0x17, 0x17, 0xc7, 0xdf, 0xb5, 0x38, 0xdf, 0x75, 0x66, 0x6f, + 0x03, 0x36, 0x3d, 0x9a, 0x9d, 0xf6, 0x8b, 0xee, 0x9c, 0xf1, 0xda, 0xce, + 0xb9, 0x0f, 0x59, 0x13, 0x19, 0x7c, 0xf8, 0x64, 0x0f, 0xdf, 0x32, 0xd9, + 0x36, 0xb9, 0x93, 0x25, 0xed, 0x6a, 0x49, 0x65, 0x00, 0xf7, 0x47, 0x8c, + 0x92, 0xbb, 0x86, 0x4f, 0x59, 0xb5, 0x1d, 0xea, 0x62, 0x49, 0x1d, 0x7e, + 0x50, 0x55, 0x9b, 0x87, 0xfd, 0x19, 0x1b, 0xc2, 0x9e, 0xc4, 0xec, 0x2a, + 0xa2, 0xa9, 0x4d, 0xa2, 0x65, 0x47, 0x84, 0xdd, 0xe2, 0xe4, 0xda, 0x6d, + 0x1d, 0x70, 0x4b, 0x14, 0x36, 0x6c, 0x5e, 0x51, 0x18, 0xc6, 0x0a, 0x28, + 0x4e, 0xd2, 0x35, 0x20, 0x77, 0xa9, 0x81, 0xef, 0xcc, 0x9d, 0xb1, 0x3b, + 0x76, 0xce, 0x17, 0x96, 0x9d, 0x2b, 0x8f, 0xde, 0x9e, 0xdf, 0x79, 0x63, + 0x88, 0x4c, 0xfa, 0x79, 0xb0, 0x69, 0xdc, 0x59, 0x66, 0x9c, 0xd7, 0xad, + 0x45, 0x53, 0xaf, 0x63, 0x6e, 0x17, 0xf7, 0xce, 0x12, 0x3b, 0xb0, 0x6f, + 0xa6, 0xd8, 0xad, 0x8f, 0xb1, 0x03, 0x8d, 0x09, 0x3a, 0xf1, 0xa1, 0xb7, + 0x31, 0xb7, 0x8b, 0x42, 0x8f, 0xf5, 0xb2, 0x8b, 0x63, 0xf0, 0xe1, 0x53, + 0x1c, 0x52, 0x1b, 0xf9, 0xf5, 0x1c, 0x07, 0x76, 0x83, 0x87, 0xbe, 0x1c, + 0x1f, 0x7a, 0x8f, 0x87, 0x56, 0x3e, 0xf4, 0xf2, 0x14, 0xbe, 0x91, 0x85, + 0x37, 0xe8, 0xc4, 0xe2, 0xd1, 0x89, 0x36, 0x18, 0x8d, 0xfe, 0x3d, 0x18, + 0x06, 0x5b, 0xff, 0x2b, 0xeb, 0xbf, 0xcd, 0xa8, 0x0f, 0x36, 0xed, 0x0d, + 0x26, 0xd6, 0x05, 0x2c, 0x7e, 0x8b, 0xdb, 0x8a, 0xb7, 0x5d, 0x9a, 0x76, + 0xbb, 0xed, 0x51, 0x37, 0x4e, 0x17, 0x41, 0x00, 0x49, 0x6f, 0xbb, 0x6d, + 0x79, 0x1b, 0x1e, 0x72, 0x7b, 0x15, 0xf2, 0xc6, 0xdb, 0xe9, 0x78, 0x3b, + 0xe2, 0x76, 0x3d, 0xde, 0x2e, 0xbc, 0x1d, 0x70, 0x7b, 0xfb, 0xb0, 0x47, + 0xdc, 0x2e, 0x1c, 0xf6, 0x2e, 0x9e, 0xc6, 0x59, 0xf8, 0x18, 0x8c, 0xe2, + 0x6c, 0x5c, 0xd7, 0x0f, 0xb1, 0xf6, 0x8e, 0x0b, 0xb1, 0x76, 0x1b, 0xa5, + 0x2c, 0x9b, 0x77, 0x5b, 0xc1, 0x0e, 0x2b, 0xb8, 0x3f, 0xf4, 0x47, 0x84, + 0xd9, 0x47, 0xe1, 0x6c, 0x8c, 0xed, 0xfc, 0x86, 0xc5, 0xff, 0x8c, 0x75, + 0xdd, 0xb8, 0xae, 0xef, 0xb0, 0xae, 0x7f, 0x62, 0x5d, 0x03, 0xd7, 0xf5, + 0xa4, 0xea, 0x65, 0xf8, 0x37, 0xf1, 0x21, 0x93, 0xee, 0xc6, 0x58, 0xb5, + 0x37, 0xa1, 0x29, 0x2e, 0x7e, 0x5c, 0xed, 0x05, 0x78, 0x19, 0x17, 0x3f, + 0xe6, 0xda, 0xe2, 0xef, 0xa3, 0x8a, 0x8b, 0xdf, 0x47, 0xb9, 0x2e, 0x2c, + 0x7b, 0x32, 0x01, 0xd1, 0x23, 0x76, 0x1b, 0xde, 0x93, 0xdc, 0x73, 0x37, + 0x54, 0xcc, 0xc5, 0x36, 0x18, 0xb1, 0x39, 0x66, 0x6c, 0xa4, 0x0d, 0xdb, + 0x6b, 0x6f, 0xaa, 0x2f, 0x76, 0xdb, 0x82, 0x3d, 0xb8, 0x62, 0x67, 0x06, + 0x2e, 0xe4, 0x90, 0x17, 0xa3, 0xc2, 0xdd, 0x4f, 0x26, 0x25, 0x57, 0xaa, + 0x62, 0xcd, 0x0f, 0x3f, 0x76, 0xfb, 0x34, 0x4f, 0xf4, 0xb1, 0x03, 0xf2, + 0x24, 0x02, 0x64, 0x50, 0x05, 0xc6, 0x93, 0x38, 0x59, 0x77, 0x78, 0xd1, + 0x07, 0xce, 0x47, 0x6c, 0x36, 0x08, 0x08, 0x91, 0xde, 0xca, 0xd1, 0x5c, + 0x4b, 0xda, 0x55, 0x36, 0x82, 0x09, 0x1f, 0x0f, 0x8d, 0x54, 0x21, 0x57, + 0x4e, 0x8d, 0x84, 0xa2, 0xb2, 0x1a, 0xe9, 0x43, 0x6e, 0xb9, 0x4f, 0x03, + 0xce, 0x95, 0xd5, 0x48, 0x43, 0xba, 0x78, 0xd2, 0xc8, 0xc6, 0xdd, 0x53, + 0x36, 0xb2, 0x8b, 0xf6, 0xac, 0x94, 0x1b, 0x59, 0xd2, 0x2c, 0xe6, 0x91, + 0x18, 0x56, 0x9e, 0x8c, 0xc4, 0x68, 0xe5, 0x78, 0xd2, 0x48, 0xc4, 0xed, + 0xf9, 0xd0, 0x88, 0x37, 0xf4, 0x5f, 0x4f, 0xa6, 0xcb, 0x76, 0xc8, 0xa1, + 0x91, 0x06, 0x9b, 0x68, 0x2a, 0x1b, 0xb1, 0x67, 0x5a, 0x40, 0x2f, 0xd6, + 0x64, 0x44, 0xeb, 0x87, 0x35, 0x99, 0x23, 0xf4, 0xa1, 0x6c, 0xa4, 0x05, + 0x2a, 0x4f, 0x65, 0x23, 0x35, 0x78, 0xcb, 0x52, 0x36, 0x62, 0xf5, 0x08, + 0x30, 0x35, 0x62, 0xf5, 0x00, 0xb0, 0xd6, 0x3a, 0x94, 0x00, 0xd5, 0x48, + 0x09, 0x50, 0x8d, 0x94, 0x00, 0x53, 0x23, 0x05, 0xc0, 0xd4, 0x48, 0x01, + 0xb0, 0x52, 0x23, 0x25, 0x40, 0x35, 0x52, 0x02, 0x4c, 0x8d, 0x14, 0x00, + 0x53, 0x23, 0x05, 0xc0, 0xd4, 0x48, 0x01, 0x30, 0x35, 0x52, 0x02, 0x4c, + 0x8d, 0x14, 0x00, 0x53, 0x23, 0x05, 0xc0, 0xd4, 0x48, 0x01, 0x30, 0x35, + 0x52, 0x00, 0xcc, 0x8d, 0x14, 0x00, 0x53, 0x23, 0x05, 0xc0, 0xd4, 0x48, + 0x01, 0x30, 0x35, 0x52, 0x00, 0xcc, 0x8d, 0x64, 0x80, 0xb9, 0x91, 0x02, + 0x60, 0x6a, 0xa4, 0x00, 0x88, 0x46, 0xfe, 0xfb, 0x00, 0xd0, 0x1a, 0x69, + 0x41, 0xf7, 0x04, 0xd0, 0x1a, 0xe9, 0x20, 0x5c, 0x08, 0xa0, 0x35, 0xd2, + 0x81, 0x6c, 0x26, 0x80, 0xa0, 0xfc, 0xf1, 0xc1, 0x0c, 0xb0, 0x07, 0xf1, + 0xde, 0x33, 0x32, 0xc0, 0x88, 0xe2, 0xb6, 0x11, 0xe7, 0x0c, 0xb0, 0x01, + 0xe3, 0x31, 0x71, 0x44, 0x00, 0x2b, 0xf0, 0xa6, 0x60, 0xaa, 0xbf, 0x00, + 0xc6, 0x46, 0x40, 0xbf, 0x33, 0xc0, 0xde, 0x44, 0x95, 0x58, 0x39, 0x03, + 0xec, 0x4c, 0xe4, 0x8b, 0xbf, 0x37, 0x09, 0x60, 0x03, 0x9e, 0x11, 0x4c, + 0x1f, 0x20, 0xc0, 0x2a, 0xd1, 0xfa, 0x2d, 0x03, 0x84, 0x08, 0x11, 0x7f, + 0x2f, 0x13, 0x40, 0x34, 0x12, 0xa5, 0xa5, 0xf7, 0x09, 0x20, 0x1a, 0x59, + 0xf7, 0xb2, 0x35, 0x01, 0x6c, 0x4c, 0xc5, 0x32, 0xa0, 0x09, 0x20, 0x1b, + 0x89, 0x37, 0x37, 0x09, 0x20, 0xee, 0xa3, 0x24, 0xf3, 0x29, 0x01, 0xec, + 0x8d, 0x0d, 0x9b, 0xb0, 0x93, 0x00, 0x76, 0x26, 0xd7, 0x18, 0x73, 0xfd, + 0x4d, 0x00, 0xd5, 0xc8, 0xfe, 0xf0, 0x1f, 0x02, 0xc8, 0xe9, 0x8a, 0x90, + 0xfe, 0x4c, 0x00, 0xc1, 0xc8, 0x8d, 0x2a, 0x04, 0x11, 0x87, 0xde, 0x1a, + 0x35, 0xaa, 0xf0, 0x4a, 0xc4, 0x01, 0x6b, 0xb2, 0xc6, 0xc2, 0x0f, 0x48, + 0x26, 0x6b, 0x84, 0x00, 0xbf, 0x52, 0xa4, 0xc3, 0xc2, 0x47, 0x80, 0x55, + 0x64, 0xe6, 0x24, 0x5f, 0x89, 0xb6, 0xf9, 0x9d, 0xdf, 0x93, 0x7c, 0xf5, + 0x2a, 0xec, 0x76, 0x91, 0x80, 0x75, 0x12, 0x6d, 0x6b, 0x30, 0x5f, 0xbd, + 0x35, 0xba, 0x24, 0x80, 0x3d, 0x24, 0x38, 0x61, 0x97, 0x01, 0xbc, 0x31, + 0xa5, 0x62, 0xd3, 0xb0, 0x0d, 0x60, 0x14, 0x14, 0x6a, 0x00, 0x18, 0x13, + 0x40, 0x6f, 0xf2, 0xed, 0xa4, 0x7a, 0x56, 0x20, 0x16, 0xd0, 0x68, 0xb1, + 0xf6, 0x82, 0xb7, 0x64, 0x01, 0x15, 0x16, 0xcb, 0x00, 0xce, 0xe2, 0x29, + 0x58, 0x2c, 0x00, 0x14, 0x4f, 0xb1, 0x7d, 0x42, 0x80, 0x0d, 0x99, 0x94, + 0xc1, 0x52, 0x4b, 0x65, 0x23, 0x02, 0xd8, 0x43, 0x5e, 0xa8, 0x80, 0x62, + 0x00, 0xd8, 0x90, 0xf7, 0x18, 0x8a, 0x11, 0xa0, 0x63, 0xc3, 0xd6, 0x88, + 0x00, 0x76, 0x90, 0x2e, 0xec, 0x56, 0x00, 0x6b, 0x74, 0xa6, 0xc1, 0xc6, + 0x00, 0x40, 0x63, 0x7b, 0x23, 0x77, 0xbc, 0x00, 0xd6, 0xe0, 0xa2, 0x69, + 0xa7, 0x59, 0x41, 0x9f, 0xf6, 0x49, 0x02, 0xb8, 0x17, 0xac, 0x8e, 0x57, + 0x09, 0x20, 0x7e, 0x20, 0x2b, 0x02, 0x88, 0x5f, 0x45, 0xfa, 0x40, 0x80, + 0x99, 0x12, 0x15, 0x00, 0x49, 0x89, 0xc6, 0x33, 0x80, 0xad, 0x95, 0x1e, + 0x01, 0xa2, 0xf4, 0x08, 0xb0, 0x22, 0x55, 0x3b, 0x00, 0x94, 0x2a, 0x54, + 0x02, 0x04, 0xed, 0x3a, 0x02, 0x44, 0x23, 0x47, 0x80, 0xa8, 0x71, 0x04, + 0x58, 0x91, 0x16, 0x1f, 0x00, 0x4a, 0x8c, 0x2b, 0x01, 0xf6, 0x54, 0x87, + 0x4b, 0x80, 0x2d, 0x25, 0xf4, 0x12, 0x60, 0x43, 0x05, 0xb4, 0x04, 0x58, + 0x49, 0x66, 0x2f, 0x01, 0x8a, 0x25, 0x95, 0x00, 0x7b, 0x4a, 0xf1, 0x25, + 0x40, 0x34, 0x72, 0x04, 0xd8, 0x48, 0xea, 0x2f, 0x00, 0x56, 0x62, 0xa4, + 0x25, 0x40, 0x31, 0xd2, 0x12, 0x60, 0x2f, 0xe9, 0x14, 0x02, 0x4b, 0xd1, + 0x08, 0x89, 0x43, 0x38, 0x34, 0xd2, 0x15, 0x22, 0x83, 0x1a, 0x69, 0x44, + 0x15, 0x8a, 0x46, 0x4a, 0x19, 0x24, 0x15, 0x7a, 0x93, 0x96, 0xb7, 0x43, + 0x23, 0x24, 0x45, 0x43, 0xd9, 0x08, 0x49, 0xd1, 0x54, 0x36, 0x42, 0x4a, + 0xb2, 0x94, 0x8d, 0x90, 0x4a, 0x24, 0x69, 0x66, 0x02, 0xc0, 0x2c, 0x76, + 0xa9, 0x91, 0x28, 0x62, 0x55, 0x59, 0x82, 0x44, 0x05, 0x6f, 0x7a, 0xc1, + 0xb1, 0x91, 0x7d, 0x7b, 0x0d, 0xe1, 0xa4, 0x91, 0xba, 0x94, 0x2a, 0xd5, + 0x2b, 0xb0, 0x80, 0x43, 0x23, 0xd2, 0x16, 0x0e, 0x8d, 0x80, 0x2a, 0x1c, + 0x1b, 0x21, 0x93, 0x3a, 0x34, 0x22, 0x25, 0xfd, 0xd0, 0x48, 0x73, 0xa1, + 0x11, 0x57, 0x88, 0xb3, 0x69, 0xe8, 0x5d, 0x6e, 0xb8, 0x10, 0x89, 0x52, + 0xc3, 0xa9, 0x91, 0x52, 0x5a, 0x4f, 0x0b, 0xd6, 0x64, 0x21, 0x3c, 0xef, + 0x2c, 0x9f, 0xf2, 0xf2, 0xaf, 0xbe, 0xa0, 0x12, 0x24, 0x55, 0xa2, 0x2e, + 0xe4, 0x8d, 0xa2, 0x07, 0x03, 0x3b, 0xaf, 0x2b, 0xaf, 0x8e, 0x56, 0xa9, + 0xcb, 0x4d, 0xba, 0xca, 0xc3, 0xf0, 0x1a, 0x64, 0x95, 0x86, 0x5b, 0xa7, + 0xab, 0x36, 0x4d, 0x4b, 0x9f, 0xae, 0xbc, 0xd6, 0x28, 0x56, 0xf0, 0x34, + 0x13, 0x45, 0x5b, 0x3c, 0x36, 0x79, 0x20, 0xe1, 0xea, 0x92, 0x1d, 0xaa, + 0x0f, 0x32, 0x0a, 0x79, 0xd3, 0x64, 0x27, 0x27, 0x96, 0x3b, 0x5a, 0xd5, + 0x01, 0x56, 0xaa, 0x06, 0x0c, 0xca, 0x71, 0x77, 0x90, 0xd2, 0x2d, 0xb4, + 0x2c, 0xf5, 0xc6, 0xb5, 0x16, 0x27, 0xd4, 0x9e, 0x09, 0xa4, 0x21, 0xe5, + 0x1c, 0x00, 0xb8, 0x06, 0xc9, 0x1e, 0x9d, 0x18, 0xf3, 0x40, 0x70, 0x06, + 0x18, 0xe0, 0xb6, 0x33, 0x70, 0x0d, 0xc1, 0x9d, 0xf5, 0xae, 0x4a, 0xbd, + 0xab, 0xc1, 0xc3, 0x39, 0x44, 0x2c, 0x7d, 0x9b, 0x4c, 0x5b, 0x6d, 0x1a, + 0x6c, 0x67, 0xea, 0xc9, 0xc4, 0x61, 0xf7, 0x94, 0x56, 0x67, 0xa7, 0xb9, + 0x9b, 0x2a, 0x49, 0xb5, 0x63, 0x43, 0x99, 0x37, 0x8c, 0x89, 0xd4, 0x40, + 0x3e, 0xb3, 0xc6, 0xbc, 0x2c, 0x09, 0x95, 0x8c, 0x08, 0x1b, 0xb5, 0x89, + 0xbd, 0xb1, 0xa4, 0x21, 0xac, 0x9d, 0x14, 0x92, 0x85, 0xb4, 0xc7, 0x0c, + 0x35, 0x44, 0x80, 0x4f, 0xc4, 0x0f, 0x0f, 0xf9, 0xc4, 0x01, 0xa5, 0xb5, + 0x4f, 0x4b, 0xf4, 0x18, 0x84, 0x45, 0x5b, 0xc2, 0x27, 0x54, 0xc8, 0x28, + 0xdb, 0x26, 0xc4, 0x97, 0xe1, 0xc4, 0xd0, 0x28, 0xed, 0xd6, 0x4c, 0x81, + 0x0a, 0x85, 0x15, 0x15, 0x5c, 0x28, 0xa8, 0x6f, 0xa2, 0xcd, 0x42, 0xfb, + 0x3a, 0x55, 0x68, 0xd3, 0xee, 0xe9, 0x8b, 0x0a, 0x19, 0xc7, 0x79, 0xd5, + 0x84, 0x62, 0x37, 0x26, 0x2d, 0x2e, 0xeb, 0x78, 0x49, 0x57, 0xb5, 0xab, + 0xff, 0x81, 0x0e, 0xef, 0x4d, 0xfc, 0x07, 0xd0, 0x78, 0xbf, 0xfa, 0x2f, + 0xcc, 0xc4, 0x4e, 0xc5, 0x67, 0x8d, 0xbf, 0xa1, 0x38, 0xbc, 0x93, 0xbe, + 0xc9, 0x91, 0xf7, 0xf7, 0xb4, 0xe8, 0x99, 0xfa, 0x1e, 0x0d, 0x32, 0x71, + 0xbd, 0x47, 0x5a, 0x45, 0x9a, 0xb8, 0x82, 0x21, 0xae, 0x7c, 0x17, 0x06, + 0x5b, 0x89, 0x25, 0x2e, 0xda, 0xbe, 0xec, 0xf1, 0xca, 0x84, 0x8a, 0xa9, + 0x37, 0x91, 0x21, 0x2e, 0xac, 0x8f, 0x72, 0x76, 0x14, 0x3e, 0x22, 0x0e, + 0x74, 0x76, 0xe3, 0xcc, 0xdc, 0x37, 0xf5, 0xf6, 0xf4, 0x68, 0xcf, 0x4c, + 0x66, 0x33, 0xdb, 0x2a, 0x18, 0x0f, 0x5f, 0x46, 0xd7, 0x57, 0x80, 0x61, + 0x6e, 0x6e, 0xad, 0xc9, 0xcd, 0x04, 0x93, 0x85, 0xa2, 0x29, 0x44, 0xb5, + 0x38, 0x2f, 0xc0, 0x5d, 0xd8, 0x53, 0x06, 0xeb, 0xfe, 0x5c, 0x43, 0x00, + 0x34, 0x44, 0xdb, 0x70, 0x35, 0x74, 0x90, 0xf3, 0xf6, 0xfb, 0x1e, 0xec, + 0xca, 0xac, 0x8d, 0x13, 0x4d, 0x62, 0x14, 0x59, 0xac, 0x17, 0x98, 0xc8, + 0xc1, 0xaa, 0x9a, 0x09, 0xce, 0x76, 0x51, 0x1d, 0x6c, 0xb8, 0x0b, 0x2d, + 0x5e, 0x3d, 0x64, 0xa3, 0x1d, 0x80, 0xa7, 0xca, 0x32, 0x02, 0x48, 0x0b, + 0xd9, 0x7d, 0x88, 0x2b, 0x44, 0xa1, 0xdb, 0xf6, 0x43, 0x43, 0x21, 0x69, + 0x26, 0x07, 0x84, 0xa8, 0xb8, 0x10, 0x07, 0x0c, 0x5c, 0x0b, 0x93, 0xe7, + 0x64, 0x8b, 0x3b, 0x82, 0x6d, 0xf8, 0xc4, 0x54, 0x02, 0xae, 0x06, 0xf4, + 0xa9, 0xa6, 0x41, 0x6b, 0xb3, 0x4d, 0x09, 0x6c, 0x6c, 0xb1, 0x51, 0xad, + 0x9f, 0x81, 0xc6, 0xdb, 0x0e, 0xd6, 0x54, 0xeb, 0xb1, 0x99, 0xa6, 0x6c, + 0xa9, 0xa2, 0x04, 0x1b, 0x87, 0x6d, 0x04, 0x8d, 0x13, 0x80, 0xdf, 0x54, + 0xe9, 0x4a, 0x36, 0xdc, 0x74, 0xf5, 0x11, 0x52, 0x6f, 0x30, 0x2b, 0x2c, + 0xaf, 0x9e, 0x53, 0xe0, 0x33, 0xbd, 0x04, 0x58, 0xb4, 0x34, 0xe8, 0x94, + 0x11, 0x46, 0xea, 0x36, 0x03, 0xf9, 0xa5, 0x75, 0x68, 0x25, 0x7a, 0x42, + 0x9c, 0x97, 0x1c, 0x8e, 0xed, 0xc1, 0xb5, 0xe1, 0xa6, 0x70, 0xcd, 0x94, + 0x36, 0x51, 0x34, 0xe1, 0x99, 0x6e, 0x10, 0x95, 0x86, 0x4f, 0x11, 0x1b, + 0x6e, 0xa2, 0x69, 0xae, 0xdf, 0xe5, 0xe9, 0x7d, 0xff, 0xb7, 0xe1, 0xf7, + 0x28, 0x30, 0xbf, 0xd8, 0x25, 0xe9, 0xad, 0xdb, 0x35, 0xae, 0xd9, 0xef, + 0xaa, 0xd8, 0xeb, 0x88, 0x8f, 0x75, 0x98, 0xfc, 0x4e, 0x34, 0x9e, 0xed, + 0x22, 0xf1, 0xd6, 0xec, 0x7c, 0x77, 0xee, 0xf6, 0xae, 0x8e, 0xfd, 0xde, + 0x4b, 0xb7, 0x63, 0xe3, 0x8e, 0x65, 0x83, 0x9f, 0xdb, 0xb5, 0xda, 0x31, + 0x6a, 0xde, 0xb9, 0xcc, 0x4e, 0x90, 0x76, 0x3c, 0xda, 0xb1, 0xbf, 0xd9, + 0x71, 0x74, 0xe8, 0xa6, 0x7a, 0x47, 0x92, 0xa1, 0x85, 0xa0, 0x62, 0xc6, + 0xfe, 0xda, 0xf0, 0xc1, 0x66, 0xd2, 0x6c, 0x9c, 0xc1, 0x70, 0x3c, 0x1a, + 0xfc, 0xec, 0x2f, 0x8e, 0xbb, 0xe5, 0x5f, 0x97, 0xff, 0xa2, 0x38, 0x3e, + 0xf4, 0x86, 0x7b, 0x6b, 0xfa, 0xf3, 0xb6, 0x14, 0xa7, 0x7f, 0xf3, 0xd9, + 0x5f, 0x78, 0xfa, 0xfb, 0x25, 0xff, 0x2e, 0xad, 0xe5, 0xa5, 0x35, 0x07, + 0xb7, 0x14, 0x5e, 0x6c, 0x86, 0x5a, 0x3b, 0xce, 0x4c, 0xc2, 0x1f, 0xe1, + 0x53, 0xc3, 0xbf, 0x9a, 0x38, 0x17, 0x71, 0xcf, 0x70, 0xb0, 0x27, 0x4e, + 0x26, 0x46, 0x0d, 0x46, 0x2b, 0x2b, 0x20, 0xfa, 0x13, 0x69, 0xee, 0xe6, + 0x58, 0x6d, 0x08, 0x46, 0x76, 0xc3, 0xc4, 0xbf, 0x99, 0x7f, 0x0b, 0xf6, + 0xaf, 0x3d, 0x6c, 0xce, 0x98, 0xd4, 0xa9, 0xee, 0xe4, 0xaf, 0x4d, 0x7f, + 0xe1, 0xe9, 0xef, 0x5f, 0xfa, 0x0f, 0xeb, 0x7c, 0xba, 0xfe, 0x22, 0x66, + 0x1e, 0xb8, 0x52, 0x1b, 0xa3, 0x00, 0xfe, 0xf0, 0x4f, 0x38, 0x35, 0x11, + 0xd7, 0x06, 0xfc, 0x6d, 0xc4, 0xc5, 0x05, 0xb8, 0xb9, 0x25, 0xff, 0x80, + 0x97, 0x4f, 0x61, 0xbb, 0x5f, 0xda, 0x5f, 0x48, 0x87, 0x4a, 0xe9, 0x18, + 0xd3, 0x7a, 0xac, 0x77, 0xd6, 0xba, 0xcb, 0xa7, 0xd3, 0x2e, 0xe2, 0xec, + 0x69, 0x1b, 0xc9, 0xfa, 0x9e, 0xf6, 0x73, 0x8c, 0x2f, 0x8a, 0x31, 0x33, + 0xad, 0xc5, 0xce, 0x44, 0x3e, 0x31, 0x46, 0x5e, 0xb0, 0xb3, 0x90, 0x9d, + 0x27, 0x98, 0xed, 0x65, 0xee, 0x56, 0x73, 0x16, 0xae, 0xdd, 0x7e, 0xb3, + 0xa7, 0x5b, 0xb7, 0x82, 0x5b, 0x76, 0x71, 0xa0, 0xfb, 0xe5, 0xbb, 0x9d, + 0x21, 0xad, 0x2d, 0xf9, 0x27, 0x3d, 0x9b, 0x71, 0xb3, 0xc5, 0x1f, 0x95, + 0x86, 0x25, 0x39, 0x4b, 0xb3, 0xa8, 0xe9, 0xb3, 0xcb, 0x6f, 0xa1, 0x44, + 0x37, 0x95, 0xa9, 0xf2, 0x7d, 0xd6, 0x34, 0xa0, 0x22, 0x00, 0x4e, 0x47, + 0xb8, 0xd6, 0x17, 0x99, 0x27, 0xa3, 0xb0, 0x62, 0xbf, 0x48, 0x33, 0x62, + 0xbf, 0xe2, 0xfc, 0xbf, 0x5a, 0x42, 0xee, 0x37, 0xc7, 0x11, 0xa2, 0x88, + 0xb6, 0x8b, 0x6b, 0x31, 0x16, 0xc9, 0xc6, 0xa9, 0x71, 0xb7, 0x3b, 0xb3, + 0xdb, 0x99, 0xe0, 0xb2, 0xcf, 0x47, 0x9c, 0x97, 0x45, 0xf3, 0x54, 0x2f, + 0x31, 0xed, 0xe6, 0x9a, 0xf3, 0x57, 0x4d, 0x98, 0xd7, 0x6a, 0x88, 0x69, + 0x35, 0x6a, 0xbe, 0x2f, 0xac, 0xc7, 0x7d, 0xd7, 0x31, 0xa5, 0x72, 0x62, + 0x0c, 0xc6, 0xf1, 0x57, 0x4c, 0x8a, 0xcd, 0x49, 0x6f, 0x45, 0x50, 0x5a, + 0x5c, 0x4b, 0xe5, 0x8d, 0x5e, 0x86, 0xf9, 0xbb, 0x57, 0xe2, 0x9a, 0xfe, + 0x98, 0xdf, 0xf8, 0x73, 0xc6, 0x74, 0xb1, 0xd2, 0xb7, 0x8c, 0x63, 0xaa, + 0xa3, 0x70, 0xbd, 0x4b, 0xd5, 0xc0, 0x17, 0x17, 0x10, 0x89, 0x36, 0xc4, + 0x0d, 0x85, 0xd8, 0xbd, 0x3d, 0x63, 0x8a, 0xe1, 0x7b, 0x3b, 0x0d, 0xb1, + 0x0c, 0xbf, 0x73, 0xa1, 0x5d, 0xba, 0xdc, 0x75, 0x88, 0x98, 0xd1, 0x45, + 0xec, 0x8a, 0xfe, 0xc3, 0x98, 0x31, 0xec, 0x92, 0x57, 0xbb, 0x7e, 0x53, + 0x7f, 0xd2, 0xfc, 0xde, 0x7b, 0x00, 0x98, 0x21, 0xba, 0xa5, 0x17, 0x4c, + 0x14, 0x2d, 0x52, 0x56, 0x96, 0x3c, 0xaa, 0x87, 0x07, 0x69, 0x9f, 0xe2, + 0xf3, 0xc7, 0x07, 0x07, 0xe7, 0x64, 0x14, 0x6a, 0x4e, 0x1e, 0x3c, 0x02, + 0x1e, 0xae, 0x03, 0x9e, 0xaf, 0x03, 0xde, 0x6e, 0x01, 0x3c, 0x66, 0xc0, + 0xf5, 0x2d, 0x80, 0x4f, 0x87, 0x56, 0x00, 0x3e, 0x1d, 0x5a, 0x01, 0xf8, + 0x74, 0x68, 0x3f, 0x6d, 0xce, 0xfe, 0xe2, 0xd0, 0x1e, 0x3e, 0x67, 0xcb, + 0x2d, 0x80, 0xdd, 0xf5, 0x39, 0x9b, 0xae, 0xcf, 0xd9, 0x7a, 0xcb, 0x9c, + 0x0d, 0x8f, 0x70, 0xce, 0xfe, 0x22, 0x3a, 0x3c, 0x86, 0x39, 0xfb, 0x96, + 0x2d, 0x54, 0x34, 0x4b, 0xeb, 0x96, 0x51, 0x0a, 0x63, 0xaf, 0x64, 0xc6, + 0x73, 0x32, 0x1c, 0x76, 0x31, 0x59, 0x64, 0x40, 0x55, 0xac, 0x80, 0xc7, + 0x6d, 0x87, 0x5b, 0xd9, 0x75, 0x49, 0x74, 0x90, 0xbb, 0x36, 0x07, 0x62, + 0xb5, 0x20, 0x37, 0x0a, 0xf7, 0x3b, 0x03, 0x8e, 0x42, 0x53, 0x94, 0xab, + 0x62, 0xf0, 0x60, 0x84, 0xfd, 0x06, 0x56, 0x81, 0x25, 0x36, 0xd5, 0x46, + 0x8d, 0x60, 0x63, 0xac, 0x4a, 0x34, 0xd4, 0x6d, 0x8c, 0x41, 0xba, 0x81, + 0x9d, 0xe3, 0x0b, 0x18, 0x4c, 0x8c, 0x0e, 0x8f, 0x0f, 0xfd, 0x11, 0xcc, + 0x34, 0xf0, 0x35, 0x98, 0xdd, 0x30, 0xfc, 0x06, 0x6b, 0x60, 0xa0, 0xe9, + 0x20, 0xe6, 0x5a, 0xa7, 0xd7, 0x14, 0x38, 0xd1, 0x70, 0x80, 0xe8, 0xb3, + 0x4c, 0xa5, 0x8a, 0x3d, 0xf1, 0x98, 0x85, 0xa7, 0xaa, 0x4f, 0x55, 0x7f, + 0x4c, 0x55, 0xda, 0xea, 0x2e, 0xe1, 0xf0, 0x4a, 0x1c, 0x7e, 0x15, 0xce, + 0x82, 0xf9, 0x0e, 0xa1, 0x5a, 0x66, 0x0b, 0xec, 0xcd, 0xbd, 0x8a, 0x60, + 0xbe, 0xfe, 0x10, 0xaa, 0x55, 0x31, 0x54, 0x8b, 0x71, 0x86, 0x9d, 0x69, + 0xd3, 0xf1, 0x72, 0xb2, 0xee, 0xa4, 0x9d, 0x79, 0xb2, 0x5f, 0x15, 0xaa, + 0xd5, 0x23, 0x17, 0x9b, 0x7a, 0xc1, 0xad, 0xdc, 0xf7, 0x0c, 0x01, 0xa0, + 0x2d, 0x55, 0xb3, 0x40, 0x97, 0xc2, 0x90, 0xec, 0xaf, 0x8e, 0x49, 0x1d, + 0x02, 0x83, 0x71, 0x48, 0x78, 0xfa, 0xe4, 0x21, 0xed, 0x20, 0xe8, 0xcf, + 0xa4, 0x51, 0x46, 0xd8, 0x2c, 0xfe, 0xb1, 0xe5, 0x84, 0xd9, 0xf6, 0xb5, + 0xb8, 0x06, 0xb3, 0xd7, 0xce, 0x50, 0x1a, 0x7a, 0x06, 0x5c, 0x82, 0xd8, + 0x58, 0x97, 0x5f, 0x84, 0x87, 0xfd, 0xbe, 0x5a, 0xd7, 0x6d, 0x70, 0x71, + 0x30, 0x4b, 0xaf, 0x39, 0x18, 0xe3, 0x32, 0xc5, 0x91, 0xcd, 0x70, 0xd0, + 0x20, 0x36, 0x89, 0xc4, 0x70, 0x71, 0xa6, 0x0a, 0x9a, 0x5e, 0x88, 0x3e, + 0x36, 0xb4, 0x53, 0x3e, 0x3d, 0xf8, 0xf4, 0xe0, 0x83, 0x1e, 0xac, 0xa4, + 0xc6, 0xd0, 0x7b, 0x14, 0xe0, 0xb7, 0x0f, 0x52, 0x57, 0x86, 0xe4, 0xc7, + 0xe1, 0x26, 0x23, 0xd9, 0x08, 0x28, 0xc4, 0xf6, 0xc4, 0x46, 0x5c, 0x90, + 0xac, 0xf2, 0xdf, 0x21, 0x19, 0x3a, 0x3c, 0x83, 0x64, 0x86, 0xae, 0x17, + 0xb9, 0xee, 0x4e, 0x00, 0xb6, 0x06, 0x88, 0x1e, 0xfb, 0xb8, 0xff, 0x3d, + 0x83, 0x3e, 0xff, 0x3b, 0x20, 0xce, 0xb1, 0x55, 0x23, 0x26, 0x66, 0xc1, + 0x87, 0x49, 0x3f, 0xd0, 0x9a, 0xfd, 0x12, 0x04, 0xe7, 0x06, 0x5d, 0xf9, + 0x00, 0x03, 0x00, 0xc3, 0x49, 0x19, 0x3f, 0x6a, 0x04, 0xac, 0x41, 0x04, + 0x6a, 0x8d, 0x68, 0xd5, 0x8a, 0xe1, 0xa9, 0x8c, 0x47, 0xf5, 0x88, 0x5d, + 0xed, 0x11, 0xac, 0xda, 0x81, 0xa6, 0x90, 0x3c, 0x92, 0x94, 0x92, 0x76, + 0x8a, 0xce, 0x72, 0xf0, 0x1e, 0x84, 0xa6, 0xc7, 0x1c, 0x3c, 0xbc, 0xa2, + 0x35, 0x3c, 0xa0, 0xe1, 0x51, 0xf2, 0x42, 0x1b, 0xdd, 0x2c, 0xb3, 0x08, + 0x31, 0xa5, 0x07, 0x23, 0xc0, 0x1b, 0x86, 0x1a, 0xe0, 0xc3, 0x70, 0x5c, + 0x48, 0xf8, 0x36, 0x1c, 0x9c, 0x1d, 0x8e, 0x6b, 0x6a, 0x94, 0x1b, 0xe2, + 0x14, 0x65, 0x34, 0x4a, 0x6c, 0x4a, 0x28, 0xef, 0x8d, 0x87, 0x64, 0x82, + 0xc8, 0xc6, 0x64, 0x2e, 0x9a, 0x48, 0xb6, 0x11, 0x26, 0x6b, 0x91, 0xd0, + 0x23, 0xdc, 0x27, 0xf3, 0xca, 0x79, 0xd2, 0x26, 0xd7, 0xee, 0x80, 0xe6, + 0xc7, 0x9c, 0xd4, 0x89, 0x2c, 0x17, 0xd4, 0xb9, 0x3a, 0x24, 0x6a, 0x3e, + 0x25, 0x65, 0xf3, 0xfe, 0xd0, 0xfc, 0xc5, 0x5e, 0xdc, 0xbf, 0xf9, 0xb3, + 0x76, 0xaf, 0x8f, 0x3e, 0xcd, 0xf3, 0x56, 0x24, 0xed, 0xa1, 0xc1, 0x8b, + 0xf3, 0x5c, 0x5d, 0x5c, 0x3c, 0x7f, 0xcb, 0xe2, 0x5d, 0x5c, 0x35, 0x05, + 0x3c, 0x04, 0x09, 0xf2, 0x25, 0x0e, 0xa4, 0xfa, 0xf6, 0x23, 0x33, 0x7a, + 0x83, 0xe4, 0x3d, 0x92, 0x8f, 0x48, 0x16, 0x24, 0x34, 0xb1, 0x6d, 0xd8, + 0xab, 0x0c, 0x9f, 0x8a, 0x51, 0xf8, 0xf1, 0xf7, 0xf6, 0x1e, 0x15, 0x5d, + 0x8a, 0x11, 0xa8, 0x82, 0xe6, 0x47, 0xde, 0x79, 0xcb, 0xc7, 0x76, 0x40, + 0x97, 0x46, 0xca, 0xec, 0xbc, 0xe5, 0xbe, 0x08, 0x33, 0x3b, 0x9c, 0x8c, + 0x79, 0x90, 0x09, 0x48, 0x4f, 0xc4, 0xfd, 0xa3, 0x3f, 0xc7, 0x6a, 0x51, + 0x36, 0x20, 0x29, 0x31, 0x33, 0x67, 0x05, 0x41, 0x22, 0x3e, 0x39, 0xf7, + 0x30, 0x92, 0x3f, 0x8f, 0x13, 0xd4, 0x47, 0x51, 0xc3, 0xb6, 0xcf, 0xcc, + 0xbd, 0xf5, 0x02, 0x1b, 0xd7, 0xc8, 0x09, 0x24, 0x96, 0x11, 0x64, 0xc5, + 0x44, 0xa1, 0x95, 0x92, 0xd1, 0x07, 0xf6, 0xb1, 0x87, 0xdc, 0xf4, 0x85, + 0x5d, 0xbf, 0x01, 0x69, 0x35, 0x21, 0x48, 0x32, 0x91, 0x44, 0x24, 0xee, + 0x62, 0x09, 0x50, 0x92, 0xa7, 0xfa, 0x62, 0xdc, 0x1b, 0xc7, 0x9d, 0x15, + 0x9a, 0x9a, 0xd3, 0x90, 0x2b, 0x4f, 0xc5, 0xc2, 0x6b, 0x55, 0xb5, 0xe4, + 0x44, 0x0b, 0xad, 0x79, 0x9d, 0xc2, 0x65, 0x56, 0x57, 0xe0, 0xd7, 0x95, + 0xa7, 0xba, 0xf4, 0xd4, 0x25, 0x58, 0x27, 0x2d, 0x2a, 0x26, 0x84, 0xa0, + 0xeb, 0x84, 0x6c, 0x88, 0x67, 0xb0, 0xdb, 0x0a, 0x2b, 0x69, 0x43, 0x22, + 0xd3, 0x08, 0x2e, 0x79, 0xc2, 0xe3, 0x16, 0x64, 0xf0, 0x81, 0xd5, 0x6d, + 0x32, 0x76, 0x70, 0xa3, 0x59, 0x0b, 0x6d, 0x38, 0x18, 0x69, 0x15, 0x0b, + 0xd0, 0x85, 0x24, 0xba, 0x31, 0x0c, 0x22, 0x21, 0x76, 0xc9, 0xae, 0xb4, + 0xeb, 0xb5, 0xa7, 0xea, 0xb3, 0xc1, 0xdd, 0x31, 0x7f, 0xb7, 0x4d, 0x6b, + 0x77, 0x84, 0xdd, 0x1c, 0xe7, 0xf1, 0xfa, 0x52, 0x71, 0x11, 0x30, 0x02, + 0x8f, 0x11, 0x48, 0x04, 0xef, 0x80, 0x0d, 0x62, 0x07, 0x92, 0xd7, 0x7b, + 0x60, 0x83, 0x98, 0xc5, 0x77, 0xaa, 0xfc, 0x99, 0x95, 0x5f, 0xa1, 0xf2, + 0xca, 0xca, 0x1f, 0x88, 0x87, 0x3d, 0xf0, 0xf0, 0x0b, 0x55, 0x84, 0x1b, + 0x68, 0x0c, 0xc0, 0x6d, 0x8a, 0xf2, 0x0d, 0x62, 0x0e, 0xe2, 0x3c, 0x92, + 0x8b, 0xbe, 0x01, 0xc3, 0xd3, 0xae, 0x9a, 0x28, 0x0b, 0xd7, 0xf0, 0x59, + 0x2f, 0x1d, 0xf8, 0x7d, 0xdc, 0x92, 0x2f, 0xe0, 0xa4, 0xb0, 0x3e, 0x5b, + 0xcf, 0xb3, 0x4e, 0xce, 0x6c, 0x0c, 0x28, 0x29, 0xf0, 0x43, 0xc5, 0x5d, + 0x8f, 0x7d, 0x3d, 0x60, 0x60, 0xa2, 0x11, 0x59, 0x8d, 0x69, 0x51, 0x4a, + 0xd7, 0x7a, 0xc2, 0x3b, 0x21, 0x9a, 0x88, 0x76, 0x7c, 0x45, 0xd9, 0xb9, + 0x8c, 0xb5, 0xf4, 0xf6, 0x63, 0x8d, 0x16, 0xae, 0x59, 0x50, 0xc1, 0xc4, + 0x82, 0x55, 0x05, 0x43, 0x89, 0x6e, 0x95, 0xc2, 0x41, 0xfa, 0x84, 0x32, + 0x69, 0xb9, 0xb5, 0xfc, 0x69, 0xdd, 0xb5, 0xcd, 0x84, 0xa1, 0x09, 0x7d, + 0x36, 0x15, 0x8c, 0x2c, 0x58, 0x58, 0x10, 0x54, 0x30, 0xb1, 0x60, 0x55, + 0xc1, 0xe0, 0x8a, 0x20, 0x93, 0x3e, 0x24, 0xb6, 0x20, 0x16, 0x20, 0xe6, + 0x91, 0x18, 0x85, 0xa6, 0x20, 0x6d, 0x36, 0xf2, 0xa3, 0xdf, 0xc8, 0xd0, + 0x3e, 0x93, 0x5b, 0x6e, 0xe2, 0x85, 0xef, 0xc8, 0x5a, 0x3f, 0x01, 0x44, + 0xbf, 0xaf, 0xff, 0x64, 0x05, 0x37, 0x00, 0x61, 0x41, 0x08, 0x71, 0x36, + 0x37, 0xd8, 0x6d, 0x9a, 0x9d, 0x2b, 0x60, 0x5f, 0x2f, 0x00, 0xd1, 0x6d, + 0xb0, 0xeb, 0x34, 0x11, 0x37, 0x50, 0x00, 0x10, 0x1d, 0x70, 0x67, 0x2f, + 0x78, 0x0d, 0x10, 0x51, 0xbb, 0x01, 0x65, 0x80, 0x01, 0xa9, 0x89, 0xe8, + 0x33, 0x5a, 0x41, 0xc7, 0x5d, 0x5f, 0x93, 0x84, 0x4c, 0x00, 0x11, 0xdd, + 0x24, 0x88, 0x19, 0x85, 0x41, 0xa9, 0xb6, 0x28, 0x17, 0x2b, 0x00, 0x88, + 0x2e, 0xc0, 0xe0, 0x54, 0x47, 0xf9, 0xd2, 0xb8, 0xcd, 0x0a, 0x10, 0x9d, + 0x45, 0xb8, 0x58, 0x01, 0xa3, 0x3f, 0x56, 0xc5, 0x88, 0x0c, 0x06, 0xa2, + 0x8e, 0x6f, 0xc8, 0x5b, 0x80, 0xc8, 0x0a, 0x10, 0x1d, 0x23, 0x56, 0x6a, + 0x46, 0xb3, 0x44, 0x8b, 0xbd, 0x87, 0x5e, 0x38, 0x30, 0x1e, 0x65, 0x06, + 0x08, 0xcf, 0x88, 0x96, 0x2e, 0x85, 0xac, 0x30, 0x9c, 0xc5, 0x6f, 0xd2, + 0x1f, 0xc7, 0x1a, 0x7b, 0x6f, 0x06, 0x08, 0xbf, 0x49, 0xa7, 0x1c, 0x19, + 0x50, 0xc2, 0x78, 0x16, 0x6f, 0x71, 0x36, 0x70, 0x12, 0x00, 0xc7, 0xf9, + 0xc2, 0x89, 0xa7, 0x73, 0xb9, 0x65, 0x80, 0x0a, 0x5e, 0x8e, 0x44, 0x6c, + 0x59, 0x05, 0x7d, 0x74, 0x34, 0x10, 0x78, 0xbf, 0x77, 0x83, 0x37, 0x07, + 0x62, 0xe8, 0xe4, 0x10, 0xe8, 0xb1, 0x64, 0xff, 0xb4, 0x0f, 0x08, 0x37, + 0x43, 0xac, 0xf5, 0x0a, 0x10, 0x3e, 0xc0, 0x18, 0xd7, 0x9a, 0xd4, 0xca, + 0x77, 0x76, 0xa1, 0x56, 0x0f, 0x06, 0xa2, 0x85, 0x05, 0x00, 0x05, 0xde, + 0xd8, 0xe9, 0x60, 0x20, 0x5a, 0x70, 0xc9, 0xa1, 0x0a, 0x8c, 0x20, 0xe9, + 0x8d, 0x58, 0xc4, 0x51, 0x1a, 0xf1, 0x18, 0x2b, 0x30, 0x35, 0x2a, 0xec, + 0x3f, 0xfd, 0x37, 0xb8, 0x64, 0xe4, 0xcc, 0xc1, 0x2e, 0x8a, 0x8b, 0xa5, + 0xad, 0x32, 0x19, 0x26, 0x1d, 0xcd, 0x9b, 0xb2, 0x65, 0xd2, 0x28, 0xf0, + 0x8b, 0x80, 0xf0, 0x36, 0xe0, 0xf9, 0xa7, 0x25, 0x53, 0xd1, 0xb3, 0x5f, + 0x29, 0xf9, 0xbf, 0x96, 0x74, 0xd8, 0x2b, 0xc1, 0x14, 0xd0, 0xf7, 0xe0, + 0x4d, 0x1f, 0x60, 0xe5, 0xf9, 0x23, 0x52, 0x5f, 0x0c, 0xf3, 0x98, 0x0c, + 0x48, 0xc6, 0x43, 0x32, 0x1d, 0x92, 0x8b, 0x93, 0x15, 0x0d, 0x3e, 0x6f, + 0x2c, 0x89, 0x8c, 0x71, 0xf1, 0xd6, 0xca, 0xc2, 0xf8, 0x14, 0x6f, 0x84, + 0xc0, 0xde, 0x8a, 0x2d, 0x13, 0xdb, 0xc1, 0x97, 0x92, 0x2d, 0x25, 0x63, + 0x91, 0xb4, 0x48, 0x9c, 0x1b, 0xb3, 0x3e, 0x78, 0xff, 0x24, 0x3c, 0xc2, + 0x24, 0xd8, 0x30, 0xef, 0x9f, 0x6c, 0x7f, 0x57, 0xb2, 0x9e, 0x26, 0x33, + 0x44, 0xae, 0x63, 0x92, 0xd6, 0xd6, 0x17, 0xeb, 0x1e, 0x55, 0x15, 0x33, + 0xfc, 0x05, 0xbe, 0x45, 0x92, 0x92, 0x0e, 0x48, 0xc4, 0x84, 0x4a, 0x12, + 0x13, 0xe8, 0x48, 0x8c, 0x0a, 0x4c, 0x7a, 0x55, 0xfc, 0x4f, 0x3b, 0x03, + 0x0d, 0xa2, 0xd4, 0xbd, 0xa6, 0x1c, 0xb8, 0xed, 0x25, 0xa2, 0x38, 0x24, + 0x12, 0x58, 0xc0, 0xef, 0x21, 0x6c, 0xc4, 0x9a, 0x23, 0x67, 0x9c, 0xa2, + 0x7e, 0x56, 0x66, 0x1a, 0xb6, 0x82, 0x6e, 0x51, 0x8c, 0x73, 0x12, 0xdf, + 0xd0, 0xf7, 0x01, 0xfd, 0xd3, 0x0b, 0xe9, 0xec, 0x75, 0x12, 0x01, 0x79, + 0x4b, 0xbd, 0x2d, 0x0e, 0x34, 0xb6, 0x55, 0x61, 0xe3, 0xcd, 0x51, 0xed, + 0x68, 0x20, 0x55, 0x46, 0x7a, 0xd8, 0x83, 0x95, 0x3d, 0xa7, 0x75, 0x99, + 0xaa, 0xdb, 0x0b, 0xd8, 0xa9, 0x4d, 0x32, 0xbd, 0xf3, 0xf6, 0x6d, 0x32, + 0x6a, 0x97, 0xef, 0xa2, 0xaf, 0x34, 0x6c, 0xdd, 0x80, 0xd5, 0xda, 0xe2, + 0xb9, 0xa4, 0xe6, 0x7d, 0xfb, 0x6d, 0xd6, 0x2d, 0xbe, 0xf3, 0xed, 0xff, + 0xb6, 0xdb, 0x8a, 0x26, 0x21, 0x6f, 0x2c, 0x39, 0xba, 0xaf, 0x66, 0x18, + 0xc3, 0xe2, 0x74, 0x6f, 0xc5, 0x74, 0x97, 0xaa, 0x72, 0x80, 0xf5, 0xcd, + 0x16, 0x05, 0xc9, 0xc6, 0xdb, 0x09, 0x89, 0x0e, 0xd8, 0xd0, 0x09, 0x1a, + 0x34, 0x06, 0x2c, 0xf9, 0xd6, 0x96, 0x2d, 0x40, 0x4f, 0xbf, 0xc1, 0x1a, + 0xad, 0x34, 0x76, 0x71, 0x62, 0x37, 0xce, 0xc6, 0x1f, 0x54, 0x98, 0xcb, + 0xdb, 0x86, 0xb7, 0xfe, 0xf4, 0x36, 0x6b, 0x35, 0xf7, 0xbd, 0xad, 0x79, + 0xdb, 0xff, 0xe2, 0xb7, 0xd2, 0xe2, 0xf2, 0x2d, 0xb5, 0x37, 0x9a, 0x2f, + 0xaf, 0xde, 0x9a, 0x37, 0x12, 0x3c, 0x6a, 0x48, 0xb7, 0xb4, 0x6a, 0xb4, + 0xe9, 0xf8, 0x84, 0xf7, 0xd8, 0xa5, 0x31, 0xac, 0x2a, 0x36, 0xf0, 0x1a, + 0x86, 0xd5, 0xe8, 0x84, 0x89, 0xdb, 0x72, 0xbf, 0x8d, 0x87, 0x2e, 0x2d, + 0x97, 0x71, 0x44, 0x02, 0x05, 0xb6, 0xf3, 0x26, 0x87, 0x0c, 0x36, 0xfb, + 0xca, 0xbd, 0x4f, 0x3b, 0x70, 0xf2, 0xcc, 0xe2, 0xa9, 0xec, 0x9e, 0x6a, + 0x90, 0x9b, 0xd4, 0x7a, 0x7f, 0x34, 0xe8, 0xe1, 0x28, 0xa5, 0xf0, 0x18, + 0x7e, 0x52, 0xf3, 0x16, 0x6e, 0x35, 0xa9, 0x7f, 0xb6, 0x03, 0x65, 0x19, + 0x20, 0x3b, 0x4a, 0x16, 0x82, 0x2b, 0x8f, 0x37, 0x57, 0x1e, 0xf7, 0x67, + 0x8f, 0x8f, 0x97, 0x1f, 0x5f, 0x4f, 0x1e, 0x9f, 0x2e, 0x3f, 0xbe, 0x7d, + 0x9f, 0xc7, 0x1f, 0xd8, 0x99, 0xc3, 0xe3, 0xe7, 0x33, 0x23, 0x45, 0xfa, + 0x7b, 0x4c, 0x64, 0x9d, 0x3b, 0x75, 0xf2, 0xb8, 0x3a, 0x75, 0xed, 0xf1, + 0xe1, 0xf2, 0xe3, 0x87, 0x56, 0x4e, 0x1f, 0x57, 0xa7, 0xfa, 0xab, 0xcb, + 0x35, 0xf1, 0xf1, 0x91, 0x8f, 0x5f, 0x6c, 0x25, 0x5b, 0x08, 0x2e, 0xb6, + 0xd2, 0x9d, 0xb5, 0xa2, 0x6a, 0x77, 0xb4, 0xa2, 0x6a, 0xd7, 0x5a, 0xb9, + 0x58, 0xed, 0xbc, 0x95, 0x8b, 0xd5, 0x64, 0x21, 0xb9, 0xde, 0xb9, 0x43, + 0xb5, 0x26, 0x57, 0xbb, 0x63, 0x4c, 0x0b, 0x5b, 0x39, 0xad, 0x76, 0x9f, + 0xd6, 0x6e, 0xa9, 0xc6, 0xb1, 0x85, 0xfb, 0x8c, 0xad, 0xb9, 0x5a, 0x4d, + 0x6c, 0x55, 0x72, 0xd0, 0xb5, 0x56, 0xad, 0x5a, 0x7e, 0x15, 0x2f, 0x24, + 0x97, 0x99, 0x4c, 0x94, 0xf2, 0x99, 0xc9, 0x0a, 0x37, 0x27, 0xdb, 0x15, + 0x88, 0x29, 0x6f, 0x75, 0x66, 0x8f, 0xde, 0x01, 0x19, 0x44, 0x5b, 0x3d, + 0xb2, 0x65, 0x35, 0xeb, 0x91, 0x4d, 0x73, 0x77, 0x24, 0xc8, 0x91, 0x5c, + 0x8f, 0xf0, 0xb0, 0x99, 0xeb, 0xcc, 0x99, 0xe0, 0xb8, 0x92, 0xa8, 0x47, + 0x1a, 0xbf, 0x75, 0x10, 0xff, 0xcc, 0xdc, 0x5d, 0x9b, 0xdc, 0x13, 0x75, + 0x79, 0x1d, 0xd4, 0xf3, 0x91, 0x86, 0xb4, 0x57, 0x30, 0xf6, 0x49, 0xfe, + 0x21, 0xfb, 0x30, 0x37, 0xbe, 0xeb, 0xe1, 0xd5, 0xaf, 0x68, 0xc8, 0x6e, + 0x69, 0xc8, 0xe6, 0x91, 0x2e, 0x35, 0x5d, 0x68, 0x99, 0xc7, 0x8b, 0x33, + 0xfd, 0x06, 0x09, 0xf1, 0x2b, 0xcd, 0xdd, 0x64, 0xfd, 0x62, 0x58, 0x77, + 0x56, 0x3e, 0xb4, 0x4c, 0x81, 0x6c, 0xa3, 0xfd, 0x5d, 0xdd, 0x7e, 0xc9, + 0x6e, 0x97, 0x36, 0x4a, 0x13, 0x7c, 0xcc, 0x3e, 0x61, 0xda, 0xa7, 0xe4, + 0x44, 0xb3, 0x51, 0xae, 0x14, 0x8f, 0x4c, 0x4e, 0xa7, 0x31, 0x64, 0xa6, + 0x07, 0xd1, 0xec, 0x43, 0xbd, 0xbd, 0x42, 0x1e, 0x2d, 0x8f, 0x23, 0x5e, + 0xae, 0x8a, 0xf2, 0xaa, 0x9d, 0x03, 0x12, 0xff, 0xe8, 0x49, 0x08, 0xe0, + 0x97, 0xc5, 0x0a, 0xd2, 0xbd, 0x17, 0xf2, 0x3a, 0xf7, 0xb8, 0x95, 0xa0, + 0xdc, 0xc5, 0x94, 0xfc, 0x4f, 0x1e, 0x42, 0xc5, 0x0e, 0x9f, 0x78, 0x3b, + 0xd4, 0x84, 0x79, 0x3b, 0xa2, 0x25, 0xb2, 0x81, 0xc4, 0x6f, 0xdb, 0xc1, + 0xdb, 0x4b, 0x56, 0xd6, 0x99, 0x0e, 0x4f, 0x3a, 0x74, 0x26, 0x62, 0x83, + 0x11, 0x09, 0x0f, 0xae, 0x5b, 0x53, 0x36, 0xee, 0x60, 0xdc, 0x31, 0x17, + 0xaa, 0x59, 0x6f, 0xcd, 0xad, 0x21, 0x29, 0xf8, 0x0d, 0x23, 0x19, 0x7a, + 0x4c, 0x98, 0x8e, 0x62, 0xd2, 0x6c, 0x73, 0x9d, 0xaf, 0xb8, 0x35, 0x02, + 0x97, 0xaa, 0xd4, 0x04, 0xee, 0x74, 0x6b, 0x84, 0x47, 0x53, 0x39, 0xa3, + 0xe7, 0x01, 0xc3, 0x28, 0x31, 0x7d, 0xa2, 0x5e, 0xf3, 0x8a, 0x7e, 0x20, + 0x4e, 0x98, 0x04, 0x29, 0xc6, 0x80, 0xcd, 0x94, 0x71, 0x9e, 0x43, 0x4f, + 0x89, 0x12, 0x54, 0xdc, 0xbc, 0x51, 0x8e, 0x7e, 0x16, 0x0c, 0xc3, 0xac, + 0x37, 0x1d, 0x52, 0xee, 0x67, 0x1d, 0xc2, 0x35, 0x60, 0x9d, 0x93, 0x46, + 0x24, 0x11, 0x0a, 0xbb, 0x7f, 0x12, 0x92, 0xa0, 0x38, 0xc7, 0xe7, 0x48, + 0xe4, 0xed, 0x30, 0xb0, 0x64, 0xd3, 0xf5, 0xc9, 0x2a, 0x0c, 0xb2, 0xd7, + 0x82, 0x4b, 0x1d, 0xa3, 0xe9, 0x9a, 0x40, 0xf3, 0xa8, 0x81, 0xaa, 0xca, + 0xb9, 0xe2, 0x1c, 0xcd, 0x92, 0xd9, 0x84, 0x9c, 0xe8, 0x1d, 0x91, 0x92, + 0xa6, 0x7a, 0x91, 0xa6, 0x11, 0x23, 0x93, 0x5d, 0x5f, 0xa2, 0x22, 0xc7, + 0x5b, 0xe3, 0x72, 0xc2, 0x18, 0x6d, 0xce, 0x9a, 0x1c, 0x4d, 0xe7, 0x81, + 0xf8, 0xdc, 0x94, 0x97, 0x4e, 0x7e, 0xb2, 0xed, 0x4f, 0x3a, 0x34, 0x27, + 0x75, 0xa1, 0x03, 0x45, 0x91, 0xf5, 0x9f, 0x7d, 0x97, 0x97, 0xa3, 0x5c, + 0xee, 0x2c, 0x5b, 0xfb, 0x90, 0x89, 0xf0, 0x90, 0x86, 0xdd, 0x17, 0x13, + 0x3a, 0xa2, 0xea, 0xf2, 0x78, 0xab, 0x2e, 0x89, 0xa8, 0x08, 0x03, 0xca, + 0xb1, 0x0e, 0x07, 0x4d, 0x41, 0x4a, 0xd6, 0x88, 0x08, 0x87, 0x25, 0xc5, + 0x34, 0x48, 0x61, 0x38, 0x9b, 0xcb, 0x57, 0x41, 0x51, 0x5d, 0x23, 0x96, + 0x61, 0x91, 0x32, 0x57, 0x9b, 0xaa, 0x67, 0xb8, 0xcc, 0x75, 0xa5, 0xff, + 0x57, 0xc7, 0x27, 0xbe, 0x40, 0x42, 0x2b, 0x96, 0x94, 0x47, 0xea, 0x92, + 0x52, 0x1b, 0xc8, 0xb4, 0x68, 0xba, 0x90, 0xcb, 0x76, 0xc0, 0xad, 0x31, + 0xbe, 0x3f, 0x80, 0x1e, 0x3c, 0x87, 0x6c, 0x01, 0xa5, 0x9f, 0x25, 0xe2, + 0x91, 0xeb, 0x76, 0xc9, 0xff, 0x38, 0x80, 0x57, 0xcf, 0x40, 0x6e, 0xb9, + 0x52, 0x46, 0xec, 0x80, 0x85, 0x9c, 0xfa, 0x5e, 0x55, 0xbd, 0x08, 0xc0, + 0x7a, 0x01, 0xe5, 0x3e, 0x24, 0xc6, 0x38, 0x26, 0xd7, 0x99, 0x87, 0x73, + 0xe4, 0x9b, 0xaa, 0xae, 0x44, 0xf4, 0x97, 0xd8, 0xe1, 0x1f, 0x93, 0x82, + 0xb6, 0x90, 0x2e, 0x93, 0x4c, 0x67, 0xaa, 0xcd, 0xa3, 0xf7, 0x38, 0x35, + 0x8d, 0x05, 0xab, 0x0e, 0xa2, 0xf8, 0x60, 0x00, 0x03, 0x4c, 0x26, 0xc6, + 0x35, 0x30, 0xb3, 0x27, 0x07, 0xfe, 0x4d, 0xd8, 0xdb, 0x8b, 0xfc, 0xea, + 0x64, 0x3c, 0xda, 0xea, 0x56, 0x67, 0x3b, 0x72, 0xa9, 0xe9, 0xe0, 0x6e, + 0x14, 0xd1, 0x00, 0x45, 0xb1, 0xe9, 0xf6, 0x87, 0xf0, 0x09, 0x57, 0xcb, + 0xc9, 0xfb, 0xd7, 0x7e, 0xa0, 0x5d, 0x7f, 0xef, 0xaf, 0xff, 0xcb, 0xbd, + 0xb5, 0xad, 0xf1, 0xa7, 0x09, 0x46, 0xbf, 0xc5, 0xfd, 0xf6, 0xc0, 0xcb, + 0xe9, 0x27, 0x0c, 0xd6, 0x7e, 0xed, 0x37, 0x8c, 0x38, 0x04, 0x1e, 0x8a, + 0x3c, 0xf4, 0xbb, 0x28, 0xba, 0xe8, 0x58, 0x69, 0x65, 0xd9, 0xe1, 0xc8, + 0xc8, 0xb2, 0x43, 0xa7, 0x87, 0x8e, 0x59, 0xf6, 0x62, 0x53, 0xca, 0xf2, + 0xbb, 0x1c, 0x83, 0x2c, 0x9c, 0x31, 0x6d, 0x59, 0xec, 0xdd, 0x60, 0xff, + 0x47, 0xfb, 0x3f, 0xc5, 0x7f, 0x15, 0x54, 0x20, 0xc8, 0xe1, 0xd8, 0xc5, + 0x74, 0x7c, 0x62, 0x30, 0x83, 0xfd, 0x8f, 0x15, 0x3a, 0x9b, 0xd3, 0x8e, + 0x26, 0xcb, 0xc5, 0x89, 0x1d, 0x42, 0xa8, 0xf7, 0x86, 0xb8, 0x41, 0x41, + 0x6c, 0x23, 0x7d, 0xac, 0x70, 0xa8, 0x22, 0xd4, 0xa0, 0x0e, 0x62, 0xc1, + 0xf0, 0x3b, 0xcf, 0xfc, 0xdf, 0x05, 0xb1, 0xe4, 0x91, 0xb6, 0xd0, 0x3e, + 0xc8, 0xbd, 0x22, 0x97, 0x73, 0x90, 0x11, 0x14, 0x4c, 0x7b, 0x95, 0x4f, + 0xb7, 0x93, 0x9b, 0x7a, 0x96, 0xfa, 0x80, 0xcd, 0x42, 0x7a, 0x25, 0xf6, + 0x3d, 0x58, 0x6f, 0x9d, 0xf5, 0x1f, 0x23, 0x9a, 0x9c, 0xf8, 0x37, 0xa8, + 0x16, 0x95, 0xc0, 0xc0, 0x21, 0x05, 0x27, 0x3f, 0x73, 0x6a, 0x21, 0xc8, + 0xe9, 0x5b, 0x85, 0xc4, 0x1d, 0xb5, 0x55, 0xeb, 0x32, 0xab, 0x2b, 0xb3, + 0xd0, 0x65, 0x64, 0x35, 0x41, 0x7a, 0xca, 0x26, 0xab, 0x2f, 0x20, 0xd2, + 0x12, 0x8c, 0x21, 0x35, 0xd6, 0x07, 0xba, 0xc1, 0x7b, 0xd1, 0x83, 0x21, + 0x8d, 0xc9, 0x5b, 0x47, 0x71, 0xb4, 0x04, 0xc3, 0x81, 0x3c, 0x02, 0x9a, + 0x6c, 0xe1, 0x78, 0x7a, 0x21, 0xb5, 0x44, 0x5b, 0xe9, 0xc6, 0x56, 0xda, + 0xc1, 0xd7, 0xf5, 0x1f, 0xf6, 0xff, 0xdf, 0xbe, 0x0d, 0x4b, 0x2f, 0xff, + 0xee, 0xb1, 0x3b, 0x1e, 0xfc, 0xfb, 0x11, 0xfd, 0xb4, 0xa9, 0x71, 0xff, + 0x59, 0x4c, 0xc7, 0xbf, 0xdb, 0xff, 0x16, 0xb3, 0x05, 0x55, 0x96, 0x6c, + 0xcf, 0xb2, 0x18, 0x3e, 0x06, 0x77, 0x3e, 0x5c, 0xf4, 0x96, 0x25, 0xa7, + 0x3b, 0xfc, 0xe5, 0xc4, 0xbb, 0x15, 0xbd, 0x76, 0x86, 0x0e, 0x53, 0x81, + 0xa8, 0x09, 0x5b, 0xb0, 0x05, 0x6e, 0x47, 0x8d, 0xe1, 0x7a, 0x56, 0xc4, + 0xbf, 0xb5, 0xcc, 0xd2, 0x66, 0x63, 0x00, 0x04, 0xe4, 0xd1, 0x4a, 0x22, + 0xec, 0xe6, 0x64, 0x67, 0xa9, 0xb4, 0x1d, 0x46, 0xa7, 0x2d, 0x50, 0x17, + 0x68, 0xa4, 0x93, 0x5e, 0x72, 0x85, 0x8e, 0x6e, 0xfc, 0x58, 0xa1, 0x97, + 0xf0, 0x34, 0xcb, 0xa6, 0x68, 0xdd, 0xa8, 0x8a, 0xff, 0x40, 0xf9, 0x26, + 0xfd, 0x9f, 0xe9, 0x0d, 0xc1, 0x7f, 0x0c, 0xb4, 0x0f, 0xc7, 0x0d, 0xae, + 0x6d, 0xde, 0x07, 0x6e, 0x1d, 0xe8, 0x19, 0x9b, 0xf6, 0x41, 0xad, 0xdd, + 0xb0, 0x38, 0x99, 0x1b, 0x3c, 0x49, 0x10, 0xe2, 0x1b, 0x26, 0x27, 0x02, + 0xd5, 0x90, 0x59, 0x0e, 0x36, 0x54, 0x5b, 0x64, 0x9a, 0x1d, 0xec, 0xff, + 0xff, 0x29, 0x56, 0xfa, 0x7f, 0xda, 0xff, 0x7f, 0x13, 0x92, 0x75, 0x9c, + 0x05, 0x82, 0x67, 0xbb, 0x12, 0x0b, 0x17, 0xc9, 0x97, 0x14, 0x84, 0x63, + 0x87, 0xc5, 0xd8, 0x91, 0x47, 0x99, 0x9d, 0xa2, 0x17, 0x3d, 0x00, 0x53, + 0x6f, 0xc9, 0x33, 0xfb, 0xbf, 0x41, 0x3a, 0x88, 0x5a, 0x4c, 0x30, 0xdd, + 0x26, 0xbe, 0x5c, 0xfb, 0x06, 0x56, 0x86, 0x38, 0xd7, 0x34, 0x1b, 0x40, + 0x4f, 0xac, 0x60, 0x25, 0x68, 0x20, 0x3a, 0x32, 0x06, 0x8e, 0xef, 0xbf, + 0x20, 0x5e, 0xae, 0x56, 0x51, 0xf0, 0xd2, 0x97, 0xa9, 0xe2, 0x4a, 0x2b, + 0xa3, 0xae, 0xf6, 0x68, 0x8a, 0xe8, 0xf0, 0xe2, 0x3c, 0x8f, 0x09, 0xc5, + 0xc8, 0x4a, 0x48, 0x7e, 0x1b, 0x06, 0xc0, 0x40, 0xe8, 0xf4, 0x17, 0x8a, + 0x68, 0xb8, 0xba, 0x04, 0x09, 0x46, 0x29, 0xda, 0xa2, 0xda, 0xf2, 0xf1, + 0x2a, 0x69, 0x68, 0xa3, 0x13, 0x4d, 0xe5, 0xfe, 0x68, 0x01, 0xdd, 0xdb, + 0xe3, 0x4d, 0x52, 0xfb, 0xe6, 0xe4, 0xc2, 0xeb, 0x93, 0x55, 0x9d, 0xda, + 0x9c, 0x69, 0xf5, 0xda, 0x80, 0x13, 0x28, 0x54, 0x0a, 0xc5, 0x6b, 0x53, + 0x25, 0xe0, 0x2b, 0x29, 0xc3, 0x52, 0x8e, 0x77, 0xc2, 0x00, 0x06, 0x1b, + 0x00, 0xfd, 0xbf, 0xcb, 0x8f, 0x2f, 0xfa, 0x09, 0xbf, 0x56, 0xa1, 0x51, + 0x8c, 0xf0, 0x1d, 0x5d, 0x0a, 0xa9, 0x78, 0x94, 0x45, 0xec, 0xf4, 0x54, + 0x8e, 0x80, 0x16, 0xc8, 0xf8, 0x6b, 0xb0, 0xd4, 0xfc, 0x19, 0x9e, 0x0f, + 0xf9, 0xb9, 0x7c, 0x27, 0x0d, 0x0c, 0x77, 0xdd, 0xe1, 0x0e, 0x37, 0xa1, + 0xac, 0xa5, 0x3b, 0x8f, 0x9b, 0x2d, 0xb7, 0x15, 0x8a, 0x20, 0x39, 0xfb, + 0x2d, 0x05, 0xf8, 0x20, 0x2d, 0x0b, 0x14, 0x03, 0xbd, 0xf6, 0xe2, 0x03, + 0x1c, 0x23, 0x22, 0xba, 0xb8, 0xa9, 0xca, 0xcd, 0x42, 0xc8, 0x9d, 0x38, + 0xd8, 0x88, 0xbb, 0x2c, 0xd6, 0x71, 0x52, 0x64, 0x1c, 0x07, 0xd7, 0x68, + 0x72, 0x5f, 0x87, 0xec, 0x42, 0x70, 0xd4, 0x5d, 0x0c, 0x86, 0xab, 0xb1, + 0x5f, 0x36, 0xcd, 0xd9, 0x52, 0x4c, 0xaf, 0x82, 0x99, 0x34, 0x33, 0x83, + 0x4b, 0x07, 0xb0, 0x99, 0x7c, 0xd6, 0xa7, 0xb9, 0x87, 0xe9, 0x22, 0x4d, + 0xe8, 0x52, 0x3c, 0x88, 0xf3, 0xec, 0xb5, 0x60, 0x08, 0xe7, 0x1a, 0x32, + 0x90, 0x74, 0x36, 0xaf, 0xc9, 0x45, 0xe9, 0xd0, 0x37, 0x03, 0x02, 0x49, + 0xb0, 0xb3, 0x91, 0x4c, 0x3a, 0x74, 0xd1, 0xc4, 0xbb, 0xa1, 0xe5, 0x9e, + 0x8f, 0xcc, 0x36, 0xba, 0xde, 0x46, 0xf1, 0xa4, 0x10, 0x83, 0xd6, 0xa4, + 0x9b, 0x99, 0x90, 0xbd, 0xc8, 0x7a, 0x60, 0x02, 0xfa, 0xa4, 0x48, 0x00, + 0x8b, 0x83, 0x1b, 0x64, 0x3c, 0x8b, 0x12, 0xfc, 0x9a, 0xbc, 0x73, 0x51, + 0x87, 0x94, 0x89, 0x7a, 0xb0, 0xd0, 0xba, 0xe4, 0xda, 0x6f, 0xe3, 0x07, + 0x52, 0xf8, 0x60, 0xd4, 0x36, 0x6b, 0x30, 0x9c, 0x21, 0x42, 0xf6, 0x76, + 0x0e, 0x18, 0x4e, 0x56, 0xdd, 0x15, 0xd2, 0xd9, 0x9b, 0xe5, 0x71, 0x8c, + 0x3d, 0x8c, 0xa1, 0x7e, 0x1b, 0xe7, 0x29, 0xc6, 0xaf, 0x34, 0x66, 0x5e, + 0x8a, 0xb2, 0x36, 0xaa, 0x8d, 0x36, 0xbd, 0x56, 0x6d, 0xe1, 0x30, 0x50, + 0xed, 0x7d, 0xe0, 0xf7, 0x51, 0x0c, 0xea, 0x4b, 0xe3, 0x6b, 0x83, 0x55, + 0xeb, 0xb7, 0x28, 0xdc, 0xf8, 0x0d, 0x72, 0xff, 0x5e, 0x2d, 0xea, 0xab, + 0xb3, 0x55, 0xab, 0xf7, 0x6a, 0x0b, 0x38, 0xac, 0x55, 0x7b, 0x65, 0x06, + 0x5d, 0xc7, 0x6a, 0xde, 0x1e, 0x67, 0xb5, 0x2f, 0xe6, 0xf9, 0x9c, 0x58, + 0xed, 0x33, 0xfa, 0xce, 0x6a, 0xef, 0xa2, 0x7d, 0x6a, 0x63, 0xb5, 0x9d, + 0x77, 0xd9, 0xa2, 0xa0, 0xda, 0x57, 0xd3, 0x0d, 0xc6, 0x54, 0x2d, 0xea, + 0x05, 0xae, 0xac, 0xb6, 0x1e, 0xaa, 0xcd, 0xac, 0x06, 0x26, 0x83, 0x6a, + 0x15, 0x79, 0x0d, 0xaa, 0x41, 0x32, 0x0a, 0xac, 0xd6, 0x81, 0x29, 0x4d, + 0xa8, 0xe6, 0x51, 0x6d, 0x28, 0xab, 0x6d, 0x87, 0x6a, 0xcb, 0xa5, 0x6a, + 0xa1, 0xac, 0x56, 0x1f, 0xaa, 0xb5, 0x87, 0x6a, 0xfd, 0xdf, 0x5b, 0x6d, + 0x3b, 0x54, 0xfb, 0xf3, 0x50, 0xed, 0x8f, 0x43, 0xb5, 0xdf, 0x0e, 0xd5, + 0x7c, 0x59, 0xed, 0x4b, 0x31, 0x93, 0xf5, 0x2e, 0x65, 0x60, 0x26, 0x2b, + 0x43, 0xae, 0x8e, 0x33, 0xd9, 0x18, 0x72, 0x59, 0x35, 0x04, 0x65, 0x56, + 0xe1, 0xa3, 0xd6, 0xcd, 0x47, 0xe4, 0x7a, 0x6b, 0x8f, 0xe7, 0x6a, 0x93, + 0xad, 0x5b, 0xc4, 0x7d, 0xbf, 0x78, 0xc3, 0xc5, 0x88, 0xe9, 0xe3, 0xde, + 0xaa, 0x99, 0xa4, 0x6c, 0xef, 0xec, 0xc5, 0xcf, 0x89, 0x25, 0x76, 0xec, + 0xea, 0xd6, 0x12, 0xb9, 0xe2, 0x26, 0xb7, 0x6f, 0x09, 0x91, 0x1a, 0x8c, + 0x4d, 0x34, 0x7d, 0xd9, 0xe2, 0xd7, 0x9f, 0xe3, 0x06, 0xa9, 0xad, 0xed, + 0x7d, 0x95, 0xde, 0x45, 0x45, 0x58, 0xdf, 0xa1, 0xf0, 0x7e, 0x6d, 0xa2, + 0x91, 0x66, 0x34, 0x6a, 0xb0, 0x44, 0xa3, 0x8e, 0x6d, 0xcc, 0xb8, 0x45, + 0xdf, 0xc7, 0xd9, 0xc1, 0x59, 0xbe, 0xfb, 0xfe, 0x8c, 0xe1, 0x16, 0x73, + 0xcd, 0x45, 0x37, 0xd9, 0x6c, 0x68, 0x29, 0xaf, 0x46, 0x93, 0x1b, 0xc8, + 0x40, 0x5c, 0x94, 0x31, 0xc0, 0x92, 0x66, 0x04, 0xd6, 0xbc, 0x44, 0x83, + 0xbe, 0xa2, 0x12, 0x4f, 0x14, 0xda, 0x9c, 0x4e, 0x58, 0x1e, 0x5b, 0x68, + 0xb4, 0x66, 0x5b, 0xda, 0x40, 0x7a, 0x7b, 0x88, 0x0c, 0x38, 0x07, 0xc9, + 0x51, 0xcc, 0x1d, 0x8d, 0xa0, 0xd6, 0xf4, 0xd0, 0x80, 0x84, 0x66, 0x5a, + 0x09, 0xc5, 0x73, 0xa2, 0xd2, 0xfa, 0xbf, 0x44, 0x7e, 0xbb, 0x44, 0x1d, + 0x4b, 0x5d, 0x2b, 0x9d, 0x07, 0x4a, 0xea, 0x58, 0xda, 0x79, 0xba, 0x82, + 0xb1, 0x95, 0xe4, 0x15, 0x40, 0xc6, 0x7c, 0x53, 0x1d, 0x40, 0x36, 0x07, + 0x90, 0xed, 0x09, 0xc8, 0xa5, 0xb8, 0xf3, 0x87, 0x06, 0x0e, 0x76, 0x97, + 0xea, 0x70, 0xd7, 0x1c, 0x9a, 0xcb, 0x2e, 0xbe, 0xd1, 0x25, 0x0e, 0xb5, + 0x5f, 0xa0, 0x97, 0xb8, 0x83, 0x39, 0xc2, 0xf3, 0x4e, 0xcc, 0x9b, 0x22, + 0xdc, 0xe4, 0x52, 0xb4, 0x76, 0x27, 0xd1, 0x27, 0xe0, 0xd3, 0x35, 0xb4, + 0x5f, 0x94, 0x2c, 0x33, 0x19, 0x65, 0x26, 0x8c, 0x20, 0x14, 0x3c, 0x39, + 0xdd, 0x39, 0x36, 0x7e, 0x81, 0xef, 0xce, 0x87, 0x3b, 0x57, 0xde, 0x4d, + 0xe5, 0x5d, 0xe6, 0x65, 0xf9, 0x39, 0xb6, 0x9e, 0x06, 0x5f, 0x87, 0xc3, + 0xbc, 0xf4, 0x57, 0x84, 0xb3, 0xba, 0x90, 0x04, 0x00, 0xb6, 0x2b, 0x7a, + 0x85, 0x25, 0xf0, 0xea, 0x99, 0x40, 0x56, 0x6a, 0x48, 0xf1, 0x67, 0x36, + 0x0f, 0x69, 0x98, 0xaa, 0x2d, 0xdf, 0x6f, 0xf2, 0xe2, 0x66, 0xc1, 0x42, + 0x7e, 0xdc, 0xe4, 0x91, 0xcd, 0x53, 0x36, 0x6a, 0x64, 0x03, 0x6b, 0xcb, + 0x06, 0x9c, 0x4c, 0xc4, 0xc9, 0x0c, 0x1c, 0x52, 0x54, 0xfd, 0xa2, 0xda, + 0x0a, 0xab, 0x4f, 0x72, 0x0a, 0x55, 0x6b, 0xc2, 0xab, 0x74, 0x51, 0x6b, + 0xe6, 0x5a, 0x01, 0x8e, 0x67, 0x5c, 0x53, 0x4a, 0xe3, 0x71, 0x97, 0xf1, + 0x78, 0x3c, 0xa2, 0xc3, 0xab, 0xc0, 0x57, 0x5c, 0x7a, 0xea, 0xb3, 0x9b, + 0xd4, 0xdb, 0x55, 0x62, 0xcf, 0x17, 0x09, 0xde, 0xef, 0xa5, 0x56, 0xbc, + 0x91, 0x12, 0xf1, 0x42, 0x2a, 0x03, 0x04, 0xe6, 0xda, 0xce, 0x0e, 0x42, + 0x6d, 0xc0, 0xeb, 0x74, 0xfe, 0x66, 0x1f, 0x7d, 0x2d, 0x83, 0xd5, 0x1e, + 0x71, 0x61, 0xaa, 0x1d, 0x6a, 0x63, 0x07, 0xd6, 0x51, 0xcb, 0x83, 0x4e, + 0xb1, 0xea, 0x54, 0xf9, 0x45, 0xf6, 0xb2, 0x19, 0x32, 0x90, 0x8f, 0xae, + 0xe6, 0xc9, 0x6a, 0x0f, 0x06, 0xb8, 0x32, 0x37, 0xe3, 0x60, 0x5b, 0xae, + 0xa2, 0xb1, 0x67, 0xd5, 0x71, 0xf1, 0x4b, 0x43, 0x23, 0xd0, 0xdc, 0xd2, + 0x2e, 0x35, 0xe9, 0x30, 0xf8, 0xa1, 0xa3, 0x74, 0x86, 0xbd, 0xd0, 0x98, + 0x0e, 0x3a, 0x62, 0xaf, 0x52, 0x6b, 0xc7, 0x99, 0x91, 0xb1, 0x76, 0x4d, + 0x73, 0xc4, 0xa4, 0x53, 0xde, 0x87, 0x86, 0x5a, 0xb5, 0xe3, 0xd1, 0xed, + 0x1b, 0x28, 0x45, 0x6b, 0xfe, 0xee, 0x19, 0x9b, 0xdc, 0x83, 0x00, 0x29, + 0xe0, 0x3e, 0x4a, 0x31, 0xb0, 0xee, 0x8d, 0x15, 0x05, 0x22, 0xc7, 0x33, + 0xd9, 0x53, 0x64, 0xfd, 0x0a, 0x5a, 0xd1, 0x05, 0x86, 0xd6, 0xf7, 0xc6, + 0x45, 0x66, 0xd4, 0xee, 0x41, 0xee, 0x45, 0xf9, 0x02, 0x6e, 0x10, 0x0d, + 0x6f, 0x24, 0x92, 0xa7, 0x0e, 0x77, 0x21, 0x1d, 0xbf, 0xce, 0xf3, 0x24, + 0xbd, 0x11, 0xe5, 0x05, 0x15, 0x3a, 0x18, 0x14, 0x07, 0x2b, 0x66, 0x38, + 0xfe, 0x84, 0xe7, 0x50, 0x0c, 0xf1, 0xc9, 0x8a, 0xe9, 0x87, 0x9e, 0x5c, + 0xfa, 0x6a, 0x04, 0x4f, 0x6d, 0x44, 0x73, 0x8d, 0x9a, 0x6b, 0x03, 0x83, + 0xeb, 0xad, 0xd7, 0xe8, 0xec, 0xac, 0xce, 0xb2, 0xd7, 0xb4, 0xb3, 0x0c, + 0x35, 0x3d, 0x42, 0xa8, 0x8d, 0x48, 0xfc, 0x15, 0x83, 0xef, 0x44, 0x72, + 0x7a, 0x5d, 0x78, 0xd1, 0x0f, 0xd1, 0x1f, 0x3a, 0x0d, 0x14, 0x53, 0x9a, + 0x5c, 0x95, 0x41, 0xaf, 0xe8, 0x04, 0xc5, 0x7d, 0x25, 0x4f, 0x60, 0x72, + 0xe9, 0x24, 0x97, 0x83, 0x42, 0xc4, 0x82, 0x82, 0x3b, 0x93, 0xbb, 0x30, + 0x85, 0x32, 0x84, 0xf4, 0x52, 0x46, 0x80, 0x64, 0x6e, 0xe7, 0xcc, 0xc6, + 0xf5, 0xe3, 0x71, 0xa5, 0x36, 0xf0, 0x96, 0xf8, 0xb5, 0x74, 0xc4, 0x2f, + 0xa2, 0x69, 0x48, 0x6f, 0x85, 0xc0, 0x33, 0x12, 0x07, 0xfe, 0x5c, 0xca, + 0x2c, 0x6a, 0x37, 0xf4, 0x9d, 0x38, 0x05, 0x05, 0xb8, 0x0e, 0x6f, 0xfa, + 0x25, 0xef, 0x4a, 0xbc, 0xf8, 0x28, 0x9b, 0xe5, 0x7b, 0x6d, 0x9a, 0xb7, + 0xda, 0x34, 0x37, 0xdc, 0x34, 0xf0, 0x8f, 0x45, 0x78, 0x3d, 0xf5, 0xe4, + 0x4d, 0x2a, 0xfc, 0xd7, 0x40, 0xcb, 0xf3, 0x9f, 0xd2, 0xe6, 0x83, 0x54, + 0xfd, 0xa0, 0x2d, 0x1c, 0xb4, 0x85, 0x03, 0xb7, 0x30, 0x5d, 0xa5, 0xd2, + 0x93, 0xe8, 0x64, 0x09, 0x0a, 0x98, 0x53, 0x44, 0x88, 0x56, 0x6b, 0x4d, + 0xa4, 0xdb, 0x33, 0x3d, 0x4e, 0xba, 0x1c, 0xb0, 0xfa, 0xce, 0x8d, 0xbc, + 0x6e, 0xf2, 0x3c, 0x33, 0x7e, 0x58, 0xe1, 0xe7, 0x78, 0x4d, 0xab, 0x4f, + 0x41, 0x22, 0xf8, 0xd4, 0x53, 0x07, 0x97, 0x52, 0x4c, 0x5b, 0x58, 0xbb, + 0xe0, 0xe6, 0xee, 0xe3, 0x94, 0x19, 0x82, 0x2f, 0x74, 0x8e, 0xcf, 0xb4, + 0xf0, 0x59, 0x54, 0x41, 0x45, 0x97, 0xae, 0x82, 0x4b, 0x1a, 0x7e, 0xb4, + 0xa9, 0xe5, 0x4b, 0x94, 0x1d, 0xc3, 0x0e, 0xcd, 0x89, 0x6e, 0x88, 0xbb, + 0xd0, 0x66, 0xf8, 0x91, 0xd5, 0xdf, 0xff, 0x2d, 0xd5, 0x17, 0x56, 0x9f, + 0x59, 0xfd, 0xb4, 0xf3, 0x2f, 0x58, 0xbd, 0xa5, 0x6f, 0x8f, 0x63, 0x5f, + 0x38, 0xf6, 0x99, 0x63, 0x9f, 0x38, 0x76, 0x9b, 0xba, 0x86, 0x31, 0xc9, + 0xad, 0xd9, 0xce, 0xe2, 0x76, 0xb6, 0x38, 0x0c, 0x67, 0x33, 0x6f, 0xee, + 0x4c, 0x61, 0xfa, 0xe0, 0xb9, 0x5d, 0xb8, 0x40, 0xf2, 0x87, 0xca, 0x73, + 0xde, 0xb0, 0x58, 0xe1, 0x25, 0x1d, 0xd3, 0x9e, 0x78, 0xf1, 0xb0, 0x75, + 0x5f, 0xd8, 0xba, 0x05, 0x4e, 0x57, 0x01, 0x9d, 0xaf, 0x72, 0xe7, 0x6f, + 0x5d, 0xb8, 0x86, 0x53, 0xa7, 0x78, 0x51, 0xba, 0x83, 0xe3, 0x0a, 0xd0, + 0x03, 0x60, 0x71, 0x22, 0xf2, 0x16, 0x3b, 0x86, 0x0b, 0x29, 0x3e, 0xc8, + 0x62, 0x7a, 0xb6, 0x1c, 0xc4, 0xa3, 0x78, 0xa1, 0x8e, 0x5b, 0x86, 0x21, + 0x17, 0x08, 0x01, 0xb2, 0xea, 0x9f, 0xef, 0x57, 0x3d, 0x24, 0xf7, 0x39, + 0xaa, 0x87, 0xe4, 0x3f, 0x97, 0x8b, 0x5c, 0x0e, 0x74, 0xb9, 0xd7, 0xbf, + 0x67, 0xeb, 0xb7, 0x56, 0x57, 0xcc, 0x4c, 0xc3, 0x80, 0x11, 0x85, 0xd4, + 0x9c, 0x4e, 0xdd, 0x09, 0xd2, 0x36, 0x9c, 0xf9, 0x36, 0x7d, 0xe7, 0xcc, + 0xb0, 0xae, 0x0a, 0xd8, 0x71, 0x51, 0x1e, 0xcf, 0x1b, 0xd6, 0x7e, 0xaf, + 0x99, 0x72, 0xdd, 0xb7, 0x2b, 0xfb, 0x5d, 0x58, 0x77, 0x82, 0x36, 0x33, + 0xd1, 0x66, 0x94, 0x57, 0xb8, 0x21, 0x76, 0x29, 0x00, 0xa9, 0xe3, 0xac, + 0xf5, 0x98, 0x54, 0xfb, 0x79, 0x85, 0x31, 0x26, 0xc9, 0x67, 0x74, 0xf2, + 0x0c, 0x61, 0xba, 0x07, 0xae, 0x8e, 0x4b, 0xab, 0x40, 0x83, 0x33, 0x9a, + 0x5f, 0x4e, 0xe2, 0x9c, 0xa6, 0x63, 0xc0, 0x8b, 0xbc, 0xd0, 0xe2, 0x24, + 0xda, 0x1a, 0x62, 0x1f, 0x71, 0x2c, 0x91, 0x6e, 0x39, 0x3c, 0x12, 0x87, + 0x1c, 0x99, 0xfc, 0xd2, 0x05, 0x05, 0x3c, 0xe5, 0x78, 0xb7, 0x96, 0xdf, + 0x82, 0xcb, 0x24, 0x4b, 0xa4, 0x4a, 0xf3, 0xcd, 0x40, 0x37, 0x2d, 0x0b, + 0x30, 0x99, 0x18, 0x5c, 0xa7, 0xd5, 0x3b, 0x2d, 0xfe, 0x9c, 0x70, 0xa3, + 0x08, 0xe5, 0xeb, 0x31, 0x67, 0xae, 0xc4, 0xbc, 0x5f, 0xa3, 0x38, 0x47, + 0x9f, 0xb6, 0x49, 0xde, 0x96, 0x94, 0xfd, 0xaf, 0x58, 0xfc, 0x18, 0xe6, + 0xfc, 0x7b, 0x17, 0xbf, 0x2b, 0xc9, 0x53, 0x9f, 0x82, 0xf2, 0x3e, 0xdf, + 0x82, 0xc8, 0x55, 0x0e, 0xec, 0x7c, 0x59, 0xf2, 0x46, 0xb2, 0x54, 0xf1, + 0x83, 0x96, 0x72, 0x40, 0x8f, 0xb7, 0xba, 0x9d, 0xb1, 0x0f, 0x93, 0x43, + 0x5f, 0x83, 0x23, 0x6d, 0x35, 0xb7, 0x60, 0x0b, 0x5b, 0xc2, 0xd4, 0x41, + 0xa7, 0x15, 0xb5, 0x39, 0xe5, 0x6d, 0x47, 0x59, 0x46, 0x3c, 0x6d, 0xc0, + 0x60, 0x72, 0x14, 0x64, 0xcd, 0xec, 0x82, 0x74, 0x07, 0xd8, 0x18, 0x82, + 0x1c, 0x7d, 0x94, 0xdc, 0x92, 0xa0, 0x25, 0xc5, 0xcd, 0x61, 0xe9, 0x81, + 0x07, 0x79, 0x02, 0x31, 0x98, 0x20, 0x67, 0x5e, 0x72, 0xfc, 0xe8, 0x2d, + 0xa9, 0x24, 0xd7, 0xb2, 0x58, 0xdc, 0x59, 0x6c, 0x55, 0xaf, 0xc9, 0x4c, + 0x28, 0x4e, 0x47, 0x5b, 0x8a, 0xfa, 0x8a, 0xdb, 0xf6, 0x10, 0xcc, 0x78, + 0x40, 0x0d, 0x66, 0xb1, 0x27, 0x4d, 0xf7, 0xe9, 0xad, 0x8b, 0x85, 0x83, + 0x54, 0x68, 0xe1, 0x0d, 0xad, 0x2c, 0x12, 0x6f, 0xc8, 0x21, 0x3e, 0x91, + 0x27, 0xff, 0x41, 0x86, 0xf2, 0x1b, 0x19, 0x09, 0x7d, 0x3b, 0x7f, 0x52, + 0xc4, 0xbf, 0xad, 0xf8, 0x91, 0xa0, 0xe8, 0x53, 0xf1, 0x3f, 0xba, 0x58, + 0xa8, 0x28, 0xc1, 0x8a, 0x02, 0xd5, 0x3d, 0x11, 0xf9, 0x13, 0x8b, 0x6f, + 0x28, 0x4f, 0x5c, 0xda, 0x25, 0x4d, 0x96, 0x9b, 0xca, 0x3d, 0xd6, 0xa4, + 0x20, 0x53, 0x13, 0xe6, 0x9b, 0x90, 0x42, 0x15, 0x25, 0x46, 0x3d, 0x47, + 0x92, 0x0e, 0x8f, 0x66, 0x31, 0x94, 0xb2, 0x1c, 0xb7, 0xcb, 0xe2, 0x01, + 0xc5, 0x92, 0xa2, 0x44, 0xd7, 0x92, 0xac, 0x8e, 0x62, 0xd2, 0x33, 0x7e, + 0xc4, 0x4e, 0x42, 0xd0, 0x20, 0x92, 0xf4, 0x43, 0x7f, 0x73, 0x62, 0x80, + 0x4f, 0xff, 0xaf, 0xff, 0x8f, 0x6b, 0xf8, 0xe3, 0xff, 0x3f, 0x86, 0x91, + 0xfe, 0x8a, 0xff, 0xff, 0x95, 0x7e, 0x8f, 0x61, 0x3e, 0x1f, 0xc3, 0xff, + 0xf0, 0xb4, 0xe3, 0x9e, 0xfe, 0x5f, 0xfc, 0xef, 0x22, 0x8f, 0xb7, 0xa4, + 0x83, 0xc6, 0x26, 0x8f, 0x53, 0x8f, 0xd4, 0x98, 0xe8, 0x44, 0xe1, 0x7f, + 0x24, 0x2e, 0x51, 0x37, 0x08, 0x14, 0x3e, 0xa4, 0x3a, 0xe4, 0xf7, 0xe7, + 0xbc, 0xa5, 0x93, 0x62, 0x5b, 0x8e, 0xd2, 0xbd, 0xf4, 0x12, 0x19, 0xcb, + 0xa2, 0x54, 0x1f, 0xff, 0x06, 0x9a, 0xb3, 0x1b, 0x98, 0x26, 0xec, 0x58, + 0xda, 0xd8, 0x4b, 0x1f, 0x74, 0x86, 0xed, 0x44, 0x49, 0x63, 0x48, 0x36, + 0xb1, 0x3e, 0x59, 0x21, 0xdf, 0x53, 0x4e, 0x79, 0x45, 0x2f, 0x03, 0xcd, + 0x45, 0x32, 0x13, 0xc9, 0xba, 0x24, 0xab, 0xd2, 0x79, 0x31, 0xad, 0x26, + 0x8c, 0xdf, 0x8a, 0x40, 0x35, 0x66, 0x8f, 0xb1, 0x3e, 0xa6, 0xe2, 0x9f, + 0xa8, 0xdc, 0x63, 0xd1, 0xc6, 0xa3, 0xf0, 0x25, 0xc3, 0xf8, 0x0f, 0x2a, + 0x06, 0x1a, 0xce, 0xd9, 0x3b, 0xda, 0x63, 0x5a, 0xdc, 0xbf, 0x60, 0xf1, + 0x67, 0x3a, 0xce, 0x0c, 0x53, 0x6b, 0x62, 0x6a, 0x4b, 0x4c, 0x3d, 0x29, + 0xbe, 0x88, 0xc8, 0x43, 0x12, 0xd7, 0x9b, 0xab, 0x4a, 0xed, 0x5b, 0x3a, + 0x18, 0xf8, 0x56, 0xea, 0xea, 0x61, 0xbc, 0xfb, 0x18, 0x1f, 0x6b, 0x4d, + 0x6c, 0x9f, 0x28, 0xb6, 0x4f, 0x14, 0xdb, 0xbf, 0x84, 0xa0, 0x57, 0x8b, + 0x4e, 0xad, 0x9f, 0x10, 0xdf, 0x37, 0x5a, 0x3d, 0xff, 0xa4, 0xd5, 0xf3, + 0x86, 0x47, 0x47, 0x77, 0xd8, 0xef, 0x8b, 0xc7, 0xfb, 0xb3, 0xaf, 0xe9, + 0xcd, 0x6a, 0xb0, 0xba, 0x4b, 0x0b, 0x7b, 0xc4, 0xd0, 0x9b, 0xad, 0x7d, + 0x75, 0x50, 0xd9, 0xa7, 0x1a, 0xea, 0x44, 0xfc, 0x18, 0xc6, 0x9e, 0x3f, + 0x0a, 0x35, 0xad, 0x85, 0x29, 0x2b, 0x3d, 0xd6, 0xa1, 0x81, 0x64, 0xc9, + 0xa5, 0x77, 0xf3, 0xa4, 0x04, 0x59, 0x4b, 0x4b, 0x56, 0x86, 0x9e, 0xaa, + 0xff, 0x4a, 0xd5, 0x1f, 0xc7, 0xef, 0x97, 0x9c, 0xba, 0xa7, 0xea, 0x3f, + 0xa7, 0xfa, 0x10, 0x9e, 0x7e, 0x3f, 0xe7, 0x77, 0x90, 0x5b, 0x78, 0x4b, + 0xb1, 0x85, 0x52, 0xcc, 0x53, 0xe1, 0x53, 0xe1, 0x23, 0x2a, 0x0c, 0xc9, + 0x2d, 0x32, 0x27, 0x0a, 0x62, 0x98, 0xfc, 0xa8, 0x0b, 0x3d, 0x0a, 0xdf, + 0xa1, 0x90, 0xc7, 0xf4, 0x7f, 0xbd, 0x56, 0x38, 0xc8, 0x23, 0xd6, 0xa6, + 0x57, 0xd9, 0x5f, 0x42, 0x5d, 0x7c, 0x0f, 0xc3, 0xb0, 0x69, 0x6f, 0x3d, + 0x4e, 0xc0, 0x6a, 0xe1, 0x34, 0xa6, 0x7f, 0xab, 0x86, 0xb8, 0xf9, 0x02, + 0x1e, 0xe6, 0x90, 0xad, 0xc1, 0xd2, 0x11, 0x90, 0x3b, 0xc9, 0x75, 0x1e, + 0xd0, 0x63, 0xcb, 0xe5, 0x57, 0x77, 0x65, 0x0a, 0x1e, 0x45, 0xc8, 0x25, + 0x6c, 0xfb, 0xa0, 0x97, 0x27, 0xcd, 0x73, 0xe5, 0x6d, 0xa8, 0x66, 0x9f, + 0xc6, 0xd2, 0x30, 0x60, 0x72, 0xd4, 0x72, 0xc9, 0x49, 0x94, 0x82, 0x5e, + 0x5a, 0x1a, 0xbc, 0x63, 0xb1, 0x32, 0x5a, 0xb2, 0x84, 0x89, 0xac, 0x63, + 0x6b, 0x69, 0x6f, 0x47, 0x46, 0x6f, 0x62, 0x32, 0xf0, 0x80, 0x9d, 0x40, + 0x06, 0xb8, 0x86, 0x65, 0x20, 0x68, 0xa5, 0x55, 0x46, 0x30, 0xcb, 0x37, + 0x30, 0x28, 0x66, 0x54, 0xca, 0xe8, 0xcc, 0x43, 0x66, 0x19, 0x53, 0x8b, + 0x25, 0x58, 0x1d, 0x97, 0x6d, 0x6c, 0xe1, 0xed, 0x42, 0x46, 0x03, 0xed, + 0x1b, 0xaf, 0x47, 0x51, 0xb8, 0x47, 0x06, 0xb4, 0x2d, 0xcb, 0xb0, 0xbf, + 0x4a, 0x19, 0x1d, 0x96, 0x02, 0x11, 0xb9, 0x5c, 0x1e, 0xcb, 0xa8, 0xe1, + 0xb7, 0xcb, 0x19, 0x0d, 0x66, 0x18, 0xdf, 0x72, 0x25, 0x9c, 0xe1, 0x0c, + 0x70, 0xbc, 0xa9, 0x94, 0x21, 0x47, 0x66, 0xc5, 0x28, 0x01, 0x93, 0xf1, + 0x1d, 0x96, 0x7b, 0x64, 0x86, 0x21, 0xcf, 0xdc, 0x30, 0x20, 0xc3, 0x29, + 0xd6, 0x29, 0x65, 0x9c, 0xce, 0x4d, 0xa5, 0x0c, 0x46, 0xcb, 0xe0, 0xb4, + 0xc2, 0x98, 0xd1, 0x33, 0xa3, 0xa6, 0xe9, 0xc2, 0xc2, 0x70, 0x92, 0x5f, + 0x15, 0xb6, 0x85, 0xe5, 0x98, 0x71, 0x58, 0xcd, 0x32, 0xa3, 0x63, 0x34, + 0xa4, 0x05, 0x8e, 0xc0, 0x11, 0x82, 0x0c, 0x04, 0xdf, 0xc8, 0x33, 0x02, + 0xbc, 0x1f, 0xb3, 0x4b, 0x58, 0x1b, 0x21, 0x09, 0x15, 0xda, 0x53, 0xc7, + 0x8c, 0x4d, 0x19, 0xd3, 0xb5, 0x8c, 0xb3, 0x2a, 0x29, 0xe3, 0xa4, 0x95, + 0xa2, 0xd9, 0x63, 0xc7, 0x3e, 0x9d, 0x76, 0x3d, 0x8d, 0xa5, 0xbb, 0x88, + 0xcc, 0xc8, 0x58, 0x4e, 0x67, 0x2c, 0x4d, 0xe1, 0x71, 0x4e, 0xeb, 0xd3, + 0x59, 0x4f, 0xcb, 0xd0, 0x95, 0x48, 0xcc, 0x95, 0xd3, 0x52, 0x2e, 0xa7, + 0x8b, 0x9d, 0x56, 0xff, 0x88, 0x0e, 0xb5, 0x10, 0xa6, 0xc0, 0x20, 0xa1, + 0xd4, 0x39, 0x36, 0x0b, 0x0b, 0x97, 0x53, 0x3c, 0x3d, 0xc3, 0xe4, 0x4d, + 0x19, 0xd3, 0x29, 0xf2, 0x6b, 0x37, 0x64, 0x2c, 0x3e, 0xdd, 0x40, 0x8b, + 0xb6, 0xd8, 0x71, 0xcf, 0xa5, 0x4d, 0xd8, 0x73, 0x9b, 0xd6, 0xda, 0xa6, + 0xdd, 0xf9, 0x46, 0x4e, 0x93, 0x72, 0xb2, 0xf7, 0x45, 0x0c, 0x9a, 0x53, + 0x72, 0x51, 0x10, 0x94, 0x13, 0x0a, 0xd3, 0x65, 0x1a, 0x74, 0xb6, 0x8e, + 0x27, 0x64, 0xcb, 0xd3, 0x20, 0x50, 0x10, 0x36, 0x64, 0xc8, 0xdf, 0x1d, + 0xa1, 0x2b, 0x63, 0x16, 0xca, 0x3d, 0xfd, 0x7f, 0xfa, 0xff, 0xf4, 0xff, + 0xda, 0xff, 0xbf, 0xe9, 0xe7, 0xe2, 0xcf, 0xc8, 0xbe, 0xb5, 0xab, 0x17, + 0x3c, 0x2d, 0xbb, 0x0b, 0x62, 0x07, 0x87, 0xd7, 0x4a, 0xef, 0xce, 0xa6, + 0x68, 0x35, 0xc6, 0xeb, 0xde, 0x2e, 0xd7, 0x7b, 0x66, 0x7b, 0xbb, 0x2c, + 0xdf, 0xa2, 0x99, 0x1e, 0x94, 0x6d, 0x63, 0x28, 0x86, 0xd6, 0xde, 0x3b, + 0x7b, 0x48, 0x43, 0xb0, 0x31, 0x54, 0x7f, 0x29, 0x7b, 0x4c, 0x23, 0xb3, + 0xa1, 0xd5, 0xf7, 0xce, 0xde, 0xf2, 0x10, 0x6c, 0x68, 0xfe, 0xde, 0xd9, + 0x73, 0xce, 0x0e, 0x79, 0x64, 0x40, 0xa2, 0x78, 0x36, 0x70, 0x7c, 0x65, + 0x31, 0x66, 0xef, 0x74, 0xd8, 0xde, 0x6c, 0xcc, 0xd9, 0x43, 0xce, 0x5e, + 0xec, 0xb8, 0xc3, 0x94, 0xdd, 0x45, 0x32, 0xbe, 0xf3, 0x77, 0xcb, 0xb6, + 0x4f, 0xd7, 0xf5, 0xc8, 0x7e, 0x67, 0xd9, 0x6b, 0x91, 0x3d, 0x2a, 0xfb, + 0x23, 0xcc, 0xcf, 0xd1, 0xae, 0x6b, 0xaf, 0xec, 0xed, 0x23, 0x7b, 0x75, + 0x96, 0x3d, 0xe5, 0xec, 0x2d, 0x65, 0xb7, 0x30, 0x35, 0xc7, 0xe9, 0x9c, + 0x61, 0x85, 0xfe, 0x78, 0x92, 0xbd, 0x14, 0xd9, 0xf1, 0xa5, 0x51, 0x65, + 0x7b, 0x63, 0x71, 0x31, 0x46, 0x6d, 0x17, 0xec, 0xe7, 0x38, 0xb2, 0xdb, + 0xb3, 0x07, 0x65, 0x3f, 0x37, 0x41, 0xc1, 0xde, 0xba, 0x8b, 0x6f, 0xe8, + 0xed, 0x43, 0x78, 0xad, 0xec, 0xea, 0x52, 0xf6, 0x9a, 0xb2, 0x3b, 0x13, + 0xff, 0x9f, 0xc5, 0xec, 0x67, 0x66, 0xe4, 0x5e, 0x52, 0x76, 0x7f, 0x29, + 0x7b, 0x52, 0xf6, 0x60, 0x2f, 0x7f, 0x98, 0x4d, 0x7b, 0xc1, 0x4b, 0x86, + 0x95, 0xb2, 0x9b, 0x22, 0xdb, 0x2b, 0x3b, 0xa4, 0xec, 0xf8, 0x6e, 0xa1, + 0xc7, 0xf1, 0x90, 0x83, 0x8f, 0xd9, 0x53, 0xca, 0x0e, 0x39, 0xbb, 0xbd, + 0x90, 0xdd, 0x47, 0xd9, 0xc2, 0x34, 0x9b, 0x25, 0xbe, 0x69, 0x48, 0x57, + 0xd9, 0x49, 0x76, 0x55, 0x64, 0x77, 0xcc, 0xb6, 0x3c, 0x44, 0xec, 0x22, + 0x6f, 0x28, 0xb2, 0x6b, 0x65, 0xf7, 0x08, 0xa1, 0x89, 0xd9, 0xb5, 0xb2, + 0xdb, 0xe8, 0x7b, 0x43, 0xb6, 0x8b, 0x3a, 0xd6, 0x5c, 0x64, 0xbb, 0xb3, + 0xec, 0x26, 0xc6, 0xf9, 0x32, 0xdb, 0xc7, 0xd7, 0x88, 0x95, 0x3d, 0xfb, + 0xad, 0xc8, 0x9e, 0xce, 0xb3, 0xfb, 0x88, 0x1f, 0xc8, 0xae, 0x0d, 0x3f, + 0x94, 0xfd, 0x92, 0xee, 0x1e, 0xcb, 0x5e, 0xcf, 0xb3, 0x2b, 0x7b, 0xd9, + 0x14, 0xd9, 0x11, 0x73, 0x53, 0xf6, 0xd7, 0xb0, 0x14, 0xd9, 0xc3, 0x79, + 0x76, 0x9b, 0xb3, 0x1d, 0xa1, 0x2a, 0xc8, 0xda, 0xe5, 0xec, 0xf9, 0x42, + 0xb6, 0xcf, 0xd9, 0xcd, 0x31, 0x7b, 0xca, 0xd9, 0xdb, 0x85, 0xec, 0xba, + 0xc8, 0xee, 0x0f, 0xd9, 0x6b, 0x91, 0x3d, 0x5e, 0xc8, 0xee, 0x72, 0x76, + 0x75, 0xcc, 0x1e, 0x72, 0xf6, 0x72, 0x21, 0xdb, 0x15, 0xd9, 0xed, 0x21, + 0x7b, 0x2e, 0xb2, 0xdd, 0x85, 0xec, 0xa6, 0xc8, 0xf6, 0x65, 0xf6, 0x56, + 0x64, 0x4f, 0xca, 0xae, 0x8b, 0xec, 0xfe, 0x5a, 0xf6, 0x98, 0xb3, 0xd7, + 0x94, 0xdd, 0xe5, 0x6c, 0x7d, 0x98, 0xc4, 0x48, 0x1f, 0xd0, 0x95, 0x14, + 0x7d, 0x24, 0x59, 0x9c, 0x5d, 0xaa, 0x67, 0x04, 0x7b, 0x15, 0x8d, 0x14, + 0x09, 0x1d, 0x48, 0x8f, 0xc7, 0x7c, 0x6e, 0xa2, 0x01, 0xa0, 0x26, 0x6f, + 0x15, 0x7a, 0x56, 0xe8, 0x58, 0x41, 0x8a, 0x94, 0xdc, 0xa7, 0x35, 0x2b, + 0xc8, 0x82, 0x0b, 0x9e, 0xe2, 0xb2, 0x85, 0xb7, 0x67, 0x85, 0x8e, 0x15, + 0xa4, 0x67, 0x35, 0xac, 0x50, 0xb3, 0x02, 0xf8, 0xc8, 0x40, 0x00, 0x13, + 0x01, 0xcc, 0x04, 0xb0, 0x38, 0xd9, 0x23, 0x48, 0xe6, 0xc5, 0x05, 0x06, + 0x02, 0xd0, 0x49, 0xa4, 0x33, 0x01, 0x2c, 0x04, 0xa0, 0x57, 0xfc, 0x83, + 0x98, 0xd6, 0x40, 0x00, 0x13, 0x01, 0x28, 0x4a, 0x77, 0x25, 0x80, 0x4d, + 0x6c, 0x51, 0xbc, 0x65, 0x24, 0x80, 0x89, 0x00, 0x14, 0xf4, 0xaf, 0x63, + 0x2d, 0xf5, 0xad, 0x56, 0x9d, 0x2f, 0x69, 0x0a, 0x11, 0x2a, 0x78, 0x56, + 0x88, 0x00, 0xfe, 0xa4, 0x49, 0xe5, 0x2b, 0x5f, 0x89, 0xd9, 0x02, 0x5f, + 0x56, 0xe8, 0xf9, 0xda, 0xc0, 0x2b, 0x53, 0x9c, 0x82, 0xbd, 0x63, 0x19, + 0x2b, 0xbe, 0xe7, 0x5e, 0xfd, 0x62, 0x6f, 0x09, 0x5a, 0x58, 0x08, 0x2a, + 0xf6, 0xf4, 0xfb, 0x75, 0xa4, 0x02, 0x2f, 0xf9, 0x16, 0xc4, 0x1b, 0xc6, + 0xf3, 0xfd, 0xce, 0x17, 0x0f, 0xe6, 0x40, 0xfa, 0xd2, 0x83, 0xb4, 0xc5, + 0x43, 0x0d, 0x0c, 0x40, 0xcb, 0x37, 0x11, 0x6a, 0x86, 0x05, 0x3f, 0x23, + 0xd1, 0x1c, 0x69, 0x75, 0xdf, 0xe9, 0xd5, 0x68, 0x00, 0x3a, 0xc4, 0x09, + 0xef, 0xd4, 0x79, 0x31, 0x00, 0x35, 0x1c, 0x94, 0xfb, 0xd3, 0x78, 0x4d, + 0xc3, 0x31, 0xee, 0x70, 0x27, 0x7a, 0xc6, 0x2d, 0xf6, 0x66, 0xec, 0x7d, + 0xac, 0xbd, 0x19, 0xfb, 0xda, 0xc3, 0x4e, 0xd3, 0xc0, 0x3a, 0x2a, 0x44, + 0x16, 0xc7, 0xfe, 0xbd, 0x08, 0x08, 0x4e, 0x78, 0x63, 0x00, 0x3a, 0x30, + 0xa5, 0x9d, 0x48, 0xda, 0xe1, 0xfb, 0x3b, 0x45, 0xb2, 0xaf, 0xee, 0x4d, + 0x15, 0xbe, 0xd7, 0x17, 0x15, 0xc5, 0x57, 0x01, 0x04, 0xe7, 0x26, 0xc0, + 0x2a, 0xf5, 0x21, 0xe0, 0xad, 0xa2, 0x3f, 0x0d, 0x40, 0x0d, 0x6e, 0x3c, + 0x90, 0x87, 0xe7, 0xb9, 0xef, 0x39, 0xf7, 0x58, 0xb4, 0xfc, 0x1a, 0x5a, + 0xcd, 0x45, 0x4b, 0xd2, 0x1e, 0x16, 0x69, 0x60, 0x05, 0x5a, 0xb8, 0xce, + 0xd0, 0x43, 0xaf, 0x7c, 0xac, 0xd7, 0xf1, 0xaa, 0x21, 0x80, 0x33, 0x84, + 0xf4, 0x00, 0x80, 0x0a, 0x6b, 0xc6, 0xe4, 0x86, 0x00, 0x6a, 0x02, 0xa8, + 0x08, 0x00, 0x15, 0x26, 0x56, 0x98, 0x59, 0x41, 0x7b, 0x46, 0xae, 0xee, + 0x2d, 0xbf, 0x9c, 0x72, 0xdc, 0x6c, 0x63, 0x76, 0xb7, 0x5c, 0xdc, 0xa5, + 0xab, 0xcb, 0x6f, 0xf2, 0xf5, 0x04, 0xd0, 0x11, 0x40, 0x43, 0x00, 0x35, + 0x01, 0x24, 0xba, 0xe0, 0x43, 0x0e, 0x55, 0x5f, 0x59, 0x21, 0xc9, 0x62, + 0x12, 0xec, 0x06, 0x56, 0x10, 0x05, 0x9a, 0x58, 0x61, 0x66, 0x85, 0x85, + 0x15, 0x24, 0x09, 0x6e, 0x22, 0x5d, 0x26, 0xd1, 0x6e, 0xe9, 0xa8, 0xac, + 0xf8, 0xf0, 0xcc, 0xb2, 0x85, 0x54, 0x6b, 0xcd, 0x8d, 0x8b, 0xd6, 0x88, + 0x84, 0x68, 0x3e, 0xb9, 0x30, 0xda, 0xc7, 0xda, 0xd7, 0xda, 0xae, 0x58, + 0x2f, 0xbd, 0x78, 0x96, 0x5e, 0xca, 0xe1, 0xee, 0x4d, 0x91, 0xf1, 0x1d, + 0xff, 0x3c, 0xf6, 0xdb, 0x48, 0x10, 0xcf, 0xb8, 0xf3, 0x9f, 0x13, 0x47, + 0x5a, 0x30, 0x8f, 0xd3, 0x17, 0x0a, 0xf5, 0x4a, 0xdf, 0x17, 0x92, 0x22, + 0x05, 0xfd, 0x7e, 0x08, 0xb7, 0xbc, 0x54, 0xd5, 0xa6, 0x20, 0x9b, 0x62, + 0xdd, 0xc7, 0xbc, 0xac, 0x5c, 0xe6, 0x47, 0xe7, 0xa3, 0x7b, 0xaa, 0xfe, + 0xcf, 0xae, 0xee, 0x51, 0x5d, 0x2f, 0x12, 0x1e, 0x5e, 0xa2, 0xbc, 0x0b, + 0xe7, 0x3b, 0x1e, 0x7d, 0xde, 0x73, 0xcb, 0x84, 0xe3, 0x3b, 0xb8, 0x75, + 0x7e, 0xff, 0x8d, 0x3b, 0x0e, 0xc7, 0xc1, 0xc3, 0x78, 0x17, 0x39, 0xa6, + 0x7d, 0x60, 0xb9, 0x09, 0x3a, 0x17, 0x36, 0xbd, 0x8a, 0x6d, 0x12, 0x38, + 0x03, 0xe0, 0xac, 0xc7, 0x36, 0x9e, 0x90, 0x42, 0xe9, 0xc8, 0x21, 0x06, + 0xc7, 0xc7, 0x1c, 0x1f, 0x73, 0x7c, 0x0c, 0xe9, 0x98, 0x25, 0x19, 0x16, + 0x3b, 0x4e, 0x93, 0xc1, 0x71, 0xa0, 0x46, 0xa6, 0xf2, 0xb7, 0x24, 0x5a, + 0xae, 0x1f, 0x5d, 0xaa, 0x2d, 0x26, 0x20, 0x61, 0xa3, 0x3f, 0x34, 0x3e, + 0x4a, 0xf1, 0x6f, 0x0f, 0x7d, 0x96, 0x47, 0x26, 0xbd, 0x04, 0x2b, 0x65, + 0x9d, 0xc5, 0x23, 0x12, 0x05, 0xfb, 0xeb, 0x6d, 0x1d, 0xa3, 0x3d, 0x3d, + 0x27, 0xb0, 0xe3, 0xab, 0x02, 0xdd, 0xe5, 0x37, 0x09, 0xaa, 0x93, 0xb7, + 0x75, 0xda, 0x1f, 0xf1, 0xb6, 0x4e, 0x75, 0xe5, 0x15, 0x89, 0xfe, 0x38, + 0xb3, 0xc2, 0x28, 0x21, 0xe2, 0xdf, 0x54, 0x7c, 0xb1, 0x6b, 0x0f, 0x1b, + 0xd8, 0x79, 0xb1, 0x66, 0xed, 0xd2, 0xa4, 0x56, 0x77, 0xbe, 0xdc, 0x41, + 0x1f, 0xde, 0xe9, 0xcb, 0x1d, 0xfa, 0x3e, 0xd1, 0xc9, 0x7a, 0x9f, 0xa0, + 0xc3, 0x76, 0x82, 0x2d, 0x23, 0x8a, 0xd3, 0x97, 0x91, 0x58, 0x3c, 0x1c, + 0xf9, 0xe0, 0x24, 0xfc, 0x3f, 0x60, 0xea, 0x92, 0x9c, 0xad, 0xb4, 0xc6, + 0x25, 0x6f, 0x6b, 0x4b, 0xcb, 0xd8, 0x53, 0xf1, 0xaf, 0x56, 0xec, 0x9e, + 0xe4, 0x2a, 0x60, 0xf8, 0x2f, 0xc7, 0x5f, 0x9f, 0xaa, 0xff, 0x33, 0xab, + 0xff, 0xe3, 0xe5, 0x2a, 0x85, 0xfb, 0x2c, 0xa4, 0x6f, 0x0f, 0x4d, 0xe7, + 0x07, 0xa5, 0x3e, 0xa5, 0xd3, 0x49, 0x3a, 0x20, 0x05, 0x79, 0xc5, 0x37, + 0xdc, 0x1c, 0xc3, 0x59, 0x62, 0x4a, 0xea, 0xfa, 0xff, 0x98, 0xfe, 0x17, + 0xd3, 0xff, 0xd4, 0x90, 0x8f, 0x14, 0x53, 0x87, 0x53, 0xa4, 0xb7, 0x38, + 0x86, 0xe3, 0xcc, 0xea, 0x44, 0x95, 0x14, 0xfa, 0x28, 0xd7, 0x8a, 0x9c, + 0x26, 0xac, 0x9e, 0xc4, 0x3e, 0x56, 0x97, 0xb4, 0xc0, 0x0f, 0xab, 0x62, + 0xbd, 0x1b, 0xc6, 0x24, 0x34, 0x27, 0x07, 0x73, 0x34, 0x67, 0xa7, 0xc9, + 0x5c, 0x3e, 0xd7, 0xc3, 0xa7, 0x93, 0x22, 0x2e, 0x62, 0x5d, 0x9d, 0x5e, + 0x0f, 0x39, 0xa5, 0xb4, 0xd7, 0x4e, 0x54, 0xf9, 0x1e, 0x87, 0x92, 0x54, + 0xf7, 0x6c, 0xfd, 0x8e, 0xce, 0x9f, 0x6f, 0x99, 0x95, 0x63, 0xbf, 0x76, + 0x10, 0xcf, 0x0b, 0xda, 0x0d, 0x5b, 0xd8, 0x7b, 0xf4, 0x09, 0x2a, 0x7d, + 0x99, 0x4a, 0xd1, 0xfc, 0x92, 0xcf, 0x9f, 0x71, 0xa1, 0x24, 0x98, 0x71, + 0xe1, 0xa6, 0xe3, 0xba, 0x67, 0x49, 0xcc, 0x33, 0x45, 0xf1, 0x7c, 0xc2, + 0x41, 0x55, 0x5d, 0x9c, 0xf4, 0xc2, 0x11, 0x48, 0xb6, 0xee, 0x13, 0x39, + 0xe9, 0x6b, 0xae, 0xfb, 0x73, 0xae, 0xfb, 0x0b, 0xae, 0x7b, 0x8b, 0x75, + 0xdf, 0x18, 0xdc, 0xb3, 0x5e, 0x1c, 0xbb, 0x67, 0x28, 0x4b, 0x7e, 0x0d, + 0xe8, 0x2d, 0x67, 0xfe, 0xe5, 0x5f, 0x5b, 0xf7, 0x0f, 0x0f, 0x59, 0xb8, + 0x1f, 0x86, 0x36, 0xff, 0xf8, 0xea, 0x55, 0x7e, 0x0d, 0x46, 0xdc, 0x66, + 0xb0, 0xb7, 0xbb, 0x22, 0xc1, 0xaa, 0xe9, 0x49, 0x0e, 0xd9, 0xb6, 0x27, + 0x63, 0xa1, 0xf8, 0x98, 0x34, 0xda, 0x64, 0xc5, 0x94, 0x75, 0x13, 0xc8, + 0x38, 0x88, 0xd4, 0x01, 0x47, 0xf5, 0x39, 0x16, 0xea, 0xb7, 0xe9, 0x20, + 0x1c, 0xa9, 0xbd, 0xc4, 0xdc, 0xca, 0x6c, 0xc9, 0x38, 0x75, 0xa3, 0xb1, + 0xed, 0x13, 0x3d, 0x50, 0x81, 0x0c, 0xc9, 0x76, 0x57, 0xc5, 0xa3, 0xd0, + 0xec, 0x53, 0xcf, 0xb6, 0xe9, 0xc4, 0xce, 0xde, 0x62, 0x4f, 0xde, 0xe7, + 0x03, 0x6a, 0x35, 0x3f, 0xca, 0xd4, 0x45, 0x24, 0x37, 0xe4, 0x7e, 0x0b, + 0x3a, 0x20, 0x56, 0xf9, 0x85, 0xb8, 0xce, 0x4f, 0xdb, 0xda, 0xc9, 0xef, + 0xee, 0xec, 0x33, 0x61, 0xfa, 0x00, 0xee, 0x07, 0x12, 0x11, 0xea, 0x78, + 0xa7, 0x5f, 0x74, 0xf3, 0x90, 0x58, 0x3f, 0x91, 0xdd, 0xbe, 0x84, 0x40, + 0x6b, 0x2f, 0x06, 0xa1, 0x43, 0x33, 0x77, 0x63, 0xf4, 0x2c, 0xc4, 0xe3, + 0x90, 0x62, 0xe5, 0x37, 0x99, 0xe9, 0x4d, 0xe0, 0x3d, 0xc6, 0x7c, 0x2a, + 0xae, 0x8c, 0x78, 0x61, 0x8f, 0xe2, 0x38, 0xdb, 0xb1, 0xb8, 0x61, 0x71, + 0xcf, 0xe2, 0x80, 0xe2, 0x9a, 0xc5, 0x1d, 0x8b, 0x3d, 0x8a, 0x2b, 0x16, + 0x37, 0x2c, 0xee, 0xd9, 0x26, 0x96, 0xd9, 0x6a, 0x8d, 0x68, 0xeb, 0xc0, + 0x87, 0xef, 0x2e, 0x2e, 0xdb, 0x6c, 0xcf, 0xbb, 0x34, 0xb2, 0x98, 0x03, + 0x59, 0x8b, 0x81, 0x38, 0xd6, 0xaa, 0x99, 0xdd, 0x51, 0x87, 0xf1, 0xa8, + 0xa5, 0xe1, 0x37, 0x04, 0xd6, 0x85, 0x14, 0x2b, 0x41, 0xbc, 0x95, 0x05, + 0x66, 0x24, 0x50, 0x87, 0x5a, 0x0b, 0x69, 0xe0, 0x5b, 0x62, 0x6c, 0x0f, + 0x51, 0xe8, 0x4b, 0x32, 0x7d, 0xe8, 0xcc, 0x24, 0x43, 0x12, 0x7d, 0x48, + 0xea, 0x5d, 0xd2, 0xe9, 0x27, 0x6e, 0x20, 0xee, 0x37, 0xdb, 0x67, 0x5f, + 0x93, 0xf4, 0x22, 0x1d, 0x49, 0x66, 0x85, 0x21, 0x19, 0xd6, 0x5b, 0x10, + 0x72, 0xe0, 0x7b, 0xb6, 0xbb, 0x73, 0x0b, 0xdd, 0x56, 0x79, 0xcb, 0x92, + 0xdf, 0x9d, 0x9f, 0x12, 0xbc, 0x8a, 0xb5, 0xe7, 0x3b, 0x81, 0x62, 0x60, + 0x95, 0x4e, 0xc2, 0x89, 0x01, 0x01, 0x26, 0x15, 0xc6, 0xec, 0x36, 0x7d, + 0xe8, 0x6d, 0xe9, 0xb0, 0x5b, 0xa3, 0xe3, 0xe7, 0x43, 0x66, 0x5d, 0x62, + 0x59, 0x27, 0xca, 0xdd, 0x89, 0x2d, 0x61, 0x94, 0x6f, 0x04, 0x9c, 0x6a, + 0x3a, 0x6a, 0x8e, 0xd3, 0x51, 0xb1, 0x9c, 0x8e, 0x7a, 0xe7, 0x80, 0xe5, + 0xe4, 0xaa, 0x43, 0xd2, 0x6a, 0x25, 0x16, 0xfe, 0x3d, 0x3f, 0xc4, 0xf4, + 0x26, 0xc5, 0xb9, 0x13, 0x31, 0x9c, 0x9d, 0xe8, 0x24, 0x55, 0xec, 0x0a, + 0x48, 0x4b, 0xc5, 0xfa, 0xa9, 0xd2, 0x53, 0xa5, 0xa7, 0x4a, 0xdf, 0x5e, + 0xe9, 0x97, 0x56, 0xd5, 0x9f, 0xaa, 0x3f, 0x55, 0xff, 0xd5, 0xab, 0xff, + 0x20, 0x75, 0xe5, 0x86, 0xd5, 0xa9, 0x6b, 0xeb, 0xe8, 0xd5, 0xd3, 0x43, + 0x6f, 0x0f, 0xe6, 0xa9, 0x86, 0x02, 0x49, 0xc7, 0xc3, 0x2b, 0x7a, 0x9c, + 0x8e, 0xb9, 0x17, 0x47, 0xf3, 0xd4, 0xd2, 0x65, 0xed, 0x77, 0x62, 0x2a, + 0xe3, 0x09, 0x45, 0x91, 0xa4, 0x6a, 0x24, 0xa5, 0x1a, 0xe9, 0x48, 0x79, + 0xe2, 0xba, 0x59, 0xca, 0xa3, 0xf8, 0x10, 0xe9, 0x30, 0x39, 0xcc, 0x93, + 0x03, 0xe5, 0x8a, 0xb7, 0x0e, 0x5f, 0xf5, 0x03, 0x35, 0x6b, 0x29, 0x9a, + 0x25, 0xe9, 0xd0, 0xf5, 0x3a, 0x34, 0x99, 0x27, 0x61, 0xc0, 0xe1, 0xc4, + 0x40, 0x07, 0x93, 0xc8, 0x92, 0x36, 0x92, 0x94, 0x97, 0xa4, 0xae, 0x40, + 0x0b, 0x9f, 0x5c, 0x92, 0xe2, 0x62, 0xed, 0xdf, 0x15, 0x57, 0xf1, 0x3c, + 0x30, 0x62, 0xab, 0x31, 0xc0, 0x0d, 0x35, 0xa2, 0x58, 0xbb, 0xa3, 0x38, + 0x85, 0x6f, 0x8c, 0x46, 0x25, 0x09, 0xf0, 0x4c, 0x9e, 0x9b, 0x60, 0xff, + 0x37, 0xc0, 0xf5, 0xf5, 0x73, 0xa9, 0x7b, 0x9d, 0x4b, 0xed, 0x75, 0xee, + 0xb9, 0xd9, 0xfe, 0xe0, 0x17, 0x18, 0x0c, 0x70, 0x6d, 0x82, 0xe0, 0x0c, + 0xbd, 0x91, 0x92, 0xdc, 0x0a, 0x78, 0xbd, 0xce, 0x3d, 0xf7, 0x3a, 0xf7, + 0x1c, 0x3a, 0x1d, 0x6a, 0xb7, 0x44, 0x44, 0xd7, 0x01, 0x13, 0x37, 0xd8, + 0xea, 0xce, 0xcf, 0x3d, 0x8f, 0xd0, 0xc9, 0x14, 0xc6, 0x8a, 0xe2, 0xed, + 0x50, 0x53, 0x1a, 0x76, 0x0d, 0xb5, 0x36, 0x77, 0xf5, 0xdc, 0xf3, 0xc9, + 0x51, 0xd2, 0x1f, 0x0d, 0x54, 0x05, 0x7b, 0xa4, 0xe9, 0x61, 0xc8, 0xbd, + 0xf5, 0xdc, 0xf3, 0x68, 0x16, 0x35, 0xa9, 0x75, 0xb4, 0x8e, 0xda, 0x73, + 0x11, 0x5e, 0x0d, 0x2d, 0xe2, 0x96, 0x73, 0xcf, 0x47, 0xab, 0x6d, 0x1d, + 0xf5, 0x50, 0x31, 0x50, 0x9b, 0xe7, 0x9e, 0xa3, 0xb3, 0x0d, 0xb4, 0x8e, + 0xf3, 0x73, 0xcf, 0x67, 0xab, 0xed, 0x80, 0xad, 0x23, 0x00, 0x73, 0x33, + 0x0d, 0x35, 0x77, 0x13, 0x6a, 0x9f, 0x9c, 0x7b, 0x6e, 0xfb, 0x71, 0x45, + 0x6d, 0xcc, 0xe1, 0x08, 0xc0, 0x5c, 0x8a, 0xb8, 0x71, 0xb4, 0x14, 0x9b, + 0x96, 0x62, 0xd5, 0x52, 0xcc, 0xb8, 0xb0, 0xda, 0xd7, 0x4e, 0xb2, 0x37, + 0xc4, 0x98, 0x6b, 0x22, 0xc6, 0x54, 0x20, 0x06, 0xf1, 0xab, 0x17, 0x7e, + 0x59, 0xed, 0x08, 0x4f, 0x96, 0x05, 0xd4, 0x3e, 0x9e, 0xab, 0x0f, 0xf3, + 0xc2, 0xdc, 0x12, 0xdb, 0xe7, 0x9e, 0xd8, 0x3e, 0x79, 0x62, 0xfb, 0x28, + 0x6c, 0x7f, 0x66, 0xb5, 0xeb, 0xb3, 0x53, 0xfe, 0x9b, 0x48, 0x09, 0xb0, + 0xf7, 0xec, 0x2b, 0x3d, 0x06, 0xd8, 0x73, 0xef, 0xcd, 0xda, 0x7b, 0xbf, + 0x4b, 0x0e, 0x29, 0xbe, 0x39, 0x40, 0x15, 0x58, 0x9f, 0x70, 0x44, 0x4c, + 0xb6, 0x33, 0x23, 0xc0, 0x08, 0x78, 0xd2, 0x60, 0xf9, 0xe9, 0x82, 0x6e, + 0xd7, 0xe1, 0xa9, 0xcb, 0x7e, 0xb0, 0xda, 0xae, 0xf8, 0x02, 0xc2, 0x3b, + 0x29, 0xe2, 0xbf, 0x49, 0xbf, 0xf5, 0xd2, 0x64, 0x13, 0xbd, 0x48, 0xba, + 0x7b, 0x90, 0xf6, 0x8a, 0xda, 0x22, 0x2d, 0x46, 0x6b, 0x46, 0x5d, 0x0c, + 0x00, 0x9c, 0x74, 0xd8, 0x64, 0x9b, 0x41, 0xed, 0x46, 0xb5, 0x5b, 0xd5, + 0x6e, 0x55, 0xbb, 0x53, 0xed, 0x9e, 0xb5, 0x23, 0x3c, 0xf9, 0x04, 0x51, + 0xbb, 0x52, 0x6d, 0x19, 0x01, 0x92, 0x3e, 0xef, 0x64, 0x0e, 0x48, 0x9a, + 0x7d, 0x84, 0x87, 0xda, 0x7d, 0x36, 0xc1, 0x27, 0x1b, 0x39, 0xa9, 0xa0, + 0x6a, 0xcb, 0x14, 0x91, 0x34, 0xfc, 0x08, 0x8f, 0x6a, 0x9c, 0x6a, 0xb7, + 0xaa, 0xdd, 0xa1, 0x36, 0x49, 0x11, 0x70, 0xca, 0xbe, 0xed, 0x9c, 0x90, + 0xd0, 0x97, 0x45, 0x1f, 0x2e, 0x15, 0x85, 0x43, 0xd1, 0x7c, 0xad, 0x48, + 0x74, 0x8a, 0x8f, 0xa0, 0xe8, 0x3d, 0xd3, 0x0b, 0x45, 0x6f, 0x98, 0x2e, + 0xb4, 0x8d, 0xce, 0x92, 0x55, 0xc3, 0xa5, 0xa2, 0xf6, 0x50, 0x44, 0xbe, + 0xba, 0x76, 0x65, 0xd1, 0xeb, 0x93, 0xa2, 0x45, 0x76, 0x0a, 0x2b, 0xb2, + 0x47, 0x6c, 0x1f, 0x2f, 0x87, 0xa2, 0x67, 0xdc, 0xf7, 0x20, 0x6b, 0xdc, + 0xe1, 0xa0, 0x83, 0xc7, 0xa2, 0xb6, 0x2c, 0x1a, 0x58, 0xb4, 0x1d, 0x8a, + 0x26, 0x16, 0x8d, 0xa9, 0x68, 0x26, 0xe5, 0x41, 0x91, 0xa3, 0xa1, 0xe0, + 0xce, 0xa2, 0x86, 0x45, 0x33, 0x39, 0xc0, 0xc8, 0xc5, 0xee, 0xef, 0x28, + 0xda, 0xa8, 0xda, 0xd7, 0x46, 0x5c, 0x8c, 0xbb, 0x5b, 0xd1, 0x74, 0x2c, + 0xea, 0x59, 0x14, 0x89, 0xed, 0x54, 0xb3, 0x68, 0xb9, 0x4f, 0x51, 0x1b, + 0x40, 0x71, 0x27, 0x7e, 0x68, 0x22, 0xe0, 0x83, 0x65, 0x3d, 0x0c, 0xe1, + 0x20, 0xc6, 0x20, 0xfd, 0x9b, 0xd1, 0xdf, 0xd5, 0xa8, 0x5e, 0x7c, 0xf5, + 0x23, 0xf2, 0x87, 0xd1, 0x28, 0xd4, 0xbe, 0xed, 0xcb, 0xa2, 0x9b, 0x5c, + 0x54, 0x1d, 0x8a, 0xba, 0xdb, 0x8b, 0xa2, 0xf5, 0x7e, 0x60, 0x91, 0x8f, + 0x44, 0x7a, 0xb1, 0xbf, 0x6e, 0x27, 0x3c, 0x56, 0x84, 0xe2, 0xa5, 0x28, + 0xea, 0xcb, 0xa2, 0xfa, 0xf6, 0xa2, 0x50, 0x14, 0x3d, 0x27, 0x7d, 0xb7, + 0xa2, 0x9d, 0x82, 0xba, 0xd6, 0x38, 0x13, 0x3e, 0x62, 0xa6, 0xcf, 0x25, + 0xed, 0x04, 0x3f, 0x16, 0x75, 0x56, 0x14, 0x7d, 0x75, 0xb5, 0xf9, 0x15, + 0xae, 0x14, 0x2d, 0x45, 0x51, 0x87, 0x8f, 0x9c, 0x58, 0xd1, 0x56, 0x95, + 0x45, 0x53, 0x87, 0xcf, 0xa3, 0xc5, 0x88, 0xf4, 0x80, 0x22, 0x63, 0x9b, + 0x63, 0x5b, 0x14, 0x6d, 0x87, 0xa2, 0xc9, 0x8a, 0xc6, 0x54, 0xb4, 0x57, + 0x5c, 0xeb, 0x54, 0xb4, 0x57, 0x1c, 0xfb, 0x4b, 0x45, 0x5d, 0x2a, 0xb2, + 0x0f, 0x46, 0xa1, 0xc8, 0xf0, 0x3e, 0x15, 0x8d, 0xa9, 0x68, 0xcb, 0x45, + 0x43, 0x83, 0x6f, 0xbc, 0x55, 0x51, 0xcc, 0xd9, 0xd9, 0xa1, 0x8a, 0xe6, + 0x43, 0x51, 0x9d, 0x8b, 0xda, 0x38, 0x15, 0x43, 0x43, 0xfe, 0xc3, 0xa2, + 0xc0, 0x6f, 0xcd, 0xa1, 0xc8, 0xbe, 0xfe, 0x66, 0x45, 0x91, 0x4d, 0xe7, + 0xa2, 0xbd, 0xd7, 0x17, 0x8b, 0xe2, 0x62, 0xe5, 0xa2, 0x17, 0xb9, 0xa8, + 0x61, 0x91, 0xbd, 0x8d, 0xb3, 0xb7, 0x82, 0xa2, 0x17, 0x2a, 0x8a, 0x72, + 0xc9, 0x42, 0x4a, 0xf3, 0xc2, 0x44, 0xe0, 0x97, 0x20, 0x42, 0xc7, 0xa2, + 0x97, 0x87, 0xa2, 0x50, 0x16, 0xdd, 0x58, 0xd1, 0x0d, 0xf8, 0xfa, 0x6a, + 0x45, 0x2b, 0x39, 0xf8, 0x8d, 0xd9, 0xfe, 0x52, 0xd1, 0x6a, 0x68, 0xbf, + 0x1d, 0x8a, 0x8c, 0x82, 0x7e, 0x3d, 0x14, 0xbd, 0xb3, 0xa2, 0x77, 0x65, + 0x51, 0x48, 0x45, 0x83, 0x18, 0x51, 0x05, 0x1e, 0xe3, 0x03, 0xd9, 0x3c, + 0x8d, 0xa9, 0xb7, 0x15, 0x8d, 0x65, 0xd1, 0x7a, 0xa9, 0x68, 0x3e, 0x14, + 0x39, 0x15, 0xd1, 0x18, 0xdd, 0x07, 0x0a, 0xd0, 0x32, 0xb2, 0xde, 0xb7, + 0x68, 0x71, 0xb2, 0x50, 0xcb, 0x5e, 0x8d, 0x8e, 0x1e, 0x8a, 0xc4, 0xd2, + 0xc0, 0xeb, 0x3a, 0x14, 0x35, 0x0f, 0x28, 0x1a, 0xad, 0x68, 0x4e, 0xbc, + 0xb0, 0x0a, 0x12, 0x47, 0x20, 0x61, 0x49, 0x02, 0xa1, 0x99, 0x93, 0x0c, + 0xf6, 0xbe, 0x45, 0xcb, 0xa1, 0x68, 0x38, 0x2d, 0xf2, 0xc9, 0xfe, 0x3e, + 0x24, 0xa5, 0xa5, 0x3a, 0x14, 0x75, 0x27, 0x45, 0xf3, 0xa1, 0xc8, 0xdd, + 0x5a, 0x54, 0x1f, 0x8a, 0xfa, 0x64, 0xb5, 0x77, 0x39, 0xee, 0xe8, 0x50, + 0xd4, 0x4a, 0xe5, 0x19, 0x21, 0xd6, 0x82, 0x5b, 0x8f, 0xb4, 0x57, 0x5b, + 0xba, 0x7a, 0x6a, 0x12, 0x7d, 0x99, 0x76, 0xe4, 0xb4, 0xc6, 0x05, 0x2f, + 0xa4, 0x7d, 0xe4, 0x58, 0xcb, 0x79, 0x2a, 0xed, 0xc5, 0x47, 0x2e, 0x73, + 0x9a, 0x1a, 0x93, 0x18, 0xeb, 0xb3, 0x34, 0x48, 0xe1, 0x30, 0x8e, 0x79, + 0x9a, 0x92, 0xb2, 0x93, 0xe2, 0xda, 0xb3, 0x4a, 0x51, 0xd7, 0x13, 0x96, + 0xa7, 0x9c, 0xad, 0xb6, 0xfa, 0x9c, 0x4a, 0xe4, 0xa7, 0xc2, 0x52, 0xa4, + 0x0b, 0x09, 0xd4, 0x52, 0x0a, 0x03, 0x45, 0x6a, 0x1b, 0x5d, 0x02, 0x49, + 0x91, 0x4e, 0x94, 0x61, 0x6c, 0x73, 0x26, 0xb9, 0x49, 0x92, 0x90, 0xe7, + 0x46, 0x52, 0x1a, 0xca, 0xd4, 0xa4, 0xcc, 0xe1, 0x42, 0xea, 0x33, 0xa2, + 0x5e, 0x4c, 0xfb, 0xec, 0xdc, 0x39, 0xa4, 0x12, 0x18, 0x4f, 0xd3, 0x36, + 0xa7, 0x4b, 0x99, 0x36, 0x39, 0x9d, 0x2f, 0xa5, 0x75, 0x4e, 0xa7, 0x32, + 0x6d, 0x72, 0x3a, 0x5e, 0x4a, 0xdb, 0x3b, 0xd2, 0x2e, 0xa7, 0x53, 0x99, + 0xf6, 0x39, 0x9d, 0x2f, 0xa5, 0x3e, 0x48, 0xfe, 0x3f, 0xa6, 0x21, 0xfb, + 0xc0, 0x4e, 0x53, 0xaa, 0xfc, 0x57, 0x53, 0xee, 0x98, 0xf3, 0x74, 0xa0, + 0xa9, 0xc6, 0xd2, 0x2d, 0xa7, 0x87, 0xbd, 0xb3, 0x5e, 0xdc, 0x3b, 0x5d, + 0x4a, 0x97, 0x8b, 0x7b, 0xa7, 0xcf, 0x7b, 0xa7, 0x7b, 0xc8, 0xde, 0x09, + 0x69, 0xef, 0x4c, 0x97, 0xf6, 0x4e, 0x95, 0xf7, 0xce, 0x61, 0x0f, 0xd5, + 0xdc, 0x37, 0xf5, 0x95, 0xbd, 0xd3, 0x24, 0xc9, 0x22, 0x5c, 0xdc, 0x3b, + 0xed, 0x31, 0x4d, 0x7b, 0xa6, 0x3b, 0xa6, 0x4b, 0x4e, 0xb1, 0x67, 0xfa, + 0x63, 0x8a, 0xcf, 0x63, 0x35, 0xb4, 0xb1, 0xe4, 0x14, 0xde, 0xbf, 0x62, + 0xef, 0x50, 0x2d, 0xc9, 0xac, 0x2b, 0xa5, 0xb3, 0xe1, 0x0a, 0x6d, 0x3d, + 0x0a, 0x52, 0x70, 0x81, 0x46, 0x9a, 0x8a, 0x6e, 0xe6, 0x58, 0xf7, 0x85, + 0x08, 0x28, 0x2c, 0xe1, 0x9d, 0x8c, 0x34, 0x3d, 0xbb, 0x19, 0xe7, 0xb8, + 0x27, 0x75, 0x9f, 0x64, 0x54, 0x19, 0xbd, 0x34, 0x91, 0x80, 0xe5, 0xdc, + 0x2a, 0xf2, 0x17, 0x5a, 0x57, 0xbc, 0xb9, 0xce, 0x07, 0xae, 0x04, 0x64, + 0x7d, 0x4c, 0x5b, 0x2d, 0xeb, 0x4a, 0xfc, 0xc7, 0x89, 0x58, 0x1d, 0x3d, + 0xd3, 0x0b, 0xac, 0x21, 0x11, 0x3a, 0xad, 0x21, 0xa3, 0xac, 0x21, 0x30, + 0x8b, 0xd0, 0x4e, 0x61, 0x7e, 0x41, 0xe4, 0xc2, 0x1a, 0x62, 0x92, 0xf3, + 0x0c, 0xdd, 0x28, 0x04, 0x98, 0x45, 0x2a, 0x14, 0x27, 0xab, 0xc9, 0xea, + 0xb8, 0x2e, 0x0b, 0xda, 0x85, 0x19, 0x63, 0x56, 0x73, 0x93, 0xd5, 0x94, + 0x0d, 0x67, 0x94, 0x0d, 0x67, 0x68, 0xc8, 0x7c, 0x61, 0x88, 0x68, 0xcc, + 0xfe, 0xb0, 0xa0, 0xfb, 0xc2, 0x65, 0x47, 0x0e, 0xba, 0xc2, 0xa2, 0xd4, + 0x5b, 0x04, 0x8c, 0x2b, 0x0c, 0x53, 0x9e, 0xf8, 0x8b, 0x39, 0x9c, 0x6d, + 0x05, 0x46, 0xad, 0xd6, 0x33, 0x2d, 0xc5, 0x73, 0x2d, 0x05, 0xa2, 0x1c, + 0xcc, 0xf5, 0x09, 0x26, 0x0f, 0xcd, 0xcf, 0x75, 0xdc, 0x3e, 0x30, 0xbb, + 0x8d, 0x76, 0xf1, 0x51, 0x04, 0xef, 0xb3, 0x0c, 0x07, 0x7f, 0x68, 0x4b, + 0xbf, 0xb3, 0xda, 0xc2, 0x0b, 0x20, 0xca, 0xe8, 0xf2, 0x6e, 0x75, 0x07, + 0x8d, 0x5f, 0x74, 0x30, 0x9c, 0xab, 0xfe, 0x23, 0x49, 0xc8, 0x51, 0xe3, + 0x17, 0xd1, 0x90, 0x64, 0x84, 0x16, 0x44, 0x06, 0x13, 0xdd, 0x3b, 0x57, + 0xd5, 0x37, 0x5d, 0x24, 0x9d, 0xfd, 0x44, 0x55, 0xf7, 0x6c, 0xd2, 0xa9, + 0x76, 0xa5, 0x4a, 0x72, 0xbb, 0x4b, 0x76, 0x28, 0xac, 0x9c, 0x22, 0x99, + 0xd4, 0x67, 0x9d, 0xb8, 0xbc, 0x4b, 0xac, 0x5d, 0x6e, 0x1e, 0x27, 0x96, + 0x9f, 0xbc, 0x40, 0x59, 0x16, 0x00, 0x2e, 0x11, 0x8c, 0x23, 0x98, 0xed, + 0x09, 0xcc, 0x3f, 0x07, 0x4c, 0xc4, 0xfc, 0x80, 0xf3, 0x0b, 0xec, 0x74, + 0xa4, 0x1f, 0x75, 0xe3, 0x92, 0x50, 0xda, 0x49, 0xe4, 0x9c, 0xac, 0xeb, + 0x59, 0xfe, 0xe4, 0x38, 0x28, 0x2c, 0x78, 0xdd, 0x0c, 0x69, 0x60, 0xad, + 0xa4, 0xa1, 0x25, 0xf5, 0x3f, 0xc1, 0xbc, 0xb3, 0x81, 0xe9, 0x5f, 0xb8, + 0x81, 0xf1, 0xe7, 0x35, 0x30, 0x7c, 0xbf, 0x06, 0xc2, 0xc3, 0x1a, 0x08, + 0x3f, 0xaf, 0x81, 0xed, 0xa1, 0x0d, 0xc0, 0x8b, 0x65, 0x47, 0x9a, 0x04, + 0xbc, 0x09, 0xfd, 0x43, 0x6f, 0x62, 0x2f, 0xf5, 0x19, 0x3d, 0x6a, 0x9a, + 0x85, 0x41, 0xb9, 0xe7, 0x85, 0xc4, 0x59, 0xd0, 0x80, 0xd4, 0x4b, 0x47, + 0x96, 0xb9, 0xf1, 0x51, 0x69, 0xc8, 0x81, 0xd6, 0x53, 0xc0, 0xf7, 0x76, + 0x31, 0xb2, 0x24, 0xa8, 0x64, 0x63, 0x9d, 0xa0, 0x17, 0xb2, 0x21, 0xa6, + 0xe0, 0xd9, 0xbd, 0x64, 0xf2, 0x90, 0x6d, 0xec, 0xc3, 0x7a, 0xe0, 0x66, + 0xc1, 0x24, 0x14, 0x9e, 0x44, 0xe6, 0x21, 0xc0, 0x8c, 0x15, 0xc4, 0x1a, + 0x9e, 0x71, 0x96, 0x64, 0x26, 0x1f, 0x70, 0x36, 0x59, 0x65, 0xa2, 0x2e, + 0x3c, 0x39, 0x43, 0x0b, 0x81, 0x67, 0x03, 0x86, 0xc2, 0xd3, 0x35, 0x65, + 0x59, 0x2c, 0x0a, 0x33, 0x9d, 0x44, 0x30, 0x3e, 0xb2, 0xea, 0x91, 0x59, + 0x8f, 0x8c, 0x7c, 0x84, 0x1e, 0xb4, 0xde, 0x5e, 0xf2, 0x1b, 0xed, 0x91, + 0x96, 0x82, 0xdc, 0xd8, 0xc3, 0x24, 0xc5, 0x93, 0xcc, 0x1e, 0xe9, 0x23, + 0xf8, 0xd5, 0x4c, 0xf5, 0xc1, 0x21, 0x3a, 0x93, 0x82, 0x6c, 0x15, 0x81, + 0x86, 0xa7, 0x90, 0x4c, 0x19, 0x0f, 0x7e, 0x24, 0x33, 0xa2, 0xc4, 0x7f, + 0xc4, 0x76, 0x12, 0xb7, 0xb9, 0xfb, 0x91, 0xef, 0xd3, 0x97, 0x87, 0x3c, + 0xe2, 0x7e, 0xfe, 0x1a, 0xfd, 0x7d, 0x8f, 0x5c, 0x42, 0xef, 0x3b, 0x76, + 0xc0, 0xc9, 0x3e, 0xe2, 0x56, 0x1b, 0x8e, 0x5b, 0x8d, 0xbb, 0x71, 0x39, + 0xee, 0xc6, 0x58, 0xdc, 0xc0, 0x1b, 0xb0, 0x82, 0x05, 0x68, 0x4f, 0x37, + 0xd0, 0x6d, 0x70, 0xee, 0x60, 0xad, 0x6d, 0xbf, 0x3f, 0x3f, 0xc5, 0xbf, + 0xb8, 0xff, 0x7f, 0x0f, 0x50, 0x33, 0xb1, 0x80, 0x24, 0x1e, 0x13, 0xd7, + 0x8f, 0xc6, 0x47, 0x3a, 0x3c, 0xb8, 0xb4, 0x3d, 0x4b, 0x9c, 0x4a, 0x12, + 0x95, 0xaa, 0x55, 0xd2, 0x08, 0x1d, 0x5a, 0x40, 0x63, 0x6d, 0xe7, 0x0a, + 0xd9, 0xbf, 0x0f, 0x24, 0x90, 0x9d, 0x84, 0xec, 0x4e, 0x58, 0x5b, 0x53, + 0x56, 0x72, 0x0c, 0xc4, 0x2e, 0x0d, 0x26, 0x06, 0xad, 0x21, 0xb4, 0x9a, + 0x0d, 0x3b, 0x35, 0x6c, 0x7d, 0x5b, 0x84, 0x75, 0x03, 0x7b, 0xa4, 0x70, + 0x86, 0xa0, 0xce, 0xcf, 0x69, 0x58, 0x69, 0xc0, 0x9a, 0x01, 0x6e, 0xdc, + 0x91, 0x13, 0x60, 0x01, 0x13, 0xb1, 0x67, 0x43, 0x0b, 0x0a, 0xaa, 0x83, + 0x22, 0xb9, 0x5c, 0x81, 0x7a, 0xb8, 0x74, 0x52, 0xb8, 0x7c, 0x65, 0x3c, + 0xd8, 0xe4, 0xf1, 0x1d, 0x4d, 0x93, 0x97, 0xe6, 0x6d, 0x7a, 0x1b, 0x9c, + 0x50, 0x53, 0x36, 0x3b, 0x20, 0xf6, 0xc0, 0x06, 0x33, 0x7a, 0xda, 0x2b, + 0x5a, 0x72, 0x01, 0xa9, 0x7c, 0x93, 0x0c, 0x5d, 0x98, 0x19, 0x81, 0x90, + 0xd6, 0x5f, 0x2b, 0x7c, 0xc1, 0x53, 0x79, 0x6e, 0x19, 0xbd, 0x50, 0x29, + 0xc0, 0xa1, 0xa7, 0x7a, 0xdd, 0x18, 0xb2, 0xda, 0x22, 0x0e, 0x1e, 0xc6, + 0x90, 0x99, 0xe1, 0x08, 0x65, 0x7f, 0x93, 0x1a, 0x84, 0x05, 0xf1, 0xa4, + 0x22, 0x2d, 0xd7, 0x25, 0xc9, 0xb9, 0xdd, 0xf5, 0x27, 0x83, 0x08, 0xd0, + 0x95, 0x27, 0xfb, 0xac, 0x62, 0x5d, 0x7e, 0xb2, 0x12, 0x55, 0xbb, 0xfa, + 0x64, 0xd1, 0x9d, 0x8b, 0x4f, 0x62, 0xd1, 0xd3, 0x47, 0x74, 0xd3, 0x0b, + 0x29, 0x4b, 0xc7, 0x0b, 0x91, 0xed, 0x09, 0x58, 0x90, 0xc9, 0xf7, 0x33, + 0xa6, 0x7a, 0xa9, 0xe4, 0x01, 0x20, 0x6e, 0x99, 0x8c, 0xfb, 0x4c, 0xdb, + 0xfd, 0x27, 0xf8, 0x6c, 0xec, 0xab, 0xc6, 0x7e, 0xe7, 0x93, 0x77, 0xcc, + 0xfc, 0x7d, 0x1a, 0x3b, 0x82, 0x48, 0xfd, 0x3d, 0xeb, 0x85, 0x18, 0x50, + 0x77, 0xbd, 0x60, 0xbb, 0x5c, 0xd0, 0x9f, 0x14, 0x54, 0xb9, 0x20, 0x39, + 0xd4, 0x07, 0x76, 0x77, 0x62, 0xcd, 0xe5, 0x22, 0xc8, 0xea, 0xf4, 0x81, + 0x3e, 0xd3, 0x97, 0x81, 0x0f, 0x8e, 0x7c, 0x10, 0x8b, 0xc8, 0xd4, 0x4e, + 0xdb, 0x89, 0xbf, 0x4f, 0x4c, 0x37, 0xae, 0xb2, 0x1d, 0xbf, 0x13, 0x7f, + 0x5f, 0xf4, 0x24, 0x11, 0xc5, 0xce, 0xe3, 0xf9, 0x46, 0x10, 0xd3, 0x3f, + 0xc9, 0xc2, 0x16, 0x2b, 0x34, 0xff, 0x60, 0x0b, 0xdb, 0xa7, 0x7f, 0xa2, + 0x85, 0xad, 0x13, 0xad, 0x24, 0xca, 0x2b, 0x3c, 0x31, 0xe8, 0x43, 0x4d, + 0xe9, 0x13, 0x5f, 0x89, 0x21, 0xdb, 0xf9, 0xed, 0xf6, 0x13, 0xab, 0xde, + 0xee, 0x03, 0xa6, 0xa0, 0x06, 0x7f, 0xbf, 0xf9, 0xe7, 0x47, 0x0d, 0x2a, + 0x81, 0xf9, 0x19, 0x83, 0x7a, 0xec, 0x60, 0xfe, 0x3f, 0xa1, 0xf4, 0x77, + 0x98, 0xe4, 0xf5, 0x00, 0x00 +}; const GFXglyph Antonio_SemiBold90pt7bGlyphs[] PROGMEM = { {0, 1, 1, 38, 0, 0}, // 0x20 ' ' @@ -5322,8 +1086,16 @@ const GFXglyph Antonio_SemiBold90pt7bGlyphs[] PROGMEM = { }; -const GFXfont Antonio_SemiBold90pt7b PROGMEM = { - (uint8_t *)Antonio_SemiBold90pt7bBitmaps, - (GFXglyph *)Antonio_SemiBold90pt7bGlyphs, 0x20, 0x5E, 231}; -// Approx. 60745 bytes + + +// Font properties +static constexpr FontData Antonio_SemiBold90pt7b_Properties = { + Antonio_SemiBold90pt7bBitmaps_Gzip, + Antonio_SemiBold90pt7bGlyphs, + sizeof(Antonio_SemiBold90pt7bBitmaps_Gzip), + 62948, // Original size + 0x20, // First char + 0x5E, // Last char + 231 // yAdvance +}; \ No newline at end of file diff --git a/src/fonts/fonts.hpp b/src/fonts/fonts.hpp index 099c4e0..a1f03bd 100644 --- a/src/fonts/fonts.hpp +++ b/src/fonts/fonts.hpp @@ -1,15 +1,71 @@ #pragma once -#include "antonio-semibold20.h" -//#include "antonio-semibold30.h" -#include "antonio-semibold40.h" -#include "antonio-semibold90.h" -#include "sats-symbol.h" -//#include "icons.h" +#include +#include +#include -// #include "oswald-20.h" -// #include "oswald-30.h" -// #include "oswald-90.h" -// #include "ubuntu-italic40.h" -// #include "ubuntu-italic60.h" -// #include "ubuntu-italic70.h" \ No newline at end of file +// Font metadata structure +struct FontData { + const uint8_t* compressedData; + const GFXglyph* glyphs; + const size_t compressedSize; + const size_t originalSize; + const uint16_t first; + const uint16_t last; + const uint8_t yAdvance; +}; + + +class FontLoader { +public: + static GFXfont* loadCompressedFont( + const uint8_t* compressedData, + const GFXglyph* glyphs, + const size_t compressedSize, + const size_t originalSize, + const uint16_t first, + const uint16_t last, + const uint8_t yAdvance) + { + uint8_t* decompressedData = (uint8_t*)malloc(originalSize); + if (!decompressedData) { + Serial.println(F("Failed to allocate memory for font decompression")); + return nullptr; + } + + size_t decompressedSize = originalSize; + if (GzipDecompressor::decompressData(compressedData, + compressedSize, + decompressedData, + &decompressedSize)) + { + GFXfont* font = (GFXfont*)malloc(sizeof(GFXfont)); + if (!font) { + free(decompressedData); + Serial.println(F("Failed to allocate memory for font structure")); + return nullptr; + } + + font->bitmap = decompressedData; + font->glyph = (GFXglyph*)glyphs; + font->first = first; + font->last = last; + font->yAdvance = yAdvance; + + return font; + } + + Serial.println(F("Font decompression failed")); + free(decompressedData); + return nullptr; + } + + static void unloadFont(GFXfont* font) { + if (font) { + if (font->bitmap) { + free((void*)font->bitmap); + } + free(font); + } + } +}; diff --git a/src/fonts/oswald-medium20.h b/src/fonts/oswald-medium20.h new file mode 100644 index 0000000..0509361 --- /dev/null +++ b/src/fonts/oswald-medium20.h @@ -0,0 +1,323 @@ +#pragma once + +#include +#include +#include "fonts.hpp" + +const uint8_t Oswald_Medium20pt7bBitmaps_Gzip[] = { + 0x1f,0x8b,0x08,0x00,0xf7,0xa4,0x71,0x67,0x02,0xff,0xad,0x58, + 0xcf,0x8e,0xdb,0xb8,0x19,0xa7,0xa0,0xa2,0xbc,0x04,0xe1,0xb5, + 0x87,0x81,0x98,0x37,0xe8,0x1e,0xb3,0x80,0x22,0xf6,0x51,0xda, + 0x37,0x48,0xb1,0x87,0x3a,0x18,0x45,0xd4,0xc0,0x07,0xdf,0x56, + 0x2f,0xb0,0x88,0x5f,0x63,0x81,0xa6,0x19,0x1a,0x2e,0xe0,0x4b, + 0xb1,0x7e,0x81,0x36,0xa6,0xa1,0x83,0x6f,0x2b,0x1a,0x3e,0x98, + 0x86,0x39,0x64,0x7f,0x94,0xec,0x19,0x4f,0x32,0x49,0x16,0x45, + 0xc5,0xb1,0xf4,0xf1,0xff,0xc7,0xef,0xef,0x8f,0x43,0x42,0x7c, + 0x8e,0xff,0xde,0x7c,0xff,0xcb,0x0f,0x3f,0x6d,0xbe,0xff,0xd7, + 0x8b,0x24,0x56,0xbd,0x5c,0xbe,0xe9,0x5e,0x6d,0x7e,0xde,0x67, + 0xed,0x4f,0x3f,0xfc,0x48,0x58,0x43,0x27,0xe3,0xc5,0xac,0x55, + 0x5b,0x3d,0x32,0xf9,0xa8,0xc8,0xb3,0x8c,0x31,0xd1,0xcf,0x34, + 0x5b,0x6d,0xcd,0x68,0x94,0xe7,0x32,0xdc,0x86,0x55,0xe8,0xc2, + 0xae,0x9d,0xad,0xb5,0x31,0x23,0x9b,0x8f,0xb2,0x9c,0x65,0xb4, + 0xa1,0x8b,0xf1,0x7c,0xd6,0x6a,0x52,0x93,0x3f,0x91,0x17,0xc4, + 0x27,0x61,0x16,0xb6,0xc1,0xba,0xca,0xf1,0x8a,0xdd,0xd2,0xd5, + 0xb8,0x53,0xa9,0x49,0x1c,0x09,0x44,0x28,0x66,0xd2,0x33,0x81, + 0x96,0x8a,0x88,0x9c,0x79,0x1a,0xc6,0x61,0x76,0xd4,0x77,0xd6, + 0x49,0x2f,0x3c,0x0b,0xa9,0x27,0x7f,0x20,0xcf,0xc8,0xef,0x49, + 0x4a,0x58,0x9d,0x11,0x66,0x69,0x4d,0x43,0xa2,0xd2,0xa0,0x5f, + 0x13,0x6b,0x73,0x92,0x17,0x8c,0x30,0x3a,0xae,0x53,0xb0,0x41, + 0xc0,0x19,0xc9,0xb3,0x2b,0x34,0x34,0x24,0x05,0xff,0xc4,0x58, + 0x4d,0x8a,0xe2,0x25,0x61,0x21,0x23,0x49,0x58,0x4c,0xac,0x58, + 0xcf,0x43,0xaa,0xb6,0x41,0x93,0x7c,0x64,0xc9,0xf3,0x22,0x23, + 0x69,0x33,0x51,0x49,0xbb,0x36,0x64,0x64,0x4b,0x72,0x55,0x70, + 0xc2,0xd8,0x44,0xa5,0x73,0x34,0x68,0x3b,0x22,0x23,0x8c,0xc8, + 0x68,0xa8,0xe9,0x4d,0x50,0x89,0x12,0x86,0x18,0x6a,0xa8,0x4e, + 0x03,0x09,0x86,0x7b,0xda,0x6a,0x5b,0x72,0x36,0x5e,0x9b,0xb2, + 0x60,0x93,0x7a,0x6b,0x78,0x9e,0x74,0x44,0xe8,0xd4,0xe2,0x30, + 0xac,0x4e,0x6d,0x1e,0x26,0x1f,0xb6,0xfb,0x95,0xd8,0x6e,0x3e, + 0x14,0xfb,0xb9,0xb7,0x72,0x4a,0x77,0xba,0x2c,0xf9,0x26,0xf8, + 0x10,0x96,0xce,0x06,0x06,0x91,0xfe,0xfa,0xab,0xa6,0x8c,0x8b, + 0xaa,0x2c,0xed,0x97,0x9e,0xb2,0x2c,0x85,0xe0,0x54,0x97,0x82, + 0xcf,0x35,0x36,0xc3,0x9e,0x33,0x63,0xe3,0x77,0x02,0x46,0xef, + 0x89,0x81,0x62,0xcd,0x72,0x31,0x57,0xac,0x7e,0x99,0xa8,0x1f, + 0xff,0xf8,0x37,0x6c,0xd0,0x5a,0x56,0x7b,0x36,0x3a,0xb6,0x3f, + 0x3e,0xfb,0x73,0x5a,0x53,0xf2,0x9c,0x5c,0x91,0x97,0xe4,0x75, + 0xaf,0x50,0x7f,0x5f,0x25,0x3a,0x51,0x68,0xf8,0xe9,0xd7,0x3d, + 0xc1,0xc7,0xe1,0x57,0x93,0x51,0xaa,0xae,0x88,0x66,0xf8,0xd6, + 0x79,0xa2,0x9f,0x93,0xd7,0x14,0x5f,0x95,0x41,0x08,0xe4,0x65, + 0x8a,0xef,0xd0,0x75,0x95,0xe0,0x7b,0xee,0xa2,0x86,0x41,0x6b, + 0x4d,0x58,0x84,0xdd,0xfa,0x68,0xde,0x5a,0xe1,0x38,0xea,0xbd, + 0x56,0x83,0x0e,0x46,0x7e,0xa1,0x61,0x45,0x97,0x8b,0x0d,0x0c, + 0xc5,0x48,0xc3,0x4d,0x3a,0xdb,0xde,0x45,0xe6,0x2a,0x4e,0x67, + 0xa6,0xfc,0xca,0xcb,0x70,0x27,0xbc,0xf4,0x52,0x3a,0x61,0xf9, + 0xa9,0x08,0x22,0x48,0x01,0xf9,0x3b,0xe2,0x12,0x9b,0x9a,0x14, + 0xea,0xa2,0x8a,0x29,0x5e,0xf3,0x5a,0xa0,0x39,0x76,0x40,0xfa, + 0x7d,0x61,0x46,0x58,0x09,0x3b,0x73,0x95,0x15,0xf6,0xb4,0x02, + 0x89,0xf3,0xab,0xd4,0xa5,0x16,0xc5,0xc1,0xfa,0xaa,0xbe,0xe5, + 0x7e,0x75,0xb0,0x5b,0x05,0x8f,0x0d,0x1d,0x37,0xc4,0x13,0x51, + 0x33,0x4d,0x6d,0xe2,0x49,0xa8,0x85,0xce,0x2c,0xfd,0x90,0x74, + 0xf5,0x4e,0xe7,0x36,0x2b,0x68,0x33,0x6e,0xb5,0xb1,0x79,0xd4, + 0x0d,0x28,0x1b,0xce,0x0f,0xb8,0x83,0x6d,0x68,0x62,0xef,0x89, + 0x33,0x3f,0xc1,0x5b,0xf2,0x50,0x0e,0x26,0x58,0xe8,0xe1,0xc4, + 0x1d,0xe1,0xe7,0x72,0xe6,0xc4,0x15,0xd2,0xf7,0x07,0x37,0x83, + 0xcc,0x27,0x61,0xd1,0xee,0xf4,0x01,0x32,0x2f,0x7a,0x67,0x22, + 0xbc,0x66,0xff,0xa4,0xa1,0x0d,0x87,0x68,0x6d,0x15,0x8f,0xce, + 0xf7,0x48,0xe6,0xd3,0x5e,0xe6,0xeb,0x41,0xe6,0x67,0xe6,0x5c, + 0xaa,0x59,0x5d,0x24,0x96,0x2a,0x4e,0xca,0xc4,0x30,0x55,0x10, + 0x9b,0x6a,0x5e,0x83,0xa6,0x4a,0x44,0xfa,0xa1,0x3b,0x35,0xac, + 0x66,0x26,0xb2,0x22,0x7d,0x55,0xb9,0xe2,0x2c,0x43,0x27,0xca, + 0xa2,0xac,0xb0,0x87,0x1d,0xfa,0xca,0xe2,0x42,0x3f,0xa7,0x11, + 0xe0,0xdd,0x0b,0xc7,0xa0,0x9d,0xd3,0x98,0xca,0xdd,0xeb,0xe0, + 0x61,0x14,0x54,0x1b,0x64,0x10,0x2b,0x36,0xbd,0x38,0xbd,0xb8, + 0x3c,0x7b,0xb4,0x55,0x12,0x9f,0x34,0x46,0xa7,0xfb,0x1a,0x21, + 0xd1,0xbc,0xaf,0xfe,0xfa,0xee,0x35,0x79,0xf1,0x8c,0x8e,0xb7, + 0x90,0xc0,0x42,0x1b,0x9e,0x3a,0xd1,0x7a,0xae,0x2c,0x25,0x2f, + 0x86,0xf3,0x9a,0x61,0x70,0xef,0x0a,0xf5,0x33,0x82,0xf3,0x06, + 0x0a,0xcd,0x4a,0x62,0x04,0xdb,0xf9,0xd0,0x68,0xfb,0x1c,0x91, + 0x8c,0x69,0xb9,0x0d,0x7b,0x44,0xbb,0x00,0x41,0xe3,0x58,0x42, + 0x95,0xc4,0x26,0x91,0x77,0xd8,0x94,0x83,0x18,0x20,0x99,0x92, + 0x98,0x44,0xa7,0x8a,0xd6,0xc3,0x8a,0xbd,0xf1,0x51,0xcd,0x14, + 0x41,0x68,0x43,0xfc,0x51,0x84,0x07,0x8b,0x1f,0x4c,0x06,0xb6, + 0x28,0xa0,0x77,0x4e,0x08,0xcc,0x8d,0xe4,0x3c,0xd9,0x34,0x2c, + 0x39,0x2e,0x9a,0x71,0x68,0x17,0x37,0xc1,0xec,0x67,0xd6,0x5c, + 0xcf,0xec,0xe8,0x95,0xb6,0x79,0x66,0x6c,0xc1,0x46,0xb0,0x74, + 0x57,0xb0,0xb1,0xcf,0xe8,0xcc,0xb3,0x54,0x75,0xf4,0x46,0xef, + 0xc7,0xca,0x5c,0xc3,0xf5,0xdf,0x18,0xeb,0x72,0x2b,0x7d,0x9e, + 0xf3,0xce,0x65,0x74,0xef,0xd8,0x8d,0xb1,0xa9,0x22,0x24,0x89, + 0x27,0x2b,0xa3,0x1c,0xf0,0x63,0x08,0xc7,0x69,0x98,0x2a,0x9c, + 0x53,0x83,0x07,0x83,0x58,0xa8,0x48,0x6a,0x88,0x44,0x0f,0x42, + 0xb0,0x84,0x16,0x13,0xc4,0x61,0xcd,0x5c,0xb2,0xaf,0x0b,0x43, + 0x57,0xe4,0xa8,0x8b,0x92,0x2e,0x6b,0x6b,0x38,0x4f,0x5b,0xed, + 0x86,0x28,0x27,0x11,0xaf,0xda,0xe0,0x64,0x68,0x6e,0xb6,0x46, + 0x14,0x69,0xa7,0xde,0x5a,0x76,0x9b,0xec,0x95,0x08,0x5a,0xa0, + 0x6f,0x17,0x9c,0x93,0xb7,0x68,0x3e,0x9a,0xc2,0x21,0x74,0x0f, + 0x04,0xbf,0x0d,0xcb,0x30,0x87,0x2d,0x07,0xc1,0x3a,0x15,0x8c, + 0x70,0x08,0xe0,0x41,0xc1,0xe8,0x06,0x02,0xf6,0x17,0x42,0x1c, + 0xd3,0x06,0xb8,0x52,0x0c,0x0c,0xdb,0xe0,0x2a,0x3e,0xa5,0xa7, + 0x75,0x6e,0xd3,0xd0,0xcf,0xc2,0x49,0x18,0x72,0x07,0x79,0x20, + 0xb0,0x45,0xec,0xea,0xc7,0x74,0xea,0x60,0xab,0xc8,0x20,0x2c, + 0x5c,0x98,0x4b,0x7e,0xe8,0xb0,0xe9,0x69,0xf0,0x37,0x89,0xd9, + 0xd1,0xc0,0x58,0xc4,0xc0,0xcf,0xc9,0x2b,0x4e,0x2a,0xbe,0xff, + 0xa0,0x53,0x38,0x2c,0xbf,0xbc,0x6c,0xec,0x3f,0xe1,0xd1,0xa3, + 0xaa,0xd4,0xf0,0xda,0x51,0x2d,0x12,0xcb,0x50,0x09,0x2b,0x0f, + 0x33,0xba,0x1d,0x2a,0x8f,0x7a,0x50,0x39,0x9f,0xdd,0xe3,0xec, + 0xe9,0x23,0x9e,0x2f,0x8e,0x2c,0x03,0x47,0x68,0x85,0x80,0x2e, + 0x64,0x88,0x31,0x77,0x16,0x8e,0xb2,0xf4,0xdb,0xf0,0x5e,0x2c, + 0x3f,0x11,0xef,0x67,0xc4,0x03,0x77,0x5f,0x1e,0x13,0x89,0xf0, + 0xc4,0xf3,0x8d,0x78,0x3c,0x33,0x4e,0x60,0xde,0xd1,0x21,0xf8, + 0xb2,0xd5,0xcd,0xce,0x54,0x15,0x5b,0xce,0xb6,0xb6,0x12,0x6c, + 0xd2,0x1a,0x58,0xd1,0x74,0x8c,0xb6,0xd8,0x05,0x05,0x61,0xa3, + 0x3a,0x58,0x1e,0xd2,0xa3,0xc6,0xb0,0xc5,0xcc,0x62,0xee,0x64, + 0x1d,0x57,0xc0,0xd8,0x38,0x11,0x1a,0xe5,0xb7,0xe9,0x1e,0x23, + 0x3f,0x11,0xff,0x37,0x3f,0x27,0x6e,0x2b,0x72,0x67,0x31,0x9f, + 0xad,0x94,0x94,0xc9,0x9d,0xa3,0x7b,0xc3,0x57,0x2a,0xc8,0xf1, + 0x9d,0x67,0x7b,0x2b,0x56,0xba,0xbb,0x9e,0xfc,0xa3,0xcb,0xf6, + 0xef,0xaf,0x3f,0x6e,0xbb,0xeb,0xc5,0xab,0x4d,0xbe,0x7f,0xb7, + 0xfb,0x78,0xbd,0x3c,0x74,0x62,0xf3,0x73,0x68,0x5a,0x2f,0x1a, + 0xeb,0x45,0x6b,0xc3,0x64,0xee,0x39,0xb3,0xa5,0x58,0x9b,0x30, + 0x19,0xfb,0xe7,0xcc,0x32,0x47,0x7d,0x1a,0x6e,0x7a,0xdb,0xb5, + 0xc2,0xf3,0x10,0xa3,0x6f,0x1b,0xd5,0x12,0x3e,0xca,0x4e,0xec, + 0x57,0x87,0x0e,0x81,0x5b,0x40,0x57,0x0d,0x2c,0x7f,0x7d,0x8e, + 0xb8,0x51,0x55,0x35,0x64,0x0b,0x03,0x65,0x17,0xda,0xbe,0xfd, + 0x6d,0x86,0xf9,0x40,0xdc,0x45,0x4b,0x6f,0x4e,0x96,0x6e,0x04, + 0xc8,0x1d,0xd2,0x84,0xb8,0x4d,0x3f,0xb5,0xf4,0x5b,0xd6,0x85, + 0x63,0xcc,0x21,0xa0,0x1f,0xbb,0xce,0x67,0xc4,0xff,0x8b,0x9f, + 0x98,0xd4,0x54,0x12,0x73,0x1b,0x25,0x44,0x45,0x3f,0xbc,0xe7, + 0x2e,0x3c,0x38,0xff,0x30,0xf5,0xc4,0x1d,0x34,0xce,0x16,0xed, + 0xd6,0xba,0x42,0xb0,0xe5,0x7c,0x67,0x9c,0xe3,0x82,0x76,0xf0, + 0xc3,0xea,0xec,0xfc,0x9c,0xe9,0x21,0x53,0xfb,0xca,0x9e,0xb2, + 0x0c,0x2c,0x0c,0xe9,0x57,0x22,0x76,0x09,0x8d,0x0c,0x88,0x5c, + 0x9d,0x0c,0x0d,0x62,0x74,0x9f,0x85,0xbc,0x88,0x18,0x32,0x66, + 0x99,0x7b,0x03,0xd6,0x08,0xdb,0x69,0x04,0x04,0x35,0x07,0x8b, + 0x7d,0x14,0xff,0x56,0xf5,0xb7,0xcb,0xe1,0x53,0x62,0xff,0x48, + 0x32,0x96,0x02,0x0c,0xd7,0x6f,0x0d,0x2f,0xd9,0x2a,0xdd,0xa8, + 0x83,0x29,0x0a,0xd6,0x4c,0xda,0x01,0xbf,0xd1,0xc9,0x6c,0xab, + 0x4b,0xcb,0x0b,0x04,0xdd,0x9d,0x2e,0x0c,0x7b,0x1f,0x31,0xa6, + 0x8a,0x27,0x03,0xb8,0x90,0x35,0x8f,0xa0,0x72,0x50,0x96,0xcd, + 0xa8,0xa7,0x37,0xfb,0x1b,0xfd,0x46,0xdb,0xa2,0x14,0x6c,0xca, + 0xe6,0x9b,0xb9,0x39,0x18,0x17,0x2b,0x0d,0x9b,0xcf,0x17,0xd6, + 0x1c,0x90,0x73,0xe5,0x94,0x4d,0x37,0xf3,0xcd,0xf7,0xe6,0xf0, + 0x4b,0x99,0xed,0x3e,0xd2,0xf7,0xfb,0x9b,0xee,0x95,0x96,0x4b, + 0xcb,0xd7,0x9e,0x5a,0x79,0xe3,0xb9,0x16,0x13,0xc3,0xd6,0x80, + 0x3a,0x12,0xee,0xaa,0x44,0xf4,0x1d,0x38,0x10,0x52,0x19,0xce, + 0x9f,0xea,0x12,0xe6,0x64,0x2d,0xe2,0xff,0x1c,0x49,0x88,0xd3, + 0x8d,0x2a,0x2d,0x9b,0x42,0x77,0xdc,0xa6,0x31,0x89,0xd1,0x1e, + 0xe4,0x2a,0xb0,0x25,0x09,0x20,0x1b,0x98,0x54,0xdc,0xa5,0x5d, + 0xfd,0xd6,0xf6,0x29,0xc3,0x02,0xbc,0xcd,0xb5,0xeb,0xa7,0x68, + 0x04,0x95,0xae,0x3e,0x18,0xa8,0x75,0x40,0xcc,0x73,0xdd,0x2f, + 0x8c,0x83,0x5a,0xe4,0x9a,0xa0,0x99,0xed,0xd3,0x4f,0xbf,0x16, + 0x8b,0xc8,0x88,0x13,0xe0,0xa2,0x12,0xf0,0x28,0x89,0x06,0x45, + 0xd5,0x65,0x93,0xf4,0xe1,0x0e,0x76,0x03,0x38,0x12,0xb3,0x6f, + 0x89,0x3c,0xab,0x23,0x59,0x0c,0x24,0xeb,0x49,0x77,0x22,0x49, + 0x24,0xa1,0x43,0x76,0x11,0xc3,0x1e,0x63,0xe6,0x2f,0x11,0xc1, + 0x9b,0x14,0xf7,0x0d,0xbc,0xae,0x00,0x77,0xcf,0x2f,0x7d,0x7a, + 0xe5,0xe7,0x17,0x01,0x2e,0x3e,0xbd,0x5e,0x26,0xfd,0x36,0xda, + 0x8c,0xf2,0x0c,0x37,0x92,0xd9,0x57,0x09,0x19,0x3c,0xb0,0x82, + 0x06,0x40,0x30,0x11,0x41,0x65,0xa3,0x6c,0x54,0x94,0x79,0x0e, + 0xdc,0x54,0xd8,0x73,0xe4,0x05,0xec,0xcf,0x8b,0xec,0x39,0x83, + 0xf1,0x6b,0x44,0x97,0xcd,0x72,0xc5,0x3e,0xf0,0x12,0xe7,0x4c, + 0x23,0xee,0x69,0xf7,0xcb,0xe6,0x1d,0xaa,0xf6,0xad,0x39,0xb6, + 0x11,0x9b,0x2c,0x37,0x4d,0x53,0x7f,0x66,0xc0,0xdb,0xb6,0xdb, + 0xa0,0x73,0x75,0x02,0x2e,0x46,0x6a,0x58,0xe3,0x38,0xd0,0x87, + 0xea,0x3c,0x74,0xab,0xf0,0xc1,0x97,0x30,0x01,0xa4,0x96,0x5b, + 0x6f,0x11,0xb0,0x26,0x9e,0x5b,0x19,0x91,0x5e,0x0f,0xf8,0xfa, + 0x1a,0x1a,0x43,0x21,0x6d,0x98,0x79,0x12,0x41,0xf4,0x19,0xde, + 0xf4,0xa8,0x3a,0x8f,0x0a,0xc1,0xd3,0x78,0x78,0x9d,0x95,0x06, + 0x2b,0xcc,0x31,0x9c,0x5d,0x56,0x97,0x01,0xf7,0xc5,0xe9,0xed, + 0x79,0x93,0xe3,0x69,0x93,0xe1,0xa4,0x3d,0xaa,0x3c,0x6d,0xe2, + 0x87,0x4d,0xe8,0xda,0xc9,0x29,0xb2,0x05,0x00,0x4d,0x3f,0x06, + 0x17,0x27,0x90,0x05,0x55,0x36,0xda,0xe6,0x25,0x09,0xc4,0x75, + 0x63,0xff,0x12,0xde,0x07,0x5f,0x54,0x9f,0xeb,0xb2,0x77,0x48, + 0x84,0x5c,0x8d,0xbb,0x49,0x0d,0x07,0x94,0x08,0xd7,0xb3,0x60, + 0xb4,0x7b,0xcd,0xde,0x03,0xac,0xc7,0x00,0x84,0x38,0x3d,0x0e, + 0x4f,0x88,0x6e,0xb7,0xe9,0x31,0x5f,0x3c,0xd5,0xd3,0xa2,0xbb, + 0xaf,0x0e,0xb8,0xf3,0xb3,0x74,0xa9,0x78,0x13,0x03,0x1b,0x10, + 0xd8,0x40,0xb8,0x4a,0x3c,0x41,0x40,0x30,0x9d,0xbe,0x44,0xfe, + 0xa7,0x12,0x91,0x6e,0x85,0xe2,0xac,0x3d,0xd8,0xa3,0x39,0x02, + 0xd5,0x44,0xf4,0x1e,0x8c,0x3b,0xdd,0x0a,0x51,0x62,0x3c,0xec, + 0x23,0x62,0xf8,0xc2,0x83,0x61,0x47,0xe7,0x4f,0x30,0xa6,0xe2, + 0xf0,0xe4,0xff,0xe5,0xef,0xb0,0x3b,0x02,0xb8,0x40,0x73,0xec, + 0x2b,0x1a,0xee,0xab,0xf5,0xa7,0x56,0xf4,0xd9,0x27,0x88,0x41, + 0xc1,0x76,0xbb,0xdf,0x45,0x50,0x3d,0x79,0x52,0xa2,0xb1,0xba, + 0x0e,0x7b,0x58,0xae,0x2c,0xca,0x47,0x81,0x99,0x64,0x95,0xec, + 0xaf,0x87,0x5f,0xe3,0x66,0x13,0xa2,0x47,0xac,0xfa,0x2b,0xdf, + 0xbd,0xad,0x5a,0x29,0x3a,0xcc,0xf4,0xf2,0x09,0x23,0x02,0x89, + 0x68,0x86,0x45,0xb8,0x2f,0xaf,0xd7,0x61,0xcc,0x49,0x95,0xb8, + 0xd4,0x51,0x0b,0x07,0x8d,0x46,0xfe,0x9d,0x9c,0x85,0xc9,0xea, + 0xe4,0x00,0xe7,0x59,0xfd,0x15,0xda,0x3d,0xb1,0x96,0xa0,0x2e, + 0x34,0xc6,0x3f,0x71,0xfa,0x4f,0x64,0x21,0xc3,0xdd,0xdd,0x7e, + 0xa3,0x5c,0xef,0xc6,0xeb,0xfd,0xbc,0x9b,0x34,0x53,0x5e,0xe0, + 0xc4,0xf6,0xa0,0x77,0xb3,0x4d,0x2f,0x0c,0xb0,0x80,0x50,0xad, + 0x64,0xed,0xe3,0x51,0x88,0x19,0xc9,0xf9,0xdc,0x17,0x7c,0x6b, + 0xf6,0x4d,0xf3,0xbe,0x7c,0xd3,0xee,0x96,0xfc,0xdd,0x1b,0xb7, + 0xeb,0x36,0xd3,0xbf,0xe5,0xd7,0x7f,0x6f,0xff,0xe3,0xb3,0x8d, + 0x09,0x62,0xb2,0x75,0xa2,0xd1,0x4e,0xd2,0x16,0x57,0x99,0x1b, + 0x5b,0xb2,0xb1,0x2e,0x71,0x67,0xe3,0x65,0x56,0x14,0x45,0x2e, + 0x72,0x5e,0x72,0x1b,0x97,0x8e,0xff,0xcf,0x78,0x08,0x44,0x08, + 0x45,0xc8,0x23,0x79,0x35,0x04,0x22,0x8b,0x41,0x28,0xa0,0xf3, + 0x22,0xce,0x2a,0xf2,0xac,0xcc,0x62,0xd3,0x88,0x8d,0xd8,0x79, + 0x76,0x5f,0x52,0x3d,0x14,0xa1,0x50,0x10,0x36,0xe4,0x31,0x62, + 0x5d,0xc3,0x81,0x6e,0x81,0x72,0x55,0x91,0x3e,0x26,0xa1,0x1c, + 0x8c,0x50,0x74,0xb1,0x75,0xb8,0x15,0x8c,0x91,0xc8,0x1e,0x5e, + 0xbc,0x41,0xde,0x10,0x8f,0xdb,0xf0,0x72,0x7c,0x61,0x5c,0xf2, + 0x94,0x85,0x0b,0xd6,0xe2,0x37,0x07,0x72,0x3c,0xbf,0x00,0x45, + 0x31,0x9e,0x2d,0xb6,0x26,0x26,0x9b,0x8b,0x0e,0xe0,0xb9,0x66, + 0x4e,0xf8,0xef,0xc4,0x2f,0x21,0x48,0xff,0xc2,0x91,0xef,0xfe, + 0x0b,0x06,0x62,0xc2,0xe3,0x11,0x13,0x00,0x00, +}; + +const GFXglyph Oswald_Medium20pt7bGlyphs[] PROGMEM = { + { 0, 1, 1, 10, 0, 0 }, // 0x20 ' ' + { 1, 5, 32, 9, 2, -31 }, // 0x21 '!' + { 21, 11, 11, 12, 1, -31 }, // 0x22 '"' + { 37, 17, 32, 20, 2, -31 }, // 0x23 '#' + { 105, 17, 39, 19, 1, -34 }, // 0x24 '$' + { 188, 34, 32, 37, 2, -31 }, // 0x25 '%' + { 324, 19, 32, 23, 2, -31 }, // 0x26 '&' + { 400, 4, 11, 6, 1, -31 }, // 0x27 ''' + { 406, 8, 39, 13, 3, -31 }, // 0x28 '(' + { 445, 9, 39, 12, 1, -31 }, // 0x29 ')' + { 489, 13, 14, 16, 2, -31 }, // 0x2A '*' + { 512, 15, 16, 17, 1, -23 }, // 0x2B '+' + { 542, 5, 10, 8, 2, -4 }, // 0x2C ',' + { 549, 10, 3, 12, 1, -12 }, // 0x2D '-' + { 553, 5, 5, 9, 2, -4 }, // 0x2E '.' + { 557, 13, 32, 16, 1, -31 }, // 0x2F '/' + { 609, 17, 32, 21, 2, -31 }, // 0x30 '0' + { 677, 10, 32, 15, 1, -31 }, // 0x31 '1' + { 717, 16, 32, 19, 2, -31 }, // 0x32 '2' + { 781, 16, 32, 19, 2, -31 }, // 0x33 '3' + { 845, 18, 32, 20, 1, -31 }, // 0x34 '4' + { 917, 16, 32, 19, 2, -31 }, // 0x35 '5' + { 981, 17, 32, 20, 2, -31 }, // 0x36 '6' + { 1049, 14, 32, 16, 1, -31 }, // 0x37 '7' + { 1105, 16, 32, 20, 2, -31 }, // 0x38 '8' + { 1169, 16, 32, 20, 2, -31 }, // 0x39 '9' + { 1233, 6, 18, 9, 2, -20 }, // 0x3A ':' + { 1247, 6, 25, 10, 2, -21 }, // 0x3B ';' + { 1266, 11, 17, 15, 2, -24 }, // 0x3C '<' + { 1290, 13, 11, 17, 2, -21 }, // 0x3D '=' + { 1308, 12, 17, 15, 2, -24 }, // 0x3E '>' + { 1334, 15, 32, 19, 2, -31 }, // 0x3F '?' + { 1394, 33, 37, 36, 2, -31 }, // 0x40 '@' + { 1547, 19, 32, 20, 1, -31 }, // 0x41 'A' + { 1623, 18, 32, 22, 2, -31 }, // 0x42 'B' + { 1695, 18, 32, 21, 2, -31 }, // 0x43 'C' + { 1767, 18, 32, 22, 2, -31 }, // 0x44 'D' + { 1839, 14, 32, 17, 2, -31 }, // 0x45 'E' + { 1895, 13, 32, 16, 2, -31 }, // 0x46 'F' + { 1947, 18, 32, 22, 2, -31 }, // 0x47 'G' + { 2019, 18, 32, 23, 2, -31 }, // 0x48 'H' + { 2091, 5, 32, 11, 3, -31 }, // 0x49 'I' + { 2111, 10, 33, 13, 0, -31 }, // 0x4A 'J' + { 2153, 19, 32, 21, 2, -31 }, // 0x4B 'K' + { 2229, 14, 32, 16, 2, -31 }, // 0x4C 'L' + { 2285, 22, 32, 27, 2, -31 }, // 0x4D 'M' + { 2373, 17, 32, 21, 2, -31 }, // 0x4E 'N' + { 2441, 18, 32, 22, 2, -31 }, // 0x4F 'O' + { 2513, 18, 32, 21, 2, -31 }, // 0x50 'P' + { 2585, 18, 38, 22, 2, -31 }, // 0x51 'Q' + { 2671, 18, 32, 22, 2, -31 }, // 0x52 'R' + { 2743, 16, 32, 19, 2, -31 }, // 0x53 'S' + { 2807, 15, 32, 17, 1, -31 }, // 0x54 'T' + { 2867, 18, 32, 22, 2, -31 }, // 0x55 'U' + { 2939, 18, 32, 20, 1, -31 }, // 0x56 'V' + { 3011, 26, 32, 28, 1, -31 }, // 0x57 'W' + { 3115, 19, 32, 20, 0, -31 }, // 0x58 'X' + { 3191, 19, 32, 19, 0, -31 }, // 0x59 'Y' + { 3267, 15, 32, 17, 1, -31 }, // 0x5A 'Z' + { 3327, 9, 39, 13, 2, -31 }, // 0x5B '[' + { 3371, 13, 32, 16, 1, -31 }, // 0x5C '\' + { 3423, 9, 39, 12, 1, -31 }, // 0x5D ']' + { 3467, 16, 13, 18, 1, -31 }, // 0x5E '^' + { 3493, 14, 4, 14, 0, 3 }, // 0x5F '_' + { 3500, 8, 8, 11, 2, -31 }, // 0x60 '`' + { 3508, 15, 23, 17, 1, -22 }, // 0x61 'a' + { 3552, 15, 32, 19, 2, -31 }, // 0x62 'b' + { 3612, 14, 23, 17, 2, -22 }, // 0x63 'c' + { 3653, 15, 32, 19, 2, -31 }, // 0x64 'd' + { 3713, 14, 23, 17, 2, -22 }, // 0x65 'e' + { 3754, 11, 31, 12, 1, -30 }, // 0x66 'f' + { 3797, 18, 31, 18, 1, -23 }, // 0x67 'g' + { 3867, 15, 32, 19, 2, -31 }, // 0x68 'h' + { 3927, 6, 31, 10, 2, -30 }, // 0x69 'i' + { 3951, 9, 37, 10, -1, -30 }, // 0x6A 'j' + { 3993, 16, 32, 18, 2, -31 }, // 0x6B 'k' + { 4057, 6, 32, 10, 2, -31 }, // 0x6C 'l' + { 4081, 24, 23, 28, 2, -22 }, // 0x6D 'm' + { 4150, 15, 23, 19, 2, -22 }, // 0x6E 'n' + { 4194, 14, 23, 18, 2, -22 }, // 0x6F 'o' + { 4235, 15, 30, 19, 2, -22 }, // 0x70 'p' + { 4292, 15, 30, 19, 2, -22 }, // 0x71 'q' + { 4349, 11, 23, 14, 2, -22 }, // 0x72 'r' + { 4381, 14, 23, 16, 1, -22 }, // 0x73 's' + { 4422, 11, 29, 13, 1, -28 }, // 0x74 't' + { 4462, 14, 23, 19, 2, -22 }, // 0x75 'u' + { 4503, 15, 23, 16, 0, -22 }, // 0x76 'v' + { 4547, 21, 23, 23, 1, -22 }, // 0x77 'w' + { 4608, 16, 23, 16, 0, -22 }, // 0x78 'x' + { 4654, 16, 29, 16, 0, -22 }, // 0x79 'y' + { 4712, 13, 23, 15, 1, -22 }, // 0x7A 'z' + { 4750, 10, 40, 13, 2, -31 }, // 0x7B '{' + { 4800, 4, 38, 10, 3, -31 }, // 0x7C '|' + { 4819, 10, 40, 14, 2, -31 }, // 0x7D '}' + { 4869, 16, 6, 18, 1, -18 } }; // 0x7E '~' + +// const GFXfont Oswald_Medium20pt7b PROGMEM = { +// (uint8_t *)Oswald_Medium20pt7bBitmaps, +// (GFXglyph *)Oswald_Medium20pt7bGlyphs, +// 0x20, 0x7E, 58 }; + +// // Approx. 5553 bytes + + +// Font properties +static constexpr FontData Oswald_Medium20pt7b_Properties = { + Oswald_Medium20pt7bBitmaps_Gzip, + Oswald_Medium20pt7bGlyphs, + sizeof(Oswald_Medium20pt7bBitmaps_Gzip), + 5553, // Original size + 0x20, // First char + 0x7E, // Last char + 58 // yAdvance +}; diff --git a/src/fonts/oswald-medium30.h b/src/fonts/oswald-medium30.h new file mode 100644 index 0000000..3cab489 --- /dev/null +++ b/src/fonts/oswald-medium30.h @@ -0,0 +1,497 @@ +#pragma once + +#include +#include +#include "fonts.hpp" + +const uint8_t Oswald_Medium30pt7bBitmaps_Gzip[] = { + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcd, 0x5a, + 0xbb, 0x72, 0x23, 0x3b, 0x92, 0x05, 0xb7, 0x8c, 0x72, 0x26, 0x1a, 0x63, + 0x5e, 0x63, 0xe2, 0x62, 0x3f, 0x61, 0xcc, 0x36, 0xee, 0x08, 0xf7, 0x53, + 0xf6, 0x13, 0xc6, 0x6c, 0x43, 0x4b, 0x94, 0x82, 0x86, 0xbc, 0xd1, 0x27, + 0xf0, 0x53, 0x04, 0x86, 0x0c, 0x99, 0xfc, 0x83, 0x65, 0x31, 0x68, 0xd0, + 0x14, 0x14, 0x32, 0x08, 0x86, 0x4a, 0xc8, 0x3d, 0x27, 0xc1, 0xa7, 0xd4, + 0x52, 0xf7, 0xbd, 0xdd, 0x3b, 0xb1, 0x25, 0x50, 0x55, 0x85, 0x42, 0xe1, + 0x91, 0x48, 0x9c, 0x3c, 0x99, 0x28, 0x23, 0x3c, 0x0a, 0x8f, 0xf1, 0xee, + 0xb8, 0xac, 0xc7, 0x6f, 0x7a, 0x7c, 0xd6, 0xc3, 0x18, 0x23, 0xbb, 0xa3, + 0x78, 0x71, 0x72, 0xb3, 0xb8, 0x7f, 0x58, 0x6d, 0x96, 0xcf, 0xe9, 0x25, + 0x8f, 0x87, 0x8b, 0xb1, 0xbb, 0xb0, 0xd3, 0x76, 0x3e, 0x59, 0xcf, 0x56, + 0xfd, 0x63, 0xff, 0x25, 0xfd, 0x66, 0x46, 0x83, 0xeb, 0x42, 0xdb, 0xbb, + 0x49, 0x6e, 0xfb, 0x61, 0x94, 0xbd, 0x19, 0xdb, 0xe8, 0x26, 0x09, 0x37, + 0x0d, 0x6e, 0x8a, 0x8b, 0xbe, 0x4d, 0x76, 0x96, 0x9b, 0x34, 0x36, 0x28, + 0xe9, 0xdb, 0x25, 0x2a, 0x0e, 0x22, 0x0b, 0x91, 0x8d, 0xc8, 0x0b, 0x6e, + 0x76, 0xaf, 0x15, 0x1b, 0xfd, 0x35, 0x4a, 0x0e, 0x28, 0x69, 0xf7, 0x3d, + 0x90, 0x5b, 0x91, 0x07, 0x91, 0x67, 0xf4, 0xa5, 0xd6, 0x79, 0x6c, 0xc0, + 0xb2, 0x81, 0x80, 0x3a, 0xd1, 0x40, 0x7f, 0xda, 0x40, 0xef, 0xee, 0x72, + 0x9b, 0x0a, 0x4b, 0x9a, 0xbf, 0x19, 0xf3, 0xc9, 0x98, 0xd6, 0x98, 0xa6, + 0x33, 0xa3, 0x68, 0xda, 0xc1, 0x38, 0xe9, 0x9c, 0xf4, 0x4e, 0xb2, 0x43, + 0x95, 0x22, 0x76, 0x90, 0x79, 0x76, 0xeb, 0xdc, 0x3e, 0x0d, 0xcd, 0x4b, + 0x19, 0x15, 0x31, 0x12, 0xba, 0x70, 0x1b, 0xff, 0xe6, 0x92, 0xb1, 0x83, + 0x69, 0x8a, 0x19, 0x49, 0x67, 0xa4, 0x37, 0x7e, 0x30, 0x56, 0x4c, 0x23, + 0xd1, 0x48, 0x7a, 0x73, 0xd3, 0xd6, 0x62, 0x01, 0xc5, 0xf0, 0x5a, 0xfe, + 0xd2, 0xc8, 0x30, 0x12, 0x54, 0x25, 0x5d, 0x90, 0x58, 0x9b, 0xb3, 0xcf, + 0x43, 0xbb, 0x95, 0xeb, 0x21, 0x50, 0xaa, 0xc5, 0x4a, 0x69, 0xa4, 0x18, + 0x24, 0x37, 0x18, 0x93, 0x8c, 0xf9, 0xfc, 0xaa, 0xaf, 0x68, 0x1a, 0xb9, + 0xa8, 0xfd, 0xd2, 0x98, 0x20, 0xc6, 0x76, 0xe8, 0x78, 0x42, 0x16, 0xdf, + 0xba, 0xe4, 0x0c, 0xf5, 0xcc, 0xa2, 0xb0, 0x0c, 0xc4, 0xdc, 0x21, 0x6b, + 0xdc, 0x64, 0x66, 0xc5, 0x30, 0x62, 0x96, 0xed, 0xc7, 0x78, 0x71, 0x34, + 0x20, 0xcb, 0xf6, 0xfe, 0x2a, 0xa1, 0xc6, 0x16, 0x02, 0x32, 0xbe, 0x2b, + 0xc8, 0x6a, 0x93, 0x9b, 0xa1, 0xfa, 0xd2, 0x64, 0x64, 0xd9, 0x18, 0x6c, + 0xc4, 0x73, 0xcb, 0x2c, 0x3f, 0xc9, 0x17, 0xe8, 0x44, 0x66, 0x16, 0x1a, + 0x5e, 0x22, 0xcb, 0x4a, 0xbe, 0x68, 0x30, 0x18, 0x4c, 0x10, 0x86, 0x21, + 0xb3, 0x1c, 0xa4, 0x93, 0xfe, 0x02, 0xd9, 0xa3, 0xd8, 0xde, 0x61, 0x98, + 0x66, 0x94, 0xc3, 0x0d, 0x0a, 0x5e, 0xd8, 0xbe, 0xe0, 0xdd, 0xbb, 0xec, + 0x22, 0xb3, 0x9a, 0xac, 0x59, 0x01, 0x59, 0xb3, 0xa1, 0xed, 0x91, 0xe5, + 0x3b, 0x0c, 0x16, 0xea, 0xe0, 0xd0, 0x83, 0x58, 0x38, 0x40, 0x14, 0x65, + 0xa7, 0xd0, 0x5f, 0x4c, 0x4e, 0xd4, 0x57, 0xb2, 0xbe, 0xe2, 0xd1, 0x9f, + 0xde, 0x60, 0x2e, 0x67, 0x78, 0x25, 0x37, 0x03, 0xb2, 0x1c, 0xfa, 0xc3, + 0xac, 0x56, 0x98, 0x45, 0xa9, 0x20, 0xab, 0xc5, 0x1c, 0xa0, 0x6e, 0xdf, + 0x1b, 0xde, 0x72, 0x1a, 0x32, 0x24, 0xd5, 0x43, 0xfa, 0x9d, 0x45, 0x39, + 0xb1, 0xa9, 0x4d, 0xbe, 0xf3, 0x57, 0x03, 0xeb, 0x63, 0xcd, 0x68, 0xa3, + 0x41, 0xab, 0x2e, 0x16, 0x68, 0x5c, 0x4f, 0x0d, 0x72, 0xf7, 0xc9, 0x14, + 0x6f, 0x9a, 0xe7, 0x6c, 0xec, 0x02, 0x93, 0x98, 0x75, 0x2e, 0x6d, 0xa6, + 0xb0, 0x4c, 0xc3, 0x1e, 0x27, 0x37, 0x91, 0x6e, 0xf0, 0xa5, 0x5d, 0x49, + 0xf2, 0x6e, 0x31, 0xdb, 0x96, 0xb1, 0x9b, 0xaf, 0x72, 0x09, 0x76, 0xbd, + 0x4e, 0xc1, 0xfb, 0x2b, 0xd9, 0x0e, 0xad, 0xdc, 0xf4, 0x1e, 0xdd, 0x94, + 0x55, 0x6e, 0xa1, 0xf4, 0xae, 0x2f, 0x23, 0xb9, 0x86, 0x92, 0xb9, 0xa5, + 0x14, 0xe8, 0xf1, 0x13, 0x7e, 0x37, 0xf2, 0x34, 0x78, 0xb1, 0x3d, 0xf4, + 0xc1, 0xfc, 0xd3, 0x7c, 0xa6, 0x7a, 0x2f, 0x6e, 0xc7, 0x2f, 0xcf, 0xeb, + 0xf9, 0xf4, 0xe2, 0x32, 0x99, 0x2f, 0x36, 0x16, 0x9b, 0xe4, 0x66, 0x08, + 0x6d, 0x46, 0x87, 0x51, 0x03, 0xba, 0xce, 0xb3, 0xe0, 0x7e, 0x86, 0x47, + 0x61, 0x72, 0xc8, 0xc4, 0x48, 0x38, 0x0a, 0xbd, 0xd9, 0x3f, 0xa9, 0xc5, + 0xf6, 0x8f, 0xeb, 0xbf, 0x62, 0x07, 0xdf, 0x0b, 0xc5, 0xfb, 0x2b, 0x56, + 0x0f, 0xcb, 0x66, 0x1f, 0x71, 0xef, 0xf4, 0x7d, 0x3e, 0xd9, 0x55, 0x32, + 0x9c, 0x55, 0xf2, 0xb5, 0x9b, 0x93, 0x86, 0xfd, 0x8c, 0x67, 0x3c, 0x9c, + 0x0c, 0xe1, 0xae, 0xf0, 0x51, 0x0f, 0xfd, 0x1d, 0x74, 0x22, 0x0c, 0xd4, + 0xcf, 0x76, 0xbf, 0x5c, 0x7e, 0x7e, 0x5a, 0xcd, 0x65, 0x1c, 0x38, 0xc8, + 0x7b, 0x49, 0x58, 0x20, 0x0e, 0x93, 0x42, 0x6d, 0x7f, 0x4e, 0x76, 0x1e, + 0x87, 0x71, 0xbb, 0xcc, 0x9f, 0xac, 0xf9, 0xfb, 0x7f, 0x72, 0x2a, 0x9b, + 0x9e, 0x0a, 0x7e, 0x71, 0x7e, 0xd9, 0xc8, 0xe9, 0x91, 0xde, 0x16, 0x38, + 0x5c, 0xee, 0xcb, 0xb4, 0xad, 0x75, 0x17, 0x97, 0x5f, 0xfe, 0x7e, 0xf2, + 0xd6, 0xfe, 0x82, 0x65, 0x2f, 0x8d, 0xeb, 0x4e, 0x4f, 0xb6, 0x6b, 0xd2, + 0xab, 0xd3, 0x18, 0xa7, 0xd1, 0xe9, 0x29, 0xe2, 0x74, 0xf1, 0xea, 0xd4, + 0xc6, 0x51, 0x3e, 0x3d, 0xa1, 0x27, 0xfe, 0xec, 0xe4, 0x28, 0x08, 0x23, + 0x1d, 0x74, 0xb1, 0xe1, 0x3a, 0x97, 0x2b, 0x91, 0xa5, 0x76, 0x66, 0x90, + 0x49, 0x09, 0x51, 0x7c, 0x0c, 0x0b, 0x60, 0x42, 0xc2, 0x12, 0x82, 0x32, + 0xa3, 0xcc, 0x11, 0x2c, 0xbc, 0xfc, 0xd0, 0x83, 0x97, 0xd2, 0x14, 0x19, + 0x49, 0x98, 0x89, 0x7f, 0x84, 0xbe, 0xc9, 0xb5, 0xc8, 0x4c, 0x24, 0x2a, + 0x0a, 0x45, 0xe2, 0x15, 0x30, 0xd1, 0x8c, 0xb1, 0x16, 0x72, 0x78, 0x3a, + 0x91, 0xee, 0x3d, 0xa6, 0xdf, 0xf5, 0xe8, 0x56, 0x27, 0xa3, 0xd2, 0x0c, + 0x6d, 0xfe, 0x73, 0xb7, 0x26, 0x44, 0x8c, 0x19, 0x5d, 0x1b, 0x69, 0xb3, + 0x18, 0x73, 0xc6, 0x98, 0xd1, 0x19, 0x8c, 0xf9, 0x36, 0x7a, 0x8c, 0xf9, + 0x21, 0xd9, 0x4d, 0x6e, 0x9f, 0x0f, 0x58, 0x4b, 0x31, 0xe1, 0x2d, 0xe3, + 0x23, 0x97, 0x30, 0x12, 0x60, 0x97, 0xc8, 0x4b, 0x14, 0x65, 0x6a, 0x33, + 0x31, 0xbb, 0x55, 0x20, 0xae, 0x09, 0x4a, 0x54, 0x13, 0xdf, 0xac, 0x09, + 0xef, 0xef, 0xaa, 0x50, 0x7b, 0xb1, 0x50, 0x93, 0xb1, 0x51, 0xab, 0x01, + 0xfb, 0x02, 0x94, 0x8d, 0x87, 0x99, 0x98, 0x68, 0xaf, 0xb6, 0x58, 0x64, + 0x72, 0x55, 0xd0, 0xe3, 0xdb, 0x2a, 0xbe, 0xde, 0x42, 0x45, 0x59, 0x66, + 0x18, 0x01, 0xc1, 0x50, 0x77, 0xe8, 0x34, 0xb1, 0xe2, 0x86, 0xaf, 0x03, + 0xe8, 0xa3, 0xc2, 0x3b, 0x0d, 0x08, 0x40, 0xb8, 0x63, 0x5f, 0xd1, 0x4b, + 0xf4, 0x6c, 0xff, 0x86, 0x74, 0x5e, 0xb1, 0x5e, 0xab, 0xda, 0x0d, 0x70, + 0xc4, 0x91, 0xfb, 0xc4, 0x99, 0xb8, 0xdf, 0xcf, 0x04, 0x9a, 0x8b, 0x44, + 0x2d, 0xa8, 0x30, 0x2d, 0x8c, 0xda, 0x0d, 0x0c, 0x97, 0x23, 0x8b, 0x04, + 0x1f, 0x35, 0x2c, 0xbd, 0x09, 0x6a, 0xaa, 0x1a, 0x58, 0x80, 0xff, 0xc6, + 0xda, 0xb9, 0x8d, 0xcd, 0x26, 0x9b, 0x01, 0x0b, 0x68, 0xda, 0xb7, 0xab, + 0xc1, 0x0c, 0xa1, 0x73, 0x37, 0xa9, 0x5d, 0x16, 0x33, 0x78, 0x98, 0x4d, + 0x98, 0x5e, 0x81, 0x1d, 0xee, 0xb1, 0x20, 0x5b, 0x5d, 0xfa, 0x0a, 0x0b, + 0x3d, 0xd6, 0x29, 0x16, 0xa9, 0xbc, 0x3d, 0x12, 0xa5, 0x05, 0xd9, 0x2a, + 0x68, 0xf6, 0x0a, 0x72, 0x18, 0x2e, 0xc6, 0xc3, 0xc1, 0x9c, 0x3e, 0x0a, + 0x98, 0xbe, 0xaf, 0x26, 0xbc, 0x00, 0x45, 0x3a, 0x4f, 0xa5, 0x26, 0x1f, + 0x0b, 0x75, 0x9d, 0x53, 0xaf, 0xa9, 0x40, 0xe9, 0x45, 0x67, 0xbb, 0xe8, + 0x84, 0xbf, 0x4d, 0xf2, 0x3a, 0x69, 0x79, 0x4c, 0x90, 0xb6, 0xe5, 0x69, + 0xab, 0xa1, 0xe0, 0x3d, 0xa5, 0x46, 0xdb, 0x57, 0x95, 0x8c, 0x4b, 0x60, + 0xbf, 0xb0, 0xf6, 0xd3, 0x09, 0x2d, 0x9c, 0xf6, 0x6e, 0x5e, 0x57, 0x43, + 0xe6, 0xb8, 0x8e, 0xf3, 0x89, 0x61, 0xb9, 0xd5, 0x60, 0x37, 0x72, 0xfd, + 0x2c, 0x2b, 0xea, 0x00, 0xfb, 0x26, 0xa1, 0x97, 0xdb, 0xde, 0xeb, 0x6a, + 0xdc, 0x29, 0x00, 0x7b, 0x29, 0xe7, 0xd3, 0x59, 0xf5, 0x75, 0x40, 0xa7, + 0x30, 0x9d, 0x80, 0xc5, 0x1b, 0x55, 0xa4, 0xd3, 0x85, 0xa5, 0x88, 0xf4, + 0x56, 0xce, 0xb4, 0x4a, 0x6d, 0x42, 0xeb, 0xe8, 0x89, 0x7b, 0x75, 0x53, + 0x28, 0xef, 0x7a, 0x13, 0x47, 0x5f, 0xbd, 0x01, 0xa0, 0x1c, 0x6e, 0xda, + 0x93, 0x1b, 0x73, 0x72, 0x23, 0x87, 0x1b, 0x2c, 0x89, 0x56, 0xbb, 0x0b, + 0xb2, 0xe1, 0x29, 0x35, 0x62, 0x33, 0x2c, 0x00, 0x12, 0x05, 0x7a, 0x2e, + 0xdf, 0x80, 0x34, 0xd2, 0xa7, 0x93, 0xc1, 0xaf, 0x07, 0xf2, 0x13, 0x0a, + 0xe0, 0xfc, 0xf5, 0x59, 0x7d, 0xf7, 0xf8, 0x62, 0xd9, 0xa7, 0xb3, 0xda, + 0xae, 0x84, 0xf5, 0x90, 0xd6, 0xf0, 0xad, 0x5a, 0x55, 0xb3, 0x9b, 0x2a, + 0x60, 0x60, 0x3a, 0x4c, 0x55, 0xcf, 0xa9, 0x02, 0x03, 0xda, 0x4d, 0xd5, + 0x11, 0x0f, 0x5e, 0x23, 0xda, 0x11, 0x28, 0x4a, 0xf3, 0x22, 0x4d, 0x09, + 0x6b, 0x81, 0x16, 0x4f, 0x75, 0x11, 0x71, 0xbe, 0x03, 0xf8, 0xda, 0xdd, + 0xeb, 0xb9, 0xc5, 0x7a, 0x3c, 0x81, 0x16, 0xac, 0xbc, 0x6e, 0x37, 0x55, + 0x6f, 0x30, 0xf0, 0x38, 0x55, 0xe6, 0x70, 0xec, 0x18, 0x67, 0x2a, 0xbb, + 0xc3, 0x9c, 0x1f, 0x7b, 0x42, 0xfc, 0xe9, 0xd3, 0xaf, 0x17, 0xc3, 0x97, + 0x7f, 0x1a, 0xf3, 0x3b, 0x2c, 0xf8, 0x25, 0xa6, 0x22, 0xc4, 0x90, 0x3c, + 0xc6, 0xed, 0x8b, 0x2f, 0x16, 0xe0, 0x0b, 0x2b, 0xe8, 0x23, 0x2e, 0xa4, + 0x0f, 0x05, 0xf2, 0x0c, 0xe0, 0x05, 0x28, 0xd3, 0xd2, 0xc2, 0x80, 0xd9, + 0xfd, 0x7e, 0xa2, 0x1b, 0xa7, 0x4d, 0x9c, 0xdb, 0x3a, 0x68, 0xd3, 0x67, + 0xda, 0xa3, 0x0c, 0xf9, 0x79, 0x48, 0xf3, 0x8a, 0x0b, 0xe0, 0x0a, 0x33, + 0x03, 0x3e, 0x03, 0x23, 0x64, 0x93, 0x85, 0x94, 0x1d, 0xe4, 0x71, 0x03, + 0x35, 0xec, 0x50, 0xa6, 0x43, 0xe1, 0xce, 0x80, 0xb0, 0x01, 0x4c, 0x4e, + 0x27, 0x11, 0x93, 0xc2, 0x34, 0x91, 0x30, 0x3a, 0x9b, 0x32, 0x88, 0xe6, + 0xcb, 0x61, 0xf9, 0x51, 0x75, 0x0a, 0x97, 0x0a, 0x52, 0xab, 0xa0, 0x0b, + 0x00, 0x06, 0xba, 0x01, 0xfc, 0x38, 0x7d, 0x0a, 0xbb, 0xc3, 0x57, 0xd2, + 0xe9, 0xf1, 0xd5, 0x02, 0xb5, 0xcc, 0xb8, 0x8e, 0x8f, 0xd7, 0x2d, 0x66, + 0x41, 0x25, 0x3d, 0xe8, 0x35, 0x99, 0x1b, 0xfe, 0x67, 0xc2, 0x69, 0x2b, + 0x0a, 0x84, 0xa4, 0x71, 0xe0, 0x5c, 0x99, 0x8d, 0x43, 0xb8, 0x9e, 0xc5, + 0xc1, 0xda, 0xc8, 0x30, 0x21, 0x42, 0xa8, 0x7e, 0x03, 0x80, 0x06, 0xfd, + 0x87, 0x0a, 0x2e, 0x26, 0x29, 0x90, 0x10, 0x8e, 0xc1, 0xff, 0x21, 0x9f, + 0x6b, 0xac, 0x60, 0xf0, 0xb3, 0x0c, 0xbe, 0x73, 0x95, 0x87, 0x66, 0xb0, + 0xf1, 0xc2, 0xc3, 0x3a, 0x25, 0x3b, 0x8d, 0xc0, 0xc3, 0x66, 0x9d, 0x40, + 0x8c, 0xcd, 0x16, 0xdc, 0xd2, 0xc5, 0x0b, 0x30, 0x65, 0xb8, 0x24, 0xd3, + 0x0e, 0x4b, 0xba, 0x59, 0x83, 0x12, 0x8e, 0xf1, 0x00, 0x8c, 0xad, 0x1b, + 0x83, 0xe2, 0xa0, 0xc0, 0x2d, 0xca, 0xe7, 0xf6, 0x01, 0x0f, 0xca, 0xe8, + 0x09, 0x0f, 0xc0, 0x5a, 0xf5, 0x01, 0x78, 0x1e, 0xe8, 0xb6, 0xbb, 0x21, + 0xc0, 0x82, 0xbd, 0x80, 0xaa, 0xc1, 0xe5, 0xc0, 0xcc, 0xcd, 0xb2, 0xeb, + 0x80, 0x27, 0x28, 0xe3, 0xc0, 0xf4, 0x50, 0x27, 0x66, 0xa6, 0x43, 0xdf, + 0xee, 0x40, 0x41, 0x7b, 0x90, 0x5a, 0x4e, 0x24, 0x8f, 0xa0, 0xff, 0xa1, + 0xa7, 0x14, 0x48, 0xcd, 0xc2, 0x60, 0x99, 0x95, 0xaa, 0x8c, 0x6a, 0xa9, + 0x6c, 0x7e, 0xad, 0xea, 0x08, 0x2f, 0x40, 0x21, 0x04, 0x76, 0x00, 0x42, + 0xd2, 0x1b, 0x55, 0x54, 0x55, 0x1c, 0x50, 0x6c, 0x43, 0x71, 0xf1, 0x2d, + 0x47, 0xb4, 0x06, 0x33, 0xc6, 0xa5, 0xcf, 0xea, 0x95, 0x38, 0xae, 0x8c, + 0xac, 0xe4, 0xd8, 0x63, 0xfa, 0x80, 0xf7, 0x0e, 0xcc, 0x16, 0x5a, 0xdd, + 0x6e, 0x30, 0xb7, 0xb7, 0x5d, 0xf3, 0x02, 0xa0, 0x99, 0x03, 0x83, 0x7c, + 0xd7, 0x3e, 0x42, 0x63, 0x6f, 0x7a, 0x32, 0x6c, 0xb7, 0xca, 0xf0, 0xd7, + 0xfa, 0x36, 0x09, 0xdd, 0x80, 0x66, 0x50, 0x16, 0x6b, 0x40, 0x02, 0xc1, + 0xfc, 0x22, 0x0c, 0x0a, 0xc6, 0x0a, 0xc5, 0x82, 0xc6, 0x41, 0xd2, 0xb8, + 0xf4, 0x8a, 0x82, 0xb0, 0x3a, 0x60, 0xb4, 0x26, 0x5c, 0xe3, 0x05, 0x1f, + 0xdd, 0x0a, 0x2f, 0xa0, 0x8a, 0x0c, 0x4b, 0xb5, 0x86, 0xfe, 0xfa, 0x88, + 0x35, 0x6c, 0xb0, 0xa0, 0x47, 0x9c, 0x75, 0xc7, 0x85, 0x8e, 0x45, 0x41, + 0xff, 0x87, 0x0b, 0xb9, 0xf8, 0x7b, 0xb9, 0xcf, 0x2d, 0xcc, 0x1a, 0x60, + 0xdb, 0x3e, 0x61, 0x6e, 0x61, 0xd6, 0xe6, 0xa9, 0xd9, 0x16, 0x13, 0xb0, + 0x8a, 0xd6, 0xa8, 0xb2, 0x3e, 0x5a, 0x61, 0x46, 0xc3, 0x95, 0xd4, 0xb7, + 0xd0, 0x30, 0x20, 0x83, 0x68, 0x42, 0x07, 0x6e, 0x35, 0xb4, 0x78, 0x2b, + 0xcc, 0x53, 0xfb, 0x82, 0xb7, 0x6e, 0x23, 0x40, 0x80, 0xca, 0xee, 0x45, + 0xfd, 0x04, 0xa1, 0xb7, 0x97, 0xe8, 0x34, 0xd5, 0x47, 0x0d, 0xf1, 0x6c, + 0xd1, 0x7b, 0x90, 0x1f, 0x2c, 0x0d, 0xa2, 0x03, 0x49, 0x8a, 0xe7, 0x80, + 0x8a, 0x0a, 0x51, 0xd1, 0x0d, 0x58, 0x41, 0xb3, 0x89, 0xe6, 0xd6, 0xc5, + 0x6d, 0x09, 0xfb, 0x80, 0x25, 0x2c, 0xab, 0xac, 0x3e, 0x1b, 0x2d, 0xc3, + 0x9b, 0x1b, 0x2e, 0x13, 0xb3, 0xa3, 0x05, 0x1f, 0xdc, 0xbc, 0x5f, 0x01, + 0x61, 0x0b, 0x6c, 0x21, 0x4c, 0xb3, 0x5f, 0x55, 0xe3, 0x89, 0xc1, 0x35, + 0x15, 0x10, 0x39, 0x8f, 0x0e, 0x95, 0x60, 0xa6, 0x88, 0xae, 0x14, 0x7b, + 0x52, 0xef, 0x5c, 0xe6, 0xf0, 0x2c, 0x20, 0x00, 0x0c, 0xea, 0x36, 0x02, + 0x33, 0xdb, 0xea, 0x77, 0x2a, 0xd4, 0xfd, 0xec, 0x1b, 0x20, 0x6b, 0x6d, + 0x47, 0x1b, 0xad, 0x5d, 0x54, 0x4f, 0x56, 0x1a, 0x15, 0xf4, 0x5b, 0x8e, + 0x21, 0xd5, 0x40, 0xbd, 0xf7, 0x0f, 0xd2, 0xcf, 0x27, 0xff, 0x3e, 0x2e, + 0x7c, 0xf2, 0xda, 0x47, 0x47, 0x04, 0x82, 0x41, 0xf5, 0xa0, 0xce, 0x30, + 0x0b, 0x36, 0x01, 0xd8, 0xfc, 0x79, 0x16, 0xed, 0xbe, 0x97, 0x35, 0x6d, + 0xff, 0x14, 0xa2, 0x7b, 0xa7, 0xd4, 0x47, 0x59, 0xd4, 0x92, 0x20, 0x27, + 0x33, 0x01, 0x3d, 0x72, 0x83, 0x5f, 0x01, 0xfc, 0x43, 0xe7, 0xa1, 0x87, + 0x50, 0x78, 0x4c, 0xa4, 0x7b, 0xa0, 0x07, 0x63, 0x54, 0x6f, 0x28, 0xc6, + 0x8e, 0xcb, 0x9c, 0xaa, 0x00, 0x68, 0xb3, 0x59, 0x09, 0x2c, 0x34, 0x02, + 0xfc, 0xd1, 0xec, 0x2a, 0xa1, 0x24, 0x67, 0xaa, 0x8c, 0x5f, 0xd3, 0x5e, + 0x89, 0x56, 0xf6, 0x8a, 0x6d, 0x9f, 0x07, 0xaa, 0x8a, 0x7f, 0x18, 0x2c, + 0x29, 0xcc, 0x54, 0x9e, 0x1f, 0x45, 0xc6, 0x4e, 0xe6, 0x33, 0x79, 0xcc, + 0xe8, 0x8a, 0xf9, 0x8d, 0xb8, 0xfe, 0x71, 0x1d, 0xdf, 0xf3, 0xe8, 0xbd, + 0xe3, 0x4f, 0x57, 0x78, 0xfe, 0xe8, 0x0f, 0x1e, 0x4d, 0x69, 0xe1, 0xb6, + 0xb8, 0xe4, 0x7b, 0x90, 0xb0, 0xab, 0x1f, 0xb8, 0x1d, 0xe9, 0x8d, 0xdf, + 0xc0, 0x4b, 0x98, 0x0a, 0x5c, 0xf6, 0x04, 0x44, 0x23, 0x44, 0x51, 0xac, + 0x15, 0x4a, 0xec, 0x23, 0x26, 0x13, 0x5c, 0x12, 0xfe, 0x3b, 0x40, 0x1e, + 0x90, 0x48, 0x07, 0x98, 0x5e, 0x30, 0x30, 0xff, 0x0a, 0xb7, 0xfe, 0x1e, + 0xbc, 0x1a, 0x6f, 0xf9, 0xde, 0xad, 0x07, 0xc5, 0xa8, 0xdb, 0xfe, 0x14, + 0x77, 0x14, 0x43, 0x1c, 0x17, 0x38, 0x96, 0x2f, 0x98, 0xcc, 0x16, 0x4b, + 0xdb, 0xf7, 0xfe, 0x0e, 0x6f, 0xa1, 0xfd, 0x56, 0x1d, 0x6f, 0x56, 0x48, + 0xd7, 0xdd, 0x2f, 0xd1, 0x1d, 0x6d, 0xcb, 0x66, 0xb0, 0x16, 0xd7, 0x83, + 0xa4, 0xee, 0x35, 0x09, 0x88, 0x26, 0x07, 0x44, 0xfb, 0xce, 0xe5, 0xf1, + 0xc3, 0xff, 0xce, 0x0f, 0xb2, 0x80, 0x29, 0x18, 0xe6, 0x1a, 0x6c, 0x73, + 0x0b, 0x3b, 0x5d, 0x02, 0xa0, 0x1c, 0x19, 0xa0, 0x64, 0x06, 0xd0, 0x18, + 0x91, 0x81, 0x59, 0x9d, 0x62, 0x82, 0x91, 0xe1, 0xb7, 0x50, 0xce, 0x12, + 0x80, 0xce, 0x53, 0x8c, 0x78, 0x8d, 0xc1, 0x23, 0xc3, 0x8d, 0x41, 0x82, + 0x16, 0x53, 0x69, 0x36, 0x6b, 0x89, 0x2f, 0xdb, 0x97, 0xe4, 0xc7, 0xe1, + 0xd2, 0x4e, 0xa7, 0x8b, 0xc9, 0x7a, 0xbd, 0x59, 0x6e, 0xb7, 0xdb, 0x3c, + 0x1e, 0x8f, 0x2f, 0xdc, 0x74, 0x7a, 0x73, 0x7d, 0xbf, 0x5e, 0x3d, 0x3d, + 0x6e, 0xf3, 0x30, 0x8c, 0xc7, 0xde, 0xbb, 0xe9, 0xf5, 0xfc, 0x7e, 0xbd, + 0x7c, 0x5a, 0x6e, 0x73, 0x40, 0x11, 0x57, 0x90, 0x21, 0xd7, 0xeb, 0x5e, + 0x90, 0xe1, 0xd3, 0x78, 0x0c, 0x12, 0x34, 0x9d, 0x48, 0x0b, 0x03, 0x3e, + 0xdb, 0x32, 0x9e, 0x31, 0x86, 0x5c, 0x17, 0x57, 0xa5, 0xdd, 0xc0, 0x3e, + 0xbf, 0x30, 0x88, 0x34, 0x86, 0xb1, 0x96, 0x0e, 0x04, 0xac, 0xf7, 0x70, + 0x18, 0x6c, 0x84, 0x47, 0xc5, 0x54, 0xf6, 0x49, 0x6a, 0xea, 0x34, 0xc5, + 0x7d, 0xea, 0x35, 0xa5, 0x7d, 0xca, 0x9a, 0xd4, 0xe5, 0x29, 0x45, 0xd3, + 0x38, 0x94, 0xa0, 0xc9, 0x6b, 0x24, 0xcf, 0xed, 0x93, 0xd5, 0xd4, 0x6a, + 0x6a, 0xf6, 0x49, 0xb9, 0x6f, 0x39, 0x32, 0xe7, 0xda, 0xb4, 0xaf, 0xe9, + 0x35, 0x92, 0x64, 0x45, 0x92, 0xf0, 0x54, 0x91, 0x64, 0x91, 0xce, 0x14, + 0xe9, 0x04, 0x49, 0xbc, 0xfc, 0xb4, 0x47, 0xaa, 0xf2, 0x31, 0xcc, 0x07, + 0x97, 0xab, 0x39, 0x9d, 0xa9, 0x8d, 0x57, 0xdc, 0xb7, 0xc4, 0x2c, 0xf5, + 0xce, 0x40, 0x25, 0xdf, 0x5a, 0x1d, 0x5a, 0x83, 0x50, 0xad, 0xce, 0xf3, + 0x50, 0x55, 0x3f, 0x2a, 0xf3, 0x3f, 0x18, 0x8d, 0x87, 0x9d, 0xd1, 0x68, + 0xe8, 0x95, 0xe3, 0x9d, 0x6a, 0xd7, 0xb2, 0xd6, 0x96, 0xc9, 0x0e, 0x45, + 0x9d, 0x4d, 0x28, 0xdd, 0x9f, 0xbd, 0xf9, 0xff, 0x21, 0x41, 0x79, 0x5f, + 0x82, 0x51, 0xe3, 0xbb, 0xe8, 0x70, 0xb3, 0x3b, 0x31, 0xaa, 0x68, 0x18, + 0x8d, 0x62, 0xc4, 0xb7, 0x31, 0xa7, 0xa4, 0x48, 0xf6, 0xa4, 0x68, 0x26, + 0xeb, 0x03, 0x29, 0xd2, 0xea, 0x3b, 0x88, 0xb2, 0x39, 0xd2, 0x1b, 0x0a, + 0x7e, 0xb1, 0xe7, 0x4b, 0x80, 0x2b, 0xac, 0x32, 0x9d, 0x96, 0xeb, 0xea, + 0x62, 0x41, 0x17, 0x41, 0xc5, 0x7a, 0x85, 0xab, 0x0a, 0x31, 0xb3, 0x03, + 0xe6, 0xf4, 0xe1, 0x8e, 0xb1, 0x9f, 0x4e, 0x6c, 0x72, 0x4b, 0x05, 0x39, + 0x0f, 0x02, 0x06, 0xe3, 0x2b, 0xf0, 0x9b, 0x6b, 0x85, 0xaf, 0x80, 0x47, + 0x63, 0x2c, 0xb9, 0x7a, 0x66, 0xa9, 0x2a, 0xc2, 0x75, 0xf1, 0x4b, 0x54, + 0xa6, 0x0e, 0x96, 0x9b, 0xe7, 0xf6, 0x89, 0x0e, 0x57, 0x87, 0xde, 0xfe, + 0xda, 0x56, 0xc3, 0x16, 0x7a, 0x8d, 0x9d, 0xd7, 0xc8, 0x86, 0x2b, 0xfb, + 0x78, 0x06, 0x15, 0x4a, 0x76, 0x19, 0xf1, 0x24, 0xe8, 0xe1, 0x13, 0x03, + 0xe8, 0xb0, 0x83, 0x30, 0x69, 0xaa, 0x4c, 0x70, 0x4f, 0x19, 0x20, 0x83, + 0x14, 0x80, 0x9c, 0xf4, 0xb9, 0x6f, 0x72, 0x58, 0xa9, 0x91, 0x1c, 0x9c, + 0x86, 0x71, 0x30, 0xe3, 0x70, 0x19, 0x76, 0xea, 0xf9, 0x95, 0xe3, 0x10, + 0x24, 0xfa, 0xf7, 0xa7, 0x9f, 0x65, 0x1d, 0xff, 0xc4, 0xa3, 0x66, 0xa7, + 0x18, 0xdf, 0x5c, 0xd4, 0x1d, 0xa1, 0x1e, 0x9e, 0x80, 0x04, 0xfa, 0xcc, + 0x86, 0xac, 0x7b, 0x0d, 0xb5, 0xf2, 0x1d, 0x3c, 0x00, 0x9c, 0xa2, 0xbb, + 0x1b, 0x46, 0x8c, 0x2b, 0xcd, 0x06, 0x3a, 0x01, 0x3c, 0x41, 0x7d, 0xe8, + 0x00, 0x10, 0x56, 0xbb, 0xd2, 0x6a, 0x88, 0x5e, 0xe0, 0x13, 0xd1, 0x05, + 0x63, 0x84, 0x1d, 0xed, 0xc2, 0xd5, 0x49, 0xe8, 0x08, 0x3c, 0x89, 0x0c, + 0x68, 0x9b, 0xf6, 0xcd, 0x16, 0x6c, 0x75, 0x1a, 0xd5, 0xd3, 0x58, 0xc4, + 0xd1, 0x8b, 0x86, 0xb3, 0x6a, 0x74, 0x5e, 0x15, 0x6a, 0xa7, 0x0c, 0x56, + 0x74, 0x97, 0x83, 0xbe, 0x4b, 0xa8, 0x6a, 0x00, 0xe5, 0xe1, 0x89, 0xbe, + 0x4d, 0x61, 0x3c, 0x89, 0xb1, 0x3b, 0x0d, 0x4d, 0xd0, 0x7d, 0x47, 0xb3, + 0x0c, 0x3a, 0x6e, 0x19, 0x75, 0x5c, 0x33, 0xec, 0x08, 0xf7, 0xae, 0x63, + 0x28, 0x63, 0x9f, 0xe5, 0x13, 0xda, 0x96, 0xd9, 0xe0, 0x61, 0x1a, 0x52, + 0x81, 0x8d, 0xb8, 0x83, 0xb1, 0x40, 0xe7, 0x98, 0x05, 0xf3, 0x91, 0x0a, + 0xec, 0xc8, 0x1d, 0x0c, 0x4a, 0x68, 0x1f, 0x9f, 0x56, 0xd9, 0xdd, 0xcf, + 0xe1, 0xce, 0xb9, 0x0b, 0x78, 0x76, 0x03, 0x9c, 0xbc, 0xa7, 0x27, 0xf8, + 0x7b, 0xf3, 0xf9, 0xbc, 0x0f, 0xde, 0xc1, 0xeb, 0xcb, 0x97, 0x43, 0xf3, + 0xbc, 0xdc, 0x24, 0x8b, 0x95, 0x15, 0x3d, 0x04, 0x89, 0x7e, 0x07, 0x2c, + 0xd6, 0x9e, 0xd1, 0x28, 0xa8, 0xb0, 0x1b, 0xa0, 0xc0, 0x70, 0xff, 0x31, + 0x27, 0x91, 0x33, 0x02, 0x85, 0x77, 0x20, 0xe3, 0x18, 0x81, 0x43, 0x56, + 0x17, 0xfa, 0x06, 0xe0, 0x0f, 0xb2, 0x07, 0x92, 0x07, 0xa6, 0x90, 0xe8, + 0xcd, 0xc7, 0x46, 0x7d, 0xf8, 0xd4, 0x68, 0x98, 0x80, 0xb1, 0x1c, 0x0f, + 0xf2, 0x61, 0x1f, 0x92, 0xba, 0x3e, 0xf7, 0xea, 0x43, 0x81, 0x27, 0x34, + 0xd9, 0x33, 0x78, 0x0f, 0x8f, 0x92, 0x82, 0x86, 0xc3, 0x0f, 0xd1, 0x62, + 0x85, 0xb6, 0x90, 0x69, 0x80, 0x4c, 0xd5, 0x11, 0xd8, 0x0b, 0x73, 0xb4, + 0x97, 0x62, 0x7f, 0x10, 0x1f, 0x61, 0x32, 0x72, 0x09, 0x32, 0x53, 0x37, + 0x45, 0x52, 0x0d, 0x5b, 0xa6, 0xba, 0x70, 0x32, 0xdd, 0xab, 0x16, 0xec, + 0x17, 0xac, 0xc4, 0x2e, 0x0b, 0x9d, 0x3e, 0xc7, 0x00, 0x22, 0xa0, 0x22, + 0x86, 0x09, 0xf0, 0xc0, 0x77, 0xea, 0xcf, 0xa1, 0x77, 0xf7, 0x89, 0x70, + 0xe3, 0x1e, 0xe8, 0xc0, 0x71, 0x63, 0x45, 0xb9, 0x3e, 0x34, 0x64, 0xe7, + 0x9b, 0x55, 0x18, 0x21, 0x7f, 0x51, 0x70, 0x51, 0xc8, 0xe1, 0xbe, 0x8a, + 0x53, 0x8f, 0x8d, 0x8e, 0x25, 0xd6, 0x33, 0x03, 0x0e, 0x96, 0x35, 0x0c, + 0xb5, 0xf9, 0x3d, 0x18, 0x8c, 0xd8, 0xbb, 0x1d, 0x4e, 0xec, 0x7a, 0xfd, + 0x01, 0x4b, 0xfe, 0x8e, 0x47, 0x81, 0xf1, 0xde, 0x8d, 0x46, 0x80, 0xf5, + 0xb2, 0x67, 0x14, 0x4d, 0xc3, 0x64, 0x3e, 0x8e, 0x34, 0x52, 0xa6, 0x41, + 0x38, 0x46, 0xd9, 0x18, 0x53, 0x63, 0x04, 0x8d, 0xc1, 0x33, 0x06, 0xd1, + 0x34, 0x24, 0xa7, 0x01, 0xb8, 0x5a, 0xba, 0x7c, 0x58, 0x3a, 0x1f, 0x4b, + 0xbf, 0xc3, 0x56, 0x75, 0xad, 0xf8, 0xee, 0xff, 0xe0, 0x54, 0xeb, 0x8f, + 0xe8, 0x42, 0x57, 0xb7, 0x23, 0xea, 0x5e, 0x06, 0xae, 0x7d, 0xdd, 0xe5, + 0xb0, 0x75, 0x0f, 0x02, 0xd7, 0xe3, 0xdd, 0x7e, 0xc4, 0xa1, 0xe0, 0xf0, + 0x7d, 0x05, 0xe3, 0xeb, 0x82, 0xdd, 0x88, 0xaa, 0xb6, 0xc3, 0xd6, 0xa1, + 0x65, 0x30, 0xe5, 0xe7, 0x9f, 0x76, 0xf5, 0x47, 0x2c, 0xfa, 0x91, 0xc6, + 0xfc, 0x29, 0x6e, 0xa8, 0x6a, 0x82, 0xfa, 0x36, 0x9b, 0xbe, 0x7d, 0x88, + 0x00, 0x12, 0xef, 0xba, 0x82, 0xd5, 0xea, 0x5b, 0x2e, 0xea, 0xe2, 0xba, + 0x01, 0xef, 0x96, 0xe6, 0x19, 0xe6, 0x98, 0x30, 0x74, 0x7e, 0x0c, 0x02, + 0xe5, 0x26, 0x00, 0xb4, 0x69, 0xdc, 0xc6, 0xc1, 0x5e, 0x25, 0xae, 0x50, + 0xc6, 0x2f, 0x5a, 0x8d, 0x2a, 0xcb, 0xed, 0x3a, 0xc3, 0x6a, 0x49, 0x98, + 0xbc, 0x14, 0xc0, 0xa1, 0x4e, 0x2d, 0x17, 0x26, 0xa3, 0x97, 0x9e, 0x5e, + 0xad, 0x7b, 0x78, 0x2c, 0x30, 0x87, 0xe2, 0x77, 0x05, 0x16, 0x51, 0x9d, + 0x5d, 0x4b, 0x43, 0xb8, 0x94, 0xb0, 0x50, 0x6d, 0x5b, 0xcc, 0x4b, 0x70, + 0x8f, 0x40, 0x97, 0xf4, 0xd7, 0x5d, 0x38, 0x6d, 0x17, 0x48, 0x4b, 0x54, + 0x12, 0x54, 0x1a, 0xba, 0xaf, 0x64, 0xdf, 0xe7, 0x70, 0x9b, 0x35, 0x0a, + 0x0d, 0x57, 0x7a, 0x33, 0xc0, 0xf0, 0xc1, 0x03, 0x81, 0x7d, 0x67, 0x6c, + 0x0e, 0xe6, 0x0b, 0x46, 0x0e, 0xc4, 0x35, 0x6b, 0x24, 0x0f, 0x53, 0x1e, + 0xb9, 0xe5, 0xfa, 0x95, 0x6c, 0x46, 0x5e, 0x05, 0xcc, 0xa0, 0x7d, 0x16, + 0xb7, 0x51, 0x8e, 0x35, 0x05, 0x13, 0x58, 0x0c, 0xdc, 0x8e, 0xfd, 0x0f, + 0x2e, 0x2c, 0xcf, 0xb8, 0xab, 0xe5, 0x68, 0xb7, 0x82, 0x35, 0x4b, 0x6c, + 0x0c, 0x80, 0x64, 0x1d, 0x41, 0x1d, 0x4c, 0xd5, 0xf7, 0x3a, 0xf2, 0xe3, + 0xe5, 0xa1, 0x00, 0x07, 0xce, 0xd7, 0x4a, 0xb8, 0xcf, 0xca, 0xe0, 0xb4, + 0xf9, 0x08, 0xe0, 0x6b, 0x40, 0xbf, 0xbe, 0x73, 0xb0, 0x33, 0x74, 0xa8, + 0x88, 0x63, 0xc8, 0x05, 0x0e, 0xeb, 0x73, 0x71, 0x9b, 0xec, 0x8e, 0x03, + 0xbe, 0x62, 0x3f, 0xc0, 0x9a, 0xc9, 0x0a, 0x1d, 0xdb, 0x05, 0x17, 0x8a, + 0x1a, 0x30, 0x3e, 0xcb, 0xde, 0x97, 0xe6, 0x80, 0xc5, 0x3e, 0xab, 0xe0, + 0xd6, 0x0c, 0x09, 0x03, 0xaa, 0xc4, 0xc4, 0x3a, 0xda, 0x11, 0x49, 0x38, + 0x46, 0xfb, 0xb8, 0x1b, 0x6d, 0x39, 0x1f, 0xed, 0xa9, 0x72, 0x9c, 0x0f, + 0x7c, 0x37, 0xda, 0x81, 0xa3, 0x5d, 0xbc, 0x33, 0x5a, 0x54, 0xd0, 0xe2, + 0xcf, 0xf2, 0x2f, 0x1d, 0xff, 0x4e, 0x6b, 0x3d, 0xcd, 0xff, 0x23, 0x7f, + 0xa8, 0x1d, 0xe6, 0xe4, 0xb7, 0x46, 0xe0, 0xdf, 0x28, 0x11, 0x84, 0xc9, + 0xee, 0xab, 0xfd, 0xed, 0x7d, 0xdc, 0xaf, 0xff, 0xf6, 0x68, 0x7f, 0xf7, + 0x68, 0x30, 0x2b, 0x2c, 0xe2, 0x96, 0x34, 0xee, 0xe4, 0x00, 0xa4, 0xc3, + 0x44, 0x58, 0xda, 0x86, 0xca, 0x33, 0x49, 0x37, 0x69, 0x4f, 0x89, 0xdd, + 0xd4, 0x6b, 0x06, 0xda, 0x61, 0xbf, 0xa8, 0x50, 0xd9, 0x99, 0x30, 0xe9, + 0x47, 0x79, 0x6c, 0xdc, 0x3d, 0x4e, 0xc5, 0xb8, 0x1b, 0x92, 0x41, 0x65, + 0x92, 0x0c, 0x6b, 0x90, 0x97, 0x82, 0xea, 0xd2, 0x59, 0x79, 0xa5, 0x1f, + 0xef, 0x5e, 0x8a, 0x9f, 0x17, 0x09, 0xcf, 0x55, 0x1a, 0x5b, 0x92, 0xf2, + 0x53, 0x65, 0xfb, 0xc1, 0xcb, 0x7a, 0x9c, 0x06, 0xe4, 0x3f, 0x38, 0x4e, + 0xf7, 0xae, 0xf7, 0x71, 0xea, 0x6f, 0x6c, 0x71, 0xbf, 0x7b, 0xb3, 0xe4, + 0x94, 0xdc, 0xbe, 0xc8, 0x43, 0x09, 0xab, 0xd2, 0x76, 0x67, 0x9b, 0x0e, + 0x89, 0x8a, 0xfe, 0x66, 0xa7, 0xe9, 0xf8, 0x80, 0x8e, 0x20, 0xf7, 0xb3, + 0xa0, 0xe7, 0x20, 0xe2, 0xa8, 0x17, 0x42, 0xba, 0xce, 0xa8, 0x95, 0xfb, + 0x2b, 0xba, 0x17, 0xbc, 0xdf, 0x80, 0xda, 0x6f, 0xee, 0x42, 0x8b, 0x6f, + 0x3b, 0x59, 0x80, 0xc1, 0x25, 0x7f, 0x97, 0x61, 0x60, 0xf1, 0x86, 0x6e, + 0xb6, 0xd7, 0x4b, 0x86, 0x42, 0x41, 0xd2, 0x50, 0x15, 0xb0, 0x09, 0x6a, + 0x6e, 0xeb, 0x9e, 0xc7, 0xb7, 0x25, 0xf2, 0xea, 0x30, 0x4d, 0xf7, 0xc9, + 0x3e, 0x16, 0x78, 0x1a, 0x21, 0x71, 0xc7, 0xf4, 0xb6, 0x1c, 0x9f, 0x4d, + 0x84, 0x32, 0xa7, 0xf4, 0x81, 0x37, 0x64, 0x05, 0xff, 0xee, 0x8b, 0x24, + 0xf0, 0x6f, 0xe4, 0x61, 0x43, 0xd7, 0x91, 0xc7, 0x94, 0x7e, 0xe3, 0x4f, + 0x51, 0x22, 0x5e, 0xa6, 0x1d, 0x58, 0x9c, 0x42, 0xe3, 0x82, 0xd0, 0xf8, + 0x47, 0xea, 0xd9, 0x83, 0x85, 0x1c, 0xc1, 0x02, 0x0f, 0xfb, 0x0a, 0x16, + 0x82, 0xb9, 0x62, 0xde, 0x5a, 0x51, 0x79, 0x91, 0xe4, 0xf6, 0x04, 0xac, + 0xbf, 0x81, 0x74, 0x35, 0xfb, 0xa4, 0x34, 0xe1, 0x32, 0x87, 0x05, 0x23, + 0x97, 0x80, 0xd0, 0x2c, 0x01, 0x66, 0x69, 0x32, 0xfc, 0xe5, 0x43, 0xdc, + 0x35, 0x76, 0x35, 0x84, 0x87, 0xa7, 0x1d, 0x19, 0xa2, 0x1b, 0xf0, 0x43, + 0x52, 0x03, 0x22, 0xec, 0x98, 0x95, 0x7f, 0xa6, 0x79, 0xf9, 0xe5, 0x43, + 0x20, 0x80, 0x5c, 0x6f, 0x30, 0xee, 0x07, 0xbe, 0xc2, 0x63, 0x05, 0x0b, + 0x16, 0xc1, 0x1a, 0x7b, 0x38, 0x0b, 0x99, 0x7b, 0x38, 0x28, 0x05, 0x4f, + 0xf3, 0x9b, 0x19, 0x4a, 0xea, 0xa8, 0x15, 0x41, 0xee, 0x30, 0x84, 0xf5, + 0xb6, 0x58, 0x90, 0xf3, 0x30, 0x7a, 0x1a, 0x3e, 0xb9, 0xf4, 0x3b, 0xf7, + 0xe6, 0x49, 0x20, 0xc9, 0x10, 0x62, 0xbb, 0xbb, 0x34, 0xdc, 0xe3, 0x53, + 0xea, 0xd0, 0x77, 0xf2, 0x2b, 0x68, 0x81, 0x5b, 0x74, 0xa5, 0xb4, 0x1b, + 0x58, 0x7a, 0x86, 0x07, 0xee, 0x38, 0xa4, 0xe8, 0xb2, 0xf9, 0x0b, 0x58, + 0x1d, 0xa9, 0xb9, 0x72, 0x74, 0x90, 0xf5, 0x48, 0x8a, 0x6e, 0x4f, 0x76, + 0xcb, 0x4b, 0xcd, 0x78, 0x53, 0xe2, 0xbd, 0x8c, 0xa0, 0x2e, 0x82, 0xc5, + 0xd2, 0x81, 0x33, 0xe0, 0xd3, 0x4f, 0xd2, 0x54, 0x5e, 0xce, 0x74, 0xa3, + 0x82, 0xc7, 0x02, 0xd8, 0x8a, 0x65, 0x61, 0xd3, 0x7f, 0xa9, 0x35, 0xda, + 0x95, 0x84, 0x91, 0xdb, 0x0e, 0xf0, 0x7d, 0xc2, 0x74, 0x59, 0x02, 0x5d, + 0x1c, 0x38, 0x38, 0x76, 0x49, 0x46, 0x42, 0xaa, 0x04, 0xb7, 0x06, 0x4e, + 0x0d, 0x5c, 0x1a, 0xf8, 0x38, 0xcd, 0x13, 0x3f, 0xbe, 0xf1, 0xe8, 0x3d, + 0xdd, 0x18, 0x78, 0xd0, 0x70, 0x0e, 0x02, 0x7c, 0x15, 0x5c, 0xd2, 0x5d, + 0xf0, 0x47, 0xe9, 0xf1, 0x6b, 0x9f, 0xf1, 0xee, 0x17, 0xea, 0x2f, 0xec, + 0x7e, 0x63, 0x6f, 0xf3, 0xf9, 0xef, 0x26, 0x17, 0xfc, 0x06, 0x3f, 0xbd, + 0x1c, 0xdc, 0xeb, 0xdf, 0xff, 0xfc, 0x23, 0xbb, 0xf2, 0x8f, 0x6c, 0x8b, + 0x3f, 0xff, 0xc1, 0x39, 0xc5, 0x8f, 0x5b, 0x99, 0xa9, 0xdd, 0xff, 0x32, + 0x7f, 0x54, 0x00, 0x38, 0x93, 0x99, 0x1f, 0x67, 0x71, 0x67, 0xa9, 0xc0, + 0xb7, 0xc3, 0x18, 0xe0, 0xc9, 0x61, 0x44, 0x79, 0x0c, 0x1f, 0xc8, 0x3e, + 0xf1, 0x6b, 0x00, 0xc7, 0x30, 0x8c, 0xc6, 0xd1, 0x72, 0x9d, 0xf6, 0xba, + 0x5d, 0x09, 0x1f, 0x88, 0x23, 0x19, 0xb8, 0x91, 0x26, 0x4a, 0x0b, 0x51, + 0x74, 0xd1, 0xfb, 0xdb, 0x38, 0x26, 0x0f, 0x99, 0x64, 0xb8, 0xa8, 0xe2, + 0x80, 0xbb, 0x57, 0xa5, 0xc0, 0x2b, 0xa5, 0x17, 0x03, 0x37, 0x98, 0xb4, + 0x0b, 0x96, 0xd5, 0x93, 0x5c, 0x6a, 0x9a, 0x0d, 0xee, 0x90, 0xee, 0x06, + 0xbb, 0xca, 0x87, 0xd4, 0xae, 0x52, 0xbb, 0xd9, 0xa5, 0x86, 0x09, 0x76, + 0x15, 0xbe, 0x4d, 0x4d, 0xfb, 0x4f, 0x45, 0xb4, 0x37, 0xfb, 0xcf, 0x53, + 0x6a, 0xd2, 0x0d, 0x40, 0xa1, 0x3b, 0xe6, 0xf4, 0xab, 0x3f, 0xa7, 0x7e, + 0x85, 0xc3, 0xd2, 0xc5, 0xaa, 0xda, 0xd0, 0x5d, 0xe1, 0x45, 0x52, 0xdd, + 0xe7, 0x52, 0xa0, 0x1c, 0xce, 0x2f, 0xc5, 0x9c, 0x5d, 0x72, 0x9b, 0x8d, + 0x97, 0xa7, 0x47, 0xc2, 0xc4, 0x41, 0xb2, 0x00, 0xf4, 0xa5, 0xb4, 0xdf, + 0xf1, 0x51, 0x0f, 0x8c, 0x92, 0x16, 0xc3, 0xe2, 0x0c, 0xfc, 0xeb, 0x20, + 0x8a, 0x6f, 0x7c, 0xf2, 0x83, 0xbf, 0x06, 0x70, 0xd0, 0xa2, 0xa1, 0x26, + 0xff, 0x61, 0xa3, 0x23, 0x94, 0x77, 0xa4, 0x0b, 0x8d, 0x95, 0xa9, 0xd4, + 0xa7, 0x7d, 0xff, 0x2f, 0xef, 0xff, 0x1a, 0x10, 0x5f, 0x2e, 0x31, 0x36, + 0xdd, 0x94, 0x43, 0xfe, 0x07, 0xef, 0xb2, 0x66, 0x87, 0x36, 0xd0, 0x52, + 0x8f, 0xf6, 0xe8, 0xd3, 0xf8, 0xfe, 0xaf, 0x92, 0xea, 0x57, 0x4f, 0xb0, + 0x76, 0xff, 0xb2, 0xe5, 0x17, 0x7e, 0x60, 0xd4, 0xd7, 0x8f, 0x70, 0xe8, + 0xc9, 0x41, 0x67, 0x34, 0xae, 0x07, 0xd5, 0x02, 0x5e, 0x2d, 0xd1, 0x52, + 0x53, 0x2c, 0xbd, 0x61, 0x88, 0x9a, 0x3b, 0x9c, 0x98, 0x19, 0x2a, 0x6a, + 0x88, 0xee, 0x11, 0xb7, 0xf7, 0xa0, 0x5c, 0xdc, 0xb9, 0xa5, 0x3b, 0xaa, + 0x9e, 0x2d, 0x63, 0xe7, 0x91, 0xc1, 0x29, 0xba, 0xa6, 0xf4, 0x4b, 0xbf, + 0xf5, 0xf4, 0xb4, 0x2a, 0xd6, 0x9c, 0x43, 0x6d, 0x68, 0x52, 0x46, 0x68, + 0xd7, 0x32, 0x70, 0x01, 0x63, 0x48, 0x33, 0xa5, 0x11, 0xc2, 0x56, 0xc3, + 0x37, 0x35, 0x72, 0xa2, 0xc4, 0x8e, 0x5f, 0x9f, 0xea, 0x97, 0x4d, 0x40, + 0x48, 0x24, 0x8d, 0x40, 0x27, 0x4d, 0xfd, 0x18, 0x53, 0xbb, 0x4f, 0xe6, + 0xbd, 0x24, 0x04, 0x99, 0xb3, 0xf4, 0x41, 0xe1, 0x57, 0xc9, 0xf3, 0xab, + 0xc6, 0xf3, 0x64, 0x34, 0x36, 0xb9, 0x8f, 0x25, 0x45, 0x0d, 0x01, 0xd4, + 0x68, 0xc6, 0xa0, 0xd1, 0x23, 0xc6, 0x20, 0xa1, 0x40, 0x35, 0x6c, 0xa4, + 0x1f, 0x66, 0x6a, 0xbc, 0xa8, 0xdd, 0xd6, 0x78, 0xd1, 0x0b, 0xa4, 0xb4, + 0x88, 0x23, 0x39, 0x0f, 0x14, 0x1d, 0x23, 0x44, 0xf0, 0xc8, 0x35, 0xd2, + 0xd5, 0x9f, 0x9c, 0x9a, 0xb3, 0xe0, 0xea, 0x47, 0xcf, 0x8e, 0xa7, 0xff, + 0x05, 0xbc, 0x47, 0xa4, 0x19, 0x06, 0x2d, 0x00, 0x00 +}; + +const GFXglyph Oswald_Medium30pt7bGlyphs[] PROGMEM = { + { 0, 1, 1, 14, 0, 0 }, // 0x20 ' ' + { 1, 8, 48, 14, 3, -47 }, // 0x21 '!' + { 49, 17, 17, 19, 1, -47 }, // 0x22 '"' + { 86, 26, 48, 30, 2, -47 }, // 0x23 '#' + { 242, 25, 59, 29, 2, -52 }, // 0x24 '$' + { 427, 51, 48, 56, 2, -47 }, // 0x25 '%' + { 733, 29, 49, 34, 3, -47 }, // 0x26 '&' + { 911, 7, 17, 9, 1, -47 }, // 0x27 ''' + { 926, 13, 59, 19, 4, -47 }, // 0x28 '(' + { 1022, 13, 59, 17, 2, -47 }, // 0x29 ')' + { 1118, 21, 21, 24, 2, -47 }, // 0x2A '*' + { 1174, 22, 24, 25, 2, -35 }, // 0x2B '+' + { 1240, 8, 16, 13, 2, -7 }, // 0x2C ',' + { 1256, 14, 6, 18, 2, -19 }, // 0x2D '-' + { 1267, 8, 8, 13, 3, -7 }, // 0x2E '.' + { 1275, 19, 48, 23, 2, -47 }, // 0x2F '/' + { 1389, 25, 49, 31, 3, -47 }, // 0x30 '0' + { 1543, 15, 48, 22, 2, -47 }, // 0x31 '1' + { 1633, 25, 48, 29, 2, -47 }, // 0x32 '2' + { 1783, 25, 49, 29, 2, -47 }, // 0x33 '3' + { 1937, 27, 48, 30, 2, -47 }, // 0x34 '4' + { 2099, 24, 49, 29, 3, -47 }, // 0x35 '5' + { 2246, 25, 49, 31, 3, -47 }, // 0x36 '6' + { 2400, 21, 48, 24, 1, -47 }, // 0x37 '7' + { 2526, 24, 49, 30, 3, -47 }, // 0x38 '8' + { 2673, 25, 49, 31, 2, -47 }, // 0x39 '9' + { 2827, 7, 28, 14, 4, -31 }, // 0x3A ':' + { 2852, 8, 38, 15, 4, -32 }, // 0x3B ';' + { 2890, 18, 25, 23, 2, -36 }, // 0x3C '<' + { 2947, 19, 16, 25, 3, -31 }, // 0x3D '=' + { 2985, 18, 25, 23, 3, -36 }, // 0x3E '>' + { 3042, 24, 48, 28, 2, -47 }, // 0x3F '?' + { 3186, 50, 56, 55, 3, -47 }, // 0x40 '@' + { 3536, 29, 48, 31, 1, -47 }, // 0x41 'A' + { 3710, 27, 48, 33, 4, -47 }, // 0x42 'B' + { 3872, 26, 49, 32, 3, -47 }, // 0x43 'C' + { 4032, 26, 48, 33, 4, -47 }, // 0x44 'D' + { 4188, 20, 48, 25, 4, -47 }, // 0x45 'E' + { 4308, 19, 48, 24, 4, -47 }, // 0x46 'F' + { 4422, 27, 49, 33, 3, -47 }, // 0x47 'G' + { 4588, 27, 48, 34, 4, -47 }, // 0x48 'H' + { 4750, 8, 48, 16, 4, -47 }, // 0x49 'I' + { 4798, 15, 49, 19, 1, -47 }, // 0x4A 'J' + { 4890, 27, 48, 31, 4, -47 }, // 0x4B 'K' + { 5052, 20, 48, 25, 4, -47 }, // 0x4C 'L' + { 5172, 34, 48, 40, 3, -47 }, // 0x4D 'M' + { 5376, 24, 48, 32, 4, -47 }, // 0x4E 'N' + { 5520, 27, 49, 33, 3, -47 }, // 0x4F 'O' + { 5686, 26, 48, 31, 4, -47 }, // 0x50 'P' + { 5842, 27, 57, 33, 3, -47 }, // 0x51 'Q' + { 6035, 27, 48, 33, 4, -47 }, // 0x52 'R' + { 6197, 26, 49, 29, 2, -47 }, // 0x53 'S' + { 6357, 24, 48, 25, 1, -47 }, // 0x54 'T' + { 6501, 27, 49, 33, 3, -47 }, // 0x55 'U' + { 6667, 28, 48, 30, 1, -47 }, // 0x56 'V' + { 6835, 38, 48, 42, 2, -47 }, // 0x57 'W' + { 7063, 28, 48, 29, 1, -47 }, // 0x58 'X' + { 7231, 27, 48, 29, 1, -47 }, // 0x59 'Y' + { 7393, 22, 48, 25, 2, -47 }, // 0x5A 'Z' + // Euro sign ([) - ASCII code 91 + { 11030, 30, 49, 31, 0, -47 }, // 0x5B '[' + // Backslash placeholder - ASCII code 92 + { 0, 0, 0, 0, 0, 0 }, // 0x5C '\' + // Pound sign (]) - ASCII code 93 + { 11214, 24, 48, 26, 1, -47 }, // 0x5D ']' + // Yen sign (^) - ASCII code 94 + { 11358, 28, 48, 27, 0, -47 }, // 0x5E '^' + { 7905, 21, 6, 21, 0, 4 }, // 0x5F '_' + { 7921, 11, 12, 17, 3, -47 }, // 0x60 '`' + { 7938, 22, 35, 26, 1, -33 }, // 0x61 'a' + { 8035, 23, 49, 28, 3, -47 }, // 0x62 'b' + { 8176, 22, 35, 26, 2, -33 }, // 0x63 'c' + { 8273, 23, 49, 28, 2, -47 }, // 0x64 'd' + { 8414, 22, 35, 26, 2, -33 }, // 0x65 'e' + { 8511, 16, 46, 18, 1, -45 }, // 0x66 'f' + { 8603, 28, 46, 28, 1, -34 }, // 0x67 'g' + { 8764, 22, 48, 28, 3, -47 }, // 0x68 'h' + { 8896, 8, 46, 15, 3, -45 }, // 0x69 'i' + { 8942, 13, 56, 15, -1, -45 }, // 0x6A 'j' + { 9033, 25, 48, 28, 3, -47 }, // 0x6B 'k' + { 9183, 8, 48, 15, 4, -47 }, // 0x6C 'l' + { 9231, 36, 35, 42, 3, -34 }, // 0x6D 'm' + { 9389, 22, 34, 28, 3, -33 }, // 0x6E 'n' + { 9483, 22, 35, 27, 2, -33 }, // 0x6F 'o' + { 9580, 23, 45, 28, 3, -33 }, // 0x70 'p' + { 9710, 22, 45, 28, 3, -33 }, // 0x71 'q' + { 9834, 17, 34, 21, 3, -33 }, // 0x72 'r' + { 9907, 21, 35, 24, 1, -33 }, // 0x73 's' + { 9999, 17, 44, 19, 1, -43 }, // 0x74 't' + { 10093, 22, 35, 28, 3, -33 }, // 0x75 'u' + { 10190, 22, 34, 24, 1, -33 }, // 0x76 'v' + { 10284, 32, 34, 35, 1, -33 }, // 0x77 'w' + { 10420, 23, 34, 24, 1, -33 }, // 0x78 'x' + { 10518, 24, 43, 25, 0, -33 }, // 0x79 'y' + { 10647, 18, 34, 22, 2, -33 }, // 0x7A 'z' + { 10724, 15, 59, 20, 3, -47 }, // 0x7B '{' + { 10835, 7, 58, 15, 4, -47 }, // 0x7C '|' + { 10886, 16, 59, 21, 2, -47 }, // 0x7D '}' + { 11004, 23, 9, 27, 2, -28 } }; // 0x7E '~' + +// const GFXfont Oswald_Medium30pt7b PROGMEM = { +// (uint8_t *)Oswald_Medium30pt7bBitmaps, +// (GFXglyph *)Oswald_Medium30pt7bGlyphs, +// 0x20, 0x7E, 87 }; + +// Approx. 11702 bytes + + +// Font properties +static constexpr FontData Oswald_Medium30pt7b_Properties = { + Oswald_Medium30pt7bBitmaps_Gzip, + Oswald_Medium30pt7bGlyphs, + sizeof(Oswald_Medium30pt7bBitmaps_Gzip), + 11526, // Original size + 0x20, // First char + 0x7E, // Last char + 87 // yAdvance +}; diff --git a/src/fonts/oswald-medium80.h b/src/fonts/oswald-medium80.h new file mode 100644 index 0000000..dfab628 --- /dev/null +++ b/src/fonts/oswald-medium80.h @@ -0,0 +1,1083 @@ +#pragma once + +#include +#include +#include "fonts.hpp" + +const uint8_t Oswald_Medium80pt7bBitmaps_Gzip[] = { + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xed, 0x7d, + 0x4d, 0xae, 0xdc, 0x38, 0xb3, 0xa5, 0xf4, 0xd4, 0x80, 0xde, 0xa0, 0xd1, + 0xea, 0x05, 0x34, 0x9a, 0xbd, 0x84, 0x5e, 0x40, 0xe3, 0xb1, 0x97, 0xf5, + 0x06, 0x0d, 0x50, 0x05, 0x0f, 0x3c, 0xac, 0x25, 0x78, 0x29, 0x56, 0xc1, + 0x83, 0x1a, 0x7a, 0x09, 0xa6, 0x51, 0x03, 0x0f, 0x2d, 0xc3, 0x83, 0x92, + 0x61, 0x95, 0xd8, 0x8a, 0x88, 0x73, 0x82, 0x4a, 0x65, 0xa6, 0x7d, 0x7d, + 0xcb, 0xe5, 0xfa, 0xf9, 0x9c, 0xa8, 0xba, 0xa2, 0x23, 0xc9, 0x10, 0x19, + 0x8c, 0x08, 0xc6, 0x9f, 0x94, 0x4d, 0xb9, 0xf1, 0xd9, 0x4a, 0xf9, 0xb5, + 0x94, 0xe7, 0xe5, 0xb7, 0x52, 0xde, 0x96, 0x12, 0xcb, 0x87, 0x52, 0x5e, + 0x96, 0x2d, 0x95, 0xf7, 0xa5, 0x3c, 0x2b, 0x6b, 0x29, 0x6f, 0xca, 0x16, + 0xcb, 0xbb, 0x52, 0x7e, 0x2c, 0x6b, 0x2a, 0xbf, 0x94, 0x12, 0xca, 0x52, + 0xca, 0x8b, 0xb2, 0x85, 0x32, 0x97, 0xf2, 0xb4, 0xac, 0xb1, 0xbc, 0x2e, + 0xdb, 0x50, 0xe6, 0x54, 0x9e, 0x94, 0x35, 0x94, 0x5c, 0x4a, 0x5f, 0x96, + 0x58, 0x7e, 0x52, 0x60, 0x2c, 0x3f, 0x94, 0x75, 0x28, 0x53, 0xda, 0xba, + 0x32, 0x87, 0x32, 0x96, 0xb5, 0x2f, 0x39, 0x96, 0xb6, 0x2c, 0x17, 0xc0, + 0xae, 0x4c, 0x61, 0x6b, 0xca, 0xdc, 0x97, 0x31, 0xae, 0x6d, 0xc9, 0x43, + 0x69, 0xd2, 0x72, 0x02, 0x4e, 0xc3, 0xd6, 0xc4, 0xb9, 0x2d, 0xe3, 0xb0, + 0x36, 0x29, 0x77, 0xa5, 0x09, 0x4b, 0x53, 0xa6, 0xfe, 0x00, 0x9c, 0xba, + 0xad, 0x09, 0x73, 0x53, 0xc6, 0x6e, 0x6d, 0x42, 0x6e, 0x4a, 0xd3, 0x2f, + 0x4d, 0x9c, 0xda, 0xad, 0x19, 0xe6, 0x26, 0x09, 0xf0, 0xce, 0x27, 0x62, + 0xed, 0xa9, 0x7c, 0x2c, 0xe5, 0xd5, 0x89, 0x20, 0xf7, 0x81, 0xd3, 0xfe, + 0x5f, 0xda, 0x09, 0xb8, 0x2f, 0x65, 0xff, 0xb4, 0xf2, 0x67, 0x8a, 0xf2, + 0xef, 0x5e, 0x9a, 0x8d, 0xf4, 0xce, 0x61, 0x1f, 0xb5, 0xaf, 0x6e, 0x1f, + 0x3d, 0xa6, 0x1d, 0xcb, 0xbe, 0xb0, 0x8f, 0x65, 0x5f, 0xcb, 0x8e, 0x60, + 0x8c, 0x3b, 0x99, 0xf7, 0xb5, 0x7d, 0x28, 0xfb, 0x1a, 0x77, 0xb2, 0x8f, + 0x61, 0xa7, 0xf4, 0xdc, 0xed, 0x14, 0xdf, 0x9a, 0xb4, 0x13, 0x79, 0x1a, + 0x76, 0x62, 0x2f, 0xed, 0x4e, 0xf4, 0x7d, 0x85, 0x3b, 0xf1, 0xa7, 0x7e, + 0xdf, 0x84, 0x7d, 0xc5, 0xfb, 0x66, 0x34, 0x61, 0xa7, 0xfb, 0x4e, 0x81, + 0x79, 0xff, 0x77, 0xda, 0xf7, 0xa1, 0x19, 0xf6, 0xfd, 0xc8, 0x3b, 0x4d, + 0xd3, 0xda, 0xc4, 0x9d, 0xea, 0x63, 0xbf, 0x53, 0x7f, 0xa7, 0xc3, 0x12, + 0x77, 0x3a, 0xec, 0xbb, 0x31, 0x76, 0xfb, 0xae, 0xec, 0x24, 0x58, 0x76, + 0x72, 0x0e, 0x65, 0x27, 0xeb, 0x4e, 0xe1, 0x34, 0x37, 0x71, 0xdd, 0x29, + 0xda, 0xef, 0x1b, 0x34, 0xed, 0x44, 0x8e, 0x4b, 0x13, 0xf6, 0xbd, 0x69, + 0xba, 0x7d, 0x3b, 0xa6, 0x26, 0xcd, 0x3b, 0x71, 0x87, 0x7d, 0x7b, 0x9a, + 0x9d, 0xee, 0x3b, 0x85, 0x82, 0x0c, 0xdf, 0x5b, 0xfb, 0xcc, 0xf7, 0x11, + 0x0b, 0x01, 0xe3, 0x11, 0x90, 0x01, 0x90, 0x7b, 0x00, 0xb0, 0xaf, 0x7a, + 0x47, 0x08, 0x40, 0x54, 0x40, 0x03, 0xc0, 0x7c, 0x13, 0x30, 0xb5, 0x06, + 0x58, 0xf5, 0x06, 0x0e, 0xe8, 0x09, 0x48, 0x02, 0xd8, 0x08, 0xc8, 0x47, + 0xc0, 0x42, 0xc0, 0xd8, 0x11, 0x20, 0x37, 0x90, 0x39, 0x28, 0x60, 0x50, + 0xc0, 0x04, 0xc0, 0x7a, 0x13, 0x60, 0x8b, 0x6c, 0x74, 0x4d, 0x07, 0x40, + 0x4b, 0xc0, 0x8d, 0x55, 0xdf, 0x20, 0x43, 0xb9, 0x41, 0x86, 0x04, 0x61, + 0xfb, 0x95, 0x52, 0xf7, 0x6d, 0x00, 0x8f, 0x5f, 0xe4, 0xe7, 0xf6, 0xfa, + 0xd6, 0x22, 0xcf, 0x7b, 0x3d, 0x5e, 0xed, 0xf5, 0x50, 0x75, 0x8e, 0x7d, + 0xde, 0x7e, 0x13, 0x40, 0x3e, 0x90, 0xe1, 0x72, 0xd5, 0xcd, 0x97, 0xac, + 0x7a, 0x7e, 0xe4, 0xaa, 0xbf, 0x12, 0x87, 0xaf, 0xc6, 0xd0, 0x57, 0x1c, + 0x9e, 0x2e, 0x38, 0x3c, 0x7f, 0x92, 0xc3, 0x97, 0xdb, 0x9b, 0xff, 0x30, + 0x32, 0x0c, 0x5f, 0x42, 0x06, 0x53, 0xad, 0xdd, 0x02, 0x1d, 0x9b, 0x70, + 0x1d, 0xb2, 0x5d, 0x5b, 0x6a, 0xe3, 0x38, 0xda, 0xb5, 0x9f, 0x01, 0xd8, + 0x70, 0x0d, 0xd3, 0x17, 0xa2, 0xd8, 0xa7, 0xa8, 0x43, 0xba, 0x62, 0x77, + 0x97, 0xeb, 0x6a, 0x70, 0xfb, 0x46, 0x79, 0x42, 0xf5, 0xbd, 0xf0, 0x84, + 0xcc, 0xdc, 0x00, 0xbd, 0x31, 0x89, 0x75, 0x14, 0x40, 0x02, 0x20, 0x00, + 0xd0, 0x19, 0x1b, 0x4d, 0x8d, 0x5d, 0x57, 0xc3, 0x50, 0x44, 0xd1, 0xea, + 0x67, 0x69, 0x29, 0x6f, 0xf8, 0x62, 0xde, 0x19, 0x7d, 0x6b, 0xf1, 0xbf, + 0x70, 0x7d, 0x4e, 0x42, 0xa2, 0x22, 0x67, 0xe1, 0x8e, 0x77, 0xff, 0xf3, + 0xc3, 0x3e, 0x4a, 0x6e, 0xb8, 0x9f, 0x94, 0x45, 0x67, 0x32, 0x08, 0xfe, + 0xfd, 0x46, 0xaf, 0x8b, 0xd1, 0x70, 0x8d, 0xc6, 0x17, 0xbb, 0xaa, 0xb7, + 0x3d, 0x5d, 0x8a, 0xed, 0xd8, 0x7e, 0x36, 0x14, 0x5d, 0xd4, 0x7e, 0x16, + 0x2b, 0x07, 0xed, 0xc7, 0xb2, 0x2d, 0xe2, 0xc7, 0x62, 0x5b, 0xf9, 0xae, + 0xd8, 0xbe, 0x6c, 0xd1, 0x78, 0xad, 0xfc, 0x5c, 0x8c, 0x4f, 0xb2, 0xa2, + 0xe8, 0xe5, 0xac, 0x91, 0x9e, 0xab, 0x7c, 0xb7, 0xf7, 0xfc, 0x5f, 0xba, + 0x62, 0x25, 0x62, 0xaf, 0x38, 0x8d, 0x56, 0xb6, 0x0b, 0x00, 0x90, 0xa8, + 0xb2, 0xc2, 0x19, 0x3d, 0x0b, 0x7b, 0xea, 0x86, 0x0c, 0x46, 0x5c, 0xa5, + 0xe2, 0x8c, 0xa1, 0xbe, 0x0f, 0x33, 0x86, 0x5e, 0x02, 0x12, 0x00, 0xfd, + 0x11, 0x30, 0x02, 0xb0, 0x00, 0xb9, 0x02, 0x86, 0x07, 0x01, 0x56, 0xe2, + 0x98, 0x80, 0xe3, 0x0b, 0x00, 0x23, 0x26, 0xb6, 0x70, 0xa6, 0x9f, 0x07, + 0xdc, 0x5c, 0x6d, 0x4b, 0x7a, 0x84, 0x03, 0x3d, 0x26, 0x00, 0x56, 0x02, + 0x46, 0x00, 0x96, 0x33, 0x6d, 0x33, 0x00, 0x1b, 0x01, 0x3b, 0x53, 0xe8, + 0x4c, 0x17, 0xe5, 0x7b, 0xd9, 0xa7, 0x68, 0x6c, 0xf0, 0x4e, 0xb1, 0xa8, + 0x96, 0x9b, 0x15, 0xd7, 0x2b, 0x19, 0xb4, 0x23, 0xff, 0xa8, 0xf7, 0x8b, + 0x72, 0x1c, 0x2c, 0x3a, 0xf4, 0x2d, 0x7a, 0x16, 0xf6, 0x54, 0xf4, 0x1d, + 0x78, 0xda, 0xb8, 0x7d, 0x51, 0x9c, 0x6f, 0x4d, 0xb2, 0xc5, 0xca, 0x51, + 0xd6, 0xda, 0xed, 0x12, 0x63, 0xad, 0x37, 0x60, 0xc2, 0xb5, 0x98, 0x96, + 0x30, 0x5e, 0xeb, 0xc8, 0x6b, 0x45, 0x79, 0x6d, 0x94, 0x2f, 0x5e, 0x08, + 0x40, 0xd8, 0x48, 0xa6, 0x2a, 0xec, 0x3f, 0x14, 0xd5, 0x3a, 0x62, 0x2e, + 0xa9, 0x18, 0xcc, 0x26, 0x55, 0x2a, 0x1b, 0x26, 0x45, 0x14, 0x1a, 0x88, + 0xd9, 0x95, 0x78, 0x65, 0x08, 0xe4, 0x02, 0x49, 0x75, 0x09, 0x1d, 0x5d, + 0x74, 0x7d, 0x11, 0x3d, 0x3a, 0x18, 0x60, 0xc4, 0x32, 0x27, 0x6c, 0x50, + 0x06, 0xc7, 0xcc, 0xd8, 0x07, 0xfd, 0xf7, 0xde, 0x77, 0xb4, 0xeb, 0xef, + 0xd7, 0x41, 0x0f, 0x47, 0x11, 0x6c, 0xef, 0x9b, 0x02, 0x0c, 0xad, 0xf3, + 0x0f, 0x00, 0x3d, 0xe6, 0xdb, 0xa2, 0xa3, 0x2e, 0x60, 0x3e, 0x02, 0x52, + 0xa1, 0x82, 0x03, 0x80, 0x6b, 0xef, 0x00, 0x30, 0x0a, 0x2b, 0xc0, 0xa6, + 0xd5, 0x15, 0xa7, 0xca, 0x11, 0x30, 0xc9, 0xdd, 0x66, 0xbf, 0x2b, 0x00, + 0xb6, 0xc4, 0x81, 0x14, 0xbe, 0x0b, 0x08, 0xe4, 0xac, 0xe1, 0x1a, 0x30, + 0x11, 0xf0, 0x04, 0x2c, 0x66, 0x80, 0x5d, 0x69, 0x35, 0xc9, 0x94, 0x14, + 0x01, 0x8b, 0xfe, 0xbf, 0x03, 0x46, 0x00, 0x66, 0x23, 0xd1, 0x25, 0x60, + 0x95, 0xc6, 0x88, 0xd5, 0x3b, 0x80, 0xe4, 0x10, 0xcd, 0xfa, 0x20, 0x40, + 0xba, 0x02, 0x6c, 0x47, 0xc0, 0x76, 0x03, 0x50, 0xae, 0x00, 0x2b, 0x89, + 0x9e, 0x77, 0x52, 0x3c, 0x04, 0xd0, 0x5e, 0x03, 0x96, 0xcf, 0x00, 0xba, + 0x6b, 0xc0, 0xfc, 0x19, 0x40, 0xff, 0x00, 0x40, 0xfe, 0x0c, 0x60, 0xb8, + 0x06, 0x4c, 0x77, 0x00, 0xa4, 0x47, 0xb8, 0x06, 0x8c, 0x9f, 0x04, 0xac, + 0xd7, 0x80, 0x78, 0x0d, 0x68, 0xee, 0x02, 0x6c, 0xf7, 0xb9, 0x93, 0xce, + 0x1f, 0xdc, 0x38, 0x65, 0x27, 0xe1, 0xa0, 0x0b, 0x40, 0xbc, 0x04, 0x18, + 0x17, 0x16, 0x97, 0x55, 0xf5, 0xc5, 0x66, 0xdf, 0x38, 0xe7, 0x64, 0x07, + 0x18, 0xf3, 0xcf, 0xed, 0x09, 0x90, 0x75, 0xe3, 0x5a, 0x93, 0x8a, 0x0a, + 0x88, 0x38, 0xc2, 0x45, 0xa2, 0x3a, 0x3b, 0xef, 0xf7, 0x2e, 0x10, 0xc2, + 0x0e, 0xfa, 0x6c, 0x81, 0x98, 0x8e, 0xb2, 0x93, 0x83, 0x4a, 0x30, 0xe4, + 0x56, 0x00, 0xd1, 0x24, 0xd8, 0x24, 0xbb, 0x57, 0x63, 0x4c, 0x25, 0xd8, + 0x64, 0xbf, 0xa7, 0x6e, 0x9c, 0x74, 0xaa, 0x8b, 0x02, 0x20, 0x9f, 0x03, + 0xfe, 0xe6, 0x16, 0x8b, 0xe8, 0x74, 0xe0, 0x20, 0x53, 0x81, 0x7c, 0x26, + 0xb3, 0x28, 0x00, 0x58, 0x44, 0x1d, 0x8c, 0x0a, 0xe8, 0x09, 0x00, 0x15, + 0x00, 0xa8, 0x64, 0x19, 0xaf, 0x00, 0x83, 0x2a, 0x72, 0x57, 0x87, 0x02, + 0xd8, 0x94, 0xa0, 0x04, 0xe8, 0xfe, 0x0d, 0x47, 0x40, 0xd0, 0x15, 0x10, + 0x90, 0x8a, 0x6e, 0xd7, 0x0d, 0x80, 0xef, 0xf9, 0x76, 0x1b, 0xd0, 0x39, + 0xa0, 0x5c, 0x01, 0xd6, 0x6b, 0x40, 0x34, 0x5a, 0xd8, 0xbf, 0xdb, 0x07, + 0x00, 0x96, 0xcf, 0x00, 0xba, 0x6b, 0xc0, 0xfc, 0x19, 0x40, 0x7f, 0x0d, + 0xc8, 0x5f, 0x0a, 0x18, 0xae, 0x01, 0xd3, 0x67, 0x00, 0xe1, 0x1a, 0x30, + 0x7e, 0x06, 0x10, 0x1f, 0x00, 0x68, 0x2e, 0x89, 0x7c, 0x05, 0x48, 0x57, + 0x80, 0xed, 0x0e, 0xc0, 0xf7, 0xb6, 0x28, 0xe0, 0xc0, 0x1f, 0xd7, 0x00, + 0xe5, 0xdd, 0x03, 0x4b, 0x19, 0xa0, 0x32, 0x5d, 0x0b, 0x7b, 0xb9, 0x21, + 0x5b, 0xb6, 0x30, 0x10, 0xa6, 0x72, 0x02, 0x38, 0x27, 0x77, 0x26, 0x04, + 0x95, 0xf9, 0x6f, 0x00, 0x66, 0x9e, 0xab, 0x3c, 0x30, 0x1d, 0x90, 0x2b, + 0xa0, 0xb9, 0x00, 0x64, 0x02, 0xa6, 0x03, 0x00, 0x82, 0xcc, 0x9d, 0x6c, + 0x28, 0xea, 0xdc, 0x38, 0xd3, 0x3e, 0xdb, 0x11, 0xd0, 0x57, 0x91, 0x33, + 0x75, 0xeb, 0xd6, 0xa7, 0x9f, 0xa4, 0x89, 0x37, 0xa1, 0x76, 0x25, 0x79, + 0xaa, 0xd0, 0x10, 0x67, 0x24, 0x32, 0x5a, 0x1a, 0xb6, 0x8c, 0x11, 0xdf, + 0xd9, 0x97, 0xbd, 0xaf, 0xa3, 0x70, 0x7a, 0x81, 0xd4, 0x70, 0xe3, 0xc1, + 0xd6, 0xb2, 0xb1, 0x7b, 0x25, 0x40, 0x69, 0xa8, 0x21, 0x17, 0x12, 0x49, + 0xf0, 0x07, 0x92, 0xbc, 0x33, 0x57, 0x69, 0x92, 0x1b, 0x6e, 0xb6, 0x4f, + 0x3b, 0x68, 0x6a, 0x61, 0xd2, 0x2d, 0x36, 0xfb, 0xde, 0x7c, 0xa7, 0x6c, + 0x5a, 0x9f, 0x20, 0x3b, 0x14, 0x14, 0xd4, 0x9f, 0x41, 0x99, 0xa0, 0xed, + 0xd3, 0xa0, 0xc1, 0x41, 0x37, 0xd0, 0xc3, 0x38, 0x9e, 0xcd, 0x42, 0x10, + 0x50, 0xeb, 0xa0, 0x80, 0xa9, 0x0a, 0x68, 0x3c, 0x98, 0x2f, 0x9d, 0xea, + 0xf1, 0xd2, 0x10, 0x64, 0xbc, 0x31, 0x1a, 0x5b, 0xdb, 0x79, 0x65, 0xcc, + 0x30, 0x29, 0x52, 0x45, 0x4d, 0xe7, 0x34, 0x9b, 0x49, 0xd8, 0xab, 0x65, + 0x3c, 0x2a, 0x55, 0xb3, 0x62, 0x10, 0xac, 0x9d, 0xed, 0x5a, 0x14, 0xbb, + 0x3a, 0xdb, 0x56, 0x3d, 0xb5, 0x1d, 0xd2, 0x78, 0xec, 0x68, 0x3b, 0xf4, + 0xcc, 0xb8, 0x61, 0x10, 0x03, 0x1e, 0x9b, 0x8d, 0xdd, 0xab, 0xac, 0x13, + 0xb9, 0xc7, 0x95, 0x79, 0x82, 0xf3, 0x99, 0xf3, 0xe8, 0xe0, 0xea, 0x3f, + 0x55, 0x05, 0x44, 0x5e, 0x8b, 0xec, 0xde, 0x97, 0x6a, 0x17, 0x54, 0x2b, + 0x55, 0xb1, 0xcb, 0xa4, 0x57, 0xc7, 0xe0, 0x48, 0x55, 0x8a, 0x67, 0xbb, + 0xb5, 0xc4, 0x14, 0x42, 0x31, 0xff, 0x77, 0x36, 0xcf, 0x4a, 0x40, 0xa9, + 0x98, 0x2b, 0x31, 0x9b, 0x4b, 0xd7, 0x69, 0x2c, 0xb5, 0x98, 0xe6, 0x32, + 0x91, 0x50, 0x7a, 0x28, 0x8a, 0x28, 0x24, 0xfa, 0xa8, 0x67, 0xe5, 0xd6, + 0x8b, 0xbb, 0xa2, 0x21, 0x90, 0xa4, 0xce, 0x51, 0x27, 0xbe, 0xc7, 0x36, + 0x28, 0xd1, 0x77, 0xaf, 0x7a, 0x77, 0x7e, 0x73, 0x2f, 0x61, 0xeb, 0xb5, + 0xd7, 0x10, 0xeb, 0x4f, 0x1a, 0xbe, 0x9d, 0x7b, 0xf1, 0xb4, 0x97, 0x4e, + 0xef, 0xbb, 0xfb, 0x2e, 0xbb, 0x6b, 0xbc, 0x0c, 0xe2, 0x52, 0xcb, 0x1c, + 0x47, 0xf5, 0xbe, 0x65, 0x93, 0x86, 0xb2, 0x24, 0x0d, 0x7c, 0x64, 0x03, + 0x29, 0xa2, 0xa5, 0xa8, 0x06, 0x7e, 0x27, 0xce, 0xbb, 0x4e, 0x4a, 0x43, + 0xe2, 0x79, 0x9f, 0xfa, 0x47, 0xbd, 0xb5, 0x71, 0x7c, 0x96, 0xa9, 0xeb, + 0xb9, 0x0e, 0xd3, 0xd3, 0x22, 0xc7, 0xb6, 0x23, 0x30, 0x4f, 0xf5, 0x56, + 0x93, 0x79, 0x97, 0x03, 0x3c, 0xac, 0xd2, 0xc0, 0x9d, 0x17, 0x42, 0xac, + 0x20, 0x1e, 0x1d, 0xb6, 0x4c, 0x9e, 0x5c, 0x8d, 0x73, 0xa3, 0x72, 0x94, + 0x79, 0x75, 0x8b, 0x81, 0x82, 0x82, 0x0a, 0xbc, 0x49, 0x9c, 0xf7, 0xb2, + 0x5e, 0x35, 0x02, 0x74, 0xf1, 0x30, 0x3d, 0x74, 0x17, 0x55, 0x84, 0xa3, + 0x45, 0x2b, 0x8a, 0x04, 0xff, 0x2d, 0x8c, 0x5d, 0x62, 0xc1, 0xe7, 0x1d, + 0x1b, 0x25, 0xb0, 0x31, 0x3b, 0xc8, 0xfa, 0x7e, 0x34, 0xb7, 0xcf, 0x46, + 0x99, 0x76, 0x78, 0x4d, 0x87, 0x4f, 0x22, 0x1f, 0xa6, 0x14, 0x46, 0xa5, + 0x7a, 0x51, 0x33, 0xca, 0x18, 0x60, 0xd5, 0x40, 0x94, 0x29, 0x87, 0x54, + 0x94, 0x0c, 0x12, 0x8d, 0x99, 0xc1, 0x85, 0x43, 0x31, 0xd9, 0xd9, 0x97, + 0x29, 0x4e, 0x85, 0xc7, 0x12, 0x76, 0x77, 0xf5, 0xa3, 0xb8, 0xbf, 0xcf, + 0xb5, 0xb1, 0xca, 0x5d, 0x5f, 0xee, 0x33, 0xd7, 0xc6, 0x8f, 0x12, 0x3d, + 0x17, 0xaf, 0xf4, 0xc7, 0x7d, 0x57, 0x67, 0xd9, 0xe3, 0x41, 0x1b, 0x8b, + 0x04, 0xc8, 0x9f, 0xec, 0x9b, 0xa2, 0x8d, 0x6e, 0xdf, 0x8a, 0x39, 0xae, + 0xd6, 0xc8, 0x71, 0x91, 0x90, 0xf7, 0xa8, 0x0d, 0x65, 0x5d, 0xf1, 0xf2, + 0x82, 0x92, 0x7e, 0x54, 0xb5, 0xde, 0x99, 0xa6, 0x98, 0x54, 0xb8, 0x07, + 0xe5, 0x3a, 0xb5, 0xb7, 0xd4, 0x63, 0x15, 0x0b, 0x68, 0xd6, 0x78, 0x8f, + 0xf0, 0xfb, 0xbe, 0x2c, 0x61, 0xaa, 0x59, 0xbf, 0x0d, 0xd6, 0x75, 0xd2, + 0x5d, 0x08, 0x6a, 0xc8, 0xa9, 0x46, 0x9b, 0x71, 0xa2, 0xdd, 0xfb, 0x47, + 0x67, 0x04, 0xb1, 0x31, 0x9d, 0xed, 0x92, 0xe9, 0xc4, 0xf6, 0x38, 0x8b, + 0xd6, 0xf8, 0xf0, 0x62, 0xf0, 0x56, 0x07, 0x0f, 0x97, 0x83, 0x3f, 0xd1, + 0xff, 0x6b, 0x76, 0x09, 0x24, 0x4f, 0xd2, 0xed, 0xd5, 0x58, 0xc0, 0xac, + 0x9a, 0xa3, 0x37, 0x4a, 0xdc, 0xe8, 0xf2, 0x47, 0xcd, 0xe5, 0x7e, 0x17, + 0xa7, 0x23, 0x34, 0xfe, 0x8d, 0x81, 0x8d, 0x89, 0xb4, 0xef, 0xc6, 0x01, + 0xdd, 0xc5, 0x1e, 0x9d, 0xfb, 0x1a, 0x86, 0x0b, 0xbc, 0x3e, 0x87, 0xe3, + 0xd7, 0x1a, 0x16, 0x6c, 0xc0, 0x3c, 0x2a, 0x0f, 0xb9, 0x23, 0x4b, 0x75, + 0xa4, 0x59, 0xc7, 0x79, 0xea, 0xe1, 0x12, 0x55, 0x3c, 0xc0, 0x98, 0x4d, + 0x12, 0x81, 0xd8, 0x34, 0xb0, 0xb9, 0x18, 0x48, 0xad, 0x96, 0x02, 0x3b, + 0xcd, 0xb7, 0xbf, 0xa8, 0x72, 0xd4, 0x20, 0xbc, 0xdd, 0xa1, 0x58, 0xc0, + 0x32, 0xf7, 0xb8, 0x9d, 0xcc, 0x26, 0x63, 0x67, 0xb6, 0x9b, 0x0c, 0x6b, + 0xb3, 0x1f, 0x78, 0x14, 0xa6, 0xeb, 0x6f, 0x5d, 0x2e, 0x6c, 0x2c, 0x08, + 0x7e, 0xdd, 0xbd, 0xb5, 0x7d, 0x5f, 0x2e, 0x01, 0x11, 0xec, 0xdd, 0x71, + 0x8f, 0x78, 0xbb, 0x0b, 0x84, 0xff, 0x0a, 0x80, 0x23, 0x3d, 0x3f, 0x45, + 0x31, 0x1a, 0x23, 0xfd, 0x35, 0x9e, 0xad, 0xe2, 0x39, 0x0c, 0xb3, 0xad, + 0xb0, 0x5e, 0x17, 0xc8, 0xeb, 0xd0, 0x60, 0xa7, 0x80, 0x58, 0x2d, 0x13, + 0x2c, 0xb4, 0x05, 0x87, 0x48, 0xa1, 0xa6, 0xcb, 0x50, 0x6e, 0xcb, 0xf1, + 0x66, 0x64, 0xba, 0x11, 0x5c, 0x38, 0x7a, 0x18, 0x2c, 0x98, 0x15, 0x92, + 0xd4, 0x36, 0x68, 0xcd, 0x7c, 0xe8, 0xcd, 0x64, 0xc0, 0x57, 0xf0, 0xec, + 0xcd, 0x66, 0xe8, 0x68, 0xc7, 0x4c, 0xa7, 0xaf, 0xfe, 0x4d, 0xbf, 0xfa, + 0xef, 0xff, 0x4d, 0xbe, 0x6a, 0xa7, 0xff, 0x50, 0x2f, 0xb2, 0xdd, 0x27, + 0xb6, 0xb6, 0x5b, 0xbf, 0x76, 0xfb, 0xb1, 0xb8, 0x48, 0x16, 0x73, 0x57, + 0xe1, 0x65, 0x0d, 0x9b, 0x68, 0xfc, 0x35, 0x2d, 0x72, 0x60, 0xfd, 0xb6, + 0x1f, 0x11, 0x9b, 0x1d, 0x4d, 0x1f, 0xec, 0xc4, 0x62, 0x92, 0xe8, 0xf8, + 0x59, 0xad, 0x87, 0x05, 0x24, 0xdd, 0xf7, 0x0e, 0x85, 0xe7, 0xe9, 0x66, + 0x36, 0xcc, 0xd4, 0x34, 0x74, 0x32, 0xcc, 0xc6, 0x81, 0x65, 0x14, 0x0a, + 0x2d, 0xfd, 0xc9, 0x0c, 0xae, 0xd1, 0x47, 0xed, 0x87, 0x92, 0x9e, 0xd7, + 0xef, 0x8b, 0x86, 0x05, 0x9e, 0x4a, 0x7f, 0x31, 0x21, 0xc4, 0x0c, 0x98, + 0xcd, 0xa3, 0x9a, 0x94, 0x7e, 0x5b, 0xab, 0x9b, 0xb9, 0x58, 0x76, 0x67, + 0x3f, 0xc0, 0xf5, 0x90, 0x8c, 0x16, 0x50, 0x48, 0xa2, 0x42, 0x72, 0xab, + 0x31, 0x04, 0xf9, 0xaf, 0xe9, 0x56, 0x3d, 0x0e, 0xbb, 0x9d, 0x53, 0x64, + 0x1a, 0x63, 0xf3, 0x9f, 0xfb, 0xe5, 0xbf, 0x34, 0xed, 0x68, 0x44, 0x5c, + 0x60, 0xad, 0xfd, 0xcd, 0xfe, 0x39, 0x5c, 0x6d, 0xcc, 0x1f, 0xf4, 0x99, + 0xff, 0x1a, 0xeb, 0x7d, 0xd4, 0x3f, 0x1f, 0xb5, 0xde, 0x76, 0x17, 0x17, + 0xfb, 0xb3, 0x73, 0x4f, 0x9c, 0xbb, 0xdd, 0x56, 0xc9, 0xc3, 0xce, 0x72, + 0x53, 0x5c, 0xa5, 0x66, 0x60, 0xb7, 0x71, 0x77, 0xdf, 0x54, 0xca, 0x32, + 0x26, 0xfd, 0x32, 0x8e, 0xed, 0xf4, 0xa8, 0x1b, 0x9d, 0x6e, 0xfb, 0xc8, + 0x71, 0xba, 0x68, 0xd3, 0x01, 0x50, 0x08, 0x48, 0xd7, 0xa8, 0xe8, 0x05, + 0x64, 0x8a, 0x72, 0xa5, 0x8c, 0x7d, 0x6d, 0xea, 0x82, 0x1e, 0xb3, 0x7c, + 0x8d, 0xb0, 0x6a, 0xda, 0x2a, 0x31, 0xbf, 0x01, 0xda, 0xf6, 0x3e, 0xda, + 0xf9, 0x8c, 0x36, 0xdc, 0x47, 0x7b, 0x26, 0xc2, 0xdf, 0x0d, 0xed, 0xf2, + 0x05, 0x68, 0xc7, 0x33, 0xda, 0xf2, 0x70, 0xb4, 0xc3, 0xdf, 0x0c, 0xed, + 0xf4, 0x70, 0xb4, 0x57, 0xfc, 0xd7, 0x5c, 0x67, 0xbb, 0xe5, 0xbc, 0x99, + 0x71, 0x2d, 0x80, 0x0b, 0x40, 0xaf, 0xdb, 0x21, 0x44, 0xa5, 0xd7, 0xb5, + 0xa6, 0xd0, 0xa2, 0xc9, 0xa8, 0x07, 0x65, 0x7a, 0x08, 0x1f, 0xb2, 0x71, + 0x33, 0xc2, 0x36, 0x2b, 0x06, 0xd4, 0x74, 0x1d, 0xd4, 0xf4, 0x8a, 0x01, + 0x5a, 0x01, 0xa5, 0x49, 0xbe, 0x62, 0x26, 0x82, 0xa4, 0xb6, 0x55, 0x7d, + 0x0c, 0x66, 0xca, 0x78, 0x6a, 0xf0, 0x9d, 0xde, 0xdf, 0x8e, 0x5b, 0xf5, + 0xe4, 0x9e, 0xc1, 0x27, 0x7d, 0x63, 0x7e, 0x9f, 0xf8, 0x91, 0x8b, 0x06, + 0xaa, 0x98, 0x6d, 0x7c, 0x5e, 0x0a, 0x33, 0x99, 0x53, 0xcd, 0x64, 0x46, + 0xac, 0xc4, 0x26, 0x72, 0x88, 0x47, 0x7d, 0xef, 0xf0, 0xbd, 0xc3, 0xad, + 0x0e, 0x09, 0x1d, 0x82, 0x72, 0x94, 0x66, 0x8f, 0xc9, 0x72, 0x1f, 0xc8, + 0x72, 0xa9, 0xf2, 0xe4, 0x04, 0x9e, 0xb4, 0x7c, 0x36, 0x12, 0x33, 0x52, + 0x97, 0x41, 0xae, 0xd6, 0xbc, 0xf6, 0x0f, 0x45, 0x43, 0x1a, 0x9a, 0xdb, + 0xd6, 0xfb, 0x50, 0x2e, 0x20, 0x40, 0xc5, 0x05, 0x27, 0xd8, 0x75, 0xa2, + 0x64, 0xe1, 0x68, 0x5d, 0x5c, 0xf4, 0xf0, 0x45, 0x95, 0xcd, 0x01, 0x2b, + 0x70, 0xe1, 0x8d, 0x58, 0x49, 0x8f, 0xab, 0xf6, 0x5c, 0x9a, 0x43, 0xc5, + 0x44, 0xaa, 0x45, 0x05, 0x0c, 0x50, 0x8f, 0xa6, 0x31, 0x8a, 0x99, 0x0d, + 0x13, 0x82, 0x9d, 0xfa, 0x3d, 0x62, 0x6e, 0xab, 0x05, 0x89, 0x54, 0x97, + 0xa8, 0xe1, 0xaa, 0x01, 0x22, 0x99, 0x96, 0xae, 0x4a, 0x0f, 0x70, 0xd8, + 0xcd, 0x8f, 0xf9, 0xa8, 0xad, 0xfd, 0x74, 0xff, 0x7f, 0x93, 0x3b, 0xcc, + 0x56, 0x11, 0x81, 0x3c, 0xfe, 0x8a, 0x70, 0x62, 0x90, 0x75, 0x0f, 0xd8, + 0x95, 0xc9, 0xe2, 0x02, 0xad, 0xcf, 0xf1, 0x7b, 0xc7, 0x7f, 0x52, 0x47, + 0xf5, 0x5a, 0x8d, 0x25, 0x3d, 0x6b, 0x51, 0xec, 0x8c, 0x33, 0xee, 0x0d, + 0xc6, 0xf6, 0xc6, 0xe6, 0x2b, 0x25, 0x99, 0x87, 0xd7, 0x06, 0x39, 0x28, + 0x19, 0x02, 0x72, 0xa8, 0xd0, 0x32, 0xc9, 0x59, 0x21, 0x52, 0x4c, 0x5c, + 0x96, 0x85, 0x66, 0xac, 0x9f, 0x5e, 0xc7, 0x53, 0x4b, 0x71, 0x45, 0x0b, + 0x79, 0x4a, 0x18, 0x59, 0xe3, 0x24, 0x3f, 0x01, 0xaf, 0x1c, 0x63, 0x7a, + 0x4a, 0x3e, 0x2d, 0x9a, 0x6a, 0xc0, 0xf1, 0x95, 0x50, 0x5e, 0x35, 0xa0, + 0xbc, 0xaa, 0x65, 0x85, 0x56, 0x40, 0x85, 0x56, 0xa7, 0x51, 0xd4, 0x5c, + 0xcf, 0xb1, 0x41, 0x4a, 0x74, 0xac, 0xbe, 0xe6, 0x23, 0xf5, 0x55, 0x42, + 0x18, 0x97, 0x25, 0x3a, 0x56, 0x78, 0x13, 0x44, 0x3f, 0x59, 0x30, 0xf7, + 0x57, 0x44, 0x7c, 0x37, 0x96, 0xe8, 0xbc, 0x12, 0xdc, 0x86, 0x42, 0xf5, + 0xc1, 0x86, 0x24, 0x6e, 0x79, 0x09, 0xdc, 0x1f, 0x88, 0xbb, 0x31, 0x7b, + 0xc1, 0xdc, 0xeb, 0x96, 0x01, 0xfa, 0xbb, 0x5f, 0xa4, 0xd3, 0x17, 0xdd, + 0xf9, 0x8b, 0x50, 0x2d, 0x8e, 0x05, 0xbb, 0x77, 0xa8, 0x52, 0x6a, 0x6a, + 0x82, 0xa0, 0xe5, 0x17, 0xc9, 0x6d, 0xf8, 0xc2, 0x22, 0xb2, 0xf5, 0x8c, + 0x32, 0x63, 0xe4, 0x6d, 0x94, 0x43, 0x45, 0xb9, 0x5e, 0xa0, 0x0c, 0xe7, + 0x59, 0x82, 0x83, 0xfe, 0x7e, 0x93, 0xe1, 0xc8, 0xab, 0xc9, 0x70, 0xe4, + 0xd5, 0x64, 0x2e, 0x96, 0xd1, 0xde, 0x5b, 0xc6, 0x43, 0xb6, 0xe9, 0x72, + 0x19, 0x87, 0xc9, 0x98, 0xd0, 0xe0, 0xea, 0x01, 0xff, 0x5f, 0x70, 0x45, + 0x9c, 0x44, 0xab, 0xc0, 0xf4, 0xc3, 0xdc, 0xc0, 0x06, 0xe9, 0x12, 0x91, + 0xf8, 0x6a, 0x28, 0x6a, 0xa5, 0x96, 0x4c, 0x6c, 0x6c, 0xea, 0x61, 0xa7, + 0x32, 0x3c, 0xe2, 0xba, 0x70, 0xe2, 0x87, 0xfc, 0xac, 0x61, 0xe4, 0x79, + 0x3a, 0x41, 0x6d, 0xf0, 0xc0, 0xf5, 0x7a, 0x64, 0xd7, 0x12, 0x5e, 0xc7, + 0x89, 0xeb, 0x84, 0xc9, 0x2c, 0x18, 0x20, 0xca, 0x41, 0xeb, 0xd6, 0x5e, + 0xa0, 0xae, 0x53, 0x4e, 0x46, 0x5a, 0x05, 0xaa, 0x24, 0x7e, 0xac, 0x66, + 0xc3, 0x7c, 0xb2, 0x2b, 0xb6, 0xaa, 0x02, 0x5c, 0xb0, 0x39, 0x51, 0xbd, + 0xcf, 0xc1, 0x74, 0x69, 0x31, 0x61, 0x9b, 0x39, 0xab, 0xf6, 0x56, 0x26, + 0x58, 0x1f, 0xd3, 0x21, 0x56, 0xf9, 0x9e, 0x40, 0xcc, 0x0c, 0xfe, 0xa0, + 0x66, 0xd8, 0xc8, 0x40, 0x23, 0xf8, 0x64, 0x02, 0x9f, 0x50, 0x5b, 0x93, + 0x5f, 0x2e, 0x59, 0x31, 0xa0, 0x63, 0x40, 0xc7, 0x68, 0x18, 0x2d, 0x7d, + 0x67, 0xbb, 0x82, 0x60, 0x59, 0xd5, 0xf2, 0x23, 0x3a, 0x4c, 0xe8, 0x90, + 0xd1, 0x21, 0xa3, 0x43, 0xc6, 0x54, 0x69, 0xcb, 0x30, 0xc3, 0x69, 0x80, + 0x08, 0x4c, 0x03, 0x46, 0x74, 0xb8, 0x15, 0x72, 0x48, 0xd6, 0x61, 0x46, + 0x07, 0x78, 0x5d, 0xc5, 0x33, 0xdb, 0x14, 0xff, 0xdb, 0xa2, 0xe8, 0x62, + 0x71, 0x26, 0xd8, 0x41, 0x53, 0x5e, 0x12, 0xea, 0x40, 0xc9, 0xdb, 0x23, + 0xbb, 0x33, 0x05, 0x03, 0x3a, 0x3c, 0x7e, 0x37, 0xef, 0x76, 0xb8, 0xc1, + 0x51, 0xaf, 0x70, 0x1c, 0xbd, 0xc1, 0x11, 0x6a, 0x3c, 0x19, 0xc1, 0x93, + 0x01, 0xfe, 0x57, 0x5f, 0x99, 0x76, 0xa1, 0x83, 0x16, 0x2d, 0xb9, 0x51, + 0x06, 0x84, 0x43, 0x7f, 0x2a, 0xc8, 0x50, 0x24, 0x3b, 0x17, 0x17, 0x9d, + 0x06, 0xec, 0x3a, 0x9d, 0x08, 0xae, 0x13, 0xbe, 0xc8, 0xa7, 0xf3, 0x97, + 0xb5, 0x9d, 0x9b, 0xbb, 0x99, 0xf8, 0x62, 0x82, 0x4c, 0xb2, 0x3c, 0x8a, + 0xd6, 0xfa, 0x52, 0xa5, 0xbb, 0xc1, 0x8a, 0x9c, 0xb1, 0x1a, 0x5e, 0x5d, + 0x49, 0x0e, 0xb4, 0x75, 0x3d, 0xe7, 0xec, 0xc5, 0xb6, 0xf4, 0x93, 0xa5, + 0xb3, 0x6f, 0x9f, 0x6f, 0x97, 0xab, 0x6d, 0x6a, 0x46, 0x3f, 0x0a, 0x5c, + 0xf5, 0x3b, 0xaf, 0x7b, 0x66, 0x9d, 0x85, 0x15, 0x8c, 0x59, 0x03, 0x0d, + 0x3d, 0x71, 0xed, 0x9b, 0xc9, 0xae, 0x13, 0x06, 0x21, 0x02, 0x0e, 0x34, + 0x2e, 0x1b, 0xbe, 0xa6, 0x40, 0x34, 0x89, 0x68, 0x0a, 0xd0, 0x78, 0x1d, + 0x7b, 0x2f, 0xca, 0x63, 0xd4, 0x41, 0x6f, 0x29, 0x51, 0xcf, 0x0c, 0x4d, + 0x2a, 0x51, 0xd1, 0xb4, 0xb2, 0xb9, 0x8b, 0xde, 0x60, 0x61, 0x5c, 0xe0, + 0x9d, 0xa1, 0x09, 0xa2, 0x83, 0xa7, 0xc6, 0xc2, 0xd0, 0x8a, 0x46, 0xf7, + 0xd7, 0x06, 0x05, 0x54, 0x71, 0x2c, 0x11, 0x94, 0x9e, 0x13, 0x0c, 0xb2, + 0x4c, 0x7f, 0xe3, 0x07, 0x43, 0xa3, 0x09, 0xde, 0x49, 0x6e, 0x20, 0x01, + 0x80, 0x51, 0x07, 0x19, 0x9a, 0x20, 0x19, 0x5f, 0xab, 0xb3, 0x9f, 0x0c, + 0x4d, 0x12, 0x07, 0xc9, 0xf4, 0x78, 0x83, 0xa0, 0xc4, 0x6a, 0x3a, 0x7d, + 0xd0, 0xcc, 0xc2, 0xa4, 0x83, 0x0c, 0x4d, 0x42, 0xd6, 0xba, 0x51, 0x87, + 0xc9, 0x02, 0x17, 0x4d, 0x34, 0x56, 0x47, 0xd1, 0xe8, 0xa0, 0xec, 0xa4, + 0x3c, 0x9e, 0x59, 0x2a, 0x32, 0x75, 0xf0, 0x93, 0xc6, 0xde, 0x14, 0xec, + 0x66, 0x09, 0xb9, 0x1e, 0xf9, 0x8c, 0x26, 0x14, 0x4b, 0x55, 0xc8, 0x20, + 0x43, 0xc3, 0x94, 0x47, 0xcb, 0x5c, 0x4a, 0xcf, 0xac, 0xd7, 0x50, 0x90, + 0x26, 0x94, 0x41, 0x43, 0x41, 0x5d, 0x49, 0xa8, 0xd9, 0x5f, 0xab, 0x4a, + 0x40, 0x06, 0x6f, 0x6b, 0x90, 0x26, 0x5b, 0x99, 0xe0, 0x9b, 0x1b, 0x24, + 0xf8, 0xb2, 0xa2, 0x69, 0x71, 0x26, 0xd8, 0x20, 0xcb, 0xae, 0xa8, 0x0d, + 0xbb, 0xea, 0x20, 0x45, 0x13, 0xed, 0xb8, 0x9a, 0xe9, 0x2c, 0xfe, 0xd5, + 0x3e, 0x60, 0xd6, 0x89, 0x22, 0x34, 0x42, 0xde, 0x50, 0x1b, 0xe2, 0x85, + 0x7e, 0xb1, 0x78, 0xd1, 0x87, 0xc9, 0x54, 0x43, 0xdd, 0xe7, 0xe5, 0xd6, + 0xff, 0x18, 0x34, 0xc1, 0x48, 0x43, 0x87, 0x1f, 0x05, 0x13, 0xee, 0xf8, + 0x6f, 0x67, 0x6b, 0x42, 0xa2, 0x04, 0xf2, 0xa1, 0x55, 0x91, 0xbf, 0x05, + 0x82, 0x11, 0xf3, 0x9d, 0xb0, 0x80, 0x8c, 0x15, 0xb1, 0xf2, 0x87, 0x8a, + 0x93, 0xa5, 0x60, 0x1b, 0xa9, 0x42, 0x32, 0x8d, 0xb8, 0x4e, 0x40, 0x94, + 0x81, 0x68, 0x06, 0xa2, 0x05, 0x88, 0x56, 0x20, 0xda, 0x48, 0x4d, 0x22, + 0x1a, 0x8f, 0x88, 0xbe, 0x6c, 0x26, 0xd9, 0x66, 0x12, 0x21, 0xda, 0x38, + 0x96, 0xe4, 0x14, 0x92, 0x63, 0x49, 0x6c, 0x49, 0x39, 0x96, 0xde, 0x97, + 0x83, 0xc7, 0x77, 0xb6, 0xe9, 0xfc, 0xa9, 0x02, 0x10, 0x73, 0x3b, 0x13, + 0x33, 0x83, 0x98, 0x7c, 0x2e, 0x61, 0x05, 0x82, 0x8d, 0x1e, 0xe2, 0x93, + 0x62, 0x31, 0x9c, 0x9f, 0x60, 0xf3, 0x65, 0x3a, 0x86, 0xc9, 0x44, 0x7f, + 0x8d, 0x66, 0x62, 0xee, 0xca, 0xd3, 0xb2, 0x85, 0x43, 0xf5, 0x0b, 0xd5, + 0xd4, 0xfb, 0x05, 0x9e, 0xd9, 0x3b, 0x1c, 0xd0, 0x0b, 0x4e, 0xf2, 0x4b, + 0x5b, 0x60, 0x38, 0x99, 0x5d, 0xb4, 0x2a, 0x0e, 0xe6, 0x17, 0xcd, 0x0f, + 0x1e, 0x5b, 0xdb, 0x1f, 0x8e, 0xa0, 0x54, 0xdb, 0x62, 0x84, 0x6d, 0x31, + 0xe1, 0x64, 0xce, 0x35, 0x1a, 0xa5, 0x94, 0x33, 0xf7, 0x94, 0x0e, 0xed, + 0x73, 0xd8, 0x1c, 0xaf, 0xb0, 0xf6, 0x37, 0x58, 0xfb, 0xfb, 0x6a, 0x83, + 0x58, 0x01, 0x32, 0x6c, 0x91, 0x15, 0xb6, 0x88, 0x39, 0xd5, 0x46, 0x44, + 0x8d, 0x7f, 0x3d, 0x35, 0xcd, 0x6c, 0x0f, 0x10, 0xf4, 0xba, 0x0b, 0xaa, + 0x9c, 0xc5, 0x04, 0x51, 0x57, 0x66, 0x1f, 0x90, 0x87, 0xba, 0x7d, 0x94, + 0x81, 0x85, 0xfb, 0xee, 0x96, 0x47, 0xc2, 0xfe, 0x07, 0x5c, 0x2f, 0x63, + 0x07, 0xdb, 0x29, 0xb8, 0xb0, 0xc1, 0x18, 0xdf, 0x6a, 0x08, 0x5d, 0x31, + 0x1c, 0x0d, 0x90, 0xb6, 0x80, 0xa4, 0xc1, 0xb9, 0x1a, 0x8a, 0xa2, 0x39, + 0x90, 0x10, 0x24, 0xbd, 0xf0, 0x58, 0x3a, 0x50, 0xec, 0x92, 0xc4, 0xf9, + 0x7e, 0x74, 0x9e, 0x93, 0xc5, 0xea, 0xce, 0x31, 0xc4, 0xed, 0x1c, 0x64, + 0x3c, 0x46, 0x21, 0x95, 0x04, 0x2d, 0xb9, 0x37, 0x99, 0xc7, 0xb2, 0x04, + 0x13, 0xa2, 0x6d, 0x40, 0x1c, 0xe5, 0x49, 0xb1, 0x73, 0x6b, 0xc6, 0xfd, + 0x57, 0xc6, 0x74, 0x02, 0xac, 0x43, 0x86, 0x39, 0xde, 0x31, 0x9a, 0x93, + 0x8e, 0xe1, 0x8e, 0x5e, 0x23, 0x10, 0xdc, 0x63, 0x3d, 0x9c, 0x57, 0x1a, + 0xa0, 0x11, 0xcc, 0xf0, 0xf2, 0x9e, 0x3d, 0x4c, 0x4e, 0x24, 0x07, 0xde, + 0xf5, 0x4d, 0xbe, 0x4e, 0x87, 0xde, 0xe4, 0x32, 0xe3, 0x44, 0x17, 0x52, + 0x68, 0x99, 0xcd, 0x00, 0x1a, 0x89, 0x4f, 0x9a, 0xcd, 0x60, 0x56, 0xe2, + 0x7d, 0x54, 0xca, 0x46, 0x7b, 0xa0, 0x94, 0x94, 0x75, 0x9b, 0x77, 0xc4, + 0x75, 0x8e, 0xf8, 0x82, 0xf9, 0xeb, 0x27, 0xfc, 0x02, 0xd7, 0x15, 0x1d, + 0x14, 0xff, 0x2f, 0xf8, 0x5f, 0xac, 0x1d, 0xf1, 0x92, 0x35, 0xa6, 0x1c, + 0x8b, 0xda, 0x19, 0x42, 0x28, 0x65, 0xfa, 0xf7, 0xc5, 0x0c, 0x15, 0xa3, + 0x64, 0x44, 0x58, 0xa8, 0xaf, 0x0f, 0x6a, 0x7d, 0xac, 0x11, 0xa6, 0xa5, + 0xc6, 0x8d, 0xfa, 0x1a, 0x50, 0xfa, 0x58, 0x05, 0x75, 0x39, 0x71, 0xb4, + 0x4b, 0xf4, 0xb7, 0xea, 0xe0, 0x61, 0xb0, 0xe7, 0xe0, 0x87, 0xb7, 0x60, + 0x18, 0x86, 0xc3, 0x36, 0x72, 0xd4, 0x33, 0x70, 0xd4, 0x1b, 0x18, 0x75, + 0xce, 0x72, 0xe4, 0x49, 0x6a, 0x87, 0x17, 0x60, 0xda, 0x8c, 0xa3, 0xc1, + 0xb9, 0xba, 0x37, 0x4b, 0xac, 0xa8, 0x37, 0x37, 0xd8, 0x91, 0x29, 0xa4, + 0x96, 0xdd, 0x13, 0x0d, 0xbf, 0xf8, 0x71, 0x90, 0xac, 0xe1, 0xe7, 0x06, + 0xb6, 0x35, 0xe3, 0x8b, 0x05, 0x5f, 0xac, 0x90, 0x51, 0x0f, 0x3e, 0xd2, + 0xf7, 0x3a, 0xe8, 0xc5, 0x80, 0xa5, 0x2a, 0x8a, 0xb9, 0xa9, 0x6e, 0x28, + 0xc5, 0xdf, 0xbd, 0xcf, 0x6a, 0x7e, 0xb8, 0x67, 0xfc, 0x0d, 0x3f, 0x78, + 0x30, 0x7a, 0x3b, 0xc8, 0xc5, 0xf9, 0x62, 0xc9, 0xe0, 0xdb, 0x97, 0xe5, + 0x70, 0x29, 0xb7, 0x2f, 0x96, 0xf5, 0xbc, 0x7d, 0xc9, 0xf5, 0xd2, 0xdd, + 0xb9, 0x4c, 0x8d, 0x9f, 0x42, 0x57, 0x97, 0xb1, 0x4a, 0xf9, 0xd5, 0xa5, + 0xa9, 0x97, 0x70, 0xfb, 0xf2, 0xd8, 0x35, 0x1f, 0x97, 0xfe, 0x88, 0x35, + 0x1f, 0x96, 0xfe, 0x98, 0x35, 0x4f, 0x9f, 0x58, 0xf3, 0x61, 0xe9, 0x8f, + 0x58, 0xf3, 0xf6, 0xfb, 0xd6, 0xbc, 0xfc, 0xbe, 0x35, 0xe7, 0xdf, 0xb7, + 0xe6, 0xf1, 0xfe, 0x9a, 0xcb, 0xe7, 0xd7, 0xec, 0x25, 0xef, 0x72, 0x27, + 0x3f, 0xa9, 0x3b, 0x88, 0xac, 0xca, 0x70, 0x53, 0x65, 0xb9, 0x85, 0xc4, + 0x5c, 0x06, 0x5a, 0x16, 0x9e, 0xd4, 0xe7, 0x94, 0xc4, 0x55, 0x1e, 0x3d, + 0x9f, 0xec, 0x90, 0x42, 0x83, 0x35, 0x53, 0x23, 0xf1, 0xa4, 0x6e, 0x60, + 0xa4, 0x4c, 0xc9, 0x5c, 0x46, 0xb1, 0x6c, 0xa8, 0xd3, 0x34, 0x4c, 0xf2, + 0xc3, 0x59, 0xe9, 0x45, 0xd3, 0x4a, 0x1b, 0x73, 0x2f, 0x2f, 0x70, 0x52, + 0xcf, 0x55, 0x6d, 0xae, 0xd5, 0x32, 0xb5, 0x0e, 0x13, 0x3a, 0xcc, 0x5f, + 0xdc, 0xe1, 0xde, 0x2d, 0xcc, 0x7e, 0x63, 0x07, 0x0d, 0x13, 0x74, 0x6a, + 0x6f, 0xb8, 0x66, 0xd6, 0x49, 0xf6, 0xf4, 0x86, 0x61, 0xd0, 0x4d, 0xd1, + 0x12, 0xab, 0x73, 0x6f, 0x87, 0xe0, 0xd2, 0x9a, 0x1b, 0xbc, 0xe9, 0x4e, + 0x05, 0xd3, 0xcc, 0xe2, 0xe9, 0x4c, 0x42, 0xfa, 0x58, 0x35, 0xf3, 0xfc, + 0x7b, 0x34, 0x73, 0xb2, 0xcd, 0x33, 0x54, 0x63, 0x35, 0x65, 0x89, 0x21, + 0xdc, 0xd9, 0xcd, 0xf6, 0xce, 0x6e, 0x8a, 0xdd, 0x25, 0x93, 0x94, 0xdd, + 0x94, 0xa0, 0x84, 0x04, 0x45, 0x66, 0x1c, 0x40, 0x0b, 0xec, 0x55, 0x6e, + 0x96, 0x31, 0xcb, 0x99, 0x92, 0x3c, 0xe3, 0x3c, 0xa1, 0xf3, 0xac, 0x86, + 0xed, 0xa6, 0x8b, 0x53, 0xf2, 0xe2, 0x9c, 0x75, 0xe3, 0x3c, 0x61, 0x89, + 0x01, 0x7c, 0xd9, 0xff, 0x71, 0x1d, 0x22, 0x3a, 0x5c, 0xc6, 0x16, 0xa7, + 0x6a, 0xd7, 0xc7, 0x8b, 0x55, 0xe8, 0x32, 0x7f, 0xb9, 0x60, 0x98, 0x82, + 0xf7, 0x1b, 0x44, 0x54, 0x87, 0x04, 0x18, 0xf6, 0x30, 0x50, 0x25, 0x88, + 0x23, 0x0c, 0x23, 0xc6, 0x7c, 0xcd, 0xa3, 0xe3, 0x3a, 0x05, 0xec, 0x01, + 0x3d, 0x3c, 0xdf, 0x0b, 0xfb, 0xc2, 0xb3, 0x81, 0x3c, 0x57, 0x47, 0xdf, + 0x4d, 0xcf, 0x23, 0x46, 0x1b, 0x68, 0x4b, 0x5c, 0x9a, 0x1b, 0xb1, 0xc5, + 0x54, 0x63, 0xcf, 0x66, 0xab, 0x76, 0x88, 0x0a, 0x48, 0xb0, 0x09, 0x8a, + 0xc3, 0x4c, 0xcd, 0x84, 0x11, 0xd1, 0x50, 0xdb, 0xcd, 0x9a, 0x8a, 0xfb, + 0xd2, 0x7d, 0x5a, 0xc8, 0x63, 0x23, 0x78, 0x8a, 0xcf, 0x7f, 0x5a, 0xa4, + 0xb5, 0x58, 0x28, 0xc9, 0xe6, 0x7f, 0x65, 0xe4, 0x1f, 0x56, 0x2e, 0x82, + 0xe6, 0x25, 0xdc, 0x62, 0xdd, 0x88, 0xa2, 0x59, 0x68, 0xf6, 0xa8, 0xab, + 0xdc, 0x99, 0x4d, 0xda, 0xb8, 0x3d, 0x24, 0x12, 0x76, 0x41, 0xfe, 0x00, + 0xff, 0xaa, 0xa5, 0xd9, 0x1f, 0xe1, 0xc5, 0x72, 0xc3, 0xdc, 0xf6, 0x0c, + 0xd8, 0xc9, 0xb6, 0x9a, 0xf7, 0x16, 0x3e, 0x3e, 0xd8, 0xfd, 0xbf, 0x55, + 0x23, 0xb4, 0x30, 0x79, 0x99, 0x2f, 0xf2, 0x9f, 0x05, 0x28, 0x4a, 0x95, + 0xb5, 0x8d, 0xd2, 0x7a, 0x50, 0xa9, 0x01, 0xdb, 0xe7, 0xdb, 0x95, 0xb0, + 0x3d, 0xc3, 0xcd, 0x14, 0xaa, 0x5b, 0xbc, 0x0f, 0x9c, 0xc5, 0x2b, 0x28, + 0x37, 0xc6, 0xc1, 0xcd, 0x3f, 0xe9, 0x6b, 0xfc, 0x7b, 0x2d, 0x48, 0x1a, + 0x3d, 0x03, 0x6f, 0xbe, 0x83, 0xeb, 0x25, 0xde, 0xa9, 0x48, 0xb7, 0x26, + 0xa7, 0x7e, 0x28, 0x1a, 0x03, 0xb0, 0x0f, 0x6d, 0xfe, 0x8c, 0xeb, 0x8a, + 0xad, 0xd2, 0x5e, 0xba, 0xde, 0x88, 0x4d, 0x24, 0x3b, 0x7b, 0x6e, 0xc9, + 0xf9, 0x5b, 0x70, 0xfd, 0x0a, 0xbe, 0x5e, 0x19, 0x2b, 0x0f, 0x38, 0x42, + 0x5e, 0x80, 0x31, 0x32, 0xa2, 0x0e, 0xf6, 0xdc, 0x5c, 0xa7, 0xd5, 0x14, + 0xf4, 0x70, 0x3c, 0xc0, 0x9d, 0xc1, 0xa0, 0x1e, 0x61, 0x18, 0x2f, 0x58, + 0x99, 0x67, 0xdf, 0x55, 0x66, 0xe3, 0x77, 0xa1, 0x60, 0x40, 0x68, 0x8b, + 0xd8, 0x91, 0x9f, 0x41, 0xe7, 0x85, 0x74, 0xbe, 0x62, 0xad, 0x74, 0x3c, + 0x55, 0x3a, 0x7b, 0x5a, 0xa8, 0x86, 0x54, 0x82, 0xba, 0x50, 0x2a, 0xb5, + 0x73, 0x82, 0x53, 0x3a, 0x40, 0x9c, 0x7f, 0x10, 0x9c, 0xce, 0xe0, 0xa6, + 0x25, 0x54, 0xdf, 0x4a, 0x58, 0x67, 0x84, 0xa1, 0x5f, 0x28, 0x23, 0xca, + 0x78, 0xd8, 0x91, 0xec, 0x81, 0x01, 0x6c, 0x00, 0xc5, 0xac, 0x5a, 0xfc, + 0xc6, 0x90, 0x9e, 0x37, 0xa4, 0xa4, 0x92, 0x11, 0x0f, 0xaa, 0xd1, 0xcf, + 0x8f, 0x0e, 0x1d, 0x94, 0x77, 0x19, 0xb6, 0x67, 0xa2, 0x69, 0x81, 0xa5, + 0x31, 0x36, 0x8f, 0x33, 0xf5, 0xe7, 0xe6, 0xeb, 0x7e, 0x86, 0xcf, 0xdf, + 0xf2, 0xd6, 0xe7, 0x41, 0x6f, 0x45, 0x3b, 0x03, 0xbf, 0xf2, 0xd4, 0xef, + 0x7f, 0xd2, 0xe3, 0x16, 0x55, 0xdf, 0x20, 0xb7, 0x34, 0xc9, 0xfe, 0xd1, + 0xed, 0xbc, 0xb2, 0x48, 0x51, 0xf4, 0xae, 0x35, 0x5f, 0x0b, 0x13, 0xcd, + 0xf2, 0xc6, 0xba, 0x59, 0x5e, 0x4a, 0x37, 0xcb, 0xdb, 0xe4, 0x46, 0xbb, + 0xe1, 0xbf, 0xe9, 0xdf, 0xff, 0xaa, 0x7f, 0xff, 0x53, 0xfe, 0x74, 0x96, + 0xf5, 0xc9, 0x3a, 0x9b, 0x49, 0x00, 0xb0, 0x50, 0x05, 0x80, 0xc4, 0x8a, + 0x88, 0x53, 0xc4, 0xa9, 0x30, 0x33, 0xe9, 0x98, 0x50, 0x2e, 0x83, 0x93, + 0x4a, 0x99, 0xc4, 0x42, 0x3d, 0xc6, 0xa4, 0x96, 0x3d, 0xb3, 0x92, 0x15, + 0x55, 0x1b, 0x16, 0x19, 0xb6, 0x48, 0x84, 0x99, 0x32, 0x96, 0x1c, 0xea, + 0x7c, 0xa0, 0x59, 0x2e, 0xca, 0x8e, 0x0b, 0x53, 0xff, 0x66, 0xd1, 0xeb, + 0x1d, 0x5b, 0xd8, 0xb6, 0x36, 0x29, 0x99, 0xe6, 0x40, 0x3b, 0x29, 0xd3, + 0x4b, 0x4d, 0x30, 0x2f, 0x0b, 0x1e, 0x64, 0x34, 0x1e, 0x37, 0x7b, 0x36, + 0xdb, 0x04, 0x74, 0x5e, 0x0b, 0xe2, 0x62, 0x51, 0x3b, 0x85, 0xc2, 0xd8, + 0xda, 0x0a, 0xb7, 0xd7, 0x2c, 0x6a, 0xe4, 0xd4, 0x0a, 0x15, 0xfd, 0xc8, + 0x8a, 0x05, 0xb3, 0xc7, 0x03, 0x4e, 0x5f, 0x0b, 0x92, 0x99, 0x01, 0x2e, + 0x84, 0xb4, 0xf7, 0xcf, 0x35, 0x38, 0x69, 0x95, 0xd6, 0xff, 0xa1, 0x7f, + 0xff, 0x87, 0xfe, 0xfd, 0xf7, 0xc7, 0x6d, 0xfa, 0xdd, 0xcf, 0xf2, 0x75, + 0x78, 0xf1, 0xe6, 0xe7, 0x91, 0x52, 0xf7, 0x99, 0xcf, 0xa4, 0x94, 0xc1, + 0x13, 0x1f, 0x4a, 0xab, 0x3e, 0xeb, 0xdd, 0x8c, 0x19, 0x2d, 0xea, 0x60, + 0x1e, 0xbb, 0xe5, 0x4c, 0xb7, 0xa6, 0x6e, 0x3f, 0x8a, 0x27, 0x26, 0x32, + 0x62, 0xe0, 0xa1, 0xba, 0xdc, 0xdd, 0x7e, 0x63, 0x42, 0xfb, 0x7b, 0xc1, + 0x0a, 0x49, 0xc9, 0xb7, 0x8f, 0x85, 0x21, 0xa6, 0xc6, 0xdc, 0xed, 0xed, + 0x8f, 0x7a, 0xe3, 0xa0, 0x93, 0x18, 0x0e, 0x82, 0x31, 0xc0, 0x14, 0x9b, + 0x79, 0x02, 0x45, 0x9c, 0x20, 0x77, 0x05, 0xc3, 0x66, 0x10, 0x74, 0x7e, + 0xba, 0x7f, 0x36, 0xb1, 0x54, 0x18, 0xe8, 0xb7, 0xf2, 0x65, 0x65, 0xda, + 0xf5, 0x2c, 0x18, 0x2b, 0x2b, 0x0d, 0x12, 0x12, 0x8e, 0x0b, 0x13, 0x1d, + 0x14, 0x0c, 0x2b, 0x21, 0x10, 0xda, 0x06, 0x33, 0xf1, 0x94, 0xb4, 0xc6, + 0x86, 0x4a, 0xd3, 0x56, 0x29, 0xfe, 0x6f, 0xdc, 0x62, 0x66, 0x39, 0x42, + 0x3d, 0x03, 0xb6, 0x06, 0x87, 0xc3, 0x08, 0x0e, 0xc8, 0xb0, 0x6f, 0x0e, + 0x39, 0x7a, 0xdd, 0x48, 0xbe, 0xf6, 0xa3, 0xb8, 0x3d, 0x88, 0x73, 0x69, + 0x82, 0x9d, 0x3b, 0x81, 0x81, 0x32, 0xae, 0x8c, 0x78, 0x7b, 0xe4, 0x3b, + 0x5e, 0x5f, 0x85, 0x34, 0x52, 0x6a, 0x23, 0xdb, 0xa6, 0xe5, 0xd6, 0x6d, + 0x41, 0xa8, 0xbd, 0xc0, 0x44, 0x2f, 0xc8, 0x14, 0x33, 0x86, 0xc8, 0x6b, + 0xbc, 0xba, 0x1e, 0xe6, 0x4c, 0x1b, 0xed, 0xf6, 0x35, 0x5d, 0x5d, 0xd7, + 0x7a, 0x55, 0xbb, 0x71, 0x32, 0x3b, 0xc1, 0x94, 0xe1, 0x16, 0x47, 0xbb, + 0xfe, 0xef, 0xa6, 0xa9, 0x71, 0x5a, 0x5e, 0x93, 0x5f, 0xd7, 0x8b, 0x6b, + 0xf1, 0xeb, 0x02, 0xca, 0x9f, 0xaf, 0x3c, 0x7d, 0xf5, 0xda, 0xd7, 0x6b, + 0x86, 0x30, 0xf2, 0x3a, 0x61, 0xc7, 0x26, 0xbb, 0xad, 0x97, 0x89, 0x8c, + 0x76, 0xbb, 0x82, 0xdb, 0x6c, 0x40, 0xcb, 0x2b, 0x93, 0xfe, 0xcb, 0x11, + 0xfd, 0x50, 0x53, 0xff, 0x19, 0x68, 0x26, 0xa0, 0x19, 0xc1, 0x10, 0x47, + 0x34, 0x5d, 0xb9, 0x2c, 0x60, 0xb8, 0x37, 0xbc, 0x5c, 0x0e, 0xe7, 0x6c, + 0x0e, 0x44, 0x98, 0xff, 0xd4, 0xeb, 0x1f, 0xfd, 0xf9, 0xb3, 0xd7, 0xf7, + 0x65, 0x74, 0x88, 0x30, 0x9e, 0xf1, 0x69, 0x0b, 0xb7, 0xc9, 0x3e, 0x5d, + 0xb9, 0x04, 0x98, 0x98, 0x2f, 0x17, 0xfd, 0xcb, 0x11, 0x63, 0x82, 0xfc, + 0x57, 0xfc, 0x50, 0x14, 0xf8, 0xf0, 0x60, 0x59, 0x2f, 0x10, 0x1e, 0x50, + 0xf0, 0xdf, 0xac, 0x8e, 0x09, 0xfc, 0x37, 0x42, 0x60, 0x7d, 0x39, 0x8d, + 0x28, 0xa7, 0x11, 0xd1, 0xff, 0xbd, 0xd6, 0x01, 0x8b, 0xdb, 0xbc, 0x36, + 0x60, 0xb4, 0x99, 0xfa, 0x80, 0xb1, 0xa9, 0x5e, 0x74, 0x5f, 0x2a, 0x27, + 0xf3, 0x9a, 0xb1, 0x58, 0xd6, 0x67, 0x2d, 0x44, 0x8d, 0xf0, 0xdb, 0xe6, + 0x93, 0x05, 0x11, 0x46, 0x4e, 0x6e, 0x69, 0xaa, 0xa8, 0xf0, 0x00, 0x6b, + 0xeb, 0xfa, 0xcd, 0x96, 0x08, 0x3e, 0xa0, 0x61, 0xe8, 0x87, 0xf4, 0xe8, + 0x15, 0xa5, 0x47, 0x00, 0x91, 0x84, 0x1e, 0xea, 0x80, 0x16, 0xfe, 0xba, + 0xef, 0x01, 0xde, 0x74, 0xe9, 0x03, 0x1a, 0x58, 0x6c, 0x13, 0xff, 0xdd, + 0x9b, 0x6e, 0xab, 0xdb, 0x1a, 0xcd, 0xdf, 0x16, 0x8c, 0x88, 0x76, 0x6e, + 0xcc, 0x9a, 0x6b, 0x50, 0x68, 0xc7, 0x96, 0x71, 0xf8, 0x45, 0xf1, 0x16, + 0xf5, 0x39, 0x4f, 0x3b, 0x7d, 0x7a, 0x71, 0x84, 0xec, 0x8d, 0xa1, 0xba, + 0x14, 0x8b, 0x7b, 0x49, 0xc8, 0x09, 0x47, 0x76, 0x14, 0x27, 0x5c, 0xce, + 0x41, 0xbc, 0x75, 0x44, 0x18, 0xe0, 0xb9, 0xfa, 0x2f, 0x63, 0x5f, 0xb3, + 0x89, 0xd6, 0x21, 0x79, 0xb8, 0x43, 0x23, 0x03, 0x13, 0xdf, 0x95, 0x52, + 0x2c, 0x50, 0x82, 0xd7, 0x8f, 0x90, 0xc3, 0x22, 0x5e, 0x4c, 0x12, 0xb0, + 0xd9, 0xad, 0xe6, 0xcd, 0xe9, 0xb3, 0x6b, 0xf8, 0x71, 0x0a, 0x35, 0x86, + 0x21, 0x1d, 0xb6, 0xb6, 0x46, 0xdc, 0xb4, 0x43, 0x8e, 0xb0, 0x1e, 0xcd, + 0x69, 0x53, 0x8f, 0xd7, 0x6a, 0xf9, 0x50, 0x08, 0x93, 0xa3, 0x85, 0x1c, + 0xec, 0x65, 0x4d, 0x8d, 0x04, 0x27, 0xcc, 0xdb, 0x9b, 0x5a, 0x4b, 0xeb, + 0xe4, 0x04, 0xaf, 0xaf, 0x76, 0x40, 0xe9, 0x78, 0xed, 0x30, 0x99, 0x2a, + 0xb7, 0x0e, 0x05, 0xaf, 0xd6, 0x58, 0xd9, 0x61, 0x46, 0x7e, 0x68, 0x34, + 0x02, 0xa5, 0x32, 0x58, 0x3f, 0xbc, 0xb6, 0xa8, 0xb7, 0x0e, 0xc1, 0x42, + 0x50, 0x3a, 0xdb, 0x60, 0x46, 0x4a, 0x66, 0x87, 0x77, 0x66, 0x24, 0xac, + 0x17, 0x1d, 0x3a, 0x6c, 0xbb, 0x77, 0x88, 0x46, 0x8b, 0x63, 0x87, 0x91, + 0x1d, 0xde, 0xdb, 0x8e, 0x2f, 0xa8, 0x75, 0x48, 0x1b, 0x58, 0x02, 0xb5, + 0x0d, 0xfd, 0xee, 0x06, 0x93, 0x25, 0x0e, 0x1d, 0x06, 0xef, 0x30, 0x58, + 0x07, 0x58, 0x28, 0xb9, 0xd1, 0x77, 0x3f, 0x83, 0x67, 0xee, 0x77, 0x98, + 0x6c, 0xd2, 0x78, 0x65, 0xc8, 0x1b, 0x23, 0xc9, 0x84, 0x30, 0xb7, 0x9d, + 0xbd, 0x9f, 0xea, 0xb0, 0x5e, 0x76, 0x08, 0xbb, 0x13, 0x7f, 0xec, 0xd0, + 0x5e, 0x74, 0x58, 0x0e, 0x1d, 0x46, 0xfe, 0x41, 0x07, 0xfd, 0x6e, 0xb1, + 0x2a, 0x33, 0xbc, 0x25, 0xa1, 0x35, 0xe2, 0x2c, 0x49, 0x19, 0xed, 0x5e, + 0x87, 0xfe, 0xdc, 0x41, 0x1e, 0x4a, 0xc5, 0x2b, 0x13, 0xc0, 0x6a, 0xb3, + 0xcf, 0x21, 0x68, 0xbc, 0x40, 0xf9, 0xa3, 0xf5, 0xbd, 0x01, 0x7f, 0xf8, + 0xe6, 0xb5, 0xe7, 0x0e, 0x41, 0x2c, 0xc4, 0xc9, 0xe4, 0x39, 0xe9, 0xae, + 0xad, 0xe8, 0x80, 0x0d, 0x8a, 0x12, 0x46, 0x40, 0x07, 0x61, 0x1a, 0x7d, + 0x20, 0x7b, 0xb5, 0x36, 0x80, 0x1a, 0x06, 0x1c, 0xcc, 0x4a, 0x93, 0x4d, + 0x99, 0xd1, 0x61, 0x51, 0xbd, 0xd2, 0x6a, 0x62, 0x31, 0x33, 0x74, 0xad, + 0x92, 0x07, 0x0d, 0x20, 0x11, 0xb7, 0xad, 0xe1, 0xeb, 0x7c, 0x7b, 0xea, + 0xdd, 0x82, 0xb7, 0xf8, 0x42, 0xd5, 0xea, 0xc4, 0xa3, 0x87, 0x2c, 0xd5, + 0xb0, 0xe5, 0xe4, 0x35, 0xc6, 0xf5, 0xc2, 0xb0, 0x9a, 0x65, 0x2d, 0x21, + 0x2d, 0x04, 0xc2, 0x11, 0xc2, 0x84, 0xf2, 0x0e, 0x10, 0x45, 0x2b, 0xb3, + 0x9e, 0x49, 0xe1, 0x62, 0xef, 0x69, 0xd9, 0x7c, 0x0b, 0x50, 0xed, 0xa2, + 0x4a, 0xcf, 0xa4, 0x3d, 0xc7, 0x02, 0x0f, 0xd5, 0x0a, 0x3a, 0x56, 0x1e, + 0x63, 0x6e, 0xc1, 0x0f, 0x05, 0x46, 0x2d, 0xbd, 0xca, 0x64, 0x3a, 0x3d, + 0x99, 0xb6, 0x5d, 0x68, 0x8b, 0x59, 0x4d, 0x91, 0xbc, 0xff, 0x12, 0xcf, + 0xd3, 0xc6, 0x93, 0xd5, 0xd0, 0x9d, 0xa3, 0x04, 0xf1, 0xe4, 0x87, 0xb5, + 0x07, 0x45, 0xab, 0x9f, 0x70, 0x71, 0xa0, 0xe2, 0xf6, 0xc7, 0xcf, 0x70, + 0x46, 0x99, 0x4e, 0x28, 0xfb, 0x33, 0xca, 0x78, 0x50, 0xee, 0xb8, 0xe7, + 0xe5, 0x2c, 0x0f, 0xe7, 0x09, 0xef, 0x79, 0x39, 0x89, 0xfe, 0x3c, 0x89, + 0x74, 0x1a, 0x51, 0xcf, 0xb4, 0x8a, 0xf2, 0xf2, 0x1e, 0x7e, 0x9e, 0x36, + 0xff, 0x97, 0x28, 0x81, 0xe2, 0xff, 0x70, 0x96, 0x58, 0x58, 0x9a, 0x38, + 0x4b, 0x03, 0x70, 0x2e, 0x83, 0x69, 0xe1, 0x7a, 0x34, 0x25, 0x9e, 0xdc, + 0x9b, 0x4f, 0x02, 0x9f, 0x7c, 0x18, 0x71, 0xe8, 0x50, 0x47, 0xa0, 0x43, + 0x7b, 0xee, 0xe0, 0x23, 0x38, 0xf9, 0x48, 0xc0, 0x61, 0x1d, 0x17, 0x1d, + 0xba, 0x73, 0x87, 0xfe, 0xd4, 0x81, 0x38, 0x2b, 0x39, 0xc2, 0x71, 0x0a, + 0x0e, 0x98, 0x0e, 0xc4, 0xea, 0xcb, 0x71, 0x93, 0x13, 0xbf, 0xec, 0x7d, + 0xa2, 0x89, 0xe3, 0x6f, 0x80, 0x06, 0x07, 0xf9, 0x5d, 0x07, 0xc7, 0x77, + 0x0d, 0x6a, 0x1d, 0x14, 0xb8, 0x25, 0x02, 0x5a, 0xee, 0x81, 0x22, 0x41, + 0x5d, 0xa9, 0x35, 0x2e, 0x87, 0x4c, 0xe3, 0x09, 0xd4, 0x3b, 0x28, 0x71, + 0xd1, 0xbd, 0x13, 0xfc, 0x06, 0xc8, 0x49, 0x33, 0x38, 0x51, 0x9d, 0x7a, + 0x37, 0x40, 0x81, 0x20, 0xdd, 0xca, 0xc5, 0x41, 0xa3, 0x81, 0x9e, 0x11, + 0xf4, 0xc1, 0x40, 0x9d, 0x83, 0xf4, 0xd7, 0x20, 0x26, 0x82, 0xd6, 0x33, + 0x68, 0x60, 0xaa, 0x64, 0xf6, 0xac, 0xed, 0xc0, 0xec, 0xea, 0x6c, 0x33, + 0xbc, 0x01, 0x1a, 0xe4, 0x75, 0x51, 0x28, 0x7b, 0xc8, 0x09, 0x3e, 0xf6, + 0xd6, 0x83, 0x8f, 0xaf, 0x40, 0xad, 0x83, 0x82, 0x9a, 0x12, 0xa3, 0xe9, + 0x03, 0xd3, 0x11, 0x41, 0x03, 0xbf, 0x17, 0xa0, 0x48, 0x50, 0x57, 0x58, + 0x7f, 0x1c, 0x55, 0x7b, 0x4d, 0x16, 0xf1, 0x08, 0x8c, 0xc1, 0xb9, 0xb1, + 0x05, 0x50, 0x52, 0x50, 0x26, 0xc8, 0xa2, 0xbb, 0x78, 0x99, 0x56, 0xaf, + 0x69, 0xc8, 0xad, 0xb1, 0x23, 0x40, 0x41, 0x83, 0x65, 0x26, 0x1d, 0x34, + 0xdf, 0x04, 0x05, 0x8b, 0x57, 0x20, 0x13, 0x9e, 0x68, 0x46, 0xf6, 0x50, + 0xb3, 0x67, 0x50, 0xe7, 0xa0, 0xc8, 0x33, 0xaf, 0x2b, 0x28, 0x39, 0xbe, + 0x05, 0x4a, 0x04, 0xf5, 0x06, 0xda, 0xdc, 0x0a, 0xf2, 0xa3, 0xc5, 0xc3, + 0xd8, 0x85, 0xd9, 0xcc, 0xb2, 0xb9, 0x84, 0xce, 0x2e, 0xcc, 0xb7, 0x40, + 0xad, 0x83, 0x02, 0x5a, 0xcc, 0x7f, 0x96, 0xe5, 0x16, 0x28, 0x12, 0x44, + 0x79, 0xf7, 0x18, 0xbb, 0xc6, 0x8a, 0xb2, 0x4d, 0x8e, 0xe9, 0x81, 0x89, + 0x31, 0x9e, 0xd5, 0x9c, 0x7a, 0xe9, 0xd1, 0xe3, 0x74, 0xd9, 0x6e, 0x81, + 0x0a, 0x8c, 0xe1, 0xec, 0xb1, 0x4a, 0x8f, 0xd9, 0xcc, 0x83, 0x87, 0x94, + 0x1c, 0x14, 0x08, 0x6a, 0x99, 0xe2, 0x5b, 0x02, 0x42, 0x4e, 0x96, 0x42, + 0xbf, 0x04, 0x3d, 0x71, 0x50, 0x24, 0xe8, 0x85, 0x81, 0x98, 0xdd, 0x96, + 0x49, 0xbf, 0xe0, 0x19, 0x67, 0x51, 0x14, 0x01, 0xfd, 0x4c, 0xd0, 0xe6, + 0xa0, 0x37, 0x06, 0x62, 0x1a, 0xb4, 0xd6, 0x3a, 0x59, 0x38, 0x05, 0xa0, + 0xb9, 0x50, 0xa0, 0x0b, 0xe5, 0x12, 0xf4, 0x63, 0x63, 0x66, 0x63, 0xf5, + 0xed, 0xf1, 0xc6, 0xc8, 0x46, 0xae, 0x3b, 0xe7, 0x3b, 0xe1, 0xf4, 0x3f, + 0x37, 0xbc, 0xfc, 0xb5, 0x5c, 0x37, 0xc6, 0x52, 0xac, 0x1c, 0x6a, 0x64, + 0x34, 0x6a, 0x22, 0xfb, 0x4c, 0x85, 0x26, 0x7a, 0x31, 0xcb, 0xd3, 0xaa, + 0x60, 0xf5, 0xcc, 0xd3, 0x46, 0x77, 0xd5, 0x68, 0x0f, 0x8d, 0xf9, 0x4e, + 0xa3, 0xf9, 0xe3, 0x1b, 0xc7, 0x9b, 0x5e, 0x4f, 0xec, 0xd4, 0xe8, 0xb8, + 0x40, 0x6f, 0xf4, 0x87, 0x25, 0x8f, 0x24, 0x82, 0x35, 0x22, 0x4a, 0x35, + 0x1a, 0xa3, 0xea, 0x66, 0x67, 0xca, 0x99, 0xe0, 0xbe, 0x17, 0xbe, 0x3b, + 0xd3, 0x79, 0x07, 0x7d, 0x73, 0x33, 0x1b, 0xcb, 0xf5, 0x76, 0x4f, 0x57, + 0x78, 0xae, 0x77, 0xf9, 0x62, 0x2b, 0x0f, 0x7b, 0xda, 0xfb, 0x56, 0x16, + 0xae, 0x34, 0xb2, 0x31, 0x90, 0x3e, 0x3d, 0x1b, 0x9d, 0x66, 0xec, 0x8e, + 0x0d, 0x4f, 0x89, 0x7a, 0xa3, 0x39, 0x34, 0xb6, 0x53, 0x23, 0x3d, 0xa8, + 0x51, 0x1e, 0xde, 0x88, 0xf7, 0x1b, 0x0f, 0xc3, 0x73, 0x77, 0x1a, 0xd7, + 0x93, 0x67, 0xe3, 0x7a, 0xc9, 0xdd, 0x55, 0xa3, 0x27, 0x7d, 0x06, 0x36, + 0x22, 0x1b, 0x05, 0xc4, 0x0c, 0xa5, 0xd4, 0xd7, 0xdf, 0xe4, 0xab, 0xc6, + 0x74, 0x6b, 0xbf, 0x2e, 0xb7, 0xf2, 0xf7, 0x71, 0x94, 0x2b, 0x10, 0xaa, + 0x14, 0x18, 0x58, 0x8c, 0x54, 0xc8, 0xfc, 0x9a, 0xa6, 0x46, 0xa8, 0x8d, + 0xb2, 0xe3, 0xa1, 0x7c, 0x33, 0xd8, 0x6c, 0x88, 0x87, 0x96, 0x9a, 0x9f, + 0x2a, 0xfe, 0xd6, 0x02, 0x16, 0x4a, 0x16, 0xe6, 0x51, 0xbd, 0x94, 0xd2, + 0x5c, 0x85, 0x42, 0xed, 0x52, 0x0e, 0x35, 0x1d, 0x2c, 0xa6, 0x55, 0x77, + 0x43, 0xd7, 0x23, 0xf9, 0x72, 0x0d, 0x0e, 0xf4, 0x48, 0x1e, 0x48, 0x26, + 0x7d, 0xaa, 0xdc, 0x39, 0xe0, 0x3d, 0x22, 0x32, 0xd3, 0x1f, 0x71, 0xa6, + 0xd8, 0x4b, 0x1b, 0x2c, 0xa3, 0xbf, 0xd6, 0x4c, 0xbe, 0xcc, 0xfd, 0x19, + 0xe2, 0x52, 0xa6, 0x9b, 0x5b, 0x96, 0x07, 0x78, 0x65, 0x01, 0x8b, 0x12, + 0x2a, 0x4b, 0x61, 0x31, 0x7f, 0x66, 0x17, 0xe3, 0xc3, 0x06, 0x1b, 0x63, + 0x16, 0x25, 0x03, 0xd6, 0x1e, 0x99, 0xfe, 0xde, 0xe5, 0xaf, 0xbe, 0x8d, + 0x09, 0xc5, 0x29, 0xf7, 0x18, 0x73, 0xba, 0xe0, 0x5d, 0x57, 0x25, 0xbf, + 0x90, 0xbd, 0x07, 0x9c, 0x08, 0x55, 0x02, 0x92, 0x45, 0xb4, 0xec, 0x39, + 0x4c, 0x11, 0x12, 0xb9, 0xa9, 0xaa, 0x1f, 0xb9, 0xe9, 0x8b, 0x52, 0xfc, + 0x69, 0x16, 0x7f, 0xeb, 0x88, 0xab, 0x8d, 0xec, 0xd2, 0xd8, 0xf3, 0x1b, + 0x17, 0x58, 0x0c, 0xaa, 0x32, 0x7d, 0x3e, 0x90, 0xe8, 0x05, 0xce, 0x07, + 0xcd, 0xd0, 0x61, 0xe1, 0x55, 0x79, 0x74, 0x85, 0x1b, 0x57, 0xe8, 0x4a, + 0x0d, 0xb0, 0xea, 0x8d, 0x56, 0x27, 0x1a, 0x2d, 0x35, 0x8e, 0xe8, 0x8a, + 0xcb, 0xab, 0x33, 0x30, 0x39, 0xb7, 0x2a, 0xab, 0xda, 0xe3, 0x42, 0x98, + 0x08, 0xf3, 0x52, 0x1a, 0xd7, 0x9e, 0x5e, 0x64, 0xc3, 0x87, 0x79, 0x3c, + 0x29, 0x56, 0x75, 0xef, 0x0b, 0xaa, 0xac, 0x01, 0x96, 0xb1, 0xfd, 0x84, + 0x89, 0xeb, 0xf2, 0xc0, 0x9d, 0x48, 0xa8, 0xc7, 0x97, 0xfb, 0x47, 0x18, + 0xe9, 0x7e, 0x00, 0xbc, 0x67, 0xd2, 0xeb, 0x2d, 0x74, 0x91, 0xbd, 0x59, + 0xa6, 0xe5, 0x39, 0xd2, 0xf1, 0x6d, 0x46, 0x03, 0xbb, 0x44, 0x74, 0x69, + 0x6e, 0x75, 0x29, 0xec, 0x52, 0xaa, 0xca, 0xde, 0x0e, 0x29, 0x82, 0xef, + 0x5d, 0xfe, 0x85, 0xba, 0x3c, 0x80, 0x5f, 0x2e, 0xbb, 0x38, 0xd7, 0x1d, + 0x19, 0xf3, 0x25, 0x19, 0x33, 0x5e, 0xf0, 0xee, 0xc0, 0x2e, 0x09, 0xe7, + 0x68, 0x7b, 0x25, 0x01, 0xa9, 0xbe, 0xb2, 0x4b, 0x85, 0x44, 0xc3, 0x1b, + 0x36, 0xe3, 0x83, 0x1c, 0x5d, 0x89, 0x5a, 0x55, 0x41, 0xb8, 0x2e, 0x57, + 0x02, 0x4b, 0x99, 0x76, 0x0b, 0x66, 0x3c, 0x8b, 0xfd, 0x74, 0xd6, 0x0c, + 0xe3, 0x49, 0x79, 0x64, 0xea, 0x95, 0x6f, 0xf5, 0x81, 0x6b, 0x37, 0xfb, + 0x69, 0x84, 0x8c, 0x13, 0xce, 0xa8, 0xc4, 0x92, 0x0a, 0x0b, 0x4b, 0xa8, + 0xb3, 0xf7, 0x0f, 0x18, 0xe4, 0xba, 0x14, 0x55, 0x06, 0xa6, 0x61, 0xf1, + 0xce, 0x37, 0xec, 0xb4, 0x1d, 0x0d, 0xf6, 0x33, 0x98, 0x56, 0x7b, 0xf1, + 0x98, 0x41, 0x7f, 0x71, 0x42, 0xfc, 0x49, 0x83, 0xbe, 0xd1, 0x27, 0x7f, + 0xbe, 0xcb, 0xd7, 0xfa, 0x6c, 0x75, 0xb1, 0xff, 0x1a, 0xff, 0x28, 0xf4, + 0xf3, 0xd6, 0x3f, 0xf6, 0x1f, 0x7f, 0xfe, 0x4a, 0xff, 0x15, 0xff, 0x21, + 0x1f, 0x7a, 0xd3, 0xb2, 0x23, 0x63, 0xd3, 0xd8, 0xb9, 0x24, 0x5d, 0x54, + 0xe3, 0x59, 0xe8, 0xba, 0x1c, 0x02, 0x7c, 0x2b, 0xcf, 0x79, 0xaf, 0x8a, + 0x5f, 0x1f, 0x60, 0x09, 0x7b, 0x30, 0x75, 0xa1, 0x6d, 0xef, 0xef, 0x2b, + 0x72, 0x93, 0xb8, 0xfa, 0xd3, 0x01, 0xfd, 0x72, 0xc2, 0x61, 0x2a, 0x8c, + 0xa2, 0x77, 0xf9, 0x81, 0xb7, 0x7b, 0xca, 0xf3, 0x7f, 0x80, 0x89, 0x20, + 0xb5, 0xff, 0x93, 0x2e, 0x2c, 0xc2, 0xe5, 0xf7, 0x18, 0xc8, 0x07, 0xce, + 0xda, 0x8c, 0x06, 0xf7, 0x64, 0x06, 0x96, 0xff, 0x07, 0xfa, 0xda, 0x36, + 0xc9, 0xe6, 0x1c, 0xa4, 0x59, 0xb9, 0xf8, 0xe5, 0xca, 0x97, 0xc8, 0x87, + 0x47, 0x00, 0xdc, 0x79, 0x0a, 0x5f, 0x80, 0xa6, 0xee, 0x89, 0x2b, 0xda, + 0x83, 0xcb, 0x98, 0x6a, 0x5a, 0xc7, 0x36, 0xcc, 0x4b, 0x45, 0xdc, 0xcf, + 0xec, 0xff, 0x24, 0x34, 0x67, 0x4f, 0xcc, 0xa3, 0xea, 0x33, 0xf7, 0xba, + 0x06, 0x53, 0xdc, 0x54, 0xe2, 0xa6, 0x93, 0x41, 0x1e, 0x89, 0x86, 0x44, + 0x07, 0xdf, 0xea, 0xa2, 0x02, 0x49, 0x1c, 0x41, 0x62, 0x1b, 0x36, 0x93, + 0xe8, 0xf9, 0xf0, 0xfc, 0x5b, 0xf7, 0x95, 0xd1, 0x0c, 0x44, 0x13, 0x88, + 0x26, 0x12, 0x4d, 0x22, 0x1a, 0x5a, 0xbe, 0xad, 0x96, 0x98, 0xcf, 0x0c, + 0xac, 0x1b, 0x03, 0xbd, 0x22, 0x1f, 0x3e, 0x27, 0x1f, 0xc6, 0x1a, 0xfc, + 0x29, 0x97, 0x91, 0xbc, 0x0f, 0xb4, 0x81, 0xf5, 0xc9, 0x0e, 0xe9, 0xfb, + 0x0b, 0x4d, 0xde, 0x9f, 0xa5, 0x21, 0xb3, 0x7a, 0x5a, 0xcc, 0xb7, 0xd6, + 0x67, 0x3b, 0xc4, 0xe3, 0xf6, 0x07, 0xbb, 0xfd, 0xe1, 0x8e, 0x85, 0x0d, + 0x3c, 0xdd, 0xf1, 0x8a, 0xd6, 0xcd, 0x73, 0xda, 0x41, 0x09, 0xef, 0x99, + 0x58, 0xe9, 0x91, 0xcf, 0x8c, 0x82, 0xfd, 0x54, 0xf0, 0xf0, 0xd8, 0x13, + 0x08, 0xf4, 0xd6, 0x63, 0xbf, 0x16, 0xfb, 0x65, 0xaf, 0x22, 0xa5, 0x36, + 0x93, 0x85, 0xe8, 0x22, 0xec, 0xf2, 0xbd, 0x63, 0x73, 0x48, 0xee, 0x86, + 0xa5, 0x32, 0x64, 0x22, 0xd9, 0xbe, 0x37, 0xfe, 0x59, 0x8d, 0xbf, 0xec, + 0xe7, 0x2f, 0x42, 0x9f, 0xef, 0x8d, 0x3f, 0xab, 0xf1, 0xfd, 0xf3, 0xcd, + 0x3e, 0xa3, 0xa9, 0xf9, 0x16, 0x86, 0xa1, 0xbd, 0x92, 0xda, 0xec, 0x8c, + 0x00, 0x03, 0x6f, 0x34, 0xdb, 0xe2, 0x7b, 0xb7, 0x7f, 0x70, 0xb7, 0x1e, + 0x41, 0x6b, 0x7b, 0x14, 0x54, 0xbe, 0x94, 0x9a, 0xd9, 0x62, 0x15, 0x4e, + 0x11, 0x31, 0x16, 0x7d, 0x5d, 0xcd, 0x1b, 0xf9, 0xf3, 0x52, 0xfe, 0x3c, + 0xdb, 0xff, 0xd7, 0xb7, 0xaa, 0xea, 0x3b, 0x57, 0x35, 0x1b, 0xf9, 0x5a, + 0xfe, 0x3c, 0x29, 0xc5, 0xca, 0xfe, 0x34, 0x08, 0x23, 0x0e, 0x83, 0xbe, + 0x1d, 0x59, 0xcd, 0x13, 0x0d, 0xcc, 0x79, 0xdd, 0xe7, 0xd6, 0x5c, 0xf8, + 0x02, 0xcb, 0x65, 0xa3, 0x3b, 0x24, 0x8e, 0x4f, 0xa9, 0x64, 0x2f, 0x0f, + 0x18, 0x0e, 0x8d, 0xe9, 0xb2, 0x11, 0x6e, 0x25, 0xd6, 0xbd, 0x61, 0x77, + 0x4f, 0xb5, 0x61, 0xa9, 0x76, 0xfd, 0x83, 0xc6, 0x7a, 0xd9, 0x68, 0x0f, + 0x8d, 0x45, 0x1b, 0xdd, 0xa1, 0x31, 0xd3, 0xee, 0xf6, 0x46, 0xd6, 0xc6, + 0x70, 0xd5, 0x08, 0x66, 0x2c, 0x5f, 0x36, 0xc6, 0x06, 0x84, 0xf6, 0x86, + 0x4d, 0x25, 0x5d, 0x35, 0xce, 0xb3, 0xdc, 0x5a, 0x38, 0x77, 0x17, 0x8d, + 0x45, 0x1b, 0xdd, 0x55, 0xa3, 0x47, 0xea, 0xb6, 0x36, 0xcc, 0xa5, 0x38, + 0x36, 0x02, 0x77, 0xc7, 0x1b, 0xf1, 0xd0, 0x18, 0x2f, 0x1b, 0x09, 0x0e, + 0x5d, 0x6d, 0x70, 0x5b, 0xbd, 0x51, 0x0e, 0x8d, 0xf5, 0x01, 0x8d, 0xeb, + 0x51, 0xde, 0x28, 0xd7, 0x8d, 0xf1, 0x7e, 0x63, 0xba, 0xd3, 0x78, 0x83, + 0x95, 0xd6, 0xc6, 0xcf, 0xcc, 0x68, 0xbf, 0x60, 0xe3, 0xc9, 0xa1, 0xa1, + 0xa4, 0x2b, 0xed, 0xa1, 0xb1, 0x72, 0x0b, 0xae, 0x1b, 0x1b, 0xf7, 0xeb, + 0xba, 0x81, 0x1d, 0x8c, 0x87, 0xc6, 0x69, 0xdf, 0xc3, 0xa1, 0x31, 0x91, + 0x6d, 0xae, 0x1b, 0xf9, 0x92, 0xc7, 0xfa, 0x2b, 0xf6, 0xeb, 0x0e, 0x8d, + 0xe5, 0x92, 0x69, 0xdb, 0x2b, 0x7e, 0x3e, 0xb2, 0xfa, 0x99, 0xbf, 0x52, + 0x6d, 0x9c, 0x45, 0x26, 0x5e, 0x89, 0xd5, 0x51, 0xe2, 0xa6, 0xcb, 0xc6, + 0x51, 0x3c, 0x4f, 0x92, 0xdb, 0x5f, 0x49, 0xf7, 0x51, 0xf0, 0x3f, 0x5b, + 0x31, 0x72, 0x2c, 0x1d, 0xb9, 0x5b, 0x7d, 0x91, 0xc8, 0x45, 0xde, 0xf8, + 0x4b, 0x06, 0x65, 0xbf, 0x0f, 0xfa, 0x3e, 0xe8, 0x6f, 0x14, 0xdb, 0x8f, + 0x36, 0xbf, 0xd6, 0x02, 0x17, 0x78, 0x30, 0x75, 0x1b, 0x10, 0xb5, 0x4a, + 0xfa, 0xeb, 0xad, 0x28, 0xe4, 0x15, 0x35, 0x2a, 0xab, 0x60, 0x91, 0xc1, + 0x68, 0x33, 0x15, 0xa3, 0x61, 0xb2, 0x85, 0xc8, 0x1b, 0x2f, 0xb2, 0xad, + 0x53, 0xde, 0x21, 0x32, 0x5b, 0x53, 0xce, 0xa0, 0xc5, 0x16, 0x27, 0xe1, + 0x92, 0xcd, 0x6e, 0x67, 0x21, 0x94, 0x86, 0x1a, 0x5b, 0xb1, 0x25, 0xb3, + 0x3e, 0x26, 0x6b, 0x0a, 0xe2, 0x6c, 0xb7, 0x13, 0xc4, 0x20, 0x8c, 0x20, + 0x06, 0xdd, 0x04, 0xf1, 0x66, 0x4d, 0x8d, 0xc3, 0xd8, 0xed, 0x14, 0xf1, + 0x68, 0xb7, 0x7b, 0x51, 0x3c, 0xa0, 0x24, 0x88, 0x11, 0x64, 0x12, 0xc4, + 0x88, 0xb7, 0x0a, 0x62, 0x44, 0x91, 0x04, 0xf1, 0x66, 0xb7, 0x13, 0xc4, + 0x8c, 0x33, 0x0e, 0xc5, 0x63, 0x8f, 0x4f, 0x0d, 0xdb, 0x00, 0xc4, 0xb3, + 0xdd, 0xee, 0x75, 0xf1, 0x12, 0x0f, 0x41, 0xbc, 0xa1, 0xd4, 0x3b, 0x15, + 0x56, 0x46, 0xe8, 0xab, 0xfd, 0x46, 0xbd, 0x9d, 0x22, 0x9e, 0x4c, 0x85, + 0x0d, 0x86, 0x2d, 0x02, 0xf1, 0x62, 0xb7, 0x13, 0xc4, 0x78, 0xc6, 0xea, + 0x75, 0xa1, 0x92, 0x35, 0xc3, 0xcc, 0x6e, 0xb7, 0x23, 0x7e, 0x85, 0x84, + 0xe7, 0x8e, 0xf8, 0x6d, 0x91, 0xe4, 0xec, 0x47, 0x41, 0xfc, 0xab, 0x3e, + 0xc2, 0xf1, 0x9b, 0x20, 0xfe, 0xa8, 0xa7, 0xdc, 0x26, 0x88, 0x7f, 0xb3, + 0x4a, 0x60, 0xf9, 0xfd, 0xe2, 0x2d, 0x69, 0x8c, 0xf7, 0xb9, 0x20, 0x8e, + 0x5a, 0x2b, 0xf2, 0x4c, 0x10, 0x3f, 0xd3, 0x38, 0xd2, 0x4b, 0x41, 0xfc, + 0xb2, 0x48, 0xb1, 0xc3, 0x1b, 0x41, 0xfc, 0x46, 0x9f, 0x6c, 0x79, 0x2f, + 0x88, 0xdf, 0xa9, 0x09, 0xaa, 0xbf, 0x64, 0xbc, 0xe8, 0x71, 0xb4, 0xe8, + 0xef, 0x4b, 0xa7, 0x62, 0x0f, 0xf4, 0xbc, 0x10, 0x4b, 0x62, 0xd4, 0xe7, + 0x8b, 0x5e, 0xcb, 0x6b, 0x3c, 0xa6, 0x46, 0x1e, 0x77, 0x7a, 0x57, 0xf4, + 0x87, 0x0c, 0xa3, 0x0e, 0xda, 0xfb, 0x48, 0xa9, 0x86, 0x0e, 0x7a, 0x5d, + 0xe4, 0x11, 0x70, 0x1d, 0x34, 0xeb, 0x49, 0xa8, 0x83, 0x96, 0x28, 0x76, + 0xea, 0x2c, 0xe9, 0xe6, 0x9d, 0x0f, 0x27, 0x7d, 0x8c, 0xe7, 0x8d, 0xf0, + 0x61, 0xee, 0xe4, 0xbb, 0xf7, 0xc2, 0x87, 0x73, 0x2b, 0xdf, 0x7d, 0xb0, + 0xa0, 0x98, 0xfe, 0x62, 0xb2, 0x1c, 0x48, 0x12, 0x28, 0xeb, 0x65, 0x6d, + 0x39, 0x49, 0x14, 0xad, 0x93, 0xb5, 0xc9, 0xaf, 0x26, 0x46, 0x89, 0x65, + 0x3f, 0x2b, 0x4b, 0xd0, 0x48, 0x99, 0x98, 0xbb, 0xeb, 0x20, 0x49, 0xe6, + 0xac, 0x88, 0x3b, 0x79, 0x26, 0x67, 0x56, 0xc4, 0xad, 0x18, 0xc6, 0xb3, + 0x15, 0xb8, 0xcb, 0x17, 0x8b, 0x21, 0x4e, 0xf6, 0x85, 0x20, 0x8e, 0xf6, + 0x85, 0x20, 0x1e, 0xec, 0x0b, 0x41, 0xac, 0x73, 0x6c, 0x14, 0xb1, 0xce, + 0x71, 0x54, 0xc4, 0x3a, 0xc7, 0x49, 0x11, 0xeb, 0x1c, 0xb3, 0x21, 0x16, + 0x3a, 0xcc, 0x86, 0x58, 0x9e, 0x8a, 0x9a, 0x3b, 0x45, 0x2c, 0x0f, 0x69, + 0x49, 0x9c, 0x3e, 0xca, 0x6c, 0xde, 0xe9, 0x09, 0xfe, 0x4c, 0x32, 0xe2, + 0x8b, 0x9a, 0x1a, 0x2f, 0x05, 0xb0, 0x69, 0x80, 0xef, 0x8d, 0x2e, 0x33, + 0xc9, 0x83, 0x81, 0xef, 0xd5, 0xd6, 0x78, 0x2e, 0x75, 0x73, 0x3b, 0xe2, + 0x1d, 0xf0, 0x4a, 0xc8, 0xb5, 0x6a, 0xe9, 0xce, 0x5b, 0x21, 0x97, 0x3c, + 0xc6, 0xa5, 0xcc, 0xa8, 0x88, 0x35, 0x31, 0x3f, 0x37, 0xf6, 0xf3, 0xdf, + 0xc5, 0xa2, 0x84, 0x2f, 0x2d, 0xa8, 0xb8, 0x02, 0x71, 0x30, 0x63, 0xe5, + 0x7d, 0x41, 0x95, 0xaa, 0x21, 0x16, 0x5e, 0x6b, 0x0c, 0xb1, 0x60, 0x1b, + 0x0d, 0xb1, 0x16, 0xfe, 0x1a, 0xe2, 0x26, 0x99, 0xed, 0xf2, 0xcc, 0x22, + 0x93, 0x19, 0x88, 0x83, 0x45, 0x96, 0xdf, 0x58, 0xc4, 0x79, 0x01, 0xe2, + 0xde, 0x22, 0xd0, 0x1f, 0x50, 0x9a, 0x04, 0xc4, 0x30, 0x6f, 0xf4, 0xc1, + 0xb3, 0x64, 0x5f, 0x45, 0x0b, 0x6f, 0x8e, 0x40, 0x1c, 0x8a, 0x7e, 0xf5, + 0xd2, 0x1c, 0xa0, 0x0c, 0xc4, 0x9d, 0xb9, 0x41, 0xef, 0xcd, 0x02, 0x9a, + 0x81, 0xb8, 0x31, 0x37, 0x69, 0x35, 0xcf, 0x48, 0x7a, 0x6d, 0x05, 0x0f, + 0x6a, 0xb5, 0x52, 0x6d, 0x25, 0xbc, 0xbd, 0x99, 0x15, 0xa9, 0xbf, 0xd5, + 0x62, 0x62, 0xa8, 0x75, 0x84, 0x5a, 0x38, 0x65, 0xf6, 0x9f, 0x05, 0x55, + 0xd5, 0x48, 0xca, 0x16, 0x77, 0x16, 0xa1, 0x41, 0xc5, 0xfc, 0xb8, 0x7f, + 0x39, 0x5b, 0x58, 0x7a, 0x6a, 0xe4, 0x19, 0x37, 0x0d, 0x55, 0xcb, 0x83, + 0x58, 0x2b, 0x11, 0xb7, 0x30, 0xb0, 0x4c, 0x04, 0x1b, 0x22, 0x4e, 0x78, + 0x3a, 0x4b, 0x21, 0x23, 0x11, 0x0f, 0x5a, 0xb0, 0xbf, 0xf1, 0x59, 0x06, + 0x57, 0x7d, 0x7e, 0x0a, 0xe0, 0xd4, 0xd0, 0x2f, 0xda, 0x02, 0x15, 0x96, + 0x0c, 0xa5, 0x1d, 0x13, 0x23, 0x3a, 0x40, 0xcd, 0xd5, 0x98, 0x38, 0x3b, + 0x64, 0x3e, 0x92, 0x8b, 0x0e, 0x6e, 0x42, 0x4d, 0xe8, 0x30, 0xd7, 0x57, + 0xd6, 0x58, 0xe4, 0x7d, 0x44, 0x87, 0xb9, 0x46, 0xeb, 0xb5, 0x83, 0x57, + 0x7a, 0x65, 0x74, 0x58, 0x6a, 0x2a, 0xc6, 0x3a, 0x4c, 0xe8, 0xb0, 0x54, + 0x2b, 0x2d, 0x00, 0xa5, 0x75, 0xc0, 0x23, 0x69, 0x46, 0x11, 0x52, 0xd4, + 0x50, 0xf6, 0xf8, 0x02, 0x29, 0x0c, 0x76, 0x98, 0xd0, 0xa1, 0xbe, 0x79, + 0x07, 0x1d, 0x26, 0x74, 0xe0, 0x03, 0x08, 0xf5, 0x67, 0x03, 0xd0, 0x21, + 0xa3, 0x43, 0x7d, 0xfd, 0x33, 0x3a, 0x64, 0x74, 0x60, 0xae, 0xcc, 0xdf, + 0x9d, 0x35, 0xa1, 0x03, 0x7f, 0xd7, 0xee, 0xfa, 0xcd, 0xb9, 0xda, 0xe1, + 0x2d, 0x5e, 0x18, 0xfd, 0x11, 0x71, 0x7b, 0x11, 0x65, 0xed, 0xf0, 0x0c, + 0xef, 0x98, 0x78, 0x83, 0x12, 0x86, 0x05, 0x25, 0x0f, 0xbb, 0xae, 0x5b, + 0xb4, 0xc3, 0x53, 0x3c, 0x4b, 0xf7, 0x1a, 0xef, 0x7e, 0xda, 0xd5, 0x86, + 0x3d, 0x6c, 0x37, 0x20, 0x6f, 0xf0, 0xc4, 0x0e, 0x03, 0xd1, 0x52, 0xea, + 0x87, 0xef, 0xc3, 0xd4, 0x33, 0x17, 0xf5, 0xa3, 0x1d, 0x46, 0xfc, 0xf8, + 0x49, 0x8e, 0xf6, 0xa3, 0x5b, 0x4b, 0x6f, 0xbf, 0x5d, 0x2b, 0x0e, 0xe3, + 0x2b, 0xed, 0x10, 0x25, 0xfd, 0x51, 0xbc, 0x9e, 0x86, 0x05, 0x36, 0x57, + 0x6b, 0x61, 0xcd, 0x1f, 0x6b, 0xe7, 0x36, 0xe6, 0x83, 0xc6, 0x2b, 0x32, + 0x45, 0x74, 0x00, 0xca, 0x33, 0x81, 0x17, 0xdf, 0x01, 0xa0, 0x1c, 0x1b, + 0x76, 0x08, 0xe8, 0x70, 0xda, 0xbb, 0x11, 0x28, 0x21, 0x61, 0x14, 0x24, + 0x8a, 0xce, 0x91, 0x2d, 0xbc, 0xe8, 0x89, 0x1d, 0x02, 0x3a, 0xf4, 0xe8, + 0xe0, 0x1c, 0x17, 0xd1, 0x81, 0x69, 0xc2, 0x2b, 0x5e, 0x65, 0x0e, 0xca, + 0xd3, 0x4a, 0xec, 0x10, 0xd0, 0x81, 0x62, 0xd0, 0xb0, 0x43, 0x44, 0x87, + 0x01, 0x1d, 0x2e, 0x05, 0x68, 0xac, 0xe5, 0x46, 0x5e, 0xef, 0xc8, 0x0e, + 0x01, 0x1d, 0x28, 0x9b, 0x0d, 0x3b, 0xc4, 0x52, 0x8d, 0x16, 0x98, 0x81, + 0x6e, 0x01, 0x6a, 0x87, 0x01, 0x1d, 0x3a, 0x64, 0xc9, 0x2c, 0x8f, 0x68, + 0x6a, 0x9c, 0xda, 0xa0, 0x39, 0x08, 0xb7, 0xcb, 0xe8, 0x29, 0xbb, 0x4a, + 0xe3, 0xa2, 0x4a, 0x23, 0xd5, 0xd1, 0x61, 0x03, 0x8a, 0xd7, 0x77, 0x7a, + 0x3a, 0xd0, 0xc5, 0xc5, 0xdf, 0x42, 0xe9, 0x2c, 0x53, 0x8b, 0xb4, 0x44, + 0x10, 0x54, 0x6c, 0xd6, 0x1e, 0x11, 0x2a, 0xe1, 0xd0, 0x95, 0xde, 0xf6, + 0x4a, 0x23, 0xf1, 0xec, 0x24, 0x26, 0x26, 0xdb, 0x12, 0x43, 0x0d, 0x91, + 0xfa, 0x26, 0x14, 0x3c, 0x3c, 0xfa, 0x23, 0x49, 0xfe, 0x86, 0xca, 0xcb, + 0xf3, 0x79, 0x9e, 0xe1, 0xfb, 0x8d, 0xb1, 0x86, 0xea, 0x1c, 0x26, 0x2e, + 0xfd, 0x39, 0x6d, 0xb7, 0x57, 0x87, 0xac, 0x31, 0xb5, 0x60, 0xcd, 0x2c, + 0x73, 0x3b, 0x2f, 0x83, 0x16, 0xe9, 0x92, 0x86, 0x23, 0xf9, 0xed, 0x3b, + 0xa2, 0x7f, 0x24, 0xa2, 0x2f, 0xe3, 0x23, 0x67, 0xc8, 0xf7, 0x34, 0xf9, + 0xbd, 0xf4, 0xa1, 0x86, 0x36, 0x12, 0x39, 0x3b, 0xd0, 0xd4, 0x67, 0x09, + 0x45, 0x31, 0xff, 0x2f, 0x1e, 0x44, 0x64, 0x2a, 0x28, 0xbc, 0x90, 0x73, + 0x42, 0xa3, 0xba, 0x72, 0x92, 0xe8, 0xc1, 0x34, 0x33, 0xb5, 0xec, 0x3f, + 0x47, 0xe7, 0x25, 0x1d, 0x5e, 0xe4, 0xb1, 0x56, 0xa1, 0xf5, 0x42, 0x10, + 0xd7, 0xf7, 0x7e, 0x88, 0x55, 0xe9, 0x0f, 0x6c, 0x50, 0x1f, 0x1f, 0xe2, + 0x76, 0x91, 0x0d, 0x5a, 0x0b, 0xb4, 0x68, 0xa0, 0x62, 0x72, 0x03, 0x50, + 0x63, 0x1f, 0xcb, 0x33, 0x93, 0xa8, 0x3c, 0xbd, 0xbd, 0x54, 0xc5, 0x0f, + 0x0f, 0x4c, 0xcc, 0x7f, 0xbd, 0x64, 0x62, 0x3d, 0x0a, 0xb5, 0x8a, 0x3f, + 0xc5, 0xc2, 0xd7, 0xf3, 0xd7, 0x2a, 0x51, 0x2e, 0xd8, 0xeb, 0x47, 0x67, + 0x20, 0xf1, 0xf7, 0xa7, 0x6f, 0x81, 0xdf, 0xf0, 0x04, 0xfb, 0x19, 0xe6, + 0x9d, 0x17, 0xac, 0x7e, 0xe0, 0xbc, 0x5e, 0x16, 0x44, 0x47, 0x53, 0x29, + 0x97, 0xa5, 0xb2, 0xaf, 0xb0, 0x55, 0x5e, 0x44, 0xfb, 0x2b, 0x0b, 0x58, + 0x9e, 0x57, 0x73, 0xc8, 0x2b, 0x73, 0x78, 0x62, 0x78, 0x00, 0x73, 0xa9, + 0xf6, 0x8f, 0x9f, 0x42, 0x5e, 0x80, 0xe2, 0x55, 0x2b, 0x7f, 0x2c, 0x12, + 0x3f, 0x06, 0xaf, 0x96, 0xe3, 0x0a, 0x34, 0x62, 0x39, 0xdd, 0x99, 0x26, + 0x3d, 0x69, 0x52, 0xea, 0x8f, 0xb0, 0xf9, 0xaf, 0xb2, 0xf9, 0x23, 0x4a, + 0x4f, 0x71, 0xf5, 0x32, 0xdf, 0x9f, 0x70, 0xf5, 0xdd, 0x51, 0x63, 0x47, + 0x00, 0xdc, 0xe2, 0x09, 0x48, 0xfc, 0x41, 0x03, 0x5a, 0x58, 0x5e, 0xb9, + 0x5f, 0x6d, 0x09, 0x2f, 0x76, 0x4a, 0x58, 0x7c, 0x87, 0xb5, 0x9b, 0x13, + 0x60, 0xcc, 0xa6, 0xf1, 0x07, 0xc6, 0x51, 0x6a, 0xe5, 0x8c, 0x97, 0xdb, + 0x78, 0x71, 0x4d, 0x02, 0x9f, 0x7a, 0xfd, 0xcd, 0x77, 0x24, 0x7f, 0x65, + 0x24, 0xd6, 0xfd, 0x6f, 0x6d, 0xea, 0xac, 0x97, 0xa6, 0x8e, 0xfd, 0x02, + 0xcc, 0xa7, 0x4c, 0x9d, 0xf0, 0xdd, 0xd4, 0xf9, 0x8e, 0xe8, 0xdb, 0x21, + 0xfa, 0x3a, 0xa6, 0x4e, 0xfb, 0x17, 0x34, 0x75, 0xd6, 0x07, 0x98, 0x3a, + 0x17, 0x29, 0xca, 0x08, 0xaa, 0x9c, 0x4c, 0x9d, 0xd5, 0x75, 0x4d, 0x43, + 0x10, 0x35, 0x1b, 0xf4, 0xd6, 0x8e, 0x1e, 0xfa, 0x2a, 0x40, 0xd9, 0x09, + 0x8a, 0x91, 0x6a, 0x0b, 0x9d, 0x5c, 0xa9, 0x45, 0x76, 0x1a, 0x88, 0xa9, + 0xa3, 0x6e, 0x6c, 0xa8, 0x13, 0x5d, 0xed, 0x35, 0xfc, 0x79, 0x2c, 0xe9, + 0xd4, 0xb0, 0xd3, 0xc8, 0x4e, 0x23, 0x3b, 0x4d, 0xec, 0x94, 0xd9, 0x89, + 0x8d, 0xc8, 0x37, 0xa4, 0x0c, 0x54, 0xaa, 0x1d, 0x50, 0x37, 0xcd, 0xff, + 0x63, 0xe3, 0x7f, 0xb2, 0xd1, 0x55, 0x67, 0xb5, 0xb9, 0x24, 0x51, 0xcd, + 0xb5, 0xd2, 0xed, 0x66, 0xdc, 0xac, 0x54, 0xdf, 0xfe, 0x41, 0x0f, 0x9d, + 0x7f, 0xe6, 0x8d, 0x02, 0x40, 0x74, 0x68, 0xe0, 0x05, 0xb5, 0xbc, 0x61, + 0xa6, 0x22, 0xcf, 0xdc, 0x53, 0x7f, 0xd0, 0xf7, 0x21, 0x0f, 0xa6, 0x7f, + 0xb6, 0xd1, 0x1c, 0x12, 0x8f, 0x7f, 0x5c, 0x63, 0xb9, 0xd3, 0x78, 0xc8, + 0x0c, 0x8f, 0xeb, 0x3a, 0x2d, 0xd9, 0x89, 0x10, 0xae, 0x08, 0x45, 0xd2, + 0xf5, 0x27, 0xf2, 0x9e, 0x28, 0x7f, 0xb5, 0x29, 0x5f, 0xf4, 0x40, 0x39, + 0x59, 0x62, 0xbd, 0x62, 0x92, 0x3b, 0x8d, 0xcb, 0xb4, 0xf9, 0x75, 0xc3, + 0xd3, 0xe6, 0x9f, 0x68, 0x4c, 0xda, 0xb8, 0x99, 0x51, 0xf7, 0x46, 0x6e, + 0xb0, 0xf6, 0xeb, 0xc6, 0x75, 0x6a, 0xfd, 0x21, 0xc9, 0xf6, 0x87, 0x64, + 0xdd, 0x1f, 0x93, 0x7e, 0xf7, 0x46, 0x7c, 0x54, 0x42, 0xde, 0x1b, 0x9f, + 0xc8, 0xcc, 0x7f, 0x22, 0x45, 0x7f, 0xdd, 0xb8, 0x16, 0xa2, 0x63, 0xe3, + 0x5e, 0xd2, 0xbe, 0x3d, 0xb0, 0xfa, 0x27, 0xde, 0x9d, 0x50, 0xfc, 0xd8, + 0x69, 0x2c, 0xce, 0x6e, 0x3a, 0xd3, 0x1f, 0x8a, 0x60, 0x96, 0x51, 0xd5, + 0x59, 0x34, 0x06, 0x33, 0x6d, 0xec, 0xee, 0x25, 0x63, 0x7a, 0x4b, 0x3d, + 0x06, 0x03, 0x98, 0x13, 0x07, 0x07, 0x4f, 0x82, 0xd9, 0x0f, 0x02, 0x1c, + 0x16, 0xd9, 0xcf, 0x8a, 0x04, 0x36, 0x0e, 0x60, 0xf0, 0x0e, 0xfc, 0x2f, + 0x52, 0x21, 0xa1, 0x4f, 0x79, 0x2e, 0x4d, 0x22, 0x9b, 0x1b, 0xcb, 0xae, + 0x72, 0xb2, 0xbd, 0x5a, 0x03, 0x1c, 0x4a, 0xd6, 0x95, 0x98, 0x89, 0x17, + 0xf0, 0x8a, 0xfa, 0x96, 0xaf, 0xa8, 0x8f, 0x78, 0x25, 0x4c, 0xaf, 0x2e, + 0xd3, 0x04, 0x79, 0x37, 0xcf, 0x2c, 0xc0, 0x55, 0xfb, 0x05, 0x36, 0xab, + 0xbd, 0xe5, 0xbe, 0xc7, 0x6f, 0x43, 0x37, 0xfc, 0xa5, 0x8f, 0x80, 0x17, + 0xcd, 0x74, 0x7c, 0x11, 0x4e, 0x82, 0x79, 0xfd, 0xef, 0xd5, 0xde, 0xee, + 0x78, 0x82, 0x44, 0x00, 0x7a, 0x9e, 0x3b, 0x24, 0x6a, 0x00, 0xc0, 0xa9, + 0x1c, 0x01, 0xe8, 0x09, 0x48, 0x00, 0x0c, 0xe7, 0x7d, 0x40, 0xd6, 0xd3, + 0xf2, 0x97, 0xc0, 0x75, 0x09, 0x88, 0x00, 0x74, 0xb7, 0x00, 0x1b, 0x01, + 0xf9, 0xcb, 0x00, 0x01, 0x80, 0xf6, 0xcb, 0x01, 0x0d, 0x01, 0xc3, 0x01, + 0x70, 0xb1, 0x96, 0x0b, 0x00, 0x57, 0x7b, 0xb5, 0x7c, 0x7f, 0x4f, 0x16, + 0x49, 0x99, 0x01, 0x58, 0x09, 0x98, 0x00, 0xb8, 0x22, 0xf6, 0x2c, 0xaf, + 0xda, 0xb6, 0xf4, 0x96, 0xa5, 0x4e, 0xa6, 0x00, 0xc9, 0x49, 0x1e, 0x86, + 0x5e, 0x2b, 0x2f, 0x9b, 0x70, 0xcc, 0xb0, 0xbb, 0x4c, 0x90, 0x3e, 0xd2, + 0xfd, 0x4f, 0x88, 0x07, 0xbc, 0x45, 0xcf, 0xdf, 0xd8, 0xf3, 0x79, 0xf1, + 0x08, 0xc5, 0xa4, 0xca, 0x25, 0xc1, 0xf3, 0x78, 0x09, 0x26, 0xe4, 0xaf, + 0xac, 0x1c, 0x7f, 0xb9, 0x22, 0xc3, 0x5c, 0x33, 0xc5, 0x32, 0xc0, 0xdd, + 0x7e, 0x0d, 0xd3, 0xc9, 0xde, 0x21, 0x90, 0x90, 0xe0, 0x0f, 0xc5, 0x7e, + 0xc2, 0x39, 0x14, 0x3e, 0x95, 0x59, 0xcf, 0x07, 0x4f, 0x2a, 0xf8, 0x19, + 0x00, 0x29, 0x9a, 0x5c, 0xee, 0x0c, 0x70, 0x48, 0x05, 0x44, 0x1b, 0x59, + 0x6d, 0xd1, 0x68, 0x1d, 0x6a, 0xb2, 0x49, 0x87, 0x4c, 0x4d, 0x8d, 0x37, + 0xf5, 0xdc, 0x98, 0x58, 0xa9, 0x0c, 0x93, 0x26, 0xe5, 0xc6, 0x4d, 0x91, + 0x3f, 0xf7, 0xb3, 0x55, 0x51, 0x8c, 0x55, 0x9c, 0x30, 0x5b, 0xe5, 0x44, + 0xfa, 0xbd, 0x5d, 0x15, 0x3b, 0x72, 0x57, 0x06, 0xcb, 0x7c, 0x1f, 0xfe, + 0x7d, 0xf8, 0xf7, 0xe1, 0x77, 0x87, 0x97, 0x9a, 0xce, 0xb6, 0x7f, 0x16, + 0x45, 0xe7, 0x99, 0x3d, 0xd3, 0x29, 0xd3, 0x41, 0xa7, 0x9a, 0x82, 0x6a, + 0xa0, 0x54, 0xb6, 0xe6, 0x10, 0xd7, 0xfe, 0x8e, 0xe6, 0x3b, 0x9a, 0x7f, + 0x2d, 0x34, 0x81, 0x68, 0x22, 0xd1, 0x24, 0x36, 0x0a, 0xf0, 0xb5, 0x8c, + 0x34, 0x7a, 0xd2, 0x83, 0x16, 0x03, 0x6c, 0x8a, 0x49, 0x47, 0x3f, 0x63, + 0x80, 0x27, 0xc2, 0x1e, 0xb1, 0xd8, 0x4f, 0xa7, 0x46, 0x70, 0x39, 0xb8, + 0x10, 0x41, 0xcd, 0x8a, 0x8d, 0xa1, 0x1f, 0x73, 0x00, 0x3b, 0x18, 0x04, + 0x5a, 0xfc, 0xa0, 0x66, 0x29, 0x0d, 0x8b, 0x8b, 0x67, 0x92, 0x6d, 0xda, + 0x6c, 0xd0, 0xb4, 0xf0, 0xc0, 0xcf, 0xe1, 0x81, 0x55, 0x34, 0x68, 0x5c, + 0x6c, 0x87, 0xf0, 0x6f, 0x24, 0x39, 0x22, 0xa9, 0xe0, 0xa4, 0x0b, 0xa0, + 0x98, 0xe7, 0xde, 0xab, 0xa1, 0xe1, 0x66, 0x5c, 0x63, 0xbf, 0xcb, 0xe3, + 0xe1, 0x21, 0x35, 0xcc, 0x84, 0x4a, 0xbf, 0x16, 0x94, 0x28, 0xfe, 0xe6, + 0x49, 0x89, 0xc4, 0x74, 0xd9, 0xcb, 0x82, 0xe2, 0xcd, 0x5f, 0x68, 0xc7, + 0x2c, 0x05, 0x95, 0x9e, 0xf6, 0x83, 0x57, 0x72, 0xc7, 0x1f, 0x0b, 0xaa, + 0x12, 0x5f, 0x9b, 0x2a, 0xd4, 0x64, 0xd6, 0xd2, 0xc0, 0xb3, 0xd8, 0x0c, + 0x65, 0xcf, 0xa2, 0x81, 0x9f, 0xb8, 0xb7, 0x73, 0xc4, 0xb6, 0xcb, 0x93, + 0x18, 0xda, 0x49, 0x1c, 0x93, 0x49, 0x51, 0x8e, 0x0c, 0xf2, 0xe5, 0x88, + 0x4d, 0x5d, 0x7a, 0x2c, 0x79, 0x6d, 0xb9, 0x87, 0x0d, 0x4d, 0xc9, 0x29, + 0xc0, 0xea, 0xb2, 0x5f, 0x53, 0x54, 0x38, 0xac, 0xca, 0xcd, 0xa2, 0x50, + 0x32, 0x78, 0x80, 0x87, 0x92, 0x3b, 0xfa, 0x2e, 0x0d, 0xbd, 0x1a, 0xed, + 0xa8, 0x28, 0x7b, 0xa4, 0x91, 0x26, 0xbb, 0x8b, 0xf9, 0x5b, 0xcb, 0xa1, + 0x53, 0xb0, 0x0d, 0x9f, 0xac, 0x27, 0xea, 0x7e, 0xb2, 0xdd, 0x45, 0x7a, + 0x0e, 0xe6, 0xbb, 0xd5, 0x4e, 0x06, 0xee, 0x58, 0xb0, 0xd5, 0xc0, 0xa7, + 0x1b, 0x75, 0x48, 0x0b, 0x83, 0xd5, 0x3b, 0x8d, 0x1a, 0x2c, 0x6b, 0x61, + 0x56, 0x4e, 0x76, 0x73, 0xb3, 0x3e, 0x37, 0x9b, 0x45, 0x0f, 0x5f, 0x4d, + 0x3a, 0x4d, 0xf6, 0x27, 0xc9, 0x32, 0xa4, 0xa7, 0xce, 0x22, 0x98, 0x6f, + 0x68, 0x8b, 0xee, 0xd0, 0x49, 0xe2, 0x04, 0xca, 0x3a, 0xf5, 0xe5, 0xf9, + 0x16, 0x96, 0xeb, 0x2c, 0x75, 0xa5, 0xac, 0x3f, 0xb7, 0x74, 0xde, 0x0c, + 0x65, 0xaf, 0xbc, 0x6a, 0xb2, 0x34, 0xe9, 0x52, 0xe4, 0x2e, 0x1d, 0x62, + 0xfc, 0x5b, 0x43, 0xa9, 0x1a, 0x23, 0xe4, 0x36, 0xf3, 0xd5, 0xfe, 0x4b, + 0x47, 0x69, 0x6f, 0x28, 0xc1, 0x53, 0x42, 0xa7, 0x39, 0x80, 0x67, 0x57, + 0x43, 0xd9, 0x6b, 0x36, 0x74, 0xb2, 0xbb, 0x24, 0xd4, 0x81, 0x2d, 0xec, + 0xb4, 0x19, 0xca, 0x4e, 0x85, 0xce, 0x18, 0x38, 0xd3, 0x93, 0x5e, 0xec, + 0xbe, 0x03, 0xdf, 0xb6, 0xdb, 0x69, 0x95, 0x69, 0xa3, 0x08, 0xec, 0x67, + 0xe7, 0xe5, 0x2e, 0x89, 0x96, 0xb7, 0xa1, 0x6c, 0x55, 0x0b, 0x58, 0x27, + 0xbc, 0xfa, 0x77, 0x10, 0x77, 0x25, 0x1b, 0x82, 0xe7, 0x05, 0x51, 0xd3, + 0xb7, 0xf4, 0xe4, 0x3e, 0xb2, 0x53, 0xa9, 0x8e, 0xa2, 0x1d, 0xfd, 0xa9, + 0x9c, 0x43, 0xab, 0xfd, 0x45, 0xa7, 0xdc, 0x40, 0x43, 0xb9, 0x2f, 0xb6, + 0x99, 0x20, 0x52, 0x26, 0x2f, 0x3a, 0x79, 0x66, 0x48, 0x51, 0xb6, 0x44, + 0xa9, 0x77, 0x99, 0x78, 0x17, 0xef, 0xe4, 0xc2, 0xad, 0x28, 0x15, 0xc1, + 0xc8, 0xbb, 0x64, 0xde, 0xc5, 0x3b, 0x99, 0x8b, 0x17, 0x88, 0xb2, 0x27, + 0x4a, 0xcf, 0x48, 0xc9, 0x5d, 0xbc, 0x93, 0xa1, 0xec, 0x5c, 0x73, 0x10, + 0x65, 0xf5, 0x5a, 0x86, 0x63, 0xa7, 0x86, 0x08, 0x26, 0x22, 0x98, 0x79, + 0x97, 0x9a, 0xf7, 0xf2, 0x4e, 0x23, 0x11, 0x64, 0x22, 0x00, 0xef, 0xc8, + 0xc8, 0x0c, 0x5a, 0x8e, 0xd2, 0x75, 0x84, 0x32, 0x17, 0x04, 0x1b, 0x36, + 0x47, 0x3d, 0xc2, 0x05, 0x5b, 0xa6, 0xc2, 0x9b, 0xe5, 0xcf, 0x07, 0x88, + 0xb4, 0xfe, 0x79, 0x03, 0x05, 0xae, 0x7f, 0x9e, 0xd9, 0x10, 0xfd, 0xb3, + 0x25, 0x1b, 0x32, 0xfb, 0x10, 0xca, 0xd0, 0xcf, 0xc5, 0xea, 0xae, 0xc0, + 0x27, 0x90, 0x73, 0xe1, 0x1e, 0x65, 0xb1, 0x64, 0x7f, 0x66, 0xf8, 0x9b, + 0xfa, 0xe7, 0x05, 0x86, 0xe8, 0x9f, 0xc1, 0xa4, 0xf3, 0x30, 0x04, 0x21, + 0xe6, 0x5c, 0xac, 0xac, 0x72, 0x06, 0x07, 0x4f, 0x16, 0xcf, 0xe3, 0x7b, + 0x9e, 0xa3, 0xfd, 0x31, 0x6e, 0x47, 0xc0, 0x31, 0xa7, 0xc3, 0x90, 0x1f, + 0x4c, 0x6f, 0x1c, 0x86, 0x24, 0xd3, 0x1d, 0x2a, 0x45, 0x2d, 0x82, 0x76, + 0x2a, 0x5b, 0x3d, 0xa2, 0x3a, 0x4a, 0xcb, 0x60, 0x7f, 0xec, 0xa5, 0xd0, + 0xc9, 0xfe, 0xcc, 0x03, 0x0e, 0x2b, 0x1d, 0x12, 0x4d, 0x59, 0xad, 0x3e, + 0x24, 0x9a, 0x9a, 0x31, 0xd1, 0x2d, 0xa6, 0x57, 0x32, 0x86, 0xd8, 0x6f, + 0x70, 0x04, 0x4b, 0x51, 0xac, 0xaa, 0x39, 0x92, 0x85, 0xa2, 0xe4, 0xec, + 0xd2, 0x97, 0x4a, 0xb7, 0x05, 0x5a, 0xa6, 0x37, 0x35, 0xaa, 0xba, 0x47, + 0x87, 0x04, 0x8b, 0x56, 0xad, 0x1c, 0x22, 0x2a, 0x68, 0x3e, 0x0e, 0x91, + 0xc2, 0x09, 0x0b, 0x55, 0xf4, 0x50, 0x4b, 0xb1, 0x40, 0xf5, 0x44, 0xd5, + 0xd2, 0x18, 0x6b, 0xba, 0xdb, 0xc6, 0x76, 0xaa, 0xd1, 0xdf, 0x9a, 0x5e, + 0xb2, 0x21, 0xcf, 0x65, 0x88, 0xe9, 0xb7, 0xb2, 0xea, 0x10, 0x89, 0x76, + 0x65, 0x29, 0xf6, 0x96, 0x19, 0x4a, 0x42, 0x7e, 0x94, 0x7a, 0x70, 0x5d, + 0x54, 0xaf, 0xe7, 0x47, 0x34, 0xdd, 0x15, 0xe4, 0x54, 0x59, 0xd3, 0xa6, + 0x74, 0x48, 0x56, 0xb3, 0xac, 0x74, 0x68, 0xf5, 0x70, 0x79, 0x2a, 0x43, + 0x40, 0xa8, 0x2d, 0xc8, 0x10, 0xa9, 0xcc, 0x5d, 0xf5, 0x47, 0x1d, 0x1a, + 0x4b, 0xf9, 0xcc, 0x52, 0xee, 0xbd, 0x76, 0x16, 0xf3, 0xdd, 0x69, 0xfb, + 0xc4, 0x36, 0x48, 0x70, 0x88, 0x0a, 0x53, 0xbd, 0x36, 0x68, 0x75, 0x76, + 0x34, 0x6d, 0xa7, 0x9b, 0x3e, 0x69, 0x21, 0x36, 0x36, 0xbd, 0x13, 0x88, + 0xd6, 0x0b, 0xfe, 0xa0, 0x15, 0xdd, 0x32, 0xfd, 0x5e, 0xdf, 0x8f, 0x10, + 0x84, 0x0d, 0x46, 0x59, 0xdc, 0x3e, 0x24, 0xd9, 0x0f, 0x87, 0xec, 0x08, + 0xd3, 0xd6, 0x9a, 0x0a, 0x54, 0x6e, 0xdc, 0x0f, 0x48, 0x55, 0x8c, 0xca, + 0x8d, 0x39, 0x98, 0x26, 0x54, 0x6e, 0x1c, 0x93, 0xbd, 0xb3, 0x3c, 0x4a, + 0x5d, 0x7a, 0x2b, 0x10, 0x0d, 0xf2, 0xbd, 0x90, 0x25, 0xea, 0x3b, 0xcc, + 0x3b, 0x19, 0x32, 0x0d, 0x36, 0x64, 0x90, 0x0e, 0x4d, 0xe4, 0x90, 0x0f, + 0x12, 0xff, 0x35, 0xc1, 0x11, 0xc9, 0x9a, 0x3b, 0x53, 0x9a, 0x2a, 0x59, + 0x93, 0x94, 0xd4, 0x6b, 0x3c, 0x50, 0x2a, 0xf0, 0x83, 0xbd, 0x3f, 0x5d, + 0xca, 0xc2, 0x97, 0x26, 0x49, 0xe9, 0xa8, 0xcc, 0xf2, 0x8d, 0x54, 0x5b, + 0x7e, 0x40, 0x04, 0xe7, 0xb9, 0xec, 0xf0, 0xaf, 0x18, 0xa2, 0x11, 0x99, + 0x57, 0x36, 0x44, 0x98, 0x02, 0x7a, 0x2e, 0x81, 0x29, 0xbc, 0x7e, 0x84, + 0x81, 0x38, 0xbb, 0x0c, 0xa6, 0xb1, 0xec, 0x12, 0x0b, 0xcd, 0x38, 0x04, + 0xef, 0x6f, 0x0e, 0xe9, 0xeb, 0x10, 0x15, 0x0c, 0x1a, 0x90, 0x2a, 0x18, + 0xb0, 0x1d, 0xad, 0xa8, 0x68, 0xc1, 0x23, 0x0e, 0x3a, 0x24, 0x37, 0xb8, + 0x5c, 0x0c, 0x89, 0x3e, 0x64, 0x65, 0x98, 0xcd, 0x94, 0x68, 0x67, 0x73, + 0xb1, 0x0b, 0xc2, 0x6c, 0x76, 0x89, 0x9e, 0x9b, 0x5b, 0x3d, 0x10, 0x57, + 0x60, 0x39, 0xd4, 0x21, 0xbd, 0x0f, 0x31, 0x63, 0x73, 0x75, 0x7d, 0x9b, + 0x4c, 0x57, 0x26, 0x28, 0x1e, 0xd6, 0x56, 0xaa, 0xe2, 0xd9, 0x4c, 0xcf, + 0x6e, 0x1e, 0xb7, 0x0b, 0xb4, 0x15, 0xb3, 0xeb, 0xe4, 0x3a, 0xa4, 0x31, + 0xf1, 0xa7, 0x6a, 0x1e, 0xdc, 0x68, 0x9c, 0x3d, 0xd8, 0x1a, 0xb9, 0x09, + 0x50, 0xfc, 0xee, 0xb9, 0x9a, 0xa2, 0xee, 0x7d, 0x48, 0x76, 0x97, 0x37, + 0x32, 0xfb, 0x6f, 0x43, 0xcc, 0x14, 0x5b, 0x1a, 0x5e, 0x3a, 0x9b, 0x4b, + 0x4f, 0xb3, 0x6d, 0xb4, 0x59, 0x36, 0x9e, 0x45, 0x4c, 0x48, 0xd0, 0x61, + 0xc8, 0x7c, 0x1c, 0x32, 0x9d, 0x86, 0x04, 0x86, 0x64, 0xcd, 0x74, 0xc4, + 0x63, 0x3d, 0xd9, 0x8c, 0x07, 0x9b, 0xe5, 0x68, 0x86, 0x0b, 0x7d, 0xec, + 0x9e, 0x21, 0x68, 0x0b, 0x63, 0x2f, 0x36, 0x3a, 0xd0, 0xf4, 0x78, 0x42, + 0x73, 0x14, 0x96, 0x66, 0x54, 0xb3, 0x24, 0xd3, 0x76, 0x31, 0xe3, 0x27, + 0x0f, 0x07, 0xe3, 0x13, 0xd6, 0x53, 0x38, 0x98, 0x93, 0x33, 0x8d, 0xa6, + 0x6a, 0x45, 0x66, 0x5a, 0x5d, 0xab, 0x59, 0x5d, 0xc3, 0xc1, 0x6c, 0x5b, + 0xec, 0xbb, 0x70, 0xb0, 0xfb, 0x66, 0x5a, 0x81, 0xa6, 0x9c, 0x0d, 0x03, + 0x8c, 0xbf, 0xd5, 0xbe, 0x1b, 0xa0, 0x8f, 0x0c, 0x03, 0xac, 0x52, 0xbc, + 0x7a, 0xbf, 0x83, 0x56, 0x34, 0x0c, 0x6e, 0x17, 0xf3, 0xe5, 0xfd, 0x6b, + 0x35, 0xac, 0x13, 0x38, 0x76, 0xa1, 0xa9, 0x56, 0x3a, 0x32, 0xa1, 0x5b, + 0xed, 0x1b, 0x7f, 0x9e, 0xd0, 0x7e, 0x11, 0x1d, 0x5e, 0x11, 0x7c, 0x83, + 0x67, 0xf4, 0x1b, 0x3e, 0xfa, 0xee, 0xdb, 0x77, 0x6a, 0xd6, 0x60, 0x43, + 0x4b, 0xf5, 0x42, 0xb8, 0x47, 0x87, 0xa8, 0xb6, 0x7e, 0x57, 0xcd, 0xa8, + 0x58, 0xae, 0x0c, 0xa3, 0xc4, 0xef, 0x86, 0x72, 0x88, 0x4f, 0x7b, 0x3c, + 0xda, 0xbe, 0xf3, 0x88, 0x7d, 0xb5, 0x7e, 0xba, 0x42, 0xbb, 0x22, 0xf1, + 0x3b, 0x0f, 0x81, 0x57, 0x33, 0x26, 0x1c, 0x0d, 0x93, 0x91, 0x18, 0xec, + 0xbb, 0x1b, 0x46, 0xcb, 0xed, 0xef, 0x7c, 0xdc, 0xcc, 0xdb, 0x6c, 0xfe, + 0x5d, 0xe6, 0x77, 0x75, 0x0a, 0x13, 0xbf, 0x5b, 0x2e, 0x67, 0x3c, 0x1c, + 0x57, 0xb3, 0x71, 0xea, 0x86, 0xc1, 0x17, 0xaf, 0xb4, 0x9a, 0xf8, 0x9d, + 0x5b, 0x93, 0x27, 0x3a, 0x26, 0x62, 0xd0, 0xef, 0x32, 0x09, 0xea, 0xe9, + 0x27, 0xc5, 0xa0, 0xdf, 0x2d, 0xf6, 0xdd, 0x2b, 0xda, 0xc1, 0xef, 0x29, + 0xd5, 0x78, 0x99, 0x7f, 0x77, 0x78, 0xbf, 0xff, 0x4c, 0x17, 0x73, 0x1b, + 0xc8, 0x28, 0x3f, 0x15, 0x30, 0xca, 0x4c, 0xa1, 0xdc, 0x3a, 0xca, 0xed, + 0x98, 0xc0, 0x73, 0x73, 0x0f, 0x1d, 0x81, 0x07, 0x90, 0xed, 0xc0, 0xae, + 0x8e, 0xc6, 0x62, 0xdf, 0x05, 0xb0, 0xef, 0xd8, 0x21, 0xf7, 0x34, 0x37, + 0x48, 0x3e, 0xad, 0x26, 0x04, 0xf0, 0xb3, 0x56, 0xfb, 0x6e, 0xb0, 0x83, + 0x70, 0x35, 0x21, 0x80, 0x1f, 0x55, 0xec, 0xbb, 0xce, 0x0c, 0x98, 0xd5, + 0x84, 0x80, 0xa6, 0xd9, 0xd4, 0x00, 0xf1, 0x6a, 0x5a, 0x63, 0x30, 0x33, + 0x63, 0x64, 0xfa, 0x33, 0x9b, 0x18, 0x45, 0xcc, 0x71, 0xee, 0xa1, 0xcd, + 0xcc, 0x18, 0x50, 0x0c, 0x11, 0x0a, 0x6a, 0xed, 0xe9, 0xd5, 0xfc, 0x40, + 0x9d, 0xb3, 0x44, 0x2a, 0xea, 0xfe, 0xe4, 0x05, 0x27, 0xf1, 0x90, 0x2f, + 0xdc, 0x68, 0x4b, 0x76, 0xe4, 0x06, 0xe5, 0x97, 0x70, 0x46, 0x16, 0xd7, + 0xdb, 0x85, 0x0e, 0xf5, 0x73, 0x2a, 0xa7, 0x97, 0xc4, 0xf9, 0x86, 0x5e, + 0xd4, 0x2f, 0xee, 0x3d, 0xd3, 0x6e, 0x5e, 0x48, 0x70, 0xfc, 0x82, 0x43, + 0xc2, 0xcf, 0x45, 0x8b, 0x76, 0xed, 0xe9, 0xaa, 0x75, 0x4c, 0xb2, 0x34, + 0xd4, 0x5f, 0x63, 0xa2, 0x5f, 0x1c, 0x61, 0xf6, 0x4e, 0x03, 0x0e, 0xf6, + 0xdc, 0xd3, 0x69, 0xec, 0x70, 0x4a, 0xcd, 0x34, 0x67, 0x17, 0x53, 0xd6, + 0xe6, 0x6b, 0x16, 0xd3, 0x7a, 0x83, 0x6d, 0xc2, 0x66, 0xc4, 0x0e, 0x76, + 0xfa, 0xc2, 0xab, 0x2d, 0xd4, 0x7c, 0xc9, 0xb6, 0x73, 0xd2, 0x8e, 0x1d, + 0x8e, 0xc8, 0xb1, 0xc5, 0x06, 0x4f, 0x2d, 0xf6, 0x2f, 0x73, 0xb3, 0x16, + 0xda, 0xdc, 0xf8, 0x99, 0x8c, 0x48, 0x4f, 0x3e, 0x14, 0xfc, 0x4c, 0x49, + 0x6f, 0x99, 0x4e, 0x3b, 0x2c, 0xe8, 0xdb, 0x2f, 0xdc, 0x3d, 0x68, 0xbc, + 0xc8, 0x98, 0x42, 0x50, 0x27, 0x13, 0xfb, 0xe9, 0x67, 0x8c, 0x13, 0xd3, + 0xe3, 0x15, 0xdc, 0xce, 0x8d, 0xfe, 0xa7, 0x79, 0x03, 0x75, 0x13, 0x3b, + 0xba, 0x8f, 0xc7, 0xc8, 0x49, 0x71, 0x55, 0x48, 0xaf, 0xb3, 0xf8, 0x09, + 0x56, 0xaa, 0x72, 0x9c, 0x29, 0xae, 0x0b, 0x45, 0xd2, 0xf3, 0x8b, 0xae, + 0x1b, 0xb7, 0x86, 0xc3, 0x9a, 0xe6, 0xa0, 0x11, 0xdb, 0x0b, 0xd5, 0x38, + 0x71, 0x58, 0xe6, 0xb0, 0xcc, 0x61, 0x33, 0x87, 0x2d, 0x97, 0x0a, 0xc7, + 0xf5, 0x61, 0xa4, 0x9a, 0x09, 0x6c, 0xf4, 0xd4, 0x74, 0xee, 0xf1, 0x55, + 0xfd, 0x96, 0xe8, 0xd5, 0xb9, 0x12, 0x0c, 0x07, 0x6d, 0x38, 0x73, 0x98, + 0xdd, 0xa3, 0x65, 0xa3, 0xe1, 0xcd, 0x4c, 0x96, 0x31, 0xbe, 0xe1, 0x78, + 0x43, 0x3d, 0x10, 0x75, 0x4f, 0x8c, 0x1d, 0x31, 0x7e, 0x47, 0xf4, 0xed, + 0x11, 0x29, 0xf3, 0xe2, 0xe5, 0x29, 0x5a, 0x1c, 0xa7, 0x67, 0x87, 0x5d, + 0xca, 0xd7, 0xfa, 0xf2, 0x17, 0xbb, 0x2c, 0xe8, 0x73, 0x98, 0x2b, 0x26, + 0x88, 0xe9, 0xb5, 0x2e, 0x23, 0xdb, 0x75, 0x9f, 0xce, 0x25, 0xe9, 0xd8, + 0x27, 0x78, 0x98, 0xe6, 0xd0, 0xa7, 0x79, 0x58, 0x9f, 0xf5, 0xba, 0x4f, + 0xef, 0x27, 0xe8, 0xb1, 0x4f, 0xbc, 0xd5, 0xa7, 0x3d, 0xf7, 0x29, 0x37, + 0xfb, 0x2c, 0xd7, 0x7d, 0xee, 0x2d, 0xfa, 0x46, 0x9f, 0xee, 0x26, 0x61, + 0xc2, 0xd7, 0x25, 0x4c, 0x7f, 0x93, 0x30, 0x37, 0x17, 0x7d, 0xd5, 0xe7, + 0xf6, 0xa2, 0x6f, 0xf4, 0x19, 0x6e, 0x12, 0xe6, 0xe6, 0xa2, 0x1f, 0xc8, + 0x0d, 0x0f, 0x25, 0xcc, 0x97, 0x2c, 0xfa, 0x5e, 0x9f, 0x6f, 0xfe, 0x39, + 0x6e, 0xc1, 0x21, 0x72, 0x57, 0x4d, 0x64, 0x9d, 0xd4, 0x82, 0xc9, 0x1e, + 0xcd, 0xbd, 0xd5, 0x67, 0xbc, 0x36, 0xcc, 0xbc, 0x78, 0xc6, 0xa5, 0xe6, + 0x4a, 0xe8, 0x28, 0x5b, 0xab, 0xf7, 0x56, 0xf0, 0x56, 0xb2, 0xd6, 0xe2, + 0xf5, 0x09, 0x8b, 0x53, 0xc2, 0xeb, 0x93, 0xd4, 0xf4, 0xd2, 0xd3, 0xda, + 0x42, 0x49, 0xd9, 0x3c, 0xc9, 0x04, 0x0b, 0x6d, 0x6a, 0x99, 0xcc, 0x18, + 0x3b, 0x7a, 0xa8, 0x38, 0x41, 0x52, 0x41, 0xfd, 0x9b, 0xfa, 0x8e, 0x91, + 0x69, 0x18, 0x73, 0x28, 0x61, 0xa4, 0xad, 0xee, 0xe2, 0x98, 0x67, 0x93, + 0x7b, 0xba, 0xf4, 0x93, 0xbb, 0xa2, 0x63, 0x60, 0x30, 0x60, 0x8c, 0xee, + 0x91, 0x26, 0x78, 0x82, 0xa8, 0x54, 0x13, 0x54, 0x2d, 0xbd, 0x3a, 0x31, + 0x16, 0xcc, 0x3f, 0x9d, 0x07, 0x86, 0xb2, 0x73, 0xa0, 0xf3, 0x37, 0x45, + 0x1a, 0x0e, 0x63, 0x62, 0xb6, 0xc5, 0x1c, 0x62, 0x99, 0x71, 0xeb, 0xe8, + 0xba, 0x13, 0x3a, 0xb0, 0x1d, 0x2a, 0x56, 0x03, 0xd5, 0x2d, 0xfd, 0xeb, + 0xe6, 0x10, 0x04, 0x05, 0x3a, 0x66, 0xba, 0xb6, 0x8b, 0xfd, 0xea, 0x49, + 0x73, 0xec, 0xdc, 0xcc, 0x0d, 0x56, 0x84, 0xb6, 0x87, 0x13, 0xb7, 0x1a, + 0x91, 0xf1, 0x52, 0x68, 0x9a, 0x94, 0xea, 0x52, 0xad, 0xce, 0x39, 0x8f, + 0x9c, 0x5d, 0xd3, 0xd2, 0x52, 0xf8, 0x72, 0x74, 0x9f, 0x9c, 0xdd, 0xef, + 0x59, 0xec, 0xef, 0x9f, 0xdd, 0x17, 0xef, 0xec, 0x3d, 0x46, 0x09, 0x8e, + 0x2e, 0x3a, 0xba, 0x13, 0xdf, 0xb5, 0xce, 0x77, 0x82, 0xa4, 0xfb, 0x24, + 0x1b, 0x0f, 0xee, 0x93, 0x04, 0xf7, 0xe8, 0x4f, 0x52, 0xd1, 0x99, 0x9b, + 0x54, 0xa0, 0x21, 0x19, 0x32, 0x3a, 0x08, 0x59, 0x8b, 0x0c, 0x25, 0x02, + 0xbe, 0x1d, 0xe3, 0x60, 0x16, 0x26, 0x92, 0xd6, 0x4f, 0x05, 0x56, 0x3a, + 0x88, 0xcb, 0x96, 0x0b, 0xfe, 0xe6, 0xad, 0xc5, 0x5b, 0xb3, 0xdb, 0x09, + 0x93, 0xb7, 0x7c, 0x83, 0x56, 0x6f, 0xcd, 0x17, 0x9b, 0x16, 0xd8, 0xed, + 0xa0, 0xa0, 0xdc, 0x45, 0xad, 0xb6, 0xee, 0x21, 0x63, 0x71, 0x60, 0xc2, + 0x8e, 0x8d, 0x1e, 0x7b, 0x9b, 0xaa, 0x65, 0x4c, 0xe4, 0x53, 0xe3, 0xa9, + 0x94, 0x0e, 0x57, 0xe2, 0x8f, 0x98, 0x04, 0x26, 0xd3, 0xe2, 0xda, 0x83, + 0x8f, 0x02, 0xae, 0x11, 0x53, 0xc4, 0x8a, 0xc8, 0xa2, 0x1d, 0xae, 0x03, + 0xd6, 0x17, 0xf0, 0xeb, 0x28, 0xc6, 0x30, 0xb3, 0x6e, 0x48, 0xd1, 0xc7, + 0xc9, 0x19, 0x9c, 0xce, 0x48, 0x95, 0x21, 0xf8, 0x6d, 0xbf, 0x5e, 0x6b, + 0xce, 0x91, 0xfd, 0xba, 0xdf, 0xa0, 0x43, 0x24, 0xe4, 0x6c, 0xbf, 0xbb, + 0x18, 0x95, 0x1d, 0xc4, 0x2f, 0xca, 0xbd, 0x39, 0x4a, 0x13, 0x3c, 0x27, + 0x75, 0x73, 0x5a, 0xe5, 0x25, 0x7d, 0xe5, 0x43, 0x63, 0x3b, 0xb7, 0xb6, + 0xe6, 0x07, 0x2f, 0x5d, 0x25, 0xe0, 0x04, 0x92, 0x8e, 0x20, 0x32, 0xb8, + 0x9c, 0xe1, 0x04, 0x06, 0x50, 0xe8, 0x12, 0xf0, 0xd8, 0xf8, 0xf3, 0x86, + 0xf7, 0x20, 0xe8, 0x00, 0xfe, 0x0a, 0x60, 0x1b, 0xdb, 0x87, 0x0c, 0x39, + 0x9f, 0xb0, 0x1f, 0x63, 0x8b, 0x7d, 0xe1, 0x7e, 0xfc, 0xce, 0xe1, 0x7f, + 0xee, 0xda, 0xff, 0xf2, 0xc3, 0x8d, 0x58, 0x76, 0xd9, 0x68, 0x0f, 0x00, + 0xfc, 0xa1, 0x7c, 0xa3, 0x8f, 0x9b, 0x2c, 0x88, 0x89, 0xbc, 0xba, 0x13, + 0x13, 0x69, 0x0b, 0xa2, 0x57, 0x37, 0x62, 0x22, 0xea, 0xcf, 0x23, 0xd0, + 0x7c, 0x15, 0x13, 0x29, 0x1d, 0x75, 0xef, 0x78, 0x15, 0x13, 0x99, 0xe2, + 0x21, 0xb0, 0xa0, 0x91, 0x22, 0x8f, 0x89, 0xcc, 0x46, 0xbf, 0xa2, 0xe2, + 0xbb, 0x58, 0x28, 0x04, 0x11, 0x0a, 0xfc, 0xc8, 0x67, 0x2c, 0x28, 0xec, + 0x0f, 0x66, 0xe2, 0xa8, 0x6a, 0xf5, 0x98, 0xc8, 0xd8, 0xc2, 0x68, 0x9a, + 0x20, 0xd7, 0x88, 0x89, 0x78, 0x44, 0xb8, 0x7e, 0xef, 0x31, 0x11, 0xb9, + 0x47, 0x6b, 0xfc, 0xed, 0xc1, 0x97, 0x95, 0x37, 0x32, 0x35, 0x5d, 0x43, + 0xc4, 0x3d, 0xa7, 0xde, 0x63, 0xea, 0xa6, 0x5f, 0x30, 0xe3, 0xcc, 0x28, + 0x76, 0xb6, 0x61, 0x4e, 0x83, 0x84, 0x13, 0x6e, 0x92, 0x60, 0xb5, 0x0e, + 0x63, 0xd4, 0x6b, 0x09, 0x0c, 0x8c, 0x5b, 0x58, 0x38, 0xf0, 0x37, 0x6a, + 0x07, 0x2d, 0x03, 0x1f, 0x99, 0x77, 0x1f, 0x19, 0x62, 0x9f, 0x1a, 0x14, + 0x8a, 0x64, 0xdb, 0x03, 0x1e, 0xe7, 0x96, 0x45, 0x92, 0x61, 0x7a, 0x0f, + 0x93, 0x62, 0x44, 0xc1, 0x70, 0x2c, 0x70, 0xc3, 0x4d, 0x82, 0xc1, 0x96, + 0x6e, 0xca, 0x1f, 0x82, 0xca, 0x13, 0x87, 0x4d, 0x1c, 0x96, 0x39, 0xcc, + 0x63, 0xca, 0x0b, 0x87, 0x2d, 0xe0, 0x77, 0xbb, 0x47, 0xc7, 0x7b, 0x34, + 0xde, 0x48, 0xe5, 0xc0, 0xfc, 0x23, 0x87, 0x8d, 0x1c, 0x36, 0x71, 0x58, + 0xe6, 0xb0, 0xcc, 0x61, 0x1e, 0xd2, 0xf1, 0xdc, 0x13, 0x4d, 0xcf, 0x72, + 0x38, 0x23, 0x33, 0x0f, 0xc1, 0xb9, 0x71, 0x9d, 0xe5, 0x4a, 0xac, 0xaa, + 0xa5, 0x07, 0x21, 0xfa, 0x03, 0xe3, 0x05, 0x8f, 0x9c, 0xd1, 0x23, 0x97, + 0xf6, 0xd7, 0x0d, 0x85, 0x38, 0xa2, 0xff, 0x0f, 0x02, 0xc7, 0x66, 0x05, + 0x3b, 0xdc, 0x00, 0x00 +}; + +const GFXglyph Oswald_Medium80pt7bGlyphs[] PROGMEM = { + { 0, 1, 1, 38, 0, 0 }, // 0x20 ' ' + { 1, 21, 127, 37, 8, -126 }, // 0x21 '!' + { 335, 43, 43, 49, 4, -126 }, // 0x22 '"' + { 567, 68, 127, 80, 6, -126 }, // 0x23 '#' + { 1647, 67, 156, 76, 5, 116 }, // 0x24 '$' + { 2954, 136, 127, 149, 6, -126 }, // 0x25 '%' + { 5113, 76, 130, 92, 8, -127 }, // 0x26 '&' + { 6348, 18, 43, 23, 4, -126 }, // 0x27 ''' + { 6445, 35, 157, 50, 10, -127 }, // 0x28 '(' + { 7132, 34, 157, 46, 5, -127 }, // 0x29 ')' + { 7800, 54, 55, 64, 7, -126 }, // 0x2A '*' + { 8172, 60, 64, 68, 4, -96 }, // 0x2B '+' + { 8652, 20, 42, 33, 7, -20 }, // 0x2C ',' + { 8757, 38, 14, 49, 6, -52 }, // 0x2D '-' + { 8824, 21, 21, 34, 7, -20 }, // 0x2E '.' + { 8880, 50, 127, 62, 6, -126 }, // 0x2F '/' + { 9674, 66, 130, 84, 9, -127 }, // 0x30 '0' + { 10747, 41, 127, 60, 4, -126 }, // 0x31 '1' + { 11398, 67, 128, 78, 6, -127 }, // 0x32 '2' + { 12470, 66, 130, 78, 6, -127 }, // 0x33 '3' + { 13543, 71, 127, 79, 5, -126 }, // 0x34 '4' + { 14671, 65, 129, 77, 7, -126 }, // 0x35 '5' + { 15720, 66, 130, 82, 9, -127 }, // 0x36 '6' + { 16793, 56, 127, 65, 3, -126 }, // 0x37 '7' + { 17682, 66, 130, 80, 7, -127 }, // 0x38 '8' + { 18755, 67, 130, 82, 6, -127 }, // 0x39 '9' + { 19844, 20, 74, 37, 10, -85 }, // 0x3A ':' + { 20029, 21, 102, 39, 10, -88 }, // 0x3B ';' + { 20297, 47, 67, 60, 6, -98 }, // 0x3C '<' + { 20691, 49, 42, 67, 9, -85 }, // 0x3D '=' + { 20949, 47, 67, 60, 9, -98 }, // 0x3E '>' + { 21343, 64, 128, 76, 6, -127 }, // 0x3F '?' + { 22367, 132, 147, 145, 8, -126 }, // 0x40 '@' + { 24793, 76, 127, 82, 3, -126 }, // 0x41 'A' + { 26000, 72, 127, 87, 10, -126 }, // 0x42 'B' + { 27143, 70, 130, 85, 8, -127 }, // 0x43 'C' + { 28281, 70, 127, 87, 10, -126 }, // 0x44 'D' + { 29393, 53, 127, 67, 10, -126 }, // 0x45 'E' + { 30235, 52, 127, 65, 10, -126 }, // 0x46 'F' + { 31061, 71, 130, 88, 8, -127 }, // 0x47 'G' + { 32215, 72, 127, 92, 10, -126 }, // 0x48 'H' + { 33358, 23, 127, 43, 10, -126 }, // 0x49 'I' + { 33724, 39, 130, 51, 2, -126 }, // 0x4A 'J' + { 34358, 72, 127, 83, 10, -126 }, // 0x4B 'K' + { 35501, 53, 127, 66, 10, -126 }, // 0x4C 'L' + { 36343, 89, 127, 107, 9, -126 }, // 0x4D 'M' + { 37756, 66, 127, 85, 10, -126 }, // 0x4E 'N' + { 38804, 73, 130, 88, 8, -127 }, // 0x4F 'O' + { 39991, 69, 127, 83, 10, -126 }, // 0x50 'P' + { 41087, 73, 153, 88, 8, -127 }, // 0x51 'Q' + { 42484, 72, 127, 88, 10, -126 }, // 0x52 'R' + { 43627, 67, 130, 77, 6, -127 }, // 0x53 'S' + { 44716, 63, 127, 67, 2, -126 }, // 0x54 'T' + { 45717, 71, 129, 89, 9, -126 }, // 0x55 'U' + { 46862, 74, 127, 81, 3, -126 }, // 0x56 'V' + { 48037, 102, 127, 112, 5, -126 }, // 0x57 'W' + { 49657, 75, 127, 78, 2, -126 }, // 0x58 'X' + { 50848, 73, 127, 76, 2, -126 }, // 0x59 'Y' + { 52007, 58, 127, 67, 5, -126 }, // 0x5A 'Z' + // Euro sign ([) - ASCII code 91 + { 52928, 79, 130, 83, 0, -127 }, // 0x5B '[' + // Backslash placeholder - ASCII code 92 + { 0, 0, 0, 0, 0, 0 }, // 0x5C '\' + // Pound sign (]) - ASCII code 93 + { 54212, 63, 128, 70, 2, -127 }, // 0x5D ']' + // Yen sign (^) - ASCII code 94 + { 55220, 73, 127, 73, 1, -126 } // 0x5E '^' + }; + + +// const GFXfont Oswald_Medium80pt7b PROGMEM = { +// (uint8_t *)Oswald_Medium80pt7bBitmaps, +// (GFXglyph *)Oswald_Medium80pt7bGlyphs, +// 0x20, 0x5A, 232 }; + +// Approx. 53348 bytes +// Font properties +static constexpr FontData Oswald_Medium80pt7b_Properties = { + Oswald_Medium80pt7bBitmaps_Gzip, + Oswald_Medium80pt7bGlyphs, + sizeof(Oswald_Medium80pt7bBitmaps_Gzip), + 56626, // Original size + 0x20, // First char + 0x5E, // Last char + 232 // yAdvance +}; diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index 8849817..29d7eee 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -65,6 +65,7 @@ #define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422" #define DEFAULT_LED_FLASH_ON_ZAP true #define DEFAULT_FL_FLASH_ON_ZAP true +#define DEFAULT_FONT_NAME "antonio" #define DEFAULT_HTTP_AUTH_ENABLED false #define DEFAULT_HTTP_AUTH_USERNAME "btclock" @@ -93,3 +94,7 @@ enum DataSourceType { }; #define DEFAULT_DATA_SOURCE BTCLOCK_SOURCE + +#ifndef DEFAULT_BOOT_TEXT +#define DEFAULT_BOOT_TEXT "BTCLOCK" +#endif \ No newline at end of file diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 151b1c0..cca11a7 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -59,7 +59,7 @@ MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = { MCP23X17_Pin(mcp2, 5), MCP23X17_Pin(mcp2, 7), }; -#else +#else Native_Pin EPD_CS[NUM_SCREENS] = { Native_Pin(2), Native_Pin(4), @@ -123,10 +123,20 @@ QueueHandle_t updateQueue; int fgColor = GxEPD_WHITE; int bgColor = GxEPD_BLACK; -#define FONT_SMALL Antonio_SemiBold20pt7b -#define FONT_BIG Antonio_SemiBold90pt7b -#define FONT_MEDIUM Antonio_SemiBold40pt7b -#define FONT_SATSYMBOL Satoshi_Symbol90pt7b +struct FontFamily { + GFXfont* big; + GFXfont* medium; + GFXfont* small; +}; + +FontFamily antonioFonts = {nullptr, nullptr, nullptr}; +FontFamily oswaldFonts = {nullptr, nullptr, nullptr}; + +const GFXfont *FONT_SMALL; +const GFXfont *FONT_BIG; +const GFXfont *FONT_MEDIUM; +const GFXfont *FONT_SATSYMBOL; + std::mutex epdUpdateMutex; std::mutex epdMutex[NUM_SCREENS]; @@ -149,8 +159,83 @@ void forceFullRefresh() } } +GFXfont font90; + void setupDisplays() { + String fontName = preferences.getString("fontName", DEFAULT_FONT_NAME); // Default to antonio + + if (fontName == "antonio") + { + // Load Antonio fonts + antonioFonts.big = FontLoader::loadCompressedFont( + Antonio_SemiBold90pt7b_Properties.compressedData, + Antonio_SemiBold90pt7b_Properties.glyphs, + Antonio_SemiBold90pt7b_Properties.compressedSize, + Antonio_SemiBold90pt7b_Properties.originalSize, + Antonio_SemiBold90pt7b_Properties.first, + Antonio_SemiBold90pt7b_Properties.last, + Antonio_SemiBold90pt7b_Properties.yAdvance); + + antonioFonts.medium = FontLoader::loadCompressedFont( + Antonio_SemiBold40pt7b_Properties.compressedData, + Antonio_SemiBold40pt7b_Properties.glyphs, + Antonio_SemiBold40pt7b_Properties.compressedSize, + Antonio_SemiBold40pt7b_Properties.originalSize, + Antonio_SemiBold40pt7b_Properties.first, + Antonio_SemiBold40pt7b_Properties.last, + Antonio_SemiBold40pt7b_Properties.yAdvance); + + antonioFonts.small = FontLoader::loadCompressedFont( + Antonio_SemiBold20pt7b_Properties.compressedData, + Antonio_SemiBold20pt7b_Properties.glyphs, + Antonio_SemiBold20pt7b_Properties.compressedSize, + Antonio_SemiBold20pt7b_Properties.originalSize, + Antonio_SemiBold20pt7b_Properties.first, + Antonio_SemiBold20pt7b_Properties.last, + Antonio_SemiBold20pt7b_Properties.yAdvance); + + FONT_BIG = antonioFonts.big; + FONT_MEDIUM = antonioFonts.medium; + FONT_SMALL = antonioFonts.small; + } + else if (fontName == "oswald") + { + // Load Oswald fonts + oswaldFonts.big = FontLoader::loadCompressedFont( + Oswald_Medium80pt7b_Properties.compressedData, + Oswald_Medium80pt7b_Properties.glyphs, + Oswald_Medium80pt7b_Properties.compressedSize, + Oswald_Medium80pt7b_Properties.originalSize, + Oswald_Medium80pt7b_Properties.first, + Oswald_Medium80pt7b_Properties.last, + Oswald_Medium80pt7b_Properties.yAdvance); + + oswaldFonts.medium = FontLoader::loadCompressedFont( + Oswald_Medium30pt7b_Properties.compressedData, + Oswald_Medium30pt7b_Properties.glyphs, + Oswald_Medium30pt7b_Properties.compressedSize, + Oswald_Medium30pt7b_Properties.originalSize, + Oswald_Medium30pt7b_Properties.first, + Oswald_Medium30pt7b_Properties.last, + Oswald_Medium30pt7b_Properties.yAdvance); + + oswaldFonts.small = FontLoader::loadCompressedFont( + Oswald_Medium20pt7b_Properties.compressedData, + Oswald_Medium20pt7b_Properties.glyphs, + Oswald_Medium20pt7b_Properties.compressedSize, + Oswald_Medium20pt7b_Properties.originalSize, + Oswald_Medium20pt7b_Properties.first, + Oswald_Medium20pt7b_Properties.last, + Oswald_Medium20pt7b_Properties.yAdvance); + + FONT_BIG = oswaldFonts.big; + FONT_MEDIUM = oswaldFonts.medium; + FONT_SMALL = oswaldFonts.small; + } + + FONT_SATSYMBOL = &Satoshi_Symbol90pt7b; + std::lock_guard lockMcp(mcpMutex); for (uint i = 0; i < NUM_SCREENS; i++) @@ -160,13 +245,10 @@ void setupDisplays() updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem)); - xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", EPD_TASK_STACK_SIZE*2, NULL, 11, NULL); + xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", EPD_TASK_STACK_SIZE * 2, NULL, 11, NULL); for (uint i = 0; i < NUM_SCREENS; i++) { - // epdUpdateSemaphore[i] = xSemaphoreCreateBinary(); - // xSemaphoreGive(epdUpdateSemaphore[i]); - int *taskParam = new int; *taskParam = i; @@ -184,239 +266,255 @@ void setupDisplays() } else { - #ifdef IS_BTCLOCK_V8 - epdContent = {"B", "T", "C", "L", "O", "C", "K", "v8"}; - #else - epdContent = {"B", "T", "C", "L", "O", "C", "K"}; - #endif + // Get custom text from preferences or use default "BTCLOCK" + String customText = preferences.getString("displayText", DEFAULT_BOOT_TEXT); + + // Initialize array with spaces + std::array newContent; + newContent.fill(" "); + + // Fill in the custom text, truncating if longer than NUM_SCREENS + for (size_t i = 0; i < std::min(customText.length(), (size_t)NUM_SCREENS); i++) { + newContent[i] = String(customText[i]); + } + + epdContent = newContent; } - setEpdContent(epdContent); + setEpdContent(epdContent); } void setEpdContent(std::array newEpdContent) { - setEpdContent(newEpdContent, false); + setEpdContent(newEpdContent, false); } void setEpdContent(std::array newEpdContent) { - std::array conv; + std::array conv; - for (size_t i = 0; i < newEpdContent.size(); ++i) - { - conv[i] = String(newEpdContent[i].c_str()); - } + for (size_t i = 0; i < newEpdContent.size(); ++i) + { + conv[i] = String(newEpdContent[i].c_str()); + } - return setEpdContent(conv); + return setEpdContent(conv); } void setEpdContent(std::array newEpdContent, bool forceUpdate) { - std::lock_guard lock(epdUpdateMutex); + std::lock_guard lock(epdUpdateMutex); - waitUntilNoneBusy(); + waitUntilNoneBusy(); - for (uint i = 0; i < NUM_SCREENS; i++) - { - if (newEpdContent[i].compareTo(currentEpdContent[i]) != 0 || forceUpdate) + for (uint i = 0; i < NUM_SCREENS; i++) { - epdContent[i] = newEpdContent[i]; - UpdateDisplayTaskItem dispUpdate = {i}; - xQueueSend(updateQueue, &dispUpdate, portMAX_DELAY); + if (newEpdContent[i].compareTo(currentEpdContent[i]) != 0 || forceUpdate) + { + epdContent[i] = newEpdContent[i]; + UpdateDisplayTaskItem dispUpdate = {i}; + xQueueSend(updateQueue, &dispUpdate, portMAX_DELAY); + } } - } } void prepareDisplayUpdateTask(void *pvParameters) { - UpdateDisplayTaskItem receivedItem; + UpdateDisplayTaskItem receivedItem; - while (1) - { - // Wait for a work item to be available in the queue - if (xQueueReceive(updateQueue, &receivedItem, portMAX_DELAY)) + while (1) { - uint epdIndex = receivedItem.dispNum; - std::lock_guard lock(epdMutex[epdIndex]); - // displays[epdIndex].init(0, false); // Little longer reset duration - // because of MCP - - bool updatePartial = true; - - if (epdContent[epdIndex].length() > 1 && strstr(epdContent[epdIndex].c_str(), "/") != NULL) - { - String top = epdContent[epdIndex].substring( - 0, epdContent[epdIndex].indexOf("/")); - String bottom = epdContent[epdIndex].substring( - epdContent[epdIndex].indexOf("/") + 1); - splitText(epdIndex, top, bottom, updatePartial); - } - else if (epdContent[epdIndex].startsWith(F("qr"))) - { - renderQr(epdIndex, epdContent[epdIndex], updatePartial); - } - else if (epdContent[epdIndex].startsWith(F("mdi"))) - { - bool updated = renderIcon(epdIndex, epdContent[epdIndex], updatePartial); - if (!updated) { - continue; - } - } - else if (epdContent[epdIndex].length() > 5) - { - renderText(epdIndex, epdContent[epdIndex], updatePartial); - } - else - { - if (epdContent[epdIndex].length() == 2) { - showChars(epdIndex, epdContent[epdIndex], updatePartial, &FONT_BIG); - } - else if (epdContent[epdIndex].length() > 1 && epdContent[epdIndex].indexOf(".") == -1) - { - if (epdContent[epdIndex].equals("STS")) - { - showDigit(epdIndex, 'S', updatePartial, - &FONT_SATSYMBOL); - } - else - { - showChars(epdIndex, epdContent[epdIndex], updatePartial, - &FONT_MEDIUM); - } - } - else + // Wait for a work item to be available in the queue + if (xQueueReceive(updateQueue, &receivedItem, portMAX_DELAY)) { + uint epdIndex = receivedItem.dispNum; + std::lock_guard lock(epdMutex[epdIndex]); + // displays[epdIndex].init(0, false); // Little longer reset duration + // because of MCP - showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, - &FONT_BIG); - } - } + bool updatePartial = true; - xTaskNotifyGive(tasks[epdIndex]); + if (epdContent[epdIndex].length() > 1 && strstr(epdContent[epdIndex].c_str(), "/") != NULL) + { + String top = epdContent[epdIndex].substring( + 0, epdContent[epdIndex].indexOf("/")); + String bottom = epdContent[epdIndex].substring( + epdContent[epdIndex].indexOf("/") + 1); + splitText(epdIndex, top, bottom, updatePartial); + } + else if (epdContent[epdIndex].startsWith(F("qr"))) + { + renderQr(epdIndex, epdContent[epdIndex], updatePartial); + } + else if (epdContent[epdIndex].startsWith(F("mdi"))) + { + bool updated = renderIcon(epdIndex, epdContent[epdIndex], updatePartial); + if (!updated) + { + continue; + } + } + else if (epdContent[epdIndex].length() > 5) + { + renderText(epdIndex, epdContent[epdIndex], updatePartial); + } + else + { + if (epdContent[epdIndex].length() == 2) + { + showChars(epdIndex, epdContent[epdIndex], updatePartial, FONT_BIG); + } + else if (epdContent[epdIndex].length() > 1 && epdContent[epdIndex].indexOf(".") == -1) + { + if (epdContent[epdIndex].equals("STS")) + { + showDigit(epdIndex, 'S', updatePartial, + FONT_SATSYMBOL); + } + else + { + showChars(epdIndex, epdContent[epdIndex], updatePartial, + FONT_MEDIUM); + } + } + else + { + + showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, + FONT_BIG); + } + } + + xTaskNotifyGive(tasks[epdIndex]); + } } - } } extern "C" void updateDisplay(void *pvParameters) noexcept { - const int epdIndex = *(int *)pvParameters; - delete (int *)pvParameters; - - for (;;) - { - // Wait for the task notification - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - - std::lock_guard lock(epdMutex[epdIndex]); + const int epdIndex = *(int *)pvParameters; + delete (int *)pvParameters; + for (;;) { - std::lock_guard lockMcp(mcpMutex); + // Wait for the task notification + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - displays[epdIndex].init(0, false, 40); + std::lock_guard lock(epdMutex[epdIndex]); + + { + std::lock_guard lockMcp(mcpMutex); + + displays[epdIndex].init(0, false, 40); + } + uint count = 0; + while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) + { + vTaskDelay(pdMS_TO_TICKS(100)); + count++; + } + + bool updatePartial = true; + + // Full Refresh every x minutes + if (!lastFullRefresh[epdIndex] || + (millis() - lastFullRefresh[epdIndex]) > + (preferences.getUInt("fullRefreshMin", + DEFAULT_MINUTES_FULL_REFRESH) * + 60 * 1000)) + { + updatePartial = false; + } + + char tries = 0; + while (tries < 3) + { + if (displays[epdIndex].displayWithReturn(updatePartial)) + { + displays[epdIndex].powerOff(); + currentEpdContent[epdIndex] = epdContent[epdIndex]; + if (!updatePartial) + lastFullRefresh[epdIndex] = millis(); + + if (eventSourceTaskHandle != NULL) + xTaskNotifyGive(eventSourceTaskHandle); + + break; + } + + vTaskDelay(pdMS_TO_TICKS(100)); + tries++; + } } - uint count = 0; - while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) - { - vTaskDelay(pdMS_TO_TICKS(100)); - count++; - } - - bool updatePartial = true; - - // Full Refresh every x minutes - if (!lastFullRefresh[epdIndex] || - (millis() - lastFullRefresh[epdIndex]) > - (preferences.getUInt("fullRefreshMin", - DEFAULT_MINUTES_FULL_REFRESH) * - 60 * 1000)) - { - updatePartial = false; - } - - char tries = 0; - while (tries < 3) - { - if (displays[epdIndex].displayWithReturn(updatePartial)) - { - displays[epdIndex].powerOff(); - currentEpdContent[epdIndex] = epdContent[epdIndex]; - if (!updatePartial) - lastFullRefresh[epdIndex] = millis(); - - if (eventSourceTaskHandle != NULL) - xTaskNotifyGive(eventSourceTaskHandle); - - break; - } - - vTaskDelay(pdMS_TO_TICKS(100)); - tries++; - } - } } void splitText(const uint dispNum, const String &top, const String &bottom, bool partial) { - if(preferences.getBool("verticalDesc", DEFAULT_VERTICAL_DESC) && dispNum == 0) { - displays[dispNum].setRotation(1); - } else { - displays[dispNum].setRotation(2); - } - displays[dispNum].setFont(&FONT_SMALL); - displays[dispNum].setTextColor(getFgColor()); + if (preferences.getBool("verticalDesc", DEFAULT_VERTICAL_DESC) && dispNum == 0) + { + displays[dispNum].setRotation(1); + } + else + { + displays[dispNum].setRotation(2); + } + displays[dispNum].setFont(FONT_SMALL); + displays[dispNum].setTextColor(getFgColor()); - // Top text - int16_t ttbx, ttby; - uint16_t ttbw, ttbh; - displays[dispNum].getTextBounds(top, 0, 0, &ttbx, &ttby, &ttbw, &ttbh); - uint16_t tx = ((displays[dispNum].width() - ttbw) / 2) - ttbx; - uint16_t ty = - ((displays[dispNum].height() - ttbh) / 2) - ttby - ttbh / 2 - 12; + // Top text + int16_t ttbx, ttby; + uint16_t ttbw, ttbh; + displays[dispNum].getTextBounds(top, 0, 0, &ttbx, &ttby, &ttbw, &ttbh); + uint16_t tx = ((displays[dispNum].width() - ttbw) / 2) - ttbx; + uint16_t ty = + ((displays[dispNum].height() - ttbh) / 2) - ttby - ttbh / 2 - 12; - // Bottom text - int16_t tbbx, tbby; - uint16_t tbbw, tbbh; - displays[dispNum].getTextBounds(bottom, 0, 0, &tbbx, &tbby, &tbbw, &tbbh); - uint16_t bx = ((displays[dispNum].width() - tbbw) / 2) - tbbx; - uint16_t by = - ((displays[dispNum].height() - tbbh) / 2) - tbby + tbbh / 2 + 12; + // Bottom text + int16_t tbbx, tbby; + uint16_t tbbw, tbbh; + displays[dispNum].getTextBounds(bottom, 0, 0, &tbbx, &tbby, &tbbw, &tbbh); + uint16_t bx = ((displays[dispNum].width() - tbbw) / 2) - tbbx; + uint16_t by = + ((displays[dispNum].height() - tbbh) / 2) - tbby + tbbh / 2 + 12; - // Make separator as wide as the shortest text. - uint16_t lineWidth, lineX; - if (tbbw < ttbh) - lineWidth = tbbw; - else - lineWidth = ttbw; - lineX = round((displays[dispNum].width() - lineWidth) / 2); + // Make separator as wide as the shortest text. + uint16_t lineWidth, lineX; + if (tbbw < ttbh) + lineWidth = tbbw; + else + lineWidth = ttbw; + lineX = round((displays[dispNum].width() - lineWidth) / 2); - displays[dispNum].fillScreen(getBgColor()); - displays[dispNum].setCursor(tx, ty); - displays[dispNum].print(top); - displays[dispNum].fillRoundRect(lineX, displays[dispNum].height() / 2 - 3, - lineWidth, 6, 3, getFgColor()); - displays[dispNum].setCursor(bx, by); - displays[dispNum].print(bottom); + displays[dispNum].fillScreen(getBgColor()); + displays[dispNum].setCursor(tx, ty); + displays[dispNum].print(top); + displays[dispNum].fillRoundRect(lineX, displays[dispNum].height() / 2 - 3, + lineWidth, 6, 3, getFgColor()); + displays[dispNum].setCursor(bx, by); + displays[dispNum].print(bottom); } // Consolidate common display setup code into a helper function -void setupDisplay(const uint dispNum, const GFXfont *font) { +void setupDisplay(const uint dispNum, const GFXfont *font) +{ displays[dispNum].setRotation(2); displays[dispNum].setFont(font); displays[dispNum].setTextColor(getFgColor()); displays[dispNum].fillScreen(getBgColor()); } -void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font) { +void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font) +{ String str(chr); - if (chr == '.') { + if (chr == '.') + { str = "!"; } - + setupDisplay(dispNum, font); - + int16_t tbx, tby; uint16_t tbw, tbh; displays[dispNum].getTextBounds(str, 0, 0, &tbx, &tby, &tbw, &tbh); @@ -427,57 +525,64 @@ void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font) displays[dispNum].setCursor(x, y); displays[dispNum].print(str); - if (chr == '.') { - displays[dispNum].fillRect(x, y, displays[dispNum].width(), - round(displays[dispNum].height() * 0.9), getBgColor()); + if (chr == '.') + { + displays[dispNum].fillRect(x, y, displays[dispNum].width(), + round(displays[dispNum].height() * 0.9), getBgColor()); } } -int16_t calculateDescent(const GFXfont *font) { - int16_t maxDescent = 0; - for (uint16_t i = font->first; i <= font->last; i++) { - GFXglyph *glyph = &font->glyph[i - font->first]; - int16_t descent = glyph->yOffset; - if (descent > maxDescent) { - maxDescent = descent; +int16_t calculateDescent(const GFXfont *font) +{ + int16_t maxDescent = 0; + for (uint16_t i = font->first; i <= font->last; i++) + { + GFXglyph *glyph = &font->glyph[i - font->first]; + int16_t descent = glyph->yOffset; + if (descent > maxDescent) + { + maxDescent = descent; + } } - } - return maxDescent; + return maxDescent; } void showChars(const uint dispNum, const String &chars, bool partial, const GFXfont *font) { - setupDisplay(dispNum, font); + setupDisplay(dispNum, font); + int16_t tbx, tby; + uint16_t tbw, tbh; + displays[dispNum].getTextBounds(chars, 0, 0, &tbx, &tby, &tbw, &tbh); - int16_t tbx, tby; - uint16_t tbw, tbh; - displays[dispNum].getTextBounds(chars, 0, 0, &tbx, &tby, &tbw, &tbh); + // center the bounding box by transposition of the origin: + uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx; + uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby; - // center the bounding box by transposition of the origin: - uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx; - uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby; + for (int i = 0; i < chars.length(); i++) + { + char c = chars[i]; + if (c == '.' || c == ',') + { + // For the dot, calculate its specific descent + GFXglyph *dotGlyph = &font->glyph[c - font->first]; + int16_t dotDescent = dotGlyph->yOffset; - for (int i = 0; i < chars.length(); i++) { - char c = chars[i]; - if (c == '.' || c == ',') { - // For the dot, calculate its specific descent - GFXglyph *dotGlyph = &font->glyph[c -font->first]; - int16_t dotDescent = dotGlyph->yOffset; - - // Draw the dot with adjusted y-position - displays[dispNum].setCursor(x, y + dotDescent + dotGlyph->height + 8); - displays[dispNum].print(c); - } else { - // For other characters, use the original y-position - displays[dispNum].setCursor(x, y); - displays[dispNum].print(c); + // Draw the dot with adjusted y-position + displays[dispNum].setCursor(x, y + dotDescent + dotGlyph->height + 8); + displays[dispNum].print(c); + } + else + { + // For other characters, use the original y-position + displays[dispNum].setCursor(x, y); + displays[dispNum].print(c); + } + + // Move x-position for the next character + x += font->glyph[c - font->first].xAdvance; } - - // Move x-position for the next character - x += font->glyph[c - font->first].xAdvance; - } } int getBgColor() { return bgColor; } @@ -490,142 +595,146 @@ void setFgColor(int color) { fgColor = color; } std::array getCurrentEpdContent() { - return currentEpdContent; + return currentEpdContent; } void renderText(const uint dispNum, const String &text, bool partial) { - displays[dispNum].setRotation(2); - displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), - displays[dispNum].height()); - displays[dispNum].fillScreen(GxEPD_WHITE); - displays[dispNum].setTextColor(GxEPD_BLACK); - displays[dispNum].setCursor(0, 50); + displays[dispNum].setRotation(2); + displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), + displays[dispNum].height()); + displays[dispNum].fillScreen(GxEPD_WHITE); + displays[dispNum].setTextColor(GxEPD_BLACK); + displays[dispNum].setCursor(0, 50); - std::stringstream ss; - ss.str(text.c_str()); + std::stringstream ss; + ss.str(text.c_str()); - std::string line; + std::string line; - while (std::getline(ss, line, '\n')) - { - if (line.rfind("*", 0) == 0) + while (std::getline(ss, line, '\n')) { - line.erase(std::remove(line.begin(), line.end(), '*'), line.end()); + if (line.rfind("*", 0) == 0) + { + line.erase(std::remove(line.begin(), line.end(), '*'), line.end()); - displays[dispNum].setFont(&FreeSansBold9pt7b); - displays[dispNum].println(line.c_str()); + displays[dispNum].setFont(&FreeSansBold9pt7b); + displays[dispNum].println(line.c_str()); + } + else + { + displays[dispNum].setFont(&FreeSans9pt7b); + displays[dispNum].println(line.c_str()); + } } - else - { - displays[dispNum].setFont(&FreeSans9pt7b); - displays[dispNum].println(line.c_str()); - } - } } bool renderIcon(const uint dispNum, const String &text, bool partial) { - displays[dispNum].setRotation(2); + displays[dispNum].setRotation(2); - displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), - displays[dispNum].height()); + displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), + displays[dispNum].height()); displays[dispNum].fillScreen(getBgColor()); displays[dispNum].setTextColor(getFgColor()); - uint iconIndex = 0; - uint width = 122; - uint height = 122; - if (text.endsWith("rocket")) { - iconIndex = 1; - } - else if (text.endsWith("lnbolt")) { - iconIndex = 2; - } - else if (text.endsWith("bitaxe")) { - width = 88; - height = 220; - iconIndex = 3; - } - else if (text.endsWith("miningpool")) { - LogoData logo = getMiningPoolLogo(); + uint iconIndex = 0; + uint width = 122; + uint height = 122; + if (text.endsWith("rocket")) + { + iconIndex = 1; + } + else if (text.endsWith("lnbolt")) + { + iconIndex = 2; + } + else if (text.endsWith("bitaxe")) + { + width = 88; + height = 220; + iconIndex = 3; + } + else if (text.endsWith("miningpool")) + { + LogoData logo = getMiningPoolLogo(); - if (logo.size == 0) { - Serial.println(F("No logo found")); - return false; - } + if (logo.size == 0) + { + Serial.println(F("No logo found")); + return false; + } - int x_offset = (displays[dispNum].width() - logo.width) / 2; - int y_offset = (displays[dispNum].height() - logo.height) / 2; - // Close the file + int x_offset = (displays[dispNum].width() - logo.width) / 2; + int y_offset = (displays[dispNum].height() - logo.height) / 2; + // Close the file + + displays[dispNum].drawInvertedBitmap(x_offset, y_offset, logo.data, logo.width, logo.height, getFgColor()); + return true; + } + + int x_offset = (displays[dispNum].width() - width) / 2; + int y_offset = (displays[dispNum].height() - height) / 2; + + displays[dispNum].drawInvertedBitmap(x_offset, y_offset, epd_icons_allArray[iconIndex], width, height, getFgColor()); - displays[dispNum].drawInvertedBitmap(x_offset,y_offset, logo.data, logo.width, logo.height, getFgColor()); return true; - } - - - int x_offset = (displays[dispNum].width() - width) / 2; - int y_offset = (displays[dispNum].height() - height) / 2; - - - displays[dispNum].drawInvertedBitmap(x_offset,y_offset, epd_icons_allArray[iconIndex], width, height, getFgColor()); - - return true; -// displays[dispNum].drawInvertedBitmap(0,0, getOceanIcon(), 122, 250, getFgColor()); - - + // displays[dispNum].drawInvertedBitmap(0,0, getOceanIcon(), 122, 250, getFgColor()); } void renderQr(const uint dispNum, const String &text, bool partial) { #ifdef USE_QR - uint8_t tempBuffer[800]; - bool ok = qrcodegen_encodeText( - text.substring(2).c_str(), tempBuffer, qrcode, qrcodegen_Ecc_LOW, - qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true); + uint8_t tempBuffer[800]; + bool ok = qrcodegen_encodeText( + text.substring(2).c_str(), tempBuffer, qrcode, qrcodegen_Ecc_LOW, + qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true); - const int size = qrcodegen_getSize(qrcode); + const int size = qrcodegen_getSize(qrcode); - const int padding = floor(float(displays[dispNum].width() - (size * 4)) / 2); - const int paddingY = - floor(float(displays[dispNum].height() - (size * 4)) / 2); - displays[dispNum].setRotation(2); + const int padding = floor(float(displays[dispNum].width() - (size * 4)) / 2); + const int paddingY = + floor(float(displays[dispNum].height() - (size * 4)) / 2); + displays[dispNum].setRotation(2); - displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), - displays[dispNum].height()); - displays[dispNum].fillScreen(GxEPD_WHITE); - const int border = 0; + displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), + displays[dispNum].height()); + displays[dispNum].fillScreen(GxEPD_WHITE); + const int border = 0; - for (int y = -border; y < size * 4 + border; y++) - { - for (int x = -border; x < size * 4 + border; x++) + for (int y = -border; y < size * 4 + border; y++) { - displays[dispNum].drawPixel( - padding + x, paddingY + y, - qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4)) - ? GxEPD_BLACK - : GxEPD_WHITE); + for (int x = -border; x < size * 4 + border; x++) + { + displays[dispNum].drawPixel( + padding + x, paddingY + y, + qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4)) + ? GxEPD_BLACK + : GxEPD_WHITE); + } } - } #endif } void waitUntilNoneBusy() { - for (int i = 0; i < NUM_SCREENS; i++) - { - uint count = 0; - while (EPD_BUSY[i].digitalRead()) + for (int i = 0; i < NUM_SCREENS; i++) { - count++; - vTaskDelay(BUSY_RETRY_DELAY); - - if (count == BUSY_TIMEOUT_COUNT) { - vTaskDelay(pdMS_TO_TICKS(100)); - } else if (count > BUSY_TIMEOUT_COUNT + 5) { - log_e("Display %d busy timeout", i); - break; - } + uint count = 0; + while (EPD_BUSY[i].digitalRead()) + { + count++; + vTaskDelay(BUSY_RETRY_DELAY); + + if (count == BUSY_TIMEOUT_COUNT) + { + vTaskDelay(pdMS_TO_TICKS(100)); + } + else if (count > BUSY_TIMEOUT_COUNT + 5) + { + log_e("Display %d busy timeout", i); + break; + } + } } - } } \ No newline at end of file diff --git a/src/lib/epd.hpp b/src/lib/epd.hpp index 35fcdd3..1825189 100644 --- a/src/lib/epd.hpp +++ b/src/lib/epd.hpp @@ -3,7 +3,7 @@ #include #include #include - +#include "gzip_decompressor.hpp" #include #include @@ -16,6 +16,18 @@ #include "icons/icons.h" #include "mining_pool_stats_fetch.hpp" +// Font includes +#include "../fonts/antonio-semibold20.h" +#include "../fonts/antonio-semibold40.h" +#include "../fonts/antonio-semibold90.h" + +// Oswald fonts +#include "../fonts/oswald-medium20.h" +#include "../fonts/oswald-medium30.h" +#include "../fonts/oswald-medium80.h" + +#include "../fonts/sats-symbol.h" + #ifdef USE_QR #include "qrcodegen.h" #endif diff --git a/src/lib/gzip_decompressor.hpp b/src/lib/gzip_decompressor.hpp new file mode 100644 index 0000000..a74b04e --- /dev/null +++ b/src/lib/gzip_decompressor.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "rom/miniz.h" +#include + +class GzipDecompressor { +public: + static bool decompressData(const uint8_t* input, size_t inputSize, + uint8_t* output, size_t* outputSize) { + if (!input || !output || !outputSize || inputSize < 18) { // Minimum gzip size + return false; + } + + tinfl_decompressor* decomp = new tinfl_decompressor; + if (!decomp) { + return false; + } + + tinfl_init(decomp); + + size_t inPos = 10; // Skip gzip header + size_t outPos = 0; + + while (inPos < inputSize - 8) { // -8 for footer + size_t inBytes = inputSize - inPos - 8; + size_t outBytes = *outputSize - outPos; + + tinfl_status status = tinfl_decompress(decomp, + &input[inPos], &inBytes, + output, &output[outPos], &outBytes, + TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + + inPos += inBytes; + outPos += outBytes; + + if (status == TINFL_STATUS_DONE) { + *outputSize = outPos; + delete decomp; + return true; + } else if (status < 0) { + delete decomp; + return false; + } + } + + delete decomp; + return false; + } +}; \ No newline at end of file diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 66c6895..539fb17 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -3,7 +3,7 @@ static const char* JSON_CONTENT = "application/json"; static const char *const PROGMEM strSettings[] = { - "hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl", "ceEndpoint"}; + "hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl", "ceEndpoint", "fontName"}; static const char *const PROGMEM uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout"}; @@ -675,7 +675,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["nostrZapNotify"] = preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED); root["nostrZapPubkey"] = preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY); root["ledFlashOnZap"] = preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP); - + root["fontName"] = preferences.getString("fontName", DEFAULT_FONT_NAME); // Custom endpoint settings (only used for CUSTOM_SOURCE) root["customEndpoint"] = preferences.getString("customEndpoint", DEFAULT_CUSTOM_ENDPOINT); root["customEndpointDisableSSL"] = preferences.getBool("customEndpointDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); From 13c8e67b4c850aad5541dfc71217ce086a81d5b4 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 30 Dec 2024 00:53:50 +0100 Subject: [PATCH 093/130] More efficient handling of multiple fonts, restore data bugfix --- data | 2 +- src/fonts/fonts.hpp | 26 +++++++++ src/lib/epd.cpp | 114 ++++++++++--------------------------- src/lib/epd.hpp | 2 +- src/lib/price_notify.cpp | 31 ++++++++-- src/lib/price_notify.hpp | 3 +- src/lib/screen_handler.cpp | 1 + src/lib/shared.hpp | 10 ++++ src/lib/webserver.cpp | 1 + 9 files changed, 96 insertions(+), 94 deletions(-) diff --git a/data b/data index 48e585d..0041ec3 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 48e585d4ec12bbc441499936d7cbf53d4307b9ec +Subproject commit 0041ec3d9a174955383836bba02caf79f3961072 diff --git a/src/fonts/fonts.hpp b/src/fonts/fonts.hpp index a1f03bd..8f66032 100644 --- a/src/fonts/fonts.hpp +++ b/src/fonts/fonts.hpp @@ -15,9 +15,35 @@ struct FontData { const uint8_t yAdvance; }; +// Font name constants +namespace FontNames { + static const String ANTONIO = "antonio"; + static const String OSWALD = "oswald"; + + static const std::array AVAILABLE_FONTS = { + ANTONIO, + OSWALD + }; + + static const std::array& getAvailableFonts() { + return AVAILABLE_FONTS; + } +} class FontLoader { public: + static GFXfont* loadCompressedFont(const FontData& fontData) { + return loadCompressedFont( + fontData.compressedData, + fontData.glyphs, + fontData.compressedSize, + fontData.originalSize, + fontData.first, + fontData.last, + fontData.yAdvance + ); + } + static GFXfont* loadCompressedFont( const uint8_t* compressedData, const GFXglyph* glyphs, diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index cca11a7..31fbf86 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -161,73 +161,21 @@ void forceFullRefresh() GFXfont font90; -void setupDisplays() -{ - String fontName = preferences.getString("fontName", DEFAULT_FONT_NAME); // Default to antonio - - if (fontName == "antonio") - { +void loadFonts(const String& fontName) { + if (fontName == FontNames::ANTONIO) { // Load Antonio fonts - antonioFonts.big = FontLoader::loadCompressedFont( - Antonio_SemiBold90pt7b_Properties.compressedData, - Antonio_SemiBold90pt7b_Properties.glyphs, - Antonio_SemiBold90pt7b_Properties.compressedSize, - Antonio_SemiBold90pt7b_Properties.originalSize, - Antonio_SemiBold90pt7b_Properties.first, - Antonio_SemiBold90pt7b_Properties.last, - Antonio_SemiBold90pt7b_Properties.yAdvance); - - antonioFonts.medium = FontLoader::loadCompressedFont( - Antonio_SemiBold40pt7b_Properties.compressedData, - Antonio_SemiBold40pt7b_Properties.glyphs, - Antonio_SemiBold40pt7b_Properties.compressedSize, - Antonio_SemiBold40pt7b_Properties.originalSize, - Antonio_SemiBold40pt7b_Properties.first, - Antonio_SemiBold40pt7b_Properties.last, - Antonio_SemiBold40pt7b_Properties.yAdvance); - - antonioFonts.small = FontLoader::loadCompressedFont( - Antonio_SemiBold20pt7b_Properties.compressedData, - Antonio_SemiBold20pt7b_Properties.glyphs, - Antonio_SemiBold20pt7b_Properties.compressedSize, - Antonio_SemiBold20pt7b_Properties.originalSize, - Antonio_SemiBold20pt7b_Properties.first, - Antonio_SemiBold20pt7b_Properties.last, - Antonio_SemiBold20pt7b_Properties.yAdvance); + antonioFonts.big = FontLoader::loadCompressedFont(Antonio_SemiBold90pt7b_Properties); + antonioFonts.medium = FontLoader::loadCompressedFont(Antonio_SemiBold40pt7b_Properties); + antonioFonts.small = FontLoader::loadCompressedFont(Antonio_SemiBold20pt7b_Properties); FONT_BIG = antonioFonts.big; FONT_MEDIUM = antonioFonts.medium; FONT_SMALL = antonioFonts.small; - } - else if (fontName == "oswald") - { + } else if (fontName == FontNames::OSWALD) { // Load Oswald fonts - oswaldFonts.big = FontLoader::loadCompressedFont( - Oswald_Medium80pt7b_Properties.compressedData, - Oswald_Medium80pt7b_Properties.glyphs, - Oswald_Medium80pt7b_Properties.compressedSize, - Oswald_Medium80pt7b_Properties.originalSize, - Oswald_Medium80pt7b_Properties.first, - Oswald_Medium80pt7b_Properties.last, - Oswald_Medium80pt7b_Properties.yAdvance); - - oswaldFonts.medium = FontLoader::loadCompressedFont( - Oswald_Medium30pt7b_Properties.compressedData, - Oswald_Medium30pt7b_Properties.glyphs, - Oswald_Medium30pt7b_Properties.compressedSize, - Oswald_Medium30pt7b_Properties.originalSize, - Oswald_Medium30pt7b_Properties.first, - Oswald_Medium30pt7b_Properties.last, - Oswald_Medium30pt7b_Properties.yAdvance); - - oswaldFonts.small = FontLoader::loadCompressedFont( - Oswald_Medium20pt7b_Properties.compressedData, - Oswald_Medium20pt7b_Properties.glyphs, - Oswald_Medium20pt7b_Properties.compressedSize, - Oswald_Medium20pt7b_Properties.originalSize, - Oswald_Medium20pt7b_Properties.first, - Oswald_Medium20pt7b_Properties.last, - Oswald_Medium20pt7b_Properties.yAdvance); + oswaldFonts.big = FontLoader::loadCompressedFont(Oswald_Medium80pt7b_Properties); + oswaldFonts.medium = FontLoader::loadCompressedFont(Oswald_Medium30pt7b_Properties); + oswaldFonts.small = FontLoader::loadCompressedFont(Oswald_Medium20pt7b_Properties); FONT_BIG = oswaldFonts.big; FONT_MEDIUM = oswaldFonts.medium; @@ -235,53 +183,49 @@ void setupDisplays() } FONT_SATSYMBOL = &Satoshi_Symbol90pt7b; +} +void setupDisplays() { + // Load fonts based on preference + String fontName = preferences.getString("fontName", DEFAULT_FONT_NAME); + loadFonts(fontName); + + // Initialize displays std::lock_guard lockMcp(mcpMutex); - - for (uint i = 0; i < NUM_SCREENS; i++) - { + for (uint i = 0; i < NUM_SCREENS; i++) { displays[i].init(0, true, 30); } + // Create update queue and task updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem)); - xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", EPD_TASK_STACK_SIZE * 2, NULL, 11, NULL); - for (uint i = 0; i < NUM_SCREENS; i++) - { + // Create display update tasks + for (uint i = 0; i < NUM_SCREENS; i++) { int *taskParam = new int; *taskParam = i; - - xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), EPD_TASK_STACK_SIZE, taskParam, - 11, &tasks[i]); // create task + xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), EPD_TASK_STACK_SIZE, taskParam, 11, &tasks[i]); } - // Hold lower button to enable "storage mode" (prevents burn-in of ePaper displays) - if (mcp1.read1(0) == LOW) - { + // Check for storage mode (prevents burn-in) + if (mcp1.read1(0) == LOW) { setFgColor(GxEPD_BLACK); setBgColor(GxEPD_WHITE); - epdContent.fill(""); - } - else - { - // Get custom text from preferences or use default "BTCLOCK" + } else { + // Initialize with custom text or default String customText = preferences.getString("displayText", DEFAULT_BOOT_TEXT); - - // Initialize array with spaces std::array newContent; newContent.fill(" "); - // Fill in the custom text, truncating if longer than NUM_SCREENS for (size_t i = 0; i < std::min(customText.length(), (size_t)NUM_SCREENS); i++) { - newContent[i] = String(customText[i]); + newContent[i] = String(customText[i]); } epdContent = newContent; } - setEpdContent(epdContent); + setEpdContent(epdContent); } void setEpdContent(std::array newEpdContent) @@ -527,8 +471,8 @@ void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font) if (chr == '.') { - displays[dispNum].fillRect(x, y, displays[dispNum].width(), - round(displays[dispNum].height() * 0.9), getBgColor()); + displays[dispNum].fillRect(0, 0, displays[dispNum].width(), + round(displays[dispNum].height() * 0.67), getBgColor()); } } diff --git a/src/lib/epd.hpp b/src/lib/epd.hpp index 1825189..4796776 100644 --- a/src/lib/epd.hpp +++ b/src/lib/epd.hpp @@ -31,7 +31,6 @@ #ifdef USE_QR #include "qrcodegen.h" #endif -// extern TaskHandle_t epdTaskHandle; typedef struct { char dispNum; @@ -39,6 +38,7 @@ typedef struct { void forceFullRefresh(); void setupDisplays(); +void loadFonts(const String& fontName); void splitText(const uint dispNum, const String &top, const String &bottom, bool partial); diff --git a/src/lib/price_notify.cpp b/src/lib/price_notify.cpp index 0d56a90..2c6fe94 100644 --- a/src/lib/price_notify.cpp +++ b/src/lib/price_notify.cpp @@ -110,15 +110,17 @@ void processNewPrice(uint newPrice, char currency) if (lastUpdateMap.find(currency) == lastUpdateMap.end() || (currentTime - lastUpdateMap[currency]) > minSecPriceUpd) { - // const unsigned long oldPrice = currentPrice; currencyMap[currency] = newPrice; - if (currency == CURRENCY_USD && ( lastUpdateMap[currency] == 0 || - (currentTime - lastUpdateMap[currency]) > 120)) + + // Store price in preferences if enough time has passed + if (lastUpdateMap[currency] == 0 || (currentTime - lastUpdateMap[currency]) > 120) { - preferences.putUInt("lastPrice", currentPrice); + String prefKey = String("lastPrice_") + getCurrencyCode(currency).c_str(); + preferences.putUInt(prefKey.c_str(), newPrice); } + lastUpdateMap[currency] = currentTime; - // if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) { + if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BTC_TICKER || ScreenHandler::getCurrentScreen() == SCREEN_SATS_PER_CURRENCY || ScreenHandler::getCurrentScreen() == SCREEN_MARKET_CAP)) @@ -126,7 +128,24 @@ void processNewPrice(uint newPrice, char currency) WorkItem priceUpdate = {TASK_PRICE_UPDATE, currency}; xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); } - //} + } +} + +void loadStoredPrices() +{ + // Load prices for all supported currencies + std::vector currencies = getAvailableCurrencies(); + + for (const std::string ¤cy : currencies) { + // Get first character as the currency identifier + String prefKey = String("lastPrice_") + currency.c_str(); + uint storedPrice = preferences.getUInt(prefKey.c_str(), 0); + + if (storedPrice > 0) { + currencyMap[getCurrencyChar(currency)] = storedPrice; + // Initialize lastUpdateMap to 0 so next update will store immediately + lastUpdateMap[getCurrencyChar(currency)] = 0; + } } } diff --git a/src/lib/price_notify.hpp b/src/lib/price_notify.hpp index 4aad356..3591d40 100644 --- a/src/lib/price_notify.hpp +++ b/src/lib/price_notify.hpp @@ -27,4 +27,5 @@ void stopPriceNotify(); void restartPriceNotify(); bool getPriceNotifyInit(); -uint getLastPriceUpdate(char currency); \ No newline at end of file +uint getLastPriceUpdate(char currency); +void loadStoredPrices(); \ No newline at end of file diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index f837e5e..4d8d1b9 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -321,6 +321,7 @@ void taskScreenRotate(void *pvParameters) { void setupTasks() { workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem)); + loadStoredPrices(); xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY, &workerTaskHandle); diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index adbbe5e..78fb9ea 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -97,6 +97,16 @@ namespace ArduinoJson { array.add(item); } }; + + template + struct Converter> { + static void toJson(const std::array& src, JsonVariant dst) { + JsonArray array = dst.to(); + for (const String& item : src) { + array.add(item); + } + } + }; } class HttpHelper { diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 539fb17..c2bc86a 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -676,6 +676,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["nostrZapPubkey"] = preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY); root["ledFlashOnZap"] = preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP); root["fontName"] = preferences.getString("fontName", DEFAULT_FONT_NAME); + root["availableFonts"] = FontNames::getAvailableFonts(); // Custom endpoint settings (only used for CUSTOM_SOURCE) root["customEndpoint"] = preferences.getString("customEndpoint", DEFAULT_CUSTOM_ENDPOINT); root["customEndpointDisableSSL"] = preferences.getBool("customEndpointDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); From 2e1b15e688c4a7cfb675c96c10d2cb01e2de5545 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 30 Dec 2024 02:04:18 +0100 Subject: [PATCH 094/130] Add Do Not Disturb feature --- data | 2 +- src/lib/led_handler.cpp | 108 +++++++++++++++++++++++++++++++++++++--- src/lib/led_handler.hpp | 21 +++++++- src/lib/webserver.cpp | 67 ++++++++++++++++++++++++- src/lib/webserver.hpp | 4 ++ 5 files changed, 189 insertions(+), 13 deletions(-) diff --git a/data b/data index 0041ec3..033fe09 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 0041ec3d9a174955383836bba02caf79f3961072 +Subproject commit 033fe098295ab6da6568d6298b4380e51bec0b98 diff --git a/src/lib/led_handler.cpp b/src/lib/led_handler.cpp index 42ef5e5..16612ba 100644 --- a/src/lib/led_handler.cpp +++ b/src/lib/led_handler.cpp @@ -50,6 +50,9 @@ void frontlightFadeOut(uint num) void frontlightSetBrightness(uint brightness) { + if (isDNDActive()) { + return; // Don't change brightness during DND mode + } if (brightness > 4096) { return; @@ -183,6 +186,9 @@ bool frontlightIsOn() void frontlightFadeIn(uint num, int flDelayTime) { + if (isDNDActive()) { + return; // Don't change brightness during DND mode + } if (preferences.getBool("flDisable")) return; for (int dutyCycle = 0; dutyCycle <= preferences.getUInt("flMaxBrightness"); dutyCycle += 5) @@ -194,6 +200,9 @@ void frontlightFadeIn(uint num, int flDelayTime) void frontlightFadeOut(uint num, int flDelayTime) { + if (isDNDActive()) { + return; // Don't change brightness during DND mode + } if (preferences.getBool("flDisable")) return; if (!frontlightIsOn()) @@ -207,6 +216,85 @@ void frontlightFadeOut(uint num, int flDelayTime) } #endif +// Do Not Disturb mode variables +bool dndEnabled = false; +bool dndTimeBasedEnabled = false; +DNDTimeRange dndTimeRange = {23, 0, 7, 0}; // Default: 23:00 to 07:00 + +void loadDNDSettings() { + dndEnabled = preferences.getBool("dndEnabled", false); + dndTimeBasedEnabled = preferences.getBool("dndTimeEnabled", false); + + dndTimeRange.startHour = preferences.getUChar("dndStartHour", 23); + dndTimeRange.startMinute = preferences.getUChar("dndStartMin", 0); + dndTimeRange.endHour = preferences.getUChar("dndEndHour", 7); + dndTimeRange.endMinute = preferences.getUChar("dndEndMin", 0); +} + +void setDNDEnabled(bool enabled) { + dndEnabled = enabled; + preferences.putBool("dndEnabled", enabled); + if (enabled && isDNDActive()) { + clearLeds(); + #ifdef HAS_FRONTLIGHT + frontlightFadeOutAll(); + #endif + } +} + +void setDNDTimeBasedEnabled(bool enabled) { + dndTimeBasedEnabled = enabled; + preferences.putBool("dndTimeEnabled", enabled); + if (enabled && isDNDActive()) { + clearLeds(); + #ifdef HAS_FRONTLIGHT + frontlightFadeOutAll(); + #endif + } +} + +void setDNDTimeRange(uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute) { + dndTimeRange.startHour = startHour; + dndTimeRange.startMinute = startMinute; + dndTimeRange.endHour = endHour; + dndTimeRange.endMinute = endMinute; + + preferences.putUChar("dndStartHour", startHour); + preferences.putUChar("dndStartMin", startMinute); + preferences.putUChar("dndEndHour", endHour); + preferences.putUChar("dndEndMin", endMinute); +} + +bool isTimeInDNDRange(uint8_t hour, uint8_t minute) { + uint16_t currentTime = hour * 60 + minute; + uint16_t startTime = dndTimeRange.startHour * 60 + dndTimeRange.startMinute; + uint16_t endTime = dndTimeRange.endHour * 60 + dndTimeRange.endMinute; + + if (startTime <= endTime) { + // Simple case: start time is before end time (e.g., 09:00 to 17:00) + return currentTime >= startTime && currentTime < endTime; + } else { + // Complex case: start time is after end time (e.g., 23:00 to 07:00) + return currentTime >= startTime || currentTime < endTime; + } +} + +bool isDNDActive() { + if (dndEnabled) { + return true; + } + + if (dndTimeBasedEnabled) { + time_t now; + struct tm timeinfo; + time(&now); + localtime_r(&now, &timeinfo); + return isTimeInDNDRange(timeinfo.tm_hour, timeinfo.tm_min); + } + + return false; +} + void ledTask(void *parameter) { while (1) @@ -450,6 +538,7 @@ void ledTask(void *parameter) void setupLeds() { + loadDNDSettings(); pixels.begin(); pixels.setBrightness(preferences.getUInt("ledBrightness", DEFAULT_LED_BRIGHTNESS)); pixels.clear(); @@ -595,15 +684,18 @@ void restoreLedState() QueueHandle_t getLedTaskQueue() { return ledTaskQueue; } -bool queueLedEffect(uint effect) -{ - if (ledTaskQueue == NULL) - { - return false; - } +bool queueLedEffect(uint effect) { + if (isDNDActive()) { + return false; // Don't queue any effects during DND mode + } + if (ledTaskQueue == NULL) + { + return false; + } - uint flashType = effect; - xQueueSend(ledTaskQueue, &flashType, portMAX_DELAY); + uint flashType = effect; + xQueueSend(ledTaskQueue, &flashType, portMAX_DELAY); + return true; } void ledRainbow(int wait) diff --git a/src/lib/led_handler.hpp b/src/lib/led_handler.hpp index 98d8834..4fdbd28 100644 --- a/src/lib/led_handler.hpp +++ b/src/lib/led_handler.hpp @@ -28,7 +28,6 @@ const int LED_EFFECT_WIFI_CONNECT_ERROR = 102; const int LED_EFFECT_WIFI_CONNECT_SUCCESS = 103; const int LED_EFFECT_WIFI_ERASE_SETTINGS = 104; - const int LED_PROGRESS_25 = 200; const int LED_PROGRESS_50 = 201; const int LED_PROGRESS_75 = 202; @@ -82,4 +81,22 @@ void frontlightFadeOutAll(int flDelayTime, bool staggered); void frontlightFadeIn(uint num, int flDelayTime); void frontlightFadeOut(uint num, int flDelayTime); -#endif \ No newline at end of file +#endif + +// Do Not Disturb mode settings +struct DNDTimeRange { + uint8_t startHour; + uint8_t startMinute; + uint8_t endHour; + uint8_t endMinute; +}; + +extern bool dndEnabled; +extern bool dndTimeBasedEnabled; +extern DNDTimeRange dndTimeRange; + +void setDNDEnabled(bool enabled); +void setDNDTimeBasedEnabled(bool enabled); +void setDNDTimeRange(uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute); +bool isDNDActive(); +bool isTimeInDNDRange(uint8_t hour, uint8_t minute); \ No newline at end of file diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index c2bc86a..2ba0a4d 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -16,7 +16,7 @@ static const char *const PROGMEM boolSettings[] = {"ledTestOnPower", "ledFlashOn "mempoolSecure", "bitaxeEnabled", "miningPoolStats", "verticalDesc", "nostrZapNotify", "httpAuthEnabled", - "enableDebugLog", "ceDisableSSL"}; + "enableDebugLog", "ceDisableSSL", "dndEnabled", "dndTimeBasedEnabled"}; AsyncWebServer server(80); AsyncEventSource events("/events"); @@ -116,6 +116,10 @@ void setupWebserver() server.addRewrite(new OneParamRewrite("/api/show/number/{number}", "/api/show/text?t={text}")); + server.on("/api/dnd/status", HTTP_GET, onApiDNDStatus); + server.on("/api/dnd/enable", HTTP_POST, onApiDNDEnable); + server.on("/api/dnd/disable", HTTP_POST, onApiDNDDisable); + server.onNotFound(onNotFound); DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*"); @@ -265,6 +269,15 @@ JsonDocument getStatusObject() } #endif + // Add DND status + root["dnd"]["enabled"] = dndEnabled; + root["dnd"]["timeBasedEnabled"] = dndTimeBasedEnabled; + root["dnd"]["startTime"] = String(dndTimeRange.startHour) + ":" + + (dndTimeRange.startMinute < 10 ? "0" : "") + String(dndTimeRange.startMinute); + root["dnd"]["endTime"] = String(dndTimeRange.endHour) + ":" + + (dndTimeRange.endMinute < 10 ? "0" : "") + String(dndTimeRange.endMinute); + root["dnd"]["active"] = isDNDActive(); + return root; } @@ -605,6 +618,23 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) settingsChanged = true; } + // Handle DND settings + if (settings.containsKey("dnd")) { + JsonObject dndObj = settings["dnd"]; + if (dndObj.containsKey("timeBasedEnabled")) { + setDNDTimeBasedEnabled(dndObj["timeBasedEnabled"].as()); + } + if (dndObj.containsKey("startHour") && dndObj.containsKey("startMinute") && + dndObj.containsKey("endHour") && dndObj.containsKey("endMinute")) { + setDNDTimeRange( + dndObj["startHour"].as(), + dndObj["startMinute"].as(), + dndObj["endHour"].as(), + dndObj["endMinute"].as() + ); + } + } + request->send(HTTP_OK); if (settingsChanged) { @@ -766,6 +796,14 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["ceEndpoint"] = preferences.getString("ceEndpoint", DEFAULT_CUSTOM_ENDPOINT); root["ceDisableSSL"] = preferences.getBool("ceDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); + // Add DND settings + root["dnd"]["enabled"] = dndEnabled; + root["dnd"]["timeBasedEnabled"] = dndTimeBasedEnabled; + root["dnd"]["startHour"] = dndTimeRange.startHour; + root["dnd"]["startMinute"] = dndTimeRange.startMinute; + root["dnd"]["endHour"] = dndTimeRange.endHour; + root["dnd"]["endMinute"] = dndTimeRange.endMinute; + AsyncResponseStream *response = request->beginResponseStream(JSON_CONTENT); serializeJson(root, *response); @@ -1091,4 +1129,29 @@ void onApiFrontlightOff(AsyncWebServerRequest *request) request->send(HTTP_OK); } -#endif \ No newline at end of file +#endif + +void onApiDNDStatus(AsyncWebServerRequest *request) { + JsonDocument doc; + doc["enabled"] = dndEnabled; + doc["timeBasedEnabled"] = dndTimeBasedEnabled; + doc["startTime"] = String(dndTimeRange.startHour) + ":" + + (dndTimeRange.startMinute < 10 ? "0" : "") + String(dndTimeRange.startMinute); + doc["endTime"] = String(dndTimeRange.endHour) + ":" + + (dndTimeRange.endMinute < 10 ? "0" : "") + String(dndTimeRange.endMinute); + doc["active"] = isDNDActive(); + + String response; + serializeJson(doc, response); + request->send(200, "application/json", response); +} + +void onApiDNDEnable(AsyncWebServerRequest *request) { + setDNDEnabled(true); + request->send(200); +} + +void onApiDNDDisable(AsyncWebServerRequest *request) { + setDNDEnabled(false); + request->send(200); +} \ No newline at end of file diff --git a/src/lib/webserver.hpp b/src/lib/webserver.hpp index 45fa854..ddd6b73 100644 --- a/src/lib/webserver.hpp +++ b/src/lib/webserver.hpp @@ -67,6 +67,10 @@ void eventSourceTask(void *pvParameters); void onApiStopDataSources(AsyncWebServerRequest *request); void onApiRestartDataSources(AsyncWebServerRequest *request); +void onApiDNDStatus(AsyncWebServerRequest *request); +void onApiDNDEnable(AsyncWebServerRequest *request); +void onApiDNDDisable(AsyncWebServerRequest *request); + #ifdef HAS_FRONTLIGHT void onApiFrontlightOn(AsyncWebServerRequest *request); void onApiFrontlightFlash(AsyncWebServerRequest *request); From aea69d54b66d91bdb083a62654711ec50da617b6 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Tue, 31 Dec 2024 11:33:50 +0100 Subject: [PATCH 095/130] Add tag and HW revision to setup screen, change setup SSID same as hostname --- src/lib/config.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 5870ec4..5ef77dc 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -157,8 +157,7 @@ void setupWifi() byte mac[6]; WiFi.macAddress(mac); - String softAP_SSID = - String("BTClock" + String(mac[5], 16) + String(mac[1], 16)); + String softAP_SSID = getMyHostname(); WiFi.setHostname(softAP_SSID.c_str()); String softAP_password = replaceAmbiguousChars( base64::encode(String(mac[2], 16) + String(mac[4], 16) + @@ -183,7 +182,8 @@ void setupWifi() ";T:WPA;P:" + softAP_password.c_str() + ";;"; const String explainText = "*SSID: *\r\n" + wifiManager->getConfigPortalSSID() + - "\r\n\r\n*Password:*\r\n" + softAP_password; + "\r\n\r\n*Password:*\r\n" + softAP_password + + "\r\n\r\n*Hostname*:\r\n" + getMyHostname(); // Set the UNIX timestamp time_t timestamp = LAST_BUILD_TIME; // Example timestamp: March 7, 2021 00:00:00 UTC @@ -193,14 +193,19 @@ void setupWifi() // Format the date char formattedDate[20]; strftime(formattedDate, sizeof(formattedDate), "%y-%m-%d\r\n%H:%M:%S", timeinfo); - + String hwStr = String(HW_REV); + hwStr.replace("_EPD_", "\r\nEPD_"); std::array epdContent = { "Welcome!", "Bienvenidos!", "To setup\r\nscan QR or\r\nconnect\r\nmanually", "Para\r\nconfigurar\r\nescanear QR\r\no conectar\r\nmanualmente", explainText, - "*Hostname*:\r\n" + getMyHostname() + "\r\n\r\n" + "*FW build date:*\r\n" + formattedDate, + "*HW version:*\r\n" + hwStr + +#ifdef GIT_TAG + "\r\n\r\n*SW Version:*\r\n" + GIT_TAG + +#endif + "\r\n\r\n*FW build date:*\r\n" + formattedDate, qrText}; setEpdContent(epdContent); }); From b8428e1650027943c43698d7a285b1f31ef97ed5 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Tue, 31 Dec 2024 11:51:34 +0100 Subject: [PATCH 096/130] Add LED effect when retrying time synchronization --- src/lib/config.cpp | 1 + src/lib/led_handler.cpp | 20 ++++++++++++++++++++ src/lib/led_handler.hpp | 11 +++++++---- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 5ef77dc..2269cc6 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -279,6 +279,7 @@ void syncTime() while (!getLocalTime(&timeinfo)) { + queueLedEffect(LED_EFFECT_CONFIGURING); configTime(preferences.getInt("gmtOffset", DEFAULT_TIME_OFFSET_SECONDS), 0, NTP_SERVER); delay(500); diff --git a/src/lib/led_handler.cpp b/src/lib/led_handler.cpp index 16612ba..806ee9c 100644 --- a/src/lib/led_handler.cpp +++ b/src/lib/led_handler.cpp @@ -333,6 +333,26 @@ void ledTask(void *parameter) blinkDelayTwoColor(100, 3, pixels.Color(8, 161, 236), pixels.Color(255, 0, 0)); break; + case LED_EFFECT_CONFIGURING: + for (int i = NEOPIXEL_COUNT; i--; i > 0) + { + for (int j = NEOPIXEL_COUNT; j--; j > 0) + { + uint32_t c = pixels.Color(0, 0, 0); + if (i == j) + c = pixels.Color(0, 0, 255); + + pixels.setPixelColor(j, c); + } + + pixels.show(); + + delay(100); + } + + pixels.clear(); + pixels.show(); + break; case LED_FLASH_ERROR: blinkDelayColor(250, 3, 255, 0, 0); break; diff --git a/src/lib/led_handler.hpp b/src/lib/led_handler.hpp index 4fdbd28..fe72ffa 100644 --- a/src/lib/led_handler.hpp +++ b/src/lib/led_handler.hpp @@ -18,10 +18,13 @@ const int LED_FLASH_ERROR = 0; const int LED_FLASH_SUCCESS = 1; const int LED_FLASH_UPDATE = 2; -const int LED_FLASH_BLOCK_NOTIFY = 3; -const int LED_EFFECT_START_TIMER = 4; -const int LED_EFFECT_PAUSE_TIMER = 5; -const int LED_EFFECT_HEARTBEAT = 6; + +const int LED_EFFECT_CONFIGURING = 10; + +const int LED_FLASH_BLOCK_NOTIFY = 4; +const int LED_EFFECT_START_TIMER = 5; +const int LED_EFFECT_PAUSE_TIMER = 6; +const int LED_EFFECT_HEARTBEAT = 7; const int LED_EFFECT_WIFI_WAIT_FOR_CONFIG = 100; const int LED_EFFECT_WIFI_CONNECTING = 101; const int LED_EFFECT_WIFI_CONNECT_ERROR = 102; From b4864b1db6e6fd9d0940fde06edf73c521cd47db Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 5 Jan 2025 18:08:21 +0100 Subject: [PATCH 097/130] Improve bitaxe handling code --- lib/btclock/bitaxe_handler.cpp | 72 ++++++++++++++++++------- lib/btclock/bitaxe_handler.hpp | 6 ++- lib/btclock/utils.cpp | 11 ++++ lib/btclock/utils.hpp | 3 +- src/lib/bitaxe_fetch.cpp | 24 ++++++--- src/lib/bitaxe_fetch.hpp | 5 +- src/lib/block_notify.cpp | 16 +++--- src/lib/block_notify.hpp | 16 +++--- test/test_bitaxehandler/test_main.cpp | 75 +++++++++++++++++++++++++++ 9 files changed, 183 insertions(+), 45 deletions(-) create mode 100644 test/test_bitaxehandler/test_main.cpp diff --git a/lib/btclock/bitaxe_handler.cpp b/lib/btclock/bitaxe_handler.cpp index c18b7de..c51ca7c 100644 --- a/lib/btclock/bitaxe_handler.cpp +++ b/lib/btclock/bitaxe_handler.cpp @@ -1,14 +1,20 @@ #include "bitaxe_handler.hpp" -std::array parseBitaxeHashRate(std::string text) +std::array parseBitaxeHashRate(uint64_t hashrate) { std::array ret; ret.fill(""); // Initialize all elements to empty strings - std::size_t textLength = text.length(); + // Convert hashrate to GH/s and round to nearest integer + double hashRateGH = static_cast(hashrate) / std::pow(10, getHashrateMultiplier('G')); + std::string hashRateStr = std::to_string(static_cast(std::round(hashRateGH))); + + // Place the icons + ret[0] = "mdi:bitaxe"; + ret[NUM_SCREENS - 1] = "GH/S"; // Calculate the position where the digits should start - // Account for the position of the "mdi:pickaxe" and the "GH/S" label + std::size_t textLength = hashRateStr.length(); std::size_t startIndex = NUM_SCREENS - 1 - textLength; // Insert the "mdi:pickaxe" icon just before the digits @@ -17,34 +23,64 @@ std::array parseBitaxeHashRate(std::string text) ret[startIndex - 1] = "mdi:pickaxe"; } - // Place the digits + // Place each digit for (std::size_t i = 0; i < textLength; ++i) { - ret[startIndex + i] = text.substr(i, 1); + ret[startIndex + i] = std::string(1, hashRateStr[i]); } - ret[NUM_SCREENS - 1] = "GH/S"; - ret[0] = "mdi:bitaxe"; - return ret; } -std::array parseBitaxeBestDiff(std::string text) +std::array parseBitaxeBestDiff(uint64_t difficulty) { std::array ret; - std::uint32_t firstIndex = 0; + ret.fill(""); - if (text.length() < NUM_SCREENS) - { - text.insert(text.begin(), NUM_SCREENS - text.length(), ' '); - ret[0] = "mdi:bitaxe"; - ret[1] = "mdi:rocket"; - firstIndex = 2; + // Add icons at the start + ret[0] = "mdi:bitaxe"; + ret[1] = "mdi:rocket"; + + if (difficulty == 0) { + ret[NUM_SCREENS - 1] = "0"; + return ret; } - for (std::uint8_t i = firstIndex; i < NUM_SCREENS; i++) + // Find the appropriate suffix and format the number + const std::pair suffixes[] = { + {'Q', 15}, {'T', 12}, {'G', 9}, {'M', 6}, {'K', 3} + }; + + std::string text; + for (const auto& suffix : suffixes) { + if (difficulty >= std::pow(10, suffix.second)) { + double value = difficulty / std::pow(10, suffix.second); + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%.1f", value); + text = buffer; + // Remove trailing zeros and decimal point if not needed + if (text.find('.') != std::string::npos) { + text = text.substr(0, text.find_last_not_of('0') + 1); + if (text.back() == '.') { + text.pop_back(); + } + } + text += suffix.first; + break; + } + } + + if (text.empty()) { + text = std::to_string(difficulty); + } + + // Calculate start position to right-align the text + std::size_t startIndex = NUM_SCREENS - text.length(); + + // Place the formatted difficulty string + for (std::size_t i = 0; i < text.length() && (startIndex + i) < NUM_SCREENS; ++i) { - ret[i] = text[i]; + ret[startIndex + i] = std::string(1, text[i]); } return ret; diff --git a/lib/btclock/bitaxe_handler.hpp b/lib/btclock/bitaxe_handler.hpp index c78c8f7..f1484ef 100644 --- a/lib/btclock/bitaxe_handler.hpp +++ b/lib/btclock/bitaxe_handler.hpp @@ -1,5 +1,7 @@ #include #include +#include +#include "utils.hpp" -std::array parseBitaxeHashRate(std::string text); -std::array parseBitaxeBestDiff(std::string text); +std::array parseBitaxeHashRate(uint64_t hashrate); +std::array parseBitaxeBestDiff(uint64_t difficulty); diff --git a/lib/btclock/utils.cpp b/lib/btclock/utils.cpp index d5c8027..443eb1e 100644 --- a/lib/btclock/utils.cpp +++ b/lib/btclock/utils.cpp @@ -243,3 +243,14 @@ int getHashrateMultiplier(char unit) { }; return multipliers.at(unit); } + +int getDifficultyMultiplier(char unit) { + if (unit == '0') + return 0; + + static const std::unordered_map multipliers = { + {'Q', 15}, {'T', 12}, {'B', 9}, {'M', 6}, {'K', 3}, {'G', 9}, + {'q', 15}, {'t', 12}, {'b', 9}, {'m', 6}, {'k', 3}, {'g', 9} + }; + return multipliers.at(unit); +} diff --git a/lib/btclock/utils.hpp b/lib/btclock/utils.hpp index 44df032..05540d4 100644 --- a/lib/btclock/utils.hpp +++ b/lib/btclock/utils.hpp @@ -16,4 +16,5 @@ std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters = 4); std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters, bool mowMode); int64_t getAmountInSatoshis(std::string bolt11); void parseHashrateString(const std::string& hashrate, std::string& label, std::string& output, unsigned int maxCharacters); -int getHashrateMultiplier(char unit); \ No newline at end of file +int getHashrateMultiplier(char unit); +int getDifficultyMultiplier(char unit); \ No newline at end of file diff --git a/src/lib/bitaxe_fetch.cpp b/src/lib/bitaxe_fetch.cpp index f439cb4..d2dae13 100644 --- a/src/lib/bitaxe_fetch.cpp +++ b/src/lib/bitaxe_fetch.cpp @@ -2,15 +2,15 @@ TaskHandle_t bitaxeFetchTaskHandle; -std::string bitaxeHashrate; -std::string bitaxeBestDiff; +uint64_t bitaxeHashrate; +uint64_t bitaxeBestDiff; -std::string getBitAxeHashRate() +uint64_t getBitAxeHashRate() { return bitaxeHashrate; } -std::string getBitaxeBestDiff() +uint64_t getBitaxeBestDiff() { return bitaxeBestDiff; } @@ -33,8 +33,20 @@ void taskBitaxeFetch(void *pvParameters) String payload = http.getString(); JsonDocument doc; deserializeJson(doc, payload); - bitaxeHashrate = std::to_string(static_cast(std::round(doc["hashRate"].as()))); - bitaxeBestDiff = doc["bestDiff"].as(); + + // Convert GH/s to H/s (multiply by 10^9) + float hashRateGH = doc["hashRate"].as(); + bitaxeHashrate = static_cast(std::round(hashRateGH * std::pow(10, getHashrateMultiplier('G')))); + + // Parse difficulty string and convert to uint64_t + std::string diffStr = doc["bestDiff"].as(); + char diffUnit = diffStr[diffStr.length() - 1]; + if (std::isalpha(diffUnit)) { + float diffValue = std::stof(diffStr.substr(0, diffStr.length() - 1)); + bitaxeBestDiff = static_cast(std::round(diffValue * std::pow(10, getDifficultyMultiplier(diffUnit)))); + } else { + bitaxeBestDiff = std::stoull(diffStr); + } if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_BESTDIFF)) { diff --git a/src/lib/bitaxe_fetch.hpp b/src/lib/bitaxe_fetch.hpp index 8e4f7f3..8e1da37 100644 --- a/src/lib/bitaxe_fetch.hpp +++ b/src/lib/bitaxe_fetch.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "lib/config.hpp" #include "lib/shared.hpp" @@ -11,5 +12,5 @@ extern TaskHandle_t bitaxeFetchTaskHandle; void setupBitaxeFetchTask(); void taskBitaxeFetch(void *pvParameters); -std::string getBitAxeHashRate(); -std::string getBitaxeBestDiff(); \ No newline at end of file +uint64_t getBitAxeHashRate(); +uint64_t getBitaxeBestDiff(); \ No newline at end of file diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index a1ce1fc..ec72138 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -2,8 +2,8 @@ char *wsServer; esp_websocket_client_handle_t blockNotifyClient = NULL; -uint currentBlockHeight = 873400; -uint blockMedianFee = 1; +uint32_t currentBlockHeight = 873400; +uint16_t blockMedianFee = 1; bool blockNotifyInit = false; unsigned long int lastBlockUpdate; @@ -179,7 +179,7 @@ void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data) doc.clear(); } -void processNewBlock(uint newBlockHeight) { +void processNewBlock(uint32_t newBlockHeight) { if (newBlockHeight < currentBlockHeight) return; @@ -222,7 +222,7 @@ void processNewBlock(uint newBlockHeight) { } } -void processNewBlockFee(uint newBlockFee) { +void processNewBlockFee(uint16_t newBlockFee) { if (blockMedianFee == newBlockFee) { return; @@ -238,16 +238,16 @@ void processNewBlockFee(uint newBlockFee) { } } -uint getBlockHeight() { return currentBlockHeight; } +uint32_t getBlockHeight() { return currentBlockHeight; } -void setBlockHeight(uint newBlockHeight) +void setBlockHeight(uint32_t newBlockHeight) { currentBlockHeight = newBlockHeight; } -uint getBlockMedianFee() { return blockMedianFee; } +uint16_t getBlockMedianFee() { return blockMedianFee; } -void setBlockMedianFee(uint newBlockMedianFee) +void setBlockMedianFee(uint16_t newBlockMedianFee) { blockMedianFee = newBlockMedianFee; } diff --git a/src/lib/block_notify.hpp b/src/lib/block_notify.hpp index d5565eb..9c41bf0 100644 --- a/src/lib/block_notify.hpp +++ b/src/lib/block_notify.hpp @@ -22,20 +22,20 @@ void onWebsocketBlockEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data); void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data); -void setBlockHeight(uint newBlockHeight); -uint getBlockHeight(); +void setBlockHeight(uint32_t newBlockHeight); +uint32_t getBlockHeight(); -void setBlockMedianFee(uint blockMedianFee); -uint getBlockMedianFee(); +void setBlockMedianFee(uint16_t blockMedianFee); +uint16_t getBlockMedianFee(); bool isBlockNotifyConnected(); void stopBlockNotify(); void restartBlockNotify(); -void processNewBlock(uint newBlockHeight); -void processNewBlockFee(uint newBlockFee); +void processNewBlock(uint32_t newBlockHeight); +void processNewBlockFee(uint16_t newBlockFee); bool getBlockNotifyInit(); -uint getLastBlockUpdate(); +uint32_t getLastBlockUpdate(); int getBlockFetch(); -void setLastBlockUpdate(uint lastUpdate); \ No newline at end of file +void setLastBlockUpdate(uint32_t lastUpdate); diff --git a/test/test_bitaxehandler/test_main.cpp b/test/test_bitaxehandler/test_main.cpp new file mode 100644 index 0000000..4336107 --- /dev/null +++ b/test/test_bitaxehandler/test_main.cpp @@ -0,0 +1,75 @@ +#include +#include + +template +std::string joinArrayWithBrackets(const std::array& arr, const std::string& separator = " ") { + std::ostringstream result; + for (size_t i = 0; i < N; ++i) { + if (i > 0) { + result << separator; + } + result << '[' << arr[i] << ']'; + } + return result.str(); +} + +void setUp(void) +{ + // set stuff up here +} + +void tearDown(void) +{ + // clean stuff up here +} + +void test_BitaxeParseHashrate(void) +{ + std::array output = parseBitaxeHashRate(656130000000); + + std::string joined = joinArrayWithBrackets(output); + + + TEST_ASSERT_EQUAL_STRING_MESSAGE("mdi:bitaxe", output[0].c_str(), joined.c_str()); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("6", output[NUM_SCREENS - 4].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("5", output[NUM_SCREENS - 3].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("6", output[NUM_SCREENS - 2].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("GH/S", output[NUM_SCREENS - 1].c_str(), joined.c_str()); +} + +void test_BitaxeParseBestDiff(void) +{ + std::array output = parseBitaxeBestDiff(15800000000); + + std::string joined = joinArrayWithBrackets(output); + + TEST_ASSERT_EQUAL_STRING_MESSAGE("mdi:bitaxe", output[0].c_str(), joined.c_str()); + + + TEST_ASSERT_EQUAL_STRING_MESSAGE("1", output[NUM_SCREENS - 5].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("5", output[NUM_SCREENS - 4].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE(".", output[NUM_SCREENS - 3].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("8", output[NUM_SCREENS - 2].c_str(), joined.c_str()); + TEST_ASSERT_EQUAL_STRING_MESSAGE("G", output[NUM_SCREENS - 1].c_str(), joined.c_str()); +} + +// not needed when using generate_test_runner.rb +int runUnityTests(void) +{ + UNITY_BEGIN(); + RUN_TEST(test_BitaxeParseHashrate); + RUN_TEST(test_BitaxeParseBestDiff); + + return UNITY_END(); +} + +int main(void) +{ + return runUnityTests(); +} + +extern "C" void app_main() +{ + runUnityTests(); +} From cd4dea9d340078817596413664150dbb2e4fd7fb Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 5 Jan 2025 18:50:19 +0100 Subject: [PATCH 098/130] Add explicit LED frequency, compress sats symbol font --- src/lib/config.cpp | 1 + src/lib/epd.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 2269cc6..765bedd 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -674,6 +674,7 @@ void setupFrontlight() Serial.println(F("FL driver error")); return; } + flArray.setFrequency(200); Serial.println(F("FL driver active")); if (!preferences.isKey("flMaxBrightness")) diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 31fbf86..d9b5303 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -182,7 +182,7 @@ void loadFonts(const String& fontName) { FONT_SMALL = oswaldFonts.small; } - FONT_SATSYMBOL = &Satoshi_Symbol90pt7b; + FONT_SATSYMBOL = FontLoader::loadCompressedFont(Satoshi_Symbol90pt7b_Properties); } void setupDisplays() { From fa15e46d349a5a4ffeb028085b1250c776a1c88c Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 5 Jan 2025 20:07:56 +0100 Subject: [PATCH 099/130] Add compressed sat symbol font file --- src/fonts/sats-symbol.h | 424 ++++++++++++++++++++++------------------ 1 file changed, 229 insertions(+), 195 deletions(-) diff --git a/src/fonts/sats-symbol.h b/src/fonts/sats-symbol.h index d21a9a5..182c6ea 100644 --- a/src/fonts/sats-symbol.h +++ b/src/fonts/sats-symbol.h @@ -1,201 +1,235 @@ -const uint8_t Satoshi_Symbol90pt7bBitmaps[] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 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, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xE0, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, - 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, - 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, - 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, - 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, - 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, - 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, - 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, - 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0 }; +#pragma once + +#include +#include +#include "fonts.hpp" + +const uint8_t Satoshi_Symbol90pt7bBitmaps_Gzip[] = { + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x63, 0x60, + 0x60, 0x60, 0xe0, 0xff, 0xc7, 0x00, 0x05, 0xcc, 0xff, 0x1b, 0x60, 0xcc, + 0xff, 0x0f, 0x60, 0x2c, 0xfb, 0x1f, 0x30, 0xd6, 0x60, 0x53, 0x38, 0x28, + 0x81, 0xfd, 0x7f, 0x3a, 0x83, 0x81, 0xf6, 0x30, 0x1a, 0xe0, 0xa7, 0xb7, + 0xff, 0x0f, 0x0c, 0xb4, 0x8f, 0x51, 0x01, 0x33, 0xbd, 0xfd, 0xff, 0x61, + 0xa0, 0x7d, 0x8c, 0x17, 0x0c, 0x8e, 0x92, 0x82, 0x44, 0x85, 0x54, 0x8f, + 0x23, 0x88, 0xe1, 0xec, 0xff, 0xa1, 0x56, 0xf2, 0xff, 0xff, 0x03, 0x61, + 0xc8, 0xff, 0x87, 0x3a, 0xc7, 0x1e, 0x16, 0x8d, 0xf5, 0x30, 0xa7, 0xc2, + 0x12, 0x36, 0xe3, 0x7f, 0xa8, 0xeb, 0x98, 0x47, 0x8d, 0x19, 0x35, 0x66, + 0x78, 0x1b, 0x43, 0x65, 0xf0, 0x00, 0x00, 0xc7, 0x63, 0x9f, 0x4b, 0xde, + 0x08, 0x00, 0x00 +}; +// unsigned int satoshi_bin_gz_len = 123; + + +// const uint8_t Satoshi_Symbol90pt7bBitmaps[] PROGMEM = { +// 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +// 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, +// 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, +// 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 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, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, +// 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0xFF, 0xE0, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +// 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +// 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, +// 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, +// 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +// 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, +// 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, +// 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, +// 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, +// 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, +// 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, +// 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, +// 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, +// 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +// 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, +// 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, +// 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, +// 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +// 0xFF, 0xE0 }; const GFXglyph Satoshi_Symbol90pt7bGlyphs[] PROGMEM = { { 0, 82, 127, 99, 8, -126 }, { 1302, 71, 109, 93, 0, -117 } }; // 0x53 'S' -const GFXfont Satoshi_Symbol90pt7b PROGMEM = { - (uint8_t *)Satoshi_Symbol90pt7bBitmaps, - (GFXglyph *)Satoshi_Symbol90pt7bGlyphs, - 0x53, 0x53, 192 }; +// const GFXfont Satoshi_Symbol90pt7b PROGMEM = { +// (uint8_t *)Satoshi_Symbol90pt7bBitmaps, +// (GFXglyph *)Satoshi_Symbol90pt7bGlyphs, +// 0x53, 0x53, 192 }; + + // Font properties +static constexpr FontData Satoshi_Symbol90pt7b_Properties = { + Satoshi_Symbol90pt7bBitmaps_Gzip, + Satoshi_Symbol90pt7bGlyphs, + sizeof(Satoshi_Symbol90pt7bBitmaps_Gzip), + 2270, // Original size + 0x53, // First char + 0x53, // Last char + 192 // yAdvance +}; + // Approx. 2284 bytes From c91428dd5f872dc0613ce55c5e2ebcfe031d051b Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 5 Jan 2025 20:14:55 +0100 Subject: [PATCH 100/130] Refactor BitAxeFetch to a class --- src/lib/bitaxe_fetch.cpp | 53 ++++++++++++++------------------------ src/lib/bitaxe_fetch.hpp | 28 ++++++++++++++++---- src/lib/config.cpp | 4 +-- src/lib/screen_handler.cpp | 4 +-- src/lib/timers.cpp | 5 ++-- 5 files changed, 50 insertions(+), 44 deletions(-) diff --git a/src/lib/bitaxe_fetch.cpp b/src/lib/bitaxe_fetch.cpp index d2dae13..8fa1db0 100644 --- a/src/lib/bitaxe_fetch.cpp +++ b/src/lib/bitaxe_fetch.cpp @@ -1,24 +1,19 @@ #include "bitaxe_fetch.hpp" -TaskHandle_t bitaxeFetchTaskHandle; - -uint64_t bitaxeHashrate; -uint64_t bitaxeBestDiff; - -uint64_t getBitAxeHashRate() -{ - return bitaxeHashrate; +void BitAxeFetch::taskWrapper(void* pvParameters) { + BitAxeFetch::getInstance().task(); } -uint64_t getBitaxeBestDiff() -{ - return bitaxeBestDiff; +uint64_t BitAxeFetch::getHashRate() const { + return hashrate; } -void taskBitaxeFetch(void *pvParameters) -{ - for (;;) - { +uint64_t BitAxeFetch::getBestDiff() const { + return bestDiff; +} + +void BitAxeFetch::task() { + for (;;) { ulTaskNotifyTake(pdTRUE, portMAX_DELAY); HTTPClient http; @@ -28,46 +23,38 @@ void taskBitaxeFetch(void *pvParameters) int httpCode = http.GET(); - if (httpCode == 200) - { + if (httpCode == 200) { String payload = http.getString(); JsonDocument doc; deserializeJson(doc, payload); // Convert GH/s to H/s (multiply by 10^9) float hashRateGH = doc["hashRate"].as(); - bitaxeHashrate = static_cast(std::round(hashRateGH * std::pow(10, getHashrateMultiplier('G')))); + hashrate = static_cast(std::round(hashRateGH * std::pow(10, getHashrateMultiplier('G')))); // Parse difficulty string and convert to uint64_t std::string diffStr = doc["bestDiff"].as(); char diffUnit = diffStr[diffStr.length() - 1]; if (std::isalpha(diffUnit)) { float diffValue = std::stof(diffStr.substr(0, diffStr.length() - 1)); - bitaxeBestDiff = static_cast(std::round(diffValue * std::pow(10, getDifficultyMultiplier(diffUnit)))); + bestDiff = static_cast(std::round(diffValue * std::pow(10, getDifficultyMultiplier(diffUnit)))); } else { - bitaxeBestDiff = std::stoull(diffStr); + bestDiff = std::stoull(diffStr); } - if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_BESTDIFF)) - { + if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_BESTDIFF)) { WorkItem priceUpdate = {TASK_BITAXE_UPDATE, 0}; xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); } - } - else - { - Serial.print( - F("Error retrieving BitAxe data. HTTP status code: ")); + } else { + Serial.print(F("Error retrieving BitAxe data. HTTP status code: ")); Serial.println(httpCode); Serial.println(bitaxeApiUrl); } } } -void setupBitaxeFetchTask() -{ - xTaskCreate(taskBitaxeFetch, "bitaxeFetch", (3 * 1024), NULL, tskIDLE_PRIORITY, - &bitaxeFetchTaskHandle); - - xTaskNotifyGive(bitaxeFetchTaskHandle); +void BitAxeFetch::setup() { + xTaskCreate(taskWrapper, "bitaxeFetch", (3 * 1024), NULL, tskIDLE_PRIORITY, &taskHandle); + xTaskNotifyGive(taskHandle); } \ No newline at end of file diff --git a/src/lib/bitaxe_fetch.hpp b/src/lib/bitaxe_fetch.hpp index 8e1da37..0dd98d9 100644 --- a/src/lib/bitaxe_fetch.hpp +++ b/src/lib/bitaxe_fetch.hpp @@ -7,10 +7,28 @@ #include "lib/config.hpp" #include "lib/shared.hpp" -extern TaskHandle_t bitaxeFetchTaskHandle; +class BitAxeFetch { +public: + static BitAxeFetch& getInstance() { + static BitAxeFetch instance; + return instance; + } -void setupBitaxeFetchTask(); -void taskBitaxeFetch(void *pvParameters); + void setup(); + uint64_t getHashRate() const; + uint64_t getBestDiff() const; + static void taskWrapper(void* pvParameters); + TaskHandle_t getTaskHandle() const { return taskHandle; } -uint64_t getBitAxeHashRate(); -uint64_t getBitaxeBestDiff(); \ No newline at end of file +private: + BitAxeFetch() = default; + ~BitAxeFetch() = default; + BitAxeFetch(const BitAxeFetch&) = delete; + BitAxeFetch& operator=(const BitAxeFetch&) = delete; + + void task(); + + TaskHandle_t taskHandle = nullptr; + uint64_t hashrate = 0; + uint64_t bestDiff = 0; +}; \ No newline at end of file diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 765bedd..2dce75e 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -100,7 +100,7 @@ void setup() if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED)) { - setupBitaxeFetchTask(); + BitAxeFetch::getInstance().setup(); } if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) @@ -221,7 +221,7 @@ void setupWifi() // waitUntilNoneBusy(); // std::array epdContent = {"Welcome!", - // "Bienvenidos!", "Use\r\nweb-interface\r\nto configure", "Use\r\nla + // "Bienvenidos!", "Use\r\nweb-interface\r\npara configurar", "Use\r\nla // interfaz web\r\npara configurar", "Or // restart\r\nwhile\r\nholding\r\n2nd button\r\r\nto start\r\n QR-config", // "O reinicie\r\nmientras\r\n mantiene presionado\r\nel segundo diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 4d8d1b9..27d83b9 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -220,8 +220,8 @@ void workerTask(void *pvParameters) { currentScreenValue != SCREEN_BITAXE_BESTDIFF) break; taskEpdContent = (currentScreenValue == SCREEN_BITAXE_HASHRATE) ? - parseBitaxeHashRate(getBitAxeHashRate()) : - parseBitaxeBestDiff(getBitaxeBestDiff()); + parseBitaxeHashRate(BitAxeFetch::getInstance().getHashRate()) : + parseBitaxeBestDiff(BitAxeFetch::getInstance().getBestDiff()); setEpdContent(taskEpdContent); break; } diff --git a/src/lib/timers.cpp b/src/lib/timers.cpp index 2fdb71c..3779c2d 100644 --- a/src/lib/timers.cpp +++ b/src/lib/timers.cpp @@ -68,8 +68,9 @@ void IRAM_ATTR minuteTimerISR(void *arg) { WorkItem timeUpdate = {TASK_TIME_UPDATE, 0}; xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken); - if (bitaxeFetchTaskHandle != NULL) { - vTaskNotifyGiveFromISR(bitaxeFetchTaskHandle, &xHigherPriorityTaskWoken); + TaskHandle_t bitaxeHandle = BitAxeFetch::getInstance().getTaskHandle(); + if (bitaxeHandle != NULL) { + vTaskNotifyGiveFromISR(bitaxeHandle, &xHigherPriorityTaskWoken); } if (miningPoolStatsFetchTaskHandle != NULL) { From ac130988240d41c02b663608b6df13b9445309e7 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 5 Jan 2025 20:24:13 +0100 Subject: [PATCH 101/130] Refactor mining pool stats fetch to a class --- src/lib/config.cpp | 4 +- src/lib/epd.cpp | 2 +- src/lib/mining_pool_stats_fetch.cpp | 128 ++++++++++++---------------- src/lib/mining_pool_stats_fetch.hpp | 42 +++++++-- src/lib/screen_handler.cpp | 7 +- src/lib/timers.cpp | 5 +- 6 files changed, 100 insertions(+), 88 deletions(-) diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 2dce75e..f0db973 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -105,7 +105,7 @@ void setup() if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) { - setupMiningPoolStatsFetchTask(); + MiningPoolStatsFetch::getInstance().setup(); } ButtonHandler::setup(); @@ -374,7 +374,7 @@ void setupPreferences() if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) { addScreenMapping(SCREEN_MINING_POOL_STATS_HASHRATE, "Mining Pool Hashrate"); - if (getMiningPool()->supportsDailyEarnings()) { + if (MiningPoolStatsFetch::getInstance().getPool()->supportsDailyEarnings()) { addScreenMapping(SCREEN_MINING_POOL_STATS_EARNINGS, "Mining Pool Earnings"); } } diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index d9b5303..04d3c5c 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -600,7 +600,7 @@ bool renderIcon(const uint dispNum, const String &text, bool partial) } else if (text.endsWith("miningpool")) { - LogoData logo = getMiningPoolLogo(); + LogoData logo = MiningPoolStatsFetch::getInstance().getLogo(); if (logo.size == 0) { diff --git a/src/lib/mining_pool_stats_fetch.cpp b/src/lib/mining_pool_stats_fetch.cpp index a35a00e..e04f208 100644 --- a/src/lib/mining_pool_stats_fetch.cpp +++ b/src/lib/mining_pool_stats_fetch.cpp @@ -1,95 +1,98 @@ #include "mining_pool_stats_fetch.hpp" -TaskHandle_t miningPoolStatsFetchTaskHandle; - -std::string miningPoolName; -std::string miningPoolStatsHashrate; -int miningPoolStatsDailyEarnings; - -std::string getMiningPoolStatsHashRate() -{ - return miningPoolStatsHashrate; +void MiningPoolStatsFetch::taskWrapper(void* pvParameters) { + MiningPoolStatsFetch::getInstance().task(); } -int getMiningPoolStatsDailyEarnings() -{ - return miningPoolStatsDailyEarnings; +void MiningPoolStatsFetch::downloadLogoTaskWrapper(void* pvParameters) { + MiningPoolStatsFetch::getInstance().downloadLogoTask(); } -void taskMiningPoolStatsFetch(void *pvParameters) -{ +std::string MiningPoolStatsFetch::getHashRate() const { + return hashrate; +} + +int MiningPoolStatsFetch::getDailyEarnings() const { + return dailyEarnings; +} + +MiningPoolInterface* MiningPoolStatsFetch::getPool() { + if (!currentPool) { + std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); + currentPool = PoolFactory::createPool(poolName); + } + return currentPool.get(); +} + +const MiningPoolInterface* MiningPoolStatsFetch::getPool() const { + return currentPool.get(); +} + +LogoData MiningPoolStatsFetch::getLogo() const { + if (const auto* pool = getPool()) { + return pool->getLogo(); + } + return LogoData{}; +} + +void MiningPoolStatsFetch::task() { std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); - auto poolInterface = PoolFactory::createPool(poolName); + auto* poolInterface = getPool(); + if (!poolInterface) return; std::string poolUser = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str(); // Main stats fetching loop - for (;;) - { + for (;;) { ulTaskNotifyTake(pdTRUE, portMAX_DELAY); HTTPClient http; http.setUserAgent(USER_AGENT); - - - + poolInterface->setPoolUser(poolUser); std::string apiUrl = poolInterface->getApiUrl(); http.begin(apiUrl.c_str()); - if (debugLogEnabled()) - { + if (debugLogEnabled()) { Serial.printf("Fetching mining pool stats from %s\r\n", apiUrl.c_str()); } poolInterface->prepareRequest(http); int httpCode = http.GET(); - if (httpCode == 200) - { + if (httpCode == 200) { String payload = http.getString(); JsonDocument doc; deserializeJson(doc, payload); - if (debugLogEnabled()) - { + if (debugLogEnabled()) { Serial.printf("Mining pool stats response: %s\r\n", payload.c_str()); } PoolStats stats = poolInterface->parseResponse(doc); + hashrate = stats.hashrate; - miningPoolStatsHashrate = stats.hashrate; - - if (debugLogEnabled()) - { + if (debugLogEnabled()) { Serial.printf("Mining pool stats parsed hashrate: %s\r\n", stats.hashrate.c_str()); } - if (stats.dailyEarnings) - { - miningPoolStatsDailyEarnings = *stats.dailyEarnings; - } - else - { - miningPoolStatsDailyEarnings = 0; // or any other default value - } + dailyEarnings = stats.dailyEarnings ? *stats.dailyEarnings : 0; - if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS)) - { + if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || + ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS)) { WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0}; xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); } - } - else - { - Serial.print( - F("Error retrieving mining pool data. HTTP status code: ")); + } else { + Serial.print(F("Error retrieving mining pool data. HTTP status code: ")); Serial.println(httpCode); } } } -void downloadMiningPoolLogoTask(void *pvParameters) { +void MiningPoolStatsFetch::downloadLogoTask() { std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); - auto poolInterface = PoolFactory::createPool(poolName); - PoolFactory::downloadPoolLogo(poolName, poolInterface.get()); + auto* poolInterface = getPool(); + if (!poolInterface) return; + + PoolFactory::downloadPoolLogo(poolName, poolInterface); // If we're on the mining pool stats screen, trigger a display update if (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) { @@ -97,41 +100,22 @@ void downloadMiningPoolLogoTask(void *pvParameters) { xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); } - xTaskNotifyGive(miningPoolStatsFetchTaskHandle); + xTaskNotifyGive(taskHandle); vTaskDelete(NULL); } -void setupMiningPoolStatsFetchTask() -{ - xTaskCreate(downloadMiningPoolLogoTask, +void MiningPoolStatsFetch::setup() { + xTaskCreate(downloadLogoTaskWrapper, "logoDownload", (6 * 1024), NULL, tskIDLE_PRIORITY, NULL); - xTaskCreate(taskMiningPoolStatsFetch, + xTaskCreate(taskWrapper, "miningPoolStatsFetch", (6 * 1024), NULL, tskIDLE_PRIORITY, - &miningPoolStatsFetchTaskHandle); -} - -std::unique_ptr& getMiningPool() -{ - static std::unique_ptr currentMiningPool; - - if (!currentMiningPool) { - std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); - currentMiningPool = PoolFactory::createPool(poolName); - } - - return currentMiningPool; -} - -LogoData getMiningPoolLogo() -{ - LogoData logo = getMiningPool()->getLogo(); - return logo; + &taskHandle); } diff --git a/src/lib/mining_pool_stats_fetch.hpp b/src/lib/mining_pool_stats_fetch.hpp index 7a84454..9ea351a 100644 --- a/src/lib/mining_pool_stats_fetch.hpp +++ b/src/lib/mining_pool_stats_fetch.hpp @@ -2,18 +2,44 @@ #include #include -#include "mining_pool/pool_factory.hpp" +#include +#include #include "lib/config.hpp" #include "lib/shared.hpp" +#include "lib/mining_pool/mining_pool_interface.hpp" +#include "mining_pool/pool_factory.hpp" -extern TaskHandle_t miningPoolStatsFetchTaskHandle; +class MiningPoolStatsFetch { +public: + static MiningPoolStatsFetch& getInstance() { + static MiningPoolStatsFetch instance; + return instance; + } -void setupMiningPoolStatsFetchTask(); -void taskMiningPoolStatsFetch(void *pvParameters); + void setup(); + std::string getHashRate() const; + int getDailyEarnings() const; + TaskHandle_t getTaskHandle() const { return taskHandle; } + static void taskWrapper(void* pvParameters); + static void downloadLogoTaskWrapper(void* pvParameters); + + // Pool interface methods + MiningPoolInterface* getPool(); + const MiningPoolInterface* getPool() const; + LogoData getLogo() const; -std::string getMiningPoolStatsHashRate(); -int getMiningPoolStatsDailyEarnings(); +private: + MiningPoolStatsFetch() = default; + ~MiningPoolStatsFetch() = default; + MiningPoolStatsFetch(const MiningPoolStatsFetch&) = delete; + MiningPoolStatsFetch& operator=(const MiningPoolStatsFetch&) = delete; -std::unique_ptr& getMiningPool(); -LogoData getMiningPoolLogo(); \ No newline at end of file + void task(); + void downloadLogoTask(); + + TaskHandle_t taskHandle = nullptr; + std::string hashrate; + int dailyEarnings = 0; + std::unique_ptr currentPool; +}; \ No newline at end of file diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 27d83b9..0692c1d 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -231,9 +231,10 @@ void workerTask(void *pvParameters) { currentScreenValue != SCREEN_MINING_POOL_STATS_EARNINGS) break; taskEpdContent = (currentScreenValue == SCREEN_MINING_POOL_STATS_HASHRATE) ? - parseMiningPoolStatsHashRate(getMiningPoolStatsHashRate(), *getMiningPool()) : - parseMiningPoolStatsDailyEarnings(getMiningPoolStatsDailyEarnings(), - getMiningPool()->getDailyEarningsLabel(), *getMiningPool()); + parseMiningPoolStatsHashRate(MiningPoolStatsFetch::getInstance().getHashRate(), *MiningPoolStatsFetch::getInstance().getPool()) : + parseMiningPoolStatsDailyEarnings(MiningPoolStatsFetch::getInstance().getDailyEarnings(), + MiningPoolStatsFetch::getInstance().getPool()->getDailyEarningsLabel(), + *MiningPoolStatsFetch::getInstance().getPool()); setEpdContent(taskEpdContent); break; } diff --git a/src/lib/timers.cpp b/src/lib/timers.cpp index 3779c2d..4e67951 100644 --- a/src/lib/timers.cpp +++ b/src/lib/timers.cpp @@ -73,8 +73,9 @@ void IRAM_ATTR minuteTimerISR(void *arg) { vTaskNotifyGiveFromISR(bitaxeHandle, &xHigherPriorityTaskWoken); } - if (miningPoolStatsFetchTaskHandle != NULL) { - vTaskNotifyGiveFromISR(miningPoolStatsFetchTaskHandle, &xHigherPriorityTaskWoken); + TaskHandle_t miningPoolHandle = MiningPoolStatsFetch::getInstance().getTaskHandle(); + if (miningPoolHandle != NULL) { + vTaskNotifyGiveFromISR(miningPoolHandle, &xHigherPriorityTaskWoken); } if (xHigherPriorityTaskWoken == pdTRUE) { From d023643090370e32408b129ba4167fa971431e5b Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 5 Jan 2025 21:19:28 +0100 Subject: [PATCH 102/130] Refactor LedHandler to a class --- src/lib/block_notify.cpp | 3 +- src/lib/config.cpp | 78 +-- src/lib/config.hpp | 8 +- src/lib/epd.cpp | 50 +- src/lib/led_handler.cpp | 1324 +++++++++++++++++--------------------- src/lib/led_handler.hpp | 142 ++-- src/lib/nostr_notify.cpp | 3 +- src/lib/ota.cpp | 10 +- src/lib/timers.cpp | 5 +- src/lib/webserver.cpp | 228 +++++-- src/main.cpp | 15 +- 11 files changed, 931 insertions(+), 935 deletions(-) diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index ec72138..111a7a7 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -1,4 +1,5 @@ #include "block_notify.hpp" +#include "led_handler.hpp" char *wsServer; esp_websocket_client_handle_t blockNotifyClient = NULL; @@ -217,7 +218,7 @@ void processNewBlock(uint32_t newBlockHeight) { if (preferences.getBool("ledFlashOnUpd", DEFAULT_LED_FLASH_ON_UPD)) { vTaskDelay(pdMS_TO_TICKS(250)); // Wait until screens are updated - queueLedEffect(LED_FLASH_BLOCK_NOTIFY); + getLedHandler().queueEffect(LED_FLASH_BLOCK_NOTIFY); } } } diff --git a/src/lib/config.cpp b/src/lib/config.cpp index f0db973..5a3fa7d 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -1,4 +1,5 @@ #include "config.hpp" +#include "led_handler.hpp" #define MAX_ATTEMPTS_WIFI_CONNECTION 20 @@ -50,7 +51,8 @@ void setup() setupDisplays(); if (preferences.getBool("ledTestOnPower", DEFAULT_LED_TEST_ON_POWER)) { - queueLedEffect(LED_POWER_TEST); + auto& ledHandler = getLedHandler(); + ledHandler.queueEffect(LED_POWER_TEST); } { std::lock_guard lockMcp(mcpMutex); @@ -60,7 +62,8 @@ void setup() preferences.remove("txPower"); WiFi.eraseAP(); - queueLedEffect(LED_EFFECT_WIFI_ERASE_SETTINGS); + auto& ledHandler = getLedHandler(); + ledHandler.queueEffect(LED_EFFECT_WIFI_ERASE_SETTINGS); } } @@ -76,7 +79,8 @@ void setup() else if (mcp1.read1(1) == LOW) { preferences.clear(); - queueLedEffect(LED_EFFECT_WIFI_ERASE_SETTINGS); + auto& ledHandler = getLedHandler(); + ledHandler.queueEffect(LED_EFFECT_WIFI_ERASE_SETTINGS); nvs_flash_erase(); delay(1000); @@ -116,13 +120,13 @@ void setup() #ifdef HAS_FRONTLIGHT if (!preferences.getBool("flAlwaysOn", DEFAULT_FL_ALWAYS_ON)) { - frontlightFadeOutAll(preferences.getUInt("flEffectDelay"), true); + auto& ledHandler = getLedHandler(); + ledHandler.frontlightFadeOutAll(preferences.getUInt("flEffectDelay"), true); flArray.allOFF(); } #endif forceFullRefresh(); - } void setupWifi() @@ -144,7 +148,8 @@ void setupWifi() // if (!preferences.getBool("wifiConfigured", DEFAULT_WIFI_CONFIGURED) { - queueLedEffect(LED_EFFECT_WIFI_WAIT_FOR_CONFIG); + auto& ledHandler = getLedHandler(); + ledHandler.queueEffect(LED_EFFECT_WIFI_WAIT_FOR_CONFIG); bool buttonPress = false; { @@ -279,7 +284,8 @@ void syncTime() while (!getLocalTime(&timeinfo)) { - queueLedEffect(LED_EFFECT_CONFIGURING); + auto& ledHandler = getLedHandler(); + ledHandler.queueEffect(LED_EFFECT_CONFIGURING); configTime(preferences.getInt("gmtOffset", DEFAULT_TIME_OFFSET_SECONDS), 0, NTP_SERVER); delay(500); @@ -420,13 +426,14 @@ void setupTimers() void finishSetup() { + auto& ledHandler = getLedHandler(); if (preferences.getBool("ledStatus", DEFAULT_LED_STATUS)) { - restoreLedState(); + ledHandler.restoreLedState(); } else { - clearLeds(); + ledHandler.clear(); } } @@ -475,22 +482,9 @@ void setupHardware() Serial.println(F("Error loading WebUI")); } - // { - // File f = LittleFS.open("/qr.txt", "w"); - - // if(f) { - // if (f.print("Hello")) { - // Serial.println(F("Written QR to FS")); - // Serial.printf("\nLittleFS free: %zu\n", LittleFS.totalBytes() - LittleFS.usedBytes()); - // } - // } else { - // Serial.println(F("Can't write QR to FS")); - // } - - // f.close(); - // } - - setupLeds(); + // Initialize LED handler + auto& ledHandler = getLedHandler(); + ledHandler.setup(); WiFi.setHostname(getMyHostname().c_str()); if (!psramInit()) @@ -548,7 +542,8 @@ void setupHardware() #endif #ifdef HAS_FRONTLIGHT - setupFrontlight(); + // Initialize frontlight through LedHandler + ledHandler.initializeFrontlight(); Wire.beginTransmission(0x5C); byte error = Wire.endTransmission(); @@ -570,6 +565,7 @@ void setupHardware() void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { static bool first_connect = true; + auto& ledHandler = getLedHandler(); // Get ledHandler reference once at the start Serial.printf("[WiFi-event] event: %d\n", event); @@ -595,7 +591,7 @@ void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) if (!first_connect) { Serial.println(F("Disconnected from WiFi access point")); - queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR); + ledHandler.queueEffect(LED_EFFECT_WIFI_CONNECT_ERROR); uint8_t reason = info.wifi_sta_disconnected.reason; if (reason) Serial.printf("Disconnect reason: %s, ", @@ -611,13 +607,13 @@ void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) Serial.print("Obtained IP address: "); Serial.println(WiFi.localIP()); if (!first_connect) - queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS); + ledHandler.queueEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS); first_connect = false; break; } case ARDUINO_EVENT_WIFI_STA_LOST_IP: Serial.println(F("Lost IP address and IP address is reset to 0")); - queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR); + ledHandler.queueEffect(LED_EFFECT_WIFI_CONNECT_ERROR); WiFi.reconnect(); break; case ARDUINO_EVENT_WIFI_AP_START: @@ -667,30 +663,6 @@ uint getLastTimeSync() } #ifdef HAS_FRONTLIGHT -void setupFrontlight() -{ - if (!flArray.begin(PCA9685_MODE1_AUTOINCR | PCA9685_MODE1_ALLCALL, PCA9685_MODE2_TOTEMPOLE)) - { - Serial.println(F("FL driver error")); - return; - } - flArray.setFrequency(200); - Serial.println(F("FL driver active")); - - if (!preferences.isKey("flMaxBrightness")) - { - preferences.putUInt("flMaxBrightness", DEFAULT_FL_MAX_BRIGHTNESS); - } - if (!preferences.isKey("flEffectDelay")) - { - preferences.putUInt("flEffectDelay", DEFAULT_FL_EFFECT_DELAY); - } - - if (!preferences.isKey("flFlashOnUpd")) - { - preferences.putBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE); - } -} float getLightLevel() { diff --git a/src/lib/config.hpp b/src/lib/config.hpp index d8e27b6..95c877d 100644 --- a/src/lib/config.hpp +++ b/src/lib/config.hpp @@ -52,10 +52,10 @@ void setupTimers(); void finishSetup(); void setupMcp(); #ifdef HAS_FRONTLIGHT -void setupFrontlight(); +extern BH1750 bh1750; +extern bool hasLuxSensor; float getLightLevel(); bool hasLightLevel(); -extern PCA9685 flArray; #endif String getMyHostname(); @@ -98,6 +98,10 @@ extern MCP23017 mcp1; extern MCP23017 mcp2; #endif +#ifdef HAS_FRONTLIGHT +extern PCA9685 flArray; +#endif + // Expose DataSourceType enum extern DataSourceType getDataSource(); extern void setDataSource(DataSourceType source); \ No newline at end of file diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 04d3c5c..9808aa7 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -140,8 +140,6 @@ const GFXfont *FONT_SATSYMBOL; std::mutex epdUpdateMutex; std::mutex epdMutex[NUM_SCREENS]; -uint8_t qrcode[800]; - #ifdef IS_BTCLOCK_V8 #define EPD_TASK_STACK_SIZE 4096 #else @@ -159,8 +157,6 @@ void forceFullRefresh() } } -GFXfont font90; - void loadFonts(const String& fontName) { if (fontName == FontNames::ANTONIO) { // Load Antonio fonts @@ -628,35 +624,45 @@ bool renderIcon(const uint dispNum, const String &text, bool partial) void renderQr(const uint dispNum, const String &text, bool partial) { #ifdef USE_QR + // Dynamically allocate QR buffer + uint8_t* qrcode = (uint8_t*)malloc(qrcodegen_BUFFER_LEN_MAX); + if (!qrcode) { + log_e("Failed to allocate QR buffer"); + return; + } uint8_t tempBuffer[800]; bool ok = qrcodegen_encodeText( text.substring(2).c_str(), tempBuffer, qrcode, qrcodegen_Ecc_LOW, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true); - const int size = qrcodegen_getSize(qrcode); + if (ok) { + const int size = qrcodegen_getSize(qrcode); + const int padding = floor(float(displays[dispNum].width() - (size * 4)) / 2); + const int paddingY = + floor(float(displays[dispNum].height() - (size * 4)) / 2); + displays[dispNum].setRotation(2); - const int padding = floor(float(displays[dispNum].width() - (size * 4)) / 2); - const int paddingY = - floor(float(displays[dispNum].height() - (size * 4)) / 2); - displays[dispNum].setRotation(2); + displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), + displays[dispNum].height()); + displays[dispNum].fillScreen(GxEPD_WHITE); + const int border = 0; - displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), - displays[dispNum].height()); - displays[dispNum].fillScreen(GxEPD_WHITE); - const int border = 0; - - for (int y = -border; y < size * 4 + border; y++) - { - for (int x = -border; x < size * 4 + border; x++) + for (int y = -border; y < size * 4 + border; y++) { - displays[dispNum].drawPixel( - padding + x, paddingY + y, - qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4)) - ? GxEPD_BLACK - : GxEPD_WHITE); + for (int x = -border; x < size * 4 + border; x++) + { + displays[dispNum].drawPixel( + padding + x, paddingY + y, + qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4)) + ? GxEPD_BLACK + : GxEPD_WHITE); + } } } + + // Free the buffer after we're done + free(qrcode); #endif } diff --git a/src/lib/led_handler.cpp b/src/lib/led_handler.cpp index 806ee9c..3cdb953 100644 --- a/src/lib/led_handler.cpp +++ b/src/lib/led_handler.cpp @@ -1,227 +1,431 @@ #include "led_handler.hpp" -TaskHandle_t ledTaskHandle = NULL; -QueueHandle_t ledTaskQueue = NULL; -Adafruit_NeoPixel pixels(NEOPIXEL_COUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800); -uint ledTaskParams; +// Singleton instance +LedHandler& LedHandler::getInstance() { + static LedHandler instance; + return instance; +} + +LedHandler::LedHandler() + : pixels(NEOPIXEL_COUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800) + , ledTaskHandle(nullptr) + , ledTaskQueue(nullptr) + , ledTaskParams(0) + , dndEnabled(false) + , dndTimeBasedEnabled(false) + , dndTimeRange{23, 0, 7, 0} // Default: 23:00 to 07:00 +#ifdef HAS_FRONTLIGHT + , frontlightOn(false) + , flInTransition(false) +#endif +{ +} + +void LedHandler::setup() { + loadDNDSettings(); + pixels.begin(); + pixels.setBrightness(preferences.getUInt("ledBrightness", DEFAULT_LED_BRIGHTNESS)); + pixels.clear(); + pixels.show(); + setupTask(); + + if (preferences.getBool("ledTestOnPower", DEFAULT_LED_TEST_ON_POWER)) { + while (!ledTaskQueue) { + delay(1); + } + queueEffect(LED_POWER_TEST); + } +} + +void LedHandler::setupTask() { + ledTaskQueue = xQueueCreate(5, sizeof(uint)); + xTaskCreate(ledTask, "LedTask", 2048, this, 10, &ledTaskHandle); +} + +void LedHandler::ledTask(void* pvParameters) { + auto* handler = static_cast(pvParameters); + while (true) { + if (handler->ledTaskQueue != nullptr) { + if (xQueueReceive(handler->ledTaskQueue, &handler->ledTaskParams, portMAX_DELAY) == pdPASS) { + if (preferences.getBool("disableLeds", DEFAULT_DISABLE_LEDS)) { + continue; + } + + std::array oldLights; + for (int i = 0; i < NEOPIXEL_COUNT; i++) { + oldLights[i] = handler->pixels.getPixelColor(i); + } #ifdef HAS_FRONTLIGHT -constexpr uint16_t FL_FADE_STEP = 25; - -bool frontlightOn = false; -bool flInTransition = false; - -void frontlightFlash(int flDelayTime) -{ - if (preferences.getBool("flDisable")) - return; - - if (frontlightOn) - { - frontlightFadeOutAll(flDelayTime, true); - frontlightFadeInAll(flDelayTime, true); - } - else - { - frontlightFadeInAll(flDelayTime, true); - frontlightFadeOutAll(flDelayTime, true); - } -} - -void frontlightFadeInAll() -{ - frontlightFadeInAll(preferences.getUInt("flEffectDelay")); -} - -void frontlightFadeOutAll() -{ - frontlightFadeOutAll(preferences.getUInt("flEffectDelay")); -} - -void frontlightFadeIn(uint num) -{ - frontlightFadeIn(num, preferences.getUInt("flEffectDelay")); -} - -void frontlightFadeOut(uint num) -{ - frontlightFadeOut(num, preferences.getUInt("flEffectDelay")); -} - -void frontlightSetBrightness(uint brightness) -{ - if (isDNDActive()) { - return; // Don't change brightness during DND mode - } - if (brightness > 4096) - { - return; - } - - for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) - { - flArray.setPWM(ledPin, 0, brightness); - } -} - -void frontlightFadeInAll(int flDelayTime) -{ - frontlightFadeInAll(flDelayTime, false); -} - -void frontlightFadeInAll(int flDelayTime, bool staggered) -{ - if (preferences.getBool("flDisable") || frontlightIsOn() || flInTransition) - return; - - flInTransition = true; - - const int maxBrightness = preferences.getUInt("flMaxBrightness"); - - if (staggered) - { - int step = FL_FADE_STEP; - int staggerDelay = flDelayTime / NUM_SCREENS; - - for (int dutyCycle = 0; dutyCycle <= maxBrightness + (NUM_SCREENS - 1) * maxBrightness / NUM_SCREENS; dutyCycle += step) - { - for (int ledPin = 0; ledPin < NUM_SCREENS; ledPin++) - { - int ledBrightness = dutyCycle - ledPin * maxBrightness / NUM_SCREENS; - if (ledBrightness < 0) - ledBrightness = 0; - else if (ledBrightness > maxBrightness) - ledBrightness = maxBrightness; - - flArray.setPWM(ledPin + 1, 0, ledBrightness); - } - vTaskDelay(pdMS_TO_TICKS(staggerDelay)); - } - } - else - { - for (int dutyCycle = 0; dutyCycle <= maxBrightness; dutyCycle += FL_FADE_STEP) - { - for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) - { - flArray.setPWM(ledPin, 0, dutyCycle); - } - vTaskDelay(pdMS_TO_TICKS(flDelayTime)); - } - } - frontlightOn = true; - flInTransition = false; -} - -void frontlightFadeOutAll(int flDelayTime) -{ - frontlightFadeOutAll(flDelayTime, false); -} - -void frontlightFadeOutAll(int flDelayTime, bool staggered) -{ - if (preferences.getBool("flDisable")) - return; - if (!frontlightIsOn()) - return; - if (flInTransition) - return; - flInTransition = true; - - if (staggered) - { - int maxBrightness = preferences.getUInt("flMaxBrightness"); - int step = FL_FADE_STEP; - int staggerDelay = flDelayTime / NUM_SCREENS; - - for (int dutyCycle = maxBrightness; dutyCycle >= 0; dutyCycle -= step) - { - for (int ledPin = 0; ledPin < NUM_SCREENS; ledPin++) - { - int ledBrightness = dutyCycle - (NUM_SCREENS - 1 - ledPin) * maxBrightness / NUM_SCREENS; - if (ledBrightness < 0) - ledBrightness = 0; - else if (ledBrightness > maxBrightness) - ledBrightness = maxBrightness; - - flArray.setPWM(ledPin + 1, 0, ledBrightness); - } - vTaskDelay(pdMS_TO_TICKS(staggerDelay)); - } - } - else - { - for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= FL_FADE_STEP) - { - for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) - { - flArray.setPWM(ledPin, 0, dutyCycle); - } - vTaskDelay(pdMS_TO_TICKS(flDelayTime)); - } - } - - flArray.allOFF(); - frontlightOn = false; - flInTransition = false; -} - -std::vector frontlightGetStatus() -{ - std::vector statuses; - for (int ledPin = 1; ledPin <= NUM_SCREENS; ledPin++) - { - uint16_t a = 0, b = 0; - flArray.getPWM(ledPin, &a, &b); - statuses.push_back(round(b - a / 4096)); - } - - return statuses; -} - -bool frontlightIsOn() -{ - return frontlightOn; -} - -void frontlightFadeIn(uint num, int flDelayTime) -{ - if (isDNDActive()) { - return; // Don't change brightness during DND mode - } - if (preferences.getBool("flDisable")) - return; - for (int dutyCycle = 0; dutyCycle <= preferences.getUInt("flMaxBrightness"); dutyCycle += 5) - { - flArray.setPWM(num, 0, dutyCycle); - vTaskDelay(pdMS_TO_TICKS(flDelayTime)); - } -} - -void frontlightFadeOut(uint num, int flDelayTime) -{ - if (isDNDActive()) { - return; // Don't change brightness during DND mode - } - if (preferences.getBool("flDisable")) - return; - if (!frontlightIsOn()) - return; - - for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= 5) - { - flArray.setPWM(num, 0, dutyCycle); - vTaskDelay(pdMS_TO_TICKS(flDelayTime)); - } -} + uint flDelayTime = preferences.getUInt("flEffectDelay"); #endif -// Do Not Disturb mode variables -bool dndEnabled = false; -bool dndTimeBasedEnabled = false; -DNDTimeRange dndTimeRange = {23, 0, 7, 0}; // Default: 23:00 to 07:00 + switch (handler->ledTaskParams) { + case LED_POWER_TEST: +#ifdef HAS_FRONTLIGHT + handler->frontlightFadeInAll(preferences.getUInt("flEffectDelay"), true); +#endif + handler->rainbow(20); + handler->pixels.clear(); + break; -void loadDNDSettings() { + case LED_EFFECT_WIFI_CONNECT_ERROR: + handler->blinkDelayTwoColor(100, 3, handler->pixels.Color(8, 161, 236), + handler->pixels.Color(255, 0, 0)); + break; + + case LED_EFFECT_CONFIGURING: + for (int i = NEOPIXEL_COUNT; i--; i > 0) { + for (int j = NEOPIXEL_COUNT; j--; j > 0) { + uint32_t c = handler->pixels.Color(0, 0, 0); + if (i == j) + c = handler->pixels.Color(0, 0, 255); + handler->pixels.setPixelColor(j, c); + } + handler->pixels.show(); + delay(100); + } + handler->pixels.clear(); + handler->pixels.show(); + break; + + case LED_FLASH_ERROR: + handler->blinkDelayColor(250, 3, 255, 0, 0); + break; + + case LED_EFFECT_HEARTBEAT: + handler->blinkDelayColor(150, 2, 0, 0, 255); + break; + + case LED_DATA_BLOCK_ERROR: + handler->blinkDelayColor(150, 2, 128, 0, 128); + break; + + case LED_DATA_PRICE_ERROR: + handler->blinkDelayColor(150, 2, 177, 90, 31); + break; + + case LED_FLASH_IDENTIFY: + handler->blinkDelayTwoColor(100, 2, handler->pixels.Color(255, 0, 0), + handler->pixels.Color(0, 255, 255)); + handler->blinkDelayTwoColor(100, 2, handler->pixels.Color(0, 255, 0), + handler->pixels.Color(0, 0, 255)); + break; + + case LED_EFFECT_WIFI_CONNECT_SUCCESS: + case LED_FLASH_SUCCESS: + handler->blinkDelayColor(150, 3, 0, 255, 0); + break; + + case LED_PROGRESS_100: + handler->pixels.setPixelColor(0, handler->pixels.Color(0, 255, 0)); + [[fallthrough]]; + case LED_PROGRESS_75: + handler->pixels.setPixelColor(1, handler->pixels.Color(0, 255, 0)); + [[fallthrough]]; + case LED_PROGRESS_50: + handler->pixels.setPixelColor(2, handler->pixels.Color(0, 255, 0)); + [[fallthrough]]; + case LED_PROGRESS_25: + handler->pixels.setPixelColor(3, handler->pixels.Color(0, 255, 0)); + handler->pixels.show(); + break; + + case LED_EFFECT_NOSTR_ZAP: + { +#ifdef HAS_FRONTLIGHT + bool frontlightWasOn = false; + if (preferences.getBool("flFlashOnZap", DEFAULT_FL_FLASH_ON_ZAP)) { + if (handler->frontlightOn) { + frontlightWasOn = true; + handler->frontlightFadeOutAll(flDelayTime, true); + } else { + handler->frontlightFadeInAll(flDelayTime, true); + } + } +#endif + for (int flash = 0; flash < random(7, 10); flash++) { + handler->lightningStrike(); + delay(random(50, 150)); + } +#ifdef HAS_FRONTLIGHT + if (preferences.getBool("flFlashOnZap", DEFAULT_FL_FLASH_ON_ZAP)) { + vTaskDelay(pdMS_TO_TICKS(10)); + if (frontlightWasOn) { + handler->frontlightFadeInAll(flDelayTime, true); + } else { + handler->frontlightFadeOutAll(flDelayTime, true); + } + } +#endif + break; + } + + case LED_FLASH_UPDATE: + handler->blinkDelayTwoColor(250, 3, handler->pixels.Color(0, 230, 0), + handler->pixels.Color(230, 230, 0)); + break; + + case LED_FLASH_BLOCK_NOTIFY: + { +#ifdef HAS_FRONTLIGHT + bool frontlightWasOn = false; + if (preferences.getBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE)) { + if (handler->frontlightOn) { + frontlightWasOn = true; + handler->frontlightFadeOutAll(flDelayTime, true); + } else { + handler->frontlightFadeInAll(flDelayTime, true); + } + } +#endif + handler->blinkDelayTwoColor(250, 3, handler->pixels.Color(224, 67, 0), + handler->pixels.Color(8, 2, 0)); +#ifdef HAS_FRONTLIGHT + if (preferences.getBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE)) { + vTaskDelay(pdMS_TO_TICKS(10)); + if (frontlightWasOn) { + handler->frontlightFadeInAll(flDelayTime, true); + } else { + handler->frontlightFadeOutAll(flDelayTime, true); + } + } +#endif + break; + } + + case LED_EFFECT_WIFI_WAIT_FOR_CONFIG: + handler->blinkDelayTwoColor(100, 1, handler->pixels.Color(8, 161, 236), + handler->pixels.Color(156, 225, 240)); + break; + + case LED_EFFECT_WIFI_ERASE_SETTINGS: + handler->blinkDelay(100, 3); + break; + + case LED_EFFECT_WIFI_CONNECTING: + for (int i = NEOPIXEL_COUNT; i >= 0; i--) { + for (int j = NEOPIXEL_COUNT; j >= 0; j--) { + if (j == i) { + handler->pixels.setPixelColor(i, handler->pixels.Color(16, 197, 236)); + } else { + handler->pixels.setPixelColor(j, handler->pixels.Color(0, 0, 0)); + } + } + handler->pixels.show(); + vTaskDelay(pdMS_TO_TICKS(100)); + } + break; + + case LED_EFFECT_PAUSE_TIMER: + for (int i = NEOPIXEL_COUNT; i >= 0; i--) { + for (int j = NEOPIXEL_COUNT; j >= 0; j--) { + uint32_t c = handler->pixels.Color(0, 0, 0); + if (i == j) + c = handler->pixels.Color(0, 255, 0); + handler->pixels.setPixelColor(j, c); + } + handler->pixels.show(); + delay(100); + } + handler->pixels.setPixelColor(0, handler->pixels.Color(255, 0, 0)); + handler->pixels.show(); + delay(900); + handler->pixels.clear(); + handler->pixels.show(); + break; + + case LED_EFFECT_START_TIMER: + handler->pixels.clear(); + handler->pixels.setPixelColor((NEOPIXEL_COUNT - 1), handler->pixels.Color(255, 0, 0)); + handler->pixels.show(); + delay(900); + for (int i = NEOPIXEL_COUNT; i--; i > 0) { + for (int j = NEOPIXEL_COUNT; j--; j > 0) { + uint32_t c = handler->pixels.Color(0, 0, 0); + if (i == j) + c = handler->pixels.Color(0, 255, 0); + handler->pixels.setPixelColor(j, c); + } + handler->pixels.show(); + delay(100); + } + handler->pixels.clear(); + handler->pixels.show(); + break; + } + + // Restore previous state unless power test + for (int i = 0; i < NEOPIXEL_COUNT; i++) { + handler->pixels.setPixelColor(i, oldLights[i]); + } + handler->pixels.show(); + } + } + } +} + +bool LedHandler::queueEffect(uint effect) { + if (isDNDActive()) { + return false; + } + if (ledTaskQueue == nullptr) { + return false; + } + xQueueSend(ledTaskQueue, &effect, portMAX_DELAY); + return true; +} + +void LedHandler::clear() { + preferences.putBool("ledStatus", false); + pixels.clear(); + pixels.show(); +} + +void LedHandler::setLights(int r, int g, int b) { + setLights(pixels.Color(r, g, b)); +} + +void LedHandler::setLights(uint32_t color) { + bool ledStatus = true; + for (int i = 0; i < NEOPIXEL_COUNT; i++) { + pixels.setPixelColor(i, color); + } + pixels.show(); + + if (color == pixels.Color(0, 0, 0)) { + ledStatus = false; + } else { + saveLedState(); + } + preferences.putBool("ledStatus", ledStatus); +} + +void LedHandler::saveLedState() { + for (int i = 0; i < pixels.numPixels(); i++) { + int pixelColor = pixels.getPixelColor(i); + char key[12]; + snprintf(key, 12, "%s%d", "ledColor_", i); + preferences.putUInt(key, pixelColor); + } + xTaskNotifyGive(eventSourceTaskHandle); +} + +void LedHandler::restoreLedState() { + for (int i = 0; i < pixels.numPixels(); i++) { + char key[12]; + snprintf(key, 12, "%s%d", "ledColor_", i); + uint pixelColor = preferences.getUInt(key, pixels.Color(0, 0, 0)); + pixels.setPixelColor(i, pixelColor); + } + pixels.show(); +} + +void LedHandler::rainbow(int wait) { + for (long firstPixelHue = 0; firstPixelHue < 5 * 65536; firstPixelHue += 256) { + pixels.rainbow(firstPixelHue); + pixels.show(); + delayMicroseconds(wait); + } +} + +void LedHandler::theaterChase(uint32_t color, int wait) { + for (int a = 0; a < 10; a++) { + for (int b = 0; b < 3; b++) { + pixels.clear(); + for (int c = b; c < pixels.numPixels(); c += 3) { + pixels.setPixelColor(c, color); + } + pixels.show(); + vTaskDelay(pdMS_TO_TICKS(wait)); + } + } +} + +void LedHandler::theaterChaseRainbow(int wait) { + int firstPixelHue = 0; + for (int a = 0; a < 30; a++) { + for (int b = 0; b < 3; b++) { + pixels.clear(); + for (int c = b; c < pixels.numPixels(); c += 3) { + int hue = firstPixelHue + c * 65536L / pixels.numPixels(); + uint32_t color = pixels.gamma32(pixels.ColorHSV(hue)); + pixels.setPixelColor(c, color); + } + pixels.show(); + vTaskDelay(pdMS_TO_TICKS(wait)); + firstPixelHue += 65536 / 90; + } + } +} + +void LedHandler::lightningStrike() { + uint32_t PURPLE = pixels.Color(128, 0, 128); + uint32_t YELLOW = pixels.Color(255, 226, 41); + + for (int i = 0; i < pixels.numPixels(); i++) { + pixels.setPixelColor(i, random(2) == 0 ? YELLOW : PURPLE); + } + pixels.show(); + delay(random(10, 50)); +} + +void LedHandler::blinkDelay(int d, int times) { + for (int j = 0; j < times; j++) { + pixels.setPixelColor(0, pixels.Color(255, 0, 0)); + pixels.setPixelColor(1, pixels.Color(0, 255, 0)); + pixels.setPixelColor(2, pixels.Color(255, 0, 0)); + pixels.setPixelColor(3, pixels.Color(0, 255, 0)); + pixels.show(); + vTaskDelay(pdMS_TO_TICKS(d)); + + pixels.setPixelColor(0, pixels.Color(255, 255, 0)); + pixels.setPixelColor(1, pixels.Color(0, 255, 255)); + pixels.setPixelColor(2, pixels.Color(255, 255, 0)); + pixels.setPixelColor(3, pixels.Color(0, 255, 255)); + pixels.show(); + vTaskDelay(pdMS_TO_TICKS(d)); + } + pixels.clear(); + pixels.show(); +} + +void LedHandler::blinkDelayColor(int d, int times, uint r, uint g, uint b) { + for (int j = 0; j < times; j++) { + for (int i = 0; i < NEOPIXEL_COUNT; i++) { + pixels.setPixelColor(i, pixels.Color(r, g, b)); + } + pixels.show(); + vTaskDelay(pdMS_TO_TICKS(d)); + + pixels.clear(); + pixels.show(); + vTaskDelay(pdMS_TO_TICKS(d)); + } + pixels.clear(); + pixels.show(); +} + +void LedHandler::blinkDelayTwoColor(int d, int times, const uint32_t& c1, const uint32_t& c2) { + for (int j = 0; j < times; j++) { + for (int i = 0; i < NEOPIXEL_COUNT; i++) { + pixels.setPixelColor(i, c1); + } + pixels.show(); + vTaskDelay(pdMS_TO_TICKS(d)); + + for (int i = 0; i < NEOPIXEL_COUNT; i++) { + pixels.setPixelColor(i, c2); + } + pixels.show(); + vTaskDelay(pdMS_TO_TICKS(d)); + } + pixels.clear(); + pixels.show(); +} + +// DND Implementation +void LedHandler::loadDNDSettings() { dndEnabled = preferences.getBool("dndEnabled", false); dndTimeBasedEnabled = preferences.getBool("dndTimeEnabled", false); @@ -231,29 +435,29 @@ void loadDNDSettings() { dndTimeRange.endMinute = preferences.getUChar("dndEndMin", 0); } -void setDNDEnabled(bool enabled) { +void LedHandler::setDNDEnabled(bool enabled) { dndEnabled = enabled; preferences.putBool("dndEnabled", enabled); if (enabled && isDNDActive()) { - clearLeds(); - #ifdef HAS_FRONTLIGHT + clear(); +#ifdef HAS_FRONTLIGHT frontlightFadeOutAll(); - #endif +#endif } } -void setDNDTimeBasedEnabled(bool enabled) { +void LedHandler::setDNDTimeBasedEnabled(bool enabled) { dndTimeBasedEnabled = enabled; preferences.putBool("dndTimeEnabled", enabled); if (enabled && isDNDActive()) { - clearLeds(); - #ifdef HAS_FRONTLIGHT + clear(); +#ifdef HAS_FRONTLIGHT frontlightFadeOutAll(); - #endif +#endif } } -void setDNDTimeRange(uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute) { +void LedHandler::setDNDTimeRange(uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute) { dndTimeRange.startHour = startHour; dndTimeRange.startMinute = startMinute; dndTimeRange.endHour = endHour; @@ -265,21 +469,19 @@ void setDNDTimeRange(uint8_t startHour, uint8_t startMinute, uint8_t endHour, ui preferences.putUChar("dndEndMin", endMinute); } -bool isTimeInDNDRange(uint8_t hour, uint8_t minute) { +bool LedHandler::isTimeInDNDRange(uint8_t hour, uint8_t minute) const { uint16_t currentTime = hour * 60 + minute; uint16_t startTime = dndTimeRange.startHour * 60 + dndTimeRange.startMinute; uint16_t endTime = dndTimeRange.endHour * 60 + dndTimeRange.endMinute; if (startTime <= endTime) { - // Simple case: start time is before end time (e.g., 09:00 to 17:00) return currentTime >= startTime && currentTime < endTime; } else { - // Complex case: start time is after end time (e.g., 23:00 to 07:00) return currentTime >= startTime || currentTime < endTime; } } -bool isDNDActive() { +bool LedHandler::isDNDActive() const { if (dndEnabled) { return true; } @@ -295,518 +497,174 @@ bool isDNDActive() { return false; } -void ledTask(void *parameter) -{ - while (1) - { - if (ledTaskQueue != NULL) - { - if (xQueueReceive(ledTaskQueue, &ledTaskParams, portMAX_DELAY) == - pdPASS) - { - - if (preferences.getBool("disableLeds", DEFAULT_DISABLE_LEDS)) - { - continue; - } - - std::array oldLights; - - // get current state - for (int i = 0; i < NEOPIXEL_COUNT; i++) - { - oldLights[i] = pixels.getPixelColor(i); - } #ifdef HAS_FRONTLIGHT - uint flDelayTime = preferences.getUInt("flEffectDelay"); -#endif - switch (ledTaskParams) - { - case LED_POWER_TEST: -#ifdef HAS_FRONTLIGHT - frontlightFadeInAll(preferences.getUInt("flEffectDelay"), true); -#endif - ledRainbow(20); - pixels.clear(); - break; - case LED_EFFECT_WIFI_CONNECT_ERROR: - blinkDelayTwoColor(100, 3, pixels.Color(8, 161, 236), - pixels.Color(255, 0, 0)); - break; - case LED_EFFECT_CONFIGURING: - for (int i = NEOPIXEL_COUNT; i--; i > 0) - { - for (int j = NEOPIXEL_COUNT; j--; j > 0) - { - uint32_t c = pixels.Color(0, 0, 0); - if (i == j) - c = pixels.Color(0, 0, 255); +// Frontlight implementation +void LedHandler::frontlightFlash(int flDelayTime) { + if (preferences.getBool("flDisable")) { + return; + } - pixels.setPixelColor(j, c); - } + if (frontlightOn) { + frontlightFadeOutAll(flDelayTime, true); + frontlightFadeInAll(flDelayTime, true); + } else { + frontlightFadeInAll(flDelayTime, true); + frontlightFadeOutAll(flDelayTime, true); + } +} - pixels.show(); +void LedHandler::frontlightFadeInAll() { + frontlightFadeInAll(preferences.getUInt("flEffectDelay")); +} - delay(100); - } +void LedHandler::frontlightFadeOutAll() { + frontlightFadeOutAll(preferences.getUInt("flEffectDelay")); +} - pixels.clear(); - pixels.show(); - break; - case LED_FLASH_ERROR: - blinkDelayColor(250, 3, 255, 0, 0); - break; - case LED_EFFECT_HEARTBEAT: - blinkDelayColor(150, 2, 0, 0, 255); - break; - case LED_DATA_BLOCK_ERROR: - blinkDelayColor(150, 2, 128, 0, 128); - break; - case LED_DATA_PRICE_ERROR: - blinkDelayColor(150, 2, 177, 90, 31); - break; - case LED_FLASH_IDENTIFY: - blinkDelayTwoColor(100, 2, pixels.Color(255, 0, 0), - pixels.Color(0, 255, 255)); - blinkDelayTwoColor(100, 2, pixels.Color(0, 255, 0), - pixels.Color(0, 0, 255)); - break; - case LED_EFFECT_WIFI_CONNECT_SUCCESS: - case LED_FLASH_SUCCESS: - blinkDelayColor(150, 3, 0, 255, 0); - break; - case LED_PROGRESS_100: - pixels.setPixelColor(0, pixels.Color(0, 255, 0)); - case LED_PROGRESS_75: - pixels.setPixelColor(1, pixels.Color(0, 255, 0)); - case LED_PROGRESS_50: - pixels.setPixelColor(2, pixels.Color(0, 255, 0)); - case LED_PROGRESS_25: - pixels.setPixelColor(3, pixels.Color(0, 255, 0)); - pixels.show(); - break; - case LED_EFFECT_NOSTR_ZAP: - { -#ifdef HAS_FRONTLIGHT - bool frontlightWasOn = false; +void LedHandler::frontlightFadeIn(uint num) { + frontlightFadeIn(num, preferences.getUInt("flEffectDelay")); +} - if (preferences.getBool("flFlashOnZap", DEFAULT_FL_FLASH_ON_ZAP)) - { - if (frontlightOn) - { - frontlightWasOn = true; - frontlightFadeOutAll(flDelayTime, true); +void LedHandler::frontlightFadeOut(uint num) { + frontlightFadeOut(num, preferences.getUInt("flEffectDelay")); +} + +void LedHandler::frontlightSetBrightness(uint brightness) { + if (isDNDActive() || brightness > 4096) { + return; + } + + for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) { + flArray.setPWM(ledPin, 0, brightness); + } +} + +std::vector LedHandler::frontlightGetStatus() { + std::vector statuses; + for (int ledPin = 1; ledPin <= NUM_SCREENS; ledPin++) { + uint16_t a = 0, b = 0; + flArray.getPWM(ledPin, &a, &b); + statuses.push_back(round(b - a / 4096)); + } + return statuses; +} + +void LedHandler::frontlightFadeInAll(int flDelayTime, bool staggered) { + if (preferences.getBool("flDisable") || frontlightIsOn() || flInTransition) { + return; + } + + flInTransition = true; + const int maxBrightness = preferences.getUInt("flMaxBrightness"); + + if (staggered) { + int step = FL_FADE_STEP; + int staggerDelay = flDelayTime / NUM_SCREENS; + + for (int dutyCycle = 0; dutyCycle <= maxBrightness + (NUM_SCREENS - 1) * maxBrightness / NUM_SCREENS; dutyCycle += step) { + for (int ledPin = 0; ledPin < NUM_SCREENS; ledPin++) { + int ledBrightness = dutyCycle - ledPin * maxBrightness / NUM_SCREENS; + if (ledBrightness < 0) { + ledBrightness = 0; + } else if (ledBrightness > maxBrightness) { + ledBrightness = maxBrightness; + } + flArray.setPWM(ledPin + 1, 0, ledBrightness); } - else - { - frontlightFadeInAll(flDelayTime, true); - } - } -#endif - for (int flash = 0; flash < random(7, 10); flash++) - { - lightningStrike(); - delay(random(50, 150)); - } - // blinkDelayColor(250, 3, 142, 48, 235); - // blinkDelayTwoColor(250, 3, pixels.Color(142, 48, 235), - // pixels.Color(169, 21, 255)); -#ifdef HAS_FRONTLIGHT - if (preferences.getBool("flFlashOnZap", DEFAULT_FL_FLASH_ON_ZAP)) - { - vTaskDelay(pdMS_TO_TICKS(10)); - if (frontlightWasOn) - { - frontlightFadeInAll(flDelayTime, true); - } - else - { - frontlightFadeOutAll(flDelayTime, true); - } - } -#endif - break; + vTaskDelay(pdMS_TO_TICKS(staggerDelay)); } - case LED_FLASH_UPDATE: - blinkDelayTwoColor(250, 3, pixels.Color(0, 230, 0), - pixels.Color(230, 230, 0)); - break; - case LED_FLASH_BLOCK_NOTIFY: - { -#ifdef HAS_FRONTLIGHT - bool frontlightWasOn = false; + } else { + for (int dutyCycle = 0; dutyCycle <= maxBrightness; dutyCycle += FL_FADE_STEP) { + for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) { + flArray.setPWM(ledPin, 0, dutyCycle); + } + vTaskDelay(pdMS_TO_TICKS(flDelayTime)); + } + } + frontlightOn = true; + flInTransition = false; +} - if (preferences.getBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE)) - { - if (frontlightOn) - { - frontlightWasOn = true; - frontlightFadeOutAll(flDelayTime, true); +void LedHandler::frontlightFadeOutAll(int flDelayTime, bool staggered) { + if (preferences.getBool("flDisable") || !frontlightIsOn() || flInTransition) { + return; + } + + flInTransition = true; + if (staggered) { + int maxBrightness = preferences.getUInt("flMaxBrightness"); + int step = FL_FADE_STEP; + int staggerDelay = flDelayTime / NUM_SCREENS; + + for (int dutyCycle = maxBrightness; dutyCycle >= 0; dutyCycle -= step) { + for (int ledPin = 0; ledPin < NUM_SCREENS; ledPin++) { + int ledBrightness = dutyCycle - (NUM_SCREENS - 1 - ledPin) * maxBrightness / NUM_SCREENS; + if (ledBrightness < 0) { + ledBrightness = 0; + } else if (ledBrightness > maxBrightness) { + ledBrightness = maxBrightness; + } + flArray.setPWM(ledPin + 1, 0, ledBrightness); } - else - { - frontlightFadeInAll(flDelayTime, true); + vTaskDelay(pdMS_TO_TICKS(staggerDelay)); + } + } else { + for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= FL_FADE_STEP) { + for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) { + flArray.setPWM(ledPin, 0, dutyCycle); } - } + vTaskDelay(pdMS_TO_TICKS(flDelayTime)); + } + } + + flArray.allOFF(); + frontlightOn = false; + flInTransition = false; +} + +void LedHandler::frontlightFadeIn(uint num, int flDelayTime) { + if (isDNDActive() || preferences.getBool("flDisable")) { + return; + } + + for (int dutyCycle = 0; dutyCycle <= preferences.getUInt("flMaxBrightness"); dutyCycle += 5) { + flArray.setPWM(num, 0, dutyCycle); + vTaskDelay(pdMS_TO_TICKS(flDelayTime)); + } +} + +void LedHandler::frontlightFadeOut(uint num, int flDelayTime) { + if (isDNDActive() || preferences.getBool("flDisable") || !frontlightIsOn()) { + return; + } + + for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= 5) { + flArray.setPWM(num, 0, dutyCycle); + vTaskDelay(pdMS_TO_TICKS(flDelayTime)); + } +} + +void LedHandler::initializeFrontlight() { + if (!flArray.begin(PCA9685_MODE1_AUTOINCR | PCA9685_MODE1_ALLCALL, PCA9685_MODE2_TOTEMPOLE)) + { + Serial.println(F("FL driver error")); + return; + } + flArray.setFrequency(200); + Serial.println(F("FL driver active")); + + if (!preferences.isKey("flMaxBrightness")) + { + preferences.putUInt("flMaxBrightness", DEFAULT_FL_MAX_BRIGHTNESS); + } + if (!preferences.isKey("flEffectDelay")) + { + preferences.putUInt("flEffectDelay", DEFAULT_FL_EFFECT_DELAY); + } + + if (!preferences.isKey("flFlashOnUpd")) + { + preferences.putBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE); + } +} #endif - blinkDelayTwoColor(250, 3, pixels.Color(224, 67, 0), - pixels.Color(8, 2, 0)); -#ifdef HAS_FRONTLIGHT - if (preferences.getBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE)) - { - vTaskDelay(pdMS_TO_TICKS(10)); - if (frontlightWasOn) - { - frontlightFadeInAll(flDelayTime, true); - } - else - { - frontlightFadeOutAll(flDelayTime, true); - } - } -#endif - break; - } - case LED_EFFECT_WIFI_WAIT_FOR_CONFIG: - blinkDelayTwoColor(100, 1, pixels.Color(8, 161, 236), - pixels.Color(156, 225, 240)); - break; - case LED_EFFECT_WIFI_ERASE_SETTINGS: - blinkDelay(100, 3); - break; - case LED_EFFECT_WIFI_CONNECTING: - for (int i = NEOPIXEL_COUNT; i >= 0; i--) - { - for (int j = NEOPIXEL_COUNT; j >= 0; j--) - { - if (j == i) - { - pixels.setPixelColor(i, pixels.Color(16, 197, 236)); - } - else - { - pixels.setPixelColor(j, pixels.Color(0, 0, 0)); - } - } - pixels.show(); - vTaskDelay(pdMS_TO_TICKS(100)); - } - break; - case LED_EFFECT_PAUSE_TIMER: - for (int i = NEOPIXEL_COUNT; i >= 0; i--) - { - for (int j = NEOPIXEL_COUNT; j >= 0; j--) - { - uint32_t c = pixels.Color(0, 0, 0); - if (i == j) - c = pixels.Color(0, 255, 0); - pixels.setPixelColor(j, c); - } - - pixels.show(); - - delay(100); - } - pixels.setPixelColor(0, pixels.Color(255, 0, 0)); - pixels.show(); - - delay(900); - - pixels.clear(); - pixels.show(); - break; - case LED_EFFECT_START_TIMER: - pixels.clear(); - pixels.setPixelColor((NEOPIXEL_COUNT - 1), pixels.Color(255, 0, 0)); - pixels.show(); - - delay(900); - - for (int i = NEOPIXEL_COUNT; i--; i > 0) - { - for (int j = NEOPIXEL_COUNT; j--; j > 0) - { - uint32_t c = pixels.Color(0, 0, 0); - if (i == j) - c = pixels.Color(0, 255, 0); - - pixels.setPixelColor(j, c); - } - - pixels.show(); - - delay(100); - } - - pixels.clear(); - pixels.show(); - break; - } - - // revert to previous state unless power test - - for (int i = 0; i < NEOPIXEL_COUNT; i++) - { - pixels.setPixelColor(i, oldLights[i]); - } - - pixels.show(); - } - } - } -} - -void setupLeds() -{ - loadDNDSettings(); - pixels.begin(); - pixels.setBrightness(preferences.getUInt("ledBrightness", DEFAULT_LED_BRIGHTNESS)); - pixels.clear(); - pixels.show(); - setupLedTask(); - if (preferences.getBool("ledTestOnPower", DEFAULT_LED_TEST_ON_POWER)) - { - while (!ledTaskQueue) - { - delay(1); - // wait until queue is available - } - queueLedEffect(LED_POWER_TEST); - } -} - -void setupLedTask() -{ - ledTaskQueue = xQueueCreate(5, sizeof(uint)); - - xTaskCreate(ledTask, "LedTask", 2048, NULL, 10, &ledTaskHandle); -} - -void blinkDelay(int d, int times) -{ - for (int j = 0; j < times; j++) - { - pixels.setPixelColor(0, pixels.Color(255, 0, 0)); - pixels.setPixelColor(1, pixels.Color(0, 255, 0)); - pixels.setPixelColor(2, pixels.Color(255, 0, 0)); - pixels.setPixelColor(3, pixels.Color(0, 255, 0)); - pixels.show(); - vTaskDelay(pdMS_TO_TICKS(d)); - - pixels.setPixelColor(0, pixels.Color(255, 255, 0)); - pixels.setPixelColor(1, pixels.Color(0, 255, 255)); - pixels.setPixelColor(2, pixels.Color(255, 255, 0)); - pixels.setPixelColor(3, pixels.Color(0, 255, 255)); - pixels.show(); - vTaskDelay(pdMS_TO_TICKS(d)); - } - pixels.clear(); - pixels.show(); -} - -void blinkDelayColor(int d, int times, uint r, uint g, uint b) -{ - for (int j = 0; j < times; j++) - { - for (int i = 0; i < NEOPIXEL_COUNT; i++) - { - pixels.setPixelColor(i, pixels.Color(r, g, b)); - } - - pixels.show(); - vTaskDelay(pdMS_TO_TICKS(d)); - - pixels.clear(); - pixels.show(); - vTaskDelay(pdMS_TO_TICKS(d)); - } - pixels.clear(); - pixels.show(); -} - -void blinkDelayTwoColor(int d, int times, const uint32_t& c1, const uint32_t& c2) -{ - for (int j = 0; j < times; j++) - { - for (int i = 0; i < NEOPIXEL_COUNT; i++) - { - pixels.setPixelColor(i, c1); - } - pixels.show(); - vTaskDelay(pdMS_TO_TICKS(d)); - - for (int i = 0; i < NEOPIXEL_COUNT; i++) - { - pixels.setPixelColor(i, c2); - } - pixels.show(); - vTaskDelay(pdMS_TO_TICKS(d)); - } - pixels.clear(); - pixels.show(); -} - -void clearLeds() -{ - preferences.putBool("ledStatus", false); - pixels.clear(); - pixels.show(); -} - -void setLights(int r, int g, int b) { setLights(pixels.Color(r, g, b)); } - -void setLights(uint32_t color) -{ - bool ledStatus = true; - - for (int i = 0; i < NEOPIXEL_COUNT; i++) - { - pixels.setPixelColor(i, color); - } - pixels.show(); - - if (color == pixels.Color(0, 0, 0)) - { - ledStatus = false; - } - else - { - saveLedState(); - } - preferences.putBool("ledStatus", ledStatus); -} - -void saveLedState() -{ - for (int i = 0; i < pixels.numPixels(); i++) - { - int pixelColor = pixels.getPixelColor(i); - char key[12]; - snprintf(key, 12, "%s%d", "ledColor_", i); - preferences.putUInt(key, pixelColor); - } - - xTaskNotifyGive(eventSourceTaskHandle); -} - -void restoreLedState() -{ - for (int i = 0; i < pixels.numPixels(); i++) - { - char key[12]; - snprintf(key, 12, "%s%d", "ledColor_", i); - uint pixelColor = preferences.getUInt(key, pixels.Color(0, 0, 0)); - pixels.setPixelColor(i, pixelColor); - } - - pixels.show(); -} - -QueueHandle_t getLedTaskQueue() { return ledTaskQueue; } - -bool queueLedEffect(uint effect) { - if (isDNDActive()) { - return false; // Don't queue any effects during DND mode - } - if (ledTaskQueue == NULL) - { - return false; - } - - uint flashType = effect; - xQueueSend(ledTaskQueue, &flashType, portMAX_DELAY); - return true; -} - -void ledRainbow(int wait) -{ - // Hue of first pixel runs 5 complete loops through the color wheel. - // Color wheel has a range of 65536 but it's OK if we roll over, so - // just count from 0 to 5*65536. Adding 256 to firstPixelHue each time - // means we'll make 5*65536/256 = 1280 passes through this loop: - for (long firstPixelHue = 0; firstPixelHue < 5 * 65536; - firstPixelHue += 256) - { - // strip.rainbow() can take a single argument (first pixel hue) or - // optionally a few extras: number of rainbow repetitions (default 1), - // saturation and value (brightness) (both 0-255, similar to the - // ColorHSV() function, default 255), and a true/false flag for whether - // to apply gamma correction to provide 'truer' colors (default true). - pixels.rainbow(firstPixelHue); - // Above line is equivalent to: - // strip.rainbow(firstPixelHue, 1, 255, 255, true); - pixels.show(); // Update strip with new contents - delayMicroseconds(wait); - // vTaskDelay(pdMS_TO_TICKS(wait)); // Pause for a moment - } -} - -void ledTheaterChase(uint32_t color, int wait) -{ - for (int a = 0; a < 10; a++) - { // Repeat 10 times... - for (int b = 0; b < 3; b++) - { // 'b' counts from 0 to 2... - pixels.clear(); // Set all pixels in RAM to 0 (off) - // 'c' counts up from 'b' to end of strip in steps of 3... - for (int c = b; c < pixels.numPixels(); c += 3) - { - pixels.setPixelColor(c, color); // Set pixel 'c' to value 'color' - } - pixels.show(); // Update strip with new contents - vTaskDelay(pdMS_TO_TICKS(wait)); // Pause for a moment - } - } -} - -void ledTheaterChaseRainbow(int wait) -{ - int firstPixelHue = 0; // First pixel starts at red (hue 0) - for (int a = 0; a < 30; a++) - { // Repeat 30 times... - for (int b = 0; b < 3; b++) - { // 'b' counts from 0 to 2... - pixels.clear(); // Set all pixels in RAM to 0 (off) - // 'c' counts up from 'b' to end of strip in increments of 3... - for (int c = b; c < pixels.numPixels(); c += 3) - { - // hue of pixel 'c' is offset by an amount to make one full - // revolution of the color wheel (range 65536) along the length - // of the strip (strip.numPixels() steps): - int hue = firstPixelHue + c * 65536L / pixels.numPixels(); - uint32_t color = pixels.gamma32(pixels.ColorHSV(hue)); // hue -> RGB - pixels.setPixelColor(c, color); // Set pixel 'c' to value 'color' - } - pixels.show(); // Update strip with new contents - vTaskDelay(pdMS_TO_TICKS(wait)); // Pause for a moment - firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames - } - } -} - -void lightningStrike() -{ - uint32_t PURPLE = pixels.Color(128, 0, 128); - uint32_t YELLOW = pixels.Color(255, 226, 41); - - // Randomly choose which LEDs to light up - for (int i = 0; i < pixels.numPixels(); i++) - { - if (random(2) == 0) - { // 50% chance for each LED - pixels.setPixelColor(i, YELLOW); - } - else - { - pixels.setPixelColor(i, PURPLE); - } - } - pixels.show(); - - delay(random(10, 50)); // Flash duration - - // Return to purple background - // setAllPixels(PURPLE); -} - -Adafruit_NeoPixel getPixels() { return pixels; } diff --git a/src/lib/led_handler.hpp b/src/lib/led_handler.hpp index fe72ffa..e599e2a 100644 --- a/src/lib/led_handler.hpp +++ b/src/lib/led_handler.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "lib/shared.hpp" #include "lib/webserver.hpp" @@ -15,12 +16,11 @@ #define NEOPIXEL_COUNT 4 #endif +// LED effect constants const int LED_FLASH_ERROR = 0; const int LED_FLASH_SUCCESS = 1; const int LED_FLASH_UPDATE = 2; - const int LED_EFFECT_CONFIGURING = 10; - const int LED_FLASH_BLOCK_NOTIFY = 4; const int LED_EFFECT_START_TIMER = 5; const int LED_EFFECT_PAUSE_TIMER = 6; @@ -30,61 +30,15 @@ const int LED_EFFECT_WIFI_CONNECTING = 101; const int LED_EFFECT_WIFI_CONNECT_ERROR = 102; const int LED_EFFECT_WIFI_CONNECT_SUCCESS = 103; const int LED_EFFECT_WIFI_ERASE_SETTINGS = 104; - const int LED_PROGRESS_25 = 200; const int LED_PROGRESS_50 = 201; const int LED_PROGRESS_75 = 202; const int LED_PROGRESS_100 = 203; - const int LED_DATA_PRICE_ERROR = 300; const int LED_DATA_BLOCK_ERROR = 301; - const int LED_EFFECT_NOSTR_ZAP = 400; - const int LED_FLASH_IDENTIFY = 990; const int LED_POWER_TEST = 999; -extern TaskHandle_t ledTaskHandle; -extern Adafruit_NeoPixel pixels; - -void ledTask(void *pvParameters); -void setupLeds(); -void setupLedTask(); -void blinkDelay(int d, int times); -void blinkDelayColor(int d, int times, uint r, uint g, uint b); -void blinkDelayTwoColor(int d, int times, const uint32_t& c1, const uint32_t& c2); -void clearLeds(); -void saveLedState(); -void restoreLedState(); -QueueHandle_t getLedTaskQueue(); -bool queueLedEffect(uint effect); -void setLights(int r, int g, int b); -void setLights(uint32_t color); -void ledRainbow(int wait); -void ledTheaterChaseRainbow(int wait); -void ledTheaterChase(uint32_t color, int wait); -Adafruit_NeoPixel getPixels(); -void lightningStrike(); - -#ifdef HAS_FRONTLIGHT -void frontlightFlash(int flDelayTime); -void frontlightFadeInAll(); -void frontlightFadeOutAll(); -void frontlightFadeIn(uint num); -void frontlightFadeOut(uint num); - -std::vector frontlightGetStatus(); - -void frontlightSetBrightness(uint brightness); -bool frontlightIsOn(); - -void frontlightFadeInAll(int flDelayTime); -void frontlightFadeInAll(int flDelayTime, bool staggered); -void frontlightFadeOutAll(int flDelayTime); -void frontlightFadeOutAll(int flDelayTime, bool staggered); - -void frontlightFadeIn(uint num, int flDelayTime); -void frontlightFadeOut(uint num, int flDelayTime); -#endif // Do Not Disturb mode settings struct DNDTimeRange { @@ -94,12 +48,88 @@ struct DNDTimeRange { uint8_t endMinute; }; -extern bool dndEnabled; -extern bool dndTimeBasedEnabled; -extern DNDTimeRange dndTimeRange; +class LedHandler { +public: + static LedHandler& getInstance(); + + // Delete copy constructor and assignment operator + LedHandler(const LedHandler&) = delete; + LedHandler& operator=(const LedHandler&) = delete; -void setDNDEnabled(bool enabled); -void setDNDTimeBasedEnabled(bool enabled); -void setDNDTimeRange(uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute); -bool isDNDActive(); -bool isTimeInDNDRange(uint8_t hour, uint8_t minute); \ No newline at end of file + void setup(); + void setupTask(); + bool queueEffect(uint effect); + void clear(); + void setLights(int r, int g, int b); + void setLights(uint32_t color); + void saveLedState(); + void restoreLedState(); + QueueHandle_t getTaskQueue() const { return ledTaskQueue; } + Adafruit_NeoPixel& getPixels() { return pixels; } + + // DND methods + void setDNDEnabled(bool enabled); + void setDNDTimeBasedEnabled(bool enabled); + void setDNDTimeRange(uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute); + bool isDNDActive() const; + bool isTimeInDNDRange(uint8_t hour, uint8_t minute) const; + + // DND getters + bool isDNDEnabled() const { return dndEnabled; } + bool isDNDTimeBasedEnabled() const { return dndTimeBasedEnabled; } + uint8_t getDNDStartHour() const { return dndTimeRange.startHour; } + uint8_t getDNDStartMinute() const { return dndTimeRange.startMinute; } + uint8_t getDNDEndHour() const { return dndTimeRange.endHour; } + uint8_t getDNDEndMinute() const { return dndTimeRange.endMinute; } + + // Effect methods + void rainbow(int wait); + void theaterChase(uint32_t color, int wait); + void theaterChaseRainbow(int wait); + void lightningStrike(); + void blinkDelay(int d, int times); + void blinkDelayColor(int d, int times, uint r, uint g, uint b); + void blinkDelayTwoColor(int d, int times, const uint32_t& c1, const uint32_t& c2); + +#ifdef HAS_FRONTLIGHT + void frontlightFlash(int flDelayTime); + void frontlightFadeInAll(); + void frontlightFadeOutAll(); + void frontlightFadeIn(uint num); + void frontlightFadeOut(uint num); + std::vector frontlightGetStatus(); + void frontlightSetBrightness(uint brightness); + bool frontlightIsOn() const { return frontlightOn; } + void frontlightFadeInAll(int flDelayTime, bool staggered = false); + void frontlightFadeOutAll(int flDelayTime, bool staggered = false); + void frontlightFadeIn(uint num, int flDelayTime); + void frontlightFadeOut(uint num, int flDelayTime); + void initializeFrontlight(); +#endif + +private: + LedHandler(); // Private constructor for singleton + void loadDNDSettings(); + static void ledTask(void* pvParameters); + + Adafruit_NeoPixel pixels; + TaskHandle_t ledTaskHandle; + QueueHandle_t ledTaskQueue; + uint ledTaskParams; + + // DND members + bool dndEnabled; + bool dndTimeBasedEnabled; + DNDTimeRange dndTimeRange; + +#ifdef HAS_FRONTLIGHT + static constexpr uint16_t FL_FADE_STEP = 25; + bool frontlightOn; + bool flInTransition; +#endif +}; + +// Global accessor function +inline LedHandler& getLedHandler() { + return LedHandler::getInstance(); +} \ No newline at end of file diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index b9a7a46..3c996a2 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -1,4 +1,5 @@ #include "nostr_notify.hpp" +#include "led_handler.hpp" std::vector pools; nostr::Transport *transport; @@ -286,7 +287,7 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event) vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250)); if (preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP)) { - queueLedEffect(LED_EFFECT_NOSTR_ZAP); + getLedHandler().queueEffect(LED_EFFECT_NOSTR_ZAP); } if (timerPeriod > 0) { diff --git a/src/lib/ota.cpp b/src/lib/ota.cpp index c481b72..b42a505 100644 --- a/src/lib/ota.cpp +++ b/src/lib/ota.cpp @@ -1,4 +1,5 @@ #include "ota.hpp" +#include "led_handler.hpp" TaskHandle_t taskOtaHandle = NULL; bool isOtaUpdating = false; @@ -31,6 +32,9 @@ void setupOTA() void onOTAProgress(unsigned int progress, unsigned int total) { uint percentage = progress / (total / 100); + auto& ledHandler = getLedHandler(); + auto& pixels = ledHandler.getPixels(); + pixels.fill(pixels.Color(0, 255, 0)); if (percentage < 100) { @@ -84,15 +88,15 @@ void handleOTATask(void *parameter) { if (msg.updateType == UPDATE_ALL) { isOtaUpdating = true; - queueLedEffect(LED_FLASH_UPDATE); + getLedHandler().queueEffect(LED_FLASH_UPDATE); int resultWebUi = downloadUpdateHandler(UPDATE_WEBUI); - queueLedEffect(LED_FLASH_UPDATE); + getLedHandler().queueEffect(LED_FLASH_UPDATE); int resultFw = downloadUpdateHandler(UPDATE_FIRMWARE); if (resultWebUi == 0 && resultFw == 0) { ESP.restart(); } else { - queueLedEffect(LED_FLASH_ERROR); + getLedHandler().queueEffect(LED_FLASH_ERROR); vTaskDelay(pdMS_TO_TICKS(3000)); ESP.restart(); } diff --git a/src/lib/timers.cpp b/src/lib/timers.cpp index 4e67951..850ead3 100644 --- a/src/lib/timers.cpp +++ b/src/lib/timers.cpp @@ -1,4 +1,5 @@ #include "timers.hpp" +#include "led_handler.hpp" esp_timer_handle_t screenRotateTimer; esp_timer_handle_t minuteTimer; @@ -49,11 +50,11 @@ void setTimerActive(bool status) { if (status) { esp_timer_start_periodic(screenRotateTimer, getTimerSeconds() * usPerSecond); - queueLedEffect(LED_EFFECT_START_TIMER); + getLedHandler().queueEffect(LED_EFFECT_START_TIMER); preferences.putBool("timerActive", true); } else { esp_timer_stop(screenRotateTimer); - queueLedEffect(LED_EFFECT_PAUSE_TIMER); + getLedHandler().queueEffect(LED_EFFECT_PAUSE_TIMER); preferences.putBool("timerActive", false); } diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 2ba0a4d..4897811 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -1,4 +1,6 @@ #include "webserver.hpp" +#include "lib/led_handler.hpp" +#include "lib/shared.hpp" static const char* JSON_CONTENT = "application/json"; @@ -231,6 +233,7 @@ void asyncFirmwareUpdateHandler(AsyncWebServerRequest *request, String filename, JsonDocument getStatusObject() { + auto& ledHandler = getLedHandler(); JsonDocument root; root["currentScreen"] = ScreenHandler::getCurrentScreen(); @@ -238,25 +241,21 @@ JsonDocument getStatusObject() root["timerRunning"] = isTimerActive(); root["isOTAUpdating"] = getIsOTAUpdating(); root["espUptime"] = esp_timer_get_time() / 1000000; - // root["currentPrice"] = getPrice(); - // root["currentBlockHeight"] = getBlockHeight(); root["espFreeHeap"] = ESP.getFreeHeap(); root["espHeapSize"] = ESP.getHeapSize(); - // root["espFreePsram"] = ESP.getFreePsram(); - // root["espPsramSize"] = ESP.getPsramSize(); JsonObject conStatus = root["connectionStatus"].to(); conStatus["price"] = isPriceNotifyConnected(); conStatus["blocks"] = isBlockNotifyConnected(); conStatus["V2"] = V2Notify::isV2NotifyConnected(); - conStatus["nostr"] = nostrConnected(); root["rssi"] = WiFi.RSSI(); root["currency"] = getCurrencyCode(ScreenHandler::getCurrentCurrency()); + #ifdef HAS_FRONTLIGHT - std::vector statuses = frontlightGetStatus(); + std::vector statuses = ledHandler.frontlightGetStatus(); uint16_t arr[NUM_SCREENS]; std::copy(statuses.begin(), statuses.end(), arr); @@ -270,22 +269,24 @@ JsonDocument getStatusObject() #endif // Add DND status - root["dnd"]["enabled"] = dndEnabled; - root["dnd"]["timeBasedEnabled"] = dndTimeBasedEnabled; - root["dnd"]["startTime"] = String(dndTimeRange.startHour) + ":" + - (dndTimeRange.startMinute < 10 ? "0" : "") + String(dndTimeRange.startMinute); - root["dnd"]["endTime"] = String(dndTimeRange.endHour) + ":" + - (dndTimeRange.endMinute < 10 ? "0" : "") + String(dndTimeRange.endMinute); - root["dnd"]["active"] = isDNDActive(); + root["dnd"]["enabled"] = ledHandler.isDNDEnabled(); + root["dnd"]["timeBasedEnabled"] = ledHandler.isDNDTimeBasedEnabled(); + root["dnd"]["startTime"] = String(ledHandler.getDNDStartHour()) + ":" + + (ledHandler.getDNDStartMinute() < 10 ? "0" : "") + String(ledHandler.getDNDStartMinute()); + root["dnd"]["endTime"] = String(ledHandler.getDNDEndHour()) + ":" + + (ledHandler.getDNDEndMinute() < 10 ? "0" : "") + String(ledHandler.getDNDEndMinute()); + root["dnd"]["active"] = ledHandler.isDNDActive(); return root; } JsonDocument getLedStatusObject() { + auto& ledHandler = getLedHandler(); + auto& pixels = ledHandler.getPixels(); + JsonDocument root; JsonArray colors = root["data"].to(); - // Adafruit_NeoPixel pix = getPixels(); for (uint i = 0; i < pixels.numPixels(); i++) { @@ -295,13 +296,7 @@ JsonDocument getLedStatusObject() uint blue = pixColor & 0xFF; char hexColor[8]; snprintf(hexColor, sizeof(hexColor), "#%02X%02X%02X", red, green, blue); - - - JsonObject object = colors.add(); - object["red"] = red; - object["green"] = green; - object["blue"] = blue; - object["hex"] = hexColor; + colors.add(hexColor); } return root; @@ -621,24 +616,26 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) // Handle DND settings if (settings.containsKey("dnd")) { JsonObject dndObj = settings["dnd"]; + auto& ledHandler = getLedHandler(); + if (dndObj.containsKey("timeBasedEnabled")) { - setDNDTimeBasedEnabled(dndObj["timeBasedEnabled"].as()); + ledHandler.setDNDTimeBasedEnabled(dndObj["timeBasedEnabled"].as()); } if (dndObj.containsKey("startHour") && dndObj.containsKey("startMinute") && dndObj.containsKey("endHour") && dndObj.containsKey("endMinute")) { - setDNDTimeRange( - dndObj["startHour"].as(), - dndObj["startMinute"].as(), - dndObj["endHour"].as(), - dndObj["endMinute"].as() - ); + ledHandler.setDNDTimeRange( + dndObj["startHour"].as(), + dndObj["startMinute"].as(), + dndObj["endHour"].as(), + dndObj["endMinute"].as()); } } request->send(HTTP_OK); if (settingsChanged) { - queueLedEffect(LED_FLASH_SUCCESS); + auto& ledHandler = getLedHandler(); + ledHandler.queueEffect(LED_FLASH_SUCCESS); } } @@ -659,7 +656,8 @@ void onApiRestart(AsyncWebServerRequest *request) void onApiIdentify(AsyncWebServerRequest *request) { - queueLedEffect(LED_FLASH_IDENTIFY); + auto& ledHandler = getLedHandler(); + ledHandler.queueEffect(LED_FLASH_IDENTIFY); request->send(HTTP_OK); } @@ -797,12 +795,13 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["ceDisableSSL"] = preferences.getBool("ceDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); // Add DND settings - root["dnd"]["enabled"] = dndEnabled; - root["dnd"]["timeBasedEnabled"] = dndTimeBasedEnabled; - root["dnd"]["startHour"] = dndTimeRange.startHour; - root["dnd"]["startMinute"] = dndTimeRange.startMinute; - root["dnd"]["endHour"] = dndTimeRange.endHour; - root["dnd"]["endMinute"] = dndTimeRange.endMinute; + auto& ledHandler = getLedHandler(); + root["dnd"]["enabled"] = ledHandler.isDNDEnabled(); + root["dnd"]["timeBasedEnabled"] = ledHandler.isDNDTimeBasedEnabled(); + root["dnd"]["startHour"] = ledHandler.getDNDStartHour(); + root["dnd"]["startMinute"] = ledHandler.getDNDStartMinute(); + root["dnd"]["endHour"] = ledHandler.getDNDEndHour(); + root["dnd"]["endMinute"] = ledHandler.getDNDEndMinute(); AsyncResponseStream *response = request->beginResponseStream(JSON_CONTENT); @@ -929,7 +928,8 @@ void onApiRestartDataSources(AsyncWebServerRequest *request) void onApiLightsOff(AsyncWebServerRequest *request) { - setLights(0, 0, 0); + auto& ledHandler = getLedHandler(); + ledHandler.setLights(0, 0, 0); request->send(HTTP_OK); } @@ -944,13 +944,15 @@ void onApiLightsSetColor(AsyncWebServerRequest *request) if (rgbColor.compareTo("off") == 0) { - setLights(0, 0, 0); + auto& ledHandler = getLedHandler(); + ledHandler.setLights(0, 0, 0); } else { uint r, g, b; sscanf(rgbColor.c_str(), "%02x%02x%02x", &r, &g, &b); - setLights(r, g, b); + auto& ledHandler = getLedHandler(); + ledHandler.setLights(r, g, b); } JsonDocument doc; @@ -968,6 +970,9 @@ void onApiLightsSetColor(AsyncWebServerRequest *request) void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json) { + auto& ledHandler = getLedHandler(); + auto& pixels = ledHandler.getPixels(); + JsonArray lights = json.as(); if (lights.size() != pixels.numPixels()) @@ -1016,7 +1021,7 @@ void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json) } pixels.show(); - saveLedState(); + ledHandler.saveLedState(); request->send(HTTP_OK); } @@ -1080,19 +1085,21 @@ void onApiShowCurrency(AsyncWebServerRequest *request) #ifdef HAS_FRONTLIGHT void onApiFrontlightOn(AsyncWebServerRequest *request) { - frontlightFadeInAll(); + auto& ledHandler = getLedHandler(); + ledHandler.frontlightFadeInAll(); request->send(HTTP_OK); } void onApiFrontlightStatus(AsyncWebServerRequest *request) { + auto& ledHandler = getLedHandler(); AsyncResponseStream *response = request->beginResponseStream(JSON_CONTENT); JsonDocument root; - std::vector statuses = frontlightGetStatus(); + std::vector statuses = ledHandler.frontlightGetStatus(); uint16_t arr[NUM_SCREENS]; std::copy(statuses.begin(), statuses.end(), arr); @@ -1105,7 +1112,8 @@ void onApiFrontlightStatus(AsyncWebServerRequest *request) void onApiFrontlightFlash(AsyncWebServerRequest *request) { - frontlightFlash(preferences.getUInt("flEffectDelay")); + auto& ledHandler = getLedHandler(); + ledHandler.frontlightFlash(preferences.getUInt("flEffectDelay")); request->send(HTTP_OK); } @@ -1114,7 +1122,8 @@ void onApiFrontlightSetBrightness(AsyncWebServerRequest *request) { if (request->hasParam("b")) { - frontlightSetBrightness(request->getParam("b")->value().toInt()); + auto& ledHandler = getLedHandler(); + ledHandler.frontlightSetBrightness(request->getParam("b")->value().toInt()); request->send(HTTP_OK); } else @@ -1125,21 +1134,51 @@ void onApiFrontlightSetBrightness(AsyncWebServerRequest *request) void onApiFrontlightOff(AsyncWebServerRequest *request) { - frontlightFadeOutAll(); + auto& ledHandler = getLedHandler(); + ledHandler.frontlightFadeOutAll(); request->send(HTTP_OK); } #endif +void onApiDNDTimeBasedEnable(AsyncWebServerRequest *request) { + auto& ledHandler = getLedHandler(); + ledHandler.setDNDTimeBasedEnabled(true); + request->send(200); +} + +void onApiDNDTimeBasedDisable(AsyncWebServerRequest *request) { + auto& ledHandler = getLedHandler(); + ledHandler.setDNDTimeBasedEnabled(false); + request->send(200); +} + +void onApiDNDSetTimeRange(AsyncWebServerRequest *request) { + if (request->hasParam("startHour") && request->hasParam("startMinute") && + request->hasParam("endHour") && request->hasParam("endMinute")) { + auto& ledHandler = getLedHandler(); + uint8_t startHour = request->getParam("startHour")->value().toInt(); + uint8_t startMinute = request->getParam("startMinute")->value().toInt(); + uint8_t endHour = request->getParam("endHour")->value().toInt(); + uint8_t endMinute = request->getParam("endMinute")->value().toInt(); + + ledHandler.setDNDTimeRange(startHour, startMinute, endHour, endMinute); + request->send(200); + } else { + request->send(400); + } +} + void onApiDNDStatus(AsyncWebServerRequest *request) { + auto& ledHandler = getLedHandler(); JsonDocument doc; - doc["enabled"] = dndEnabled; - doc["timeBasedEnabled"] = dndTimeBasedEnabled; - doc["startTime"] = String(dndTimeRange.startHour) + ":" + - (dndTimeRange.startMinute < 10 ? "0" : "") + String(dndTimeRange.startMinute); - doc["endTime"] = String(dndTimeRange.endHour) + ":" + - (dndTimeRange.endMinute < 10 ? "0" : "") + String(dndTimeRange.endMinute); - doc["active"] = isDNDActive(); + doc["enabled"] = ledHandler.isDNDEnabled(); + doc["timeBasedEnabled"] = ledHandler.isDNDTimeBasedEnabled(); + doc["startTime"] = String(ledHandler.getDNDStartHour()) + ":" + + (ledHandler.getDNDStartMinute() < 10 ? "0" : "") + String(ledHandler.getDNDStartMinute()); + doc["endTime"] = String(ledHandler.getDNDEndHour()) + ":" + + (ledHandler.getDNDEndMinute() < 10 ? "0" : "") + String(ledHandler.getDNDEndMinute()); + doc["active"] = ledHandler.isDNDActive(); String response; serializeJson(doc, response); @@ -1147,11 +1186,92 @@ void onApiDNDStatus(AsyncWebServerRequest *request) { } void onApiDNDEnable(AsyncWebServerRequest *request) { - setDNDEnabled(true); + auto& ledHandler = getLedHandler(); + ledHandler.setDNDEnabled(true); request->send(200); } void onApiDNDDisable(AsyncWebServerRequest *request) { - setDNDEnabled(false); + auto& ledHandler = getLedHandler(); + ledHandler.setDNDEnabled(false); request->send(200); +} + +void onApiLightsGet(AsyncWebServerRequest *request) +{ + auto& ledHandler = getLedHandler(); + auto& pixels = ledHandler.getPixels(); + + DynamicJsonDocument doc(1024); + JsonArray lights = doc.createNestedArray("lights"); + + for (uint i = 0; i < pixels.numPixels(); i++) + { + uint32_t pixColor = pixels.getPixelColor(pixels.numPixels() - i - 1); + JsonObject light = lights.createNestedObject(); + light["r"] = (uint8_t)(pixColor >> 16); + light["g"] = (uint8_t)(pixColor >> 8); + light["b"] = (uint8_t)pixColor; + } + + String output; + serializeJson(doc, output); + request->send(200, "application/json", output); +} + +void onApiLightsPost(AsyncWebServerRequest *request, uint8_t *data, size_t len, + size_t index, size_t total) +{ + auto& ledHandler = getLedHandler(); + auto& pixels = ledHandler.getPixels(); + + DynamicJsonDocument doc(1024); + DeserializationError error = deserializeJson(doc, data); + if (error) + { + request->send(400); + return; + } + + JsonArray lights = doc["lights"]; + if (lights.size() != pixels.numPixels()) + { + request->send(400); + return; + } + + for (uint i = 0; i < pixels.numPixels(); i++) + { + JsonObject light = lights[i]; + uint8_t red = light["r"]; + uint8_t green = light["g"]; + uint8_t blue = light["b"]; + + pixels.setPixelColor((pixels.numPixels() - i - 1), + pixels.Color(red, green, blue)); + } + pixels.show(); + + request->send(200); +} + +void onApiSettings(AsyncWebServerRequest *request, JsonVariant &json) +{ + JsonObject settings = json.as(); + auto& ledHandler = getLedHandler(); + + if (settings.containsKey("dnd")) { + JsonObject dndObj = settings["dnd"]; + if (dndObj.containsKey("timeBasedEnabled")) { + ledHandler.setDNDTimeBasedEnabled(dndObj["timeBasedEnabled"].as()); + } + if (dndObj.containsKey("startHour") && dndObj.containsKey("startMinute") && + dndObj.containsKey("endHour") && dndObj.containsKey("endMinute")) { + ledHandler.setDNDTimeRange( + dndObj["startHour"].as(), + dndObj["startMinute"].as(), + dndObj["endHour"].as(), + dndObj["endMinute"].as()); + } + } } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 4943a51..c892a03 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,6 +18,7 @@ #define WEBSERVER_H #include "ESPAsyncWebServer.h" #include "lib/config.hpp" +#include "lib/led_handler.hpp" uint wifiLostConnection; uint priceNotifyLostConnection = 0; @@ -58,13 +59,14 @@ void handleFrontlight() { if (hasLightLevel() && preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE) != 0) { uint lightLevel = getLightLevel(); uint luxThreshold = preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE); + auto& ledHandler = getLedHandler(); if (lightLevel <= 1 && preferences.getBool("flOffWhenDark", DEFAULT_FL_OFF_WHEN_DARK)) { - if (frontlightIsOn()) frontlightFadeOutAll(); - } else if (lightLevel < luxThreshold && !frontlightIsOn()) { - frontlightFadeInAll(); - } else if (frontlightIsOn() && lightLevel > luxThreshold) { - frontlightFadeOutAll(); + if (ledHandler.frontlightIsOn()) ledHandler.frontlightFadeOutAll(); + } else if (lightLevel < luxThreshold && !ledHandler.frontlightIsOn()) { + ledHandler.frontlightFadeInAll(); + } else if (ledHandler.frontlightIsOn() && lightLevel > luxThreshold) { + ledHandler.frontlightFadeOutAll(); } } #endif @@ -100,9 +102,7 @@ void checkMissedBlocks() { } } - void monitorDataConnections() { - // Price notification monitoring if (getPriceNotifyInit() && !preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE) && !isPriceNotifyConnected()) { handlePriceNotifyDisconnection(); @@ -137,7 +137,6 @@ extern "C" void app_main() { bool thirdPartySource = getDataSource() == THIRD_PARTY_SOURCE; - while (true) { if (eventSourceTaskHandle != NULL) { xTaskNotifyGive(eventSourceTaskHandle); From a6a8b5a0710a4555e18201f7c7fc3a3f1e561370 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 5 Jan 2025 22:11:53 +0100 Subject: [PATCH 103/130] Refactor EPD code to EPDManager class --- src/lib/block_notify.cpp | 37 +- src/lib/config.cpp | 60 +-- src/lib/epd.cpp | 867 +++++++++++++++---------------------- src/lib/epd.hpp | 119 +++-- src/lib/nostr_notify.cpp | 20 +- src/lib/ota.cpp | 4 +- src/lib/screen_handler.cpp | 16 +- src/lib/shared.cpp | 3 +- src/lib/shared.hpp | 5 +- src/lib/v2_notify.cpp | 5 + src/lib/webserver.cpp | 34 +- 11 files changed, 532 insertions(+), 638 deletions(-) diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index 111a7a7..37b5b2f 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -181,45 +181,42 @@ void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data) } void processNewBlock(uint32_t newBlockHeight) { - if (newBlockHeight < currentBlockHeight) - return; + if (currentBlockHeight == newBlockHeight) + { + return; + } - currentBlockHeight = newBlockHeight; - - // Serial.printf("New block found: %d\r\n", block["height"].as()); - preferences.putUInt("blockHeight", currentBlockHeight); + currentBlockHeight = newBlockHeight; lastBlockUpdate = esp_timer_get_time() / 1000000; if (workQueue != nullptr) { - WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0}; - xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); - // xTaskNotifyGive(blockUpdateTaskHandle); + WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0}; + xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); + } - if (ScreenHandler::getCurrentScreen() != SCREEN_BLOCK_HEIGHT && - preferences.getBool("stealFocus", DEFAULT_STEAL_FOCUS)) - { + if (ScreenHandler::getCurrentScreen() != SCREEN_BLOCK_HEIGHT && + preferences.getBool("stealFocus", DEFAULT_STEAL_FOCUS)) + { uint64_t timerPeriod = 0; if (isTimerActive()) { - // store timer periode before making inactive to prevent artifacts - timerPeriod = getTimerSeconds(); - esp_timer_stop(screenRotateTimer); + timerPeriod = getTimerSeconds(); + esp_timer_stop(screenRotateTimer); } ScreenHandler::setCurrentScreen(SCREEN_BLOCK_HEIGHT); if (timerPeriod > 0) { - esp_timer_start_periodic(screenRotateTimer, + esp_timer_start_periodic(screenRotateTimer, timerPeriod * usPerSecond); } vTaskDelay(pdMS_TO_TICKS(315*NUM_SCREENS)); // Extra delay because of screen switching - } + } - if (preferences.getBool("ledFlashOnUpd", DEFAULT_LED_FLASH_ON_UPD)) - { + if (preferences.getBool("ledFlashOnUpd", DEFAULT_LED_FLASH_ON_UPD)) + { vTaskDelay(pdMS_TO_TICKS(250)); // Wait until screens are updated getLedHandler().queueEffect(LED_FLASH_BLOCK_NOTIFY); - } } } diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 5a3fa7d..6354a7a 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -48,7 +48,7 @@ void setup() setupPreferences(); setupHardware(); - setupDisplays(); + EPDManager::getInstance().initialize(); if (preferences.getBool("ledTestOnPower", DEFAULT_LED_TEST_ON_POWER)) { auto& ledHandler = getLedHandler(); @@ -115,7 +115,7 @@ void setup() ButtonHandler::setup(); setupOTA(); - waitUntilNoneBusy(); + EPDManager::getInstance().waitUntilNoneBusy(); #ifdef HAS_FRONTLIGHT if (!preferences.getBool("flAlwaysOn", DEFAULT_FL_ALWAYS_ON)) @@ -126,7 +126,7 @@ void setup() } #endif - forceFullRefresh(); + EPDManager::getInstance().forceFullRefresh(); } void setupWifi() @@ -181,8 +181,8 @@ void setupWifi() wifiManager->getConfigPortalSSID().c_str(), softAP_password.c_str()); // delay(6000); - setFgColor(GxEPD_BLACK); - setBgColor(GxEPD_WHITE); + EPDManager::getInstance().setForegroundColor(GxEPD_BLACK); + EPDManager::getInstance().setBackgroundColor(GxEPD_WHITE); const String qrText = "qrWIFI:S:" + wifiManager->getConfigPortalSSID() + ";T:WPA;P:" + softAP_password.c_str() + ";;"; const String explainText = "*SSID: *\r\n" + @@ -212,58 +212,22 @@ void setupWifi() #endif "\r\n\r\n*FW build date:*\r\n" + formattedDate, qrText}; - setEpdContent(epdContent); }); + + EPDManager::getInstance().setContent(epdContent); }); wm.setSaveConfigCallback([]() { preferences.putBool("wifiConfigured", true); delay(1000); - // just restart after succes + // just restart after success ESP.restart(); }); bool ac = wm.autoConnect(softAP_SSID.c_str(), softAP_password.c_str()); - - // waitUntilNoneBusy(); - // std::array epdContent = {"Welcome!", - // "Bienvenidos!", "Use\r\nweb-interface\r\npara configurar", "Use\r\nla - // interfaz web\r\npara configurar", "Or - // restart\r\nwhile\r\nholding\r\n2nd button\r\r\nto start\r\n QR-config", - // "O reinicie\r\nmientras\r\n mantiene presionado\r\nel segundo - // botón\r\r\npara iniciar\r\nQR-config", ""}; setEpdContent(epdContent); - // esp_task_wdt_init(30, false); - // uint count = 0; - // while (WiFi.status() != WL_CONNECTED) - // { - // if (Serial.available() > 0) - // { - // uint8_t b = Serial.read(); - - // if (parse_improv_serial_byte(x_position, b, x_buffer, - // onImprovCommandCallback, onImprovErrorCallback)) - // { - // x_buffer[x_position++] = b; - // } - // else - // { - // x_position = 0; - // } - // } - // count++; - - // if (count > 2000000) { - // queueLedEffect(LED_EFFECT_HEARTBEAT); - // count = 0; - // } - // } - // esp_task_wdt_deinit(); - // esp_task_wdt_reset(); } - - - setFgColor(preferences.getUInt("fgColor", isWhiteVersion() ? GxEPD_BLACK : GxEPD_WHITE)); - setBgColor(preferences.getUInt("bgColor", isWhiteVersion() ? GxEPD_WHITE : GxEPD_BLACK)); + EPDManager::getInstance().setForegroundColor(preferences.getUInt("fgColor", isWhiteVersion() ? GxEPD_BLACK : GxEPD_WHITE)); + EPDManager::getInstance().setBackgroundColor(preferences.getUInt("bgColor", isWhiteVersion() ? GxEPD_WHITE : GxEPD_BLACK)); } // else // { @@ -299,8 +263,8 @@ void setupPreferences() { preferences.begin("btclock", false); - setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR)); - setBgColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR)); + EPDManager::getInstance().setForegroundColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR)); + EPDManager::getInstance().setBackgroundColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR)); setBlockHeight(preferences.getUInt("blockHeight", INITIAL_BLOCK_HEIGHT)); setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD); diff --git a/src/lib/epd.cpp b/src/lib/epd.cpp index 9808aa7..fa389c6 100644 --- a/src/lib/epd.cpp +++ b/src/lib/epd.cpp @@ -1,455 +1,278 @@ #include "epd.hpp" +// Initialize static members #ifdef IS_BTCLOCK_REV_B -Native_Pin EPD_CS[NUM_SCREENS] = { - Native_Pin(2), - Native_Pin(4), - Native_Pin(6), - Native_Pin(10), - Native_Pin(38), - Native_Pin(21), - Native_Pin(17), +Native_Pin EPDManager::EPD_DC(14); +std::array EPDManager::EPD_CS = { + Native_Pin(2), Native_Pin(4), Native_Pin(6), Native_Pin(10), + Native_Pin(38), Native_Pin(21), Native_Pin(17) }; -Native_Pin EPD_BUSY[NUM_SCREENS] = { - Native_Pin(3), - Native_Pin(5), - Native_Pin(7), - Native_Pin(9), - Native_Pin(37), - Native_Pin(18), - Native_Pin(16), +std::array EPDManager::EPD_BUSY = { + Native_Pin(3), Native_Pin(5), Native_Pin(7), Native_Pin(9), + Native_Pin(37), Native_Pin(18), Native_Pin(16) }; -MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = { - MCP23X17_Pin(mcp1, 8), - MCP23X17_Pin(mcp1, 9), - MCP23X17_Pin(mcp1, 10), - MCP23X17_Pin(mcp1, 11), - MCP23X17_Pin(mcp1, 12), - MCP23X17_Pin(mcp1, 13), - MCP23X17_Pin(mcp1, 14), +std::array EPDManager::EPD_RESET = { + MCP23X17_Pin(mcp1, 8), MCP23X17_Pin(mcp1, 9), MCP23X17_Pin(mcp1, 10), + MCP23X17_Pin(mcp1, 11), MCP23X17_Pin(mcp1, 12), MCP23X17_Pin(mcp1, 13), + MCP23X17_Pin(mcp1, 14) }; - -Native_Pin EPD_DC = Native_Pin(14); -#elif IS_BTCLOCK_V8 -Native_Pin EPD_DC = Native_Pin(38); - -MCP23X17_Pin EPD_BUSY[NUM_SCREENS] = { - MCP23X17_Pin(mcp1, 8), - MCP23X17_Pin(mcp1, 9), - MCP23X17_Pin(mcp1, 10), - MCP23X17_Pin(mcp1, 11), - MCP23X17_Pin(mcp1, 12), - MCP23X17_Pin(mcp1, 13), - MCP23X17_Pin(mcp1, 14), - MCP23X17_Pin(mcp1, 4), +#elif defined(IS_BTCLOCK_V8) +Native_Pin EPDManager::EPD_DC(38); +std::array EPDManager::EPD_BUSY = { + MCP23X17_Pin(mcp1, 8), MCP23X17_Pin(mcp1, 9), MCP23X17_Pin(mcp1, 10), + MCP23X17_Pin(mcp1, 11), MCP23X17_Pin(mcp1, 12), MCP23X17_Pin(mcp1, 13), + MCP23X17_Pin(mcp1, 14), MCP23X17_Pin(mcp1, 4) }; - -MCP23X17_Pin EPD_CS[NUM_SCREENS] = { +std::array EPDManager::EPD_CS = { MCP23X17_Pin(mcp2, 8), MCP23X17_Pin(mcp2, 10), MCP23X17_Pin(mcp2, 12), MCP23X17_Pin(mcp2, 14), MCP23X17_Pin(mcp2, 0), MCP23X17_Pin(mcp2, 2), - MCP23X17_Pin(mcp2, 4), MCP23X17_Pin(mcp2, 6)}; - -MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = { - MCP23X17_Pin(mcp2, 9), - MCP23X17_Pin(mcp2, 11), - MCP23X17_Pin(mcp2, 13), - MCP23X17_Pin(mcp2, 15), - MCP23X17_Pin(mcp2, 1), - MCP23X17_Pin(mcp2, 3), - MCP23X17_Pin(mcp2, 5), - MCP23X17_Pin(mcp2, 7), + MCP23X17_Pin(mcp2, 4), MCP23X17_Pin(mcp2, 6) +}; +std::array EPDManager::EPD_RESET = { + MCP23X17_Pin(mcp2, 9), MCP23X17_Pin(mcp2, 11), MCP23X17_Pin(mcp2, 13), + MCP23X17_Pin(mcp2, 15), MCP23X17_Pin(mcp2, 1), MCP23X17_Pin(mcp2, 3), + MCP23X17_Pin(mcp2, 5), MCP23X17_Pin(mcp2, 7) }; #else -Native_Pin EPD_CS[NUM_SCREENS] = { - Native_Pin(2), - Native_Pin(4), - Native_Pin(6), - Native_Pin(10), - Native_Pin(33), - Native_Pin(21), - Native_Pin(17), -#if NUM_SCREENS == 9 - // MCP23X17_Pin(mcp2, 7), - Native_Pin(-1), - Native_Pin(-1), -#endif +Native_Pin EPDManager::EPD_DC(14); +std::array EPDManager::EPD_CS = { + Native_Pin(2), Native_Pin(4), Native_Pin(6), Native_Pin(10), + Native_Pin(33), Native_Pin(21), Native_Pin(17) }; -Native_Pin EPD_BUSY[NUM_SCREENS] = { - Native_Pin(3), - Native_Pin(5), - Native_Pin(7), - Native_Pin(9), - Native_Pin(37), - Native_Pin(18), - Native_Pin(16), +std::array EPDManager::EPD_BUSY = { + Native_Pin(3), Native_Pin(5), Native_Pin(7), Native_Pin(9), + Native_Pin(37), Native_Pin(18), Native_Pin(16) }; -MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = { - MCP23X17_Pin(mcp1, 8), - MCP23X17_Pin(mcp1, 9), - MCP23X17_Pin(mcp1, 10), - MCP23X17_Pin(mcp1, 11), - MCP23X17_Pin(mcp1, 12), - MCP23X17_Pin(mcp1, 13), - MCP23X17_Pin(mcp1, 14), +std::array EPDManager::EPD_RESET = { + MCP23X17_Pin(mcp1, 8), MCP23X17_Pin(mcp1, 9), MCP23X17_Pin(mcp1, 10), + MCP23X17_Pin(mcp1, 11), MCP23X17_Pin(mcp1, 12), MCP23X17_Pin(mcp1, 13), + MCP23X17_Pin(mcp1, 14) }; - -Native_Pin EPD_DC = Native_Pin(14); #endif -GxEPD2_BW displays[NUM_SCREENS] = { - EPD_CLASS(&EPD_CS[0], &EPD_DC, &EPD_RESET_MPD[0], &EPD_BUSY[0]), - EPD_CLASS(&EPD_CS[1], &EPD_DC, &EPD_RESET_MPD[1], &EPD_BUSY[1]), - EPD_CLASS(&EPD_CS[2], &EPD_DC, &EPD_RESET_MPD[2], &EPD_BUSY[2]), - EPD_CLASS(&EPD_CS[3], &EPD_DC, &EPD_RESET_MPD[3], &EPD_BUSY[3]), - EPD_CLASS(&EPD_CS[4], &EPD_DC, &EPD_RESET_MPD[4], &EPD_BUSY[4]), - EPD_CLASS(&EPD_CS[5], &EPD_DC, &EPD_RESET_MPD[5], &EPD_BUSY[5]), - EPD_CLASS(&EPD_CS[6], &EPD_DC, &EPD_RESET_MPD[6], &EPD_BUSY[6]), -#ifdef IS_BTCLOCK_V8 - EPD_CLASS(&EPD_CS[7], &EPD_DC, &EPD_RESET_MPD[7], &EPD_BUSY[7]), -#endif -}; - -std::array currentEpdContent; -std::array epdContent; -uint32_t lastFullRefresh[NUM_SCREENS]; -TaskHandle_t tasks[NUM_SCREENS]; -// TaskHandle_t epdTaskHandle = NULL; - -#define UPDATE_QUEUE_SIZE 14 -QueueHandle_t updateQueue; - -// SemaphoreHandle_t epdUpdateSemaphore[NUM_SCREENS]; - -int fgColor = GxEPD_WHITE; -int bgColor = GxEPD_BLACK; - -struct FontFamily { - GFXfont* big; - GFXfont* medium; - GFXfont* small; -}; - -FontFamily antonioFonts = {nullptr, nullptr, nullptr}; -FontFamily oswaldFonts = {nullptr, nullptr, nullptr}; - -const GFXfont *FONT_SMALL; -const GFXfont *FONT_BIG; -const GFXfont *FONT_MEDIUM; -const GFXfont *FONT_SATSYMBOL; - -std::mutex epdUpdateMutex; -std::mutex epdMutex[NUM_SCREENS]; - -#ifdef IS_BTCLOCK_V8 -#define EPD_TASK_STACK_SIZE 4096 -#else -#define EPD_TASK_STACK_SIZE 2048 -#endif - -#define BUSY_TIMEOUT_COUNT 200 -#define BUSY_RETRY_DELAY pdMS_TO_TICKS(10) - -void forceFullRefresh() -{ - for (uint i = 0; i < NUM_SCREENS; i++) - { - lastFullRefresh[i] = NULL; - } +EPDManager& EPDManager::getInstance() { + static EPDManager instance; + return instance; } -void loadFonts(const String& fontName) { - if (fontName == FontNames::ANTONIO) { - // Load Antonio fonts - antonioFonts.big = FontLoader::loadCompressedFont(Antonio_SemiBold90pt7b_Properties); - antonioFonts.medium = FontLoader::loadCompressedFont(Antonio_SemiBold40pt7b_Properties); - antonioFonts.small = FontLoader::loadCompressedFont(Antonio_SemiBold20pt7b_Properties); - - FONT_BIG = antonioFonts.big; - FONT_MEDIUM = antonioFonts.medium; - FONT_SMALL = antonioFonts.small; - } else if (fontName == FontNames::OSWALD) { - // Load Oswald fonts - oswaldFonts.big = FontLoader::loadCompressedFont(Oswald_Medium80pt7b_Properties); - oswaldFonts.medium = FontLoader::loadCompressedFont(Oswald_Medium30pt7b_Properties); - oswaldFonts.small = FontLoader::loadCompressedFont(Oswald_Medium20pt7b_Properties); - - FONT_BIG = oswaldFonts.big; - FONT_MEDIUM = oswaldFonts.medium; - FONT_SMALL = oswaldFonts.small; - } - - FONT_SATSYMBOL = FontLoader::loadCompressedFont(Satoshi_Symbol90pt7b_Properties); -} - -void setupDisplays() { - // Load fonts based on preference - String fontName = preferences.getString("fontName", DEFAULT_FONT_NAME); - loadFonts(fontName); - - // Initialize displays - std::lock_guard lockMcp(mcpMutex); - for (uint i = 0; i < NUM_SCREENS; i++) { - displays[i].init(0, true, 30); - } - - // Create update queue and task - updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem)); - xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", EPD_TASK_STACK_SIZE * 2, NULL, 11, NULL); - - // Create display update tasks - for (uint i = 0; i < NUM_SCREENS; i++) { - int *taskParam = new int; - *taskParam = i; - xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), EPD_TASK_STACK_SIZE, taskParam, 11, &tasks[i]); - } - - // Check for storage mode (prevents burn-in) - if (mcp1.read1(0) == LOW) { - setFgColor(GxEPD_BLACK); - setBgColor(GxEPD_WHITE); - epdContent.fill(""); - } else { - // Initialize with custom text or default - String customText = preferences.getString("displayText", DEFAULT_BOOT_TEXT); - std::array newContent; - newContent.fill(" "); - - for (size_t i = 0; i < std::min(customText.length(), (size_t)NUM_SCREENS); i++) { - newContent[i] = String(customText[i]); +EPDManager::EPDManager() + : currentContent{} + , content{} + , lastFullRefresh{} + , tasks{} + , updateQueue{nullptr} + , antonioFonts{nullptr, nullptr, nullptr} + , oswaldFonts{nullptr, nullptr, nullptr} + , fontSmall{nullptr} + , fontBig{nullptr} + , fontMedium{nullptr} + , fontSatsymbol{nullptr} + , bgColor{GxEPD_BLACK} + , fgColor{GxEPD_WHITE} + , displays{ + #ifdef IS_BTCLOCK_V8 + EPD_CLASS(&EPD_CS[0], &EPD_DC, &EPD_RESET[0], &EPD_BUSY[0]), + EPD_CLASS(&EPD_CS[1], &EPD_DC, &EPD_RESET[1], &EPD_BUSY[1]), + EPD_CLASS(&EPD_CS[2], &EPD_DC, &EPD_RESET[2], &EPD_BUSY[2]), + EPD_CLASS(&EPD_CS[3], &EPD_DC, &EPD_RESET[3], &EPD_BUSY[3]), + EPD_CLASS(&EPD_CS[4], &EPD_DC, &EPD_RESET[4], &EPD_BUSY[4]), + EPD_CLASS(&EPD_CS[5], &EPD_DC, &EPD_RESET[5], &EPD_BUSY[5]), + EPD_CLASS(&EPD_CS[6], &EPD_DC, &EPD_RESET[6], &EPD_BUSY[6]), + EPD_CLASS(&EPD_CS[7], &EPD_DC, &EPD_RESET[7], &EPD_BUSY[7]) + #else + EPD_CLASS(&EPD_CS[0], &EPD_DC, &EPD_RESET[0], &EPD_BUSY[0]), + EPD_CLASS(&EPD_CS[1], &EPD_DC, &EPD_RESET[1], &EPD_BUSY[1]), + EPD_CLASS(&EPD_CS[2], &EPD_DC, &EPD_RESET[2], &EPD_BUSY[2]), + EPD_CLASS(&EPD_CS[3], &EPD_DC, &EPD_RESET[3], &EPD_BUSY[3]), + EPD_CLASS(&EPD_CS[4], &EPD_DC, &EPD_RESET[4], &EPD_BUSY[4]), + EPD_CLASS(&EPD_CS[5], &EPD_DC, &EPD_RESET[5], &EPD_BUSY[5]), + EPD_CLASS(&EPD_CS[6], &EPD_DC, &EPD_RESET[6], &EPD_BUSY[6]) + #endif } - - epdContent = newContent; - } - - setEpdContent(epdContent); +{ } -void setEpdContent(std::array newEpdContent) -{ - setEpdContent(newEpdContent, false); -} - -void setEpdContent(std::array newEpdContent) -{ - std::array conv; - - for (size_t i = 0; i < newEpdContent.size(); ++i) - { - conv[i] = String(newEpdContent[i].c_str()); +EPDManager::~EPDManager() { + // Clean up tasks + for (auto& task : tasks) { + if (task != nullptr) { + vTaskDelete(task); + } } - return setEpdContent(conv); + // Clean up queue + if (updateQueue != nullptr) { + vQueueDelete(updateQueue); + } + + // Clean up fonts + delete antonioFonts.big; + delete antonioFonts.medium; + delete antonioFonts.small; + delete oswaldFonts.big; + delete oswaldFonts.medium; + delete oswaldFonts.small; } -void setEpdContent(std::array newEpdContent, - bool forceUpdate) -{ - std::lock_guard lock(epdUpdateMutex); +void EPDManager::initialize() { + // Load fonts based on preference + String fontName = preferences.getString("fontName", DEFAULT_FONT_NAME); + loadFonts(fontName); + // Initialize displays + std::lock_guard lockMcp(mcpMutex); + for (auto& display : displays) { + display.init(0, true, 30); + } + + // Create update queue and task + updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem)); + xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", EPD_TASK_STACK_SIZE * 2, nullptr, 11, nullptr); + + // Create display update tasks + for (size_t i = 0; i < NUM_SCREENS; i++) { + auto* taskParam = new int(i); + xTaskCreate(updateDisplayTask, ("EpdUpd" + String(i)).c_str(), EPD_TASK_STACK_SIZE, + taskParam, 11, &tasks[i]); + } + + // Check for storage mode (prevents burn-in) + if (mcp1.read1(0) == LOW) { + setForegroundColor(GxEPD_BLACK); + setBackgroundColor(GxEPD_WHITE); + content.fill(""); + } else { + // Initialize with custom text or default + String customText = preferences.getString("displayText", DEFAULT_BOOT_TEXT); + std::array newContent; + newContent.fill(" "); + + for (size_t i = 0; i < std::min(customText.length(), (size_t)NUM_SCREENS); i++) { + newContent[i] = String(customText[i]); + } + + content = newContent; + } + + setContent(content); +} + +void EPDManager::loadFonts(const String& fontName) { + if (fontName == FontNames::ANTONIO) { + // Load Antonio fonts + antonioFonts.big = FontLoader::loadCompressedFont(Antonio_SemiBold90pt7b_Properties); + antonioFonts.medium = FontLoader::loadCompressedFont(Antonio_SemiBold40pt7b_Properties); + antonioFonts.small = FontLoader::loadCompressedFont(Antonio_SemiBold20pt7b_Properties); + + fontBig = antonioFonts.big; + fontMedium = antonioFonts.medium; + fontSmall = antonioFonts.small; + } else if (fontName == FontNames::OSWALD) { + // Load Oswald fonts + oswaldFonts.big = FontLoader::loadCompressedFont(Oswald_Medium80pt7b_Properties); + oswaldFonts.medium = FontLoader::loadCompressedFont(Oswald_Medium30pt7b_Properties); + oswaldFonts.small = FontLoader::loadCompressedFont(Oswald_Medium20pt7b_Properties); + + fontBig = oswaldFonts.big; + fontMedium = oswaldFonts.medium; + fontSmall = oswaldFonts.small; + } + + fontSatsymbol = FontLoader::loadCompressedFont(Satoshi_Symbol90pt7b_Properties); +} + +void EPDManager::forceFullRefresh() { + std::fill(lastFullRefresh.begin(), lastFullRefresh.end(), 0); +} + +void EPDManager::setContent(const std::array& newContent, bool forceUpdate) { + std::lock_guard lock(updateMutex); waitUntilNoneBusy(); - for (uint i = 0; i < NUM_SCREENS; i++) - { - if (newEpdContent[i].compareTo(currentEpdContent[i]) != 0 || forceUpdate) - { - epdContent[i] = newEpdContent[i]; - UpdateDisplayTaskItem dispUpdate = {i}; + for (size_t i = 0; i < NUM_SCREENS; i++) { + if (newContent[i].compareTo(currentContent[i]) != 0 || forceUpdate) { + content[i] = newContent[i]; + UpdateDisplayTaskItem dispUpdate{static_cast(i)}; xQueueSend(updateQueue, &dispUpdate, portMAX_DELAY); } } } -void prepareDisplayUpdateTask(void *pvParameters) -{ - UpdateDisplayTaskItem receivedItem; - - while (1) - { - // Wait for a work item to be available in the queue - if (xQueueReceive(updateQueue, &receivedItem, portMAX_DELAY)) - { - uint epdIndex = receivedItem.dispNum; - std::lock_guard lock(epdMutex[epdIndex]); - // displays[epdIndex].init(0, false); // Little longer reset duration - // because of MCP - - bool updatePartial = true; - - if (epdContent[epdIndex].length() > 1 && strstr(epdContent[epdIndex].c_str(), "/") != NULL) - { - String top = epdContent[epdIndex].substring( - 0, epdContent[epdIndex].indexOf("/")); - String bottom = epdContent[epdIndex].substring( - epdContent[epdIndex].indexOf("/") + 1); - splitText(epdIndex, top, bottom, updatePartial); - } - else if (epdContent[epdIndex].startsWith(F("qr"))) - { - renderQr(epdIndex, epdContent[epdIndex], updatePartial); - } - else if (epdContent[epdIndex].startsWith(F("mdi"))) - { - bool updated = renderIcon(epdIndex, epdContent[epdIndex], updatePartial); - if (!updated) - { - continue; - } - } - else if (epdContent[epdIndex].length() > 5) - { - renderText(epdIndex, epdContent[epdIndex], updatePartial); - } - else - { - if (epdContent[epdIndex].length() == 2) - { - showChars(epdIndex, epdContent[epdIndex], updatePartial, FONT_BIG); - } - else if (epdContent[epdIndex].length() > 1 && epdContent[epdIndex].indexOf(".") == -1) - { - if (epdContent[epdIndex].equals("STS")) - { - showDigit(epdIndex, 'S', updatePartial, - FONT_SATSYMBOL); - } - else - { - showChars(epdIndex, epdContent[epdIndex], updatePartial, - FONT_MEDIUM); - } - } - else - { - - showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, - FONT_BIG); - } - } - - xTaskNotifyGive(tasks[epdIndex]); - } +void EPDManager::setContent(const std::array& newContent) { + std::array conv; + for (size_t i = 0; i < newContent.size(); ++i) { + conv[i] = String(newContent[i].c_str()); } + setContent(conv); } -extern "C" void updateDisplay(void *pvParameters) noexcept -{ - const int epdIndex = *(int *)pvParameters; - delete (int *)pvParameters; +std::array EPDManager::getCurrentContent() const { + return currentContent; +} - for (;;) - { - // Wait for the task notification - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - - std::lock_guard lock(epdMutex[epdIndex]); - - { - std::lock_guard lockMcp(mcpMutex); - - displays[epdIndex].init(0, false, 40); - } - uint count = 0; - while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) - { - vTaskDelay(pdMS_TO_TICKS(100)); +void EPDManager::waitUntilNoneBusy() { + for (size_t i = 0; i < NUM_SCREENS; i++) { + uint32_t count = 0; + while (EPD_BUSY[i].digitalRead()) { count++; - } - - bool updatePartial = true; - - // Full Refresh every x minutes - if (!lastFullRefresh[epdIndex] || - (millis() - lastFullRefresh[epdIndex]) > - (preferences.getUInt("fullRefreshMin", - DEFAULT_MINUTES_FULL_REFRESH) * - 60 * 1000)) - { - updatePartial = false; - } - - char tries = 0; - while (tries < 3) - { - if (displays[epdIndex].displayWithReturn(updatePartial)) - { - displays[epdIndex].powerOff(); - currentEpdContent[epdIndex] = epdContent[epdIndex]; - if (!updatePartial) - lastFullRefresh[epdIndex] = millis(); - - if (eventSourceTaskHandle != NULL) - xTaskNotifyGive(eventSourceTaskHandle); + vTaskDelay(BUSY_RETRY_DELAY); + if (count == BUSY_TIMEOUT_COUNT) { + vTaskDelay(pdMS_TO_TICKS(100)); + } else if (count > BUSY_TIMEOUT_COUNT + 5) { + log_e("Display %d busy timeout", i); break; } - - vTaskDelay(pdMS_TO_TICKS(100)); - tries++; } } } -void splitText(const uint dispNum, const String &top, const String &bottom, - bool partial) -{ - if (preferences.getBool("verticalDesc", DEFAULT_VERTICAL_DESC) && dispNum == 0) - { +void EPDManager::setupDisplay(uint dispNum, const GFXfont* font) { + displays[dispNum].setRotation(2); + displays[dispNum].setFont(font); + displays[dispNum].setTextColor(fgColor); + displays[dispNum].fillScreen(bgColor); +} + +void EPDManager::splitText(uint dispNum, const String& top, const String& bottom, bool partial) { + if (preferences.getBool("verticalDesc", DEFAULT_VERTICAL_DESC) && dispNum == 0) { displays[dispNum].setRotation(1); - } - else - { + } else { displays[dispNum].setRotation(2); } - displays[dispNum].setFont(FONT_SMALL); - displays[dispNum].setTextColor(getFgColor()); + displays[dispNum].setFont(fontSmall); + displays[dispNum].setTextColor(fgColor); // Top text int16_t ttbx, ttby; uint16_t ttbw, ttbh; displays[dispNum].getTextBounds(top, 0, 0, &ttbx, &ttby, &ttbw, &ttbh); uint16_t tx = ((displays[dispNum].width() - ttbw) / 2) - ttbx; - uint16_t ty = - ((displays[dispNum].height() - ttbh) / 2) - ttby - ttbh / 2 - 12; + uint16_t ty = ((displays[dispNum].height() - ttbh) / 2) - ttby - ttbh / 2 - 12; // Bottom text int16_t tbbx, tbby; uint16_t tbbw, tbbh; displays[dispNum].getTextBounds(bottom, 0, 0, &tbbx, &tbby, &tbbw, &tbbh); uint16_t bx = ((displays[dispNum].width() - tbbw) / 2) - tbbx; - uint16_t by = - ((displays[dispNum].height() - tbbh) / 2) - tbby + tbbh / 2 + 12; + uint16_t by = ((displays[dispNum].height() - tbbh) / 2) - tbby + tbbh / 2 + 12; - // Make separator as wide as the shortest text. - uint16_t lineWidth, lineX; - if (tbbw < ttbh) - lineWidth = tbbw; - else - lineWidth = ttbw; - lineX = round((displays[dispNum].width() - lineWidth) / 2); + // Make separator as wide as the shortest text + uint16_t lineWidth = (tbbw < ttbh) ? tbbw : ttbw; + uint16_t lineX = round((displays[dispNum].width() - lineWidth) / 2); - displays[dispNum].fillScreen(getBgColor()); + displays[dispNum].fillScreen(bgColor); displays[dispNum].setCursor(tx, ty); displays[dispNum].print(top); displays[dispNum].fillRoundRect(lineX, displays[dispNum].height() / 2 - 3, - lineWidth, 6, 3, getFgColor()); + lineWidth, 6, 3, fgColor); displays[dispNum].setCursor(bx, by); displays[dispNum].print(bottom); } -// Consolidate common display setup code into a helper function -void setupDisplay(const uint dispNum, const GFXfont *font) -{ - displays[dispNum].setRotation(2); - displays[dispNum].setFont(font); - displays[dispNum].setTextColor(getFgColor()); - displays[dispNum].fillScreen(getBgColor()); -} - -void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font) -{ +void EPDManager::showDigit(uint dispNum, char chr, bool partial, const GFXfont* font) { String str(chr); - if (chr == '.') - { + if (chr == '.') { str = "!"; } @@ -465,56 +288,34 @@ void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font) displays[dispNum].setCursor(x, y); displays[dispNum].print(str); - if (chr == '.') - { + if (chr == '.') { displays[dispNum].fillRect(0, 0, displays[dispNum].width(), - round(displays[dispNum].height() * 0.67), getBgColor()); + round(displays[dispNum].height() * 0.67), bgColor); } } -int16_t calculateDescent(const GFXfont *font) -{ - int16_t maxDescent = 0; - for (uint16_t i = font->first; i <= font->last; i++) - { - GFXglyph *glyph = &font->glyph[i - font->first]; - int16_t descent = glyph->yOffset; - if (descent > maxDescent) - { - maxDescent = descent; - } - } - return maxDescent; -} - -void showChars(const uint dispNum, const String &chars, bool partial, - const GFXfont *font) -{ +void EPDManager::showChars(uint dispNum, const String& chars, bool partial, const GFXfont* font) { setupDisplay(dispNum, font); int16_t tbx, tby; uint16_t tbw, tbh; displays[dispNum].getTextBounds(chars, 0, 0, &tbx, &tby, &tbw, &tbh); - // center the bounding box by transposition of the origin: + // Center the bounding box by transposition of the origin uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx; uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby; - for (int i = 0; i < chars.length(); i++) - { + for (size_t i = 0; i < chars.length(); i++) { char c = chars[i]; - if (c == '.' || c == ',') - { + if (c == '.' || c == ',') { // For the dot, calculate its specific descent - GFXglyph *dotGlyph = &font->glyph[c - font->first]; + GFXglyph* dotGlyph = &font->glyph[c - font->first]; int16_t dotDescent = dotGlyph->yOffset; // Draw the dot with adjusted y-position displays[dispNum].setCursor(x, y + dotDescent + dotGlyph->height + 8); displays[dispNum].print(c); - } - else - { + } else { // For other characters, use the original y-position displays[dispNum].setCursor(x, y); displays[dispNum].print(c); @@ -525,104 +326,70 @@ void showChars(const uint dispNum, const String &chars, bool partial, } } -int getBgColor() { return bgColor; } - -int getFgColor() { return fgColor; } - -void setBgColor(int color) { bgColor = color; } - -void setFgColor(int color) { fgColor = color; } - -std::array getCurrentEpdContent() -{ - return currentEpdContent; -} -void renderText(const uint dispNum, const String &text, bool partial) -{ +bool EPDManager::renderIcon(uint dispNum, const String& text, bool partial) { displays[dispNum].setRotation(2); displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), - displays[dispNum].height()); - displays[dispNum].fillScreen(GxEPD_WHITE); - displays[dispNum].setTextColor(GxEPD_BLACK); - displays[dispNum].setCursor(0, 50); - - std::stringstream ss; - ss.str(text.c_str()); - - std::string line; - - while (std::getline(ss, line, '\n')) - { - if (line.rfind("*", 0) == 0) - { - line.erase(std::remove(line.begin(), line.end(), '*'), line.end()); - - displays[dispNum].setFont(&FreeSansBold9pt7b); - displays[dispNum].println(line.c_str()); - } - else - { - displays[dispNum].setFont(&FreeSans9pt7b); - displays[dispNum].println(line.c_str()); - } - } -} - -bool renderIcon(const uint dispNum, const String &text, bool partial) -{ - displays[dispNum].setRotation(2); - - displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), - displays[dispNum].height()); - displays[dispNum].fillScreen(getBgColor()); - displays[dispNum].setTextColor(getFgColor()); + displays[dispNum].height()); + displays[dispNum].fillScreen(bgColor); + displays[dispNum].setTextColor(fgColor); uint iconIndex = 0; uint width = 122; uint height = 122; - if (text.endsWith("rocket")) - { + + if (text.endsWith("rocket")) { iconIndex = 1; - } - else if (text.endsWith("lnbolt")) - { + } else if (text.endsWith("lnbolt")) { iconIndex = 2; - } - else if (text.endsWith("bitaxe")) - { + } else if (text.endsWith("bitaxe")) { width = 88; height = 220; iconIndex = 3; - } - else if (text.endsWith("miningpool")) - { + } else if (text.endsWith("miningpool")) { LogoData logo = MiningPoolStatsFetch::getInstance().getLogo(); - - if (logo.size == 0) - { + if (logo.size == 0) { Serial.println(F("No logo found")); return false; } int x_offset = (displays[dispNum].width() - logo.width) / 2; int y_offset = (displays[dispNum].height() - logo.height) / 2; - // Close the file - - displays[dispNum].drawInvertedBitmap(x_offset, y_offset, logo.data, logo.width, logo.height, getFgColor()); + displays[dispNum].drawInvertedBitmap(x_offset, y_offset, logo.data, + logo.width, logo.height, fgColor); return true; } int x_offset = (displays[dispNum].width() - width) / 2; int y_offset = (displays[dispNum].height() - height) / 2; - - displays[dispNum].drawInvertedBitmap(x_offset, y_offset, epd_icons_allArray[iconIndex], width, height, getFgColor()); - + displays[dispNum].drawInvertedBitmap(x_offset, y_offset, epd_icons_allArray[iconIndex], + width, height, fgColor); return true; - // displays[dispNum].drawInvertedBitmap(0,0, getOceanIcon(), 122, 250, getFgColor()); } -void renderQr(const uint dispNum, const String &text, bool partial) -{ +void EPDManager::renderText(uint dispNum, const String& text, bool partial) { + displays[dispNum].setRotation(2); + displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), + displays[dispNum].height()); + displays[dispNum].fillScreen(GxEPD_WHITE); + displays[dispNum].setTextColor(GxEPD_BLACK); + displays[dispNum].setCursor(0, 50); + + std::stringstream ss; + ss.str(text.c_str()); + std::string line; + + while (std::getline(ss, line, '\n')) { + if (line.rfind("*", 0) == 0) { + line.erase(std::remove(line.begin(), line.end(), '*'), line.end()); + displays[dispNum].setFont(&FreeSansBold9pt7b); + } else { + displays[dispNum].setFont(&FreeSans9pt7b); + } + displays[dispNum].println(line.c_str()); + } +} + +void EPDManager::renderQr(uint dispNum, const String& text, bool partial) { #ifdef USE_QR // Dynamically allocate QR buffer uint8_t* qrcode = (uint8_t*)malloc(qrcodegen_BUFFER_LEN_MAX); @@ -639,19 +406,15 @@ void renderQr(const uint dispNum, const String &text, bool partial) if (ok) { const int size = qrcodegen_getSize(qrcode); const int padding = floor(float(displays[dispNum].width() - (size * 4)) / 2); - const int paddingY = - floor(float(displays[dispNum].height() - (size * 4)) / 2); + const int paddingY = floor(float(displays[dispNum].height() - (size * 4)) / 2); + displays[dispNum].setRotation(2); - displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), - displays[dispNum].height()); + displays[dispNum].height()); displays[dispNum].fillScreen(GxEPD_WHITE); - const int border = 0; - for (int y = -border; y < size * 4 + border; y++) - { - for (int x = -border; x < size * 4 + border; x++) - { + for (int y = 0; y < size * 4; y++) { + for (int x = 0; x < size * 4; x++) { displays[dispNum].drawPixel( padding + x, paddingY + y, qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4)) @@ -661,30 +424,114 @@ void renderQr(const uint dispNum, const String &text, bool partial) } } - // Free the buffer after we're done free(qrcode); #endif } -void waitUntilNoneBusy() -{ - for (int i = 0; i < NUM_SCREENS; i++) - { - uint count = 0; - while (EPD_BUSY[i].digitalRead()) - { - count++; - vTaskDelay(BUSY_RETRY_DELAY); +int16_t EPDManager::calculateDescent(const GFXfont* font) { + int16_t maxDescent = 0; + for (uint16_t i = font->first; i <= font->last; i++) { + GFXglyph* glyph = &font->glyph[i - font->first]; + int16_t descent = glyph->yOffset; + if (descent > maxDescent) { + maxDescent = descent; + } + } + return maxDescent; +} - if (count == BUSY_TIMEOUT_COUNT) - { - vTaskDelay(pdMS_TO_TICKS(100)); - } - else if (count > BUSY_TIMEOUT_COUNT + 5) - { - log_e("Display %d busy timeout", i); +void EPDManager::updateDisplayTask(void* pvParameters) noexcept { + auto& instance = EPDManager::getInstance(); + const int epdIndex = *(int*)pvParameters; + delete (int*)pvParameters; + + for (;;) { + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + std::lock_guard lock(instance.displayMutexes[epdIndex]); + { + std::lock_guard lockMcp(mcpMutex); + instance.displays[epdIndex].init(0, false, 40); + } + + uint32_t count = 0; + while (instance.EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) { + vTaskDelay(pdMS_TO_TICKS(100)); + count++; + } + + bool updatePartial = true; + if (!instance.lastFullRefresh[epdIndex] || + (millis() - instance.lastFullRefresh[epdIndex]) > + (preferences.getUInt("fullRefreshMin", DEFAULT_MINUTES_FULL_REFRESH) * 60 * 1000)) { + updatePartial = false; + } + + char tries = 0; + while (tries < 3) { + if (instance.displays[epdIndex].displayWithReturn(updatePartial)) { + instance.displays[epdIndex].powerOff(); + instance.currentContent[epdIndex] = instance.content[epdIndex]; + if (!updatePartial) { + instance.lastFullRefresh[epdIndex] = millis(); + } + + if (eventSourceTaskHandle != nullptr) { + xTaskNotifyGive(eventSourceTaskHandle); + } break; } + + vTaskDelay(pdMS_TO_TICKS(100)); + tries++; + } + } +} + +void EPDManager::prepareDisplayUpdateTask(void* pvParameters) { + auto& instance = EPDManager::getInstance(); + UpdateDisplayTaskItem receivedItem; + + for (;;) { + if (xQueueReceive(instance.updateQueue, &receivedItem, portMAX_DELAY)) { + uint epdIndex = receivedItem.dispNum; + std::lock_guard lock(instance.displayMutexes[epdIndex]); + + bool updatePartial = true; + + if (instance.content[epdIndex].length() > 1 && + strstr(instance.content[epdIndex].c_str(), "/") != nullptr) { + String top = instance.content[epdIndex].substring( + 0, instance.content[epdIndex].indexOf("/")); + String bottom = instance.content[epdIndex].substring( + instance.content[epdIndex].indexOf("/") + 1); + instance.splitText(epdIndex, top, bottom, updatePartial); + } else if (instance.content[epdIndex].startsWith(F("qr"))) { + instance.renderQr(epdIndex, instance.content[epdIndex], updatePartial); + } else if (instance.content[epdIndex].startsWith(F("mdi"))) { + if (!instance.renderIcon(epdIndex, instance.content[epdIndex], updatePartial)) { + continue; + } + } else if (instance.content[epdIndex].length() > 5) { + instance.renderText(epdIndex, instance.content[epdIndex], updatePartial); + } else { + if (instance.content[epdIndex].length() == 2) { + instance.showChars(epdIndex, instance.content[epdIndex], updatePartial, instance.fontBig); + } else if (instance.content[epdIndex].length() > 1 && + instance.content[epdIndex].indexOf(".") == -1) { + if (instance.content[epdIndex].equals("STS")) { + instance.showDigit(epdIndex, 'S', updatePartial, instance.fontSatsymbol); + } else { + instance.showChars(epdIndex, instance.content[epdIndex], updatePartial, + instance.fontMedium); + } + } else { + instance.showDigit(epdIndex, instance.content[epdIndex].c_str()[0], + updatePartial, instance.fontBig); + } + } + + xTaskNotifyGive(instance.tasks[epdIndex]); } } } \ No newline at end of file diff --git a/src/lib/epd.hpp b/src/lib/epd.hpp index 4796776..80bed83 100644 --- a/src/lib/epd.hpp +++ b/src/lib/epd.hpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include "fonts/fonts.hpp" #include "lib/config.hpp" @@ -32,39 +34,102 @@ #include "qrcodegen.h" #endif -typedef struct { - char dispNum; -} UpdateDisplayTaskItem; +struct UpdateDisplayTaskItem { + char dispNum; +}; -void forceFullRefresh(); -void setupDisplays(); -void loadFonts(const String& fontName); +struct FontFamily { + GFXfont* big; + GFXfont* medium; + GFXfont* small; +}; -void splitText(const uint dispNum, const String &top, const String &bottom, - bool partial); +class EPDManager { +public: + static EPDManager& getInstance(); -void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font); -void showChars(const uint dispNum, const String &chars, bool partial, - const GFXfont *font); + // Delete copy constructor and assignment operator + EPDManager(const EPDManager&) = delete; + EPDManager& operator=(const EPDManager&) = delete; -extern "C" void updateDisplay(void *pvParameters) noexcept; -void updateDisplayAlt(int epdIndex); -void prepareDisplayUpdateTask(void *pvParameters); + void initialize(); + void forceFullRefresh(); + void loadFonts(const String& fontName); + void setContent(const std::array& newContent, bool forceUpdate = false); + void setContent(const std::array& newContent); + std::array getCurrentContent() const; -int getBgColor(); -int getFgColor(); -void setBgColor(int color); -void setFgColor(int color); + int getBackgroundColor() const { return bgColor; } + int getForegroundColor() const { return fgColor; } + void setBackgroundColor(int color) { bgColor = color; } + void setForegroundColor(int color) { fgColor = color; } + void waitUntilNoneBusy(); -bool renderIcon(const uint dispNum, const String &text, bool partial); -void renderText(const uint dispNum, const String &text, bool partial); -void renderQr(const uint dispNum, const String &text, bool partial); +private: + EPDManager(); // Private constructor for singleton + ~EPDManager(); // Private destructor -void setEpdContent(std::array newEpdContent, - bool forceUpdate); -void setEpdContent(std::array newEpdContent); + void setupDisplay(uint dispNum, const GFXfont* font); + void splitText(uint dispNum, const String& top, const String& bottom, bool partial); + void showDigit(uint dispNum, char chr, bool partial, const GFXfont* font); + void showChars(uint dispNum, const String& chars, bool partial, const GFXfont* font); + bool renderIcon(uint dispNum, const String& text, bool partial); + void renderText(uint dispNum, const String& text, bool partial); + void renderQr(uint dispNum, const String& text, bool partial); + int16_t calculateDescent(const GFXfont* font); -void setEpdContent(std::array newEpdContent); + static void updateDisplayTask(void* pvParameters) noexcept; + static void prepareDisplayUpdateTask(void* pvParameters); -std::array getCurrentEpdContent(); -void waitUntilNoneBusy(); \ No newline at end of file + // Member variables + std::array currentContent; + std::array content; + std::array lastFullRefresh; + std::array tasks; + QueueHandle_t updateQueue; + + FontFamily antonioFonts; + FontFamily oswaldFonts; + const GFXfont* fontSmall; + const GFXfont* fontBig; + const GFXfont* fontMedium; + const GFXfont* fontSatsymbol; + + int bgColor; + int fgColor; + + std::mutex updateMutex; + std::array displayMutexes; + + // Pin configurations based on board version + #ifdef IS_BTCLOCK_REV_B + static Native_Pin EPD_DC; + static std::array EPD_CS; + static std::array EPD_BUSY; + static std::array EPD_RESET; + #elif defined(IS_BTCLOCK_V8) + static Native_Pin EPD_DC; + static std::array EPD_BUSY; + static std::array EPD_CS; + static std::array EPD_RESET; + #else + static Native_Pin EPD_DC; + static std::array EPD_CS; + static std::array EPD_BUSY; + static std::array EPD_RESET; + #endif + + // Display array + std::array, NUM_SCREENS> displays; + + static constexpr size_t UPDATE_QUEUE_SIZE = 14; + static constexpr uint32_t BUSY_TIMEOUT_COUNT = 200; + static constexpr TickType_t BUSY_RETRY_DELAY = pdMS_TO_TICKS(10); + static constexpr size_t EPD_TASK_STACK_SIZE = + #ifdef IS_BTCLOCK_V8 + 4096 + #else + 2048 + #endif + ; +}; \ No newline at end of file diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index 3c996a2..6d9cce9 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -283,7 +283,7 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event) } ScreenHandler::setCurrentScreen(SCREEN_CUSTOM); - setEpdContent(textEpdContent); + EPDManager::getInstance().setContent(textEpdContent); vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250)); if (preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP)) { @@ -294,4 +294,20 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event) esp_timer_start_periodic(screenRotateTimer, timerPeriod * usPerSecond); } -} \ No newline at end of file +} + +// void onNostrEvent(const String &subId, const nostr::Event &event) { +// // This is the callback that will be called when a new event is received +// if (event.kind == 9735) { +// // Parse the zap amount from the event +// uint16_t amount = parseZapAmount(event); +// if (amount > 0) { +// std::array zapContent = parseZapNotify(amount, true); +// EPDManager::getInstance().setContent(zapContent); + +// if (preferences.getBool("ledFlashOnUpd", DEFAULT_LED_FLASH_ON_UPD)) { +// getLedHandler().queueEffect(LED_FLASH_BLOCK_NOTIFY); +// } +// } +// } +// } \ No newline at end of file diff --git a/src/lib/ota.cpp b/src/lib/ota.cpp index b42a505..59497c7 100644 --- a/src/lib/ota.cpp +++ b/src/lib/ota.cpp @@ -57,10 +57,10 @@ void onOTAProgress(unsigned int progress, unsigned int total) void onOTAStart() { - forceFullRefresh(); + EPDManager::getInstance().forceFullRefresh(); std::array epdContent = {"U", "P", "D", "A", "T", "E", "!"}; - setEpdContent(epdContent); + EPDManager::getInstance().setContent(epdContent); // Stop all timers esp_timer_stop(screenRotateTimer); esp_timer_stop(minuteTimer); diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 0692c1d..6b3241e 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -203,7 +203,7 @@ void ScreenHandler::showSystemStatusScreen() { String((int)round(ESP.getFreeHeap() / 1024)) + "/" + (int)round(ESP.getHeapSize() / 1024); setCurrentScreen(SCREEN_CUSTOM); - setEpdContent(sysStatusEpdContent); + EPDManager::getInstance().setContent(sysStatusEpdContent); } // Keep these as free functions @@ -222,7 +222,7 @@ void workerTask(void *pvParameters) { taskEpdContent = (currentScreenValue == SCREEN_BITAXE_HASHRATE) ? parseBitaxeHashRate(BitAxeFetch::getInstance().getHashRate()) : parseBitaxeBestDiff(BitAxeFetch::getInstance().getBestDiff()); - setEpdContent(taskEpdContent); + EPDManager::getInstance().setContent(taskEpdContent); break; } @@ -235,7 +235,7 @@ void workerTask(void *pvParameters) { parseMiningPoolStatsDailyEarnings(MiningPoolStatsFetch::getInstance().getDailyEarnings(), MiningPoolStatsFetch::getInstance().getPool()->getDailyEarningsLabel(), *MiningPoolStatsFetch::getInstance().getPool()); - setEpdContent(taskEpdContent); + EPDManager::getInstance().setContent(taskEpdContent); break; } @@ -256,13 +256,13 @@ void workerTask(void *pvParameters) { preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR)); } - setEpdContent(taskEpdContent); + EPDManager::getInstance().setContent(taskEpdContent); break; } case TASK_FEE_UPDATE: { if (currentScreenValue == SCREEN_BLOCK_FEE_RATE) { taskEpdContent = parseBlockFees(static_cast(getBlockMedianFee())); - setEpdContent(taskEpdContent); + EPDManager::getInstance().setContent(taskEpdContent); } break; } @@ -275,7 +275,7 @@ void workerTask(void *pvParameters) { if (currentScreenValue == SCREEN_HALVING_COUNTDOWN || currentScreenValue == SCREEN_BLOCK_HEIGHT) { - setEpdContent(taskEpdContent); + EPDManager::getInstance().setContent(taskEpdContent); } break; } @@ -302,7 +302,7 @@ void workerTask(void *pvParameters) { for (uint i = 1; i < NUM_SCREENS; i++) { taskEpdContent[i] = timeString[i]; } - setEpdContent(taskEpdContent); + EPDManager::getInstance().setContent(taskEpdContent); } break; @@ -330,8 +330,6 @@ void setupTasks() { xTaskCreate(taskScreenRotate, "rotateScreen", 4096, NULL, tskIDLE_PRIORITY, &taskScreenRotateTaskHandle); - waitUntilNoneBusy(); - if (findScreenIndexByValue(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)) != -1) ScreenHandler::setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)); } diff --git a/src/lib/shared.cpp b/src/lib/shared.cpp index a776750..aa67768 100644 --- a/src/lib/shared.cpp +++ b/src/lib/shared.cpp @@ -179,4 +179,5 @@ void HttpHelper::end(HTTPClient* http) { http->end(); delete http; } -} \ No newline at end of file +} + diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index 78fb9ea..479a52f 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -16,6 +16,8 @@ #include #include +#include +#include #include "defaults.hpp" @@ -118,4 +120,5 @@ private: static WiFiClientSecure secureClient; static bool certBundleSet; static WiFiClient insecureClient; -}; \ No newline at end of file +}; + diff --git a/src/lib/v2_notify.cpp b/src/lib/v2_notify.cpp index 469e6e1..c0007dd 100644 --- a/src/lib/v2_notify.cpp +++ b/src/lib/v2_notify.cpp @@ -106,6 +106,11 @@ namespace V2Notify JsonDocument doc; DeserializationError error = deserializeMsgPack(doc, payload, length); + if (error) { + Serial.println(F("Error deserializing message")); + break; + } + V2Notify::handleV2Message(doc); break; } diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 4897811..382faa9 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -309,7 +309,7 @@ void eventSourceUpdate() { doc["leds"] = getLedStatusObject()["data"]; // Get current EPD content directly as array - std::array epdContent = getCurrentEpdContent(); + std::array epdContent = EPDManager::getInstance().getCurrentContent(); // Add EPD content arrays JsonArray data = doc["data"].to(); @@ -336,7 +336,7 @@ void onApiStatus(AsyncWebServerRequest *request) JsonDocument root = getStatusObject(); // Get current EPD content directly as array - std::array epdContent = getCurrentEpdContent(); + std::array epdContent = EPDManager::getInstance().getCurrentContent(); // Add EPD content arrays JsonArray data = root["data"].to(); @@ -378,11 +378,9 @@ void onApiActionTimerRestart(AsyncWebServerRequest *request) */ void onApiFullRefresh(AsyncWebServerRequest *request) { - forceFullRefresh(); - std::array newEpdContent = getCurrentEpdContent(); - - setEpdContent(newEpdContent, true); - + EPDManager::getInstance().forceFullRefresh(); + std::array newEpdContent = EPDManager::getInstance().getCurrentContent(); + EPDManager::getInstance().setContent(newEpdContent, true); request->send(HTTP_OK); } @@ -429,7 +427,7 @@ void onApiShowText(AsyncWebServerRequest *request) textEpdContent[i] = t[i]; } - setEpdContent(textEpdContent); + EPDManager::getInstance().setContent(textEpdContent); } ScreenHandler::setCurrentScreen(SCREEN_CUSTOM); request->send(HTTP_OK); @@ -447,7 +445,7 @@ void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json) i++; } - setEpdContent(epdContent); + EPDManager::getInstance().setContent(epdContent); ScreenHandler::setCurrentScreen(SCREEN_CUSTOM); request->send(HTTP_OK); @@ -475,13 +473,13 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) if (inverted) { preferences.putUInt("fgColor", GxEPD_WHITE); preferences.putUInt("bgColor", GxEPD_BLACK); - setFgColor(GxEPD_WHITE); - setBgColor(GxEPD_BLACK); + EPDManager::getInstance().setForegroundColor(GxEPD_WHITE); + EPDManager::getInstance().setBackgroundColor(GxEPD_BLACK); } else { preferences.putUInt("fgColor", GxEPD_BLACK); preferences.putUInt("bgColor", GxEPD_WHITE); - setFgColor(GxEPD_BLACK); - setBgColor(GxEPD_WHITE); + EPDManager::getInstance().setForegroundColor(GxEPD_BLACK); + EPDManager::getInstance().setBackgroundColor(GxEPD_WHITE); } Serial.printf("Setting invertedColor to %d\r\n", inverted); settingsChanged = true; @@ -680,7 +678,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) JsonDocument root; root["numScreens"] = NUM_SCREENS; - root["invertedColor"] = preferences.getBool("invertedColor", getFgColor() == GxEPD_WHITE); + root["invertedColor"] = preferences.getBool("invertedColor", EPDManager::getInstance().getForegroundColor() == GxEPD_WHITE); root["timerSeconds"] = getTimerSeconds(); root["timerRunning"] = isTimerActive(); root["minSecPriceUpd"] = preferences.getUInt( @@ -818,7 +816,7 @@ bool processEpdColorSettings(AsyncWebServerRequest *request) const AsyncWebParameter *fgColor = request->getParam("fgColor", true); uint32_t color = strtol(fgColor->value().c_str(), NULL, 16); preferences.putUInt("fgColor", color); - setFgColor(color); + EPDManager::getInstance().setForegroundColor(color); // Serial.print(F("Setting foreground color to ")); // Serial.println(fgColor->value().c_str()); settingsChanged = true; @@ -829,7 +827,7 @@ bool processEpdColorSettings(AsyncWebServerRequest *request) uint32_t color = strtol(bgColor->value().c_str(), NULL, 16); preferences.putUInt("bgColor", color); - setBgColor(color); + EPDManager::getInstance().setBackgroundColor(color); // Serial.print(F("Setting background color to ")); // Serial.println(bgColor->value().c_str()); settingsChanged = true; @@ -1202,7 +1200,7 @@ void onApiLightsGet(AsyncWebServerRequest *request) auto& ledHandler = getLedHandler(); auto& pixels = ledHandler.getPixels(); - DynamicJsonDocument doc(1024); + JsonDocument doc; JsonArray lights = doc.createNestedArray("lights"); for (uint i = 0; i < pixels.numPixels(); i++) @@ -1225,7 +1223,7 @@ void onApiLightsPost(AsyncWebServerRequest *request, uint8_t *data, size_t len, auto& ledHandler = getLedHandler(); auto& pixels = ledHandler.getPixels(); - DynamicJsonDocument doc(1024); + JsonDocument doc; DeserializationError error = deserializeJson(doc, data); if (error) { From b435552c92685ad4525c7538df36138bffb199fb Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 5 Jan 2025 22:12:39 +0100 Subject: [PATCH 104/130] fix: verify block update --- src/lib/block_notify.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index 37b5b2f..0dab659 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -181,7 +181,7 @@ void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data) } void processNewBlock(uint32_t newBlockHeight) { - if (currentBlockHeight == newBlockHeight) + if (currentBlockHeight <= newBlockHeight) { return; } From 178748b94d5019a6702497749d032e3ebac537ca Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 5 Jan 2025 22:47:13 +0100 Subject: [PATCH 105/130] WebUI update --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 033fe09..732dd26 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 033fe098295ab6da6568d6298b4380e51bec0b98 +Subproject commit 732dd260ea708841f0e15ee1ee64a3d5115cd475 From 0999dd08ad30bc91efe9cacebcc79f4c2f0893fe Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 5 Jan 2025 23:13:05 +0100 Subject: [PATCH 106/130] Remove deprecated ArduinoJson methods --- src/lib/block_notify.cpp | 6 +++--- src/lib/v2_notify.cpp | 6 +++--- src/lib/webserver.cpp | 29 ++++------------------------- 3 files changed, 10 insertions(+), 31 deletions(-) diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index 0dab659..60b3034 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -158,7 +158,7 @@ void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data) // return; // } - if (doc.containsKey("block")) + if (doc["block"].is()) { JsonObject block = doc["block"]; @@ -168,7 +168,7 @@ void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data) processNewBlock(block["height"].as()); } - else if (doc.containsKey("mempool-blocks")) + else if (doc["mempool-blocks"].is()) { JsonArray blockInfo = doc["mempool-blocks"].as(); @@ -181,7 +181,7 @@ void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data) } void processNewBlock(uint32_t newBlockHeight) { - if (currentBlockHeight <= newBlockHeight) + if (newBlockHeight <= currentBlockHeight) { return; } diff --git a/src/lib/v2_notify.cpp b/src/lib/v2_notify.cpp index c0007dd..560b39d 100644 --- a/src/lib/v2_notify.cpp +++ b/src/lib/v2_notify.cpp @@ -127,7 +127,7 @@ namespace V2Notify void handleV2Message(JsonDocument doc) { - if (doc.containsKey("blockheight")) + if (doc["blockheight"].is()) { uint newBlockHeight = doc["blockheight"].as(); @@ -138,13 +138,13 @@ namespace V2Notify processNewBlock(newBlockHeight); } - else if (doc.containsKey("blockfee")) + else if (doc["blockfee"].is()) { uint medianFee = doc["blockfee"].as(); processNewBlockFee(medianFee); } - else if (doc.containsKey("price")) + else if (doc["price"].is()) { // Iterate through the key-value pairs of the "price" object diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 382faa9..1d6a878 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -612,15 +612,15 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) } // Handle DND settings - if (settings.containsKey("dnd")) { + if (settings["dnd"].is()) { JsonObject dndObj = settings["dnd"]; auto& ledHandler = getLedHandler(); - if (dndObj.containsKey("timeBasedEnabled")) { + if (dndObj["timeBasedEnabled"].is()) { ledHandler.setDNDTimeBasedEnabled(dndObj["timeBasedEnabled"].as()); } - if (dndObj.containsKey("startHour") && dndObj.containsKey("startMinute") && - dndObj.containsKey("endHour") && dndObj.containsKey("endMinute")) { + if (dndObj["startHour"].is() && dndObj["startMinute"].is() && + dndObj["endHour"].is() && dndObj["endMinute"].is()) { ledHandler.setDNDTimeRange( dndObj["startHour"].as(), dndObj["startMinute"].as(), @@ -1251,25 +1251,4 @@ void onApiLightsPost(AsyncWebServerRequest *request, uint8_t *data, size_t len, pixels.show(); request->send(200); -} - -void onApiSettings(AsyncWebServerRequest *request, JsonVariant &json) -{ - JsonObject settings = json.as(); - auto& ledHandler = getLedHandler(); - - if (settings.containsKey("dnd")) { - JsonObject dndObj = settings["dnd"]; - if (dndObj.containsKey("timeBasedEnabled")) { - ledHandler.setDNDTimeBasedEnabled(dndObj["timeBasedEnabled"].as()); - } - if (dndObj.containsKey("startHour") && dndObj.containsKey("startMinute") && - dndObj.containsKey("endHour") && dndObj.containsKey("endMinute")) { - ledHandler.setDNDTimeRange( - dndObj["startHour"].as(), - dndObj["startMinute"].as(), - dndObj["endHour"].as(), - dndObj["endMinute"].as()); - } - } } \ No newline at end of file From 7195b7d3432bf844798ffd58f7764b13afbe73dd Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 5 Jan 2025 23:13:25 +0100 Subject: [PATCH 107/130] Rewrite price notify to websocketsclient --- src/lib/price_notify.cpp | 165 +++++++++++++++------------------------ src/lib/price_notify.hpp | 14 ++-- 2 files changed, 71 insertions(+), 108 deletions(-) diff --git a/src/lib/price_notify.cpp b/src/lib/price_notify.cpp index 2c6fe94..6ac2f3b 100644 --- a/src/lib/price_notify.cpp +++ b/src/lib/price_notify.cpp @@ -2,103 +2,64 @@ const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin"; -// WebsocketsClient client; -esp_websocket_client_handle_t clientPrice = NULL; -esp_websocket_client_config_t config; +WebSocketsClient webSocket; uint currentPrice = 90000; unsigned long int lastPriceUpdate; bool priceNotifyInit = false; std::map currencyMap; std::map lastUpdateMap; -WebSocketsClient priceNotifyWs; +TaskHandle_t priceNotifyTaskHandle; + +void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length); void setupPriceNotify() { - config = {.uri = wsServerPrice, - .user_agent = USER_AGENT}; - config.cert_pem = isrg_root_x1cert; + webSocket.beginSSL("ws.coincap.io", 443, "/prices?assets=bitcoin"); + webSocket.onEvent([](WStype_t type, uint8_t * payload, size_t length) { + onWebsocketPriceEvent(type, payload, length); + }); + webSocket.setReconnectInterval(5000); + webSocket.enableHeartbeat(15000, 3000, 2); - config.task_stack = (6*1024); - - - clientPrice = esp_websocket_client_init(&config); - esp_websocket_register_events(clientPrice, WEBSOCKET_EVENT_ANY, - onWebsocketPriceEvent, clientPrice); - esp_websocket_client_start(clientPrice); - - // priceNotifyWs.beginSSL("ws.coincap.io", 443, "/prices?assets=bitcoin"); - // priceNotifyWs.onEvent(onWebsocketPriceEvent); - // priceNotifyWs.setReconnectInterval(5000); - // priceNotifyWs.enableHeartbeat(15000, 3000, 2); + setupPriceNotifyTask(); } +void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length) { + switch(type) { + case WStype_DISCONNECTED: + Serial.println(F("Price WS Connection Closed")); + break; + case WStype_CONNECTED: + { + Serial.println("Connected to " + String(wsServerPrice)); + priceNotifyInit = true; + break; + } + case WStype_TEXT: + { + JsonDocument doc; + deserializeJson(doc, (char *)payload); -// void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length) { -// switch(type) { -// case WStype_DISCONNECTED: -// Serial.printf("[WSc] Disconnected!\n"); -// break; -// case WStype_CONNECTED: -// { -// Serial.printf("[WSc] Connected to url: %s\n", payload); - - -// break; -// } -// case WStype_TEXT: -// String message = String((char*)payload); -// onWebsocketPriceMessage(message); -// break; -// case WStype_BIN: -// break; -// case WStype_ERROR: -// case WStype_FRAGMENT_TEXT_START: -// case WStype_FRAGMENT_BIN_START: -// case WStype_FRAGMENT: -// case WStype_PING: -// case WStype_PONG: -// case WStype_FRAGMENT_FIN: -// break; -// } -// } - -void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base, - int32_t event_id, void *event_data) -{ - esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data; - - switch (event_id) - { - case WEBSOCKET_EVENT_CONNECTED: - Serial.println("Connected to " + String(config.uri) + " WebSocket"); - priceNotifyInit = true; - - break; - case WEBSOCKET_EVENT_DATA: - onWebsocketPriceMessage(data); - break; - case WEBSOCKET_EVENT_ERROR: - Serial.println(F("Price WS Connnection error")); - break; - case WEBSOCKET_EVENT_DISCONNECTED: - Serial.println(F("Price WS Connnection Closed")); - break; - } -} - -void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data) -{ - JsonDocument doc; - - deserializeJson(doc, (char *)event_data->data_ptr); - - if (doc.containsKey("bitcoin")) - { - if (currentPrice != doc["bitcoin"].as()) - { - processNewPrice(doc["bitcoin"].as(), CURRENCY_USD); + if (doc["bitcoin"].is()) + { + if (currentPrice != doc["bitcoin"].as()) + { + processNewPrice(doc["bitcoin"].as(), CURRENCY_USD); + } + } + break; + } + case WStype_BIN: + break; + case WStype_ERROR: + case WStype_FRAGMENT_TEXT_START: + case WStype_FRAGMENT_BIN_START: + case WStype_FRAGMENT: + case WStype_PING: + case WStype_PONG: + case WStype_FRAGMENT_FIN: + break; } - } } void processNewPrice(uint newPrice, char currency) @@ -175,9 +136,7 @@ void setPrice(uint newPrice, char currency) bool isPriceNotifyConnected() { - if (clientPrice == NULL) - return false; - return esp_websocket_client_is_connected(clientPrice); + return webSocket.isConnected(); } bool getPriceNotifyInit() @@ -187,24 +146,30 @@ bool getPriceNotifyInit() void stopPriceNotify() { - if (clientPrice == NULL) - return; - esp_websocket_client_close(clientPrice, pdMS_TO_TICKS(5000)); - esp_websocket_client_stop(clientPrice); - esp_websocket_client_destroy(clientPrice); - - clientPrice = NULL; + webSocket.disconnect(); + if (priceNotifyTaskHandle != NULL) { + vTaskDelete(priceNotifyTaskHandle); + priceNotifyTaskHandle = NULL; + } } void restartPriceNotify() { stopPriceNotify(); - if (clientPrice == NULL) + setupPriceNotify(); +} + +void taskPriceNotify(void *pvParameters) +{ + for (;;) { - setupPriceNotify(); - return; + webSocket.loop(); + vTaskDelay(10 / portTICK_PERIOD_MS); } - // esp_websocket_client_close(clientPrice, pdMS_TO_TICKS(5000)); - // esp_websocket_client_stop(clientPrice); - // esp_websocket_client_start(clientPrice); +} + +void setupPriceNotifyTask() +{ + xTaskCreate(taskPriceNotify, "priceNotify", (6 * 1024), NULL, tskIDLE_PRIORITY, + &priceNotifyTaskHandle); } \ No newline at end of file diff --git a/src/lib/price_notify.hpp b/src/lib/price_notify.hpp index 3591d40..6c8c6df 100644 --- a/src/lib/price_notify.hpp +++ b/src/lib/price_notify.hpp @@ -2,24 +2,22 @@ #include #include -#include -#include "block_notify.hpp" +#include #include #include "lib/screen_handler.hpp" +extern TaskHandle_t priceNotifyTaskHandle; + void setupPriceNotify(); +void setupPriceNotifyTask(); +void taskPriceNotify(void *pvParameters); -void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base, - int32_t event_id, void *event_data); -//void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length); - -void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data); +void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length); uint getPrice(char currency); void setPrice(uint newPrice, char currency); -//void processNewPrice(uint newPrice); void processNewPrice(uint newPrice, char currency); bool isPriceNotifyConnected(); From e19cad05bced9337c727e23a33d35fba65bc257e Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 5 Jan 2025 23:15:34 +0100 Subject: [PATCH 108/130] Update ESPAsyncWebserver --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index b65defd..d46c153 100644 --- a/platformio.ini +++ b/platformio.ini @@ -38,7 +38,7 @@ build_unflags = lib_deps = https://github.com/joltwallet/esp_littlefs.git bblanchon/ArduinoJson@^7.2.1 - mathieucarbou/ESPAsyncWebServer @ 3.3.23 + mathieucarbou/ESPAsyncWebServer @ 3.4.5 robtillaart/MCP23017@^0.8.0 adafruit/Adafruit NeoPixel@^1.12.3 https://github.com/dsbaars/universal_pin#feature/mcp23017_rt From ebbec75e6bc9e51a973d13ad78f277f7be2c2865 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 6 Jan 2025 00:01:34 +0100 Subject: [PATCH 109/130] Fix V2 message parsing --- src/lib/v2_notify.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/lib/v2_notify.cpp b/src/lib/v2_notify.cpp index 560b39d..6d9fc61 100644 --- a/src/lib/v2_notify.cpp +++ b/src/lib/v2_notify.cpp @@ -127,7 +127,7 @@ namespace V2Notify void handleV2Message(JsonDocument doc) { - if (doc["blockheight"].is()) + if (doc["blockheight"].is()) { uint newBlockHeight = doc["blockheight"].as(); @@ -136,16 +136,29 @@ namespace V2Notify return; } + if (debugLogEnabled()) { + Serial.print(F("processNewBlock ")); + Serial.println(newBlockHeight); + } processNewBlock(newBlockHeight); } - else if (doc["blockfee"].is()) + else if (doc["blockfee"].is()) { uint medianFee = doc["blockfee"].as(); + if (debugLogEnabled()) { + Serial.print(F("processNewBlockFee ")); + Serial.println(medianFee); + } + processNewBlockFee(medianFee); } else if (doc["price"].is()) { + if (debugLogEnabled()) { + Serial.print(F("processNewPrice ")); + Serial.println(doc["price"].as().size()); + } // Iterate through the key-value pairs of the "price" object for (JsonPair kv : doc["price"].as()) From e330984ba23504f1a214c93d48101d4dc3630bf9 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 6 Jan 2025 00:43:31 +0100 Subject: [PATCH 110/130] Refactor BlockNotify to a class, use websocketsClient --- src/lib/block_notify.cpp | 363 ++++++++++++++++--------------------- src/lib/block_notify.hpp | 65 +++++-- src/lib/config.cpp | 4 +- src/lib/nostr_notify.cpp | 11 +- src/lib/ota.cpp | 4 +- src/lib/screen_handler.cpp | 14 +- src/lib/v2_notify.cpp | 6 +- src/lib/webserver.cpp | 9 +- src/main.cpp | 20 +- 9 files changed, 239 insertions(+), 257 deletions(-) diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index 60b3034..4c32a2a 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -1,186 +1,146 @@ #include "block_notify.hpp" -#include "led_handler.hpp" -char *wsServer; -esp_websocket_client_handle_t blockNotifyClient = NULL; -uint32_t currentBlockHeight = 873400; -uint16_t blockMedianFee = 1; -bool blockNotifyInit = false; -unsigned long int lastBlockUpdate; +// Initialize static members +WebSocketsClient BlockNotify::webSocket; +uint32_t BlockNotify::currentBlockHeight = 878000; +uint16_t BlockNotify::blockMedianFee = 1; +bool BlockNotify::notifyInit = false; +unsigned long int BlockNotify::lastBlockUpdate = 0; +TaskHandle_t BlockNotify::taskHandle = nullptr; -const char *mempoolWsCert = R"EOF( ------BEGIN CERTIFICATE----- -MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB -iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl -cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV -BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw -MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV -BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU -aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B -3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY -tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ -Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 -VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT -79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 -c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT -Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l -c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee -UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE -Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd -BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF -Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO -VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 -ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs -8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR -iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze -Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ -XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ -qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB -VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB -L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG -jjxDah2nGN59PRbxYvnKkKj9 ------END CERTIFICATE----- -)EOF"; - -void setupBlockNotify() +void BlockNotify::taskNotify(void* pvParameters) { - IPAddress result; - - int dnsErr = -1; - String mempoolInstance = - preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); - - while (dnsErr != 1 && !strchr(mempoolInstance.c_str(), ':')) - { - dnsErr = WiFi.hostByName(mempoolInstance.c_str(), result); - - if (dnsErr != 1) + for (;;) { - Serial.print(mempoolInstance); - Serial.println(F("mempool DNS could not be resolved")); - WiFi.reconnect(); - vTaskDelay(pdMS_TO_TICKS(1000)); + webSocket.loop(); + vTaskDelay(10 / portTICK_PERIOD_MS); } - } - - // Get current block height through regular API - int blockFetch = getBlockFetch(); - - if (blockFetch > currentBlockHeight) - currentBlockHeight = blockFetch; - - if (currentBlockHeight != -1) - { - lastBlockUpdate = esp_timer_get_time() / 1000000; - } - - if (workQueue != nullptr) - { - WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0}; - xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); - } - - // std::strcpy(wsServer, String("wss://" + mempoolInstance + - // "/api/v1/ws").c_str()); - - const String protocol = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE) ? "wss" : "ws"; - - String mempoolUri = protocol + "://" + preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE) + "/api/v1/ws"; - - esp_websocket_client_config_t config = { - // .uri = "wss://mempool.space/api/v1/ws", - .task_stack = (6*1024), - .user_agent = USER_AGENT - }; - - if (preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE)) { - config.cert_pem = mempoolWsCert; - } - - config.uri = mempoolUri.c_str(); - - Serial.printf("Connecting to %s\r\n", preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE)); - - blockNotifyClient = esp_websocket_client_init(&config); - esp_websocket_register_events(blockNotifyClient, WEBSOCKET_EVENT_ANY, - onWebsocketBlockEvent, blockNotifyClient); - esp_websocket_client_start(blockNotifyClient); } -void onWebsocketBlockEvent(void *handler_args, esp_event_base_t base, - int32_t event_id, void *event_data) +void BlockNotify::setupTask() { - esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data; - const String sub = "{\"action\": \"want\", \"data\":[\"blocks\", \"mempool-blocks\"]}"; - switch (event_id) - { - case WEBSOCKET_EVENT_CONNECTED: - blockNotifyInit = true; + xTaskCreate(taskNotify, "blockNotify", (6 * 1024), NULL, tskIDLE_PRIORITY, + &taskHandle); +} - Serial.println(F("Connected to Mempool.space WebSocket")); +void BlockNotify::onWebsocketEvent(WStype_t type, uint8_t* payload, size_t length) { + switch(type) { + case WStype_DISCONNECTED: { + Serial.println(F("Mempool.space WS Connection Closed")); + break; + } + case WStype_CONNECTED: { + notifyInit = true; + Serial.print(F("Connected to ")); + Serial.println(preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE)); - Serial.println(sub); - if (esp_websocket_client_send_text(blockNotifyClient, sub.c_str(), - sub.length(), portMAX_DELAY) == -1) + JsonDocument doc; + doc["action"] = "want"; + JsonArray data = doc.createNestedArray("data"); + data.add("blocks"); + data.add("mempool-blocks"); + + String sub; + serializeJson(doc, sub); + Serial.println(sub); + webSocket.sendTXT(sub.c_str()); + break; + } + case WStype_TEXT: { + JsonDocument doc; + JsonDocument filter; + filter["block"]["height"] = true; + filter["mempool-blocks"][0]["medianFee"] = true; + + deserializeJson(doc, (char*)payload, DeserializationOption::Filter(filter)); + + if (debugLogEnabled()) { + Serial.println(doc.as()); + } + + if (doc["block"].is()) + { + JsonObject block = doc["block"]; + if (block["height"].as() != currentBlockHeight) { + BlockNotify::getInstance().processNewBlock(block["height"].as()); + } + } + else if (doc["mempool-blocks"].is()) + { + JsonArray blockInfo = doc["mempool-blocks"].as(); + uint medianFee = (uint)round(blockInfo[0]["medianFee"].as()); + BlockNotify::getInstance().processNewBlockFee(medianFee); + } + break; + } + case WStype_BIN: + case WStype_ERROR: + case WStype_FRAGMENT_TEXT_START: + case WStype_FRAGMENT_BIN_START: + case WStype_FRAGMENT: + case WStype_PING: + case WStype_PONG: + case WStype_FRAGMENT_FIN: { + break; + } + } +} + +void BlockNotify::setup() +{ + IPAddress result; + int dnsErr = -1; + String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); + + while (dnsErr != 1 && !strchr(mempoolInstance.c_str(), ':')) { - Serial.println(F("Mempool.space WS Block Subscribe Error")); + dnsErr = WiFi.hostByName(mempoolInstance.c_str(), result); + + if (dnsErr != 1) + { + Serial.print(mempoolInstance); + Serial.println(F("mempool DNS could not be resolved")); + WiFi.reconnect(); + vTaskDelay(pdMS_TO_TICKS(1000)); + } } - break; - case WEBSOCKET_EVENT_DATA: - onWebsocketBlockMessage(data); - break; - case WEBSOCKET_EVENT_ERROR: - Serial.println(F("Mempool.space WS Connnection error")); - break; - case WEBSOCKET_EVENT_DISCONNECTED: - Serial.println(F("Mempool.space WS Connnection Closed")); - break; - } -} + // Get current block height through regular API + int blockFetch = fetchLatestBlock(); -void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data) -{ - JsonDocument doc; + if (blockFetch > currentBlockHeight) + currentBlockHeight = blockFetch; - JsonDocument filter; - filter["block"]["height"] = true; - filter["mempool-blocks"][0]["medianFee"] = true; - - deserializeJson(doc, (char *)event_data->data_ptr, DeserializationOption::Filter(filter)); - - // if (error) { - // Serial.print("deserializeJson() failed: "); - // Serial.println(error.c_str()); - // return; - // } - - if (doc["block"].is()) - { - JsonObject block = doc["block"]; - - if (block["height"].as() == currentBlockHeight) { - return; + if (currentBlockHeight != -1) + { + lastBlockUpdate = esp_timer_get_time() / 1000000; } - processNewBlock(block["height"].as()); - } - else if (doc["mempool-blocks"].is()) - { - JsonArray blockInfo = doc["mempool-blocks"].as(); + if (workQueue != nullptr) + { + WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0}; + xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); + } - uint medianFee = (uint)round(blockInfo[0]["medianFee"].as()); + const bool useSSL = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE); + const int port = useSSL ? 443 : 80; - processNewBlockFee(medianFee); - } + if (useSSL) { + webSocket.beginSSL(mempoolInstance.c_str(), port, "/api/v1/ws"); +// webSocket.beginSSL("ws.btclock.dev", port, "/api/v1/ws"); - doc.clear(); + } else { + webSocket.begin(mempoolInstance.c_str(), port, "/api/v1/ws"); + } + + webSocket.onEvent(onWebsocketEvent); + webSocket.setReconnectInterval(5000); + webSocket.enableHeartbeat(15000, 3000, 2); + + setupTask(); } -void processNewBlock(uint32_t newBlockHeight) { +void BlockNotify::processNewBlock(uint32_t newBlockHeight) { if (newBlockHeight <= currentBlockHeight) { return; @@ -220,76 +180,65 @@ void processNewBlock(uint32_t newBlockHeight) { } } -void processNewBlockFee(uint16_t newBlockFee) { - if (blockMedianFee == newBlockFee) +void BlockNotify::processNewBlockFee(uint16_t newBlockFee) { + if (blockMedianFee == newBlockFee) { - return; + return; } - // Serial.printf("New median fee: %d\r\n", medianFee); blockMedianFee = newBlockFee; if (workQueue != nullptr) { - WorkItem blockUpdate = {TASK_FEE_UPDATE, 0}; - xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); + WorkItem blockUpdate = {TASK_FEE_UPDATE, 0}; + xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); } } -uint32_t getBlockHeight() { return currentBlockHeight; } - -void setBlockHeight(uint32_t newBlockHeight) -{ - currentBlockHeight = newBlockHeight; +uint32_t BlockNotify::getBlockHeight() const { + return currentBlockHeight; } -uint16_t getBlockMedianFee() { return blockMedianFee; } - -void setBlockMedianFee(uint16_t newBlockMedianFee) +void BlockNotify::setBlockHeight(uint32_t newBlockHeight) { - blockMedianFee = newBlockMedianFee; + currentBlockHeight = newBlockHeight; } -bool isBlockNotifyConnected() -{ - if (blockNotifyClient == NULL) - return false; - return esp_websocket_client_is_connected(blockNotifyClient); +uint16_t BlockNotify::getBlockMedianFee() const { + return blockMedianFee; } -bool getBlockNotifyInit() +void BlockNotify::setBlockMedianFee(uint16_t newBlockMedianFee) { - return blockNotifyInit; + blockMedianFee = newBlockMedianFee; } -void stopBlockNotify() +bool BlockNotify::isConnected() const { - if (blockNotifyClient == NULL) - return; - - esp_websocket_client_close(blockNotifyClient, pdMS_TO_TICKS(5000)); - esp_websocket_client_stop(blockNotifyClient); - esp_websocket_client_destroy(blockNotifyClient); - - blockNotifyClient = NULL; + return webSocket.isConnected(); } -void restartBlockNotify() +bool BlockNotify::isInitialized() const { - stopBlockNotify(); - - if (blockNotifyClient == NULL) { - setupBlockNotify(); - return; - } - - // esp_websocket_client_close(blockNotifyClient, pdMS_TO_TICKS(5000)); - // esp_websocket_client_stop(blockNotifyClient); - // esp_websocket_client_start(blockNotifyClient); + return notifyInit; } +void BlockNotify::stop() +{ + webSocket.disconnect(); + if (taskHandle != NULL) { + vTaskDelete(taskHandle); + taskHandle = NULL; + } +} -int getBlockFetch() { +void BlockNotify::restart() +{ + stop(); + setup(); +} + +int BlockNotify::fetchLatestBlock() { try { String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); const String protocol = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE) ? "https" : "http"; @@ -312,12 +261,12 @@ int getBlockFetch() { return 2203; // B-T-C } -uint getLastBlockUpdate() +uint BlockNotify::getLastBlockUpdate() const { - return lastBlockUpdate; + return lastBlockUpdate; } -void setLastBlockUpdate(uint lastUpdate) +void BlockNotify::setLastBlockUpdate(uint lastUpdate) { - lastBlockUpdate = lastUpdate; + lastBlockUpdate = lastUpdate; } \ No newline at end of file diff --git a/src/lib/block_notify.hpp b/src/lib/block_notify.hpp index 9c41bf0..aa99f2b 100644 --- a/src/lib/block_notify.hpp +++ b/src/lib/block_notify.hpp @@ -4,8 +4,7 @@ #include #include #include -#include - +#include #include #include @@ -14,28 +13,54 @@ #include "lib/timers.hpp" #include "lib/shared.hpp" -// using namespace websockets; +class BlockNotify { +public: + static BlockNotify& getInstance() { + static BlockNotify instance; + return instance; + } -void setupBlockNotify(); + // Delete copy constructor and assignment operator + BlockNotify(const BlockNotify&) = delete; + void operator=(const BlockNotify&) = delete; -void onWebsocketBlockEvent(void *handler_args, esp_event_base_t base, - int32_t event_id, void *event_data); -void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data); + // Block notification setup and control + void setup(); + void stop(); + void restart(); + bool isConnected() const; + bool isInitialized() const; -void setBlockHeight(uint32_t newBlockHeight); -uint32_t getBlockHeight(); + // Block height management + void setBlockHeight(uint32_t newBlockHeight); + uint32_t getBlockHeight() const; -void setBlockMedianFee(uint16_t blockMedianFee); -uint16_t getBlockMedianFee(); + // Block fee management + void setBlockMedianFee(uint16_t blockMedianFee); + uint16_t getBlockMedianFee() const; -bool isBlockNotifyConnected(); -void stopBlockNotify(); -void restartBlockNotify(); + // Block processing + void processNewBlock(uint32_t newBlockHeight); + void processNewBlockFee(uint16_t newBlockFee); -void processNewBlock(uint32_t newBlockHeight); -void processNewBlockFee(uint16_t newBlockFee); + // Block fetch and update tracking + int fetchLatestBlock(); + uint getLastBlockUpdate() const; + void setLastBlockUpdate(uint lastUpdate); -bool getBlockNotifyInit(); -uint32_t getLastBlockUpdate(); -int getBlockFetch(); -void setLastBlockUpdate(uint32_t lastUpdate); + // Task handling + static void taskNotify(void* pvParameters); + +private: + BlockNotify() = default; // Private constructor for singleton + + void setupTask(); + static void onWebsocketEvent(WStype_t type, uint8_t* payload, size_t length); + + static WebSocketsClient webSocket; + static uint32_t currentBlockHeight; + static uint16_t blockMedianFee; + static bool notifyInit; + static unsigned long int lastBlockUpdate; + static TaskHandle_t taskHandle; +}; \ No newline at end of file diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 6354a7a..def33ea 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -265,7 +265,7 @@ void setupPreferences() EPDManager::getInstance().setForegroundColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR)); EPDManager::getInstance().setBackgroundColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR)); - setBlockHeight(preferences.getUInt("blockHeight", INITIAL_BLOCK_HEIGHT)); + BlockNotify::getInstance().setBlockHeight(preferences.getUInt("blockHeight", INITIAL_BLOCK_HEIGHT)); setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD); if (!preferences.isKey("enableDebugLog")) { @@ -373,7 +373,7 @@ void setupWebsocketClients(void *pvParameters) } else if (dataSource == THIRD_PARTY_SOURCE) { - setupBlockNotify(); + BlockNotify::getInstance().setup(); setupPriceNotify(); } diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index 6d9cce9..7df5ea1 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -79,8 +79,9 @@ void nostrTask(void *pvParameters) { DataSourceType dataSource = getDataSource(); if(dataSource == NOSTR_SOURCE) { - int blockFetch = getBlockFetch(); - processNewBlock(blockFetch); + auto& blockNotify = BlockNotify::getInstance(); + int blockFetch = blockNotify.fetchLatestBlock(); + blockNotify.processNewBlock(blockFetch); } while (1) @@ -174,11 +175,13 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even processNewPrice(obj["content"].as(), CURRENCY_USD); } else if (typeValue == "blockHeight") { - processNewBlock(obj["content"].as()); + auto& blockNotify = BlockNotify::getInstance(); + blockNotify.processNewBlock(obj["content"].as()); } if (medianFee != 0) { - processNewBlockFee(medianFee); + auto& blockNotify = BlockNotify::getInstance(); + blockNotify.processNewBlockFee(medianFee); } } } diff --git a/src/lib/ota.cpp b/src/lib/ota.cpp index 59497c7..2d94d48 100644 --- a/src/lib/ota.cpp +++ b/src/lib/ota.cpp @@ -74,8 +74,8 @@ void onOTAStart() ButtonHandler::suspendTask(); // stopWebServer(); - stopBlockNotify(); - stopPriceNotify(); + auto& blockNotify = BlockNotify::getInstance(); + blockNotify.stop(); } void handleOTATask(void *parameter) diff --git a/src/lib/screen_handler.cpp b/src/lib/screen_handler.cpp index 6b3241e..75e59aa 100644 --- a/src/lib/screen_handler.cpp +++ b/src/lib/screen_handler.cpp @@ -251,9 +251,8 @@ void workerTask(void *pvParameters) { } else if (currentScreenValue == SCREEN_SATS_PER_CURRENCY) { taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); } else { - taskEpdContent = - parseMarketCap(getBlockHeight(), price, currency, - preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR)); + auto& blockNotify = BlockNotify::getInstance(); + taskEpdContent = parseMarketCap(blockNotify.getBlockHeight(), price, currency, preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR)); } EPDManager::getInstance().setContent(taskEpdContent); @@ -261,16 +260,19 @@ void workerTask(void *pvParameters) { } case TASK_FEE_UPDATE: { if (currentScreenValue == SCREEN_BLOCK_FEE_RATE) { - taskEpdContent = parseBlockFees(static_cast(getBlockMedianFee())); + auto& blockNotify = BlockNotify::getInstance(); + taskEpdContent = parseBlockFees(static_cast(blockNotify.getBlockMedianFee())); EPDManager::getInstance().setContent(taskEpdContent); } break; } case TASK_BLOCK_UPDATE: { if (currentScreenValue != SCREEN_HALVING_COUNTDOWN) { - taskEpdContent = parseBlockHeight(getBlockHeight()); + auto& blockNotify = BlockNotify::getInstance(); + taskEpdContent = parseBlockHeight(blockNotify.getBlockHeight()); } else { - taskEpdContent = parseHalvingCountdown(getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN)); + auto& blockNotify = BlockNotify::getInstance(); + taskEpdContent = parseHalvingCountdown(blockNotify.getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN)); } if (currentScreenValue == SCREEN_HALVING_COUNTDOWN || diff --git a/src/lib/v2_notify.cpp b/src/lib/v2_notify.cpp index 6d9fc61..a8174a1 100644 --- a/src/lib/v2_notify.cpp +++ b/src/lib/v2_notify.cpp @@ -131,7 +131,7 @@ namespace V2Notify { uint newBlockHeight = doc["blockheight"].as(); - if (newBlockHeight == getBlockHeight()) + if (newBlockHeight == BlockNotify::getInstance().getBlockHeight()) { return; } @@ -140,7 +140,7 @@ namespace V2Notify Serial.print(F("processNewBlock ")); Serial.println(newBlockHeight); } - processNewBlock(newBlockHeight); + BlockNotify::getInstance().processNewBlock(newBlockHeight); } else if (doc["blockfee"].is()) { @@ -151,7 +151,7 @@ namespace V2Notify Serial.println(medianFee); } - processNewBlockFee(medianFee); + BlockNotify::getInstance().processNewBlockFee(medianFee); } else if (doc["price"].is()) { diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 1d6a878..430828d 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -247,7 +247,8 @@ JsonDocument getStatusObject() JsonObject conStatus = root["connectionStatus"].to(); conStatus["price"] = isPriceNotifyConnected(); - conStatus["blocks"] = isBlockNotifyConnected(); + auto& blockNotify = BlockNotify::getInstance(); + conStatus["blocks"] = blockNotify.isConnected(); conStatus["V2"] = V2Notify::isV2NotifyConnected(); conStatus["nostr"] = nostrConnected(); @@ -906,7 +907,7 @@ void onApiStopDataSources(AsyncWebServerRequest *request) request->beginResponseStream(JSON_CONTENT); stopPriceNotify(); - stopBlockNotify(); + BlockNotify::getInstance().stop(); request->send(response); } @@ -917,9 +918,7 @@ void onApiRestartDataSources(AsyncWebServerRequest *request) request->beginResponseStream(JSON_CONTENT); restartPriceNotify(); - restartBlockNotify(); - // setupPriceNotify(); - // setupBlockNotify(); + BlockNotify::getInstance().restart(); request->send(response); } diff --git a/src/main.cpp b/src/main.cpp index c892a03..08d38ad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,6 +19,7 @@ #include "ESPAsyncWebServer.h" #include "lib/config.hpp" #include "lib/led_handler.hpp" +#include "lib/block_notify.hpp" uint wifiLostConnection; uint priceNotifyLostConnection = 0; @@ -49,7 +50,8 @@ void handleBlockNotifyDisconnection() { if ((getUptime() - blockNotifyLostConnection) > 300) { // 5 minutes timeout Serial.println(F("Block notification connection lost for 5 minutes, restarting handler...")); - restartBlockNotify(); + auto& blockNotify = BlockNotify::getInstance(); + blockNotify.restart(); blockNotifyLostConnection = 0; } } @@ -92,13 +94,14 @@ void checkWiFiConnection() { void checkMissedBlocks() { Serial.println(F("Long time (45 min) since last block, checking if I missed anything...")); - int currentBlock = getBlockFetch(); + auto& blockNotify = BlockNotify::getInstance(); + int currentBlock = blockNotify.fetchLatestBlock(); if (currentBlock != -1) { - if (currentBlock != getBlockHeight()) { + if (currentBlock != blockNotify.getBlockHeight()) { Serial.println(F("Detected stuck block height... restarting block handler.")); - restartBlockNotify(); + blockNotify.restart(); } - setLastBlockUpdate(getUptime()); + blockNotify.setLastBlockUpdate(getUptime()); } } @@ -111,9 +114,10 @@ void monitorDataConnections() { } // Block notification monitoring - if (getBlockNotifyInit() && !isBlockNotifyConnected()) { + auto& blockNotify = BlockNotify::getInstance(); + if (blockNotify.isInitialized() && !blockNotify.isConnected()) { handleBlockNotifyDisconnection(); - } else if (blockNotifyLostConnection > 0 && isBlockNotifyConnected()) { + } else if (blockNotifyLostConnection > 0 && blockNotify.isConnected()) { blockNotifyLostConnection = 0; } @@ -125,7 +129,7 @@ void monitorDataConnections() { } // Check for missed blocks - if ((getLastBlockUpdate() - getUptime()) > 45 * 60) { + if ((blockNotify.getLastBlockUpdate() - getUptime()) > 45 * 60) { checkMissedBlocks(); } } From 1d61453563f62430d441630e642737bb8aad5406 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 6 Jan 2025 01:13:09 +0100 Subject: [PATCH 111/130] Revert to esp websocket client because websocketsClient does not work --- src/lib/block_notify.cpp | 195 ++++++++++++++++++++++----------------- src/lib/block_notify.hpp | 11 +-- src/lib/v2_notify.cpp | 2 +- 3 files changed, 114 insertions(+), 94 deletions(-) diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index 4c32a2a..8502e3d 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -1,103 +1,116 @@ #include "block_notify.hpp" // Initialize static members -WebSocketsClient BlockNotify::webSocket; +esp_websocket_client_handle_t BlockNotify::wsClient = nullptr; uint32_t BlockNotify::currentBlockHeight = 878000; uint16_t BlockNotify::blockMedianFee = 1; bool BlockNotify::notifyInit = false; unsigned long int BlockNotify::lastBlockUpdate = 0; TaskHandle_t BlockNotify::taskHandle = nullptr; -void BlockNotify::taskNotify(void* pvParameters) -{ - for (;;) - { - webSocket.loop(); - vTaskDelay(10 / portTICK_PERIOD_MS); - } -} +const char* BlockNotify::mempoolWsCert = R"EOF( +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- +)EOF"; -void BlockNotify::setupTask() -{ - xTaskCreate(taskNotify, "blockNotify", (6 * 1024), NULL, tskIDLE_PRIORITY, - &taskHandle); -} +void BlockNotify::onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { + esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data; + BlockNotify& instance = BlockNotify::getInstance(); -void BlockNotify::onWebsocketEvent(WStype_t type, uint8_t* payload, size_t length) { - switch(type) { - case WStype_DISCONNECTED: { - Serial.println(F("Mempool.space WS Connection Closed")); - break; - } - case WStype_CONNECTED: { + switch (event_id) { + case WEBSOCKET_EVENT_CONNECTED: + { notifyInit = true; Serial.print(F("Connected to ")); Serial.println(preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE)); JsonDocument doc; doc["action"] = "want"; - JsonArray data = doc.createNestedArray("data"); - data.add("blocks"); - data.add("mempool-blocks"); + JsonArray dataArray = doc.createNestedArray("data"); + dataArray.add("blocks"); + dataArray.add("mempool-blocks"); String sub; serializeJson(doc, sub); - Serial.println(sub); - webSocket.sendTXT(sub.c_str()); + esp_websocket_client_send_text(wsClient, sub.c_str(), sub.length(), portMAX_DELAY); break; } - case WStype_TEXT: { - JsonDocument doc; - JsonDocument filter; - filter["block"]["height"] = true; - filter["mempool-blocks"][0]["medianFee"] = true; - - deserializeJson(doc, (char*)payload, DeserializationOption::Filter(filter)); - - if (debugLogEnabled()) { - Serial.println(doc.as()); - } - - if (doc["block"].is()) - { - JsonObject block = doc["block"]; - if (block["height"].as() != currentBlockHeight) { - BlockNotify::getInstance().processNewBlock(block["height"].as()); - } - } - else if (doc["mempool-blocks"].is()) - { - JsonArray blockInfo = doc["mempool-blocks"].as(); - uint medianFee = (uint)round(blockInfo[0]["medianFee"].as()); - BlockNotify::getInstance().processNewBlockFee(medianFee); - } + case WEBSOCKET_EVENT_DATA: + instance.onWebsocketMessage(data); break; - } - case WStype_BIN: - case WStype_ERROR: - case WStype_FRAGMENT_TEXT_START: - case WStype_FRAGMENT_BIN_START: - case WStype_FRAGMENT: - case WStype_PING: - case WStype_PONG: - case WStype_FRAGMENT_FIN: { + + case WEBSOCKET_EVENT_DISCONNECTED: + Serial.println(F("Mempool.space WS Connection Closed")); + break; + + case WEBSOCKET_EVENT_ERROR: + Serial.println(F("Mempool.space WS Connection Error")); break; - } } } -void BlockNotify::setup() -{ +void BlockNotify::onWebsocketMessage(esp_websocket_event_data_t *data) { + JsonDocument doc; + JsonDocument filter; + filter["block"]["height"] = true; + filter["mempool-blocks"][0]["medianFee"] = true; + + deserializeJson(doc, (char*)data->data_ptr, DeserializationOption::Filter(filter)); + + if (doc["block"].is()) { + JsonObject block = doc["block"]; + if (block["height"].as() != currentBlockHeight) { + processNewBlock(block["height"].as()); + } + } + else if (doc["mempool-blocks"].is()) { + JsonArray blockInfo = doc["mempool-blocks"].as(); + uint medianFee = (uint)round(blockInfo[0]["medianFee"].as()); + processNewBlockFee(medianFee); + } +} + +void BlockNotify::setup() { IPAddress result; int dnsErr = -1; String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); - while (dnsErr != 1 && !strchr(mempoolInstance.c_str(), ':')) - { + while (dnsErr != 1 && !strchr(mempoolInstance.c_str(), ':')) { dnsErr = WiFi.hostByName(mempoolInstance.c_str(), result); - if (dnsErr != 1) - { + if (dnsErr != 1) { Serial.print(mempoolInstance); Serial.println(F("mempool DNS could not be resolved")); WiFi.reconnect(); @@ -111,35 +124,39 @@ void BlockNotify::setup() if (blockFetch > currentBlockHeight) currentBlockHeight = blockFetch; - if (currentBlockHeight != -1) - { + if (currentBlockHeight != -1) { lastBlockUpdate = esp_timer_get_time() / 1000000; } - if (workQueue != nullptr) - { + if (workQueue != nullptr) { WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0}; xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); } const bool useSSL = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE); - const int port = useSSL ? 443 : 80; + const String protocol = useSSL ? "wss" : "ws"; + String wsUri = protocol + "://" + mempoolInstance + "/api/v1/ws"; + + esp_websocket_client_config_t config = { + .task_stack = (6*1024), + .user_agent = USER_AGENT + }; if (useSSL) { - webSocket.beginSSL(mempoolInstance.c_str(), port, "/api/v1/ws"); -// webSocket.beginSSL("ws.btclock.dev", port, "/api/v1/ws"); - - } else { - webSocket.begin(mempoolInstance.c_str(), port, "/api/v1/ws"); + config.cert_pem = mempoolWsCert; } - webSocket.onEvent(onWebsocketEvent); - webSocket.setReconnectInterval(5000); - webSocket.enableHeartbeat(15000, 3000, 2); + config.uri = wsUri.c_str(); - setupTask(); + Serial.printf("Connecting to %s\r\n", mempoolInstance.c_str()); + + wsClient = esp_websocket_client_init(&config); + esp_websocket_register_events(wsClient, WEBSOCKET_EVENT_ANY, onWebsocketEvent, wsClient); + esp_websocket_client_start(wsClient); } + + void BlockNotify::processNewBlock(uint32_t newBlockHeight) { if (newBlockHeight <= currentBlockHeight) { @@ -215,7 +232,9 @@ void BlockNotify::setBlockMedianFee(uint16_t newBlockMedianFee) bool BlockNotify::isConnected() const { - return webSocket.isConnected(); + if (wsClient == NULL) + return false; + return esp_websocket_client_is_connected(wsClient); } bool BlockNotify::isInitialized() const @@ -225,11 +244,13 @@ bool BlockNotify::isInitialized() const void BlockNotify::stop() { - webSocket.disconnect(); - if (taskHandle != NULL) { - vTaskDelete(taskHandle); - taskHandle = NULL; - } + if (wsClient == NULL) + return; + + esp_websocket_client_close(wsClient, portMAX_DELAY); + esp_websocket_client_stop(wsClient); + esp_websocket_client_destroy(wsClient); + wsClient = NULL; } void BlockNotify::restart() diff --git a/src/lib/block_notify.hpp b/src/lib/block_notify.hpp index aa99f2b..15aabee 100644 --- a/src/lib/block_notify.hpp +++ b/src/lib/block_notify.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -48,16 +48,15 @@ public: uint getLastBlockUpdate() const; void setLastBlockUpdate(uint lastUpdate); - // Task handling - static void taskNotify(void* pvParameters); - private: BlockNotify() = default; // Private constructor for singleton void setupTask(); - static void onWebsocketEvent(WStype_t type, uint8_t* payload, size_t length); + static void onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data); + void onWebsocketMessage(esp_websocket_event_data_t *data); - static WebSocketsClient webSocket; + static const char* mempoolWsCert; + static esp_websocket_client_handle_t wsClient; static uint32_t currentBlockHeight; static uint16_t blockMedianFee; static bool notifyInit; diff --git a/src/lib/v2_notify.cpp b/src/lib/v2_notify.cpp index a8174a1..4d23f3a 100644 --- a/src/lib/v2_notify.cpp +++ b/src/lib/v2_notify.cpp @@ -176,7 +176,7 @@ namespace V2Notify for (;;) { webSocket.loop(); - vTaskDelay(10 / portTICK_PERIOD_MS); + vTaskDelay(pdMS_TO_TICKS(10)); } } From bf64b2f64f26ca189ade22a40c0928d0b36b3b9e Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 6 Jan 2025 01:27:13 +0100 Subject: [PATCH 112/130] Merge root certificates --- src/lib/block_notify.cpp | 32 +++++++++++++++++++ src/lib/shared.cpp | 66 ++++++++++++++++++++-------------------- src/lib/shared.hpp | 2 +- 3 files changed, 66 insertions(+), 34 deletions(-) diff --git a/src/lib/block_notify.cpp b/src/lib/block_notify.cpp index 8502e3d..20e6267 100644 --- a/src/lib/block_notify.cpp +++ b/src/lib/block_notify.cpp @@ -43,6 +43,38 @@ VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG jjxDah2nGN59PRbxYvnKkKj9 -----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- )EOF"; void BlockNotify::onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { diff --git a/src/lib/shared.cpp b/src/lib/shared.cpp index aa67768..b8efc0c 100644 --- a/src/lib/shared.cpp +++ b/src/lib/shared.cpp @@ -40,39 +40,39 @@ // "MrY=\n" // "-----END CERTIFICATE-----\n"; -const char* isrg_root_x1cert = R"EOF( ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- -)EOF"; +// const char* isrg_root_x1cert = R"EOF( +// -----BEGIN CERTIFICATE----- +// MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +// TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +// cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +// WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +// ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +// MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +// h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +// 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +// A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +// T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +// B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +// B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +// KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +// OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +// jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +// qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +// rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +// HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +// hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +// ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +// 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +// NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +// ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +// TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +// jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +// oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +// 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +// mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +// emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +// -----END CERTIFICATE----- +// )EOF"; #ifdef TEST_SCREENS diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index 479a52f..54d48aa 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -68,7 +68,7 @@ const int usPerSecond = 1000000; const int usPerMinute = 60 * usPerSecond; // extern const char *github_root_ca; -extern const char *isrg_root_x1cert; +// extern const char *isrg_root_x1cert; extern const uint8_t rootca_crt_bundle_start[] asm("_binary_x509_crt_bundle_start"); // extern const uint8_t ocean_logo_comp[] asm("_binary_ocean_gz_start"); From 963f3b10b7a42ebfb50aba1e71b20d6fe8557dcc Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 6 Jan 2025 01:30:46 +0100 Subject: [PATCH 113/130] Update WebUI --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 732dd26..91e60d2 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 732dd260ea708841f0e15ee1ee64a3d5115cd475 +Subproject commit 91e60d2f4cd7437075a6e10ea0f395b2650ed531 From 1083a3222bf71ab96d27196efa6666e4093bbb3b Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 8 Jan 2025 02:14:33 +0100 Subject: [PATCH 114/130] Add local public pool support --- data | 2 +- dependencies.lock | 2 +- src/lib/defaults.hpp | 1 + src/lib/mining_pool/pool_factory.cpp | 2 ++ src/lib/mining_pool/pool_factory.hpp | 3 +++ src/lib/mining_pool/public_pool/local_public_pool.cpp | 11 +++++++++++ src/lib/mining_pool/public_pool/local_public_pool.hpp | 11 +++++++++++ src/lib/v2_notify.cpp | 4 ---- src/lib/webserver.cpp | 5 ++++- 9 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 src/lib/mining_pool/public_pool/local_public_pool.cpp create mode 100644 src/lib/mining_pool/public_pool/local_public_pool.hpp diff --git a/data b/data index 91e60d2..e0d539a 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 91e60d2f4cd7437075a6e10ea0f395b2650ed531 +Subproject commit e0d539a8a3d29669ccc116311870f317b0d9dfcc diff --git a/dependencies.lock b/dependencies.lock index c338e6c..f52d5f2 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -4,6 +4,6 @@ dependencies: source: type: idf version: 4.4.7 -manifest_hash: cd2f3ee15e776d949eb4ea4eddc8f39b30c2a7905050850eed01ab4928143cff +manifest_hash: 04e75badb795f8a851d8b088baff06d145ecf7a66457d960c2f4ede17b45ef05 target: esp32s3 version: 1.0.0 diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index 29d7eee..a662344 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -60,6 +60,7 @@ #define DEFAULT_MINING_POOL_STATS_ENABLED false #define DEFAULT_MINING_POOL_NAME "ocean" #define DEFAULT_MINING_POOL_USER "38Qkkei3SuF1Eo45BaYmRHUneRD54yyTFy" // Random actual Ocean hasher +#define DEFAULT_LOCAL_POOL_ENDPOINT "umbrel.local:2019" #define DEFAULT_ZAP_NOTIFY_ENABLED false #define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422" diff --git a/src/lib/mining_pool/pool_factory.cpp b/src/lib/mining_pool/pool_factory.cpp index c353996..45bc6ce 100644 --- a/src/lib/mining_pool/pool_factory.cpp +++ b/src/lib/mining_pool/pool_factory.cpp @@ -5,6 +5,7 @@ const char* PoolFactory::MINING_POOL_NAME_NODERUNNERS = "noderunners"; const char* PoolFactory::MINING_POOL_NAME_BRAIINS = "braiins"; const char* PoolFactory::MINING_POOL_NAME_SATOSHI_RADIO = "satoshi_radio"; const char* PoolFactory::MINING_POOL_NAME_PUBLIC_POOL = "public_pool"; +const char* PoolFactory::MINING_POOL_NAME_LOCAL_PUBLIC_POOL = "local_public_pool"; const char* PoolFactory::MINING_POOL_NAME_GOBRRR_POOL = "gobrrr_pool"; const char* PoolFactory::MINING_POOL_NAME_CKPOOL = "ckpool"; const char* PoolFactory::MINING_POOL_NAME_EU_CKPOOL = "eu_ckpool"; @@ -17,6 +18,7 @@ std::unique_ptr PoolFactory::createPool(const std::string& {MINING_POOL_NAME_BRAIINS, []() { return std::make_unique(); }}, {MINING_POOL_NAME_SATOSHI_RADIO, []() { return std::make_unique(); }}, {MINING_POOL_NAME_PUBLIC_POOL, []() { return std::make_unique(); }}, + {MINING_POOL_NAME_LOCAL_PUBLIC_POOL, []() { return std::make_unique(); }}, {MINING_POOL_NAME_GOBRRR_POOL, []() { return std::make_unique(); }}, {MINING_POOL_NAME_CKPOOL, []() { return std::make_unique(); }}, {MINING_POOL_NAME_EU_CKPOOL, []() { return std::make_unique(); }} diff --git a/src/lib/mining_pool/pool_factory.hpp b/src/lib/mining_pool/pool_factory.hpp index 951dbe5..9885d74 100644 --- a/src/lib/mining_pool/pool_factory.hpp +++ b/src/lib/mining_pool/pool_factory.hpp @@ -10,6 +10,7 @@ #include "ocean/ocean_pool.hpp" #include "satoshi_radio/satoshi_radio_pool.hpp" #include "public_pool/public_pool.hpp" +#include "public_pool/local_public_pool.hpp" #include "gobrrr_pool/gobrrr_pool.hpp" #include "ckpool/ckpool.hpp" #include "ckpool/eu_ckpool.hpp" @@ -28,6 +29,7 @@ class PoolFactory { MINING_POOL_NAME_SATOSHI_RADIO, MINING_POOL_NAME_BRAIINS, MINING_POOL_NAME_PUBLIC_POOL, + MINING_POOL_NAME_LOCAL_PUBLIC_POOL, MINING_POOL_NAME_GOBRRR_POOL, MINING_POOL_NAME_CKPOOL, MINING_POOL_NAME_EU_CKPOOL @@ -55,6 +57,7 @@ class PoolFactory { static const char* MINING_POOL_NAME_BRAIINS; static const char* MINING_POOL_NAME_SATOSHI_RADIO; static const char* MINING_POOL_NAME_PUBLIC_POOL; + static const char* MINING_POOL_NAME_LOCAL_PUBLIC_POOL; static const char* MINING_POOL_NAME_GOBRRR_POOL; static const char* MINING_POOL_NAME_CKPOOL; static const char* MINING_POOL_NAME_EU_CKPOOL; diff --git a/src/lib/mining_pool/public_pool/local_public_pool.cpp b/src/lib/mining_pool/public_pool/local_public_pool.cpp new file mode 100644 index 0000000..048197c --- /dev/null +++ b/src/lib/mining_pool/public_pool/local_public_pool.cpp @@ -0,0 +1,11 @@ +#include "local_public_pool.hpp" +#include "lib/shared.hpp" +#include "lib/defaults.hpp" + +std::string LocalPublicPool::getEndpoint() const { + return preferences.getString("localPoolEndpoint", DEFAULT_LOCAL_POOL_ENDPOINT).c_str(); +} + +std::string LocalPublicPool::getApiUrl() const { + return "http://" + getEndpoint() + "/api/client/" + poolUser; +} \ No newline at end of file diff --git a/src/lib/mining_pool/public_pool/local_public_pool.hpp b/src/lib/mining_pool/public_pool/local_public_pool.hpp new file mode 100644 index 0000000..a9e37ad --- /dev/null +++ b/src/lib/mining_pool/public_pool/local_public_pool.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "public_pool.hpp" + +class LocalPublicPool : public PublicPool { +public: + std::string getApiUrl() const override; + std::string getDisplayLabel() const override { return "LOCAL/POOL"; } +private: + std::string getEndpoint() const; +}; \ No newline at end of file diff --git a/src/lib/v2_notify.cpp b/src/lib/v2_notify.cpp index 4d23f3a..b915518 100644 --- a/src/lib/v2_notify.cpp +++ b/src/lib/v2_notify.cpp @@ -155,10 +155,6 @@ namespace V2Notify } else if (doc["price"].is()) { - if (debugLogEnabled()) { - Serial.print(F("processNewPrice ")); - Serial.println(doc["price"].as().size()); - } // Iterate through the key-value pairs of the "price" object for (JsonPair kv : doc["price"].as()) diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 430828d..fef1634 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -5,7 +5,7 @@ static const char* JSON_CONTENT = "application/json"; static const char *const PROGMEM strSettings[] = { - "hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl", "ceEndpoint", "fontName"}; + "hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl", "ceEndpoint", "fontName", "localPoolEndpoint"}; static const char *const PROGMEM uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout"}; @@ -696,6 +696,9 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["mempoolInstance"] = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); root["mempoolSecure"] = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE); + // Local pool settings + root["localPoolEndpoint"] = preferences.getString("localPoolEndpoint", DEFAULT_LOCAL_POOL_ENDPOINT); + // Nostr settings (used for NOSTR_SOURCE or when zapNotify is enabled) root["nostrPubKey"] = preferences.getString("nostrPubKey", DEFAULT_NOSTR_NPUB); root["nostrRelay"] = preferences.getString("nostrRelay", DEFAULT_NOSTR_RELAY); From b01003f07549cbd26e89b871bba4004a0356813b Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 15 Jan 2025 22:09:05 +0100 Subject: [PATCH 115/130] fix: Never write to LED0 --- src/lib/led_handler.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/led_handler.cpp b/src/lib/led_handler.cpp index 3cdb953..453b067 100644 --- a/src/lib/led_handler.cpp +++ b/src/lib/led_handler.cpp @@ -535,7 +535,7 @@ void LedHandler::frontlightSetBrightness(uint brightness) { } for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) { - flArray.setPWM(ledPin, 0, brightness); + flArray.setPWM(ledPin + 1, 0, brightness); } } @@ -543,7 +543,7 @@ std::vector LedHandler::frontlightGetStatus() { std::vector statuses; for (int ledPin = 1; ledPin <= NUM_SCREENS; ledPin++) { uint16_t a = 0, b = 0; - flArray.getPWM(ledPin, &a, &b); + flArray.getPWM(ledPin + 1, &a, &b); statuses.push_back(round(b - a / 4096)); } return statuses; @@ -576,7 +576,7 @@ void LedHandler::frontlightFadeInAll(int flDelayTime, bool staggered) { } else { for (int dutyCycle = 0; dutyCycle <= maxBrightness; dutyCycle += FL_FADE_STEP) { for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) { - flArray.setPWM(ledPin, 0, dutyCycle); + flArray.setPWM(ledPin + 1, 0, dutyCycle); } vTaskDelay(pdMS_TO_TICKS(flDelayTime)); } @@ -611,7 +611,7 @@ void LedHandler::frontlightFadeOutAll(int flDelayTime, bool staggered) { } else { for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= FL_FADE_STEP) { for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) { - flArray.setPWM(ledPin, 0, dutyCycle); + flArray.setPWM(ledPin + 1, 0, dutyCycle); } vTaskDelay(pdMS_TO_TICKS(flDelayTime)); } @@ -628,7 +628,7 @@ void LedHandler::frontlightFadeIn(uint num, int flDelayTime) { } for (int dutyCycle = 0; dutyCycle <= preferences.getUInt("flMaxBrightness"); dutyCycle += 5) { - flArray.setPWM(num, 0, dutyCycle); + flArray.setPWM(num + 1, 0, dutyCycle); vTaskDelay(pdMS_TO_TICKS(flDelayTime)); } } @@ -639,7 +639,7 @@ void LedHandler::frontlightFadeOut(uint num, int flDelayTime) { } for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= 5) { - flArray.setPWM(num, 0, dutyCycle); + flArray.setPWM(num + 1, 0, dutyCycle); vTaskDelay(pdMS_TO_TICKS(flDelayTime)); } } From 9ea021086490c53845508e2a6eac27b6f016b63e Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 16 Jan 2025 00:30:40 +0100 Subject: [PATCH 116/130] fix: set better defaults for frontlight enabled devices --- data | 2 +- src/lib/defaults.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data b/data index e0d539a..68207a7 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit e0d539a8a3d29669ccc116311870f317b0d9dfcc +Subproject commit 68207a7d95b6cb16df5c991b84ff40c25c23755b diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index a662344..55da6e3 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -46,8 +46,8 @@ #define DEFAULT_LUX_LIGHT_TOGGLE 128 #define DEFAULT_FL_OFF_WHEN_DARK true -#define DEFAULT_FL_ALWAYS_ON false -#define DEFAULT_FL_FLASH_ON_UPDATE false +#define DEFAULT_FL_ALWAYS_ON true +#define DEFAULT_FL_FLASH_ON_UPDATE true #define DEFAULT_LED_STATUS false #define DEFAULT_TIMER_ACTIVE true From 678a4ba0998121d78fa582c2353d44a92866bafc Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sun, 19 Jan 2025 22:32:04 +0100 Subject: [PATCH 117/130] fix: Set WiFi country to NL for scanning --- src/lib/config.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/lib/config.cpp b/src/lib/config.cpp index def33ea..16cb80a 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -132,9 +132,25 @@ void setup() void setupWifi() { WiFi.onEvent(WiFiEvent); + + // wifi_country_t country = { + // .cc = "NL", + // .schan = 1, + // .nchan = 13, + // .policy = WIFI_COUNTRY_POLICY_MANUAL + // }; + + // esp_err_t err = esp_wifi_set_country(&country); + // if (err != ESP_OK) { + // Serial.printf("Failed to set country: %d\n", err); + // } + WiFi.setAutoConnect(true); WiFi.setAutoReconnect(true); WiFi.begin(); + + + if (preferences.getInt("txPower", DEFAULT_TX_POWER)) { if (WiFi.setTxPower( @@ -172,6 +188,7 @@ void setupWifi() wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", DEFAULT_WP_TIMEOUT)); wm.setWiFiAutoReconnect(false); wm.setDebugOutput(false); + wm.setCountry("NL"); wm.setConfigPortalBlocking(true); wm.setAPCallback([&](WiFiManager *wifiManager) From 3265eec30886a6ff3b6b4f54eb96b36773133cbc Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Mon, 20 Jan 2025 12:05:48 +0100 Subject: [PATCH 118/130] chore: update dependencies and make eventsource use static jsondocument --- platformio.ini | 13 ++++++++----- src/lib/webserver.cpp | 15 ++++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/platformio.ini b/platformio.ini index d46c153..1eb178a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -30,17 +30,17 @@ build_flags = -DLAST_BUILD_TIME=$UNIX_TIME -DARDUINO_USB_CDC_ON_BOOT -DCORE_DEBUG_LEVEL=0 - -D DEFAULT_BOOT_TEXT=\"BTCLOCK\" + -D CONFIG_ASYNC_TCP_STACK_SIZE=16384 -fexceptions build_unflags = -Werror=all -fno-exceptions lib_deps = https://github.com/joltwallet/esp_littlefs.git - bblanchon/ArduinoJson@^7.2.1 - mathieucarbou/ESPAsyncWebServer @ 3.4.5 + bblanchon/ArduinoJson@^7.3.0 + mathieucarbou/ESPAsyncWebServer @ 3.6.0 robtillaart/MCP23017@^0.8.0 - adafruit/Adafruit NeoPixel@^1.12.3 + adafruit/Adafruit NeoPixel@^1.12.4 https://github.com/dsbaars/universal_pin#feature/mcp23017_rt https://github.com/dsbaars/GxEPD2#universal_pin https://github.com/tzapu/WiFiManager.git#v2.0.17 @@ -79,9 +79,10 @@ build_flags = -D I2C_SDA_PIN=35 -D I2C_SCK_PIN=36 -D HAS_FRONTLIGHT - -D PCA_OE_PIN=45 + -D PCA_OE_PIN=48 -D PCA_I2C_ADDR=0x42 -D IS_HW_REV_B + lib_deps = ${btclock_base.lib_deps} robtillaart/PCA9685@^0.7.1 @@ -100,6 +101,7 @@ build_flags = -D USE_QR -D VERSION_EPD_2_13 -D HW_REV=\"REV_A_EPD_2_13\" + -D CONFIG_ARDUINO_MAIN_TASK_STACK_SIZE=16384 platform_packages = platformio/tool-mklittlefs@^1.203.210628 earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 @@ -112,6 +114,7 @@ build_flags = -D USE_QR -D VERSION_EPD_2_13 -D HW_REV=\"REV_B_EPD_2_13\" + -D CONFIG_ARDUINO_MAIN_TASK_STACK_SIZE=16384 platform_packages = platformio/tool-mklittlefs@^1.203.210628 earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index fef1634..cfb5d62 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -30,7 +30,8 @@ TaskHandle_t eventSourceTaskHandle; void setupWebserver() { events.onConnect([](AsyncEventSourceClient *client) - { client->send("welcome", NULL, millis(), 1000); }); + { client->send("welcome", NULL, millis(), 1000); + }); server.addHandler(&events); AsyncStaticWebHandler &staticHandler = server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html"); @@ -306,14 +307,18 @@ JsonDocument getLedStatusObject() void eventSourceUpdate() { if (!events.count()) return; - JsonDocument doc = getStatusObject(); - doc["leds"] = getLedStatusObject()["data"]; + static JsonDocument doc; + doc.clear(); + + JsonDocument root = getStatusObject(); + + root["leds"] = getLedStatusObject()["data"]; // Get current EPD content directly as array std::array epdContent = EPDManager::getInstance().getCurrentContent(); // Add EPD content arrays - JsonArray data = doc["data"].to(); + JsonArray data = root["data"].to(); // Copy array elements directly for(const auto& content : epdContent) { @@ -321,7 +326,7 @@ void eventSourceUpdate() { } String buffer; - serializeJson(doc, buffer); + serializeJson(root, buffer); events.send(buffer.c_str(), "status"); } From 0b1a362b53d44aa9c31b1bfd13a1781f92a585c4 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 19 Feb 2025 14:12:16 +0100 Subject: [PATCH 119/130] chore: dependency updates --- platformio.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platformio.ini b/platformio.ini index 1eb178a..f9dc11e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,7 +15,7 @@ default_envs = lolin_s3_mini_213epd, lolin_s3_mini_29epd, btclock_rev_b_213epd, [env] [btclock_base] -platform = espressif32 @ ^6.9.0 +platform = espressif32 @ ^6.10.0 framework = arduino, espidf monitor_speed = 115200 monitor_filters = esp32_exception_decoder, colorize @@ -38,8 +38,8 @@ build_unflags = lib_deps = https://github.com/joltwallet/esp_littlefs.git bblanchon/ArduinoJson@^7.3.0 - mathieucarbou/ESPAsyncWebServer @ 3.6.0 - robtillaart/MCP23017@^0.8.0 + esp32async/ESPAsyncWebServer @ 3.7.0 + robtillaart/MCP23017@^0.9.0 adafruit/Adafruit NeoPixel@^1.12.4 https://github.com/dsbaars/universal_pin#feature/mcp23017_rt https://github.com/dsbaars/GxEPD2#universal_pin From e4ac3c5c948372f6cc58048d24656b9ec0f0b187 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 19 Feb 2025 15:15:53 +0100 Subject: [PATCH 120/130] feat: switch to replaceable events for nostr source --- data | 2 +- dependencies.lock | 2 +- src/lib/nostr_notify.cpp | 12 +++++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/data b/data index 68207a7..0116cd6 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 68207a7d95b6cb16df5c991b84ff40c25c23755b +Subproject commit 0116cd68cdfdf383823f74e0f9665a1700cf0500 diff --git a/dependencies.lock b/dependencies.lock index f52d5f2..c338e6c 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -4,6 +4,6 @@ dependencies: source: type: idf version: 4.4.7 -manifest_hash: 04e75badb795f8a851d8b088baff06d145ecf7a66457d960c2f4ede17b45ef05 +manifest_hash: cd2f3ee15e776d949eb4ea4eddc8f39b30c2a7905050850eed01ab4928143cff target: esp32s3 version: 1.0.0 diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index 7df5ea1..dda24e1 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -41,7 +41,7 @@ void setupNostrNotify(bool asDatasource, bool zapNotify) {relay}, {// First filter { - {"kinds", {"1"}}, + {"kinds", {"12203"}}, {"since", {String(getMinutesAgo(60))}}, {"authors", {pubKey}}, }}, @@ -146,6 +146,7 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even // Use direct value access instead of multiple comparisons String typeValue; uint medianFee = 0; + uint blockHeight = 0; for (JsonArray tag : tags) { if (tag.size() != 2) continue; @@ -166,6 +167,11 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even medianFee = tag[1].as(); } break; + case 'b': // blockHeight + if (strcmp(key, "block") == 0) { + blockHeight = tag[1].as(); + } + break; } } @@ -173,6 +179,10 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even if (!typeValue.isEmpty()) { if (typeValue == "priceUsd") { processNewPrice(obj["content"].as(), CURRENCY_USD); + if (blockHeight != 0) { + auto& blockNotify = BlockNotify::getInstance(); + blockNotify.processNewBlock(blockHeight); + } } else if (typeValue == "blockHeight") { auto& blockNotify = BlockNotify::getInstance(); From dc8e348aa349e9fcf3c0f7b12733b4f2306a995f Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Wed, 19 Feb 2025 15:38:54 +0100 Subject: [PATCH 121/130] fix: Set explicit littlefs version tag --- dependencies.lock | 2 +- platformio.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.lock b/dependencies.lock index c338e6c..2274b85 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -4,6 +4,6 @@ dependencies: source: type: idf version: 4.4.7 -manifest_hash: cd2f3ee15e776d949eb4ea4eddc8f39b30c2a7905050850eed01ab4928143cff +manifest_hash: 1d4ef353a86901733b106a1897b186dbf9fc091a4981f0560ea2f6899b7a3d44 target: esp32s3 version: 1.0.0 diff --git a/platformio.ini b/platformio.ini index f9dc11e..37e99da 100644 --- a/platformio.ini +++ b/platformio.ini @@ -36,7 +36,7 @@ build_unflags = -Werror=all -fno-exceptions lib_deps = - https://github.com/joltwallet/esp_littlefs.git + https://github.com/joltwallet/esp_littlefs.git#v1.16.4 bblanchon/ArduinoJson@^7.3.0 esp32async/ESPAsyncWebServer @ 3.7.0 robtillaart/MCP23017@^0.9.0 From 7266a51a92c776350bd7cb3b5ff409695478313f Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 5 Apr 2025 22:35:40 +0200 Subject: [PATCH 122/130] chore: update dependencies --- platformio.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platformio.ini b/platformio.ini index 37e99da..140946d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -37,10 +37,10 @@ build_unflags = -fno-exceptions lib_deps = https://github.com/joltwallet/esp_littlefs.git#v1.16.4 - bblanchon/ArduinoJson@^7.3.0 - esp32async/ESPAsyncWebServer @ 3.7.0 - robtillaart/MCP23017@^0.9.0 - adafruit/Adafruit NeoPixel@^1.12.4 + bblanchon/ArduinoJson@^7.3.1 + esp32async/ESPAsyncWebServer @ 3.7.4 + robtillaart/MCP23017@^0.9.1 + adafruit/Adafruit NeoPixel@^1.12.5 https://github.com/dsbaars/universal_pin#feature/mcp23017_rt https://github.com/dsbaars/GxEPD2#universal_pin https://github.com/tzapu/WiFiManager.git#v2.0.17 From c62563c3c2a9886e09a617aa136c94901acebb50 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 5 Apr 2025 22:40:12 +0200 Subject: [PATCH 123/130] feat: Replace timezone offset with timezone selector --- include/timezone_data.hpp | 721 ++++++++++++++++++++++++++++++++++++++ src/lib/config.cpp | 13 +- src/lib/config.hpp | 3 +- src/lib/defaults.hpp | 1 + src/lib/webserver.cpp | 7 +- 5 files changed, 739 insertions(+), 6 deletions(-) create mode 100644 include/timezone_data.hpp diff --git a/include/timezone_data.hpp b/include/timezone_data.hpp new file mode 100644 index 0000000..1ebb5db --- /dev/null +++ b/include/timezone_data.hpp @@ -0,0 +1,721 @@ +#pragma once + +#include +#include +#include + +namespace timezone_data { + +// Enum for unique timezone strings +enum class TimezoneValue : uint8_t { + plus000plus02_2M350_1M1050_3, + plus01_1, + plus02_2, + plus0330_330, + plus03_3, + plus0430_430, + plus04_4, + plus0530_530, + plus0545_545, + plus05_5, + plus0630_630, + plus06_6, + plus07_7, + plus0845_845, + plus08_8, + plus09_9, + plus1030_1030plus11_11M1010M410, + plus10_10, + plus11_11, + plus11_11plus12M1010M410_3, + plus1245_1245plus1345M950_245M410_345, + plus12_12, + plus13_13, + plus14_14, + _011, + _011plus00M350_0M1050_1, + _022, + _022_01M350__1M1050_0, + _033, + _033_02M320M1110, + _044, + _044_03M1010_0M340_0, + _044_03M916_24M416_24, + _055, + _066, + _066_05M916_22M416_22, + _077, + _088, + _0930930, + _099, + _1010, + _1111, + _1212, + ACST_930, + ACST_930ACDTM1010M410_3, + AEST_10, + AEST_10AEDTM1010M410_3, + AKST9AKDTM320M1110, + AST4, + AST4ADTM320M1110, + AWST_8, + CAT_2, + CET_1, + CET_1CESTM350M1050_3, + CST_8, + CST5CDTM320_0M1110_1, + CST6, + CST6CDTM320M1110, + ChST_10, + EAT_3, + EET_2, + EET_2EESTM344_50M1044_50, + EET_2EESTM350M1050_3, + EET_2EESTM350_0M1050_0, + EET_2EESTM350_3M1050_4, + EET_2EESTM455_0M1054_24, + EST5, + EST5EDTM320M1110, + GMT0, + GMT0BSTM350_1M1050, + HKT_8, + HST10, + HST10HDTM320M1110, + IST_1GMT0M1050M350_1, + IST_2IDTM344_26M1050, + IST_530, + JST_9, + KST_9, + MSK_3, + MST7, + MST7MDTM320M1110, + NST330NDTM320M1110, + NZST_12NZDTM950M410_3, + PKT_5, + PST_8, + PST8PDTM320M1110, + SAST_2, + SST11, + UTC0, + WAT_1, + WET0WESTM350_1M1050, + WIB_7, + WIT_9, + WITA_8, +}; + +// Key-value pair type +using TimezoneEntry = std::pair; + +// Lookup table +constexpr std::array TIMEZONE_DATA = {{ + {"Africa/Abidjan", TimezoneValue::GMT0}, + {"Africa/Accra", TimezoneValue::GMT0}, + {"Africa/Addis_Ababa", TimezoneValue::EAT_3}, + {"Africa/Algiers", TimezoneValue::CET_1}, + {"Africa/Asmara", TimezoneValue::EAT_3}, + {"Africa/Bamako", TimezoneValue::GMT0}, + {"Africa/Bangui", TimezoneValue::WAT_1}, + {"Africa/Banjul", TimezoneValue::GMT0}, + {"Africa/Bissau", TimezoneValue::GMT0}, + {"Africa/Blantyre", TimezoneValue::CAT_2}, + {"Africa/Brazzaville", TimezoneValue::WAT_1}, + {"Africa/Bujumbura", TimezoneValue::CAT_2}, + {"Africa/Cairo", TimezoneValue::EET_2EESTM455_0M1054_24}, + {"Africa/Casablanca", TimezoneValue::plus01_1}, + {"Africa/Ceuta", TimezoneValue::CET_1CESTM350M1050_3}, + {"Africa/Conakry", TimezoneValue::GMT0}, + {"Africa/Dakar", TimezoneValue::GMT0}, + {"Africa/Dar_es_Salaam", TimezoneValue::EAT_3}, + {"Africa/Djibouti", TimezoneValue::EAT_3}, + {"Africa/Douala", TimezoneValue::WAT_1}, + {"Africa/El_Aaiun", TimezoneValue::plus01_1}, + {"Africa/Freetown", TimezoneValue::GMT0}, + {"Africa/Gaborone", TimezoneValue::CAT_2}, + {"Africa/Harare", TimezoneValue::CAT_2}, + {"Africa/Johannesburg", TimezoneValue::SAST_2}, + {"Africa/Juba", TimezoneValue::CAT_2}, + {"Africa/Kampala", TimezoneValue::EAT_3}, + {"Africa/Khartoum", TimezoneValue::CAT_2}, + {"Africa/Kigali", TimezoneValue::CAT_2}, + {"Africa/Kinshasa", TimezoneValue::WAT_1}, + {"Africa/Lagos", TimezoneValue::WAT_1}, + {"Africa/Libreville", TimezoneValue::WAT_1}, + {"Africa/Lome", TimezoneValue::GMT0}, + {"Africa/Luanda", TimezoneValue::WAT_1}, + {"Africa/Lubumbashi", TimezoneValue::CAT_2}, + {"Africa/Lusaka", TimezoneValue::CAT_2}, + {"Africa/Malabo", TimezoneValue::WAT_1}, + {"Africa/Maputo", TimezoneValue::CAT_2}, + {"Africa/Maseru", TimezoneValue::SAST_2}, + {"Africa/Mbabane", TimezoneValue::SAST_2}, + {"Africa/Mogadishu", TimezoneValue::EAT_3}, + {"Africa/Monrovia", TimezoneValue::GMT0}, + {"Africa/Nairobi", TimezoneValue::EAT_3}, + {"Africa/Ndjamena", TimezoneValue::WAT_1}, + {"Africa/Niamey", TimezoneValue::WAT_1}, + {"Africa/Nouakchott", TimezoneValue::GMT0}, + {"Africa/Ouagadougou", TimezoneValue::GMT0}, + {"Africa/Porto-Novo", TimezoneValue::WAT_1}, + {"Africa/Sao_Tome", TimezoneValue::GMT0}, + {"Africa/Tripoli", TimezoneValue::EET_2}, + {"Africa/Tunis", TimezoneValue::CET_1}, + {"Africa/Windhoek", TimezoneValue::CAT_2}, + {"America/Adak", TimezoneValue::HST10HDTM320M1110}, + {"America/Anchorage", TimezoneValue::AKST9AKDTM320M1110}, + {"America/Anguilla", TimezoneValue::AST4}, + {"America/Antigua", TimezoneValue::AST4}, + {"America/Araguaina", TimezoneValue::_033}, + {"America/Argentina/Buenos_Aires", TimezoneValue::_033}, + {"America/Argentina/Catamarca", TimezoneValue::_033}, + {"America/Argentina/Cordoba", TimezoneValue::_033}, + {"America/Argentina/Jujuy", TimezoneValue::_033}, + {"America/Argentina/La_Rioja", TimezoneValue::_033}, + {"America/Argentina/Mendoza", TimezoneValue::_033}, + {"America/Argentina/Rio_Gallegos", TimezoneValue::_033}, + {"America/Argentina/Salta", TimezoneValue::_033}, + {"America/Argentina/San_Juan", TimezoneValue::_033}, + {"America/Argentina/San_Luis", TimezoneValue::_033}, + {"America/Argentina/Tucuman", TimezoneValue::_033}, + {"America/Argentina/Ushuaia", TimezoneValue::_033}, + {"America/Aruba", TimezoneValue::AST4}, + {"America/Asuncion", TimezoneValue::_044_03M1010_0M340_0}, + {"America/Atikokan", TimezoneValue::EST5}, + {"America/Bahia", TimezoneValue::_033}, + {"America/Bahia_Banderas", TimezoneValue::CST6}, + {"America/Barbados", TimezoneValue::AST4}, + {"America/Belem", TimezoneValue::_033}, + {"America/Belize", TimezoneValue::CST6}, + {"America/Blanc-Sablon", TimezoneValue::AST4}, + {"America/Boa_Vista", TimezoneValue::_044}, + {"America/Bogota", TimezoneValue::_055}, + {"America/Boise", TimezoneValue::MST7MDTM320M1110}, + {"America/Cambridge_Bay", TimezoneValue::MST7MDTM320M1110}, + {"America/Campo_Grande", TimezoneValue::_044}, + {"America/Cancun", TimezoneValue::EST5}, + {"America/Caracas", TimezoneValue::_044}, + {"America/Cayenne", TimezoneValue::_033}, + {"America/Cayman", TimezoneValue::EST5}, + {"America/Chicago", TimezoneValue::CST6CDTM320M1110}, + {"America/Chihuahua", TimezoneValue::CST6}, + {"America/Costa_Rica", TimezoneValue::CST6}, + {"America/Creston", TimezoneValue::MST7}, + {"America/Cuiaba", TimezoneValue::_044}, + {"America/Curacao", TimezoneValue::AST4}, + {"America/Danmarkshavn", TimezoneValue::GMT0}, + {"America/Dawson", TimezoneValue::MST7}, + {"America/Dawson_Creek", TimezoneValue::MST7}, + {"America/Denver", TimezoneValue::MST7MDTM320M1110}, + {"America/Detroit", TimezoneValue::EST5EDTM320M1110}, + {"America/Dominica", TimezoneValue::AST4}, + {"America/Edmonton", TimezoneValue::MST7MDTM320M1110}, + {"America/Eirunepe", TimezoneValue::_055}, + {"America/El_Salvador", TimezoneValue::CST6}, + {"America/Fort_Nelson", TimezoneValue::MST7}, + {"America/Fortaleza", TimezoneValue::_033}, + {"America/Glace_Bay", TimezoneValue::AST4ADTM320M1110}, + {"America/Godthab", TimezoneValue::_022_01M350__1M1050_0}, + {"America/Goose_Bay", TimezoneValue::AST4ADTM320M1110}, + {"America/Grand_Turk", TimezoneValue::EST5EDTM320M1110}, + {"America/Grenada", TimezoneValue::AST4}, + {"America/Guadeloupe", TimezoneValue::AST4}, + {"America/Guatemala", TimezoneValue::CST6}, + {"America/Guayaquil", TimezoneValue::_055}, + {"America/Guyana", TimezoneValue::_044}, + {"America/Halifax", TimezoneValue::AST4ADTM320M1110}, + {"America/Havana", TimezoneValue::CST5CDTM320_0M1110_1}, + {"America/Hermosillo", TimezoneValue::MST7}, + {"America/Indiana/Indianapolis", TimezoneValue::EST5EDTM320M1110}, + {"America/Indiana/Knox", TimezoneValue::CST6CDTM320M1110}, + {"America/Indiana/Marengo", TimezoneValue::EST5EDTM320M1110}, + {"America/Indiana/Petersburg", TimezoneValue::EST5EDTM320M1110}, + {"America/Indiana/Tell_City", TimezoneValue::CST6CDTM320M1110}, + {"America/Indiana/Vevay", TimezoneValue::EST5EDTM320M1110}, + {"America/Indiana/Vincennes", TimezoneValue::EST5EDTM320M1110}, + {"America/Indiana/Winamac", TimezoneValue::EST5EDTM320M1110}, + {"America/Inuvik", TimezoneValue::MST7MDTM320M1110}, + {"America/Iqaluit", TimezoneValue::EST5EDTM320M1110}, + {"America/Jamaica", TimezoneValue::EST5}, + {"America/Juneau", TimezoneValue::AKST9AKDTM320M1110}, + {"America/Kentucky/Louisville", TimezoneValue::EST5EDTM320M1110}, + {"America/Kentucky/Monticello", TimezoneValue::EST5EDTM320M1110}, + {"America/Kralendijk", TimezoneValue::AST4}, + {"America/La_Paz", TimezoneValue::_044}, + {"America/Lima", TimezoneValue::_055}, + {"America/Los_Angeles", TimezoneValue::PST8PDTM320M1110}, + {"America/Lower_Princes", TimezoneValue::AST4}, + {"America/Maceio", TimezoneValue::_033}, + {"America/Managua", TimezoneValue::CST6}, + {"America/Manaus", TimezoneValue::_044}, + {"America/Marigot", TimezoneValue::AST4}, + {"America/Martinique", TimezoneValue::AST4}, + {"America/Matamoros", TimezoneValue::CST6CDTM320M1110}, + {"America/Mazatlan", TimezoneValue::MST7}, + {"America/Menominee", TimezoneValue::CST6CDTM320M1110}, + {"America/Merida", TimezoneValue::CST6}, + {"America/Metlakatla", TimezoneValue::AKST9AKDTM320M1110}, + {"America/Mexico_City", TimezoneValue::CST6}, + {"America/Miquelon", TimezoneValue::_033_02M320M1110}, + {"America/Moncton", TimezoneValue::AST4ADTM320M1110}, + {"America/Monterrey", TimezoneValue::CST6}, + {"America/Montevideo", TimezoneValue::_033}, + {"America/Montreal", TimezoneValue::EST5EDTM320M1110}, + {"America/Montserrat", TimezoneValue::AST4}, + {"America/Nassau", TimezoneValue::EST5EDTM320M1110}, + {"America/New_York", TimezoneValue::EST5EDTM320M1110}, + {"America/Nipigon", TimezoneValue::EST5EDTM320M1110}, + {"America/Nome", TimezoneValue::AKST9AKDTM320M1110}, + {"America/Noronha", TimezoneValue::_022}, + {"America/North_Dakota/Beulah", TimezoneValue::CST6CDTM320M1110}, + {"America/North_Dakota/Center", TimezoneValue::CST6CDTM320M1110}, + {"America/North_Dakota/New_Salem", TimezoneValue::CST6CDTM320M1110}, + {"America/Nuuk", TimezoneValue::_022_01M350__1M1050_0}, + {"America/Ojinaga", TimezoneValue::CST6CDTM320M1110}, + {"America/Panama", TimezoneValue::EST5}, + {"America/Pangnirtung", TimezoneValue::EST5EDTM320M1110}, + {"America/Paramaribo", TimezoneValue::_033}, + {"America/Phoenix", TimezoneValue::MST7}, + {"America/Port-au-Prince", TimezoneValue::EST5EDTM320M1110}, + {"America/Port_of_Spain", TimezoneValue::AST4}, + {"America/Porto_Velho", TimezoneValue::_044}, + {"America/Puerto_Rico", TimezoneValue::AST4}, + {"America/Punta_Arenas", TimezoneValue::_033}, + {"America/Rainy_River", TimezoneValue::CST6CDTM320M1110}, + {"America/Rankin_Inlet", TimezoneValue::CST6CDTM320M1110}, + {"America/Recife", TimezoneValue::_033}, + {"America/Regina", TimezoneValue::CST6}, + {"America/Resolute", TimezoneValue::CST6CDTM320M1110}, + {"America/Rio_Branco", TimezoneValue::_055}, + {"America/Santarem", TimezoneValue::_033}, + {"America/Santiago", TimezoneValue::_044_03M916_24M416_24}, + {"America/Santo_Domingo", TimezoneValue::AST4}, + {"America/Sao_Paulo", TimezoneValue::_033}, + {"America/Scoresbysund", TimezoneValue::_022_01M350__1M1050_0}, + {"America/Sitka", TimezoneValue::AKST9AKDTM320M1110}, + {"America/St_Barthelemy", TimezoneValue::AST4}, + {"America/St_Johns", TimezoneValue::NST330NDTM320M1110}, + {"America/St_Kitts", TimezoneValue::AST4}, + {"America/St_Lucia", TimezoneValue::AST4}, + {"America/St_Thomas", TimezoneValue::AST4}, + {"America/St_Vincent", TimezoneValue::AST4}, + {"America/Swift_Current", TimezoneValue::CST6}, + {"America/Tegucigalpa", TimezoneValue::CST6}, + {"America/Thule", TimezoneValue::AST4ADTM320M1110}, + {"America/Thunder_Bay", TimezoneValue::EST5EDTM320M1110}, + {"America/Tijuana", TimezoneValue::PST8PDTM320M1110}, + {"America/Toronto", TimezoneValue::EST5EDTM320M1110}, + {"America/Tortola", TimezoneValue::AST4}, + {"America/Vancouver", TimezoneValue::PST8PDTM320M1110}, + {"America/Whitehorse", TimezoneValue::MST7}, + {"America/Winnipeg", TimezoneValue::CST6CDTM320M1110}, + {"America/Yakutat", TimezoneValue::AKST9AKDTM320M1110}, + {"America/Yellowknife", TimezoneValue::MST7MDTM320M1110}, + {"Antarctica/Casey", TimezoneValue::plus08_8}, + {"Antarctica/Davis", TimezoneValue::plus07_7}, + {"Antarctica/DumontDUrville", TimezoneValue::plus10_10}, + {"Antarctica/Macquarie", TimezoneValue::AEST_10AEDTM1010M410_3}, + {"Antarctica/Mawson", TimezoneValue::plus05_5}, + {"Antarctica/McMurdo", TimezoneValue::NZST_12NZDTM950M410_3}, + {"Antarctica/Palmer", TimezoneValue::_033}, + {"Antarctica/Rothera", TimezoneValue::_033}, + {"Antarctica/Syowa", TimezoneValue::plus03_3}, + {"Antarctica/Troll", TimezoneValue::plus000plus02_2M350_1M1050_3}, + {"Antarctica/Vostok", TimezoneValue::plus05_5}, + {"Arctic/Longyearbyen", TimezoneValue::CET_1CESTM350M1050_3}, + {"Asia/Aden", TimezoneValue::plus03_3}, + {"Asia/Almaty", TimezoneValue::plus05_5}, + {"Asia/Amman", TimezoneValue::plus03_3}, + {"Asia/Anadyr", TimezoneValue::plus12_12}, + {"Asia/Aqtau", TimezoneValue::plus05_5}, + {"Asia/Aqtobe", TimezoneValue::plus05_5}, + {"Asia/Ashgabat", TimezoneValue::plus05_5}, + {"Asia/Atyrau", TimezoneValue::plus05_5}, + {"Asia/Baghdad", TimezoneValue::plus03_3}, + {"Asia/Bahrain", TimezoneValue::plus03_3}, + {"Asia/Baku", TimezoneValue::plus04_4}, + {"Asia/Bangkok", TimezoneValue::plus07_7}, + {"Asia/Barnaul", TimezoneValue::plus07_7}, + {"Asia/Beirut", TimezoneValue::EET_2EESTM350_0M1050_0}, + {"Asia/Bishkek", TimezoneValue::plus06_6}, + {"Asia/Brunei", TimezoneValue::plus08_8}, + {"Asia/Chita", TimezoneValue::plus09_9}, + {"Asia/Choibalsan", TimezoneValue::plus08_8}, + {"Asia/Colombo", TimezoneValue::plus0530_530}, + {"Asia/Damascus", TimezoneValue::plus03_3}, + {"Asia/Dhaka", TimezoneValue::plus06_6}, + {"Asia/Dili", TimezoneValue::plus09_9}, + {"Asia/Dubai", TimezoneValue::plus04_4}, + {"Asia/Dushanbe", TimezoneValue::plus05_5}, + {"Asia/Famagusta", TimezoneValue::EET_2EESTM350_3M1050_4}, + {"Asia/Gaza", TimezoneValue::EET_2EESTM344_50M1044_50}, + {"Asia/Hebron", TimezoneValue::EET_2EESTM344_50M1044_50}, + {"Asia/Ho_Chi_Minh", TimezoneValue::plus07_7}, + {"Asia/Hong_Kong", TimezoneValue::HKT_8}, + {"Asia/Hovd", TimezoneValue::plus07_7}, + {"Asia/Irkutsk", TimezoneValue::plus08_8}, + {"Asia/Jakarta", TimezoneValue::WIB_7}, + {"Asia/Jayapura", TimezoneValue::WIT_9}, + {"Asia/Jerusalem", TimezoneValue::IST_2IDTM344_26M1050}, + {"Asia/Kabul", TimezoneValue::plus0430_430}, + {"Asia/Kamchatka", TimezoneValue::plus12_12}, + {"Asia/Karachi", TimezoneValue::PKT_5}, + {"Asia/Kathmandu", TimezoneValue::plus0545_545}, + {"Asia/Khandyga", TimezoneValue::plus09_9}, + {"Asia/Kolkata", TimezoneValue::IST_530}, + {"Asia/Krasnoyarsk", TimezoneValue::plus07_7}, + {"Asia/Kuala_Lumpur", TimezoneValue::plus08_8}, + {"Asia/Kuching", TimezoneValue::plus08_8}, + {"Asia/Kuwait", TimezoneValue::plus03_3}, + {"Asia/Macau", TimezoneValue::CST_8}, + {"Asia/Magadan", TimezoneValue::plus11_11}, + {"Asia/Makassar", TimezoneValue::WITA_8}, + {"Asia/Manila", TimezoneValue::PST_8}, + {"Asia/Muscat", TimezoneValue::plus04_4}, + {"Asia/Nicosia", TimezoneValue::EET_2EESTM350_3M1050_4}, + {"Asia/Novokuznetsk", TimezoneValue::plus07_7}, + {"Asia/Novosibirsk", TimezoneValue::plus07_7}, + {"Asia/Omsk", TimezoneValue::plus06_6}, + {"Asia/Oral", TimezoneValue::plus05_5}, + {"Asia/Phnom_Penh", TimezoneValue::plus07_7}, + {"Asia/Pontianak", TimezoneValue::WIB_7}, + {"Asia/Pyongyang", TimezoneValue::KST_9}, + {"Asia/Qatar", TimezoneValue::plus03_3}, + {"Asia/Qyzylorda", TimezoneValue::plus05_5}, + {"Asia/Riyadh", TimezoneValue::plus03_3}, + {"Asia/Sakhalin", TimezoneValue::plus11_11}, + {"Asia/Samarkand", TimezoneValue::plus05_5}, + {"Asia/Seoul", TimezoneValue::KST_9}, + {"Asia/Shanghai", TimezoneValue::CST_8}, + {"Asia/Singapore", TimezoneValue::plus08_8}, + {"Asia/Srednekolymsk", TimezoneValue::plus11_11}, + {"Asia/Taipei", TimezoneValue::CST_8}, + {"Asia/Tashkent", TimezoneValue::plus05_5}, + {"Asia/Tbilisi", TimezoneValue::plus04_4}, + {"Asia/Tehran", TimezoneValue::plus0330_330}, + {"Asia/Thimphu", TimezoneValue::plus06_6}, + {"Asia/Tokyo", TimezoneValue::JST_9}, + {"Asia/Tomsk", TimezoneValue::plus07_7}, + {"Asia/Ulaanbaatar", TimezoneValue::plus08_8}, + {"Asia/Urumqi", TimezoneValue::plus06_6}, + {"Asia/Ust-Nera", TimezoneValue::plus10_10}, + {"Asia/Vientiane", TimezoneValue::plus07_7}, + {"Asia/Vladivostok", TimezoneValue::plus10_10}, + {"Asia/Yakutsk", TimezoneValue::plus09_9}, + {"Asia/Yangon", TimezoneValue::plus0630_630}, + {"Asia/Yekaterinburg", TimezoneValue::plus05_5}, + {"Asia/Yerevan", TimezoneValue::plus04_4}, + {"Atlantic/Azores", TimezoneValue::_011plus00M350_0M1050_1}, + {"Atlantic/Bermuda", TimezoneValue::AST4ADTM320M1110}, + {"Atlantic/Canary", TimezoneValue::WET0WESTM350_1M1050}, + {"Atlantic/Cape_Verde", TimezoneValue::_011}, + {"Atlantic/Faroe", TimezoneValue::WET0WESTM350_1M1050}, + {"Atlantic/Madeira", TimezoneValue::WET0WESTM350_1M1050}, + {"Atlantic/Reykjavik", TimezoneValue::GMT0}, + {"Atlantic/South_Georgia", TimezoneValue::_022}, + {"Atlantic/St_Helena", TimezoneValue::GMT0}, + {"Atlantic/Stanley", TimezoneValue::_033}, + {"Australia/Adelaide", TimezoneValue::ACST_930ACDTM1010M410_3}, + {"Australia/Brisbane", TimezoneValue::AEST_10}, + {"Australia/Broken_Hill", TimezoneValue::ACST_930ACDTM1010M410_3}, + {"Australia/Currie", TimezoneValue::AEST_10AEDTM1010M410_3}, + {"Australia/Darwin", TimezoneValue::ACST_930}, + {"Australia/Eucla", TimezoneValue::plus0845_845}, + {"Australia/Hobart", TimezoneValue::AEST_10AEDTM1010M410_3}, + {"Australia/Lindeman", TimezoneValue::AEST_10}, + {"Australia/Lord_Howe", TimezoneValue::plus1030_1030plus11_11M1010M410}, + {"Australia/Melbourne", TimezoneValue::AEST_10AEDTM1010M410_3}, + {"Australia/Perth", TimezoneValue::AWST_8}, + {"Australia/Sydney", TimezoneValue::AEST_10AEDTM1010M410_3}, + {"Etc/GMT", TimezoneValue::GMT0}, + {"Etc/GMT+0", TimezoneValue::GMT0}, + {"Etc/GMT+1", TimezoneValue::_011}, + {"Etc/GMT+10", TimezoneValue::_1010}, + {"Etc/GMT+11", TimezoneValue::_1111}, + {"Etc/GMT+12", TimezoneValue::_1212}, + {"Etc/GMT+2", TimezoneValue::_022}, + {"Etc/GMT+3", TimezoneValue::_033}, + {"Etc/GMT+4", TimezoneValue::_044}, + {"Etc/GMT+5", TimezoneValue::_055}, + {"Etc/GMT+6", TimezoneValue::_066}, + {"Etc/GMT+7", TimezoneValue::_077}, + {"Etc/GMT+8", TimezoneValue::_088}, + {"Etc/GMT+9", TimezoneValue::_099}, + {"Etc/GMT-0", TimezoneValue::GMT0}, + {"Etc/GMT-1", TimezoneValue::plus01_1}, + {"Etc/GMT-10", TimezoneValue::plus10_10}, + {"Etc/GMT-11", TimezoneValue::plus11_11}, + {"Etc/GMT-12", TimezoneValue::plus12_12}, + {"Etc/GMT-13", TimezoneValue::plus13_13}, + {"Etc/GMT-14", TimezoneValue::plus14_14}, + {"Etc/GMT-2", TimezoneValue::plus02_2}, + {"Etc/GMT-3", TimezoneValue::plus03_3}, + {"Etc/GMT-4", TimezoneValue::plus04_4}, + {"Etc/GMT-5", TimezoneValue::plus05_5}, + {"Etc/GMT-6", TimezoneValue::plus06_6}, + {"Etc/GMT-7", TimezoneValue::plus07_7}, + {"Etc/GMT-8", TimezoneValue::plus08_8}, + {"Etc/GMT-9", TimezoneValue::plus09_9}, + {"Etc/GMT0", TimezoneValue::GMT0}, + {"Etc/Greenwich", TimezoneValue::GMT0}, + {"Etc/UCT", TimezoneValue::UTC0}, + {"Etc/UTC", TimezoneValue::UTC0}, + {"Etc/Universal", TimezoneValue::UTC0}, + {"Etc/Zulu", TimezoneValue::UTC0}, + {"Europe/Amsterdam", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Andorra", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Astrakhan", TimezoneValue::plus04_4}, + {"Europe/Athens", TimezoneValue::EET_2EESTM350_3M1050_4}, + {"Europe/Belgrade", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Berlin", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Bratislava", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Brussels", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Bucharest", TimezoneValue::EET_2EESTM350_3M1050_4}, + {"Europe/Budapest", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Busingen", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Chisinau", TimezoneValue::EET_2EESTM350M1050_3}, + {"Europe/Copenhagen", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Dublin", TimezoneValue::IST_1GMT0M1050M350_1}, + {"Europe/Gibraltar", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Guernsey", TimezoneValue::GMT0BSTM350_1M1050}, + {"Europe/Helsinki", TimezoneValue::EET_2EESTM350_3M1050_4}, + {"Europe/Isle_of_Man", TimezoneValue::GMT0BSTM350_1M1050}, + {"Europe/Istanbul", TimezoneValue::plus03_3}, + {"Europe/Jersey", TimezoneValue::GMT0BSTM350_1M1050}, + {"Europe/Kaliningrad", TimezoneValue::EET_2}, + {"Europe/Kiev", TimezoneValue::EET_2EESTM350_3M1050_4}, + {"Europe/Kirov", TimezoneValue::MSK_3}, + {"Europe/Lisbon", TimezoneValue::WET0WESTM350_1M1050}, + {"Europe/Ljubljana", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/London", TimezoneValue::GMT0BSTM350_1M1050}, + {"Europe/Luxembourg", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Madrid", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Malta", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Mariehamn", TimezoneValue::EET_2EESTM350_3M1050_4}, + {"Europe/Minsk", TimezoneValue::plus03_3}, + {"Europe/Monaco", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Moscow", TimezoneValue::MSK_3}, + {"Europe/Oslo", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Paris", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Podgorica", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Prague", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Riga", TimezoneValue::EET_2EESTM350_3M1050_4}, + {"Europe/Rome", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Samara", TimezoneValue::plus04_4}, + {"Europe/San_Marino", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Sarajevo", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Saratov", TimezoneValue::plus04_4}, + {"Europe/Simferopol", TimezoneValue::MSK_3}, + {"Europe/Skopje", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Sofia", TimezoneValue::EET_2EESTM350_3M1050_4}, + {"Europe/Stockholm", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Tallinn", TimezoneValue::EET_2EESTM350_3M1050_4}, + {"Europe/Tirane", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Ulyanovsk", TimezoneValue::plus04_4}, + {"Europe/Uzhgorod", TimezoneValue::EET_2EESTM350_3M1050_4}, + {"Europe/Vaduz", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Vatican", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Vienna", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Vilnius", TimezoneValue::EET_2EESTM350_3M1050_4}, + {"Europe/Volgograd", TimezoneValue::MSK_3}, + {"Europe/Warsaw", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Zagreb", TimezoneValue::CET_1CESTM350M1050_3}, + {"Europe/Zaporozhye", TimezoneValue::EET_2EESTM350_3M1050_4}, + {"Europe/Zurich", TimezoneValue::CET_1CESTM350M1050_3}, + {"Indian/Antananarivo", TimezoneValue::EAT_3}, + {"Indian/Chagos", TimezoneValue::plus06_6}, + {"Indian/Christmas", TimezoneValue::plus07_7}, + {"Indian/Cocos", TimezoneValue::plus0630_630}, + {"Indian/Comoro", TimezoneValue::EAT_3}, + {"Indian/Kerguelen", TimezoneValue::plus05_5}, + {"Indian/Mahe", TimezoneValue::plus04_4}, + {"Indian/Maldives", TimezoneValue::plus05_5}, + {"Indian/Mauritius", TimezoneValue::plus04_4}, + {"Indian/Mayotte", TimezoneValue::EAT_3}, + {"Indian/Reunion", TimezoneValue::plus04_4}, + {"Pacific/Apia", TimezoneValue::plus13_13}, + {"Pacific/Auckland", TimezoneValue::NZST_12NZDTM950M410_3}, + {"Pacific/Bougainville", TimezoneValue::plus11_11}, + {"Pacific/Chatham", TimezoneValue::plus1245_1245plus1345M950_245M410_345}, + {"Pacific/Chuuk", TimezoneValue::plus10_10}, + {"Pacific/Easter", TimezoneValue::_066_05M916_22M416_22}, + {"Pacific/Efate", TimezoneValue::plus11_11}, + {"Pacific/Enderbury", TimezoneValue::plus13_13}, + {"Pacific/Fakaofo", TimezoneValue::plus13_13}, + {"Pacific/Fiji", TimezoneValue::plus12_12}, + {"Pacific/Funafuti", TimezoneValue::plus12_12}, + {"Pacific/Galapagos", TimezoneValue::_066}, + {"Pacific/Gambier", TimezoneValue::_099}, + {"Pacific/Guadalcanal", TimezoneValue::plus11_11}, + {"Pacific/Guam", TimezoneValue::ChST_10}, + {"Pacific/Honolulu", TimezoneValue::HST10}, + {"Pacific/Kiritimati", TimezoneValue::plus14_14}, + {"Pacific/Kosrae", TimezoneValue::plus11_11}, + {"Pacific/Kwajalein", TimezoneValue::plus12_12}, + {"Pacific/Majuro", TimezoneValue::plus12_12}, + {"Pacific/Marquesas", TimezoneValue::_0930930}, + {"Pacific/Midway", TimezoneValue::SST11}, + {"Pacific/Nauru", TimezoneValue::plus12_12}, + {"Pacific/Niue", TimezoneValue::_1111}, + {"Pacific/Norfolk", TimezoneValue::plus11_11plus12M1010M410_3}, + {"Pacific/Noumea", TimezoneValue::plus11_11}, + {"Pacific/Pago_Pago", TimezoneValue::SST11}, + {"Pacific/Palau", TimezoneValue::plus09_9}, + {"Pacific/Pitcairn", TimezoneValue::_088}, + {"Pacific/Pohnpei", TimezoneValue::plus11_11}, + {"Pacific/Port_Moresby", TimezoneValue::plus10_10}, + {"Pacific/Rarotonga", TimezoneValue::_1010}, + {"Pacific/Saipan", TimezoneValue::ChST_10}, + {"Pacific/Tahiti", TimezoneValue::_1010}, + {"Pacific/Tarawa", TimezoneValue::plus12_12}, + {"Pacific/Tongatapu", TimezoneValue::plus13_13}, + {"Pacific/Wake", TimezoneValue::plus12_12}, + {"Pacific/Wallis", TimezoneValue::plus12_12}, +}}; + +// Helper function to find timezone value +inline TimezoneValue find_timezone_value(std::string_view key) { + for (const auto& entry : TIMEZONE_DATA) { + if (entry.first == key) { + return entry.second; + } + } + return TimezoneValue::plus000plus02_2M350_1M1050_3; // Default fallback +} + +// Overload for String +inline TimezoneValue find_timezone_value(const String& key) { + return find_timezone_value(std::string_view(key.c_str())); +} + +// Overload for std::string +inline TimezoneValue find_timezone_value(const std::string& key) { + return find_timezone_value(std::string_view(key)); +} + +// Helper function to convert TimezoneValue to string representation +inline String get_timezone_string(TimezoneValue value) { + for (const auto& entry : TIMEZONE_DATA) { + if (entry.second == value) { + return String(entry.first.data(), entry.first.length()); + } + } + return String("GMT0"); // Default fallback +} + +// Overload for std::string +inline std::string get_timezone_string_std(TimezoneValue value) { + for (const auto& entry : TIMEZONE_DATA) { + if (entry.second == value) { + return std::string(entry.first.data(), entry.first.length()); + } + } + return "GMT0"; // Default fallback +} + +// Helper function to convert TimezoneValue enum to its string representation +inline String get_timezone_value_string(TimezoneValue value) { + switch (value) { + case TimezoneValue::plus000plus02_2M350_1M1050_3: return String("+00:00+02:00,M3.5.0/1,M10.5.0/3"); + case TimezoneValue::plus01_1: return String("+01:00"); + case TimezoneValue::plus02_2: return String("+02:00"); + case TimezoneValue::plus0330_330: return String("+03:30"); + case TimezoneValue::plus03_3: return String("+03:00"); + case TimezoneValue::plus0430_430: return String("+04:30"); + case TimezoneValue::plus04_4: return String("+04:00"); + case TimezoneValue::plus0530_530: return String("+05:30"); + case TimezoneValue::plus0545_545: return String("+05:45"); + case TimezoneValue::plus05_5: return String("+05:00"); + case TimezoneValue::plus0630_630: return String("+06:30"); + case TimezoneValue::plus06_6: return String("+06:00"); + case TimezoneValue::plus07_7: return String("+07:00"); + case TimezoneValue::plus0845_845: return String("+08:45"); + case TimezoneValue::plus08_8: return String("+08:00"); + case TimezoneValue::plus09_9: return String("+09:00"); + case TimezoneValue::plus1030_1030plus11_11M1010M410: return String("+10:30+11:00,M10.1.0,M4.1.0"); + case TimezoneValue::plus10_10: return String("+10:00"); + case TimezoneValue::plus11_11: return String("+11:00"); + case TimezoneValue::plus11_11plus12M1010M410_3: return String("+11:00+12:00,M10.1.0,M4.1.0/3"); + case TimezoneValue::plus1245_1245plus1345M950_245M410_345: return String("+12:45+13:45,M9.5.0/2:45,M4.1.0/3:45"); + case TimezoneValue::plus12_12: return String("+12:00"); + case TimezoneValue::plus13_13: return String("+13:00"); + case TimezoneValue::plus14_14: return String("+14:00"); + case TimezoneValue::_011: return String("-01:00"); + case TimezoneValue::_011plus00M350_0M1050_1: return String("-01:00+00:00,M3.5.0/0,M10.5.0/1"); + case TimezoneValue::_022: return String("-02:00"); + case TimezoneValue::_022_01M350__1M1050_0: return String("-02:00-01:00,M3.5.0/-1,M10.5.0/0"); + case TimezoneValue::_033: return String("-03:00"); + case TimezoneValue::_033_02M320M1110: return String("-03:00-02:00,M3.2.0,M11.1.0"); + case TimezoneValue::_044: return String("-04:00"); + case TimezoneValue::_044_03M1010_0M340_0: return String("-04:00-03:00,M10.1.0/0,M3.4.0/0"); + case TimezoneValue::_044_03M916_24M416_24: return String("-04:00-03:00,M9.1.6/24,M4.1.6/24"); + case TimezoneValue::_055: return String("-05:00"); + case TimezoneValue::_066: return String("-06:00"); + case TimezoneValue::_066_05M916_22M416_22: return String("-06:00-05:00,M9.1.6/22,M4.1.6/22"); + case TimezoneValue::_077: return String("-07:00"); + case TimezoneValue::_088: return String("-08:00"); + case TimezoneValue::_0930930: return String("-09:30"); + case TimezoneValue::_099: return String("-09:00"); + case TimezoneValue::_1010: return String("-10:00"); + case TimezoneValue::_1111: return String("-11:00"); + case TimezoneValue::_1212: return String("-12:00"); + case TimezoneValue::ACST_930: return String("ACST-9:30"); + case TimezoneValue::ACST_930ACDTM1010M410_3: return String("ACST-9:30ACDT,M10.1.0,M4.1.0/3"); + case TimezoneValue::AEST_10: return String("AEST-10"); + case TimezoneValue::AEST_10AEDTM1010M410_3: return String("AEST-10AEDT,M10.1.0,M4.1.0/3"); + case TimezoneValue::AKST9AKDTM320M1110: return String("AKST9AKDT,M3.2.0,M11.1.0"); + case TimezoneValue::AST4: return String("AST4"); + case TimezoneValue::AST4ADTM320M1110: return String("AST4ADT,M3.2.0,M11.1.0"); + case TimezoneValue::AWST_8: return String("AWST-8"); + case TimezoneValue::CAT_2: return String("CAT-2"); + case TimezoneValue::CET_1: return String("CET-1"); + case TimezoneValue::CET_1CESTM350M1050_3: return String("CET-1CEST,M3.5.0,M10.5.0/3"); + case TimezoneValue::CST_8: return String("CST-8"); + case TimezoneValue::CST5CDTM320_0M1110_1: return String("CST5CDT,M3.2.0/0,M11.1.0/1"); + case TimezoneValue::CST6: return String("CST6"); + case TimezoneValue::CST6CDTM320M1110: return String("CST6CDT,M3.2.0,M11.1.0"); + case TimezoneValue::ChST_10: return String("ChST-10"); + case TimezoneValue::EAT_3: return String("EAT-3"); + case TimezoneValue::EET_2: return String("EET-2"); + case TimezoneValue::EET_2EESTM344_50M1044_50: return String("EET-2EEST,M3.4.4/50,M10.4.4/50"); + case TimezoneValue::EET_2EESTM350M1050_3: return String("EET-2EEST,M3.5.0,M10.5.0/3"); + case TimezoneValue::EET_2EESTM350_0M1050_0: return String("EET-2EEST,M3.5.0/0,M10.5.0/0"); + case TimezoneValue::EET_2EESTM350_3M1050_4: return String("EET-2EEST,M3.5.0/3,M10.5.0/4"); + case TimezoneValue::EET_2EESTM455_0M1054_24: return String("EET-2EEST,M4.5.5/0,M10.5.4/24"); + case TimezoneValue::EST5: return String("EST5"); + case TimezoneValue::EST5EDTM320M1110: return String("EST5EDT,M3.2.0,M11.1.0"); + case TimezoneValue::GMT0: return String("GMT0"); + case TimezoneValue::GMT0BSTM350_1M1050: return String("GMT0BST,M3.5.0/1,M10.5.0"); + case TimezoneValue::HKT_8: return String("HKT-8"); + case TimezoneValue::HST10: return String("HST10"); + case TimezoneValue::HST10HDTM320M1110: return String("HST10HDT,M3.2.0,M11.1.0"); + case TimezoneValue::IST_1GMT0M1050M350_1: return String("IST-1GMT0,M10.5.0,M3.5.0/1"); + case TimezoneValue::IST_2IDTM344_26M1050: return String("IST-2IDT,M3.4.4/26,M10.5.0"); + case TimezoneValue::IST_530: return String("IST-5:30"); + case TimezoneValue::JST_9: return String("JST-9"); + case TimezoneValue::KST_9: return String("KST-9"); + case TimezoneValue::MSK_3: return String("MSK-3"); + case TimezoneValue::MST7: return String("MST7"); + case TimezoneValue::MST7MDTM320M1110: return String("MST7MDT,M3.2.0,M11.1.0"); + case TimezoneValue::NST330NDTM320M1110: return String("NST3:30NDT,M3.2.0,M11.1.0"); + case TimezoneValue::NZST_12NZDTM950M410_3: return String("NZST-12NZDT,M9.5.0,M4.1.0/3"); + case TimezoneValue::PKT_5: return String("PKT-5"); + case TimezoneValue::PST_8: return String("PST-8"); + case TimezoneValue::PST8PDTM320M1110: return String("PST8PDT,M3.2.0,M11.1.0"); + case TimezoneValue::SAST_2: return String("SAST-2"); + case TimezoneValue::SST11: return String("SST11"); + case TimezoneValue::UTC0: return String("UTC0"); + case TimezoneValue::WAT_1: return String("WAT-1"); + case TimezoneValue::WET0WESTM350_1M1050: return String("WET0WEST,M3.5.0/1,M10.5.0"); + case TimezoneValue::WIB_7: return String("WIB-7"); + case TimezoneValue::WIT_9: return String("WIT-9"); + case TimezoneValue::WITA_8: return String("WITA-8"); + default: return String("GMT0"); // Default fallback + } +} + +// Overload for std::string +inline std::string get_timezone_value_string_std(TimezoneValue value) { + return std::string(get_timezone_value_string(value).c_str()); +} + +} // namespace timezone_data diff --git a/src/lib/config.cpp b/src/lib/config.cpp index 16cb80a..908a5a6 100644 --- a/src/lib/config.cpp +++ b/src/lib/config.cpp @@ -259,7 +259,7 @@ void setupWifi() void syncTime() { - configTime(preferences.getInt("gmtOffset", DEFAULT_TIME_OFFSET_SECONDS), 0, + configTime(0, 0, NTP_SERVER); struct tm timeinfo; @@ -267,15 +267,24 @@ void syncTime() { auto& ledHandler = getLedHandler(); ledHandler.queueEffect(LED_EFFECT_CONFIGURING); - configTime(preferences.getInt("gmtOffset", DEFAULT_TIME_OFFSET_SECONDS), 0, + configTime(0, 0, NTP_SERVER); delay(500); Serial.println(F("Retry set time")); } + setTimezone(get_timezone_value_string(timezone_data::find_timezone_value(preferences.getString("tzString", DEFAULT_TZ_STRING)))); + lastTimeSync = esp_timer_get_time() / 1000000; } +void setTimezone(String timezone) { + Serial.printf(" Setting Timezone to %s\n",timezone.c_str()); + setenv("TZ",timezone.c_str(),1); // Now adjust the TZ. Clock settings are adjusted to show the new local time + tzset(); +} + + void setupPreferences() { preferences.begin("btclock", false); diff --git a/src/lib/config.hpp b/src/lib/config.hpp index 95c877d..c8d5336 100644 --- a/src/lib/config.hpp +++ b/src/lib/config.hpp @@ -33,7 +33,7 @@ #include "shared.hpp" #include "defaults.hpp" - +#include "timezone_data.hpp" #define NTP_SERVER "pool.ntp.org" #define DEFAULT_TIME_OFFSET_SECONDS 3600 #ifndef MCP_DEV_ADDR @@ -43,6 +43,7 @@ void setup(); void syncTime(); +void setTimezone(String timezone); uint getLastTimeSync(); void setupPreferences(); void setupWebsocketClients(void *pvParameters); diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index 55da6e3..00d8bc0 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -24,6 +24,7 @@ #define DEFAULT_V2_SOURCE_CURRENCY CURRENCY_USD #define DEFAULT_TIME_OFFSET_SECONDS 3600 +#define DEFAULT_TZ_STRING "Europe/Amsterdam" #define DEFAULT_HOSTNAME_PREFIX "btclock" #define DEFAULT_MEMPOOL_INSTANCE "mempool.space" diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index cfb5d62..8313b76 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -5,7 +5,7 @@ static const char* JSON_CONTENT = "application/json"; static const char *const PROGMEM strSettings[] = { - "hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl", "ceEndpoint", "fontName", "localPoolEndpoint"}; + "hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl", "ceEndpoint", "fontName", "localPoolEndpoint", "tzString"}; static const char *const PROGMEM uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout"}; @@ -692,8 +692,9 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["fullRefreshMin"] = preferences.getUInt("fullRefreshMin", DEFAULT_MINUTES_FULL_REFRESH); root["wpTimeout"] = preferences.getUInt("wpTimeout", DEFAULT_WP_TIMEOUT); - root["tzOffset"] = preferences.getInt("gmtOffset", DEFAULT_TIME_OFFSET_SECONDS) / 60; - + //root["tzOffset"] = preferences.getInt("gmtOffset", DEFAULT_TIME_OFFSET_SECONDS) / 60; + root["tzString"] = preferences.getString("tzString", DEFAULT_TZ_STRING); + // Add data source settings root["dataSource"] = preferences.getUChar("dataSource", DEFAULT_DATA_SOURCE); From 3e54343da8b995aae663ce972631561b6a950e7b Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 5 Apr 2025 22:40:52 +0200 Subject: [PATCH 124/130] chore: Update WebUI --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 0116cd6..0e278d1 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 0116cd68cdfdf383823f74e0f9665a1700cf0500 +Subproject commit 0e278d1be4160ab382213e80ec0716f8aad14a65 From d648551835d3db3ad80921ee652f4c518aae53dd Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Fri, 2 May 2025 22:28:46 +0200 Subject: [PATCH 125/130] fix: Fix LED status object --- src/lib/webserver.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 8313b76..6ee62f9 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -298,7 +298,13 @@ JsonDocument getLedStatusObject() uint blue = pixColor & 0xFF; char hexColor[8]; snprintf(hexColor, sizeof(hexColor), "#%02X%02X%02X", red, green, blue); - colors.add(hexColor); + // colors.add(hexColor); + + JsonObject object = colors.add(); + object["red"] = red; + object["green"] = green; + object["blue"] = blue; + object["hex"] = hexColor; } return root; From 064fe8fe6ce83b04bfdc28529bf6685ffda095ca Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 3 May 2025 00:03:01 +0200 Subject: [PATCH 126/130] chore: Update WebUI and dependencies --- data | 2 +- platformio.ini | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data b/data index 0e278d1..8389ed8 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 0e278d1be4160ab382213e80ec0716f8aad14a65 +Subproject commit 8389ed8e36a9a1a7a39ca31f53324a0949aedb1d diff --git a/platformio.ini b/platformio.ini index 140946d..98192fe 100644 --- a/platformio.ini +++ b/platformio.ini @@ -37,8 +37,8 @@ build_unflags = -fno-exceptions lib_deps = https://github.com/joltwallet/esp_littlefs.git#v1.16.4 - bblanchon/ArduinoJson@^7.3.1 - esp32async/ESPAsyncWebServer @ 3.7.4 + bblanchon/ArduinoJson@^7.4.1 + esp32async/ESPAsyncWebServer @ 3.7.7 robtillaart/MCP23017@^0.9.1 adafruit/Adafruit NeoPixel@^1.12.5 https://github.com/dsbaars/universal_pin#feature/mcp23017_rt From 2ac2a62c617ca0469cba1027c70c0ddd9ac3ae76 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 3 May 2025 00:03:19 +0200 Subject: [PATCH 127/130] feat: change 3rd party price source to kraken --- src/lib/price_notify.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/lib/price_notify.cpp b/src/lib/price_notify.cpp index 6ac2f3b..c851e85 100644 --- a/src/lib/price_notify.cpp +++ b/src/lib/price_notify.cpp @@ -1,6 +1,6 @@ #include "price_notify.hpp" -const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin"; +const char *wsServerPrice = "wss://ws.kraken.com/v2"; WebSocketsClient webSocket; uint currentPrice = 90000; @@ -14,7 +14,7 @@ void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length); void setupPriceNotify() { - webSocket.beginSSL("ws.coincap.io", 443, "/prices?assets=bitcoin"); + webSocket.beginSSL("ws.kraken.com", 443, "/v2"); webSocket.onEvent([](WStype_t type, uint8_t * payload, size_t length) { onWebsocketPriceEvent(type, payload, length); }); @@ -32,7 +32,14 @@ void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length) { case WStype_CONNECTED: { Serial.println("Connected to " + String(wsServerPrice)); - priceNotifyInit = true; + + JsonDocument doc; + doc["method"] = "subscribe"; + JsonObject params = doc["params"].to(); + params["channel"] = "ticker"; + params["symbol"][0] = "BTC/USD"; + + webSocket.sendTXT(doc.as().c_str()); break; } case WStype_TEXT: @@ -40,13 +47,15 @@ void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length) { JsonDocument doc; deserializeJson(doc, (char *)payload); - if (doc["bitcoin"].is()) + if (doc["data"][0].is()) { - if (currentPrice != doc["bitcoin"].as()) + float price = doc["data"][0]["last"].as(); + uint roundedPrice = round(price); + if (currentPrice != roundedPrice) { - processNewPrice(doc["bitcoin"].as(), CURRENCY_USD); + processNewPrice(roundedPrice, CURRENCY_USD); } - } + } break; } case WStype_BIN: From 7853bf3e069ed8b3daafb950bb8006569a0c519b Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 12 Jun 2025 16:10:17 +0200 Subject: [PATCH 128/130] feat: Add restore screen after zap setting --- src/lib/defaults.hpp | 1 + src/lib/nostr_notify.cpp | 15 ++++++++++++++- src/lib/shared.hpp | 1 + src/lib/webserver.cpp | 3 ++- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/lib/defaults.hpp b/src/lib/defaults.hpp index 00d8bc0..a785561 100644 --- a/src/lib/defaults.hpp +++ b/src/lib/defaults.hpp @@ -86,6 +86,7 @@ #define DEFAULT_CUSTOM_ENDPOINT "ws-staging.btclock.dev" #define DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL false #define DEFAULT_MOW_MODE false +#define DEFAULT_SCREEN_RESTORE_AFTER_ZAP true // Define data source types enum DataSourceType { diff --git a/src/lib/nostr_notify.cpp b/src/lib/nostr_notify.cpp index dda24e1..5bab443 100644 --- a/src/lib/nostr_notify.cpp +++ b/src/lib/nostr_notify.cpp @@ -10,6 +10,14 @@ boolean nostrIsSubscribing = true; String subIdZap; +void screenRestoreAfterZapCallback(TimerHandle_t xTimer) +{ + Serial.println("Restoring screen after zap"); + int screenBeforeZap = (int)(uintptr_t)pvTimerGetTimerID(xTimer); + ScreenHandler::setCurrentScreen(screenBeforeZap); + xTimerDelete(xTimer, 0); +} + void setupNostrNotify(bool asDatasource, bool zapNotify) { nostr::esp32::ESP32Platform::initNostr(false); @@ -288,12 +296,13 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event) } uint64_t timerPeriod = 0; + int screenBeforeZap = ScreenHandler::getCurrentScreen(); if (isTimerActive()) { // store timer periode before making inactive to prevent artifacts timerPeriod = getTimerSeconds(); esp_timer_stop(screenRotateTimer); - } + } ScreenHandler::setCurrentScreen(SCREEN_CUSTOM); EPDManager::getInstance().setContent(textEpdContent); @@ -306,6 +315,10 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event) { esp_timer_start_periodic(screenRotateTimer, timerPeriod * usPerSecond); + } else if (preferences.getBool("scrnRestoreZap", DEFAULT_SCREEN_RESTORE_AFTER_ZAP)) { + TimerHandle_t screenRestoreAfterZapTimer = xTimerCreate("screenRestoreAfterZap", pdMS_TO_TICKS(getTimerSeconds() * msPerSecond), pdFALSE, (void*)(uintptr_t)screenBeforeZap, screenRestoreAfterZapCallback); + Serial.println("Starting screen restore after zap"); + xTimerStart(screenRestoreAfterZapTimer, 0); } } diff --git a/src/lib/shared.hpp b/src/lib/shared.hpp index 54d48aa..97af754 100644 --- a/src/lib/shared.hpp +++ b/src/lib/shared.hpp @@ -66,6 +66,7 @@ const PROGMEM int screens[SCREEN_COUNT] = { SCREEN_BLOCK_FEE_RATE}; const int usPerSecond = 1000000; const int usPerMinute = 60 * usPerSecond; +const int msPerSecond = 1000; // extern const char *github_root_ca; // extern const char *isrg_root_x1cert; diff --git a/src/lib/webserver.cpp b/src/lib/webserver.cpp index 6ee62f9..2d447d6 100644 --- a/src/lib/webserver.cpp +++ b/src/lib/webserver.cpp @@ -18,7 +18,7 @@ static const char *const PROGMEM boolSettings[] = {"ledTestOnPower", "ledFlashOn "mempoolSecure", "bitaxeEnabled", "miningPoolStats", "verticalDesc", "nostrZapNotify", "httpAuthEnabled", - "enableDebugLog", "ceDisableSSL", "dndEnabled", "dndTimeBasedEnabled"}; + "enableDebugLog", "ceDisableSSL", "dndEnabled", "dndTimeBasedEnabled", "scrnRestoreZap"}; AsyncWebServer server(80); AsyncEventSource events("/events"); @@ -717,6 +717,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request) root["nostrZapNotify"] = preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED); root["nostrZapPubkey"] = preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY); root["ledFlashOnZap"] = preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP); + root["scrnRestoreZap"] = preferences.getBool("scrnRestoreZap", DEFAULT_SCREEN_RESTORE_AFTER_ZAP); root["fontName"] = preferences.getString("fontName", DEFAULT_FONT_NAME); root["availableFonts"] = FontNames::getAvailableFonts(); // Custom endpoint settings (only used for CUSTOM_SOURCE) From b185d861862d2e9bfb2e87344413cdffc9cd5d05 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 12 Jun 2025 16:10:33 +0200 Subject: [PATCH 129/130] chore: dependency update --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 98192fe..be356f0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -40,7 +40,7 @@ lib_deps = bblanchon/ArduinoJson@^7.4.1 esp32async/ESPAsyncWebServer @ 3.7.7 robtillaart/MCP23017@^0.9.1 - adafruit/Adafruit NeoPixel@^1.12.5 + adafruit/Adafruit NeoPixel@^1.15.1 https://github.com/dsbaars/universal_pin#feature/mcp23017_rt https://github.com/dsbaars/GxEPD2#universal_pin https://github.com/tzapu/WiFiManager.git#v2.0.17 From 3149259309255f2c6de2d57fd48983ef10512f60 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Thu, 12 Jun 2025 16:28:12 +0200 Subject: [PATCH 130/130] chore: update webui --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 8389ed8..f5a9133 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 8389ed8e36a9a1a7a39ca31f53324a0949aedb1d +Subproject commit f5a9133cabfbab82325275575545c12f7aacf8f2