Compare commits

..

1 commit

Author SHA1 Message Date
f7907d0082 Tryout with multiple fonts 2024-12-29 04:02:47 +01:00
49 changed files with 15539 additions and 6454 deletions

2
data

@ -1 +1 @@
Subproject commit 0116cd68cdfdf383823f74e0f9665a1700cf0500 Subproject commit 468e105adfaded0440ff8bba61a8241d54f28cd4

View file

@ -4,6 +4,6 @@ dependencies:
source: source:
type: idf type: idf
version: 4.4.7 version: 4.4.7
manifest_hash: 1d4ef353a86901733b106a1897b186dbf9fc091a4981f0560ea2f6899b7a3d44 manifest_hash: cd2f3ee15e776d949eb4ea4eddc8f39b30c2a7905050850eed01ab4928143cff
target: esp32s3 target: esp32s3
version: 1.0.0 version: 1.0.0

View file

@ -1,20 +1,14 @@
#include "bitaxe_handler.hpp" #include "bitaxe_handler.hpp"
std::array<std::string, NUM_SCREENS> parseBitaxeHashRate(uint64_t hashrate) std::array<std::string, NUM_SCREENS> parseBitaxeHashRate(std::string text)
{ {
std::array<std::string, NUM_SCREENS> ret; std::array<std::string, NUM_SCREENS> ret;
ret.fill(""); // Initialize all elements to empty strings ret.fill(""); // Initialize all elements to empty strings
// Convert hashrate to GH/s and round to nearest integer std::size_t textLength = text.length();
double hashRateGH = static_cast<double>(hashrate) / std::pow(10, getHashrateMultiplier('G'));
std::string hashRateStr = std::to_string(static_cast<uint64_t>(std::round(hashRateGH)));
// Place the icons
ret[0] = "mdi:bitaxe";
ret[NUM_SCREENS - 1] = "GH/S";
// Calculate the position where the digits should start // Calculate the position where the digits should start
std::size_t textLength = hashRateStr.length(); // Account for the position of the "mdi:pickaxe" and the "GH/S" label
std::size_t startIndex = NUM_SCREENS - 1 - textLength; std::size_t startIndex = NUM_SCREENS - 1 - textLength;
// Insert the "mdi:pickaxe" icon just before the digits // Insert the "mdi:pickaxe" icon just before the digits
@ -23,64 +17,34 @@ std::array<std::string, NUM_SCREENS> parseBitaxeHashRate(uint64_t hashrate)
ret[startIndex - 1] = "mdi:pickaxe"; ret[startIndex - 1] = "mdi:pickaxe";
} }
// Place each digit // Place the digits
for (std::size_t i = 0; i < textLength; ++i) for (std::size_t i = 0; i < textLength; ++i)
{ {
ret[startIndex + i] = std::string(1, hashRateStr[i]); ret[startIndex + i] = text.substr(i, 1);
} }
ret[NUM_SCREENS - 1] = "GH/S";
ret[0] = "mdi:bitaxe";
return ret; return ret;
} }
std::array<std::string, NUM_SCREENS> parseBitaxeBestDiff(uint64_t difficulty) std::array<std::string, NUM_SCREENS> parseBitaxeBestDiff(std::string text)
{ {
std::array<std::string, NUM_SCREENS> ret; std::array<std::string, NUM_SCREENS> ret;
ret.fill(""); std::uint32_t firstIndex = 0;
// Add icons at the start if (text.length() < NUM_SCREENS)
{
text.insert(text.begin(), NUM_SCREENS - text.length(), ' ');
ret[0] = "mdi:bitaxe"; ret[0] = "mdi:bitaxe";
ret[1] = "mdi:rocket"; ret[1] = "mdi:rocket";
firstIndex = 2;
if (difficulty == 0) {
ret[NUM_SCREENS - 1] = "0";
return ret;
} }
// Find the appropriate suffix and format the number for (std::uint8_t i = firstIndex; i < NUM_SCREENS; i++)
const std::pair<char, int> 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[startIndex + i] = std::string(1, text[i]); ret[i] = text[i];
} }
return ret; return ret;

View file

@ -1,7 +1,5 @@
#include <array> #include <array>
#include <string> #include <string>
#include <cstdint>
#include "utils.hpp"
std::array<std::string, NUM_SCREENS> parseBitaxeHashRate(uint64_t hashrate); std::array<std::string, NUM_SCREENS> parseBitaxeHashRate(std::string text);
std::array<std::string, NUM_SCREENS> parseBitaxeBestDiff(uint64_t difficulty); std::array<std::string, NUM_SCREENS> parseBitaxeBestDiff(std::string text);

View file

@ -243,14 +243,3 @@ int getHashrateMultiplier(char unit) {
}; };
return multipliers.at(unit); return multipliers.at(unit);
} }
int getDifficultyMultiplier(char unit) {
if (unit == '0')
return 0;
static const std::unordered_map<char, int> 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);
}

View file

@ -17,4 +17,3 @@ std::string formatNumberWithSuffix(std::uint64_t num, int numCharacters, bool mo
int64_t getAmountInSatoshis(std::string bolt11); int64_t getAmountInSatoshis(std::string bolt11);
void parseHashrateString(const std::string& hashrate, std::string& label, std::string& output, unsigned int maxCharacters); void parseHashrateString(const std::string& hashrate, std::string& label, std::string& output, unsigned int maxCharacters);
int getHashrateMultiplier(char unit); int getHashrateMultiplier(char unit);
int getDifficultyMultiplier(char unit);

View file

@ -15,7 +15,7 @@ default_envs = lolin_s3_mini_213epd, lolin_s3_mini_29epd, btclock_rev_b_213epd,
[env] [env]
[btclock_base] [btclock_base]
platform = espressif32 @ ^6.10.0 platform = espressif32 @ ^6.9.0
framework = arduino, espidf framework = arduino, espidf
monitor_speed = 115200 monitor_speed = 115200
monitor_filters = esp32_exception_decoder, colorize monitor_filters = esp32_exception_decoder, colorize
@ -30,17 +30,16 @@ build_flags =
-DLAST_BUILD_TIME=$UNIX_TIME -DLAST_BUILD_TIME=$UNIX_TIME
-DARDUINO_USB_CDC_ON_BOOT -DARDUINO_USB_CDC_ON_BOOT
-DCORE_DEBUG_LEVEL=0 -DCORE_DEBUG_LEVEL=0
-D CONFIG_ASYNC_TCP_STACK_SIZE=16384
-fexceptions -fexceptions
build_unflags = build_unflags =
-Werror=all -Werror=all
-fno-exceptions -fno-exceptions
lib_deps = lib_deps =
https://github.com/joltwallet/esp_littlefs.git#v1.16.4 https://github.com/joltwallet/esp_littlefs.git
bblanchon/ArduinoJson@^7.3.0 bblanchon/ArduinoJson@^7.2.1
esp32async/ESPAsyncWebServer @ 3.7.0 mathieucarbou/ESPAsyncWebServer @ 3.3.23
robtillaart/MCP23017@^0.9.0 robtillaart/MCP23017@^0.8.0
adafruit/Adafruit NeoPixel@^1.12.4 adafruit/Adafruit NeoPixel@^1.12.3
https://github.com/dsbaars/universal_pin#feature/mcp23017_rt https://github.com/dsbaars/universal_pin#feature/mcp23017_rt
https://github.com/dsbaars/GxEPD2#universal_pin https://github.com/dsbaars/GxEPD2#universal_pin
https://github.com/tzapu/WiFiManager.git#v2.0.17 https://github.com/tzapu/WiFiManager.git#v2.0.17
@ -79,10 +78,9 @@ build_flags =
-D I2C_SDA_PIN=35 -D I2C_SDA_PIN=35
-D I2C_SCK_PIN=36 -D I2C_SCK_PIN=36
-D HAS_FRONTLIGHT -D HAS_FRONTLIGHT
-D PCA_OE_PIN=48 -D PCA_OE_PIN=45
-D PCA_I2C_ADDR=0x42 -D PCA_I2C_ADDR=0x42
-D IS_HW_REV_B -D IS_HW_REV_B
lib_deps = lib_deps =
${btclock_base.lib_deps} ${btclock_base.lib_deps}
robtillaart/PCA9685@^0.7.1 robtillaart/PCA9685@^0.7.1
@ -101,7 +99,6 @@ build_flags =
-D USE_QR -D USE_QR
-D VERSION_EPD_2_13 -D VERSION_EPD_2_13
-D HW_REV=\"REV_A_EPD_2_13\" -D HW_REV=\"REV_A_EPD_2_13\"
-D CONFIG_ARDUINO_MAIN_TASK_STACK_SIZE=16384
platform_packages = platform_packages =
platformio/tool-mklittlefs@^1.203.210628 platformio/tool-mklittlefs@^1.203.210628
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216
@ -114,7 +111,6 @@ build_flags =
-D USE_QR -D USE_QR
-D VERSION_EPD_2_13 -D VERSION_EPD_2_13
-D HW_REV=\"REV_B_EPD_2_13\" -D HW_REV=\"REV_B_EPD_2_13\"
-D CONFIG_ARDUINO_MAIN_TASK_STACK_SIZE=16384
platform_packages = platform_packages =
platformio/tool-mklittlefs@^1.203.210628 platformio/tool-mklittlefs@^1.203.210628
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216

View file

@ -1,191 +1,384 @@
#pragma once
#include <Adafruit_GFX.h> #include <Adafruit_GFX.h>
#include <Arduino.h> #include <Arduino.h>
#include "fonts.hpp"
const uint8_t Antonio_SemiBold20pt7bBitmaps_Gzip[] = { const uint8_t Antonio_SemiBold20pt7bBitmaps[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xa5, 0x57, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x66, 0x66, 0x66,
0x4f, 0x6f, 0xe3, 0xba, 0x11, 0xa7, 0xaa, 0xe2, 0xf1, 0x1d, 0x16, 0xe6, 0x66, 0x66, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x7B, 0xDE, 0xF7,
0xf5, 0x1d, 0xbc, 0x62, 0x3f, 0xc2, 0xeb, 0xcd, 0x8b, 0x55, 0xac, 0xaf, 0x98, 0xC6, 0x00, 0x03, 0x8F, 0x01, 0xC7, 0x80, 0xE3, 0x80, 0xF1, 0xC0,
0xf2, 0x4e, 0x7b, 0x76, 0xb0, 0x40, 0x57, 0x46, 0x94, 0x48, 0x81, 0x81, 0x70, 0xE0, 0x38, 0x70, 0x1C, 0x78, 0x0E, 0x3C, 0x07, 0x1C, 0x07, 0x8E,
0xea, 0x52, 0xac, 0xaf, 0x5b, 0x60, 0x9b, 0x7c, 0x8d, 0x2d, 0x10, 0x6c, 0x03, 0x87, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x38, 0xE0, 0x3C,
0x64, 0x08, 0x78, 0xbe, 0x45, 0x5f, 0x60, 0x11, 0x53, 0x10, 0x50, 0x5f, 0x70, 0x1E, 0x38, 0x0E, 0x1C, 0x07, 0x0E, 0x03, 0x8F, 0x0F, 0xFF, 0xF7,
0x8a, 0x8a, 0x86, 0x80, 0x4a, 0x41, 0x14, 0xb1, 0x3f, 0xd2, 0x72, 0xfe, 0xFF, 0xF8, 0xF1, 0xC0, 0x70, 0xE0, 0x38, 0x70, 0x1C, 0x78, 0x0E, 0x3C,
0x6c, 0xb2, 0xd9, 0xd7, 0x96, 0xa4, 0x39, 0x43, 0x8a, 0x96, 0x86, 0x33, 0x0F, 0x1C, 0x07, 0x8E, 0x03, 0x87, 0x01, 0xC3, 0x80, 0xE3, 0xC0, 0x71,
0xc3, 0xdf, 0x0c, 0x89, 0xea, 0xcb, 0x1b, 0x5d, 0x08, 0xd3, 0x6c, 0x79, 0xE0, 0x78, 0xE0, 0x00, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60,
0x70, 0x59, 0x7f, 0xf8, 0x95, 0xd8, 0x73, 0x6b, 0x19, 0x15, 0xd1, 0x26, 0x1F, 0xC1, 0xFF, 0x9F, 0xFC, 0xFB, 0xF7, 0x87, 0xBC, 0x3D, 0xE1, 0xEF,
0x99, 0x88, 0xd1, 0x64, 0xe8, 0x0f, 0x5c, 0x3a, 0xa4, 0xef, 0xed, 0x98, 0x0F, 0x78, 0x7B, 0xE3, 0xDF, 0x00, 0x7C, 0x01, 0xF8, 0x0F, 0xE0, 0x3F,
0x9b, 0xe5, 0xed, 0x48, 0xb8, 0x13, 0x67, 0x34, 0x18, 0xd2, 0x81, 0x3d, 0x80, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x3E, 0xF0, 0xF7, 0x87, 0xFC, 0x3F,
0x67, 0xaa, 0x56, 0xcd, 0xdd, 0x3a, 0x66, 0xd6, 0x59, 0x69, 0x54, 0x24, 0xE1, 0xFF, 0x0F, 0xFC, 0x7B, 0xFF, 0xCF, 0xFE, 0x3F, 0xE0, 0xFE, 0x01,
0xfb, 0xc2, 0x17, 0xe4, 0x07, 0xf2, 0xb3, 0x15, 0xbd, 0x20, 0xbf, 0xf0, 0xC0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0x1F, 0x80, 0x01, 0xC0,
0x85, 0x3a, 0x6d, 0xaf, 0xeb, 0xf8, 0x6c, 0x2f, 0x2f, 0x99, 0x7f, 0x50, 0x07, 0xFE, 0x00, 0x3C, 0x00, 0x7F, 0xE0, 0x03, 0xC0, 0x0F, 0x9F, 0x00,
0xac, 0x48, 0x60, 0x35, 0x4c, 0x78, 0x51, 0x60, 0x49, 0x9a, 0x8c, 0x65, 0x38, 0x00, 0xF0, 0xF0, 0x07, 0x80, 0x0F, 0x0F, 0x00, 0x70, 0x00, 0xF0,
0x1d, 0xb7, 0x5e, 0xae, 0x58, 0x7b, 0xa0, 0xb2, 0xce, 0x13, 0x9d, 0x95, 0xF0, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0xF0, 0x00, 0xF0, 0xF0, 0x0E, 0x00,
0x0c, 0xc8, 0xc4, 0x8e, 0x86, 0x84, 0x47, 0x56, 0x42, 0x3b, 0xe2, 0x92, 0x0F, 0x0F, 0x01, 0xE0, 0x00, 0xF0, 0xF0, 0x1C, 0x00, 0x0F, 0x0F, 0x03,
0x50, 0xd8, 0x09, 0x3b, 0x25, 0x23, 0x22, 0x25, 0x8d, 0x18, 0x23, 0x13, 0xC0, 0x60, 0xF0, 0xF0, 0x3C, 0x3F, 0xCF, 0x0F, 0x03, 0x87, 0xFE, 0xF0,
0x30, 0x8c, 0x80, 0x91, 0x60, 0x06, 0x60, 0x2c, 0x01, 0x66, 0x08, 0xc6, 0xF0, 0x78, 0xFF, 0xEF, 0x0F, 0x07, 0x8F, 0x0E, 0xF0, 0xF0, 0xF0, 0xF0,
0x4e, 0x7e, 0x91, 0xd2, 0xf5, 0x32, 0x66, 0xc7, 0x9d, 0x94, 0xbe, 0x2a, 0xFF, 0x0F, 0x0F, 0x0E, 0x0F, 0xF0, 0xF0, 0xE0, 0xE0, 0xF7, 0xDF, 0x1E,
0x19, 0x9d, 0x0f, 0x24, 0x8a, 0x62, 0x6c, 0xc0, 0xa4, 0x14, 0xa2, 0x5e, 0x0E, 0x0F, 0x7F, 0xE1, 0xE0, 0xE0, 0xF3, 0xFC, 0x1C, 0x0E, 0x0F, 0x1F,
0x39, 0x03, 0x16, 0xe6, 0x42, 0x54, 0xed, 0x70, 0xc0, 0xf8, 0x2c, 0x11, 0x83, 0xC0, 0xE0, 0xF0, 0x00, 0x38, 0x0E, 0x0F, 0x00, 0x07, 0x80, 0xE0,
0x92, 0x8c, 0x06, 0x8c, 0xd0, 0x08, 0x8c, 0xaf, 0x19, 0x02, 0x46, 0x82, 0xF0, 0x00, 0x78, 0x0E, 0x0F, 0x00, 0x07, 0x00, 0xE0, 0xF0, 0x00, 0xF0,
0x19, 0x80, 0xb1, 0x04, 0xbe, 0xe2, 0x90, 0x8d, 0xb0, 0x12, 0x66, 0x24, 0x0E, 0x0F, 0x00, 0x0E, 0x00, 0xE0, 0xF0, 0x01, 0xE0, 0x0F, 0x0F, 0x00,
0x49, 0xec, 0xc8, 0x6e, 0x6c, 0x61, 0x77, 0x44, 0x45, 0x81, 0x74, 0x86, 0x1E, 0x00, 0xF1, 0xE0, 0x01, 0xC0, 0x0F, 0xFE, 0x00, 0x3C, 0x00, 0x7F,
0x34, 0xb6, 0xf2, 0xc4, 0x9f, 0x80, 0x99, 0x93, 0x2a, 0xda, 0x13, 0xcc, 0xC0, 0x03, 0x80, 0x03, 0xF8, 0x03, 0xE0, 0x03, 0xFE, 0x00, 0xFF, 0x80,
0xb7, 0x5a, 0x72, 0x04, 0xd1, 0x69, 0x62, 0x4b, 0xd2, 0xfd, 0x18, 0xfe, 0x7C, 0xF0, 0x1E, 0x1C, 0x07, 0x87, 0x01, 0xE1, 0xC0, 0x78, 0x70, 0x1E,
0xd9, 0x2b, 0xe6, 0x6e, 0x3d, 0x9f, 0xe6, 0xad, 0x1f, 0xba, 0x7c, 0x6e, 0x1C, 0x07, 0x8F, 0x00, 0xF3, 0x80, 0x3D, 0xE0, 0x0F, 0x78, 0x01, 0xFC,
0x17, 0x89, 0x94, 0x63, 0x87, 0xc7, 0x6a, 0xa3, 0x5a, 0x6f, 0x1d, 0x6f, 0x00, 0x7E, 0x00, 0x1F, 0x80, 0x07, 0xC0, 0x03, 0xF0, 0x00, 0xFE, 0x08,
0x84, 0x52, 0xf5, 0x9f, 0xde, 0xbc, 0x19, 0x2b, 0x95, 0x39, 0xae, 0xbf, 0x7F, 0x86, 0x3F, 0xE3, 0x8F, 0x3C, 0xF7, 0x8F, 0x79, 0xE1, 0xFC, 0x78,
0x29, 0x96, 0xf3, 0x27, 0xc8, 0x75, 0x9d, 0x27, 0x9b, 0x0a, 0xc3, 0xec, 0x7F, 0x3C, 0x1F, 0x8F, 0x03, 0xE3, 0xC0, 0xF0, 0xF0, 0x3E, 0x1E, 0x1F,
0x74, 0x1c, 0x5c, 0x55, 0xeb, 0x47, 0xe4, 0xa0, 0x2e, 0x3f, 0x40, 0xf2, 0x87, 0xFF, 0xF1, 0xFF, 0xFC, 0x3F, 0xE7, 0x87, 0xF1, 0xE0, 0xFF, 0xFF,
0xe1, 0xef, 0xf7, 0x5f, 0x5d, 0x5c, 0x1f, 0xaa, 0x45, 0x6b, 0x0b, 0xaf, 0xF7, 0x76, 0x66, 0x66, 0x3E, 0xFF, 0xFF, 0xCF, 0x1E, 0x3C, 0x78, 0xF1,
0x28, 0xd5, 0xdb, 0xbf, 0xfe, 0x4a, 0x7f, 0x1c, 0x42, 0x5f, 0x50, 0x15, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C,
0x9a, 0x36, 0xa0, 0xd6, 0x5c, 0xcf, 0xff, 0x65, 0xfd, 0xc7, 0x8f, 0x09, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xFB, 0xF7,
0x28, 0x44, 0x20, 0x0d, 0x8d, 0x5c, 0x4b, 0x0c, 0x88, 0xd4, 0x34, 0x71, 0xE1, 0xC0, 0xF1, 0xF3, 0xF1, 0xE3, 0xC7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9,
0x34, 0x1d, 0xd9, 0x5b, 0xea, 0x1b, 0xca, 0x88, 0xa6, 0xd0, 0x87, 0xa6, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E,
0xae, 0xa1, 0x34, 0x22, 0x4c, 0x9b, 0x56, 0xd5, 0x73, 0x63, 0xc0, 0x26, 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7B, 0xF7, 0xEF, 0x98, 0x00,
0x4c, 0x3b, 0x2e, 0x55, 0xfc, 0xed, 0xc1, 0xd9, 0x61, 0x5d, 0x76, 0x9e, 0x07, 0x00, 0x1C, 0x04, 0x71, 0x39, 0xCE, 0xFB, 0x7D, 0xFF, 0xC1, 0xFC,
0x54, 0xc4, 0x9e, 0xa5, 0x85, 0x96, 0xe6, 0x94, 0xc5, 0x69, 0x2e, 0x9b, 0x03, 0xE0, 0x3F, 0xE3, 0xEF, 0xFF, 0x73, 0x99, 0xC6, 0x07, 0x08, 0x1C,
0x60, 0xcc, 0x9f, 0x62, 0x12, 0x76, 0xac, 0x78, 0xa3, 0xca, 0x79, 0x70, 0x00, 0x70, 0x00, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 0xFF,
0x90, 0x5e, 0x3a, 0xdb, 0x97, 0xc1, 0x83, 0x7c, 0x9a, 0xb8, 0xb6, 0x70, 0xFF, 0xF0, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 0xFF,
0x2c, 0xc8, 0x04, 0xb1, 0x03, 0xb8, 0x90, 0x2d, 0xb8, 0x96, 0x34, 0x00, 0x8C, 0xE7, 0x31, 0x9C, 0xC0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0x00,
0xed, 0xe0, 0x93, 0x11, 0x4b, 0x54, 0xac, 0x78, 0xe7, 0x5f, 0xe7, 0x65, 0xF8, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0E, 0x00, 0xF0, 0x07, 0x80, 0x3C,
0x7c, 0xe6, 0xc8, 0x83, 0x85, 0xa0, 0x91, 0x03, 0xc1, 0x85, 0x67, 0x35, 0x01, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x38, 0x03, 0xC0, 0x1E, 0x00,
0x54, 0xf0, 0x84, 0x91, 0x31, 0xf1, 0x2d, 0x41, 0xf1, 0x2c, 0x5c, 0x28, 0xF0, 0x07, 0x80, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x0F, 0x00, 0x78,
0x4d, 0x0e, 0xf2, 0xf5, 0xea, 0xb4, 0xf5, 0x44, 0x48, 0xb4, 0x4f, 0x7a, 0x03, 0xC0, 0x1E, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x3C, 0x01,
0xa4, 0xb5, 0x25, 0x4f, 0x42, 0xab, 0xfd, 0x41, 0xbe, 0x4e, 0x4a, 0xfb, 0xE0, 0x0F, 0x00, 0x78, 0x07, 0x80, 0x00, 0x0F, 0xC1, 0xFF, 0x9F, 0xFC,
0x6c, 0x28, 0xdf, 0x2e, 0x32, 0xe6, 0x8e, 0x24, 0x2c, 0x32, 0x74, 0x27, 0xFF, 0xF7, 0x8F, 0xFC, 0x3F, 0xE1, 0xFF, 0x0F, 0xF8, 0x7F, 0xC3, 0xFE,
0x9b, 0x34, 0x63, 0x23, 0xb7, 0x3f, 0x41, 0x44, 0xc2, 0x3b, 0xe1, 0x1b, 0x1F, 0xF0, 0xFF, 0x87, 0xFC, 0x3F, 0xE1, 0xFF, 0x0F, 0xF8, 0x7F, 0xC3,
0x20, 0xaa, 0xec, 0xd0, 0x7a, 0x0d, 0x33, 0x52, 0xb1, 0x16, 0xc3, 0xab, 0xFE, 0x1F, 0xF0, 0xFF, 0x87, 0xFC, 0x3F, 0xE1, 0xFF, 0x0F, 0xF8, 0x7F,
0x92, 0xcb, 0xcd, 0x6e, 0x4a, 0x32, 0xb8, 0xa2, 0x69, 0xfc, 0xba, 0xec, 0xC3, 0xFE, 0x1F, 0xF0, 0xFF, 0x87, 0xBC, 0x7D, 0xF7, 0xEF, 0xFE, 0x3F,
0xc2, 0xb4, 0x81, 0xa8, 0x33, 0xc5, 0x5b, 0xff, 0x0a, 0xa2, 0x7e, 0x76, 0xF0, 0xFF, 0x00, 0x03, 0x83, 0xC3, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F,
0x9a, 0x83, 0xbc, 0x8c, 0xc6, 0xa4, 0xb1, 0xcb, 0xb9, 0xf2, 0x3a, 0x75, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC3,
0xbd, 0x9d, 0x0c, 0x73, 0x15, 0x77, 0x7c, 0x47, 0xa6, 0xf9, 0x5a, 0x9d, 0xE1, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8,
0x42, 0x8b, 0x61, 0xb4, 0x13, 0x20, 0x80, 0x39, 0x22, 0x08, 0x40, 0x13, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC0, 0x0F, 0x81, 0xFF, 0x1F, 0xF8, 0xFF,
0xb3, 0xc9, 0x27, 0x78, 0x4e, 0xf4, 0x59, 0x83, 0x0e, 0x1a, 0x3d, 0x85, 0xEF, 0x8F, 0x7C, 0x7B, 0xC3, 0xDE, 0x1E, 0xF0, 0xFF, 0x87, 0xFC, 0x3F,
0x0f, 0x10, 0x1c, 0x4a, 0xde, 0x5e, 0x2b, 0x58, 0x6e, 0xd1, 0x31, 0x19, 0xE1, 0xEF, 0x0F, 0x78, 0x78, 0x07, 0xC0, 0x3C, 0x03, 0xE0, 0x1E, 0x01,
0xce, 0x5a, 0x2e, 0x60, 0x9f, 0xa9, 0x5a, 0xb6, 0x5e, 0xa1, 0x4e, 0xf6, 0xF0, 0x0F, 0x00, 0xF8, 0x07, 0x80, 0x7C, 0x07, 0xC0, 0x3E, 0x03, 0xE0,
0x36, 0x8a, 0x36, 0xf7, 0x9e, 0xd0, 0xd6, 0x33, 0x96, 0xeb, 0x08, 0x87, 0x1F, 0x00, 0xF0, 0x07, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0xFE, 0xFF, 0xF7,
0x49, 0x6e, 0x60, 0x12, 0x1f, 0x26, 0xbd, 0x7d, 0xda, 0x2f, 0x5d, 0xae, 0xFF, 0x80, 0x0F, 0xC0, 0xFF, 0x87, 0xFF, 0x1F, 0xFE, 0x78, 0xFB, 0xE1,
0x3a, 0x55, 0x29, 0xed, 0x48, 0xbb, 0x27, 0xac, 0x9d, 0xd6, 0xe6, 0x50, 0xEF, 0x87, 0xBC, 0x1E, 0xF0, 0x7B, 0xC1, 0xE0, 0x07, 0x80, 0x1E, 0x00,
0x13, 0x78, 0x1e, 0x41, 0x31, 0x40, 0xa3, 0x22, 0xcd, 0x12, 0x20, 0x4a, 0x78, 0x03, 0xE0, 0x3F, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0xC0, 0x0F, 0x00,
0xf5, 0xf1, 0xe2, 0xed, 0x07, 0xf2, 0x87, 0x17, 0xf4, 0x58, 0x76, 0xde, 0x3E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0xBC, 0x1E, 0xF0, 0x7F, 0xC1, 0xFF,
0xe9, 0x52, 0x36, 0x43, 0x5b, 0x1c, 0x51, 0xe9, 0xd9, 0x0d, 0xb7, 0xc4, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xE1, 0xE7, 0xDF, 0x9F, 0xFC, 0x3F, 0xE0,
0x0b, 0xa2, 0x77, 0xd8, 0xf6, 0xff, 0x4a, 0xa2, 0x9f, 0xec, 0x28, 0x60, 0x7F, 0x00, 0x01, 0xF0, 0x07, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x1F,
0x49, 0x47, 0x65, 0x68, 0x0b, 0x97, 0xcd, 0x36, 0x6d, 0xe7, 0xc5, 0x89, 0xC0, 0x7F, 0x01, 0xFC, 0x06, 0xF0, 0x3B, 0xC0, 0xEF, 0x03, 0xBC, 0x1C,
0xfc, 0xe9, 0x77, 0x78, 0x53, 0xdc, 0x86, 0x65, 0xb7, 0x29, 0xf9, 0x46, 0xF0, 0x73, 0xC1, 0xCF, 0x0F, 0x3C, 0x38, 0xF0, 0xE3, 0xC7, 0x8F, 0x1C,
0xf5, 0xcd, 0x92, 0xf0, 0x55, 0xf8, 0x45, 0xeb, 0xcd, 0xa4, 0x0b, 0x87, 0x3C, 0x70, 0xF1, 0xC3, 0xCF, 0x0F, 0x38, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF,
0x45, 0x33, 0xdf, 0xec, 0x79, 0x3b, 0x21, 0x5e, 0x44, 0x20, 0x12, 0x5e, 0xFF, 0xFF, 0xFF, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0,
0xdf, 0x30, 0x6d, 0x3a, 0x0d, 0x25, 0x64, 0xe4, 0x93, 0xe1, 0x88, 0xc7, 0x03, 0xC0, 0xFF, 0xEF, 0xFE, 0xFF, 0xEF, 0xFE, 0xF0, 0x0F, 0x00, 0xF0,
0xae, 0x57, 0x9c, 0x38, 0x9b, 0x8b, 0xe1, 0x68, 0x3d, 0x18, 0xbe, 0x7b, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF3, 0x0F, 0xFC, 0xFF, 0xEF, 0xFE, 0xF9,
0x3f, 0xe0, 0x4b, 0xca, 0x8a, 0x59, 0xbc, 0x59, 0xa4, 0x8d, 0xc8, 0xdb, 0xEF, 0x1F, 0xF0, 0xF1, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00,
0xc9, 0xa4, 0x1b, 0x8d, 0xc2, 0xa1, 0x7e, 0xf0, 0x6a, 0x49, 0x87, 0xc5, 0xF0, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x1F, 0xFB,
0xf2, 0x62, 0xf2, 0xef, 0xce, 0x0d, 0x3d, 0x87, 0x33, 0x7a, 0x4c, 0xf0, 0xEF, 0xFE, 0x7F, 0xC3, 0xF8, 0x0F, 0xC0, 0xFF, 0x83, 0xFF, 0x1F, 0xFC,
0x62, 0xa0, 0x12, 0xbc, 0x01, 0x10, 0x30, 0xa1, 0xaa, 0x21, 0x0a, 0x2a, 0x78, 0xF9, 0xE1, 0xEF, 0x87, 0xBE, 0x1E, 0xF8, 0x7B, 0xE1, 0xEF, 0x80,
0x93, 0x84, 0x26, 0x54, 0xb0, 0xbb, 0x2a, 0x07, 0xd2, 0xd9, 0xd5, 0x89, 0x3E, 0x00, 0xF8, 0x03, 0xEF, 0x8F, 0xFF, 0x3F, 0xFE, 0xFF, 0xFB, 0xE1,
0xe3, 0x0f, 0x7d, 0x77, 0x57, 0x51, 0x02, 0x90, 0xb0, 0x45, 0xed, 0xc2, 0xEF, 0x87, 0xBE, 0x1E, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8,
0xce, 0x77, 0x1a, 0x54, 0x2c, 0xe3, 0x92, 0x2b, 0x5b, 0xc1, 0x29, 0x5a, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x79, 0xE1, 0xE7, 0xFF, 0x9F,
0x79, 0x9d, 0x96, 0xc6, 0x63, 0x17, 0x20, 0x63, 0x8c, 0x32, 0xe5, 0x35, 0xFE, 0x3F, 0xF0, 0x7F, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x50, 0x7b, 0xc6, 0xfa, 0xc9, 0x96, 0xdf, 0x3a, 0x75, 0x5a, 0xaa, 0xf3, 0x00, 0x7C, 0x01, 0xE0, 0x0F, 0x80, 0x3C, 0x00, 0xF0, 0x07, 0xC0, 0x1E,
0x56, 0x15, 0x8a, 0xb0, 0x24, 0x4c, 0xe1, 0x34, 0xc1, 0x54, 0xbb, 0x10, 0x00, 0x78, 0x03, 0xE0, 0x0F, 0x80, 0x3C, 0x00, 0xF0, 0x07, 0xC0, 0x1E,
0x6b, 0x3c, 0xa1, 0x66, 0x86, 0x18, 0x5f, 0xe8, 0x5d, 0xe2, 0x76, 0x12, 0x00, 0x78, 0x03, 0xE0, 0x0F, 0x80, 0x3C, 0x00, 0xF0, 0x07, 0xC0, 0x1F,
0x84, 0xfb, 0x87, 0xf9, 0xba, 0x9c, 0xc3, 0xe2, 0x5e, 0xa4, 0xa8, 0xf2, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0x80, 0x1E, 0x00, 0xF8, 0x03, 0xE0, 0x0F,
0x60, 0x71, 0x1c, 0xe2, 0xc5, 0x23, 0x8b, 0x3f, 0x35, 0x08, 0x15, 0xdc, 0x80, 0x3E, 0x00, 0xF8, 0x00, 0x1F, 0xC1, 0xFF, 0x1F, 0xFC, 0xFB, 0xFF,
0x60, 0xdd, 0x12, 0x63, 0x69, 0xe9, 0x02, 0x93, 0x6f, 0x3b, 0x33, 0x95, 0x8F, 0xFC, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0,
0x3c, 0x98, 0x33, 0x8b, 0x1e, 0x2f, 0x35, 0x33, 0xf6, 0xc3, 0xa5, 0xba, 0xFF, 0x87, 0xBC, 0x79, 0xFF, 0xC7, 0xFC, 0x3F, 0xE3, 0xFF, 0x9E, 0x3D,
0x23, 0x4c, 0x6c, 0x77, 0x72, 0x78, 0x4f, 0x5a, 0xd6, 0x6f, 0xe1, 0x4a, 0xF1, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC,
0xe9, 0x93, 0xc1, 0x1e, 0xec, 0x84, 0xf9, 0x7b, 0x79, 0x5d, 0x42, 0x47, 0x1F, 0xE0, 0xFF, 0x07, 0xFC, 0x3F, 0xF7, 0xEF, 0xFE, 0x3F, 0xF0, 0xFE,
0xff, 0xf4, 0x7e, 0x36, 0x7a, 0xe9, 0xd5, 0xf3, 0x80, 0xf4, 0xe5, 0xc9, 0x00, 0x1F, 0x81, 0xFF, 0x1F, 0xFD, 0xFF, 0xEF, 0x8F, 0x78, 0x7F, 0xC3,
0x67, 0x5b, 0x22, 0xd5, 0xd7, 0x05, 0xd8, 0x93, 0x8c, 0x81, 0x41, 0x06, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F,
0x75, 0x9e, 0x1c, 0xdc, 0x83, 0x40, 0x1d, 0xf7, 0xea, 0xac, 0x0d, 0xf3, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0xC7, 0xDF, 0xFE, 0xFF, 0xF3, 0xFF, 0x80,
0x8e, 0xc8, 0x3d, 0x71, 0xbd, 0x58, 0xcf, 0x32, 0x76, 0xe2, 0xb8, 0xae, 0x3C, 0x01, 0xE0, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x0F,
0xdf, 0x6c, 0xf2, 0x75, 0x9a, 0xc5, 0x27, 0x2c, 0x70, 0x9a, 0x3d, 0x11, 0xFC, 0x79, 0xF7, 0xCF, 0xFE, 0x3F, 0xE0, 0xFE, 0x00, 0xFF, 0xFF, 0xF0,
0x26, 0xca, 0xea, 0xec, 0x8e, 0x9e, 0xe9, 0xa1, 0x2b, 0xa7, 0x72, 0x93, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00,
0x17, 0xe9, 0x72, 0x19, 0xcf, 0xd9, 0x09, 0x77, 0x1d, 0x7f, 0x2c, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xF3, 0x9C, 0xCE, 0x73, 0x98,
0x45, 0xf0, 0x48, 0x25, 0x4f, 0x76, 0x46, 0xa1, 0x8d, 0xa5, 0x22, 0xde, 0x00, 0x20, 0x0C, 0x07, 0x81, 0xF0, 0xFE, 0x3F, 0x9F, 0xC7, 0xF0, 0xF8,
0xd8, 0x2a, 0xf1, 0xda, 0x5d, 0x17, 0x76, 0x54, 0x09, 0x74, 0x9d, 0x08, 0x1C, 0x03, 0xE0, 0x7E, 0x07, 0xF0, 0x3F, 0x03, 0xF8, 0x1F, 0x01, 0xE0,
0xff, 0xc5, 0x3a, 0xa9, 0xca, 0x41, 0x37, 0x29, 0xd7, 0xa6, 0x73, 0xba, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x0F, 0xFF,
0x69, 0x56, 0x7c, 0x54, 0xaf, 0xb2, 0xea, 0xa3, 0x7a, 0x9d, 0x55, 0x8d, 0xFF, 0xFF, 0xC0, 0x80, 0x18, 0x03, 0x80, 0x7C, 0x0F, 0xC0, 0xFE, 0x07,
0xe2, 0xf3, 0xcd, 0x6d, 0x67, 0x22, 0xa8, 0xe9, 0x10, 0xb7, 0x95, 0xdd, 0xF0, 0x7F, 0x03, 0xE0, 0x3C, 0x0F, 0x83, 0xF1, 0xFC, 0xFE, 0x3F, 0x87,
0x6e, 0xb5, 0x8b, 0xf3, 0x0d, 0x34, 0x2f, 0x14, 0x1c, 0xa5, 0x55, 0xd5, 0xC0, 0xF0, 0x18, 0x02, 0x00, 0x00, 0x1F, 0x87, 0xFC, 0x7F, 0xEF, 0xFE,
0x4d, 0x56, 0x9f, 0x5f, 0xaa, 0xd7, 0xe0, 0x56, 0xcb, 0x90, 0xb7, 0xa1, 0xF1, 0xEF, 0x1F, 0xF1, 0xFF, 0x1F, 0xF1, 0xFF, 0x1F, 0xF1, 0xFF, 0x1F,
0x54, 0x29, 0x16, 0x18, 0x25, 0xe2, 0x0f, 0xd2, 0x4b, 0x26, 0xb7, 0xc6, 0x01, 0xF0, 0x1E, 0x01, 0xE0, 0x3E, 0x03, 0xE0, 0xFC, 0x3F, 0x83, 0xF0,
0xcb, 0xef, 0x1b, 0xef, 0x19, 0x02, 0x37, 0xac, 0x55, 0xef, 0x86, 0x71, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00,
0xef, 0x86, 0x5f, 0x7b, 0x1e, 0x54, 0xac, 0xce, 0x6f, 0x54, 0xd6, 0xf8, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x00, 0x3F, 0x80,
0x7d, 0xc0, 0x72, 0xfb, 0x28, 0x65, 0x06, 0xe4, 0xff, 0xf9, 0xa6, 0x83, 0x00, 0xFF, 0xF0, 0x00, 0xFF, 0xFC, 0x00, 0xF8, 0x0F, 0x00, 0xF0, 0x03,
0x83, 0x8c, 0x38, 0x61, 0x13, 0x6c, 0x55, 0x03, 0xb2, 0xbc, 0x5e, 0xdc, 0xC0, 0xF0, 0x00, 0xF0, 0xF0, 0x00, 0x38, 0x78, 0x00, 0x1C, 0x38, 0x1F,
0x9d, 0x3d, 0x73, 0xbe, 0xb8, 0xa7, 0xcf, 0xd7, 0xed, 0xd9, 0x7b, 0x82, 0x87, 0x3C, 0x3F, 0xE3, 0x9E, 0x1E, 0xF1, 0xCE, 0x1C, 0x38, 0xE7, 0x0E,
0x48, 0x20, 0x7c, 0xaa, 0x83, 0xd1, 0x54, 0x83, 0x39, 0x6f, 0xf0, 0xf6, 0x1C, 0x77, 0x8E, 0x0E, 0x1F, 0xC7, 0x07, 0x0F, 0xE3, 0x83, 0x87, 0xF1,
0x78, 0xc5, 0x8f, 0x48, 0x6b, 0x35, 0xb6, 0x64, 0x82, 0x47, 0x1e, 0xf2, 0xC1, 0xC3, 0xF8, 0xE0, 0xE1, 0xFC, 0x70, 0x70, 0xFE, 0x38, 0x38, 0x7F,
0x85, 0x2b, 0x4c, 0x5e, 0xc2, 0x55, 0x45, 0x3d, 0xbb, 0xdc, 0x7a, 0x6c, 0x1C, 0x1C, 0x77, 0x8E, 0x0E, 0x39, 0xC7, 0x07, 0x1C, 0xE3, 0xC7, 0xCE,
0xbf, 0x69, 0x53, 0x58, 0xd4, 0xfc, 0xf6, 0xf6, 0x1b, 0x76, 0xf8, 0xd4, 0x70, 0xF6, 0xFE, 0x3C, 0x7F, 0x3F, 0x1E, 0x1F, 0x0F, 0x07, 0x81, 0x00,
0x01, 0xe9, 0xbc, 0x26, 0x8c, 0x00, 0x33, 0x06, 0x93, 0x1a, 0xc7, 0xd7, 0x03, 0xC0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1F, 0x80,
0xd5, 0x20, 0x52, 0xe0, 0xf6, 0xc5, 0x0c, 0x9d, 0x5d, 0x9d, 0x38, 0x00, 0x70, 0x07, 0xFF, 0xF8, 0x00, 0xFF, 0xFE, 0x00, 0x1F, 0xF0, 0x00, 0x07,
0x31, 0xb6, 0xab, 0x00, 0x35, 0xda, 0x57, 0x38, 0xdf, 0xae, 0x39, 0x52, 0xC0, 0x07, 0xE0, 0x0F, 0xE0, 0x0F, 0xE0, 0x0F, 0xE0, 0x0F, 0xE0, 0x0F,
0x3b, 0xad, 0xe3, 0x1f, 0x7d, 0xdd, 0x80, 0x9f, 0xa3, 0x7a, 0xe8, 0xd6, 0xE0, 0x0F, 0xF0, 0x0E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E,
0xae, 0xbb, 0xbe, 0xdf, 0xce, 0x5e, 0x16, 0x9f, 0x5e, 0xa6, 0xba, 0xf1, 0xF0, 0x1E, 0x70, 0x1E, 0x78, 0x1C, 0x78, 0x3C, 0x78, 0x3C, 0x78, 0x3C,
0xbe, 0x35, 0xba, 0x2d, 0x1a, 0x76, 0x8c, 0x26, 0xef, 0x37, 0x78, 0x53, 0x78, 0x3C, 0x78, 0x3C, 0x3C, 0x3C, 0x3C, 0x7C, 0x3C, 0x78, 0x3C, 0x7F,
0x4d, 0x4f, 0x1c, 0xdf, 0x2f, 0x0a, 0xc4, 0x65, 0x57, 0x86, 0xc7, 0x1d, 0xFC, 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFE, 0x78, 0x1E, 0xF8, 0x1E, 0xF8,
0xd5, 0x39, 0x25, 0xd4, 0x0a, 0xa3, 0x6b, 0x50, 0x83, 0xde, 0x43, 0x0b, 0x1E, 0xF0, 0x1E, 0xF0, 0x1F, 0xF0, 0x1F, 0xFF, 0x03, 0xFF, 0x8F, 0xFF,
0x93, 0x9e, 0xa8, 0x10, 0xad, 0x5d, 0x7f, 0x3f, 0x5f, 0xc7, 0x27, 0x03, 0x3F, 0xFC, 0xF0, 0xFB, 0xC3, 0xEF, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xC1,
0xfc, 0x4f, 0x36, 0xcc, 0xe7, 0xbe, 0x13, 0x38, 0xae, 0xe3, 0x8e, 0x5d, 0xEF, 0x07, 0xBC, 0x3E, 0xF0, 0xFB, 0xC3, 0xCF, 0xFF, 0x3F, 0xF8, 0xFF,
0x34, 0x30, 0xd8, 0x11, 0xd3, 0x15, 0x7b, 0xa1, 0xba, 0x0a, 0xfb, 0x3b, 0xF3, 0xFF, 0xCF, 0x0F, 0xBC, 0x1E, 0xF0, 0x7B, 0xC1, 0xEF, 0x07, 0xFC,
0x35, 0xac, 0x15, 0xda, 0x2e, 0xca, 0xb8, 0x34, 0x41, 0x1a, 0xe2, 0x1b, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xC3, 0xEF,
0x03, 0x48, 0xfe, 0x68, 0xf6, 0x0e, 0x34, 0xe4, 0x33, 0x45, 0x3f, 0x76, 0xFF, 0xBF, 0xFC, 0xFF, 0xE3, 0xFF, 0x00, 0x0F, 0xC0, 0x7F, 0xC3, 0xFF,
0xec, 0xc4, 0xa7, 0x64, 0x4b, 0x22, 0x4d, 0x5c, 0x4d, 0x2c, 0x43, 0x06, 0x9F, 0xFE, 0x7C, 0x79, 0xE1, 0xFF, 0x87, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0,
0x96, 0xd0, 0x84, 0x19, 0xe2, 0x6b, 0x62, 0x7c, 0xe3, 0x99, 0xa2, 0x1f, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8,
0x27, 0x70, 0xb0, 0x08, 0x8a, 0xb0, 0xbf, 0xd0, 0xb3, 0x81, 0x0f, 0x4c, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE,
0x11, 0xc0, 0x14, 0x8d, 0x28, 0x0e, 0x73, 0x35, 0xe4, 0x04, 0x46, 0xac, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x1F, 0x78, 0x7D, 0xE1, 0xE7,
0xab, 0xf5, 0xfb, 0xd1, 0x7e, 0xfa, 0xc0, 0x53, 0x9d, 0xc6, 0xa4, 0xe7, 0xEF, 0x8F, 0xFE, 0x3F, 0xF0, 0x3F, 0x80, 0xFF, 0x07, 0xFF, 0x3F, 0xFD,
0x21, 0x6b, 0xc3, 0x6a, 0x7d, 0xc9, 0xbf, 0x4a, 0x42, 0x0e, 0x8b, 0x5a, 0xFF, 0xEF, 0x0F, 0xF8, 0x7F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC,
0xad, 0x94, 0x17, 0xec, 0x8e, 0xdb, 0xb4, 0x58, 0x9d, 0x76, 0x0a, 0xd9, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83,
0xc3, 0xf3, 0xc1, 0xa1, 0x85, 0xd2, 0xba, 0xba, 0x3e, 0xd5, 0x89, 0xe3, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F,
0x1c, 0x89, 0x63, 0x7c, 0x76, 0x97, 0x1e, 0xde, 0x03, 0xcf, 0x7b, 0xa8, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x7F, 0xFF, 0xDF, 0xFE, 0xFF,
0xb9, 0x5e, 0x19, 0xd4, 0x34, 0xf9, 0x8b, 0x4e, 0x63, 0x0e, 0x2b, 0x7c, 0xE7, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3C, 0x0F, 0x03,
0x37, 0xbc, 0x79, 0x20, 0xcc, 0x93, 0x04, 0xe7, 0x6c, 0x05, 0x09, 0xdb, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xFF, 0xFF,
0x43, 0x69, 0x82, 0xdf, 0xdd, 0xb6, 0x0e, 0xcc, 0x73, 0x63, 0x8e, 0xce, 0xFF, 0xFF, 0xFF, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F,
0x04, 0xbf, 0x3e, 0xef, 0x8a, 0xe1, 0x4e, 0xd3, 0x6a, 0xad, 0x21, 0x4b, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF,
0xd0, 0x74, 0xd3, 0x06, 0x0e, 0x9d, 0xeb, 0x45, 0x1b, 0xe1, 0x3b, 0xf4, 0xFF, 0xFF, 0xFF, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03,
0xf8, 0x5b, 0x5d, 0xc4, 0x03, 0xa5, 0x55, 0x01, 0xd4, 0x78, 0x56, 0x96, 0xC0, 0xF0, 0x3C, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xF0,
0x6c, 0x2b, 0x8b, 0xde, 0xc3, 0x34, 0x5d, 0x23, 0x2c, 0xc3, 0x11, 0x77, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F,
0xba, 0xab, 0x20, 0xa8, 0x52, 0xe9, 0xf7, 0x02, 0x6b, 0x3f, 0x40, 0xca, 0x03, 0xC0, 0xF0, 0x3C, 0x00, 0x0F, 0xE0, 0x7F, 0xC3, 0xFF, 0x9F, 0xFE,
0x4e, 0x1e, 0x86, 0x22, 0x89, 0x3b, 0x82, 0x20, 0xec, 0x1b, 0x77, 0x83, 0x7C, 0x7D, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83,
0xe0, 0x4a, 0xad, 0x3e, 0xdf, 0x25, 0xa9, 0xdb, 0xd4, 0x00, 0x69, 0x03, 0xFE, 0x0F, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF9, 0xFF, 0xE7,
0xd7, 0x37, 0x8b, 0x6c, 0xee, 0xee, 0x49, 0x0d, 0x3a, 0x8d, 0x87, 0x44, 0xFF, 0x9F, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0xF8,
0x54, 0x63, 0x8f, 0xc4, 0x71, 0xc1, 0xad, 0x23, 0xd0, 0x54, 0xc3, 0x5a, 0x3F, 0xE0, 0xFF, 0x83, 0xFE, 0x0F, 0x78, 0x3D, 0xE1, 0xF7, 0xEF, 0xCF,
0x98, 0x3c, 0x8e, 0x7d, 0x55, 0x5e, 0xad, 0xb2, 0xd2, 0xb0, 0x0d, 0x12, 0xFF, 0x3F, 0xEC, 0x3F, 0x30, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC, 0x1F,
0x48, 0x08, 0x37, 0x6b, 0x1d, 0x26, 0xfd, 0xff, 0x91, 0x75, 0xab, 0xf5, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07,
0xf9, 0x39, 0xde, 0x15, 0x7f, 0x7f, 0xf3, 0x66, 0x80, 0xfc, 0x3e, 0x9c, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xdd, 0x83, 0xd4, 0x6f, 0xba, 0xc1, 0xe5, 0x9d, 0x45, 0xab, 0xe5, 0x39, 0xFF, 0x07, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC, 0x1F, 0xF0,
0x82, 0x84, 0x9a, 0x7f, 0x27, 0x8b, 0xc1, 0x6d, 0x43, 0x21, 0xca, 0x1c, 0x7F, 0xC1, 0xFF, 0x07, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xFC,
0xdd, 0x86, 0x0f, 0xa7, 0x37, 0xef, 0x73, 0xae, 0xb6, 0x25, 0xfe, 0x61, 0x1F, 0xF0, 0x7F, 0xC1, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x5d, 0xab, 0x4c, 0xf1, 0x9d, 0xa7, 0x5a, 0xb2, 0xba, 0xc6, 0xa6, 0x96, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xF8,
0xb3, 0x85, 0xc0, 0x16, 0x1d, 0x46, 0x1f, 0x31, 0x84, 0x23, 0xd3, 0xba, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0x00,
0x42, 0xf4, 0xf0, 0xcd, 0xfd, 0xa6, 0x5e, 0x7e, 0x26, 0xfa, 0x7a, 0x12, 0xF8, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F,
0x1d, 0x99, 0x5b, 0x4a, 0x74, 0x98, 0x97, 0xfd, 0xd1, 0xa8, 0x4b, 0xdc, 0x00, 0xF8, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0xF8, 0x7F, 0xC3, 0xFE,
0xb2, 0x16, 0x2d, 0x19, 0xb3, 0x99, 0x68, 0xc6, 0x4c, 0xbb, 0x65, 0x66, 0x1F, 0xF0, 0xFF, 0x87, 0xFC, 0x3F, 0xE1, 0xEF, 0x0F, 0x78, 0x7B, 0xF7,
0xb8, 0x27, 0x3b, 0xdc, 0x2d, 0x52, 0xf9, 0x5f, 0xe0, 0xff, 0x61, 0x05, 0xCF, 0xFC, 0x7F, 0xE1, 0xFE, 0x00, 0xF0, 0x3D, 0xE0, 0xFB, 0xC1, 0xE7,
0xb9, 0x4b, 0x0e, 0x10, 0x35, 0x31, 0x0b, 0x5a, 0x05, 0x52, 0x0e, 0xfd, 0x83, 0xCF, 0x0F, 0x9E, 0x1E, 0x3C, 0x3C, 0x78, 0xF8, 0xF1, 0xE1, 0xE7,
0x7d, 0xdc, 0x75, 0x06, 0x80, 0xd6, 0x2a, 0xbd, 0xc0, 0x65, 0x47, 0x54, 0xC3, 0xCF, 0x87, 0x9E, 0x0F, 0x7C, 0x1E, 0xF8, 0x3D, 0xE0, 0x7F, 0xC0,
0xc7, 0x97, 0xd4, 0xe7, 0x02, 0x77, 0x22, 0x8a, 0xab, 0x91, 0xb9, 0x21, 0xFF, 0x01, 0xFE, 0x03, 0xFE, 0x07, 0xBC, 0x0F, 0x7C, 0x1E, 0xF8, 0x3C,
0x01, 0xec, 0xfc, 0x30, 0x4e, 0xdb, 0x31, 0xcf, 0x65, 0xcd, 0xe2, 0x4f, 0xF0, 0x79, 0xF0, 0xF1, 0xE1, 0xE3, 0xC3, 0xC7, 0xC7, 0x87, 0x8F, 0x0F,
0xc1, 0xab, 0x34, 0xbf, 0xe0, 0xef, 0xa7, 0x5f, 0xde, 0x5e, 0xac, 0x4f, 0x9E, 0x1F, 0x3C, 0x1E, 0x78, 0x3E, 0xF0, 0x7D, 0xE0, 0x7C, 0xF0, 0x3C,
0xde, 0xb9, 0xd5, 0xdf, 0x8b, 0xbf, 0x65, 0xc3, 0x7f, 0x4c, 0xd6, 0xaf, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03,
0xe3, 0xfd, 0x2f, 0xaf, 0xdf, 0xe7, 0x5f, 0xde, 0xb1, 0xe2, 0x53, 0xf8, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0,
0x32, 0x6d, 0x3a, 0x08, 0x1a, 0x70, 0x5b, 0x34, 0x9c, 0x26, 0xcd, 0x98, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F,
0x2e, 0xe4, 0x98, 0x1d, 0x8b, 0x80, 0x20, 0x58, 0xe2, 0xc3, 0xae, 0x6f, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x03,
0xbe, 0xb8, 0xfd, 0x94, 0xfe, 0x46, 0x9f, 0xa1, 0x9a, 0x0f, 0x9b, 0x00, 0xFF, 0xC0, 0x3F, 0xFC, 0x03, 0xFF, 0xC0, 0x3F, 0xFC, 0x03, 0xFF, 0xC0,
0x69, 0xae, 0xc4, 0x99, 0xf6, 0xe2, 0x00, 0x70, 0xae, 0x68, 0xd7, 0x8b, 0x7F, 0xFE, 0x07, 0xFF, 0xE0, 0x7F, 0xFE, 0x07, 0xFE, 0xE0, 0x7F, 0xEE,
0xac, 0x49, 0x1a, 0x33, 0x23, 0x32, 0x10, 0x7f, 0x28, 0xde, 0x1e, 0x5f, 0x0F, 0xFE, 0xF0, 0xFF, 0xEF, 0x0E, 0xFE, 0x70, 0xEF, 0xE7, 0x0E, 0xFE,
0xd0, 0x4f, 0x78, 0x4f, 0xa4, 0xdf, 0xb3, 0x15, 0xd9, 0xdc, 0x81, 0xcc, 0x70, 0xEF, 0xE7, 0x1E, 0xFE, 0x79, 0xCF, 0xE3, 0x9C, 0xFF, 0x39, 0xCF,
0xab, 0x49, 0x58, 0xde, 0xa8, 0x73, 0xe9, 0xd0, 0x64, 0xfb, 0xb3, 0x93, 0xF3, 0x9C, 0xFF, 0x3B, 0xCF, 0xF3, 0xF8, 0xFF, 0x1F, 0x8F, 0xF1, 0xF8,
0x66, 0xf7, 0xe3, 0x80, 0x5f, 0xf3, 0x33, 0x18, 0xa1, 0xb1, 0xe0, 0xe8, 0xFF, 0x1F, 0x8F, 0xF1, 0xF8, 0xFF, 0x1F, 0x8F, 0xF0, 0xF0, 0xFF, 0x0F,
0xe1, 0xb9, 0x6f, 0x8e, 0x3c, 0xa8, 0xb9, 0x63, 0x5f, 0x61, 0xc1, 0xa2, 0x0F, 0xF0, 0xF0, 0xFF, 0x0F, 0x0F, 0xE0, 0x3F, 0x80, 0xFF, 0x03, 0xFC,
0xf5, 0x68, 0xf2, 0xe8, 0xb0, 0x20, 0x0f, 0xf3, 0xd8, 0x02, 0xfb, 0x7c, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x83, 0xFF, 0x0F, 0xFC, 0x3F, 0xF0, 0xFF,
0xb0, 0x9a, 0xcf, 0x64, 0xe0, 0xf1, 0xe5, 0x83, 0x39, 0x58, 0x16, 0x86, 0xE3, 0xFF, 0x8F, 0xFE, 0x3F, 0xFC, 0xFF, 0xF3, 0xFD, 0xCF, 0xF7, 0xBF,
0x23, 0x0e, 0x3d, 0xad, 0x56, 0xf0, 0xb9, 0x52, 0xe5, 0xb6, 0xf8, 0x0f, 0xDE, 0xFF, 0x3B, 0xFC, 0xFF, 0xF3, 0xDF, 0xC7, 0x7F, 0x1F, 0xFC, 0x7F,
0x50, 0xdd, 0x7d, 0xcc, 0xa9, 0x11, 0x00, 0x00 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 GFXglyph Antonio_SemiBold20pt7bGlyphs[] PROGMEM = { const GFXglyph Antonio_SemiBold20pt7bGlyphs[] PROGMEM = {
{0, 1, 1, 8, 0, 0}, // 0x20 ' ' {0, 1, 1, 8, 0, 0}, // 0x20 ' '
@ -284,13 +477,8 @@ const GFXglyph Antonio_SemiBold20pt7bGlyphs[] PROGMEM = {
{4461, 10, 37, 14, 2, -33}, // 0x7D '}' {4461, 10, 37, 14, 2, -33}, // 0x7D '}'
{4508, 17, 6, 21, 2, -21}}; // 0x7E '~' {4508, 17, 6, 21, 2, -21}}; // 0x7E '~'
// Font properties const GFXfont Antonio_SemiBold20pt7b PROGMEM = {
static constexpr FontData Antonio_SemiBold20pt7b_Properties = { (uint8_t *)Antonio_SemiBold20pt7bBitmaps,
Antonio_SemiBold20pt7bBitmaps_Gzip, (GFXglyph *)Antonio_SemiBold20pt7bGlyphs, 0x20, 0x7E, 51};
Antonio_SemiBold20pt7bGlyphs,
sizeof(Antonio_SemiBold20pt7bBitmaps_Gzip), // Approx. 5193 bytes
4521, // Original size
0x20, // First char
0x7E, // Last char
51 // yAdvance
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,97 +1,15 @@
#pragma once #pragma once
#include <Adafruit_GFX.h> #include "antonio-semibold20.h"
#include <Arduino.h> //#include "antonio-semibold30.h"
#include <rom/miniz.h> #include "antonio-semibold40.h"
#include "antonio-semibold90.h"
#include "sats-symbol.h"
//#include "icons.h"
// Font metadata structure #include "oswald-20.h"
struct FontData { #include "oswald-30.h"
const uint8_t* compressedData; #include "oswald-90.h"
const GFXglyph* glyphs; // #include "ubuntu-italic40.h"
const size_t compressedSize; // #include "ubuntu-italic60.h"
const size_t originalSize; // #include "ubuntu-italic70.h"
const uint16_t first;
const uint16_t last;
const uint8_t yAdvance;
};
// Font name constants
namespace FontNames {
static const String ANTONIO = "antonio";
static const String OSWALD = "oswald";
static const std::array<String, 2> AVAILABLE_FONTS = {
ANTONIO,
OSWALD
};
static const std::array<String, 2>& 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,
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);
}
}
};

512
src/fonts/oswald-20.h Normal file
View file

@ -0,0 +1,512 @@
const uint8_t Oswald_Medium20pt7bBitmaps[] PROGMEM = {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xDC, 0xE7, 0x39, 0xCE, 0x73,
0x9C, 0xE7, 0x39, 0xCC, 0x20, 0x01, 0xFF, 0xFF, 0xFF, 0xFB, 0xFE, 0x7F,
0xCF, 0x79, 0xEF, 0x3D, 0xE7, 0xB8, 0xF7, 0x1E, 0xE3, 0x9C, 0x73, 0x8E,
0x00, 0x0F, 0x8F, 0x07, 0x87, 0x83, 0xC7, 0xC1, 0xE3, 0xC0, 0xF1, 0xE0,
0x78, 0xF0, 0x3C, 0x78, 0x3E, 0x3C, 0x1E, 0x1E, 0x0F, 0x0F, 0x3F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF1, 0xE0, 0xF8, 0xF0, 0x78, 0x78, 0x3C,
0x3C, 0x7F, 0xFF, 0xBF, 0xFF, 0xDF, 0xFF, 0xEF, 0xFF, 0xF3, 0xE3, 0xC1,
0xE1, 0xE0, 0xF0, 0xF0, 0x78, 0xF8, 0x3C, 0x78, 0x1E, 0x3C, 0x0F, 0x1E,
0x07, 0x8F, 0x07, 0xC7, 0x83, 0xC3, 0xC1, 0xE3, 0xE0, 0x00, 0x80, 0x00,
0x40, 0x00, 0x20, 0x00, 0xFE, 0x01, 0xFF, 0xC1, 0xFF, 0xF1, 0xFF, 0xF8,
0xFC, 0x7E, 0xFC, 0x1F, 0x7E, 0x0F, 0xBF, 0x07, 0xDF, 0x83, 0xEF, 0xC0,
0x03, 0xF0, 0x01, 0xFC, 0x00, 0xFF, 0x00, 0x3F, 0xC0, 0x0F, 0xF0, 0x03,
0xFC, 0x00, 0xFF, 0x00, 0x3F, 0xC0, 0x0F, 0xF0, 0x01, 0xFC, 0x00, 0x7E,
0x00, 0x3F, 0x3C, 0x0F, 0xFE, 0x07, 0xFF, 0x83, 0xFF, 0xC1, 0xFB, 0xE0,
0xFD, 0xF8, 0xFC, 0x7F, 0xFE, 0x3F, 0xFE, 0x0F, 0xFF, 0x03, 0xFE, 0x00,
0x18, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x03, 0x00, 0x0F, 0x80, 0x1E, 0x00,
0x0F, 0xF8, 0x07, 0x80, 0x07, 0xFF, 0x01, 0xC0, 0x03, 0xFF, 0xE0, 0x70,
0x00, 0xF8, 0xF8, 0x3C, 0x00, 0x3C, 0x3E, 0x0F, 0x00, 0x0F, 0x07, 0x83,
0x80, 0x03, 0xC1, 0xE1, 0xE0, 0x00, 0xF0, 0x78, 0x78, 0x00, 0x3C, 0x1E,
0x1C, 0x00, 0x0F, 0x07, 0x8F, 0x00, 0x03, 0xC1, 0xE3, 0xC0, 0x00, 0xF0,
0xF8, 0xE0, 0x00, 0x3E, 0x3E, 0x38, 0x00, 0x0F, 0xFF, 0x1E, 0x00, 0x01,
0xFF, 0xC7, 0x87, 0xF8, 0x3F, 0xE1, 0xC3, 0xFF, 0x03, 0xC0, 0xF1, 0xFF,
0xE0, 0x00, 0x3C, 0x78, 0xF8, 0x00, 0x0E, 0x3E, 0x1E, 0x00, 0x03, 0x8F,
0x87, 0xC0, 0x01, 0xE3, 0xE1, 0xF0, 0x00, 0x78, 0xF8, 0x7C, 0x00, 0x1C,
0x3E, 0x1F, 0x00, 0x0F, 0x0F, 0x87, 0xC0, 0x03, 0xC3, 0xE1, 0xF0, 0x00,
0xE0, 0xF8, 0x78, 0x00, 0x78, 0x3E, 0x1E, 0x00, 0x1E, 0x07, 0xFF, 0x80,
0x07, 0x81, 0xFF, 0xC0, 0x01, 0xC0, 0x3F, 0xF0, 0x00, 0xF0, 0x07, 0xF0,
0x07, 0xE0, 0x03, 0xFF, 0x00, 0xFF, 0xF0, 0x1F, 0xFE, 0x07, 0xE3, 0xE0,
0xF8, 0x7C, 0x1F, 0x0F, 0x83, 0xE1, 0xF0, 0x7C, 0x3E, 0x0F, 0x87, 0x80,
0xF1, 0xF0, 0x1F, 0x3C, 0x01, 0xEF, 0x00, 0x3F, 0xE0, 0x03, 0xF8, 0x00,
0x7E, 0x00, 0x0F, 0x80, 0x03, 0xF8, 0x3C, 0xFF, 0x87, 0xBE, 0xF1, 0xF7,
0xDF, 0x3F, 0xF1, 0xE7, 0xBE, 0x3E, 0xF7, 0xC3, 0xFE, 0xF8, 0x7F, 0x9F,
0x07, 0xF3, 0xE0, 0x7C, 0x7C, 0x1F, 0xE7, 0xFF, 0xFE, 0xFF, 0xFF, 0xCF,
0xFC, 0xF8, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xEE, 0xEE, 0xE0, 0x07, 0x0F,
0x1F, 0x3F, 0x7E, 0x7C, 0x7C, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x7C, 0x7C, 0x7C, 0x3F, 0x3F, 0x1F,
0x07, 0xE0, 0x7C, 0x3F, 0x1F, 0xC3, 0xE0, 0xF0, 0x7C, 0x3E, 0x1F, 0x0F,
0x83, 0xC1, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0,
0xF8, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF0, 0xF8, 0x7C,
0x3E, 0x1F, 0x0F, 0x0F, 0x8F, 0xCF, 0xC7, 0xC3, 0xC0, 0x0F, 0x80, 0x38,
0x01, 0xC0, 0x8E, 0x2F, 0x77, 0xFF, 0xFF, 0xFF, 0xE3, 0xF8, 0x0F, 0x80,
0xFE, 0x0F, 0x78, 0xFB, 0xE3, 0x8E, 0x0C, 0x60, 0x03, 0x80, 0x07, 0x00,
0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF,
0xFE, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0,
0x01, 0xC0, 0xFF, 0xFF, 0xFF, 0x9C, 0xEE, 0xF7, 0x00, 0xFF, 0xFF, 0xFF,
0xFC, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x78, 0x03, 0xC0, 0x1C, 0x00, 0xE0,
0x0F, 0x00, 0x78, 0x03, 0x80, 0x3C, 0x01, 0xE0, 0x0E, 0x00, 0x70, 0x07,
0x80, 0x3C, 0x01, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x00, 0x38, 0x03, 0xC0,
0x1E, 0x00, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0x80, 0x1C, 0x01, 0xE0, 0x0F,
0x00, 0x70, 0x07, 0x80, 0x3C, 0x01, 0xC0, 0x1E, 0x00, 0x07, 0xF0, 0x0F,
0xFE, 0x0F, 0xFF, 0x8F, 0xFF, 0xC7, 0xFF, 0xF3, 0xE1, 0xFB, 0xF0, 0x7D,
0xF8, 0x3F, 0xFC, 0x1F, 0xFE, 0x0F, 0xFF, 0x07, 0xFF, 0x83, 0xFF, 0xC1,
0xFF, 0xE0, 0xFF, 0xF0, 0x7F, 0xF8, 0x3F, 0xFC, 0x1F, 0xFE, 0x0F, 0xFF,
0x07, 0xFF, 0x83, 0xFF, 0xC1, 0xFF, 0xE0, 0xFF, 0xF0, 0x7F, 0xF8, 0x3F,
0xFC, 0x1F, 0xFE, 0x0F, 0xDF, 0x07, 0xCF, 0xC7, 0xE7, 0xFF, 0xF1, 0xFF,
0xF0, 0x7F, 0xF0, 0x1F, 0xF0, 0x03, 0xC1, 0xF1, 0xFD, 0xFF, 0xFF, 0xFF,
0xFF, 0x7E, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C,
0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07,
0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xF0, 0x1F,
0xFC, 0x3F, 0xFE, 0x7F, 0xFE, 0x7F, 0x7F, 0xFC, 0x3F, 0xF8, 0x1F, 0xF8,
0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x3F, 0x00, 0x3F, 0x00, 0x3E, 0x00,
0x7E, 0x00, 0xFC, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x03, 0xF0, 0x07,
0xE0, 0x07, 0xC0, 0x0F, 0xC0, 0x1F, 0x80, 0x1F, 0x80, 0x3F, 0x00, 0x7E,
0x00, 0x7E, 0x00, 0xFC, 0x00, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF,
0xFE, 0x0F, 0xF0, 0x3F, 0xF8, 0x7F, 0xFC, 0x7F, 0xFE, 0xFC, 0x7E, 0xF8,
0x3F, 0xF8, 0x3F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0x00, 0x3F, 0x00,
0x3F, 0x00, 0x7E, 0x03, 0xFC, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xFC, 0x03,
0xFE, 0x00, 0x7E, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x1F, 0xF8, 0x1F, 0xF8,
0x1F, 0xF8, 0x1F, 0xF8, 0x3F, 0xF8, 0x3F, 0xFC, 0x7E, 0xFF, 0xFE, 0x7F,
0xFC, 0x3F, 0xFC, 0x1F, 0xF0, 0x00, 0xFE, 0x00, 0x3F, 0x80, 0x0F, 0xE0,
0x07, 0xF8, 0x01, 0xFE, 0x00, 0xFF, 0x80, 0x3F, 0xE0, 0x1E, 0xF8, 0x07,
0xBE, 0x01, 0xEF, 0x80, 0xF3, 0xE0, 0x3C, 0xF8, 0x1E, 0x3E, 0x07, 0x8F,
0x83, 0xE3, 0xE0, 0xF0, 0xF8, 0x3C, 0x3E, 0x1F, 0x0F, 0x87, 0x83, 0xE3,
0xE0, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x3E, 0x00, 0x0F, 0x80, 0x03, 0xE0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x0F,
0x80, 0x03, 0xE0, 0x00, 0xF8, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF,
0xFE, 0xFF, 0xFE, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8,
0x00, 0xF8, 0x00, 0xF9, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF, 0xFE, 0xFC,
0x7E, 0xF8, 0x3F, 0xF8, 0x3F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00,
0x1F, 0x00, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x3F, 0xFC,
0x3E, 0x7F, 0xFE, 0x7F, 0xFC, 0x3F, 0xF8, 0x1F, 0xF0, 0x07, 0xF0, 0x0F,
0xFE, 0x0F, 0xFF, 0x87, 0xFF, 0xC7, 0xE3, 0xF3, 0xE0, 0xF9, 0xF0, 0x7D,
0xF8, 0x3E, 0xFC, 0x00, 0x7E, 0x00, 0x3F, 0x00, 0x1F, 0x80, 0x0F, 0xC4,
0x07, 0xFF, 0xE3, 0xFF, 0xF9, 0xFF, 0xFE, 0xFF, 0xFF, 0x7E, 0x1F, 0xBF,
0x07, 0xDF, 0x83, 0xFF, 0xC1, 0xFF, 0xE0, 0xFF, 0xF0, 0x7F, 0xF8, 0x3F,
0xFC, 0x1F, 0xFE, 0x0F, 0x9F, 0x07, 0xCF, 0xC7, 0xE7, 0xFF, 0xE1, 0xFF,
0xF0, 0x7F, 0xF0, 0x1F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0xFC, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x01, 0xF8, 0x07, 0xC0, 0x1F,
0x00, 0x7C, 0x01, 0xF0, 0x0F, 0xC0, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x1F,
0x80, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x3F, 0x00, 0xF8, 0x03, 0xE0, 0x0F,
0x80, 0x3E, 0x01, 0xF8, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x03, 0xF0, 0x0F,
0x80, 0x0F, 0xF0, 0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0x7E, 0x7E, 0xFC,
0x3E, 0xF8, 0x3F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFC, 0x3F, 0x7C,
0x3E, 0x7C, 0x7E, 0x3F, 0xFC, 0x1F, 0xF8, 0x1F, 0xF8, 0x3F, 0xFC, 0x7F,
0xFE, 0x7C, 0x3E, 0xFC, 0x3F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8,
0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFC, 0x3F, 0x7F, 0xFE, 0x7F,
0xFE, 0x3F, 0xFC, 0x0F, 0xF0, 0x07, 0xE0, 0x1F, 0xF8, 0x3F, 0xFC, 0x7F,
0xFE, 0x7C, 0x7E, 0xFC, 0x3F, 0xF8, 0x3F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8,
0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFC, 0x3F, 0xFE,
0x7F, 0x7F, 0xFF, 0x7F, 0xFF, 0x3F, 0xDF, 0x0F, 0x9F, 0x00, 0x1F, 0x00,
0x1F, 0x00, 0x1F, 0x00, 0x1F, 0xF8, 0x1F, 0xF8, 0x3F, 0xF8, 0x3F, 0xFC,
0x3E, 0x7F, 0xFE, 0x7F, 0xFC, 0x3F, 0xF8, 0x1F, 0xF0, 0xFF, 0xFF, 0xFF,
0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF,
0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF,
0xFF, 0xFF, 0x1C, 0x71, 0x9E, 0x70, 0x00, 0x20, 0x0C, 0x07, 0x83, 0xF1,
0xFE, 0xFF, 0xFF, 0xC7, 0xE0, 0xF0, 0x1F, 0x03, 0xFC, 0x3F, 0xE3, 0xFE,
0x1F, 0xC0, 0xF8, 0x07, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0x80, 0x0C, 0x00, 0xF0, 0x0F, 0xC0, 0xFF, 0x07, 0xFC, 0x1F, 0xF0, 0x7F,
0x00, 0xF0, 0x3F, 0x0F, 0xF3, 0xFE, 0xFF, 0x8F, 0xE0, 0xF8, 0x0E, 0x00,
0x80, 0x00, 0x0F, 0xE0, 0x7F, 0xF1, 0xFF, 0xF7, 0xFF, 0xEF, 0xFF, 0xFF,
0x0F, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xC0, 0x7C, 0x00, 0xF8, 0x01,
0xF0, 0x07, 0xE0, 0x1F, 0x80, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0,
0x3F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0,
0x0F, 0xC0, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x1F,
0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x3F, 0xC0, 0x1F, 0x80, 0x3F,
0x80, 0x03, 0xE0, 0x1F, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0x3C, 0x1F,
0x01, 0xE7, 0x8F, 0x0F, 0x01, 0xFB, 0xC7, 0x8F, 0x83, 0xFF, 0xE3, 0xC7,
0x81, 0xFF, 0xF0, 0xF7, 0xC1, 0xF8, 0xF0, 0x7B, 0xC1, 0xF8, 0x78, 0x3D,
0xE0, 0xF8, 0x3C, 0x1E, 0xF0, 0xF8, 0x3E, 0x0F, 0x78, 0x7C, 0x1F, 0x07,
0xFC, 0x3E, 0x0F, 0x83, 0xFE, 0x1E, 0x07, 0xC1, 0xFE, 0x0F, 0x03, 0xC0,
0xEF, 0x07, 0x81, 0xE0, 0xF7, 0x83, 0xC0, 0xF0, 0x7B, 0xE1, 0xF0, 0xF8,
0x79, 0xF0, 0xF8, 0xFC, 0x3C, 0xF8, 0x7F, 0xFE, 0x3C, 0x3C, 0x1F, 0xEF,
0xFC, 0x1E, 0x07, 0xF7, 0xFC, 0x0F, 0x81, 0xF0, 0xF8, 0x03, 0xC0, 0x00,
0x00, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x3F, 0x00,
0x00, 0x00, 0x0F, 0xE0, 0x00, 0x80, 0x03, 0xFF, 0x9F, 0xC0, 0x00, 0xFF,
0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x03,
0xF0, 0x00, 0x7F, 0x00, 0x0F, 0xE0, 0x03, 0xFC, 0x00, 0x7F, 0x80, 0x0F,
0xF0, 0x01, 0xFF, 0x00, 0x3F, 0xE0, 0x0F, 0xFC, 0x01, 0xF7, 0x80, 0x3E,
0xF0, 0x07, 0xDF, 0x00, 0xFB, 0xE0, 0x3E, 0x7C, 0x07, 0xCF, 0x80, 0xF8,
0xF0, 0x1F, 0x1F, 0x03, 0xE3, 0xE0, 0xFC, 0x7C, 0x1F, 0x0F, 0x83, 0xE1,
0xF0, 0x7F, 0xFF, 0x0F, 0xFF, 0xE3, 0xFF, 0xFC, 0x7F, 0xFF, 0x8F, 0x81,
0xF1, 0xF0, 0x3F, 0x3E, 0x03, 0xEF, 0xC0, 0x7D, 0xF8, 0x0F, 0xBF, 0x01,
0xF7, 0xC0, 0x3F, 0xFF, 0xE0, 0x3F, 0xFF, 0x0F, 0xFF, 0xF3, 0xFF, 0xFC,
0xFC, 0x7F, 0xBF, 0x03, 0xEF, 0xC0, 0xFB, 0xF0, 0x3E, 0xFC, 0x0F, 0xFF,
0x03, 0xEF, 0xC0, 0xFB, 0xF0, 0x3E, 0xFC, 0x1F, 0xBF, 0xFF, 0xCF, 0xFF,
0xC3, 0xFF, 0xF8, 0xFF, 0xFF, 0x3F, 0x0F, 0xEF, 0xC0, 0xFF, 0xF0, 0x3F,
0xFC, 0x07, 0xFF, 0x01, 0xFF, 0xC0, 0x7F, 0xF0, 0x1F, 0xFC, 0x07, 0xFF,
0x01, 0xFF, 0xC0, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xBF, 0xFF, 0xCF, 0xFF,
0xE3, 0xFF, 0xE0, 0x07, 0xF8, 0x07, 0xFF, 0x83, 0xFF, 0xF1, 0xFF, 0xFC,
0x7E, 0x1F, 0x9F, 0x07, 0xEF, 0xC0, 0xFB, 0xF0, 0x3E, 0xFC, 0x0F, 0xBF,
0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0,
0x03, 0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00,
0xFC, 0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3E, 0xFC, 0x0F, 0xBF,
0x03, 0xEF, 0xC0, 0xF9, 0xF8, 0x7E, 0x7F, 0xFF, 0x0F, 0xFF, 0xC1, 0xFF,
0xE0, 0x3F, 0xF0, 0xFF, 0xE0, 0x3F, 0xFF, 0x0F, 0xFF, 0xF3, 0xFF, 0xFC,
0xFC, 0x7F, 0xBF, 0x07, 0xEF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF,
0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03, 0xFF, 0xC0,
0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F,
0xFC, 0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF,
0x03, 0xFF, 0xC1, 0xFB, 0xF0, 0xFE, 0xFF, 0xFF, 0x3F, 0xFF, 0xCF, 0xFF,
0xE3, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x03,
0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00,
0xFC, 0x03, 0xFF, 0xCF, 0xFF, 0x3F, 0xFC, 0xFF, 0xF3, 0xFF, 0xCF, 0xC0,
0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0,
0x0F, 0xC0, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80,
0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xFF, 0xDF,
0xFE, 0xFF, 0xF7, 0xFF, 0xBF, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0,
0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03,
0xF0, 0x1F, 0x80, 0x07, 0xF8, 0x07, 0xFF, 0x83, 0xFF, 0xF1, 0xFF, 0xFE,
0x7E, 0x1F, 0x9F, 0x03, 0xEF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF,
0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0,
0x03, 0xF0, 0x00, 0xFC, 0x7F, 0xFF, 0x1F, 0xFF, 0xC7, 0xFF, 0xF1, 0xFF,
0xFC, 0x07, 0xFF, 0x01, 0xFF, 0xC0, 0x7F, 0xF0, 0x1F, 0xFC, 0x07, 0xFF,
0x03, 0xFF, 0xC0, 0xFD, 0xF8, 0x7F, 0x7F, 0xFF, 0xCF, 0xFE, 0xF1, 0xFF,
0xBC, 0x3F, 0xCF, 0xFC, 0x07, 0xFF, 0x01, 0xFF, 0xC0, 0x7F, 0xF0, 0x1F,
0xFC, 0x07, 0xFF, 0x01, 0xFF, 0xC0, 0x7F, 0xF0, 0x1F, 0xFC, 0x07, 0xFF,
0x01, 0xFF, 0xC0, 0x7F, 0xF0, 0x1F, 0xFC, 0x07, 0xFF, 0x01, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7F, 0xF0, 0x1F,
0xFC, 0x07, 0xFF, 0x01, 0xFF, 0xC0, 0x7F, 0xF0, 0x1F, 0xFC, 0x07, 0xFF,
0x01, 0xFF, 0xC0, 0x7F, 0xF0, 0x1F, 0xFC, 0x07, 0xFF, 0x01, 0xFF, 0xC0,
0x7F, 0xF0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07,
0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0,
0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F,
0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0xFC, 0x3F, 0x1F, 0xFF,
0xFF, 0xFB, 0xFC, 0xFC, 0x00, 0xFC, 0x0F, 0xDF, 0x81, 0xF3, 0xF0, 0x7E,
0x7E, 0x0F, 0xCF, 0xC1, 0xF1, 0xF8, 0x7E, 0x3F, 0x0F, 0x87, 0xE3, 0xF0,
0xFC, 0x7C, 0x1F, 0x9F, 0x83, 0xF3, 0xF0, 0x7E, 0xFC, 0x0F, 0xDF, 0x81,
0xFF, 0xE0, 0x3F, 0xFC, 0x07, 0xFF, 0x80, 0xFF, 0xF8, 0x1F, 0xFF, 0x03,
0xFB, 0xE0, 0x7E, 0x7E, 0x0F, 0xC7, 0xC1, 0xF8, 0xFC, 0x3F, 0x1F, 0x87,
0xE1, 0xF0, 0xFC, 0x3F, 0x1F, 0x87, 0xE3, 0xF0, 0x7E, 0x7E, 0x0F, 0xCF,
0xC0, 0xF9, 0xF8, 0x1F, 0xBF, 0x03, 0xF7, 0xE0, 0x3F, 0xFC, 0x03, 0xF0,
0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC,
0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F,
0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F,
0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x00, 0xFD, 0xF8, 0x03, 0xF7, 0xE0,
0x0F, 0xDF, 0xC0, 0x7F, 0x7F, 0x01, 0xFD, 0xFC, 0x07, 0xF7, 0xF0, 0x1F,
0xDF, 0xC0, 0xFF, 0x7F, 0x83, 0xFD, 0xFE, 0x0F, 0xF7, 0xF8, 0x3F, 0xDF,
0xE0, 0xEF, 0x7B, 0x87, 0xBD, 0xEF, 0x1E, 0xF7, 0xBC, 0x7B, 0xDE, 0xF1,
0xEF, 0x7B, 0xC7, 0x3D, 0xE7, 0x3C, 0xF7, 0x9E, 0xF3, 0xDE, 0x7B, 0xCF,
0xF9, 0xEF, 0x3F, 0xE7, 0xB8, 0xFF, 0x8F, 0xE3, 0xFE, 0x3F, 0x8F, 0xF8,
0xFE, 0x3F, 0xE3, 0xF8, 0xFF, 0x87, 0xC3, 0xFE, 0x1F, 0x0F, 0xF8, 0x7C,
0x3F, 0xE1, 0xF0, 0xFF, 0x87, 0x83, 0xFE, 0x0E, 0x0F, 0xF8, 0x0F, 0xFC,
0x07, 0xFE, 0x03, 0xFF, 0x81, 0xFF, 0xC0, 0xFF, 0xF0, 0x7F, 0xF8, 0x3F,
0xFE, 0x1F, 0xFF, 0x0F, 0xFF, 0x87, 0xFF, 0xE3, 0xFF, 0xF1, 0xFF, 0xFC,
0xFF, 0xDE, 0x7F, 0xEF, 0x3F, 0xF7, 0xDF, 0xF9, 0xEF, 0xFC, 0xFF, 0xFE,
0x3F, 0xFF, 0x1F, 0xFF, 0x8F, 0xFF, 0xC3, 0xFF, 0xE1, 0xFF, 0xF0, 0x7F,
0xF8, 0x3F, 0xFC, 0x1F, 0xFE, 0x07, 0xFF, 0x03, 0xFF, 0x80, 0xFF, 0xC0,
0x7F, 0xE0, 0x3F, 0xF0, 0x0F, 0x07, 0xF8, 0x07, 0xFF, 0x83, 0xFF, 0xF1,
0xFF, 0xFE, 0x7E, 0x1F, 0xBF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC,
0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03,
0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF,
0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC,
0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFD, 0xF8, 0x7E, 0x7F, 0xFF, 0x8F, 0xFF,
0xC1, 0xFF, 0xE0, 0x3F, 0xF0, 0xFF, 0xF0, 0x3F, 0xFF, 0x8F, 0xFF, 0xF3,
0xFF, 0xFE, 0xFC, 0x3F, 0xBF, 0x03, 0xEF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC,
0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xBF, 0x0F,
0xEF, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF, 0xFE, 0x3F, 0xFC, 0x0F, 0xC0, 0x03,
0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xFC,
0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00,
0x0F, 0xC0, 0x03, 0xF0, 0x00, 0x07, 0xF8, 0x07, 0xFF, 0x83, 0xFF, 0xF1,
0xFF, 0xFE, 0x7E, 0x1F, 0xBF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC,
0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03,
0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF,
0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC,
0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFD, 0xF8, 0x7E, 0x7F, 0xFF, 0x8F, 0xFF,
0xC1, 0xFF, 0xE0, 0x3F, 0xF0, 0x00, 0x3E, 0x00, 0x0F, 0xC0, 0x01, 0xF8,
0x00, 0x3E, 0x00, 0x07, 0x00, 0x00, 0xC0, 0xFF, 0xE0, 0x3F, 0xFF, 0x8F,
0xFF, 0xF3, 0xFF, 0xFE, 0xFC, 0x3F, 0xBF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0,
0x3F, 0xFC, 0x07, 0xFF, 0x01, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F,
0xFF, 0x0F, 0xEF, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF, 0xFC, 0x3F, 0x1F, 0x0F,
0xC7, 0xE3, 0xF1, 0xF8, 0xFC, 0x3E, 0x3F, 0x0F, 0xCF, 0xC3, 0xF3, 0xF0,
0xFC, 0xFC, 0x1F, 0x3F, 0x07, 0xEF, 0xC1, 0xFB, 0xF0, 0x7E, 0xFC, 0x0F,
0xBF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x1F, 0x0F, 0xE0, 0x3F, 0xF8, 0x7F,
0xFC, 0x7F, 0xFE, 0xFE, 0x7E, 0xF8, 0x3E, 0xF8, 0x3F, 0xF8, 0x1F, 0xF8,
0x1F, 0xFC, 0x00, 0xFC, 0x00, 0xFE, 0x00, 0x7F, 0x00, 0x7F, 0x80, 0x3F,
0xE0, 0x1F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFC, 0x00, 0xFE, 0x00,
0x7F, 0x00, 0x3F, 0x78, 0x3F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFC,
0x3F, 0xFE, 0x3F, 0x7F, 0xFE, 0x3F, 0xFE, 0x3F, 0xFC, 0x0F, 0xF0, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF8, 0x01, 0xF0,
0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00,
0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E,
0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80,
0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0xFC,
0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03,
0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF,
0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC,
0x0F, 0xFF, 0x03, 0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03,
0xFF, 0xC0, 0xFF, 0xF0, 0x3F, 0xFC, 0x0F, 0xFF, 0x03, 0xF7, 0xC0, 0xFD,
0xF8, 0x7E, 0x7F, 0xFF, 0x8F, 0xFF, 0xC1, 0xFF, 0xE0, 0x3F, 0xF0, 0xF8,
0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7D, 0xF0, 0x1F, 0x7C, 0x0F, 0xDF, 0x03,
0xE7, 0xC0, 0xF9, 0xF0, 0x3E, 0x3E, 0x0F, 0x8F, 0x87, 0xE3, 0xE1, 0xF0,
0xF8, 0x7C, 0x3E, 0x1F, 0x07, 0x87, 0xC1, 0xF1, 0xE0, 0x7C, 0xF8, 0x1F,
0x3E, 0x07, 0xCF, 0x80, 0xF3, 0xE0, 0x3E, 0xF0, 0x0F, 0xBC, 0x03, 0xFF,
0x00, 0xFF, 0xC0, 0x1F, 0xF0, 0x07, 0xF8, 0x01, 0xFE, 0x00, 0x7F, 0x80,
0x1F, 0xE0, 0x03, 0xF8, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0xF8,
0x1E, 0x07, 0xFE, 0x07, 0x81, 0xF7, 0x81, 0xE0, 0x79, 0xE0, 0xF8, 0x3E,
0x7C, 0x3F, 0x0F, 0x9F, 0x0F, 0xC3, 0xE7, 0xC3, 0xF0, 0xF9, 0xF0, 0xFC,
0x3E, 0x7C, 0x3F, 0x0F, 0x8F, 0x0F, 0xC3, 0xC3, 0xC7, 0xF8, 0xF0, 0xF9,
0xFE, 0x7C, 0x3E, 0x7F, 0x9F, 0x0F, 0x9F, 0xE7, 0xC3, 0xE7, 0x39, 0xF0,
0xF9, 0xCE, 0x7C, 0x1E, 0xF3, 0xDE, 0x07, 0xBC, 0xF7, 0x81, 0xEF, 0x3D,
0xE0, 0x7F, 0xCF, 0xF8, 0x1F, 0xE1, 0xFE, 0x07, 0xF8, 0x7F, 0x81, 0xFE,
0x1F, 0xE0, 0x3F, 0x87, 0xF0, 0x0F, 0xE1, 0xFC, 0x03, 0xF8, 0x7F, 0x00,
0xFC, 0x0F, 0xC0, 0x3F, 0x03, 0xF0, 0x0F, 0xC0, 0xFC, 0x03, 0xF0, 0x3F,
0x00, 0x7C, 0x0F, 0x80, 0x1F, 0x03, 0xE0, 0x7C, 0x03, 0xEF, 0xC0, 0xF8,
0xF8, 0x1F, 0x1F, 0x03, 0xC3, 0xF0, 0xF8, 0x3E, 0x1F, 0x07, 0xE7, 0xC0,
0x7C, 0xF8, 0x0F, 0x9F, 0x01, 0xFF, 0xC0, 0x1F, 0xF8, 0x03, 0xFE, 0x00,
0x3F, 0xC0, 0x07, 0xF8, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x03, 0xF8, 0x00,
0x7F, 0x00, 0x1F, 0xF0, 0x03, 0xFE, 0x00, 0x7F, 0xC0, 0x1F, 0xFC, 0x03,
0xEF, 0x80, 0x7D, 0xF8, 0x1F, 0x1F, 0x03, 0xE3, 0xE0, 0xF8, 0x7E, 0x1F,
0x07, 0xC3, 0xE0, 0xFC, 0xF8, 0x0F, 0x9F, 0x01, 0xFF, 0xE0, 0x1F, 0xFC,
0x07, 0xEF, 0x80, 0xF9, 0xF0, 0x1F, 0x3F, 0x07, 0xE3, 0xE0, 0xF8, 0x7C,
0x1F, 0x0F, 0xC3, 0xE0, 0xF8, 0xF8, 0x1F, 0x1F, 0x03, 0xF3, 0xE0, 0x3E,
0xF8, 0x07, 0xDF, 0x00, 0xFF, 0xE0, 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x3F,
0xE0, 0x03, 0xF8, 0x00, 0x7F, 0x00, 0x0F, 0xE0, 0x00, 0xF8, 0x00, 0x1F,
0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3E,
0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0x7C,
0x00, 0x0F, 0x80, 0x7F, 0xFE, 0xFF, 0xFD, 0xFF, 0xFB, 0xFF, 0xF0, 0x07,
0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x7C, 0x01, 0xF8, 0x03, 0xE0, 0x07, 0xC0,
0x1F, 0x80, 0x3E, 0x00, 0x7C, 0x01, 0xF8, 0x03, 0xE0, 0x0F, 0xC0, 0x1F,
0x80, 0x3E, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xE0, 0x0F, 0xC0, 0x1F, 0x00,
0x3E, 0x00, 0xFC, 0x01, 0xF0, 0x03, 0xE0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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,
0xC3, 0xE1, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xFF, 0xFE, 0xF0,
0x03, 0x80, 0x1E, 0x00, 0xF0, 0x03, 0x80, 0x1C, 0x00, 0xF0, 0x07, 0x80,
0x1C, 0x00, 0xF0, 0x07, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x80, 0x1C, 0x00,
0xE0, 0x07, 0x80, 0x3C, 0x00, 0xE0, 0x07, 0x80, 0x3C, 0x00, 0xE0, 0x07,
0x00, 0x3C, 0x01, 0xE0, 0x07, 0x00, 0x3C, 0x01, 0xE0, 0x07, 0x00, 0x38,
0x01, 0xE0, 0x0F, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F,
0x07, 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, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x7F, 0xFF, 0xFE, 0x03,
0xC0, 0x07, 0xE0, 0x07, 0xE0, 0x0F, 0xF0, 0x0F, 0xF0, 0x1F, 0xF8, 0x1E,
0x78, 0x1E, 0x78, 0x3E, 0x7C, 0x3C, 0x3C, 0x7C, 0x3E, 0x7C, 0x3E, 0xF8,
0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7C, 0x7C, 0x3C,
0x3E, 0x1E, 0x0E, 0x0F, 0x0F, 0xE0, 0x3F, 0xE0, 0xFF, 0xE3, 0xFF, 0xE7,
0xCF, 0xDF, 0x0F, 0xBE, 0x1F, 0x7C, 0x3E, 0x00, 0x7C, 0x03, 0xF8, 0x1F,
0xF0, 0xFF, 0xE3, 0xF7, 0xCF, 0x8F, 0x9E, 0x1F, 0x7C, 0x3E, 0xF8, 0x7D,
0xF0, 0xFB, 0xE3, 0xF7, 0xFF, 0xEF, 0xFF, 0xCF, 0xE7, 0x8F, 0x8F, 0x80,
0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E,
0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF1, 0xE3, 0xEF, 0xE7, 0xFF, 0xEF, 0xFF,
0xDF, 0x0F, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7F, 0xE0, 0xFF,
0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0,
0x7F, 0xE0, 0xFF, 0xC3, 0xFF, 0xEF, 0xDF, 0xFF, 0xBE, 0xFE, 0x7C, 0xFC,
0x0F, 0xC0, 0xFF, 0xC7, 0xFF, 0xBF, 0xFE, 0xF8, 0xFF, 0xE1, 0xFF, 0x87,
0xFE, 0x1F, 0xF8, 0x7F, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0,
0x0F, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFF, 0x3E, 0x7F,
0xF8, 0xFF, 0xC1, 0xFE, 0x00, 0x00, 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x03,
0xF0, 0x07, 0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x3C, 0xFD,
0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0xFE, 0x1F, 0xFC, 0x3F, 0xF8,
0x7F, 0xF0, 0xFF, 0xE1, 0xFF, 0xC3, 0xFF, 0x87, 0xFF, 0x0F, 0xFE, 0x1F,
0xFC, 0x3F, 0xF8, 0x7F, 0xF0, 0xFF, 0xE1, 0xFF, 0xC3, 0xFF, 0xCF, 0xFF,
0xFF, 0xDF, 0xFF, 0x9F, 0xBF, 0x0F, 0xC0, 0xFF, 0xC7, 0xFF, 0xBF, 0xFE,
0xF8, 0xFB, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x1F, 0xF8, 0x7F, 0xE1,
0xFF, 0x87, 0xFF, 0xFE, 0x7F, 0xF8, 0xFF, 0xC1, 0xFE, 0x00, 0x07, 0xE1,
0xFC, 0x7F, 0x9F, 0xF3, 0xF0, 0x7E, 0x0F, 0x81, 0xF0, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xF3, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, 0xC0, 0xF8,
0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, 0xC0, 0xF8, 0x1F,
0x03, 0xE0, 0x7C, 0x0F, 0x80, 0x00, 0x00, 0x81, 0xF8, 0x61, 0xFF, 0xBC,
0xFF, 0xFE, 0x3E, 0x7E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C,
0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C, 0x3E, 0x0F, 0xFF,
0x03, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xE0, 0x1E, 0x00, 0x07, 0x80, 0x01,
0xFF, 0x80, 0x7F, 0xFE, 0x1F, 0xFF, 0xC1, 0xFF, 0xF0, 0xE0, 0xFC, 0x70,
0x0F, 0xBC, 0x01, 0xEF, 0x80, 0xFB, 0xFF, 0xFC, 0xFF, 0xFF, 0x1F, 0xFF,
0x83, 0xFF, 0x80, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80,
0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF1, 0xF3, 0xE7, 0xF7,
0xFF, 0xEF, 0xFF, 0xFF, 0x8F, 0xFE, 0x1F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0,
0x7F, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0xFC, 0x1F,
0xF8, 0x3F, 0xF0, 0x7F, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE,
0x0F, 0xFC, 0x1F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xC0, 0x1F, 0x8F, 0xC7, 0xE3, 0xF1, 0xF8, 0x00, 0x00, 0x00,
0x1F, 0x8F, 0xC7, 0xE3, 0xF1, 0xF8, 0xFC, 0x7E, 0x3F, 0x1F, 0x8F, 0xC7,
0xE3, 0xF1, 0xF8, 0xFC, 0x7E, 0x3F, 0x1F, 0x8F, 0xC7, 0xE3, 0xF1, 0xF8,
0xFC, 0x7E, 0x3F, 0x1F, 0xFF, 0xFF, 0xDF, 0xEF, 0xE0, 0xF8, 0x00, 0xF8,
0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8,
0x00, 0xF8, 0x00, 0xF8, 0x1F, 0xF8, 0x3F, 0xF8, 0x7E, 0xF8, 0x7E, 0xF8,
0xFC, 0xF8, 0xF8, 0xF9, 0xF8, 0xFB, 0xF0, 0xFB, 0xF0, 0xFF, 0xE0, 0xFF,
0xE0, 0xFF, 0xF0, 0xFF, 0xF0, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
0x7C, 0xF8, 0x7C, 0xF8, 0x7E, 0xF8, 0x3E, 0xF8, 0x3E, 0xF8, 0x3F, 0xF8,
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, 0xF8, 0xF8, 0x7C, 0xFB, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFC, 0x7E, 0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0x3E,
0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0x3E,
0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0x3E,
0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0x3E,
0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0x3E, 0x1F, 0xF8, 0xF9,
0xF3, 0xFB, 0xFF, 0xF7, 0xFF, 0xFF, 0xC7, 0xFF, 0x0F, 0xFE, 0x1F, 0xFC,
0x3F, 0xF8, 0x7F, 0xF0, 0xFF, 0xE1, 0xFF, 0xC3, 0xFF, 0x87, 0xFF, 0x0F,
0xFE, 0x1F, 0xFC, 0x3F, 0xF8, 0x7F, 0xF0, 0xFF, 0xE1, 0xFF, 0xC3, 0xFF,
0x87, 0xFF, 0x0F, 0xFE, 0x1F, 0x80, 0x0F, 0xC0, 0xFF, 0xC7, 0xFF, 0xBF,
0xFE, 0xF8, 0xFF, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF,
0x87, 0xFE, 0x1F, 0xF8, 0x7F, 0xE1, 0xFF, 0x87, 0xFE, 0x1F, 0xF8, 0x7F,
0xE1, 0xFF, 0x87, 0xFF, 0x3F, 0x7F, 0xF8, 0xFF, 0xC1, 0xFE, 0x00, 0xF8,
0xF1, 0xF7, 0xF3, 0xFF, 0xF7, 0xFF, 0xEF, 0x87, 0xFF, 0x07, 0xFE, 0x0F,
0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7F, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF,
0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7F, 0xE1, 0xFF, 0xF7,
0xEF, 0xFF, 0xDF, 0x7F, 0x3E, 0x7C, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03,
0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x00, 0x1E, 0x7E, 0x7F, 0xFD,
0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0x0F, 0xFE, 0x1F, 0xFC, 0x3F, 0xF8,
0x7F, 0xF0, 0xFF, 0xE1, 0xFF, 0xC3, 0xFF, 0x87, 0xFF, 0x0F, 0xFE, 0x1F,
0xFC, 0x3F, 0xF8, 0x7F, 0xF0, 0xFF, 0xE1, 0xFF, 0xE7, 0xFF, 0xFF, 0xEF,
0xFF, 0xCF, 0xDF, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x03,
0xF0, 0x07, 0xE0, 0x0F, 0xC0, 0xF8, 0x7F, 0x3F, 0xEF, 0xFD, 0xFF, 0xFF,
0xFE, 0x7F, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xF0,
0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E,
0x00, 0x0F, 0xC0, 0xFF, 0x87, 0xFF, 0x1F, 0xFE, 0x7C, 0x7B, 0xE1, 0xFF,
0x83, 0x1F, 0x00, 0x7E, 0x01, 0xFC, 0x03, 0xFC, 0x07, 0xF8, 0x0F, 0xF0,
0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x30, 0x7F, 0xC1, 0xFF, 0x87, 0xDF, 0x3E,
0x7F, 0xF8, 0xFF, 0xC1, 0xFE, 0x00, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03,
0xE0, 0x7C, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xF8, 0x1F, 0x03, 0xE0,
0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C,
0x0F, 0x81, 0xF0, 0x3F, 0x07, 0xFC, 0xFF, 0x8F, 0xF0, 0xFE, 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, 0x7F, 0xE1, 0xFF, 0x87, 0xFF, 0x7F, 0xFF, 0xFD, 0xFD,
0xF7, 0xE7, 0xC0, 0xFC, 0x3E, 0xF8, 0x7D, 0xF0, 0xFB, 0xE1, 0xF7, 0xC3,
0xEF, 0x87, 0x8F, 0x9F, 0x1F, 0x3E, 0x3E, 0x7C, 0x7C, 0xF8, 0xF9, 0xE0,
0xF3, 0xC1, 0xE7, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0xF8, 0x0F, 0xF0, 0x1F,
0xE0, 0x3F, 0xC0, 0x7F, 0x80, 0xFE, 0x00, 0xFC, 0x01, 0xF8, 0x00, 0xF0,
0x78, 0x7F, 0xC3, 0xC3, 0xFE, 0x3E, 0x1F, 0xF1, 0xF0, 0xF7, 0x8F, 0x8F,
0xBC, 0x7C, 0x79, 0xE3, 0xF3, 0xCF, 0x1F, 0x9E, 0x79, 0xFC, 0xF3, 0xEF,
0xE7, 0x9F, 0x77, 0x3C, 0x7B, 0xBB, 0xE3, 0xDD, 0xFE, 0x1E, 0xE7, 0xF0,
0xFF, 0x3F, 0x87, 0xF1, 0xFC, 0x3F, 0x8F, 0xE0, 0xFC, 0x7F, 0x07, 0xE3,
0xF0, 0x3F, 0x0F, 0x81, 0xF8, 0x7C, 0x0F, 0x83, 0xE0, 0x7C, 0x1F, 0x00,
0x7C, 0x1F, 0x7C, 0x1E, 0x3E, 0x3E, 0x3E, 0x3C, 0x3F, 0x3C, 0x1F, 0x7C,
0x1F, 0xF8, 0x0F, 0xF8, 0x0F, 0xF0, 0x07, 0xF0, 0x07, 0xE0, 0x07, 0xE0,
0x07, 0xE0, 0x0F, 0xF0, 0x0F, 0xF0, 0x1F, 0xF8, 0x1F, 0xF8, 0x1E, 0xFC,
0x3E, 0x7C, 0x3C, 0x7E, 0x7C, 0x3E, 0x7C, 0x3E, 0xF8, 0x1F, 0xF8, 0x1F,
0x7C, 0x1F, 0x7C, 0x1F, 0x7C, 0x3E, 0x7C, 0x3E, 0x3C, 0x3E, 0x3E, 0x3E,
0x3E, 0x3C, 0x3E, 0x3C, 0x1E, 0x7C, 0x1E, 0x7C, 0x1F, 0x7C, 0x1F, 0x78,
0x0F, 0x78, 0x0F, 0xF8, 0x0F, 0xF8, 0x0F, 0xF0, 0x07, 0xF0, 0x07, 0xF0,
0x07, 0xF0, 0x07, 0xF0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0,
0x3F, 0xC0, 0x3F, 0xC0, 0x3F, 0x80, 0x3E, 0x00, 0x7F, 0xFB, 0xFF, 0xDF,
0xFE, 0xFF, 0xF0, 0x1F, 0x01, 0xF8, 0x0F, 0x80, 0xFC, 0x07, 0xC0, 0x3E,
0x03, 0xF0, 0x1F, 0x01, 0xF8, 0x0F, 0x80, 0xFC, 0x07, 0xC0, 0x3E, 0x03,
0xF0, 0x1F, 0x01, 0xFF, 0xEF, 0xFF, 0x7F, 0xFB, 0xFF, 0xC0, 0x07, 0xC7,
0xF1, 0xFC, 0xFF, 0x3F, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0,
0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x1F, 0x8F, 0xC3, 0xE0, 0xFC,
0x3F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83,
0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xFC, 0x1F, 0xC7, 0xF0, 0xFC, 0x01,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x3F, 0x0F, 0xE3, 0xF8,
0x3F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F,
0xC3, 0xF0, 0x7C, 0x1F, 0x07, 0xE0, 0xFC, 0x1F, 0x0F, 0xC7, 0xF1, 0xF0,
0x7C, 0x1F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F,
0x0F, 0xC3, 0xF0, 0xF8, 0xFE, 0x3F, 0x8F, 0xC3, 0x00, 0x1F, 0x04, 0x3F,
0xCE, 0xFF, 0xFF, 0x7F, 0xFE, 0x20, 0xFC, 0x00, 0x30 };
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

1025
src/fonts/oswald-30.h Normal file

File diff suppressed because it is too large Load diff

4480
src/fonts/oswald-90.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,323 +0,0 @@
#pragma once
#include <Adafruit_GFX.h>
#include <Arduino.h>
#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
};

View file

@ -1,497 +0,0 @@
#pragma once
#include <Adafruit_GFX.h>
#include <Arduino.h>
#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
};

File diff suppressed because it is too large Load diff

View file

@ -1,235 +1,201 @@
#pragma once const uint8_t Satoshi_Symbol90pt7bBitmaps[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#include <Adafruit_GFX.h> 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#include <Arduino.h> 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
#include "fonts.hpp" 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00,
const uint8_t Satoshi_Symbol90pt7bBitmaps_Gzip[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00,
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x63, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x60, 0x60, 0xe0, 0xff, 0xc7, 0x00, 0x05, 0xcc, 0xff, 0x1b, 0x60, 0xcc, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x0f, 0x60, 0x2c, 0xfb, 0x1f, 0x30, 0xd6, 0x60, 0x53, 0x38, 0x28, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x81, 0xfd, 0x7f, 0x3a, 0x83, 0x81, 0xf6, 0x30, 0x1a, 0xe0, 0xa7, 0xb7, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00,
0xff, 0x0f, 0x0c, 0xb4, 0x8f, 0x51, 0x01, 0x33, 0xbd, 0xfd, 0xff, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00,
0xa0, 0x7d, 0x8c, 0x17, 0x0c, 0x8e, 0x92, 0x82, 0x44, 0x85, 0x54, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
0x23, 0x88, 0xe1, 0xec, 0xff, 0xa1, 0x56, 0xf2, 0xff, 0xff, 0x03, 0x61, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc8, 0xff, 0x87, 0x3a, 0xc7, 0x1e, 0x16, 0x8d, 0xf5, 0x30, 0xa7, 0xc2, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x12, 0x36, 0xe3, 0x7f, 0xa8, 0xeb, 0x98, 0x47, 0x8d, 0x19, 0x35, 0x66, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
0x78, 0x1b, 0x43, 0x65, 0xf0, 0x00, 0x00, 0xc7, 0x63, 0x9f, 0x4b, 0xde, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}; 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// unsigned int satoshi_bin_gz_len = 123; 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// const uint8_t Satoshi_Symbol90pt7bBitmaps[] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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,
// 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, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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,
// 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, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xF0, 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, 0x00, 0x00, 0x00, 0x00, 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, 0xFF, 0xE0, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 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,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE,
// 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0,
// 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00,
// 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
// 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF,
// 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 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,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00,
// 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00,
// 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00,
// 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00,
// 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00,
// 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00,
// 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8,
// 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00,
// 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80,
// 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
// 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00,
// 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00,
// 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00,
// 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00,
// 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC,
// 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00,
// 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0,
// 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00,
// 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00,
// 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00,
// 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00,
// 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xE0 };
// 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 = { const GFXglyph Satoshi_Symbol90pt7bGlyphs[] PROGMEM = {
{ 0, 82, 127, 99, 8, -126 }, { 1302, 71, 109, 93, 0, -117 } }; // 0x53 'S' { 0, 82, 127, 99, 8, -126 }, { 1302, 71, 109, 93, 0, -117 } }; // 0x53 'S'
// const GFXfont Satoshi_Symbol90pt7b PROGMEM = { const GFXfont Satoshi_Symbol90pt7b PROGMEM = {
// (uint8_t *)Satoshi_Symbol90pt7bBitmaps, (uint8_t *)Satoshi_Symbol90pt7bBitmaps,
// (GFXglyph *)Satoshi_Symbol90pt7bGlyphs, (GFXglyph *)Satoshi_Symbol90pt7bGlyphs,
// 0x53, 0x53, 192 }; 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 // Approx. 2284 bytes

View file

@ -1,19 +1,24 @@
#include "bitaxe_fetch.hpp" #include "bitaxe_fetch.hpp"
void BitAxeFetch::taskWrapper(void* pvParameters) { TaskHandle_t bitaxeFetchTaskHandle;
BitAxeFetch::getInstance().task();
std::string bitaxeHashrate;
std::string bitaxeBestDiff;
std::string getBitAxeHashRate()
{
return bitaxeHashrate;
} }
uint64_t BitAxeFetch::getHashRate() const { std::string getBitaxeBestDiff()
return hashrate; {
return bitaxeBestDiff;
} }
uint64_t BitAxeFetch::getBestDiff() const { void taskBitaxeFetch(void *pvParameters)
return bestDiff; {
} for (;;)
{
void BitAxeFetch::task() {
for (;;) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
HTTPClient http; HTTPClient http;
@ -23,38 +28,34 @@ void BitAxeFetch::task() {
int httpCode = http.GET(); int httpCode = http.GET();
if (httpCode == 200) { if (httpCode == 200)
{
String payload = http.getString(); String payload = http.getString();
JsonDocument doc; JsonDocument doc;
deserializeJson(doc, payload); deserializeJson(doc, payload);
bitaxeHashrate = std::to_string(static_cast<int>(std::round(doc["hashRate"].as<float>())));
bitaxeBestDiff = doc["bestDiff"].as<std::string>();
// Convert GH/s to H/s (multiply by 10^9) if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_BESTDIFF))
float hashRateGH = doc["hashRate"].as<float>(); {
hashrate = static_cast<uint64_t>(std::round(hashRateGH * std::pow(10, getHashrateMultiplier('G'))));
// Parse difficulty string and convert to uint64_t
std::string diffStr = doc["bestDiff"].as<std::string>();
char diffUnit = diffStr[diffStr.length() - 1];
if (std::isalpha(diffUnit)) {
float diffValue = std::stof(diffStr.substr(0, diffStr.length() - 1));
bestDiff = static_cast<uint64_t>(std::round(diffValue * std::pow(10, getDifficultyMultiplier(diffUnit))));
} else {
bestDiff = std::stoull(diffStr);
}
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_BESTDIFF)) {
WorkItem priceUpdate = {TASK_BITAXE_UPDATE, 0}; WorkItem priceUpdate = {TASK_BITAXE_UPDATE, 0};
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); 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(httpCode);
Serial.println(bitaxeApiUrl); Serial.println(bitaxeApiUrl);
} }
} }
} }
void BitAxeFetch::setup() { void setupBitaxeFetchTask()
xTaskCreate(taskWrapper, "bitaxeFetch", (3 * 1024), NULL, tskIDLE_PRIORITY, &taskHandle); {
xTaskNotifyGive(taskHandle); xTaskCreate(taskBitaxeFetch, "bitaxeFetch", (3 * 1024), NULL, tskIDLE_PRIORITY,
&bitaxeFetchTaskHandle);
xTaskNotifyGive(bitaxeFetchTaskHandle);
} }

View file

@ -2,33 +2,14 @@
#include <Arduino.h> #include <Arduino.h>
#include <HTTPClient.h> #include <HTTPClient.h>
#include <utils.hpp>
#include "lib/config.hpp" #include "lib/config.hpp"
#include "lib/shared.hpp" #include "lib/shared.hpp"
class BitAxeFetch { extern TaskHandle_t bitaxeFetchTaskHandle;
public:
static BitAxeFetch& getInstance() {
static BitAxeFetch instance;
return instance;
}
void setup(); void setupBitaxeFetchTask();
uint64_t getHashRate() const; void taskBitaxeFetch(void *pvParameters);
uint64_t getBestDiff() const;
static void taskWrapper(void* pvParameters);
TaskHandle_t getTaskHandle() const { return taskHandle; }
private: std::string getBitAxeHashRate();
BitAxeFetch() = default; std::string getBitaxeBestDiff();
~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;
};

View file

@ -1,14 +1,13 @@
#include "block_notify.hpp" #include "block_notify.hpp"
// Initialize static members char *wsServer;
esp_websocket_client_handle_t BlockNotify::wsClient = nullptr; esp_websocket_client_handle_t blockNotifyClient = NULL;
uint32_t BlockNotify::currentBlockHeight = 878000; uint currentBlockHeight = 873400;
uint16_t BlockNotify::blockMedianFee = 1; uint blockMedianFee = 1;
bool BlockNotify::notifyInit = false; bool blockNotifyInit = false;
unsigned long int BlockNotify::lastBlockUpdate = 0; unsigned long int lastBlockUpdate;
TaskHandle_t BlockNotify::taskHandle = nullptr;
const char* BlockNotify::mempoolWsCert = R"EOF( const char *mempoolWsCert = R"EOF(
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
@ -43,106 +42,22 @@ VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
jjxDah2nGN59PRbxYvnKkKj9 jjxDah2nGN59PRbxYvnKkKj9
-----END CERTIFICATE----- -----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"; )EOF";
void BlockNotify::onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { void setupBlockNotify()
esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
BlockNotify& instance = BlockNotify::getInstance();
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 dataArray = doc.createNestedArray("data");
dataArray.add("blocks");
dataArray.add("mempool-blocks");
String sub;
serializeJson(doc, sub);
esp_websocket_client_send_text(wsClient, sub.c_str(), sub.length(), portMAX_DELAY);
break;
}
case WEBSOCKET_EVENT_DATA:
instance.onWebsocketMessage(data);
break;
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::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>()) {
JsonObject block = doc["block"];
if (block["height"].as<uint>() != currentBlockHeight) {
processNewBlock(block["height"].as<uint>());
}
}
else if (doc["mempool-blocks"].is<JsonArray>()) {
JsonArray blockInfo = doc["mempool-blocks"].as<JsonArray>();
uint medianFee = (uint)round(blockInfo[0]["medianFee"].as<double>());
processNewBlockFee(medianFee);
}
}
void BlockNotify::setup() {
IPAddress result; IPAddress result;
int dnsErr = -1;
String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
while (dnsErr != 1 && !strchr(mempoolInstance.c_str(), ':')) { 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); dnsErr = WiFi.hostByName(mempoolInstance.c_str(), result);
if (dnsErr != 1) { if (dnsErr != 1)
{
Serial.print(mempoolInstance); Serial.print(mempoolInstance);
Serial.println(F("mempool DNS could not be resolved")); Serial.println(F("mempool DNS could not be resolved"));
WiFi.reconnect(); WiFi.reconnect();
@ -151,52 +66,15 @@ void BlockNotify::setup() {
} }
// Get current block height through regular API // Get current block height through regular API
int blockFetch = fetchLatestBlock(); int blockFetch = getBlockFetch();
if (blockFetch > currentBlockHeight) if (blockFetch > currentBlockHeight)
currentBlockHeight = blockFetch; currentBlockHeight = blockFetch;
if (currentBlockHeight != -1) { if (currentBlockHeight != -1)
lastBlockUpdate = esp_timer_get_time() / 1000000;
}
if (workQueue != nullptr) {
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
}
const bool useSSL = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE);
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) {
config.cert_pem = mempoolWsCert;
}
config.uri = wsUri.c_str();
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)
{ {
return;
}
currentBlockHeight = newBlockHeight;
lastBlockUpdate = esp_timer_get_time() / 1000000; lastBlockUpdate = esp_timer_get_time() / 1000000;
}
if (workQueue != nullptr) if (workQueue != nullptr)
{ {
@ -204,12 +82,126 @@ void BlockNotify::processNewBlock(uint32_t newBlockHeight) {
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); 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)
{
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;
Serial.println(F("Connected to Mempool.space WebSocket"));
Serial.println(sub);
if (esp_websocket_client_send_text(blockNotifyClient, sub.c_str(),
sub.length(), portMAX_DELAY) == -1)
{
Serial.println(F("Mempool.space WS Block Subscribe Error"));
}
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;
}
}
void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data)
{
JsonDocument doc;
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.containsKey("block"))
{
JsonObject block = doc["block"];
if (block["height"].as<uint>() == currentBlockHeight) {
return;
}
processNewBlock(block["height"].as<uint>());
}
else if (doc.containsKey("mempool-blocks"))
{
JsonArray blockInfo = doc["mempool-blocks"].as<JsonArray>();
uint medianFee = (uint)round(blockInfo[0]["medianFee"].as<double>());
processNewBlockFee(medianFee);
}
doc.clear();
}
void processNewBlock(uint newBlockHeight) {
if (newBlockHeight < currentBlockHeight)
return;
currentBlockHeight = newBlockHeight;
// Serial.printf("New block found: %d\r\n", block["height"].as<uint>());
preferences.putUInt("blockHeight", currentBlockHeight);
lastBlockUpdate = esp_timer_get_time() / 1000000;
if (workQueue != nullptr)
{
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
// xTaskNotifyGive(blockUpdateTaskHandle);
if (ScreenHandler::getCurrentScreen() != SCREEN_BLOCK_HEIGHT && if (ScreenHandler::getCurrentScreen() != SCREEN_BLOCK_HEIGHT &&
preferences.getBool("stealFocus", DEFAULT_STEAL_FOCUS)) preferences.getBool("stealFocus", DEFAULT_STEAL_FOCUS))
{ {
uint64_t timerPeriod = 0; uint64_t timerPeriod = 0;
if (isTimerActive()) if (isTimerActive())
{ {
// store timer periode before making inactive to prevent artifacts
timerPeriod = getTimerSeconds(); timerPeriod = getTimerSeconds();
esp_timer_stop(screenRotateTimer); esp_timer_stop(screenRotateTimer);
} }
@ -225,16 +217,18 @@ void BlockNotify::processNewBlock(uint32_t newBlockHeight) {
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 vTaskDelay(pdMS_TO_TICKS(250)); // Wait until screens are updated
getLedHandler().queueEffect(LED_FLASH_BLOCK_NOTIFY); queueLedEffect(LED_FLASH_BLOCK_NOTIFY);
}
} }
} }
void BlockNotify::processNewBlockFee(uint16_t newBlockFee) { void processNewBlockFee(uint newBlockFee) {
if (blockMedianFee == newBlockFee) if (blockMedianFee == newBlockFee)
{ {
return; return;
} }
// Serial.printf("New median fee: %d\r\n", medianFee);
blockMedianFee = newBlockFee; blockMedianFee = newBlockFee;
if (workQueue != nullptr) if (workQueue != nullptr)
@ -244,54 +238,60 @@ void BlockNotify::processNewBlockFee(uint16_t newBlockFee) {
} }
} }
uint32_t BlockNotify::getBlockHeight() const { uint getBlockHeight() { return currentBlockHeight; }
return currentBlockHeight;
}
void BlockNotify::setBlockHeight(uint32_t newBlockHeight) void setBlockHeight(uint newBlockHeight)
{ {
currentBlockHeight = newBlockHeight; currentBlockHeight = newBlockHeight;
} }
uint16_t BlockNotify::getBlockMedianFee() const { uint getBlockMedianFee() { return blockMedianFee; }
return blockMedianFee;
}
void BlockNotify::setBlockMedianFee(uint16_t newBlockMedianFee) void setBlockMedianFee(uint newBlockMedianFee)
{ {
blockMedianFee = newBlockMedianFee; blockMedianFee = newBlockMedianFee;
} }
bool BlockNotify::isConnected() const bool isBlockNotifyConnected()
{ {
if (wsClient == NULL) if (blockNotifyClient == NULL)
return false; return false;
return esp_websocket_client_is_connected(wsClient); return esp_websocket_client_is_connected(blockNotifyClient);
} }
bool BlockNotify::isInitialized() const bool getBlockNotifyInit()
{ {
return notifyInit; return blockNotifyInit;
} }
void BlockNotify::stop() void stopBlockNotify()
{ {
if (wsClient == NULL) if (blockNotifyClient == NULL)
return; return;
esp_websocket_client_close(wsClient, portMAX_DELAY); esp_websocket_client_close(blockNotifyClient, pdMS_TO_TICKS(5000));
esp_websocket_client_stop(wsClient); esp_websocket_client_stop(blockNotifyClient);
esp_websocket_client_destroy(wsClient); esp_websocket_client_destroy(blockNotifyClient);
wsClient = NULL;
blockNotifyClient = NULL;
} }
void BlockNotify::restart() void restartBlockNotify()
{ {
stop(); stopBlockNotify();
setup();
if (blockNotifyClient == NULL) {
setupBlockNotify();
return;
} }
int BlockNotify::fetchLatestBlock() { // esp_websocket_client_close(blockNotifyClient, pdMS_TO_TICKS(5000));
// esp_websocket_client_stop(blockNotifyClient);
// esp_websocket_client_start(blockNotifyClient);
}
int getBlockFetch() {
try { try {
String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
const String protocol = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE) ? "https" : "http"; const String protocol = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE) ? "https" : "http";
@ -314,12 +314,12 @@ int BlockNotify::fetchLatestBlock() {
return 2203; // B-T-C return 2203; // B-T-C
} }
uint BlockNotify::getLastBlockUpdate() const uint getLastBlockUpdate()
{ {
return lastBlockUpdate; return lastBlockUpdate;
} }
void BlockNotify::setLastBlockUpdate(uint lastUpdate) void setLastBlockUpdate(uint lastUpdate)
{ {
lastBlockUpdate = lastUpdate; lastBlockUpdate = lastUpdate;
} }

View file

@ -5,6 +5,7 @@
#include <HTTPClient.h> #include <HTTPClient.h>
#include <esp_timer.h> #include <esp_timer.h>
#include <esp_websocket_client.h> #include <esp_websocket_client.h>
#include <cstring> #include <cstring>
#include <string> #include <string>
@ -13,53 +14,28 @@
#include "lib/timers.hpp" #include "lib/timers.hpp"
#include "lib/shared.hpp" #include "lib/shared.hpp"
class BlockNotify { // using namespace websockets;
public:
static BlockNotify& getInstance() {
static BlockNotify instance;
return instance;
}
// Delete copy constructor and assignment operator void setupBlockNotify();
BlockNotify(const BlockNotify&) = delete;
void operator=(const BlockNotify&) = delete;
// Block notification setup and control void onWebsocketBlockEvent(void *handler_args, esp_event_base_t base,
void setup(); int32_t event_id, void *event_data);
void stop(); void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data);
void restart();
bool isConnected() const;
bool isInitialized() const;
// Block height management void setBlockHeight(uint newBlockHeight);
void setBlockHeight(uint32_t newBlockHeight); uint getBlockHeight();
uint32_t getBlockHeight() const;
// Block fee management void setBlockMedianFee(uint blockMedianFee);
void setBlockMedianFee(uint16_t blockMedianFee); uint getBlockMedianFee();
uint16_t getBlockMedianFee() const;
// Block processing bool isBlockNotifyConnected();
void processNewBlock(uint32_t newBlockHeight); void stopBlockNotify();
void processNewBlockFee(uint16_t newBlockFee); void restartBlockNotify();
// Block fetch and update tracking void processNewBlock(uint newBlockHeight);
int fetchLatestBlock(); void processNewBlockFee(uint newBlockFee);
uint getLastBlockUpdate() const;
bool getBlockNotifyInit();
uint getLastBlockUpdate();
int getBlockFetch();
void setLastBlockUpdate(uint lastUpdate); void setLastBlockUpdate(uint lastUpdate);
private:
BlockNotify() = default; // Private constructor for singleton
void setupTask();
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 const char* mempoolWsCert;
static esp_websocket_client_handle_t wsClient;
static uint32_t currentBlockHeight;
static uint16_t blockMedianFee;
static bool notifyInit;
static unsigned long int lastBlockUpdate;
static TaskHandle_t taskHandle;
};

View file

@ -1,5 +1,4 @@
#include "config.hpp" #include "config.hpp"
#include "led_handler.hpp"
#define MAX_ATTEMPTS_WIFI_CONNECTION 20 #define MAX_ATTEMPTS_WIFI_CONNECTION 20
@ -48,11 +47,10 @@ void setup()
setupPreferences(); setupPreferences();
setupHardware(); setupHardware();
EPDManager::getInstance().initialize(); setupDisplays();
if (preferences.getBool("ledTestOnPower", DEFAULT_LED_TEST_ON_POWER)) if (preferences.getBool("ledTestOnPower", DEFAULT_LED_TEST_ON_POWER))
{ {
auto& ledHandler = getLedHandler(); queueLedEffect(LED_POWER_TEST);
ledHandler.queueEffect(LED_POWER_TEST);
} }
{ {
std::lock_guard<std::mutex> lockMcp(mcpMutex); std::lock_guard<std::mutex> lockMcp(mcpMutex);
@ -62,8 +60,7 @@ void setup()
preferences.remove("txPower"); preferences.remove("txPower");
WiFi.eraseAP(); WiFi.eraseAP();
auto& ledHandler = getLedHandler(); queueLedEffect(LED_EFFECT_WIFI_ERASE_SETTINGS);
ledHandler.queueEffect(LED_EFFECT_WIFI_ERASE_SETTINGS);
} }
} }
@ -79,8 +76,7 @@ void setup()
else if (mcp1.read1(1) == LOW) else if (mcp1.read1(1) == LOW)
{ {
preferences.clear(); preferences.clear();
auto& ledHandler = getLedHandler(); queueLedEffect(LED_EFFECT_WIFI_ERASE_SETTINGS);
ledHandler.queueEffect(LED_EFFECT_WIFI_ERASE_SETTINGS);
nvs_flash_erase(); nvs_flash_erase();
delay(1000); delay(1000);
@ -104,53 +100,37 @@ void setup()
if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED)) if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED))
{ {
BitAxeFetch::getInstance().setup(); setupBitaxeFetchTask();
} }
if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED))
{ {
MiningPoolStatsFetch::getInstance().setup(); setupMiningPoolStatsFetchTask();
} }
ButtonHandler::setup(); ButtonHandler::setup();
setupOTA(); setupOTA();
EPDManager::getInstance().waitUntilNoneBusy(); waitUntilNoneBusy();
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
if (!preferences.getBool("flAlwaysOn", DEFAULT_FL_ALWAYS_ON)) if (!preferences.getBool("flAlwaysOn", DEFAULT_FL_ALWAYS_ON))
{ {
auto& ledHandler = getLedHandler(); frontlightFadeOutAll(preferences.getUInt("flEffectDelay"), true);
ledHandler.frontlightFadeOutAll(preferences.getUInt("flEffectDelay"), true);
flArray.allOFF(); flArray.allOFF();
} }
#endif #endif
EPDManager::getInstance().forceFullRefresh(); forceFullRefresh();
} }
void setupWifi() void setupWifi()
{ {
WiFi.onEvent(WiFiEvent); 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.setAutoConnect(true);
WiFi.setAutoReconnect(true); WiFi.setAutoReconnect(true);
WiFi.begin(); WiFi.begin();
if (preferences.getInt("txPower", DEFAULT_TX_POWER)) if (preferences.getInt("txPower", DEFAULT_TX_POWER))
{ {
if (WiFi.setTxPower( if (WiFi.setTxPower(
@ -164,8 +144,7 @@ void setupWifi()
// if (!preferences.getBool("wifiConfigured", DEFAULT_WIFI_CONFIGURED) // if (!preferences.getBool("wifiConfigured", DEFAULT_WIFI_CONFIGURED)
{ {
auto& ledHandler = getLedHandler(); queueLedEffect(LED_EFFECT_WIFI_WAIT_FOR_CONFIG);
ledHandler.queueEffect(LED_EFFECT_WIFI_WAIT_FOR_CONFIG);
bool buttonPress = false; bool buttonPress = false;
{ {
@ -178,7 +157,8 @@ void setupWifi()
byte mac[6]; byte mac[6];
WiFi.macAddress(mac); WiFi.macAddress(mac);
String softAP_SSID = getMyHostname(); String softAP_SSID =
String("BTClock" + String(mac[5], 16) + String(mac[1], 16));
WiFi.setHostname(softAP_SSID.c_str()); WiFi.setHostname(softAP_SSID.c_str());
String softAP_password = replaceAmbiguousChars( String softAP_password = replaceAmbiguousChars(
base64::encode(String(mac[2], 16) + String(mac[4], 16) + base64::encode(String(mac[2], 16) + String(mac[4], 16) +
@ -188,7 +168,6 @@ void setupWifi()
wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", DEFAULT_WP_TIMEOUT)); wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", DEFAULT_WP_TIMEOUT));
wm.setWiFiAutoReconnect(false); wm.setWiFiAutoReconnect(false);
wm.setDebugOutput(false); wm.setDebugOutput(false);
wm.setCountry("NL");
wm.setConfigPortalBlocking(true); wm.setConfigPortalBlocking(true);
wm.setAPCallback([&](WiFiManager *wifiManager) wm.setAPCallback([&](WiFiManager *wifiManager)
@ -198,14 +177,13 @@ void setupWifi()
wifiManager->getConfigPortalSSID().c_str(), wifiManager->getConfigPortalSSID().c_str(),
softAP_password.c_str()); softAP_password.c_str());
// delay(6000); // delay(6000);
EPDManager::getInstance().setForegroundColor(GxEPD_BLACK); setFgColor(GxEPD_BLACK);
EPDManager::getInstance().setBackgroundColor(GxEPD_WHITE); setBgColor(GxEPD_WHITE);
const String qrText = "qrWIFI:S:" + wifiManager->getConfigPortalSSID() + const String qrText = "qrWIFI:S:" + wifiManager->getConfigPortalSSID() +
";T:WPA;P:" + softAP_password.c_str() + ";;"; ";T:WPA;P:" + softAP_password.c_str() + ";;";
const String explainText = "*SSID: *\r\n" + const String explainText = "*SSID: *\r\n" +
wifiManager->getConfigPortalSSID() + 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 // Set the UNIX timestamp
time_t timestamp = LAST_BUILD_TIME; // Example timestamp: March 7, 2021 00:00:00 UTC time_t timestamp = LAST_BUILD_TIME; // Example timestamp: March 7, 2021 00:00:00 UTC
@ -215,36 +193,67 @@ void setupWifi()
// Format the date // Format the date
char formattedDate[20]; char formattedDate[20];
strftime(formattedDate, sizeof(formattedDate), "%y-%m-%d\r\n%H:%M:%S", timeinfo); 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<String, NUM_SCREENS> epdContent = { std::array<String, NUM_SCREENS> epdContent = {
"Welcome!", "Welcome!",
"Bienvenidos!", "Bienvenidos!",
"To setup\r\nscan QR or\r\nconnect\r\nmanually", "To setup\r\nscan QR or\r\nconnect\r\nmanually",
"Para\r\nconfigurar\r\nescanear QR\r\no conectar\r\nmanualmente", "Para\r\nconfigurar\r\nescanear QR\r\no conectar\r\nmanualmente",
explainText, explainText,
"*HW version:*\r\n" + hwStr + "*Hostname*:\r\n" + getMyHostname() + "\r\n\r\n" + "*FW build date:*\r\n" + formattedDate,
#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}; qrText};
setEpdContent(epdContent); });
EPDManager::getInstance().setContent(epdContent); });
wm.setSaveConfigCallback([]() wm.setSaveConfigCallback([]()
{ {
preferences.putBool("wifiConfigured", true); preferences.putBool("wifiConfigured", true);
delay(1000); delay(1000);
// just restart after success // just restart after succes
ESP.restart(); }); ESP.restart(); });
bool ac = wm.autoConnect(softAP_SSID.c_str(), softAP_password.c_str()); bool ac = wm.autoConnect(softAP_SSID.c_str(), softAP_password.c_str());
// waitUntilNoneBusy();
// std::array<String, NUM_SCREENS> epdContent = {"Welcome!",
// "Bienvenidos!", "Use\r\nweb-interface\r\nto configure", "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();
} }
EPDManager::getInstance().setForegroundColor(preferences.getUInt("fgColor", isWhiteVersion() ? GxEPD_BLACK : GxEPD_WHITE));
EPDManager::getInstance().setBackgroundColor(preferences.getUInt("bgColor", isWhiteVersion() ? GxEPD_WHITE : GxEPD_BLACK));
setFgColor(preferences.getUInt("fgColor", isWhiteVersion() ? GxEPD_BLACK : GxEPD_WHITE));
setBgColor(preferences.getUInt("bgColor", isWhiteVersion() ? GxEPD_WHITE : GxEPD_BLACK));
} }
// else // else
// { // {
@ -265,8 +274,6 @@ void syncTime()
while (!getLocalTime(&timeinfo)) while (!getLocalTime(&timeinfo))
{ {
auto& ledHandler = getLedHandler();
ledHandler.queueEffect(LED_EFFECT_CONFIGURING);
configTime(preferences.getInt("gmtOffset", DEFAULT_TIME_OFFSET_SECONDS), 0, configTime(preferences.getInt("gmtOffset", DEFAULT_TIME_OFFSET_SECONDS), 0,
NTP_SERVER); NTP_SERVER);
delay(500); delay(500);
@ -280,9 +287,9 @@ void setupPreferences()
{ {
preferences.begin("btclock", false); preferences.begin("btclock", false);
EPDManager::getInstance().setForegroundColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR)); setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
EPDManager::getInstance().setBackgroundColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR)); setBgColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR));
BlockNotify::getInstance().setBlockHeight(preferences.getUInt("blockHeight", INITIAL_BLOCK_HEIGHT)); setBlockHeight(preferences.getUInt("blockHeight", INITIAL_BLOCK_HEIGHT));
setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD); setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD);
if (!preferences.isKey("enableDebugLog")) { if (!preferences.isKey("enableDebugLog")) {
@ -361,7 +368,7 @@ void setupPreferences()
if (preferences.getBool("miningPoolStats", 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_HASHRATE, "Mining Pool Hashrate");
if (MiningPoolStatsFetch::getInstance().getPool()->supportsDailyEarnings()) { if (getMiningPool()->supportsDailyEarnings()) {
addScreenMapping(SCREEN_MINING_POOL_STATS_EARNINGS, "Mining Pool Earnings"); addScreenMapping(SCREEN_MINING_POOL_STATS_EARNINGS, "Mining Pool Earnings");
} }
} }
@ -390,7 +397,7 @@ void setupWebsocketClients(void *pvParameters)
} }
else if (dataSource == THIRD_PARTY_SOURCE) else if (dataSource == THIRD_PARTY_SOURCE)
{ {
BlockNotify::getInstance().setup(); setupBlockNotify();
setupPriceNotify(); setupPriceNotify();
} }
@ -407,14 +414,13 @@ void setupTimers()
void finishSetup() void finishSetup()
{ {
auto& ledHandler = getLedHandler();
if (preferences.getBool("ledStatus", DEFAULT_LED_STATUS)) if (preferences.getBool("ledStatus", DEFAULT_LED_STATUS))
{ {
ledHandler.restoreLedState(); restoreLedState();
} }
else else
{ {
ledHandler.clear(); clearLeds();
} }
} }
@ -463,9 +469,22 @@ void setupHardware()
Serial.println(F("Error loading WebUI")); Serial.println(F("Error loading WebUI"));
} }
// Initialize LED handler // {
auto& ledHandler = getLedHandler(); // File f = LittleFS.open("/qr.txt", "w");
ledHandler.setup();
// 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();
WiFi.setHostname(getMyHostname().c_str()); WiFi.setHostname(getMyHostname().c_str());
if (!psramInit()) if (!psramInit())
@ -523,8 +542,7 @@ void setupHardware()
#endif #endif
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
// Initialize frontlight through LedHandler setupFrontlight();
ledHandler.initializeFrontlight();
Wire.beginTransmission(0x5C); Wire.beginTransmission(0x5C);
byte error = Wire.endTransmission(); byte error = Wire.endTransmission();
@ -546,7 +564,6 @@ void setupHardware()
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
{ {
static bool first_connect = true; static bool first_connect = true;
auto& ledHandler = getLedHandler(); // Get ledHandler reference once at the start
Serial.printf("[WiFi-event] event: %d\n", event); Serial.printf("[WiFi-event] event: %d\n", event);
@ -572,7 +589,7 @@ void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
if (!first_connect) if (!first_connect)
{ {
Serial.println(F("Disconnected from WiFi access point")); Serial.println(F("Disconnected from WiFi access point"));
ledHandler.queueEffect(LED_EFFECT_WIFI_CONNECT_ERROR); queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR);
uint8_t reason = info.wifi_sta_disconnected.reason; uint8_t reason = info.wifi_sta_disconnected.reason;
if (reason) if (reason)
Serial.printf("Disconnect reason: %s, ", Serial.printf("Disconnect reason: %s, ",
@ -588,13 +605,13 @@ void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
Serial.print("Obtained IP address: "); Serial.print("Obtained IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
if (!first_connect) if (!first_connect)
ledHandler.queueEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS); queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS);
first_connect = false; first_connect = false;
break; break;
} }
case ARDUINO_EVENT_WIFI_STA_LOST_IP: case ARDUINO_EVENT_WIFI_STA_LOST_IP:
Serial.println(F("Lost IP address and IP address is reset to 0")); Serial.println(F("Lost IP address and IP address is reset to 0"));
ledHandler.queueEffect(LED_EFFECT_WIFI_CONNECT_ERROR); queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR);
WiFi.reconnect(); WiFi.reconnect();
break; break;
case ARDUINO_EVENT_WIFI_AP_START: case ARDUINO_EVENT_WIFI_AP_START:
@ -644,6 +661,29 @@ uint getLastTimeSync()
} }
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
void setupFrontlight()
{
if (!flArray.begin(PCA9685_MODE1_AUTOINCR | PCA9685_MODE1_ALLCALL, PCA9685_MODE2_TOTEMPOLE))
{
Serial.println(F("FL driver error"));
return;
}
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() float getLightLevel()
{ {

View file

@ -52,10 +52,10 @@ void setupTimers();
void finishSetup(); void finishSetup();
void setupMcp(); void setupMcp();
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
extern BH1750 bh1750; void setupFrontlight();
extern bool hasLuxSensor;
float getLightLevel(); float getLightLevel();
bool hasLightLevel(); bool hasLightLevel();
extern PCA9685 flArray;
#endif #endif
String getMyHostname(); String getMyHostname();
@ -98,10 +98,6 @@ extern MCP23017 mcp1;
extern MCP23017 mcp2; extern MCP23017 mcp2;
#endif #endif
#ifdef HAS_FRONTLIGHT
extern PCA9685 flArray;
#endif
// Expose DataSourceType enum // Expose DataSourceType enum
extern DataSourceType getDataSource(); extern DataSourceType getDataSource();
extern void setDataSource(DataSourceType source); extern void setDataSource(DataSourceType source);

View file

@ -46,8 +46,8 @@
#define DEFAULT_LUX_LIGHT_TOGGLE 128 #define DEFAULT_LUX_LIGHT_TOGGLE 128
#define DEFAULT_FL_OFF_WHEN_DARK true #define DEFAULT_FL_OFF_WHEN_DARK true
#define DEFAULT_FL_ALWAYS_ON true #define DEFAULT_FL_ALWAYS_ON false
#define DEFAULT_FL_FLASH_ON_UPDATE true #define DEFAULT_FL_FLASH_ON_UPDATE false
#define DEFAULT_LED_STATUS false #define DEFAULT_LED_STATUS false
#define DEFAULT_TIMER_ACTIVE true #define DEFAULT_TIMER_ACTIVE true
@ -60,13 +60,11 @@
#define DEFAULT_MINING_POOL_STATS_ENABLED false #define DEFAULT_MINING_POOL_STATS_ENABLED false
#define DEFAULT_MINING_POOL_NAME "ocean" #define DEFAULT_MINING_POOL_NAME "ocean"
#define DEFAULT_MINING_POOL_USER "38Qkkei3SuF1Eo45BaYmRHUneRD54yyTFy" // Random actual Ocean hasher #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_ENABLED false
#define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422" #define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422"
#define DEFAULT_LED_FLASH_ON_ZAP true #define DEFAULT_LED_FLASH_ON_ZAP true
#define DEFAULT_FL_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_ENABLED false
#define DEFAULT_HTTP_AUTH_USERNAME "btclock" #define DEFAULT_HTTP_AUTH_USERNAME "btclock"
@ -95,7 +93,3 @@ enum DataSourceType {
}; };
#define DEFAULT_DATA_SOURCE BTCLOCK_SOURCE #define DEFAULT_DATA_SOURCE BTCLOCK_SOURCE
#ifndef DEFAULT_BOOT_TEXT
#define DEFAULT_BOOT_TEXT "BTCLOCK"
#endif

File diff suppressed because it is too large Load diff

View file

@ -3,14 +3,12 @@
#include <Fonts/FreeSans9pt7b.h> #include <Fonts/FreeSans9pt7b.h>
#include <Fonts/FreeSansBold9pt7b.h> #include <Fonts/FreeSansBold9pt7b.h>
#include <GxEPD2_BW.h> #include <GxEPD2_BW.h>
#include "gzip_decompressor.hpp"
#include <mcp23x17_pin.hpp> #include <mcp23x17_pin.hpp>
#include <mutex> #include <mutex>
#include <native_pin.hpp> #include <native_pin.hpp>
#include <regex> #include <regex>
#include <array>
#include <memory>
#include "fonts/fonts.hpp" #include "fonts/fonts.hpp"
#include "lib/config.hpp" #include "lib/config.hpp"
@ -18,118 +16,43 @@
#include "icons/icons.h" #include "icons/icons.h"
#include "mining_pool_stats_fetch.hpp" #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 #ifdef USE_QR
#include "qrcodegen.h" #include "qrcodegen.h"
#endif #endif
// extern TaskHandle_t epdTaskHandle;
struct UpdateDisplayTaskItem { typedef struct {
char dispNum; char dispNum;
}; } UpdateDisplayTaskItem;
struct FontFamily {
GFXfont* big;
GFXfont* medium;
GFXfont* small;
};
class EPDManager {
public:
static EPDManager& getInstance();
// Delete copy constructor and assignment operator
EPDManager(const EPDManager&) = delete;
EPDManager& operator=(const EPDManager&) = delete;
void initialize();
void forceFullRefresh(); void forceFullRefresh();
void loadFonts(const String& fontName); void setupDisplays();
void setContent(const std::array<String, NUM_SCREENS>& newContent, bool forceUpdate = false);
void setContent(const std::array<std::string, NUM_SCREENS>& newContent);
std::array<String, NUM_SCREENS> getCurrentContent() const;
int getBackgroundColor() const { return bgColor; } void splitText(const uint dispNum, const String &top, const String &bottom,
int getForegroundColor() const { return fgColor; } bool partial);
void setBackgroundColor(int color) { bgColor = color; }
void setForegroundColor(int color) { fgColor = color; } 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);
extern "C" void updateDisplay(void *pvParameters) noexcept;
void updateDisplayAlt(int epdIndex);
void prepareDisplayUpdateTask(void *pvParameters);
int getBgColor();
int getFgColor();
void setBgColor(int color);
void setFgColor(int color);
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);
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent,
bool forceUpdate);
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent);
void setEpdContent(std::array<std::string, NUM_SCREENS> newEpdContent);
std::array<String, NUM_SCREENS> getCurrentEpdContent();
void waitUntilNoneBusy(); void waitUntilNoneBusy();
private:
EPDManager(); // Private constructor for singleton
~EPDManager(); // Private destructor
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);
static void updateDisplayTask(void* pvParameters) noexcept;
static void prepareDisplayUpdateTask(void* pvParameters);
// Member variables
std::array<String, NUM_SCREENS> currentContent;
std::array<String, NUM_SCREENS> content;
std::array<uint32_t, NUM_SCREENS> lastFullRefresh;
std::array<TaskHandle_t, NUM_SCREENS> 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<std::mutex, NUM_SCREENS> displayMutexes;
// Pin configurations based on board version
#ifdef IS_BTCLOCK_REV_B
static Native_Pin EPD_DC;
static std::array<Native_Pin, NUM_SCREENS> EPD_CS;
static std::array<Native_Pin, NUM_SCREENS> EPD_BUSY;
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
#elif defined(IS_BTCLOCK_V8)
static Native_Pin EPD_DC;
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_BUSY;
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_CS;
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
#else
static Native_Pin EPD_DC;
static std::array<Native_Pin, NUM_SCREENS> EPD_CS;
static std::array<Native_Pin, NUM_SCREENS> EPD_BUSY;
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
#endif
// Display array
std::array<GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT>, 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
;
};

View file

@ -1,49 +0,0 @@
#pragma once
#include "rom/miniz.h"
#include <Arduino.h>
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;
}
};

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,6 @@
#include <Arduino.h> #include <Arduino.h>
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
#include <memory>
#include "lib/shared.hpp" #include "lib/shared.hpp"
#include "lib/webserver.hpp" #include "lib/webserver.hpp"
@ -16,80 +15,53 @@
#define NEOPIXEL_COUNT 4 #define NEOPIXEL_COUNT 4
#endif #endif
// LED effect constants
const int LED_FLASH_ERROR = 0; const int LED_FLASH_ERROR = 0;
const int LED_FLASH_SUCCESS = 1; const int LED_FLASH_SUCCESS = 1;
const int LED_FLASH_UPDATE = 2; const int LED_FLASH_UPDATE = 2;
const int LED_EFFECT_CONFIGURING = 10; const int LED_FLASH_BLOCK_NOTIFY = 3;
const int LED_FLASH_BLOCK_NOTIFY = 4; const int LED_EFFECT_START_TIMER = 4;
const int LED_EFFECT_START_TIMER = 5; const int LED_EFFECT_PAUSE_TIMER = 5;
const int LED_EFFECT_PAUSE_TIMER = 6; const int LED_EFFECT_HEARTBEAT = 6;
const int LED_EFFECT_HEARTBEAT = 7;
const int LED_EFFECT_WIFI_WAIT_FOR_CONFIG = 100; const int LED_EFFECT_WIFI_WAIT_FOR_CONFIG = 100;
const int LED_EFFECT_WIFI_CONNECTING = 101; const int LED_EFFECT_WIFI_CONNECTING = 101;
const int LED_EFFECT_WIFI_CONNECT_ERROR = 102; const int LED_EFFECT_WIFI_CONNECT_ERROR = 102;
const int LED_EFFECT_WIFI_CONNECT_SUCCESS = 103; const int LED_EFFECT_WIFI_CONNECT_SUCCESS = 103;
const int LED_EFFECT_WIFI_ERASE_SETTINGS = 104; const int LED_EFFECT_WIFI_ERASE_SETTINGS = 104;
const int LED_PROGRESS_25 = 200; const int LED_PROGRESS_25 = 200;
const int LED_PROGRESS_50 = 201; const int LED_PROGRESS_50 = 201;
const int LED_PROGRESS_75 = 202; const int LED_PROGRESS_75 = 202;
const int LED_PROGRESS_100 = 203; const int LED_PROGRESS_100 = 203;
const int LED_DATA_PRICE_ERROR = 300; const int LED_DATA_PRICE_ERROR = 300;
const int LED_DATA_BLOCK_ERROR = 301; const int LED_DATA_BLOCK_ERROR = 301;
const int LED_EFFECT_NOSTR_ZAP = 400; const int LED_EFFECT_NOSTR_ZAP = 400;
const int LED_FLASH_IDENTIFY = 990; const int LED_FLASH_IDENTIFY = 990;
const int LED_POWER_TEST = 999; const int LED_POWER_TEST = 999;
extern TaskHandle_t ledTaskHandle;
extern Adafruit_NeoPixel pixels;
// Do Not Disturb mode settings void ledTask(void *pvParameters);
struct DNDTimeRange { void setupLeds();
uint8_t startHour; void setupLedTask();
uint8_t startMinute;
uint8_t endHour;
uint8_t endMinute;
};
class LedHandler {
public:
static LedHandler& getInstance();
// Delete copy constructor and assignment operator
LedHandler(const LedHandler&) = delete;
LedHandler& operator=(const LedHandler&) = delete;
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 blinkDelay(int d, int times);
void blinkDelayColor(int d, int times, uint r, uint g, uint b); 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 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 #ifdef HAS_FRONTLIGHT
void frontlightFlash(int flDelayTime); void frontlightFlash(int flDelayTime);
@ -97,39 +69,17 @@ public:
void frontlightFadeOutAll(); void frontlightFadeOutAll();
void frontlightFadeIn(uint num); void frontlightFadeIn(uint num);
void frontlightFadeOut(uint num); void frontlightFadeOut(uint num);
std::vector<uint16_t> frontlightGetStatus(); std::vector<uint16_t> frontlightGetStatus();
void frontlightSetBrightness(uint brightness); void frontlightSetBrightness(uint brightness);
bool frontlightIsOn() const { return frontlightOn; } bool frontlightIsOn();
void frontlightFadeInAll(int flDelayTime, bool staggered = false);
void frontlightFadeOutAll(int flDelayTime, bool staggered = false); 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 frontlightFadeIn(uint num, int flDelayTime);
void frontlightFadeOut(uint num, int flDelayTime); void frontlightFadeOut(uint num, int flDelayTime);
void initializeFrontlight();
#endif #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();
}

View file

@ -5,7 +5,6 @@ const char* PoolFactory::MINING_POOL_NAME_NODERUNNERS = "noderunners";
const char* PoolFactory::MINING_POOL_NAME_BRAIINS = "braiins"; const char* PoolFactory::MINING_POOL_NAME_BRAIINS = "braiins";
const char* PoolFactory::MINING_POOL_NAME_SATOSHI_RADIO = "satoshi_radio"; 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_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_GOBRRR_POOL = "gobrrr_pool";
const char* PoolFactory::MINING_POOL_NAME_CKPOOL = "ckpool"; const char* PoolFactory::MINING_POOL_NAME_CKPOOL = "ckpool";
const char* PoolFactory::MINING_POOL_NAME_EU_CKPOOL = "eu_ckpool"; const char* PoolFactory::MINING_POOL_NAME_EU_CKPOOL = "eu_ckpool";
@ -18,7 +17,6 @@ std::unique_ptr<MiningPoolInterface> PoolFactory::createPool(const std::string&
{MINING_POOL_NAME_BRAIINS, []() { return std::make_unique<BraiinsPool>(); }}, {MINING_POOL_NAME_BRAIINS, []() { return std::make_unique<BraiinsPool>(); }},
{MINING_POOL_NAME_SATOSHI_RADIO, []() { return std::make_unique<SatoshiRadioPool>(); }}, {MINING_POOL_NAME_SATOSHI_RADIO, []() { return std::make_unique<SatoshiRadioPool>(); }},
{MINING_POOL_NAME_PUBLIC_POOL, []() { return std::make_unique<PublicPool>(); }}, {MINING_POOL_NAME_PUBLIC_POOL, []() { return std::make_unique<PublicPool>(); }},
{MINING_POOL_NAME_LOCAL_PUBLIC_POOL, []() { return std::make_unique<LocalPublicPool>(); }},
{MINING_POOL_NAME_GOBRRR_POOL, []() { return std::make_unique<GoBrrrPool>(); }}, {MINING_POOL_NAME_GOBRRR_POOL, []() { return std::make_unique<GoBrrrPool>(); }},
{MINING_POOL_NAME_CKPOOL, []() { return std::make_unique<CKPool>(); }}, {MINING_POOL_NAME_CKPOOL, []() { return std::make_unique<CKPool>(); }},
{MINING_POOL_NAME_EU_CKPOOL, []() { return std::make_unique<EUCKPool>(); }} {MINING_POOL_NAME_EU_CKPOOL, []() { return std::make_unique<EUCKPool>(); }}

View file

@ -10,7 +10,6 @@
#include "ocean/ocean_pool.hpp" #include "ocean/ocean_pool.hpp"
#include "satoshi_radio/satoshi_radio_pool.hpp" #include "satoshi_radio/satoshi_radio_pool.hpp"
#include "public_pool/public_pool.hpp" #include "public_pool/public_pool.hpp"
#include "public_pool/local_public_pool.hpp"
#include "gobrrr_pool/gobrrr_pool.hpp" #include "gobrrr_pool/gobrrr_pool.hpp"
#include "ckpool/ckpool.hpp" #include "ckpool/ckpool.hpp"
#include "ckpool/eu_ckpool.hpp" #include "ckpool/eu_ckpool.hpp"
@ -29,7 +28,6 @@ class PoolFactory {
MINING_POOL_NAME_SATOSHI_RADIO, MINING_POOL_NAME_SATOSHI_RADIO,
MINING_POOL_NAME_BRAIINS, MINING_POOL_NAME_BRAIINS,
MINING_POOL_NAME_PUBLIC_POOL, MINING_POOL_NAME_PUBLIC_POOL,
MINING_POOL_NAME_LOCAL_PUBLIC_POOL,
MINING_POOL_NAME_GOBRRR_POOL, MINING_POOL_NAME_GOBRRR_POOL,
MINING_POOL_NAME_CKPOOL, MINING_POOL_NAME_CKPOOL,
MINING_POOL_NAME_EU_CKPOOL MINING_POOL_NAME_EU_CKPOOL
@ -57,7 +55,6 @@ class PoolFactory {
static const char* MINING_POOL_NAME_BRAIINS; static const char* MINING_POOL_NAME_BRAIINS;
static const char* MINING_POOL_NAME_SATOSHI_RADIO; static const char* MINING_POOL_NAME_SATOSHI_RADIO;
static const char* MINING_POOL_NAME_PUBLIC_POOL; 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_GOBRRR_POOL;
static const char* MINING_POOL_NAME_CKPOOL; static const char* MINING_POOL_NAME_CKPOOL;
static const char* MINING_POOL_NAME_EU_CKPOOL; static const char* MINING_POOL_NAME_EU_CKPOOL;

View file

@ -1,11 +0,0 @@
#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;
}

View file

@ -1,11 +0,0 @@
#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;
};

View file

@ -1,98 +1,95 @@
#include "mining_pool_stats_fetch.hpp" #include "mining_pool_stats_fetch.hpp"
void MiningPoolStatsFetch::taskWrapper(void* pvParameters) { TaskHandle_t miningPoolStatsFetchTaskHandle;
MiningPoolStatsFetch::getInstance().task();
std::string miningPoolName;
std::string miningPoolStatsHashrate;
int miningPoolStatsDailyEarnings;
std::string getMiningPoolStatsHashRate()
{
return miningPoolStatsHashrate;
} }
void MiningPoolStatsFetch::downloadLogoTaskWrapper(void* pvParameters) { int getMiningPoolStatsDailyEarnings()
MiningPoolStatsFetch::getInstance().downloadLogoTask(); {
return miningPoolStatsDailyEarnings;
} }
std::string MiningPoolStatsFetch::getHashRate() const { void taskMiningPoolStatsFetch(void *pvParameters)
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(); std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str();
currentPool = PoolFactory::createPool(poolName); auto poolInterface = 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 = getPool();
if (!poolInterface) return;
std::string poolUser = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str(); std::string poolUser = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str();
// Main stats fetching loop // Main stats fetching loop
for (;;) { for (;;)
{
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
HTTPClient http; HTTPClient http;
http.setUserAgent(USER_AGENT); http.setUserAgent(USER_AGENT);
poolInterface->setPoolUser(poolUser); poolInterface->setPoolUser(poolUser);
std::string apiUrl = poolInterface->getApiUrl(); std::string apiUrl = poolInterface->getApiUrl();
http.begin(apiUrl.c_str()); http.begin(apiUrl.c_str());
if (debugLogEnabled()) { if (debugLogEnabled())
{
Serial.printf("Fetching mining pool stats from %s\r\n", apiUrl.c_str()); Serial.printf("Fetching mining pool stats from %s\r\n", apiUrl.c_str());
} }
poolInterface->prepareRequest(http); poolInterface->prepareRequest(http);
int httpCode = http.GET(); int httpCode = http.GET();
if (httpCode == 200) { if (httpCode == 200)
{
String payload = http.getString(); String payload = http.getString();
JsonDocument doc; JsonDocument doc;
deserializeJson(doc, payload); deserializeJson(doc, payload);
if (debugLogEnabled()) { if (debugLogEnabled())
{
Serial.printf("Mining pool stats response: %s\r\n", payload.c_str()); Serial.printf("Mining pool stats response: %s\r\n", payload.c_str());
} }
PoolStats stats = poolInterface->parseResponse(doc); PoolStats stats = poolInterface->parseResponse(doc);
hashrate = stats.hashrate;
if (debugLogEnabled()) { miningPoolStatsHashrate = stats.hashrate;
if (debugLogEnabled())
{
Serial.printf("Mining pool stats parsed hashrate: %s\r\n", stats.hashrate.c_str()); Serial.printf("Mining pool stats parsed hashrate: %s\r\n", stats.hashrate.c_str());
} }
dailyEarnings = stats.dailyEarnings ? *stats.dailyEarnings : 0; if (stats.dailyEarnings)
{
miningPoolStatsDailyEarnings = *stats.dailyEarnings;
}
else
{
miningPoolStatsDailyEarnings = 0; // or any other default value
}
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS))
ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS)) { {
WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0}; WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); 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); Serial.println(httpCode);
} }
} }
} }
void MiningPoolStatsFetch::downloadLogoTask() { void downloadMiningPoolLogoTask(void *pvParameters) {
std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str();
auto* poolInterface = getPool(); auto poolInterface = PoolFactory::createPool(poolName);
if (!poolInterface) return; PoolFactory::downloadPoolLogo(poolName, poolInterface.get());
PoolFactory::downloadPoolLogo(poolName, poolInterface);
// If we're on the mining pool stats screen, trigger a display update // If we're on the mining pool stats screen, trigger a display update
if (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) { if (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) {
@ -100,22 +97,41 @@ void MiningPoolStatsFetch::downloadLogoTask() {
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
} }
xTaskNotifyGive(taskHandle); xTaskNotifyGive(miningPoolStatsFetchTaskHandle);
vTaskDelete(NULL); vTaskDelete(NULL);
} }
void MiningPoolStatsFetch::setup() { void setupMiningPoolStatsFetchTask()
xTaskCreate(downloadLogoTaskWrapper, {
xTaskCreate(downloadMiningPoolLogoTask,
"logoDownload", "logoDownload",
(6 * 1024), (6 * 1024),
NULL, NULL,
tskIDLE_PRIORITY, tskIDLE_PRIORITY,
NULL); NULL);
xTaskCreate(taskWrapper, xTaskCreate(taskMiningPoolStatsFetch,
"miningPoolStatsFetch", "miningPoolStatsFetch",
(6 * 1024), (6 * 1024),
NULL, NULL,
tskIDLE_PRIORITY, tskIDLE_PRIORITY,
&taskHandle); &miningPoolStatsFetchTaskHandle);
}
std::unique_ptr<MiningPoolInterface>& getMiningPool()
{
static std::unique_ptr<MiningPoolInterface> 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;
} }

View file

@ -2,44 +2,18 @@
#include <Arduino.h> #include <Arduino.h>
#include <HTTPClient.h> #include <HTTPClient.h>
#include <utils.hpp> #include "mining_pool/pool_factory.hpp"
#include <memory>
#include "lib/config.hpp" #include "lib/config.hpp"
#include "lib/shared.hpp" #include "lib/shared.hpp"
#include "lib/mining_pool/mining_pool_interface.hpp"
#include "mining_pool/pool_factory.hpp"
class MiningPoolStatsFetch { extern TaskHandle_t miningPoolStatsFetchTaskHandle;
public:
static MiningPoolStatsFetch& getInstance() {
static MiningPoolStatsFetch instance;
return instance;
}
void setup(); void setupMiningPoolStatsFetchTask();
std::string getHashRate() const; void taskMiningPoolStatsFetch(void *pvParameters);
int getDailyEarnings() const;
TaskHandle_t getTaskHandle() const { return taskHandle; }
static void taskWrapper(void* pvParameters);
static void downloadLogoTaskWrapper(void* pvParameters);
// Pool interface methods std::string getMiningPoolStatsHashRate();
MiningPoolInterface* getPool(); int getMiningPoolStatsDailyEarnings();
const MiningPoolInterface* getPool() const;
LogoData getLogo() const;
private: std::unique_ptr<MiningPoolInterface>& getMiningPool();
MiningPoolStatsFetch() = default; LogoData getMiningPoolLogo();
~MiningPoolStatsFetch() = default;
MiningPoolStatsFetch(const MiningPoolStatsFetch&) = delete;
MiningPoolStatsFetch& operator=(const MiningPoolStatsFetch&) = delete;
void task();
void downloadLogoTask();
TaskHandle_t taskHandle = nullptr;
std::string hashrate;
int dailyEarnings = 0;
std::unique_ptr<MiningPoolInterface> currentPool;
};

View file

@ -1,5 +1,4 @@
#include "nostr_notify.hpp" #include "nostr_notify.hpp"
#include "led_handler.hpp"
std::vector<nostr::NostrPool *> pools; std::vector<nostr::NostrPool *> pools;
nostr::Transport *transport; nostr::Transport *transport;
@ -41,7 +40,7 @@ void setupNostrNotify(bool asDatasource, bool zapNotify)
{relay}, {relay},
{// First filter {// First filter
{ {
{"kinds", {"12203"}}, {"kinds", {"1"}},
{"since", {String(getMinutesAgo(60))}}, {"since", {String(getMinutesAgo(60))}},
{"authors", {pubKey}}, {"authors", {pubKey}},
}}, }},
@ -79,9 +78,8 @@ void nostrTask(void *pvParameters)
{ {
DataSourceType dataSource = getDataSource(); DataSourceType dataSource = getDataSource();
if(dataSource == NOSTR_SOURCE) { if(dataSource == NOSTR_SOURCE) {
auto& blockNotify = BlockNotify::getInstance(); int blockFetch = getBlockFetch();
int blockFetch = blockNotify.fetchLatestBlock(); processNewBlock(blockFetch);
blockNotify.processNewBlock(blockFetch);
} }
while (1) while (1)
@ -146,7 +144,6 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even
// Use direct value access instead of multiple comparisons // Use direct value access instead of multiple comparisons
String typeValue; String typeValue;
uint medianFee = 0; uint medianFee = 0;
uint blockHeight = 0;
for (JsonArray tag : tags) { for (JsonArray tag : tags) {
if (tag.size() != 2) continue; if (tag.size() != 2) continue;
@ -167,11 +164,6 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even
medianFee = tag[1].as<uint>(); medianFee = tag[1].as<uint>();
} }
break; break;
case 'b': // blockHeight
if (strcmp(key, "block") == 0) {
blockHeight = tag[1].as<uint>();
}
break;
} }
} }
@ -179,19 +171,13 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even
if (!typeValue.isEmpty()) { if (!typeValue.isEmpty()) {
if (typeValue == "priceUsd") { if (typeValue == "priceUsd") {
processNewPrice(obj["content"].as<uint>(), CURRENCY_USD); processNewPrice(obj["content"].as<uint>(), CURRENCY_USD);
if (blockHeight != 0) {
auto& blockNotify = BlockNotify::getInstance();
blockNotify.processNewBlock(blockHeight);
}
} }
else if (typeValue == "blockHeight") { else if (typeValue == "blockHeight") {
auto& blockNotify = BlockNotify::getInstance(); processNewBlock(obj["content"].as<uint>());
blockNotify.processNewBlock(obj["content"].as<uint>());
} }
if (medianFee != 0) { if (medianFee != 0) {
auto& blockNotify = BlockNotify::getInstance(); processNewBlockFee(medianFee);
blockNotify.processNewBlockFee(medianFee);
} }
} }
} }
@ -296,11 +282,11 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event)
} }
ScreenHandler::setCurrentScreen(SCREEN_CUSTOM); ScreenHandler::setCurrentScreen(SCREEN_CUSTOM);
EPDManager::getInstance().setContent(textEpdContent); setEpdContent(textEpdContent);
vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250)); vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250));
if (preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP)) if (preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP))
{ {
getLedHandler().queueEffect(LED_EFFECT_NOSTR_ZAP); queueLedEffect(LED_EFFECT_NOSTR_ZAP);
} }
if (timerPeriod > 0) if (timerPeriod > 0)
{ {
@ -308,19 +294,3 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event)
timerPeriod * usPerSecond); timerPeriod * usPerSecond);
} }
} }
// 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<std::string, NUM_SCREENS> zapContent = parseZapNotify(amount, true);
// EPDManager::getInstance().setContent(zapContent);
// if (preferences.getBool("ledFlashOnUpd", DEFAULT_LED_FLASH_ON_UPD)) {
// getLedHandler().queueEffect(LED_FLASH_BLOCK_NOTIFY);
// }
// }
// }
// }

View file

@ -1,5 +1,4 @@
#include "ota.hpp" #include "ota.hpp"
#include "led_handler.hpp"
TaskHandle_t taskOtaHandle = NULL; TaskHandle_t taskOtaHandle = NULL;
bool isOtaUpdating = false; bool isOtaUpdating = false;
@ -32,9 +31,6 @@ void setupOTA()
void onOTAProgress(unsigned int progress, unsigned int total) void onOTAProgress(unsigned int progress, unsigned int total)
{ {
uint percentage = progress / (total / 100); uint percentage = progress / (total / 100);
auto& ledHandler = getLedHandler();
auto& pixels = ledHandler.getPixels();
pixels.fill(pixels.Color(0, 255, 0)); pixels.fill(pixels.Color(0, 255, 0));
if (percentage < 100) if (percentage < 100)
{ {
@ -57,10 +53,10 @@ void onOTAProgress(unsigned int progress, unsigned int total)
void onOTAStart() void onOTAStart()
{ {
EPDManager::getInstance().forceFullRefresh(); forceFullRefresh();
std::array<String, NUM_SCREENS> epdContent = {"U", "P", "D", "A", std::array<String, NUM_SCREENS> epdContent = {"U", "P", "D", "A",
"T", "E", "!"}; "T", "E", "!"};
EPDManager::getInstance().setContent(epdContent); setEpdContent(epdContent);
// Stop all timers // Stop all timers
esp_timer_stop(screenRotateTimer); esp_timer_stop(screenRotateTimer);
esp_timer_stop(minuteTimer); esp_timer_stop(minuteTimer);
@ -74,8 +70,8 @@ void onOTAStart()
ButtonHandler::suspendTask(); ButtonHandler::suspendTask();
// stopWebServer(); // stopWebServer();
auto& blockNotify = BlockNotify::getInstance(); stopBlockNotify();
blockNotify.stop(); stopPriceNotify();
} }
void handleOTATask(void *parameter) void handleOTATask(void *parameter)
@ -88,15 +84,15 @@ void handleOTATask(void *parameter)
{ {
if (msg.updateType == UPDATE_ALL) { if (msg.updateType == UPDATE_ALL) {
isOtaUpdating = true; isOtaUpdating = true;
getLedHandler().queueEffect(LED_FLASH_UPDATE); queueLedEffect(LED_FLASH_UPDATE);
int resultWebUi = downloadUpdateHandler(UPDATE_WEBUI); int resultWebUi = downloadUpdateHandler(UPDATE_WEBUI);
getLedHandler().queueEffect(LED_FLASH_UPDATE); queueLedEffect(LED_FLASH_UPDATE);
int resultFw = downloadUpdateHandler(UPDATE_FIRMWARE); int resultFw = downloadUpdateHandler(UPDATE_FIRMWARE);
if (resultWebUi == 0 && resultFw == 0) { if (resultWebUi == 0 && resultFw == 0) {
ESP.restart(); ESP.restart();
} else { } else {
getLedHandler().queueEffect(LED_FLASH_ERROR); queueLedEffect(LED_FLASH_ERROR);
vTaskDelay(pdMS_TO_TICKS(3000)); vTaskDelay(pdMS_TO_TICKS(3000));
ESP.restart(); ESP.restart();
} }

View file

@ -2,64 +2,103 @@
const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin"; const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin";
WebSocketsClient webSocket; // WebsocketsClient client;
esp_websocket_client_handle_t clientPrice = NULL;
esp_websocket_client_config_t config;
uint currentPrice = 90000; uint currentPrice = 90000;
unsigned long int lastPriceUpdate; unsigned long int lastPriceUpdate;
bool priceNotifyInit = false; bool priceNotifyInit = false;
std::map<char, std::uint64_t> currencyMap; std::map<char, std::uint64_t> currencyMap;
std::map<char, unsigned long int> lastUpdateMap; std::map<char, unsigned long int> lastUpdateMap;
TaskHandle_t priceNotifyTaskHandle; WebSocketsClient priceNotifyWs;
void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length);
void setupPriceNotify() void setupPriceNotify()
{ {
webSocket.beginSSL("ws.coincap.io", 443, "/prices?assets=bitcoin"); config = {.uri = wsServerPrice,
webSocket.onEvent([](WStype_t type, uint8_t * payload, size_t length) { .user_agent = USER_AGENT};
onWebsocketPriceEvent(type, payload, length); config.cert_pem = isrg_root_x1cert;
});
webSocket.setReconnectInterval(5000);
webSocket.enableHeartbeat(15000, 3000, 2);
setupPriceNotifyTask(); 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) { // void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length) {
case WStype_DISCONNECTED: // switch(type) {
Serial.println(F("Price WS Connection Closed")); // case WStype_DISCONNECTED:
break; // Serial.printf("[WSc] Disconnected!\n");
case WStype_CONNECTED: // 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)
{ {
Serial.println("Connected to " + String(wsServerPrice)); 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; 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; break;
} }
case WStype_TEXT: }
void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data)
{ {
JsonDocument doc; JsonDocument doc;
deserializeJson(doc, (char *)payload);
if (doc["bitcoin"].is<JsonObject>()) deserializeJson(doc, (char *)event_data->data_ptr);
if (doc.containsKey("bitcoin"))
{ {
if (currentPrice != doc["bitcoin"].as<long>()) if (currentPrice != doc["bitcoin"].as<long>())
{ {
processNewPrice(doc["bitcoin"].as<long>(), CURRENCY_USD); processNewPrice(doc["bitcoin"].as<long>(), 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) void processNewPrice(uint newPrice, char currency)
@ -71,17 +110,15 @@ void processNewPrice(uint newPrice, char currency)
if (lastUpdateMap.find(currency) == lastUpdateMap.end() || if (lastUpdateMap.find(currency) == lastUpdateMap.end() ||
(currentTime - lastUpdateMap[currency]) > minSecPriceUpd) (currentTime - lastUpdateMap[currency]) > minSecPriceUpd)
{ {
// const unsigned long oldPrice = currentPrice;
currencyMap[currency] = newPrice; currencyMap[currency] = newPrice;
if (currency == CURRENCY_USD && ( lastUpdateMap[currency] == 0 ||
// Store price in preferences if enough time has passed (currentTime - lastUpdateMap[currency]) > 120))
if (lastUpdateMap[currency] == 0 || (currentTime - lastUpdateMap[currency]) > 120)
{ {
String prefKey = String("lastPrice_") + getCurrencyCode(currency).c_str(); preferences.putUInt("lastPrice", currentPrice);
preferences.putUInt(prefKey.c_str(), newPrice);
} }
lastUpdateMap[currency] = currentTime; lastUpdateMap[currency] = currentTime;
// if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) {
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BTC_TICKER || if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BTC_TICKER ||
ScreenHandler::getCurrentScreen() == SCREEN_SATS_PER_CURRENCY || ScreenHandler::getCurrentScreen() == SCREEN_SATS_PER_CURRENCY ||
ScreenHandler::getCurrentScreen() == SCREEN_MARKET_CAP)) ScreenHandler::getCurrentScreen() == SCREEN_MARKET_CAP))
@ -89,24 +126,7 @@ void processNewPrice(uint newPrice, char currency)
WorkItem priceUpdate = {TASK_PRICE_UPDATE, currency}; WorkItem priceUpdate = {TASK_PRICE_UPDATE, currency};
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
} }
} //}
}
void loadStoredPrices()
{
// Load prices for all supported currencies
std::vector<std::string> currencies = getAvailableCurrencies();
for (const std::string &currency : 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;
}
} }
} }
@ -136,7 +156,9 @@ void setPrice(uint newPrice, char currency)
bool isPriceNotifyConnected() bool isPriceNotifyConnected()
{ {
return webSocket.isConnected(); if (clientPrice == NULL)
return false;
return esp_websocket_client_is_connected(clientPrice);
} }
bool getPriceNotifyInit() bool getPriceNotifyInit()
@ -146,30 +168,24 @@ bool getPriceNotifyInit()
void stopPriceNotify() void stopPriceNotify()
{ {
webSocket.disconnect(); if (clientPrice == NULL)
if (priceNotifyTaskHandle != NULL) { return;
vTaskDelete(priceNotifyTaskHandle); esp_websocket_client_close(clientPrice, pdMS_TO_TICKS(5000));
priceNotifyTaskHandle = NULL; esp_websocket_client_stop(clientPrice);
} esp_websocket_client_destroy(clientPrice);
clientPrice = NULL;
} }
void restartPriceNotify() void restartPriceNotify()
{ {
stopPriceNotify(); stopPriceNotify();
if (clientPrice == NULL)
{
setupPriceNotify(); setupPriceNotify();
return;
} }
// esp_websocket_client_close(clientPrice, pdMS_TO_TICKS(5000));
void taskPriceNotify(void *pvParameters) // esp_websocket_client_stop(clientPrice);
{ // esp_websocket_client_start(clientPrice);
for (;;)
{
webSocket.loop();
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
void setupPriceNotifyTask()
{
xTaskCreate(taskPriceNotify, "priceNotify", (6 * 1024), NULL, tskIDLE_PRIORITY,
&priceNotifyTaskHandle);
} }

View file

@ -2,22 +2,24 @@
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <WebSocketsClient.h> #include <esp_websocket_client.h>
#include "block_notify.hpp"
#include <string> #include <string>
#include "lib/screen_handler.hpp" #include "lib/screen_handler.hpp"
extern TaskHandle_t priceNotifyTaskHandle;
void setupPriceNotify(); void setupPriceNotify();
void setupPriceNotifyTask();
void taskPriceNotify(void *pvParameters);
void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length); 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); uint getPrice(char currency);
void setPrice(uint newPrice, char currency); void setPrice(uint newPrice, char currency);
//void processNewPrice(uint newPrice);
void processNewPrice(uint newPrice, char currency); void processNewPrice(uint newPrice, char currency);
bool isPriceNotifyConnected(); bool isPriceNotifyConnected();
@ -26,4 +28,3 @@ void restartPriceNotify();
bool getPriceNotifyInit(); bool getPriceNotifyInit();
uint getLastPriceUpdate(char currency); uint getLastPriceUpdate(char currency);
void loadStoredPrices();

View file

@ -108,7 +108,6 @@ bool ScreenHandler::handleCurrencyRotation(bool forward) {
setCurrentScreen(getCurrentScreen()); setCurrentScreen(getCurrentScreen());
return true; return true;
} }
// If we're at the last/first currency of current screen, let nextScreen/previousScreen handle it
return false; return false;
} }
return false; return false;
@ -144,38 +143,14 @@ int ScreenHandler::findNextVisibleScreen(int currentScreen, bool forward) {
void ScreenHandler::nextScreen() { void ScreenHandler::nextScreen() {
if (handleCurrencyRotation(true)) return; if (handleCurrencyRotation(true)) return;
int currentIndex = findScreenIndexByValue(getCurrentScreen()); int currentIndex = findScreenIndexByValue(getCurrentScreen());
int nextScreen = findNextVisibleScreen(currentIndex, true); setCurrentScreen(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<std::string> ac = getActiveCurrencies();
if (!ac.empty()) {
setCurrentCurrency(getCurrencyChar(ac.front()));
}
}
setCurrentScreen(nextScreen);
} }
void ScreenHandler::previousScreen() { void ScreenHandler::previousScreen() {
if (handleCurrencyRotation(false)) return; if (handleCurrencyRotation(false)) return;
int currentIndex = findScreenIndexByValue(getCurrentScreen()); int currentIndex = findScreenIndexByValue(getCurrentScreen());
int prevScreen = findNextVisibleScreen(currentIndex, false); setCurrentScreen(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<std::string> ac = getActiveCurrencies();
if (!ac.empty()) {
setCurrentCurrency(getCurrencyChar(ac.back()));
}
}
setCurrentScreen(prevScreen);
} }
void ScreenHandler::showSystemStatusScreen() { void ScreenHandler::showSystemStatusScreen() {
@ -203,7 +178,7 @@ void ScreenHandler::showSystemStatusScreen() {
String((int)round(ESP.getFreeHeap() / 1024)) + "/" + String((int)round(ESP.getFreeHeap() / 1024)) + "/" +
(int)round(ESP.getHeapSize() / 1024); (int)round(ESP.getHeapSize() / 1024);
setCurrentScreen(SCREEN_CUSTOM); setCurrentScreen(SCREEN_CUSTOM);
EPDManager::getInstance().setContent(sysStatusEpdContent); setEpdContent(sysStatusEpdContent);
} }
// Keep these as free functions // Keep these as free functions
@ -220,9 +195,9 @@ void workerTask(void *pvParameters) {
currentScreenValue != SCREEN_BITAXE_BESTDIFF) break; currentScreenValue != SCREEN_BITAXE_BESTDIFF) break;
taskEpdContent = (currentScreenValue == SCREEN_BITAXE_HASHRATE) ? taskEpdContent = (currentScreenValue == SCREEN_BITAXE_HASHRATE) ?
parseBitaxeHashRate(BitAxeFetch::getInstance().getHashRate()) : parseBitaxeHashRate(getBitAxeHashRate()) :
parseBitaxeBestDiff(BitAxeFetch::getInstance().getBestDiff()); parseBitaxeBestDiff(getBitaxeBestDiff());
EPDManager::getInstance().setContent(taskEpdContent); setEpdContent(taskEpdContent);
break; break;
} }
@ -231,11 +206,10 @@ void workerTask(void *pvParameters) {
currentScreenValue != SCREEN_MINING_POOL_STATS_EARNINGS) break; currentScreenValue != SCREEN_MINING_POOL_STATS_EARNINGS) break;
taskEpdContent = (currentScreenValue == SCREEN_MINING_POOL_STATS_HASHRATE) ? taskEpdContent = (currentScreenValue == SCREEN_MINING_POOL_STATS_HASHRATE) ?
parseMiningPoolStatsHashRate(MiningPoolStatsFetch::getInstance().getHashRate(), *MiningPoolStatsFetch::getInstance().getPool()) : parseMiningPoolStatsHashRate(getMiningPoolStatsHashRate(), *getMiningPool()) :
parseMiningPoolStatsDailyEarnings(MiningPoolStatsFetch::getInstance().getDailyEarnings(), parseMiningPoolStatsDailyEarnings(getMiningPoolStatsDailyEarnings(),
MiningPoolStatsFetch::getInstance().getPool()->getDailyEarningsLabel(), getMiningPool()->getDailyEarningsLabel(), *getMiningPool());
*MiningPoolStatsFetch::getInstance().getPool()); setEpdContent(taskEpdContent);
EPDManager::getInstance().setContent(taskEpdContent);
break; break;
} }
@ -251,33 +225,31 @@ void workerTask(void *pvParameters) {
} else if (currentScreenValue == SCREEN_SATS_PER_CURRENCY) { } else if (currentScreenValue == SCREEN_SATS_PER_CURRENCY) {
taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL));
} else { } else {
auto& blockNotify = BlockNotify::getInstance(); taskEpdContent =
taskEpdContent = parseMarketCap(blockNotify.getBlockHeight(), price, currency, preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR)); parseMarketCap(getBlockHeight(), price, currency,
preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR));
} }
EPDManager::getInstance().setContent(taskEpdContent); setEpdContent(taskEpdContent);
break; break;
} }
case TASK_FEE_UPDATE: { case TASK_FEE_UPDATE: {
if (currentScreenValue == SCREEN_BLOCK_FEE_RATE) { if (currentScreenValue == SCREEN_BLOCK_FEE_RATE) {
auto& blockNotify = BlockNotify::getInstance(); taskEpdContent = parseBlockFees(static_cast<std::uint16_t>(getBlockMedianFee()));
taskEpdContent = parseBlockFees(static_cast<std::uint16_t>(blockNotify.getBlockMedianFee())); setEpdContent(taskEpdContent);
EPDManager::getInstance().setContent(taskEpdContent);
} }
break; break;
} }
case TASK_BLOCK_UPDATE: { case TASK_BLOCK_UPDATE: {
if (currentScreenValue != SCREEN_HALVING_COUNTDOWN) { if (currentScreenValue != SCREEN_HALVING_COUNTDOWN) {
auto& blockNotify = BlockNotify::getInstance(); taskEpdContent = parseBlockHeight(getBlockHeight());
taskEpdContent = parseBlockHeight(blockNotify.getBlockHeight());
} else { } else {
auto& blockNotify = BlockNotify::getInstance(); taskEpdContent = parseHalvingCountdown(getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN));
taskEpdContent = parseHalvingCountdown(blockNotify.getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN));
} }
if (currentScreenValue == SCREEN_HALVING_COUNTDOWN || if (currentScreenValue == SCREEN_HALVING_COUNTDOWN ||
currentScreenValue == SCREEN_BLOCK_HEIGHT) { currentScreenValue == SCREEN_BLOCK_HEIGHT) {
EPDManager::getInstance().setContent(taskEpdContent); setEpdContent(taskEpdContent);
} }
break; break;
} }
@ -304,7 +276,7 @@ void workerTask(void *pvParameters) {
for (uint i = 1; i < NUM_SCREENS; i++) { for (uint i = 1; i < NUM_SCREENS; i++) {
taskEpdContent[i] = timeString[i]; taskEpdContent[i] = timeString[i];
} }
EPDManager::getInstance().setContent(taskEpdContent); setEpdContent(taskEpdContent);
} }
break; break;
@ -324,7 +296,6 @@ void taskScreenRotate(void *pvParameters) {
void setupTasks() { void setupTasks() {
workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem)); workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem));
loadStoredPrices();
xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY, xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY,
&workerTaskHandle); &workerTaskHandle);
@ -332,6 +303,8 @@ void setupTasks() {
xTaskCreate(taskScreenRotate, "rotateScreen", 4096, NULL, tskIDLE_PRIORITY, xTaskCreate(taskScreenRotate, "rotateScreen", 4096, NULL, tskIDLE_PRIORITY,
&taskScreenRotateTaskHandle); &taskScreenRotateTaskHandle);
waitUntilNoneBusy();
if (findScreenIndexByValue(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)) != -1) if (findScreenIndexByValue(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)) != -1)
ScreenHandler::setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)); ScreenHandler::setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN));
} }

View file

@ -40,39 +40,39 @@
// "MrY=\n" // "MrY=\n"
// "-----END CERTIFICATE-----\n"; // "-----END CERTIFICATE-----\n";
// const char* isrg_root_x1cert = R"EOF( const char* isrg_root_x1cert = R"EOF(
// -----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
// MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
// TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
// cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
// WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
// ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
// MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
// h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
// 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
// A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
// T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
// B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
// B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
// KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
// OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
// jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
// qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
// rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
// HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
// hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
// ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
// 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
// NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
// ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
// TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
// jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
// oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
// 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
// mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
// emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
// -----END CERTIFICATE----- -----END CERTIFICATE-----
// )EOF"; )EOF";
#ifdef TEST_SCREENS #ifdef TEST_SCREENS
@ -180,4 +180,3 @@ void HttpHelper::end(HTTPClient* http) {
delete http; delete http;
} }
} }

View file

@ -16,8 +16,6 @@
#include <mutex> #include <mutex>
#include <utils.hpp> #include <utils.hpp>
#include <array>
#include <string>
#include "defaults.hpp" #include "defaults.hpp"
@ -68,7 +66,7 @@ const int usPerSecond = 1000000;
const int usPerMinute = 60 * usPerSecond; 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 char *isrg_root_x1cert;
extern const uint8_t rootca_crt_bundle_start[] asm("_binary_x509_crt_bundle_start"); 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[] asm("_binary_ocean_gz_start");
@ -99,16 +97,6 @@ namespace ArduinoJson {
array.add(item); array.add(item);
} }
}; };
template <size_t N>
struct Converter<std::array<String, N>> {
static void toJson(const std::array<String, N>& src, JsonVariant dst) {
JsonArray array = dst.to<JsonArray>();
for (const String& item : src) {
array.add(item);
}
}
};
} }
class HttpHelper { class HttpHelper {
@ -121,4 +109,3 @@ private:
static bool certBundleSet; static bool certBundleSet;
static WiFiClient insecureClient; static WiFiClient insecureClient;
}; };

View file

@ -1,5 +1,4 @@
#include "timers.hpp" #include "timers.hpp"
#include "led_handler.hpp"
esp_timer_handle_t screenRotateTimer; esp_timer_handle_t screenRotateTimer;
esp_timer_handle_t minuteTimer; esp_timer_handle_t minuteTimer;
@ -50,11 +49,11 @@ void setTimerActive(bool status) {
if (status) { if (status) {
esp_timer_start_periodic(screenRotateTimer, esp_timer_start_periodic(screenRotateTimer,
getTimerSeconds() * usPerSecond); getTimerSeconds() * usPerSecond);
getLedHandler().queueEffect(LED_EFFECT_START_TIMER); queueLedEffect(LED_EFFECT_START_TIMER);
preferences.putBool("timerActive", true); preferences.putBool("timerActive", true);
} else { } else {
esp_timer_stop(screenRotateTimer); esp_timer_stop(screenRotateTimer);
getLedHandler().queueEffect(LED_EFFECT_PAUSE_TIMER); queueLedEffect(LED_EFFECT_PAUSE_TIMER);
preferences.putBool("timerActive", false); preferences.putBool("timerActive", false);
} }
@ -69,14 +68,12 @@ void IRAM_ATTR minuteTimerISR(void *arg) {
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0}; WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken); xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken);
TaskHandle_t bitaxeHandle = BitAxeFetch::getInstance().getTaskHandle(); if (bitaxeFetchTaskHandle != NULL) {
if (bitaxeHandle != NULL) { vTaskNotifyGiveFromISR(bitaxeFetchTaskHandle, &xHigherPriorityTaskWoken);
vTaskNotifyGiveFromISR(bitaxeHandle, &xHigherPriorityTaskWoken);
} }
TaskHandle_t miningPoolHandle = MiningPoolStatsFetch::getInstance().getTaskHandle(); if (miningPoolStatsFetchTaskHandle != NULL) {
if (miningPoolHandle != NULL) { vTaskNotifyGiveFromISR(miningPoolStatsFetchTaskHandle, &xHigherPriorityTaskWoken);
vTaskNotifyGiveFromISR(miningPoolHandle, &xHigherPriorityTaskWoken);
} }
if (xHigherPriorityTaskWoken == pdTRUE) { if (xHigherPriorityTaskWoken == pdTRUE) {

View file

@ -106,12 +106,11 @@ namespace V2Notify
JsonDocument doc; JsonDocument doc;
DeserializationError error = deserializeMsgPack(doc, payload, length); DeserializationError error = deserializeMsgPack(doc, payload, length);
if (error) { if (!error)
Serial.println(F("Error deserializing message")); {
break; handleV2Message(doc);
} }
V2Notify::handleV2Message(doc);
break; break;
} }
case WStype_ERROR: case WStype_ERROR:
@ -127,33 +126,24 @@ namespace V2Notify
void handleV2Message(JsonDocument doc) void handleV2Message(JsonDocument doc)
{ {
if (doc["blockheight"].is<uint>()) if (doc.containsKey("blockheight"))
{ {
uint newBlockHeight = doc["blockheight"].as<uint>(); uint newBlockHeight = doc["blockheight"].as<uint>();
if (newBlockHeight == BlockNotify::getInstance().getBlockHeight()) if (newBlockHeight == getBlockHeight())
{ {
return; return;
} }
if (debugLogEnabled()) { processNewBlock(newBlockHeight);
Serial.print(F("processNewBlock "));
Serial.println(newBlockHeight);
} }
BlockNotify::getInstance().processNewBlock(newBlockHeight); else if (doc.containsKey("blockfee"))
}
else if (doc["blockfee"].is<uint>())
{ {
uint medianFee = doc["blockfee"].as<uint>(); uint medianFee = doc["blockfee"].as<uint>();
if (debugLogEnabled()) { processNewBlockFee(medianFee);
Serial.print(F("processNewBlockFee "));
Serial.println(medianFee);
} }
else if (doc.containsKey("price"))
BlockNotify::getInstance().processNewBlockFee(medianFee);
}
else if (doc["price"].is<JsonObject>())
{ {
// Iterate through the key-value pairs of the "price" object // Iterate through the key-value pairs of the "price" object
@ -172,7 +162,7 @@ namespace V2Notify
for (;;) for (;;)
{ {
webSocket.loop(); webSocket.loop();
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(10 / portTICK_PERIOD_MS);
} }
} }

View file

@ -1,11 +1,9 @@
#include "webserver.hpp" #include "webserver.hpp"
#include "lib/led_handler.hpp"
#include "lib/shared.hpp"
static const char* JSON_CONTENT = "application/json"; static const char* JSON_CONTENT = "application/json";
static const char *const PROGMEM strSettings[] = { 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", "fontPreference"};
static const char *const PROGMEM uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout"}; static const char *const PROGMEM uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout"};
@ -18,7 +16,7 @@ static const char *const PROGMEM boolSettings[] = {"ledTestOnPower", "ledFlashOn
"mempoolSecure", "bitaxeEnabled", "mempoolSecure", "bitaxeEnabled",
"miningPoolStats", "verticalDesc", "miningPoolStats", "verticalDesc",
"nostrZapNotify", "httpAuthEnabled", "nostrZapNotify", "httpAuthEnabled",
"enableDebugLog", "ceDisableSSL", "dndEnabled", "dndTimeBasedEnabled"}; "enableDebugLog", "ceDisableSSL"};
AsyncWebServer server(80); AsyncWebServer server(80);
AsyncEventSource events("/events"); AsyncEventSource events("/events");
@ -30,8 +28,7 @@ TaskHandle_t eventSourceTaskHandle;
void setupWebserver() void setupWebserver()
{ {
events.onConnect([](AsyncEventSourceClient *client) events.onConnect([](AsyncEventSourceClient *client)
{ client->send("welcome", NULL, millis(), 1000); { client->send("welcome", NULL, millis(), 1000); });
});
server.addHandler(&events); server.addHandler(&events);
AsyncStaticWebHandler &staticHandler = server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html"); AsyncStaticWebHandler &staticHandler = server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html");
@ -119,10 +116,6 @@ void setupWebserver()
server.addRewrite(new OneParamRewrite("/api/show/number/{number}", server.addRewrite(new OneParamRewrite("/api/show/number/{number}",
"/api/show/text?t={text}")); "/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); server.onNotFound(onNotFound);
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*"); DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
@ -234,7 +227,6 @@ void asyncFirmwareUpdateHandler(AsyncWebServerRequest *request, String filename,
JsonDocument getStatusObject() JsonDocument getStatusObject()
{ {
auto& ledHandler = getLedHandler();
JsonDocument root; JsonDocument root;
root["currentScreen"] = ScreenHandler::getCurrentScreen(); root["currentScreen"] = ScreenHandler::getCurrentScreen();
@ -242,22 +234,25 @@ JsonDocument getStatusObject()
root["timerRunning"] = isTimerActive(); root["timerRunning"] = isTimerActive();
root["isOTAUpdating"] = getIsOTAUpdating(); root["isOTAUpdating"] = getIsOTAUpdating();
root["espUptime"] = esp_timer_get_time() / 1000000; root["espUptime"] = esp_timer_get_time() / 1000000;
// root["currentPrice"] = getPrice();
// root["currentBlockHeight"] = getBlockHeight();
root["espFreeHeap"] = ESP.getFreeHeap(); root["espFreeHeap"] = ESP.getFreeHeap();
root["espHeapSize"] = ESP.getHeapSize(); root["espHeapSize"] = ESP.getHeapSize();
// root["espFreePsram"] = ESP.getFreePsram();
// root["espPsramSize"] = ESP.getPsramSize();
JsonObject conStatus = root["connectionStatus"].to<JsonObject>(); JsonObject conStatus = root["connectionStatus"].to<JsonObject>();
conStatus["price"] = isPriceNotifyConnected(); conStatus["price"] = isPriceNotifyConnected();
auto& blockNotify = BlockNotify::getInstance(); conStatus["blocks"] = isBlockNotifyConnected();
conStatus["blocks"] = blockNotify.isConnected();
conStatus["V2"] = V2Notify::isV2NotifyConnected(); conStatus["V2"] = V2Notify::isV2NotifyConnected();
conStatus["nostr"] = nostrConnected(); conStatus["nostr"] = nostrConnected();
root["rssi"] = WiFi.RSSI(); root["rssi"] = WiFi.RSSI();
root["currency"] = getCurrencyCode(ScreenHandler::getCurrentCurrency()); root["currency"] = getCurrencyCode(ScreenHandler::getCurrentCurrency());
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
std::vector<uint16_t> statuses = ledHandler.frontlightGetStatus(); std::vector<uint16_t> statuses = frontlightGetStatus();
uint16_t arr[NUM_SCREENS]; uint16_t arr[NUM_SCREENS];
std::copy(statuses.begin(), statuses.end(), arr); std::copy(statuses.begin(), statuses.end(), arr);
@ -270,25 +265,14 @@ JsonDocument getStatusObject()
} }
#endif #endif
// Add DND status
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; return root;
} }
JsonDocument getLedStatusObject() JsonDocument getLedStatusObject()
{ {
auto& ledHandler = getLedHandler();
auto& pixels = ledHandler.getPixels();
JsonDocument root; JsonDocument root;
JsonArray colors = root["data"].to<JsonArray>(); JsonArray colors = root["data"].to<JsonArray>();
// Adafruit_NeoPixel pix = getPixels();
for (uint i = 0; i < pixels.numPixels(); i++) for (uint i = 0; i < pixels.numPixels(); i++)
{ {
@ -298,7 +282,13 @@ JsonDocument getLedStatusObject()
uint blue = pixColor & 0xFF; uint blue = pixColor & 0xFF;
char hexColor[8]; char hexColor[8];
snprintf(hexColor, sizeof(hexColor), "#%02X%02X%02X", red, green, blue); snprintf(hexColor, sizeof(hexColor), "#%02X%02X%02X", red, green, blue);
colors.add(hexColor);
JsonObject object = colors.add<JsonObject>();
object["red"] = red;
object["green"] = green;
object["blue"] = blue;
object["hex"] = hexColor;
} }
return root; return root;
@ -307,18 +297,14 @@ JsonDocument getLedStatusObject()
void eventSourceUpdate() { void eventSourceUpdate() {
if (!events.count()) return; if (!events.count()) return;
static JsonDocument doc; JsonDocument doc = getStatusObject();
doc.clear(); doc["leds"] = getLedStatusObject()["data"];
JsonDocument root = getStatusObject();
root["leds"] = getLedStatusObject()["data"];
// Get current EPD content directly as array // Get current EPD content directly as array
std::array<String, NUM_SCREENS> epdContent = EPDManager::getInstance().getCurrentContent(); std::array<String, NUM_SCREENS> epdContent = getCurrentEpdContent();
// Add EPD content arrays // Add EPD content arrays
JsonArray data = root["data"].to<JsonArray>(); JsonArray data = doc["data"].to<JsonArray>();
// Copy array elements directly // Copy array elements directly
for(const auto& content : epdContent) { for(const auto& content : epdContent) {
@ -326,7 +312,7 @@ void eventSourceUpdate() {
} }
String buffer; String buffer;
serializeJson(root, buffer); serializeJson(doc, buffer);
events.send(buffer.c_str(), "status"); events.send(buffer.c_str(), "status");
} }
@ -342,7 +328,7 @@ void onApiStatus(AsyncWebServerRequest *request)
JsonDocument root = getStatusObject(); JsonDocument root = getStatusObject();
// Get current EPD content directly as array // Get current EPD content directly as array
std::array<String, NUM_SCREENS> epdContent = EPDManager::getInstance().getCurrentContent(); std::array<String, NUM_SCREENS> epdContent = getCurrentEpdContent();
// Add EPD content arrays // Add EPD content arrays
JsonArray data = root["data"].to<JsonArray>(); JsonArray data = root["data"].to<JsonArray>();
@ -384,9 +370,11 @@ void onApiActionTimerRestart(AsyncWebServerRequest *request)
*/ */
void onApiFullRefresh(AsyncWebServerRequest *request) void onApiFullRefresh(AsyncWebServerRequest *request)
{ {
EPDManager::getInstance().forceFullRefresh(); forceFullRefresh();
std::array<String, NUM_SCREENS> newEpdContent = EPDManager::getInstance().getCurrentContent(); std::array<String, NUM_SCREENS> newEpdContent = getCurrentEpdContent();
EPDManager::getInstance().setContent(newEpdContent, true);
setEpdContent(newEpdContent, true);
request->send(HTTP_OK); request->send(HTTP_OK);
} }
@ -433,7 +421,7 @@ void onApiShowText(AsyncWebServerRequest *request)
textEpdContent[i] = t[i]; textEpdContent[i] = t[i];
} }
EPDManager::getInstance().setContent(textEpdContent); setEpdContent(textEpdContent);
} }
ScreenHandler::setCurrentScreen(SCREEN_CUSTOM); ScreenHandler::setCurrentScreen(SCREEN_CUSTOM);
request->send(HTTP_OK); request->send(HTTP_OK);
@ -451,7 +439,7 @@ void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json)
i++; i++;
} }
EPDManager::getInstance().setContent(epdContent); setEpdContent(epdContent);
ScreenHandler::setCurrentScreen(SCREEN_CUSTOM); ScreenHandler::setCurrentScreen(SCREEN_CUSTOM);
request->send(HTTP_OK); request->send(HTTP_OK);
@ -479,13 +467,13 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
if (inverted) { if (inverted) {
preferences.putUInt("fgColor", GxEPD_WHITE); preferences.putUInt("fgColor", GxEPD_WHITE);
preferences.putUInt("bgColor", GxEPD_BLACK); preferences.putUInt("bgColor", GxEPD_BLACK);
EPDManager::getInstance().setForegroundColor(GxEPD_WHITE); setFgColor(GxEPD_WHITE);
EPDManager::getInstance().setBackgroundColor(GxEPD_BLACK); setBgColor(GxEPD_BLACK);
} else { } else {
preferences.putUInt("fgColor", GxEPD_BLACK); preferences.putUInt("fgColor", GxEPD_BLACK);
preferences.putUInt("bgColor", GxEPD_WHITE); preferences.putUInt("bgColor", GxEPD_WHITE);
EPDManager::getInstance().setForegroundColor(GxEPD_BLACK); setFgColor(GxEPD_BLACK);
EPDManager::getInstance().setBackgroundColor(GxEPD_WHITE); setBgColor(GxEPD_WHITE);
} }
Serial.printf("Setting invertedColor to %d\r\n", inverted); Serial.printf("Setting invertedColor to %d\r\n", inverted);
settingsChanged = true; settingsChanged = true;
@ -617,29 +605,10 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
settingsChanged = true; settingsChanged = true;
} }
// Handle DND settings
if (settings["dnd"].is<JsonObject>()) {
JsonObject dndObj = settings["dnd"];
auto& ledHandler = getLedHandler();
if (dndObj["timeBasedEnabled"].is<bool>()) {
ledHandler.setDNDTimeBasedEnabled(dndObj["timeBasedEnabled"].as<bool>());
}
if (dndObj["startHour"].is<uint8_t>() && dndObj["startMinute"].is<uint8_t>() &&
dndObj["endHour"].is<uint8_t>() && dndObj["endMinute"].is<uint8_t>()) {
ledHandler.setDNDTimeRange(
dndObj["startHour"].as<uint8_t>(),
dndObj["startMinute"].as<uint8_t>(),
dndObj["endHour"].as<uint8_t>(),
dndObj["endMinute"].as<uint8_t>());
}
}
request->send(HTTP_OK); request->send(HTTP_OK);
if (settingsChanged) if (settingsChanged)
{ {
auto& ledHandler = getLedHandler(); queueLedEffect(LED_FLASH_SUCCESS);
ledHandler.queueEffect(LED_FLASH_SUCCESS);
} }
} }
@ -660,8 +629,7 @@ void onApiRestart(AsyncWebServerRequest *request)
void onApiIdentify(AsyncWebServerRequest *request) void onApiIdentify(AsyncWebServerRequest *request)
{ {
auto& ledHandler = getLedHandler(); queueLedEffect(LED_FLASH_IDENTIFY);
ledHandler.queueEffect(LED_FLASH_IDENTIFY);
request->send(HTTP_OK); request->send(HTTP_OK);
} }
@ -684,7 +652,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
JsonDocument root; JsonDocument root;
root["numScreens"] = NUM_SCREENS; root["numScreens"] = NUM_SCREENS;
root["invertedColor"] = preferences.getBool("invertedColor", EPDManager::getInstance().getForegroundColor() == GxEPD_WHITE); root["invertedColor"] = preferences.getBool("invertedColor", getFgColor() == GxEPD_WHITE);
root["timerSeconds"] = getTimerSeconds(); root["timerSeconds"] = getTimerSeconds();
root["timerRunning"] = isTimerActive(); root["timerRunning"] = isTimerActive();
root["minSecPriceUpd"] = preferences.getUInt( root["minSecPriceUpd"] = preferences.getUInt(
@ -694,6 +662,8 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
root["wpTimeout"] = preferences.getUInt("wpTimeout", DEFAULT_WP_TIMEOUT); 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["fontPreference"] = preferences.getString("fontPreference", "Oswald");
// Add data source settings // Add data source settings
root["dataSource"] = preferences.getUChar("dataSource", DEFAULT_DATA_SOURCE); root["dataSource"] = preferences.getUChar("dataSource", DEFAULT_DATA_SOURCE);
@ -701,17 +671,13 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
root["mempoolInstance"] = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); root["mempoolInstance"] = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
root["mempoolSecure"] = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE); 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) // Nostr settings (used for NOSTR_SOURCE or when zapNotify is enabled)
root["nostrPubKey"] = preferences.getString("nostrPubKey", DEFAULT_NOSTR_NPUB); root["nostrPubKey"] = preferences.getString("nostrPubKey", DEFAULT_NOSTR_NPUB);
root["nostrRelay"] = preferences.getString("nostrRelay", DEFAULT_NOSTR_RELAY); root["nostrRelay"] = preferences.getString("nostrRelay", DEFAULT_NOSTR_RELAY);
root["nostrZapNotify"] = preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED); root["nostrZapNotify"] = preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED);
root["nostrZapPubkey"] = preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY); root["nostrZapPubkey"] = preferences.getString("nostrZapPubkey", DEFAULT_ZAP_NOTIFY_PUBKEY);
root["ledFlashOnZap"] = preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP); 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) // Custom endpoint settings (only used for CUSTOM_SOURCE)
root["customEndpoint"] = preferences.getString("customEndpoint", DEFAULT_CUSTOM_ENDPOINT); root["customEndpoint"] = preferences.getString("customEndpoint", DEFAULT_CUSTOM_ENDPOINT);
root["customEndpointDisableSSL"] = preferences.getBool("customEndpointDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); root["customEndpointDisableSSL"] = preferences.getBool("customEndpointDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL);
@ -801,15 +767,6 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
root["ceEndpoint"] = preferences.getString("ceEndpoint", DEFAULT_CUSTOM_ENDPOINT); root["ceEndpoint"] = preferences.getString("ceEndpoint", DEFAULT_CUSTOM_ENDPOINT);
root["ceDisableSSL"] = preferences.getBool("ceDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); root["ceDisableSSL"] = preferences.getBool("ceDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL);
// Add DND settings
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 = AsyncResponseStream *response =
request->beginResponseStream(JSON_CONTENT); request->beginResponseStream(JSON_CONTENT);
serializeJson(root, *response); serializeJson(root, *response);
@ -825,7 +782,7 @@ bool processEpdColorSettings(AsyncWebServerRequest *request)
const AsyncWebParameter *fgColor = request->getParam("fgColor", true); const AsyncWebParameter *fgColor = request->getParam("fgColor", true);
uint32_t color = strtol(fgColor->value().c_str(), NULL, 16); uint32_t color = strtol(fgColor->value().c_str(), NULL, 16);
preferences.putUInt("fgColor", color); preferences.putUInt("fgColor", color);
EPDManager::getInstance().setForegroundColor(color); setFgColor(color);
// Serial.print(F("Setting foreground color to ")); // Serial.print(F("Setting foreground color to "));
// Serial.println(fgColor->value().c_str()); // Serial.println(fgColor->value().c_str());
settingsChanged = true; settingsChanged = true;
@ -836,7 +793,7 @@ bool processEpdColorSettings(AsyncWebServerRequest *request)
uint32_t color = strtol(bgColor->value().c_str(), NULL, 16); uint32_t color = strtol(bgColor->value().c_str(), NULL, 16);
preferences.putUInt("bgColor", color); preferences.putUInt("bgColor", color);
EPDManager::getInstance().setBackgroundColor(color); setBgColor(color);
// Serial.print(F("Setting background color to ")); // Serial.print(F("Setting background color to "));
// Serial.println(bgColor->value().c_str()); // Serial.println(bgColor->value().c_str());
settingsChanged = true; settingsChanged = true;
@ -915,7 +872,7 @@ void onApiStopDataSources(AsyncWebServerRequest *request)
request->beginResponseStream(JSON_CONTENT); request->beginResponseStream(JSON_CONTENT);
stopPriceNotify(); stopPriceNotify();
BlockNotify::getInstance().stop(); stopBlockNotify();
request->send(response); request->send(response);
} }
@ -926,15 +883,16 @@ void onApiRestartDataSources(AsyncWebServerRequest *request)
request->beginResponseStream(JSON_CONTENT); request->beginResponseStream(JSON_CONTENT);
restartPriceNotify(); restartPriceNotify();
BlockNotify::getInstance().restart(); restartBlockNotify();
// setupPriceNotify();
// setupBlockNotify();
request->send(response); request->send(response);
} }
void onApiLightsOff(AsyncWebServerRequest *request) void onApiLightsOff(AsyncWebServerRequest *request)
{ {
auto& ledHandler = getLedHandler(); setLights(0, 0, 0);
ledHandler.setLights(0, 0, 0);
request->send(HTTP_OK); request->send(HTTP_OK);
} }
@ -949,15 +907,13 @@ void onApiLightsSetColor(AsyncWebServerRequest *request)
if (rgbColor.compareTo("off") == 0) if (rgbColor.compareTo("off") == 0)
{ {
auto& ledHandler = getLedHandler(); setLights(0, 0, 0);
ledHandler.setLights(0, 0, 0);
} }
else else
{ {
uint r, g, b; uint r, g, b;
sscanf(rgbColor.c_str(), "%02x%02x%02x", &r, &g, &b); sscanf(rgbColor.c_str(), "%02x%02x%02x", &r, &g, &b);
auto& ledHandler = getLedHandler(); setLights(r, g, b);
ledHandler.setLights(r, g, b);
} }
JsonDocument doc; JsonDocument doc;
@ -975,9 +931,6 @@ void onApiLightsSetColor(AsyncWebServerRequest *request)
void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json) void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json)
{ {
auto& ledHandler = getLedHandler();
auto& pixels = ledHandler.getPixels();
JsonArray lights = json.as<JsonArray>(); JsonArray lights = json.as<JsonArray>();
if (lights.size() != pixels.numPixels()) if (lights.size() != pixels.numPixels())
@ -1026,7 +979,7 @@ void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json)
} }
pixels.show(); pixels.show();
ledHandler.saveLedState(); saveLedState();
request->send(HTTP_OK); request->send(HTTP_OK);
} }
@ -1090,21 +1043,19 @@ void onApiShowCurrency(AsyncWebServerRequest *request)
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
void onApiFrontlightOn(AsyncWebServerRequest *request) void onApiFrontlightOn(AsyncWebServerRequest *request)
{ {
auto& ledHandler = getLedHandler(); frontlightFadeInAll();
ledHandler.frontlightFadeInAll();
request->send(HTTP_OK); request->send(HTTP_OK);
} }
void onApiFrontlightStatus(AsyncWebServerRequest *request) void onApiFrontlightStatus(AsyncWebServerRequest *request)
{ {
auto& ledHandler = getLedHandler();
AsyncResponseStream *response = AsyncResponseStream *response =
request->beginResponseStream(JSON_CONTENT); request->beginResponseStream(JSON_CONTENT);
JsonDocument root; JsonDocument root;
std::vector<uint16_t> statuses = ledHandler.frontlightGetStatus(); std::vector<uint16_t> statuses = frontlightGetStatus();
uint16_t arr[NUM_SCREENS]; uint16_t arr[NUM_SCREENS];
std::copy(statuses.begin(), statuses.end(), arr); std::copy(statuses.begin(), statuses.end(), arr);
@ -1117,8 +1068,7 @@ void onApiFrontlightStatus(AsyncWebServerRequest *request)
void onApiFrontlightFlash(AsyncWebServerRequest *request) void onApiFrontlightFlash(AsyncWebServerRequest *request)
{ {
auto& ledHandler = getLedHandler(); frontlightFlash(preferences.getUInt("flEffectDelay"));
ledHandler.frontlightFlash(preferences.getUInt("flEffectDelay"));
request->send(HTTP_OK); request->send(HTTP_OK);
} }
@ -1127,8 +1077,7 @@ void onApiFrontlightSetBrightness(AsyncWebServerRequest *request)
{ {
if (request->hasParam("b")) if (request->hasParam("b"))
{ {
auto& ledHandler = getLedHandler(); frontlightSetBrightness(request->getParam("b")->value().toInt());
ledHandler.frontlightSetBrightness(request->getParam("b")->value().toInt());
request->send(HTTP_OK); request->send(HTTP_OK);
} }
else else
@ -1139,123 +1088,8 @@ void onApiFrontlightSetBrightness(AsyncWebServerRequest *request)
void onApiFrontlightOff(AsyncWebServerRequest *request) void onApiFrontlightOff(AsyncWebServerRequest *request)
{ {
auto& ledHandler = getLedHandler(); frontlightFadeOutAll();
ledHandler.frontlightFadeOutAll();
request->send(HTTP_OK); request->send(HTTP_OK);
} }
#endif #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"] = 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);
request->send(200, "application/json", response);
}
void onApiDNDEnable(AsyncWebServerRequest *request) {
auto& ledHandler = getLedHandler();
ledHandler.setDNDEnabled(true);
request->send(200);
}
void onApiDNDDisable(AsyncWebServerRequest *request) {
auto& ledHandler = getLedHandler();
ledHandler.setDNDEnabled(false);
request->send(200);
}
void onApiLightsGet(AsyncWebServerRequest *request)
{
auto& ledHandler = getLedHandler();
auto& pixels = ledHandler.getPixels();
JsonDocument doc;
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();
JsonDocument doc;
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);
}

View file

@ -67,10 +67,6 @@ void eventSourceTask(void *pvParameters);
void onApiStopDataSources(AsyncWebServerRequest *request); void onApiStopDataSources(AsyncWebServerRequest *request);
void onApiRestartDataSources(AsyncWebServerRequest *request); void onApiRestartDataSources(AsyncWebServerRequest *request);
void onApiDNDStatus(AsyncWebServerRequest *request);
void onApiDNDEnable(AsyncWebServerRequest *request);
void onApiDNDDisable(AsyncWebServerRequest *request);
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
void onApiFrontlightOn(AsyncWebServerRequest *request); void onApiFrontlightOn(AsyncWebServerRequest *request);
void onApiFrontlightFlash(AsyncWebServerRequest *request); void onApiFrontlightFlash(AsyncWebServerRequest *request);

View file

@ -18,8 +18,6 @@
#define WEBSERVER_H #define WEBSERVER_H
#include "ESPAsyncWebServer.h" #include "ESPAsyncWebServer.h"
#include "lib/config.hpp" #include "lib/config.hpp"
#include "lib/led_handler.hpp"
#include "lib/block_notify.hpp"
uint wifiLostConnection; uint wifiLostConnection;
uint priceNotifyLostConnection = 0; uint priceNotifyLostConnection = 0;
@ -50,8 +48,7 @@ void handleBlockNotifyDisconnection() {
if ((getUptime() - blockNotifyLostConnection) > 300) { // 5 minutes timeout if ((getUptime() - blockNotifyLostConnection) > 300) { // 5 minutes timeout
Serial.println(F("Block notification connection lost for 5 minutes, restarting handler...")); Serial.println(F("Block notification connection lost for 5 minutes, restarting handler..."));
auto& blockNotify = BlockNotify::getInstance(); restartBlockNotify();
blockNotify.restart();
blockNotifyLostConnection = 0; blockNotifyLostConnection = 0;
} }
} }
@ -61,14 +58,13 @@ void handleFrontlight() {
if (hasLightLevel() && preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE) != 0) { if (hasLightLevel() && preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE) != 0) {
uint lightLevel = getLightLevel(); uint lightLevel = getLightLevel();
uint luxThreshold = preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE); uint luxThreshold = preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE);
auto& ledHandler = getLedHandler();
if (lightLevel <= 1 && preferences.getBool("flOffWhenDark", DEFAULT_FL_OFF_WHEN_DARK)) { if (lightLevel <= 1 && preferences.getBool("flOffWhenDark", DEFAULT_FL_OFF_WHEN_DARK)) {
if (ledHandler.frontlightIsOn()) ledHandler.frontlightFadeOutAll(); if (frontlightIsOn()) frontlightFadeOutAll();
} else if (lightLevel < luxThreshold && !ledHandler.frontlightIsOn()) { } else if (lightLevel < luxThreshold && !frontlightIsOn()) {
ledHandler.frontlightFadeInAll(); frontlightFadeInAll();
} else if (ledHandler.frontlightIsOn() && lightLevel > luxThreshold) { } else if (frontlightIsOn() && lightLevel > luxThreshold) {
ledHandler.frontlightFadeOutAll(); frontlightFadeOutAll();
} }
} }
#endif #endif
@ -94,18 +90,19 @@ void checkWiFiConnection() {
void checkMissedBlocks() { void checkMissedBlocks() {
Serial.println(F("Long time (45 min) since last block, checking if I missed anything...")); Serial.println(F("Long time (45 min) since last block, checking if I missed anything..."));
auto& blockNotify = BlockNotify::getInstance(); int currentBlock = getBlockFetch();
int currentBlock = blockNotify.fetchLatestBlock();
if (currentBlock != -1) { if (currentBlock != -1) {
if (currentBlock != blockNotify.getBlockHeight()) { if (currentBlock != getBlockHeight()) {
Serial.println(F("Detected stuck block height... restarting block handler.")); Serial.println(F("Detected stuck block height... restarting block handler."));
blockNotify.restart(); restartBlockNotify();
} }
blockNotify.setLastBlockUpdate(getUptime()); setLastBlockUpdate(getUptime());
} }
} }
void monitorDataConnections() { void monitorDataConnections() {
// Price notification monitoring // Price notification monitoring
if (getPriceNotifyInit() && !preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE) && !isPriceNotifyConnected()) { if (getPriceNotifyInit() && !preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE) && !isPriceNotifyConnected()) {
handlePriceNotifyDisconnection(); handlePriceNotifyDisconnection();
@ -114,10 +111,9 @@ void monitorDataConnections() {
} }
// Block notification monitoring // Block notification monitoring
auto& blockNotify = BlockNotify::getInstance(); if (getBlockNotifyInit() && !isBlockNotifyConnected()) {
if (blockNotify.isInitialized() && !blockNotify.isConnected()) {
handleBlockNotifyDisconnection(); handleBlockNotifyDisconnection();
} else if (blockNotifyLostConnection > 0 && blockNotify.isConnected()) { } else if (blockNotifyLostConnection > 0 && isBlockNotifyConnected()) {
blockNotifyLostConnection = 0; blockNotifyLostConnection = 0;
} }
@ -129,7 +125,7 @@ void monitorDataConnections() {
} }
// Check for missed blocks // Check for missed blocks
if ((blockNotify.getLastBlockUpdate() - getUptime()) > 45 * 60) { if ((getLastBlockUpdate() - getUptime()) > 45 * 60) {
checkMissedBlocks(); checkMissedBlocks();
} }
} }
@ -141,6 +137,7 @@ extern "C" void app_main() {
bool thirdPartySource = getDataSource() == THIRD_PARTY_SOURCE; bool thirdPartySource = getDataSource() == THIRD_PARTY_SOURCE;
while (true) { while (true) {
if (eventSourceTaskHandle != NULL) { if (eventSourceTaskHandle != NULL) {
xTaskNotifyGive(eventSourceTaskHandle); xTaskNotifyGive(eventSourceTaskHandle);

View file

@ -1,75 +0,0 @@
#include <bitaxe_handler.hpp>
#include <unity.h>
template<size_t N>
std::string joinArrayWithBrackets(const std::array<std::string, N>& 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<std::string, NUM_SCREENS> 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<std::string, NUM_SCREENS> 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();
}