diff options
Diffstat (limited to 'dev/Boot/BootKit')
| -rw-r--r-- | dev/Boot/BootKit/Qr.h | 973 | ||||
| -rw-r--r-- | dev/Boot/BootKit/QrPrelude.h | 1 | ||||
| -rw-r--r-- | dev/Boot/BootKit/Rsrc/zka_swirl.rsrc | 70 | ||||
| -rw-r--r-- | dev/Boot/BootKit/Shared/base.h | 26 | ||||
| -rw-r--r-- | dev/Boot/BootKit/Shared/bit.h | 247 |
5 files changed, 1317 insertions, 0 deletions
diff --git a/dev/Boot/BootKit/Qr.h b/dev/Boot/BootKit/Qr.h new file mode 100644 index 00000000..0a30c6ca --- /dev/null +++ b/dev/Boot/BootKit/Qr.h @@ -0,0 +1,973 @@ +#ifndef QR_H +#define QR_H + +#include <BootKit/Shared/base.h> +#include <BootKit/Shared/bit.h> + +#include <BootKit/QrPrelude.h> +#include <Mod/CoreGfx/FBMgr.h> +#include <BootKit/Support.h> +#include <CompilerKit/Detail.h> + +/// @note the QR code is still code 128, it utilizes the same concept of having it's own character set. + +namespace qr +{ + inline uint8_t min_poly = + 0b11101, /* Minimal polynomial x^8 + x^4 + x^3 + x^2 + 1 */ + generator = 0b10; /* Generator of Galois field */ + + /// @brief galois finite field multiplication. + inline uint8_t gf_mul(uint8_t a, uint8_t b) + { + uint8_t res = 0; + + for (; b; b >>= 1) + { + if (b & 1) + res ^= a; + if (a & 0x80) + a = (a << 1) ^ min_poly; + else + a <<= 1; + } + + return res; + } + + // Size of Ecc block with respect to level and version. 0 version is for + // padding. + constexpr int ECC_CODEWORDS_PER_BLOCK[4][41] = { + {0, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, + 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, + {0, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, + 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, + {0, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, + 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, + {0, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, + 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, + }; + + // Number of Ecc blocks with respect to level and version. 0 version is for + // padding. + constexpr int N_ECC_BLOCKS[4][41] = { + {0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, + 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, + 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, + {0, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, + 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, + 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, + {0, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, + 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, + 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, + {0, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, + 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, + 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, + }; + + // Positions of central modules of alignment patterns according to version. 0 + // version is for padding. + constexpr int ALIGN_POS[41][7] = { + {}, + {0}, + {6, 18}, + {6, 22}, + {6, 26}, + {6, 30}, + {6, 34}, + {6, 22, 38}, + {6, 24, 42}, + {6, 26, 46}, + {6, 28, 50}, + {6, 30, 54}, + {6, 32, 58}, + {6, 34, 62}, + {6, 26, 46, 66}, + {6, 26, 48, 70}, + {6, 26, 50, 74}, + {6, 30, 54, 78}, + {6, 30, 56, 82}, + {6, 30, 58, 86}, + {6, 34, 62, 90}, + {6, 28, 50, 72, 94}, + {6, 26, 50, 74, 98}, + {6, 30, 54, 78, 102}, + {6, 28, 54, 80, 106}, + {6, 32, 58, 84, 110}, + {6, 30, 58, 86, 114}, + {6, 34, 62, 90, 118}, + {6, 26, 50, 74, 98, 122}, + {6, 30, 54, 78, 102, 126}, + {6, 26, 52, 78, 104, 130}, + {6, 30, 56, 82, 108, 134}, + {6, 34, 60, 86, 112, 138}, + {6, 30, 58, 86, 114, 142}, + {6, 34, 62, 90, 118, 146}, + {6, 30, 54, 78, 102, 126, 150}, + {6, 24, 50, 76, 102, 128, 154}, + {6, 28, 54, 80, 106, 132, 158}, + {6, 32, 58, 84, 110, 136, 162}, + {6, 26, 54, 82, 110, 138, 166}, + {6, 30, 58, 86, 114, 142, 170}, + }; + + // Return n-th bit of arr starting from MSB. + constexpr uint8_t get_bit_r(uint8_t* arr, int n) + { + return (arr[n >> 3] >> (7 - (n & 7))) & 1; + } + + // Add up to 16 bits to arr. Data starts from MSB as well as each byte of an + // array. + constexpr void add_bits(uint16_t data, int n, uint8_t* arr, size_t& pos) + { + while (n--) + { + arr[pos >> 3] |= ((data >> n) & 1) << (7 - (pos & 7)); + ++pos; + } + } + + // Translate char to alphanumeric encoding value, + constexpr int alphanumeric(char c) + { + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'A' && c <= 'Z') + return c - 'A' + 10; + + switch (c) + { + case ' ': + return 36; + case '$': + return 37; + case '%': + return 38; + case '*': + return 39; + case '+': + return 40; + case '-': + return 41; + case '.': + return 42; + case '/': + return 43; + case ':': + return 44; + } + return -1; + } + + // Check if string can be encoded in alphanumeric mode. + constexpr bool is_alphanumeric(const char* str, size_t len) + { + for (size_t i = 0; i < len; ++i) + if (alphanumeric(str[i]) == -1) + return false; + return true; + } + + // Check if string can be encoded in numeric mode. + constexpr bool is_numeric(const char* str, size_t len) + { + for (size_t i = 0; i < len; ++i) + if (str[i] < '0' || str[i] > '9') + return false; + return true; + } + + // Check if string can be encoded in kanji mode. + constexpr bool is_kanji(const char* str, size_t len) + { + for (size_t i = 0; i < len; i += 2) + { + uint16_t val = uint16_t(str[i]) | (uint16_t(str[i + 1]) << 8); + if (val < 0x8140 || val > 0xebbf || (val > 0x9ffc && val < 0xe040)) + return false; + } + return true; + } + + // Reed-Solomon Ecc generator polynomial for the given degree. + constexpr void gf_gen_poly(int degree, uint8_t* poly) + { + SetMem(poly, 0, degree); + + uint8_t root = poly[degree - 1] = 1; + + for (int i = 0; i < degree; ++i) + { + for (int j = 0; j < degree - 1; ++j) + poly[j] = gf_mul(poly[j], root) ^ poly[j + 1]; + poly[degree - 1] = gf_mul(poly[degree - 1], root); + root = (root << 1) ^ ((root >> 7) * 0x11d); + } + } + + // Polynomial division if Galois Field. + constexpr void gf_poly_div(uint8_t* dividend, size_t len, uint8_t* divisor, int degree, uint8_t* result) + { + SetMem(result, 0, degree); + + for (size_t i = 0; i < len; ++i) + { + uint8_t factor = dividend[i] ^ result[0]; + MoveMem(&result[0], &result[1], degree - 1); + result[degree - 1] = 0; + for (int j = 0; j < degree; ++j) + result[j] ^= gf_mul(divisor[j], factor); + } + } + + enum Ecc + { + L, + M, + Q, + H, + }; + + enum Mode + { + M_NUMERIC, + M_ALPHANUMERIC, + M_BYTE, + M_KANJI, + }; + + // Select appropriate encoding mode for string. + constexpr Mode select_mode(const char* str, size_t len) + { + if (is_numeric(str, len)) + return M_NUMERIC; + if (is_alphanumeric(str, len)) + return M_ALPHANUMERIC; + if (is_kanji(str, len)) + return M_KANJI; + return M_BYTE; + } + + // Return size of Character Control Indicator in bits for given version and + // mode. + constexpr int cci(int ver, Mode mode) + { + constexpr int cnt[4][3] = { + {10, 12, 14}, + {9, 11, 13}, + {8, 16, 16}, + {8, 10, 12}, + }; + if (ver < 10) + return cnt[mode][0]; + if (ver < 27) + return cnt[mode][1]; + return cnt[mode][2]; + } + + template <int V> + struct Qr + { + private: + friend class QrDelegate; + bool draw(int x, int y) noexcept; + + public: + constexpr auto side_size() const + { + return SIDE; + } + + bool module(int x, int y); + bool encode(const char* str, size_t len, Ecc ecc, int mask = -1); + + private: + bool encode_data(const char* data, size_t len, Ecc ecc, uint8_t* out); + void encode_ecc(uint8_t* data, Ecc ecc, uint8_t* out); + + void add_data(uint8_t* data, uint8_t* patterns); + void add_patterns(); + void add_version(); + void add_format(Ecc ecc, int mask); + void reserve_patterns(uint8_t* out); + + template <bool Black> + void draw_rect(int y, int x, int height, int width, uint8_t* out); + template <bool Black> + void draw_bound(int y, int x, int height, int width, uint8_t* out); + + template <bool Horizontal> + int rule_1_3_score(); + int penalty_score(); + int select_mask(Ecc ecc, uint8_t* patterns); + void apply_mask(int mask, uint8_t* patterns); + + private: + static_assert(V >= 1 && V <= 40, "invalid version"); + static constexpr int SIDE = 17 + V * 4; + static constexpr int N_BITS = SIDE * SIDE; + static constexpr int N_ALIGN = V == 1 ? 0 : V / 7 + 2; + static constexpr int N_ALIGN_BITS = V > 1 ? (N_ALIGN* N_ALIGN - 3) * 25 : 0; + static constexpr int N_TIMING_BITS = + (SIDE - 16) * 2 - (10 * (V > 1 ? N_ALIGN - 2 : 0)); + static constexpr int N_VER_BITS = V > 6 ? 36 : 0; + static constexpr int N_DAT_BITS = + N_BITS - (192 + N_ALIGN_BITS + N_TIMING_BITS + 31 + N_VER_BITS); + static constexpr int N_BYTES = utl::bytes_in_bits(N_BITS); // Actual number of bytes_in_bits + // required to store whole Qr code + static constexpr int N_DAT_BYTES = utl::bytes_in_bits(N_DAT_BITS); // Actual number of bytes_in_bits required to store + // [data + ecc] + static constexpr int N_DAT_CAPACITY = + N_DAT_BITS >> 3; // Capacity of [data + ecc] without remainder bits + private: + /// @brief internal function to retrieve bit from a bitset. + uint8_t get_arr_bit(uint8_t* arr, unsigned bit) const + { + return utl::get_arr_bit(arr, bit); + } + + /// @brief internal function to set bit from a bitset. + void set_arr_bit(uint8_t* arr, unsigned bit) + { + utl::set_arr_bit(arr, bit); + } + + /// @brief internal function to clear bit from a bitset. + void clr_arr_bit(uint8_t* arr, unsigned bit) + { + utl::clr_arr_bit(arr, bit); + } + + uint8_t code[N_BYTES] = {}; + + bool status = false; + }; + + // Get color of a module from left-to-right and top-to-bottom. Black is true. + template <int V> + bool Qr<V>::module(int x, int y) + { + return get_arr_bit(code, y * SIDE + x); + } + + /// @brief draw a new QR code. + template <int V> + bool Qr<V>::draw(int whereX, int whereY) noexcept + { + if (!this->status) + return false; // it may be invalid. + + fb_init(); + + for (int y = 0; y < (this->side_size()); ++y) + { + for (int x = 0; x < (this->side_size()); ++x) + { + FBDrawInRegion( + (this->module(x, y) ? RGB(00, 00, 00) : RGB(0xFF, 0xFF, 0xFF)), + 1, 1, + x + whereX, y + whereY); + } + } + + fb_clear(); + + return false; + } + + // Create Qr code with given error correction level. If mask == -1, + // then best mask selected automatically. NOTE: Automatic mask is the + // most expensive operation. Takes about 95 % of all computation time. + template <int V> + bool Qr<V>::encode(const char* str, size_t len, Ecc ecc, int mask) + { + uint8_t data[N_DAT_BYTES] = {}; + uint8_t data_with_ecc[N_DAT_BYTES] = {}; + uint8_t patterns[N_BYTES] = {}; + + if (!encode_data(str, len, ecc, data)) + { + return status = false; + } + + encode_ecc(data, ecc, data_with_ecc); + + reserve_patterns(patterns); + CopyMem(code, patterns, N_BYTES); + + add_data(data_with_ecc, patterns); + add_patterns(); + add_version(); + + mask = mask != -1 ? mask & 7 : select_mask(ecc, patterns); + + add_format(ecc, mask); + apply_mask(mask, patterns); + + return status = true; + } + + template <int V> + bool Qr<V>::encode_data(const char* data, size_t len, Ecc ecc, uint8_t* out) + { + Mode mode = select_mode(data, len); + + size_t n_bits = + (N_DAT_CAPACITY - ECC_CODEWORDS_PER_BLOCK[ecc][V] * N_ECC_BLOCKS[ecc][V]) + << 3; + size_t pos = 0; + + add_bits(1 << mode, 4, out, pos); + add_bits(len, cci(V, mode), out, pos); + + if (mode == M_NUMERIC) + { + const size_t triplets = len / 3; + const size_t triplets_size = triplets * 3; + const size_t rem = len % 3; + const size_t rem_bits = rem == 2 ? 7 : rem == 1 ? 4 + : 0; + const size_t total_size = 10 * triplets + rem_bits; + + if (pos + total_size > n_bits) + return false; + + char buf[4] = {}; + + for (size_t i = 0; i < triplets_size; i += 3) + { + buf[0] = data[i]; + buf[1] = data[i + 1]; + buf[2] = data[i + 2]; + + uint16_t num = StringToLong(buf, NULL, 10); + add_bits(num, 10, out, pos); + } + + if (rem) + { + buf[0] = data[triplets_size]; + buf[1] = data[triplets_size + 1]; + buf[rem] = 0; + + uint16_t num = StringToLong(buf, NULL, 10); + add_bits(num, rem_bits, out, pos); + } + } + else if (mode == M_ALPHANUMERIC) + { + if (pos + 11 * (int(len & ~1ul) / 2) > n_bits) + return false; + + for (int i = 0; i < int(len & ~1ul); i += 2) + { + uint16_t num = alphanumeric(data[i]) * 45 + alphanumeric(data[i + 1]); + add_bits(num, 11, out, pos); + } + if (len & 1) + { + if (pos + 6 > n_bits) + return false; + + add_bits(alphanumeric(data[len - 1]), 6, out, pos); + } + } + else if (mode == M_BYTE) + { + if (pos + len * 8 > n_bits) + return false; + + for (size_t i = 0; i < len; ++i) + add_bits(data[i], 8, out, pos); + } + else + { + if (pos + 13 * (len / 2) > n_bits) + return false; + + for (size_t i = 0; i < len; i += 2) + { + uint16_t val = ((uint8_t)data[i]) | (((uint8_t)data[i + 1]) << 8); + uint16_t res = 0; + val -= val < 0x9FFC ? 0x8140 : 0xC140; + res += val & 0xff; + res += (val >> 8) * 0xc0; + add_bits(res, 13, out, pos); + } + } + + size_t padding = n_bits - pos; + size_t i = 0; + + add_bits(0, padding > 4 ? 4 : padding, out, pos); + + if (pos & 7) + add_bits(0, (8 - pos) & 7, out, pos); + + while (pos < n_bits) + add_bits(++i & 1 ? 0xec : 0x11, 8, out, pos); + + return true; + } + + template <int V> + void Qr<V>::encode_ecc(uint8_t* data, Ecc ecc, uint8_t* out) + { + int n_blocks = N_ECC_BLOCKS[ecc][V]; + int ecc_len = ECC_CODEWORDS_PER_BLOCK[ecc][V]; + + int n_data_bytes = N_DAT_CAPACITY - ecc_len * n_blocks; + + int n_short_blocks = n_blocks - N_DAT_CAPACITY % n_blocks; + int short_len = N_DAT_CAPACITY / n_blocks - ecc_len; + + uint8_t gen_poly[30]; + uint8_t ecc_buf[30]; + + gf_gen_poly(ecc_len, gen_poly); + + uint8_t* data_ptr = data; + + for (int i = 0; i < n_blocks; ++i) + { + int data_len = short_len; + + if (i >= n_short_blocks) + ++data_len; + + gf_poly_div(data_ptr, data_len, gen_poly, ecc_len, ecc_buf); + + for (int j = 0, k = i; j < data_len; ++j, k += n_blocks) + { + if (j == short_len) + k -= n_short_blocks; + out[k] = data_ptr[j]; + } + for (int j = 0, k = n_data_bytes + i; j < ecc_len; ++j, k += n_blocks) + out[k] = ecc_buf[j]; + + data_ptr += data_len; + } + } + + template <int V> + void Qr<V>::add_data(uint8_t* data, uint8_t* patterns) + { + int data_pos = 0; + + for (int x = SIDE - 1; x >= 1; x -= 2) + { + if (x == 6) + x = 5; + + for (int i = 0; i < SIDE; ++i) + { + int y = !((x + 1) & 2) ? SIDE - 1 - i : i; + int coord = y * SIDE + x; + + if (!get_arr_bit(patterns, coord)) + { + if (get_bit_r(data, data_pos)) + set_arr_bit(code, coord); + + ++data_pos; + } + + if (!get_arr_bit(patterns, coord - 1)) + { + if (get_bit_r(data, data_pos)) + set_arr_bit(code, coord - 1); + + ++data_pos; + } + } + } + } + + template <int V> + void Qr<V>::add_patterns() + { + // White bounds inside finders + draw_bound<false>(1, 1, 5, 5, code); + draw_bound<false>(1, SIDE - 6, 5, 5, code); + draw_bound<false>(SIDE - 6, 1, 5, 5, code); + + // Finish alignment patterns + for (int i = 0; i < N_ALIGN; ++i) + { + for (int j = 0; j < N_ALIGN; ++j) + { + if ((!i && !j) || (!i && j == N_ALIGN - 1) || (!j && i == N_ALIGN - 1)) + continue; + draw_bound<false>(ALIGN_POS[V][i] - 1, ALIGN_POS[V][j] - 1, 3, 3, code); + } + } + + // Draw white separators + draw_rect<false>(7, 0, 1, 8, code); + draw_rect<false>(0, 7, 8, 1, code); + draw_rect<false>(SIDE - 8, 0, 1, 8, code); + draw_rect<false>(SIDE - 8, 7, 8, 1, code); + draw_rect<false>(7, SIDE - 8, 1, 8, code); + draw_rect<false>(0, SIDE - 8, 8, 1, code); + + // Perforate timing patterns + for (int i = 7; i < SIDE - 7; i += 2) + { + clr_arr_bit(code, 6 * SIDE + i); + clr_arr_bit(code, i * SIDE + 6); + } + } + + template <int V> + void Qr<V>::add_version() + { + if (V < 7) + return; + + uint32_t rem = V; + + for (uint8_t i = 0; i < 12; ++i) + rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); + + uint32_t data = V << 12 | rem; + + for (int x = 0; x < 6; ++x) + { + for (int j = 0; j < 3; ++j) + { + int y = SIDE - 11 + j; + + bool black = (data >> (x * 3 + j)) & 1; + + if (!black) + { + clr_arr_bit(code, y * SIDE + x); + clr_arr_bit(code, y + SIDE * x); + } + } + } + } + + template <int V> + void Qr<V>::add_format(Ecc ecc, int mask) + { + int data = (ecc ^ 1) << 3 | mask; + int rem = data; + + for (int i = 0; i < 10; i++) + rem = (rem << 1) ^ ((rem >> 9) * 0b10100110111); + + int res = (data << 10 | rem) ^ 0b101010000010010; + + for (int i = 0; i < 6; ++i) + { + if ((res >> i) & 1) + { + set_arr_bit(code, SIDE * 8 + SIDE - 1 - i); + set_arr_bit(code, SIDE * i + 8); + } + else + { + clr_arr_bit(code, SIDE * 8 + SIDE - 1 - i); + clr_arr_bit(code, SIDE * i + 8); + } + } + + for (int i = 6; i < 8; ++i) + { + if ((res >> i) & 1) + { + set_arr_bit(code, SIDE * 8 + SIDE - 1 - i); + set_arr_bit(code, SIDE * (i + 1) + 8); + } + else + { + clr_arr_bit(code, SIDE * 8 + SIDE - 1 - i); + clr_arr_bit(code, SIDE * (i + 1) + 8); + } + } + + if ((res >> 8) & 1) + { + set_arr_bit(code, SIDE * 8 + 7); + set_arr_bit(code, SIDE * (SIDE - 7) + 8); + } + else + { + clr_arr_bit(code, SIDE * 8 + 7); + clr_arr_bit(code, SIDE * (SIDE - 7) + 8); + } + + for (int i = 9, j = 5; i < 15; ++i, --j) + { + if ((res >> i) & 1) + { + set_arr_bit(code, SIDE * 8 + j); + set_arr_bit(code, SIDE * (SIDE - 1 - j) + 8); + } + else + { + clr_arr_bit(code, SIDE * 8 + j); + clr_arr_bit(code, SIDE * (SIDE - 1 - j) + 8); + } + } + } + + template <int V> + template <bool B> + void Qr<V>::draw_rect(int y, int x, int height, int width, uint8_t* out) + { + if (B) + { + for (int dy = y * SIDE; dy < (y + height) * SIDE; dy += SIDE) + for (int dx = x; dx < x + width; ++dx) + set_arr_bit(out, dy + dx); + } + else + { + for (int dy = y * SIDE; dy < (y + height) * SIDE; dy += SIDE) + for (int dx = x; dx < x + width; ++dx) + clr_arr_bit(out, dy + dx); + } + } + + template <int V> + template <bool B> + void Qr<V>::draw_bound(int y, int x, int height, int width, uint8_t* out) + { + if (B) + { + for (int i = y * SIDE + x; i < y * SIDE + x + width; ++i) + set_arr_bit(out, i); + for (int i = (y + height - 1) * SIDE + x; + i < (y + height - 1) * SIDE + x + width; ++i) + set_arr_bit(out, i); + for (int i = (y + 1) * SIDE + x; i < (y + height - 1) * SIDE + x; i += SIDE) + set_arr_bit(out, i); + for (int i = (y + 1) * SIDE + x + width - 1; + i < (y + height - 1) * SIDE + x + width - 1; i += SIDE) + set_arr_bit(out, i); + } + else + { + for (int i = y * SIDE + x; i < y * SIDE + x + width; ++i) + clr_arr_bit(out, i); + for (int i = (y + height - 1) * SIDE + x; + i < (y + height - 1) * SIDE + x + width; ++i) + clr_arr_bit(out, i); + for (int i = (y + 1) * SIDE + x; i < (y + height - 1) * SIDE + x; i += SIDE) + clr_arr_bit(out, i); + for (int i = (y + 1) * SIDE + x + width - 1; + i < (y + height - 1) * SIDE + x + width - 1; i += SIDE) + clr_arr_bit(out, i); + } + } + + template <int V> + void Qr<V>::reserve_patterns(uint8_t* out) + { + draw_rect<true>(0, 6, SIDE, 1, out); + draw_rect<true>(6, 0, 1, SIDE, out); + + draw_rect<true>(0, 0, 9, 9, out); + draw_rect<true>(SIDE - 8, 0, 8, 9, out); + draw_rect<true>(0, SIDE - 8, 9, 8, out); + + for (int i = 0; i < N_ALIGN; ++i) + { + for (int j = 0; j < N_ALIGN; ++j) + { + if ((!i && !j) || (!i && j == N_ALIGN - 1) || (!j && i == N_ALIGN - 1)) + continue; + draw_rect<true>(ALIGN_POS[V][i] - 2, ALIGN_POS[V][j] - 2, 5, 5, out); + } + } + + if (V >= 7) + { + draw_rect<true>(SIDE - 11, 0, 3, 6, out); + draw_rect<true>(0, SIDE - 11, 6, 3, out); + } + } + + template <int V> + template <bool H> + int Qr<V>::rule_1_3_score() + { + constexpr int y_max = H ? N_BITS : SIDE; + constexpr int x_max = H ? SIDE : N_BITS; + constexpr int y_step = H ? SIDE : 1; + constexpr int x_step = H ? 1 : SIDE; + + int res = 0; + + for (int y = 0; y < y_max; y += y_step) + { + bool color = get_arr_bit(code, y); + int finder = color; + int cnt = 1; + for (int x = 1; x < x_max; x += x_step) + { + if (get_arr_bit(code, y + x) == color) + { + ++cnt; + if (cnt == 5) + res += 3; + if (cnt > 5) + ++res; + } + else + { + color = !color; + cnt = 1; + } + // Finder-like + finder = ((finder << 1) & 0x7ff) | color; + if (x >= x_step * 10) + { + if (finder == 0x05d || finder == 0x5d0) + res += 40; + } + } + } + return res; + } + + template <int V> + int Qr<V>::penalty_score() + { + int res = 0; + + res += rule_1_3_score<true>(); + res += rule_1_3_score<false>(); + + for (int y = 0; y < N_BITS - SIDE; y += SIDE) + { + for (int x = 0; x < SIDE - 1; ++x) + { + bool c = get_arr_bit(code, y + x); + + if (c == get_arr_bit(code, y + x + 1) && + c == get_arr_bit(code, y + x + SIDE) && + c == get_arr_bit(code, y + x + SIDE + 1)) + res += 3; + } + } + + int black = 0; + for (int y = 0; y < N_BITS; y += SIDE) + { + for (int x = 0; x < SIDE; ++x) + black += get_arr_bit(code, y + x); + } + res += abs((black * 100) / N_BITS - 50) / 5 * 10; + + return res; + } + + template <int V> + int Qr<V>::select_mask(Ecc ecc, uint8_t* patterns) + { + unsigned min_score = -1; + unsigned score = 0; + uint8_t mask = 0; + + for (int i = 0; i < 8; ++i) + { + add_format(ecc, i); + apply_mask(i, patterns); + score = penalty_score(); + if (score < min_score) + { + mask = i; + min_score = score; + } + apply_mask(i, patterns); + } + return mask; + } + + template <int V> + void Qr<V>::apply_mask(int mask, uint8_t* patterns) + { + for (int y = 0, dy = 0; y < SIDE; ++y, dy += SIDE) + { + for (int x = 0; x < SIDE; ++x) + { + int coord = dy + x; + + if (get_arr_bit(patterns, coord)) + continue; + + bool keep = true; + + switch (mask) + { + case 0: + keep = (x + y) & 1; + break; + case 1: + keep = y & 1; + break; + case 2: + keep = x % 3; + break; + case 3: + keep = (x + y) % 3; + break; + case 4: + keep = (y / 2 + x / 3) & 1; + break; + case 5: + keep = x * y % 2 + x * y % 3; + break; + case 6: + keep = (x * y % 2 + x * y % 3) & 1; + break; + case 7: + keep = ((x + y) % 2 + x * y % 3) & 1; + break; + } + + if (!keep) + { + if (get_arr_bit(code, coord)) + clr_arr_bit(code, coord); + else + set_arr_bit(code, coord); + } + } + } + } + + /// @brief QR code encoder class. + class QrDelegate final + { + public: + explicit QrDelegate() = default; + ~QrDelegate() = default; + + NE_COPY_DEFAULT(QrDelegate); + + /// @brief Draw method delegate. + template <int V> + bool draw(Qr<V>& subject, int x, int y) noexcept + { + return subject.draw(x, y); + } + }; +} // namespace qr + +namespace Kernel::Qr +{ + using namespace qr; +} // namespace Kernel::Qr + +#endif // QR_H
\ No newline at end of file diff --git a/dev/Boot/BootKit/QrPrelude.h b/dev/Boot/BootKit/QrPrelude.h new file mode 100644 index 00000000..e89fad7a --- /dev/null +++ b/dev/Boot/BootKit/QrPrelude.h @@ -0,0 +1 @@ +#include <BootKit/BitManip.h>
\ No newline at end of file diff --git a/dev/Boot/BootKit/Rsrc/zka_swirl.rsrc b/dev/Boot/BootKit/Rsrc/zka_swirl.rsrc new file mode 100644 index 00000000..0cb11bde --- /dev/null +++ b/dev/Boot/BootKit/Rsrc/zka_swirl.rsrc @@ -0,0 +1,70 @@ +#define ZKA_SWIRL_HEIGHT 64 +#define ZKA_SWIRL_WIDTH 64 + +// array size is 12288 (32x32) +const unsigned int zka_swirl[] = { + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xf5f5f5, 0x7b7893, 0x020039, 0x020239, 0x01013a, 0x01013b, 0x00013b, 0x00013b, 0x01033f, 0x8587a0, 0xf7f7f7, 0xf7f7f7, 0xf8f8f8, 0xf7f7f7, 0xf5f5f5, 0xf7f7f7, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff, 0xf7f7f7, 0xf6f6f6, 0xf6f6f6, 0xd4d2da, 0x1e174b, 0x030138, 0x020139, 0x010139, 0x01013a, 0x00013a, 0x1a1e53, 0xcbccd5, 0xf6f6f6, 0xf6f6f6, 0xf6f6f6, 0xf6f6f6, 0xf6f6f6, 0xf6f6f6, 0xf5f5f6, 0xf6f6f6, 0xcdcbd6, 0x2b2453, 0x2a2a55, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff, 0xf6f6f6, 0xf6f6f6, 0xf5f5f5, 0xf5f5f5, 0xe9e9ec, 0x302856, 0x050137, 0x040138, 0x020139, 0x010139, 0x01013a, 0x4a4c74, 0xe0e0e5, 0xf5f5f5, 0xf5f5f5, 0xf6f6f6, 0xf5f5f5, 0xf5f5f5, 0xf5f5f5, 0xebebee, 0xb8b6c4, 0x554e74, 0x140940, 0x0b0135, 0x0d0134, 0x100235, 0x0a0033, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xbfbfbf, 0xf6f6f6, 0xf4f4f4, 0xf5f5f5, 0xf5f5f5, 0xf5f5f5, 0xf5f5f5, 0x756e8c, 0x070136, 0x060137, 0x040138, 0x030138, 0x020139, 0x6a6a8b, 0xecedef, 0xf5f5f5, 0xf5f5f5, 0xf5f5f5, 0xf5f5f5, 0xf5f5f5, 0xeeeef0, 0x908ea6, 0x272152, 0x060137, 0x060136, 0x0a0135, 0x0b0135, 0x0d0134, 0x100134, 0x120133, 0x130032, 0x1c0039, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x1d0031, 0x746583, 0xf4f4f4, 0xf4f4f4, 0xf4f4f4, 0xf4f4f4, 0xf4f4f4, 0xb6b3c0, 0x0a0135, 0x070136, 0x060137, 0x040137, 0x030138, 0x7a7994, 0xf4f4f4, 0xf5f5f5, 0xf4f4f4, 0xf4f4f4, 0xf4f4f4, 0xf3f3f3, 0x9999af, 0x131147, 0x030138, 0x040137, 0x060137, 0x090136, 0x0a0135, 0x0c0135, 0x0e0135, 0x110133, 0x120133, 0x140133, 0x160132, 0x180031, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x200030, 0x1d012e, 0x1b0130, 0xcdc8d1, 0xf4f4f4, 0xf4f4f4, 0xf4f4f4, 0xf4f4f4, 0xe6e6e9, 0x241549, 0x0b0135, 0x090136, 0x060137, 0x050137, 0x656183, 0xf4f4f4, 0xf3f3f4, 0xf4f4f4, 0xf4f4f4, 0xf3f3f3, 0xc9cad3, 0x3d3e6a, 0x010139, 0x020139, 0x030138, 0x050137, 0x060136, 0x090136, 0x0b0135, 0x0d0135, 0x100134, 0x120134, 0x3e2b56, 0x645476, 0x7d708a, 0x9a8fa3, 0xcfcbd3, 0xf7f7f7, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x220031, 0x20012e, 0x1e012e, 0x5b4567, 0xf3f3f3, 0xf3f3f3, 0xf3f3f3, 0xf3f3f3, 0xf3f3f3, 0x837993, 0x0d0134, 0x0c0135, 0x0a0136, 0x060137, 0x5d587c, 0xf3f3f3, 0xf3f3f3, 0xf3f3f3, 0xf3f3f3, 0xf3f3f3, 0x82849f, 0x010340, 0x01013a, 0x010139, 0x020139, 0x030138, 0x060137, 0x070137, 0x0a0136, 0x392d5a, 0x8b849b, 0xbfbac6, 0xeaeaec, 0xf3f3f3, 0xf3f3f3, 0xf3f3f3, 0xf3f3f3, 0xf3f3f3, 0xf4f4f4, 0xf4f4f4, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x550055, 0x24002d, 0x22012d, 0x21012e, 0x20012e, 0xa99eb0, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xdcdadf, 0x1f0b3f, 0x0e0134, 0x0c0135, 0x0a0136, 0x2d2353, 0xe0dee3, 0xf2f2f2, 0xf3f3f3, 0xf3f3f3, 0xe9e9eb, 0x5c5f83, 0x00013c, 0x00013c, 0x01013a, 0x010139, 0x030138, 0x040138, 0x251e50, 0x86829b, 0xceccd5, 0xf2f2f3, 0xf3f3f3, 0xf3f3f3, 0xf3f3f3, 0xf2f2f2, 0xf2f2f2, 0xf3f3f3, 0xf3f3f3, 0xf3f3f3, 0xf2f2f2, 0xf2f2f3, 0xf4f4f4, 0xffffff, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff, 0x320937, 0x25012c, 0x23012c, 0x23012e, 0x240232, 0xe2dfe3, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0x6a5c7c, 0x120133, 0x100134, 0x0d0134, 0x1b0d42, 0xd0cfd7, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xd6d6dc, 0x333463, 0x00013c, 0x00013d, 0x00013c, 0x01013a, 0x020139, 0x363360, 0xa4a2b5, 0xececee, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf3f3f3, 0xffffff, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff, 0xeae9ea, 0x2a012c, 0x27012c, 0x25012c, 0x23012d, 0x52365b, 0xf1f1f1, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xdedce0, 0x1a0235, 0x130133, 0x110133, 0x0d0134, 0x9791a6, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xd5d5db, 0x282758, 0x00013a, 0x00013c, 0x00013c, 0x00013c, 0x1b1e52, 0x9f9eb3, 0xf1f1f1, 0xf2f2f2, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xf2f2f2, 0xf1f1f1, 0xf2f2f2, 0xf2f2f2, 0xf2f2f2, 0xf1f1f1, 0xf1f1f1, 0xf2f2f2, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xf2f2f2, 0xf1f1f1, 0xffffff, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff, 0xf1f1f1, 0xd9d4d9, 0x2a012b, 0x28012b, 0x27012c, 0x25012c, 0x8b7990, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0x897c94, 0x170131, 0x140132, 0x120133, 0x473962, 0xf0f0f0, 0xf1f1f1, 0xf1f1f1, 0xe4e3e7, 0x2e2b5b, 0x010139, 0x01013a, 0x00013c, 0x00013d, 0x6c6e8e, 0xe9e9eb, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xf0f0f0, 0xdad6dc, 0xbdb6c2, 0xb1a9b6, 0xaea2b3, 0xaea2b2, 0xb2a7b5, 0xb9afba, 0xc4bac4, 0xdfdadf, 0xf1f1f1, 0xf1f1f1, 0xeaeaea, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xf0f0f0, 0xf0f0f0, 0xbfb4be, 0x2b012a, 0x2a012b, 0x29012b, 0x27012c, 0xbcb3bd, 0xf0f0f0, 0xf0f0f0, 0xf0f0f0, 0xeff0f0, 0x452d56, 0x180131, 0x150132, 0x130133, 0xc2bec9, 0xf0f0f0, 0xf1f1f1, 0xeff0f0, 0x423c65, 0x030138, 0x020139, 0x01013b, 0x0a0e49, 0x9fa1b5, 0xf1f1f1, 0xf0f0f0, 0xf0f0f0, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xf1f1f1, 0xe7e6e8, 0xa9a2b4, 0x756885, 0x3f2a54, 0x1f0536, 0x1a0131, 0x1c0130, 0x1f012e, 0x21012e, 0x22012d, 0x24012d, 0x25012c, 0x28012b, 0x29012b, 0x330634, 0x563255, 0x5f375b, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xf2f2f2, 0xf0f0f0, 0xf0f0f0, 0xaa98a9, 0x2d012a, 0x2b012a, 0x2a012a, 0x29012c, 0xd6d1d7, 0xf0f0f0, 0xf0f0f0, 0xf0f0f0, 0xc6bfc9, 0x1c0130, 0x1a0130, 0x180132, 0x615273, 0xf0f0f0, 0xf0f0f0, 0xeff0f0, 0x7f7993, 0x060137, 0x030138, 0x020139, 0x242657, 0xd4d4da, 0xeff0f0, 0xf0f0f0, 0xeff0f0, 0xf0f0f0, 0xf0f0f0, 0xe2e1e4, 0x9793a9, 0x4d4168, 0x140338, 0x120133, 0x140132, 0x180132, 0x1a0131, 0x1c0130, 0x1f012e, 0x20012e, 0x22012d, 0x24012d, 0x25012c, 0x28012b, 0x29002a, 0x2b012a, 0x2c012a, 0x2d012a, 0x2e0129, 0x2f0028, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xf0f0f0, 0xeef0f0, 0xeff0f0, 0xeff0f0, 0xa08d9e, 0x2e0029, 0x2d012a, 0x2b012a, 0x411841, 0xedeced, 0xeff0f0, 0xeff0f0, 0xeff0f0, 0x8f8196, 0x1e012e, 0x1b0130, 0x190131, 0xc6c2cb, 0xeff0f0, 0xeff0f0, 0xbfbbc7, 0x10033a, 0x060136, 0x040138, 0x353360, 0xd9d8de, 0xeff0f0, 0xeff0f0, 0xeff0f0, 0xeff0f0, 0xd8d7dd, 0x807c96, 0x1b1045, 0x0b0135, 0x0d0135, 0x100133, 0x130132, 0x150132, 0x190131, 0x1b0130, 0x1e0130, 0x20012e, 0x22012d, 0x24012d, 0x25012c, 0x28012b, 0x29012b, 0x2b012a, 0x2c012a, 0x2d012a, 0x300129, 0x310128, 0x320129, 0x320027, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xc4b9c3, 0xefeff0, 0xeff0f0, 0xeff0f0, 0x9e899a, 0x310129, 0x2e0129, 0x2d012a, 0x5e3c5d, 0xefeff0, 0xefefef, 0xeff0f0, 0xeff0f0, 0x5e4466, 0x20012e, 0x1c0130, 0x452e57, 0xeff0f0, 0xefefef, 0xe7e6e9, 0x312150, 0x0b0135, 0x070137, 0x272051, 0xd7d6dc, 0xefeff0, 0xeff0f0, 0xefefef, 0xebebec, 0x9595ab, 0x151046, 0x050137, 0x070136, 0x0b0135, 0x0e0134, 0x120133, 0x140133, 0x250b3d, 0x371e49, 0x4f375c, 0x5c4366, 0x5e4465, 0x55385c, 0x45244c, 0x370e3a, 0x2b012c, 0x2b012b, 0x2c012a, 0x2e012a, 0x300129, 0x310128, 0x320128, 0x340128, 0x350027, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x3a0025, 0x8a6a80, 0xefefef, 0xefefef, 0xefefef, 0x9f899a, 0x320028, 0x310028, 0x300129, 0x795c76, 0xefefef, 0xefefef, 0xefefef, 0xe3e0e3, 0x2c0635, 0x22012e, 0x20012e, 0x9d92a5, 0xefefef, 0xefefef, 0x877d95, 0x100134, 0x0c0135, 0x1b1044, 0xd1d1d7, 0xefefef, 0xefefef, 0xefefef, 0xcccdd5, 0x333462, 0x010139, 0x030138, 0x060137, 0x0a0137, 0x3f335d, 0x7e748e, 0xaca6b5, 0xe0dde2, 0xefefef, 0xefefef, 0xefefef, 0xefefef, 0xefefef, 0xefefef, 0xefefef, 0xefefef, 0xe7e6e7, 0xc5bcc5, 0xa796a7, 0x755571, 0x4c1e44, 0x320028, 0x340127, 0x350127, 0x360127, 0x390027, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x2a002a, 0x3a0024, 0x7c5670, 0xeeeeee, 0xefefef, 0xefefef, 0xa48e9e, 0x340127, 0x330028, 0x310129, 0x81667e, 0xeeeeee, 0xeeeeee, 0xefefef, 0xc6bdc7, 0x26012c, 0x23012d, 0x21012d, 0xd7d3d9, 0xeeeeee, 0xe1e0e3, 0x2c1747, 0x110133, 0x0d0135, 0xaaa6b6, 0xefefef, 0xefefef, 0xeeeeee, 0xa2a3b5, 0x0a104a, 0x00013b, 0x020139, 0x130d44, 0x78748f, 0xc9c7cf, 0xefefef, 0xefefef, 0xeeeeef, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xefeeef, 0xefefef, 0xefeeef, 0xeeeded, 0xc3b7c1, 0x84657d, 0x4c193f, 0x370125, 0x370026, 0x400033, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x3e0027, 0x3d0024, 0x6a3d5b, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xad99a8, 0x360027, 0x350027, 0x330128, 0x876b81, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xb0a2b1, 0x28012b, 0x25012c, 0x4e3156, 0xeeeeee, 0xeeeeee, 0xa097a9, 0x170132, 0x120133, 0x756a87, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0x8c8ca3, 0x020340, 0x00013c, 0x0e1149, 0x8f8ea6, 0xe0e0e3, 0xeeeeee, 0xeeeeee, 0xe8e7e9, 0xd2cfd5, 0xb2acb8, 0x908398, 0x817089, 0x7d6983, 0x7c6783, 0x826c85, 0x907c91, 0xab9cac, 0xc2b9c2, 0xddd9dd, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xeeeeee, 0xedecec, 0xb7a6b2, 0x714662, 0x3e0228, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x40152a, 0x3f0025, 0x3e0023, 0x4b0d34, 0xededed, 0xededed, 0xededed, 0xc1b5be, 0x380025, 0x360025, 0x350027, 0x866980, 0xededed, 0xededed, 0xededed, 0x958295, 0x2a012a, 0x28012c, 0x88758b, 0xededed, 0xededee, 0x4a3157, 0x180131, 0x220a3d, 0xd7d4d9, 0xededee, 0xededed, 0x8d8ba2, 0x04033d, 0x00013c, 0x4d5178, 0xd0d1d7, 0xededed, 0xe9e9eb, 0xbfbcc7, 0x756b89, 0x362552, 0x180134, 0x190131, 0x1c0130, 0x1f012e, 0x22012d, 0x24012c, 0x28012c, 0x2a012b, 0x2c012a, 0x2d012a, 0x350430, 0x633e5d, 0x998394, 0xc6bbc3, 0xececec, 0xeeeeee, 0xededed, 0xededed, 0xededed, 0xededed, 0xededed, 0xc8bbc2, 0xefefef, 0x000000, 0x000000, + 0x000000, 0x000000, 0x400023, 0x410022, 0x400022, 0x3f0023, 0xdbd5d9, 0xededed, 0xededed, 0xd9d3d7, 0x3a0025, 0x380125, 0x370025, 0x83627a, 0xededed, 0xededed, 0xededed, 0x897086, 0x2c012a, 0x2a012b, 0xb5abb6, 0xededed, 0xd2ced4, 0x1f012e, 0x1a0130, 0x8a7f95, 0xededed, 0xededed, 0xb5b3c0, 0x0b053d, 0x03023a, 0x8889a0, 0xe6e6e8, 0xe9e9eb, 0x9f9eb1, 0x36305c, 0x0a0137, 0x0e0134, 0x130133, 0x170132, 0x1a0130, 0x1f012e, 0x21012d, 0x24012c, 0x27012b, 0x2a012b, 0x2c012a, 0x2d0129, 0x310129, 0x320128, 0x330028, 0x350127, 0x360027, 0x5c2c4e, 0x94798b, 0xdbd6da, 0xededed, 0xededed, 0xededed, 0xededed, 0xededed, 0xeaeaea, 0x000000, 0x000000, + 0x000000, 0x7f0000, 0x430022, 0x430022, 0x420022, 0x410022, 0xb5a0ad, 0xededed, 0xededed, 0xe9e8e8, 0x3f0228, 0x3c0124, 0x390024, 0x77516b, 0xececec, 0xececec, 0xececec, 0x856a81, 0x300029, 0x2d012a, 0xcac3ca, 0xececec, 0x918195, 0x21012d, 0x2a0a3a, 0xe2e2e4, 0xececec, 0xd5d3d8, 0x1f1144, 0x120940, 0xacabb9, 0xececec, 0xc2c3cd, 0x2d2c5d, 0x030138, 0x060136, 0x2a1c4d, 0x6e6481, 0xa199ab, 0xb4aeba, 0xcdc8d0, 0xd6d3d8, 0xd4cfd4, 0xc6bec7, 0xb8aeb9, 0xa292a1, 0x745571, 0x400e38, 0x330128, 0x340027, 0x360027, 0x380127, 0x390125, 0x390025, 0x3c0124, 0x44062d, 0x856177, 0xdfdbde, 0xececec, 0xececec, 0xececec, 0xebecec, 0xffffff, 0x000000, + 0x000000, 0x8b6574, 0x460122, 0x450021, 0x440021, 0x430021, 0x967586, 0xececec, 0xecebeb, 0xececec, 0x693957, 0x3e0023, 0x3d0024, 0x602e4f, 0xececec, 0xececec, 0xececec, 0x866980, 0x330128, 0x300129, 0xe5e4e5, 0xececec, 0x6a4f6d, 0x24012d, 0x786580, 0xececec, 0xececec, 0x5c4e71, 0x100236, 0xb4b2be, 0xececec, 0x7b7d97, 0x020541, 0x111249, 0x716d8c, 0xc0bec8, 0xbcb9c4, 0xa49dae, 0x998fa1, 0x918498, 0x97899c, 0xa89bac, 0xbab1bb, 0xd8d3d8, 0xebebeb, 0xececec, 0xececec, 0xececec, 0xccc2c9, 0x937a8d, 0x542245, 0x3a0125, 0x3c0124, 0x3d0024, 0x3e0023, 0x3f0023, 0x400023, 0x4f1034, 0x9a7b8c, 0xe4e1e2, 0xececec, 0xececec, 0xeaeaea, 0x000000, + 0x000000, 0xe8e6e6, 0x672b49, 0x460021, 0x460021, 0x450021, 0x551436, 0xeaeaea, 0xececec, 0xebebeb, 0x8e6a7f, 0x400023, 0x3f0023, 0x4a0b32, 0xdedadd, 0xebebeb, 0xebebeb, 0x8d7084, 0x350027, 0x38032d, 0xebebeb, 0xebebeb, 0x421942, 0x28012b, 0xb9b1bb, 0xebebeb, 0xafa9b5, 0x150132, 0x878096, 0xebebeb, 0x625f81, 0x03033f, 0x757793, 0x737390, 0x423d66, 0x13063d, 0x100134, 0x150132, 0x1a0130, 0x1f012e, 0x23012d, 0x27012c, 0x2a012b, 0x2d012a, 0x471a41, 0x7f6078, 0xbaadb6, 0xebebeb, 0xebebeb, 0xebebeb, 0xebebeb, 0xbdafb8, 0x6c3d5a, 0x3f0023, 0x400023, 0x410022, 0x410022, 0x420022, 0x430021, 0x5a1b3d, 0xc7b8c0, 0xebebeb, 0xececec, 0x000000, + 0x000000, 0xebebeb, 0xa07f8f, 0x490020, 0x490020, 0x470020, 0x460020, 0xcabcc3, 0xebebeb, 0xeaeaea, 0xb9a7b1, 0x420022, 0x410122, 0x400023, 0xcec3c9, 0xebebeb, 0xebebeb, 0x9b8292, 0x380025, 0x3f0731, 0xebeaea, 0xeaeaea, 0x32032e, 0x350935, 0xdddadd, 0xebebeb, 0x4c3358, 0x554165, 0xebebeb, 0x615a7b, 0x3c3762, 0xc9c9d1, 0xeaeaea, 0xd7d7db, 0xb8b6c2, 0xc8c6ce, 0xd7d5da, 0xd3d1d6, 0xd4d0d5, 0xc4bdc6, 0xa598a8, 0x816a82, 0x5a3557, 0x34022d, 0x330128, 0x350027, 0x370125, 0x511b40, 0xa58d9b, 0xddd9dc, 0xeaeaea, 0xeaeaea, 0xeaeaea, 0xb6a3af, 0x5b1f41, 0x430022, 0x440021, 0x440021, 0x450021, 0x460021, 0x470121, 0x9d7d8c, 0xe5e3e4, 0x000000, + 0xe7e7e7, 0xeaeaea, 0xdbd4d8, 0x520629, 0x4a001f, 0x4a0020, 0x490020, 0x977284, 0xeaeaea, 0xeaeaea, 0xe7e6e7, 0x4f072d, 0x440021, 0x430022, 0xa28695, 0xeaeaea, 0xeaeaea, 0xbbabb6, 0x3c0024, 0x3e022a, 0xeaeaea, 0xe1dfe0, 0x320128, 0x5a3456, 0xeaeaea, 0xc7bfc8, 0x33103e, 0xd4d0d6, 0xe3e2e4, 0x938da1, 0xdedde0, 0xeaeaea, 0xeaeaea, 0xeaeaea, 0xeaeaea, 0xeaeaea, 0xeaeaea, 0x8f8196, 0x42224c, 0x674c6a, 0xa292a2, 0xe2e0e2, 0xeaeaea, 0xcec6cb, 0x988092, 0x4b143b, 0x3a0024, 0x3d0024, 0x3e0023, 0x571c3f, 0xa48897, 0xeaeaea, 0xeaeaea, 0xeaeaea, 0xe8e8e8, 0x9f8190, 0x470123, 0x460020, 0x470020, 0x470020, 0x490020, 0x490020, 0x6d314d, 0xad8fa3, + 0xe8e8e8, 0xe9e9e9, 0xeaeaea, 0x865369, 0x4c001f, 0x4c001f, 0x4c001f, 0x5c1636, 0xe4e2e3, 0xeaeaea, 0xeaeaea, 0x895c72, 0x460020, 0x450021, 0x794a62, 0xeaeaea, 0xeaeaea, 0xd2c9cd, 0x400124, 0x3d0023, 0xe2dfe1, 0xdad6d9, 0x360027, 0x75536d, 0xe9e9e9, 0x826b83, 0x857188, 0xeaeaea, 0xeaeaea, 0xe9e9e9, 0xe9e9e9, 0xe9e9e9, 0xe9e9ea, 0xe9e9e9, 0xe9e9e9, 0xeaeaea, 0xe9e9e9, 0xeae9ea, 0xd6d2d7, 0x887389, 0x380633, 0x3c0632, 0x83647b, 0xd8d3d6, 0xe9e9e9, 0xe2dfe1, 0x96798a, 0x46062c, 0x410022, 0x420022, 0x430021, 0x6a3350, 0xd7cfd3, 0xeaeaea, 0xeae9ea, 0xeaeaea, 0xcec3c8, 0x5e1a3a, 0x4a0020, 0x4a001f, 0x4b001f, 0x4b001f, 0x4c001f, 0x4d0021, + 0xe8e8e8, 0xe9e9e9, 0xe9e9e9, 0xcec0c6, 0x4e001e, 0x4e001e, 0x4d001e, 0x4d001e, 0xb096a2, 0xe9e8e8, 0xe9e9e9, 0xc9bbc1, 0x4b0121, 0x490020, 0x4f072a, 0xe4e1e2, 0xe9e9e9, 0xe4e2e3, 0x5b1f40, 0x410022, 0xc6b9c1, 0xe3e2e2, 0x3a0024, 0x8e7185, 0xe9e9e9, 0x4f2347, 0xd0cbd0, 0xe9e9e9, 0xe9e9e9, 0xe9e9e9, 0xe9e9e9, 0xe9e9e9, 0xe9e9e9, 0xe9e9e9, 0xe9e9e9, 0xe9e9e9, 0xe9e9e9, 0xe9e9e9, 0xe9e8e9, 0xe9e9e9, 0xd6d0d5, 0x83637b, 0x3c0127, 0x44062d, 0x967789, 0xe2e0e2, 0xe9e9e9, 0xd4ccd1, 0x76445e, 0x450021, 0x460020, 0x470020, 0x550f31, 0xb69ea9, 0xe9e9e9, 0xe9e9e9, 0xe9e9e9, 0xdad4d7, 0x784058, 0x4c001f, 0x4d001f, 0x4d001e, 0x4d001e, 0x4d001e, + 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe9e9e9, 0x844f64, 0x50001c, 0x50001c, 0x4f001e, 0x6f2e4a, 0xe9e9e9, 0xe8e8e8, 0xe8e8e8, 0x6f324e, 0x4b001f, 0x4b001f, 0xa98c99, 0xe8e8e8, 0xe8e8e8, 0x8a6176, 0x450021, 0xab93a0, 0xe8e8e8, 0x47052b, 0x997c8e, 0xe8e8e8, 0xe2e0e1, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe7e7e7, 0xe8e8e8, 0xbdaeb7, 0x521337, 0x430022, 0x642947, 0xd9d3d6, 0xe8e8e8, 0xe8e8e8, 0x9b7888, 0x4e0325, 0x4a001f, 0x4b001f, 0x4c001f, 0xa07e8c, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0x88566b, 0x4f001e, 0x4f001e, 0x50001e, 0x50001c, + 0xe9e9e9, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xd4cacd, 0x560324, 0x52001c, 0x51001c, 0x51001c, 0xb296a0, 0xe8e8e8, 0xe8e8e8, 0xbba5af, 0x4f001e, 0x4e001e, 0x71314c, 0xe8e8e8, 0xe8e8e8, 0xc1b0b8, 0x4a001f, 0x835269, 0xe8e8e8, 0x5e2141, 0x9b7b8c, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0xe8e8e8, 0x9e8393, 0x855d73, 0xe8e8e8, 0xd4cdd1, 0x5f1f3e, 0x490020, 0x5c1738, 0xc8bac0, 0xe8e8e8, 0xe8e8e8, 0xb196a2, 0x570a2b, 0x4e001e, 0x4e001e, 0x4f001e, 0x94687b, 0xe7e7e7, 0xe8e8e8, 0xe8e8e8, 0xe8e7e7, 0x996e7f, 0x51001c, 0x51001c, 0x51001d, + 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xa27c8a, 0x54001b, 0x53001b, 0x53001b, 0x661936, 0xe2e0e0, 0xe7e7e7, 0xe6e6e6, 0x80465c, 0x51001c, 0x51001c, 0xb296a0, 0xe8e8e8, 0xe2e0e1, 0x682441, 0x5a0d2d, 0xe6e6e6, 0x84556a, 0x946d7f, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe8e8e8, 0xe8e7e8, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xd8d2d5, 0x642744, 0x8e6578, 0xe7e7e7, 0xd8d0d4, 0x6a2a45, 0x4e001e, 0x5b0d2e, 0xc4b3b9, 0xe7e7e7, 0xe7e7e7, 0xc6b6bc, 0x52011f, 0x51001c, 0x51001c, 0x51001c, 0x9e7887, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe5e4e5, 0x8d5a6d, 0x53001b, 0x53001b, + 0xdcd6d8, 0xe6e6e6, 0xe7e7e7, 0xe6e6e6, 0xe7e6e6, 0xe5e3e3, 0x712541, 0x56001a, 0x55001a, 0x56001b, 0x996b7b, 0xe7e6e7, 0xe7e7e7, 0xcfc3c7, 0x5d0727, 0x54001b, 0x6e2741, 0xe3e1e2, 0xe7e7e7, 0xae8f9a, 0x52001c, 0xbba3ad, 0xa88894, 0x80475f, 0xe6e6e6, 0xe7e7e7, 0xe7e7e7, 0xe6e6e6, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe7e6e7, 0xe7e7e7, 0xe6e6e6, 0xe7e7e7, 0xe7e6e7, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xe7e7e7, 0xc7b8bd, 0x4f001e, 0xad909b, 0xe7e7e7, 0xd3c8cd, 0x601030, 0x52001c, 0x641735, 0xd4c9cd, 0xe7e7e7, 0xe6e6e6, 0xb499a4, 0x54001b, 0x54001b, 0x54001b, 0x54001b, 0xa98592, 0xe7e6e6, 0xe6e6e6, 0xe7e7e7, 0xddd8da, 0x82465d, 0x55001a, + 0x8c5164, 0xe5e5e5, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xd3c8cc, 0x630d2b, 0x580019, 0x58001a, 0x5a001a, 0xbda5ad, 0xe6e6e6, 0xe6e6e6, 0xab8693, 0x590019, 0x58001a, 0xa07683, 0xe6e6e6, 0xdfdcdd, 0x681935, 0x804156, 0xe0ddde, 0x762e47, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0x915f72, 0x5c0524, 0xd6cacf, 0xe6e6e6, 0xc4b2b8, 0x57001b, 0x56001a, 0x6e223e, 0xdcd4d7, 0xe6e6e6, 0xe6e6e6, 0xa17887, 0x56001a, 0x57001a, 0x57001a, 0x5c0220, 0xc2adb4, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xd9d2d4, 0x691935, + 0x5b0019, 0xae8b96, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e5e5, 0xe6e6e6, 0xae8a96, 0x5e011b, 0x5c0019, 0x5c0019, 0x670d2a, 0xd6cbcf, 0xe6e6e6, 0xe5e3e4, 0x8c5164, 0x5c0018, 0x640624, 0xbfa6ae, 0xe6e6e6, 0xba9ea8, 0x5d0018, 0xcab7bd, 0xd3c6ca, 0xe5e5e5, 0xe6e5e5, 0xe6e5e6, 0xe6e6e6, 0xe6e5e5, 0xe6e6e6, 0xe6e5e5, 0xe6e6e6, 0xe6e5e5, 0xe6e5e5, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe6e6e6, 0xe5e5e5, 0xccbbc0, 0xcebfc4, 0x5d011c, 0x905669, 0xe6e6e6, 0xe6e6e6, 0x9a6a7a, 0x5a0019, 0x5a0019, 0x976676, 0xe5e5e5, 0xe6e6e6, 0xe5e4e4, 0x7c374e, 0x580019, 0x5a0019, 0x5a0019, 0x691431, 0xdbd4d6, 0xe6e6e6, 0xe5e5e5, 0xe6e6e6, 0xc3afb5, + 0x5e0018, 0x630622, 0xc9b6bc, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xa27482, 0x5e0017, 0x5e0017, 0x5f0017, 0x7d3046, 0xdad4d5, 0xe5e5e5, 0xe3e2e2, 0x80364c, 0x600017, 0x690a25, 0xd0c0c4, 0xe5e4e4, 0xa16d7b, 0x813246, 0xe1dede, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe5e4e4, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe4e2e3, 0x761f36, 0xe5e5e5, 0x863f54, 0x61011a, 0xcab7bd, 0xe5e5e5, 0xdfdcdd, 0x721e37, 0x5e0018, 0x5e011a, 0xc2adb4, 0xe5e5e5, 0xe5e5e5, 0xdad2d5, 0x6b1631, 0x5c0018, 0x5c0019, 0x5c0019, 0x88495d, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, 0xe5e5e5, + 0x600018, 0x5f0018, 0x6c122d, 0xd4c7cb, 0xe5e5e5, 0xe5e5e5, 0xe4e4e4, 0xe5e5e5, 0xe4e4e4, 0x986372, 0x610017, 0x610016, 0x620016, 0x884254, 0xdbd4d6, 0xe4e4e4, 0xdedadb, 0x7d2940, 0x650016, 0x761931, 0xd1c1c5, 0xe4e3e3, 0x832e41, 0xa87580, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe5e4e4, 0xe4e4e4, 0xe4e4e4, 0xe5e5e5, 0xe5e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0x812a3e, 0xcdbbbf, 0xba9aa4, 0x640014, 0x955767, 0xe4e4e4, 0xe5e4e4, 0xaa818c, 0x610017, 0x600017, 0x7f3349, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xae8994, 0x5e0018, 0x5e0018, 0x5e0018, 0x5e0018, 0xc0a7ae, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, + 0x610016, 0x610017, 0x610017, 0x741c35, 0xdad2d4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0x9b6473, 0x640016, 0x640014, 0x650014, 0x7b2238, 0xdad0d3, 0xe4e4e4, 0xdcd6d8, 0x9e6370, 0x690013, 0x7b182e, 0xc7aeb4, 0xdfdbdc, 0x934352, 0xc19fa5, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0xe4e4e4, 0x944b5b, 0xb48b94, 0xded9db, 0x6b0118, 0x6f0922, 0xd9cfd1, 0xe4e4e4, 0xe0ddde, 0x6e0c28, 0x630016, 0x630016, 0xc2aab0, 0xe4e4e4, 0xe4e4e4, 0xdedadb, 0x79273e, 0x610017, 0x600017, 0x600017, 0x78273e, 0xe0ddde, 0xe4e4e4, 0xe5e4e4, + 0x620016, 0x630016, 0x630014, 0x630016, 0x781f37, 0xd6cccf, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xaa7c87, 0x670013, 0x680013, 0x690013, 0x791930, 0xcfbdc1, 0xe3e3e3, 0xe3e3e3, 0xb78e97, 0x740318, 0x730112, 0xaa6e7a, 0xdcd5d6, 0xd4c2c6, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe4e4e4, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0x9d5664, 0xa2616d, 0xe4e4e4, 0x83283c, 0x6c0012, 0xb58c95, 0xe3e3e3, 0xe4e4e4, 0x9b606e, 0x660014, 0x660014, 0x802d42, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xb796a0, 0x630016, 0x620016, 0x620016, 0x620016, 0xb08c96, 0xe3e3e3, 0xe5e5e5, + 0x640018, 0x650014, 0x650014, 0x650014, 0x650014, 0x771931, 0xd4c7ca, 0xe3e2e2, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xbc9aa1, 0x740b22, 0x6b0012, 0x6c0011, 0x710218, 0xaa757f, 0xded8d9, 0xe3e3e3, 0xd5c6c9, 0xa05765, 0x7a0112, 0x8c2233, 0xc8a7ab, 0xe3e3e3, 0xe3e3e3, 0xe2e2e2, 0xe3e2e2, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e3e3, 0xe3e2e2, 0xe3e3e3, 0xe3e3e3, 0xc9aaad, 0xbe8e94, 0xe3e2e2, 0x9e505d, 0x9b4d5c, 0xe3e3e3, 0x9c5765, 0x6f0011, 0x9a5564, 0xe3e3e3, 0xe3e3e3, 0xcab5b9, 0x690013, 0x690013, 0x680013, 0xccb9be, 0xe3e3e3, 0xe2e2e2, 0xdfdbdc, 0x71112a, 0x650016, 0x640016, 0x640016, 0x782138, 0xdcd6d7, 0xe2e2e2, + 0x6a031a, 0x670014, 0x670014, 0x670014, 0x680013, 0x680013, 0x6d031b, 0xc0a5ab, 0xe2e2e2, 0xe2e2e2, 0xe2e2e2, 0xe2e2e2, 0xe2e2e2, 0xd5c8ca, 0x98505f, 0x710011, 0x720010, 0x730010, 0x841c30, 0xbf99a0, 0xe2e2e2, 0xe2e2e2, 0xd9ced0, 0xb1737b, 0x8e1727, 0x941e2b, 0xbf888d, 0xdbcfd0, 0xe2e2e2, 0xe3e2e2, 0xe2e2e2, 0xe2e2e2, 0xe2e2e2, 0xe2e2e2, 0xe2e2e2, 0xe2e2e2, 0xe2e2e2, 0xe1ddde, 0x9b303c, 0xbc868c, 0xe2e2e2, 0x963846, 0x994250, 0xe2e2e2, 0xa86b77, 0x730010, 0x821e32, 0xe2e2e2, 0xe2e2e2, 0xdedbdc, 0x7b182d, 0x6b0012, 0x6a0013, 0xa26977, 0xe2e2e2, 0xe2e2e2, 0xe2e2e2, 0xae848f, 0x660014, 0x660014, 0x660014, 0x650014, 0xb5919b, 0xe1e1e1, + 0xe0e0e0, 0xaa7a85, 0x6a0117, 0x690013, 0x690013, 0x6a0013, 0x6b0012, 0x6b0012, 0xa8757f, 0xe0e0e0, 0xe2e1e1, 0xe2e1e2, 0xe2e2e2, 0xe2e2e2, 0xe2e2e2, 0xc09ea5, 0x8e3545, 0x76000e, 0x78000d, 0x7a000c, 0x8b1f30, 0xb9878d, 0xd4c2c5, 0xe2e2e2, 0xe2e1e1, 0xd5c2c4, 0xc18b8f, 0xc2878c, 0xe2e2e2, 0xe2e2e2, 0xe2e2e2, 0xe2e2e2, 0xe2e1e1, 0xe2e2e2, 0xe2e1e1, 0xdcd0d1, 0xc18085, 0xcdacae, 0x8c010a, 0xd9cacb, 0xe2e1e2, 0x8a1122, 0x9a414e, 0xe2e2e2, 0xb17c85, 0x77000e, 0x770113, 0xe0dfdf, 0xe2e1e1, 0xe2e2e2, 0x9a5563, 0x6d0011, 0x6d0012, 0x7e1f34, 0xe2e2e2, 0xe2e2e2, 0xe2e2e2, 0xd5cbcd, 0x690014, 0x680013, 0x670014, 0x670014, 0x85354a, 0xdfdfdf, + 0x000000, 0xe2e0e2, 0xbb9ba2, 0x760e25, 0x6b0012, 0x6c0012, 0x6c0011, 0x6e0012, 0x6e0011, 0x811b31, 0xc8b1b6, 0xe1e1e1, 0xe1e1e1, 0xe1e1e1, 0xe1e1e1, 0xe1e1e1, 0xe1e1e1, 0xc4a2a8, 0x9e4d5a, 0x7f0111, 0x7f000b, 0x810009, 0x85000b, 0x9a2c38, 0xac545e, 0xbc7c82, 0xc48c91, 0xca9b9e, 0xcb9a9c, 0xca8d8e, 0xc87c7d, 0xc66666, 0xd29b9c, 0xded5d5, 0xd7bfbf, 0xb13f44, 0xdcd1d2, 0xa22731, 0xa9454f, 0xe1e1e1, 0xdacecf, 0x830009, 0xa04953, 0xe1e1e1, 0xb7868e, 0x7a000d, 0x78000d, 0xd2c2c4, 0xe1e1e1, 0xe1e1e1, 0xb1838c, 0x710010, 0x6f0011, 0x6e0011, 0xd1c2c5, 0xe1e1e1, 0xe1e1e1, 0xe1e0e1, 0x8c4051, 0x6a0013, 0x690013, 0x690013, 0x680014, 0x000000, + 0x000000, 0xe0e0e0, 0xe0e0e0, 0xd2c5c8, 0x883345, 0x6e0012, 0x6f0011, 0x710011, 0x710011, 0x720010, 0x730010, 0x994c5a, 0xd4c7ca, 0xe0e0e0, 0xe0e0e0, 0xe0e0e0, 0xe0e0e0, 0xe0e0e0, 0xe1e1e1, 0xdbd3d4, 0xc0949a, 0xa95c64, 0x972432, 0x8f0614, 0x8d0005, 0x910004, 0x950004, 0x9d040c, 0xa81c22, 0xb94e51, 0xc87e7f, 0xded5d6, 0xdfdada, 0xc98283, 0xae191c, 0xd9c3c4, 0xbb6a6e, 0x960003, 0xceacaf, 0xe1e1e1, 0xc3979b, 0x870008, 0xab5f67, 0xe0e0e0, 0xb57f86, 0x7d000b, 0x7b000c, 0xc7aaaf, 0xe1e0e1, 0xe1e1e1, 0xcab3b6, 0x74000e, 0x730010, 0x710011, 0xb58c94, 0xe1e0e0, 0xe1e1e1, 0xe0e0e0, 0xb0848d, 0x6c0012, 0x6b0012, 0x6a0012, 0x6a0012, 0x000000, + 0x000000, 0xe1e1e1, 0xe0e0e0, 0xe0e0e0, 0xdfdede, 0xb48991, 0x7c1228, 0x720010, 0x730010, 0x74000f, 0x75000e, 0x76000e, 0x7b0316, 0x9c4d5a, 0xc7aaae, 0xe0e0e0, 0xe0e0e0, 0xe0e0e0, 0xe0e0e0, 0xe0e0e0, 0xe0e0e0, 0xe0e0e0, 0xe0e0e0, 0xe0e0e0, 0xdfddde, 0xded9da, 0xdfddde, 0xe0e0e0, 0xe0e0e0, 0xe0e0e0, 0xe0e0e0, 0xce8b8b, 0xb92323, 0xb72d2e, 0xdac7c7, 0xcc989a, 0x9d0002, 0xad3f45, 0xe0e0e0, 0xe0e0e0, 0xa94e56, 0x8b0007, 0xbf8d92, 0xe0e0e0, 0xb06e78, 0x80000b, 0x7e000b, 0xc4a2a7, 0xe0e0e0, 0xe0e0e0, 0xd2c4c7, 0x770010, 0x75000e, 0x74000f, 0xa56874, 0xe0e0e0, 0xe0e0e0, 0xe0e0e0, 0xd0c1c4, 0x6e0012, 0x6d0012, 0x6c0012, 0x6c0012, 0x000000, + 0x000000, 0xdbdbdb, 0xdfdfdf, 0xdfdfdf, 0xdfdfdf, 0xdfdfdf, 0xdbd5d6, 0xa2616c, 0x790318, 0x76000e, 0x77000d, 0x79000d, 0x7a000c, 0x7b000c, 0x7c000c, 0x881323, 0xb0727a, 0xcbb1b4, 0xdedbdb, 0xdfdfdf, 0xe0e0e0, 0xdfdfdf, 0xdfdfdf, 0xdfdfdf, 0xdfdfdf, 0xe0e0e0, 0xe0e0e0, 0xdfdfdf, 0xd4b5b6, 0xc26a6c, 0xb21819, 0xb10000, 0xc86d6d, 0xdfdddd, 0xd2acad, 0xa7090f, 0x9f0002, 0xd5bdbe, 0xdfdfdf, 0xdbd2d3, 0x960d19, 0x8c0006, 0xceb4b6, 0xe0e0e0, 0xaa5f68, 0x82000a, 0x80000a, 0xc5a3a9, 0xdfdfdf, 0xe0dfdf, 0xd9d0d1, 0x7e061b, 0x77000d, 0x76000f, 0x8e3443, 0xdfdfdf, 0xe0e0e0, 0xdfdfdf, 0xdfdfdf, 0x7a0f24, 0x6e0011, 0x6e0012, 0x55002a, 0x000000, + 0x000000, 0x000000, 0xdcdcdc, 0xdfdfdf, 0xdedede, 0xdfdfdf, 0xdfdfdf, 0xdfdfdf, 0xd3c6c7, 0xa25d68, 0x841123, 0x7b000c, 0x7c000c, 0x7d000b, 0x7f000b, 0x81000a, 0x820009, 0x840009, 0x87010c, 0x992a35, 0xaa535c, 0xb2656c, 0xb66b72, 0xb86c72, 0xb8686c, 0xb55a5f, 0xad383e, 0xa60a11, 0xa40001, 0xa90001, 0xba3a3c, 0xd6b5b5, 0xdfdfdf, 0xcd9293, 0xac060b, 0xa40001, 0xc68788, 0xdfdfdf, 0xdfdfdf, 0xc1898c, 0x910004, 0x940914, 0xdedcdd, 0xdfdede, 0x9c3541, 0x850009, 0x820009, 0xc8aaae, 0xdfdfdf, 0xdfdfdf, 0xdbd6d7, 0x830e21, 0x79000c, 0x78000d, 0x7c0519, 0xdfdedf, 0xdfdede, 0xdfdfdf, 0xdfdfdf, 0x924352, 0x710010, 0x6e0012, 0x000000, 0x000000, + 0x000000, 0x000000, 0xdfdfdf, 0xdddcdc, 0xdedede, 0xdedede, 0xdedede, 0xdedede, 0xdedede, 0xdedede, 0xdad4d4, 0xbf999f, 0x9d4955, 0x830414, 0x81000a, 0x82000a, 0x840009, 0x850007, 0x880006, 0x8a0006, 0x8c0006, 0x8e0005, 0x910004, 0x940003, 0x970003, 0x9a0002, 0x9e0002, 0xa5070d, 0xba5154, 0xd3b0b0, 0xdedddd, 0xdcd4d4, 0xc87071, 0xad0000, 0xa90000, 0xc0686b, 0xdedede, 0xdedede, 0xdbd4d4, 0x9f141e, 0x930004, 0xae535b, 0xdedede, 0xdddddd, 0x8d0311, 0x860007, 0x840009, 0xd1bec0, 0xdedede, 0xdedede, 0xdddbdb, 0x881326, 0x7b000c, 0x7a000c, 0x78000d, 0xdad4d5, 0xdedede, 0xdedede, 0xdedede, 0xae7a84, 0x730010, 0x70000a, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x923747, 0xb4858c, 0xdcd9d9, 0xdedede, 0xdedede, 0xdedede, 0xdedede, 0xdedede, 0xdedede, 0xdedede, 0xd6cbcc, 0xc6a7ab, 0xb17078, 0xa5515b, 0x962230, 0x900b19, 0x8d020d, 0x8f0109, 0x92010a, 0x980612, 0x9f1922, 0xad4047, 0xb96569, 0xcda1a4, 0xdacece, 0xdedede, 0xdedede, 0xd4b0b0, 0xbb2b2b, 0xb10000, 0xae0000, 0xbc4b4d, 0xdcd7d7, 0xdedede, 0xdedddd, 0xba676a, 0x980003, 0x950003, 0xcba8ab, 0xdedede, 0xcfb5b7, 0x8a0006, 0x880006, 0x87010b, 0xdcdada, 0xdedddd, 0xdedede, 0xdcd9d9, 0x881222, 0x7d000b, 0x7c000c, 0x7a000c, 0xd5cbcd, 0xdedede, 0xdedede, 0xdedede, 0xba939a, 0x730011, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x80000d, 0x78000d, 0x830d21, 0xa5606b, 0xcdb7bb, 0xdddddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xdedddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xdddddd, 0xd1acad, 0xba3d3e, 0xaf0000, 0xb20000, 0xb10000, 0xc26061, 0xdddddd, 0xdddddd, 0xdddddd, 0xd2b6b7, 0x9d0002, 0x990002, 0xa62d35, 0xdddddd, 0xdddddd, 0xb8757b, 0x8d0006, 0x8a0006, 0x921422, 0xdddddd, 0xdddddd, 0xdddddd, 0xd9d3d4, 0x86071a, 0x7f000b, 0x7d000b, 0x7c000c, 0xd2c4c6, 0xdddddd, 0xdddddd, 0xdddddd, 0xccb8bc, 0x71001c, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x7a000e, 0x7b000c, 0x7c000c, 0x7e000d, 0x932c3a, 0xb27a82, 0xcab1b5, 0xdcdbdb, 0xdddcdc, 0xdddcdc, 0xdddddd, 0xdddddd, 0xdddcdc, 0xdddcdc, 0xdddcdc, 0xdddcdc, 0xdcdcdc, 0xdcdcdc, 0xdddddd, 0xdcdcdc, 0xdddddd, 0xd6c2c3, 0xc37a7d, 0xb23336, 0xa90000, 0xab0000, 0xaf0000, 0xb30101, 0xc87272, 0xdddddd, 0xdddddd, 0xdddddd, 0xdcd8d8, 0xaa2025, 0x9e0002, 0x9b0002, 0xc79799, 0xdddddd, 0xdddcdc, 0x99141f, 0x8e0005, 0x8c0006, 0xa64c55, 0xdcdcdc, 0xdcdcdc, 0xdddcdc, 0xd4c8c9, 0x83010d, 0x80000a, 0x7f000b, 0x7e000b, 0xd2c3c5, 0xdcdcdc, 0xdcdcdc, 0xdddddd, 0xdddddd, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x7d000b, 0x7e000b, 0x7f000b, 0x80000a, 0x82000a, 0x820009, 0x870412, 0x9b3643, 0xac6169, 0xb67a81, 0xc39a9e, 0xc8a9ac, 0xccb0b2, 0xceb4b6, 0xcdb1b3, 0xcaa6a8, 0xc28b8f, 0xb9696e, 0xb14a4f, 0xa5131b, 0xa00001, 0xa30001, 0xa50001, 0xa90000, 0xac0000, 0xba3334, 0xd6bcbc, 0xdcdcdc, 0xdcdcdc, 0xdcdcdc, 0xdbd8d9, 0xb23235, 0xa10001, 0x9f0002, 0xae363d, 0xdbdada, 0xdcdcdc, 0xcba8ab, 0x920004, 0x900005, 0x8e0006, 0xb97e83, 0xdcdcdc, 0xdcdcdc, 0xdcdcdc, 0xccb4b6, 0x830009, 0x82000a, 0x80000a, 0x80000b, 0xd2c6c8, 0xdcdcdc, 0xdcdcdc, 0xdcdcdc, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x7f0011, 0x7f000a, 0x80000a, 0x81000a, 0x820009, 0x840009, 0x840007, 0x860007, 0x880007, 0x890006, 0x8b0006, 0x8d0006, 0x8e0005, 0x900004, 0x920004, 0x940003, 0x960003, 0x990003, 0x9d0002, 0x9e0002, 0xa10001, 0xa40001, 0xa70000, 0xae0a0d, 0xc98686, 0xdad3d3, 0xdbdbdb, 0xdcdbdb, 0xdcdbdb, 0xdbd9d9, 0xbf6163, 0xa50001, 0xa20001, 0xa10206, 0xd1b6b7, 0xdbdbdb, 0xdbdbdb, 0xae4b52, 0x930003, 0x910004, 0x8f0005, 0xccb1b4, 0xdcdcdc, 0xdcdbdb, 0xdcdcdc, 0xc29ca0, 0x840007, 0x830009, 0x820009, 0x81000a, 0xd5cbcd, 0xdcdbdb, 0xdbdbdb, 0xd9d9d9, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x7f000a, 0x82000a, 0x830009, 0x840009, 0x850007, 0x860007, 0x880007, 0x890006, 0x8b0006, 0x8c0006, 0x8e0005, 0x900005, 0x910004, 0x950003, 0x960003, 0x980003, 0x9a0002, 0x9c0002, 0x9f0001, 0xa20001, 0xae2227, 0xc47e7f, 0xd8cece, 0xdbdbdb, 0xdbdbdb, 0xdbdbdb, 0xdbdbdb, 0xd8cccc, 0xbe5354, 0xa80000, 0xa60001, 0xa30001, 0xc1797b, 0xdbdbdb, 0xdbdbdb, 0xd2bfc0, 0x9a0209, 0x940003, 0x920004, 0x9e242e, 0xdbdada, 0xdbdbdb, 0xdbdadb, 0xdbdbdb, 0xb27178, 0x860007, 0x840009, 0x830009, 0x83000b, 0xdad7d7, 0xdbdbdb, 0xd8d8d8, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x850009, 0x840009, 0x860008, 0x860007, 0x880006, 0x890006, 0x8b0006, 0x8c0006, 0x8e0006, 0x900005, 0x910004, 0x940003, 0x960003, 0x980003, 0x990002, 0x9c0003, 0xa61a20, 0xbc686c, 0xd0b2b3, 0xdadada, 0xdadada, 0xdadada, 0xdadada, 0xdadada, 0xdadada, 0xd6c5c5, 0xb72829, 0xad0000, 0xaa0000, 0xa60001, 0xb13135, 0xdbdbdb, 0xdadada, 0xdadada, 0xaf464d, 0x980003, 0x960003, 0x940003, 0xbb7e82, 0xdadada, 0xdadada, 0xdadada, 0xdadada, 0xa34650, 0x880008, 0x860007, 0x850007, 0x8f1424, 0xdadada, 0xd9d9d9, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xd4d4d4, 0xc9adb0, 0xc19b9f, 0xb3767c, 0xa64f59, 0xa13d46, 0x9e323d, 0x9b2430, 0x9b1e29, 0x9d1f2a, 0xa23038, 0xa94047, 0xaf5156, 0xbb7377, 0xc59294, 0xd5c9ca, 0xdadada, 0xdadada, 0xdadada, 0xdadada, 0xdadada, 0xdadada, 0xdadada, 0xdadada, 0xcd9393, 0xb50d0d, 0xae0000, 0xad0000, 0xa90000, 0xaf191e, 0xd6c6c7, 0xdadada, 0xdadada, 0xca9ea0, 0x9c0002, 0x990002, 0x970003, 0x980109, 0xd2c0c2, 0xdadada, 0xdadada, 0xdadada, 0xd7d1d1, 0x8f0917, 0x890007, 0x880007, 0x860007, 0x9c3c46, 0xdbdbdb, 0xffffff, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xd4d4d4, 0xdbdbdb, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xdad9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd6c9c9, 0xbf494a, 0xb30000, 0xb10000, 0xaf0000, 0xac0000, 0xb01618, 0xd3c0c0, 0xd9d9d9, 0xd9d9d9, 0xd7d2d2, 0xa7181e, 0x9c0002, 0x9a0002, 0x980003, 0xad4c52, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xc5a0a4, 0x8c0006, 0x8a0006, 0x890007, 0x870007, 0x9e3945, 0xd4d4d4, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xd4d4d4, 0xdadada, 0xd9d9d9, 0xd8d8d8, 0xd9d9d9, 0xd8d8d8, 0xd8d8d8, 0xd9d8d8, 0xd9d8d8, 0xd9d9d9, 0xd9d9d9, 0xd8d8d8, 0xd9d9d9, 0xd8d8d8, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd9d9d9, 0xd5caca, 0xc16566, 0xb30c0d, 0xb10000, 0xb30000, 0xb10000, 0xaf0000, 0xb21618, 0xd3bcbc, 0xd9d9d9, 0xd9d8d8, 0xd9d9d9, 0xbb6669, 0x9f0001, 0x9d0002, 0x9b0002, 0x9a0003, 0xceb5b6, 0xd9d8d8, 0xd9d9d9, 0xd8d8d8, 0xd9d9d9, 0xb1656b, 0x8d0006, 0x8b0006, 0x8a0006, 0x8a0006, 0x7f0000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xffffff, 0xd9d9d9, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xcfb2b3, 0xbe6365, 0xad0609, 0xac0000, 0xae0000, 0xb10000, 0xb30000, 0xb10000, 0xb72324, 0xd4c3c4, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xc5888a, 0xa20001, 0x9f0001, 0x9e0002, 0x9b0002, 0xaf454c, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xd8d8d8, 0xd7d7d7, 0x97141f, 0x8e0005, 0x8c0006, 0x8d0005, 0x950015, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xd5d5d5, 0xd8d8d8, 0xd8d7d7, 0xd8d8d8, 0xd7d7d7, 0xd8d8d8, 0xd8d7d7, 0xd8d8d8, 0xd8d7d7, 0xd7d6d6, 0xd0bcbc, 0xc28183, 0xae252a, 0xa60001, 0xa80000, 0xaa0000, 0xad0000, 0xb00000, 0xb10000, 0xb20000, 0xc05051, 0xd7d7d7, 0xd8d8d8, 0xd8d7d7, 0xd8d8d8, 0xd0b8b9, 0xa50001, 0xa20001, 0xa10001, 0x9e0001, 0xa0060e, 0xd2c4c5, 0xd8d8d8, 0xd8d8d8, 0xd8d7d7, 0xd8d7d7, 0xc8a8aa, 0x910004, 0x8f0004, 0x8e0005, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xd9d9d9, 0xd8d8d8, 0xd7d7d7, 0xd4cdcd, 0xcbafb0, 0xc39093, 0xbb7276, 0xb2494f, 0xa40e14, 0xa10001, 0xa40001, 0xa50001, 0xa70000, 0xa90000, 0xab0000, 0xad0000, 0xaf0000, 0xb30505, 0xc98485, 0xd7d7d7, 0xd7d7d7, 0xd7d7d7, 0xd7d7d7, 0xd0b6b7, 0xab0d11, 0xa40001, 0xa30001, 0xa10001, 0xa00001, 0xbc7578, 0xd7d7d7, 0xd7d7d7, 0xd7d7d7, 0xd7d7d7, 0xd7d7d7, 0xa8414a, 0x920005, 0x900006, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x990411, 0x970002, 0x990002, 0x9a0002, 0x9c0002, 0x9e0002, 0xa10001, 0xa10001, 0xa30001, 0xa60001, 0xa70001, 0xa90000, 0xab0000, 0xad0000, 0xbc4445, 0xd2bdbd, 0xd7d6d6, 0xd6d6d6, 0xd6d6d6, 0xd6d6d6, 0xd0b5b6, 0xad0e12, 0xa70001, 0xa50001, 0xa30001, 0xa20001, 0xab252b, 0xd5d1d2, 0xd6d6d6, 0xd6d6d6, 0xd6d6d6, 0xd7d6d6, 0xcfbcbe, 0x990510, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x8e0000, 0x9b0002, 0x9b0001, 0x9d0002, 0xa00002, 0xa00001, 0xa30001, 0xa40001, 0xa60001, 0xa80000, 0xab0001, 0xb53031, 0xcba1a2, 0xd6d6d6, 0xd6d6d6, 0xd6d6d6, 0xd6d6d6, 0xd6d6d6, 0xceaeae, 0xb11417, 0xa90000, 0xa70000, 0xa50001, 0xa40001, 0xa60a10, 0xcfbabc, 0xd6d6d6, 0xd6d5d5, 0xd6d6d6, 0xd6d6d6, 0xd7d7d7, 0xd9d9d9, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x990000, 0x9f0002, 0xa00001, 0xa10001, 0xa30001, 0xa40001, 0xa80103, 0xb74446, 0xcca7a7, 0xd5d5d5, 0xd5d5d5, 0xd5d5d5, 0xd6d5d5, 0xd5d5d5, 0xd6d6d6, 0xc78282, 0xb00305, 0xab0000, 0xa90000, 0xa90000, 0xa60001, 0xa50102, 0xc69294, 0xd5d5d5, 0xd5d5d5, 0xd6d6d6, 0xd5d3d3, 0xdfdfdf, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xaa0000, 0xa20000, 0xa40002, 0xb85659, 0xceb7b7, 0xd5d5d5, 0xd5d5d5, 0xd5d5d5, 0xd5d5d5, 0xd5d5d5, 0xd5d4d4, 0xd3c9c9, 0xc36767, 0xb00000, 0xad0000, 0xac0000, 0xaa0000, 0xa80000, 0xa70001, 0xbf7476, 0xd6d5d5, 0xd4d4d4, 0xd5d5d5, 0xdbdbdb, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0xd7d7d7, 0xd4d4d4, 0xd6d6d6, 0xd6d5d5, 0xd5d5d5, 0xd4d4d4, 0xcfabab, 0xb81e1e, 0xb20000, 0xaf0000, 0xae0000, 0xac0000, 0xab0000, 0xaa0000, 0xa70303, 0xd6d6d6, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000 +};
\ No newline at end of file diff --git a/dev/Boot/BootKit/Shared/base.h b/dev/Boot/BootKit/Shared/base.h new file mode 100644 index 00000000..1270b36a --- /dev/null +++ b/dev/Boot/BootKit/Shared/base.h @@ -0,0 +1,26 @@ +#ifndef UTL_BASE_H +#define UTL_BASE_H + +#include <cstdint> +#include <cstddef> +#include <cmath> + +namespace utl +{ + + /** + * @brief Helper to get number of elements in array. + * + * @tparam T Auto-deduced element type + * @tparam N Auto-deduced number of elements + * @return Array size + */ + template <class T, size_t N> + constexpr size_t countof(T (&)[N]) + { + return N; + } + +} // namespace utl + +#endif
\ No newline at end of file diff --git a/dev/Boot/BootKit/Shared/bit.h b/dev/Boot/BootKit/Shared/bit.h new file mode 100644 index 00000000..fa0fab82 --- /dev/null +++ b/dev/Boot/BootKit/Shared/bit.h @@ -0,0 +1,247 @@ +#ifndef UTL_BIT_H +#define UTL_BIT_H + +#include <bit> + +namespace utl +{ + + /** + * @brief Size of object in terms of bits. + * + * @tparam T Object type + * @return Number of bits + */ + template <class T> + constexpr auto bit_size() + { + return sizeof(T) * 8; + } + + /** + * @brief Integer with all bits set to 1. + * + * @tparam T Integer type + * @return All set integer + */ + template <class T> + constexpr T bit_full() + { + return T(-1); + } + + /** + * @brief Wrap around mask for power of two number of bits + * within given integer type. For example: + * [ bit_wrap<uint8_t> = 8 - 1 = 0b111 ] + * [ bit_wrap<uint16_t> = 16 - 1 = 0b1111 ] + * [ bit_wrap<uint32_t> = 32 - 1 = 0b11111 ] + * + * @tparam T Integer type + * @return Wrap around mask for number of bits + */ + template <class T> + constexpr T bit_wrap() + { + return bit_size<T>() - 1; + } + + /** + * @brief Number of bits to fit bit_wrap<T> result, in other words + * bit width of (sizeof(T) * 8 - 1). For example: + * [ bit_shft<uint8_t> = bit_width(0b111) = 3 ] + * [ bit_shft<uint16_t> = bit_width(0b1111) = 4 ] + * [ bit_shft<uint32_t> = bit_width(0b11111) = 5 ] + * + * @tparam T Integer type + * @return Number of bits to shift to divide by sizeof(T) * 8 + */ + template <class T> + constexpr auto bit_shft() + { + return std::bit_width(bit_wrap<T>()); + } + + /** + * @brief Round up division by number of bits within given integer type, + * which sizeof(T) * 8 is power of two. + * + * @tparam T Inetegr type + * @param x Dividend + * @return Quotient + */ + template <class T> + constexpr auto bit_ceil(auto x) + { + return (x + bit_wrap<T>()) >> bit_shft<T>(); + } + + /** + * @brief Count leading zeros. + * + * @param x Unsigned integer argument + * @return Number of leading zeros + */ + constexpr unsigned cntlz(auto x) + { + if constexpr (std::is_same_v<decltype(x), int>) + return std::countl_zero(unsigned(x)); + else + return std::countl_zero(x); + } + + /** + * @brief Count trailing zeros. + * + * @param x Unsigned integer argument + * @return Number of trailing zeros + */ + constexpr unsigned cnttz(auto x) + { + if constexpr (std::is_same_v<decltype(x), int>) + return std::countr_zero(unsigned(x)); + else + return std::countr_zero(x); + } + + /** + * @brief Get number of words (integers) required to store N bits. + * + * @tparam T Word integer type + * @param n Number of bits to store + * @return Number of words + */ + template <class T> + constexpr size_t words_in_bits(size_t n) + { + return (n >> bit_shft<T>()) + !!(n & bit_wrap<T>()); + } + + /** + * @brief Get number of bytes required to store N bits. + * + * @param n Number of bits to store + * @return Number of bytes + */ + constexpr size_t bytes_in_bits(size_t n) + { + return words_in_bits<uint8_t>(n); + } + + /** + * @brief Make integer with bit at given position. + * + * @tparam T Inetegr type + * @param n Bit position + * @return Integer with set bit + */ + template <class T = unsigned> + constexpr T bit(int n) + { + return T(1) << n; + } + + /** + * @brief Get n-th bit of an integer. + * + * @tparam T Integer type + * @param x Integer + * @param n Bit position from LSB + * @return true if set + */ + template <class T> + constexpr bool get_bit(T x, int n) + { + return (x >> n) & 1; + } + + /** + * @brief Set n-th bit of an integer. + * + * @tparam T Integer type + * @param x Integer + * @param n Bit position from LSB + */ + template <class T> + constexpr void set_bit(T& x, int n) + { + x |= 1 << n; + } + + /** + * @brief Clear n-th bit of an integer. + * + * @tparam T Integer type + * @param x Integer + * @param n Bit position from LSB + */ + template <class T> + constexpr void clr_bit(T& x, int n) + { + x &= ~(1 << n); + } + + /** + * @brief Get n-th bit in array of words (starting from LSB). + * + * @tparam T Word type + * @param p Array of words + * @param n Index of bit to get + * @return true if set + */ + template <class T> + constexpr bool get_arr_bit(const T* p, unsigned n) + { + return get_bit(p[n >> bit_shft<T>()], n & bit_wrap<T>()); + } + + /** + * @brief Set n-th bit in array of words (starting from LSB). + * + * @tparam T Word type + * @param p Array of words + * @param n Index of bit to set + */ + template <class T> + constexpr void set_arr_bit(T* p, unsigned n) + { + set_bit(p[n >> bit_shft<T>()], n & bit_wrap<T>()); + } + + /** + * @brief Clear n-th bit in array of words (starting from LSB). + * + * @tparam T Word type + * @param p Array of words + * @param n Index of bit to clear + */ + template <class T> + constexpr void clr_arr_bit(T* p, unsigned n) + { + clr_bit(p[n >> bit_shft<T>()], n & bit_wrap<T>()); + } + + /** + * @brief Shift bits left in array of integer elements from least significant bit + * and considering 0-th byte as the right most. + * uint16_t example: 0b10000000'11100001 ==> 0b00000001'11000010. + * + * @tparam T Integer type + * @tparam L Length of array + * @param x Array of integers, nullptr not acceptable! + * @param len Number of elements + */ + template <class T, size_t L> + constexpr void shift_left(T (&x)[L]) + { + for (int i = L - 1; i > 0; --i) + { + x[i] <<= 1; + x[i] |= x[i - 1] >> bit_wrap<T>(); + } + x[0] <<= 1; + } + +} // namespace utl + +#endif
\ No newline at end of file |
