Files
crosspoint-reader-mod/lib/EpdFont/builtinFonts/bookerly_12_regular.h

2192 lines
164 KiB
C
Raw Normal View History

/**
* generated by fontconvert.py
* name: bookerly_12_regular
* size: 12
perf: Reduce overall flash usage by 30.7% by compressing built-in fonts (#831) ## Summary **What is the goal of this PR?** Compress reader font bitmaps to reduce flash usage by 30.7%. **What changes are included?** - New `EpdFontGroup` struct and extended `EpdFontData` with `groups`/`groupCount` fields - `--compress` flag in `fontconvert.py`: groups glyphs (ASCII base group + groups of 8) and compresses each with raw DEFLATE - `FontDecompressor` class with 4-slot LRU cache for on-demand decompression during rendering - `GfxRenderer` transparently routes bitmap access through `getGlyphBitmap()` (compressed or direct flash) - Uses `uzlib` for decompression with minimal heap overhead. - 48 reader fonts (Bookerly, NotoSans 12-18pt, OpenDyslexic) regenerated with compression; 5 UI fonts unchanged - Round-trip verification script (`verify_compression.py`) runs as part of font generation ## Additional Context ## Flash & RAM | | baseline | font-compression | Difference | |--|--------|-----------------|------------| | Flash (ELF) | 6,302,476 B (96.2%) | 4,365,022 B (66.6%) | -1,937,454 B (-30.7%) | | firmware.bin | 6,468,192 B | 4,531,008 B | -1,937,184 B (-29.9%) | | RAM | 101,700 B (31.0%) | 103,076 B (31.5%) | +1,376 B (+0.5%) | ## Script-Based Grouping (Cold Cache) Comparison of uncompressed baseline vs script-based group compression (4-slot LRU cache, cleared each page). Glyphs are grouped by Unicode block (ASCII, Latin-1, Latin Extended-A, Combining Marks, Cyrillic, General Punctuation, etc.) instead of sequential groups of 8. ### Render Time | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Median** | 414.9 ms | 431.6 ms | +16.7 ms (+4.0%) | | **Pages** | 37 | 37 | | ### Memory Usage | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Heap free (median)** | 187.0 KB | 176.3 KB | -10.7 KB | | **Heap free (min)** | 186.0 KB | 166.5 KB | -19.5 KB | | **Largest block (median)** | 148.0 KB | 128.0 KB | -20.0 KB | | **Largest block (min)** | 148.0 KB | 120.0 KB | -28.0 KB | ### Cache Effectiveness | | Misses/page | Hit rate | |---|---|---| | **Compressed (cold cache)** | 2.1 | 99.85% | ------ ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**YES**_ Implementation was done by Claude Code (Opus 4.6) based on a plan developed collaboratively. All generated font headers were verified with an automated round-trip decompression test. The firmware was compiled successfully but has not yet been tested on-device. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:30:15 +11:00
* mode: 2-bit compressed: true
fix: force auto-hinting for Bookerly to fix inconsistent stem widths (#1098) ## Summary Bookerly's native TrueType hinting is effectively a no-op at the sizes used here, causing FreeType to place stems at inconsistent sub-pixel positions. This results in the 'k' stem (8-bit fringe: 0x38=56) falling just below the 2-bit quantization threshold while 'l' and 'h' stems (fringes: 0x4C=76, 0x40=64) land above it --- making 'k' visibly narrower (2.00px vs 2.33px effective width). FreeType's auto-hinter snaps all stems to consistent grid positions, normalizing effective stem width to 2.67px across all glyphs. Adds --force-autohint flag to fontconvert.py and applies it to Bookerly only. NotoSans, OpenDyslexic, and Ubuntu fonts are unaffected. Here is an example of before/after. Take notice of the vertical stems on characters like `l`, `k`, `n`, `i`, etc. The font is Bookerly 12pt regular: **BEFORE**: ![before](https://github.com/user-attachments/assets/65b2acab-ad95-489e-885e-e3a0163cc252) **AFTER**: ![after](https://github.com/user-attachments/assets/d09a8b5d-40af-4a7d-b622-e1b2cabcce85) Claude generated this script to quantitatively determine that this change makes the vertical stems on a variety of characters more consistent for Bookerly _only_. <details> <summary>Python script</summary> ```python #!/usr/bin/env python3 """Compare stem consistency across all font families with and without auto-hinting. Run from repo root: python3 compare_all_fonts.py """ import freetype DPI = 150 CHARS = ["k", "l", "h", "i", "b", "d"] SIZES = [12, 14, 16, 18] FONTS = { "Bookerly": "lib/EpdFont/builtinFonts/source/Bookerly/Bookerly-Regular.ttf", "NotoSans": "lib/EpdFont/builtinFonts/source/NotoSans/NotoSans-Regular.ttf", "OpenDyslexic": "lib/EpdFont/builtinFonts/source/OpenDyslexic/OpenDyslexic-Regular.otf", "Ubuntu": "lib/EpdFont/builtinFonts/source/Ubuntu/Ubuntu-Regular.ttf", } MODES = { "default": freetype.FT_LOAD_RENDER, "autohint": freetype.FT_LOAD_RENDER | freetype.FT_LOAD_FORCE_AUTOHINT, } def q4to2(v): if v >= 12: return 3 elif v >= 8: return 2 elif v >= 4: return 1 else: return 0 def get_stem_eff(face, char, flags): gi = face.get_char_index(ord(char)) if gi == 0: return None face.load_glyph(gi, flags) bm = face.glyph.bitmap w, h = bm.width, bm.rows if w == 0 or h == 0: return None p2 = [] for y in range(h): row = [] for x in range(w): row.append(q4to2(bm.buffer[y * bm.pitch + x] >> 4)) p2.append(row) # Measure leftmost stem in stable middle rows mid_start, mid_end = h // 4, h - h // 4 widths = [] for y in range(mid_start, mid_end): first = next((x for x in range(w) if p2[y][x] > 0), -1) if first < 0: continue last = first for x in range(first, w): if p2[y][x] > 0: last = x else: break eff = sum(p2[y][x] for x in range(first, last + 1)) / 3.0 widths.append(eff) return round(sum(widths) / len(widths), 2) if widths else None def main(): for font_name, font_path in FONTS.items(): try: freetype.Face(font_path) except Exception: print(f"\n {font_name}: SKIPPED (file not found)") continue print(f"\n{'=' * 80}") print(f" {font_name}") print(f"{'=' * 80}") for size in SIZES: print(f"\n {size}pt:") print(f" {'':6s}", end="") for c in CHARS: print(f" '{c}' ", end="") print(" | spread") for mode_name, flags in MODES.items(): face = freetype.Face(font_path) face.set_char_size(size << 6, size << 6, DPI, DPI) vals = [] print(f" {mode_name:6s}", end="") for c in CHARS: v = get_stem_eff(face, c, flags) vals.append(v) print(f" {v:5.2f}" if v else " N/A", end="") valid = [v for v in vals if v is not None] spread = max(valid) - min(valid) if len(valid) >= 2 else 0 marker = " <-- inconsistent" if spread > 0.5 else "" print(f" | {spread:.2f}{marker}") if __name__ == "__main__": main() ``` </details> Here are the results. The table compares how the font-generation `autohint` flag affects the range of widths of various characters. Lower `spread` mean that glyph stroke widths should appear more consistent. ``` Spread = max stem width - min stem width across glyphs (lower = more consistent): ┌──────────────┬──────┬─────────┬──────────┬──────────┐ │ Font │ Size │ Default │ Autohint │ Winner │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Bookerly │ 12pt │ 1.49 │ 1.12 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.39 │ 1.13 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.38 │ 1.16 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.90 │ 1.58 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ NotoSans │ 12pt │ 1.16 │ 0.94 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 0.83 │ 1.14 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.41 │ 1.51 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.74 │ 1.63 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ OpenDyslexic │ 12pt │ 2.22 │ 1.44 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 2.57 │ 3.29 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 3.13 │ 2.60 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 3.21 │ 3.23 │ ~tied │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Ubuntu │ 12pt │ 1.25 │ 1.31 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.41 │ 1.64 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 2.21 │ 1.71 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.80 │ 1.71 │ autohint │ └──────────────┴──────┴─────────┴──────────┴──────────┘ ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? I used AI to make sure I'm not doing something stupid, since I'm not a typography expert. I made the changes though.
2026-02-24 06:13:08 +11:00
* Command used: fontconvert.py bookerly_12_regular 12 ../builtinFonts/source/Bookerly/Bookerly-Regular.ttf --2bit --compress --force-autohint
*/
#pragma once
#include "EpdFontData.h"
fix: force auto-hinting for Bookerly to fix inconsistent stem widths (#1098) ## Summary Bookerly's native TrueType hinting is effectively a no-op at the sizes used here, causing FreeType to place stems at inconsistent sub-pixel positions. This results in the 'k' stem (8-bit fringe: 0x38=56) falling just below the 2-bit quantization threshold while 'l' and 'h' stems (fringes: 0x4C=76, 0x40=64) land above it --- making 'k' visibly narrower (2.00px vs 2.33px effective width). FreeType's auto-hinter snaps all stems to consistent grid positions, normalizing effective stem width to 2.67px across all glyphs. Adds --force-autohint flag to fontconvert.py and applies it to Bookerly only. NotoSans, OpenDyslexic, and Ubuntu fonts are unaffected. Here is an example of before/after. Take notice of the vertical stems on characters like `l`, `k`, `n`, `i`, etc. The font is Bookerly 12pt regular: **BEFORE**: ![before](https://github.com/user-attachments/assets/65b2acab-ad95-489e-885e-e3a0163cc252) **AFTER**: ![after](https://github.com/user-attachments/assets/d09a8b5d-40af-4a7d-b622-e1b2cabcce85) Claude generated this script to quantitatively determine that this change makes the vertical stems on a variety of characters more consistent for Bookerly _only_. <details> <summary>Python script</summary> ```python #!/usr/bin/env python3 """Compare stem consistency across all font families with and without auto-hinting. Run from repo root: python3 compare_all_fonts.py """ import freetype DPI = 150 CHARS = ["k", "l", "h", "i", "b", "d"] SIZES = [12, 14, 16, 18] FONTS = { "Bookerly": "lib/EpdFont/builtinFonts/source/Bookerly/Bookerly-Regular.ttf", "NotoSans": "lib/EpdFont/builtinFonts/source/NotoSans/NotoSans-Regular.ttf", "OpenDyslexic": "lib/EpdFont/builtinFonts/source/OpenDyslexic/OpenDyslexic-Regular.otf", "Ubuntu": "lib/EpdFont/builtinFonts/source/Ubuntu/Ubuntu-Regular.ttf", } MODES = { "default": freetype.FT_LOAD_RENDER, "autohint": freetype.FT_LOAD_RENDER | freetype.FT_LOAD_FORCE_AUTOHINT, } def q4to2(v): if v >= 12: return 3 elif v >= 8: return 2 elif v >= 4: return 1 else: return 0 def get_stem_eff(face, char, flags): gi = face.get_char_index(ord(char)) if gi == 0: return None face.load_glyph(gi, flags) bm = face.glyph.bitmap w, h = bm.width, bm.rows if w == 0 or h == 0: return None p2 = [] for y in range(h): row = [] for x in range(w): row.append(q4to2(bm.buffer[y * bm.pitch + x] >> 4)) p2.append(row) # Measure leftmost stem in stable middle rows mid_start, mid_end = h // 4, h - h // 4 widths = [] for y in range(mid_start, mid_end): first = next((x for x in range(w) if p2[y][x] > 0), -1) if first < 0: continue last = first for x in range(first, w): if p2[y][x] > 0: last = x else: break eff = sum(p2[y][x] for x in range(first, last + 1)) / 3.0 widths.append(eff) return round(sum(widths) / len(widths), 2) if widths else None def main(): for font_name, font_path in FONTS.items(): try: freetype.Face(font_path) except Exception: print(f"\n {font_name}: SKIPPED (file not found)") continue print(f"\n{'=' * 80}") print(f" {font_name}") print(f"{'=' * 80}") for size in SIZES: print(f"\n {size}pt:") print(f" {'':6s}", end="") for c in CHARS: print(f" '{c}' ", end="") print(" | spread") for mode_name, flags in MODES.items(): face = freetype.Face(font_path) face.set_char_size(size << 6, size << 6, DPI, DPI) vals = [] print(f" {mode_name:6s}", end="") for c in CHARS: v = get_stem_eff(face, c, flags) vals.append(v) print(f" {v:5.2f}" if v else " N/A", end="") valid = [v for v in vals if v is not None] spread = max(valid) - min(valid) if len(valid) >= 2 else 0 marker = " <-- inconsistent" if spread > 0.5 else "" print(f" | {spread:.2f}{marker}") if __name__ == "__main__": main() ``` </details> Here are the results. The table compares how the font-generation `autohint` flag affects the range of widths of various characters. Lower `spread` mean that glyph stroke widths should appear more consistent. ``` Spread = max stem width - min stem width across glyphs (lower = more consistent): ┌──────────────┬──────┬─────────┬──────────┬──────────┐ │ Font │ Size │ Default │ Autohint │ Winner │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Bookerly │ 12pt │ 1.49 │ 1.12 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.39 │ 1.13 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.38 │ 1.16 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.90 │ 1.58 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ NotoSans │ 12pt │ 1.16 │ 0.94 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 0.83 │ 1.14 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.41 │ 1.51 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.74 │ 1.63 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ OpenDyslexic │ 12pt │ 2.22 │ 1.44 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 2.57 │ 3.29 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 3.13 │ 2.60 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 3.21 │ 3.23 │ ~tied │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Ubuntu │ 12pt │ 1.25 │ 1.31 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.41 │ 1.64 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 2.21 │ 1.71 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.80 │ 1.71 │ autohint │ └──────────────┴──────┴─────────┴──────────┴──────────┘ ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? I used AI to make sure I'm not doing something stupid, since I'm not a typography expert. I made the changes though.
2026-02-24 06:13:08 +11:00
static const uint8_t bookerly_12_regularBitmaps[21351] = {
0x8D, 0x58, 0xBD, 0x8F, 0xDC, 0xC6, 0x15, 0x7F, 0xE4, 0x38, 0x37, 0x81, 0x29, 0x6B, 0x04, 0xC4,
0x95, 0x37, 0x16, 0x5D, 0xA4, 0xD3, 0x07, 0x55, 0xB8, 0x10, 0x90, 0x5D, 0x92, 0xB6, 0x00, 0xAB,
0x70, 0x21, 0x15, 0x69, 0x13, 0xA7, 0x70, 0x19, 0xE0, 0x54, 0x04, 0xC1, 0x01, 0xDE, 0x5B, 0x52,
0x56, 0x99, 0x42, 0xF7, 0x07, 0x18, 0x88, 0xFF, 0x80, 0x00, 0xA7, 0xC2, 0x85, 0x9C, 0xEC, 0x1E,
0x79, 0x52, 0x61, 0x20, 0x29, 0x44, 0x45, 0x85, 0x0B, 0x23, 0xD1, 0x38, 0x12, 0x60, 0x07, 0x0A,
0x70, 0x74, 0xC2, 0xC4, 0x73, 0xBA, 0x59, 0x4E, 0x7E, 0x6F, 0xB8, 0x27, 0x5B, 0xF1, 0x49, 0xC9,
0x2E, 0x6F, 0x96, 0xE4, 0x7C, 0xBD, 0x8F, 0xDF, 0xFB, 0xBD, 0x37, 0x57, 0xB8, 0x9D, 0x83, 0x3D,
0xBE, 0x7E, 0xB7, 0x45, 0xBF, 0x3F, 0x28, 0x37, 0xDE, 0x7B, 0xB0, 0x77, 0x7D, 0x27, 0x35, 0x07,
0xF8, 0x29, 0x89, 0x8E, 0x8B, 0x9A, 0x5E, 0x12, 0x25, 0xFD, 0x50, 0xE6, 0x74, 0x3A, 0xCA, 0x95,
0x73, 0xF6, 0x7B, 0x1F, 0xFF, 0xEC, 0x27, 0x74, 0xE5, 0x55, 0xA2, 0x1B, 0xA7, 0x89, 0xF4, 0x98,
0x0A, 0xE7, 0x5A, 0xFC, 0xE9, 0xB0, 0xBE, 0x42, 0xA2, 0xBE, 0x41, 0xA2, 0x6C, 0x49, 0xE6, 0x1A,
0x73, 0x0F, 0xAF, 0x24, 0x97, 0xCE, 0x24, 0x1F, 0x2C, 0x36, 0x8F, 0xA5, 0xF3, 0x63, 0xA7, 0x17,
0xC7, 0x28, 0xFB, 0x80, 0xE2, 0x25, 0x85, 0xAE, 0xA1, 0x1F, 0x1B, 0x3A, 0xB7, 0xBC, 0x72, 0x2E,
0x6D, 0xCF, 0xA5, 0xE6, 0xDC, 0x74, 0xE7, 0x57, 0x26, 0x71, 0x4D, 0xD0, 0x11, 0xB5, 0xDF, 0xBA,
0xFC, 0x27, 0x24, 0x2A, 0x4A, 0xDA, 0xA0, 0xC4, 0x91, 0x22, 0x79, 0xD7, 0x04, 0x0D, 0xCD, 0x55,
0x7D, 0x9E, 0x54, 0x39, 0x8F, 0x88, 0x4C, 0xB4, 0xDB, 0x90, 0xAA, 0xCD, 0xF9, 0x64, 0x6B, 0x11,
0x5F, 0x54, 0xEE, 0x82, 0xD3, 0xF7, 0x5A, 0x1B, 0x75, 0xA7, 0x27, 0xB2, 0x21, 0x79, 0xB1, 0x4E,
0x21, 0xE9, 0x5C, 0x68, 0xA8, 0x50, 0x4F, 0x20, 0xDC, 0x14, 0x6F, 0x5B, 0xA1, 0x2D, 0x9D, 0xE1,
0xF5, 0x64, 0xC9, 0x4B, 0xBF, 0xE6, 0xB7, 0x49, 0x1E, 0x12, 0x49, 0x07, 0x01, 0x52, 0xA9, 0x29,
0x68, 0x55, 0x4E, 0xB2, 0x9E, 0x12, 0x29, 0x59, 0x13, 0x4D, 0x5E, 0x20, 0x12, 0x56, 0xB8, 0x3A,
0x35, 0xCA, 0x05, 0x6D, 0x27, 0x6A, 0x75, 0xB5, 0x53, 0x94, 0x06, 0x66, 0x4C, 0x26, 0x58, 0xEA,
0xB0, 0x25, 0x97, 0xCB, 0x2E, 0x70, 0x5B, 0xD2, 0xB9, 0x6D, 0x1B, 0x3A, 0x1D, 0x35, 0xEF, 0xB1,
0x69, 0x4B, 0x7A, 0x81, 0xC6, 0xD4, 0x85, 0x5A, 0xD6, 0x2A, 0x4F, 0x68, 0x42, 0x53, 0x9A, 0x93,
0x59, 0x7D, 0x2D, 0xEE, 0xA7, 0x94, 0x52, 0x02, 0x55, 0xA2, 0x46, 0xB4, 0x78, 0x01, 0xBB, 0x9E,
0xA0, 0x9B, 0x94, 0xE1, 0x8D, 0xC4, 0x1B, 0xD8, 0x83, 0x07, 0x6D, 0x62, 0x62, 0x8A, 0xEF, 0x64,
0xB5, 0x40, 0x17, 0xB4, 0xA2, 0x89, 0xEA, 0x18, 0x4B, 0x5F, 0x61, 0xD1, 0x37, 0xE4, 0x49, 0x71,
0x40, 0xF1, 0x9E, 0x7C, 0x74, 0xE7, 0xB7, 0xC1, 0xAF, 0xF3, 0x40, 0xC3, 0x76, 0x8A, 0x56, 0x0D,
0x1C, 0x07, 0x37, 0x3D, 0x79, 0xA4, 0x40, 0xB4, 0x36, 0x55, 0x6F, 0x5F, 0xDB, 0xAD, 0xAB, 0xA5,
0x5B, 0xCE, 0xDC, 0x82, 0xB0, 0x0C, 0xCC, 0x4B, 0x1D, 0xB4, 0xA6, 0xB0, 0x81, 0x27, 0x29, 0x2A,
0x79, 0xEC, 0x49, 0xDF, 0x33, 0xE5, 0x1E, 0xFA, 0x4E, 0xCF, 0x04, 0xFB, 0x56, 0x4D, 0xE0, 0x5C,
0x60, 0xA4, 0x36, 0x34, 0x9F, 0x92, 0xDA, 0x26, 0x58, 0x88, 0x2A, 0x4D, 0x89, 0xA1, 0xA8, 0x87,
0x93, 0x4B, 0x72, 0x2D, 0xA5, 0x73, 0x52, 0x97, 0xCA, 0xE8, 0x56, 0x17, 0xD5, 0x19, 0x3C, 0x8C,
0x97, 0xF4, 0x6E, 0x50, 0x95, 0xCE, 0x04, 0xDB, 0x25, 0x8C, 0xA0, 0x9E, 0xD1, 0x04, 0x95, 0x2D,
0x5C, 0x83, 0x35, 0x12, 0xD7, 0xCE, 0x42, 0x63, 0xC9, 0x62, 0x93, 0x77, 0xA1, 0x3C, 0xFA, 0x61,
0x6E, 0xF8, 0x48, 0xD5, 0xB0, 0x13, 0xEC, 0x23, 0x5B, 0x8A, 0x6B, 0x2A, 0x20, 0x8E, 0x5B, 0x16,
0xCE, 0x62, 0x87, 0xCA, 0x7D, 0xA2, 0x93, 0x9F, 0x52, 0x7A, 0x02, 0x92, 0x47, 0x35, 0x2D, 0x68,
0xBD, 0x11, 0x90, 0x24, 0xF2, 0x73, 0x12, 0x9E, 0x13, 0x35, 0x61, 0x1F, 0xBB, 0x86, 0x7D, 0x1E,
0xDC, 0x24, 0xCA, 0xA0, 0x95, 0xF1, 0x02, 0x6F, 0x62, 0xF7, 0xEB, 0x65, 0xD8, 0x1A, 0x9A, 0xAA,
0x52, 0xE5, 0x46, 0x68, 0xC0, 0x8C, 0xE0, 0x75, 0xD7, 0x03, 0xE9, 0x0D, 0x8B, 0x06, 0x01, 0x56,
0x3F, 0xC2, 0x39, 0xE1, 0x7A, 0xE1, 0x0D, 0xC3, 0xD7, 0xDF, 0x00, 0xA0, 0x66, 0xCD, 0x19, 0x0A,
0x2C, 0xC1, 0x69, 0xF0, 0x18, 0x5F, 0x9B, 0xFC, 0x38, 0x6A, 0x33, 0x57, 0xC7, 0x98, 0xB9, 0x66,
0xA8, 0x58, 0x86, 0x7D, 0x0E, 0x61, 0xE2, 0x92, 0xBB, 0x0B, 0x97, 0x57, 0xAE, 0x35, 0x21, 0xF4,
0x5B, 0x18, 0x4A, 0x2D, 0x5F, 0x93, 0x4D, 0x9A, 0x66, 0x39, 0x76, 0x6D, 0x43, 0xEE, 0x5D, 0x3A,
0xB7, 0x6C, 0x69, 0xDE, 0x06, 0xED, 0x16, 0x90, 0x0C, 0x8D, 0x00, 0xCE, 0xC4, 0xBB, 0x60, 0xCE,
0xCE, 0x81, 0x39, 0xF0, 0x1A, 0x62, 0x00, 0xAA, 0xD2, 0x4B, 0x12, 0x54, 0x4D, 0xE4, 0x4C, 0x5C,
0x2E, 0x33, 0x4A, 0x01, 0x9B, 0x04, 0xCA, 0xDC, 0xED, 0xE0, 0x1C, 0x00, 0x53, 0x5D, 0xB4, 0x63,
0x5A, 0x1A, 0x9A, 0xF9, 0xBD, 0x36, 0x77, 0x02, 0x0B, 0x03, 0xAF, 0xB9, 0xDC, 0x3B, 0xB3, 0x47,
0x38, 0xE9, 0x39, 0xD9, 0x94, 0xE2, 0x4B, 0xA5, 0x78, 0xD0, 0x92, 0x59, 0x50, 0xAA, 0x9A, 0xF8,
0x0D, 0xE7, 0xEA, 0x17, 0x61, 0x41, 0x46, 0x82, 0xE5, 0x2B, 0x5C, 0xD2, 0xBA, 0xA1, 0x18, 0xA1,
0xEE, 0x01, 0xE4, 0x3F, 0xB8, 0x93, 0xDA, 0x45, 0x0D, 0x1D, 0x7E, 0x66, 0xB2, 0xCD, 0x64, 0x33,
0x57, 0xA2, 0x39, 0x81, 0xA7, 0xCB, 0xF0, 0x92, 0x5C, 0x06, 0x3D, 0x22, 0x4E, 0x74, 0x24, 0x61,
0xA4, 0xDE, 0x07, 0x76, 0xDC, 0x10, 0xC2, 0x98, 0x18, 0xA5, 0xCE, 0x4F, 0xF3, 0x77, 0xAF, 0xB1,
0x7D, 0x0F, 0x47, 0x68, 0xF6, 0xF1, 0x7A, 0x19, 0x6B, 0xCC, 0xEA, 0xC1, 0x32, 0x3E, 0x5C, 0x9B,
0xD8, 0x49, 0xD7, 0xE6, 0x9B, 0xAC, 0x72, 0x4B, 0xE3, 0xB5, 0x5E, 0xF5, 0x58, 0x57, 0xD3, 0xF9,
0x61, 0x73, 0x0E, 0x22, 0x80, 0x15, 0xA6, 0xC0, 0x22, 0x80, 0x29, 0xDA, 0x2A, 0x5F, 0xB3, 0x94,
0x21, 0xAE, 0x5B, 0x98, 0x90, 0xE2, 0xAB, 0x1D, 0xB4, 0xB0, 0x19, 0xB9, 0x4E, 0x7E, 0xDA, 0xA4,
0x71, 0x39, 0x99, 0x87, 0xB5, 0x11, 0x7B, 0xB0, 0x6E, 0x99, 0x1A, 0xA8, 0x27, 0xEE, 0x97, 0x99,
0x2B, 0xA7, 0x46, 0x36, 0x46, 0x5D, 0xAF, 0xE7, 0xF1, 0xAD, 0x76, 0x2E, 0x5D, 0xB5, 0x94, 0x4D,
0x7C, 0xAB, 0x67, 0xE4, 0x61, 0x59, 0xC3, 0x2D, 0x3C, 0x89, 0xA0, 0x05, 0x94, 0x66, 0xEC, 0x4C,
0xC6, 0xF7, 0xE8, 0x71, 0x8E, 0xF7, 0x67, 0x78, 0x04, 0xAC, 0x45, 0x8A, 0x99, 0xEC, 0x3D, 0x8C,
0x12, 0x7F, 0xC4, 0xBE, 0x2A, 0x46, 0xE7, 0x47, 0x70, 0xBC, 0xA8, 0xE1, 0xBD, 0xB3, 0x3E, 0xB8,
0x10, 0xFB, 0x20, 0x0E, 0xE0, 0x99, 0xA7, 0xB7, 0x83, 0xE4, 0x9B, 0x1C, 0x7C, 0x46, 0xEE, 0xD3,
0x68, 0xBF, 0x00, 0xA8, 0xED, 0x2B, 0xC0, 0x15, 0x38, 0x98, 0xD2, 0x10, 0xDC, 0x21, 0xC0, 0x61,
0x51, 0xAD, 0xCA, 0x04, 0x08, 0xEA, 0xF0, 0xBA, 0x06, 0x14, 0xF9, 0x11, 0x74, 0x17, 0xE7, 0xF0,
0x2C, 0xF0, 0x60, 0x98, 0x42, 0x52, 0xAA, 0xA4, 0x27, 0xE9, 0x7D, 0x48, 0xD5, 0xE7, 0xB1, 0xB3,
0x91, 0x96, 0xBB, 0x1D, 0x8D, 0x53, 0x12, 0x9F, 0xD4, 0x74, 0x62, 0x4E, 0x4F, 0x23, 0x9A, 0xC1,
0xC5, 0xC8, 0x85, 0x40, 0x6C, 0xF6, 0xCB, 0x85, 0x83, 0xA3, 0x7B, 0x3A, 0x85, 0xF9, 0x08, 0x01,
0x2C, 0x4C, 0x05, 0xB6, 0x09, 0x11, 0x16, 0xA0, 0x76, 0x04, 0x80, 0x86, 0x1E, 0x16, 0x53, 0x13,
0x8F, 0x4B, 0x8E, 0x4C, 0xBC, 0xC0, 0xCE, 0x34, 0xE1, 0x11, 0x58, 0x30, 0xCE, 0x53, 0x78, 0x0E,
0x66, 0xC9, 0xBD, 0x0C, 0x50, 0xB0, 0xDD, 0x86, 0xA8, 0x29, 0x58, 0xC4, 0xD0, 0x69, 0x0C, 0xF2,
0x1B, 0xA7, 0xDE, 0xED, 0x08, 0x52, 0x97, 0x1F, 0x3E, 0x42, 0x16, 0xF4, 0xBE, 0xAE, 0xCA, 0x00,
0x4A, 0x44, 0x6F, 0x39, 0x8E, 0x6D, 0x87, 0x20, 0x72, 0x7F, 0xC0, 0x4F, 0x4A, 0x63, 0x50, 0xA6,
0xD0, 0x01, 0x64, 0xE0, 0xD1, 0x98, 0x84, 0xB9, 0x58, 0xA2, 0x5C, 0x3D, 0x68, 0xBF, 0x00, 0x1E,
0xD6, 0xBF, 0xE4, 0x00, 0x83, 0xF2, 0x4E, 0xA3, 0xDB, 0xC8, 0x87, 0x64, 0x60, 0x7F, 0x36, 0xFF,
0x15, 0x10, 0x1B, 0xC7, 0x0F, 0x0F, 0x5C, 0xFD, 0x65, 0x30, 0xEF, 0x2B, 0x4B, 0xBC, 0x9B, 0xC3,
0x95, 0x73, 0x90, 0xC2, 0x3C, 0xFE, 0x57, 0x00, 0xDA, 0xC7, 0xEB, 0x75, 0xB7, 0x55, 0x60, 0x83,
0xE5, 0xA9, 0x8E, 0xD6, 0x1F, 0x7A, 0x65, 0x8F, 0x6C, 0xDC, 0xE0, 0x0A, 0x57, 0x3F, 0x7B, 0x08,
0x37, 0xA3, 0x7D, 0x70, 0xA4, 0x5F, 0xAF, 0x70, 0xA7, 0x60, 0xCC, 0x67, 0x7D, 0xE1, 0x7A, 0x06,
0xF9, 0x8B, 0x3D, 0x6B, 0xA4, 0x3C, 0x5D, 0x98, 0xE7, 0xDE, 0x4E, 0x98, 0xC3, 0x15, 0x53, 0x1E,
0xC2, 0x6A, 0xC9, 0x78, 0x94, 0xEE, 0x56, 0x55, 0xC6, 0x10, 0x39, 0x60, 0xEF, 0x2D, 0x30, 0x2E,
0xC9, 0x29, 0x85, 0x9B, 0x39, 0xBC, 0x29, 0x63, 0x33, 0x33, 0x64, 0xD3, 0x1D, 0xDC, 0x3C, 0x60,
0x9B, 0x29, 0x50, 0x89, 0xCE, 0x78, 0xD5, 0x1D, 0xDC, 0x84, 0x36, 0xA8, 0xB6, 0xA2, 0x0E, 0xB2,
0xC6, 0x0D, 0x1A, 0xDA, 0xD6, 0xDF, 0x76, 0x0F, 0x3D, 0xED, 0x2D, 0xFA, 0x8E, 0xF3, 0x42, 0x38,
0x4F, 0xC1, 0x79, 0x96, 0x9D, 0x87, 0xC4, 0x8F, 0xBD, 0x0A, 0xE0, 0x5B, 0x07, 0x8E, 0x22, 0x43,
0x27, 0x3B, 0x3A, 0x28, 0x83, 0xFB, 0xE5, 0xF1, 0x29, 0x9D, 0x99, 0x86, 0x9F, 0xD6, 0xE1, 0xED,
0x66, 0x3C, 0xA5, 0xF1, 0x59, 0x71, 0xAD, 0x16, 0xBB, 0xED, 0x8D, 0x31, 0xBC, 0x7C, 0x49, 0x34,
0xA2, 0xFE, 0xB8, 0x99, 0xD0, 0x58, 0xFE, 0x5D, 0x34, 0xB2, 0xCC, 0x00, 0x9D, 0x8D, 0x90, 0x13,
0x6A, 0xA9, 0x28, 0x01, 0x8F, 0x5E, 0x8E, 0xF6, 0xE1, 0x1E, 0xD0, 0x7B, 0xD6, 0x42, 0xDB, 0xD8,
0x12, 0xEC, 0xC9, 0xE6, 0x12, 0x2E, 0x47, 0xB3, 0x07, 0x7B, 0x8B, 0x07, 0x6C, 0xCB, 0xCF, 0x3B,
0x36, 0xE8, 0x9C, 0x9B, 0x94, 0x1B, 0x75, 0x01, 0x4D, 0x74, 0x5B, 0xAF, 0xFA, 0xE9, 0x6B, 0x6E,
0x0A, 0x6E, 0x12, 0x98, 0x9D, 0x94, 0x86, 0xB6, 0xAC, 0x12, 0x7F, 0x10, 0x39, 0x58, 0xDB, 0xC2,
0x20, 0x49, 0xCD, 0x6C, 0x0E, 0x15, 0x93, 0x77, 0xA0, 0xE2, 0x23, 0x04, 0x0B, 0x70, 0xC5, 0xF9,
0x8E, 0x13, 0x1E, 0x12, 0x08, 0x5E, 0x3C, 0x86, 0x59, 0x27, 0xC0, 0x4F, 0xA2, 0x1A, 0xA0, 0xBF,
0xA7, 0xA4, 0x44, 0xE4, 0xE4, 0xB4, 0x0E, 0xF4, 0x23, 0x8C, 0x18, 0x4C, 0xD8, 0x1C, 0x71, 0x93,
0xC1, 0xB8, 0x00, 0x72, 0xE2, 0x25, 0xF2, 0x28, 0xA3, 0xAC, 0xCF, 0xC5, 0x60, 0xDF, 0x6F, 0x7E,
0x02, 0xE4, 0xD3, 0x01, 0xC1, 0x10, 0xC2, 0x93, 0x04, 0x4B, 0x81, 0x2A, 0x26, 0x66, 0xAC, 0x27,
0x70, 0xB7, 0xF7, 0x26, 0x73, 0x36, 0x71, 0xDA, 0x22, 0xE8, 0xC4, 0x9B, 0x97, 0x8C, 0x60, 0x5E,
0x01, 0xD1, 0x1C, 0x33, 0x69, 0x1B, 0x00, 0x40, 0xD5, 0x61, 0xFF, 0x96, 0x65, 0x3A, 0x44, 0x77,
0xCC, 0x4C, 0x0D, 0xAC, 0x60, 0x0A, 0x38, 0x08, 0x26, 0xE4, 0xB6, 0x2A, 0x4F, 0x21, 0xCC, 0x15,
0xA7, 0x3A, 0x08, 0x05, 0x87, 0xC6, 0x6C, 0x46, 0xB0, 0x09, 0x68, 0x26, 0x45, 0xB8, 0xA8, 0xAB,
0xEC, 0x44, 0x2C, 0xE7, 0x18, 0x2B, 0x08, 0x25, 0xF5, 0x3E, 0x67, 0x1F, 0xEC, 0x04, 0x4E, 0x62,
0x7A, 0x40, 0x78, 0x48, 0x86, 0x4B, 0x92, 0x07, 0xD5, 0xC3, 0xC8, 0xD9, 0xB8, 0x1C, 0x67, 0x4C,
0x37, 0x68, 0x3D, 0xD5, 0x2F, 0xB1, 0x3B, 0x84, 0x07, 0xB9, 0x2F, 0x5F, 0xA3, 0x74, 0x83, 0xCB,
0x83, 0xCD, 0x59, 0x00, 0x7C, 0xB4, 0x91, 0xCB, 0xDD, 0xEA, 0x83, 0xC5, 0xD8, 0x4A, 0x1F, 0xAA,
0xF2, 0xF5, 0xFF, 0x0F, 0x6D, 0xA3, 0xC7, 0x90, 0x6A, 0x09, 0x43, 0x51, 0x65, 0x39, 0x44, 0xF5,
0xF3, 0xE3, 0xEF, 0xC8, 0x06, 0x81, 0x53, 0x86, 0x1D, 0x7C, 0x86, 0x1C, 0x53, 0x91, 0x77, 0x38,
0x45, 0x6E, 0x0B, 0x65, 0x45, 0xE8, 0xDA, 0x4A, 0x23, 0x19, 0x6D, 0x72, 0xAA, 0x85, 0x51, 0x72,
0xFC, 0x4C, 0x49, 0x36, 0x21, 0xC7, 0x1C, 0xCA, 0xA1, 0x84, 0x8B, 0xA4, 0x09, 0x12, 0x30, 0xA8,
0x0F, 0x9C, 0xDF, 0xA2, 0x98, 0x12, 0xF7, 0xF0, 0x14, 0x5D, 0x87, 0x74, 0x31, 0xEA, 0x0B, 0xCA,
0xD8, 0xCC, 0x15, 0x63, 0xA9, 0xE3, 0x3A, 0x85, 0x5E, 0x26, 0x67, 0x81, 0x9A, 0x29, 0x24, 0x45,
0x25, 0xB3, 0xC0, 0x32, 0xD8, 0xBE, 0x1F, 0x56, 0x46, 0xA8, 0x51, 0xD0, 0x85, 0x7B, 0xF9, 0x59,
0x36, 0xEA, 0x9D, 0x92, 0xD3, 0x3C, 0x32, 0x07, 0x97, 0x62, 0xF2, 0x1A, 0x97, 0xA4, 0x13, 0x25,
0xF4, 0x47, 0x48, 0x1D, 0x2A, 0x6C, 0x99, 0xA6, 0x4F, 0x12, 0xFF, 0xA8, 0x5F, 0xD0, 0xBF, 0xB1,
0xA5, 0x9A, 0x53, 0x85, 0xBD, 0x90, 0x28, 0x79, 0x4B, 0x24, 0x44, 0x44, 0x32, 0xB3, 0x79, 0xC2,
0xDC, 0x7B, 0xD5, 0xDD, 0xAD, 0x1A, 0xD9, 0x85, 0x16, 0x1B, 0x47, 0x1A, 0xA2, 0x66, 0x90, 0x39,
0xB0, 0x37, 0x59, 0xCF, 0x95, 0x90, 0x3E, 0x61, 0x65, 0xBC, 0xDE, 0x3B, 0x25, 0x85, 0x1A, 0xB9,
0x7D, 0xCA, 0x86, 0x01, 0xDA, 0x60, 0xA4, 0x05, 0xE2, 0x6D, 0xB4, 0x5F, 0x59, 0x8E, 0x36, 0x14,
0xDA, 0x77, 0x1D, 0x98, 0x01, 0x02, 0x8F, 0x81, 0x22, 0x24, 0xAC, 0x05, 0x32, 0x97, 0x68, 0x21,
0x6D, 0x7C, 0x11, 0x0B, 0xCD, 0xB1, 0x06, 0x02, 0x91, 0xB8, 0x36, 0x1B, 0xF8, 0x95, 0xDD, 0xF5,
0xF4, 0x0D, 0xC8, 0x19, 0x52, 0x35, 0xA8, 0xC4, 0xDD, 0x6D, 0xC4, 0xC5, 0x98, 0xE2, 0x0B, 0x70,
0xC3, 0x8F, 0x18, 0xAD, 0x20, 0x29, 0x18, 0xC6, 0xDF, 0x41, 0x9B, 0xC6, 0xDF, 0x01, 0x41, 0xA8,
0x2E, 0xEE, 0x1A, 0x7A, 0x35, 0x23, 0xF1, 0xD9, 0x40, 0x2A, 0xBC, 0xB8, 0xBB, 0x63, 0x91, 0x72,
0x9E, 0x73, 0x61, 0xC0, 0xD8, 0x17, 0xAD, 0x50, 0x19, 0x82, 0xA2, 0x40, 0x42, 0x31, 0x4B, 0x43,
0x39, 0xB3, 0xE1, 0x8B, 0xDC, 0x55, 0x5F, 0xBE, 0xEA, 0x0B, 0x86, 0xE3, 0x07, 0xF7, 0x15, 0x5F,
0xF4, 0x9E, 0x31, 0x9E, 0x79, 0x61, 0x00, 0xBB, 0x9F, 0x71, 0x4D, 0xE1, 0x67, 0xB9, 0xF8, 0xA4,
0x8C, 0x2E, 0xD4, 0x2A, 0xD4, 0x70, 0xCB, 0x84, 0x3E, 0x1A, 0xD3, 0xF4, 0x26, 0x8D, 0x07, 0x54,
0x23, 0xC9, 0x13, 0xF2, 0x6F, 0x9C, 0x8F, 0x99, 0x2A, 0xF2, 0x08, 0x85, 0x87, 0xCE, 0x02, 0x14,
0x23, 0x2F, 0xC3, 0x88, 0x88, 0xAD, 0x75, 0xCE, 0x60, 0xF5, 0x82, 0x59, 0x01, 0x07, 0x9C, 0x22,
0x70, 0x07, 0x7D, 0xAC, 0x67, 0x34, 0x02, 0x09, 0xB8, 0x23, 0x90, 0x9F, 0x70, 0x46, 0x6B, 0x85,
0x91, 0x2D, 0x1F, 0x1F, 0xC0, 0xB3, 0xDF, 0x24, 0x7E, 0x81, 0xC7, 0x18, 0x83, 0xE7, 0xBE, 0x4A,
0x40, 0x60, 0x8C, 0x78, 0x81, 0xAA, 0x49, 0xDC, 0x5F, 0xDB, 0xF8, 0x4E, 0x7E, 0x76, 0x4E, 0x3F,
0x38, 0xCC, 0x1C, 0xA8, 0xE5, 0x3A, 0x12, 0x86, 0x2E, 0x3A, 0xC0, 0x1C, 0x3B, 0x21, 0x0F, 0xC4,
0xDF, 0x89, 0x2F, 0x64, 0xCF, 0x10, 0x9C, 0x91, 0xE4, 0x33, 0x9C, 0x48, 0x0C, 0x07, 0x0C, 0xB6,
0x2B, 0x0F, 0xB7, 0xC3, 0x23, 0x1F, 0x61, 0x32, 0x8E, 0x1B, 0x57, 0x95, 0xC5, 0xE7, 0x3D, 0x0B,
0x9C, 0xB9, 0xDB, 0x6D, 0xFC, 0x1B, 0xCA, 0x00, 0x48, 0xAF, 0xFD, 0xCE, 0xE1, 0x5E, 0x1D, 0xF6,
0xEA, 0x43, 0x04, 0x16, 0x32, 0x00, 0x02, 0xD6, 0x1C, 0x5F, 0xD5, 0xAF, 0x60, 0x5E, 0xAE, 0x54,
0xF4, 0x70, 0x7F, 0xE4, 0x15, 0x3D, 0x66, 0x2E, 0x0C, 0xDC, 0x76, 0x83, 0x7A, 0x00, 0x05, 0x08,
0x38, 0x1C, 0x9A, 0xA6, 0x5C, 0x0D, 0xC5, 0x39, 0x6F, 0x54, 0xAA, 0x6A, 0x0B, 0x51, 0xC9, 0x50,
0x81, 0xC0, 0x5B, 0xE0, 0xB1, 0x6B, 0x0D, 0x01, 0xE0, 0xD1, 0x1D, 0x1C, 0x29, 0xC0, 0x0F, 0x20,
0xD0, 0x32, 0x82, 0x2D, 0x60, 0x53, 0xAF, 0xA6, 0xD7, 0x8F, 0xF5, 0xF4, 0x54, 0xEF, 0x5F, 0x24,
0x1D, 0xD3, 0x1F, 0x4C, 0x22, 0xB5, 0x3F, 0xA3, 0xAD, 0xCE, 0x67, 0x35, 0xD3, 0x35, 0x9B, 0xF4,
0xA9, 0x17, 0x61, 0x1F, 0xF4, 0xD7, 0x5C, 0xE3, 0x3A, 0x90, 0x2B, 0x73, 0xDE, 0x90, 0x2F, 0x82,
0x8A, 0x50, 0x6B, 0xA3, 0x62, 0xC7, 0xC8, 0xE8, 0xDB, 0x37, 0x41, 0xFF, 0x3E, 0x58, 0x76, 0x86,
0xA1, 0xAB, 0xA2, 0x79, 0xCD, 0x2A, 0x3E, 0xE0, 0x1D, 0xFD, 0xB5, 0x41, 0x27, 0x5B, 0x2E, 0xE9,
0x58, 0xDA, 0x4C, 0x0F, 0x42, 0x3E, 0xFD, 0x87, 0x58, 0xD4, 0xB1, 0x66, 0xFE, 0x15, 0x38, 0x84,
0x89, 0x2F, 0x1A, 0x9F, 0xCD, 0xC5, 0xA3, 0xC6, 0xA7, 0x77, 0x3E, 0xE7, 0x0E, 0x7D, 0x71, 0x13,
0x19, 0x69, 0x32, 0xD4, 0xBB, 0x23, 0x1D, 0x73, 0x21, 0xA0, 0x4A, 0x4F, 0xEA, 0xCF, 0xBA, 0x09,
0xFB, 0x8B, 0xAE, 0x1D, 0xED, 0xBA, 0x37, 0xAA, 0x3C, 0x3E, 0x70, 0x5F, 0x03, 0xBA, 0x45, 0x59,
0x35, 0x33, 0xA6, 0xBB, 0x5A, 0x0D, 0x9A, 0x0F, 0xC6, 0x18, 0xCC, 0x31, 0x18, 0x24, 0x3A, 0xAA,
0x23, 0xD1, 0xF1, 0xC3, 0xF8, 0xCB, 0x6C, 0xA9, 0x7A, 0xE5, 0xF2, 0xD1, 0x2D, 0xC7, 0xEB, 0xF1,
0x6A, 0xC3, 0x5A, 0x47, 0x1A, 0xF5, 0xC9, 0x0B, 0xCC, 0xE5, 0x99, 0xF0, 0x78, 0xC5, 0xF8, 0x7B,
0xB3, 0x93, 0x5F, 0xB5, 0x34, 0x43, 0x12, 0x1A, 0x0E, 0x97, 0x7C, 0xD2, 0x04, 0x1B, 0x6F, 0xE7,
0xF2, 0x1E, 0x22, 0xA9, 0x60, 0x8C, 0x6E, 0xD1, 0xE8, 0x56, 0x1F, 0x38, 0x30, 0x6C, 0x51, 0x16,
0x58, 0x67, 0x01, 0x9D, 0x3A, 0x56, 0x68, 0xC0, 0x2B, 0xAA, 0xD2, 0x80, 0xA3, 0xA5, 0xE6, 0x4A,
0xC8, 0x17, 0x9C, 0xE6, 0xBF, 0x93, 0x4A, 0x61, 0x90, 0x65, 0x5B, 0xF6, 0xE1, 0x43, 0xE0, 0x09,
0xC5, 0xD2, 0x0C, 0x07, 0x71, 0x9C, 0x89, 0x52, 0x5E, 0xC5, 0x0C, 0x3F, 0x96, 0x53, 0xAE, 0xD0,
0x45, 0x00, 0x18, 0x3B, 0x2D, 0x97, 0x4F, 0x25, 0x6C, 0xFE, 0x81, 0x58, 0x91, 0x6B, 0x46, 0xBB,
0xFB, 0xAE, 0x68, 0xB3, 0x5D, 0xB2, 0x47, 0xD5, 0x6C, 0x6B, 0x28, 0x85, 0x40, 0x02, 0xFD, 0x05,
0x67, 0x2D, 0xE0, 0x79, 0x7E, 0x49, 0xB2, 0x67, 0xCD, 0x22, 0xFB, 0xF3, 0xE8, 0x3E, 0xA5, 0x26,
0xBA, 0xEF, 0x0C, 0x17, 0x0D, 0x97, 0x99, 0xB2, 0xFC, 0xCC, 0xC4, 0x7D, 0x35, 0x54, 0xB8, 0x47,
0x14, 0x7E, 0x59, 0x40, 0xD5, 0x92, 0xAA, 0xAD, 0x91, 0x8E, 0x5A, 0x65, 0xA2, 0xFF, 0x01, 0x5B,
0x48, 0x64, 0x29, 0x79, 0xC3, 0x41, 0xD5, 0x03, 0x1C, 0xC8, 0x34, 0x0E, 0x99, 0x26, 0xB1, 0xF0,
0x75, 0x6D, 0x69, 0x1C, 0xC0, 0x85, 0x48, 0xBE, 0x79, 0x84, 0x5C, 0xA3, 0xDE, 0x44, 0x1D, 0x00,
0x66, 0x9C, 0x82, 0x0A, 0xBF, 0x06, 0x35, 0xF6, 0x3E, 0xA7, 0xF0, 0x29, 0xA1, 0x30, 0x92, 0xAA,
0x7F, 0xE0, 0xC0, 0x18, 0x58, 0x0F, 0x0A, 0x9A, 0x07, 0x96, 0xFF, 0x2D, 0x91, 0xE9, 0x33, 0x08,
0xC8, 0x3D, 0x51, 0x07, 0xED, 0x2F, 0x5B, 0x64, 0x86, 0x4B, 0xEA, 0xED, 0x9C, 0x8C, 0x9E, 0x82,
0xFC, 0xFE, 0x2C, 0xFE, 0xC2, 0x49, 0x26, 0x69, 0x28, 0x34, 0x9C, 0x67, 0x62, 0x2E, 0xF6, 0x13,
0x9B, 0xD8, 0xA2, 0x49, 0x70, 0x92, 0xC1, 0x89, 0x4D, 0x42, 0xA7, 0xF1, 0x90, 0x88, 0x50, 0x41,
0x09, 0x14, 0xB0, 0x93, 0x39, 0xB2, 0x90, 0xE5, 0xA3, 0x04, 0x0E, 0x1D, 0xFB, 0x99, 0xCD, 0x6C,
0xD5, 0x65, 0xC6, 0xE5, 0x09, 0xBC, 0x39, 0x05, 0xD8, 0xB4, 0x6C, 0x14, 0xD4, 0xDA, 0xA0, 0x18,
0xA9, 0x6C, 0x02, 0x49, 0x6F, 0x22, 0x33, 0xFE, 0xB3, 0xF6, 0xA9, 0x47, 0xB6, 0x43, 0x6C, 0x33,
0xDD, 0xEA, 0x21, 0x91, 0x18, 0x1F, 0x1F, 0xBE, 0xDE, 0x41, 0xB1, 0x8F, 0x6B, 0x1C, 0x74, 0xAF,
0xE3, 0x7C, 0xCA, 0x82, 0x30, 0x05, 0x83, 0xDE, 0x84, 0x7E, 0x41, 0xD5, 0x2F, 0x25, 0x74, 0xA6,
0xE0, 0x04, 0x83, 0x18, 0xCC, 0xFE, 0x04, 0x04, 0xA5, 0x5C, 0xDF, 0x44, 0x75, 0xC2, 0x94, 0x9A,
0xF1, 0x7F, 0x6F, 0x42, 0xFF, 0xC4, 0x55, 0x4A, 0xC9, 0x75, 0x91, 0xAB, 0x2B, 0xF7, 0xE4, 0xB3,
0x3F, 0xC3, 0x31, 0x49, 0xFA, 0x58, 0x08, 0xBD, 0x31, 0xF9, 0x0B, 0xAB, 0x2F, 0x91, 0x41, 0xBB,
0x55, 0x6D, 0xFF, 0xA4, 0x8F, 0x2B, 0xDA, 0x51, 0xF9, 0xFD, 0xC2, 0x9C, 0xE9, 0x0A, 0xFB, 0x61,
0xA4, 0xFF, 0x03, 0xBD, 0x58, 0xBF, 0x8F, 0xDC, 0xC6, 0x15, 0x7E, 0x24, 0xED, 0x23, 0x9C, 0x91,
0x6E, 0x04, 0xC4, 0x40, 0x8C, 0xAC, 0x24, 0xAA, 0x48, 0x11, 0xC4, 0xD2, 0x31, 0x40, 0x54, 0xA8,
0xD8, 0x25, 0x69, 0x39, 0x80, 0x0B, 0x17, 0x16, 0x90, 0x3F, 0x40, 0x2E, 0xD2, 0x9F, 0x0B, 0x15,
0x02, 0xB2, 0x77, 0xE4, 0x49, 0x40, 0x12, 0xC0, 0x85, 0x2F, 0x7D, 0x00, 0x2B, 0x48, 0x15, 0xA7,
0xF0, 0x01, 0xB9, 0x00, 0x97, 0x80, 0x77, 0x1C, 0xEB, 0x0A, 0x15, 0x02, 0x6C, 0x1A, 0x2E, 0x5C,
0x05, 0x1E, 0x5B, 0x17, 0x04, 0x48, 0x10, 0x68, 0x6C, 0x51, 0x11, 0x4F, 0xE2, 0xEE, 0xE4, 0x7B,
0xB3, 0xBB, 0xF7, 0x43, 0xB2, 0x1D, 0x29, 0x91, 0xC3, 0xDD, 0x9D, 0xDD, 0x25, 0x87, 0xEF, 0xCD,
0x7B, 0xF3, 0xBD, 0xEF, 0xBD, 0xC7, 0xCD, 0x71, 0x49, 0x74, 0x7A, 0x30, 0x48, 0xA6, 0xC7, 0xF2,
0xD2, 0x06, 0xE1, 0x90, 0x07, 0xDE, 0x51, 0xE6, 0xDB, 0x56, 0xFE, 0x73, 0x94, 0x1C, 0x19, 0x0C,
0x8F, 0x1C, 0x2F, 0x8F, 0x50, 0x3B, 0x7B, 0x77, 0x47, 0x68, 0xEB, 0x08, 0xA5, 0xBF, 0x7E, 0x2E,
0xB2, 0x23, 0xDF, 0xEE, 0x50, 0x9F, 0x0E, 0xBD, 0x8F, 0x11, 0x85, 0x23, 0x12, 0x56, 0x87, 0xAA,
0x0C, 0x6A, 0x49, 0x86, 0x68, 0x48, 0x14, 0x13, 0x59, 0x5B, 0xE7, 0xB6, 0xA1, 0xC6, 0xCD, 0x8A,
0x88, 0x44, 0x41, 0x41, 0x4D, 0xD2, 0xBA, 0x23, 0xB7, 0x36, 0xC3, 0x0A, 0xE6, 0x88, 0x9E, 0x1B,
0xE6, 0x1F, 0x7D, 0x68, 0x6D, 0x13, 0xAA, 0x25, 0x5A, 0xF7, 0x8C, 0x24, 0x16, 0x61, 0x64, 0x76,
0x92, 0x36, 0xC3, 0x3A, 0xB2, 0xF6, 0xD5, 0x9F, 0xEF, 0x0E, 0x4E, 0x11, 0x15, 0xB6, 0x09, 0xEC,
0x62, 0xED, 0xB5, 0x52, 0x91, 0x09, 0xB5, 0x5F, 0xFB, 0x26, 0x50, 0xD4, 0x0A, 0x68, 0x9B, 0xA7,
0xD0, 0xC6, 0xDA, 0xBB, 0xF8, 0xA7, 0x8C, 0x84, 0xA1, 0xC0, 0x5A, 0xE5, 0xE3, 0x43, 0x81, 0xA6,
0xBD, 0x4F, 0x6F, 0x97, 0xD7, 0x43, 0xAC, 0xD9, 0x4C, 0x96, 0x40, 0x55, 0x11, 0xD9, 0x15, 0x13,
0xCB, 0xEC, 0xEC, 0x26, 0x05, 0x23, 0x92, 0xCB, 0xD4, 0xCF, 0x33, 0x13, 0xAF, 0x18, 0x79, 0xB5,
0x91, 0xE7, 0xDB, 0x79, 0x6F, 0xD4, 0xA7, 0x4D, 0x43, 0xF9, 0x2F, 0x69, 0xB3, 0xF5, 0xEF, 0xB4,
0x51, 0x68, 0x8D, 0xBF, 0x4B, 0x6B, 0xA7, 0xDB, 0x64, 0xFD, 0x0C, 0xF5, 0xC6, 0x19, 0x61, 0x6D,
0x14, 0xEE, 0x78, 0x9B, 0x5E, 0x43, 0x5E, 0x33, 0x08, 0x47, 0xE1, 0x8D, 0x15, 0xAB, 0xCF, 0xAC,
0xF7, 0xE7, 0xBD, 0xDB, 0x22, 0xCB, 0xA4, 0x81, 0x23, 0x2C, 0xFB, 0xD6, 0xAC, 0x13, 0x3D, 0x78,
0x45, 0xD1, 0xC9, 0xCB, 0xA9, 0xF5, 0x3F, 0xAA, 0x2B, 0x35, 0x8C, 0x70, 0x73, 0xB6, 0x9C, 0xF5,
0x6A, 0x0F, 0x76, 0x93, 0x57, 0xED, 0x50, 0x4F, 0xC7, 0x5B, 0x32, 0x50, 0x99, 0xE9, 0x75, 0xF1,
0x45, 0x19, 0x6C, 0xDF, 0xDF, 0x4D, 0x2F, 0xC2, 0x3B, 0xEF, 0xFC, 0xC1, 0xB6, 0xB4, 0x16, 0x52,
0x23, 0x56, 0x1A, 0x79, 0x05, 0xA6, 0x77, 0xA2, 0x8E, 0xB3, 0x0E, 0x5E, 0x2A, 0x24, 0xAD, 0xD3,
0xB5, 0x90, 0x72, 0x3B, 0x66, 0x93, 0xE0, 0x0A, 0xE9, 0xFC, 0xBC, 0x5A, 0x8D, 0xEC, 0x88, 0x16,
0x77, 0x68, 0xE0, 0xE9, 0x79, 0x0A, 0x56, 0xB6, 0x47, 0x47, 0xCF, 0x1E, 0x79, 0xE3, 0xB7, 0x74,
0x23, 0xFC, 0xA1, 0xAC, 0x7F, 0x44, 0xEF, 0x87, 0x67, 0x8F, 0x5C, 0xFA, 0xCD, 0xF6, 0xE7, 0x7F,
0x99, 0x27, 0xBF, 0xC0, 0x14, 0x9E, 0x99, 0xDB, 0x45, 0xAB, 0x84, 0x4E, 0xBB, 0x8D, 0xD8, 0x48,
0x23, 0x9B, 0x93, 0x79, 0x17, 0x69, 0xEC, 0x01, 0x04, 0x4E, 0x06, 0xE7, 0x2F, 0xB3, 0xF7, 0x97,
0x1C, 0x74, 0xDC, 0x39, 0xD1, 0xE4, 0xE3, 0x36, 0x6A, 0x22, 0x5A, 0xA0, 0xA1, 0x67, 0x42, 0xB5,
0x40, 0xD5, 0x38, 0xB7, 0x91, 0xAE, 0x3A, 0xDD, 0xA7, 0xE1, 0x9C, 0x8E, 0x1B, 0x60, 0xA1, 0x4F,
0x65, 0x65, 0xAA, 0x82, 0xA8, 0x2E, 0x97, 0x06, 0x27, 0xDC, 0xDD, 0xBE, 0x81, 0x09, 0x4A, 0xA8,
0x04, 0x38, 0x69, 0xA9, 0x0C, 0xB4, 0x0F, 0x8B, 0xF6, 0xFF, 0x9A, 0x00, 0x57, 0xA3, 0x3A, 0x55,
0x0F, 0x94, 0xB5, 0x1F, 0xD8, 0x9B, 0xAD, 0x7C, 0x1B, 0x60, 0x19, 0xE0, 0xC6, 0x76, 0xB2, 0x9D,
0x32, 0xA3, 0xC9, 0x51, 0x59, 0x55, 0xD9, 0x9D, 0xD8, 0xF6, 0x03, 0x7B, 0x47, 0xE5, 0xB6, 0x1F,
0x4E, 0xBE, 0xF8, 0x1F, 0x4E, 0x12, 0xBE, 0xFC, 0xDB, 0xF0, 0xCA, 0x1D, 0xB8, 0xE7, 0xD1, 0xAF,
0x82, 0x24, 0xC0, 0x0B, 0x71, 0xCF, 0x10, 0x2D, 0xDB, 0xCD, 0xF8, 0xE5, 0x51, 0xA0, 0x87, 0x91,
0x07, 0xD9, 0x73, 0x75, 0x5E, 0xF7, 0x54, 0x70, 0xE0, 0x15, 0xEE, 0xE4, 0x9D, 0x68, 0xE4, 0xBB,
0xE2, 0xFC, 0x2D, 0xD5, 0x37, 0xB2, 0x1F, 0xDC, 0x5C, 0xD1, 0xF7, 0x0D, 0xFC, 0x44, 0xDE, 0x3B,
0xD7, 0x6C, 0xBB, 0x16, 0x64, 0x32, 0xDB, 0xC0, 0x3E, 0xA9, 0xA8, 0xE8, 0x02, 0x13, 0xAD, 0xB4,
0xF2, 0xBD, 0x46, 0xAA, 0x46, 0x16, 0x6B, 0xE1, 0x6C, 0xAD, 0x94, 0xB1, 0xF3, 0x7A, 0x86, 0xE0,
0xF6, 0x4A, 0xF3, 0x96, 0xC1, 0x14, 0x5C, 0xC5, 0x28, 0x9D, 0x59, 0x27, 0xDC, 0x78, 0x8E, 0x5E,
0xC7, 0xB8, 0x06, 0x78, 0x6B, 0xD2, 0x21, 0x46, 0x5F, 0x49, 0x13, 0x8F, 0x82, 0xAC, 0x6F, 0x7E,
0xF0, 0x3B, 0xC4, 0x06, 0xFC, 0x7F, 0xC2, 0xAF, 0x31, 0xC2, 0x4A, 0x4B, 0xB4, 0xE6, 0x46, 0xCD,
0xA2, 0x21, 0x11, 0x63, 0x08, 0x4F, 0xAF, 0x92, 0x37, 0x53, 0xBA, 0xCA, 0xEA, 0xF0, 0xCE, 0x9D,
0xC6, 0x9E, 0xE6, 0xEB, 0x0F, 0x69, 0xEC, 0xBB, 0xF1, 0x0D, 0xD1, 0xB0, 0xC6, 0xBC, 0x63, 0x8D,
0xCD, 0x72, 0xA0, 0x83, 0xCC, 0x0C, 0xF2, 0xB1, 0x70, 0xE1, 0x8C, 0x89, 0x2E, 0x8E, 0xD9, 0xF9,
0x97, 0x00, 0x5E, 0x56, 0xB4, 0x84, 0x7D, 0x54, 0x1E, 0x07, 0x41, 0xE1, 0xD9, 0x31, 0x09, 0xA7,
0x6E, 0x4F, 0xEF, 0x31, 0xF2, 0x10, 0xE1, 0x12, 0xE1, 0xD8, 0xF0, 0x25, 0x93, 0x50, 0x50, 0xF0,
0xC6, 0xF1, 0x22, 0xA3, 0xCC, 0xAB, 0x89, 0xF2, 0x82, 0xB1, 0xF4, 0xDD, 0x0E, 0x02, 0xAF, 0x91,
0x2C, 0x00, 0x13, 0xF0, 0xC3, 0x71, 0xCA, 0x29, 0x34, 0xF3, 0x94, 0x2B, 0xDB, 0x08, 0xEA, 0x9B,
0x78, 0x35, 0x28, 0xFA, 0x7D, 0xD6, 0x74, 0x06, 0x4B, 0xF6, 0x6A, 0x69, 0x3B, 0x08, 0x73, 0x36,
0x5F, 0x9A, 0x31, 0x10, 0x2E, 0x9C, 0xC1, 0xB5, 0x62, 0xAA, 0x7C, 0x83, 0x52, 0xE6, 0x1A, 0x72,
0xF4, 0xE2, 0x2B, 0x6A, 0xE6, 0x46, 0xC2, 0xBE, 0xBA, 0x1B, 0x30, 0xA6, 0xFB, 0x7C, 0xA5, 0x7D,
0x26, 0xB6, 0xE7, 0x6D, 0xCD, 0x9B, 0xC7, 0xC7, 0xF7, 0x79, 0x18, 0xF1, 0xDA, 0x2D, 0xFF, 0xCA,
0xE9, 0xE0, 0xC1, 0xDE, 0x74, 0xA7, 0x7C, 0x9E, 0x31, 0x0F, 0xFC, 0xD1, 0x1F, 0xB1, 0xEA, 0x60,
0x1B, 0x06, 0x9C, 0x14, 0xEC, 0xF0, 0x88, 0x27, 0x25, 0x0C, 0xCF, 0x92, 0x5C, 0x3C, 0x0B, 0x6B,
0xD9, 0xA7, 0x42, 0xF9, 0x1A, 0x96, 0x02, 0xAA, 0x29, 0x6D, 0x65, 0xFE, 0xF8, 0x35, 0x4B, 0xA9,
0x9D, 0x4A, 0xFD, 0x16, 0x6B, 0x83, 0x21, 0x94, 0x42, 0x4C, 0xD0, 0x1C, 0xD2, 0x28, 0x66, 0xCB,
0x09, 0x78, 0xC2, 0x02, 0x87, 0xDB, 0x1D, 0xAC, 0x54, 0xBC, 0x0A, 0x65, 0x7D, 0x48, 0xF3, 0x74,
0xC2, 0x7E, 0x1C, 0xF2, 0xBE, 0x34, 0xE4, 0x4F, 0x09, 0x4D, 0xC1, 0x6C, 0x59, 0x80, 0x5F, 0x63,
0xA6, 0xDA, 0x25, 0x6F, 0x4C, 0x73, 0xE3, 0x78, 0x4C, 0xD5, 0x68, 0x22, 0xD4, 0x63, 0x1D, 0x92,
0x87, 0xBB, 0x18, 0xE4, 0x4B, 0x86, 0x37, 0x28, 0x7B, 0x1C, 0x1B, 0xE5, 0xCC, 0x46, 0x35, 0xB5,
0x91, 0x0E, 0xDB, 0x68, 0x1E, 0xB5, 0x51, 0x5E, 0x81, 0x64, 0xFB, 0x16, 0x24, 0xDC, 0x84, 0x09,
0xCF, 0x86, 0xC5, 0x21, 0x87, 0x2A, 0x36, 0x9B, 0x97, 0x34, 0xE6, 0x25, 0x41, 0x1E, 0x5D, 0x6E,
0x58, 0x19, 0x87, 0x35, 0x3B, 0x74, 0x1D, 0xD2, 0x02, 0x85, 0x19, 0x0B, 0x8C, 0x30, 0x0B, 0x02,
0x0C, 0xD9, 0xC6, 0x01, 0x85, 0x35, 0x13, 0x90, 0xC2, 0x06, 0xC6, 0x54, 0x65, 0x9E, 0x7D, 0xCB,
0x16, 0x29, 0x20, 0xB6, 0x00, 0x37, 0x53, 0x87, 0x65, 0xFA, 0x7A, 0xE1, 0x90, 0x23, 0x2F, 0xB3,
0x36, 0x33, 0x75, 0x32, 0xDD, 0x86, 0x68, 0x81, 0xAC, 0x44, 0xE7, 0x12, 0x46, 0x13, 0x16, 0x26,
0xD9, 0x29, 0x97, 0x02, 0x8E, 0x0B, 0xE8, 0x8D, 0x38, 0x21, 0x59, 0xE0, 0x18, 0x0B, 0x2C, 0x81,
0x27, 0x5C, 0x44, 0x44, 0x71, 0x84, 0xC7, 0x7F, 0xB5, 0x3A, 0xC0, 0x0A, 0x7C, 0x76, 0x4C, 0xCC,
0x83, 0x71, 0xDE, 0x61, 0x81, 0x6C, 0x83, 0xD0, 0x33, 0x8D, 0x27, 0x79, 0xE0, 0x5D, 0x13, 0xEC,
0xE9, 0x04, 0xB3, 0xBC, 0x5B, 0x98, 0x25, 0x5F, 0x83, 0x07, 0x86, 0xD0, 0xED, 0xEB, 0x01, 0xA3,
0x15, 0x33, 0x4A, 0xDF, 0x25, 0x2A, 0xCD, 0x6A, 0x91, 0xC5, 0x28, 0xE6, 0xB8, 0x60, 0xFA, 0xA3,
0xCE, 0x1B, 0x51, 0xC8, 0x5B, 0x07, 0x1A, 0x07, 0xBD, 0x41, 0x2F, 0x08, 0x1A, 0x73, 0xBC, 0xDB,
0x05, 0x27, 0x93, 0x84, 0x4E, 0xC3, 0x45, 0xBC, 0x08, 0xE7, 0x31, 0x3A, 0x23, 0x21, 0xDB, 0x33,
0xA9, 0x45, 0x66, 0xCD, 0xD8, 0x84, 0xCB, 0x2E, 0xE5, 0x59, 0x8B, 0xD3, 0xB1, 0xE5, 0xE5, 0x19,
0x88, 0x3F, 0x06, 0x68, 0x68, 0xAA, 0x87, 0x80, 0x88, 0x78, 0xA5, 0xF5, 0x2A, 0x3B, 0xAA, 0xDA,
0x88, 0x65, 0x23, 0x8F, 0x45, 0xB6, 0x13, 0x5A, 0xBC, 0xD7, 0x50, 0x1F, 0x21, 0x7A, 0x43, 0xD1,
0x31, 0x6C, 0x09, 0x0B, 0x6D, 0xF7, 0xBE, 0x78, 0x57, 0xB0, 0x15, 0x01, 0x96, 0x02, 0x77, 0x5C,
0xC8, 0x39, 0xC1, 0x8C, 0x27, 0x59, 0x00, 0x9E, 0xB5, 0x4C, 0xE7, 0x8E, 0x9D, 0xA3, 0x09, 0xA0,
0x00, 0x42, 0x92, 0x58, 0x44, 0xD4, 0x4C, 0xAE, 0xD0, 0x2C, 0x61, 0x74, 0x2F, 0x72, 0x1A, 0x29,
0x02, 0x20, 0x49, 0xEC, 0x31, 0x39, 0x54, 0xA4, 0x00, 0x14, 0x8A, 0x85, 0xD9, 0xDF, 0xC4, 0xF1,
0xFC, 0x51, 0xFC, 0x3D, 0x2B, 0x0B, 0xFF, 0x43, 0xF8, 0xE0, 0xA2, 0xE5, 0xA8, 0x67, 0xCC, 0x40,
0x5C, 0xAC, 0x5C, 0x64, 0x9C, 0xA4, 0x2F, 0x97, 0x2C, 0x1F, 0x95, 0xAC, 0x1E, 0x95, 0x7C, 0xE9,
0x61, 0xC9, 0x11, 0x39, 0xBE, 0x8A, 0x16, 0x33, 0x0F, 0xE9, 0xCC, 0x7B, 0x3A, 0x6B, 0x66, 0x44,
0x22, 0x67, 0x4F, 0x20, 0x3A, 0x39, 0x90, 0x35, 0xAF, 0xE3, 0x2A, 0x26, 0xF7, 0x99, 0xE5, 0xF7,
0xEF, 0xE5, 0x3D, 0xCB, 0x24, 0x5C, 0x9B, 0x1C, 0x48, 0x73, 0x05, 0xD5, 0x09, 0x52, 0x44, 0x4B,
0x67, 0x7A, 0xD6, 0xDE, 0xB5, 0x8C, 0x03, 0xC0, 0x3A, 0xCF, 0x50, 0xED, 0xAC, 0x3B, 0xAE, 0xB2,
0x2F, 0xB6, 0x20, 0xEA, 0xAF, 0x78, 0xF5, 0x76, 0x73, 0xEB, 0x4C, 0xAB, 0xC2, 0x4E, 0x16, 0x8F,
0x3D, 0xBF, 0xA5, 0x4A, 0x95, 0x5D, 0x29, 0x7E, 0x0C, 0x82, 0xF0, 0xE0, 0x80, 0x16, 0x67, 0x12,
0x72, 0x08, 0xFA, 0x92, 0x1F, 0x5E, 0xF5, 0x2B, 0xDB, 0x6D, 0x88, 0x2A, 0x78, 0x50, 0x4C, 0x6A,
0x4A, 0xD8, 0xB7, 0xFA, 0x55, 0x93, 0xDD, 0x8F, 0xDE, 0xFD, 0xC8, 0xAA, 0x45, 0xBB, 0x0B, 0x7C,
0xC2, 0x89, 0xA5, 0x57, 0x65, 0x31, 0x38, 0x10, 0x20, 0x4B, 0x81, 0x16, 0xA1, 0x00, 0xBF, 0x7B,
0x70, 0x50, 0x02, 0x63, 0xE5, 0x15, 0x44, 0x49, 0x8D, 0x13, 0x0D, 0x02, 0xA3, 0xC4, 0x8C, 0x04,
0x33, 0x52, 0x84, 0x67, 0x8E, 0xC8, 0x00, 0xB9, 0xA1, 0x18, 0x65, 0x47, 0xAD, 0x42, 0x6B, 0x0B,
0x64, 0xC8, 0xD8, 0x3C, 0x4C, 0x37, 0x69, 0x83, 0x9D, 0x8A, 0x3A, 0xEA, 0xB5, 0xC1, 0x18, 0x33,
0x03, 0x9B, 0x61, 0xB8, 0x0D, 0x40, 0x04, 0xB7, 0xD8, 0xE4, 0x4F, 0x1B, 0xB6, 0xBB, 0xE4, 0x21,
0xE1, 0x41, 0xBE, 0x8C, 0x41, 0x6C, 0xEB, 0xE9, 0x75, 0xBA, 0xC7, 0x43, 0xCE, 0x43, 0x0C, 0xEF,
0x00, 0xD5, 0x70, 0x50, 0xA0, 0xF7, 0xC5, 0x1F, 0xA5, 0x49, 0x58, 0x10, 0x17, 0xB3, 0x73, 0x1C,
0x95, 0xCF, 0x4E, 0xAF, 0x2C, 0xEE, 0x72, 0x32, 0x30, 0xE0, 0x8C, 0x0A, 0x4C, 0x12, 0x1A, 0x5C,
0xDB, 0x04, 0x65, 0xCB, 0x77, 0x79, 0xA3, 0xB1, 0x42, 0x14, 0x00, 0x8E, 0x4B, 0x04, 0x3C, 0x1E,
0xFC, 0x03, 0xDB, 0x7A, 0x17, 0x7F, 0xCA, 0x34, 0xA3, 0xA5, 0xA0, 0xA5, 0x2D, 0x2C, 0x7A, 0xE4,
0xEA, 0xC2, 0x29, 0x7B, 0xAB, 0x89, 0x9A, 0x10, 0x58, 0x15, 0x38, 0xE9, 0x65, 0x4F, 0x5B, 0xCB,
0x05, 0x7C, 0x38, 0xA4, 0x1F, 0xE0, 0x86, 0x36, 0x61, 0x5A, 0x3C, 0xE0, 0xC5, 0xA7, 0xA5, 0x45,
0x20, 0x2F, 0x48, 0x26, 0xD2, 0x5F, 0x1C, 0xCE, 0x78, 0xEE, 0x2A, 0x48, 0x1E, 0x45, 0xA8, 0xDF,
0x81, 0xE5, 0x23, 0x30, 0x9B, 0x7F, 0x17, 0xF6, 0x26, 0x4C, 0x45, 0x58, 0x96, 0xBF, 0xA7, 0xA5,
0x9B, 0xAA, 0xFD, 0x18, 0x33, 0x0C, 0xC4, 0x36, 0x52, 0x63, 0x59, 0x8C, 0xA3, 0x39, 0x0B, 0x18,
0x6C, 0x20, 0x39, 0xA4, 0xF0, 0x94, 0x98, 0x60, 0xF1, 0x1B, 0xD0, 0x40, 0x21, 0x1D, 0x2F, 0xC3,
0xEB, 0x9F, 0x1B, 0xD1, 0x81, 0xAD, 0xC3, 0xCE, 0xFB, 0xC2, 0x0C, 0xC5, 0x4D, 0xAE, 0x3F, 0x88,
0x27, 0x9C, 0x82, 0xA3, 0xEE, 0xA9, 0xB8, 0x88, 0x3A, 0x78, 0x0A, 0xC5, 0x74, 0x41, 0x39, 0x58,
0x57, 0x7C, 0x02, 0x20, 0x97, 0x29, 0x97, 0xB8, 0x65, 0x42, 0xAD, 0x6F, 0x5A, 0xFC, 0xDC, 0x86,
0x1F, 0x13, 0xF1, 0x49, 0x41, 0x0D, 0x88, 0x52, 0xA8, 0x54, 0x81, 0x63, 0x6D, 0x2D, 0xB4, 0x64,
0x7E, 0x3D, 0xC5, 0x0D, 0xC6, 0x81, 0xEC, 0x2C, 0xCC, 0x2C, 0x3D, 0x53, 0xEF, 0xA0, 0x5D, 0xC0,
0x63, 0xD5, 0xBD, 0xD8, 0xD0, 0x22, 0x63, 0x54, 0xA8, 0x27, 0x1B, 0x90, 0x4D, 0x0B, 0xBF, 0x61,
0xDA, 0x46, 0x2C, 0xB1, 0x2C, 0x86, 0x97, 0x33, 0x72, 0x52, 0xA4, 0xD7, 0x53, 0x86, 0x27, 0x2E,
0xDE, 0x69, 0xE7, 0xFF, 0xA0, 0xF7, 0x85, 0x59, 0x01, 0xE6, 0x31, 0xD3, 0x85, 0xD7, 0x39, 0xA8,
0xE9, 0x8D, 0x6F, 0x5C, 0xAF, 0xB8, 0xC2, 0x64, 0xBB, 0x6D, 0xA6, 0xBF, 0x0E, 0x1F, 0x50, 0x69,
0xBF, 0x21, 0x17, 0x8B, 0x6C, 0xE2, 0x60, 0xAE, 0x44, 0xE7, 0xF7, 0xDA, 0x04, 0x2E, 0x99, 0xD3,
0x51, 0xBE, 0xE3, 0x8F, 0x70, 0x67, 0x1F, 0x7C, 0xB7, 0x80, 0xD2, 0x27, 0xE2, 0x1A, 0x07, 0xE1,
0x83, 0x3E, 0xD2, 0x47, 0xFF, 0x42, 0xA9, 0x9E, 0x16, 0x37, 0x4C, 0x3A, 0x9C, 0x32, 0x98, 0xE0,
0x1D, 0x35, 0xB5, 0x8C, 0xF6, 0x6B, 0x40, 0xF4, 0x88, 0x97, 0xEE, 0x57, 0xAE, 0xC1, 0xA0, 0xF4,
0x9D, 0x8C, 0x13, 0x4C, 0xE2, 0x75, 0x8E, 0xEC, 0x28, 0xE6, 0x9E, 0x2B, 0x41, 0xB0, 0xE8, 0x50,
0x27, 0x7E, 0xC7, 0x05, 0x75, 0x3A, 0xCE, 0x78, 0x66, 0x9E, 0x91, 0x4B, 0x03, 0x73, 0x63, 0xCE,
0x72, 0x8A, 0xBA, 0x10, 0xCD, 0x9A, 0xEF, 0x5E, 0xB8, 0x15, 0x19, 0x0F, 0x35, 0xBC, 0xE6, 0x4E,
0x60, 0x03, 0x1F, 0x94, 0xEC, 0x3A, 0xC7, 0xFF, 0x08, 0x42, 0x43, 0xA4, 0x16, 0x42, 0x0B, 0x45,
0x49, 0xF0, 0x59, 0x96, 0x04, 0xB7, 0x54, 0x19, 0xDF, 0xB2, 0x6D, 0xAA, 0x2B, 0x36, 0x17, 0x75,
0xB8, 0x87, 0x95, 0xC5, 0x05, 0xF9, 0x8D, 0xAB, 0xD8, 0xA7, 0x18, 0xB3, 0x99, 0x40, 0xEB, 0xAF,
0x53, 0xCF, 0x08, 0xF5, 0x3C, 0x57, 0x0B, 0x25, 0x2D, 0x72, 0x9F, 0xAE, 0x36, 0x79, 0x79, 0xA5,
0x54, 0xB9, 0x67, 0x1F, 0x8C, 0x23, 0xBD, 0xBC, 0x47, 0x84, 0xAD, 0x2B, 0xB1, 0x86, 0xAE, 0xF2,
0x7F, 0x72, 0x21, 0x3F, 0x75, 0x06, 0xA6, 0x86, 0x16, 0x16, 0x28, 0x0A, 0x94, 0xC7, 0x8F, 0x2F,
0xB0, 0x11, 0x23, 0x24, 0xA3, 0x1A, 0xAD, 0x5B, 0xA8, 0x62, 0xBA, 0x80, 0x44, 0x83, 0x06, 0xB5,
0x62, 0xA7, 0xF8, 0xC8, 0x4B, 0x88, 0xD7, 0xD4, 0xEB, 0x42, 0x7B, 0xBB, 0xCD, 0xD1, 0xD6, 0xAD,
0x14, 0xC8, 0x35, 0xC1, 0x8D, 0x8E, 0x5E, 0xBF, 0x3C, 0xD3, 0x8F, 0x2E, 0xB7, 0xB2, 0xD9, 0x32,
0x8A, 0x45, 0x64, 0x33, 0x24, 0x33, 0x6C, 0xFC, 0x1C, 0x8A, 0x06, 0xCB, 0xCD, 0x3A, 0xD2, 0x89,
0x82, 0x07, 0x23, 0x5B, 0x7D, 0x3A, 0x16, 0x7A, 0x3E, 0x28, 0xC4, 0x75, 0xE3, 0xE9, 0xCB, 0x07,
0xF0, 0xF5, 0xF8, 0x77, 0xC3, 0x81, 0x1E, 0x78, 0xEA, 0x73, 0xB4, 0x31, 0x7D, 0x92, 0x92, 0xED,
0x46, 0xE1, 0xF8, 0x44, 0x1E, 0xD8, 0x24, 0x7F, 0x8C, 0x97, 0xED, 0x6C, 0xB7, 0x1C, 0x8C, 0xC2,
0xBF, 0x81, 0xAA, 0xD2, 0xE7, 0xFD, 0x06, 0x77, 0xC4, 0xBF, 0xB7, 0x73, 0xD6, 0xFE, 0xFD, 0x27,
0xBB, 0x8B, 0xB8, 0xD9, 0x63, 0xDC, 0x02, 0x51, 0x5D, 0x38, 0xA6, 0xEF, 0xD8, 0x7B, 0x76, 0x1C,
0x35, 0x21, 0x94, 0x55, 0x75, 0x6C, 0x3F, 0x6B, 0xA2, 0x0F, 0xB2, 0xB8, 0xA4, 0x6F, 0x6B, 0x86,
0x5C, 0xC2, 0x9B, 0x81, 0x1D, 0x05, 0xD1, 0xBF, 0x02, 0x6F, 0x59, 0x3D, 0xA9, 0x87, 0x63, 0xCD,
0x2D, 0xFA, 0x86, 0x03, 0xB8, 0xCB, 0x92, 0x4B, 0x6E, 0xD3, 0xF0, 0x5E, 0x9F, 0xF2, 0x31, 0xD7,
0xEE, 0xDB, 0x26, 0x7A, 0x9B, 0xD2, 0x92, 0xAB, 0x5C, 0x1C, 0x5B, 0x33, 0x51, 0x0D, 0x44, 0x61,
0x89, 0x2E, 0x48, 0xE6, 0xD9, 0x12, 0x86, 0x14, 0xB7, 0xB0, 0x4F, 0x72, 0xA7, 0xA3, 0x5F, 0xFA,
0xB3, 0x09, 0xAE, 0xEB, 0xD3, 0xD3, 0x5C, 0xF6, 0x38, 0x77, 0x0A, 0xD2, 0x89, 0x50, 0xEB, 0xFB,
0xC5, 0x65, 0xD4, 0x06, 0xB6, 0x4B, 0xBD, 0x5D, 0x13, 0x3C, 0x50, 0xC2, 0xDD, 0x83, 0x14, 0x89,
0x66, 0x03, 0x7E, 0x4F, 0xB3, 0x67, 0x72, 0xAB, 0xE3, 0x5D, 0xEE, 0x29, 0x60, 0x60, 0x9A, 0x09,
0xC5, 0x6D, 0x2D, 0x18, 0x5A, 0xE7, 0x5F, 0x52, 0x5D, 0x89, 0x49, 0x75, 0x75, 0x1A, 0x95, 0x72,
0x87, 0x50, 0x2A, 0xBE, 0x7E, 0xA6, 0xB7, 0x1A, 0x1A, 0xD9, 0x0D, 0x92, 0x0D, 0x79, 0xE1, 0x6B,
0xE7, 0xAD, 0x9F, 0x69, 0x93, 0xB5, 0xD3, 0x5F, 0x23, 0xAB, 0x4D, 0x3B, 0x2F, 0x7B, 0x9D, 0xCA,
0x0D, 0xCE, 0x21, 0xE8, 0x39, 0x83, 0x8F, 0x15, 0x15, 0x43, 0x7E, 0x1A, 0x17, 0xEE, 0x02, 0x65,
0x63, 0xA9, 0xE2, 0x1B, 0x2A, 0xF8, 0x17, 0xDA, 0xF9, 0x96, 0xE4, 0x16, 0x05, 0xB7, 0x0B, 0xBA,
0x67, 0x68, 0xB8, 0x49, 0xB1, 0xAC, 0xE3, 0x97, 0x40, 0x19, 0xDC, 0xE3, 0x24, 0x3E, 0xB8, 0xE0,
0x0B, 0x85, 0x4E, 0x06, 0x32, 0x8A, 0x7D, 0x8A, 0xF4, 0xCA, 0xD8, 0x78, 0x16, 0x76, 0x85, 0x6D,
0xC8, 0xE5, 0x5D, 0xE7, 0x7A, 0x18, 0xCE, 0x73, 0x4C, 0x2F, 0xFC, 0x2C, 0xE7, 0xD0, 0x09, 0x7F,
0xEC, 0x8D, 0xAF, 0xDA, 0xDA, 0xBA, 0xF4, 0xBF, 0xE6, 0x78, 0x8B, 0x9B, 0xA7, 0x4D, 0x72, 0x8F,
0x2E, 0xA6, 0x89, 0x5A, 0xA3, 0xA5, 0x3D, 0xDF, 0x84, 0x40, 0xF9, 0x72, 0xC9, 0xB9, 0x99, 0x53,
0x33, 0x32, 0x33, 0x12, 0xB3, 0x7C, 0x37, 0x0B, 0x3F, 0x02, 0xCA, 0xE1, 0x75, 0x7F, 0xC6, 0xA1,
0x67, 0x5D, 0x33, 0x09, 0x7E, 0x05, 0xDE, 0x44, 0xF6, 0xDF, 0x09, 0x41, 0xBC, 0xA3, 0xB2, 0x0A,
0x3E, 0x41, 0xFB, 0xDC, 0x78, 0xFA, 0xE8, 0x93, 0x0B, 0x09, 0xCC, 0xA9, 0xC0, 0x1E, 0xA7, 0xBB,
0x96, 0x5E, 0xD8, 0x43, 0x4E, 0x6F, 0x0C, 0x4A, 0x69, 0xE2, 0x2C, 0x8F, 0x28, 0x44, 0x4D, 0x84,
0xC8, 0x40, 0x89, 0x24, 0x58, 0x88, 0xA2, 0xFB, 0x0D, 0x2D, 0xA5, 0xD9, 0x72, 0x88, 0x1A, 0x16,
0xF0, 0x09, 0x8A, 0x73, 0xBE, 0x89, 0xE9, 0xF2, 0xC1, 0xC2, 0xF5, 0xF1, 0xEF, 0x46, 0x44, 0x21,
0x0E, 0xD7, 0x0E, 0x3C, 0x94, 0xA3, 0xFD, 0x73, 0x8B, 0xCD, 0x29, 0xC1, 0x24, 0x00, 0xFA, 0xAA,
0x43, 0x14, 0xD1, 0x3F, 0x33, 0x6D, 0xF8, 0xE6, 0xB6, 0xDE, 0x88, 0xE5, 0x9B, 0x59, 0x99, 0xAE,
0x33, 0x77, 0x47, 0xD9, 0xC8, 0x6B, 0x71, 0x63, 0x71, 0x6A, 0x56, 0x6E, 0xCA, 0x59, 0x51, 0xBB,
0xC5, 0xD5, 0x47, 0xED, 0xE0, 0xBD, 0xBF, 0x30, 0x2D, 0x8C, 0x6C, 0xC5, 0x7F, 0xD8, 0x68, 0x00,
0x01, 0xE5, 0xD1, 0x4B, 0xC0, 0x05, 0x58, 0x07, 0x05, 0xB4, 0xCD, 0xF6, 0x9F, 0x6D, 0xB0, 0x44,
0x16, 0xEF, 0x5A, 0x43, 0xFD, 0xB4, 0x24, 0xB7, 0xD3, 0x32, 0x65, 0x09, 0xD8, 0x1A, 0x20, 0x59,
0x9E, 0xF0, 0xD4, 0xFF, 0x2E, 0xF9, 0x1C, 0xCA, 0xBA, 0x18, 0x9E, 0x0C, 0xAF, 0xD4, 0x87, 0xAB,
0xC9, 0x2D, 0x24, 0x73, 0x5B, 0x54, 0x5F, 0x21, 0x68, 0xEF, 0x84, 0x92, 0xCA, 0x6F, 0x22, 0x43,
0xF9, 0xD8, 0xEA, 0x70, 0x14, 0x37, 0x7B, 0xED, 0x31, 0xD8, 0x83, 0xB3, 0x21, 0x3F, 0xC6, 0xFC,
0xDE, 0x9E, 0xD4, 0x0A, 0xA1, 0x6A, 0xB3, 0xB8, 0x40, 0x6B, 0x88, 0x50, 0xD1, 0x61, 0x2D, 0x21,
0x72, 0x88, 0x2C, 0x55, 0xD3, 0x00, 0x7B, 0x52, 0xAE, 0xBB, 0x27, 0x97, 0xFE, 0x78, 0x92, 0xF8,
0x39, 0xDF, 0x0F, 0x26, 0x5E, 0x84, 0xB4, 0xB0, 0x75, 0xA5, 0xB8, 0x7B, 0xEE, 0xD0, 0xD3, 0x2E,
0x4D, 0x3C, 0xD4, 0x48, 0x52, 0x02, 0x52, 0x06, 0x3A, 0x82, 0x36, 0xE4, 0x67, 0xAD, 0xE8, 0x2B,
0x25, 0xFA, 0xCA, 0x84, 0xBB, 0x32, 0x7E, 0x6E, 0x94, 0xA0, 0x4D, 0x74, 0x4F, 0x62, 0x45, 0xCD,
0x4D, 0x68, 0x0A, 0x01, 0x07, 0xEF, 0x85, 0x4E, 0x9C, 0x61, 0x02, 0xF3, 0x6B, 0x80, 0xEB, 0xAA,
0xA6, 0xD3, 0x62, 0xCF, 0x1B, 0xF6, 0xBA, 0xBD, 0x3E, 0xF2, 0x46, 0x5C, 0x1D, 0x84, 0x8A, 0x9F,
0xDF, 0x6F, 0x40, 0x6E, 0x4D, 0x43, 0x2C, 0xBA, 0x59, 0x27, 0xFF, 0x16, 0xC2, 0xEB, 0x7D, 0x7E,
0x0E, 0xEE, 0x7A, 0x77, 0x5E, 0xB4, 0x37, 0x5D, 0x7F, 0xE9, 0x4A, 0x1F, 0xE4, 0x18, 0x57, 0x05,
0xFD, 0x1B, 0xBD, 0x5A, 0x4D, 0x6F, 0xDD, 0x56, 0x7A, 0x7E, 0x49, 0x3A, 0x62, 0x60, 0xD6, 0x39,
0x2E, 0x6A, 0x14, 0x41, 0x55, 0x0F, 0x67, 0x31, 0x8B, 0x01, 0x1C, 0x99, 0xB3, 0xF0, 0x22, 0x05,
0x74, 0x49, 0x26, 0x06, 0x9A, 0x45, 0x16, 0x93, 0x7F, 0x90, 0xF9, 0x03, 0x85, 0x06, 0x45, 0x16,
0x5E, 0x58, 0x22, 0x63, 0x17, 0xD3, 0x45, 0x80, 0xC6, 0xBF, 0xA0, 0xD5, 0xBA, 0x40, 0xE1, 0x2C,
0xBC, 0xD0, 0xA0, 0x57, 0x22, 0x3D, 0x02, 0x9A, 0xC5, 0x2C, 0x4C, 0x8F, 0x17, 0x59, 0xCC, 0x22,
0x74, 0xAD, 0xC2, 0xC1, 0xA4, 0x80, 0x98, 0x86, 0x69, 0x28, 0x8B, 0x97, 0x67, 0x9E, 0xE7, 0x90,
0x57, 0xBA, 0x92, 0xAF, 0x2C, 0xC5, 0xC9, 0x0C, 0xAF, 0x2E, 0x45, 0xF2, 0x9E, 0x8F, 0xF7, 0xBC,
0x9F, 0xCF, 0xFB, 0x1E, 0x8A, 0xD2, 0x85, 0x48, 0xA2, 0x63, 0x39, 0x7E, 0xDC, 0xC3, 0xD7, 0xAD,
0x70, 0x8A, 0x72, 0x11, 0x6B, 0x37, 0x15, 0x51, 0x01, 0xEE, 0x96, 0x57, 0x45, 0xEC, 0xA2, 0xC1,
0x9D, 0x8D, 0x1F, 0x37, 0x9C, 0x42, 0x9C, 0x5C, 0xE5, 0xE2, 0x6B, 0x2D, 0xA2, 0x75, 0x87, 0x3B,
0x69, 0xE5, 0xAA, 0x58, 0xB5, 0x54, 0xE2, 0x94, 0xFE, 0x8E, 0xAC, 0xFC, 0x8F, 0xAE, 0x5C, 0x5D,
0x05, 0xBA, 0xF0, 0x74, 0x35, 0x8C, 0x6D, 0xEB, 0xD8, 0xD3, 0xB5, 0x5B, 0x46, 0x56, 0xE5, 0xE5,
0x97, 0x38, 0xD0, 0x58, 0x56, 0x34, 0xFA, 0xE7, 0x9B, 0x76, 0x15, 0xCA, 0x58, 0xE5, 0x89, 0xA5,
0xF7, 0x3B, 0xBF, 0x5C, 0x1B, 0x3A, 0xAC, 0x3B, 0x82, 0xD1, 0x96, 0x41, 0x91, 0x06, 0x35, 0x76,
0x73, 0x84, 0x52, 0x9F, 0xA7, 0x96, 0xE4, 0xF2, 0x79, 0x88, 0xD1, 0xAC, 0x27, 0x58, 0x94, 0xFA,
0x39, 0x68, 0x5E, 0x0E, 0x48, 0xEE, 0x08, 0x77, 0x6C, 0x71, 0x03, 0x64, 0x39, 0x5A, 0x97, 0x24,
0x37, 0x97, 0x46, 0xFC, 0x18, 0xE4, 0x46, 0x20, 0x57, 0xC6, 0xD6, 0x44, 0xDC, 0x2E, 0xEA, 0x44,
0x4F, 0x30, 0xC6, 0x79, 0xF9, 0x19, 0x67, 0x4B, 0x26, 0x33, 0x53, 0x79, 0x13, 0xC1, 0x1A, 0xFC,
0xB4, 0x75, 0xF3, 0x40, 0xDE, 0xF3, 0x72, 0xB1, 0x2B, 0x2B, 0x6B, 0x31, 0x9A, 0x5D, 0x7B, 0x79,
0x63, 0x57, 0x91, 0xD5, 0xBA, 0x7A, 0xB7, 0x49, 0x6E, 0xA1, 0x07, 0x08, 0x15, 0x87, 0x8B, 0xF5,
0x4B, 0x9C, 0x48, 0xB2, 0xBB, 0x0B, 0x0E, 0x5F, 0x8D, 0x70, 0x57, 0x83, 0x0E, 0xEF, 0x3E, 0x1A,
0x8D, 0xD0, 0xC2, 0xAA, 0x54, 0x21, 0x2A, 0xF5, 0x53, 0x88, 0x40, 0x93, 0xB4, 0x89, 0xA8, 0x18,
0x94, 0x8E, 0xD1, 0xDD, 0x2D, 0xC5, 0x6B, 0x74, 0xE3, 0xE8, 0x1A, 0xBD, 0x6E, 0x72, 0x79, 0x39,
0x97, 0x37, 0x5D, 0xAC, 0x4D, 0x99, 0xD9, 0xAD, 0xD8, 0x1D, 0x98, 0x52, 0x39, 0x25, 0x38, 0xA7,
0xD2, 0x65, 0x07, 0x13, 0x36, 0x6C, 0xB5, 0xA8, 0xD3, 0x44, 0x97, 0x91, 0x34, 0xE0, 0xA5, 0xAD,
0xF7, 0x5B, 0xBF, 0xDC, 0x32, 0x9D, 0xC1, 0x0F, 0x95, 0x1A, 0xE2, 0xB2, 0x54, 0xBC, 0xD2, 0x2C,
0xCD, 0xC2, 0xC0, 0x9B, 0x46, 0xD0, 0xEA, 0xCE, 0x74, 0xB9, 0x56, 0xB6, 0x63, 0x51, 0x1E, 0x32,
0x06, 0x93, 0xB6, 0x4B, 0x59, 0xBE, 0x29, 0x16, 0x16, 0xCD, 0xC1, 0xD1, 0x7F, 0xFA, 0x6F, 0x0C,
0xAA, 0xC0, 0x6A, 0xAC, 0xCB, 0xEA, 0xE4, 0x15, 0x57, 0xEB, 0x62, 0x41, 0x9B, 0x31, 0xCF, 0x8B,
0xAC, 0x72, 0x16, 0x4C, 0x57, 0x0E, 0x23, 0x66, 0x45, 0xA0, 0xFF, 0xBB, 0xF2, 0x1F, 0xC4, 0x57,
0xC7, 0xF2, 0x57, 0x25, 0xBB, 0x87, 0x5C, 0x89, 0x0D, 0x91, 0x34, 0xF2, 0x0E, 0xF8, 0x88, 0x9E,
0x16, 0xC6, 0x4C, 0x62, 0xF1, 0x37, 0xC5, 0x7D, 0x58, 0x49, 0xE5, 0xC6, 0x47, 0xA9, 0xD9, 0x92,
0x9B, 0x3D, 0x35, 0x6F, 0x80, 0x1F, 0xDF, 0x81, 0x9A, 0x46, 0x54, 0x2D, 0xBF, 0xAE, 0x9C, 0xFB,
0xD5, 0x1B, 0x76, 0x7E, 0x76, 0x6A, 0xEC, 0xD2, 0x0C, 0x66, 0x97, 0xB3, 0xDA, 0xB6, 0xD8, 0xC5,
0xBE, 0x6E, 0xBD, 0xD2, 0xBD, 0x5F, 0xCB, 0x72, 0x28, 0xCE, 0xA7, 0xB9, 0x99, 0x78, 0x86, 0x8C,
0xA6, 0xA7, 0x6D, 0xB5, 0xD7, 0x01, 0xA8, 0xC0, 0x7B, 0x09, 0xE4, 0xBA, 0xD2, 0xC1, 0x5C, 0xF8,
0xC4, 0x4B, 0xE5, 0x50, 0xA7, 0x6C, 0xDD, 0x05, 0x56, 0x5B, 0xDB, 0x5F, 0xE6, 0x56, 0xC8, 0x9E,
0x90, 0x1F, 0xAC, 0x29, 0x88, 0x25, 0x4A, 0xCF, 0x25, 0xB0, 0x9A, 0x0E, 0xC2, 0xF1, 0x62, 0x1F,
0x26, 0x32, 0x86, 0x4E, 0xC0, 0xC6, 0xA0, 0x2F, 0x72, 0x69, 0x2E, 0x4F, 0xDE, 0x3C, 0x3B, 0x4F,
0x5E, 0x93, 0x6A, 0xA4, 0xE2, 0xD1, 0x86, 0x24, 0xB9, 0xD1, 0x2C, 0x1E, 0x41, 0xED, 0xE9, 0x66,
0xEC, 0x7E, 0x5D, 0x78, 0x2B, 0x53, 0x42, 0x52, 0x76, 0x83, 0x62, 0x74, 0xF2, 0x97, 0x98, 0x28,
0x6B, 0x24, 0xB6, 0xA0, 0x89, 0x50, 0x43, 0x8F, 0x8B, 0xCE, 0xF2, 0x41, 0x25, 0x87, 0xE3, 0xAE,
0xDE, 0x91, 0x88, 0xC6, 0xD5, 0x58, 0x1A, 0xCC, 0xF4, 0x4A, 0xF4, 0xDF, 0x34, 0xC3, 0x60, 0x34,
0x58, 0x35, 0xCC, 0x3A, 0x95, 0x00, 0x0F, 0x60, 0x2E, 0x18, 0x1E, 0x0F, 0x6A, 0x3C, 0x18, 0xE3,
0xC1, 0x2A, 0xBA, 0x6C, 0x61, 0x2D, 0x13, 0x7C, 0x77, 0x40, 0xE8, 0x96, 0x27, 0x96, 0xBE, 0x05,
0xCF, 0x52, 0x42, 0xF5, 0x1B, 0x18, 0x53, 0x78, 0x01, 0x8B, 0xB9, 0x05, 0x9D, 0x2E, 0x61, 0x83,
0x0D, 0xD8, 0xB3, 0x06, 0xD3, 0x55, 0xA9, 0x97, 0x3B, 0x25, 0xBA, 0x37, 0xF8, 0x84, 0xF8, 0xA8,
0x54, 0xE1, 0x01, 0x58, 0xD5, 0x80, 0xEE, 0x4E, 0x3C, 0xBD, 0xDF, 0x48, 0xF2, 0xB8, 0x83, 0x67,
0xD9, 0x43, 0x37, 0x98, 0xD1, 0xD8, 0xCA, 0xE2, 0x40, 0x1C, 0xD8, 0xAB, 0x44, 0x68, 0xE6, 0xE5,
0x60, 0xCE, 0xB7, 0xB0, 0xBB, 0x10, 0xAB, 0x53, 0xB7, 0xE0, 0xAF, 0x0A, 0x3C, 0xA8, 0xA1, 0xB2,
0x63, 0xB4, 0x08, 0xD1, 0x22, 0x02, 0xFB, 0x12, 0xC9, 0xE0, 0xD6, 0x32, 0x12, 0x06, 0xCA, 0xA0,
0xD9, 0x0D, 0x5D, 0x11, 0x64, 0xD1, 0x8A, 0xA2, 0x43, 0x6B, 0x48, 0x96, 0xAD, 0x75, 0x0A, 0xAA,
0xE0, 0x5E, 0x1A, 0x12, 0x15, 0x9A, 0x45, 0x87, 0xA4, 0x8D, 0x24, 0x05, 0xB8, 0x25, 0x45, 0x99,
0xCE, 0x52, 0x12, 0x24, 0x9A, 0x36, 0x5B, 0xCF, 0x6A, 0x95, 0xD6, 0xFA, 0x37, 0x19, 0x48, 0x69,
0x84, 0x26, 0xFC, 0x09, 0x25, 0x17, 0x1A, 0xC5, 0xA5, 0x53, 0x88, 0x15, 0xF4, 0x67, 0x7A, 0x5B,
0x1A, 0xB9, 0x16, 0xA1, 0xB8, 0x71, 0x23, 0x4B, 0x8B, 0x5A, 0x7F, 0x83, 0xBE, 0x39, 0x7C, 0x6B,
0x34, 0x38, 0x71, 0x4B, 0xA7, 0x91, 0xDE, 0xAE, 0xFC, 0x7F, 0x93, 0x68, 0x8C, 0x29, 0x79, 0x6C,
0x4D, 0x55, 0xBB, 0x86, 0x6A, 0x77, 0xB6, 0x36, 0x56, 0x6E, 0xA7, 0x7F, 0x21, 0xEA, 0xC3, 0x0A,
0xBE, 0x50, 0xA6, 0x8E, 0x00, 0x87, 0xD2, 0xBA, 0xBD, 0xA2, 0x35, 0x7C, 0x89, 0x9D, 0x63, 0x8E,
0x99, 0x29, 0x21, 0xDC, 0x06, 0x74, 0x96, 0xD3, 0xDB, 0x9E, 0xA0, 0x0B, 0xB8, 0xBD, 0x86, 0xC6,
0x0F, 0x31, 0xD3, 0xFB, 0xE8, 0x8B, 0x87, 0x3F, 0x95, 0xBC, 0xF1, 0x2D, 0xAC, 0x6F, 0x6B, 0x18,
0x33, 0x29, 0xC1, 0xA9, 0xD6, 0x7D, 0x9A, 0xAB, 0x5D, 0x0A, 0x02, 0xC7, 0xEE, 0x54, 0xB5, 0x26,
0x54, 0xAD, 0x34, 0xAB, 0x8D, 0x55, 0xD0, 0x3D, 0x6E, 0xCC, 0x72, 0x05, 0x6B, 0xD7, 0xE7, 0x31,
0x28, 0xE6, 0x00, 0x41, 0x4E, 0x3E, 0xCB, 0x03, 0xB0, 0x24, 0xD2, 0xD5, 0x2C, 0x7D, 0x30, 0x46,
0xB0, 0xE4, 0x32, 0x6E, 0xEF, 0xAD, 0x68, 0xFD, 0x99, 0x66, 0x48, 0x3A, 0x6E, 0x71, 0x3E, 0xFC,
0x69, 0x1B, 0x59, 0x7B, 0x95, 0xB3, 0x0F, 0x9E, 0xF1, 0xD8, 0x3F, 0xB0, 0xB8, 0x18, 0x16, 0x57,
0x06, 0x7B, 0x54, 0xE2, 0xEA, 0x2E, 0x78, 0x0A, 0x29, 0x0E, 0xF2, 0xB8, 0xF3, 0x9C, 0x3C, 0xDA,
0x19, 0x79, 0x60, 0xF9, 0x16, 0xE4, 0xA1, 0xFE, 0x1E, 0x94, 0xC2, 0x8D, 0x57, 0xC6, 0x5B, 0xD3,
0x32, 0xC2, 0xDE, 0x55, 0xD3, 0x53, 0xC3, 0x51, 0x5B, 0x3A, 0x8E, 0xF4, 0xED, 0x2A, 0x78, 0x3F,
0xA6, 0x5C, 0x2A, 0xDB, 0xCC, 0xDE, 0x35, 0x88, 0x23, 0x94, 0x8B, 0x4B, 0xB9, 0xD4, 0x8C, 0x65,
0x35, 0xAD, 0x98, 0xF4, 0x94, 0x74, 0x85, 0xF2, 0x0A, 0x22, 0xC2, 0x58, 0xFC, 0x77, 0x11, 0x63,
0x31, 0x96, 0x8F, 0x61, 0x5F, 0x3F, 0x26, 0x28, 0xF2, 0xC5, 0x3B, 0x2A, 0xA8, 0x1A, 0x82, 0x2A,
0x9E, 0x17, 0xD4, 0x07, 0x33, 0x82, 0x7A, 0x4D, 0xCA, 0x91, 0x92, 0xD1, 0x3D, 0x49, 0xD2, 0x03,
0x1F, 0x70, 0xBA, 0xA0, 0x60, 0x05, 0xEF, 0x09, 0x5D, 0x24, 0xCC, 0x0B, 0x3E, 0x03, 0xC3, 0xDF,
0xB0, 0x0F, 0x7D, 0x00, 0x0D, 0x54, 0xEB, 0xC6, 0xDD, 0x91, 0xC6, 0x8F, 0x65, 0x03, 0x13, 0xFF,
0x92, 0x43, 0x8F, 0x7B, 0x56, 0x0D, 0xDF, 0x08, 0xCC, 0xFB, 0x9B, 0x09, 0x9E, 0x8D, 0x11, 0xDD,
0xC7, 0x11, 0x5C, 0x80, 0xFF, 0x8D, 0xC5, 0x40, 0xDA, 0xC2, 0x52, 0x8D, 0x66, 0xD2, 0x6D, 0x82,
0x2A, 0x75, 0x53, 0x6C, 0x44, 0x81, 0x6B, 0x0B, 0xBD, 0xE4, 0x9E, 0x4D, 0xB0, 0xE4, 0xDF, 0xD5,
0xEA, 0x9F, 0x42, 0x84, 0x4E, 0x68, 0x61, 0x24, 0xA1, 0x05, 0x53, 0x86, 0xD7, 0x92, 0xFD, 0x3D,
0xC6, 0x70, 0x76, 0x0B, 0x60, 0xEB, 0xA0, 0x60, 0x24, 0xEA, 0xB7, 0x18, 0x18, 0x7E, 0xFF, 0xE3,
0xC2, 0xAD, 0x12, 0x34, 0xC9, 0x86, 0x40, 0x0E, 0xE5, 0x94, 0xD0, 0xCD, 0x8D, 0xD6, 0xCF, 0xE2,
0x88, 0x29, 0xE9, 0xB5, 0x6C, 0x20, 0x02, 0xDF, 0x00, 0xE9, 0xD7, 0xE6, 0x93, 0xBE, 0xF0, 0x42,
0xD2, 0xD7, 0x6D, 0xB0, 0xBC, 0x22, 0x72, 0x38, 0xD0, 0xFE, 0xB3, 0x92, 0x1E, 0xE9, 0x3D, 0xF8,
0xBF, 0x66, 0x55, 0xD4, 0x83, 0xE7, 0x49, 0x67, 0x0C, 0x62, 0xA3, 0xA3, 0xB1, 0xE8, 0x38, 0xC7,
0xEF, 0xCD, 0xE7, 0x78, 0xF2, 0x62, 0x8E, 0x0F, 0xF3, 0x5F, 0x9D, 0x1D, 0xD7, 0xD2, 0x77, 0x0B,
0x38, 0xE4, 0x20, 0x6E, 0xAE, 0x97, 0x0E, 0x94, 0x3B, 0x74, 0x00, 0x31, 0xFC, 0x98, 0x0E, 0x25,
0x55, 0xD9, 0x9D, 0x69, 0x64, 0xD4, 0xFA, 0x0E, 0x56, 0x76, 0xBB, 0x90, 0x76, 0x43, 0x3C, 0x90,
0xDD, 0x4C, 0x24, 0x41, 0x8C, 0x49, 0x3D, 0x9D, 0x9E, 0x91, 0x36, 0xB2, 0xF4, 0xAF, 0x5F, 0xC8,
0x52, 0x5A, 0x44, 0x0F, 0x79, 0xC6, 0xFD, 0xB5, 0x85, 0x78, 0xE6, 0xF5, 0xAC, 0x58, 0xEE, 0x0D,
0x6D, 0xDC, 0x43, 0xD5, 0xAB, 0x3F, 0x18, 0xE9, 0xFD, 0x61, 0xB0, 0x16, 0x6F, 0xED, 0x27, 0xE8,
0xE4, 0xA5, 0xF7, 0x68, 0x8D, 0x17, 0x07, 0x53, 0xD1, 0x92, 0x4D, 0xAE, 0xD4, 0x12, 0xEC, 0xC0,
0xAE, 0xDC, 0x7C, 0xEE, 0x89, 0x8E, 0xB9, 0x3F, 0x9D, 0xD8, 0x84, 0xA7, 0xC5, 0x3D, 0xB8, 0x25,
0x33, 0x9E, 0xC8, 0xC0, 0x17, 0x4E, 0xFA, 0x6B, 0x2C, 0xF5, 0xA6, 0x9A, 0x46, 0x7B, 0x1C, 0x2B,
0x04, 0x47, 0xE5, 0xD0, 0x82, 0xB4, 0xD1, 0xB8, 0x1D, 0xF3, 0x20, 0x2B, 0x0C, 0x23, 0x55, 0xE9,
0xA7, 0xD0, 0x2F, 0x7A, 0xC5, 0x31, 0x5A, 0x30, 0xEE, 0x78, 0xD3, 0x90, 0x78, 0xF8, 0xC0, 0x6B,
0xDC, 0x67, 0x4A, 0x5F, 0xD7, 0x05, 0x26, 0x04, 0xFC, 0x00, 0x44, 0xDF, 0x81, 0xC7, 0xF1, 0xF2,
0xBB, 0x7F, 0xF8, 0xF7, 0xBB, 0x7F, 0x30, 0x56, 0x6F, 0x6E, 0xFB, 0x53, 0x1F, 0x5C, 0x78, 0x3A,
0x7C, 0x36, 0xE7, 0x14, 0x20, 0x2A, 0x37, 0x1C, 0x6F, 0xB2, 0x48, 0x56, 0x4D, 0x29, 0xA4, 0x0B,
0x8E, 0x74, 0x3E, 0x90, 0xEC, 0x37, 0xF4, 0x5A, 0xA9, 0x33, 0x01, 0x85, 0x2D, 0xA2, 0xBE, 0x09,
0xD9, 0xE9, 0xF1, 0x18, 0x3E, 0x3C, 0x00, 0xAE, 0xCD, 0x6E, 0x83, 0xC6, 0x3A, 0x5C, 0xD0, 0x1F,
0x7F, 0xA5, 0x7F, 0x71, 0xC3, 0xA0, 0xB6, 0xEE, 0x4A, 0xC3, 0x9F, 0xE7, 0x7F, 0x16, 0xF7, 0xB2,
0x0E, 0xAD, 0x7F, 0xFB, 0x7F, 0xFA, 0x3D, 0xD3, 0x7A, 0xB1, 0x4C, 0xE6, 0xB6, 0x4A, 0x74, 0xA2,
0x0D, 0x55, 0xC6, 0x38, 0x11, 0x78, 0xCD, 0xA4, 0x86, 0x82, 0x79, 0x17, 0x8B, 0x7B, 0xBE, 0xCE,
0x03, 0xBD, 0x6D, 0x82, 0x9B, 0xC8, 0x02, 0xF0, 0x4D, 0x4A, 0x48, 0x39, 0xE7, 0x14, 0xEC, 0xF8,
0x1C, 0x77, 0xDD, 0x6E, 0x54, 0xD2, 0xF6, 0x41, 0x35, 0x39, 0x95, 0xE4, 0xA1, 0xFD, 0xA4, 0x6F,
0x7F, 0x32, 0xD1, 0x7A, 0x42, 0x41, 0x9D, 0xF4, 0x09, 0xBE, 0xD0, 0x13, 0x37, 0xF5, 0x41, 0x71,
0x44, 0x2C, 0x57, 0x59, 0x08, 0xD6, 0x0C, 0x23, 0x03, 0x56, 0x44, 0x16, 0x42, 0x10, 0x09, 0x15,
0xF0, 0x66, 0x2F, 0xAC, 0xEE, 0x96, 0xAE, 0xAD, 0x86, 0xC0, 0x05, 0xFD, 0xBC, 0x3D, 0xC9, 0xA0,
0xE7, 0x2A, 0x9F, 0x46, 0xCC, 0xD3, 0xA7, 0x9C, 0x4F, 0xAE, 0x67, 0x78, 0x6C, 0x58, 0x7B, 0xB7,
0x7C, 0x01, 0x6B, 0x4F, 0xB9, 0xB0, 0x32, 0x44, 0x5E, 0x58, 0x46, 0x3D, 0x64, 0x79, 0x26, 0xA7,
0xDA, 0x14, 0x93, 0x23, 0x30, 0x6A, 0x5B, 0x0D, 0x72, 0xC8, 0x9C, 0x19, 0x58, 0x31, 0xE3, 0x12,
0xAB, 0xC5, 0xAF, 0xB5, 0xA3, 0xED, 0xCA, 0xAE, 0x02, 0x09, 0x4E, 0xFC, 0x97, 0xAC, 0x07, 0x81,
0x7E, 0xBB, 0x32, 0x19, 0x11, 0xC7, 0x5D, 0x35, 0xC1, 0xD5, 0xAB, 0x7A, 0x5D, 0x25, 0x72, 0xF0,
0x90, 0x87, 0xB5, 0x5E, 0x7E, 0xEF, 0x9C, 0xC4, 0xF4, 0x2A, 0xAD, 0x9D, 0xA5, 0x07, 0xC0, 0x38,
0x94, 0x17, 0x5E, 0xC6, 0x08, 0xA9, 0xCC, 0x7E, 0x62, 0xC4, 0x93, 0x28, 0xEE, 0x7D, 0x49, 0x54,
0xFA, 0x37, 0x95, 0xFB, 0x91, 0xAC, 0x53, 0xC6, 0xFE, 0x0B, 0xD7, 0x3F, 0x02, 0x51, 0x41, 0x9A,
0x00, 0x52, 0x42, 0x7D, 0x3C, 0x72, 0xD1, 0x07, 0x17, 0x01, 0xE0, 0x42, 0x66, 0x86, 0x08, 0x1F,
0x12, 0x32, 0x89, 0xA3, 0x57, 0x8A, 0x6A, 0x42, 0x12, 0x4C, 0x11, 0x82, 0x2F, 0xCE, 0x93, 0x9A,
0x3F, 0x11, 0x39, 0x63, 0xD6, 0x10, 0x41, 0x1B, 0xC2, 0x20, 0x17, 0xBD, 0x3A, 0xE9, 0x0C, 0x76,
0x98, 0xBA, 0x53, 0x95, 0x0F, 0xFE, 0x54, 0xC5, 0xBD, 0x43, 0xA5, 0xD9, 0x46, 0x65, 0xEF, 0x4F,
0x8E, 0x7E, 0x91, 0xE4, 0x22, 0x8F, 0x27, 0x8A, 0x75, 0x4A, 0xAC, 0xEE, 0x29, 0xB1, 0x2F, 0x26,
0xFF, 0x12, 0xB3, 0x3C, 0x61, 0x8E, 0xDF, 0x1A, 0x8A, 0xD0, 0xA6, 0x80, 0x63, 0x69, 0xA2, 0x89,
0xF4, 0x66, 0x62, 0x31, 0x0F, 0x6F, 0x06, 0x8F, 0x8D, 0x6B, 0x27, 0x95, 0x2B, 0x18, 0x2B, 0x29,
0xB9, 0x14, 0x8E, 0x35, 0xEE, 0xFB, 0xEF, 0xE6, 0x18, 0x0F, 0xDF, 0xA7, 0xB8, 0x7E, 0xCC, 0xB1,
0x32, 0x7C, 0x83, 0x61, 0x2C, 0xAB, 0x1F, 0x8B, 0x99, 0x0D, 0x92, 0x65, 0xDD, 0x93, 0x3B, 0x8D,
0xAA, 0xE8, 0x75, 0xA5, 0x99, 0x85, 0x38, 0x72, 0x14, 0xF1, 0xC8, 0xF3, 0x00, 0xE8, 0x1E, 0x18,
0x4C, 0x00, 0xE4, 0x33, 0xBE, 0xBC, 0x0A, 0xF9, 0x64, 0x45, 0x67, 0x46, 0x64, 0xFE, 0x71, 0x06,
0xB5, 0x0C, 0x76, 0xA0, 0x8D, 0xF8, 0x93, 0xBB, 0xE5, 0xD9, 0x26, 0x9D, 0x8F, 0x0F, 0x7B, 0xAE,
0x50, 0xEB, 0x98, 0xB0, 0x8D, 0x58, 0xA2, 0x38, 0xC9, 0xF0, 0x8F, 0x5B, 0x15, 0xBA, 0x15, 0x0E,
0xD4, 0xD7, 0x29, 0xBC, 0xD8, 0x84, 0x41, 0x59, 0x42, 0xFA, 0x5F, 0x9F, 0xEF, 0x1C, 0x38, 0xFA,
0x0B, 0x98, 0xF9, 0xC7, 0xA7, 0xD2, 0x45, 0x94, 0xBC, 0x84, 0xDB, 0x1A, 0x28, 0xF9, 0x53, 0xA2,
0xE4, 0xC5, 0xF2, 0x69, 0xA7, 0x9C, 0xC7, 0x55, 0x78, 0xD9, 0x79, 0x9C, 0x87, 0x97, 0xF0, 0x53,
0x28, 0x27, 0x9C, 0xB2, 0x3B, 0x50, 0x24, 0x52, 0xC1, 0x7C, 0xE8, 0xB9, 0x91, 0x37, 0xA4, 0x61,
0xB0, 0x85, 0x07, 0x39, 0x32, 0x2F, 0xB9, 0x0E, 0x06, 0xF8, 0x03, 0x03, 0x4A, 0xE8, 0x1A, 0xE2,
0x98, 0x33, 0xE7, 0xEF, 0x2A, 0x54, 0xC9, 0x9C, 0x8F, 0xFF, 0xB4, 0xC8, 0x59, 0x63, 0x8A, 0xFC,
0x7C, 0x77, 0x04, 0x3F, 0xE0, 0x8B, 0x88, 0xBC, 0x07, 0x76, 0xEA, 0x82, 0x28, 0x1B, 0x61, 0x48,
0xE4, 0xC6, 0xE1, 0xEF, 0x17, 0xF0, 0x5D, 0xA2, 0x49, 0x2D, 0x60, 0x72, 0x8A, 0xFD, 0x39, 0xF7,
0x1D, 0xAB, 0xFF, 0x10, 0x40, 0xFA, 0xDC, 0xE1, 0x0F, 0x3F, 0x9D, 0xE3, 0xCD, 0xFB, 0x54, 0x84,
0x17, 0xC6, 0x82, 0x32, 0x2A, 0xCC, 0xCE, 0x2C, 0x58, 0x8A, 0x00, 0xF8, 0x34, 0xD0, 0x39, 0x1C,
0x7D, 0x47, 0x8B, 0xD3, 0x31, 0x4E, 0xBB, 0x4C, 0x4E, 0x9F, 0x50, 0x6E, 0x8F, 0x6B, 0x0A, 0x6F,
0xCC, 0x53, 0xC8, 0x93, 0xBA, 0x4E, 0x59, 0x6E, 0x97, 0xC3, 0xEF, 0xF2, 0x2D, 0x4F, 0x94, 0xBD,
0x04, 0xF0, 0xF3, 0x08, 0xE2, 0xE0, 0xAF, 0x33, 0x8B, 0xF3, 0x58, 0x06, 0x71, 0x06, 0x00, 0x48,
0x53, 0x92, 0x4F, 0x66, 0xBC, 0xDD, 0x6F, 0xC0, 0x96, 0x7D, 0x28, 0x55, 0x92, 0xAE, 0xCD, 0x66,
0xC0, 0x27, 0xC4, 0xFF, 0xA0, 0xF4, 0xBF, 0x88, 0x80, 0x46, 0x63, 0xD0, 0x9C, 0x1D, 0xA1, 0x59,
0x5E, 0x9E, 0xE6, 0x86, 0x34, 0x77, 0x87, 0x34, 0x9B, 0x74, 0xC2, 0x94, 0xEE, 0x46, 0x07, 0xB7,
0x9F, 0xBC, 0x1C, 0xA9, 0xAD, 0x1A, 0xB2, 0xDA, 0xD1, 0xE0, 0xB4, 0x58, 0x2C, 0x34, 0x1E, 0xEC,
0x03, 0x7C, 0xCF, 0x31, 0x19, 0xF9, 0x11, 0x1F, 0xA9, 0x8F, 0x72, 0x31, 0xF5, 0x91, 0x1E, 0x29,
0x1E, 0x80, 0xA6, 0x3F, 0xA1, 0x68, 0x7E, 0x09, 0xE3, 0x53, 0x6E, 0x2A, 0xF6, 0xB7, 0x98, 0x3A,
0xC8, 0xE5, 0x88, 0xCC, 0x56, 0x3C, 0xC0, 0xC9, 0x5D, 0x9D, 0x5B, 0x9D, 0xD5, 0x98, 0x90, 0x3C,
0x17, 0x89, 0x1D, 0x3C, 0xC8, 0xD2, 0x64, 0x5D, 0xD7, 0xD1, 0x24, 0x30, 0x89, 0xB9, 0xA9, 0x0C,
0xA8, 0x74, 0xEA, 0xAB, 0xFB, 0x02, 0xA7, 0x93, 0x07, 0xBF, 0xEA, 0xE0, 0x4B, 0x9E, 0x11, 0x86,
0x78, 0x35, 0xEB, 0x40, 0x1C, 0x48, 0x38, 0xCA, 0xE9, 0x97, 0x56, 0x17, 0x67, 0x77, 0x90, 0x49,
0x04, 0xFA, 0x39, 0x8E, 0x1C, 0x0A, 0xBE, 0x20, 0x47, 0x2A, 0xF2, 0xA1, 0xE5, 0xC9, 0xA4, 0x2A,
0xBE, 0x61, 0xCB, 0x6D, 0x72, 0xE4, 0x11, 0x4E, 0xD6, 0xD7, 0x64, 0xC6, 0x7F, 0xF2, 0x14, 0x91,
0x23, 0x3E, 0x39, 0x62, 0xA2, 0xAF, 0x83, 0xD3, 0x2B, 0x04, 0xE3, 0x8A, 0x94, 0x2B, 0x8A, 0x02,
0xF9, 0x15, 0x64, 0xFE, 0x4E, 0xA7, 0x5B, 0x17, 0x81, 0x1A, 0x5C, 0xE0, 0x7A, 0x43, 0xD6, 0x80,
0x8E, 0xFF, 0xCB, 0xD2, 0x20, 0x9A, 0xD8, 0x27, 0x04, 0xE3, 0x04, 0xF6, 0x1A, 0xE8, 0xE2, 0x68,
0xE2, 0xB3, 0x80, 0xE4, 0x80, 0x45, 0xE7, 0x20, 0xF5, 0x2A, 0x64, 0x17, 0x09, 0x26, 0xF5, 0x3E,
0xC3, 0xEC, 0xCF, 0x98, 0x49, 0x31, 0x3D, 0xED, 0x88, 0xF1, 0x41, 0x49, 0x86, 0x07, 0x21, 0x0B,
0x74, 0xEF, 0xA3, 0xC5, 0x36, 0x12, 0xED, 0x22, 0x4A, 0x3D, 0x2C, 0x1B, 0x03, 0x2E, 0xC2, 0xF7,
0xBB, 0x1A, 0x66, 0x3F, 0x39, 0x28, 0x33, 0xB2, 0x92, 0xF3, 0x76, 0xED, 0x7E, 0x55, 0xC9, 0xDA,
0x58, 0x54, 0x67, 0x86, 0xC8, 0x20, 0x7D, 0x60, 0xEB, 0xBB, 0xB1, 0xFB, 0xA8, 0x76, 0xB1, 0xDE,
0xD2, 0x14, 0x50, 0x2E, 0x09, 0x32, 0xD4, 0xB8, 0x12, 0x66, 0xED, 0x7D, 0x9D, 0x77, 0xF6, 0x58,
0xD9, 0x43, 0xB8, 0xD2, 0x15, 0x38, 0x90, 0x01, 0x5B, 0xB9, 0x15, 0x28, 0xDA, 0x84, 0x1D, 0xA8,
0xBB, 0x62, 0xA2, 0x27, 0xC7, 0x34, 0x9E, 0x8A, 0x59, 0xB4, 0xF3, 0x25, 0xE8, 0xFE, 0xA6, 0x61,
0xFA, 0x13, 0xCB, 0x2A, 0x72, 0xEB, 0x2D, 0x60, 0xE6, 0x09, 0xEB, 0x7B, 0x7D, 0x99, 0xE6, 0x55,
0x69, 0x3C, 0xAC, 0x35, 0x3E, 0xCC, 0x28, 0x17, 0x98, 0xA6, 0x4C, 0xBC, 0xC2, 0xFF, 0x34, 0xB7,
0xB0, 0x60, 0xAC, 0xD7, 0x1B, 0x48, 0xAD, 0x88, 0x03, 0xFC, 0x9F, 0x17, 0xFE, 0x87, 0x4C, 0x65,
0xBA, 0x21, 0x5A, 0xBE, 0x09, 0x0F, 0x92, 0x40, 0x4A, 0x09, 0x20, 0xE6, 0x2A, 0xFE, 0xBF, 0x6A,
0xC5, 0x3F, 0x2C, 0x99, 0xAF, 0xBF, 0x2A, 0xEA, 0xDD, 0xD4, 0xDB, 0x2E, 0x9C, 0xDF, 0x95, 0x76,
0x51, 0xCA, 0xC5, 0x8B, 0xDF, 0x91, 0xCC, 0x45, 0xC4, 0xA1, 0xC2, 0x67, 0x41, 0xC4, 0x83, 0x49,
0x5A, 0x0F, 0x69, 0x34, 0x17, 0x4C, 0xC4, 0x81, 0x4A, 0xB1, 0x76, 0x38, 0x2D, 0x48, 0x6A, 0xD0,
0x08, 0xE1, 0x4D, 0xEB, 0xB5, 0xA6, 0x9C, 0xC8, 0x4B, 0xD3, 0xF6, 0x1F, 0xD9, 0xCD, 0x53, 0x35,
0xEB, 0x45, 0xA6, 0x7E, 0x61, 0xC6, 0x2D, 0x01, 0x80, 0xFC, 0xDA, 0xD1, 0x1D, 0xCB, 0x2F, 0x4A,
0x3B, 0x10, 0xAE, 0x96, 0xD1, 0x18, 0x1A, 0xA6, 0xB6, 0x38, 0xD6, 0x6E, 0x8A, 0x3C, 0xE5, 0xDB,
0xB2, 0x1F, 0xD0, 0x67, 0xED, 0xC5, 0x63, 0xA9, 0xCC, 0xD3, 0xF1, 0xC5, 0x44, 0x7F, 0x06, 0xDC,
0xA7, 0xD3, 0x60, 0x5A, 0x29, 0xB8, 0xCC, 0x4A, 0x69, 0xDA, 0x6F, 0x8A, 0x84, 0xF1, 0x6C, 0xF1,
0xB3, 0x64, 0xDD, 0x28, 0x96, 0x06, 0x89, 0x68, 0x08, 0xFD, 0x1D, 0x12, 0x99, 0x02, 0x89, 0x0C,
0x1E, 0x00, 0x06, 0xB2, 0x58, 0xE8, 0xB0, 0x1C, 0x8D, 0x0C, 0x5F, 0x42, 0x10, 0xAD, 0x52, 0x92,
0x0F, 0x9F, 0xD6, 0x58, 0x2D, 0x29, 0x7C, 0x08, 0xC3, 0x26, 0xB6, 0x95, 0xD7, 0x48, 0x87, 0x5B,
0xC0, 0xE5, 0x59, 0x83, 0xD2, 0x2F, 0xDE, 0xDF, 0xD3, 0x49, 0x15, 0xDD, 0xEF, 0x17, 0x7C, 0x1C,
0x73, 0x2E, 0xB0, 0xD4, 0x1F, 0x5F, 0xD1, 0x26, 0xBB, 0x2A, 0x24, 0x04, 0x68, 0x52, 0xA9, 0x1F,
0x0F, 0x79, 0x55, 0x0F, 0x1A, 0xD5, 0x87, 0xC0, 0x82, 0xD4, 0x73, 0x7A, 0x8F, 0xD0, 0x87, 0xEA,
0xDE, 0xAA, 0x7B, 0x94, 0x88, 0x88, 0x8D, 0x16, 0x49, 0xBC, 0xF2, 0x85, 0x5B, 0x63, 0x98, 0x21,
0x63, 0x50, 0x32, 0xF8, 0x33, 0x6E, 0x03, 0x71, 0x3B, 0xE3, 0x0D, 0xFA, 0xEF, 0xD3, 0xA9, 0xE8,
0x3D, 0x75, 0x4B, 0x37, 0x0D, 0xA8, 0x86, 0xCE, 0x4E, 0x8C, 0x9E, 0x35, 0x32, 0x73, 0x7F, 0x45,
0x0C, 0x82, 0xEB, 0xBD, 0xD9, 0x0F, 0xCC, 0xB6, 0xCB, 0x56, 0xB1, 0xAC, 0xE4, 0x66, 0xC5, 0xE0,
0x3C, 0x1E, 0x6C, 0xA4, 0x5A, 0x4B, 0x3E, 0x6F, 0x55, 0x15, 0x47, 0xF3, 0xA0, 0x3A, 0x2C, 0x7D,
0xEA, 0x52, 0x4A, 0xD6, 0x0E, 0x82, 0xA2, 0xE7, 0x7D, 0x5F, 0x57, 0xF7, 0x00, 0x15, 0xD2, 0xE5,
0x88, 0xF5, 0x7D, 0x9C, 0xC5, 0x2F, 0xB8, 0xFB, 0x63, 0xA1, 0x3D, 0x60, 0xBB, 0x35, 0x01, 0xC2,
0xBA, 0x41, 0x97, 0xB2, 0xBA, 0x66, 0x01, 0xCE, 0x54, 0x5E, 0x1F, 0xA1, 0x0A, 0xF8, 0x2E, 0x08,
0xAD, 0x36, 0x2A, 0xC2, 0xDA, 0x7E, 0x77, 0x5D, 0xB7, 0xAD, 0xF7, 0x20, 0x7D, 0x93, 0x3B, 0x4B,
0xF4, 0x25, 0x5E, 0xFB, 0x0B, 0xEF, 0x73, 0x09, 0x1B, 0xEF, 0x73, 0xDD, 0xC0, 0xF0, 0x58, 0xC7,
0x03, 0xFF, 0xF7, 0x0B, 0xE7, 0x61, 0xE5, 0xC6, 0xD7, 0xBE, 0xCF, 0xE4, 0x98, 0xB9, 0x95, 0xFF,
0xAF, 0x42, 0xF5, 0x4E, 0x7E, 0xED, 0x6C, 0x93, 0xBF, 0xE4, 0x22, 0xD7, 0xCC, 0xB6, 0x11, 0x24,
0x1B, 0x98, 0x04, 0xE9, 0xD4, 0x25, 0xB2, 0xB2, 0x09, 0x53, 0x81, 0xAD, 0x09, 0x22, 0xE5, 0x79,
0xF9, 0x40, 0xBD, 0x55, 0xB9, 0x4F, 0x0B, 0x0B, 0xA3, 0xAD, 0x0D, 0x41, 0xFA, 0x25, 0x28, 0xB9,
0xE7, 0x7E, 0x94, 0x57, 0xD1, 0x48, 0x80, 0xD8, 0x87, 0x1D, 0xC5, 0x6C, 0x27, 0xD2, 0x0F, 0xF2,
0x71, 0xE3, 0x7C, 0x5C, 0x10, 0x5A, 0x42, 0x5F, 0xB2, 0xFF, 0x92, 0xCD, 0xCA, 0xD9, 0x4D, 0x37,
0xB5, 0xFE, 0x95, 0xBE, 0xA3, 0x87, 0x03, 0xDA, 0x8E, 0xD0, 0xA6, 0xD6, 0x55, 0x7A, 0xED, 0x6C,
0xF0, 0x7D, 0xF1, 0x59, 0x6F, 0x36, 0xD2, 0x27, 0x33, 0x5E, 0xDD, 0xB7, 0x80, 0x0E, 0xC3, 0x5F,
0xCA, 0x2B, 0xC2, 0x72, 0xA8, 0x37, 0x28, 0x56, 0xA0, 0xBF, 0x82, 0x37, 0x9B, 0x9F, 0x19, 0x46,
0x16, 0xCB, 0x3B, 0xD9, 0x9D, 0x9E, 0x25, 0x8A, 0x9B, 0x0F, 0xC0, 0x45, 0x6E, 0x6A, 0x40, 0x0C,
0xCB, 0xCC, 0x2C, 0xA5, 0xD2, 0xCB, 0x10, 0x48, 0xF4, 0xE0, 0x25, 0x1A, 0x68, 0xCE, 0x43, 0x21,
0xDD, 0x5F, 0xF4, 0xF0, 0xFE, 0x0C, 0x69, 0xC7, 0x42, 0x47, 0x87, 0x16, 0x33, 0xA9, 0x40, 0x8E,
0xB0, 0x2C, 0x3F, 0x41, 0x68, 0xC7, 0x6F, 0x36, 0xD3, 0x9E, 0xE6, 0x84, 0x9C, 0xB5, 0xBA, 0xE8,
0xE9, 0x02, 0xE9, 0x3F, 0xE0, 0x79, 0xC7, 0xEF, 0x86, 0x97, 0x2F, 0x7D, 0xE0, 0xE5, 0x97, 0x7F,
0xEC, 0xE5, 0xAF, 0x9B, 0x24, 0x85, 0xDF, 0x7E, 0x8F, 0x57, 0x0E, 0xEE, 0x8F, 0x7F, 0x29, 0x71,
0xFE, 0x3E, 0xCB, 0x92, 0x6A, 0x86, 0x25, 0x5A, 0x73, 0xD7, 0xE4, 0x39, 0x96, 0xB8, 0xD5, 0xBA,
0xF4, 0x7B, 0x29, 0xE7, 0x55, 0x71, 0x7C, 0x1B, 0x9A, 0x75, 0xB1, 0xF6, 0x4A, 0x2D, 0x2B, 0xA5,
0x71, 0xF5, 0xDF, 0xED, 0x54, 0x71, 0xD9, 0xB5, 0x00, 0x1F, 0x74, 0x92, 0x89, 0xA9, 0x83, 0x22,
0x94, 0x41, 0x08, 0xE1, 0x02, 0xF8, 0xFB, 0x04, 0xCE, 0xC4, 0x47, 0x5A, 0xF9, 0xE1, 0x61, 0xF0,
0xB6, 0xB6, 0xD0, 0x4E, 0xA7, 0xD9, 0x29, 0xD0, 0x54, 0xE5, 0x2A, 0xB7, 0x6B, 0x9F, 0x48, 0x2A,
0x2B, 0xDD, 0x4E, 0xD5, 0x62, 0xF6, 0xB6, 0x95, 0x2E, 0xFF, 0x3C, 0xE4, 0x33, 0x01, 0x0B, 0xF4,
0x4C, 0xDD, 0xBD, 0xF4, 0x2A, 0xD5, 0x78, 0xED, 0xC9, 0x35, 0x3F, 0xF3, 0xA0, 0xC5, 0x27, 0x78,
0x4B, 0x03, 0xF3, 0xEC, 0x23, 0x9D, 0x2A, 0xA7, 0x9B, 0xFE, 0xE7, 0xE5, 0x67, 0x62, 0xAA, 0xD6,
0xFD, 0xEE, 0xFA, 0x4C, 0xE1, 0xFA, 0x4F, 0xB6, 0x80, 0xBE, 0x12, 0x9F, 0x9A, 0x59, 0xB9, 0x53,
0x34, 0xB3, 0x01, 0xC5, 0x3A, 0x67, 0x90, 0x47, 0x65, 0x70, 0x4A, 0x15, 0x13, 0x89, 0x66, 0x25,
0x9B, 0xF0, 0x7B, 0xBE, 0xDE, 0x05, 0x84, 0xBB, 0x0D, 0x23, 0xFD, 0x07, 0x53, 0xFD, 0x65, 0xB2,
0xB4, 0x9D, 0xCF, 0x9E, 0xCC, 0x33, 0x62, 0xCA, 0xE9, 0x8A, 0xF4, 0x0F, 0xBF, 0xA2, 0x05, 0xE6,
0x67, 0xC4, 0x9C, 0x8F, 0x30, 0x61, 0x05, 0x5E, 0x2E, 0xB1, 0x36, 0x3D, 0x39, 0x9C, 0xF7, 0xE5,
0x65, 0x64, 0xD0, 0xDA, 0x2A, 0x70, 0x90, 0xD5, 0x02, 0x7A, 0xB8, 0x25, 0x02, 0x95, 0x7A, 0xAB,
0xFC, 0xB3, 0xC8, 0x48, 0xD6, 0x61, 0x9A, 0x37, 0x11, 0xD1, 0x43, 0x38, 0x7C, 0x1F, 0xA0, 0xC0,
0x73, 0xE5, 0x7B, 0x6B, 0x1D, 0x52, 0xC5, 0xEF, 0x45, 0x6E, 0x4E, 0x72, 0x53, 0x92, 0x0B, 0x54,
0xAB, 0x3B, 0x92, 0x4B, 0x78, 0xE6, 0x17, 0xD3, 0x92, 0xBD, 0x41, 0x00, 0x9B, 0x43, 0xFA, 0x67,
0x7E, 0xF8, 0xEE, 0xA4, 0x4E, 0x06, 0xE6, 0xAB, 0x01, 0x0C, 0x31, 0xB3, 0x31, 0x89, 0x19, 0x8B,
0x64, 0x6E, 0x75, 0xC8, 0x85, 0x41, 0xBC, 0xBD, 0x31, 0x39, 0x9F, 0x19, 0x07, 0x86, 0x28, 0x27,
0xC6, 0xB3, 0x5F, 0x3C, 0xAC, 0x11, 0xE8, 0xF8, 0x92, 0x24, 0x93, 0x60, 0x0F, 0xF8, 0x68, 0xB1,
0xC6, 0x32, 0xD6, 0x30, 0x24, 0xA6, 0xCC, 0xB0, 0x28, 0x84, 0x12, 0x1D, 0x9B, 0x8A, 0x83, 0x4E,
0x31, 0x57, 0x6B, 0xFF, 0x3E, 0x47, 0x80, 0xB9, 0xE9, 0x7C, 0x5A, 0x5C, 0xE5, 0x6B, 0x22, 0xDB,
0x25, 0x04, 0x10, 0xB9, 0x6F, 0x57, 0xCB, 0x94, 0x81, 0x55, 0x6D, 0xF0, 0xDD, 0x16, 0x69, 0x40,
0x8C, 0xFA, 0x57, 0x19, 0xD3, 0x6C, 0xFF, 0x57, 0xD6, 0xA8, 0x7E, 0xAD, 0x44, 0x85, 0xD9, 0x9C,
0x0B, 0xFA, 0x44, 0xD9, 0x67, 0x78, 0xE9, 0x77, 0xCF, 0xB2, 0x7E, 0x3B, 0xD5, 0x64, 0xD2, 0x4C,
0xA5, 0x6D, 0xBE, 0x4C, 0x63, 0xE2, 0xD7, 0xB4, 0x98, 0x26, 0x45, 0xD0, 0x06, 0xA5, 0x97, 0xFA,
0x45, 0x80, 0x74, 0x75, 0x84, 0x75, 0x4D, 0x04, 0x2C, 0xF2, 0x1A, 0x37, 0xB5, 0xAB, 0x51, 0xB5,
0x04, 0x72, 0x9F, 0x14, 0xE0, 0xFE, 0xBB, 0xEF, 0xFE, 0x33, 0x22, 0xD5, 0xB2, 0x0F, 0x58, 0x37,
0x2A, 0x47, 0x98, 0x5D, 0x13, 0x12, 0x58, 0x64, 0x9D, 0x29, 0x4D, 0x4D, 0xF7, 0x91, 0xE3, 0xDE,
0x1E, 0xA4, 0xE1, 0xEB, 0x28, 0x00, 0x74, 0x56, 0x7C, 0x6E, 0xD8, 0xD3, 0x45, 0x9E, 0xEB, 0xEF,
0x89, 0xD9, 0x8A, 0xE7, 0xCB, 0x42, 0xC0, 0x11, 0x05, 0x56, 0x1D, 0xB1, 0x4D, 0xCD, 0x4A, 0xDF,
0x83, 0x81, 0xCB, 0xA6, 0xF8, 0x67, 0xD2, 0xE0, 0xE6, 0xF8, 0x05, 0x43, 0xDC, 0x34, 0x2E, 0x53,
0xE6, 0x0E, 0x2E, 0x03, 0xF4, 0xAD, 0x6E, 0x88, 0xC7, 0x02, 0x2B, 0xEE, 0x26, 0xAA, 0x8B, 0x0A,
0x8F, 0x5B, 0xF1, 0x90, 0xF2, 0x86, 0x55, 0xB3, 0x3E, 0x06, 0x14, 0x92, 0x23, 0xFA, 0x5E, 0xCF,
0xE5, 0xEA, 0x12, 0x60, 0x6D, 0x65, 0x36, 0x5A, 0x38, 0x8D, 0x89, 0x9E, 0xBD, 0xE6, 0x20, 0x90,
0x59, 0xDC, 0xA2, 0x2F, 0xC5, 0x36, 0xE3, 0x6F, 0x20, 0x96, 0xA9, 0xBC, 0xED, 0x2F, 0x0E, 0x5E,
0xDC, 0xD0, 0x55, 0xD2, 0xAE, 0xD4, 0x08, 0x17, 0x6B, 0x88, 0x75, 0x60, 0x35, 0xD5, 0x12, 0x43,
0x6E, 0x62, 0x45, 0x4E, 0x05, 0xD8, 0xEB, 0xFF, 0x8B, 0xF4, 0x6F, 0x48, 0x38, 0xB5, 0xC1, 0x67,
0x43, 0xE1, 0xE2, 0xC8, 0xC5, 0xE2, 0x33, 0xA6, 0x9F, 0xED, 0x30, 0x62, 0xCC, 0xA6, 0x9C, 0xF9,
0xEF, 0xE4, 0xE0, 0x2D, 0x29, 0xDD, 0x02, 0x04, 0x3C, 0x2A, 0xAC, 0x66, 0x59, 0x22, 0x3B, 0x05,
0xE6, 0xE5, 0x8E, 0x65, 0x62, 0x0A, 0x21, 0xD4, 0xC5, 0x35, 0x73, 0xC5, 0x19, 0xB6, 0xE4, 0x82,
0x9F, 0x5B, 0x8F, 0x2A, 0x19, 0x65, 0xA6, 0xA6, 0xD7, 0x1E, 0xEC, 0xA0, 0x17, 0xCC, 0xCE, 0xC1,
0x32, 0x08, 0xFD, 0x27, 0x07, 0xAA, 0x88, 0x61, 0xDB, 0x65, 0xAB, 0xBE, 0xE6, 0x14, 0x17, 0x09,
0x3B, 0xB8, 0x6E, 0xBE, 0x19, 0x55, 0x9E, 0x53, 0xF9, 0x85, 0x40, 0x96, 0x12, 0x96, 0xE9, 0xDA,
0xF9, 0x5B, 0xF2, 0x7C, 0xA3, 0x80, 0xBB, 0x73, 0x4A, 0x54, 0xF1, 0x26, 0xE6, 0xBD, 0x43, 0x5B,
0x88, 0xFA, 0x2D, 0x61, 0xAA, 0x5D, 0xDB, 0xBF, 0xA2, 0xB2, 0xD5, 0x1B, 0x49, 0x24, 0xCE, 0xF5,
0x46, 0x96, 0xF0, 0x43, 0x0D, 0x24, 0xB3, 0xCD, 0x17, 0xC4, 0x78, 0x5C, 0x35, 0x5D, 0x66, 0x36,
0x1C, 0x7D, 0x3D, 0xC1, 0xDF, 0x65, 0x69, 0xFE, 0xD6, 0xA9, 0xCE, 0xF5, 0xDB, 0xDF, 0x6B, 0x26,
0xBD, 0xAB, 0x2C, 0x28, 0x87, 0x9F, 0xAA, 0x88, 0xD9, 0xDB, 0xC4, 0x82, 0x49, 0x6D, 0xB8, 0xB9,
0xF3, 0x18, 0xEC, 0x9E, 0x18, 0xF4, 0xCC, 0x02, 0xD0, 0x01, 0xA7, 0xB6, 0x61, 0x49, 0xE4, 0x54,
0x7C, 0x84, 0x3F, 0x76, 0x5F, 0x4F, 0x20, 0xA7, 0x2A, 0xBA, 0x85, 0x0B, 0x7E, 0x7A, 0x9C, 0x53,
0xE7, 0xA5, 0xF2, 0x6E, 0x17, 0xCE, 0xEF, 0x81, 0x9B, 0xE4, 0x60, 0x33, 0xFC, 0x38, 0x9B, 0xA2,
0x93, 0xD8, 0xC4, 0x0D, 0x56, 0x69, 0x7E, 0x64, 0x55, 0x73, 0x4B, 0x9A, 0x73, 0xFE, 0xBC, 0x67,
0x2C, 0x66, 0xFE, 0x11, 0x55, 0x8F, 0x31, 0x4E, 0xC3, 0x30, 0x14, 0x86, 0x5F, 0x52, 0xA8, 0x45,
0x32, 0x3C, 0x76, 0x04, 0xEE, 0xC0, 0x48, 0xE3, 0x95, 0xA1, 0x0E, 0x96, 0x72, 0x00, 0xAE, 0x50,
0x71, 0x0A, 0x06, 0xA3, 0x66, 0x67, 0xE0, 0x0A, 0x39, 0x42, 0x87, 0x6C, 0x44, 0x24, 0x52, 0x2E,
0x10, 0x95, 0x91, 0x01, 0xAB, 0xC0, 0x86, 0xA8, 0x41, 0x19, 0x9E, 0xD4, 0xA4, 0x86, 0x22, 0x04,
0xE2, 0x9F, 0xFE, 0xED, 0xFB, 0x3E, 0x60, 0xD0, 0x85, 0x86, 0xAB, 0x09, 0x7C, 0xAD, 0x29, 0xAE,
0xE4, 0xE1, 0xF6, 0x0C, 0x0C, 0xB6, 0x5C, 0x4F, 0x8E, 0xE6, 0xC1, 0x78, 0xD7, 0xDD, 0x7C, 0xB8,
0x69, 0x21, 0x5C, 0xED, 0x28, 0xF3, 0x09, 0xCB, 0x9E, 0x9B, 0xDB, 0x75, 0x3A, 0x3F, 0xA1, 0x38,
0x1F, 0x1F, 0x2C, 0xDC, 0xEA, 0xFC, 0x55, 0x78, 0x36, 0x86, 0x0C, 0x40, 0x5C, 0x6F, 0xAC, 0xC3,
0x72, 0x49, 0x7B, 0x43, 0x56, 0xDF, 0x2F, 0xDF, 0x6D, 0x6B, 0xF3, 0xFD, 0x1D, 0xC8, 0x30, 0xC2,
0xE4, 0x21, 0x3D, 0xAB, 0x58, 0x05, 0xA3, 0xE3, 0x98, 0x87, 0x75, 0x43, 0x1A, 0x99, 0x52, 0x2A,
0x7C, 0x9E, 0xF5, 0xAD, 0xA8, 0x02, 0x00, 0x94, 0x9A, 0xBA, 0x5E, 0x46, 0xD8, 0x90, 0xE4, 0x61,
0x92, 0xCA, 0xBE, 0x23, 0x2D, 0xF1, 0xE2, 0x51, 0x3F, 0x01, 0xC8, 0x58, 0x52, 0x03, 0xBF, 0xD0,
0x6F, 0xCC, 0x46, 0xA4, 0x9C, 0x99, 0x56, 0x9F, 0x82, 0x48, 0xFA, 0x81, 0xD1, 0xDC, 0x53, 0xC3,
0xA4, 0x22, 0xAC, 0xCA, 0x45, 0xB7, 0x5E, 0xDD, 0x91, 0xA7, 0x98, 0xC5, 0x42, 0x46, 0x79, 0x30,
0xFD, 0x91, 0xFE, 0x57, 0xF2, 0x47, 0xDE, 0xD6, 0x2A, 0xDF, 0x7A, 0x2D, 0x10, 0x5C, 0x02, 0xF8,
0x26, 0xEA, 0xF0, 0xCD, 0x37, 0x14, 0xE3, 0x0B, 0x7D, 0x02, 0xC5, 0x5B, 0x4F, 0x8C, 0xDC, 0xE6,
0x75, 0x7F, 0x24, 0x9D, 0x65, 0x22, 0xC6, 0xA2, 0x81, 0x1A, 0x68, 0xD1, 0xB5, 0x4C, 0x1F, 0x72,
0x08, 0x6A, 0x49, 0x0C, 0x02, 0x1D, 0x14, 0x74, 0x86, 0xA4, 0xAD, 0xA2, 0x3E, 0xA4, 0x80, 0x0D,
0xE4, 0x98, 0x02, 0xCE, 0xB9, 0x97, 0xF5, 0xC1, 0x40, 0x05, 0x64, 0x77, 0x87, 0xB6, 0xD0, 0xFA,
0x90, 0xA0, 0x16, 0x50, 0xF4, 0xD2, 0x43, 0xE3, 0x83, 0x11, 0xA0, 0x76, 0x8B, 0xF5, 0x61, 0x5B,
0x6C, 0x81, 0xD9, 0x25, 0x25, 0x01, 0x0D, 0x50, 0x03, 0x35, 0x1D, 0x17, 0xC8, 0xC1, 0x68, 0x4D,
0x3B, 0x9B, 0xDA, 0x95, 0x8B, 0x88, 0x71, 0x18, 0x8B, 0x23, 0x71, 0xF8, 0xF5, 0xF7, 0x7B, 0xE4,
0xEC, 0x3F, 0x49, 0xB6, 0x1C, 0xCB, 0xE8, 0xEE, 0xCE, 0x2C, 0x87, 0x43, 0x7E, 0x7F, 0xDE, 0xF7,
0xDE, 0xEF, 0xFD, 0xDE, 0xFB, 0x1E, 0x45, 0x44, 0x9C, 0x42, 0xC4, 0x2F, 0x45, 0x82, 0x5A, 0xC4,
0xAE, 0x64, 0xF8, 0xF1, 0x8D, 0x69, 0x1F, 0x35, 0xA6, 0xF2, 0x53, 0x27, 0x8F, 0xC4, 0x93, 0x06,
0x17, 0xE2, 0x22, 0x3F, 0x15, 0x89, 0x4D, 0x2D, 0xC6, 0x14, 0x8B, 0x8F, 0x11, 0xAE, 0x6E, 0xE4,
0x7E, 0x7C, 0x3C, 0xE3, 0xA7, 0xF6, 0x9B, 0x99, 0x31, 0x4F, 0xE3, 0x5E, 0xBB, 0x3C, 0x2D, 0x7E,
0xDE, 0xCA, 0x69, 0xBB, 0x5C, 0x34, 0x69, 0x8C, 0xB9, 0x8C, 0x6F, 0x71, 0xF1, 0x08, 0x17, 0xBF,
0xB6, 0x7F, 0xAF, 0x38, 0xC6, 0x24, 0xBE, 0x99, 0xEF, 0x7D, 0xEC, 0x5B, 0x2E, 0x22, 0x71, 0x93,
0x46, 0x4E, 0x2D, 0x1B, 0xF3, 0x1B, 0xDC, 0x9B, 0xE3, 0x35, 0xC7, 0x95, 0x18, 0x93, 0x34, 0x4E,
0x8E, 0x36, 0x7C, 0x79, 0xC9, 0x4F, 0xBF, 0xD6, 0xB7, 0xC2, 0xFB, 0xD0, 0x4E, 0xA7, 0x23, 0x4F,
0x71, 0x6A, 0x92, 0xE0, 0x54, 0xCC, 0xB6, 0xD6, 0xD8, 0x58, 0x83, 0x53, 0x38, 0x6E, 0x70, 0xBC,
0x3C, 0x93, 0xB1, 0x6D, 0x5A, 0x8B, 0x73, 0xF5, 0x73, 0xBC, 0x6D, 0xE3, 0x15, 0xA0, 0xCF, 0x18,
0x77, 0xCB, 0x24, 0xED, 0x47, 0xEB, 0x25, 0xE2, 0xD4, 0x62, 0xE3, 0xD4, 0xB7, 0x16, 0x13, 0x70,
0x7B, 0x99, 0x40, 0x1E, 0xAB, 0x4E, 0xE9, 0xE2, 0xDF, 0x59, 0xA7, 0xB4, 0xD8, 0x3B, 0x07, 0x7C,
0xA7, 0x7F, 0xCB, 0x37, 0x70, 0x1F, 0x44, 0x1B, 0x76, 0x89, 0x87, 0x69, 0x6E, 0xCB, 0xBA, 0x97,
0xCB, 0xE6, 0x58, 0xAC, 0x37, 0xD1, 0xBF, 0xA7, 0xE2, 0x6C, 0x0E, 0x8A, 0x33, 0x46, 0x47, 0x6B,
0x22, 0xDF, 0x6B, 0xC5, 0x79, 0x73, 0x2E, 0x93, 0xC7, 0x0C, 0xBE, 0x5E, 0xE9, 0xC4, 0xCA, 0x76,
0x3D, 0xD3, 0x06, 0xE9, 0x28, 0x96, 0x51, 0x24, 0x78, 0x97, 0xA0, 0x10, 0x6F, 0x2E, 0x96, 0x29,
0x24, 0x68, 0xC4, 0x9A, 0x3F, 0x22, 0xD1, 0x79, 0x89, 0xA6, 0xB2, 0xB6, 0x6E, 0xB5, 0x13, 0x53,
0x79, 0x26, 0x99, 0x98, 0x47, 0x1B, 0xA7, 0xBC, 0xD3, 0xEF, 0xF2, 0x6C, 0x62, 0xB6, 0xBC, 0xCC,
0xB9, 0x99, 0x6E, 0xF5, 0xEB, 0x7D, 0x39, 0xBB, 0x88, 0xC5, 0x2E, 0x55, 0x52, 0xB7, 0x3B, 0x58,
0xBE, 0x11, 0x98, 0xDC, 0x35, 0xD5, 0xB1, 0x8E, 0x53, 0xF3, 0x29, 0x63, 0x7C, 0xF3, 0x49, 0x87,
0x98, 0x64, 0x45, 0x09, 0x6F, 0x73, 0xAC, 0x73, 0xC1, 0x58, 0x21, 0x3C, 0xB1, 0x39, 0x23, 0x91,
0x8A, 0x93, 0xA5, 0x6E, 0xA1, 0x6F, 0x5D, 0x3C, 0x2A, 0x85, 0x58, 0xA5, 0x6F, 0x2E, 0x8A, 0x9B,
0x52, 0xC7, 0x4E, 0x49, 0xE3, 0xD6, 0x52, 0xE9, 0x70, 0x73, 0x3F, 0xF5, 0xF2, 0xD3, 0x68, 0x3C,
0x94, 0x1A, 0x57, 0x6F, 0x7F, 0x3B, 0xC7, 0xC9, 0x6B, 0x73, 0xF4, 0x32, 0x89, 0x0B, 0xB4, 0x58,
0x6F, 0x4B, 0x68, 0x66, 0x32, 0x31, 0x0E, 0x6E, 0x3C, 0x36, 0x97, 0x95, 0x5D, 0x0A, 0x9F, 0xEA,
0x8C, 0x6E, 0xA6, 0xBA, 0x18, 0xA1, 0x2A, 0x09, 0x84, 0xBF, 0xF8, 0x02, 0xA3, 0xB9, 0x91, 0x50,
0xA1, 0xA0, 0x79, 0xFC, 0x22, 0xC8, 0xF9, 0x85, 0x55, 0xEB, 0x1D, 0x91, 0xDE, 0xE1, 0xA7, 0xFC,
0xC2, 0x2D, 0xF8, 0x85, 0x57, 0x4D, 0x1A, 0xF4, 0x54, 0xB1, 0x0F, 0x8C, 0x11, 0xB7, 0xB5, 0xFD,
0x1B, 0x66, 0x32, 0xEA, 0xDF, 0x7A, 0x75, 0xE4, 0xC4, 0x86, 0xB7, 0x8D, 0xB9, 0xF6, 0x93, 0xE3,
0xA3, 0x47, 0x91, 0x38, 0x90, 0x47, 0x6A, 0xDF, 0xF2, 0xB6, 0xB2, 0xEB, 0xCE, 0x6C, 0xD3, 0x84,
0x66, 0x50, 0xB4, 0xAF, 0x53, 0x21, 0x31, 0x50, 0x1F, 0x7A, 0x03, 0x25, 0xDC, 0xFB, 0x71, 0x4C,
0xE5, 0xE6, 0xF1, 0xDC, 0xA2, 0xA5, 0xC4, 0xD0, 0x18, 0xA8, 0x4F, 0x04, 0x11, 0x3B, 0xE5, 0x08,
0x93, 0xA2, 0xC2, 0x1A, 0xCC, 0x2B, 0xDE, 0x48, 0x71, 0x66, 0x15, 0x67, 0x1C, 0x7E, 0x15, 0x70,
0x49, 0xB6, 0x71, 0x80, 0x4F, 0x11, 0x5A, 0x5D, 0xEE, 0x24, 0xC3, 0x2A, 0x5A, 0xCD, 0xA0, 0xD3,
0x1C, 0xA7, 0x47, 0x53, 0xA0, 0xAA, 0x43, 0x5D, 0xE5, 0xC0, 0xCF, 0xC4, 0x88, 0x99, 0x3F, 0x5A,
0x63, 0x7C, 0x90, 0x86, 0x07, 0x91, 0xE3, 0x7E, 0xBC, 0x4D, 0xF0, 0x66, 0x19, 0xBC, 0xB9, 0x6F,
0xE3, 0x2D, 0xE0, 0x5A, 0xAC, 0xE1, 0xDB, 0x77, 0x6B, 0xBC, 0xBD, 0x5F, 0xE0, 0xCD, 0x24, 0x78,
0x9B, 0xF3, 0x8E, 0xBA, 0xBF, 0xCD, 0xCB, 0x61, 0x74, 0xC1, 0x07, 0xDA, 0x9E, 0x7C, 0x49, 0x9E,
0xC2, 0x4A, 0x00, 0x76, 0x9C, 0x3A, 0x4C, 0x60, 0x1C, 0x2D, 0xFA, 0xDE, 0x49, 0xF6, 0x7B, 0x0D,
0x4C, 0x31, 0x99, 0x87, 0xD0, 0xFA, 0x02, 0xBA, 0xB3, 0x2A, 0x41, 0x82, 0x4B, 0x63, 0x09, 0x68,
0x16, 0x90, 0xC5, 0xD4, 0x85, 0x60, 0xEA, 0x31, 0xEE, 0xF9, 0x15, 0x46, 0xED, 0xBC, 0xC3, 0x39,
0x34, 0x0B, 0x4B, 0x7E, 0x98, 0xF7, 0xF3, 0xF4, 0x8F, 0x92, 0x1E, 0xD0, 0x24, 0xC6, 0xC1, 0xA4,
0xB3, 0x4D, 0xBD, 0x51, 0x2C, 0x75, 0x89, 0xAE, 0x7C, 0xD3, 0x8F, 0x29, 0xEC, 0x55, 0xE3, 0xEE,
0x4F, 0x2D, 0x61, 0xB5, 0x31, 0x05, 0x28, 0x9B, 0xDA, 0x76, 0xBF, 0xC4, 0xA7, 0xD8, 0xE3, 0x26,
0x5E, 0x16, 0xFB, 0x77, 0x74, 0x02, 0x3C, 0x67, 0xB5, 0xBC, 0x82, 0x72, 0xFD, 0x3E, 0xAE, 0x75,
0x5E, 0xE7, 0x6A, 0x06, 0x18, 0xCB, 0x26, 0x91, 0x21, 0x87, 0x46, 0x9E, 0xE6, 0x64, 0x2A, 0x2C,
0x8A, 0x4B, 0xFD, 0x88, 0x09, 0x5A, 0x15, 0xA6, 0x89, 0x25, 0x5D, 0x13, 0x2C, 0x67, 0xE3, 0xCE,
0x04, 0x26, 0xDA, 0x5A, 0x06, 0xD6, 0x6C, 0xF2, 0x0D, 0xE0, 0x26, 0xCC, 0x1E, 0xA3, 0xAA, 0x88,
0x39, 0x0B, 0xEC, 0x34, 0x1D, 0x15, 0xB8, 0xF0, 0x53, 0xEA, 0x6E, 0x00, 0xB0, 0xA4, 0xDA, 0x36,
0x7E, 0x4A, 0x8D, 0xC5, 0x2A, 0x53, 0x59, 0x67, 0xF2, 0xFB, 0x0A, 0x30, 0xAD, 0x44, 0x76, 0x03,
0xB1, 0xE3, 0x7E, 0x0F, 0xD6, 0x14, 0xE2, 0x7E, 0xC2, 0x38, 0x16, 0xCB, 0xF0, 0xE3, 0x27, 0xDC,
0x3F, 0x51, 0xDC, 0x6E, 0x69, 0x85, 0x11, 0xAD, 0x94, 0xFF, 0x1E, 0xFC, 0x24, 0xC8, 0xC3, 0x3F,
0x2B, 0x7B, 0x09, 0xF7, 0x25, 0x34, 0x76, 0x93, 0xAE, 0xE8, 0xE4, 0x30, 0x66, 0xE0, 0x25, 0x96,
0xA8, 0x81, 0xD2, 0x41, 0x9E, 0x18, 0xB5, 0xBC, 0x86, 0x13, 0x9C, 0xD4, 0x71, 0x21, 0xD6, 0xD3,
0xD7, 0xE0, 0x04, 0x65, 0xBF, 0x89, 0x13, 0xAB, 0xE2, 0x3F, 0x07, 0x7F, 0x31, 0xA3, 0x85, 0xC2,
0x32, 0x6C, 0x34, 0x22, 0xEB, 0x70, 0x56, 0xC7, 0x9F, 0x41, 0x17, 0x7F, 0x8A, 0xD9, 0x17, 0x90,
0x5A, 0xB5, 0xA1, 0x80, 0x4C, 0x08, 0x39, 0x79, 0xD0, 0x23, 0x11, 0x51, 0xE9, 0x55, 0x0E, 0x38,
0x19, 0x75, 0x50, 0x16, 0x66, 0xE6, 0xFD, 0x31, 0x4C, 0x1E, 0xB3, 0xAA, 0x9C, 0xC2, 0x37, 0x40,
0x95, 0x49, 0x62, 0x6A, 0xBF, 0x72, 0x5B, 0x81, 0x7D, 0x63, 0x9D, 0x69, 0xC9, 0xE2, 0x27, 0x8D,
0x8F, 0xE5, 0x1A, 0xF9, 0xCF, 0x29, 0x2A, 0x35, 0x23, 0x19, 0x3C, 0x8B, 0x58, 0x37, 0x3A, 0x2C,
0x9F, 0x8C, 0xFD, 0x0B, 0xEC, 0x2E, 0x6F, 0xB0, 0xAA, 0xC4, 0x8C, 0x96, 0xD0, 0xDD, 0xD0, 0xC0,
0x29, 0xCE, 0xD4, 0x81, 0xAC, 0x81, 0x79, 0x9D, 0xAC, 0x34, 0x4E, 0x13, 0xA6, 0x80, 0x4E, 0xBF,
0x58, 0x32, 0x18, 0x71, 0x3B, 0x96, 0xED, 0x91, 0x44, 0x67, 0x81, 0x8E, 0x98, 0x21, 0xD7, 0xA0,
0x14, 0x9A, 0xC0, 0xB6, 0x42, 0x7F, 0xF8, 0x0D, 0x81, 0xE6, 0x47, 0x9D, 0x62, 0xB8, 0xDB, 0x25,
0x5F, 0x8C, 0x05, 0x06, 0xB4, 0x91, 0xF0, 0xB1, 0x86, 0x53, 0xAA, 0x06, 0xC9, 0x1E, 0x31, 0xFA,
0xE6, 0x1E, 0x75, 0x19, 0xF6, 0x5D, 0xC6, 0x06, 0x3E, 0xD3, 0x14, 0x01, 0x40, 0xCB, 0x21, 0x7A,
0x6D, 0x11, 0x99, 0x08, 0x51, 0x39, 0x0E, 0x36, 0xE9, 0x04, 0xB1, 0x40, 0x37, 0x30, 0xA0, 0xC8,
0xE5, 0x19, 0x48, 0x22, 0xB2, 0xE8, 0x46, 0xFC, 0x82, 0x50, 0x87, 0x03, 0xAB, 0xB5, 0xB2, 0x12,
0x10, 0x6C, 0x24, 0x48, 0xD5, 0x8F, 0xC0, 0x99, 0x96, 0xBD, 0xE7, 0xA0, 0x66, 0xED, 0x1D, 0x50,
0xBD, 0xE0, 0x44, 0x52, 0x7A, 0x0F, 0xA1, 0xDB, 0x50, 0xFD, 0xF2, 0x52, 0x1C, 0xC0, 0x71, 0x7C,
0x89, 0xE6, 0x0C, 0x8F, 0xD9, 0x00, 0x59, 0xB3, 0x16, 0x7E, 0xC9, 0xE4, 0xC1, 0x1C, 0xB0, 0x99,
0x4E, 0x60, 0x7B, 0x98, 0x9E, 0x78, 0x8D, 0x3C, 0x5C, 0xCB, 0xCD, 0xD4, 0x7A, 0x27, 0x3D, 0xBE,
0x2A, 0xA7, 0x56, 0xED, 0x9F, 0xE5, 0xF6, 0x95, 0x62, 0xB4, 0x2A, 0xA3, 0xD3, 0xCE, 0x85, 0xDC,
0xB9, 0x54, 0xBD, 0x36, 0x82, 0x4E, 0x3C, 0xE9, 0x14, 0x4E, 0xFE, 0x2F, 0xC5, 0x58, 0x46, 0xEE,
0xFF, 0x3A, 0x05, 0xBC, 0x15, 0x34, 0xF0, 0xBC, 0x5D, 0xDB, 0xA5, 0x9B, 0xFA, 0x12, 0xDA, 0x5D,
0xF2, 0x94, 0x37, 0xC3, 0x9A, 0x3A, 0xB4, 0x9F, 0xA3, 0xEB, 0x77, 0xEB, 0x9B, 0xE9, 0xAD, 0xD0,
0xE4, 0x77, 0xBE, 0x64, 0x21, 0xCC, 0xA6, 0x5F, 0xBF, 0xE5, 0x2E, 0xC1, 0x32, 0xB5, 0xB2, 0x23,
0x61, 0xBE, 0x06, 0xA8, 0x81, 0x86, 0x87, 0x4F, 0x43, 0x80, 0x1F, 0x02, 0x65, 0x20, 0x15, 0xAA,
0x90, 0x78, 0x1D, 0x17, 0x16, 0x27, 0x6E, 0x60, 0x85, 0xC7, 0xEB, 0x38, 0x09, 0x59, 0x06, 0x49,
0x27, 0x61, 0x0A, 0x3D, 0x4E, 0x64, 0x65, 0xC6, 0xA5, 0xEE, 0x19, 0x8D, 0x29, 0xD5, 0x61, 0x7F,
0x9E, 0x37, 0x8C, 0x6E, 0x65, 0x97, 0xA3, 0x43, 0x7B, 0x33, 0xCC, 0x06, 0x70, 0xE1, 0x97, 0x58,
0x3A, 0xA7, 0xB4, 0x2B, 0x78, 0x6D, 0x3A, 0xF1, 0xC8, 0x6A, 0xF1, 0x05, 0x58, 0x56, 0x72, 0x1B,
0xB8, 0x28, 0x15, 0x2E, 0x38, 0xB3, 0xC0, 0xB4, 0x5E, 0xE9, 0x5E, 0xAA, 0xC9, 0x73, 0x9C, 0x9F,
0xE4, 0xF2, 0xC0, 0xB4, 0xB7, 0xEA, 0x66, 0xEF, 0x1F, 0x7D, 0x38, 0x28, 0x12, 0x6C, 0x8D, 0xB4,
0xED, 0xA9, 0x09, 0x24, 0x02, 0x86, 0x64, 0x86, 0x1F, 0x18, 0x21, 0x3B, 0x87, 0x2F, 0x3E, 0x73,
0x84, 0x50, 0xDE, 0xE1, 0x23, 0x18, 0x9A, 0x83, 0x26, 0x48, 0x2E, 0xFF, 0xBB, 0x4B, 0x96, 0x6B,
0xAF, 0x80, 0xCE, 0x10, 0x89, 0x2D, 0xB0, 0x0F, 0x98, 0xF3, 0x69, 0xF4, 0x46, 0x3D, 0xAD, 0x40,
0x94, 0x82, 0x27, 0xC9, 0x17, 0x89, 0xE8, 0xC4, 0xF7, 0x30, 0xE9, 0xDD, 0x0D, 0x11, 0xDF, 0x7E,
0x9B, 0xE4, 0x0D, 0x1F, 0x7A, 0xCF, 0x1A, 0x72, 0x36, 0xE0, 0xA0, 0x4A, 0x35, 0x3C, 0xF0, 0x52,
0xEF, 0xE6, 0x8D, 0xCE, 0xA9, 0x42, 0xBB, 0x59, 0x05, 0x95, 0x78, 0x23, 0x0F, 0x65, 0xDC, 0xD8,
0x95, 0x73, 0x8D, 0x40, 0xDC, 0xDA, 0x95, 0xFB, 0xB3, 0x32, 0x94, 0x36, 0xFE, 0x69, 0x95, 0x49,
0x46, 0x7F, 0xB0, 0x01, 0x86, 0xA1, 0x8C, 0x05, 0x6E, 0x40, 0xDD, 0x7A, 0x6C, 0x9E, 0x33, 0x6F,
0x66, 0x85, 0x5B, 0xDB, 0x2D, 0x60, 0xC3, 0x03, 0xF7, 0x85, 0x6C, 0x0B, 0xAC, 0xFD, 0x16, 0x9B,
0xA7, 0xA3, 0xCB, 0x07, 0xA7, 0xC3, 0x31, 0xF8, 0x4F, 0xA7, 0x62, 0x97, 0x80, 0x94, 0x55, 0x02,
0x12, 0x4C, 0x06, 0x53, 0xDE, 0x86, 0x5E, 0x2E, 0xCF, 0xB2, 0x96, 0x5A, 0x09, 0x87, 0xD8, 0x6C,
0x94, 0xF7, 0xC2, 0x21, 0xCE, 0x54, 0x87, 0xA4, 0x5F, 0x8D, 0xDE, 0x25, 0x9E, 0x5E, 0xB8, 0x44,
0xC9, 0x4D, 0x13, 0x9B, 0xB0, 0x81, 0x2A, 0x92, 0x42, 0x92, 0x44, 0x52, 0x5B, 0x94, 0x51, 0x36,
0x6A, 0xD7, 0xF0, 0x34, 0x35, 0x3E, 0x92, 0x11, 0xBA, 0x66, 0x67, 0x68, 0x40, 0x9D, 0x2B, 0x85,
0xC8, 0xF5, 0x21, 0x91, 0xC3, 0x9A, 0x4E, 0xBA, 0xD0, 0x78, 0xE6, 0xA7, 0x59, 0x92, 0x5D, 0xA4,
0x29, 0x61, 0x38, 0x53, 0x25, 0x83, 0x1C, 0xD2, 0x3D, 0xF9, 0x60, 0x65, 0x66, 0xE1, 0xDE, 0xE1,
0x3A, 0xFA, 0xEE, 0x2E, 0x7F, 0xD1, 0xDD, 0x35, 0x43, 0x77, 0x8A, 0xBB, 0xE3, 0x9E, 0xE2, 0xF5,
0x1F, 0x46, 0xFA, 0x6E, 0xE7, 0xFA, 0xEF, 0x21, 0x4A, 0x98, 0x8C, 0xD8, 0x57, 0x4C, 0x83, 0x58,
0xCA, 0x43, 0x72, 0x8A, 0x81, 0xDF, 0xBE, 0xE9, 0x7A, 0xB8, 0x6C, 0xA4, 0xD5, 0x9E, 0x48, 0x98,
0x7B, 0x59, 0xBB, 0xB5, 0x65, 0xFA, 0x90, 0x8D, 0xD8, 0xEE, 0x98, 0x8F, 0xB2, 0x54, 0x18, 0x19,
0x50, 0xC1, 0x22, 0x2A, 0xE8, 0x2D, 0x87, 0x68, 0x10, 0x87, 0xF0, 0x76, 0x3C, 0xBB, 0xCD, 0xB3,
0xD0, 0x5C, 0xB6, 0xCA, 0x43, 0x5B, 0x0F, 0x23, 0x1E, 0x06, 0x45, 0xC8, 0xA6, 0x97, 0xBB, 0x89,
0xD9, 0xED, 0xC1, 0x4E, 0x36, 0xCA, 0xDB, 0x9A, 0xD9, 0x5D, 0x11, 0x95, 0x25, 0x60, 0x57, 0x66,
0x1A, 0xBB, 0xB4, 0x5B, 0x2F, 0xB1, 0xEA, 0x87, 0xD4, 0x76, 0x34, 0x3C, 0x4D, 0x42, 0x4C, 0x6F,
0xC2, 0xB8, 0xA1, 0xFF, 0x08, 0xC5, 0xFE, 0xBA, 0x38, 0xEF, 0x56, 0x12, 0xC2, 0x20, 0x6A, 0xC6,
0x55, 0x4B, 0x30, 0x98, 0x09, 0xAC, 0xAC, 0x4B, 0x7C, 0x40, 0x9C, 0x51, 0xF5, 0x4A, 0x42, 0xBA,
0xE2, 0xC4, 0xC6, 0x5C, 0x31, 0x0E, 0x78, 0x67, 0x00, 0x87, 0x57, 0x90, 0x16, 0x4B, 0xED, 0xB3,
0xB1, 0xA8, 0x0F, 0x18, 0x53, 0x0C, 0x04, 0x0D, 0x0F, 0x5F, 0xA4, 0xC0, 0x9B, 0xE9, 0xC0, 0x9B,
0x1B, 0xF8, 0xB2, 0xB0, 0x6F, 0x2A, 0xC9, 0x1A, 0x47, 0x15, 0x51, 0x82, 0x19, 0x29, 0x33, 0x8E,
0x03, 0xCC, 0x0A, 0x22, 0xC0, 0xA2, 0x0E, 0xCB, 0xDA, 0x60, 0x95, 0x43, 0xFC, 0x3A, 0x70, 0x8A,
0x10, 0x22, 0xE8, 0x37, 0x16, 0xCE, 0xAA, 0x61, 0xC7, 0x2D, 0x4E, 0x4C, 0x71, 0xC5, 0x3A, 0xAE,
0x88, 0x29, 0x61, 0x60, 0xF4, 0x3A, 0xBD, 0x9E, 0x0D, 0xB7, 0x69, 0x6A, 0xB7, 0x8C, 0xAD, 0xCA,
0xCB, 0x1F, 0xE4, 0x84, 0xA7, 0xB2, 0x62, 0x48, 0xCC, 0xB6, 0x09, 0x9C, 0x53, 0x3F, 0x9F, 0x58,
0xE6, 0x66, 0x17, 0x94, 0xEB, 0xBD, 0x77, 0xB6, 0xF2, 0x25, 0x04, 0xC0, 0xAF, 0xD4, 0x90, 0x01,
0xA8, 0x3B, 0x60, 0xC9, 0xFA, 0xD5, 0x4E, 0x02, 0xA1, 0xC5, 0x45, 0xF8, 0x62, 0xEE, 0xFC, 0x1A,
0xD1, 0x2E, 0x42, 0xDC, 0x4C, 0x9C, 0x6B, 0xB9, 0x7C, 0x5C, 0x11, 0xF7, 0x43, 0xBF, 0x0C, 0x12,
0x08, 0xC8, 0x25, 0x42, 0x5E, 0xCC, 0x0C, 0xA9, 0x0A, 0xE6, 0xC8, 0x49, 0xA3, 0x21, 0x83, 0xA9,
0x6F, 0xFB, 0x69, 0xA4, 0x7F, 0x53, 0x48, 0x18, 0xD7, 0xC4, 0x06, 0xDA, 0xDF, 0x39, 0xE5, 0x29,
0xA7, 0x3C, 0xE1, 0x94, 0x5F, 0xC5, 0x42, 0x1D, 0xF9, 0xF3, 0x6E, 0x60, 0xE4, 0x08, 0xD8, 0x4D,
0x1D, 0x92, 0x62, 0x61, 0xD0, 0x23, 0x4C, 0x0F, 0x6A, 0xE1, 0x40, 0x76, 0x0F, 0xE3, 0xE3, 0x26,
0xE4, 0x01, 0x84, 0x3B, 0x8E, 0xB9, 0xBC, 0x66, 0x57, 0x81, 0x31, 0x5D, 0xAF, 0xE6, 0x0E, 0x14,
0xC4, 0xFB, 0x07, 0xD0, 0xF4, 0xD7, 0x44, 0xCE, 0x60, 0x32, 0x89, 0x65, 0x10, 0xE9, 0x5D, 0xA9,
0x82, 0x1F, 0x49, 0x3C, 0x15, 0x35, 0x09, 0xA2, 0x40, 0x2B, 0x76, 0xCD, 0xB8, 0xE7, 0x09, 0x03,
0x9C, 0xBA, 0x38, 0x76, 0x4C, 0x3E, 0x8D, 0x9F, 0xEB, 0xEC, 0xD6, 0xCE, 0xA7, 0x98, 0x73, 0x35,
0x05, 0xF6, 0x3D, 0x3B, 0x3D, 0x09, 0x8B, 0xD9, 0x3E, 0x4F, 0xE5, 0x07, 0xFA, 0x6C, 0x4D, 0x61,
0x3D, 0xD5, 0x34, 0xC0, 0xE8, 0xA6, 0x54, 0xFC, 0xA9, 0x5B, 0x84, 0x49, 0x67, 0xD7, 0xDB, 0x70,
0xED, 0x6B, 0x6E, 0x77, 0xCE, 0xCC, 0x37, 0xDD, 0x12, 0x16, 0x86, 0xE8, 0x09, 0x7A, 0x9D, 0xCB,
0x44, 0xEC, 0x8F, 0x25, 0xAC, 0xDD, 0xB7, 0x4D, 0x03, 0xC7, 0x65, 0xAA, 0x78, 0xBE, 0x52, 0x04,
0xBB, 0x80, 0x27, 0xA5, 0xC2, 0x7E, 0x9A, 0xE5, 0xFE, 0xF3, 0x6F, 0xE7, 0xFE, 0x0B, 0xDF, 0xCE,
0xFD, 0xBF, 0x03, 0x5B, 0x86, 0xE2, 0xF8, 0x64, 0xCD, 0x58, 0xE7, 0xB0, 0x08, 0x3E, 0xE0, 0xF5,
0xF2, 0xD4, 0x83, 0xE8, 0x8C, 0x4B, 0x3D, 0x41, 0x5C, 0x8B, 0x30, 0x2F, 0xEC, 0xF3, 0x1C, 0x9F,
0xB9, 0xAD, 0x3A, 0x9E, 0x9B, 0xDA, 0xFB, 0x41, 0xE7, 0x60, 0x55, 0xB6, 0xA4, 0x39, 0x2E, 0xFE,
0x85, 0x5C, 0x66, 0x9B, 0x30, 0xE8, 0x54, 0x1A, 0x50, 0xE0, 0xE7, 0x2B, 0xDA, 0x89, 0x9F, 0xAE,
0xD9, 0x73, 0xBB, 0xC6, 0x95, 0xC5, 0xC2, 0x5A, 0x46, 0xE8, 0xFC, 0x72, 0x25, 0x67, 0x43, 0x71,
0x71, 0xCD, 0x26, 0x2C, 0x1E, 0x92, 0xA7, 0x6D, 0xDA, 0x95, 0xC9, 0x43, 0x1F, 0x56, 0xB1, 0x6D,
0xE1, 0xCA, 0x5C, 0xCC, 0x0B, 0x0D, 0xD8, 0x9B, 0x91, 0x3F, 0x2C, 0xA3, 0xF2, 0x44, 0xE3, 0x8F,
0xFC, 0xC8, 0x79, 0xFD, 0xDC, 0x93, 0xE9, 0xAF, 0x3E, 0xBA, 0x52, 0x8E, 0xC6, 0x45, 0xE3, 0xBB,
0x15, 0x68, 0x18, 0xFA, 0xA8, 0x40, 0xA0, 0x77, 0x12, 0xBB, 0x03, 0x1B, 0x30, 0x39, 0xEE, 0x9C,
0x67, 0x45, 0xB8, 0x4B, 0x69, 0x1E, 0x7A, 0x31, 0x5C, 0xB8, 0xBA, 0x71, 0xE8, 0x5C, 0x50, 0x06,
0xBB, 0x9C, 0x37, 0xBC, 0x38, 0xF8, 0xFE, 0xE3, 0xB5, 0x8B, 0xC8, 0x6C, 0x7D, 0x2A, 0x30, 0x44,
0x32, 0x4B, 0xB8, 0xF6, 0xB0, 0x45, 0x28, 0x9C, 0xB8, 0x6F, 0x41, 0xCF, 0x27, 0x06, 0xD7, 0x68,
0xF4, 0x4C, 0x9D, 0x40, 0x78, 0x3D, 0xA5, 0xE5, 0xB0, 0x15, 0x82, 0xD6, 0xAD, 0x1F, 0x3D, 0x04,
0x42, 0x90, 0x51, 0xBB, 0x7C, 0xB9, 0xB3, 0x4C, 0x06, 0xFB, 0x4B, 0x27, 0x8C, 0xFF, 0xA1, 0x85,
0x35, 0x7D, 0x49, 0xA4, 0x21, 0xFA, 0x18, 0xFC, 0x70, 0xB8, 0x69, 0xBB, 0x67, 0xFE, 0xCD, 0x51,
0x7F, 0x3F, 0xA1, 0x87, 0xA1, 0x8B, 0xC2, 0xA4, 0xCC, 0x7B, 0x55, 0xF0, 0x46, 0x72, 0x7A, 0x2A,
0xBF, 0xB3, 0xC8, 0x58, 0xF4, 0x1A, 0xD7, 0x40, 0xE3, 0x8C, 0x6D, 0x30, 0x46, 0xF4, 0x64, 0x36,
0x23, 0xFF, 0x19, 0xFE, 0x31, 0x36, 0x39, 0xF2, 0x67, 0x65, 0x17, 0x5D, 0x53, 0x66, 0x4D, 0xD8,
0x66, 0x58, 0xE2, 0x56, 0x46, 0x56, 0x65, 0x31, 0x98, 0x00, 0x03, 0xC6, 0x8A, 0xD9, 0xE0, 0xAC,
0x50, 0xD1, 0x55, 0x28, 0xE7, 0xF5, 0x5C, 0xC3, 0x6A, 0xC6, 0xF0, 0x24, 0x2D, 0x63, 0x86, 0x12,
0xCC, 0x77, 0xC8, 0x3F, 0xA3, 0x3B, 0x30, 0x04, 0x4F, 0x95, 0xC6, 0x42, 0x3C, 0x1C, 0x10, 0xC8,
0xD7, 0x8F, 0x78, 0x40, 0x0F, 0xCB, 0x1C, 0x5E, 0x33, 0x65, 0x78, 0xAE, 0xDC, 0x01, 0x68, 0xFA,
0xAF, 0xE7, 0x91, 0x75, 0x1D, 0x58, 0x16, 0x11, 0xD1, 0x76, 0x80, 0x4E, 0xEF, 0xE0, 0xC4, 0xC7,
0x84, 0xAC, 0xF8, 0x5C, 0xB9, 0xED, 0x74, 0xA4, 0x86, 0xA6, 0xB9, 0x83, 0x17, 0x25, 0x3A, 0x87,
0x6D, 0xD8, 0x4E, 0x8A, 0x10, 0xB8, 0xBE, 0x25, 0x31, 0x6C, 0x29, 0x1A, 0xF5, 0xC4, 0x01, 0x1D,
0x83, 0x96, 0xCB, 0x78, 0x0A, 0xD6, 0xD0, 0x52, 0xF0, 0xC0, 0xCC, 0x59, 0xDC, 0xC6, 0x2D, 0xD4,
0xA0, 0x5D, 0x29, 0xC2, 0xF2, 0x16, 0x35, 0xB8, 0xCD, 0x2B, 0xBC, 0xBA, 0xD1, 0x68, 0x32, 0xA5,
0xF7, 0x65, 0x27, 0x87, 0xD7, 0x43, 0x78, 0xDD, 0x67, 0x2A, 0x73, 0x73, 0xEE, 0x35, 0x8C, 0x3B,
0x1B, 0xAE, 0x2F, 0xC8, 0x0E, 0x68, 0x50, 0x11, 0x2A, 0x4A, 0xFE, 0xD9, 0x4A, 0x4F, 0x93, 0x42,
0xA5, 0x3B, 0x70, 0x24, 0xE8, 0xF7, 0x2D, 0xF3, 0xAF, 0x6D, 0x50, 0x4E, 0x52, 0x68, 0x33, 0x5B,
0x9F, 0xD2, 0xDD, 0x84, 0xC0, 0x13, 0x98, 0x8F, 0xAA, 0xF8, 0x1D, 0x4E, 0x86, 0x57, 0xBB, 0x57,
0x67, 0x31, 0x71, 0x24, 0xD7, 0x46, 0x2E, 0x65, 0x6E, 0x13, 0x94, 0xFD, 0x55, 0x7A, 0xC1, 0x5D,
0x1E, 0x66, 0xAF, 0xDE, 0xD8, 0x68, 0xE2, 0x3D, 0xE7, 0xAC, 0xBE, 0xD9, 0x51, 0x6F, 0x7C, 0x52,
0x16, 0xC1, 0x3E, 0x66, 0x45, 0x53, 0x99, 0x8B, 0x0F, 0x59, 0x9F, 0x85, 0xCC, 0x2F, 0xF6, 0x9E,
0x8E, 0xE9, 0x4C, 0x2C, 0xC1, 0x36, 0xFD, 0x87, 0x68, 0x06, 0x2E, 0xA4, 0xEF, 0x82, 0xAF, 0x49,
0x18, 0x89, 0x7F, 0x0C, 0xE7, 0xDA, 0xC1, 0x03, 0xAA, 0xB3, 0xE5, 0x34, 0xE8, 0x0E, 0xFE, 0x1E,
0x7D, 0x1A, 0xF3, 0x3C, 0xE7, 0x03, 0x9C, 0x48, 0x23, 0x3A, 0x9D, 0x86, 0x13, 0xFB, 0x29, 0xE0,
0xB3, 0x0B, 0xE6, 0x80, 0x65, 0x53, 0x33, 0x13, 0x58, 0x70, 0x71, 0x87, 0x3F, 0x53, 0xFA, 0x1F,
0x02, 0x35, 0xD6, 0x8E, 0xE0, 0xF7, 0x12, 0xFC, 0xB6, 0xA9, 0xCE, 0x82, 0x28, 0x32, 0xF3, 0x35,
0xE6, 0x88, 0xE8, 0xE6, 0x30, 0x87, 0xF1, 0x19, 0x99, 0xAE, 0x5A, 0x75, 0x6C, 0x4A, 0x50, 0x32,
0x53, 0x2D, 0x75, 0x80, 0xC7, 0xCC, 0x24, 0x8D, 0x57, 0xC4, 0x34, 0xA5, 0x75, 0xFF, 0xB9, 0x0A,
0x24, 0x74, 0x23, 0x07, 0x82, 0x20, 0x14, 0xBA, 0x52, 0xC2, 0x9B, 0xF9, 0xCF, 0x21, 0x6C, 0x82,
0xB3, 0x76, 0x00, 0x14, 0x65, 0x1C, 0xB4, 0x70, 0x1A, 0x00, 0x21, 0xAC, 0x71, 0xC6, 0x84, 0x6C,
0x31, 0x85, 0xCD, 0x61, 0x3D, 0xF3, 0xA9, 0xDD, 0xC0, 0xF1, 0x99, 0x1C, 0x88, 0x03, 0x1C, 0x96,
0xAD, 0x50, 0x56, 0xBD, 0x7C, 0xEC, 0xCE, 0xD6, 0x5C, 0x86, 0x20, 0x72, 0xBF, 0x12, 0xF6, 0x56,
0xFF, 0x36, 0x07, 0x47, 0x76, 0x17, 0xD0, 0xEF, 0x49, 0x19, 0x79, 0xF9, 0xE6, 0xC3, 0xFB, 0xA9,
0x21, 0x48, 0xB1, 0x8D, 0xAD, 0x59, 0xE5, 0xDC, 0x64, 0x00, 0x88, 0x9F, 0x9B, 0x25, 0x33, 0x3F,
0x20, 0xE2, 0x71, 0x72, 0x1F, 0xB0, 0x25, 0x9C, 0xC9, 0x72, 0xC9, 0xB6, 0xF7, 0x8C, 0x9F, 0xFE,
0xE1, 0xE9, 0xBF, 0x79, 0xAA, 0xFF, 0x98, 0xA5, 0x9A, 0xEE, 0x28, 0x83, 0x01, 0x5E, 0xD6, 0x7A,
0x16, 0xB2, 0xC0, 0x11, 0x92, 0x92, 0x3A, 0x2C, 0x9D, 0xB7, 0x10, 0xA9, 0x8A, 0x0C, 0x79, 0x43,
0xAA, 0xA5, 0x8D, 0x86, 0x98, 0xBA, 0x6C, 0x16, 0x1C, 0xCD, 0x2D, 0x06, 0xE4, 0xF8, 0xDA, 0x30,
0xB2, 0x03, 0x4E, 0x13, 0x7F, 0x0F, 0xDD, 0xC9, 0x69, 0x5A, 0x3D, 0xFC, 0x78, 0xEF, 0xC8, 0xFD,
0x5B, 0x64, 0x07, 0x10, 0x67, 0x74, 0x64, 0xD6, 0x85, 0x07, 0x7F, 0xD5, 0xB6, 0xDE, 0x1B, 0xE9,
0xD9, 0xB9, 0xC0, 0x6B, 0x03, 0x46, 0xBD, 0xF6, 0x7B, 0xB8, 0x23, 0x6A, 0xBC, 0x77, 0x4C, 0x83,
0xB8, 0x0D, 0x11, 0x86, 0xE9, 0x63, 0x0F, 0xCA, 0x31, 0xC3, 0xC8, 0x94, 0x5F, 0x92, 0x88, 0x1C,
0x38, 0xB0, 0xBA, 0xE7, 0x4D, 0xBD, 0x79, 0xAA, 0x89, 0x5E, 0x53, 0x95, 0x5D, 0x2E, 0x27, 0xB7,
0xC9, 0x02, 0x7B, 0x4D, 0xDC, 0xC2, 0xFA, 0x8D, 0xE6, 0xC0, 0x65, 0xA9, 0xF5, 0x5B, 0xDC, 0x7F,
0xFB, 0xDF, 0xD6, 0xAA, 0xDD, 0x8A, 0x79, 0x22, 0x87, 0x6C, 0xD2, 0x63, 0x2E, 0x04, 0x6E, 0x43,
0x54, 0xFB, 0x55, 0xFD, 0xAD, 0x12, 0x13, 0x74, 0xC9, 0x35, 0x4E, 0x32, 0x82, 0x87, 0x95, 0x4F,
0x3D, 0xD8, 0xEF, 0xF5, 0x56, 0x9A, 0xE0, 0x47, 0x65, 0xC0, 0xCC, 0x07, 0x6E, 0x32, 0x55, 0xD6,
0x00, 0x84, 0x27, 0xA5, 0x46, 0x03, 0x87, 0xDF, 0xFE, 0x96, 0xA4, 0x02, 0x94, 0xE4, 0xEA, 0x06,
0x49, 0x89, 0xEA, 0xF4, 0xF0, 0xB6, 0x3D, 0xA9, 0x62, 0x28, 0x77, 0x95, 0x99, 0x8B, 0x58, 0x5F,
0x86, 0xE9, 0x8B, 0x34, 0x4F, 0xD5, 0x33, 0x80, 0xC5, 0x09, 0xFF, 0x2F, 0x11, 0xCF, 0x7F, 0xC8,
0x9C, 0xCA, 0x63, 0x2D, 0xB3, 0x86, 0xC9, 0xA1, 0x88, 0xE3, 0x60, 0x08, 0x02, 0x60, 0xCE, 0x2E,
0x98, 0x22, 0xEB, 0xF3, 0xAB, 0xC7, 0x20, 0xC9, 0x5A, 0x53, 0x30, 0x04, 0xEA, 0xFD, 0x3D, 0x8B,
0xCF, 0xE4, 0x9A, 0xE5, 0x01, 0xDC, 0xB2, 0x35, 0xEC, 0x28, 0x30, 0x91, 0xCF, 0xB6, 0xAC, 0xFD,
0xE4, 0xCA, 0xE7, 0x22, 0x1A, 0x55, 0x7C, 0x88, 0x68, 0x64, 0x6D, 0x30, 0x0F, 0x77, 0xDD, 0xDA,
0x2F, 0xEC, 0xD2, 0x2D, 0x9D, 0xDC, 0xA9, 0x18, 0xB0, 0x82, 0x16, 0x36, 0x50, 0xDD, 0x29, 0x02,
0xD2, 0x11, 0xB0, 0xFD, 0xF4, 0x66, 0x9F, 0x84, 0xE4, 0xFE, 0x0E, 0xF3, 0xA6, 0xCC, 0xF6, 0xFA,
0x3D, 0x9E, 0xFD, 0x13, 0x66, 0x4B, 0x70, 0xDB, 0xD1, 0x71, 0xC1, 0xD9, 0x27, 0xD9, 0x5D, 0x78,
0xE3, 0x1B, 0xAF, 0xCE, 0x34, 0xDE, 0x3B, 0xDD, 0x4F, 0xD4, 0x42, 0x03, 0x2E, 0x14, 0xF1, 0xAB,
0xF8, 0xF8, 0xCA, 0xCB, 0xC3, 0x0E, 0xCA, 0xB0, 0x14, 0x7F, 0xB0, 0x71, 0xF5, 0x65, 0x50, 0xBF,
0xB9, 0x9B, 0x34, 0xEE, 0x63, 0xF0, 0x53, 0xF9, 0x03, 0x7B, 0x6E, 0x09, 0x48, 0xA8, 0xDB, 0x1E,
0x9A, 0x28, 0x63, 0x62, 0xBA, 0x19, 0xC2, 0xA3, 0x7E, 0x75, 0x02, 0x72, 0x1C, 0xBE, 0xD2, 0x25,
0xB4, 0x95, 0xED, 0xC5, 0xFE, 0x86, 0xF6, 0x62, 0xF2, 0xB2, 0x39, 0xF9, 0x15, 0xFF, 0xB9, 0x44,
0x4F, 0x5E, 0x23, 0x95, 0xC8, 0x09, 0xB6, 0x4A, 0xF2, 0x01, 0x9A, 0x6E, 0x1E, 0x7E, 0x08, 0x6A,
0x3B, 0x93, 0x23, 0x59, 0x12, 0x81, 0xFA, 0x49, 0xA0, 0x59, 0x92, 0x54, 0x06, 0xC0, 0x21, 0x0B,
0xF9, 0xF4, 0x2C, 0xC9, 0x40, 0x6B, 0x2A, 0xA5, 0x35, 0x5B, 0xBA, 0x6F, 0xC0, 0x9F, 0xDB, 0xD1,
0x1A, 0x5A, 0x38, 0x61, 0x3A, 0xC4, 0x62, 0xC1, 0x2C, 0xA7, 0x50, 0x00, 0x68, 0xD5, 0x18, 0x8B,
0x67, 0x55, 0x58, 0x00, 0x6A, 0x79, 0x82, 0x65, 0x09, 0xB9, 0xF7, 0xB4, 0xEA, 0x41, 0x70, 0xF5,
0x88, 0x89, 0x6C, 0xCD, 0x10, 0xE3, 0x93, 0x3F, 0x1D, 0x76, 0xA2, 0x34, 0x6D, 0x4D, 0xFC, 0x81,
0x76, 0x36, 0x3B, 0x89, 0x5F, 0x35, 0xB2, 0xF9, 0x78, 0xE5, 0xE4, 0x6E, 0x71, 0x02, 0x82, 0xA8,
0x24, 0x70, 0x52, 0x19, 0x63, 0x8D, 0xB7, 0x2A, 0xB1, 0xAE, 0xA7, 0x9A, 0x8C, 0x60, 0x0E, 0x9F,
0x81, 0xD1, 0xA7, 0xE6, 0xF6, 0xDA, 0x7B, 0x97, 0xDB, 0x1B, 0xD2, 0x51, 0xA2, 0x99, 0xCC, 0x7E,
0xE1, 0x35, 0x1D, 0x42, 0xB5, 0x60, 0xF0, 0x7A, 0x67, 0x8E, 0xDC, 0x7E, 0x56, 0x8E, 0x3C, 0xF4,
0xB1, 0x35, 0xF4, 0xC0, 0x0E, 0x92, 0x6C, 0x0E, 0x76, 0x95, 0xD0, 0xC8, 0x8E, 0x75, 0x2F, 0x31,
0x4B, 0x40, 0x89, 0xD1, 0xE4, 0x32, 0x93, 0x12, 0x9F, 0xA6, 0x32, 0xC7, 0x60, 0xE1, 0x8E, 0x42,
0xE2, 0x21, 0x34, 0x0C, 0x54, 0xF5, 0xA7, 0x00, 0x2F, 0x04, 0x41, 0xF4, 0x12, 0x04, 0x91, 0x48,
0x15, 0x2B, 0x86, 0x0A, 0x99, 0x6A, 0xF8, 0x40, 0x0D, 0x85, 0x82, 0xC6, 0x8C, 0x94, 0x26, 0x4C,
0x96, 0x37, 0x0C, 0xC4, 0x9A, 0xF0, 0x6A, 0xCB, 0x10, 0xFC, 0x36, 0xD9, 0xAD, 0xDF, 0x0B, 0x9D,
0x77, 0xDF, 0x82, 0xA3, 0x6A, 0x19, 0x4D, 0xC6, 0x1D, 0x51, 0x35, 0xD1, 0xBD, 0xC1, 0xA3, 0xD9,
0xAD, 0x4F, 0xE2, 0xB0, 0x8F, 0x80, 0xC3, 0xFE, 0xAA, 0xF2, 0x9F, 0x7B, 0x1B, 0xFE, 0x74, 0xDE,
0x73, 0xD8, 0x9B, 0xC0, 0x2E, 0x0F, 0x4D, 0x7C, 0xF9, 0x16, 0x0E, 0x2B, 0x56, 0x2F, 0x06, 0xE6,
0xA9, 0x41, 0x56, 0xFF, 0xCD, 0xA8, 0x17, 0x19, 0xC6, 0xBE, 0x37, 0xAB, 0x3B, 0x7C, 0x58, 0xF9,
0xA0, 0x4F, 0xB5, 0x01, 0xAC, 0x3C, 0xDD, 0x94, 0xCD, 0x4C, 0xD5, 0xF4, 0x5B, 0xA4, 0x47, 0xDE,
0xC2, 0x0F, 0x7C, 0xE0, 0xA3, 0x31, 0x3F, 0x80, 0xB2, 0x4F, 0xE1, 0x18, 0xE5, 0x94, 0x97, 0xBB,
0x7D, 0x88, 0x4A, 0x8A, 0x63, 0xD4, 0xEF, 0x50, 0xE6, 0xA1, 0x8A, 0x7D, 0xF8, 0x90, 0xED, 0x42,
0xFE, 0x6C, 0x18, 0x48, 0x51, 0x36, 0xEE, 0xB9, 0xF2, 0x7E, 0x3F, 0x3D, 0x13, 0xC9, 0x93, 0x58,
0x75, 0x5A, 0x6A, 0xBF, 0x41, 0xE8, 0xCE, 0x12, 0x06, 0xD3, 0x98, 0xE7, 0xA3, 0xBA, 0xF7, 0xC9,
0xC4, 0xBF, 0x4D, 0x2D, 0x64, 0xA6, 0x4A, 0x07, 0xEB, 0xF4, 0x44, 0x0A, 0xD2, 0xD4, 0x14, 0x51,
0xCB, 0x8D, 0x5C, 0xBC, 0xA2, 0xC5, 0x8B, 0xBB, 0xB8, 0x50, 0x3F, 0x2A, 0x05, 0x37, 0x90, 0x6A,
0x35, 0x1C, 0x22, 0xB3, 0xAB, 0xBB, 0x1D, 0x81, 0x26, 0x02, 0x81, 0x5B, 0x4F, 0x71, 0xF2, 0x1F,
0xEA, 0x16, 0x6B, 0x64, 0x01, 0xC8, 0xFD, 0x0B, 0x00, 0x1C, 0xE0, 0x0D, 0x98, 0xBB, 0x61, 0x98,
0xCE, 0xBE, 0x6A, 0x1D, 0xF8, 0x0E, 0x73, 0xA6, 0x16, 0xDC, 0xC7, 0xBD, 0xDF, 0x15, 0x28, 0x6F,
0xB3, 0x2B, 0x50, 0xEB, 0xAE, 0x40, 0x1F, 0x01, 0x1C, 0x4E, 0xFE, 0x9C, 0x94, 0x7D, 0x8E, 0x29,
0xF7, 0xFD, 0x76, 0xF1, 0x6F, 0xC9, 0xF8, 0xB7, 0x61, 0xFC, 0x3B, 0xD1, 0x74, 0xA4, 0x2C, 0x76,
0xC7, 0xEE, 0xD7, 0x37, 0x2B, 0xDB, 0x05, 0xBE, 0x3E, 0x5F, 0xDB, 0xF5, 0xA6, 0x44, 0x0F, 0x11,
0x38, 0xE0, 0x1E, 0xDC, 0x02, 0xC1, 0x8F, 0xC6, 0x09, 0x00, 0x41, 0x4A, 0x35, 0xFC, 0xBA, 0x80,
0x77, 0x38, 0xEF, 0xC3, 0xF1, 0x43, 0x49, 0x96, 0xE8, 0x2E, 0x54, 0xEB, 0xAC, 0x00, 0xF6, 0x9C,
0xC8, 0xE9, 0x44, 0x96, 0x0C, 0xD6, 0xF1, 0x85, 0x24, 0x56, 0x9D, 0x00, 0x73, 0x91, 0xA0, 0x53,
0xEF, 0x37, 0xCB, 0x9D, 0x77, 0xD2, 0x30, 0x64, 0x6E, 0x88, 0xDE, 0xD4, 0x21, 0x7A, 0xA0, 0xD1,
0xDB, 0x6D, 0x03, 0x60, 0x36, 0x11, 0x42, 0x26, 0xA7, 0xE4, 0x64, 0x36, 0xFA, 0x6C, 0x27, 0x4D,
0x55, 0x68, 0x19, 0xE4, 0xE4, 0xBC, 0x26, 0xC7, 0xC5, 0xEB, 0xDC, 0xC4, 0xAC, 0x11, 0x7B, 0xF9,
0x05, 0xC6, 0x18, 0xA7, 0x3D, 0x42, 0xAA, 0x5F, 0xD3, 0x7C, 0x99, 0xC3, 0x33, 0x5F, 0xBB, 0x5B,
0x8F, 0xED, 0xD0, 0x63, 0xF7, 0xEC, 0x8E, 0x31, 0xD9, 0xC3, 0x3D, 0xA8, 0xDC, 0x87, 0x11, 0x06,
0x62, 0x1A, 0xDD, 0x62, 0xF5, 0xB9, 0xD5, 0x8C, 0x21, 0xFE, 0xFC, 0x4A, 0x2E, 0xFE, 0x8B, 0x27,
0x30, 0x98, 0x51, 0x45, 0xC5, 0x86, 0x42, 0xDD, 0xA4, 0x90, 0x5E, 0xE4, 0xF8, 0x46, 0x98, 0x6D,
0x53, 0xB5, 0xDC, 0xA2, 0xA0, 0xD9, 0x00, 0x20, 0xC1, 0x90, 0x20, 0xAB, 0xD4, 0x65, 0x3E, 0xCC,
0x2D, 0x39, 0x9E, 0x39, 0x15, 0xEF, 0xAC, 0x34, 0xAF, 0x8B, 0xFF, 0xC3, 0x92, 0x88, 0xE9, 0xFF,
0x12, 0x04, 0xE4, 0x0D, 0x7C, 0xDA, 0xA2, 0x92, 0x42, 0x33, 0xC0, 0xF3, 0x1A, 0x53, 0x3B, 0x05,
0x16, 0xB3, 0x09, 0xC1, 0xCD, 0x19, 0x0E, 0x5C, 0x30, 0xD5, 0xAA, 0x7C, 0xF7, 0x3F, 0x46, 0x50,
0x3E, 0xAC, 0xEE, 0xF4, 0x61, 0x26, 0x95, 0x19, 0x13, 0x96, 0x38, 0x01, 0x7F, 0x36, 0x25, 0xEF,
0xB5, 0x98, 0x95, 0x0D, 0x13, 0x9B, 0x1B, 0x89, 0x53, 0x99, 0x08, 0x02, 0xD3, 0x1A, 0x6D, 0x4C,
0x88, 0x6F, 0x72, 0x88, 0x05, 0xB3, 0xED, 0x38, 0xA1, 0xA4, 0x9B, 0x13, 0x18, 0x6C, 0x25, 0xFE,
0x0F, 0xE0, 0x84, 0x81, 0xAB, 0x33, 0xAC, 0x5C, 0x89, 0xA1, 0x83, 0xE8, 0x43, 0xD8, 0x10, 0x4C,
0x15, 0x77, 0x36, 0xC6, 0xDE, 0xF0, 0xAD, 0xF0, 0xEA, 0x4D, 0x3F, 0x0D, 0xEA, 0x67, 0xFD, 0x74,
0x2C, 0xCF, 0x50, 0xA8, 0xC2, 0x20, 0x41, 0xE5, 0xAA, 0x52, 0xC5, 0x1B, 0x8F, 0x54, 0xEB, 0xD1,
0x82, 0xA8, 0xCA, 0xFB, 0x54, 0x3A, 0xEA, 0x3B, 0x1D, 0x7A, 0x21, 0x2B, 0x25, 0xF4, 0x1E, 0xD8,
0xB9, 0x3D, 0x81, 0x26, 0x67, 0xE6, 0xF1, 0x76, 0x33, 0x72, 0x53, 0x06, 0xD6, 0x8F, 0x68, 0xFC,
0xC9, 0xE1, 0xE1, 0xA6, 0x88, 0xD2, 0xE4, 0x9E, 0x10, 0x17, 0x1B, 0xFC, 0x3A, 0x7B, 0xBC, 0x86,
0xE6, 0xAF, 0xD1, 0xC5, 0x74, 0xF7, 0x6E, 0x07, 0xE5, 0x06, 0xDB, 0xD3, 0x7D, 0x76, 0xF2, 0xB3,
0xBE, 0x74, 0xE4, 0xF4, 0x62, 0xD3, 0x56, 0xBE, 0xFA, 0x19, 0xD3, 0x1E, 0xFF, 0x43, 0x50, 0x1B,
0xDA, 0x3A, 0x3D, 0xBC, 0x4E, 0x48, 0xAF, 0x46, 0x00, 0xA1, 0x8D, 0xC2, 0xCA, 0x14, 0x9A, 0xA7,
0x64, 0xCA, 0xC0, 0x10, 0x1D, 0xC6, 0x19, 0x0D, 0xF9, 0xD8, 0xF5, 0x54, 0xF1, 0x97, 0x69, 0xC2,
0xBE, 0x46, 0x60, 0xFF, 0x34, 0xAF, 0xD6, 0xA8, 0xE1, 0xD0, 0xE9, 0xA5, 0x2E, 0xF1, 0xBA, 0x7E,
0x83, 0x0E, 0x22, 0x0B, 0xD8, 0x41, 0x68, 0x74, 0x7B, 0x05, 0xCD, 0x4F, 0x7D, 0x7A, 0xA3, 0xB3,
0x1C, 0x19, 0x9C, 0x17, 0x46, 0xD5, 0xBD, 0x42, 0xAD, 0xD4, 0x1A, 0x03, 0x2F, 0x57, 0x7A, 0x65,
0x75, 0x16, 0x1C, 0x1B, 0x48, 0x54, 0x32, 0xD1, 0x7E, 0x3D, 0xA5, 0x31, 0x7D, 0x65, 0x4C, 0x0F,
0xF9, 0x3C, 0xEA, 0x55, 0xA6, 0xCF, 0x9F, 0x0C, 0x5F, 0x18, 0xDD, 0xB3, 0x21, 0xD4, 0xF0, 0x8B,
0x15, 0x06, 0x01, 0xA5, 0x5D, 0xEB, 0x1D, 0xB1, 0xDE, 0x01, 0x2F, 0xA9, 0xA5, 0x0C, 0x7A, 0xC7,
0x74, 0x65, 0x17, 0x23, 0x8D, 0x59, 0x28, 0xA1, 0x55, 0x1E, 0x83, 0x8D, 0xC2, 0x18, 0x64, 0x51,
0x6C, 0x60, 0xF5, 0x7E, 0x2C, 0x2C, 0xFA, 0x12, 0x0A, 0x0E, 0x24, 0xE9, 0xC7, 0xA9, 0x5C, 0x70,
0xFF, 0x70, 0x05, 0xD6, 0xEA, 0x69, 0xD1, 0xD0, 0x8E, 0xDD, 0xF2, 0x2C, 0x7B, 0x9A, 0x02, 0x67,
0x99, 0xDE, 0x7E, 0x8F, 0xF3, 0x89, 0x40, 0x0F, 0x1A, 0x67, 0x3F, 0x4C, 0xF7, 0xF2, 0x3D, 0x2E,
0xA2, 0xD0, 0xA7, 0x11, 0x3C, 0xBB, 0xA6, 0xB5, 0xDB, 0xBB, 0xE8, 0x72, 0xCD, 0x31, 0xDC, 0xC4,
0x06, 0xAB, 0xB5, 0xE0, 0x71, 0x11, 0xF3, 0xC7, 0x24, 0xB8, 0xD3, 0x88, 0xA9, 0x09, 0x60, 0x35,
0x02, 0x5F, 0xE8, 0xAE, 0x9F, 0x87, 0x74, 0x79, 0xAB, 0x4E, 0xBE, 0x2E, 0xF5, 0x69, 0xD9, 0xB6,
0xAA, 0x4A, 0x3A, 0xFB, 0x1A, 0xFC, 0xDB, 0x87, 0x18, 0x4E, 0x38, 0x5B, 0x29, 0xE5, 0xC7, 0xDB,
0x72, 0x22, 0xEC, 0xAC, 0xB2, 0x6E, 0x7D, 0xEF, 0x52, 0xBD, 0x15, 0x39, 0x3F, 0x2F, 0x1B, 0xFF,
0xC5, 0x0B, 0xE5, 0x18, 0x21, 0x4B, 0xD5, 0x86, 0xEE, 0xE5, 0x6A, 0x3C, 0x76, 0xAA, 0x9D, 0xD2,
0xB9, 0x61, 0xFE, 0xD1, 0x32, 0x1B, 0xC5, 0xB0, 0xBB, 0xE5, 0x7E, 0xF2, 0xEE, 0x16, 0x0B, 0x19,
0xB6, 0xFB, 0xFD, 0x14, 0xF0, 0xA5, 0xA7, 0x32, 0x33, 0xB7, 0xB2, 0x4E, 0xD9, 0x8F, 0x93, 0xCB,
0x7D, 0xAB, 0x8A, 0xBC, 0xDE, 0xC5, 0x21, 0x91, 0x55, 0x07, 0x6F, 0x24, 0x88, 0x9F, 0xBF, 0x73,
0x28, 0x91, 0xE5, 0xD6, 0x08, 0x1A, 0x37, 0x3C, 0x53, 0x83, 0x7B, 0xE2, 0x1E, 0x9F, 0x27, 0x8E,
0x25, 0x9F, 0x7B, 0x83, 0x4C, 0x03, 0x24, 0x26, 0x41, 0xFC, 0x01, 0x70, 0xBF, 0x27, 0x77, 0x91,
0x29, 0x7B, 0x49, 0x29, 0x4B, 0xFF, 0x87, 0x66, 0x5F, 0xD2, 0x58, 0xF9, 0x9C, 0x79, 0x13, 0xD1,
0x7D, 0xCD, 0xCC, 0x31, 0xE6, 0xEB, 0xA5, 0x98, 0x30, 0xD4, 0x9D, 0x30, 0x17, 0x3C, 0x81, 0x0E,
0xA6, 0xCC, 0xFB, 0x77, 0x43, 0x11, 0x8C, 0x2E, 0xA5, 0xAA, 0xD1, 0xA1, 0x03, 0xD0, 0x18, 0x34,
0x04, 0xFD, 0xA9, 0xE3, 0x59, 0x97, 0x84, 0x69, 0xCD, 0xBD, 0x2E, 0x84, 0x42, 0xB9, 0x8F, 0x6B,
0x56, 0x61, 0x12, 0x85, 0x8C, 0x81, 0x26, 0xCD, 0xA6, 0x58, 0xBF, 0xCE, 0xB5, 0x35, 0x65, 0xC8,
0xF9, 0x2D, 0x93, 0xCC, 0x98, 0x49, 0x41, 0xA4, 0xD0, 0xB9, 0xE6, 0xB2, 0x49, 0x96, 0x77, 0x15,
0x49, 0xC3, 0x04, 0x93, 0x6C, 0xEC, 0x12, 0x9A, 0xCB, 0xDA, 0x1A, 0x3A, 0x7D, 0xB2, 0x74, 0x0F,
0xAB, 0x75, 0x2C, 0xBB, 0xDA, 0xC7, 0x9D, 0xEA, 0x54, 0xB5, 0x62, 0x6E, 0xEF, 0x20, 0x63, 0x0C,
0xC4, 0x72, 0x8E, 0xD6, 0x9F, 0x07, 0x20, 0x2E, 0xE0, 0x9D, 0x25, 0xF7, 0x8A, 0x6D, 0x06, 0x67,
0x15, 0x9A, 0xAC, 0x81, 0xE2, 0xAB, 0xE3, 0x3E, 0x38, 0x3B, 0x85, 0xE0, 0x2C, 0xC0, 0x5D, 0x4F,
0xFF, 0x42, 0xB7, 0xB8, 0x54, 0x71, 0x0F, 0xBE, 0xB8, 0x8B, 0x3B, 0x69, 0xEF, 0xED, 0xCE, 0xDF,
0x30, 0x58, 0x7A, 0xBC, 0x9E, 0x0E, 0xD0, 0x38, 0xEE, 0x8F, 0xF7, 0xD2, 0x82, 0xB5, 0xC4, 0x58,
0x8D, 0xF1, 0xF9, 0xBE, 0xD5, 0xED, 0x7E, 0x9F, 0x73, 0x44, 0xDF, 0xCE, 0x98, 0xAF, 0x59, 0x6A,
0xDC, 0x2E, 0x6E, 0x26, 0x6D, 0x3F, 0x5D, 0x46, 0x93, 0xC7, 0x65, 0x48, 0xE5, 0x43, 0x15, 0x5C,
0xF3, 0x13, 0xC8, 0x25, 0xDC, 0xDD, 0x8A, 0x7C, 0x99, 0x82, 0xF8, 0xC1, 0xB2, 0xA8, 0x14, 0xD3,
0x01, 0xC8, 0x14, 0xC2, 0x3E, 0xCB, 0xE1, 0x32, 0x93, 0x01, 0xEE, 0x91, 0x24, 0x5C, 0xB1, 0xB7,
0x3D, 0xD6, 0xEF, 0x8E, 0x3D, 0x84, 0x2E, 0xCD, 0xAF, 0x0D, 0xD6, 0xEE, 0x49, 0xFF, 0x45, 0xE0,
0x5F, 0x34, 0xF2, 0xF2, 0x8B, 0xCD, 0xC5, 0x50, 0x81, 0xA8, 0x2F, 0xAF, 0x22, 0x3C, 0x91, 0xCE,
0x1E, 0x38, 0x95, 0xBD, 0xB2, 0xD1, 0xF8, 0x5A, 0xCA, 0x33, 0x34, 0xE9, 0xED, 0x11, 0xAF, 0x67,
0xF8, 0x96, 0x2C, 0x76, 0x2E, 0x93, 0xCF, 0xB9, 0x73, 0x09, 0xC5, 0xF1, 0xD0, 0xBE, 0x16, 0x1B,
0x2A, 0x5B, 0xE4, 0xC0, 0x53, 0x0C, 0xF9, 0x23, 0xF3, 0x78, 0x47, 0xC0, 0x59, 0x94, 0xE3, 0xC4,
0x18, 0xDA, 0x36, 0x46, 0x46, 0x4F, 0xC0, 0x84, 0x28, 0x51, 0x90, 0x42, 0x0E, 0x76, 0x85, 0x35,
0x6D, 0x3A, 0x4A, 0x6F, 0x18, 0xE3, 0x33, 0x7B, 0x23, 0xAC, 0xDD, 0xDB, 0xED, 0xAD, 0x02, 0x5B,
0x62, 0x1F, 0x23, 0xBC, 0x7E, 0xA5, 0x1F, 0xA1, 0xC7, 0x11, 0xFA, 0x24, 0xC2, 0x57, 0x0E, 0x8E,
0x70, 0xC2, 0xE8, 0x1A, 0xCE, 0xA4, 0xCE, 0x6E, 0x76, 0xEE, 0xEC, 0x60, 0x6E, 0xF6, 0x9B, 0x95,
0xF3, 0x7E, 0x88, 0xDB, 0x60, 0x94, 0x50, 0x97, 0x6F, 0xF6, 0xBA, 0x4E, 0x76, 0xDC, 0x6F, 0xF2,
0x1D, 0xEB, 0x16, 0xD9, 0x96, 0x43, 0x93, 0xC6, 0x8C, 0xE9, 0x27, 0x9D, 0x9A, 0x85, 0x46, 0x98,
0x50, 0xA4, 0xE9, 0x4D, 0xCD, 0x73, 0x4E, 0x55, 0xFE, 0x3C, 0xC1, 0x5A, 0xB7, 0x49, 0xE7, 0x99,
0x9C, 0x0C, 0x25, 0x68, 0x6E, 0xDB, 0x50, 0x58, 0xB3, 0x21, 0x71, 0x1A, 0xB7, 0x3C, 0xB2, 0x9F,
0x69, 0x1F, 0xCC, 0x15, 0xF4, 0x27, 0x6C, 0x38, 0x81, 0x0B, 0xA6, 0xD0, 0x1A, 0xCB, 0x59, 0xBF,
0xD7, 0x0E, 0x8A, 0xBD, 0xC3, 0x35, 0x9F, 0x9E, 0x84, 0xCE, 0x7C, 0xFC, 0x1E, 0x66, 0x71, 0xED,
0x0D, 0x58, 0x39, 0x83, 0xFE, 0x79, 0xC8, 0x55, 0xDF, 0xAF, 0xDF, 0x52, 0x62, 0xBC, 0x26, 0x7D,
0x14, 0x01, 0x07, 0x29, 0x4B, 0x2C, 0x53, 0xC4, 0xF1, 0x0A, 0x22, 0x4B, 0x97, 0x21, 0x48, 0xFB,
0x40, 0xEB, 0x7E, 0x18, 0x48, 0xFC, 0x51, 0xC5, 0x62, 0x26, 0xF3, 0xE8, 0x8D, 0x57, 0x5E, 0x8A,
0x06, 0x78, 0x4E, 0xD8, 0xD3, 0x03, 0xAE, 0xD1, 0x7D, 0xC7, 0x4F, 0xEE, 0x3E, 0x1F, 0xBA, 0x8F,
0x0F, 0x77, 0xAF, 0x24, 0x64, 0x7B, 0xD1, 0x3D, 0xEC, 0x74, 0x89, 0x25, 0x53, 0x2D, 0xC7, 0x90,
0x0E, 0xF5, 0x05, 0xAB, 0x8B, 0xA8, 0x5A, 0xF9, 0xED, 0x31, 0x3A, 0xB3, 0x61, 0x58, 0xDE, 0xDE,
0xB0, 0x5E, 0xC9, 0x26, 0x7D, 0x0C, 0x38, 0xE4, 0x2B, 0x59, 0x83, 0xE0, 0x97, 0x5F, 0x02, 0x61,
0x2C, 0x24, 0x7C, 0x59, 0x6F, 0xA7, 0xE2, 0x95, 0xBC, 0xFF, 0xD3, 0xCB, 0x42, 0x45, 0x1E, 0xB4,
0x12, 0x1D, 0xA1, 0x9A, 0xDC, 0xDC, 0x53, 0x0F, 0xAA, 0xBB, 0xFC, 0x72, 0x6C, 0x26, 0x47, 0x7E,
0xA6, 0xB6, 0xA9, 0x81, 0xBA, 0x55, 0xD0, 0x81, 0x34, 0x73, 0xCB, 0x38, 0x86, 0x87, 0x25, 0xE0,
0x41, 0xE9, 0x35, 0xD1, 0xE1, 0x3D, 0x4F, 0x60, 0x97, 0x51, 0xC8, 0x6A, 0x57, 0x5B, 0x91, 0x53,
0xA2, 0x6C, 0x03, 0x1F, 0xBC, 0xCB, 0x24, 0xB2, 0x56, 0x1D, 0x52, 0xD1, 0x63, 0x5B, 0x0B, 0x79,
0xE0, 0x76, 0xB7, 0xC5, 0x6E, 0x94, 0xD1, 0x4E, 0x30, 0x97, 0x20, 0x0F, 0x73, 0x68, 0x5E, 0xF6,
0x44, 0x09, 0x33, 0x00, 0xCC, 0x79, 0xE4, 0xA0, 0x4C, 0x86, 0x69, 0x98, 0x2F, 0xE4, 0x44, 0x07,
0x06, 0x63, 0x55, 0xF1, 0xDC, 0xCD, 0x27, 0x4B, 0x73, 0xB7, 0x92, 0x92, 0xD5, 0x45, 0x27, 0xFC,
0xE7, 0x73, 0xAA, 0x3D, 0xA6, 0xFE, 0xAD, 0x19, 0xCD, 0x89, 0x8E, 0xCC, 0xF7, 0x5F, 0xC8, 0xC5,
0x3B, 0x07, 0xD6, 0xEB, 0x32, 0x52, 0x43, 0xA0, 0xC1, 0xEE, 0x02, 0x66, 0xC1, 0xE3, 0xD6, 0x06,
0xA5, 0x4B, 0x82, 0xBF, 0x98, 0x4B, 0x58, 0x85, 0xC0, 0x3C, 0x2F, 0x7F, 0x18, 0x76, 0xC8, 0x9C,
0x1A, 0x24, 0x18, 0x7A, 0xF0, 0xBD, 0xD7, 0xE6, 0xFD, 0x2C, 0xA6, 0x96, 0x61, 0xAA, 0xB5, 0x20,
0xB8, 0x60, 0x02, 0xDC, 0x36, 0xE0, 0x3E, 0x84, 0x5D, 0x85, 0x1F, 0x48, 0x0B, 0x02, 0x38, 0x1E,
0xD4, 0x2B, 0xC0, 0x28, 0x27, 0xE8, 0x0F, 0xA3, 0x05, 0x5D, 0x11, 0x70, 0xA2, 0x95, 0xDA, 0x07,
0x53, 0x00, 0xCB, 0x4D, 0xFC, 0x0B, 0xA9, 0xF3, 0x6E, 0xCE, 0xFC, 0x7C, 0xBC, 0x01, 0x3E, 0x85,
0x01, 0xB8, 0x05, 0x8C, 0x67, 0x02, 0x56, 0x53, 0xE9, 0xA6, 0xB4, 0x22, 0x47, 0x43, 0x7C, 0xF7,
0xE7, 0x5C, 0x56, 0xAD, 0x7D, 0x0A, 0x17, 0x05, 0x75, 0xAC, 0x99, 0x5D, 0x14, 0x05, 0x68, 0xD5,
0xD3, 0x79, 0x9C, 0x60, 0xE5, 0x93, 0x4F, 0xEE, 0x46, 0xE3, 0x23, 0x22, 0x20, 0x8C, 0x79, 0x10,
0x36, 0x83, 0x06, 0xFC, 0x0B, 0x98, 0x96, 0xD1, 0xBA, 0xA7, 0x01, 0xF7, 0xAA, 0xA1, 0x56, 0xE3,
0x2C, 0x59, 0xAB, 0xF4, 0x7B, 0x8B, 0xCD, 0x5D, 0xEE, 0x2D, 0x2A, 0xD7, 0x25, 0x0A, 0x9F, 0x61,
0xE5, 0xE3, 0xBD, 0x2D, 0x75, 0xF2, 0x72, 0xB4, 0xA7, 0x54, 0x6E, 0xDF, 0x4C, 0x77, 0x06, 0xCC,
0x52, 0xDA, 0x58, 0x4D, 0xDA, 0xBB, 0x27, 0xEA, 0x5E, 0x6E, 0x2A, 0x36, 0x46, 0xF7, 0xEF, 0x0F,
0x86, 0x85, 0xD6, 0x82, 0x56, 0x53, 0xA3, 0x5F, 0x4C, 0x91, 0xD6, 0x9D, 0xB2, 0x62, 0x9F, 0x6D,
0xE4, 0xFD, 0xCE, 0xEA, 0xED, 0xB2, 0x5F, 0xF7, 0xAC, 0xB6, 0x66, 0x0F, 0x80, 0xED, 0x62, 0xF0,
0x2D, 0x5F, 0x65, 0x8E, 0xEE, 0xB3, 0x6C, 0xD8, 0x51, 0xD7, 0xA9, 0x08, 0x27, 0xFB, 0xB4, 0xC5,
0x7D, 0x12, 0xD0, 0x46, 0x72, 0xC8, 0xD7, 0x6F, 0xC8, 0x71, 0xA0, 0xFE, 0xDF, 0x2F, 0x40, 0x9E,
0xAD, 0x77, 0x52, 0x7F, 0x24, 0xDE, 0xD3, 0xF2, 0x6C, 0x25, 0x27, 0xC7, 0xCE, 0x95, 0x42, 0xAA,
0xAD, 0xE3, 0x7E, 0xE2, 0x5C, 0xAA, 0x9E, 0x1D, 0x8B, 0xEF, 0xBC, 0x05, 0x6E, 0x3F, 0xF2, 0xFE,
0x0A, 0xB4, 0xAB, 0x0A, 0x36, 0xBD, 0x94, 0x85, 0x75, 0x21, 0x68, 0xCA, 0x0E, 0x26, 0x7F, 0x5E,
0x2A, 0xAB, 0xF2, 0x66, 0x56, 0x12, 0x34, 0x00, 0x22, 0x5B, 0x1D, 0xF7, 0x40, 0xF5, 0x35, 0x86,
0x53, 0xB9, 0x68, 0x2E, 0x9A, 0xE5, 0xD3, 0xDC, 0xF5, 0xBE, 0xD4, 0xA1, 0x67, 0xBF, 0x72, 0x76,
0xE4, 0x66, 0xFA, 0xE7, 0x25, 0xB7, 0xBD, 0xE5, 0xA3, 0xE2, 0xAD, 0xD2, 0x0F, 0x4E, 0x46, 0x52,
0x5D, 0x3F, 0x57, 0x72, 0xDF, 0x5B, 0xAA, 0x08, 0x4C, 0xD8, 0xCE, 0x23, 0x1B, 0x1A, 0xD7, 0x70,
0x37, 0xAF, 0x38, 0x98, 0x4C, 0x78, 0x66, 0x00, 0x5C, 0xB2, 0x9B, 0x63, 0xF3, 0x3B, 0xD4, 0xC5,
0x1F, 0x38, 0x58, 0xEA, 0x9E, 0x80, 0x2C, 0x4E, 0x73, 0x2C, 0x60, 0xF9, 0xB4, 0x55, 0xCD, 0x1E,
0x1F, 0x44, 0x4B, 0x65, 0x5E, 0x4A, 0x6B, 0x49, 0x0D, 0x9C, 0x5F, 0x32, 0xF2, 0xE4, 0xD2, 0x56,
0xB5, 0x02, 0x25, 0x58, 0x0E, 0x62, 0x25, 0x4B, 0x91, 0x10, 0x32, 0x17, 0xD6, 0xB6, 0x69, 0xC1,
0xBC, 0x9F, 0xE8, 0xD6, 0x0E, 0xC8, 0x64, 0x41, 0x27, 0x7A, 0x51, 0x26, 0x7F, 0x6D, 0x0A, 0x98,
0xF1, 0x49, 0xA7, 0xE0, 0xE3, 0x10, 0x60, 0x7C, 0x2C, 0x26, 0xE9, 0xC1, 0x79, 0x85, 0x65, 0x34,
0xB2, 0xEE, 0x15, 0xC1, 0x5E, 0xFE, 0x6F, 0xC9, 0x94, 0xBE, 0x69, 0x58, 0xFC, 0x02, 0x94, 0x68,
0xBD, 0x2A, 0x30, 0xD9, 0xA5, 0x0E, 0xA1, 0xB9, 0x3E, 0x9E, 0xD1, 0xC2, 0x2C, 0xF8, 0xBC, 0xC6,
0xC1, 0x9F, 0xF3, 0x94, 0x26, 0x65, 0x1A, 0x53, 0x22, 0xD7, 0x48, 0x49, 0x69, 0x83, 0x67, 0x59,
0x25, 0x94, 0xD3, 0x6C, 0x18, 0x0C, 0x3C, 0xCB, 0xAD, 0x2D, 0x44, 0x64, 0xC0, 0x13, 0xC3, 0xF8,
0xA2, 0x63, 0xA0, 0x37, 0x05, 0x00, 0x69, 0xE5, 0x1C, 0x10, 0xB5, 0x94, 0xF0, 0x17, 0x94, 0x6A,
0x75, 0xDC, 0x49, 0x01, 0xF6, 0x16, 0x73, 0x3C, 0x7B, 0x3F, 0xF0, 0xF2, 0x99, 0x49, 0xD6, 0x71,
0x19, 0xA0, 0x34, 0xD1, 0x1C, 0x22, 0x6B, 0x5B, 0x4C, 0x0B, 0x35, 0x23, 0x2B, 0x6A, 0x5D, 0x0E,
0xF3, 0xDD, 0x8E, 0x71, 0x5B, 0xA6, 0x6E, 0x83, 0x95, 0xD0, 0x62, 0x5D, 0x4B, 0x81, 0xC4, 0x58,
0x4D, 0x28, 0xDB, 0xA6, 0x3E, 0xF5, 0xA1, 0xA4, 0xE6, 0x14, 0x35, 0x18, 0xF0, 0x8F, 0x15, 0xF4,
0xB9, 0x07, 0xA5, 0x50, 0xC8, 0xC8, 0x9A, 0xE6, 0x4E, 0xA7, 0xAC, 0x75, 0xC5, 0x0F, 0xE8, 0x7A,
0x15, 0xAB, 0x64, 0x0F, 0x4F, 0x34, 0x88, 0xCE, 0xE7, 0x59, 0x83, 0xC1, 0x83, 0x44, 0xE0, 0xD7,
0xB4, 0xA6, 0x5D, 0x77, 0xE6, 0xEE, 0xFB, 0x79, 0x98, 0xC6, 0x0F, 0xDA, 0x0C, 0x4F, 0xC2, 0x57,
0xCD, 0x92, 0x31, 0x57, 0xBF, 0x33, 0x83, 0xC6, 0x4F, 0xF9, 0x34, 0x03, 0x77, 0xAA, 0x5A, 0x38,
0xE0, 0xDF, 0x35, 0xD7, 0x4D, 0x17, 0xD4, 0xAE, 0x49, 0x6C, 0x30, 0x72, 0x1F, 0x41, 0x62, 0x80,
0x11, 0x2E, 0x77, 0xFB, 0xA5, 0xFA, 0xC6, 0x1C, 0xD3, 0x44, 0x31, 0x9F, 0x74, 0xB1, 0xF2, 0x83,
0x41, 0x07, 0xD1, 0xDE, 0x34, 0x87, 0x03, 0x2D, 0x3B, 0xE9, 0x9F, 0xA1, 0xD9, 0x5C, 0x31, 0xE6,
0x67, 0x0C, 0xD2, 0x02, 0xA9, 0xB7, 0xDD, 0x12, 0x07, 0x0B, 0xFD, 0x39, 0xBA, 0xF7, 0xD9, 0xBD,
0xF2, 0xEA, 0x91, 0xBD, 0x4F, 0x3E, 0x0D, 0xA2, 0x15, 0x54, 0x5E, 0xE9, 0x36, 0x23, 0x44, 0x82,
0x89, 0xD2, 0x14, 0x06, 0xDF, 0x0C, 0x60, 0x22, 0x6E, 0x97, 0xE2, 0xF5, 0x0E, 0x74, 0x6B, 0x1D,
0x80, 0xD2, 0x8A, 0xF3, 0x5E, 0x2D, 0x01, 0xE8, 0x5A, 0xCD, 0x52, 0x69, 0xEE, 0x5F, 0xB8, 0x1D,
0x74, 0xF6, 0xC9, 0x64, 0x22, 0x43, 0x2C, 0xD9, 0x07, 0x8C, 0x8D, 0xDC, 0xAC, 0x9C, 0xB7, 0x8B,
0xD8, 0x67, 0x49, 0x32, 0x34, 0x65, 0x4B, 0xFC, 0x2B, 0x50, 0x73, 0xEF, 0xE0, 0xCE, 0x02, 0x13,
0x7F, 0xCC, 0xB9, 0xEF, 0xC8, 0xE4, 0x02, 0xC6, 0xF4, 0x47, 0x3D, 0xB5, 0xA1, 0x66, 0x93, 0xBB,
0x5E, 0xD3, 0x34, 0xB3, 0x99, 0x63, 0xCA, 0xD7, 0x11, 0x53, 0x81, 0x0D, 0x45, 0x61, 0x82, 0xC5,
0x4A, 0x42, 0xE6, 0xD9, 0x95, 0x38, 0x9D, 0x74, 0xD2, 0x26, 0xB4, 0x8B, 0x7D, 0x05, 0x99, 0x94,
0x81, 0xA9, 0x6B, 0x57, 0xD3, 0x20, 0x9C, 0x66, 0x3F, 0x96, 0xD4, 0xCF, 0x64, 0xBC, 0xED, 0x70,
0x83, 0x7A, 0x42, 0xC1, 0x6C, 0xE9, 0x28, 0x62, 0xAD, 0x3E, 0xF4, 0xFA, 0x47, 0x59, 0x6E, 0xF9,
0xC1, 0xF4, 0x40, 0x47, 0xFA, 0x7C, 0x6E, 0x00, 0x36, 0xEA, 0x6A, 0x89, 0x03, 0x0C, 0xC9, 0x2E,
0x22, 0xEA, 0xFF, 0x48, 0x53, 0x5A, 0xCE, 0x85, 0x52, 0x43, 0x38, 0xE5, 0x39, 0xEB, 0xD9, 0x06,
0x25, 0xC6, 0x84, 0x21, 0x8B, 0x57, 0x23, 0x7A, 0x71, 0x98, 0x0F, 0x06, 0x12, 0x41, 0x2E, 0xBE,
0x16, 0xB2, 0x79, 0x40, 0x5B, 0xBB, 0xF1, 0x98, 0xEB, 0x8B, 0x5F, 0xA0, 0x92, 0x83, 0xF6, 0x7A,
0x8F, 0x2F, 0xB2, 0x61, 0xDE, 0xE3, 0xC5, 0xD1, 0x71, 0x04, 0x8E, 0xC9, 0x57, 0x83, 0x4B, 0x19,
0x9C, 0x39, 0xB8, 0x49, 0x22, 0xCF, 0x46, 0x5F, 0x41, 0xE7, 0xD1, 0x97, 0x11, 0x8A, 0xAD, 0x7F,
0x8F, 0x5A, 0xCA, 0xE4, 0x2A, 0x53, 0x62, 0x75, 0xC4, 0x47, 0x67, 0x22, 0xA6, 0x73, 0x23, 0x3F,
0xF7, 0xF3, 0x09, 0xFE, 0x3B, 0x06, 0x03, 0x48, 0xB7, 0xC8, 0x7C, 0xB6, 0x0E, 0x4A, 0x5E, 0x2B,
0x5F, 0x81, 0x64, 0x13, 0x5F, 0xBC, 0x2B, 0x0C, 0x6D, 0xA8, 0x57, 0x53, 0x66, 0xD4, 0x7C, 0x53,
0x68, 0x5C, 0x18, 0x40, 0x0D, 0x7E, 0xAE, 0x82, 0x5F, 0xED, 0x64, 0x27, 0x60, 0x25, 0x5D, 0x23,
0x27, 0x3D, 0x69, 0x22, 0xBB, 0xD8, 0xDC, 0x6F, 0x87, 0x25, 0x71, 0x67, 0x20, 0x47, 0x98, 0xF3,
0x58, 0xB8, 0x9D, 0x55, 0x32, 0x63, 0xEB, 0xFF, 0x10, 0xD1, 0x20, 0xEB, 0x01, 0x12, 0xD6, 0xF1,
0xE8, 0x5E, 0xC0, 0x7B, 0x85, 0x53, 0xBE, 0xE6, 0x14, 0xF7, 0xF1, 0x09, 0x8E, 0x82, 0x91, 0x35,
0xA9, 0x80, 0x95, 0xF5, 0x81, 0xCE, 0x00, 0x38, 0x7F, 0x22, 0xEE, 0x4F, 0x4A, 0x0F, 0xEA, 0x5B,
0x42, 0x3A, 0xD0, 0x76, 0xF0, 0xDE, 0xF9, 0x48, 0xEA, 0x33, 0x4E, 0xF9, 0x80, 0xA7, 0xF9, 0xAC,
0x55, 0xB1, 0x66, 0xD0, 0xAF, 0x42, 0xBE, 0x5B, 0x2B, 0xF7, 0x5D, 0x5B, 0xE4, 0x0C, 0xC6, 0x8F,
0xC8, 0x74, 0xD5, 0xAE, 0x63, 0xEE, 0x83, 0x8B, 0x86, 0x20, 0x2C, 0x74, 0x38, 0x2A, 0xCA, 0x2F,
0xA6, 0x2E, 0x9E, 0x4B, 0xDF, 0xD3, 0xDC, 0xDF, 0x7E, 0xBB, 0xD6, 0x7B, 0x9E, 0x36, 0x7D, 0x45,
0x79, 0x6F, 0xF9, 0x45, 0x97, 0xD5, 0x5B, 0xE5, 0x29, 0x61, 0xD2, 0xCD, 0x2A, 0x4F, 0xEE, 0x8F,
0xBA, 0xC4, 0xA8, 0xF3, 0xBB, 0x1D, 0xB5, 0x8F, 0x51, 0x03, 0x38, 0xA8, 0x52, 0x34, 0xA2, 0x5B,
0x4C, 0xC8, 0xCA, 0x76, 0xF5, 0x09, 0x15, 0xAF, 0xB4, 0x5B, 0xB7, 0x90, 0x00, 0x58, 0x6B, 0xFF,
0x86, 0x09, 0x7A, 0xE6, 0xAD, 0xBA, 0x61, 0x7F, 0x91, 0x10, 0x15, 0xD2, 0x29, 0x30, 0x7D, 0xFF,
0x33, 0xE6, 0xA7, 0xE7, 0xDC, 0xFD, 0x80, 0x75, 0x08, 0x43, 0x6C, 0xD6, 0x66, 0x3A, 0xE9, 0x59,
0x16, 0x8E, 0x9E, 0x77, 0x0F, 0xA8, 0xEE, 0x32, 0x2B, 0x35, 0xEB, 0x30, 0x99, 0x04, 0xE2, 0x7E,
0x98, 0xB3, 0x72, 0x3D, 0x6C, 0x18, 0x65, 0x72, 0x43, 0xF6, 0x46, 0x2D, 0x6B, 0x71, 0xB2, 0xCE,
0xD8, 0x2A, 0xFC, 0xFF, 0xD9, 0xCB, 0xBD, 0x6B, 0x99, 0xF8, 0xA0, 0x31, 0x96, 0xCA, 0x44, 0x33,
0x32, 0x66, 0xAF, 0xCD, 0xCF, 0x21, 0x13, 0x51, 0x99, 0xA4, 0xB2, 0x37, 0xB3, 0x5B, 0x65, 0xC2,
0x61, 0x71, 0x78, 0x5B, 0x87, 0x71, 0x18, 0x78, 0xC0, 0x1D, 0xA9, 0x31, 0x66, 0x5D, 0x49, 0x70,
0x2E, 0x57, 0xEA, 0xBC, 0xD6, 0xA3, 0xA0, 0x29, 0xB5, 0x6C, 0x43, 0x23, 0x13, 0x98, 0x9D, 0x7B,
0x25, 0x91, 0x28, 0xC6, 0xC8, 0x10, 0xC7, 0x3C, 0x46, 0x07, 0x3B, 0x21, 0x0E, 0x7B, 0x49, 0xE4,
0xA7, 0xA7, 0xBC, 0xFD, 0xA8, 0x8A, 0xF8, 0x66, 0xAA, 0x33, 0x8B, 0x7A, 0x22, 0xC7, 0x74, 0xCE,
0xA2, 0x9E, 0xE8, 0x1B, 0x32, 0x3D, 0xBF, 0xA8, 0x27, 0x62, 0xF9, 0x8F, 0x38, 0xA6, 0x39, 0x2C,
0x2B, 0x80, 0x50, 0xDC, 0xAD, 0xEC, 0x5A, 0x59, 0xB2, 0xCD, 0x5D, 0x20, 0x0C, 0x97, 0x35, 0x19,
0x58, 0x41, 0xE6, 0xD6, 0x0A, 0xA6, 0xFF, 0x19, 0x28, 0xD6, 0x34, 0x97, 0xFF, 0x1A, 0x72, 0x59,
0xDC, 0xCB, 0xEB, 0xF3, 0x24, 0xC0, 0x93, 0x53, 0x8C, 0xF6, 0xCC, 0x10, 0x45, 0xD9, 0x9A, 0x2A,
0xDE, 0x7B, 0x46, 0xF5, 0x9E, 0x15, 0xE0, 0xDD, 0x91, 0x05, 0x31, 0xEC, 0x2D, 0x7C, 0xE3, 0xCD,
0x65, 0x99, 0xD4, 0x9A, 0xD1, 0xA0, 0x68, 0x3E, 0x9D, 0x18, 0xC6, 0xC4, 0x20, 0x6F, 0x64, 0x60,
0x28, 0x0D, 0xC6, 0x69, 0x5F, 0xCF, 0xFB, 0x3A, 0xBA, 0x3E, 0xC7, 0xED, 0x0F, 0x7B, 0xF8, 0xF2,
0x36, 0x2B, 0x2F, 0x78, 0xDA, 0xD7, 0x08, 0x00, 0xA0, 0x4B, 0x0F, 0x71, 0xD2, 0x5B, 0xF4, 0x61,
0x9B, 0xCB, 0xE6, 0xCA, 0xDC, 0x9A, 0xB3, 0xCA, 0x0A, 0x76, 0x09, 0xD7, 0xBF, 0xA5, 0x4F, 0xC6,
0xB0, 0xE1, 0x6A, 0x53, 0xEC, 0x9F, 0xE7, 0xE2, 0xFE, 0x7B, 0x5F, 0xC8, 0x11, 0xF6, 0xAB, 0x67,
0x0D, 0x9B, 0xFD, 0x5B, 0x62, 0xA3, 0x71, 0xBF, 0xED, 0xBF, 0x10, 0x79, 0xE4, 0x4B, 0x38, 0xFF,
0x78, 0x05, 0xE6, 0xB6, 0x83, 0x60, 0x31, 0x4E, 0xC0, 0x26, 0xD3, 0x43, 0x4B, 0x31, 0xFF, 0xE4,
0xA5, 0x48, 0x86, 0xA5, 0xF8, 0xCF, 0x4F, 0x5D, 0x0A, 0xFD, 0x39, 0x8E, 0x29, 0x84, 0x70, 0x2F,
0x63, 0xE0, 0xF6, 0x26, 0x7C, 0xFD, 0x4B, 0xCF, 0xC8, 0xC1, 0xB5, 0x09, 0x4B, 0x8F, 0xCF, 0x0F,
0x63, 0x4E, 0x6E, 0xCE, 0xC5, 0x61, 0x18, 0x6D, 0x55, 0xA7, 0xFB, 0xAA, 0x87, 0x55, 0xB4, 0xC6,
0xED, 0xB4, 0xB0, 0xEA, 0xE5, 0xE2, 0xE7, 0x8B, 0xFA, 0x05, 0xA5, 0x0D, 0x1F, 0x1F, 0x28, 0x4F,
0x91, 0x2D, 0xDC, 0x13, 0xE3, 0x82, 0x83, 0x88, 0x1A, 0x1B, 0xDF, 0xBC, 0x0E, 0xCE, 0x96, 0xDE,
0x12, 0xFA, 0xE8, 0x09, 0xC2, 0x2A, 0x1F, 0xEB, 0x8C, 0x0D, 0xFD, 0xD3, 0xB5, 0xA3, 0xA1, 0x0F,
0x49, 0x17, 0x60, 0x94, 0x3A, 0x4B, 0xCE, 0x11, 0x79, 0xB9, 0x9D, 0x9F, 0xDF, 0x93, 0x93, 0x67,
0xB2, 0x62, 0x92, 0x0E, 0x71, 0x0F, 0xFF, 0x31, 0x29, 0xA1, 0x15, 0xF1, 0xB2, 0xF4, 0xE3, 0x3E,
0xEE, 0xA1, 0xA3, 0x9D, 0x5C, 0xC4, 0xFD, 0x7B, 0x4F, 0xC7, 0xB9, 0xC3, 0xD3, 0x71, 0x18, 0xD0,
0x03, 0x77, 0xF9, 0x74, 0x1C, 0x39, 0xB4, 0x2F, 0x7B, 0xE9, 0x99, 0x67, 0xE4, 0x70, 0xE9, 0xF5,
0xED, 0xAA, 0xC8, 0x48, 0x1D, 0x13, 0x0A, 0xCA, 0xD3, 0x74, 0xA0, 0xAB, 0xB5, 0x00, 0xBD, 0xDA,
0x2A, 0x09, 0x3A, 0xA2, 0xC1, 0xAE, 0xE1, 0xB6, 0x0D, 0x1C, 0xA5, 0x9D, 0xA5, 0xB7, 0xAF, 0xF5,
0xEF, 0x0F, 0x59, 0xB3, 0x42, 0x52, 0xAA, 0xF9, 0xC8, 0x42, 0x4B, 0xDE, 0xF7, 0x6B, 0xFD, 0xB5,
0xEC, 0x9F, 0x85, 0x1C, 0x91, 0x35, 0xD7, 0x72, 0xEE, 0xC7, 0xB2, 0xF7, 0xB5, 0x42, 0x42, 0x4E,
0x51, 0xBD, 0x1A, 0x8A, 0x23, 0x3F, 0x7F, 0xF0, 0x31, 0xD5, 0xC2, 0x31, 0x6F, 0xC3, 0x67, 0xCD,
0xF6, 0x2B, 0x1C, 0x35, 0xA1, 0xDB, 0xBD, 0xCC, 0xAE, 0x3A, 0x9E, 0xDA, 0x5E, 0x54, 0x38, 0x3A,
0xEF, 0xF5, 0x45, 0x8F, 0x13, 0xD3, 0x4C, 0x40, 0xA9, 0xCF, 0xFD, 0x36, 0x15, 0x07, 0x1F, 0xF4,
0xA9, 0xA0, 0x7E, 0x6F, 0xDA, 0xD7, 0xD0, 0x2A, 0x4E, 0x16, 0x15, 0x08, 0xDE, 0xB9, 0xF2, 0xC4,
0xED, 0x2A, 0x10, 0x6A, 0xAD, 0x8A, 0x1C, 0xF1, 0xB6, 0x73, 0xEA, 0x61, 0x59, 0xBE, 0xF3, 0x98,
0x79, 0x97, 0x5B, 0xA8, 0x00, 0xE9, 0x55, 0xB2, 0xBC, 0x44, 0xB7, 0xB7, 0x3E, 0x31, 0xD5, 0x3E,
0xDF, 0x4B, 0xB5, 0x43, 0xC7, 0x65, 0xC7, 0xEE, 0x12, 0xA7, 0xCA, 0x5A, 0x92, 0xAE, 0x61, 0xC3,
0x22, 0xE9, 0x03, 0xA9, 0x80, 0x00, 0x90, 0x25, 0x2C, 0xAA, 0xCD, 0xD2, 0x95, 0x94, 0x4F, 0x5F,
0x8E, 0x31, 0x16, 0x9A, 0x01, 0x2B, 0x9C, 0xD0, 0xA8, 0xCB, 0x54, 0x7B, 0xAB, 0x45, 0x75, 0x63,
0xAB, 0xE1, 0x83, 0x0D, 0x59, 0xAD, 0xFC, 0xBD, 0xD8, 0xDB, 0x8D, 0xB1, 0x49, 0xB4, 0x12, 0xC2,
0x0B, 0x42, 0x3F, 0xB8, 0x89, 0x46, 0x76, 0x12, 0xBF, 0x50, 0x82, 0x0C, 0x89, 0x04, 0x97, 0xA8,
0x9B, 0x4F, 0x26, 0x1A, 0x5A, 0xC9, 0x1F, 0x64, 0x57, 0xD5, 0x7F, 0x08, 0x1F, 0x13, 0xC7, 0x20,
0x59, 0xCD, 0x58, 0xB4, 0xFD, 0x83, 0x75, 0x36, 0xB9, 0x2A, 0xE8, 0x65, 0xBD, 0xD4, 0x25, 0xC1,
0x2C, 0x36, 0x00, 0xD6, 0x70, 0xDE, 0xEF, 0x01, 0x04, 0xC9, 0x96, 0x84, 0xFB, 0xA5, 0xC1, 0xDC,
0xF3, 0xE3, 0xE6, 0x09, 0x82, 0x54, 0x1B, 0x4B, 0x82, 0x88, 0xD2, 0x9E, 0xF5, 0xA5, 0xC1, 0xFF,
0x07, 0x9D, 0x54, 0xBF, 0x6F, 0x1B, 0x37, 0x14, 0xFE, 0xEE, 0x18, 0x97, 0x40, 0x29, 0x99, 0x19,
0x32, 0xDA, 0xBD, 0x0C, 0x1D, 0x3C, 0x28, 0x96, 0x06, 0x01, 0xD5, 0xA0, 0x1F, 0xD7, 0x08, 0xA8,
0x87, 0x14, 0x48, 0x86, 0x02, 0x5D, 0xBA, 0x75, 0xE8, 0x58, 0x01, 0xF5, 0xE0, 0xE1, 0x2C, 0x5D,
0xAB, 0x21, 0x6B, 0x80, 0xFE, 0x01, 0xCD, 0x9E, 0x45, 0x43, 0x86, 0x2B, 0x70, 0xAA, 0x28, 0x0B,
0x68, 0x81, 0x2E, 0x39, 0xC5, 0x43, 0x86, 0x0E, 0x21, 0xD0, 0x21, 0x43, 0x87, 0x1C, 0x90, 0x43,
0x71, 0x01, 0x4E, 0x66, 0x1F, 0x4F, 0xB2, 0x63, 0x14, 0x6E, 0x93, 0x96, 0x3C, 0xF2, 0x3D, 0x3E,
0xBE, 0xF7, 0xBD, 0x77, 0x7C, 0x8F, 0x34, 0xC6, 0x98, 0x02, 0x7B, 0x5F, 0x4E, 0xA2, 0xD9, 0xF7,
0xD7, 0x55, 0xA3, 0xC2, 0xF0, 0xB7, 0xC9, 0x51, 0xA8, 0x81, 0x85, 0x68, 0x1A, 0xD3, 0x60, 0x15,
0xCE, 0x38, 0x14, 0x1A, 0xA8, 0x80, 0xE1, 0x1F, 0x19, 0x30, 0x7F, 0x9B, 0x8C, 0x06, 0xB0, 0x26,
0x55, 0xC6, 0xFA, 0xB4, 0xF5, 0x2F, 0x7D, 0xB6, 0x32, 0x2B, 0x3B, 0x8C, 0x6D, 0xA9, 0xB9, 0x4C,
0xAE, 0x5A, 0xE4, 0xDD, 0xFF, 0xDA, 0x37, 0x86, 0x14, 0xD7, 0x9A, 0x53, 0x0E, 0x1B, 0xCF, 0x09,
0x47, 0xCE, 0xB3, 0x2D, 0xB9, 0xCC, 0x3B, 0x92, 0x8F, 0x55, 0xF2, 0x86, 0xBB, 0x51, 0xBF, 0xBB,
0xD0, 0x91, 0x74, 0x93, 0x9A, 0x03, 0x5F, 0xB7, 0xDA, 0x92, 0x97, 0xCA, 0x63, 0x5D, 0xF4, 0xF8,
0x32, 0xDB, 0x72, 0xFA, 0xD9, 0xCA, 0xBB, 0xAF, 0xB3, 0x8E, 0x64, 0x73, 0x7D, 0xD4, 0x96, 0xCC,
0x4F, 0xAE, 0x92, 0xDD, 0xD8, 0x12, 0x4F, 0xB3, 0xA2, 0x47, 0x66, 0xD1, 0x3E, 0x53, 0xE9, 0x2D,
0xE1, 0x3F, 0xAC, 0xA1, 0x00, 0x4B, 0x21, 0x43, 0x74, 0x71, 0x2F, 0xFB, 0x9C, 0x22, 0xF9, 0xE1,
0x0F, 0xD5, 0x05, 0x72, 0x30, 0xBD, 0x96, 0x5E, 0x66, 0x4B, 0x5D, 0x11, 0x62, 0x1F, 0x9F, 0x3D,
0xFE, 0x8A, 0x74, 0x1F, 0x3D, 0x52, 0xFB, 0x40, 0x74, 0x21, 0x7D, 0xFD, 0xE3, 0xCC, 0x98, 0x3F,
0xEF, 0x7C, 0xE2, 0x9F, 0x4B, 0xA5, 0x42, 0xAF, 0x47, 0x8A, 0x3D, 0xDC, 0xC3, 0x0A, 0x26, 0x31,
0x39, 0x2D, 0x72, 0xA3, 0x56, 0xB4, 0x1E, 0x9A, 0xE9, 0x90, 0xBF, 0x4C, 0xCD, 0x54, 0x24, 0x43,
0x50, 0x37, 0xA0, 0x3E, 0x05, 0x75, 0xDA, 0xB9, 0x48, 0xF1, 0xF2, 0x7F, 0xA4, 0xF8, 0xE0, 0x5D,
0x52, 0xCC, 0x29, 0xB8, 0x8F, 0x1A, 0xA7, 0x3B, 0xFD, 0x6B, 0x0C, 0xEF, 0xD0, 0x77, 0xC0, 0xF7,
0xF0, 0x7E, 0x0B, 0xD5, 0xA6, 0x29, 0xBE, 0xC1, 0x2F, 0x95, 0xCA, 0xA0, 0xF1, 0x33, 0x39, 0x26,
0xEF, 0xE4, 0xB9, 0x81, 0xB7, 0xB0, 0x60, 0x9F, 0xE2, 0x77, 0x7F, 0x4F, 0xF3, 0x1A, 0x4E, 0xCD,
0xAB, 0x2F, 0x58, 0x75, 0xD0, 0x68, 0x2E, 0xAC, 0x06, 0x7B, 0xFB, 0x04, 0xB8, 0x34, 0xC0, 0x73,
0xF0, 0x90, 0x68, 0xDD, 0x40, 0xDA, 0xF5, 0xB1, 0x17, 0xEE, 0x5A, 0x1A, 0x4B, 0xD5, 0xB2, 0x34,
0x17, 0x6A, 0xB2, 0xA6, 0xF3, 0xC4, 0xD2, 0x42, 0x8E, 0xBF, 0x7B, 0x8D, 0xFA, 0x83, 0xA9, 0x77,
0x20, 0x8D, 0x6F, 0xB2, 0xDE, 0x59, 0xB5, 0x27, 0x17, 0x69, 0x21, 0xB2, 0x5A, 0x87, 0x9F, 0x26,
0xC7, 0xC0, 0x61, 0xC0, 0x5E, 0xD8, 0x5C, 0xEB, 0x98, 0xD9, 0x9C, 0xBB, 0x2A, 0x66, 0xBF, 0xA9,
0x0E, 0xB8, 0x1F, 0xF0, 0x67, 0xEA, 0x98, 0xBC, 0x74, 0xE5, 0x42, 0x17, 0xB8, 0x45, 0x2E, 0x5D,
0x2A, 0xD5, 0x23, 0x1B, 0xC2, 0x28, 0xC4, 0x4D, 0x6C, 0x5A, 0x12, 0x77, 0x3D, 0x79, 0xFF, 0x44,
0x95, 0x8B, 0x66, 0x55, 0x9C, 0x50, 0x49, 0x7A, 0x62, 0xA1, 0xB3, 0xC0, 0x13, 0xAE, 0xDA, 0x28,
0x55, 0xA9, 0xEE, 0xE2, 0x3A, 0x49, 0xED, 0x1E, 0x69, 0x74, 0xE4, 0xC1, 0x3C, 0x0D, 0x6A, 0xE7,
0x0A, 0x3B, 0xF2, 0x76, 0xDA, 0x11, 0x2A, 0xAD, 0x96, 0xBF, 0x88, 0x87, 0x99, 0x27, 0x54, 0xD6,
0x21, 0xC5, 0x8E, 0x74, 0x74, 0x53, 0x6C, 0x40, 0x06, 0x55, 0x57, 0xE5, 0x75, 0x96, 0xC4, 0x5E,
0x9F, 0x36, 0xE6, 0x59, 0x9D, 0xA9, 0x48, 0x7E, 0xAC, 0xDB, 0x2C, 0x9C, 0xEC, 0x6E, 0x54, 0x9C,
0x10, 0x9E, 0x72, 0x5E, 0xA8, 0x0F, 0xF8, 0x5C, 0x73, 0x05, 0x1D, 0x78, 0x77, 0x92, 0x42, 0x24,
0x1E, 0x02, 0xE8, 0x09, 0x4B, 0xA4, 0x3F, 0x64, 0xE9, 0xD0, 0xEB, 0x27, 0xE5, 0x19, 0x81, 0x4E,
0x6C, 0x7B, 0xDB, 0x55, 0x2D, 0xD6, 0xD7, 0xA9, 0xB3, 0x5C, 0x28, 0x1C, 0xD2, 0x99, 0xEE, 0xD6,
0x20, 0x78, 0x3A, 0x91, 0xE3, 0x24, 0xE7, 0x62, 0x32, 0xB0, 0x6B, 0x1C, 0x0A, 0x38, 0xCB, 0x13,
0xC5, 0x49, 0x8F, 0x62, 0x68, 0x59, 0x3B, 0x6B, 0x1F, 0xB0, 0x27, 0x2A, 0xC8, 0xC5, 0x93, 0x30,
0xBE, 0x62, 0x0A, 0x22, 0xFE, 0xAB, 0x5F, 0xE6, 0x04, 0x11, 0xE9, 0x4D, 0x23, 0xAE, 0x36, 0xD7,
0x7D, 0xF6, 0x7C, 0x05, 0x6C, 0x51, 0x35, 0x28, 0xB8, 0x94, 0x24, 0xBA, 0xFE, 0x8F, 0xCB, 0x58,
0xC8, 0x11, 0x1D, 0x00, 0x85, 0xC0, 0x7D, 0x5B, 0xF4, 0xF6, 0x6C, 0x34, 0x40, 0xA1, 0x1E, 0x01,
0x6D, 0x0A, 0xAC, 0xDC, 0x13, 0x3E, 0x40, 0x5F, 0x3D, 0xC1, 0x4F, 0xFE, 0xA8, 0x70, 0x8D, 0x1E,
0x51, 0x5A, 0xF2, 0xEB, 0x9E, 0xEF, 0x4F, 0x41, 0x7F, 0xBC, 0x6F, 0x51, 0xA5, 0x9D, 0x3C, 0x67,
0x16, 0xBE, 0xB7, 0x92, 0x67, 0xE8, 0xE5, 0x32, 0xC1, 0x88, 0x6E, 0x05, 0xF9, 0x28, 0xA7, 0x37,
0xAD, 0xBC, 0xAE, 0xF6, 0x76, 0xAE, 0x39, 0x94, 0x7E, 0x10, 0x10, 0x78, 0x3C, 0x2A, 0x68, 0x18,
0xC4, 0x84, 0x1C, 0x13, 0x70, 0x4C, 0x90, 0xE5, 0x20, 0xD4, 0x98, 0x40, 0x63, 0xC2, 0x0C, 0x08,
0xCD, 0x8E, 0xF6, 0x25, 0xB8, 0x36, 0xA1, 0x4D, 0x89, 0x06, 0x01, 0xEC, 0xCD, 0xA7, 0x17, 0xA3,
0x9E, 0x74, 0x1D, 0x7A, 0x1B, 0xB9, 0x79, 0xA5, 0xAF, 0xF1, 0xE7, 0x21, 0xF8, 0x19, 0x49, 0x73,
0xA0, 0xA7, 0xF1, 0xF5, 0xCB, 0x50, 0x9E, 0x75, 0x29, 0xB6, 0x1C, 0xDA, 0xD5, 0x2C, 0x3C, 0xC7,
0x89, 0xE8, 0xC4, 0x52, 0x96, 0x8A, 0x50, 0xAC, 0x45, 0x22, 0xC1, 0xB7, 0x26, 0x93, 0xF2, 0xB6,
0xC9, 0x3E, 0xC4, 0xCC, 0xBF, 0x08, 0x9F, 0x8A, 0xAA, 0xB9, 0x43, 0x55, 0x12, 0x77, 0xE8, 0x31,
0xCB, 0x03, 0x5B, 0x59, 0x51, 0x57, 0xF6, 0x93, 0x34, 0xF0, 0xF8, 0x89, 0x9E, 0xD4, 0x04, 0x5B,
0x97, 0xD7, 0x5F, 0xA5, 0x90, 0xB1, 0x69, 0xC4, 0x40, 0x14, 0x44, 0x47, 0x27, 0x90, 0x02, 0x61,
0x7E, 0x01, 0x07, 0xF7, 0x3B, 0x90, 0x1A, 0x58, 0x61, 0xD9, 0x0D, 0xB8, 0x9D, 0x0B, 0x64, 0x56,
0xE0, 0xA6, 0x1C, 0x1C, 0xDE, 0xCD, 0x1D, 0x9C, 0x3A, 0xF0, 0x06, 0x2A, 0xE0, 0x63, 0x6D, 0xB0,
0x18, 0x49, 0xDF, 0x72, 0xE6, 0xC8, 0x1C, 0x78, 0x06, 0x26, 0x7E, 0xF3, 0xCA, 0x74, 0x50, 0xE9,
0xAB, 0xF7, 0xC1, 0xC4, 0xFC, 0x8A, 0x9F, 0xE9, 0xFA, 0x0B, 0xBD, 0xA8, 0x54, 0x09, 0x7B, 0x32,
0xC1, 0x3D, 0x48, 0x0E, 0x1F, 0x38, 0x0B, 0x51, 0xEE, 0xC5, 0xEA, 0xA7, 0x2A, 0x08, 0x10, 0xD2,
0x5C, 0x87, 0x80, 0x67, 0xF0, 0x02, 0xF6, 0x10, 0x18, 0x58, 0xD6, 0x7C, 0x05, 0xDE, 0xB2, 0x94,
0x05, 0x7C, 0x0D, 0x6E, 0x69, 0xE9, 0x8A, 0x79, 0x34, 0x17, 0x26, 0xED, 0x1C, 0x74, 0x4F, 0x68,
0xBB, 0x57, 0x48, 0x3E, 0x96, 0xBE, 0xEA, 0x08, 0x27, 0xDC, 0xE1, 0x98, 0xEC, 0x16, 0x59, 0xB8,
0x35, 0xA7, 0x74, 0xAE, 0x85, 0x52, 0xE3, 0x56, 0x9E, 0xAA, 0xC0, 0xFA, 0xF4, 0x38, 0x7B, 0x93,
0x88, 0xD4, 0x3B, 0x41, 0x44, 0x2A, 0x52, 0x39, 0xA1, 0x69, 0x1E, 0x76, 0x80, 0x68, 0x76, 0x96,
0x9D, 0xC7, 0x10, 0x62, 0xCB, 0xF3, 0x5A, 0xFE, 0x79, 0xA3, 0x18, 0xED, 0x78, 0xF4, 0xF9, 0xAF,
0x96, 0x93, 0x5D, 0xAA, 0x68, 0xB7, 0xC4, 0x91, 0x51, 0xA3, 0xCF, 0xA4, 0xF4, 0x35, 0xDC, 0x66,
0x95, 0x83, 0x5B, 0x82, 0x41, 0x5F, 0x04, 0x8E, 0xE8, 0xF7, 0x53, 0x17, 0x27, 0x6E, 0xF8, 0xB7,
0x8A, 0xF5, 0x56, 0x15, 0x72, 0xBB, 0x8A, 0x6F, 0x2D, 0x50, 0x31, 0x6A, 0xC4, 0x30, 0x10, 0x1C,
0x59, 0x24, 0x2E, 0x04, 0xA7, 0x27, 0xF8, 0x01, 0x39, 0x50, 0x9B, 0x22, 0x9C, 0x75, 0x55, 0x3E,
0x75, 0x70, 0x7A, 0x52, 0x1E, 0x70, 0x10, 0x55, 0xA9, 0x0D, 0xF9, 0xC0, 0xC2, 0x35, 0x49, 0xA7,
0xC2, 0x85, 0x02, 0xB6, 0x27, 0x2B, 0x27, 0xDB, 0xCC, 0x0E, 0x33, 0xDA, 0xDD, 0xD1, 0x48, 0x7E,
0x90, 0x25, 0xE0, 0xE8, 0xB2, 0xEB, 0x0A, 0xE2, 0x0D, 0x08, 0x80, 0xE3, 0xD2, 0x91, 0xF8, 0x23,
0xDA, 0x8C, 0xCC, 0xFF, 0x64, 0xF8, 0xDE, 0x09, 0xFA, 0x55, 0x4D, 0xD2, 0x4F, 0x37, 0x3B, 0x1D,
0x50, 0x80, 0x0B, 0xF4, 0x41, 0x24, 0x27, 0x2B, 0x18, 0xB8, 0x38, 0x6E, 0xF0, 0xEA, 0x4A, 0xB0,
0x13, 0x3C, 0xF7, 0xBA, 0xAA, 0xE1, 0x89, 0x15, 0xAD, 0xC8, 0x75, 0xC7, 0x93, 0x59, 0x76, 0xAC,
0x66, 0x6E, 0x60, 0xC5, 0xCA, 0xB3, 0xA2, 0x4F, 0xFE, 0x2C, 0x4D, 0xC6, 0x65, 0xD8, 0xBA, 0x1F,
0x54, 0x77, 0x67, 0xBD, 0xAE, 0x56, 0xA7, 0x56, 0x5B, 0xDE, 0x3C, 0x93, 0x15, 0x9F, 0xE2, 0xA9,
0x39, 0x43, 0x42, 0x6D, 0xCE, 0x30, 0xEB, 0x6A, 0x6D, 0xFB, 0xE2, 0x75, 0xAB, 0x3C, 0x58, 0x69,
0x72, 0x7E, 0xF1, 0xAF, 0x7A, 0x6F, 0xF8, 0xDA, 0x96, 0x91, 0x9A, 0xE0, 0x93, 0x09, 0xE6, 0x5D,
0x34, 0x84, 0xF4, 0xB3, 0xD3, 0x09, 0x47, 0x4D, 0x0D, 0x1F, 0x61, 0xC9, 0x34, 0xE8, 0x55, 0x2E,
0xB7, 0x24, 0xB9, 0x05, 0x30, 0xA5, 0x5D, 0xA4, 0xBF, 0x31, 0xA9, 0x43, 0x4C, 0xF4, 0x2A, 0x3F,
0x32, 0xFD, 0x02, 0x75, 0x52, 0xB1, 0x4E, 0x02, 0x41, 0x10, 0x7D, 0xC7, 0x5E, 0x72, 0x89, 0x67,
0x58, 0x0B, 0x6A, 0xB0, 0xB4, 0xC0, 0x60, 0x61, 0x41, 0xB1, 0x84, 0x4D, 0x2C, 0x2C, 0xF5, 0x13,
0xFC, 0x08, 0x0A, 0x0B, 0x12, 0x2E, 0xB1, 0xB4, 0xF1, 0x13, 0xAC, 0x69, 0x30, 0xE1, 0x6A, 0xDD,
0x84, 0xC2, 0xC2, 0x44, 0x50, 0x4B, 0x0B, 0x31, 0x76, 0x58, 0xB8, 0x04, 0x12, 0x88, 0x22, 0xE3,
0xEC, 0x1D, 0x10, 0x62, 0x74, 0x73, 0xB3, 0x3B, 0x33, 0xF7, 0xF6, 0xCD, 0x9B, 0x9B, 0x43, 0x04,
0x48, 0x00, 0x36, 0x3D, 0x88, 0x68, 0xC4, 0xD6, 0x31, 0x80, 0x58, 0x58, 0x86, 0xD3, 0x38, 0x41,
0x29, 0x0A, 0x29, 0xF3, 0x5C, 0x8F, 0x87, 0xAF, 0xD2, 0x67, 0xB4, 0xC4, 0x9F, 0x1B, 0x72, 0x29,
0x57, 0x6A, 0x0B, 0x36, 0x26, 0x29, 0x32, 0x57, 0x0F, 0xA8, 0x70, 0xF6, 0x02, 0xB8, 0xFC, 0xEF,
0xBA, 0x0D, 0x65, 0x56, 0xB5, 0x0D, 0x59, 0x31, 0x73, 0xA1, 0xF6, 0x79, 0xAF, 0x21, 0x46, 0x1C,
0x6A, 0xC4, 0xD7, 0xCD, 0xE6, 0x84, 0xD9, 0xDE, 0x0C, 0x0A, 0xC2, 0x78, 0x36, 0x30, 0x05, 0x04,
0xD8, 0x43, 0xB2, 0xCA, 0x10, 0x53, 0x34, 0xA6, 0xC1, 0x7D, 0x5D, 0x95, 0x6B, 0xE8, 0x43, 0x44,
0xC8, 0xBA, 0x6C, 0xE2, 0x6E, 0x64, 0x37, 0xF3, 0x65, 0x9B, 0xFF, 0x40, 0xC1, 0xA2, 0x90, 0xE2,
0x5D, 0x67, 0x55, 0x23, 0xA8, 0xA7, 0xDA, 0x0F, 0x8F, 0x9D, 0x28, 0x4C, 0x14, 0x5E, 0x21, 0x63,
0x82, 0x30, 0x2B, 0x8B, 0x63, 0x49, 0x5A, 0x8E, 0x21, 0x75, 0x95, 0xBE, 0x89, 0xC6, 0x4E, 0x30,
0xE3, 0x59, 0x90, 0x72, 0x3A, 0x85, 0xF1, 0x25, 0x4E, 0x55, 0x60, 0x6C, 0x5D, 0xDC, 0x0E, 0x5A,
0x25, 0x9A, 0xED, 0x26, 0x9D, 0xF1, 0xB3, 0xEF, 0xA8, 0x77, 0x52, 0xD0, 0x1A, 0x5E, 0xCB, 0x50,
0x2B, 0xA9, 0xAD, 0x3C, 0x18, 0xB4, 0x8E, 0x68, 0x0E, 0xAF, 0xCF, 0x3A, 0x3C, 0xCB, 0xF2, 0x57,
0xCB, 0xFA, 0x50, 0x21, 0x18, 0x27, 0xEE, 0x34, 0xBE, 0x06, 0xCD, 0x1B, 0xEE, 0x54, 0xA5, 0x03,
0xE0, 0x63, 0x09, 0xDC, 0x5A, 0x65, 0x04, 0xD1, 0xBC, 0x4A, 0xF4, 0xD9, 0x4B, 0x5C, 0x3A, 0xE3,
0x70, 0x39, 0x30, 0xCF, 0x21, 0xB7, 0x21, 0x2C, 0x94, 0x15, 0x23, 0x5B, 0xED, 0x0E, 0xBB, 0xAA,
0xA7, 0x2C, 0x46, 0x46, 0x74, 0x21, 0x15, 0xD6, 0xDC, 0xDC, 0x71, 0x4A, 0x9A, 0x8E, 0xAB, 0x44,
0x64, 0xB9, 0x2E, 0xFB, 0xDE, 0x3B, 0x73, 0x96, 0x12, 0x77, 0xF1, 0x73, 0x30, 0xA9, 0x38, 0xFF,
0x75, 0x7B, 0xE1, 0x7A, 0x2F, 0x95, 0xA7, 0x19, 0x71, 0x25, 0xF1, 0x82, 0x4C, 0x3F, 0x29, 0xCF,
0x83, 0x0B, 0xA2, 0xD8, 0x8D, 0x2E, 0xE0, 0xEF, 0xD7, 0x20, 0x9A, 0xB0, 0x2E, 0x37, 0xBC, 0x43,
0x0E, 0x03, 0x1D, 0x6A, 0xF7, 0xD6, 0x87, 0xC6, 0x0F, 0xA5, 0x57, 0xBD, 0x6F, 0x1C, 0xC7, 0x15,
0xFF, 0xED, 0xAC, 0xA8, 0x89, 0xB5, 0x89, 0x96, 0x85, 0xD3, 0x44, 0xE2, 0x9D, 0x0B, 0x15, 0x2A,
0x48, 0x6E, 0x23, 0x18, 0x34, 0x70, 0x77, 0xBB, 0xB0, 0x4B, 0x17, 0x49, 0xE1, 0x94, 0x41, 0x5C,
0xBA, 0x08, 0x40, 0x15, 0x29, 0x08, 0x84, 0xD2, 0xAD, 0xA2, 0x22, 0x45, 0x1A, 0xFE, 0x07, 0x51,
0xE1, 0x8A, 0x8D, 0x69, 0x43, 0x05, 0x63, 0x1C, 0x7D, 0xE3, 0xB0, 0x70, 0x61, 0x20, 0x5A, 0xDB,
0xA5, 0x0B, 0xAF, 0x23, 0x01, 0x46, 0x9A, 0x78, 0x02, 0xAD, 0x91, 0xA5, 0xBC, 0x7B, 0x93, 0xDF,
0x9B, 0xDD, 0x93, 0x8E, 0x31, 0xEC, 0x24, 0xF6, 0x1C, 0xF7, 0x6E, 0xE7, 0xE3, 0xBD, 0x79, 0x1F,
0xBF, 0xF7, 0xC1, 0xE7, 0x81, 0xB5, 0x61, 0x8E, 0xF0, 0x13, 0x0B, 0x65, 0x4F, 0x80, 0x2A, 0xCE,
0xB1, 0xAF, 0x2C, 0xB6, 0x31, 0x75, 0x0E, 0xB1, 0x73, 0x46, 0xD9, 0xB0, 0xC0, 0x18, 0x16, 0xB1,
0x39, 0x46, 0x60, 0x47, 0xC0, 0x64, 0x00, 0x44, 0x1F, 0x66, 0xC0, 0xBF, 0x0C, 0x90, 0x16, 0x80,
0xB6, 0x20, 0x25, 0xBA, 0xB1, 0x5B, 0x60, 0xBE, 0xC0, 0x0D, 0xCD, 0xF5, 0x19, 0x30, 0x04, 0x48,
0xFE, 0x46, 0xA5, 0x5C, 0x1B, 0xDA, 0xE4, 0xE5, 0x32, 0x34, 0x16, 0xF6, 0x18, 0xA3, 0x31, 0x06,
0x71, 0x16, 0xBD, 0x52, 0x84, 0xA6, 0x52, 0x45, 0xAA, 0x4A, 0xED, 0x4A, 0x4C, 0x0F, 0xE0, 0xDC,
0xD7, 0xCE, 0x59, 0x44, 0x06, 0x89, 0x90, 0x53, 0x90, 0xE8, 0x33, 0xE7, 0xA6, 0xAE, 0xF1, 0xAF,
0x2B, 0xAB, 0x4E, 0x46, 0x2D, 0xF7, 0xAD, 0xE3, 0xCA, 0x42, 0x15, 0xDA, 0xB9, 0xB7, 0x30, 0xCF,
0x12, 0xAB, 0x4B, 0x24, 0xF9, 0x04, 0x81, 0x0B, 0x2C, 0x86, 0x93, 0xC8, 0x04, 0x76, 0x36, 0xC1,
0x30, 0xB0, 0x15, 0xAC, 0x3E, 0x2D, 0x62, 0x0C, 0xE3, 0xAC, 0xC2, 0x6C, 0x12, 0x67, 0x61, 0x39,
0xAB, 0x10, 0x67, 0x2E, 0xC3, 0x4C, 0xD5, 0x88, 0x8A, 0xB8, 0x0E, 0x16, 0x78, 0xE2, 0x5C, 0xA1,
0xF3, 0xF9, 0x23, 0x5C, 0xF0, 0xBA, 0x04, 0x39, 0xE4, 0x4A, 0x2C, 0xA8, 0x63, 0x03, 0x8C, 0x2B,
0x04, 0x0F, 0x4B, 0x44, 0xAF, 0x1A, 0x8C, 0xE2, 0x4C, 0x95, 0x29, 0x62, 0xEC, 0xF3, 0x53, 0x87,
0x45, 0x68, 0x63, 0x68, 0x1A, 0x28, 0xBE, 0x6B, 0x90, 0x52, 0xE9, 0x5B, 0xCE, 0xAB, 0xE2, 0x6C,
0xCA, 0x2F, 0x9A, 0xD1, 0xFD, 0xC5, 0x22, 0x2C, 0x6F, 0x03, 0x36, 0x36, 0x98, 0x05, 0x15, 0x2D,
0x4A, 0xB1, 0xA8, 0x52, 0x94, 0x07, 0x55, 0x48, 0x9A, 0x80, 0x7C, 0x0D, 0x6D, 0x58, 0xD3, 0xC0,
0xE9, 0x16, 0xEF, 0xFB, 0x8C, 0xF7, 0x3A, 0xB9, 0x9F, 0x46, 0x0E, 0x4B, 0x4E, 0x0E, 0xF8, 0x5C,
0xA1, 0x53, 0xC8, 0xD1, 0x4C, 0x69, 0xFD, 0x09, 0x3A, 0xE1, 0x62, 0xBE, 0x6B, 0x1E, 0x0A, 0x78,
0x4B, 0x43, 0xAF, 0x39, 0x5E, 0xEF, 0x17, 0x50, 0xF7, 0x27, 0x42, 0xF1, 0x8F, 0x90, 0x84, 0x3C,
0xE1, 0x79, 0x70, 0xDC, 0xE3, 0x33, 0x42, 0x30, 0x77, 0x56, 0x56, 0x35, 0x85, 0x08, 0x4B, 0x55,
0xD0, 0xB6, 0x96, 0xAE, 0xDC, 0xA3, 0x56, 0x5B, 0x18, 0x92, 0xD9, 0x07, 0x7C, 0xFE, 0x69, 0x55,
0xC1, 0x05, 0x42, 0x20, 0xDF, 0xA7, 0xF5, 0x29, 0x5D, 0x1A, 0xF3, 0x8A, 0xAF, 0xC5, 0xFD, 0x14,
0x26, 0x10, 0x97, 0x51, 0x6C, 0x82, 0xA6, 0x1F, 0x73, 0xB7, 0xA0, 0x87, 0x16, 0x09, 0xC5, 0xBF,
0xC5, 0xE9, 0xB1, 0xA8, 0xC2, 0x4B, 0xE4, 0x11, 0x99, 0x88, 0x0B, 0xDC, 0x16, 0xD9, 0xB8, 0x2F,
0xE7, 0xE4, 0x7C, 0xEA, 0xCE, 0x04, 0x6E, 0x5E, 0x52, 0x3E, 0x4A, 0x5E, 0x26, 0x4B, 0x45, 0x2A,
0x52, 0xB6, 0x62, 0xC9, 0xCC, 0xC3, 0xA9, 0x03, 0xDB, 0xAC, 0x3F, 0x91, 0x7A, 0xE5, 0x9C, 0xB7,
0xCC, 0x19, 0x29, 0xC9, 0x94, 0xA2, 0x8A, 0xAE, 0x82, 0x27, 0xEA, 0x6A, 0x75, 0x85, 0x01, 0x0D,
0x21, 0x1A, 0xE2, 0x3E, 0x15, 0x19, 0x20, 0xFE, 0x39, 0x77, 0x3E, 0xE1, 0x23, 0x3B, 0x63, 0xEE,
0xD0, 0x88, 0x15, 0xF1, 0x35, 0x20, 0x7C, 0xC2, 0x0F, 0x48, 0xED, 0x2A, 0x11, 0x86, 0x3C, 0x8A,
0x8E, 0xDB, 0x52, 0xB7, 0xB9, 0x97, 0x96, 0x60, 0x85, 0x12, 0x4D, 0x44, 0xBB, 0x6D, 0x11, 0x2C,
0xF5, 0x37, 0x79, 0x6B, 0x8B, 0x4C, 0x27, 0xB2, 0x2F, 0xE7, 0xE4, 0xBC, 0x40, 0xF5, 0x2B, 0x4E,
0x16, 0x99, 0x60, 0xD7, 0x03, 0xD9, 0x43, 0xD9, 0x83, 0xF9, 0x07, 0x2D, 0xE9, 0x33, 0x0C, 0x1F,
0xB9, 0x26, 0xF4, 0x66, 0xE3, 0xED, 0xD4, 0x87, 0x77, 0x15, 0x0D, 0xA2, 0x3B, 0x0D, 0x06, 0x94,
0xF0, 0x46, 0x58, 0x75, 0xEE, 0xA7, 0x5E, 0xC4, 0x38, 0xC1, 0x62, 0xBC, 0xC1, 0xC4, 0xBC, 0xC3,
0xCC, 0xDB, 0x91, 0x01, 0x4F, 0x5E, 0x6B, 0xB4, 0x33, 0x83, 0x32, 0x78, 0xFC, 0xD5, 0x2F, 0x7F,
0xFD, 0xA7, 0xCE, 0xD8, 0x9E, 0xE7, 0xD4, 0xB5, 0xFE, 0x8D, 0xEE, 0xDD, 0x93, 0xE3, 0x8C, 0x2A,
0x62, 0x81, 0x80, 0x8D, 0x72, 0x82, 0x9F, 0xC6, 0x93, 0x9D, 0x7D, 0xCF, 0xE8, 0x1B, 0x3B, 0x63,
0x2F, 0xD4, 0xC8, 0xDB, 0x8E, 0x2B, 0x51, 0x26, 0xBB, 0x74, 0x1F, 0x79, 0x88, 0x49, 0xF7, 0xCE,
0xEF, 0x51, 0x00, 0x6E, 0x33, 0x0C, 0x64, 0xEF, 0xD8, 0xEF, 0xF9, 0xB1, 0x23, 0x7F, 0xD7, 0x76,
0xAE, 0x4D, 0x5E, 0x6A, 0x22, 0x7A, 0x63, 0x01, 0xED, 0x8A, 0xF4, 0xA5, 0xFA, 0xC6, 0xCE, 0xF5,
0x6E, 0x8B, 0xE3, 0xE2, 0x41, 0xD2, 0xEC, 0x6D, 0xDB, 0x58, 0x3E, 0xC7, 0x5B, 0x69, 0x7D, 0x31,
0x5F, 0x3F, 0x59, 0x08, 0x3C, 0x9E, 0xEF, 0xEE, 0x17, 0x01, 0x7D, 0x30, 0x90, 0xB3, 0x5C, 0xAE,
0xCA, 0x0E, 0x46, 0xBC, 0x8F, 0xD2, 0x3A, 0x3A, 0x9F, 0x0F, 0x83, 0x6C, 0xE0, 0xC1, 0xED, 0x73,
0x5C, 0x45, 0x92, 0xFA, 0x3E, 0x29, 0x79, 0x7C, 0xCC, 0x27, 0x2D, 0xBB, 0x48, 0x14, 0xFB, 0x89,
0xC5, 0x2E, 0xFA, 0xF4, 0x10, 0x95, 0x83, 0xB4, 0xB9, 0x75, 0x7F, 0x50, 0x5A, 0x6D, 0x6C, 0x64,
0xEA, 0x2D, 0x9B, 0x56, 0xB7, 0x2F, 0xE5, 0x97, 0xA2, 0x32, 0x2A, 0xDC, 0xE7, 0xEE, 0xD3, 0x3B,
0xFF, 0xD0, 0x8D, 0x2A, 0x63, 0x6E, 0x4D, 0xCA, 0xDF, 0xDD, 0x79, 0xE8, 0x5E, 0x75, 0xBA, 0xF2,
0xC9, 0xD2, 0x4B, 0xF5, 0x7D, 0x9F, 0x15, 0xBC, 0xC9, 0x08, 0xF3, 0x3E, 0x18, 0xC4, 0xA1, 0x3E,
0x53, 0x34, 0x3D, 0x12, 0xC5, 0xE1, 0x41, 0xDD, 0x87, 0x88, 0x48, 0xAE, 0xAA, 0x3E, 0xF2, 0x64,
0xE2, 0xB3, 0xC2, 0x89, 0xD0, 0xF5, 0x61, 0xDE, 0x3C, 0x7E, 0x30, 0xFA, 0x8F, 0x3F, 0x3B, 0xFA,
0xBF, 0x07, 0xF0, 0x8B, 0x5E, 0x84, 0x94, 0xF2, 0x24, 0xBC, 0x24, 0xE6, 0x9A, 0xFE, 0x30, 0x87,
0xFA, 0x48, 0x1C, 0x4F, 0x54, 0xEC, 0x11, 0x22, 0xBE, 0xA2, 0xF0, 0x3B, 0xCA, 0xB5, 0xA1, 0x1F,
0x6C, 0x20, 0x35, 0xA7, 0x26, 0x0A, 0xC4, 0xF8, 0x14, 0x3E, 0x89, 0x05, 0x2E, 0x74, 0xE0, 0x1A,
0xCD, 0xAD, 0xDF, 0x27, 0xB8, 0x4A, 0x52, 0x56, 0xA4, 0xDC, 0xE7, 0xD1, 0x31, 0x3F, 0x4C, 0xB8,
0x39, 0xA7, 0x52, 0x9E, 0xB6, 0xB8, 0x24, 0xD9, 0x17, 0xE2, 0xBA, 0x6D, 0xA9, 0x39, 0x0F, 0xFA,
0xF2, 0x34, 0x14, 0x57, 0x2F, 0xB3, 0xC5, 0xAE, 0x4F, 0x31, 0x68, 0x83, 0x39, 0xC3, 0x68, 0x4C,
0x76, 0xC7, 0x96, 0x88, 0x27, 0xEE, 0x1E, 0x74, 0x42, 0x8E, 0x28, 0xDF, 0x77, 0x4F, 0xED, 0x75,
0xE0, 0xFA, 0x7F, 0x3D, 0xB5, 0x32, 0xDD, 0xAF, 0xA0, 0xFE, 0x46, 0x4D, 0x5F, 0xA9, 0x02, 0x86,
0xA9, 0xE4, 0xCA, 0x65, 0x9D, 0x7C, 0x8F, 0x06, 0x62, 0xA0, 0xFE, 0xC1, 0xA0, 0x5A, 0x97, 0x32,
0x29, 0xC0, 0xFC, 0x3E, 0x3F, 0x0C, 0xE5, 0xF5, 0x6D, 0x68, 0xD6, 0x9D, 0x69, 0x8D, 0xE0, 0xCF,
0x3D, 0x77, 0x1F, 0xEB, 0x12, 0xF3, 0x06, 0xDF, 0x35, 0x88, 0xF2, 0x7D, 0x16, 0xB7, 0x45, 0x0B,
0xB4, 0xEB, 0x52, 0x4B, 0x3B, 0x48, 0x9C, 0xC8, 0xDA, 0xAC, 0x33, 0xDA, 0xB7, 0x0F, 0x49, 0xCD,
0x72, 0x47, 0x2C, 0x30, 0x13, 0x46, 0xAD, 0xA7, 0x47, 0x1F, 0x7C, 0x04, 0x5B, 0xF8, 0x25, 0xAB,
0xF1, 0x97, 0x1D, 0xE4, 0xBE, 0x65, 0x50, 0x83, 0xC9, 0x02, 0x8A, 0x66, 0xD1, 0x9F, 0x0B, 0x1B,
0xF5, 0x26, 0x5E, 0x98, 0x2E, 0xF4, 0xA9, 0x99, 0xB7, 0x3F, 0xC2, 0x95, 0xDC, 0x87, 0xD9, 0x3D,
0xAC, 0xA7, 0x6D, 0x78, 0xFA, 0xD1, 0xBC, 0x7D, 0x0E, 0x49, 0xB1, 0x42, 0x4C, 0x6F, 0x36, 0xCB,
0x4C, 0xB5, 0x32, 0x1D, 0x1E, 0xFC, 0x78, 0x5A, 0x6F, 0x55, 0xD3, 0xE6, 0xF5, 0xA8, 0x5C, 0xC3,
0x85, 0xA4, 0xDC, 0x98, 0x36, 0xE3, 0x6A, 0x5A, 0x73, 0x7A, 0x0D, 0x78, 0x9D, 0x50, 0x37, 0xBB,
0xEE, 0xD1, 0x92, 0xC9, 0xCF, 0xDC, 0xDF, 0xE9, 0x19, 0x77, 0x39, 0xC3, 0x6F, 0x7C, 0x38, 0x01,
0x9B, 0xC3, 0xAE, 0xE7, 0xF8, 0xAD, 0xC4, 0xD6, 0x66, 0x9F, 0x03, 0x8F, 0xBA, 0xCA, 0x22, 0xD1,
0x67, 0x85, 0xC3, 0x8A, 0x18, 0x9C, 0x9E, 0x3E, 0x8B, 0xC7, 0x95, 0xE9, 0x0B, 0x52, 0x25, 0x92,
0x52, 0xB5, 0x22, 0x36, 0x8D, 0xC0, 0x6F, 0xBE, 0xCB, 0x8F, 0xB4, 0x13, 0x7B, 0xDD, 0xF1, 0xA9,
0x54, 0xED, 0xE6, 0x9A, 0x2F, 0x1C, 0x84, 0x2B, 0xBB, 0x10, 0xF9, 0x51, 0x8D, 0xFC, 0xED, 0x16,
0xBA, 0x95, 0x16, 0x6B, 0xBC, 0xE4, 0xDD, 0x1D, 0xEE, 0x27, 0xCF, 0x89, 0x48, 0x89, 0x89, 0xAC,
0x74, 0x3E, 0x05, 0x39, 0xCF, 0xB3, 0xA8, 0xE2, 0x0F, 0x53, 0x0C, 0x8F, 0x4C, 0xF3, 0x8E, 0xDB,
0x94, 0xF1, 0x23, 0xBD, 0x0D, 0x4F, 0x4A, 0xEE, 0xB9, 0x87, 0xEB, 0x2B, 0xA2, 0x5F, 0x92, 0x1E,
0x27, 0xAC, 0xE1, 0x2F, 0xD5, 0xF5, 0x39, 0xAA, 0xD8, 0x30, 0x72, 0x92, 0x22, 0xAA, 0x9E, 0xB1,
0xE7, 0xC2, 0xE2, 0x1C, 0x8B, 0x29, 0xAB, 0xDA, 0xD0, 0x79, 0x89, 0x92, 0x73, 0x2D, 0x87, 0xE9,
0xAB, 0xF4, 0x68, 0xD9, 0xA5, 0x48, 0x2B, 0xF3, 0xBE, 0x18, 0x4E, 0x48, 0x84, 0x54, 0x32, 0xD5,
0x5E, 0x7F, 0x82, 0x25, 0x60, 0x97, 0xD5, 0x5D, 0x8A, 0x57, 0xCB, 0xC4, 0x30, 0xE3, 0xC6, 0xC4,
0x87, 0xB8, 0x74, 0x55, 0xBA, 0x0B, 0x72, 0xC9, 0x18, 0x91, 0x21, 0x45, 0x3B, 0xF6, 0xAE, 0x6E,
0x3D, 0x89, 0x5A, 0x16, 0x68, 0x61, 0xC5, 0xCE, 0x04, 0x6B, 0x4F, 0x75, 0x8B, 0xB2, 0x5E, 0x8E,
0x6E, 0x9B, 0x62, 0x1E, 0x68, 0xEF, 0x17, 0xFD, 0x47, 0xA9, 0x55, 0x34, 0x37, 0x13, 0x33, 0x37,
0x2C, 0xE9, 0xFA, 0xBB, 0xF2, 0xC8, 0xA8, 0x82, 0x39, 0xD4, 0x46, 0x76, 0x2A, 0x40, 0x92, 0x1E,
0x22, 0x16, 0xA8, 0x53, 0xFA, 0xA7, 0x37, 0x75, 0x6D, 0xEE, 0x53, 0x71, 0x9F, 0x75, 0x22, 0xF1,
0xB2, 0x5F, 0x59, 0x36, 0x2F, 0x3E, 0xFA, 0x5A, 0xAC, 0x88, 0xFB, 0xAC, 0x43, 0x72, 0x6D, 0xE2,
0x3C, 0x8F, 0x33, 0x01, 0x8C, 0x74, 0xD1, 0x55, 0x9F, 0x37, 0xC7, 0x3D, 0xF5, 0xF2, 0x19, 0x77,
0xEB, 0xDA, 0xD7, 0x76, 0x39, 0xBF, 0x02, 0x34, 0xDF, 0x53, 0xE1, 0xE2, 0xBB, 0xBE, 0xFD, 0x33,
0xD8, 0x8E, 0x74, 0xA1, 0x8A, 0x4D, 0x55, 0x6C, 0xE0, 0x88, 0xAD, 0xB6, 0x32, 0xE1, 0xDD, 0x2C,
0x42, 0x7C, 0x95, 0x28, 0xBE, 0xFA, 0xEE, 0xE1, 0x93, 0xC3, 0x77, 0xA4, 0x17, 0xF9, 0x14, 0x11,
0xB4, 0x2C, 0x6D, 0xEE, 0xE0, 0x08, 0xE5, 0x91, 0x32, 0x3A, 0x2B, 0x23, 0xEC, 0x04, 0x76, 0x93,
0xD2, 0x9F, 0xBD, 0x2D, 0x28, 0x58, 0x2C, 0x25, 0x0D, 0x5E, 0x83, 0x34, 0x89, 0x19, 0x92, 0x6C,
0x98, 0xD3, 0x0B, 0xDA, 0x6C, 0x49, 0xC9, 0xA1, 0xF3, 0x74, 0xC4, 0xED, 0xCB, 0xE2, 0xBD, 0xCD,
0x27, 0x87, 0x87, 0x87, 0x8F, 0x85, 0xF5, 0x5F, 0x45, 0x69, 0x5F, 0xA7, 0x6E, 0x8A, 0x87, 0x25,
0x01, 0x89, 0xD9, 0xF6, 0x94, 0x10, 0xAA, 0x8A, 0xC5, 0xC8, 0xF3, 0xC2, 0x4F, 0x3D, 0xFB, 0xD7,
0xBC, 0x21, 0x72, 0x0C, 0x0F, 0xAE, 0x14, 0xCC, 0x66, 0x61, 0xC1, 0x4C, 0x92, 0x98, 0x77, 0x0A,
0xF5, 0xF0, 0xEE, 0xEF, 0x8B, 0xED, 0xE8, 0xAA, 0xFA, 0xB8, 0xDC, 0xB8, 0xA9, 0x16, 0x78, 0xD1,
0xB0, 0x56, 0x7D, 0x81, 0xED, 0x22, 0xFC, 0x95, 0xFA, 0xB8, 0xF8, 0xC9, 0xCE, 0x96, 0x2A, 0x8F,
0xE4, 0x54, 0xDE, 0x32, 0x46, 0x3C, 0x21, 0x19, 0x9F, 0x74, 0xBC, 0xB0, 0xF6, 0x4D, 0xD6, 0xEC,
0xE9, 0x8A, 0xCB, 0x02, 0x50, 0xC6, 0xF0, 0xC3, 0xBB, 0x39, 0xAD, 0xB4, 0xC1, 0x72, 0xB2, 0x71,
0x93, 0x15, 0xE7, 0x45, 0xC3, 0x66, 0x80, 0xAC, 0x41, 0xD6, 0x25, 0x36, 0x76, 0xD8, 0x8E, 0x90,
0x35, 0x15, 0xA4, 0xD7, 0x36, 0x7D, 0xB3, 0x13, 0x9C, 0x05, 0xE7, 0x59, 0xF7, 0x90, 0xB5, 0x1D,
0xB8, 0xE2, 0xFF, 0x79, 0x5A, 0x88, 0xBF, 0xC4, 0x4A, 0x46, 0x12, 0xE4, 0x05, 0xFE, 0x8B, 0x11,
0x68, 0xCB, 0x24, 0xD9, 0xCC, 0x91, 0xE6, 0xC3, 0x53, 0x69, 0xBD, 0xEB, 0x7F, 0x03, 0x1D, 0xCD,
0xB1, 0x0D, 0xC2, 0x40, 0x0C, 0x05, 0xD0, 0x9F, 0x13, 0x1D, 0x43, 0x64, 0x02, 0xF0, 0x06, 0x80,
0x32, 0x53, 0x0A, 0x1A, 0x74, 0xEE, 0x18, 0xEB, 0x76, 0x60, 0x82, 0x24, 0x13, 0x50, 0xBA, 0x48,
0xCE, 0xF1, 0xB7, 0x25, 0x3F, 0xF9, 0xDB, 0x85, 0x01, 0xBC, 0xC0, 0x7A, 0xA7, 0x55, 0x53, 0xA3,
0xF3, 0xC8, 0x30, 0xE7, 0xE5, 0x73, 0xB9, 0x46, 0xA8, 0xBE, 0x18, 0x3D, 0x44, 0x43, 0xFF, 0x1A,
0x5D, 0x5D, 0x43, 0x6D, 0x26, 0x6E, 0x78, 0xF6, 0xE2, 0x3B, 0x5A, 0x87, 0xF8, 0xE4, 0x1D, 0xC5,
0xB7, 0x10, 0xB2, 0xC7, 0x26, 0x02, 0x67, 0xC8, 0x8F, 0x96, 0xFF, 0x83, 0x3F, 0x6E, 0x77, 0x5A,
0x7A, 0x3E, 0xCF, 0x19, 0x43, 0xF4, 0x09,
};
static const EpdGlyph bookerly_12_regularGlyphs[] = {
{ 0, 0, 0, 0, 0, 0, 0 }, //
{ 0, 0, 0, 0, 0, 0, 0 }, // 
{ 0, 0, 5, 0, 0, 0, 0 }, //
{ 0, 0, 5, 0, 0, 0, 0 }, //
{ 0, 0, 0, 0, 0, 0, 0 }, // 
{ 0, 0, 5, 0, 0, 0, 0 }, //
fix: force auto-hinting for Bookerly to fix inconsistent stem widths (#1098) ## Summary Bookerly's native TrueType hinting is effectively a no-op at the sizes used here, causing FreeType to place stems at inconsistent sub-pixel positions. This results in the 'k' stem (8-bit fringe: 0x38=56) falling just below the 2-bit quantization threshold while 'l' and 'h' stems (fringes: 0x4C=76, 0x40=64) land above it --- making 'k' visibly narrower (2.00px vs 2.33px effective width). FreeType's auto-hinter snaps all stems to consistent grid positions, normalizing effective stem width to 2.67px across all glyphs. Adds --force-autohint flag to fontconvert.py and applies it to Bookerly only. NotoSans, OpenDyslexic, and Ubuntu fonts are unaffected. Here is an example of before/after. Take notice of the vertical stems on characters like `l`, `k`, `n`, `i`, etc. The font is Bookerly 12pt regular: **BEFORE**: ![before](https://github.com/user-attachments/assets/65b2acab-ad95-489e-885e-e3a0163cc252) **AFTER**: ![after](https://github.com/user-attachments/assets/d09a8b5d-40af-4a7d-b622-e1b2cabcce85) Claude generated this script to quantitatively determine that this change makes the vertical stems on a variety of characters more consistent for Bookerly _only_. <details> <summary>Python script</summary> ```python #!/usr/bin/env python3 """Compare stem consistency across all font families with and without auto-hinting. Run from repo root: python3 compare_all_fonts.py """ import freetype DPI = 150 CHARS = ["k", "l", "h", "i", "b", "d"] SIZES = [12, 14, 16, 18] FONTS = { "Bookerly": "lib/EpdFont/builtinFonts/source/Bookerly/Bookerly-Regular.ttf", "NotoSans": "lib/EpdFont/builtinFonts/source/NotoSans/NotoSans-Regular.ttf", "OpenDyslexic": "lib/EpdFont/builtinFonts/source/OpenDyslexic/OpenDyslexic-Regular.otf", "Ubuntu": "lib/EpdFont/builtinFonts/source/Ubuntu/Ubuntu-Regular.ttf", } MODES = { "default": freetype.FT_LOAD_RENDER, "autohint": freetype.FT_LOAD_RENDER | freetype.FT_LOAD_FORCE_AUTOHINT, } def q4to2(v): if v >= 12: return 3 elif v >= 8: return 2 elif v >= 4: return 1 else: return 0 def get_stem_eff(face, char, flags): gi = face.get_char_index(ord(char)) if gi == 0: return None face.load_glyph(gi, flags) bm = face.glyph.bitmap w, h = bm.width, bm.rows if w == 0 or h == 0: return None p2 = [] for y in range(h): row = [] for x in range(w): row.append(q4to2(bm.buffer[y * bm.pitch + x] >> 4)) p2.append(row) # Measure leftmost stem in stable middle rows mid_start, mid_end = h // 4, h - h // 4 widths = [] for y in range(mid_start, mid_end): first = next((x for x in range(w) if p2[y][x] > 0), -1) if first < 0: continue last = first for x in range(first, w): if p2[y][x] > 0: last = x else: break eff = sum(p2[y][x] for x in range(first, last + 1)) / 3.0 widths.append(eff) return round(sum(widths) / len(widths), 2) if widths else None def main(): for font_name, font_path in FONTS.items(): try: freetype.Face(font_path) except Exception: print(f"\n {font_name}: SKIPPED (file not found)") continue print(f"\n{'=' * 80}") print(f" {font_name}") print(f"{'=' * 80}") for size in SIZES: print(f"\n {size}pt:") print(f" {'':6s}", end="") for c in CHARS: print(f" '{c}' ", end="") print(" | spread") for mode_name, flags in MODES.items(): face = freetype.Face(font_path) face.set_char_size(size << 6, size << 6, DPI, DPI) vals = [] print(f" {mode_name:6s}", end="") for c in CHARS: v = get_stem_eff(face, c, flags) vals.append(v) print(f" {v:5.2f}" if v else " N/A", end="") valid = [v for v in vals if v is not None] spread = max(valid) - min(valid) if len(valid) >= 2 else 0 marker = " <-- inconsistent" if spread > 0.5 else "" print(f" | {spread:.2f}{marker}") if __name__ == "__main__": main() ``` </details> Here are the results. The table compares how the font-generation `autohint` flag affects the range of widths of various characters. Lower `spread` mean that glyph stroke widths should appear more consistent. ``` Spread = max stem width - min stem width across glyphs (lower = more consistent): ┌──────────────┬──────┬─────────┬──────────┬──────────┐ │ Font │ Size │ Default │ Autohint │ Winner │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Bookerly │ 12pt │ 1.49 │ 1.12 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.39 │ 1.13 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.38 │ 1.16 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.90 │ 1.58 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ NotoSans │ 12pt │ 1.16 │ 0.94 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 0.83 │ 1.14 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.41 │ 1.51 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.74 │ 1.63 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ OpenDyslexic │ 12pt │ 2.22 │ 1.44 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 2.57 │ 3.29 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 3.13 │ 2.60 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 3.21 │ 3.23 │ ~tied │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Ubuntu │ 12pt │ 1.25 │ 1.31 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.41 │ 1.64 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 2.21 │ 1.71 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.80 │ 1.71 │ autohint │ └──────────────┴──────┴─────────┴──────────┴──────────┘ ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? I used AI to make sure I'm not doing something stupid, since I'm not a typography expert. I made the changes though.
2026-02-24 06:13:08 +11:00
{ 3, 19, 6, 2, 19, 15, 0 }, // !
{ 7, 8, 9, 1, 17, 14, 15 }, // "
{ 16, 15, 16, 0, 14, 60, 29 }, // #
{ 12, 25, 16, 2, 19, 75, 89 }, // $
{ 22, 19, 24, 1, 18, 105, 164 }, // %
{ 19, 17, 20, 1, 17, 81, 269 }, // &
{ 3, 8, 5, 1, 17, 6, 350 }, // '
{ 8, 25, 9, 1, 20, 50, 356 }, // (
{ 8, 25, 10, 1, 20, 50, 406 }, // )
{ 9, 8, 10, 0, 17, 18, 456 }, // *
{ 10, 11, 16, 3, 14, 28, 474 }, // +
{ 5, 8, 7, 0, 3, 10, 502 }, // ,
{ 8, 2, 10, 1, 7, 4, 512 }, // -
{ 4, 3, 8, 2, 3, 3, 516 }, // .
{ 12, 19, 12, 0, 18, 57, 519 }, // /
{ 13, 17, 16, 1, 17, 56, 576 }, // 0
{ 10, 17, 16, 3, 17, 43, 632 }, // 1
{ 12, 17, 16, 2, 17, 51, 675 }, // 2
{ 11, 17, 16, 2, 17, 47, 726 }, // 3
{ 14, 17, 16, 1, 17, 60, 773 }, // 4
{ 12, 17, 16, 1, 17, 51, 833 }, // 5
{ 12, 17, 16, 2, 17, 51, 884 }, // 6
{ 12, 17, 16, 3, 17, 51, 935 }, // 7
{ 12, 17, 16, 2, 17, 51, 986 }, // 8
{ 13, 17, 16, 1, 17, 56, 1037 }, // 9
{ 4, 13, 8, 2, 13, 13, 1093 }, // :
{ 6, 17, 7, 0, 13, 26, 1106 }, // ;
{ 11, 12, 16, 3, 14, 33, 1132 }, // <
{ 10, 6, 16, 3, 11, 15, 1165 }, // =
{ 11, 12, 16, 2, 14, 33, 1180 }, // >
{ 9, 17, 11, 1, 17, 39, 1213 }, // ?
{ 22, 22, 24, 1, 17, 121, 1252 }, // @
{ 19, 17, 19, -1, 17, 81, 1373 }, // A
{ 15, 17, 15, 0, 17, 64, 1454 }, // B
{ 14, 17, 16, 1, 17, 60, 1518 }, // C
{ 17, 17, 18, 0, 17, 73, 1578 }, // D
{ 15, 17, 15, 0, 17, 64, 1651 }, // E
{ 13, 17, 14, 0, 17, 56, 1715 }, // F
{ 16, 17, 18, 1, 17, 68, 1771 }, // G
{ 20, 17, 22, 1, 17, 85, 1839 }, // H
{ 8, 17, 9, 0, 17, 34, 1924 }, // I
{ 11, 22, 9, -2, 17, 61, 1958 }, // J
{ 18, 17, 19, 1, 17, 77, 2019 }, // K
{ 15, 17, 16, 1, 17, 64, 2096 }, // L
{ 22, 17, 23, 0, 17, 94, 2160 }, // M
{ 20, 18, 21, 0, 17, 90, 2254 }, // N
{ 17, 17, 19, 1, 17, 73, 2344 }, // O
{ 14, 17, 15, 0, 17, 60, 2417 }, // P
{ 19, 22, 19, 1, 17, 105, 2477 }, // Q
{ 17, 17, 16, 0, 17, 73, 2582 }, // R
{ 12, 17, 14, 1, 17, 51, 2655 }, // S
{ 15, 17, 17, 1, 17, 64, 2706 }, // T
{ 20, 17, 20, 0, 17, 85, 2770 }, // U
{ 19, 17, 18, 0, 17, 81, 2855 }, // V
{ 28, 17, 28, 0, 17, 119, 2936 }, // W
{ 18, 17, 19, 0, 17, 77, 3055 }, // X
{ 18, 17, 17, -1, 17, 77, 3132 }, // Y
{ 14, 18, 14, 0, 17, 63, 3209 }, // Z
{ 6, 24, 8, 2, 19, 36, 3272 }, // [
{ 12, 19, 12, 0, 18, 57, 3308 }, // <backslash>
{ 6, 24, 8, 1, 19, 36, 3365 }, // ]
{ 12, 11, 16, 2, 16, 33, 3401 }, // ^
{ 13, 2, 13, 0, -1, 7, 3434 }, // _
{ 6, 7, 17, 6, 21, 11, 3441 }, // `
{ 13, 13, 14, 1, 13, 43, 3452 }, // a
{ 15, 19, 15, -1, 19, 72, 3495 }, // b
{ 11, 13, 13, 1, 13, 36, 3567 }, // c
{ 15, 19, 15, 1, 19, 72, 3603 }, // d
{ 11, 13, 13, 1, 13, 36, 3675 }, // e
{ 12, 19, 10, 0, 19, 57, 3711 }, // f
{ 14, 19, 15, 1, 13, 67, 3768 }, // g
{ 17, 19, 17, 0, 19, 81, 3835 }, // h
{ 9, 19, 8, -1, 19, 43, 3916 }, // i
{ 8, 25, 8, -2, 19, 50, 3959 }, // j
{ 16, 19, 16, 0, 19, 76, 4009 }, // k
{ 9, 19, 8, 0, 19, 43, 4085 }, // l
{ 25, 13, 25, 0, 13, 82, 4128 }, // m
{ 17, 13, 17, 0, 13, 56, 4210 }, // n
{ 13, 13, 15, 1, 13, 43, 4266 }, // o
{ 15, 19, 16, 0, 13, 72, 4309 }, // p
{ 14, 19, 15, 1, 13, 67, 4381 }, // q
{ 11, 13, 12, 0, 13, 36, 4448 }, // r
{ 10, 13, 12, 1, 13, 33, 4484 }, // s
{ 11, 17, 10, -1, 17, 47, 4517 }, // t
{ 17, 13, 16, -1, 13, 56, 4564 }, // u
{ 15, 13, 15, 0, 13, 49, 4620 }, // v
{ 22, 13, 22, 0, 13, 72, 4669 }, // w
{ 15, 13, 15, 0, 13, 49, 4741 }, // x
{ 15, 19, 15, 0, 13, 72, 4790 }, // y
{ 12, 13, 12, 0, 13, 39, 4862 }, // z
{ 7, 24, 10, 2, 20, 42, 4901 }, // {
{ 2, 22, 6, 2, 19, 11, 4943 }, // |
{ 8, 24, 9, 0, 20, 48, 4954 }, // }
{ 12, 4, 16, 2, 10, 12, 5002 }, // ~
perf: Reduce overall flash usage by 30.7% by compressing built-in fonts (#831) ## Summary **What is the goal of this PR?** Compress reader font bitmaps to reduce flash usage by 30.7%. **What changes are included?** - New `EpdFontGroup` struct and extended `EpdFontData` with `groups`/`groupCount` fields - `--compress` flag in `fontconvert.py`: groups glyphs (ASCII base group + groups of 8) and compresses each with raw DEFLATE - `FontDecompressor` class with 4-slot LRU cache for on-demand decompression during rendering - `GfxRenderer` transparently routes bitmap access through `getGlyphBitmap()` (compressed or direct flash) - Uses `uzlib` for decompression with minimal heap overhead. - 48 reader fonts (Bookerly, NotoSans 12-18pt, OpenDyslexic) regenerated with compression; 5 UI fonts unchanged - Round-trip verification script (`verify_compression.py`) runs as part of font generation ## Additional Context ## Flash & RAM | | baseline | font-compression | Difference | |--|--------|-----------------|------------| | Flash (ELF) | 6,302,476 B (96.2%) | 4,365,022 B (66.6%) | -1,937,454 B (-30.7%) | | firmware.bin | 6,468,192 B | 4,531,008 B | -1,937,184 B (-29.9%) | | RAM | 101,700 B (31.0%) | 103,076 B (31.5%) | +1,376 B (+0.5%) | ## Script-Based Grouping (Cold Cache) Comparison of uncompressed baseline vs script-based group compression (4-slot LRU cache, cleared each page). Glyphs are grouped by Unicode block (ASCII, Latin-1, Latin Extended-A, Combining Marks, Cyrillic, General Punctuation, etc.) instead of sequential groups of 8. ### Render Time | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Median** | 414.9 ms | 431.6 ms | +16.7 ms (+4.0%) | | **Pages** | 37 | 37 | | ### Memory Usage | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Heap free (median)** | 187.0 KB | 176.3 KB | -10.7 KB | | **Heap free (min)** | 186.0 KB | 166.5 KB | -19.5 KB | | **Largest block (median)** | 148.0 KB | 128.0 KB | -20.0 KB | | **Largest block (min)** | 148.0 KB | 120.0 KB | -28.0 KB | ### Cache Effectiveness | | Misses/page | Hit rate | |---|---|---| | **Compressed (cold cache)** | 2.1 | 99.85% | ------ ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**YES**_ Implementation was done by Claude Code (Opus 4.6) based on a plan developed collaboratively. All generated font headers were verified with an automated round-trip decompression test. The firmware was compiled successfully but has not yet been tested on-device. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:30:15 +11:00
{ 0, 0, 5, 0, 0, 0, 0 }, //  
fix: force auto-hinting for Bookerly to fix inconsistent stem widths (#1098) ## Summary Bookerly's native TrueType hinting is effectively a no-op at the sizes used here, causing FreeType to place stems at inconsistent sub-pixel positions. This results in the 'k' stem (8-bit fringe: 0x38=56) falling just below the 2-bit quantization threshold while 'l' and 'h' stems (fringes: 0x4C=76, 0x40=64) land above it --- making 'k' visibly narrower (2.00px vs 2.33px effective width). FreeType's auto-hinter snaps all stems to consistent grid positions, normalizing effective stem width to 2.67px across all glyphs. Adds --force-autohint flag to fontconvert.py and applies it to Bookerly only. NotoSans, OpenDyslexic, and Ubuntu fonts are unaffected. Here is an example of before/after. Take notice of the vertical stems on characters like `l`, `k`, `n`, `i`, etc. The font is Bookerly 12pt regular: **BEFORE**: ![before](https://github.com/user-attachments/assets/65b2acab-ad95-489e-885e-e3a0163cc252) **AFTER**: ![after](https://github.com/user-attachments/assets/d09a8b5d-40af-4a7d-b622-e1b2cabcce85) Claude generated this script to quantitatively determine that this change makes the vertical stems on a variety of characters more consistent for Bookerly _only_. <details> <summary>Python script</summary> ```python #!/usr/bin/env python3 """Compare stem consistency across all font families with and without auto-hinting. Run from repo root: python3 compare_all_fonts.py """ import freetype DPI = 150 CHARS = ["k", "l", "h", "i", "b", "d"] SIZES = [12, 14, 16, 18] FONTS = { "Bookerly": "lib/EpdFont/builtinFonts/source/Bookerly/Bookerly-Regular.ttf", "NotoSans": "lib/EpdFont/builtinFonts/source/NotoSans/NotoSans-Regular.ttf", "OpenDyslexic": "lib/EpdFont/builtinFonts/source/OpenDyslexic/OpenDyslexic-Regular.otf", "Ubuntu": "lib/EpdFont/builtinFonts/source/Ubuntu/Ubuntu-Regular.ttf", } MODES = { "default": freetype.FT_LOAD_RENDER, "autohint": freetype.FT_LOAD_RENDER | freetype.FT_LOAD_FORCE_AUTOHINT, } def q4to2(v): if v >= 12: return 3 elif v >= 8: return 2 elif v >= 4: return 1 else: return 0 def get_stem_eff(face, char, flags): gi = face.get_char_index(ord(char)) if gi == 0: return None face.load_glyph(gi, flags) bm = face.glyph.bitmap w, h = bm.width, bm.rows if w == 0 or h == 0: return None p2 = [] for y in range(h): row = [] for x in range(w): row.append(q4to2(bm.buffer[y * bm.pitch + x] >> 4)) p2.append(row) # Measure leftmost stem in stable middle rows mid_start, mid_end = h // 4, h - h // 4 widths = [] for y in range(mid_start, mid_end): first = next((x for x in range(w) if p2[y][x] > 0), -1) if first < 0: continue last = first for x in range(first, w): if p2[y][x] > 0: last = x else: break eff = sum(p2[y][x] for x in range(first, last + 1)) / 3.0 widths.append(eff) return round(sum(widths) / len(widths), 2) if widths else None def main(): for font_name, font_path in FONTS.items(): try: freetype.Face(font_path) except Exception: print(f"\n {font_name}: SKIPPED (file not found)") continue print(f"\n{'=' * 80}") print(f" {font_name}") print(f"{'=' * 80}") for size in SIZES: print(f"\n {size}pt:") print(f" {'':6s}", end="") for c in CHARS: print(f" '{c}' ", end="") print(" | spread") for mode_name, flags in MODES.items(): face = freetype.Face(font_path) face.set_char_size(size << 6, size << 6, DPI, DPI) vals = [] print(f" {mode_name:6s}", end="") for c in CHARS: v = get_stem_eff(face, c, flags) vals.append(v) print(f" {v:5.2f}" if v else " N/A", end="") valid = [v for v in vals if v is not None] spread = max(valid) - min(valid) if len(valid) >= 2 else 0 marker = " <-- inconsistent" if spread > 0.5 else "" print(f" | {spread:.2f}{marker}") if __name__ == "__main__": main() ``` </details> Here are the results. The table compares how the font-generation `autohint` flag affects the range of widths of various characters. Lower `spread` mean that glyph stroke widths should appear more consistent. ``` Spread = max stem width - min stem width across glyphs (lower = more consistent): ┌──────────────┬──────┬─────────┬──────────┬──────────┐ │ Font │ Size │ Default │ Autohint │ Winner │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Bookerly │ 12pt │ 1.49 │ 1.12 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.39 │ 1.13 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.38 │ 1.16 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.90 │ 1.58 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ NotoSans │ 12pt │ 1.16 │ 0.94 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 0.83 │ 1.14 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.41 │ 1.51 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.74 │ 1.63 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ OpenDyslexic │ 12pt │ 2.22 │ 1.44 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 2.57 │ 3.29 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 3.13 │ 2.60 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 3.21 │ 3.23 │ ~tied │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Ubuntu │ 12pt │ 1.25 │ 1.31 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.41 │ 1.64 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 2.21 │ 1.71 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.80 │ 1.71 │ autohint │ └──────────────┴──────┴─────────┴──────────┴──────────┘ ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? I used AI to make sure I'm not doing something stupid, since I'm not a typography expert. I made the changes though.
2026-02-24 06:13:08 +11:00
{ 4, 19, 7, 1, 13, 19, 0 }, // ¡
{ 12, 25, 16, 2, 20, 75, 19 }, // ¢
{ 13, 17, 15, 1, 17, 56, 94 }, // £
{ 14, 13, 16, 1, 15, 46, 150 }, // ¤
{ 16, 17, 16, 0, 17, 68, 196 }, // ¥
{ 2, 22, 6, 2, 19, 11, 264 }, // ¦
{ 11, 20, 13, 1, 17, 55, 275 }, // §
{ 8, 3, 16, 4, 18, 6, 330 }, // ¨
{ 18, 18, 20, 1, 18, 81, 336 }, // ©
{ 9, 12, 12, 2, 18, 27, 417 }, // ª
{ 13, 9, 14, 1, 11, 30, 444 }, // «
{ 11, 6, 16, 2, 11, 17, 474 }, // ¬
{ 8, 2, 10, 1, 7, 4, 491 }, // ­
{ 14, 13, 15, 0, 19, 46, 495 }, // ®
{ 9, 2, 17, 4, 18, 5, 541 }, // ¯
{ 8, 8, 14, 3, 17, 16, 546 }, // °
{ 10, 15, 16, 3, 15, 38, 562 }, // ±
{ 8, 11, 11, 2, 20, 22, 600 }, // ²
{ 8, 11, 11, 2, 20, 22, 622 }, // ³
{ 5, 7, 17, 6, 21, 9, 644 }, // ´
{ 15, 20, 17, 2, 14, 75, 653 }, // µ
{ 14, 21, 14, 0, 17, 74, 728 }, // ¶
{ 4, 3, 8, 2, 8, 3, 802 }, // ·
{ 6, 6, 17, 5, -1, 9, 805 }, // ¸
{ 8, 12, 11, 2, 21, 24, 814 }, // ¹
{ 9, 12, 12, 2, 18, 27, 838 }, // º
{ 13, 9, 13, 1, 11, 30, 865 }, // »
{ 24, 20, 27, 2, 18, 120, 895 }, // ¼
{ 24, 20, 27, 2, 18, 120, 1015 }, // ½
{ 25, 20, 27, 1, 18, 125, 1135 }, // ¾
{ 9, 19, 11, 1, 13, 43, 1260 }, // ¿
{ 19, 24, 19, -1, 24, 114, 1303 }, // À
{ 19, 24, 19, 0, 24, 114, 1417 }, // Á
{ 19, 24, 19, -1, 24, 114, 1531 }, // Â
{ 19, 23, 19, 0, 23, 110, 1645 }, // Ã
{ 19, 22, 20, 0, 22, 105, 1755 }, // Ä
{ 19, 24, 19, 0, 24, 114, 1860 }, // Å
{ 23, 17, 23, 0, 17, 98, 1974 }, // Æ
{ 14, 23, 16, 1, 17, 81, 2072 }, // Ç
{ 15, 24, 15, 0, 24, 90, 2153 }, // È
{ 15, 24, 15, 0, 24, 90, 2243 }, // É
{ 15, 24, 15, 0, 24, 90, 2333 }, // Ê
{ 15, 22, 15, 0, 22, 83, 2423 }, // Ë
{ 8, 24, 9, 0, 24, 48, 2506 }, // Ì
{ 8, 24, 9, 0, 24, 48, 2554 }, // Í
{ 9, 24, 9, 0, 24, 54, 2602 }, // Î
{ 9, 22, 11, 1, 22, 50, 2656 }, // Ï
{ 17, 17, 19, 1, 17, 73, 2706 }, // Ð
{ 20, 24, 21, 0, 23, 120, 2779 }, // Ñ
{ 17, 24, 19, 1, 24, 102, 2899 }, // Ò
{ 17, 24, 19, 1, 24, 102, 3001 }, // Ó
{ 17, 24, 19, 1, 24, 102, 3103 }, // Ô
{ 17, 23, 19, 1, 23, 98, 3205 }, // Õ
{ 17, 23, 19, 1, 23, 98, 3303 }, // Ö
{ 10, 11, 16, 3, 14, 28, 3401 }, // ×
{ 19, 17, 19, 0, 17, 81, 3429 }, // Ø
{ 20, 24, 20, 0, 24, 120, 3510 }, // Ù
{ 20, 24, 20, 0, 24, 120, 3630 }, // Ú
{ 20, 24, 20, 0, 24, 120, 3750 }, // Û
{ 20, 23, 20, 0, 23, 115, 3870 }, // Ü
{ 17, 24, 17, 0, 24, 102, 3985 }, // Ý
{ 14, 17, 16, 1, 17, 60, 4087 }, // Þ
{ 16, 19, 17, 0, 19, 76, 4147 }, // ß
{ 13, 21, 14, 1, 21, 69, 4223 }, // à
{ 13, 21, 14, 1, 21, 69, 4292 }, // á
{ 13, 20, 14, 1, 20, 65, 4361 }, // â
{ 13, 19, 14, 1, 19, 62, 4426 }, // ã
{ 13, 19, 14, 1, 19, 62, 4488 }, // ä
{ 13, 21, 14, 1, 21, 69, 4550 }, // å
{ 18, 13, 20, 1, 13, 59, 4619 }, // æ
{ 11, 19, 13, 1, 13, 53, 4678 }, // ç
{ 11, 21, 13, 1, 21, 58, 4731 }, // è
{ 11, 21, 13, 1, 21, 58, 4789 }, // é
{ 11, 21, 13, 1, 21, 58, 4847 }, // ê
{ 11, 19, 13, 1, 19, 53, 4905 }, // ë
{ 8, 21, 9, 0, 21, 42, 4958 }, // ì
{ 8, 21, 9, 0, 21, 42, 5000 }, // í
{ 8, 20, 9, 0, 20, 40, 5042 }, // î
{ 8, 18, 8, 0, 18, 36, 5082 }, // ï
{ 13, 20, 15, 1, 20, 65, 5118 }, // ð
{ 17, 19, 17, 0, 19, 81, 5183 }, // ñ
{ 13, 21, 15, 1, 21, 69, 5264 }, // ò
{ 13, 21, 15, 1, 21, 69, 5333 }, // ó
{ 13, 21, 15, 1, 21, 69, 5402 }, // ô
{ 13, 19, 15, 1, 19, 62, 5471 }, // õ
{ 13, 19, 15, 1, 19, 62, 5533 }, // ö
{ 10, 11, 16, 3, 14, 28, 5595 }, // ÷
{ 15, 13, 15, 0, 13, 49, 5623 }, // ø
{ 17, 21, 16, -1, 21, 90, 5672 }, // ù
{ 17, 21, 16, -1, 21, 90, 5762 }, // ú
{ 17, 21, 16, -1, 21, 90, 5852 }, // û
{ 17, 19, 16, -1, 19, 81, 5942 }, // ü
{ 15, 27, 16, 1, 21, 102, 6023 }, // ý
{ 15, 25, 16, 0, 19, 94, 6125 }, // þ
{ 15, 24, 14, 0, 18, 90, 6219 }, // ÿ
{ 19, 22, 19, -1, 22, 105, 0 }, // Ā
{ 13, 17, 14, 1, 17, 56, 105 }, // ā
{ 19, 24, 19, 0, 24, 114, 161 }, // Ă
{ 13, 20, 14, 1, 20, 65, 275 }, // ă
{ 19, 23, 19, 0, 17, 110, 340 }, // Ą
{ 13, 19, 13, 1, 13, 62, 450 }, // ą
{ 14, 24, 16, 1, 24, 84, 512 }, // Ć
{ 11, 21, 13, 1, 21, 58, 596 }, // ć
{ 14, 24, 16, 1, 24, 84, 654 }, // Ĉ
{ 11, 21, 13, 1, 21, 58, 738 }, // ĉ
{ 14, 23, 16, 1, 23, 81, 796 }, // Ċ
{ 11, 19, 13, 1, 19, 53, 877 }, // ċ
{ 14, 24, 16, 1, 24, 84, 930 }, // Č
{ 11, 20, 13, 1, 20, 55, 1014 }, // č
{ 17, 24, 18, 0, 24, 102, 1069 }, // Ď
{ 17, 19, 16, 1, 19, 81, 1171 }, // ď
{ 17, 17, 19, 1, 17, 73, 1252 }, // Đ
{ 15, 19, 16, 1, 19, 72, 1325 }, // đ
{ 15, 22, 15, 0, 22, 83, 1397 }, // Ē
{ 11, 17, 13, 1, 17, 47, 1480 }, // ē
{ 15, 24, 15, 0, 24, 90, 1527 }, // Ĕ
{ 11, 20, 13, 1, 20, 55, 1617 }, // ĕ
{ 15, 23, 15, 0, 23, 87, 1672 }, // Ė
{ 11, 19, 13, 1, 19, 53, 1759 }, // ė
{ 15, 23, 15, 0, 17, 87, 1812 }, // Ę
{ 11, 19, 13, 1, 13, 53, 1899 }, // ę
{ 15, 24, 15, 0, 24, 90, 1952 }, // Ě
{ 11, 20, 13, 1, 20, 55, 2042 }, // ě
{ 16, 24, 18, 1, 24, 96, 2097 }, // Ĝ
{ 14, 26, 15, 1, 20, 91, 2193 }, // ĝ
{ 16, 24, 18, 1, 24, 96, 2284 }, // Ğ
{ 14, 26, 15, 1, 20, 91, 2380 }, // ğ
{ 16, 23, 18, 1, 23, 92, 2471 }, // Ġ
{ 14, 25, 15, 1, 19, 88, 2563 }, // ġ
{ 16, 23, 18, 1, 17, 92, 2651 }, // Ģ
{ 14, 27, 15, 1, 21, 95, 2743 }, // ģ
{ 20, 24, 22, 1, 24, 120, 2838 }, // Ĥ
{ 17, 26, 17, 0, 26, 111, 2958 }, // ĥ
{ 20, 17, 22, 1, 17, 85, 3069 }, // Ħ
{ 17, 19, 17, 0, 19, 81, 3154 }, // ħ
{ 8, 23, 10, 1, 23, 46, 3235 }, // Ĩ
{ 8, 19, 10, 1, 19, 38, 3281 }, // ĩ
{ 9, 22, 9, 0, 22, 50, 3319 }, // Ī
{ 10, 17, 9, -1, 17, 43, 3369 }, // ī
{ 8, 24, 10, 1, 24, 48, 3412 }, // Ĭ
{ 8, 20, 10, 1, 20, 40, 3460 }, // ĭ
{ 8, 23, 10, 1, 17, 46, 3500 }, // Į
{ 9, 25, 8, -1, 19, 57, 3546 }, // į
{ 8, 23, 10, 1, 23, 46, 3603 }, // İ
{ 8, 13, 9, 0, 13, 26, 3649 }, // ı
{ 18, 22, 18, 0, 17, 99, 3675 }, // IJ
{ 14, 25, 15, -1, 19, 88, 3774 }, // ij
{ 11, 29, 9, -2, 24, 80, 3862 }, // Ĵ
{ 9, 26, 8, -1, 20, 59, 3942 }, // ĵ
{ 18, 23, 19, 1, 17, 104, 4001 }, // Ķ
{ 16, 25, 16, 0, 19, 100, 4105 }, // ķ
{ 16, 13, 16, 0, 13, 52, 4205 }, // ĸ
{ 15, 24, 16, 1, 24, 90, 4257 }, // Ĺ
{ 9, 25, 9, 0, 25, 57, 4347 }, // ĺ
{ 15, 23, 16, 1, 17, 87, 4404 }, // Ļ
{ 8, 25, 8, 0, 19, 50, 4491 }, // ļ
{ 15, 19, 16, 1, 19, 72, 4541 }, // Ľ
{ 10, 19, 9, 0, 19, 48, 4613 }, // ľ
{ 15, 17, 16, 1, 17, 64, 4661 }, // Ŀ
{ 12, 19, 13, 0, 19, 57, 4725 }, // ŀ
{ 16, 17, 16, 0, 17, 68, 4782 }, // Ł
{ 10, 19, 8, -1, 19, 48, 4850 }, // ł
{ 20, 25, 21, 0, 24, 125, 4898 }, // Ń
{ 17, 21, 17, 0, 21, 90, 5023 }, // ń
{ 20, 23, 21, 0, 17, 115, 5113 }, // Ņ
{ 17, 19, 17, 0, 13, 81, 5228 }, // ņ
{ 20, 25, 21, 0, 24, 125, 5309 }, // Ň
{ 17, 20, 17, 0, 20, 85, 5434 }, // ň
{ 22, 18, 23, 0, 18, 99, 5519 }, // ʼn
{ 20, 22, 21, 0, 17, 110, 5618 }, // Ŋ
{ 14, 19, 16, 0, 13, 67, 5728 }, // ŋ
{ 17, 22, 19, 1, 22, 94, 5795 }, // Ō
{ 13, 17, 15, 1, 17, 56, 5889 }, // ō
{ 17, 24, 19, 1, 24, 102, 5945 }, // Ŏ
{ 13, 20, 15, 1, 20, 65, 6047 }, // ŏ
{ 17, 24, 19, 1, 24, 102, 6112 }, // Ő
{ 13, 20, 15, 1, 20, 65, 6214 }, // ő
{ 22, 17, 24, 1, 17, 94, 6279 }, // Œ
{ 21, 13, 23, 1, 13, 69, 6373 }, // œ
{ 17, 24, 16, 0, 24, 102, 6442 }, // Ŕ
{ 11, 21, 12, 0, 21, 58, 6544 }, // ŕ
{ 17, 23, 16, 0, 17, 98, 6602 }, // Ŗ
{ 11, 19, 12, 0, 13, 53, 6700 }, // ŗ
{ 17, 24, 16, 0, 24, 102, 6753 }, // Ř
{ 11, 20, 12, 0, 20, 55, 6855 }, // ř
{ 12, 24, 14, 1, 24, 72, 6910 }, // Ś
{ 10, 21, 12, 1, 21, 53, 6982 }, // ś
{ 12, 24, 14, 1, 24, 72, 7035 }, // Ŝ
{ 10, 21, 12, 1, 21, 53, 7107 }, // ŝ
{ 12, 23, 14, 1, 17, 69, 7160 }, // Ş
{ 10, 19, 12, 1, 13, 48, 7229 }, // ş
{ 12, 24, 14, 1, 24, 72, 7277 }, // Š
{ 10, 20, 12, 1, 20, 50, 7349 }, // š
{ 15, 24, 17, 1, 17, 90, 7399 }, // Ţ
{ 11, 23, 10, -1, 17, 64, 7489 }, // ţ
{ 15, 24, 17, 1, 24, 90, 7553 }, // Ť
{ 11, 19, 10, -1, 19, 53, 7643 }, // ť
{ 16, 17, 17, 0, 17, 68, 7696 }, // Ŧ
{ 11, 17, 11, 0, 17, 47, 7764 }, // ŧ
{ 20, 23, 20, 0, 23, 115, 7811 }, // Ũ
{ 17, 19, 16, -1, 19, 81, 7926 }, // ũ
{ 20, 22, 20, 0, 22, 110, 8007 }, // Ū
{ 17, 17, 16, -1, 17, 73, 8117 }, // ū
{ 20, 24, 20, 0, 24, 120, 8190 }, // Ŭ
{ 17, 20, 16, -1, 20, 85, 8310 }, // ŭ
{ 20, 25, 20, 0, 25, 125, 8395 }, // Ů
{ 17, 21, 16, -1, 21, 90, 8520 }, // ů
{ 20, 24, 20, 0, 24, 120, 8610 }, // Ű
{ 17, 21, 16, -1, 21, 90, 8730 }, // ű
{ 20, 23, 20, 0, 17, 115, 8820 }, // Ų
{ 17, 19, 16, -1, 13, 81, 8935 }, // ų
{ 28, 24, 28, 0, 24, 168, 9016 }, // Ŵ
{ 23, 20, 22, 0, 20, 115, 9184 }, // ŵ
{ 18, 24, 17, -1, 24, 108, 9299 }, // Ŷ
{ 15, 26, 16, 1, 20, 98, 9407 }, // ŷ
{ 18, 22, 17, 0, 22, 99, 9505 }, // Ÿ
{ 14, 25, 14, 0, 24, 88, 9604 }, // Ź
{ 12, 21, 12, 0, 21, 63, 9692 }, // ź
{ 15, 24, 14, -1, 23, 90, 9755 }, // Ż
{ 12, 19, 13, 0, 19, 57, 9845 }, // ż
{ 14, 25, 14, 0, 24, 88, 9902 }, // Ž
{ 12, 20, 12, 0, 20, 60, 9990 }, // ž
{ 12, 19, 10, 0, 19, 57, 10050 }, // ſ
perf: Reduce overall flash usage by 30.7% by compressing built-in fonts (#831) ## Summary **What is the goal of this PR?** Compress reader font bitmaps to reduce flash usage by 30.7%. **What changes are included?** - New `EpdFontGroup` struct and extended `EpdFontData` with `groups`/`groupCount` fields - `--compress` flag in `fontconvert.py`: groups glyphs (ASCII base group + groups of 8) and compresses each with raw DEFLATE - `FontDecompressor` class with 4-slot LRU cache for on-demand decompression during rendering - `GfxRenderer` transparently routes bitmap access through `getGlyphBitmap()` (compressed or direct flash) - Uses `uzlib` for decompression with minimal heap overhead. - 48 reader fonts (Bookerly, NotoSans 12-18pt, OpenDyslexic) regenerated with compression; 5 UI fonts unchanged - Round-trip verification script (`verify_compression.py`) runs as part of font generation ## Additional Context ## Flash & RAM | | baseline | font-compression | Difference | |--|--------|-----------------|------------| | Flash (ELF) | 6,302,476 B (96.2%) | 4,365,022 B (66.6%) | -1,937,454 B (-30.7%) | | firmware.bin | 6,468,192 B | 4,531,008 B | -1,937,184 B (-29.9%) | | RAM | 101,700 B (31.0%) | 103,076 B (31.5%) | +1,376 B (+0.5%) | ## Script-Based Grouping (Cold Cache) Comparison of uncompressed baseline vs script-based group compression (4-slot LRU cache, cleared each page). Glyphs are grouped by Unicode block (ASCII, Latin-1, Latin Extended-A, Combining Marks, Cyrillic, General Punctuation, etc.) instead of sequential groups of 8. ### Render Time | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Median** | 414.9 ms | 431.6 ms | +16.7 ms (+4.0%) | | **Pages** | 37 | 37 | | ### Memory Usage | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Heap free (median)** | 187.0 KB | 176.3 KB | -10.7 KB | | **Heap free (min)** | 186.0 KB | 166.5 KB | -19.5 KB | | **Largest block (median)** | 148.0 KB | 128.0 KB | -20.0 KB | | **Largest block (min)** | 148.0 KB | 120.0 KB | -28.0 KB | ### Cache Effectiveness | | Misses/page | Hit rate | |---|---|---| | **Compressed (cold cache)** | 2.1 | 99.85% | ------ ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**YES**_ Implementation was done by Claude Code (Opus 4.6) based on a plan developed collaboratively. All generated font headers were verified with an automated round-trip decompression test. The firmware was compiled successfully but has not yet been tested on-device. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:30:15 +11:00
{ 6, 7, 0, -4, 21, 11, 0 }, // ̀
fix: force auto-hinting for Bookerly to fix inconsistent stem widths (#1098) ## Summary Bookerly's native TrueType hinting is effectively a no-op at the sizes used here, causing FreeType to place stems at inconsistent sub-pixel positions. This results in the 'k' stem (8-bit fringe: 0x38=56) falling just below the 2-bit quantization threshold while 'l' and 'h' stems (fringes: 0x4C=76, 0x40=64) land above it --- making 'k' visibly narrower (2.00px vs 2.33px effective width). FreeType's auto-hinter snaps all stems to consistent grid positions, normalizing effective stem width to 2.67px across all glyphs. Adds --force-autohint flag to fontconvert.py and applies it to Bookerly only. NotoSans, OpenDyslexic, and Ubuntu fonts are unaffected. Here is an example of before/after. Take notice of the vertical stems on characters like `l`, `k`, `n`, `i`, etc. The font is Bookerly 12pt regular: **BEFORE**: ![before](https://github.com/user-attachments/assets/65b2acab-ad95-489e-885e-e3a0163cc252) **AFTER**: ![after](https://github.com/user-attachments/assets/d09a8b5d-40af-4a7d-b622-e1b2cabcce85) Claude generated this script to quantitatively determine that this change makes the vertical stems on a variety of characters more consistent for Bookerly _only_. <details> <summary>Python script</summary> ```python #!/usr/bin/env python3 """Compare stem consistency across all font families with and without auto-hinting. Run from repo root: python3 compare_all_fonts.py """ import freetype DPI = 150 CHARS = ["k", "l", "h", "i", "b", "d"] SIZES = [12, 14, 16, 18] FONTS = { "Bookerly": "lib/EpdFont/builtinFonts/source/Bookerly/Bookerly-Regular.ttf", "NotoSans": "lib/EpdFont/builtinFonts/source/NotoSans/NotoSans-Regular.ttf", "OpenDyslexic": "lib/EpdFont/builtinFonts/source/OpenDyslexic/OpenDyslexic-Regular.otf", "Ubuntu": "lib/EpdFont/builtinFonts/source/Ubuntu/Ubuntu-Regular.ttf", } MODES = { "default": freetype.FT_LOAD_RENDER, "autohint": freetype.FT_LOAD_RENDER | freetype.FT_LOAD_FORCE_AUTOHINT, } def q4to2(v): if v >= 12: return 3 elif v >= 8: return 2 elif v >= 4: return 1 else: return 0 def get_stem_eff(face, char, flags): gi = face.get_char_index(ord(char)) if gi == 0: return None face.load_glyph(gi, flags) bm = face.glyph.bitmap w, h = bm.width, bm.rows if w == 0 or h == 0: return None p2 = [] for y in range(h): row = [] for x in range(w): row.append(q4to2(bm.buffer[y * bm.pitch + x] >> 4)) p2.append(row) # Measure leftmost stem in stable middle rows mid_start, mid_end = h // 4, h - h // 4 widths = [] for y in range(mid_start, mid_end): first = next((x for x in range(w) if p2[y][x] > 0), -1) if first < 0: continue last = first for x in range(first, w): if p2[y][x] > 0: last = x else: break eff = sum(p2[y][x] for x in range(first, last + 1)) / 3.0 widths.append(eff) return round(sum(widths) / len(widths), 2) if widths else None def main(): for font_name, font_path in FONTS.items(): try: freetype.Face(font_path) except Exception: print(f"\n {font_name}: SKIPPED (file not found)") continue print(f"\n{'=' * 80}") print(f" {font_name}") print(f"{'=' * 80}") for size in SIZES: print(f"\n {size}pt:") print(f" {'':6s}", end="") for c in CHARS: print(f" '{c}' ", end="") print(" | spread") for mode_name, flags in MODES.items(): face = freetype.Face(font_path) face.set_char_size(size << 6, size << 6, DPI, DPI) vals = [] print(f" {mode_name:6s}", end="") for c in CHARS: v = get_stem_eff(face, c, flags) vals.append(v) print(f" {v:5.2f}" if v else " N/A", end="") valid = [v for v in vals if v is not None] spread = max(valid) - min(valid) if len(valid) >= 2 else 0 marker = " <-- inconsistent" if spread > 0.5 else "" print(f" | {spread:.2f}{marker}") if __name__ == "__main__": main() ``` </details> Here are the results. The table compares how the font-generation `autohint` flag affects the range of widths of various characters. Lower `spread` mean that glyph stroke widths should appear more consistent. ``` Spread = max stem width - min stem width across glyphs (lower = more consistent): ┌──────────────┬──────┬─────────┬──────────┬──────────┐ │ Font │ Size │ Default │ Autohint │ Winner │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Bookerly │ 12pt │ 1.49 │ 1.12 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.39 │ 1.13 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.38 │ 1.16 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.90 │ 1.58 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ NotoSans │ 12pt │ 1.16 │ 0.94 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 0.83 │ 1.14 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.41 │ 1.51 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.74 │ 1.63 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ OpenDyslexic │ 12pt │ 2.22 │ 1.44 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 2.57 │ 3.29 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 3.13 │ 2.60 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 3.21 │ 3.23 │ ~tied │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Ubuntu │ 12pt │ 1.25 │ 1.31 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.41 │ 1.64 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 2.21 │ 1.71 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.80 │ 1.71 │ autohint │ └──────────────┴──────┴─────────┴──────────┴──────────┘ ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? I used AI to make sure I'm not doing something stupid, since I'm not a typography expert. I made the changes though.
2026-02-24 06:13:08 +11:00
{ 5, 7, 0, -2, 21, 9, 11 }, // ́
{ 8, 6, 0, -4, 20, 12, 20 }, // ̂
{ 8, 4, 0, -4, 19, 8, 32 }, // ̃
{ 10, 2, 0, -5, 18, 5, 40 }, // ̄
{ 8, 4, 0, -4, 19, 8, 45 }, // ̆
{ 3, 3, 0, -2, 18, 3, 53 }, // ̇
{ 8, 3, 0, -4, 18, 6, 56 }, // ̈
{ 7, 8, 0, -3, 22, 14, 62 }, // ̉
{ 6, 6, 0, -3, 20, 9, 76 }, // ̊
{ 9, 6, 0, -3, 20, 14, 85 }, // ̋
{ 9, 5, 0, -4, 20, 12, 99 }, // ̌
{ 9, 6, 0, -5, 20, 14, 111 }, // ̏
{ 8, 5, 0, -4, 19, 10, 125 }, // ̑
{ 4, 7, 0, -2, 21, 7, 135 }, // ̒
{ 5, 7, 0, -1, 22, 9, 142 }, // ̓
{ 4, 7, 0, -2, 22, 7, 151 }, // ̔
{ 3, 7, 0, -1, 21, 6, 158 }, // ̕
{ 4, 6, 0, -2, 16, 6, 164 }, // ̛
{ 3, 3, 0, -2, -2, 3, 170 }, // ̣
{ 8, 3, 0, -4, -2, 6, 173 }, // ̤
{ 6, 5, 0, -3, -1, 8, 179 }, // ̥
{ 5, 5, 0, -3, -1, 7, 187 }, // ̦
{ 6, 6, 0, -3, -1, 9, 194 }, // ̧
{ 6, 6, 0, -2, 1, 9, 203 }, // ̨
{ 3, 5, 7, 2, -1, 4, 212 }, // ̩
{ 8, 5, 0, -4, -1, 10, 216 }, // ̭
{ 8, 4, 0, -4, -2, 8, 226 }, // ̮
{ 8, 4, 0, -4, -2, 8, 234 }, // ̰
{ 10, 2, 0, -5, -3, 5, 242 }, // ̱
{ 8, 5, 0, -4, 19, 10, 247 }, // ͂
{ 9, 10, 0, -4, 25, 23, 257 }, // ̈́
{ 5, 4, 0, -1, -2, 5, 280 }, // ͅ
{ 15, 24, 15, 0, 24, 90, 0 }, // Ѐ
{ 15, 22, 15, 0, 22, 83, 90 }, // Ё
{ 19, 22, 21, 1, 17, 105, 173 }, // Ђ
{ 14, 24, 15, 1, 24, 84, 278 }, // Ѓ
{ 15, 17, 17, 1, 17, 64, 362 }, // Є
{ 12, 17, 14, 1, 17, 51, 426 }, // Ѕ
{ 8, 17, 9, 0, 17, 34, 477 }, // І
{ 9, 22, 11, 1, 22, 50, 511 }, // Ї
{ 11, 22, 9, -2, 17, 61, 561 }, // Ј
{ 23, 17, 25, 1, 17, 98, 622 }, // Љ
{ 25, 17, 26, 1, 17, 107, 720 }, // Њ
{ 20, 17, 22, 1, 17, 85, 827 }, // Ћ
{ 18, 24, 17, 0, 24, 108, 912 }, // Ќ
{ 20, 24, 22, 1, 24, 120, 1020 }, // Ѝ
{ 19, 24, 19, 0, 24, 114, 1140 }, // Ў
{ 19, 23, 21, 1, 17, 110, 1254 }, // Џ
{ 19, 17, 19, -1, 17, 81, 1364 }, // А
{ 15, 17, 16, 1, 17, 64, 1445 }, // Б
{ 15, 17, 15, 0, 17, 64, 1509 }, // В
{ 14, 17, 15, 1, 17, 60, 1573 }, // Г
{ 17, 22, 19, 1, 17, 94, 1633 }, // Д
{ 15, 17, 15, 0, 17, 64, 1727 }, // Е
{ 26, 17, 25, -1, 17, 111, 1791 }, // Ж
{ 12, 17, 14, 1, 17, 51, 1902 }, // З
{ 20, 17, 22, 1, 17, 85, 1953 }, // И
{ 20, 23, 22, 1, 23, 115, 2038 }, // Й
{ 18, 17, 17, 0, 17, 77, 2153 }, // К
{ 18, 17, 19, 1, 17, 77, 2230 }, // Л
{ 22, 17, 23, 0, 17, 94, 2307 }, // М
{ 20, 17, 22, 1, 17, 85, 2401 }, // Н
{ 17, 17, 19, 1, 17, 73, 2486 }, // О
{ 20, 17, 21, 1, 17, 85, 2559 }, // П
{ 14, 17, 15, 0, 17, 60, 2644 }, // Р
{ 14, 17, 16, 1, 17, 60, 2704 }, // С
{ 15, 17, 17, 1, 17, 64, 2764 }, // Т
{ 18, 17, 18, 0, 17, 77, 2828 }, // У
{ 18, 18, 20, 1, 18, 81, 2905 }, // Ф
{ 18, 17, 19, 0, 17, 77, 2986 }, // Х
{ 19, 22, 21, 1, 17, 105, 3063 }, // Ц
{ 17, 17, 18, 1, 17, 73, 3168 }, // Ч
{ 26, 17, 28, 1, 17, 111, 3241 }, // Ш
{ 26, 22, 27, 1, 17, 143, 3352 }, // Щ
{ 17, 17, 19, 1, 17, 73, 3495 }, // Ъ
{ 22, 17, 24, 1, 17, 94, 3568 }, // Ы
{ 15, 17, 16, 1, 17, 64, 3662 }, // Ь
{ 15, 17, 17, 1, 17, 64, 3726 }, // Э
{ 25, 17, 27, 1, 17, 107, 3790 }, // Ю
{ 17, 17, 17, 0, 17, 73, 3897 }, // Я
{ 13, 13, 14, 1, 13, 43, 3970 }, // а
{ 13, 20, 15, 1, 20, 65, 4013 }, // б
{ 12, 13, 14, 1, 13, 39, 4078 }, // в
{ 12, 13, 13, 0, 13, 39, 4117 }, // г
{ 15, 18, 17, 1, 13, 68, 4156 }, // д
{ 11, 13, 13, 1, 13, 36, 4224 }, // е
{ 20, 13, 20, 0, 13, 65, 4260 }, // ж
{ 10, 13, 12, 1, 13, 33, 4325 }, // з
{ 16, 13, 17, 1, 13, 52, 4358 }, // и
{ 16, 19, 17, 1, 19, 76, 4410 }, // й
{ 14, 13, 15, 1, 13, 46, 4486 }, // к
{ 14, 13, 16, 1, 13, 46, 4532 }, // л
{ 17, 13, 19, 1, 13, 56, 4578 }, // м
{ 16, 13, 17, 1, 13, 52, 4634 }, // н
{ 13, 13, 15, 1, 13, 43, 4686 }, // о
{ 15, 13, 17, 1, 13, 49, 4729 }, // п
{ 15, 19, 16, 0, 13, 72, 4778 }, // р
{ 11, 13, 13, 1, 13, 36, 4850 }, // с
{ 12, 13, 13, 0, 13, 39, 4886 }, // т
{ 15, 19, 15, 0, 13, 72, 4925 }, // у
{ 17, 25, 19, 1, 19, 107, 4997 }, // ф
{ 15, 13, 15, 0, 13, 49, 5104 }, // х
{ 16, 18, 17, 1, 13, 72, 5153 }, // ц
{ 14, 13, 15, 0, 13, 46, 5225 }, // ч
{ 21, 13, 22, 0, 13, 69, 5271 }, // ш
{ 22, 18, 22, 0, 13, 99, 5340 }, // щ
{ 15, 13, 16, 1, 13, 49, 5439 }, // ъ
{ 19, 13, 20, 1, 13, 62, 5488 }, // ы
{ 12, 13, 13, 1, 13, 39, 5550 }, // ь
{ 12, 13, 13, 0, 13, 39, 5589 }, // э
{ 19, 13, 21, 1, 13, 62, 5628 }, // ю
{ 13, 13, 14, 0, 13, 43, 5690 }, // я
{ 11, 21, 13, 1, 21, 58, 5733 }, // ѐ
{ 11, 19, 13, 1, 19, 53, 5791 }, // ё
{ 15, 25, 16, 0, 19, 94, 5844 }, // ђ
{ 12, 21, 13, 0, 21, 63, 5938 }, // ѓ
{ 11, 13, 13, 1, 13, 36, 6001 }, // є
{ 10, 13, 12, 1, 13, 33, 6037 }, // ѕ
{ 9, 19, 8, -1, 19, 43, 6070 }, // і
{ 8, 18, 8, 0, 18, 36, 6113 }, // ї
{ 8, 24, 8, -2, 18, 48, 6149 }, // ј
{ 19, 13, 20, 0, 13, 62, 6197 }, // љ
{ 20, 13, 21, 1, 13, 65, 6259 }, // њ
{ 17, 19, 17, 0, 19, 81, 6324 }, // ћ
{ 14, 21, 15, 1, 21, 74, 6405 }, // ќ
{ 16, 21, 17, 1, 21, 84, 6479 }, // ѝ
{ 16, 25, 15, 0, 19, 100, 6563 }, // ў
{ 15, 18, 17, 1, 13, 68, 6663 }, // џ
{ 17, 20, 18, 0, 20, 85, 6731 }, // Ѣ
{ 14, 17, 15, 1, 17, 60, 6816 }, // ѣ
{ 17, 17, 19, 1, 17, 73, 6876 }, // Ѳ
{ 13, 13, 15, 1, 13, 43, 6949 }, // ѳ
{ 19, 17, 19, -1, 17, 81, 6992 }, // Ѵ
{ 15, 13, 15, 0, 13, 49, 7073 }, // ѵ
{ 20, 28, 21, 1, 23, 140, 7122 }, // Ҋ
{ 16, 24, 17, 1, 19, 96, 7262 }, // ҋ
{ 14, 17, 16, 1, 17, 60, 7358 }, // Ҍ
{ 13, 17, 14, 0, 17, 56, 7418 }, // ҍ
{ 14, 17, 15, 0, 17, 60, 7474 }, // Ҏ
{ 15, 19, 16, 0, 13, 72, 7534 }, // ҏ
{ 13, 21, 15, 1, 21, 69, 7606 }, // Ґ
{ 10, 16, 12, 1, 16, 40, 7675 }, // ґ
{ 13, 17, 15, 1, 17, 56, 7715 }, // Ғ
{ 11, 13, 13, 1, 13, 36, 7771 }, // ғ
{ 16, 22, 18, 1, 17, 88, 7807 }, // Ҕ
{ 13, 19, 15, 1, 13, 62, 7895 }, // ҕ
{ 26, 22, 25, -1, 17, 143, 7957 }, // Җ
{ 20, 17, 20, 0, 13, 85, 8100 }, // җ
{ 13, 22, 14, 0, 17, 72, 8185 }, // Ҙ
{ 11, 17, 13, 1, 13, 47, 8257 }, // ҙ
{ 18, 22, 17, 0, 17, 99, 8304 }, // Қ
{ 14, 18, 15, 1, 13, 63, 8403 }, // қ
{ 19, 17, 18, 0, 17, 81, 8466 }, // Ҝ
{ 14, 13, 15, 1, 13, 46, 8547 }, // ҝ
{ 17, 17, 18, 1, 17, 73, 8593 }, // Ҟ
{ 15, 17, 15, 0, 17, 64, 8666 }, // ҟ
{ 20, 17, 20, 0, 17, 85, 8730 }, // Ҡ
{ 16, 13, 16, 0, 13, 52, 8815 }, // ҡ
{ 20, 22, 22, 1, 17, 110, 8867 }, // Ң
{ 16, 18, 18, 1, 13, 72, 8977 }, // ң
{ 23, 17, 24, 0, 17, 98, 9049 }, // Ҥ
{ 19, 13, 20, 0, 13, 62, 9147 }, // ҥ
{ 25, 22, 27, 1, 17, 138, 9209 }, // Ҧ
{ 22, 19, 24, 1, 13, 105, 9347 }, // ҧ
{ 19, 17, 21, 1, 17, 81, 9452 }, // Ҩ
{ 15, 13, 16, 1, 13, 49, 9533 }, // ҩ
{ 14, 22, 16, 1, 17, 77, 9582 }, // Ҫ
{ 11, 18, 13, 1, 13, 50, 9659 }, // ҫ
{ 15, 22, 17, 1, 17, 83, 9709 }, // Ҭ
{ 12, 18, 13, 0, 13, 54, 9792 }, // ҭ
{ 18, 17, 17, -1, 17, 77, 9846 }, // Ү
{ 15, 19, 15, 0, 13, 72, 9923 }, // ү
{ 18, 17, 17, 0, 17, 77, 9995 }, // Ұ
{ 16, 19, 15, 0, 13, 76, 10072 }, // ұ
{ 18, 22, 19, 0, 17, 99, 10148 }, // Ҳ
{ 15, 18, 15, 0, 13, 68, 10247 }, // ҳ
{ 22, 22, 22, 0, 17, 121, 10315 }, // Ҵ
{ 19, 18, 20, 1, 13, 86, 10436 }, // ҵ
{ 17, 22, 18, 1, 17, 94, 10522 }, // Ҷ
{ 15, 18, 15, 0, 13, 68, 10616 }, // ҷ
{ 17, 17, 18, 1, 17, 73, 10684 }, // Ҹ
{ 14, 13, 15, 0, 13, 46, 10757 }, // ҹ
{ 17, 17, 19, 1, 17, 73, 10803 }, // Һ
{ 17, 19, 17, 0, 19, 81, 10876 }, // һ
{ 19, 17, 21, 1, 17, 81, 10957 }, // Ҽ
{ 14, 13, 16, 1, 13, 46, 11038 }, // ҽ
{ 19, 22, 21, 1, 17, 105, 11084 }, // Ҿ
{ 14, 18, 16, 1, 13, 63, 11189 }, // ҿ
{ 8, 17, 9, 0, 17, 34, 11252 }, // Ӏ
{ 26, 24, 25, 0, 24, 156, 11286 }, // Ӂ
{ 21, 19, 20, 0, 19, 100, 11442 }, // ӂ
{ 17, 22, 18, 0, 17, 94, 11542 }, // Ӄ
{ 13, 19, 15, 1, 13, 62, 11636 }, // ӄ
{ 17, 22, 19, 1, 17, 94, 11698 }, // Ӆ
{ 14, 17, 16, 1, 13, 60, 11792 }, // ӆ
{ 20, 22, 21, 1, 17, 110, 11852 }, // Ӈ
{ 16, 19, 17, 1, 13, 76, 11962 }, // ӈ
{ 20, 22, 21, 1, 17, 110, 12038 }, // Ӊ
{ 16, 18, 17, 1, 13, 72, 12148 }, // ӊ
{ 17, 22, 18, 1, 17, 94, 12220 }, // Ӌ
{ 14, 18, 15, 0, 13, 63, 12314 }, // ӌ
{ 23, 22, 23, 0, 17, 127, 12377 }, // Ӎ
{ 18, 18, 19, 1, 13, 81, 12504 }, // ӎ
{ 9, 19, 8, 0, 19, 43, 12585 }, // ӏ
{ 19, 23, 19, -1, 23, 110, 12628 }, // Ӑ
{ 13, 19, 13, 1, 19, 62, 12738 }, // ӑ
{ 19, 22, 20, 0, 22, 105, 12800 }, // Ӓ
{ 13, 19, 14, 1, 19, 62, 12905 }, // ӓ
{ 23, 17, 23, 0, 17, 98, 12967 }, // Ӕ
{ 18, 13, 20, 1, 13, 59, 13065 }, // ӕ
{ 15, 23, 15, 0, 23, 87, 13124 }, // Ӗ
{ 11, 19, 13, 1, 19, 53, 13211 }, // ӗ
{ 15, 17, 17, 1, 17, 64, 13264 }, // Ә
{ 11, 13, 13, 1, 13, 36, 13328 }, // ә
{ 15, 23, 17, 1, 23, 87, 13364 }, // Ӛ
{ 11, 19, 13, 1, 19, 53, 13451 }, // ӛ
{ 25, 23, 25, 0, 23, 144, 13504 }, // Ӝ
{ 20, 19, 20, 0, 19, 95, 13648 }, // ӝ
{ 13, 23, 15, 1, 23, 75, 13743 }, // Ӟ
{ 11, 19, 12, 0, 19, 53, 13818 }, // ӟ
{ 13, 17, 14, 0, 17, 56, 13871 }, // Ӡ
{ 12, 19, 13, 0, 13, 57, 13927 }, // ӡ
{ 20, 22, 22, 1, 22, 110, 13984 }, // Ӣ
{ 16, 17, 17, 1, 17, 68, 14094 }, // ӣ
{ 20, 22, 22, 1, 22, 110, 14162 }, // Ӥ
{ 16, 18, 17, 1, 18, 72, 14272 }, // ӥ
{ 17, 23, 19, 1, 23, 98, 14344 }, // Ӧ
{ 13, 19, 15, 1, 19, 62, 14442 }, // ӧ
{ 17, 17, 19, 1, 17, 73, 14504 }, // Ө
{ 13, 13, 15, 1, 13, 43, 14577 }, // ө
{ 17, 23, 21, 1, 23, 98, 14620 }, // Ӫ
{ 13, 19, 15, 1, 19, 62, 14718 }, // ӫ
{ 15, 23, 17, 1, 23, 87, 14780 }, // Ӭ
{ 12, 19, 13, 0, 19, 57, 14867 }, // ӭ
{ 18, 22, 18, 0, 22, 99, 14924 }, // Ӯ
{ 15, 23, 15, 0, 17, 87, 15023 }, // ӯ
{ 19, 23, 18, 0, 23, 110, 15110 }, // Ӱ
{ 15, 24, 14, 0, 18, 90, 15220 }, // ӱ
{ 18, 24, 18, 0, 24, 108, 15310 }, // Ӳ
{ 16, 27, 15, 0, 21, 108, 15418 }, // ӳ
{ 17, 22, 18, 1, 22, 94, 15526 }, // Ӵ
{ 14, 18, 15, 0, 18, 63, 15620 }, // ӵ
{ 14, 22, 15, 1, 17, 77, 15683 }, // Ӷ
{ 12, 18, 13, 0, 13, 54, 15760 }, // ӷ
{ 22, 22, 25, 1, 22, 121, 15814 }, // Ӹ
{ 19, 18, 20, 1, 18, 86, 15935 }, // ӹ
{ 13, 22, 15, 1, 17, 72, 16021 }, // Ӻ
{ 11, 18, 13, 1, 13, 50, 16093 }, // ӻ
{ 18, 22, 18, 0, 17, 99, 16143 }, // Ӽ
{ 15, 19, 15, 0, 13, 72, 16242 }, // ӽ
{ 19, 17, 19, -1, 17, 81, 16314 }, // Ӿ
{ 15, 13, 15, -1, 13, 49, 16395 }, // ӿ
perf: Reduce overall flash usage by 30.7% by compressing built-in fonts (#831) ## Summary **What is the goal of this PR?** Compress reader font bitmaps to reduce flash usage by 30.7%. **What changes are included?** - New `EpdFontGroup` struct and extended `EpdFontData` with `groups`/`groupCount` fields - `--compress` flag in `fontconvert.py`: groups glyphs (ASCII base group + groups of 8) and compresses each with raw DEFLATE - `FontDecompressor` class with 4-slot LRU cache for on-demand decompression during rendering - `GfxRenderer` transparently routes bitmap access through `getGlyphBitmap()` (compressed or direct flash) - Uses `uzlib` for decompression with minimal heap overhead. - 48 reader fonts (Bookerly, NotoSans 12-18pt, OpenDyslexic) regenerated with compression; 5 UI fonts unchanged - Round-trip verification script (`verify_compression.py`) runs as part of font generation ## Additional Context ## Flash & RAM | | baseline | font-compression | Difference | |--|--------|-----------------|------------| | Flash (ELF) | 6,302,476 B (96.2%) | 4,365,022 B (66.6%) | -1,937,454 B (-30.7%) | | firmware.bin | 6,468,192 B | 4,531,008 B | -1,937,184 B (-29.9%) | | RAM | 101,700 B (31.0%) | 103,076 B (31.5%) | +1,376 B (+0.5%) | ## Script-Based Grouping (Cold Cache) Comparison of uncompressed baseline vs script-based group compression (4-slot LRU cache, cleared each page). Glyphs are grouped by Unicode block (ASCII, Latin-1, Latin Extended-A, Combining Marks, Cyrillic, General Punctuation, etc.) instead of sequential groups of 8. ### Render Time | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Median** | 414.9 ms | 431.6 ms | +16.7 ms (+4.0%) | | **Pages** | 37 | 37 | | ### Memory Usage | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Heap free (median)** | 187.0 KB | 176.3 KB | -10.7 KB | | **Heap free (min)** | 186.0 KB | 166.5 KB | -19.5 KB | | **Largest block (median)** | 148.0 KB | 128.0 KB | -20.0 KB | | **Largest block (min)** | 148.0 KB | 120.0 KB | -28.0 KB | ### Cache Effectiveness | | Misses/page | Hit rate | |---|---|---| | **Compressed (cold cache)** | 2.1 | 99.85% | ------ ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**YES**_ Implementation was done by Claude Code (Opus 4.6) based on a plan developed collaboratively. All generated font headers were verified with an automated round-trip decompression test. The firmware was compiled successfully but has not yet been tested on-device. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:30:15 +11:00
{ 0, 0, 13, 0, 0, 0, 0 }, //  
{ 0, 0, 25, 0, 0, 0, 0 }, //
{ 0, 0, 13, 0, 0, 0, 0 }, //
{ 0, 0, 25, 0, 0, 0, 0 }, //
{ 0, 0, 8, 0, 0, 0, 0 }, //
{ 0, 0, 6, 0, 0, 0, 0 }, //
{ 0, 0, 4, 0, 0, 0, 0 }, //
{ 0, 0, 16, 0, 0, 0, 0 }, //
{ 0, 0, 7, 0, 0, 0, 0 }, //
{ 0, 0, 5, 0, 0, 0, 0 }, //
{ 0, 0, 1, 0, 0, 0, 0 }, //
{ 0, 0, 0, 0, 0, 0, 0 }, //
fix: force auto-hinting for Bookerly to fix inconsistent stem widths (#1098) ## Summary Bookerly's native TrueType hinting is effectively a no-op at the sizes used here, causing FreeType to place stems at inconsistent sub-pixel positions. This results in the 'k' stem (8-bit fringe: 0x38=56) falling just below the 2-bit quantization threshold while 'l' and 'h' stems (fringes: 0x4C=76, 0x40=64) land above it --- making 'k' visibly narrower (2.00px vs 2.33px effective width). FreeType's auto-hinter snaps all stems to consistent grid positions, normalizing effective stem width to 2.67px across all glyphs. Adds --force-autohint flag to fontconvert.py and applies it to Bookerly only. NotoSans, OpenDyslexic, and Ubuntu fonts are unaffected. Here is an example of before/after. Take notice of the vertical stems on characters like `l`, `k`, `n`, `i`, etc. The font is Bookerly 12pt regular: **BEFORE**: ![before](https://github.com/user-attachments/assets/65b2acab-ad95-489e-885e-e3a0163cc252) **AFTER**: ![after](https://github.com/user-attachments/assets/d09a8b5d-40af-4a7d-b622-e1b2cabcce85) Claude generated this script to quantitatively determine that this change makes the vertical stems on a variety of characters more consistent for Bookerly _only_. <details> <summary>Python script</summary> ```python #!/usr/bin/env python3 """Compare stem consistency across all font families with and without auto-hinting. Run from repo root: python3 compare_all_fonts.py """ import freetype DPI = 150 CHARS = ["k", "l", "h", "i", "b", "d"] SIZES = [12, 14, 16, 18] FONTS = { "Bookerly": "lib/EpdFont/builtinFonts/source/Bookerly/Bookerly-Regular.ttf", "NotoSans": "lib/EpdFont/builtinFonts/source/NotoSans/NotoSans-Regular.ttf", "OpenDyslexic": "lib/EpdFont/builtinFonts/source/OpenDyslexic/OpenDyslexic-Regular.otf", "Ubuntu": "lib/EpdFont/builtinFonts/source/Ubuntu/Ubuntu-Regular.ttf", } MODES = { "default": freetype.FT_LOAD_RENDER, "autohint": freetype.FT_LOAD_RENDER | freetype.FT_LOAD_FORCE_AUTOHINT, } def q4to2(v): if v >= 12: return 3 elif v >= 8: return 2 elif v >= 4: return 1 else: return 0 def get_stem_eff(face, char, flags): gi = face.get_char_index(ord(char)) if gi == 0: return None face.load_glyph(gi, flags) bm = face.glyph.bitmap w, h = bm.width, bm.rows if w == 0 or h == 0: return None p2 = [] for y in range(h): row = [] for x in range(w): row.append(q4to2(bm.buffer[y * bm.pitch + x] >> 4)) p2.append(row) # Measure leftmost stem in stable middle rows mid_start, mid_end = h // 4, h - h // 4 widths = [] for y in range(mid_start, mid_end): first = next((x for x in range(w) if p2[y][x] > 0), -1) if first < 0: continue last = first for x in range(first, w): if p2[y][x] > 0: last = x else: break eff = sum(p2[y][x] for x in range(first, last + 1)) / 3.0 widths.append(eff) return round(sum(widths) / len(widths), 2) if widths else None def main(): for font_name, font_path in FONTS.items(): try: freetype.Face(font_path) except Exception: print(f"\n {font_name}: SKIPPED (file not found)") continue print(f"\n{'=' * 80}") print(f" {font_name}") print(f"{'=' * 80}") for size in SIZES: print(f"\n {size}pt:") print(f" {'':6s}", end="") for c in CHARS: print(f" '{c}' ", end="") print(" | spread") for mode_name, flags in MODES.items(): face = freetype.Face(font_path) face.set_char_size(size << 6, size << 6, DPI, DPI) vals = [] print(f" {mode_name:6s}", end="") for c in CHARS: v = get_stem_eff(face, c, flags) vals.append(v) print(f" {v:5.2f}" if v else " N/A", end="") valid = [v for v in vals if v is not None] spread = max(valid) - min(valid) if len(valid) >= 2 else 0 marker = " <-- inconsistent" if spread > 0.5 else "" print(f" | {spread:.2f}{marker}") if __name__ == "__main__": main() ``` </details> Here are the results. The table compares how the font-generation `autohint` flag affects the range of widths of various characters. Lower `spread` mean that glyph stroke widths should appear more consistent. ``` Spread = max stem width - min stem width across glyphs (lower = more consistent): ┌──────────────┬──────┬─────────┬──────────┬──────────┐ │ Font │ Size │ Default │ Autohint │ Winner │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Bookerly │ 12pt │ 1.49 │ 1.12 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.39 │ 1.13 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.38 │ 1.16 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.90 │ 1.58 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ NotoSans │ 12pt │ 1.16 │ 0.94 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 0.83 │ 1.14 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.41 │ 1.51 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.74 │ 1.63 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ OpenDyslexic │ 12pt │ 2.22 │ 1.44 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 2.57 │ 3.29 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 3.13 │ 2.60 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 3.21 │ 3.23 │ ~tied │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Ubuntu │ 12pt │ 1.25 │ 1.31 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.41 │ 1.64 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 2.21 │ 1.71 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.80 │ 1.71 │ autohint │ └──────────────┴──────┴─────────┴──────────┴──────────┘ ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? I used AI to make sure I'm not doing something stupid, since I'm not a typography expert. I made the changes though.
2026-02-24 06:13:08 +11:00
{ 1, 19, 0, 0, 13, 5, 0 }, //
{ 5, 22, 0, -2, 16, 28, 5 }, //
{ 9, 23, 0, -4, 17, 52, 33 }, //
{ 8, 23, 0, -4, 17, 46, 85 }, //
{ 8, 2, 10, 1, 7, 4, 131 }, //
{ 8, 2, 10, 1, 7, 4, 135 }, //
{ 11, 2, 15, 2, 9, 6, 139 }, //
{ 13, 2, 13, 0, 7, 7, 145 }, //
{ 25, 2, 25, 0, 7, 13, 152 }, // —
{ 25, 2, 25, 0, 7, 13, 165 }, // ―
{ 8, 25, 13, 3, 19, 50, 178 }, // ‖
{ 13, 5, 13, 0, -1, 17, 228 }, // ‗
{ 5, 8, 6, 1, 19, 10, 245 }, //
{ 5, 8, 6, 0, 19, 10, 255 }, //
{ 5, 8, 6, 0, 4, 10, 265 }, //
{ 5, 8, 6, 1, 19, 10, 275 }, //
{ 10, 8, 11, 1, 19, 20, 285 }, // “
{ 10, 8, 11, 0, 19, 20, 305 }, // ”
{ 10, 8, 11, 0, 4, 20, 325 }, // „
{ 10, 8, 11, 1, 19, 20, 345 }, // ‟
{ 11, 16, 13, 1, 17, 44, 365 }, // †
{ 11, 19, 13, 1, 17, 53, 409 }, // ‡
{ 5, 5, 7, 1, 9, 7, 462 }, // •
{ 8, 9, 16, 4, 13, 18, 469 }, // ‣
{ 4, 3, 8, 2, 3, 3, 487 }, //
{ 10, 3, 12, 1, 3, 8, 490 }, // ‥
{ 20, 3, 24, 2, 3, 15, 498 }, // …
{ 4, 3, 8, 2, 8, 3, 513 }, // ‧
{ 0, 0, 0, 0, 0, 0, 516 }, //
{ 0, 0, 0, 0, 0, 0, 516 }, //
{ 9, 23, 0, -4, 17, 52, 516 }, //
{ 8, 23, 0, -4, 17, 46, 568 }, //
{ 8, 23, 0, -3, 17, 46, 614 }, //
{ 11, 23, 0, -5, 17, 64, 660 }, //
{ 10, 23, 0, -5, 17, 58, 724 }, //
{ 0, 0, 3, 0, 0, 0, 782 }, //
{ 32, 19, 34, 1, 18, 152, 782 }, // ‰
{ 5, 9, 7, 1, 18, 12, 934 }, //
{ 10, 9, 12, 1, 18, 23, 946 }, // ″
{ 15, 9, 17, 1, 18, 34, 969 }, // ‴
{ 5, 9, 7, 1, 18, 12, 1003 }, //
{ 10, 9, 12, 1, 18, 23, 1015 }, // ‶
{ 16, 9, 18, 1, 18, 36, 1038 }, // ‷
{ 11, 6, 12, 1, 1, 17, 1074 }, // ‸
{ 6, 9, 8, 1, 11, 14, 1091 }, //
{ 6, 9, 8, 1, 11, 14, 1105 }, //
{ 16, 17, 15, -1, 16, 68, 1119 }, // ※
{ 10, 19, 13, 2, 19, 48, 1187 }, // ‼
{ 13, 2, 13, 0, 20, 7, 1235 }, // ‾
{ 6, 2, 8, 1, 7, 3, 1242 }, //
{ 13, 20, 5, -4, 18, 65, 1245 }, //
{ 20, 17, 22, 1, 17, 85, 1310 }, // ⁇
{ 16, 19, 18, 1, 19, 76, 1395 }, // ⁈
{ 15, 19, 18, 2, 19, 72, 1471 }, // ⁉
{ 15, 6, 25, 5, 10, 23, 1543 }, //
{ 20, 9, 21, 1, 18, 45, 1566 }, // ⁗
{ 0, 0, 6, 0, 0, 0, 1611 }, //
{ 0, 0, 0, 0, 0, 0, 1611 }, //
{ 0, 0, 0, 0, 0, 0, 1611 }, //
{ 0, 0, 0, 0, 0, 0, 1611 }, //
{ 0, 0, 0, 0, 0, 0, 1611 }, //
{ 0, 0, 0, 0, 0, 0, 1611 }, //
{ 10, 11, 11, 1, 20, 28, 0 }, // ⁰
{ 10, 12, 11, 0, 21, 30, 28 }, // ⁴
{ 9, 11, 11, 1, 20, 25, 58 }, // ⁵
{ 9, 11, 11, 2, 20, 25, 83 }, // ⁶
{ 8, 11, 11, 2, 20, 22, 108 }, // ⁷
{ 8, 11, 12, 2, 20, 22, 130 }, // ⁸
{ 9, 11, 12, 2, 20, 25, 152 }, // ⁹
{ 11, 8, 15, 2, 17, 22, 177 }, // ⁿ
{ 10, 11, 11, 1, 8, 28, 199 }, // ₀
{ 8, 12, 11, 2, 9, 24, 227 }, // ₁
{ 8, 11, 11, 2, 8, 22, 251 }, // ₂
{ 8, 11, 11, 2, 8, 22, 273 }, // ₃
{ 10, 12, 11, 0, 9, 30, 295 }, // ₄
{ 9, 11, 11, 1, 8, 25, 325 }, // ₅
{ 9, 11, 11, 2, 8, 25, 350 }, // ₆
{ 8, 11, 11, 2, 8, 22, 375 }, // ₇
{ 8, 11, 12, 2, 8, 22, 397 }, // ₈
{ 9, 11, 12, 2, 8, 25, 419 }, // ₉
{ 13, 17, 16, 1, 17, 56, 0 }, // ₣
{ 13, 17, 15, 1, 17, 56, 56 }, // ₤
{ 31, 17, 32, 0, 17, 132, 112 }, // ₧
{ 15, 17, 15, 0, 17, 64, 244 }, // €
{ 15, 10, 25, 5, 14, 38, 0 }, // ←
{ 10, 16, 25, 7, 17, 40, 38 }, // ↑
{ 15, 10, 25, 5, 14, 38, 78 }, // →
{ 10, 16, 25, 7, 17, 40, 116 }, // ↓
{ 15, 11, 25, 5, 14, 42, 156 }, // ↔
{ 11, 17, 25, 7, 17, 47, 198 }, // ↕
{ 11, 17, 25, 7, 18, 47, 245 }, // ↨
{ 11, 17, 25, 7, 17, 47, 292 }, // ↲
{ 11, 17, 25, 7, 17, 47, 339 }, // ↳
{ 13, 13, 25, 6, 15, 43, 386 }, // ↵
{ 15, 11, 25, 5, 14, 42, 429 }, // ⇐
{ 11, 15, 25, 7, 16, 42, 471 }, // ⇑
{ 15, 11, 25, 5, 14, 42, 513 }, // ⇒
{ 11, 15, 25, 7, 16, 42, 555 }, // ⇓
{ 15, 11, 25, 5, 14, 42, 597 }, // ⇔
perf: Reduce overall flash usage by 30.7% by compressing built-in fonts (#831) ## Summary **What is the goal of this PR?** Compress reader font bitmaps to reduce flash usage by 30.7%. **What changes are included?** - New `EpdFontGroup` struct and extended `EpdFontData` with `groups`/`groupCount` fields - `--compress` flag in `fontconvert.py`: groups glyphs (ASCII base group + groups of 8) and compresses each with raw DEFLATE - `FontDecompressor` class with 4-slot LRU cache for on-demand decompression during rendering - `GfxRenderer` transparently routes bitmap access through `getGlyphBitmap()` (compressed or direct flash) - Uses `uzlib` for decompression with minimal heap overhead. - 48 reader fonts (Bookerly, NotoSans 12-18pt, OpenDyslexic) regenerated with compression; 5 UI fonts unchanged - Round-trip verification script (`verify_compression.py`) runs as part of font generation ## Additional Context ## Flash & RAM | | baseline | font-compression | Difference | |--|--------|-----------------|------------| | Flash (ELF) | 6,302,476 B (96.2%) | 4,365,022 B (66.6%) | -1,937,454 B (-30.7%) | | firmware.bin | 6,468,192 B | 4,531,008 B | -1,937,184 B (-29.9%) | | RAM | 101,700 B (31.0%) | 103,076 B (31.5%) | +1,376 B (+0.5%) | ## Script-Based Grouping (Cold Cache) Comparison of uncompressed baseline vs script-based group compression (4-slot LRU cache, cleared each page). Glyphs are grouped by Unicode block (ASCII, Latin-1, Latin Extended-A, Combining Marks, Cyrillic, General Punctuation, etc.) instead of sequential groups of 8. ### Render Time | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Median** | 414.9 ms | 431.6 ms | +16.7 ms (+4.0%) | | **Pages** | 37 | 37 | | ### Memory Usage | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Heap free (median)** | 187.0 KB | 176.3 KB | -10.7 KB | | **Heap free (min)** | 186.0 KB | 166.5 KB | -19.5 KB | | **Largest block (median)** | 148.0 KB | 128.0 KB | -20.0 KB | | **Largest block (min)** | 148.0 KB | 120.0 KB | -28.0 KB | ### Cache Effectiveness | | Misses/page | Hit rate | |---|---|---| | **Compressed (cold cache)** | 2.1 | 99.85% | ------ ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**YES**_ Implementation was done by Claude Code (Opus 4.6) based on a plan developed collaboratively. All generated font headers were verified with an automated round-trip decompression test. The firmware was compiled successfully but has not yet been tested on-device. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:30:15 +11:00
{ 17, 19, 25, 4, 18, 81, 0 }, // ∀
fix: force auto-hinting for Bookerly to fix inconsistent stem widths (#1098) ## Summary Bookerly's native TrueType hinting is effectively a no-op at the sizes used here, causing FreeType to place stems at inconsistent sub-pixel positions. This results in the 'k' stem (8-bit fringe: 0x38=56) falling just below the 2-bit quantization threshold while 'l' and 'h' stems (fringes: 0x4C=76, 0x40=64) land above it --- making 'k' visibly narrower (2.00px vs 2.33px effective width). FreeType's auto-hinter snaps all stems to consistent grid positions, normalizing effective stem width to 2.67px across all glyphs. Adds --force-autohint flag to fontconvert.py and applies it to Bookerly only. NotoSans, OpenDyslexic, and Ubuntu fonts are unaffected. Here is an example of before/after. Take notice of the vertical stems on characters like `l`, `k`, `n`, `i`, etc. The font is Bookerly 12pt regular: **BEFORE**: ![before](https://github.com/user-attachments/assets/65b2acab-ad95-489e-885e-e3a0163cc252) **AFTER**: ![after](https://github.com/user-attachments/assets/d09a8b5d-40af-4a7d-b622-e1b2cabcce85) Claude generated this script to quantitatively determine that this change makes the vertical stems on a variety of characters more consistent for Bookerly _only_. <details> <summary>Python script</summary> ```python #!/usr/bin/env python3 """Compare stem consistency across all font families with and without auto-hinting. Run from repo root: python3 compare_all_fonts.py """ import freetype DPI = 150 CHARS = ["k", "l", "h", "i", "b", "d"] SIZES = [12, 14, 16, 18] FONTS = { "Bookerly": "lib/EpdFont/builtinFonts/source/Bookerly/Bookerly-Regular.ttf", "NotoSans": "lib/EpdFont/builtinFonts/source/NotoSans/NotoSans-Regular.ttf", "OpenDyslexic": "lib/EpdFont/builtinFonts/source/OpenDyslexic/OpenDyslexic-Regular.otf", "Ubuntu": "lib/EpdFont/builtinFonts/source/Ubuntu/Ubuntu-Regular.ttf", } MODES = { "default": freetype.FT_LOAD_RENDER, "autohint": freetype.FT_LOAD_RENDER | freetype.FT_LOAD_FORCE_AUTOHINT, } def q4to2(v): if v >= 12: return 3 elif v >= 8: return 2 elif v >= 4: return 1 else: return 0 def get_stem_eff(face, char, flags): gi = face.get_char_index(ord(char)) if gi == 0: return None face.load_glyph(gi, flags) bm = face.glyph.bitmap w, h = bm.width, bm.rows if w == 0 or h == 0: return None p2 = [] for y in range(h): row = [] for x in range(w): row.append(q4to2(bm.buffer[y * bm.pitch + x] >> 4)) p2.append(row) # Measure leftmost stem in stable middle rows mid_start, mid_end = h // 4, h - h // 4 widths = [] for y in range(mid_start, mid_end): first = next((x for x in range(w) if p2[y][x] > 0), -1) if first < 0: continue last = first for x in range(first, w): if p2[y][x] > 0: last = x else: break eff = sum(p2[y][x] for x in range(first, last + 1)) / 3.0 widths.append(eff) return round(sum(widths) / len(widths), 2) if widths else None def main(): for font_name, font_path in FONTS.items(): try: freetype.Face(font_path) except Exception: print(f"\n {font_name}: SKIPPED (file not found)") continue print(f"\n{'=' * 80}") print(f" {font_name}") print(f"{'=' * 80}") for size in SIZES: print(f"\n {size}pt:") print(f" {'':6s}", end="") for c in CHARS: print(f" '{c}' ", end="") print(" | spread") for mode_name, flags in MODES.items(): face = freetype.Face(font_path) face.set_char_size(size << 6, size << 6, DPI, DPI) vals = [] print(f" {mode_name:6s}", end="") for c in CHARS: v = get_stem_eff(face, c, flags) vals.append(v) print(f" {v:5.2f}" if v else " N/A", end="") valid = [v for v in vals if v is not None] spread = max(valid) - min(valid) if len(valid) >= 2 else 0 marker = " <-- inconsistent" if spread > 0.5 else "" print(f" | {spread:.2f}{marker}") if __name__ == "__main__": main() ``` </details> Here are the results. The table compares how the font-generation `autohint` flag affects the range of widths of various characters. Lower `spread` mean that glyph stroke widths should appear more consistent. ``` Spread = max stem width - min stem width across glyphs (lower = more consistent): ┌──────────────┬──────┬─────────┬──────────┬──────────┐ │ Font │ Size │ Default │ Autohint │ Winner │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Bookerly │ 12pt │ 1.49 │ 1.12 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.39 │ 1.13 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.38 │ 1.16 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.90 │ 1.58 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ NotoSans │ 12pt │ 1.16 │ 0.94 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 0.83 │ 1.14 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.41 │ 1.51 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.74 │ 1.63 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ OpenDyslexic │ 12pt │ 2.22 │ 1.44 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 2.57 │ 3.29 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 3.13 │ 2.60 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 3.21 │ 3.23 │ ~tied │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Ubuntu │ 12pt │ 1.25 │ 1.31 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.41 │ 1.64 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 2.21 │ 1.71 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.80 │ 1.71 │ autohint │ └──────────────┴──────┴─────────┴──────────┴──────────┘ ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? I used AI to make sure I'm not doing something stupid, since I'm not a typography expert. I made the changes though.
2026-02-24 06:13:08 +11:00
{ 13, 19, 16, 1, 19, 62, 81 }, // ∂
{ 11, 17, 25, 7, 17, 47, 143 }, // ∃
{ 19, 20, 25, 3, 19, 95, 190 }, // ∅
{ 15, 18, 16, 1, 18, 68, 285 }, // ∆
{ 17, 18, 25, 4, 17, 77, 353 }, // ∇
{ 17, 17, 25, 4, 17, 73, 430 }, // ∈
{ 17, 22, 25, 4, 19, 94, 503 }, // ∉
{ 16, 13, 25, 5, 15, 52, 597 }, // ∊
{ 17, 17, 25, 4, 17, 73, 649 }, // ∋
{ 17, 22, 25, 4, 19, 94, 722 }, // ∌
{ 16, 13, 25, 4, 15, 52, 816 }, // ∍
{ 19, 22, 20, 1, 17, 105, 868 }, // ∏
{ 15, 22, 15, 0, 17, 83, 973 }, // ∑
{ 11, 2, 16, 2, 9, 6, 1056 }, //
{ 12, 20, 12, 0, 18, 60, 1062 }, //
{ 12, 20, 13, 1, 18, 60, 1122 }, //
{ 12, 13, 16, 2, 15, 39, 1182 }, //
{ 8, 9, 16, 4, 13, 18, 1221 }, // ∘
{ 4, 4, 16, 6, 9, 4, 1239 }, // ∙
{ 16, 24, 16, 0, 21, 96, 1243 }, // √
{ 12, 9, 16, 2, 13, 27, 1339 }, // ∝
{ 15, 8, 16, 0, 12, 30, 1366 }, // ∞
{ 16, 18, 25, 4, 18, 72, 1396 }, // ∟
{ 18, 18, 25, 3, 18, 81, 1468 }, // ∠
{ 3, 25, 13, 5, 19, 19, 1549 }, //
{ 8, 25, 13, 2, 19, 50, 1568 }, // ∥
{ 17, 18, 25, 4, 18, 77, 1618 }, // ∧
{ 17, 18, 25, 4, 18, 77, 1695 }, //
{ 15, 18, 25, 5, 18, 68, 1772 }, // ∩
{ 15, 19, 25, 5, 18, 72, 1840 }, //
{ 14, 26, 16, 1, 20, 91, 1912 }, // ∫
{ 16, 15, 25, 5, 14, 60, 2003 }, // ∴
{ 16, 15, 25, 5, 14, 60, 2063 }, // ∵
{ 4, 13, 8, 2, 15, 13, 2123 }, //
{ 15, 15, 25, 5, 14, 57, 2136 }, // ∷
{ 15, 5, 25, 5, 9, 19, 2193 }, //
{ 15, 13, 25, 5, 15, 49, 2212 }, // ≅
{ 12, 9, 16, 2, 13, 27, 2261 }, // ≈
{ 15, 8, 25, 5, 11, 30, 2288 }, // ≍
{ 11, 13, 16, 2, 15, 36, 2318 }, // ≠
{ 15, 11, 25, 5, 13, 42, 2354 }, // ≡
{ 12, 15, 16, 2, 15, 45, 2396 }, // ≤
{ 12, 15, 16, 2, 15, 45, 2441 }, // ≥
{ 21, 13, 25, 2, 15, 69, 2486 }, // ≪
{ 21, 13, 25, 2, 15, 69, 2555 }, // ≫
{ 17, 13, 25, 4, 15, 56, 2624 }, // ⊃
{ 17, 22, 25, 4, 19, 94, 2680 }, // ⊄
{ 17, 23, 25, 4, 20, 98, 2774 }, // ⊅
{ 17, 17, 25, 4, 17, 73, 2872 }, // ⊆
{ 16, 17, 25, 5, 17, 68, 2945 }, // ⊇
{ 19, 19, 25, 3, 18, 91, 3013 }, // ⊕
{ 19, 19, 25, 3, 18, 91, 3104 }, // ⊖
{ 19, 19, 25, 3, 18, 91, 3195 }, // ⊗
{ 19, 19, 25, 3, 18, 91, 3286 }, // ⊘
{ 15, 18, 25, 5, 18, 68, 3377 }, // ⊥
{ 4, 4, 16, 6, 9, 4, 3445 }, // ⋅
{ 22, 4, 25, 2, 9, 22, 3449 }, // ⋯
perf: Reduce overall flash usage by 30.7% by compressing built-in fonts (#831) ## Summary **What is the goal of this PR?** Compress reader font bitmaps to reduce flash usage by 30.7%. **What changes are included?** - New `EpdFontGroup` struct and extended `EpdFontData` with `groups`/`groupCount` fields - `--compress` flag in `fontconvert.py`: groups glyphs (ASCII base group + groups of 8) and compresses each with raw DEFLATE - `FontDecompressor` class with 4-slot LRU cache for on-demand decompression during rendering - `GfxRenderer` transparently routes bitmap access through `getGlyphBitmap()` (compressed or direct flash) - Uses `uzlib` for decompression with minimal heap overhead. - 48 reader fonts (Bookerly, NotoSans 12-18pt, OpenDyslexic) regenerated with compression; 5 UI fonts unchanged - Round-trip verification script (`verify_compression.py`) runs as part of font generation ## Additional Context ## Flash & RAM | | baseline | font-compression | Difference | |--|--------|-----------------|------------| | Flash (ELF) | 6,302,476 B (96.2%) | 4,365,022 B (66.6%) | -1,937,454 B (-30.7%) | | firmware.bin | 6,468,192 B | 4,531,008 B | -1,937,184 B (-29.9%) | | RAM | 101,700 B (31.0%) | 103,076 B (31.5%) | +1,376 B (+0.5%) | ## Script-Based Grouping (Cold Cache) Comparison of uncompressed baseline vs script-based group compression (4-slot LRU cache, cleared each page). Glyphs are grouped by Unicode block (ASCII, Latin-1, Latin Extended-A, Combining Marks, Cyrillic, General Punctuation, etc.) instead of sequential groups of 8. ### Render Time | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Median** | 414.9 ms | 431.6 ms | +16.7 ms (+4.0%) | | **Pages** | 37 | 37 | | ### Memory Usage | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Heap free (median)** | 187.0 KB | 176.3 KB | -10.7 KB | | **Heap free (min)** | 186.0 KB | 166.5 KB | -19.5 KB | | **Largest block (median)** | 148.0 KB | 128.0 KB | -20.0 KB | | **Largest block (min)** | 148.0 KB | 120.0 KB | -28.0 KB | ### Cache Effectiveness | | Misses/page | Hit rate | |---|---|---| | **Compressed (cold cache)** | 2.1 | 99.85% | ------ ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**YES**_ Implementation was done by Claude Code (Opus 4.6) based on a plan developed collaboratively. All generated font headers were verified with an automated round-trip decompression test. The firmware was compiled successfully but has not yet been tested on-device. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:30:15 +11:00
{ 25, 24, 25, 0, 21, 150, 0 }, // <20>
};
static const EpdUnicodeInterval bookerly_12_regularIntervals[] = {
{ 0x0, 0x0, 0x0 },
{ 0x8, 0x9, 0x1 },
{ 0xD, 0xD, 0x3 },
{ 0x1D, 0x1D, 0x4 },
{ 0x20, 0x7E, 0x5 },
{ 0xA0, 0xFF, 0x64 },
{ 0x100, 0x17F, 0xC4 },
{ 0x300, 0x304, 0x144 },
{ 0x306, 0x30C, 0x149 },
{ 0x30F, 0x30F, 0x150 },
{ 0x311, 0x315, 0x151 },
{ 0x31B, 0x31B, 0x156 },
{ 0x323, 0x329, 0x157 },
{ 0x32D, 0x32E, 0x15E },
{ 0x330, 0x331, 0x160 },
{ 0x342, 0x342, 0x162 },
{ 0x344, 0x345, 0x163 },
{ 0x400, 0x45F, 0x165 },
{ 0x462, 0x463, 0x1C5 },
{ 0x472, 0x475, 0x1C7 },
{ 0x48A, 0x4FF, 0x1CB },
{ 0x2000, 0x2030, 0x241 },
{ 0x2032, 0x203C, 0x272 },
{ 0x203E, 0x203E, 0x27D },
{ 0x2043, 0x2044, 0x27E },
{ 0x2047, 0x2049, 0x280 },
{ 0x2053, 0x2053, 0x283 },
{ 0x2057, 0x2057, 0x284 },
{ 0x205F, 0x2064, 0x285 },
{ 0x2070, 0x2070, 0x28B },
{ 0x2074, 0x2079, 0x28C },
{ 0x207F, 0x2089, 0x292 },
{ 0x20A3, 0x20A4, 0x29D },
{ 0x20A7, 0x20A7, 0x29F },
{ 0x20AC, 0x20AC, 0x2A0 },
{ 0x2190, 0x2195, 0x2A1 },
{ 0x21A8, 0x21A8, 0x2A7 },
{ 0x21B2, 0x21B3, 0x2A8 },
{ 0x21B5, 0x21B5, 0x2AA },
{ 0x21D0, 0x21D4, 0x2AB },
{ 0x2200, 0x2200, 0x2B0 },
{ 0x2202, 0x2203, 0x2B1 },
{ 0x2205, 0x220D, 0x2B3 },
{ 0x220F, 0x220F, 0x2BC },
{ 0x2211, 0x2212, 0x2BD },
{ 0x2215, 0x221A, 0x2BF },
{ 0x221D, 0x2220, 0x2C5 },
{ 0x2223, 0x2223, 0x2C9 },
{ 0x2225, 0x2225, 0x2CA },
{ 0x2227, 0x222B, 0x2CB },
{ 0x2234, 0x2237, 0x2D0 },
{ 0x223C, 0x223C, 0x2D4 },
{ 0x2245, 0x2245, 0x2D5 },
{ 0x2248, 0x2248, 0x2D6 },
{ 0x224D, 0x224D, 0x2D7 },
{ 0x2260, 0x2261, 0x2D8 },
{ 0x2264, 0x2265, 0x2DA },
{ 0x226A, 0x226B, 0x2DC },
{ 0x2283, 0x2287, 0x2DE },
{ 0x2295, 0x2298, 0x2E3 },
{ 0x22A5, 0x22A5, 0x2E7 },
{ 0x22C5, 0x22C5, 0x2E8 },
{ 0x22EF, 0x22EF, 0x2E9 },
{ 0xFFFD, 0xFFFD, 0x2EA },
};
perf: Reduce overall flash usage by 30.7% by compressing built-in fonts (#831) ## Summary **What is the goal of this PR?** Compress reader font bitmaps to reduce flash usage by 30.7%. **What changes are included?** - New `EpdFontGroup` struct and extended `EpdFontData` with `groups`/`groupCount` fields - `--compress` flag in `fontconvert.py`: groups glyphs (ASCII base group + groups of 8) and compresses each with raw DEFLATE - `FontDecompressor` class with 4-slot LRU cache for on-demand decompression during rendering - `GfxRenderer` transparently routes bitmap access through `getGlyphBitmap()` (compressed or direct flash) - Uses `uzlib` for decompression with minimal heap overhead. - 48 reader fonts (Bookerly, NotoSans 12-18pt, OpenDyslexic) regenerated with compression; 5 UI fonts unchanged - Round-trip verification script (`verify_compression.py`) runs as part of font generation ## Additional Context ## Flash & RAM | | baseline | font-compression | Difference | |--|--------|-----------------|------------| | Flash (ELF) | 6,302,476 B (96.2%) | 4,365,022 B (66.6%) | -1,937,454 B (-30.7%) | | firmware.bin | 6,468,192 B | 4,531,008 B | -1,937,184 B (-29.9%) | | RAM | 101,700 B (31.0%) | 103,076 B (31.5%) | +1,376 B (+0.5%) | ## Script-Based Grouping (Cold Cache) Comparison of uncompressed baseline vs script-based group compression (4-slot LRU cache, cleared each page). Glyphs are grouped by Unicode block (ASCII, Latin-1, Latin Extended-A, Combining Marks, Cyrillic, General Punctuation, etc.) instead of sequential groups of 8. ### Render Time | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Median** | 414.9 ms | 431.6 ms | +16.7 ms (+4.0%) | | **Pages** | 37 | 37 | | ### Memory Usage | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Heap free (median)** | 187.0 KB | 176.3 KB | -10.7 KB | | **Heap free (min)** | 186.0 KB | 166.5 KB | -19.5 KB | | **Largest block (median)** | 148.0 KB | 128.0 KB | -20.0 KB | | **Largest block (min)** | 148.0 KB | 120.0 KB | -28.0 KB | ### Cache Effectiveness | | Misses/page | Hit rate | |---|---|---| | **Compressed (cold cache)** | 2.1 | 99.85% | ------ ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**YES**_ Implementation was done by Claude Code (Opus 4.6) based on a plan developed collaboratively. All generated font headers were verified with an automated round-trip decompression test. The firmware was compiled successfully but has not yet been tested on-device. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:30:15 +11:00
static const EpdFontGroup bookerly_12_regularGroups[] = {
fix: force auto-hinting for Bookerly to fix inconsistent stem widths (#1098) ## Summary Bookerly's native TrueType hinting is effectively a no-op at the sizes used here, causing FreeType to place stems at inconsistent sub-pixel positions. This results in the 'k' stem (8-bit fringe: 0x38=56) falling just below the 2-bit quantization threshold while 'l' and 'h' stems (fringes: 0x4C=76, 0x40=64) land above it --- making 'k' visibly narrower (2.00px vs 2.33px effective width). FreeType's auto-hinter snaps all stems to consistent grid positions, normalizing effective stem width to 2.67px across all glyphs. Adds --force-autohint flag to fontconvert.py and applies it to Bookerly only. NotoSans, OpenDyslexic, and Ubuntu fonts are unaffected. Here is an example of before/after. Take notice of the vertical stems on characters like `l`, `k`, `n`, `i`, etc. The font is Bookerly 12pt regular: **BEFORE**: ![before](https://github.com/user-attachments/assets/65b2acab-ad95-489e-885e-e3a0163cc252) **AFTER**: ![after](https://github.com/user-attachments/assets/d09a8b5d-40af-4a7d-b622-e1b2cabcce85) Claude generated this script to quantitatively determine that this change makes the vertical stems on a variety of characters more consistent for Bookerly _only_. <details> <summary>Python script</summary> ```python #!/usr/bin/env python3 """Compare stem consistency across all font families with and without auto-hinting. Run from repo root: python3 compare_all_fonts.py """ import freetype DPI = 150 CHARS = ["k", "l", "h", "i", "b", "d"] SIZES = [12, 14, 16, 18] FONTS = { "Bookerly": "lib/EpdFont/builtinFonts/source/Bookerly/Bookerly-Regular.ttf", "NotoSans": "lib/EpdFont/builtinFonts/source/NotoSans/NotoSans-Regular.ttf", "OpenDyslexic": "lib/EpdFont/builtinFonts/source/OpenDyslexic/OpenDyslexic-Regular.otf", "Ubuntu": "lib/EpdFont/builtinFonts/source/Ubuntu/Ubuntu-Regular.ttf", } MODES = { "default": freetype.FT_LOAD_RENDER, "autohint": freetype.FT_LOAD_RENDER | freetype.FT_LOAD_FORCE_AUTOHINT, } def q4to2(v): if v >= 12: return 3 elif v >= 8: return 2 elif v >= 4: return 1 else: return 0 def get_stem_eff(face, char, flags): gi = face.get_char_index(ord(char)) if gi == 0: return None face.load_glyph(gi, flags) bm = face.glyph.bitmap w, h = bm.width, bm.rows if w == 0 or h == 0: return None p2 = [] for y in range(h): row = [] for x in range(w): row.append(q4to2(bm.buffer[y * bm.pitch + x] >> 4)) p2.append(row) # Measure leftmost stem in stable middle rows mid_start, mid_end = h // 4, h - h // 4 widths = [] for y in range(mid_start, mid_end): first = next((x for x in range(w) if p2[y][x] > 0), -1) if first < 0: continue last = first for x in range(first, w): if p2[y][x] > 0: last = x else: break eff = sum(p2[y][x] for x in range(first, last + 1)) / 3.0 widths.append(eff) return round(sum(widths) / len(widths), 2) if widths else None def main(): for font_name, font_path in FONTS.items(): try: freetype.Face(font_path) except Exception: print(f"\n {font_name}: SKIPPED (file not found)") continue print(f"\n{'=' * 80}") print(f" {font_name}") print(f"{'=' * 80}") for size in SIZES: print(f"\n {size}pt:") print(f" {'':6s}", end="") for c in CHARS: print(f" '{c}' ", end="") print(" | spread") for mode_name, flags in MODES.items(): face = freetype.Face(font_path) face.set_char_size(size << 6, size << 6, DPI, DPI) vals = [] print(f" {mode_name:6s}", end="") for c in CHARS: v = get_stem_eff(face, c, flags) vals.append(v) print(f" {v:5.2f}" if v else " N/A", end="") valid = [v for v in vals if v is not None] spread = max(valid) - min(valid) if len(valid) >= 2 else 0 marker = " <-- inconsistent" if spread > 0.5 else "" print(f" | {spread:.2f}{marker}") if __name__ == "__main__": main() ``` </details> Here are the results. The table compares how the font-generation `autohint` flag affects the range of widths of various characters. Lower `spread` mean that glyph stroke widths should appear more consistent. ``` Spread = max stem width - min stem width across glyphs (lower = more consistent): ┌──────────────┬──────┬─────────┬──────────┬──────────┐ │ Font │ Size │ Default │ Autohint │ Winner │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Bookerly │ 12pt │ 1.49 │ 1.12 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.39 │ 1.13 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.38 │ 1.16 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.90 │ 1.58 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ NotoSans │ 12pt │ 1.16 │ 0.94 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 0.83 │ 1.14 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 1.41 │ 1.51 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.74 │ 1.63 │ mixed │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ OpenDyslexic │ 12pt │ 2.22 │ 1.44 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 2.57 │ 3.29 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 3.13 │ 2.60 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 3.21 │ 3.23 │ ~tied │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ Ubuntu │ 12pt │ 1.25 │ 1.31 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 14pt │ 1.41 │ 1.64 │ default │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 16pt │ 2.21 │ 1.71 │ autohint │ ├──────────────┼──────┼─────────┼──────────┼──────────┤ │ │ 18pt │ 1.80 │ 1.71 │ autohint │ └──────────────┴──────┴─────────┴──────────┴──────────┘ ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? I used AI to make sure I'm not doing something stupid, since I'm not a typography expert. I made the changes though.
2026-02-24 06:13:08 +11:00
{ 0, 2835, 5014, 100, 0 },
{ 2835, 2959, 6309, 96, 100 },
{ 5794, 4178, 10107, 128, 196 },
{ 9972, 246, 285, 33, 324 },
{ 10218, 7543, 16444, 220, 357 },
{ 17761, 882, 1611, 74, 577 },
{ 18643, 229, 444, 18, 651 },
{ 18872, 219, 308, 4, 669 },
{ 19091, 390, 639, 15, 673 },
{ 19481, 1765, 3471, 58, 688 },
{ 21246, 105, 150, 1, 746 },
perf: Reduce overall flash usage by 30.7% by compressing built-in fonts (#831) ## Summary **What is the goal of this PR?** Compress reader font bitmaps to reduce flash usage by 30.7%. **What changes are included?** - New `EpdFontGroup` struct and extended `EpdFontData` with `groups`/`groupCount` fields - `--compress` flag in `fontconvert.py`: groups glyphs (ASCII base group + groups of 8) and compresses each with raw DEFLATE - `FontDecompressor` class with 4-slot LRU cache for on-demand decompression during rendering - `GfxRenderer` transparently routes bitmap access through `getGlyphBitmap()` (compressed or direct flash) - Uses `uzlib` for decompression with minimal heap overhead. - 48 reader fonts (Bookerly, NotoSans 12-18pt, OpenDyslexic) regenerated with compression; 5 UI fonts unchanged - Round-trip verification script (`verify_compression.py`) runs as part of font generation ## Additional Context ## Flash & RAM | | baseline | font-compression | Difference | |--|--------|-----------------|------------| | Flash (ELF) | 6,302,476 B (96.2%) | 4,365,022 B (66.6%) | -1,937,454 B (-30.7%) | | firmware.bin | 6,468,192 B | 4,531,008 B | -1,937,184 B (-29.9%) | | RAM | 101,700 B (31.0%) | 103,076 B (31.5%) | +1,376 B (+0.5%) | ## Script-Based Grouping (Cold Cache) Comparison of uncompressed baseline vs script-based group compression (4-slot LRU cache, cleared each page). Glyphs are grouped by Unicode block (ASCII, Latin-1, Latin Extended-A, Combining Marks, Cyrillic, General Punctuation, etc.) instead of sequential groups of 8. ### Render Time | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Median** | 414.9 ms | 431.6 ms | +16.7 ms (+4.0%) | | **Pages** | 37 | 37 | | ### Memory Usage | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Heap free (median)** | 187.0 KB | 176.3 KB | -10.7 KB | | **Heap free (min)** | 186.0 KB | 166.5 KB | -19.5 KB | | **Largest block (median)** | 148.0 KB | 128.0 KB | -20.0 KB | | **Largest block (min)** | 148.0 KB | 120.0 KB | -28.0 KB | ### Cache Effectiveness | | Misses/page | Hit rate | |---|---|---| | **Compressed (cold cache)** | 2.1 | 99.85% | ------ ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**YES**_ Implementation was done by Claude Code (Opus 4.6) based on a plan developed collaboratively. All generated font headers were verified with an automated round-trip decompression test. The firmware was compiled successfully but has not yet been tested on-device. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:30:15 +11:00
};
static const EpdFontData bookerly_12_regular = {
bookerly_12_regularBitmaps,
bookerly_12_regularGlyphs,
bookerly_12_regularIntervals,
64,
33,
27,
-7,
true,
perf: Reduce overall flash usage by 30.7% by compressing built-in fonts (#831) ## Summary **What is the goal of this PR?** Compress reader font bitmaps to reduce flash usage by 30.7%. **What changes are included?** - New `EpdFontGroup` struct and extended `EpdFontData` with `groups`/`groupCount` fields - `--compress` flag in `fontconvert.py`: groups glyphs (ASCII base group + groups of 8) and compresses each with raw DEFLATE - `FontDecompressor` class with 4-slot LRU cache for on-demand decompression during rendering - `GfxRenderer` transparently routes bitmap access through `getGlyphBitmap()` (compressed or direct flash) - Uses `uzlib` for decompression with minimal heap overhead. - 48 reader fonts (Bookerly, NotoSans 12-18pt, OpenDyslexic) regenerated with compression; 5 UI fonts unchanged - Round-trip verification script (`verify_compression.py`) runs as part of font generation ## Additional Context ## Flash & RAM | | baseline | font-compression | Difference | |--|--------|-----------------|------------| | Flash (ELF) | 6,302,476 B (96.2%) | 4,365,022 B (66.6%) | -1,937,454 B (-30.7%) | | firmware.bin | 6,468,192 B | 4,531,008 B | -1,937,184 B (-29.9%) | | RAM | 101,700 B (31.0%) | 103,076 B (31.5%) | +1,376 B (+0.5%) | ## Script-Based Grouping (Cold Cache) Comparison of uncompressed baseline vs script-based group compression (4-slot LRU cache, cleared each page). Glyphs are grouped by Unicode block (ASCII, Latin-1, Latin Extended-A, Combining Marks, Cyrillic, General Punctuation, etc.) instead of sequential groups of 8. ### Render Time | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Median** | 414.9 ms | 431.6 ms | +16.7 ms (+4.0%) | | **Pages** | 37 | 37 | | ### Memory Usage | | Baseline | Compressed (cold cache) | Difference | |---|---|---|---| | **Heap free (median)** | 187.0 KB | 176.3 KB | -10.7 KB | | **Heap free (min)** | 186.0 KB | 166.5 KB | -19.5 KB | | **Largest block (median)** | 148.0 KB | 128.0 KB | -20.0 KB | | **Largest block (min)** | 148.0 KB | 120.0 KB | -28.0 KB | ### Cache Effectiveness | | Misses/page | Hit rate | |---|---|---| | **Compressed (cold cache)** | 2.1 | 99.85% | ------ ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**YES**_ Implementation was done by Claude Code (Opus 4.6) based on a plan developed collaboratively. All generated font headers were verified with an automated round-trip decompression test. The firmware was compiled successfully but has not yet been tested on-device. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:30:15 +11:00
bookerly_12_regularGroups,
11,
};