diff --git a/.skills/SKILL.md b/.skills/SKILL.md index 8e5e8f8f4a..b7b59dc732 100644 --- a/.skills/SKILL.md +++ b/.skills/SKILL.md @@ -58,6 +58,7 @@ find src -name "*.cpp" -o -name "*.h" | xargs clang-format -i 6. `constexpr` First: Compile-time constants and lookup tables must be `constexpr`, not just `static const`. This moves computation to compile time, enables dead-branch elimination, and guarantees flash placement. Use `static constexpr` for class-level constants. 7. `std::vector` Pre-allocation: Always call `.reserve(N)` before any `push_back()` loop. Each growth event allocates a new block (2×), copies all elements, then frees the old one — three heap operations that fragment DRAM. When the final size is unknown, estimate conservatively. 8. SPIFFS Write Throttling: Never write a settings file on every user interaction. Guard all writes with a value-change check (`if (newVal == _current) return;`). Progress saves during reading must be debounced — write on activity exit or every N page turns, not on every turn. SPIFFS sectors have a finite erase cycle limit. +9. `new` is not nothrow on ESP32: With `-fno-exceptions`, bare `new` that fails calls `abort()` — it does NOT return `nullptr`. Always use `new (std::nothrow)` and null-check the result, or use `makeUniqueNoThrow()` from `lib/Memory/Memory.h`. Never write bare `new` for any fallible allocation. --- @@ -266,43 +267,78 @@ When a template is necessary, limit instantiations: use explicit template instan **Rules**: NO exceptions, NO abort(), ALWAYS log before error return -### Acceptable malloc/free Patterns +### Heap Buffer Allocation -**Source**: [src/activities/home/HomeActivity.cpp:166](../src/activities/home/HomeActivity.cpp), [lib/GfxRenderer/GfxRenderer.cpp:439-440](../lib/GfxRenderer/GfxRenderer.cpp) +**Prefer `makeUniqueNoThrow` over `malloc`.** Both are nothrow (return `nullptr` on OOM rather than calling `abort()`), but `malloc` requires a manual `free` on every return path — a common source of leaks. `makeUniqueNoThrow(size)` from `lib/Memory/Memory.h` frees automatically when it goes out of scope. -Despite "prefer stack allocation," malloc is acceptable for: -1. **Large temporary buffers** (> 256 bytes, won't fit on stack) -2. **One-time allocations** during activity initialization -3. **Bitmap rendering buffers** (variable size, used briefly) - -**Pattern**: +**Preferred pattern**: ```cpp -// Allocate -auto* buffer = static_cast(malloc(bufferSize)); +#include + +auto buffer = makeUniqueNoThrow(bufferSize); if (!buffer) { - LOG_ERR("MODULE", "malloc failed: %d bytes", bufferSize); - return false; // Handle allocation failure + LOG_ERR("MODULE", "OOM: %d bytes", bufferSize); + return false; } -// Use buffer -processData(buffer, bufferSize); +processData(buffer.get(), bufferSize); +// freed automatically — no manual free needed, no leak on early return +``` -// Free immediately after use -free(buffer); -buffer = nullptr; +**`malloc` or `new (std::nothrow)` are still acceptable** when the buffer must be passed to a C API that takes ownership and frees it itself (e.g., certain SDK callbacks). In that case follow the manual pattern: +```cpp +auto* buffer = static_cast(malloc(bufferSize)); // or new (std::nothrow) uint8_t[bufferSize] +if (!buffer) { + LOG_ERR("MODULE", "OOM: %d bytes", bufferSize); + return false; +} +sdkApiThatTakesOwnership(buffer, bufferSize); // SDK calls free() / delete[] ``` **Rules**: -- **ALWAYS check for nullptr** after malloc -- **Free immediately** after use (don't hold across multiple operations) -- **Set to nullptr** after free (avoid use-after-free) -- **Document size**: Comment why stack allocation was rejected +- **Prefer `makeUniqueNoThrow`** — automatic cleanup eliminates leak risk on error paths +- **ALWAYS check for nullptr** after any allocation and `LOG_ERR` before returning false +- **Raw allocation only** when a C API takes ownership; document why in a comment **Examples in codebase**: +- Memory utilities: [Memory.h](../lib/Memory/Memory.h) (`makeUniqueNoThrow`) - Cover image buffers: [HomeActivity.cpp:166](../src/activities/home/HomeActivity.cpp) -- Text chunk buffers: [TxtReaderActivity.cpp:259](../src/activities/reader/TxtReaderActivity.cpp) - Bitmap rendering: [GfxRenderer.cpp:439-440](../lib/GfxRenderer/GfxRenderer.cpp) -- OTA update buffer: [OtaUpdater.cpp:40](../src/network/OtaUpdater.cpp) + +### Heap Allocation with `new`: Always Use `makeUniqueNoThrow` + +**CRITICAL**: With `-fno-exceptions`, bare `new` on OOM calls `abort()` — it does NOT return `nullptr`. Always use `makeUniqueNoThrow` from `lib/Memory/Memory.h`, which wraps `new (std::nothrow)` and returns a `std::unique_ptr` that is null on OOM and automatically frees on scope exit. + +**Preferred pattern**: +```cpp +#include + +auto obj = makeUniqueNoThrow(args); +if (!obj) { LOG_ERR("MOD", "OOM: MyClass"); return false; } + +auto buf = makeUniqueNoThrow(size); +if (!buf) { LOG_ERR("MOD", "OOM: %d bytes", size); return false; } + +// Pass to C APIs via .get(); unique_ptr frees automatically on return +someApi(buf.get(), size); +``` + +**`new (std::nothrow)` directly is acceptable** when the object must be passed to a C API that takes ownership and calls `delete` itself: +```cpp +auto* obj = new (std::nothrow) MyClass(args); +if (!obj) { LOG_ERR("MOD", "OOM: MyClass"); return false; } +sdkApiThatTakesOwnership(obj); // SDK calls delete +``` + +**Rules**: +- **Prefer `makeUniqueNoThrow`** — automatic cleanup eliminates leak risk on error paths +- **NEVER use bare `new`** — always `makeUniqueNoThrow` or `new (std::nothrow)` +- **ALWAYS `LOG_ERR` before returning false** on OOM +- **Use `.get()`** to pass the raw pointer to C-style APIs; ownership stays with the `unique_ptr` +- **`new (std::nothrow)` directly only** when a C API takes ownership; document why in a comment + +**Examples in codebase**: +- Memory utilities: [Memory.h](../lib/Memory/Memory.h) (`makeUniqueNoThrow`) --- diff --git a/README.md b/README.md index c870a156cc..7e1c05ae8b 100644 --- a/README.md +++ b/README.md @@ -1,122 +1,169 @@ # CrossPoint Reader -Firmware for the **Xteink X4** e-paper display reader (unaffiliated with Xteink). -Built using **PlatformIO** and targeting the **ESP32-C3** microcontroller. +CrossPoint is open-source e-reader firmware - community-built, fully hackable, free forever. It's maintained by a growing community of developers and readers who believe your device should do what you want - not what a manufacturer decided for you. -CrossPoint Reader is a purpose-built firmware designed to be a drop-in, fully open-source replacement for the official -Xteink firmware. It aims to match or improve upon the standard EPUB reading experience. +**Now running on:** ESP32C3-based Xteink [X4](https://www.xteink.com/products/xteink-x4) and [X3](https://www.xteink.com/products/xteink-x3). -![](./docs/images/cover.jpg) +![CrossPoint Reader running on Xteink device](./docs/images/cover.jpg) -## Motivation +## What can CrossPoint do? -E-paper devices are fantastic for reading, but most commercially available readers are closed systems with limited -customisation. The **Xteink X4** is an affordable, e-paper device, however the official firmware remains closed. -CrossPoint exists partly as a fun side-project and partly to open up the ecosystem and truly unlock the device's -potential. +- **Reader engine**: EPUB 2/3 rendering with embedded-style option, image handling, hyphenation, kerning, chapter navigation, footnotes, go-to-percent, auto page turn, orientation control, focus reading, KOReader progress sync and more. -CrossPoint Reader aims to: -* Provide a **fully open-source alternative** to the official firmware. -* Offer a **document reader** capable of handling EPUB content on constrained hardware. -* Support **customisable font, layout, and display** options. -* Run purely on the **Xteink X4 hardware**. +- **Various formats**: native handling for `.epub`, `.xtc/.xtch`, `.txt`, and `.bmp`. -This project is **not affiliated with Xteink**; it's built as a community project. +- **Screenshots.** -## Features & Usage +- **Custom fonts**: install your favorite fonts on the SD card. -- [x] EPUB parsing and rendering (EPUB 2 and EPUB 3) -- [x] Image support within EPUB -- [x] Saved reading position -- [x] File explorer with file picker - - [x] Basic EPUB picker from root directory - - [x] Support nested folders - - [ ] EPUB picker with cover art -- [x] Custom sleep screen - - [x] Cover sleep screen -- [x] Wifi book upload -- [x] Wifi OTA updates -- [x] KOReader Sync integration for cross-device reading progress -- [x] Configurable font, layout, and display options - - [ ] User provided fonts - - [ ] Full UTF support -- [x] Screen rotation +- **Tilt page turn (X3 only)**. -Multi-language support: Read EPUBs in various languages, including English, Spanish, French, German, Italian, Portuguese, Russian, Ukrainian, Polish, Swedish, Norwegian, [and more](./USER_GUIDE.md#supported-languages). +- **Library workflow**: folder browser, hidden-file toggle, long-press delete, recent books, SD-cache management. -See [the user guide](./USER_GUIDE.md) for instructions on operating CrossPoint, including the -[KOReader Sync quick setup](./USER_GUIDE.md#367-koreader-sync-quick-setup). +- **Wireless workflows**: + + - File transfer web UI + - EPUB Optimizer + - Web settings UI/API (edit many device settings from browser) + - WebSocket fast uploads + - WebDAV handler + - AP mode (hotspot) and STA mode (join existing WiFi), both with QR helpers + - Calibre wireless connect flow + - OPDS browser with saved servers (up to 8), search, pagination, and direct download + - OTA update checks and installs from GitHub releases -For more details about the scope of the project, see the [SCOPE.md](SCOPE.md) document. +- **Customization**: multiple themes (Classic, Lyra, Lyra Extended, RoundedRaff), sleep screen modes, front/side button remapping, status bar controls, power-button behavior, refresh cadence, and more. -## Installing +- **Localization**: 22 UI languages and counting. -### Web (latest firmware) +### Coming soon: -1. Connect your Xteink X4 to your computer via USB-C and wake/unlock the device -2. Go to https://xteink.dve.al/ and click "Flash CrossPoint firmware" +- RTL support — Arabic, Hebrew, and Farsi. -To revert back to the official firmware, you can flash the latest official firmware from https://xteink.dve.al/, or swap -back to the other partition using the "Swap boot partition" button here https://xteink.dve.al/debug. +- Bookmarks. -### Web (specific firmware version) +- Dictionary lookup — inline word lookup without leaving the reader. -1. Connect your Xteink X4 to your computer via USB-C -2. Download the `firmware.bin` file from the release of your choice via the [releases page](https://github.com/crosspoint-reader/crosspoint-reader/releases) -3. Go to https://xteink.dve.al/ and flash the firmware file using the "OTA fast flash controls" section +- More themes. -To revert back to the official firmware, you can flash the latest official firmware from https://xteink.dve.al/, or swap -back to the other partition using the "Swap boot partition" button here https://xteink.dve.al/debug. +- Much more! stay tuned. -### Command line (specific firmware version) +--- + +## USB-locked devices (Xteink Unlocker) + +Some Xteink units purchased from third-party stores (e.g. AliExpress) ship with USB flashing locked from the factory. +If your device is locked, you will need to use the **Xteink Unlocker** tool available at +https://crosspointreader.com/#unlock-tool before you can flash CrossPoint. + +**You do not need this tool if you bought your device directly from xteink.com.** Those units are not locked. + +**Not sure if your device is locked?** Power it on, connect the USB-C cable, and try flashing via the web flasher first (see +[Install firmware](#install-firmware) below). If the browser's serial device picker does not show your device, try a different +USB port or browser before assuming the device is locked. Only reach for the unlocker if the device still doesn't appear. + +> ### ⚠️ WARNING: READ THIS BEFORE USING THE UNLOCKER ⚠️ +> +> **The only officially supported firmwares in the unlock tool are CrossPoint and CrossInk.** +> +> Flashing any other firmware on a USB-locked device may **permanently brick the device** or leave it **permanently +> stuck on that firmware with no recovery path**. Once USB flashing is re-locked, your only way back is via OTA, and if +> the firmware you flashed doesn't support OTA, **there is no way out**. +> +> **The Papyrix fork has removed OTA update support from its code.** If you flash Papyrix onto a +> USB-locked unit, you will have **zero update or recovery path** and will be stuck on it forever. **Do not flash +> Papyrix (or any other unsupported firmware) on a locked device.** + +## Install firmware + +### Web installer (recommended) + +1. Connect your device to your computer via USB-C and wake/unlock the device +2. Go to https://crosspointreader.com/#flash-tools, select device (X3 or X4), and choose an official CrossPoint release. + +### Web installer (specific version) + +1. Connect your device to your computer via USB-C and wake/unlock the device +2. Download a `firmware.bin` from [Releases](https://github.com/crosspoint-reader/crosspoint-reader/releases), local build, or continuous integration artifact. +3. Go to https://crosspointreader.com/#flash-tools, select device (X3 or X4), click "Custom .bin" and upload a `firmware.bin`. + +### Revert to Official Firmware + +To revert to the official firmware, you can also flash the latest official firmware using https://crosspointreader.com/#flash-tools. + +### Command line + +1. Install [`esptool`](https://github.com/espressif/esptool): -1. Install [`esptool`](https://github.com/espressif/esptool) : ```bash pip install esptool ``` -2. Download the `firmware.bin` file from the release of your choice via the [releases page](https://github.com/crosspoint-reader/crosspoint-reader/releases) -3. Connect your Xteink X4 to your computer via USB-C. -4. Note the device location. On Linux, run `dmesg` after connecting. On MacOS, run : + +2. Download `firmware.bin` from the [releases page](https://github.com/crosspoint-reader/crosspoint-reader/releases). +3. Connect your device via USB-C. +4. Find the device port. On Linux, run `dmesg` after connecting. On macOS: + ```bash log stream --predicate 'subsystem == "com.apple.iokit"' --info ``` -5. Flash the firmware : + +5. Flash: + ```bash esptool.py --chip esp32c3 --port /dev/ttyACM0 --baud 921600 write_flash 0x10000 /path/to/firmware.bin ``` -Change `/dev/ttyACM0` to the device for your system. + +Adjust `/dev/ttyACM0` to match your system. ### Manual -See [Development](#development) below. +See [Development quick start](#development-quick-start) below. -## Development +--- -### Prerequisites +## Documentation -* **PlatformIO Core** (`pio`) or **VS Code + PlatformIO IDE** -* Python 3.8+ -* USB-C cable for flashing the ESP32-C3 -* Xteink X4 +- [User Guide](./USER_GUIDE.md) +- [Web server usage](./docs/webserver.md) +- [Web server endpoints](./docs/webserver-endpoints.md) +- [Project scope](./SCOPE.md) +- [Contributing docs](./docs/contributing/README.md) -### Checking out the code +--- -CrossPoint uses PlatformIO for building and flashing the firmware. To get started, clone the repository: +## Development quick start -``` +### Prerequisites + +- [pioarduino](https://github.com/pioarduino/pioarduino) or VS Code + pioarduino plugin +- Python 3.8+ +- `clang-format` 21 +- USB-C cable supporting data transfer + +### Setup + +```bash git clone --recursive https://github.com/crosspoint-reader/crosspoint-reader +cd crosspoint-reader -# Or, if you've already cloned without --recursive: +# if cloned without --recursive: git submodule update --init --recursive ``` -### Flashing your device +### Build / flash / monitor -Connect your Xteink X4 to your computer via USB-C and run the following command. - -```sh +```bash pio run --target upload ``` + +### Contributor pre-PR checks + +```bash +./bin/clang-format-fix +pio check -e default +pio run -e default +``` + ### Debugging After flashing the new features, it’s recommended to capture detailed logs from the serial port. @@ -126,7 +173,9 @@ First, make sure all required Python packages are installed: ```python python3 -m pip install pyserial colorama matplotlib ``` -after that run the script: + +After that run the script: + ```sh # For Linux # This was tested on Debian and should work on most Linux systems. @@ -135,63 +184,72 @@ python3 scripts/debugging_monitor.py # For macOS python3 scripts/debugging_monitor.py /dev/cu.usbmodem2101 ``` + Minor adjustments may be required for Windows. +--- + ## Internals -CrossPoint Reader is pretty aggressive about caching data down to the SD card to minimise RAM usage. The ESP32-C3 only -has ~380KB of usable RAM, so we have to be careful. A lot of the decisions made in the design of the firmware were based -on this constraint. +CrossPoint Reader is pretty aggressive about caching data down to the SD card to minimise RAM usage. The ESP32-C3 only has ~380KB of usable RAM, so we have to be careful. A lot of the decisions made in the design of the firmware were based on this constraint. ### Data caching The first time chapters of a book are loaded, they are cached to the SD card. Subsequent loads are served from the cache. This cache directory exists at `.crosspoint` on the SD card. The structure is as follows: - -``` +```text .crosspoint/ -├── epub_12471232/ # Each EPUB is cached to a subdirectory named `epub_` -│ ├── progress.bin # Stores reading progress (chapter, page, etc.) -│ ├── cover.bmp # Book cover image (once generated) -│ ├── book.bin # Book metadata (title, author, spine, table of contents, etc.) -│ └── sections/ # All chapter data is stored in the sections subdirectory -│ ├── 0.bin # Chapter data (screen count, all text layout info, etc.) -│ ├── 1.bin # files are named by their index in the spine +├── epub_/ # one directory per book, named by content hash +│ ├── progress.bin # reading position (chapter, page, etc.) +│ ├── cover.bmp # generated cover image +│ ├── book.bin # metadata: title, author, spine, TOC +│ └── sections/ # per-chapter layout cache +│ ├── 0.bin +│ ├── 1.bin │ └── ... -│ -└── epub_189013891/ ``` -Deleting the `.crosspoint` directory will clear the entire cache. - -Due the way it's currently implemented, the cache is not automatically cleared when a book is deleted and moving a book -file will use a new cache directory, resetting the reading progress. +Removing `/.crosspoint` clears all cached metadata and forces a full regeneration on next open. Note: the cache isn't cleared automatically when you delete a book, and moving a file to a new path resets its reading progress. For more details on the internal file structures, see the [file formats document](./docs/file-formats.md). +--- + ## Contributing -Contributions are very welcome! +Contributions are welcome. If you're new to the codebase, start with the [contributing docs](./docs/contributing/README.md). For things to work on, check the [ideas discussion board](https://github.com/crosspoint-reader/crosspoint-reader/discussions/categories/ideas) — leave a comment before starting so we don't duplicate effort. + +Everyone here is a volunteer, so please be respectful and patient. For governance and community expectations, see [GOVERNANCE.md](./GOVERNANCE.md). + +--- + +## Community forks + +One of the best things about open source is that anyone can take the code in a different direction. If you need something outside CrossPoint's [scope](./SCOPE.md), check out the community forks: + +- [CrossInk](https://github.com/uxjulia/CrossInk) — Typography and reading tracking: Bionic Reading (bolds word stems to create fixation points), guide dots between words, improved paragraph indents, and replaces the default fonts with ChareInk/Lexend/Bitter. + +- [papyrix-reader](https://github.com/bigbag/papyrix-reader) — Adds FB2 and MD format support. Actively maintained with Arabic script support. Custom themes via SD card. + +- [crosspet](https://github.com/trilwu/crosspet) — A Vietnamese fork that adds a Tamagotchi-style virtual chicken that grows based on your reading milestones (pages read, streaks, care). Also: Flashcards, Weather, Pomodoro timer, and mini-games. + +- [crosspoint-reader (jpirnay)](https://github.com/jpirnay/crosspoint-reader) — Faster integration of functionality. Tracks upstream PRs and integrates the good ones ahead of the official merge. + +- [crosspoint-reader-cjk](https://github.com/aBER0724/crosspoint-reader-cjk) — Purpose-built for Chinese, Japanese, and Korean reading. -If you are new to the codebase, start with the [contributing docs](./docs/contributing/README.md). +- [inx](https://github.com/obijuankenobiii/inx) — Completely reimagines the user interface with tabbed navigation. -If you're looking for a way to help out, take a look at the [ideas discussion board](https://github.com/crosspoint-reader/crosspoint-reader/discussions/categories/ideas). -If there's something there you'd like to work on, leave a comment so that we can avoid duplicated effort. +- ~~[PlusPoint](https://github.com/ngxson/pluspoint-reader) — custom JS apps support.~~ (Unmaintained) -Everyone here is a volunteer, so please be respectful and patient. For more details on our governance and community -principles, please see [GOVERNANCE.md](GOVERNANCE.md). +- [crosspoint-reader-papers3](https://github.com/juicecultus/crosspoint-reader-papers3) — Crosspoint port for M5Stack Paper S3. -### To submit a contribution: +**Note:** Many of these features will make their way into CrossPoint over time. We maintain a slower pace to ensure rock-solid stability and squash bugs before they reach your device. -1. Fork the repo -2. Create a branch (`feature/dithering-improvement`) -3. Make changes -4. Submit a PR +Want to build your own device? Be sure to check out the [de-link](https://github.com/iandchasse/de-link) project. --- -CrossPoint Reader is **not affiliated with Xteink or any manufacturer of the X4 hardware**. +CrossPoint Reader is **not affiliated with Xteink or any device manufacturer**. -Huge shoutout to [**diy-esp32-epub-reader** by atomic14](https://github.com/atomic14/diy-esp32-epub-reader), which was a project I took a lot of inspiration from as I -was making CrossPoint. +Huge shoutout to [diy-esp32-epub-reader](https://github.com/atomic14/diy-esp32-epub-reader), which inspired this project. diff --git a/lib/EpdFont/SdCardFont.cpp b/lib/EpdFont/SdCardFont.cpp index 8b49671979..6c860949af 100644 --- a/lib/EpdFont/SdCardFont.cpp +++ b/lib/EpdFont/SdCardFont.cpp @@ -16,11 +16,13 @@ static_assert(sizeof(EpdUnicodeInterval) == 12, "EpdUnicodeInterval must be 12 b static_assert(sizeof(EpdKernClassEntry) == 3, "EpdKernClassEntry must be 3 bytes to match .cpfont file layout"); static_assert(sizeof(EpdLigaturePair) == 8, "EpdLigaturePair must be 8 bytes to match .cpfont file layout"); +namespace { + // FNV-1a hash for content-based font ID generation -static constexpr uint32_t FNV_OFFSET = 2166136261u; -static constexpr uint32_t FNV_PRIME = 16777619u; +constexpr uint32_t FNV_OFFSET = 2166136261u; +constexpr uint32_t FNV_PRIME = 16777619u; -static uint32_t fnv1a(const uint8_t* data, size_t len, uint32_t hash = FNV_OFFSET) { +uint32_t fnv1a(const uint8_t* data, size_t len, uint32_t hash = FNV_OFFSET) { for (size_t i = 0; i < len; i++) { hash ^= data[i]; hash *= FNV_PRIME; @@ -29,16 +31,44 @@ static uint32_t fnv1a(const uint8_t* data, size_t len, uint32_t hash = FNV_OFFSE } // .cpfont magic bytes -static constexpr char CPFONT_MAGIC[8] = {'C', 'P', 'F', 'O', 'N', 'T', '\0', '\0'}; +constexpr char CPFONT_MAGIC[8] = {'C', 'P', 'F', 'O', 'N', 'T', '\0', '\0'}; // CPFONT_VERSION is defined as a #define in SdCardFont.h so it can be // stringified into FONT_MANIFEST_URL. -static constexpr uint32_t HEADER_SIZE = 32; -static constexpr uint32_t STYLE_TOC_ENTRY_SIZE = 32; +constexpr uint32_t HEADER_SIZE = 32; +constexpr uint32_t STYLE_TOC_ENTRY_SIZE = 32; // Helper to read little-endian values from byte buffer -static inline uint16_t readU16(const uint8_t* p) { return p[0] | (p[1] << 8); } -static inline int16_t readI16(const uint8_t* p) { return static_cast(p[0] | (p[1] << 8)); } -static inline uint32_t readU32(const uint8_t* p) { return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); } +inline uint16_t readU16(const uint8_t* p) { return p[0] | (p[1] << 8); } +inline int16_t readI16(const uint8_t* p) { return static_cast(p[0] | (p[1] << 8)); } +inline uint32_t readU32(const uint8_t* p) { return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); } + +// Walks a null-terminated UTF-8 string and appends each unique codepoint to +// codepoints[0..cpCount-1] via O(n²) dedup. Returns true if the buffer +// reached maxCount (cap hit), false if all codepoints fit. +bool collectUniqueCodepoints(const char* text, uint32_t* codepoints, uint32_t& cpCount, uint32_t maxCount) { + const unsigned char* p = reinterpret_cast(text); + while (*p) { + uint32_t cp = utf8NextCodepoint(&p); + if (cp == 0) break; + bool found = false; + for (uint32_t i = 0; i < cpCount; i++) { + if (codepoints[i] == cp) { + found = true; + break; + } + } + if (!found) { + if (cpCount >= maxCount) return true; + codepoints[cpCount++] = cp; + } + } + return false; +} + +const char* asCStr(const std::string& s) { return s.c_str(); } +const char* asCStr(const char* s) { return s; } + +} // namespace SdCardFont::~SdCardFont() { freeAll(); } @@ -1019,64 +1049,10 @@ uint16_t SdCardFont::getAdvance(uint32_t codepoint, uint8_t style) const { return 0; } -int SdCardFont::buildAdvanceTable(const char* utf8Text, uint8_t styleMask) { - if (!loaded_) return -1; - styleMask = resolveStyleMask(styleMask); - if (styleMask == 0) return 0; - - // Note: advance table is preserved across calls. We only fetch codepoints - // not already present, then merge them in. Use clearPersistentCache() to - // wipe the table when the font/size/family changes. - - unsigned long startMs = millis(); - - // Step 1: Extract unique codepoints, capped at MAX_UNIQUE_CODEPOINTS. - // The dedup buffer is sized to the cap, not total chars — a large EPUB section - // may contain 50K+ characters but real text has far fewer unique codepoints. - // 4096 × 4 bytes = 16KB temporary; bounded regardless of input size. - static constexpr uint32_t MAX_UNIQUE_CODEPOINTS = 4096; - uint32_t* codepoints = new (std::nothrow) uint32_t[MAX_UNIQUE_CODEPOINTS]; - if (!codepoints) { - LOG_ERR("SDCF", "buildAdvanceTable: failed to allocate codepoint buffer (%u bytes)", MAX_UNIQUE_CODEPOINTS * 4); - return -1; - } - uint32_t cpCount = 0; - bool hitCap = false; - - // Second pass: collect unique codepoints via O(n²) dedup. - // Bounded by uniqueCount × totalChars comparisons. For 2000 unique from 2291 total, - // worst case ~4.6M comparisons of uint32_t — ~30ms on 160MHz RISC-V, acceptable - // for one-time section indexing. - const unsigned char* p = reinterpret_cast(utf8Text); - while (*p) { - uint32_t cp = utf8NextCodepoint(&p); - if (cp == 0) break; - - bool found = false; - for (uint32_t i = 0; i < cpCount; i++) { - if (codepoints[i] == cp) { - found = true; - break; - } - } - if (!found) { - if (cpCount >= MAX_UNIQUE_CODEPOINTS) { - hitCap = true; - break; - } - codepoints[cpCount++] = cp; - } - } - if (hitCap) { - LOG_ERR("SDCF", "buildAdvanceTable: unique codepoint cap (%u) hit, layout may be approximate", - MAX_UNIQUE_CODEPOINTS); - } - - // Sort for ordered glyph index mapping and final table output - std::sort(codepoints, codepoints + cpCount); - - // Step 2: For each requested style, fetch any codepoints not yet cached and - // merge them into the persistent advance table. +// Given a sorted array of unique codepoints, resolve glyph indices per style, +// batch-read advanceX from SD, and merge into the persistent advance table. +// Caller owns the codepoints buffer. +int SdCardFont::fetchAdvancesForCodepoints(uint32_t* codepoints, uint32_t cpCount, uint8_t styleMask) { int totalMissed = 0; for (uint8_t si = 0; si < MAX_STYLES; si++) { if (!(styleMask & (1 << si)) || !styles_[si].present) continue; @@ -1175,12 +1151,55 @@ int SdCardFont::buildAdvanceTable(const char* utf8Text, uint8_t styleMask) { ADVANCE_CACHE_LIMIT); } - delete[] codepoints; + return totalMissed; +} + +template +int SdCardFont::buildAdvanceTableRange(Iter begin, Iter end, bool includeSpace, bool includeHyphen, uint8_t styleMask) { + if (!loaded_) return -1; + styleMask = resolveStyleMask(styleMask); + if (styleMask == 0) return 0; + + unsigned long startMs = millis(); + // +2 reserved slots for space and hyphen injected after the main scan. + static constexpr uint32_t MAX_UNIQUE_CODEPOINTS = 4096; + uint32_t* codepoints = new (std::nothrow) uint32_t[MAX_UNIQUE_CODEPOINTS + 2]; + if (!codepoints) { + LOG_ERR("SDCF", "buildAdvanceTable: failed to allocate codepoint buffer (%u bytes)", MAX_UNIQUE_CODEPOINTS * 4); + return -1; + } + uint32_t cpCount = 0; + bool hitCap = false; + + for (auto it = begin; it != end && !hitCap; ++it) { + hitCap = collectUniqueCodepoints(asCStr(*it), codepoints, cpCount, MAX_UNIQUE_CODEPOINTS); + } + + if (includeSpace && std::none_of(codepoints, codepoints + cpCount, [](uint32_t c) { return c == ' '; })) + codepoints[cpCount++] = ' '; + if (includeHyphen && std::none_of(codepoints, codepoints + cpCount, [](uint32_t c) { return c == '-'; })) + codepoints[cpCount++] = '-'; + + if (hitCap) { + LOG_ERR("SDCF", "buildAdvanceTable: unique codepoint cap (%u) hit, layout may be approximate", + MAX_UNIQUE_CODEPOINTS); + } + std::sort(codepoints, codepoints + cpCount); + int totalMissed = fetchAdvancesForCodepoints(codepoints, cpCount, styleMask); + delete[] codepoints; stats_.prewarmTotalMs = millis() - startMs; return totalMissed; } +int SdCardFont::buildAdvanceTable(const char* utf8Text, uint8_t styleMask) { + return buildAdvanceTableRange(&utf8Text, &utf8Text + 1, false, false, styleMask); +} + +int SdCardFont::buildAdvanceTable(const std::vector& words, bool includeHyphen, uint8_t styleMask) { + return buildAdvanceTableRange(words.begin(), words.end(), words.size() > 1, includeHyphen, styleMask); +} + // --- Stats --- void SdCardFont::logStats(const char* label) { diff --git a/lib/EpdFont/SdCardFont.h b/lib/EpdFont/SdCardFont.h index c826000e2d..d4d680edb2 100644 --- a/lib/EpdFont/SdCardFont.h +++ b/lib/EpdFont/SdCardFont.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include "EpdFont.h" #include "EpdFontData.h" @@ -43,10 +45,11 @@ class SdCardFont { int prewarm(const char* utf8Text, uint8_t styleMask = 0x0F, bool metadataOnly = false); // Build a compact advance-only table for layout measurement. - // Extracts ALL unique codepoints from utf8Text (no MAX_PAGE_GLYPHS cap), + // Extracts ALL unique codepoints from words (no MAX_PAGE_GLYPHS cap), // batch-reads advanceX from SD, stores in a sorted per-style table. // Returns number of codepoints not found in font coverage. int buildAdvanceTable(const char* utf8Text, uint8_t styleMask = 0x0F); + int buildAdvanceTable(const std::vector& words, bool includeHyphen, uint8_t styleMask = 0x0F); // Look up advanceX for a codepoint from the advance table. // Returns the 12.4 fixed-point advance, or 0 if not found. @@ -236,6 +239,9 @@ class SdCardFont { void applyKernLigaturePointers(PerStyle& s, EpdFontData& data) const; void applyGlyphMissCallback(uint8_t styleIdx); int32_t findGlobalGlyphIndex(const PerStyle& s, uint32_t codepoint) const; + int fetchAdvancesForCodepoints(uint32_t* codepoints, uint32_t cpCount, uint8_t styleMask); + template + int buildAdvanceTableRange(Iter begin, Iter end, bool includeSpace, bool includeHyphen, uint8_t styleMask); int prewarmStyle(uint8_t styleIdx, const uint32_t* codepoints, uint32_t cpCount, bool metadataOnly); // Global helpers diff --git a/lib/EpdFont/scripts/sd-fonts.yaml b/lib/EpdFont/scripts/sd-fonts.yaml index 6ef1247c8a..6ff7aaf1e5 100644 --- a/lib/EpdFont/scripts/sd-fonts.yaml +++ b/lib/EpdFont/scripts/sd-fonts.yaml @@ -113,6 +113,17 @@ families: italic: {url: "https://raw.githubusercontent.com/google/fonts/main/ofl/bitter/Bitter-Italic%5Bwght%5D.ttf", variable: {wght: 500}} bolditalic: {url: "https://raw.githubusercontent.com/google/fonts/main/ofl/bitter/Bitter-Italic%5Bwght%5D.ttf", variable: {wght: 700}} + - name: Domitian + description: "A humanist serif for literary reading (Latin, Greek, Cyrillic)" + intervals: latin-ext,greek,cyrillic + sizes: [12, 14, 16, 18] + styles: + regular: {url: "https://mirrors.ctan.org/fonts/domitian/opentype/Domitian-Roman.otf"} + bold: {url: "https://mirrors.ctan.org/fonts/domitian/opentype/Domitian-Bold.otf"} + italic: {url: "https://mirrors.ctan.org/fonts/domitian/opentype/Domitian-Italic.otf"} + bolditalic: {url: "https://mirrors.ctan.org/fonts/domitian/opentype/Domitian-BoldItalic.otf"} + + # ── Sans-serif ───────────────────────────────────────────────────────── - name: NotoSansExtended diff --git a/lib/Epub/Epub.cpp b/lib/Epub/Epub.cpp index a5befe5b37..6958dfb4e2 100644 --- a/lib/Epub/Epub.cpp +++ b/lib/Epub/Epub.cpp @@ -616,7 +616,7 @@ bool Epub::generateCoverBmp(bool cropped) const { std::string Epub::getThumbBmpPath() const { return cachePath + "/thumb_[HEIGHT].bmp"; } std::string Epub::getThumbBmpPath(int height) const { return cachePath + "/thumb_" + std::to_string(height) + ".bmp"; } -bool Epub::generateThumbBmp(int height) const { +bool Epub::generateThumbBmp(int height, uint32_t deadline) const { // Already generated, return true if (Storage.exists(getThumbBmpPath(height).c_str())) { return true; @@ -638,7 +638,7 @@ bool Epub::generateThumbBmp(int height) const { if (!Storage.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) { return false; } - readItemContentsToStream(coverImageHref, coverJpg, 1024); + readItemContentsToStream(coverImageHref, coverJpg, 1024, deadline); // Explicitly close() file before reopening for reading coverJpg.close(); @@ -655,7 +655,7 @@ bool Epub::generateThumbBmp(int height) const { int THUMB_TARGET_WIDTH = height * 0.6; int THUMB_TARGET_HEIGHT = height; const bool success = JpegToBmpConverter::jpegFileTo1BitBmpStreamWithSize(coverJpg, thumbBmp, THUMB_TARGET_WIDTH, - THUMB_TARGET_HEIGHT); + THUMB_TARGET_HEIGHT, deadline); // Explicitly close() files before calling Storage.remove() coverJpg.close(); thumbBmp.close(); @@ -675,7 +675,7 @@ bool Epub::generateThumbBmp(int height) const { if (!Storage.openFileForWrite("EBP", coverPngTempPath, coverPng)) { return false; } - readItemContentsToStream(coverImageHref, coverPng, 1024); + readItemContentsToStream(coverImageHref, coverPng, 1024, deadline); // Explicitly close() file before reopening for reading coverPng.close(); @@ -689,8 +689,8 @@ bool Epub::generateThumbBmp(int height) const { } int THUMB_TARGET_WIDTH = height * 0.6; int THUMB_TARGET_HEIGHT = height; - const bool success = - PngToBmpConverter::pngFileTo1BitBmpStreamWithSize(coverPng, thumbBmp, THUMB_TARGET_WIDTH, THUMB_TARGET_HEIGHT); + const bool success = PngToBmpConverter::pngFileTo1BitBmpStreamWithSize(coverPng, thumbBmp, THUMB_TARGET_WIDTH, + THUMB_TARGET_HEIGHT, deadline); // Explicitly close() files before calling Storage.remove() coverPng.close(); thumbBmp.close(); @@ -729,14 +729,15 @@ uint8_t* Epub::readItemContentsToBytes(const std::string& itemHref, size_t* size return content; } -bool Epub::readItemContentsToStream(const std::string& itemHref, Print& out, const size_t chunkSize) const { +bool Epub::readItemContentsToStream(const std::string& itemHref, Print& out, const size_t chunkSize, + uint32_t deadline) const { if (itemHref.empty()) { LOG_DBG("EBP", "Failed to read item, empty href"); return false; } const std::string path = FsHelpers::normalisePath(itemHref); - return ZipFile(filepath).readFileToStream(path.c_str(), out, chunkSize); + return ZipFile(filepath).readFileToStream(path.c_str(), out, chunkSize, deadline); } bool Epub::getItemSize(const std::string& itemHref, size_t* size) const { diff --git a/lib/Epub/Epub.h b/lib/Epub/Epub.h index 9ffa8d37c5..31508354aa 100644 --- a/lib/Epub/Epub.h +++ b/lib/Epub/Epub.h @@ -55,10 +55,10 @@ class Epub { bool generateCoverBmp(bool cropped = false) const; std::string getThumbBmpPath() const; std::string getThumbBmpPath(int height) const; - bool generateThumbBmp(int height) const; + bool generateThumbBmp(int height, uint32_t deadline = 0) const; uint8_t* readItemContentsToBytes(const std::string& itemHref, size_t* size = nullptr, bool trailingNullByte = false) const; - bool readItemContentsToStream(const std::string& itemHref, Print& out, size_t chunkSize) const; + bool readItemContentsToStream(const std::string& itemHref, Print& out, size_t chunkSize, uint32_t deadline = 0) const; bool getItemSize(const std::string& itemHref, size_t* size) const; BookMetadataCache::SpineEntry getSpineItem(int spineIndex) const; BookMetadataCache::TocEntry getTocItem(int tocIndex) const; diff --git a/lib/Epub/Epub/ParsedText.cpp b/lib/Epub/Epub/ParsedText.cpp index e348270b9b..09412d193b 100644 --- a/lib/Epub/Epub/ParsedText.cpp +++ b/lib/Epub/Epub/ParsedText.cpp @@ -255,20 +255,6 @@ void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fo // (advanceX only, no bitmaps) for all unique codepoints in this paragraph so // that calculateWordWidths() can measure text without on-demand SD I/O. if (renderer.isSdCardFont(fontId)) { - // Reserve upfront so the joined text allocates exactly once. Without this, - // paragraphs with many words trigger a chain of vector-like reallocations - // inside std::string during layout — visible in prewarm timings for SD fonts. - size_t totalSize = hyphenationEnabled ? 1 : 0; - if (!words.empty()) totalSize += words.size() - 1; // inter-word spaces - for (const auto& w : words) totalSize += w.size(); - std::string allText; - allText.reserve(totalSize); - for (size_t i = 0; i < words.size(); i++) { - if (i > 0) allText += ' '; - allText += words[i]; - } - if (hyphenationEnabled) allText += '-'; - // Style mask: only ask the SD font to load advances for styles actually // used in this paragraph. Style index is the low two bits (regular/bold/ // italic/bold-italic); the underline bit is irrelevant to advance metrics. @@ -277,7 +263,7 @@ void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fo styleMask |= static_cast(1u << (static_cast(s) & 0x03)); } if (styleMask == 0) styleMask = 0x01; // defensive: regular only - renderer.ensureSdCardFontReady(fontId, allText.c_str(), styleMask); + renderer.ensureSdCardFontReady(fontId, words, hyphenationEnabled, styleMask); } const int pageWidth = viewportWidth; diff --git a/lib/Epub/Epub/blocks/ImageBlock.cpp b/lib/Epub/Epub/blocks/ImageBlock.cpp index 1b71817a89..d234887a0f 100644 --- a/lib/Epub/Epub/blocks/ImageBlock.cpp +++ b/lib/Epub/Epub/blocks/ImageBlock.cpp @@ -74,13 +74,13 @@ bool renderFromCache(GfxRenderer& renderer, const std::string& cachePath, int x, } const int destY = y + row; - pw.beginRow(destY); + pw.beginRow(destY, x); for (int col = 0; col < cachedWidth; col++) { const int byteIdx = col >> 2; // col / 4 const int bitShift = 6 - (col & 3) * 2; // MSB first within byte uint8_t pixelValue = (rowBuffer[byteIdx] >> bitShift) & 0x03; - pw.writePixel(x + col, pixelValue); + pw.writePixel(pixelValue); } } diff --git a/lib/Epub/Epub/converters/DirectPixelWriter.h b/lib/Epub/Epub/converters/DirectPixelWriter.h index bc66c2f78e..44bb56fd09 100644 --- a/lib/Epub/Epub/converters/DirectPixelWriter.h +++ b/lib/Epub/Epub/converters/DirectPixelWriter.h @@ -6,16 +6,26 @@ // Direct framebuffer writer that eliminates per-pixel overhead from the image // rendering hot path. Pre-computes orientation transform as linear coefficients -// and caches render-mode state so the inner loop is: one multiply, one add, -// one shift, and one AND per pixel — no branches, no method calls. +// and caches render-mode state so the inner loop is: two increments, one shift, +// one AND, and one or two bit-writes per pixel — no multiplies, no branches on +// mode or orientation, no method calls. // -// Caller is responsible for ensuring (outX, outY) are within screen bounds. -// ImageBlock::render() already validates this before entering the pixel loop, -// and the JPEG/PNG callbacks pre-clamp destination ranges to screen bounds. +// Usage: +// pw.init(renderer); +// for each row: pw.beginRow(logicalY); // resets running X/Y state to col 0 +// for each col: pw.writePixel(value); // advances running state, writes bit +// +// Caller must call writePixel() for every column in order (0, 1, 2, …) because +// the running state is advanced unconditionally on each call. Caller is also +// responsible for ensuring columns are within screen bounds before entering the +// loop; no bounds checking is performed here. struct DirectPixelWriter { uint8_t* fb; - GfxRenderer::RenderMode mode; - uint16_t displayWidthBytes; // Runtime framebuffer stride (X4: 100, X3: 99) + uint8_t* fb2; // Secondary framebuffer for MSB plane (null = two-pass / not active) + uint8_t writeFbMask; // Bit i set → write to fb when pixelValue==i (pre-computed from render mode) + uint8_t writeFb2Mask; // Bit i set → write to fb2 when pixelValue==i + bool fbClearBit; // true = clear bit (BW black); false = set bit (all gray modes) + uint16_t displayWidthBytes; // Runtime framebuffer stride // Orientation is collapsed into a linear transform: // phyX = phyXBase + x * phyXStepX + y * phyXStepY @@ -24,14 +34,44 @@ struct DirectPixelWriter { int phyXStepX, phyYStepX; // per logical-X step int phyXStepY, phyYStepY; // per logical-Y step - // Row-precomputed: the Y-dependent portion of the physical coords - int rowPhyXBase, rowPhyYBase; + // Pre-computed once in init(): physical-Y advance per logical-X step (in byte-index units). + int32_t byteIdxYStep; + + // Running state — reset by beginRow(), advanced by writePixel(). + int curPhyX; + int32_t curByteIdx; - void init(GfxRenderer& renderer) { + void init(const GfxRenderer& renderer) { fb = renderer.getFrameBuffer(); - mode = renderer.getRenderMode(); + fb2 = renderer.getSecondaryFrameBuffer(); displayWidthBytes = renderer.getDisplayWidthBytes(); + // Pre-compute write masks once so the inner loop has zero mode branches. + writeFbMask = 0; + writeFb2Mask = 0; + fbClearBit = false; + switch (renderer.getRenderMode()) { + case GfxRenderer::BW: + writeFbMask = 0x3; + fbClearBit = true; + break; + case GfxRenderer::GRAYSCALE_MSB: + writeFbMask = 0x6; + break; + case GfxRenderer::GRAYSCALE_LSB: + writeFbMask = 0x2; + break; + case GfxRenderer::GRAY2_LSB: + writeFbMask = 0x5; + if (fb2) writeFb2Mask = 0x3; + break; + case GfxRenderer::GRAY2_MSB: + writeFbMask = 0x3; + break; + default: + break; + } + const int phyW = renderer.getDisplayWidth(); const int phyH = renderer.getDisplayHeight(); @@ -82,52 +122,47 @@ struct DirectPixelWriter { phyYStepY = 1; break; } + + // Per-column advance in physical-Y expressed as a byte-index delta. + byteIdxYStep = static_cast(phyYStepX) * static_cast(displayWidthBytes); } // Call once per row before the column loop. - // Pre-computes the Y-dependent portion so writePixel() only needs the X part. - inline void beginRow(int logicalY) { - rowPhyXBase = phyXBase + logicalY * phyXStepY; - rowPhyYBase = phyYBase + logicalY * phyYStepY; + // startLogicalX is the X coordinate of the first writePixel() call for this row (default 0). + // Running state is initialised at startLogicalX so every subsequent writePixel() call + // advances to startLogicalX+1, startLogicalX+2, … with zero per-pixel multiplies. + inline void beginRow(int logicalY, int startLogicalX = 0) { + const int rowPhyXBase = phyXBase + logicalY * phyXStepY; + const int rowPhyYBase = phyYBase + logicalY * phyYStepY; + curPhyX = rowPhyXBase + startLogicalX * phyXStepX; + curByteIdx = + static_cast(rowPhyYBase + startLogicalX * phyYStepX) * static_cast(displayWidthBytes); } - // Write a single 2-bit dithered pixel value to the framebuffer. - // Must be called after beginRow() for the current row. + // Write a single 2-bit pixel value to the framebuffer and advance to the next column. + // Must be called after beginRow() for the current row, for every column in order. // No bounds checking — caller guarantees coordinates are valid. - inline void writePixel(int logicalX, uint8_t pixelValue) const { - // Determine whether to draw based on render mode - bool draw; - bool state; - switch (mode) { - case GfxRenderer::BW: - draw = (pixelValue < 3); - state = true; - break; - case GfxRenderer::GRAYSCALE_MSB: - draw = (pixelValue == 1 || pixelValue == 2); - state = false; - break; - case GfxRenderer::GRAYSCALE_LSB: - draw = (pixelValue == 1); - state = false; - break; - default: - return; - } - - if (!draw) return; - - const int phyX = rowPhyXBase + logicalX * phyXStepX; - const int phyY = rowPhyYBase + logicalX * phyYStepX; - - const uint16_t byteIndex = phyY * displayWidthBytes + (phyX >> 3); + // No mode switch — write masks are pre-computed in init() and stored as members. + inline void writePixel(uint8_t pixelValue) { + const int phyX = curPhyX; + const int32_t byteIdx = curByteIdx; + curPhyX += phyXStepX; + curByteIdx += byteIdxYStep; + + const bool doFb = (writeFbMask >> pixelValue) & 1; + const bool doFb2 = (writeFb2Mask >> pixelValue) & 1; + if (!doFb && !doFb2) return; + + const uint32_t bi = static_cast(byteIdx) + static_cast(phyX >> 3); const uint8_t bitMask = 1 << (7 - (phyX & 7)); - if (state) { - fb[byteIndex] &= ~bitMask; // Clear bit (draw black) - } else { - fb[byteIndex] |= bitMask; // Set bit (draw white) + if (doFb) { + if (fbClearBit) + fb[bi] &= ~bitMask; + else + fb[bi] |= bitMask; } + if (doFb2) fb2[bi] |= bitMask; } }; diff --git a/lib/Epub/Epub/converters/DitherUtils.h b/lib/Epub/Epub/converters/DitherUtils.h index ec63a76840..f8614047da 100644 --- a/lib/Epub/Epub/converters/DitherUtils.h +++ b/lib/Epub/Epub/converters/DitherUtils.h @@ -13,15 +13,30 @@ inline const uint8_t bayer4x4[4][4] = { // Apply Bayer dithering and quantize to 4 levels (0-3) // Stateless - works correctly with any pixel processing order inline uint8_t applyBayerDither4Level(uint8_t gray, int x, int y) { + // Soft-shoulder darkening for factory LUT: EPUB image pages render on the + // factory LUT, where palette levels are physically lighter than on the + // differential LUT. Apply a -8 offset to mid-bright pixels onward to bring + // highlights/midtones back down without crushing deep shadow detail. + // Ramp the offset from 0 to 8 across gray [0, 64], flat -8 above 64. + int g = gray; + int offset = (g < 64) ? g * 8 / 64 : 8; + g -= offset; + int bayer = bayer4x4[y & 3][x & 3]; int dither = (bayer - 8) * 5; // Scale to +/-40 (half of quantization step 85) - int adjusted = gray + dither; + int adjusted = g + dither; if (adjusted < 0) adjusted = 0; if (adjusted > 255) adjusted = 255; - if (adjusted < 64) return 0; - if (adjusted < 128) return 1; - if (adjusted < 192) return 2; + // T01=48: slightly above original 43, keeps shadow detail while allowing + // near-black pixels to lift to dark gray. + // T12=133: raised from 128 to push more mid-bright source pixels into the + // palette 1 / palette 2 dither zone for perceptual mid-gray. + // T23=218: raised from 192 to expand light-gray range, preserving + // highlight detail on the brighter factory LUT. + if (adjusted < 48) return 0; + if (adjusted < 133) return 1; + if (adjusted < 218) return 2; return 3; } diff --git a/lib/Epub/Epub/converters/JpegToFramebufferConverter.cpp b/lib/Epub/Epub/converters/JpegToFramebufferConverter.cpp index b0863bb5c8..5bc0d42d84 100644 --- a/lib/Epub/Epub/converters/JpegToFramebufferConverter.cpp +++ b/lib/Epub/Epub/converters/JpegToFramebufferConverter.cpp @@ -176,7 +176,7 @@ int jpegDrawCallback(JPEGDRAW* pDraw) { if (fineScaleFPX == FP_ONE && fineScaleFPY == FP_ONE) { for (int dstY = dstYStart; dstY < dstYEnd; dstY++) { const int outY = cfgY + dstY; - pw.beginRow(outY); + pw.beginRow(outY, cfgX + dstXStart); if (caching) cw.beginRow(outY, ctx->config->y); const uint8_t* row = &pixels[(dstY - blockY) * stride]; for (int dstX = dstXStart; dstX < dstXEnd; dstX++) { @@ -189,7 +189,7 @@ int jpegDrawCallback(JPEGDRAW* pDraw) { dithered = gray / 85; if (dithered > 3) dithered = 3; } - pw.writePixel(outX, dithered); + pw.writePixel(dithered); if (caching) cw.writePixel(outX, dithered); } } @@ -210,7 +210,7 @@ int jpegDrawCallback(JPEGDRAW* pDraw) { for (int dstY = dstYStart; dstY < dstYEnd; dstY++) { const int outY = cfgY + dstY; - pw.beginRow(outY); + pw.beginRow(outY, cfgX + dstXStart); if (caching) cw.beginRow(outY, ctx->config->y); const int32_t srcFyFP = dstY * invScaleFPY; const int32_t fy = srcFyFP & FP_MASK; @@ -248,7 +248,7 @@ int jpegDrawCallback(JPEGDRAW* pDraw) { dithered = gray / 85; if (dithered > 3) dithered = 3; } - pw.writePixel(outX, dithered); + pw.writePixel(dithered); if (caching) cw.writePixel(outX, dithered); } @@ -271,7 +271,7 @@ int jpegDrawCallback(JPEGDRAW* pDraw) { dithered = gray / 85; if (dithered > 3) dithered = 3; } - pw.writePixel(outX, dithered); + pw.writePixel(dithered); if (caching) cw.writePixel(outX, dithered); } @@ -297,7 +297,7 @@ int jpegDrawCallback(JPEGDRAW* pDraw) { dithered = gray / 85; if (dithered > 3) dithered = 3; } - pw.writePixel(outX, dithered); + pw.writePixel(dithered); if (caching) cw.writePixel(outX, dithered); } } @@ -307,7 +307,7 @@ int jpegDrawCallback(JPEGDRAW* pDraw) { // === Nearest-neighbor (downscale: fineScale < 1.0) === for (int dstY = dstYStart; dstY < dstYEnd; dstY++) { const int outY = cfgY + dstY; - pw.beginRow(outY); + pw.beginRow(outY, cfgX + dstXStart); if (caching) cw.beginRow(outY, ctx->config->y); const int32_t srcFyFP = dstY * invScaleFPY; int ly = (srcFyFP >> FP_SHIFT) - blockY; @@ -330,7 +330,7 @@ int jpegDrawCallback(JPEGDRAW* pDraw) { dithered = gray / 85; if (dithered > 3) dithered = 3; } - pw.writePixel(outX, dithered); + pw.writePixel(dithered); if (caching) cw.writePixel(outX, dithered); } } diff --git a/lib/Epub/Epub/converters/PngToFramebufferConverter.cpp b/lib/Epub/Epub/converters/PngToFramebufferConverter.cpp index 0cc1616abc..ce0a4ab7f0 100644 --- a/lib/Epub/Epub/converters/PngToFramebufferConverter.cpp +++ b/lib/Epub/Epub/converters/PngToFramebufferConverter.cpp @@ -197,7 +197,7 @@ int pngDrawCallback(PNGDRAW* pDraw) { // Pre-compute orientation and render-mode state once per row DirectPixelWriter pw; pw.init(*ctx->renderer); - pw.beginRow(outY); + pw.beginRow(outY, outXBase); DirectCacheWriter cw; if (caching) { @@ -220,7 +220,7 @@ int pngDrawCallback(PNGDRAW* pDraw) { ditheredGray = gray / 85; if (ditheredGray > 3) ditheredGray = 3; } - pw.writePixel(outX, ditheredGray); + pw.writePixel(ditheredGray); if (caching) cw.writePixel(outX, ditheredGray); } diff --git a/lib/Epub/Epub/hyphenation/HyphenationCommon.cpp b/lib/Epub/Epub/hyphenation/HyphenationCommon.cpp index 4b2ac4a100..13be226387 100644 --- a/lib/Epub/Epub/hyphenation/HyphenationCommon.cpp +++ b/lib/Epub/Epub/hyphenation/HyphenationCommon.cpp @@ -13,9 +13,19 @@ uint32_t toLowerLatinImpl(const uint32_t cp) { return cp + 0x20; } + // Latin Extended-A (U+0100..U+017E): uppercase letters are paired with + // lowercase at cp+1. Two sub-ranges have different alignment: + // U+0100..U+0137: uppercase on EVEN codepoints + // U+0139..U+0148: uppercase on ODD codepoints + // U+014A..U+0177: uppercase on EVEN codepoints + // U+0179..U+017E: uppercase on ODD codepoints + // Covers Polish (Ą/ą, Ć/ć, Ę/ę, Ł/ł, Ń/ń, Ś/ś, Ź/ź, Ż/ż), Czech, Hungarian, Turkish, etc. + if ((cp >= 0x0100 && cp <= 0x0137 && (cp % 2 == 0)) || (cp >= 0x0139 && cp <= 0x0148 && (cp % 2 == 1)) || + (cp >= 0x014A && cp <= 0x0177 && (cp % 2 == 0)) || (cp >= 0x0179 && cp <= 0x017E && (cp % 2 == 1))) { + return cp + 1; + } + switch (cp) { - case 0x0152: // Œ - return 0x0153; // œ case 0x0178: // Ÿ return 0x00FF; // ÿ case 0x1E9E: // ẞ @@ -54,6 +64,11 @@ bool isLatinLetter(const uint32_t cp) { return true; } + // Latin Extended-A (U+0100..U+017F): Polish, Czech, Hungarian, Turkish, etc. + if (cp >= 0x0100 && cp <= 0x017F) { + return true; + } + switch (cp) { case 0x0152: // Œ case 0x0153: // œ @@ -273,6 +288,30 @@ std::vector collectCodepoints(const std::string& word) { case 0x0079: composed = 0x00FD; break; // y -> ý + case 0x0043: + composed = 0x0106; + break; // C -> Ć + case 0x0063: + composed = 0x0107; + break; // c -> ć + case 0x004E: + composed = 0x0143; + break; // N -> Ń + case 0x006E: + composed = 0x0144; + break; // n -> ń + case 0x0053: + composed = 0x015A; + break; // S -> Ś + case 0x0073: + composed = 0x015B; + break; // s -> ś + case 0x005A: + composed = 0x0179; + break; // Z -> Ź + case 0x007A: + composed = 0x017A; + break; // z -> ź default: break; } @@ -373,6 +412,18 @@ std::vector collectCodepoints(const std::string& word) { break; } break; + case 0x0307: // dot above (Polish Ż) + switch (prev) { + case 0x005A: + composed = 0x017B; + break; // Z -> Ż + case 0x007A: + composed = 0x017C; + break; // z -> ż + default: + break; + } + break; case 0x0327: // cedilla switch (prev) { case 0x0043: @@ -385,6 +436,24 @@ std::vector collectCodepoints(const std::string& word) { break; } break; + case 0x0328: // ogonek (Polish Ą, Ę) + switch (prev) { + case 0x0041: + composed = 0x0104; + break; // A -> Ą + case 0x0061: + composed = 0x0105; + break; // a -> ą + case 0x0045: + composed = 0x0118; + break; // E -> Ę + case 0x0065: + composed = 0x0119; + break; // e -> ę + default: + break; + } + break; default: break; } diff --git a/lib/Epub/Epub/hyphenation/Hyphenator.cpp b/lib/Epub/Epub/hyphenation/Hyphenator.cpp index ada620e2bb..ed05d0612b 100644 --- a/lib/Epub/Epub/hyphenation/Hyphenator.cpp +++ b/lib/Epub/Epub/hyphenation/Hyphenator.cpp @@ -22,10 +22,9 @@ struct Iso639Mapping { const char* iso639_2; const char* iso639_1; }; -static constexpr Iso639Mapping kIso639Mappings[] = { - {"eng", "en"}, {"fra", "fr"}, {"fre", "fr"}, {"deu", "de"}, {"ger", "de"}, - {"rus", "ru"}, {"spa", "es"}, {"ita", "it"}, {"ukr", "uk"}, -}; +static constexpr Iso639Mapping kIso639Mappings[] = {{"eng", "en"}, {"fra", "fr"}, {"fre", "fr"}, {"deu", "de"}, + {"ger", "de"}, {"rus", "ru"}, {"spa", "es"}, {"ita", "it"}, + {"ukr", "uk"}, {"swe", "sv"}}; // Maps a BCP-47 or ISO 639-2 language tag to a language-specific hyphenator. const LanguageHyphenator* hyphenatorForLanguage(const std::string& langTag) { diff --git a/lib/Epub/Epub/hyphenation/LanguageRegistry.cpp b/lib/Epub/Epub/hyphenation/LanguageRegistry.cpp index 052d47ee50..fc770c76c4 100644 --- a/lib/Epub/Epub/hyphenation/LanguageRegistry.cpp +++ b/lib/Epub/Epub/hyphenation/LanguageRegistry.cpp @@ -9,7 +9,9 @@ #include "generated/hyph-es.trie.h" #include "generated/hyph-fr.trie.h" #include "generated/hyph-it.trie.h" +#include "generated/hyph-pl.trie.h" #include "generated/hyph-ru.trie.h" +#include "generated/hyph-sv.trie.h" #include "generated/hyph-uk.trie.h" namespace { @@ -21,9 +23,11 @@ LanguageHyphenator germanHyphenator(de_patterns, isLatinLetter, toLowerLatin); LanguageHyphenator russianHyphenator(ru_patterns, isCyrillicLetter, toLowerCyrillic); LanguageHyphenator spanishHyphenator(es_patterns, isLatinLetter, toLowerLatin); LanguageHyphenator italianHyphenator(it_patterns, isLatinLetter, toLowerLatin); +LanguageHyphenator swedishHyphenator(sv_patterns, isLatinLetter, toLowerLatin); LanguageHyphenator ukrainianHyphenator(uk_patterns, isCyrillicLetter, toLowerCyrillic); +LanguageHyphenator polishHyphenator(pl_patterns, isLatinLetter, toLowerLatin); -using EntryArray = std::array; +using EntryArray = std::array; const EntryArray& entries() { static const EntryArray kEntries = {{{"english", "en", &englishHyphenator}, @@ -32,6 +36,8 @@ const EntryArray& entries() { {"russian", "ru", &russianHyphenator}, {"spanish", "es", &spanishHyphenator}, {"italian", "it", &italianHyphenator}, + {"polish", "pl", &polishHyphenator}, + {"swedish", "sv", &swedishHyphenator}, {"ukrainian", "uk", &ukrainianHyphenator}}}; return kEntries; } diff --git a/lib/Epub/Epub/hyphenation/generated/hyph-pl.trie.h b/lib/Epub/Epub/hyphenation/generated/hyph-pl.trie.h new file mode 100644 index 0000000000..7e4068c29a --- /dev/null +++ b/lib/Epub/Epub/hyphenation/generated/hyph-pl.trie.h @@ -0,0 +1,987 @@ +#pragma once + +#include +#include + +#include "Epub/hyphenation/SerializedHyphenationTrie.h" + +// Auto-generated by generate_hyphenation_trie.py. Do not edit manually. +alignas(4) constexpr uint8_t pl_trie_data[] = { + 0x3A, 0x26, 0x30, 0x48, 0x17, 0x3E, 0x0F, 0x52, 0x67, 0x0C, 0x44, 0x16, 0x0C, 0x0D, 0x16, 0x0D, + 0x22, 0x23, 0x21, 0x35, 0x16, 0x35, 0x0C, 0x21, 0x0C, 0x5C, 0x0D, 0x1C, 0x20, 0x0D, 0x21, 0x0E, + 0x34, 0x34, 0x0B, 0x3F, 0x16, 0x3F, 0x0C, 0x49, 0x0C, 0x53, 0x16, 0x70, 0x0D, 0x49, 0x16, 0x3E, + 0x0D, 0x3F, 0x0E, 0x21, 0x0E, 0x0D, 0x21, 0x16, 0x22, 0x17, 0x22, 0x0D, 0x23, 0x0E, 0x0C, 0x34, + 0x0D, 0x35, 0x0E, 0x7B, 0x16, 0x84, 0x0D, 0x5C, 0x17, 0x16, 0x0D, 0x0C, 0x0F, 0x16, 0x16, 0x0B, + 0x0C, 0x0B, 0x2C, 0x17, 0x0E, 0x18, 0x0F, 0x0C, 0x2B, 0x0C, 0x52, 0x0D, 0x66, 0x2A, 0x0C, 0x0D, + 0x2B, 0x18, 0x2B, 0x18, 0x0D, 0x2C, 0x19, 0x0C, 0x53, 0x0C, 0x2A, 0x17, 0x20, 0x0C, 0x21, 0x20, + 0x21, 0x0E, 0x0C, 0x22, 0x0D, 0x0C, 0x0C, 0x22, 0x0F, 0x5F, 0x2B, 0x16, 0x2D, 0x16, 0x2D, 0x0C, + 0x36, 0x0D, 0x2B, 0x0C, 0x16, 0x2B, 0x0C, 0x0C, 0x2B, 0x16, 0x0D, 0x41, 0x16, 0x34, 0x0C, 0x2C, + 0x0D, 0x2C, 0x21, 0x3E, 0x0C, 0x3F, 0x20, 0x40, 0x0D, 0x0C, 0x4B, 0x52, 0x0C, 0x53, 0x20, 0x53, + 0x0E, 0x53, 0x0E, 0x16, 0x53, 0x0C, 0x0C, 0x0D, 0x54, 0x0F, 0x54, 0x0F, 0x16, 0x54, 0x0F, 0x0C, + 0x5D, 0x16, 0x5D, 0x0C, 0x7A, 0x17, 0x0E, 0x16, 0x17, 0x10, 0x17, 0x0C, 0x18, 0x11, 0x21, 0x0C, + 0x0C, 0x2B, 0x0D, 0x23, 0x16, 0x23, 0x0C, 0x2A, 0x0D, 0x20, 0x16, 0x22, 0x0F, 0x0C, 0x2A, 0x16, + 0x34, 0x0B, 0x20, 0x34, 0x17, 0x21, 0x0C, 0x0C, 0x0D, 0x22, 0x0D, 0x0E, 0x0C, 0x0D, 0x22, 0x0F, + 0x16, 0x22, 0x17, 0x0C, 0x2B, 0x34, 0x0F, 0x35, 0x20, 0x2C, 0x0B, 0x2C, 0x0C, 0x35, 0x0E, 0x0D, + 0x35, 0x0E, 0x16, 0x35, 0x0C, 0x0C, 0x0D, 0x36, 0x0F, 0x36, 0x0F, 0x16, 0x36, 0x0F, 0x0E, 0x48, + 0x0D, 0x49, 0x0E, 0x3F, 0x2B, 0x0C, 0x21, 0x0E, 0x0D, 0x16, 0x21, 0x0E, 0x0D, 0x0C, 0x22, 0x0F, + 0x0E, 0x0D, 0x36, 0x0F, 0x0C, 0x41, 0x0C, 0x48, 0x0B, 0x66, 0x0D, 0x2A, 0x16, 0x17, 0x20, 0x11, + 0x4A, 0x0F, 0x18, 0x0D, 0x0C, 0x18, 0x17, 0x22, 0x0D, 0x20, 0x48, 0x21, 0x3E, 0x17, 0x21, 0x0C, + 0x0D, 0x68, 0x34, 0x2B, 0x2B, 0x0E, 0x22, 0x0D, 0x0C, 0x0B, 0x0C, 0x52, 0x17, 0x36, 0x21, 0x15, + 0x01, 0x16, 0x02, 0x15, 0x02, 0x0B, 0x02, 0x1F, 0x03, 0x0C, 0x03, 0x0C, 0x16, 0x03, 0x0C, 0x0C, + 0x04, 0x17, 0x04, 0x0D, 0x08, 0x16, 0x0D, 0x16, 0x16, 0x0D, 0x16, 0x0D, 0x3E, 0x0B, 0x20, 0x0B, + 0x20, 0x0C, 0x0D, 0x20, 0x17, 0x29, 0x16, 0x11, 0x16, 0x0F, 0x20, 0x0B, 0x0C, 0x2A, 0x0B, 0x16, + 0x15, 0x18, 0x0E, 0x0D, 0x20, 0x0F, 0x16, 0x11, 0x3F, 0x18, 0x16, 0x0D, 0x16, 0x16, 0x0D, 0x17, + 0x0C, 0x20, 0x15, 0x17, 0x0C, 0x0D, 0x16, 0x0C, 0x0B, 0xA0, 0x00, 0x41, 0x21, 0x87, 0xFD, 0x25, + 0x82, 0x84, 0x9B, 0xBA, 0xBC, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xA0, 0x00, 0x61, 0xA0, 0x00, 0x72, + 0x21, 0x87, 0xFD, 0x21, 0xC4, 0xFD, 0x21, 0x72, 0xFD, 0x21, 0x65, 0xFD, 0xA1, 0x00, 0x61, 0x69, + 0xFD, 0xB5, 0x00, 0x51, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, + 0x6E, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7A, 0xDB, 0xDE, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, + 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xFB, 0xE9, 0xE9, 0x21, 0x87, + 0xD3, 0xD5, 0x00, 0x51, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, + 0x6E, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7A, 0xFF, 0xAB, 0xFF, 0xAE, 0xFF, 0xB9, 0xFF, + 0xB9, 0xFF, 0xB9, 0xFF, 0xB9, 0xFF, 0xB9, 0xFF, 0xB9, 0xFF, 0xB9, 0xFF, 0xB9, 0xFF, 0xB9, 0xFF, + 0xB9, 0xFF, 0xB9, 0xFF, 0xB9, 0xFF, 0xB9, 0xFF, 0xB9, 0xFF, 0xB9, 0xFF, 0xB9, 0xFF, 0xB9, 0xFF, + 0xB9, 0xFF, 0xB9, 0xA0, 0x00, 0xB1, 0xA1, 0x00, 0x92, 0x72, 0xFD, 0x21, 0x64, 0xFB, 0x21, 0xB3, + 0xFD, 0xA1, 0x00, 0x61, 0xC3, 0xFD, 0xA0, 0x00, 0xC2, 0x21, 0x77, 0xFD, 0x21, 0x6F, 0xFD, 0x21, + 0x82, 0xFD, 0x21, 0xC5, 0xFD, 0x21, 0x74, 0xFD, 0x21, 0x61, 0xFD, 0xA1, 0x00, 0x61, 0x69, 0xFD, + 0xD5, 0x00, 0x51, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, + 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7A, 0xFF, 0x3C, 0xFF, 0x3F, 0xFF, 0x4A, 0xFF, 0x4A, + 0xFF, 0x4A, 0xFF, 0x4A, 0xFF, 0x4A, 0xFF, 0x4A, 0xFF, 0x4A, 0xFF, 0x4A, 0xFF, 0x4A, 0xFF, 0x4A, + 0xFF, 0x4A, 0xFF, 0x4A, 0xFF, 0xE1, 0xFF, 0x4A, 0xFF, 0x4A, 0xFF, 0x4A, 0xFF, 0xFB, 0xFF, 0x4A, + 0xFF, 0x4A, 0xA0, 0x00, 0xE1, 0x21, 0xBA, 0xFD, 0xA1, 0x00, 0x61, 0xC5, 0xFD, 0xD5, 0x00, 0x51, + 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, + 0x74, 0x76, 0x77, 0x78, 0x7A, 0xFE, 0xEF, 0xFE, 0xF2, 0xFE, 0xFD, 0xFE, 0xFD, 0xFF, 0xFB, 0xFE, + 0xFD, 0xFE, 0xFD, 0xFE, 0xFD, 0xFE, 0xFD, 0xFE, 0xFD, 0xFE, 0xFD, 0xFE, 0xFD, 0xFE, 0xFD, 0xFE, + 0xFD, 0xFE, 0xFD, 0xFE, 0xFD, 0xFE, 0xFD, 0xFE, 0xFD, 0xFE, 0xFD, 0xFE, 0xFD, 0xFE, 0xFD, 0x45, + 0x82, 0x84, 0x9B, 0xBA, 0xBC, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x71, 0xFF, 0xBE, 0xFF, 0x02, 0xA0, + 0x00, 0xF3, 0x21, 0x74, 0xFD, 0x21, 0x73, 0xFD, 0xA0, 0x01, 0x51, 0x21, 0x74, 0xFD, 0xA1, 0x01, + 0x41, 0x70, 0xFD, 0xA0, 0x01, 0x41, 0xA1, 0x01, 0x41, 0x75, 0xF2, 0xA2, 0x01, 0x41, 0x70, 0x72, + 0xED, 0xED, 0xA6, 0x01, 0x22, 0x61, 0x65, 0x69, 0x6F, 0x75, 0x79, 0xEC, 0xF1, 0xF4, 0xF9, 0xF1, + 0xF1, 0xA0, 0x00, 0x91, 0xA5, 0x01, 0x61, 0x61, 0x65, 0x69, 0x6F, 0x75, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0x21, 0x6F, 0xF3, 0x21, 0x72, 0xFD, 0x25, 0x61, 0x65, 0x69, 0x6F, 0x75, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0x21, 0x79, 0xF5, 0x21, 0x74, 0xFD, 0xA0, 0x01, 0x72, 0x21, 0x82, 0xFD, 0xA1, 0x01, + 0x92, 0x7A, 0xFA, 0xA0, 0x01, 0x92, 0x29, 0xC5, 0x62, 0x6B, 0x6D, 0x61, 0x65, 0x69, 0x6F, 0x75, + 0xF5, 0xF8, 0xFD, 0xFD, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0x21, 0x79, 0xED, 0x21, 0x63, 0xFD, 0xA0, + 0x01, 0xB2, 0x21, 0x68, 0xD6, 0xA0, 0x01, 0xD2, 0x21, 0x73, 0xFD, 0x21, 0x6E, 0xFD, 0x21, 0x61, + 0xFD, 0x21, 0x72, 0xFD, 0x47, 0x63, 0x61, 0x65, 0x69, 0x6F, 0x74, 0x75, 0xFF, 0xEE, 0xFF, 0x9D, + 0xFF, 0x9D, 0xFF, 0x9D, 0xFF, 0x9D, 0xFF, 0xFD, 0xFF, 0x9D, 0xA1, 0x01, 0xB2, 0x6F, 0xEA, 0x23, + 0x67, 0x6B, 0x74, 0xD0, 0xD0, 0xFB, 0x46, 0x62, 0x64, 0x65, 0x6E, 0x72, 0x75, 0xFF, 0x4F, 0xFF, + 0x6C, 0xFF, 0x8E, 0xFF, 0x9F, 0xFF, 0xC6, 0xFF, 0xF9, 0x41, 0x87, 0xFD, 0xE1, 0x45, 0x82, 0x84, + 0x9B, 0xBA, 0xBC, 0xFD, 0xDD, 0xFD, 0xDD, 0xFD, 0xDD, 0xFD, 0xDD, 0xFD, 0xDD, 0xA0, 0x00, 0x51, + 0xA0, 0x02, 0x22, 0x21, 0x6E, 0xFD, 0x21, 0x63, 0xFA, 0x21, 0x6B, 0xF7, 0x41, 0x68, 0xFF, 0x45, + 0xA0, 0x02, 0x41, 0xA0, 0x02, 0x52, 0x21, 0x6A, 0xFD, 0xA1, 0x02, 0x41, 0x62, 0xFD, 0x41, 0x77, + 0xFF, 0x33, 0xA8, 0x02, 0x02, 0x61, 0x65, 0x69, 0x63, 0x6D, 0x6F, 0x77, 0x7A, 0xE1, 0xE4, 0xE7, + 0xEA, 0xEE, 0xF7, 0xEE, 0xFC, 0x21, 0x7A, 0xED, 0xC1, 0x00, 0x51, 0x7A, 0xFD, 0x92, 0xB6, 0x01, + 0xF1, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, + 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7A, 0xAB, 0xAF, 0xBF, 0xBF, 0xBF, 0xF7, 0xBF, 0xBF, 0xBF, + 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xFA, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xA0, 0x02, 0x72, + 0x21, 0x9B, 0xFD, 0xA0, 0x02, 0x92, 0x22, 0xC5, 0x6B, 0xFA, 0xFD, 0x21, 0x6F, 0xFB, 0x21, 0x82, + 0xFD, 0x21, 0xC5, 0xFD, 0x41, 0x7A, 0xFD, 0x35, 0xA1, 0x00, 0x51, 0x72, 0xFC, 0xA0, 0x02, 0xB2, + 0x21, 0x77, 0xFD, 0x21, 0x6F, 0xFD, 0x21, 0x6B, 0xFD, 0xA0, 0x02, 0xD2, 0x21, 0x72, 0xFD, 0x21, + 0x6B, 0xFD, 0x21, 0x6F, 0xFD, 0x21, 0x82, 0xFD, 0x21, 0xC5, 0xFD, 0x22, 0x6E, 0x70, 0xEB, 0xFD, + 0x21, 0x65, 0xFB, 0x21, 0x6B, 0xDA, 0x21, 0x6F, 0xFD, 0x21, 0x6E, 0xFD, 0x21, 0x72, 0xFD, 0xA0, + 0x02, 0xF2, 0x21, 0x74, 0xFD, 0x21, 0x65, 0xFD, 0xA1, 0x00, 0x72, 0x73, 0xFD, 0x21, 0x68, 0xFB, + 0x21, 0x63, 0xFD, 0xA0, 0x03, 0x12, 0x21, 0x9B, 0xFD, 0x21, 0xC5, 0xFD, 0x22, 0x65, 0x6F, 0xF4, + 0xFD, 0x21, 0x72, 0xFB, 0x21, 0x65, 0xFD, 0xA0, 0x03, 0x52, 0x22, 0x85, 0x99, 0xFD, 0xFD, 0xA4, + 0x03, 0x32, 0xC4, 0x61, 0x65, 0x6F, 0xFB, 0xF8, 0xF8, 0xF8, 0x21, 0x72, 0xF5, 0x21, 0xB3, 0xFD, + 0x21, 0xC3, 0xFD, 0xC4, 0x00, 0x51, 0x61, 0x6B, 0x74, 0x77, 0xFF, 0xB9, 0xFC, 0xC7, 0xFF, 0xE1, + 0xFF, 0xFD, 0xD7, 0x01, 0xF1, 0xC4, 0xC5, 0x61, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x69, 0x6A, + 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7A, 0xFE, 0xD7, 0xFE, 0xDB, + 0xFF, 0x6F, 0xFE, 0xEB, 0xFE, 0xEB, 0xFE, 0xEB, 0xFE, 0xEB, 0xFE, 0xEB, 0xFF, 0x76, 0xFF, 0x9E, + 0xFE, 0xEB, 0xFE, 0xEB, 0xFE, 0xEB, 0xFE, 0xEB, 0xFE, 0xEB, 0xFE, 0xEB, 0xFE, 0xEB, 0xFE, 0xEB, + 0xFE, 0xEB, 0xFE, 0xEB, 0xFE, 0xEB, 0xFE, 0xEB, 0xFF, 0xF1, 0x41, 0x72, 0xFF, 0x79, 0x42, 0x74, + 0x77, 0xFF, 0xFC, 0xFF, 0x2F, 0x21, 0x6F, 0xF9, 0x21, 0x67, 0xFD, 0xA1, 0x00, 0x61, 0x75, 0xFD, + 0x45, 0x82, 0x84, 0x9B, 0xBA, 0xBC, 0xFF, 0xFB, 0xFC, 0x5A, 0xFC, 0x5A, 0xFC, 0x5A, 0xFC, 0x5A, + 0x41, 0x65, 0xFF, 0x16, 0x21, 0x6C, 0xFC, 0xA0, 0x03, 0x73, 0x21, 0x6C, 0xFD, 0x21, 0x69, 0xFD, + 0x21, 0x75, 0xF7, 0xA2, 0x02, 0x41, 0x62, 0x77, 0xFA, 0xFD, 0x42, 0x6C, 0x72, 0xFE, 0x66, 0xFE, + 0x66, 0xC4, 0x02, 0x02, 0x61, 0x65, 0x79, 0x6F, 0xFF, 0xF2, 0xFF, 0xF9, 0xFE, 0x5F, 0xFE, 0x6F, + 0x21, 0x7A, 0xF1, 0xA0, 0x03, 0xA2, 0x21, 0x87, 0xFD, 0xA0, 0x03, 0xC2, 0xA1, 0x03, 0xA2, 0x6B, + 0xFD, 0x24, 0x82, 0x9B, 0xBA, 0xBC, 0xFB, 0xF2, 0xF2, 0xF2, 0xC1, 0x02, 0x41, 0x7A, 0xFD, 0x87, + 0xA1, 0x01, 0xB2, 0x72, 0xFA, 0xC2, 0x01, 0xB2, 0x68, 0x7A, 0xFE, 0x3B, 0xFE, 0x3B, 0x42, 0xBA, + 0xBC, 0xFD, 0x73, 0xFD, 0x73, 0xC2, 0x01, 0xB2, 0xC5, 0x7A, 0xFF, 0xF9, 0xFE, 0x2B, 0x41, 0x7A, + 0xFD, 0x63, 0xA1, 0x01, 0xB2, 0x72, 0xFC, 0xA0, 0x03, 0xE2, 0xA1, 0x01, 0xB2, 0x74, 0xFD, 0xA1, + 0x01, 0xB2, 0x6E, 0xF8, 0xA0, 0x04, 0x03, 0xA1, 0x03, 0xE2, 0x6E, 0xFD, 0xA1, 0x01, 0xB2, 0x6B, + 0xFB, 0xC2, 0x01, 0xB2, 0x63, 0x72, 0xFD, 0xFB, 0xFF, 0xDD, 0x41, 0xBC, 0xFD, 0x37, 0xC3, 0x01, + 0xB2, 0x73, 0xC5, 0x7A, 0xFF, 0xD9, 0xFF, 0xFC, 0xFD, 0xF2, 0xC3, 0x01, 0xB2, 0x63, 0x6D, 0x7A, + 0xFD, 0xE2, 0xFD, 0xE6, 0xFD, 0xE6, 0xC2, 0x01, 0xB2, 0x6B, 0x72, 0xFD, 0xDA, 0xFD, 0xDA, 0xA1, + 0x01, 0xB2, 0x63, 0xB8, 0x51, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, + 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0xFF, 0x72, 0xFF, 0x7D, 0xFF, 0x8C, 0xFF, 0x91, 0xFF, 0xA1, + 0xFD, 0x5B, 0xFF, 0xAE, 0xFD, 0x5B, 0xFF, 0xB6, 0xFF, 0xBB, 0xFF, 0xC8, 0xFF, 0xCD, 0xFF, 0xDA, + 0xFF, 0xE6, 0xFF, 0xF2, 0xFF, 0xFB, 0xFD, 0x5B, 0x41, 0x77, 0xFD, 0xFB, 0x21, 0x6F, 0xFC, 0x21, + 0x67, 0xFD, 0xC2, 0x00, 0x51, 0x6F, 0x7A, 0xFF, 0xFD, 0xFB, 0x48, 0xA0, 0x04, 0x52, 0x22, 0x85, + 0x99, 0xFD, 0xFD, 0xA4, 0x04, 0x32, 0xC4, 0x61, 0x65, 0x6F, 0xFB, 0xF8, 0xF8, 0xF8, 0x21, 0x6A, + 0xF5, 0x21, 0xB3, 0xFD, 0xA1, 0x00, 0x51, 0xC3, 0xFD, 0x41, 0x61, 0xFD, 0x57, 0xA0, 0x01, 0x61, + 0xC5, 0x02, 0x02, 0x65, 0x6F, 0x74, 0x79, 0x7A, 0xFD, 0x50, 0xFD, 0x50, 0xFF, 0xF9, 0xFD, 0x50, + 0xFF, 0xFD, 0xC2, 0x02, 0x02, 0x65, 0x75, 0xFD, 0x3E, 0xFD, 0x4E, 0x22, 0x73, 0x7A, 0xE5, 0xF7, + 0xA0, 0x04, 0x72, 0x21, 0x9B, 0xFD, 0x21, 0xC5, 0xFD, 0x21, 0x6F, 0xFD, 0x21, 0x69, 0xFD, 0x21, + 0x63, 0xFD, 0x21, 0x99, 0xFD, 0x21, 0xC4, 0xFD, 0x21, 0x69, 0xFD, 0xA0, 0x04, 0x92, 0x21, 0x74, + 0xFD, 0x21, 0x65, 0xFD, 0xA1, 0x04, 0xB2, 0x73, 0xFD, 0x21, 0x87, 0xFB, 0x22, 0xC4, 0x63, 0xFD, + 0xE0, 0x21, 0x99, 0xFB, 0x21, 0xC4, 0xFD, 0x21, 0x69, 0xFD, 0x22, 0x73, 0x77, 0xDE, 0xFD, 0x21, + 0x65, 0xFB, 0xA1, 0x00, 0x51, 0x69, 0xFD, 0xD9, 0x01, 0xF1, 0xC4, 0xC5, 0x61, 0x62, 0x63, 0x64, + 0x65, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, + 0x78, 0x79, 0x7A, 0xFC, 0xD2, 0xFE, 0x59, 0xFE, 0x6D, 0xFC, 0xE6, 0xFC, 0xE6, 0xFC, 0xE6, 0xFE, + 0x99, 0xFC, 0xE6, 0xFC, 0xE6, 0xFC, 0xE6, 0xFC, 0xE6, 0xFC, 0xE6, 0xFC, 0xE6, 0xFC, 0xE6, 0xFC, + 0xE6, 0xFF, 0x2D, 0xFC, 0xE6, 0xFF, 0x6B, 0xFC, 0xE6, 0xFC, 0xE6, 0xFC, 0xE6, 0xFF, 0x8D, 0xFC, + 0xE6, 0xFF, 0xB4, 0xFF, 0xFB, 0xA0, 0x05, 0x61, 0xA1, 0x00, 0xF3, 0x79, 0xFD, 0x21, 0x73, 0xFB, + 0xA0, 0x04, 0xD5, 0x21, 0x74, 0xFD, 0x21, 0x65, 0xFD, 0x21, 0x7A, 0xFD, 0x21, 0x73, 0xFD, 0x21, + 0x65, 0xFD, 0xA0, 0x05, 0x24, 0x21, 0x61, 0xFD, 0x21, 0x6D, 0xFD, 0x21, 0x73, 0xFD, 0xA0, 0x05, + 0x22, 0x21, 0x61, 0xFD, 0x23, 0x65, 0x68, 0x74, 0xF7, 0xFD, 0xFA, 0x45, 0x61, 0x65, 0x69, 0x6F, + 0x75, 0xFC, 0x75, 0xFC, 0x75, 0xFC, 0x75, 0xFC, 0x75, 0xFC, 0x75, 0x21, 0x6F, 0xF0, 0xA0, 0x01, + 0xD1, 0x25, 0x61, 0x65, 0x69, 0x6F, 0x75, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0x21, 0x6F, 0xF5, 0x21, + 0x72, 0xFD, 0x21, 0x74, 0xFD, 0x21, 0x6B, 0xFD, 0x21, 0x65, 0xFD, 0x45, 0x6B, 0x6D, 0x73, 0x67, + 0x6C, 0xFF, 0xA2, 0xFF, 0xB4, 0xFF, 0xC9, 0xFF, 0xE0, 0xFF, 0xFD, 0xD5, 0x01, 0xF1, 0xC4, 0xC5, + 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x76, + 0x77, 0x78, 0x7A, 0xFC, 0x0E, 0xFC, 0x12, 0xFC, 0x22, 0xFC, 0x22, 0xFC, 0x22, 0xFC, 0x22, 0xFC, + 0x22, 0xFC, 0x22, 0xFC, 0x22, 0xFC, 0x22, 0xFC, 0x22, 0xFC, 0x22, 0xFC, 0x22, 0xFC, 0x22, 0xFC, + 0x22, 0xFC, 0x22, 0xFC, 0x22, 0xFC, 0x22, 0xFC, 0x22, 0xFC, 0x22, 0xFC, 0x22, 0xA0, 0x02, 0x02, + 0x21, 0x6F, 0xFD, 0x21, 0x75, 0xFA, 0x41, 0x62, 0xFE, 0x56, 0xC2, 0x00, 0x51, 0x75, 0x7A, 0xFF, + 0xFC, 0xF9, 0xA0, 0xD7, 0x01, 0xF1, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x6A, + 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7A, 0xFB, 0xB6, 0xFB, + 0xBA, 0xFB, 0xCA, 0xFB, 0xCA, 0xFB, 0xCA, 0xFF, 0xED, 0xFB, 0xCA, 0xFB, 0xCA, 0xFB, 0xCA, 0xFB, + 0xCA, 0xFB, 0xCA, 0xFB, 0xCA, 0xFB, 0xCA, 0xFB, 0xCA, 0xFF, 0xF0, 0xFB, 0xCA, 0xFF, 0xF7, 0xFB, + 0xCA, 0xFB, 0xCA, 0xFB, 0xCA, 0xFB, 0xCA, 0xFB, 0xCA, 0xFB, 0xCA, 0xA0, 0x00, 0x71, 0xC3, 0x04, + 0x32, 0x6F, 0x61, 0x65, 0xFE, 0x0D, 0xFF, 0xFD, 0xFF, 0xFD, 0x21, 0x72, 0xF4, 0x21, 0x65, 0xFD, + 0x21, 0x70, 0xFD, 0xD6, 0x01, 0xF1, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x69, 0x6A, + 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7A, 0xFB, 0x56, 0xFB, 0x5A, + 0xFB, 0x6A, 0xFB, 0x6A, 0xFB, 0x6A, 0xFB, 0x6A, 0xFB, 0x6A, 0xFB, 0x6A, 0xFF, 0xFD, 0xFB, 0x6A, + 0xFB, 0x6A, 0xFB, 0x6A, 0xFB, 0x6A, 0xFB, 0x6A, 0xFB, 0x6A, 0xFB, 0x6A, 0xFB, 0x6A, 0xFB, 0x6A, + 0xFB, 0x6A, 0xFB, 0x6A, 0xFB, 0x6A, 0xFB, 0x6A, 0xA0, 0x05, 0x72, 0x21, 0x63, 0xFD, 0xA0, 0x05, + 0x93, 0xA0, 0x05, 0xC2, 0xA2, 0x05, 0x72, 0x6B, 0x77, 0xFA, 0xFD, 0x41, 0x6E, 0xFD, 0x0C, 0x21, + 0x61, 0xFC, 0x21, 0x6C, 0xFD, 0xA4, 0x01, 0x22, 0x69, 0x6F, 0x75, 0x66, 0xE6, 0xEF, 0xE3, 0xFD, + 0xA0, 0x01, 0x22, 0x21, 0x6C, 0xFD, 0x43, 0x6E, 0x73, 0x7A, 0xFF, 0xEF, 0xFF, 0xFD, 0xFE, 0xA5, + 0x41, 0x82, 0xFB, 0x83, 0x21, 0xC5, 0xFC, 0x21, 0x64, 0xFD, 0xD6, 0x01, 0xF1, 0xC4, 0xC5, 0x61, + 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x76, + 0x77, 0x78, 0x7A, 0xFA, 0xCF, 0xFA, 0xD3, 0xFF, 0xFD, 0xFA, 0xE3, 0xFA, 0xE3, 0xFA, 0xE3, 0xFA, + 0xE3, 0xFA, 0xE3, 0xFA, 0xE3, 0xFA, 0xE3, 0xFA, 0xE3, 0xFA, 0xE3, 0xFA, 0xE3, 0xFA, 0xE3, 0xFA, + 0xE3, 0xFA, 0xE3, 0xFA, 0xE3, 0xFA, 0xE3, 0xFA, 0xE3, 0xFA, 0xE3, 0xFA, 0xE3, 0xFA, 0xE3, 0xA0, + 0x06, 0x01, 0xA1, 0x05, 0xE2, 0x6F, 0xFD, 0x21, 0x74, 0xFB, 0x21, 0x65, 0xFD, 0x21, 0x73, 0xFD, + 0x21, 0x75, 0xFD, 0x21, 0x6B, 0xFD, 0x21, 0x6C, 0xFD, 0x41, 0x82, 0xFD, 0x03, 0xA0, 0x06, 0x93, + 0x21, 0x69, 0xFD, 0x22, 0x65, 0x79, 0xFA, 0xFA, 0x21, 0x61, 0xF5, 0xA0, 0x06, 0x92, 0x21, 0x6D, + 0xFD, 0x21, 0x63, 0xFA, 0x21, 0x74, 0xF7, 0x21, 0x67, 0xF4, 0xA7, 0x06, 0x42, 0x67, 0x73, 0x74, + 0x64, 0x6B, 0x6C, 0x72, 0xE6, 0xE9, 0xEE, 0xF4, 0xF7, 0xFA, 0xFD, 0xA0, 0x06, 0x42, 0xA0, 0x06, + 0x63, 0xA2, 0x00, 0x71, 0x6C, 0x77, 0xFD, 0xFD, 0xC5, 0x06, 0x13, 0x61, 0x65, 0x6F, 0x79, 0x75, + 0xFF, 0xE2, 0xFF, 0xF3, 0xFF, 0xF9, 0xFF, 0xF3, 0xFE, 0xC3, 0x21, 0x72, 0xEE, 0x21, 0x74, 0xFD, + 0x42, 0xC5, 0x6E, 0xFF, 0xA9, 0xFF, 0xFD, 0xA0, 0x06, 0xC2, 0x42, 0x74, 0x77, 0xFA, 0xC2, 0xFF, + 0xFD, 0x21, 0x6F, 0xF9, 0x21, 0x6B, 0xFD, 0x21, 0x74, 0xFD, 0x21, 0xB3, 0xFD, 0xA0, 0x06, 0xE2, + 0x21, 0x87, 0xFD, 0x21, 0xC4, 0xFD, 0xC3, 0x00, 0x51, 0xC3, 0x6F, 0x7A, 0xFF, 0xF4, 0xFF, 0xFD, + 0xF7, 0xD4, 0xD7, 0x01, 0xF1, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, + 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7A, 0xF9, 0xE7, 0xF9, 0xEB, + 0xF9, 0xFB, 0xF9, 0xFB, 0xF9, 0xFB, 0xF9, 0xFB, 0xF9, 0xFB, 0xF9, 0xFB, 0xFF, 0x74, 0xF9, 0xFB, + 0xF9, 0xFB, 0xF9, 0xFB, 0xF9, 0xFB, 0xF9, 0xFB, 0xFF, 0xCE, 0xF9, 0xFB, 0xFF, 0xF4, 0xF9, 0xFB, + 0xF9, 0xFB, 0xF9, 0xFB, 0xF9, 0xFB, 0xF9, 0xFB, 0xF9, 0xFB, 0x41, 0x77, 0xF9, 0x39, 0x21, 0x6F, + 0xFC, 0x21, 0x64, 0xFD, 0xD6, 0x01, 0xF1, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, + 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x7A, 0xF9, 0x95, 0xF9, + 0x99, 0xF9, 0xA9, 0xF9, 0xA9, 0xF9, 0xA9, 0xF9, 0xA9, 0xF9, 0xA9, 0xF9, 0xA9, 0xF9, 0xA9, 0xF9, + 0xA9, 0xF9, 0xA9, 0xF9, 0xA9, 0xF9, 0xA9, 0xF9, 0xA9, 0xF9, 0xA9, 0xF9, 0xA9, 0xF9, 0xA9, 0xFF, + 0xFD, 0xF9, 0xA9, 0xF9, 0xA9, 0xF9, 0xA9, 0xF9, 0xA9, 0xA0, 0x01, 0x71, 0x21, 0x70, 0xFD, 0x21, + 0x6D, 0xFD, 0x21, 0x61, 0xFD, 0x21, 0x69, 0xFD, 0x21, 0x6C, 0xFD, 0x41, 0x6E, 0xF9, 0xE8, 0x21, + 0xBC, 0xFC, 0x21, 0xC5, 0xFD, 0xD7, 0x01, 0xF1, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, + 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7A, 0xF9, + 0x34, 0xF9, 0x38, 0xF9, 0x48, 0xF9, 0x48, 0xF9, 0x48, 0xF9, 0x48, 0xF9, 0x48, 0xF9, 0x48, 0xFF, + 0xF3, 0xF9, 0x48, 0xF9, 0x48, 0xF9, 0x48, 0xF9, 0x48, 0xF9, 0x48, 0xFF, 0xFD, 0xF9, 0x48, 0xF9, + 0x48, 0xF9, 0x48, 0xF9, 0x48, 0xF9, 0x48, 0xF9, 0x48, 0xF9, 0x48, 0xF9, 0x48, 0xA0, 0x07, 0xE2, + 0x43, 0x85, 0x99, 0x87, 0xFB, 0xAD, 0xFB, 0xAD, 0xFF, 0xFD, 0xA0, 0x07, 0x22, 0x41, 0x62, 0xF8, + 0xF3, 0xA1, 0x07, 0xE2, 0x75, 0xFC, 0xA0, 0x07, 0xD1, 0x21, 0x6D, 0xFD, 0x21, 0x65, 0xFD, 0x21, + 0x69, 0xFD, 0x21, 0x7A, 0xFD, 0x21, 0x64, 0xFD, 0x21, 0x6F, 0xFD, 0xA1, 0x07, 0xE2, 0x72, 0xFD, + 0xA0, 0x08, 0x02, 0x24, 0xBA, 0x82, 0x9B, 0xBC, 0xD7, 0xDE, 0xF8, 0xFD, 0xC1, 0x05, 0xC2, 0x72, + 0xF8, 0xC4, 0x41, 0x68, 0xF8, 0xBE, 0x21, 0x63, 0xFC, 0xA1, 0x05, 0xC2, 0x75, 0xFD, 0x41, 0x7A, + 0xF8, 0xB2, 0x21, 0x63, 0xFC, 0x21, 0x99, 0xFD, 0xA0, 0x07, 0x43, 0x42, 0x63, 0x74, 0xFF, 0xF3, + 0xF8, 0xA5, 0x21, 0x70, 0xF9, 0xA0, 0x07, 0xB2, 0x22, 0x85, 0x99, 0xFD, 0xFD, 0x21, 0x7A, 0xF8, + 0x21, 0x63, 0xFD, 0xA3, 0x02, 0x22, 0xC4, 0x65, 0x79, 0xF5, 0xFD, 0xF2, 0xC5, 0x05, 0xC2, 0xC4, + 0x77, 0x65, 0x75, 0x7A, 0xFF, 0xD9, 0xFF, 0xDC, 0xFF, 0xE6, 0xF8, 0x8D, 0xFF, 0xF7, 0x41, 0x72, + 0xF8, 0x75, 0xA1, 0x05, 0xC2, 0x6F, 0xFC, 0x41, 0x6A, 0xFB, 0x16, 0x41, 0x74, 0xFD, 0x46, 0xA1, + 0x01, 0x92, 0x61, 0xFC, 0x41, 0x87, 0xF7, 0xD4, 0x44, 0x82, 0x9B, 0xBA, 0xBC, 0xF7, 0xD0, 0xF7, + 0xD0, 0xF7, 0xD0, 0xF7, 0xD0, 0xC2, 0x01, 0x92, 0x68, 0x7A, 0xFC, 0xC6, 0xFC, 0xC6, 0x42, 0xBA, + 0xBC, 0xF6, 0x95, 0xF6, 0x95, 0xC2, 0x01, 0x92, 0xC5, 0x7A, 0xFF, 0xF9, 0xFC, 0xB6, 0xA0, 0x08, + 0x42, 0xA3, 0x01, 0x92, 0x63, 0x6E, 0x74, 0xFD, 0xFD, 0xFD, 0x41, 0xBC, 0xF6, 0x79, 0xC2, 0x01, + 0x92, 0xC5, 0x7A, 0xFF, 0xFC, 0xFC, 0x9D, 0xC1, 0x01, 0x92, 0x7A, 0xFC, 0x94, 0xD1, 0x01, 0x61, + 0x74, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x77, + 0x7A, 0xFF, 0xB2, 0xFF, 0xB7, 0xFF, 0xBB, 0xF7, 0x96, 0xFF, 0xC8, 0xFF, 0xD8, 0xF7, 0x96, 0xF7, + 0x96, 0xF7, 0x96, 0xF7, 0x96, 0xF7, 0x96, 0xF7, 0x96, 0xFF, 0xE4, 0xFF, 0xF1, 0xFF, 0xFA, 0xF7, + 0x96, 0xF7, 0x96, 0xA0, 0x07, 0x74, 0x21, 0x82, 0xFD, 0xA0, 0x07, 0x73, 0x21, 0x7A, 0xFD, 0x21, + 0x63, 0xFD, 0x21, 0x69, 0xF7, 0x22, 0x6A, 0x77, 0xFA, 0xFD, 0x21, 0x74, 0xEF, 0x21, 0x6F, 0xFD, + 0x23, 0xC5, 0x6F, 0x72, 0xE6, 0xF5, 0xFD, 0x21, 0x72, 0xE5, 0x21, 0x6E, 0xDF, 0x21, 0x65, 0xFD, + 0x21, 0x69, 0xFD, 0x41, 0x7A, 0xF9, 0xA4, 0x21, 0x72, 0xFC, 0x21, 0x62, 0xFD, 0xA4, 0x01, 0x61, + 0x62, 0x64, 0x6B, 0x6C, 0xE3, 0xEA, 0xF3, 0xFD, 0x41, 0x6D, 0xFE, 0xFD, 0xA1, 0x01, 0x61, 0x65, + 0xFC, 0xA0, 0x08, 0x01, 0x21, 0xB3, 0xFD, 0xA0, 0x08, 0x22, 0x21, 0x73, 0xFD, 0x21, 0x79, 0xFD, + 0x21, 0x7A, 0xF1, 0x21, 0x63, 0xFD, 0x21, 0x79, 0xFD, 0xA5, 0x02, 0x41, 0x69, 0xC3, 0x6D, 0x6F, + 0x77, 0xE3, 0xEB, 0xF4, 0xE8, 0xFD, 0xC2, 0x05, 0xC2, 0x68, 0x7A, 0xF6, 0xBB, 0xF6, 0xBB, 0x41, + 0xBA, 0xFB, 0xDC, 0xA1, 0x05, 0xC2, 0xC5, 0xFC, 0xC1, 0x05, 0xC2, 0x7A, 0xF6, 0xA9, 0xC1, 0x05, + 0xC2, 0x72, 0xF6, 0xA3, 0xD9, 0x07, 0x02, 0xC4, 0xC5, 0x69, 0x6D, 0x72, 0x77, 0x61, 0x65, 0x6F, + 0x79, 0x7A, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6E, 0x70, 0x73, 0x74, 0x75, + 0xFE, 0x4C, 0xFE, 0x7F, 0xFE, 0x88, 0xFE, 0x95, 0xFE, 0xC8, 0xFE, 0xDE, 0xFE, 0xE3, 0xFF, 0x39, + 0xFF, 0xA9, 0xF9, 0xF9, 0xFF, 0xD5, 0xFC, 0x2D, 0xFF, 0xE2, 0xFF, 0xEF, 0xFC, 0x2D, 0xFC, 0x2D, + 0xFC, 0x2D, 0xFC, 0x2D, 0xFC, 0x2D, 0xFC, 0x2D, 0xFC, 0x2D, 0xFC, 0x2D, 0xFF, 0xF4, 0xFF, 0xFA, + 0xFC, 0x2D, 0x41, 0x64, 0xF9, 0xAB, 0xA0, 0x05, 0xC1, 0x21, 0x74, 0xFD, 0x23, 0x7A, 0x6B, 0x75, + 0xF6, 0xFD, 0xFA, 0x42, 0x73, 0x6F, 0xFF, 0x10, 0xFF, 0x16, 0x41, 0x66, 0xF8, 0xDD, 0xC9, 0x01, + 0x61, 0x66, 0x67, 0x6B, 0x6E, 0x72, 0x73, 0x77, 0x6D, 0x75, 0xFF, 0x0B, 0xFF, 0x0B, 0xFF, 0xF5, + 0xFF, 0x0B, 0xFF, 0x0B, 0xFF, 0x0B, 0xFF, 0x0B, 0xFF, 0xFC, 0xF8, 0xD9, 0x44, 0x82, 0x9B, 0xBA, + 0xBC, 0xFD, 0xC1, 0xFD, 0xC1, 0xFD, 0xC1, 0xFD, 0xC1, 0xC1, 0x03, 0x32, 0x77, 0xF5, 0x0A, 0x21, + 0x7A, 0xFA, 0xA1, 0x05, 0xC2, 0x65, 0xFD, 0x42, 0xBA, 0xBC, 0xFB, 0x24, 0xFB, 0x24, 0x41, 0x87, + 0xF7, 0x0F, 0x44, 0x82, 0x9B, 0xBA, 0xBC, 0xF7, 0x0B, 0xF7, 0x0B, 0xF7, 0x0B, 0xF7, 0x0B, 0xC2, + 0x02, 0x92, 0x68, 0x7A, 0xF4, 0xE4, 0xF4, 0xE4, 0x42, 0xBA, 0xBC, 0xFA, 0x36, 0xFA, 0x36, 0xC2, + 0x02, 0x92, 0xC5, 0x7A, 0xFF, 0xF9, 0xF4, 0xD4, 0xC1, 0x02, 0x92, 0x7A, 0xF4, 0xCB, 0xC1, 0x02, + 0x92, 0x6B, 0xF4, 0xC5, 0x51, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, + 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0xFF, 0xCA, 0xFF, 0xCE, 0xF6, 0xDF, 0xFF, 0xDB, 0xFF, 0xEB, + 0xF6, 0xDF, 0xF6, 0xDF, 0xF6, 0xDF, 0xF6, 0xDF, 0xF6, 0xDF, 0xF6, 0xDF, 0xF6, 0xDF, 0xFF, 0xF4, + 0xFF, 0xF4, 0xFF, 0xFA, 0xF6, 0xDF, 0xF6, 0xDF, 0xC3, 0x05, 0xC2, 0xC5, 0x6F, 0x7A, 0xFF, 0x8F, + 0xFF, 0xCC, 0xF5, 0x89, 0xA0, 0x08, 0x63, 0x21, 0x87, 0xFD, 0x24, 0x82, 0x9B, 0xBA, 0xBC, 0xFA, + 0xFA, 0xFA, 0xFA, 0x41, 0x7A, 0xF4, 0x70, 0xD1, 0x08, 0x93, 0xC4, 0xC5, 0x63, 0x64, 0x66, 0x67, + 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x77, 0x72, 0xFF, 0x77, 0xFF, 0x7B, 0xFF, + 0x88, 0xFF, 0x98, 0xF6, 0x8C, 0xF6, 0x8C, 0xF6, 0x8C, 0xF6, 0x8C, 0xF6, 0x8C, 0xF6, 0x8C, 0xF6, + 0x8C, 0xF6, 0x8C, 0xF6, 0x8C, 0xFF, 0xA1, 0xF6, 0x8C, 0xF6, 0x8C, 0xFF, 0xFC, 0xC2, 0x08, 0x93, + 0x68, 0x7A, 0xFA, 0x5E, 0xFA, 0x5E, 0xA0, 0x08, 0xF2, 0x43, 0xBA, 0x9B, 0xBC, 0xF4, 0x2A, 0xF6, + 0x44, 0xFF, 0xFD, 0xD1, 0x08, 0x93, 0xC5, 0xC4, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, + 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x77, 0x7A, 0xFF, 0xF6, 0xFF, 0x2B, 0xFF, 0x3C, 0xFF, 0x4C, 0xF6, + 0x40, 0xF6, 0x40, 0xF6, 0x40, 0xF6, 0x40, 0xF6, 0x40, 0xF6, 0x40, 0xF6, 0x40, 0xF6, 0x40, 0xF6, + 0x40, 0xFF, 0x55, 0xF6, 0x40, 0xF6, 0x40, 0xFA, 0x48, 0xA0, 0x08, 0x93, 0xC1, 0x08, 0x93, 0x7A, + 0xFA, 0x0F, 0xD1, 0x05, 0xC2, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, + 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0xFF, 0x65, 0xFF, 0x68, 0xFF, 0x75, 0xFF, 0xAB, 0xFF, 0xC1, + 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xFA, + 0xFF, 0xFA, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF7, 0xC1, 0x08, 0xC3, 0x75, 0xF6, 0x3F, 0x21, 0x7A, + 0xFA, 0xC2, 0x05, 0xC2, 0x6F, 0x7A, 0xFF, 0xFD, 0xF4, 0xA0, 0xC2, 0x05, 0xC2, 0x6D, 0x7A, 0xF4, + 0x97, 0xF4, 0x97, 0xC2, 0x05, 0xC2, 0x6B, 0x72, 0xF4, 0x8E, 0xF4, 0x8E, 0x41, 0x7A, 0xF9, 0xAF, + 0xA1, 0x05, 0xC2, 0x63, 0xFC, 0xC1, 0x05, 0xC2, 0x77, 0xF4, 0x7C, 0xD6, 0x02, 0x01, 0xC4, 0x61, + 0x65, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x6F, 0x70, 0x72, 0x73, + 0x74, 0x75, 0x77, 0x7A, 0xFC, 0x25, 0xFE, 0x31, 0xFE, 0x43, 0xFE, 0x61, 0xFE, 0x77, 0xFD, 0xBB, + 0xFE, 0xED, 0xFA, 0x06, 0xFA, 0x06, 0xFA, 0x06, 0xFA, 0x06, 0xFD, 0xD3, 0xFA, 0x06, 0xFA, 0x06, + 0xFF, 0x97, 0xFA, 0x06, 0xFF, 0xD6, 0xFF, 0xDF, 0xFF, 0xE8, 0xFF, 0xF5, 0xFA, 0x06, 0xFF, 0xFA, + 0x44, 0x82, 0x9B, 0xBA, 0xBC, 0xF6, 0x93, 0xF6, 0x93, 0xF6, 0x93, 0xF6, 0x93, 0xC2, 0x01, 0xB2, + 0x63, 0x74, 0xF6, 0xCA, 0xF6, 0xCA, 0xC1, 0x01, 0xB2, 0x72, 0xF4, 0xDA, 0xA0, 0x02, 0x71, 0xC2, + 0x09, 0x12, 0xC5, 0x64, 0xFC, 0x7F, 0xFF, 0xFD, 0xC2, 0x01, 0x92, 0x70, 0x6B, 0xFC, 0x86, 0xF9, + 0x33, 0x51, 0x64, 0xC4, 0xC5, 0x62, 0x63, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, + 0x74, 0x77, 0x7A, 0xFF, 0xEE, 0xFC, 0x53, 0xFC, 0x57, 0xF4, 0x32, 0xFC, 0x64, 0xF4, 0x32, 0xF4, + 0x32, 0xF4, 0x32, 0xF4, 0x32, 0xF4, 0x32, 0xFF, 0xF7, 0xF4, 0x32, 0xFC, 0x96, 0xFC, 0x96, 0xF4, + 0x32, 0xF4, 0x32, 0xF4, 0x32, 0xC2, 0x01, 0xB2, 0x6F, 0x72, 0xFF, 0xCC, 0xF6, 0x69, 0xA0, 0x04, + 0x32, 0x21, 0x7A, 0xFD, 0xC8, 0x01, 0xB2, 0x63, 0x64, 0x6B, 0x72, 0x74, 0xC5, 0x6F, 0x7A, 0xF6, + 0x63, 0xF6, 0x63, 0xF6, 0x63, 0xF6, 0x63, 0xF6, 0x63, 0xF6, 0x86, 0xFF, 0xFD, 0xF4, 0x7C, 0xC2, + 0x01, 0xB2, 0x6D, 0x7A, 0xF4, 0x61, 0xF4, 0x61, 0xC2, 0x01, 0xB2, 0x63, 0x6B, 0xF4, 0x54, 0xF4, + 0x58, 0xC2, 0x01, 0xB2, 0x6D, 0x77, 0xF9, 0x20, 0xF4, 0x4F, 0x53, 0x64, 0x6A, 0xC4, 0xC5, 0x62, + 0x63, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x74, 0x75, 0x77, 0x7A, 0xFC, 0xEA, + 0xFF, 0x11, 0xF5, 0xEC, 0xFF, 0x56, 0xF6, 0x28, 0xF6, 0x0B, 0xFF, 0x63, 0xF6, 0x28, 0xF3, 0xD5, + 0xFF, 0x6C, 0xF3, 0xD5, 0xF3, 0xD5, 0xFF, 0xBB, 0xFF, 0xCA, 0xFF, 0xE5, 0xFF, 0xEE, 0xF3, 0xD5, + 0xF3, 0xD5, 0xFF, 0xF7, 0x41, 0x87, 0xFA, 0xF9, 0xA0, 0x09, 0x32, 0xC4, 0x05, 0xC2, 0x63, 0x6B, + 0x68, 0x7A, 0xFF, 0xFD, 0xFF, 0xFD, 0xF3, 0x46, 0xF3, 0x46, 0xA0, 0x09, 0x52, 0x42, 0xBA, 0xBC, + 0xFF, 0xFD, 0xF8, 0x5E, 0x41, 0x7A, 0xF7, 0x8A, 0xA1, 0x02, 0x92, 0x72, 0xFC, 0xC1, 0x02, 0x92, + 0x72, 0xF2, 0x26, 0x41, 0x68, 0xF7, 0x7B, 0xA1, 0x02, 0x92, 0x63, 0xFC, 0x51, 0xC4, 0xC5, 0x62, + 0x63, 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0xFD, 0x22, + 0xFD, 0x26, 0xFF, 0xEC, 0xFD, 0x33, 0xFD, 0x43, 0xF4, 0x37, 0xF4, 0x37, 0xF4, 0x37, 0xFF, 0xF1, + 0xF4, 0x37, 0xFD, 0x52, 0xFF, 0xFB, 0xFD, 0x4C, 0xFD, 0x4C, 0xFD, 0x52, 0xF4, 0x37, 0xF4, 0x37, + 0xC3, 0x05, 0xC2, 0xC5, 0x6F, 0x7A, 0xFF, 0xAD, 0xFF, 0xCC, 0xF2, 0xE1, 0xC2, 0x05, 0xC2, 0x63, + 0x6B, 0xFF, 0x8C, 0xFF, 0x8C, 0xA0, 0x09, 0x92, 0xC1, 0x03, 0x12, 0x75, 0xF4, 0x5F, 0xA0, 0x09, + 0xE1, 0x44, 0xBA, 0x82, 0x9B, 0xBC, 0xFF, 0xF4, 0xFF, 0xF7, 0xF4, 0x42, 0xFF, 0xFD, 0x41, 0x68, + 0xF4, 0x49, 0x21, 0x63, 0xFC, 0xA1, 0x02, 0xB2, 0x75, 0xFD, 0x41, 0x7A, 0xF4, 0x3D, 0x21, 0x63, + 0xFC, 0x21, 0x99, 0xFD, 0x41, 0xBC, 0xF4, 0x33, 0x42, 0xC5, 0x70, 0xFF, 0xFC, 0xF4, 0x2F, 0x42, + 0x63, 0x74, 0xFF, 0xEB, 0xF4, 0x28, 0x21, 0x70, 0xF9, 0xA3, 0x02, 0xB2, 0xC4, 0x61, 0x65, 0xE8, + 0xEF, 0xFD, 0x41, 0x6A, 0xF4, 0x15, 0xA2, 0x02, 0xB2, 0x61, 0x6F, 0xFC, 0xFC, 0xA0, 0x09, 0xB3, + 0x21, 0x63, 0xFD, 0x21, 0x6F, 0xFD, 0x21, 0x68, 0xFD, 0x21, 0x7A, 0xF4, 0x21, 0x72, 0xFD, 0x21, + 0x74, 0xFD, 0xA2, 0x02, 0x71, 0x63, 0x73, 0xF4, 0xFD, 0x41, 0x87, 0xF3, 0xDA, 0xC2, 0x02, 0xB2, + 0x68, 0x7A, 0xF6, 0xB1, 0xF6, 0xB1, 0x42, 0xBA, 0xBC, 0xF8, 0x59, 0xF8, 0x59, 0xA1, 0x02, 0xB2, + 0xC5, 0xF9, 0xC2, 0x02, 0xB2, 0x6D, 0x7A, 0xF6, 0x9C, 0xF6, 0x9C, 0xD5, 0x09, 0x72, 0xC5, 0x6D, + 0x72, 0x77, 0x6F, 0x75, 0x7A, 0xC4, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6E, + 0x70, 0x73, 0x74, 0xFF, 0x76, 0xFF, 0x8A, 0xFF, 0xAE, 0xFF, 0xBB, 0xFF, 0xD7, 0xFE, 0x21, 0xF3, + 0x52, 0xFF, 0xDE, 0xF3, 0x72, 0xFF, 0xE2, 0xFF, 0xF2, 0xF3, 0x72, 0xF3, 0x72, 0xF3, 0x72, 0xF3, + 0x72, 0xF3, 0x72, 0xF3, 0x72, 0xF3, 0x72, 0xF3, 0x72, 0xFF, 0xF7, 0xF3, 0x72, 0xC2, 0x02, 0x92, + 0x6D, 0x7A, 0xF0, 0xF6, 0xF0, 0xF6, 0x51, 0x64, 0xC4, 0xC5, 0x62, 0x63, 0x66, 0x67, 0x68, 0x6B, + 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0xFF, 0xB5, 0xFB, 0xF8, 0xFB, 0xFC, 0xF3, 0x0D, + 0xFC, 0x09, 0xF3, 0x0D, 0xF3, 0x0D, 0xF3, 0x0D, 0xF3, 0x0D, 0xF3, 0x0D, 0xF3, 0x0D, 0xF3, 0x0D, + 0xFC, 0x22, 0xFF, 0xF7, 0xF3, 0x0D, 0xF3, 0x0D, 0xF3, 0x0D, 0xA0, 0x02, 0xF1, 0xA1, 0x02, 0xD2, + 0x6B, 0xFD, 0x44, 0x82, 0x9B, 0xBA, 0xBC, 0xFF, 0xFB, 0xF2, 0xF7, 0xF2, 0xF7, 0xF2, 0xF7, 0xA0, + 0x0A, 0x12, 0xA0, 0x0A, 0xC2, 0x21, 0x63, 0xFD, 0xA1, 0x0A, 0x32, 0x79, 0xFD, 0x21, 0xBC, 0xFB, + 0x21, 0xC5, 0xFD, 0xA1, 0x0B, 0x42, 0x75, 0xFD, 0xA0, 0x0A, 0xE3, 0xA0, 0x0B, 0x42, 0x24, 0xBA, + 0x82, 0xBC, 0x9B, 0xE1, 0xF5, 0xFA, 0xFD, 0xA0, 0x0A, 0x32, 0x21, 0x68, 0xFD, 0x21, 0x63, 0xFD, + 0xA1, 0x0B, 0x62, 0x75, 0xFD, 0x21, 0x74, 0xF2, 0x21, 0x61, 0xFD, 0x21, 0x6D, 0xFD, 0x21, 0x6B, + 0xE9, 0x21, 0x6C, 0xE6, 0xA0, 0x0A, 0x53, 0xA4, 0x0B, 0x62, 0x61, 0x75, 0x79, 0x7A, 0xF4, 0xF7, + 0xFA, 0xFD, 0xA1, 0x0B, 0x62, 0x6D, 0xD5, 0xA0, 0x02, 0xD1, 0xA0, 0x0B, 0x13, 0x41, 0x6D, 0xFF, + 0xA5, 0x41, 0x6A, 0xFF, 0xA1, 0x22, 0x72, 0x6F, 0xB3, 0xFC, 0xC6, 0x02, 0xD2, 0x61, 0x67, 0x69, + 0x6A, 0x6C, 0x77, 0xFF, 0xF0, 0xFF, 0xAE, 0xFF, 0xF3, 0xFF, 0x98, 0xFF, 0x98, 0xFF, 0xFB, 0x41, + 0x87, 0xFF, 0x9C, 0xC2, 0x0B, 0x62, 0x68, 0x7A, 0xFF, 0x67, 0xFF, 0x67, 0xA0, 0x0B, 0x81, 0x22, + 0xBA, 0xBC, 0xFD, 0xFD, 0xC2, 0x0B, 0x62, 0xC5, 0x7A, 0xFF, 0xFB, 0xFF, 0x56, 0xA0, 0x0B, 0x62, + 0xC1, 0x0B, 0x62, 0x7A, 0xFF, 0x7B, 0xD5, 0x09, 0xF2, 0xC5, 0x6D, 0x72, 0x75, 0x79, 0x7A, 0xC4, + 0x63, 0x64, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6E, 0x70, 0x73, 0x74, 0x77, 0xFF, 0x78, + 0xFF, 0x8A, 0xFF, 0xA1, 0xFF, 0xAC, 0xFF, 0xB1, 0xFF, 0xC4, 0xFF, 0xD9, 0xFF, 0xDD, 0xFF, 0xEE, + 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF7, 0xFF, 0xF7, + 0xFF, 0xF7, 0xFF, 0xFA, 0xFF, 0xF7, 0xFF, 0xF7, 0x41, 0x87, 0xF2, 0x01, 0x41, 0x7A, 0xFF, 0x13, + 0xA1, 0x06, 0xC2, 0x72, 0xFC, 0xC2, 0x06, 0xC2, 0x68, 0x7A, 0xF6, 0xBA, 0xF6, 0xBA, 0xA0, 0x0A, + 0x84, 0x21, 0x73, 0xFD, 0x21, 0x6B, 0xFD, 0x41, 0x7A, 0xFE, 0xE3, 0xA1, 0x06, 0xC2, 0x72, 0xFC, + 0xC2, 0x06, 0xC2, 0x6C, 0x72, 0xF6, 0x9F, 0xF6, 0x9F, 0x41, 0x68, 0xFE, 0xD1, 0xA1, 0x06, 0xC2, + 0x63, 0xFC, 0x41, 0xBC, 0xFE, 0xC8, 0xC2, 0x06, 0xC2, 0xC5, 0x7A, 0xFF, 0xFC, 0xF6, 0x89, 0xC3, + 0x06, 0xC2, 0x63, 0x6D, 0x7A, 0xFF, 0xEA, 0xF6, 0x80, 0xF6, 0x80, 0xC2, 0x06, 0xC2, 0x6B, 0x72, + 0xF6, 0x74, 0xF6, 0x74, 0x53, 0xC5, 0x64, 0xC4, 0x62, 0x63, 0x65, 0x66, 0x67, 0x68, 0x6B, 0x6C, + 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0xFE, 0xAE, 0xFF, 0x62, 0xFF, 0xA4, 0xFF, 0xAC, + 0xFF, 0xB1, 0xFF, 0xC0, 0xF6, 0xE3, 0xFF, 0xC7, 0xF6, 0xE3, 0xFF, 0xCC, 0xF6, 0xE3, 0xF6, 0xE3, + 0xF6, 0xE3, 0xFF, 0xD9, 0xFF, 0xE2, 0xFF, 0xEB, 0xFF, 0xF7, 0xF6, 0xE3, 0xF6, 0xE3, 0x21, 0x65, + 0xC6, 0x21, 0x7A, 0xFD, 0xC2, 0x05, 0xC2, 0x6F, 0x72, 0xFE, 0x32, 0xFF, 0xFD, 0xC1, 0x03, 0x52, + 0x72, 0xF6, 0x9A, 0x41, 0x9B, 0xF4, 0x6B, 0x41, 0x7A, 0xF6, 0x18, 0x21, 0x72, 0xFC, 0x41, 0x72, + 0xF4, 0x60, 0xC6, 0x03, 0x32, 0x65, 0x75, 0xC5, 0x62, 0x6D, 0x74, 0xFF, 0xEB, 0xF1, 0x95, 0xFF, + 0xF1, 0xFF, 0xF9, 0xEF, 0x01, 0xFF, 0xFC, 0x21, 0x7A, 0xEB, 0xC2, 0x05, 0xC2, 0x6F, 0x7A, 0xFF, + 0xFD, 0xEF, 0xE7, 0x41, 0x65, 0xF1, 0x74, 0xA1, 0x03, 0x32, 0x69, 0xFC, 0x21, 0x62, 0xFB, 0xC2, + 0x05, 0xC2, 0x75, 0x7A, 0xFF, 0xFD, 0xEF, 0xD2, 0xC2, 0x05, 0xC2, 0x63, 0x77, 0xFB, 0x44, 0xEF, + 0xC9, 0xC2, 0x02, 0x92, 0x6B, 0x72, 0xEE, 0xC2, 0xEE, 0xC2, 0x51, 0xC4, 0xC5, 0x62, 0x63, 0x64, + 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0xF9, 0xC4, 0xF9, 0xC8, + 0xFC, 0x8E, 0xF9, 0xD5, 0xF9, 0xE5, 0xF0, 0xD9, 0xF0, 0xD9, 0xF0, 0xD9, 0xF0, 0xD9, 0xF0, 0xD9, + 0xF0, 0xD9, 0xF0, 0xD9, 0xF9, 0xEE, 0xF9, 0xEE, 0xFF, 0xF7, 0xF0, 0xD9, 0xF0, 0xD9, 0xA1, 0x05, + 0xC2, 0x79, 0xCC, 0x41, 0x87, 0xF4, 0xA8, 0x44, 0x82, 0x9B, 0xBA, 0xBC, 0xF4, 0xA4, 0xF4, 0xA4, + 0xF4, 0xA4, 0xF4, 0xA4, 0x43, 0x9B, 0xBA, 0xBC, 0xF0, 0x89, 0xF0, 0x89, 0xF0, 0x89, 0xCD, 0x00, + 0x91, 0xC4, 0xC5, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6D, 0x70, 0x73, 0x77, 0xF9, 0x70, + 0xFF, 0xF6, 0xF9, 0x81, 0xF9, 0x91, 0xF0, 0x85, 0xF0, 0x85, 0xF0, 0x85, 0xF0, 0x85, 0xF0, 0x85, + 0xF0, 0x85, 0xF0, 0x85, 0xF9, 0x9A, 0xF0, 0x85, 0xC2, 0x00, 0x91, 0x68, 0x7A, 0xF4, 0x63, 0xF4, + 0x63, 0x44, 0xBA, 0x82, 0x9B, 0xBC, 0xEE, 0x32, 0xF0, 0x4C, 0xF0, 0x4C, 0xFA, 0x05, 0xC1, 0x00, + 0x71, 0x72, 0xFB, 0x0E, 0xD0, 0x00, 0x91, 0xC5, 0xC4, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, + 0x6C, 0x6E, 0x70, 0x73, 0x74, 0x77, 0x7A, 0xFF, 0xED, 0xF9, 0x2A, 0xF9, 0x3B, 0xF9, 0x4B, 0xF0, + 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF9, + 0x54, 0xF0, 0x3F, 0xFF, 0xFA, 0xF4, 0x47, 0xC1, 0x00, 0x91, 0x7A, 0xF4, 0x14, 0xD1, 0x02, 0x41, + 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x74, 0x77, + 0x7A, 0xFF, 0x66, 0xFF, 0x6A, 0xFF, 0x81, 0xFF, 0xAB, 0xFF, 0xC7, 0xEE, 0xE4, 0xEE, 0xE4, 0xEE, + 0xE4, 0xEE, 0xE4, 0xEE, 0xE4, 0xEE, 0xE4, 0xEE, 0xE4, 0xFF, 0xFA, 0xFF, 0xFA, 0xEE, 0xE4, 0xEE, + 0xE4, 0xEE, 0xE4, 0x53, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x70, + 0x72, 0x73, 0x74, 0x75, 0x77, 0x7A, 0x6F, 0xFB, 0x61, 0xF8, 0x99, 0xF4, 0x3E, 0xFB, 0x68, 0xFB, + 0xCD, 0xF4, 0x3E, 0xF4, 0x3E, 0xF4, 0x3E, 0xF4, 0x3E, 0xF4, 0x3E, 0xFB, 0xD9, 0xFE, 0x91, 0xFE, + 0xC7, 0xFE, 0xDC, 0xFA, 0x20, 0xFE, 0xE5, 0xFF, 0x2B, 0xFA, 0x32, 0xFF, 0xCA, 0x21, 0x65, 0xC6, + 0xD8, 0x01, 0xF1, 0xC4, 0xC5, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, + 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7A, 0xEF, 0x09, 0xEF, 0x0D, 0xFA, + 0xEA, 0xEF, 0x1D, 0xEF, 0x1D, 0xEF, 0x1D, 0xF3, 0x40, 0xEF, 0x1D, 0xEF, 0x1D, 0xEF, 0x1D, 0xFF, + 0xFD, 0xEF, 0x1D, 0xEF, 0x1D, 0xEF, 0x1D, 0xEF, 0x1D, 0xEF, 0x1D, 0xEF, 0x1D, 0xEF, 0x1D, 0xEF, + 0x1D, 0xEF, 0x1D, 0xEF, 0x1D, 0xEF, 0x1D, 0xEF, 0x1D, 0xEF, 0x1D, 0xA0, 0x06, 0x11, 0x21, 0x87, + 0xFD, 0x41, 0x6F, 0xEF, 0xA8, 0x21, 0x69, 0xFC, 0xA1, 0x06, 0x11, 0x6D, 0xFD, 0x23, 0x9B, 0xBA, + 0xBC, 0xFB, 0xEE, 0xEE, 0x42, 0x85, 0x99, 0xF3, 0x94, 0xF3, 0x94, 0xA0, 0x05, 0x92, 0xA1, 0x05, + 0x72, 0x7A, 0xFD, 0x21, 0x63, 0xFB, 0xA2, 0x03, 0xA2, 0xC4, 0x6F, 0xEE, 0xFD, 0x44, 0x82, 0x9B, + 0xBA, 0xBC, 0xFF, 0xF9, 0xF0, 0x56, 0xF0, 0x56, 0xF0, 0x56, 0x41, 0x67, 0xF3, 0x6E, 0x21, 0x7A, + 0xFC, 0xA1, 0x01, 0xB2, 0x75, 0xFD, 0x41, 0x87, 0xF3, 0x62, 0x41, 0x6F, 0xF3, 0x5E, 0x22, 0xC4, + 0x73, 0xF8, 0xFC, 0x41, 0x84, 0xF3, 0x55, 0x42, 0xC5, 0x6E, 0xFF, 0xFC, 0xF3, 0x51, 0x41, 0xBA, + 0xF3, 0x4A, 0x42, 0xC5, 0x7A, 0xFF, 0xFC, 0xF3, 0x46, 0x21, 0x64, 0xB2, 0x22, 0x85, 0x99, 0xAF, + 0xFD, 0x21, 0x7A, 0xAA, 0x22, 0x63, 0x74, 0xA7, 0xA7, 0x41, 0x6E, 0xFF, 0xA2, 0xA4, 0x0B, 0x93, + 0xC4, 0x65, 0x75, 0x79, 0xEF, 0xF4, 0xF7, 0xFC, 0xA4, 0x01, 0x61, 0x61, 0x6F, 0x79, 0x7A, 0xC6, + 0xCF, 0xDA, 0xF5, 0xC3, 0x05, 0xC2, 0x6E, 0x68, 0x7A, 0xFA, 0x45, 0xED, 0x8E, 0xED, 0x8E, 0xC2, + 0x05, 0xC2, 0xC5, 0x7A, 0xF7, 0x88, 0xED, 0x82, 0xA0, 0x0C, 0x52, 0x41, 0xBC, 0xF2, 0xA0, 0xC4, + 0x05, 0xC2, 0x74, 0xC5, 0x6D, 0x7A, 0xFF, 0xF9, 0xFF, 0xFC, 0xF4, 0xBA, 0xED, 0x72, 0x41, 0x68, + 0xF2, 0x8D, 0xC2, 0x05, 0xC2, 0x63, 0x7A, 0xFF, 0xFC, 0xED, 0x5F, 0xC1, 0x05, 0xC2, 0x6B, 0xED, + 0x56, 0xC1, 0x05, 0xC2, 0x77, 0xFA, 0x07, 0xD1, 0x00, 0x81, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, + 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0xF9, 0xFD, 0xF7, 0x35, 0xF2, + 0xDA, 0xFF, 0xBC, 0xFF, 0xC8, 0xF2, 0xDA, 0xF2, 0xDA, 0xF2, 0xDA, 0xF2, 0xDA, 0xF2, 0xDA, 0xF2, + 0xDA, 0xF2, 0xDA, 0xFF, 0xD8, 0xFF, 0xEB, 0xFF, 0xF4, 0xF2, 0xDA, 0xFF, 0xFA, 0xC1, 0x00, 0x81, + 0x62, 0xF2, 0xA4, 0x41, 0x7A, 0xED, 0x5C, 0x21, 0x72, 0xFC, 0x21, 0x74, 0xFD, 0x21, 0x73, 0xFD, + 0xC1, 0x01, 0xB2, 0x7A, 0xED, 0xC0, 0xA0, 0x0C, 0x23, 0x21, 0x6D, 0xFD, 0xD5, 0x00, 0xF2, 0xC5, + 0x6C, 0x72, 0x65, 0x69, 0xC4, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6D, 0x6E, 0x6F, 0x70, + 0x73, 0x74, 0x75, 0x77, 0xFF, 0x01, 0xFF, 0x15, 0xFF, 0x5C, 0xFF, 0xAB, 0xFF, 0xE1, 0xEF, 0x5A, + 0xEF, 0x79, 0xEF, 0x89, 0xED, 0x43, 0xED, 0x43, 0xED, 0x43, 0xED, 0x43, 0xED, 0x43, 0xED, 0x43, + 0xED, 0x43, 0xFF, 0xF1, 0xED, 0x43, 0xFF, 0xF4, 0xED, 0x43, 0xFF, 0xFD, 0xED, 0x43, 0x41, 0x6F, + 0xED, 0x01, 0xC2, 0x01, 0xB2, 0x75, 0x7A, 0xF2, 0x36, 0xFF, 0xFC, 0x41, 0x74, 0xF2, 0x2D, 0x21, + 0x99, 0xFC, 0x41, 0x70, 0xF2, 0x26, 0x41, 0x6E, 0xF2, 0x22, 0x21, 0x69, 0xFC, 0x21, 0x62, 0xFD, + 0x41, 0x69, 0xF2, 0x18, 0x41, 0xC4, 0xFE, 0xB2, 0xC2, 0x02, 0x41, 0x65, 0x77, 0xFF, 0xFC, 0xF2, + 0x10, 0xA6, 0x01, 0xB2, 0xC4, 0x61, 0x6F, 0x75, 0x77, 0x7A, 0xDE, 0xE1, 0xEC, 0xDA, 0xEF, 0xF7, + 0xA0, 0x0C, 0x02, 0xA1, 0x0B, 0xC2, 0x72, 0xFD, 0xA1, 0x0B, 0xC2, 0x6D, 0xF8, 0x22, 0x61, 0x65, + 0xF6, 0xFB, 0xA1, 0x0C, 0x92, 0x69, 0xFB, 0xC1, 0x05, 0xC2, 0x6B, 0xF4, 0x06, 0xC1, 0x05, 0xC2, + 0x63, 0xFE, 0xF1, 0xC2, 0x05, 0xC2, 0xC5, 0x7A, 0xFE, 0xD8, 0xEC, 0x4E, 0xC2, 0x05, 0xC2, 0x63, + 0x6B, 0xFE, 0xE2, 0xEC, 0x45, 0xD1, 0x00, 0x81, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, + 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0xF8, 0xEF, 0xF6, 0x27, 0xF1, 0xCC, 0xF5, + 0x81, 0xFE, 0xBA, 0xF1, 0xCC, 0xF1, 0xCC, 0xF1, 0xCC, 0xF1, 0xCC, 0xF1, 0xCC, 0xFF, 0xE2, 0xFF, + 0xE8, 0xFF, 0xEE, 0xF5, 0x93, 0xFF, 0xF7, 0xF1, 0xCC, 0xF1, 0xCC, 0xA0, 0x0C, 0x72, 0x43, 0xBA, + 0x9B, 0xBC, 0xEC, 0xC2, 0xEE, 0x65, 0xFF, 0xFD, 0x41, 0x75, 0xEF, 0x55, 0xC1, 0x01, 0xB2, 0x65, + 0xF8, 0x35, 0x41, 0x73, 0xEC, 0x3D, 0x42, 0x63, 0x6D, 0xFE, 0xDD, 0xFE, 0xF0, 0xD8, 0x00, 0xF2, + 0x69, 0x72, 0x7A, 0x65, 0xC5, 0xC4, 0x61, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, + 0x6D, 0x6E, 0x6F, 0x70, 0x73, 0x74, 0x75, 0x77, 0xFF, 0x35, 0xFF, 0x64, 0xFF, 0x85, 0xFF, 0xA8, + 0xFF, 0xE1, 0xEE, 0x49, 0xFF, 0xEB, 0xFF, 0xEF, 0xEE, 0x68, 0xEE, 0x78, 0xEC, 0x32, 0xEC, 0x32, + 0xEC, 0x32, 0xEC, 0x32, 0xEE, 0x85, 0xEC, 0x32, 0xEC, 0x32, 0xEC, 0x32, 0xFF, 0xF5, 0xEC, 0x32, + 0xFE, 0xE3, 0xEC, 0x32, 0xFF, 0xF9, 0xEC, 0x32, 0x41, 0x82, 0xF1, 0x48, 0x21, 0xC5, 0xFC, 0x21, + 0x68, 0xFD, 0xA1, 0x02, 0x01, 0x63, 0xFD, 0xA0, 0x0B, 0xE2, 0x21, 0x6E, 0xFD, 0x21, 0x9B, 0xFD, + 0xA0, 0x0C, 0xB2, 0x21, 0x6F, 0xFD, 0x22, 0xC5, 0x65, 0xF7, 0xFD, 0x41, 0x7A, 0xEE, 0xD2, 0xC1, + 0x06, 0x11, 0x72, 0xEE, 0x0F, 0xC2, 0x02, 0x01, 0x68, 0x7A, 0xFF, 0xFA, 0xFD, 0x46, 0xA0, 0x02, + 0x01, 0x41, 0x6B, 0xF1, 0xE6, 0x21, 0x6F, 0xFC, 0x21, 0x6E, 0xFD, 0x21, 0x6C, 0xFD, 0x21, 0xB3, + 0xFD, 0x41, 0x72, 0xEC, 0x6C, 0x21, 0x74, 0xFC, 0x21, 0x6F, 0xFD, 0x21, 0x69, 0xFD, 0xA2, 0x02, + 0x01, 0xC3, 0x6E, 0xF0, 0xFD, 0x41, 0x6D, 0xF0, 0xCC, 0xC2, 0x02, 0x01, 0x61, 0x72, 0xFF, 0xFC, + 0xFD, 0x12, 0x41, 0x68, 0xEB, 0xEE, 0xA1, 0x02, 0x01, 0x63, 0xFC, 0xA0, 0x0C, 0xD2, 0x21, 0xBC, + 0xFD, 0x21, 0x99, 0xBD, 0x21, 0xC4, 0xFD, 0xA0, 0x07, 0x02, 0x23, 0xC5, 0x74, 0x7A, 0xF4, 0xFA, + 0xFD, 0xA0, 0x05, 0xE2, 0x21, 0x74, 0xFD, 0x21, 0x65, 0xFD, 0xA1, 0x04, 0x32, 0x73, 0xFD, 0x21, + 0x6D, 0xFB, 0x21, 0x65, 0xFD, 0xC2, 0x02, 0x01, 0x69, 0x7A, 0xFF, 0xFD, 0xFC, 0xD6, 0x52, 0xC4, + 0xC5, 0x62, 0x64, 0x74, 0x6C, 0x61, 0x63, 0x66, 0x67, 0x68, 0x6B, 0x6D, 0x70, 0x72, 0x73, 0x77, + 0x7A, 0xFC, 0xD0, 0xFC, 0xDF, 0xFD, 0xFE, 0xFF, 0x0F, 0xFF, 0x64, 0xFF, 0x78, 0xFF, 0x7D, 0xFF, + 0x87, 0xFF, 0x90, 0xFF, 0xB0, 0xFF, 0x90, 0xFF, 0xBB, 0xFF, 0x90, 0xFF, 0xC8, 0xFF, 0xDC, 0xFF, + 0xF7, 0xFF, 0x90, 0xFF, 0x90, 0x41, 0x77, 0xF1, 0x42, 0x21, 0x6F, 0xFC, 0x21, 0x6B, 0xFD, 0x21, + 0x73, 0xFD, 0xA1, 0x00, 0x61, 0x61, 0xFD, 0x45, 0x82, 0x84, 0x9B, 0xBA, 0xBC, 0xFF, 0xFB, 0xE9, + 0x23, 0xE9, 0x23, 0xE9, 0x23, 0xE9, 0x23, 0xC1, 0x00, 0x71, 0x72, 0xE9, 0x9C, 0x41, 0x72, 0xF9, + 0x4A, 0x41, 0x64, 0xE9, 0x92, 0xA2, 0x00, 0x71, 0x62, 0x6D, 0xF8, 0xFC, 0x41, 0x6B, 0xE9, 0x9A, + 0x21, 0x6D, 0xFC, 0x21, 0x79, 0xFD, 0x21, 0x7A, 0xFD, 0x21, 0x72, 0xFD, 0x42, 0x85, 0x99, 0xF0, + 0xCF, 0xF0, 0xCF, 0x41, 0x7A, 0xF0, 0xC8, 0x21, 0x63, 0xFC, 0xC7, 0x06, 0xE2, 0x6B, 0x6D, 0x6F, + 0x70, 0xC4, 0x65, 0x79, 0xFF, 0xCD, 0xEF, 0x91, 0xFF, 0xDB, 0xFF, 0xEF, 0xFF, 0xF2, 0xFF, 0xFD, + 0xF0, 0xC1, 0x21, 0x82, 0xE8, 0x21, 0xC5, 0xFD, 0x21, 0xB3, 0xFD, 0xC1, 0x00, 0x51, 0x68, 0xE8, + 0xBF, 0x41, 0x6B, 0xEC, 0x49, 0x21, 0x6F, 0xFC, 0x21, 0x6E, 0xFD, 0x21, 0x82, 0xFD, 0xA0, 0x0C, + 0xF3, 0xA1, 0x02, 0x22, 0x6E, 0xFD, 0xC5, 0x02, 0x02, 0x65, 0x69, 0x6F, 0x75, 0x79, 0xEA, 0xDA, + 0xFF, 0xFB, 0xEA, 0xDA, 0xEA, 0xDA, 0xEA, 0xDA, 0x41, 0x6B, 0xEA, 0x67, 0xA0, 0x0D, 0x22, 0x21, + 0x6C, 0xFD, 0x21, 0x65, 0xFD, 0x21, 0x73, 0xFD, 0x42, 0x72, 0x73, 0xEA, 0x09, 0xEA, 0x09, 0x21, + 0x65, 0xF9, 0x21, 0x65, 0xFD, 0xA0, 0x0D, 0x43, 0x21, 0x72, 0xFD, 0x21, 0x65, 0xFD, 0x21, 0x65, + 0xFD, 0x21, 0x70, 0xFD, 0x21, 0x74, 0xFD, 0x21, 0x65, 0xFD, 0x26, 0xC5, 0x72, 0x63, 0x65, 0x70, + 0x7A, 0xB1, 0xBC, 0xCE, 0xDB, 0xE8, 0xFD, 0x41, 0x74, 0xEA, 0x2E, 0x21, 0x65, 0xFC, 0xA1, 0x0D, + 0x72, 0x73, 0xFD, 0x21, 0x87, 0xFB, 0x41, 0x9B, 0xEB, 0x13, 0x21, 0xC5, 0xFC, 0x21, 0x6F, 0xFD, + 0x21, 0x69, 0xFD, 0x22, 0xC4, 0x63, 0xF0, 0xFD, 0x21, 0x99, 0xFB, 0x41, 0x77, 0xEA, 0xF8, 0x21, + 0x72, 0xFC, 0x41, 0x6E, 0xEC, 0xDA, 0x23, 0xC4, 0x65, 0x6F, 0xF2, 0xF9, 0xFC, 0xC1, 0x03, 0xA2, + 0x6B, 0xE9, 0xA4, 0x41, 0x63, 0xEC, 0x06, 0x45, 0x82, 0x9B, 0xBA, 0xBC, 0x84, 0xFF, 0xF6, 0xEB, + 0xFC, 0xEB, 0xFC, 0xEB, 0xFC, 0xFF, 0xFC, 0xC1, 0x07, 0xE2, 0x75, 0xEA, 0x39, 0xA0, 0x0E, 0x83, + 0x21, 0x64, 0xFD, 0x21, 0xB3, 0xFD, 0x21, 0xC3, 0xFD, 0xA1, 0x07, 0xE2, 0x72, 0xFD, 0x44, 0xBA, + 0x82, 0x9B, 0xBC, 0xF1, 0x2C, 0xFF, 0xE9, 0xFF, 0xFB, 0xF1, 0x52, 0x41, 0x77, 0xEA, 0x15, 0xA1, + 0x05, 0xC2, 0x61, 0xFC, 0xC1, 0x02, 0x22, 0x6E, 0xF1, 0x71, 0x21, 0x7A, 0xFA, 0x22, 0x63, 0x74, + 0xFD, 0xEE, 0x21, 0x99, 0xFB, 0x41, 0xBC, 0xE9, 0xFB, 0x21, 0xC5, 0xFC, 0x21, 0xB3, 0xFD, 0x41, + 0x69, 0xF1, 0x49, 0x42, 0xC5, 0x70, 0xFF, 0xF2, 0xE9, 0xED, 0x41, 0xB3, 0xE9, 0xE6, 0x44, 0xC3, + 0x61, 0x6F, 0x79, 0xFF, 0xFC, 0xE9, 0xE2, 0xE9, 0xE2, 0xE9, 0xE2, 0xA0, 0x03, 0x32, 0x44, 0xC5, + 0x62, 0x63, 0x7A, 0xFF, 0xD7, 0xFF, 0xF0, 0xF1, 0x20, 0xFF, 0xFD, 0x41, 0x67, 0xE9, 0xC5, 0x21, + 0x7A, 0xFC, 0x41, 0x65, 0xE9, 0xBE, 0xC9, 0x05, 0xC2, 0xC4, 0xC3, 0x77, 0x61, 0x65, 0x6F, 0x75, + 0x79, 0x7A, 0xFF, 0xBC, 0xFF, 0xC6, 0xFF, 0xC9, 0xFF, 0xCD, 0xF1, 0x1C, 0xFF, 0xE8, 0xFF, 0xF9, + 0xFF, 0xF5, 0xFF, 0xFC, 0x42, 0x6A, 0x72, 0xE9, 0x9F, 0xE9, 0x9C, 0x21, 0xB3, 0xF9, 0x41, 0x6A, + 0xE9, 0x92, 0x43, 0x69, 0x6A, 0x72, 0xE9, 0x8E, 0xE9, 0x8E, 0xF0, 0xDC, 0xA3, 0x05, 0xC2, 0xC3, + 0x61, 0x6F, 0xEF, 0xF2, 0xF6, 0x41, 0x70, 0xF2, 0x81, 0xA1, 0x01, 0x61, 0x6C, 0xFC, 0xA0, 0x0D, + 0xD5, 0xA1, 0x01, 0x92, 0x73, 0xFD, 0x41, 0x68, 0xE7, 0xBD, 0xA1, 0x01, 0x92, 0x63, 0xFC, 0xC2, + 0x01, 0x92, 0x63, 0x7A, 0xFF, 0xF7, 0xED, 0xDC, 0xC1, 0x01, 0x92, 0x6B, 0xE8, 0xD0, 0xD2, 0x01, + 0x61, 0x6A, 0x6B, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6C, 0x6D, 0x70, 0x72, 0x73, + 0x74, 0x77, 0x7A, 0xEB, 0xFF, 0xFF, 0xE3, 0xF0, 0xF6, 0xF0, 0xFA, 0xE8, 0xD5, 0xF1, 0x07, 0xF1, + 0x17, 0xE8, 0xD5, 0xE8, 0xD5, 0xE8, 0xD5, 0xE8, 0xD5, 0xE8, 0xD5, 0xFF, 0xEC, 0xF1, 0x30, 0xFF, + 0xF1, 0xFF, 0xFA, 0xE8, 0xD5, 0xE8, 0xD5, 0x42, 0x75, 0x6E, 0xEB, 0xC6, 0xED, 0xFA, 0x41, 0xB3, + 0xF1, 0x3E, 0x41, 0x64, 0xF1, 0x37, 0x21, 0x61, 0xFC, 0x41, 0x6A, 0xF1, 0x36, 0x41, 0x61, 0xF1, + 0x2F, 0x45, 0xC3, 0x69, 0x6F, 0x72, 0x73, 0xFF, 0xED, 0xFF, 0xF5, 0xFF, 0xF8, 0xFF, 0xFC, 0xF1, + 0x52, 0x41, 0x63, 0xF1, 0x18, 0x21, 0x6F, 0xFC, 0x21, 0x68, 0xFD, 0x42, 0x6D, 0x64, 0xF1, 0x0E, + 0xEA, 0xDC, 0x41, 0x67, 0xF1, 0x07, 0x21, 0x99, 0xFC, 0x41, 0x73, 0xF1, 0x00, 0x22, 0xC4, 0x65, + 0xF9, 0xFC, 0x43, 0x69, 0x6E, 0x72, 0xF1, 0x1B, 0xF0, 0xF7, 0xFF, 0xFB, 0x41, 0x65, 0xF0, 0xF3, + 0x21, 0x69, 0xFC, 0x41, 0x77, 0xF0, 0xE6, 0x21, 0x79, 0xFC, 0x41, 0x6B, 0xF0, 0xDF, 0x21, 0x61, + 0xFC, 0x21, 0x69, 0xFD, 0x21, 0x6E, 0xFD, 0x42, 0x69, 0x74, 0xFF, 0xFD, 0xF0, 0xF0, 0xCA, 0x01, + 0x61, 0x62, 0x63, 0x64, 0x66, 0x67, 0x6B, 0x70, 0x72, 0x73, 0x6C, 0xFF, 0xA3, 0xFF, 0xBA, 0xFF, + 0xBD, 0xF0, 0xCB, 0xF0, 0xCB, 0xFF, 0xD4, 0xFF, 0xE2, 0xFF, 0xE9, 0xFF, 0xF9, 0xF0, 0xFC, 0x41, + 0x61, 0xF0, 0xAA, 0x41, 0x6C, 0xF0, 0xA6, 0x21, 0x61, 0xFC, 0xA0, 0x04, 0x02, 0x21, 0x6E, 0xFD, + 0xA1, 0x07, 0x73, 0x79, 0xFD, 0x21, 0x7A, 0xFB, 0x21, 0x63, 0xFD, 0x22, 0x74, 0x7A, 0xE4, 0xFD, + 0xC5, 0x01, 0x61, 0x63, 0x64, 0x70, 0x72, 0x73, 0xF0, 0x8C, 0xF0, 0x8C, 0xFF, 0xDF, 0xFF, 0xE7, + 0xFF, 0xFB, 0x41, 0x72, 0xEF, 0xB3, 0x41, 0x74, 0xEF, 0xAF, 0x43, 0x6B, 0x6D, 0x73, 0xFF, 0xF8, + 0xEF, 0xAB, 0xFF, 0xFC, 0x41, 0x69, 0xEF, 0xA1, 0x43, 0x85, 0x87, 0x99, 0xEF, 0x9D, 0xEF, 0x9D, + 0xEF, 0x9D, 0x41, 0x82, 0xEF, 0x93, 0x41, 0x6E, 0xEF, 0x8F, 0x48, 0xC4, 0xC5, 0x63, 0x65, 0x6C, + 0x6D, 0x6F, 0x73, 0xFF, 0xEE, 0xFF, 0xF8, 0xEF, 0x8B, 0xFF, 0xFC, 0xEF, 0x8B, 0xEF, 0x8B, 0xEF, + 0x8B, 0xEF, 0x8B, 0x21, 0x69, 0xE7, 0x21, 0x6E, 0xFD, 0x21, 0x65, 0xFD, 0x42, 0x6C, 0x6D, 0xFF, + 0xFD, 0xEF, 0x69, 0x42, 0x65, 0x6F, 0xFF, 0xF9, 0xF0, 0x65, 0xA0, 0x0E, 0x23, 0x21, 0x72, 0xFD, + 0xC5, 0x03, 0xA2, 0x61, 0x62, 0x65, 0x69, 0x77, 0xFF, 0xAA, 0xFF, 0xB4, 0xEF, 0x55, 0xFF, 0xF3, + 0xFF, 0xFD, 0x41, 0x77, 0xE9, 0xD5, 0x21, 0xB3, 0xFC, 0xC1, 0x05, 0xC2, 0xC5, 0xF1, 0x2E, 0xDA, + 0x07, 0x02, 0xC4, 0xC5, 0x6D, 0x6E, 0x72, 0x77, 0x61, 0x65, 0x69, 0x6F, 0x75, 0x79, 0x7A, 0xC3, + 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x70, 0x73, 0x74, 0xEE, 0xD1, 0xFD, 0xAF, + 0xEF, 0x1A, 0xFD, 0xC0, 0xFE, 0x17, 0xFE, 0x4D, 0xFE, 0x5A, 0xFE, 0x7F, 0xFE, 0xB8, 0xFF, 0x2F, + 0xFF, 0x71, 0xEA, 0x7E, 0xFF, 0xE1, 0xFF, 0xF7, 0xEC, 0xB2, 0xF0, 0x67, 0xFF, 0xFA, 0xEC, 0xB2, + 0xEC, 0xB2, 0xEC, 0xB2, 0xEC, 0xB2, 0xEC, 0xB2, 0xEC, 0xB2, 0xEC, 0xB2, 0xF2, 0x8B, 0xEC, 0xB2, + 0xC2, 0x02, 0x41, 0x64, 0x74, 0xE9, 0x39, 0xE9, 0x39, 0xC1, 0x02, 0x41, 0x72, 0xF2, 0x43, 0xA2, + 0x01, 0xB2, 0x7A, 0x68, 0xF1, 0xFA, 0xA0, 0x0D, 0x94, 0x21, 0x73, 0xFD, 0x21, 0x6B, 0xFD, 0xC2, + 0x01, 0xB2, 0x6C, 0x72, 0xE7, 0x71, 0xE7, 0x71, 0xC1, 0x01, 0xB2, 0x73, 0xE9, 0x4F, 0xC1, 0x03, + 0xE2, 0x6B, 0xEA, 0xB7, 0xC2, 0x01, 0xB2, 0x70, 0x6B, 0xFF, 0xFA, 0xE7, 0x5C, 0xC3, 0x01, 0xB2, + 0x63, 0x6F, 0x72, 0xE7, 0x4F, 0xED, 0x8D, 0xE9, 0x31, 0x41, 0xBC, 0xE9, 0xE4, 0x41, 0x99, 0xFE, + 0xBD, 0xA0, 0x0E, 0xD2, 0xC4, 0x03, 0xE2, 0xC4, 0x77, 0x66, 0x6D, 0xFF, 0xF9, 0xFF, 0xFD, 0xEA, + 0x91, 0xEA, 0x91, 0xC1, 0x04, 0x32, 0x75, 0xE9, 0xA8, 0x21, 0x7A, 0xFA, 0xC7, 0x01, 0xB2, 0xC5, + 0x63, 0x66, 0x6E, 0x74, 0x6F, 0x7A, 0xFF, 0xDD, 0xE9, 0x0B, 0xE9, 0x0B, 0xE9, 0x0B, 0xFF, 0xE8, + 0xFF, 0xFD, 0xE7, 0x24, 0xA0, 0x0E, 0x53, 0x41, 0x6D, 0xE8, 0xB2, 0x21, 0x6F, 0xFC, 0x4B, 0x64, + 0x66, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0xE8, 0xAB, 0xE8, 0xAB, 0xE8, 0xAB, + 0xE8, 0xAB, 0xFF, 0xF6, 0xE8, 0xAB, 0xE8, 0xAB, 0xE8, 0xAB, 0xE8, 0xAB, 0xFF, 0xFD, 0xE8, 0xAB, + 0xC4, 0x01, 0xB2, 0x74, 0x63, 0x6D, 0x7A, 0xFF, 0xDE, 0xE6, 0xDC, 0xE6, 0xE0, 0xE6, 0xE0, 0xA0, + 0x0E, 0xF2, 0x41, 0x75, 0xE6, 0x41, 0xC3, 0x01, 0xB2, 0x6D, 0x61, 0x77, 0xFF, 0xF9, 0xFF, 0xFC, + 0xE6, 0xCA, 0xA0, 0x0E, 0xB2, 0x42, 0xBA, 0x9B, 0xFF, 0xFD, 0xE7, 0x18, 0xC2, 0x02, 0x92, 0x68, + 0x7A, 0xE7, 0x11, 0xE7, 0x11, 0x41, 0xBA, 0xF3, 0x20, 0x21, 0xC5, 0xFC, 0xCF, 0x09, 0x12, 0xC5, + 0x6F, 0xC4, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x70, 0x73, 0x74, 0x7A, 0xFF, 0xE9, + 0xED, 0x2D, 0xEF, 0xF2, 0xFF, 0xF0, 0xFF, 0xFD, 0xE7, 0x07, 0xE7, 0x07, 0xE7, 0x07, 0xE7, 0x07, + 0xE7, 0x07, 0xE7, 0x07, 0xE7, 0x07, 0xE7, 0x07, 0xE7, 0x07, 0xEB, 0x0F, 0xC1, 0x01, 0x92, 0x72, + 0xF0, 0x47, 0xC2, 0x01, 0x92, 0x7A, 0x68, 0xE5, 0xD6, 0xEA, 0xD9, 0xC1, 0x01, 0x92, 0x74, 0xEE, + 0x23, 0xC2, 0x01, 0x92, 0x6D, 0x7A, 0xEA, 0xCA, 0xEA, 0xCA, 0xC2, 0x01, 0x92, 0x6D, 0x77, 0xE6, + 0xB9, 0xEA, 0xC1, 0x51, 0x64, 0xC4, 0xC5, 0x62, 0x63, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x70, + 0x72, 0x73, 0x74, 0x77, 0x7A, 0xFF, 0xA9, 0xED, 0xE1, 0xED, 0xE5, 0xFF, 0xD9, 0xFF, 0xDF, 0xFF, + 0xE8, 0xE5, 0xC0, 0xE5, 0xC0, 0xE5, 0xC0, 0xE5, 0xC0, 0xE5, 0xC0, 0xE5, 0xC0, 0xEE, 0x24, 0xFF, + 0xEE, 0xE5, 0xC0, 0xE5, 0xC0, 0xFF, 0xF7, 0x42, 0x6B, 0x77, 0xE6, 0x7C, 0xE6, 0x7C, 0x21, 0x65, + 0xF9, 0x22, 0x61, 0x69, 0xC2, 0xFD, 0x53, 0xC5, 0x64, 0xC4, 0x62, 0x63, 0x65, 0x66, 0x67, 0x68, + 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0x6E, 0xFB, 0xB1, 0xFE, 0x29, 0xE7, 0xB0, + 0xE7, 0xCA, 0xFE, 0x89, 0xFE, 0x96, 0xE5, 0x99, 0xE7, 0xEC, 0xE5, 0x99, 0xFE, 0x99, 0xFE, 0xA2, + 0xFE, 0xAE, 0xFE, 0xB7, 0xFE, 0xE6, 0xFF, 0x2A, 0xE8, 0x30, 0xE5, 0x99, 0xFF, 0x40, 0xFF, 0xFB, + 0x41, 0x75, 0xEA, 0xA1, 0x42, 0x6E, 0x7A, 0xFF, 0xFC, 0xEA, 0x9D, 0x41, 0x75, 0xE6, 0x42, 0x21, + 0x6E, 0xFC, 0x21, 0x77, 0xFD, 0x21, 0x61, 0xFD, 0x21, 0x72, 0xFD, 0x43, 0x73, 0x77, 0x70, 0xEA, + 0x86, 0xFF, 0xE9, 0xFF, 0xFD, 0x41, 0x6F, 0xFB, 0xC6, 0x21, 0x70, 0xFC, 0x21, 0x73, 0xFD, 0x21, + 0x79, 0xFD, 0x21, 0x64, 0xFD, 0xC1, 0x01, 0x72, 0x6B, 0xE3, 0xDE, 0x44, 0x82, 0x9B, 0xBA, 0xBC, + 0xFF, 0xFA, 0xE4, 0xFD, 0xE4, 0xFD, 0xE4, 0xFD, 0x43, 0x85, 0x99, 0x87, 0xEC, 0x11, 0xEC, 0x11, + 0xE5, 0xE5, 0xA0, 0x0F, 0xB2, 0x21, 0x63, 0xFD, 0xA1, 0x04, 0x52, 0x79, 0xFD, 0x21, 0xBC, 0xFB, + 0x21, 0xC5, 0xFD, 0xA1, 0x02, 0x72, 0x75, 0xFD, 0xA0, 0x0F, 0xD3, 0x44, 0xBA, 0x82, 0xBC, 0x9B, + 0xFE, 0xA7, 0xFF, 0xF8, 0xFF, 0xFD, 0xE5, 0xC2, 0x41, 0x68, 0xE7, 0xD3, 0x21, 0x63, 0xFC, 0xA1, + 0x02, 0x92, 0x75, 0xFD, 0xA0, 0x0F, 0x13, 0x21, 0x72, 0xFD, 0xA0, 0x10, 0x03, 0x21, 0x74, 0xFD, + 0xA1, 0x0F, 0x13, 0x61, 0xFD, 0x21, 0x74, 0xFB, 0x21, 0x6F, 0xEC, 0xA3, 0x02, 0x92, 0x62, 0x73, + 0x7A, 0xEC, 0xFA, 0xFD, 0x41, 0x74, 0xE7, 0xA7, 0x21, 0x61, 0xFC, 0x21, 0x6D, 0xFD, 0x41, 0x6B, + 0xE7, 0x9D, 0x41, 0x6C, 0xE7, 0x99, 0xA0, 0x0F, 0x43, 0xA4, 0x02, 0x92, 0x61, 0x75, 0x79, 0x7A, + 0xF2, 0xF5, 0xF9, 0xFD, 0xC1, 0x02, 0x92, 0x6D, 0xE7, 0x87, 0xA0, 0x10, 0x32, 0x21, 0x75, 0xFD, + 0x21, 0x6B, 0xFD, 0xA1, 0x01, 0x71, 0x73, 0xFD, 0x41, 0x6D, 0xFF, 0x7A, 0x41, 0x6A, 0xFF, 0x76, + 0x42, 0x72, 0x6F, 0xFF, 0x88, 0xFF, 0xFC, 0xC6, 0x01, 0x72, 0x61, 0x67, 0x69, 0x6A, 0x6C, 0x77, + 0xFF, 0x6B, 0xFF, 0x81, 0xFF, 0xF1, 0xFF, 0x6B, 0xFF, 0x6B, 0xFF, 0xF9, 0x41, 0x6E, 0xE5, 0x37, + 0x21, 0x6F, 0xFC, 0x41, 0x63, 0xE5, 0x30, 0x41, 0x70, 0xEF, 0xF5, 0x23, 0x67, 0x6B, 0x6C, 0xF5, + 0xF8, 0xFC, 0x41, 0x7A, 0xE5, 0x21, 0x41, 0x72, 0xE5, 0x1D, 0x21, 0x65, 0xFC, 0x22, 0x67, 0x6D, + 0xF5, 0xFD, 0xA0, 0x10, 0x73, 0x21, 0x77, 0xFD, 0x21, 0x99, 0xFD, 0x21, 0xC4, 0xFD, 0xC2, 0x02, + 0x92, 0x69, 0x7A, 0xFF, 0xFD, 0xE4, 0xFF, 0xD9, 0x09, 0x12, 0xC4, 0xC5, 0x6D, 0x6F, 0x72, 0x75, + 0x79, 0x7A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6E, 0x70, + 0x73, 0x74, 0x77, 0xFF, 0x11, 0xFF, 0x34, 0xFF, 0x48, 0xFF, 0x64, 0xFF, 0x82, 0xFF, 0x8D, 0xFF, + 0x9C, 0xFF, 0xB0, 0xFF, 0xD4, 0xE4, 0xFC, 0xED, 0xF8, 0xEE, 0x08, 0xFF, 0xE6, 0xE4, 0xFC, 0xF0, + 0xB1, 0xE4, 0xFC, 0xE4, 0xFC, 0xE4, 0xFC, 0xE4, 0xFC, 0xE4, 0xFC, 0xE4, 0xFC, 0xE4, 0xFC, 0xFF, + 0xF7, 0xE4, 0xFC, 0xE4, 0xFC, 0xC1, 0x00, 0x71, 0x7A, 0xE2, 0x8E, 0xA1, 0x01, 0x92, 0x72, 0xFA, + 0xC1, 0x00, 0x71, 0x72, 0xF0, 0x54, 0xA0, 0x10, 0x52, 0x21, 0x65, 0xFD, 0xC3, 0x10, 0x32, 0x69, + 0x61, 0x77, 0xFF, 0xFD, 0xE7, 0xD2, 0xE7, 0xD2, 0x21, 0x77, 0xF4, 0xC3, 0x01, 0x92, 0x68, 0x69, + 0x7A, 0xFF, 0xE5, 0xFF, 0xFD, 0xE8, 0x90, 0xA0, 0x0F, 0x74, 0x21, 0x73, 0xFD, 0x21, 0x6B, 0xFD, + 0xC2, 0x01, 0x92, 0x6C, 0x72, 0xE8, 0x7B, 0xE8, 0x7B, 0xC1, 0x01, 0x92, 0x6B, 0xE8, 0x72, 0xC3, + 0x01, 0x92, 0x63, 0x6D, 0x7A, 0xFA, 0x87, 0xE8, 0x6C, 0xE8, 0x6C, 0xC1, 0x00, 0x71, 0x61, 0xE3, + 0x90, 0xC2, 0x01, 0x92, 0x6B, 0x72, 0xE8, 0x5A, 0xFF, 0xFA, 0x54, 0xC5, 0x64, 0xC4, 0x62, 0x63, + 0x65, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x75, 0x77, 0x7A, 0xFE, + 0x51, 0xFF, 0x4D, 0xEB, 0x7A, 0xFF, 0xA1, 0xFF, 0xC1, 0xFF, 0xD3, 0xE3, 0x59, 0xFD, 0x72, 0xE3, + 0x59, 0xFF, 0xD6, 0xE3, 0x59, 0xFF, 0xDF, 0xE3, 0x59, 0xFA, 0x70, 0xEB, 0xB4, 0xFF, 0xE5, 0xFF, + 0xF7, 0xE3, 0x59, 0xE3, 0x59, 0xE3, 0x59, 0xC1, 0x01, 0x92, 0x72, 0xE8, 0x14, 0x52, 0xC4, 0xC5, + 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0x6F, + 0xEB, 0x37, 0xEB, 0x3B, 0xFF, 0xFA, 0xEB, 0x48, 0xEB, 0x58, 0xE3, 0x16, 0xFD, 0x2F, 0xE3, 0x16, + 0xE3, 0x16, 0xE3, 0x16, 0xFF, 0x9C, 0xFA, 0x2D, 0xEB, 0x71, 0xFA, 0x32, 0xFF, 0x9C, 0xE3, 0x16, + 0xE3, 0x16, 0xEE, 0x5F, 0xC2, 0x00, 0x61, 0x65, 0x79, 0xFF, 0x86, 0xFF, 0xC9, 0xC3, 0x00, 0x51, + 0x61, 0x65, 0x7A, 0xFD, 0xAE, 0xFD, 0xC5, 0xFF, 0xF7, 0xD9, 0x01, 0xF1, 0xC4, 0xC5, 0xC3, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, + 0x74, 0x76, 0x77, 0x78, 0x7A, 0xE3, 0x30, 0xF7, 0xEE, 0xF8, 0x4F, 0xE3, 0x44, 0xF8, 0x52, 0xE3, + 0x44, 0xF8, 0xB1, 0xE3, 0x44, 0xE3, 0x44, 0xE3, 0x44, 0xF8, 0xED, 0xE3, 0x44, 0xE3, 0x44, 0xE3, + 0x44, 0xE3, 0x44, 0xE3, 0x44, 0xFD, 0x4D, 0xE3, 0x44, 0xFF, 0xF4, 0xE3, 0x44, 0xE3, 0x44, 0xE3, + 0x44, 0xE3, 0x44, 0xE3, 0x44, 0xE3, 0x44, 0x41, 0x73, 0xFE, 0x03, 0x21, 0x6E, 0xFC, 0x21, 0x61, + 0xFD, 0x21, 0x72, 0xFD, 0x21, 0x74, 0xFD, 0x41, 0x69, 0xF8, 0x07, 0x41, 0x65, 0xF8, 0x03, 0x21, + 0x69, 0xFC, 0xA2, 0x02, 0x22, 0x67, 0x6E, 0xF5, 0xFD, 0xA0, 0x10, 0xA4, 0x21, 0x87, 0xFD, 0x24, + 0x82, 0x9B, 0xBA, 0xBC, 0xFA, 0xFA, 0xFA, 0xFA, 0xA0, 0x10, 0xE4, 0xC2, 0x10, 0xE4, 0x68, 0x7A, + 0xE7, 0x40, 0xE7, 0x40, 0xC2, 0x10, 0xE4, 0xC5, 0x7A, 0xEA, 0x7A, 0xE7, 0x37, 0xA0, 0x11, 0x24, + 0xA1, 0x10, 0xE4, 0x7A, 0xFD, 0xC1, 0x10, 0xE4, 0x6F, 0xF7, 0xC9, 0xC1, 0x10, 0xE4, 0x63, 0xF9, + 0x3B, 0xC2, 0x10, 0xE4, 0xC5, 0x7A, 0xEA, 0x79, 0xE7, 0x1A, 0xC2, 0x10, 0xE4, 0x63, 0x7A, 0xF9, + 0x2C, 0xE7, 0x11, 0x21, 0x74, 0xDA, 0xD3, 0x02, 0x22, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, + 0x68, 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0x6A, 0x6E, 0xFF, 0xB6, 0xFF, 0xB9, + 0xFF, 0xC2, 0xFF, 0xC5, 0xFF, 0xCE, 0xFF, 0xC2, 0xFF, 0xDA, 0xFF, 0xC2, 0xFF, 0xC2, 0xFF, 0xC2, + 0xFF, 0xDF, 0xFF, 0xE5, 0xFF, 0xEB, 0xFF, 0xF4, 0xFF, 0xC2, 0xFF, 0xC2, 0xFF, 0xC2, 0xE2, 0x8A, + 0xFF, 0xFD, 0x41, 0x9B, 0xE1, 0x9F, 0x41, 0x72, 0xED, 0x16, 0xC1, 0x02, 0x41, 0x72, 0xE1, 0x97, + 0xCC, 0x02, 0x02, 0x61, 0x65, 0x75, 0xC5, 0x62, 0x64, 0x69, 0x6D, 0x6F, 0x70, 0x74, 0x77, 0xFF, + 0x62, 0xFF, 0xB6, 0xE2, 0x40, 0xFF, 0xF2, 0xFF, 0xF6, 0xE2, 0x50, 0xE2, 0x50, 0xE2, 0x50, 0xE2, + 0x50, 0xE4, 0xBC, 0xFF, 0xFA, 0xE2, 0x50, 0x21, 0x7A, 0xD9, 0xD7, 0x01, 0xF1, 0xC4, 0xC5, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, + 0x76, 0x77, 0x78, 0x7A, 0xE1, 0xFF, 0xE2, 0x03, 0xE2, 0x13, 0xE2, 0x13, 0xE2, 0x13, 0xFF, 0x2A, + 0xE2, 0x13, 0xE2, 0x13, 0xE2, 0x13, 0xE2, 0x13, 0xE2, 0x13, 0xE2, 0x13, 0xE2, 0x13, 0xE2, 0x13, + 0xFF, 0xFD, 0xE2, 0x13, 0xE2, 0x13, 0xE2, 0x13, 0xE2, 0x13, 0xE2, 0x13, 0xE2, 0x13, 0xE2, 0x13, + 0xE2, 0x13, 0x41, 0x7A, 0xFC, 0xD8, 0x21, 0x6F, 0xFC, 0x45, 0x63, 0x6B, 0x70, 0x77, 0x72, 0xE1, + 0x69, 0xE1, 0x4A, 0xE1, 0x4A, 0xE1, 0x4A, 0xFF, 0xFD, 0x21, 0x6F, 0xF0, 0x21, 0x6D, 0xFD, 0xC1, + 0x03, 0x32, 0x73, 0xF7, 0x2C, 0x21, 0x6D, 0xFA, 0x42, 0x65, 0x6D, 0xFF, 0xFD, 0xF7, 0x38, 0x21, + 0x64, 0xF9, 0x21, 0x65, 0xFD, 0xA0, 0x0E, 0x92, 0x21, 0x65, 0xFD, 0x21, 0xBC, 0xFD, 0x21, 0xC5, + 0xFD, 0x21, 0x64, 0xFD, 0x21, 0x85, 0xFD, 0xC3, 0x00, 0x51, 0xC4, 0x6C, 0x72, 0xFF, 0xFD, 0xDF, + 0x53, 0xDF, 0x53, 0x41, 0x62, 0xE7, 0xCB, 0xA0, 0x0D, 0x72, 0x21, 0x82, 0xFD, 0x21, 0xC5, 0xFD, + 0x21, 0xB3, 0xFD, 0xC3, 0x06, 0x12, 0x7A, 0xC5, 0x64, 0xE8, 0x6A, 0xEA, 0xC4, 0xE8, 0x06, 0xC3, + 0x05, 0xC2, 0x6E, 0x74, 0x7A, 0xED, 0x69, 0xED, 0x69, 0xE0, 0xB2, 0x51, 0x64, 0xC4, 0xC5, 0x62, + 0x63, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0xFF, 0xE8, 0xED, + 0x59, 0xEA, 0x91, 0xE6, 0x36, 0xE9, 0xEB, 0xE6, 0x36, 0xE6, 0x36, 0xE6, 0x36, 0xE6, 0x36, 0xE6, + 0x36, 0xE6, 0x36, 0xE6, 0x36, 0xFF, 0xF4, 0xE9, 0xFD, 0xE6, 0x36, 0xE6, 0x36, 0xE6, 0x36, 0xA2, + 0x00, 0x51, 0xC3, 0x6F, 0xB1, 0xCC, 0xC5, 0x03, 0x32, 0x61, 0x65, 0x69, 0x6F, 0x75, 0xDF, 0x6D, + 0xDF, 0x6D, 0xDF, 0x6D, 0xDF, 0x6D, 0xDF, 0x6D, 0x21, 0x6F, 0xEE, 0x21, 0x65, 0xFD, 0x21, 0x72, + 0xFD, 0xA1, 0x00, 0x51, 0x65, 0xFD, 0x41, 0x74, 0xE0, 0xFD, 0xC2, 0x02, 0x02, 0x69, 0x6F, 0xF7, + 0x38, 0xFF, 0xFC, 0xA0, 0x11, 0x63, 0xA1, 0x04, 0x52, 0x72, 0xFD, 0x21, 0x74, 0xFB, 0x41, 0x6F, + 0xE3, 0x6D, 0xA0, 0x11, 0x92, 0x21, 0x62, 0xFD, 0xA0, 0x11, 0xB2, 0x21, 0x74, 0xFD, 0x21, 0x75, + 0xFD, 0x21, 0x7A, 0xFD, 0x21, 0x72, 0xFD, 0x21, 0x64, 0xFD, 0xC5, 0x04, 0x32, 0x61, 0x69, 0x7A, + 0x65, 0x6F, 0xFF, 0xE1, 0xFF, 0xE4, 0xFF, 0xEB, 0xE5, 0x41, 0xFF, 0xFD, 0x21, 0x72, 0xEE, 0x21, + 0x65, 0xFD, 0x22, 0x62, 0x70, 0xB8, 0xFD, 0xA0, 0x11, 0xD2, 0x21, 0x74, 0xFD, 0x21, 0x65, 0xFD, + 0xA1, 0x11, 0xF3, 0x73, 0xFD, 0x21, 0x87, 0xFB, 0x41, 0x9B, 0xEE, 0x63, 0x21, 0xC5, 0xFC, 0x21, + 0x6F, 0xFD, 0x21, 0x69, 0xFD, 0x22, 0xC4, 0x63, 0xF0, 0xFD, 0x21, 0x9B, 0xFB, 0x42, 0xC5, 0x73, + 0xFF, 0xFD, 0xF4, 0x53, 0xA1, 0x00, 0x51, 0x65, 0xF9, 0xD9, 0x01, 0xF1, 0xC4, 0xC5, 0x61, 0x62, + 0x63, 0x64, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, + 0x75, 0x76, 0x77, 0x78, 0x7A, 0xE0, 0x60, 0xE0, 0x64, 0xFE, 0xC3, 0xE0, 0x74, 0xF5, 0x82, 0xE0, + 0x74, 0xE0, 0x74, 0xE0, 0x74, 0xE0, 0x74, 0xFE, 0xD9, 0xE0, 0x74, 0xFE, 0xEE, 0xE0, 0x74, 0xE0, + 0x74, 0xE0, 0x74, 0xFE, 0xFA, 0xFF, 0x56, 0xE0, 0x74, 0xE0, 0x74, 0xFF, 0x78, 0xFF, 0xC9, 0xE0, + 0x74, 0xE0, 0x74, 0xE0, 0x74, 0xFF, 0xFB, 0xA0, 0x12, 0x22, 0x21, 0x6E, 0xFD, 0x21, 0x61, 0xFD, + 0x21, 0x7A, 0xFD, 0x42, 0x6F, 0x72, 0xE4, 0x3A, 0xFF, 0xFD, 0x41, 0x61, 0xE9, 0x1C, 0x41, 0x7A, + 0xE2, 0x9D, 0x21, 0x63, 0xFC, 0xC2, 0x04, 0x32, 0xC4, 0x65, 0xE2, 0x99, 0xFF, 0xFD, 0x21, 0x6A, + 0xF7, 0x21, 0xB3, 0xFD, 0xC1, 0x04, 0x52, 0x75, 0xFA, 0x8E, 0x41, 0x65, 0xE2, 0x81, 0xC6, 0x04, + 0x32, 0x65, 0x69, 0x79, 0x7A, 0x61, 0x6F, 0xFF, 0xF6, 0xFF, 0xFC, 0xE2, 0x7D, 0xE6, 0x8B, 0xE4, + 0x6D, 0xE4, 0x6D, 0x21, 0x73, 0xEB, 0x21, 0x6E, 0xFD, 0x41, 0x68, 0xF5, 0x55, 0x21, 0x63, 0xFC, + 0xA1, 0x00, 0x61, 0x65, 0xFD, 0xA3, 0x00, 0x51, 0xC3, 0x61, 0x7A, 0xCC, 0xF1, 0xFB, 0xA0, 0x12, + 0x42, 0x21, 0x82, 0xFD, 0xA1, 0x02, 0xB1, 0xC5, 0xFD, 0xC3, 0x10, 0x32, 0x61, 0x65, 0x7A, 0xFB, + 0x8D, 0xFB, 0x8D, 0xFF, 0xFB, 0x21, 0x63, 0xF4, 0x21, 0x85, 0xFD, 0x21, 0xC4, 0xFD, 0x21, 0x69, + 0xFD, 0x21, 0x73, 0xFD, 0xD9, 0x01, 0xF1, 0xC4, 0xC5, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x79, 0x7A, + 0xDF, 0x85, 0xDF, 0x89, 0xFF, 0x7F, 0xDF, 0x99, 0xF4, 0xA7, 0xDF, 0x99, 0xE3, 0xBC, 0xDF, 0x99, + 0xDF, 0x99, 0xDF, 0x99, 0xDF, 0x99, 0xDF, 0x99, 0xDF, 0x99, 0xDF, 0x99, 0xDF, 0x99, 0xFF, 0x86, + 0xDF, 0x99, 0xFF, 0xD1, 0xDF, 0x99, 0xDF, 0x99, 0xDF, 0x99, 0xDF, 0x99, 0xDF, 0x99, 0xFF, 0xFD, + 0xDF, 0x99, 0xA0, 0x04, 0xC2, 0x44, 0x9B, 0x82, 0xBA, 0xBC, 0xF0, 0x76, 0xFF, 0xFD, 0xFF, 0xFD, + 0xFF, 0xFD, 0xC1, 0x0C, 0xB2, 0x77, 0xDE, 0x8F, 0x21, 0x7A, 0xFA, 0xC2, 0x0B, 0xE2, 0x65, 0x72, + 0xFF, 0xFD, 0xF0, 0x60, 0xC2, 0x0B, 0xE2, 0x68, 0x7A, 0xF0, 0x57, 0xF0, 0x57, 0xA0, 0x06, 0x72, + 0x42, 0xBA, 0xBC, 0xDF, 0x30, 0xDF, 0x30, 0xC3, 0x0B, 0xE2, 0x6B, 0xC5, 0x7A, 0xFF, 0xF6, 0xFF, + 0xF9, 0xF0, 0x44, 0xA1, 0x0B, 0xE2, 0x6E, 0xEA, 0x21, 0x6A, 0xE5, 0x21, 0x65, 0xFD, 0xC2, 0x0B, + 0xE2, 0x6C, 0x72, 0xFF, 0xFD, 0xF0, 0x2D, 0xA2, 0x0B, 0xE2, 0x73, 0x74, 0xD6, 0xD6, 0x21, 0x72, + 0xCF, 0xC2, 0x0B, 0xE2, 0x62, 0x6B, 0xFF, 0xFD, 0xF0, 0x1A, 0xA2, 0x0B, 0xE2, 0x63, 0x64, 0xC3, + 0xC3, 0xA0, 0x12, 0x63, 0x21, 0x73, 0xFD, 0xC3, 0x06, 0x12, 0x61, 0xC5, 0x64, 0xE7, 0xDF, 0xE8, + 0x30, 0xE5, 0x72, 0x51, 0x64, 0xC4, 0xC5, 0x62, 0x63, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x70, + 0x72, 0x73, 0x74, 0x77, 0x7A, 0xFF, 0xF4, 0xEA, 0xD1, 0xE8, 0x09, 0xE3, 0xAE, 0xE7, 0x63, 0xE3, + 0xAE, 0xE3, 0xAE, 0xE3, 0xAE, 0xE3, 0xAE, 0xE3, 0xAE, 0xE3, 0xAE, 0xE3, 0xAE, 0xE7, 0x75, 0xE7, + 0x75, 0xE3, 0xAE, 0xE3, 0xAE, 0xE3, 0xAE, 0xC3, 0x0B, 0xE2, 0x70, 0x63, 0x6F, 0xFF, 0xBD, 0xF2, + 0xBB, 0xFF, 0xCC, 0x41, 0xBC, 0xDE, 0x9D, 0x41, 0x7A, 0xF2, 0x59, 0xC4, 0x0B, 0xE2, 0x73, 0xC5, + 0x6F, 0x7A, 0xFF, 0x62, 0xFF, 0xF8, 0xFF, 0xFC, 0xEF, 0xB0, 0xA0, 0x12, 0x92, 0xA0, 0x05, 0x91, + 0x23, 0x6E, 0x63, 0x6B, 0xFA, 0xFD, 0xFD, 0xC3, 0x0B, 0xE2, 0x74, 0x63, 0x7A, 0xFF, 0xF9, 0xF2, + 0x8B, 0xEF, 0x94, 0xC2, 0x0B, 0xE2, 0x6B, 0x72, 0xEF, 0x88, 0xEF, 0x88, 0x41, 0x65, 0xFF, 0x31, + 0x41, 0x77, 0xE3, 0x31, 0xA2, 0x0B, 0xE2, 0x62, 0x65, 0xF8, 0xFC, 0x52, 0xC4, 0xC5, 0x62, 0x63, + 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0xEF, 0x73, + 0xFE, 0xFA, 0xFF, 0x10, 0xFF, 0x19, 0xFF, 0x2C, 0xFF, 0x38, 0xF2, 0x0C, 0xF2, 0x0C, 0xFF, 0x43, + 0xFF, 0x4C, 0xFF, 0x56, 0xFF, 0x5F, 0xFF, 0xAC, 0xFF, 0xC0, 0xFF, 0xDC, 0xFF, 0xE8, 0xF2, 0x0C, + 0xFF, 0xF9, 0xC1, 0x03, 0xA2, 0x6E, 0xDF, 0xC7, 0x43, 0x82, 0x9B, 0xBC, 0xFF, 0xFA, 0xDF, 0xBB, + 0xDF, 0xBB, 0xC1, 0x01, 0xB2, 0x77, 0xDF, 0xF5, 0xC1, 0x01, 0xB2, 0x6B, 0xDE, 0x08, 0xC2, 0x01, + 0xB2, 0x64, 0x74, 0xDF, 0xE9, 0xDF, 0xE9, 0xC1, 0x01, 0xB2, 0x63, 0xDD, 0xF5, 0xC6, 0x01, 0xB2, + 0x62, 0x64, 0x6E, 0x73, 0x74, 0x7A, 0xDF, 0xDA, 0xDF, 0xDA, 0xDF, 0xDA, 0xDF, 0xDA, 0xDF, 0xDA, + 0xDD, 0xF3, 0xA0, 0x12, 0xB3, 0x21, 0x68, 0xFD, 0x21, 0x63, 0xFD, 0xC3, 0x01, 0xB2, 0x70, 0x74, + 0x7A, 0xE6, 0x1C, 0xFF, 0xFD, 0xDD, 0xD5, 0xA0, 0x12, 0xE2, 0x21, 0x7A, 0xFD, 0x21, 0x72, 0xFD, + 0x21, 0x74, 0xFD, 0x21, 0x85, 0xFD, 0x21, 0xC4, 0xFD, 0xA1, 0x01, 0xB2, 0x6E, 0xFD, 0x41, 0x72, + 0xDF, 0x99, 0x41, 0x82, 0xDF, 0x95, 0x21, 0xC5, 0xFC, 0xA2, 0x01, 0xB2, 0x62, 0x67, 0xF5, 0xFD, + 0x52, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, + 0x74, 0x77, 0x7A, 0xDF, 0x46, 0xFF, 0x88, 0xDD, 0x2F, 0xDF, 0x65, 0xDF, 0x75, 0xDD, 0x2F, 0xDD, + 0x2F, 0xDD, 0x2F, 0xDF, 0x8A, 0xFF, 0x92, 0xFF, 0x98, 0xFF, 0x9E, 0xFF, 0xA7, 0xFF, 0xAD, 0xFF, + 0xCB, 0xFF, 0x98, 0xFF, 0xE9, 0xFF, 0xF9, 0x43, 0xC5, 0x64, 0x6B, 0xDD, 0xC9, 0xDD, 0xCC, 0xDD, + 0xCC, 0x41, 0x73, 0xF1, 0x96, 0x22, 0x6F, 0x75, 0xF2, 0xFC, 0x21, 0x6C, 0xFB, 0x41, 0x6D, 0xDD, + 0xD0, 0x21, 0x6F, 0xFC, 0x21, 0x7A, 0xFD, 0x21, 0x63, 0xFD, 0x22, 0x65, 0x6C, 0xF0, 0xFD, 0x41, + 0x62, 0xDD, 0xC4, 0x21, 0x65, 0xFC, 0xA1, 0x00, 0x51, 0x69, 0xFD, 0x41, 0x77, 0xDC, 0xCA, 0x21, + 0x62, 0xFC, 0xC4, 0x13, 0x02, 0x69, 0x6F, 0x75, 0x77, 0xE0, 0xCC, 0xFF, 0xFD, 0xE0, 0xCC, 0xE0, + 0xCC, 0x21, 0x82, 0xF1, 0x21, 0xC5, 0xFD, 0x21, 0xB3, 0xFD, 0x21, 0xC3, 0xFD, 0xC2, 0x0D, 0x72, + 0x6F, 0x77, 0xDB, 0x56, 0xDB, 0x56, 0x21, 0x68, 0xF7, 0x21, 0x63, 0xFD, 0x21, 0x65, 0xFD, 0xA2, + 0x00, 0x51, 0x70, 0x7A, 0xEB, 0xFD, 0x41, 0x7A, 0xDE, 0xA3, 0xA1, 0x03, 0xA2, 0x73, 0xFC, 0x44, + 0x82, 0x9B, 0xBA, 0xBC, 0xDE, 0x94, 0xDE, 0x94, 0xDE, 0x94, 0xFF, 0xFB, 0x41, 0x61, 0xDE, 0x8D, + 0xA1, 0x02, 0x41, 0x68, 0xFC, 0xC2, 0x01, 0xB2, 0x7A, 0x68, 0xFF, 0xFB, 0xDC, 0xDB, 0xC3, 0x01, + 0xB2, 0xC5, 0x72, 0x7A, 0xDE, 0xA0, 0xDC, 0xD2, 0xDC, 0xD2, 0xC2, 0x01, 0xB2, 0x6C, 0x72, 0xDC, + 0xC6, 0xDE, 0x80, 0xA0, 0x13, 0x23, 0x21, 0x72, 0xFD, 0x21, 0x64, 0xFD, 0xC2, 0x01, 0xB2, 0xC5, + 0x7A, 0xDE, 0xBE, 0xDC, 0xB4, 0xC3, 0x01, 0xB2, 0x63, 0x6B, 0x72, 0xDC, 0xA7, 0xDC, 0xAB, 0xDC, + 0xAB, 0xA0, 0x06, 0x13, 0x21, 0x73, 0xFD, 0x21, 0x6B, 0xFD, 0x41, 0x6F, 0xED, 0xB1, 0x21, 0x7A, + 0xFC, 0x54, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x6F, 0x70, 0x72, + 0x73, 0x74, 0x77, 0x7A, 0x65, 0x69, 0xDE, 0x35, 0xFF, 0x9E, 0xDE, 0x4F, 0xFF, 0xB4, 0xFF, 0xBD, + 0xDC, 0x1E, 0xDE, 0x71, 0xDC, 0x1E, 0xFF, 0xC9, 0xDC, 0x1E, 0xFE, 0x87, 0xFF, 0xD8, 0xDE, 0x90, + 0xFF, 0xDB, 0xDE, 0xA9, 0xFF, 0xE4, 0xDC, 0x1E, 0xDC, 0x1E, 0xFF, 0xF6, 0xFF, 0xFD, 0xD9, 0x01, + 0xF1, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, + 0x6F, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xDC, 0x2B, 0xDC, 0x2F, 0xDC, 0x3F, + 0xDC, 0x3F, 0xDC, 0x3F, 0xFE, 0xB2, 0xDC, 0x3F, 0xDC, 0x3F, 0xDC, 0x3F, 0xFF, 0x0C, 0xDC, 0x3F, + 0xDC, 0x3F, 0xDC, 0x3F, 0xDC, 0x3F, 0xFF, 0x18, 0xE2, 0x93, 0xDC, 0x3F, 0xDC, 0x3F, 0xFF, 0x51, + 0xDC, 0x3F, 0xDC, 0x3F, 0xDC, 0x3F, 0xDC, 0x3F, 0xFF, 0xC3, 0xDC, 0x3F, 0xC1, 0x00, 0x61, 0x6F, + 0xE2, 0x3E, 0x45, 0x82, 0x84, 0x9B, 0xBA, 0xBC, 0xFF, 0xFA, 0xD9, 0xB8, 0xD9, 0xB8, 0xD9, 0xB8, + 0xD9, 0xB8, 0xA0, 0x13, 0x51, 0xA1, 0x13, 0x62, 0x75, 0xFD, 0x21, 0x87, 0xFB, 0x21, 0xC4, 0xFD, + 0x21, 0x9B, 0xFD, 0x21, 0xC5, 0xFD, 0x41, 0x6F, 0xE7, 0x58, 0x21, 0x70, 0xFC, 0x21, 0x73, 0xFD, + 0xC5, 0x01, 0xB2, 0xC5, 0x6F, 0x72, 0x79, 0x7A, 0xDD, 0x9E, 0xFF, 0xF3, 0xDB, 0xD0, 0xFF, 0xFD, + 0xDB, 0xD0, 0xC3, 0x01, 0xB2, 0x74, 0x6C, 0x72, 0xDD, 0xA5, 0xDB, 0xBE, 0xDD, 0x78, 0xC3, 0x01, + 0xB2, 0x67, 0x6B, 0x74, 0xDD, 0x99, 0xDD, 0x99, 0xDD, 0x99, 0x42, 0x72, 0x73, 0xFE, 0xE9, 0xFE, + 0xE9, 0x21, 0x62, 0xF9, 0x41, 0x68, 0xDD, 0x83, 0xC3, 0x01, 0xB2, 0x63, 0xC5, 0x7A, 0xFF, 0xFC, + 0xDD, 0xA2, 0xDB, 0x98, 0x41, 0x6F, 0xDA, 0xAF, 0xA1, 0x01, 0xB2, 0x74, 0xFC, 0xA0, 0x08, 0x41, + 0x21, 0x63, 0xFD, 0xA1, 0x0C, 0xB2, 0x69, 0xFD, 0x42, 0x6E, 0x7A, 0xFF, 0xFB, 0xFE, 0xE2, 0x41, + 0x64, 0xDB, 0xD4, 0x21, 0x65, 0xFC, 0x21, 0x69, 0xFD, 0x55, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, + 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x77, 0x7A, 0x69, 0x6E, 0xDD, + 0x0D, 0xE6, 0x77, 0xDD, 0x27, 0xDD, 0x2C, 0xFF, 0x97, 0xDA, 0xF6, 0xDD, 0x49, 0xDA, 0xF6, 0xFF, + 0xA9, 0xFF, 0xB5, 0xDD, 0x63, 0xFF, 0xC8, 0xDA, 0xF6, 0xFF, 0xCF, 0xDD, 0x81, 0xDD, 0x8D, 0xFF, + 0xDF, 0xDA, 0xF6, 0xDA, 0xF6, 0xFF, 0xEF, 0xFF, 0xFD, 0xA0, 0x13, 0x82, 0x21, 0x75, 0xFD, 0x21, + 0x77, 0xFD, 0x22, 0x6C, 0x72, 0xF7, 0xF7, 0xA3, 0x0C, 0xB2, 0x61, 0x65, 0x79, 0xF8, 0xFB, 0xF2, + 0x21, 0x7A, 0xF7, 0x41, 0x74, 0xEE, 0xCD, 0x21, 0x6E, 0xFC, 0x41, 0x64, 0xEE, 0xC6, 0x21, 0x65, + 0xFC, 0x41, 0x6C, 0xEE, 0xBF, 0x21, 0x61, 0xFC, 0x23, 0x6F, 0x72, 0x77, 0xEF, 0xF6, 0xFD, 0x21, + 0x6B, 0xF9, 0x21, 0x73, 0xFD, 0xA2, 0x00, 0x51, 0x65, 0x79, 0xDB, 0xFD, 0xC1, 0x01, 0xB2, 0x6C, + 0xDA, 0xE4, 0xC3, 0x01, 0xB2, 0x6B, 0xC5, 0x7A, 0xDC, 0xC5, 0xDC, 0xE8, 0xDA, 0xDE, 0xC3, 0x01, + 0xB2, 0x63, 0x6D, 0x7A, 0xDA, 0xCE, 0xFF, 0x4F, 0xDA, 0xD2, 0xA0, 0x13, 0xA5, 0x21, 0x73, 0xFD, + 0x42, 0x65, 0x70, 0xFF, 0xFD, 0xDC, 0xA7, 0x21, 0x6C, 0xF3, 0x21, 0x65, 0xFD, 0x22, 0x6D, 0x73, + 0xF3, 0xFD, 0x41, 0x70, 0xDC, 0x95, 0x21, 0x61, 0xFC, 0xC3, 0x01, 0xB2, 0x6B, 0x65, 0x68, 0xDC, + 0x4A, 0xFF, 0xF4, 0xFF, 0xFD, 0x51, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, + 0x6D, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0xDC, 0x41, 0xE5, 0xAB, 0xDA, 0x2A, 0xDC, 0x60, 0xDC, + 0x70, 0xDA, 0x2A, 0xDA, 0x2A, 0xDA, 0x2A, 0xFF, 0xB7, 0xDA, 0x2A, 0xDA, 0x2A, 0xFC, 0xA2, 0xFF, + 0xBD, 0xFF, 0xC9, 0xFF, 0xF4, 0xDA, 0x2A, 0xDA, 0x2A, 0x41, 0x6B, 0xEE, 0x58, 0x21, 0x6F, 0xFC, + 0x21, 0x6E, 0xFD, 0x21, 0x6D, 0xFD, 0xC1, 0x13, 0xF2, 0x77, 0xE7, 0xE4, 0x21, 0x68, 0xFA, 0x21, + 0x63, 0xFD, 0x21, 0x79, 0xFD, 0x21, 0x77, 0xFD, 0x21, 0x74, 0xFD, 0x21, 0x72, 0xFD, 0xA1, 0x00, + 0x51, 0x61, 0xFD, 0x45, 0x82, 0x84, 0x9B, 0xBA, 0xBC, 0xD9, 0xA5, 0xD9, 0xA5, 0xD9, 0xA5, 0xD9, + 0xA5, 0xD9, 0xA5, 0xA0, 0x14, 0x12, 0x42, 0xBA, 0xBC, 0xFF, 0xFD, 0xD8, 0x6D, 0xC2, 0x01, 0x92, + 0xC5, 0x7A, 0xFF, 0xF9, 0xDE, 0x8E, 0xC1, 0x01, 0x92, 0x63, 0xE1, 0xD8, 0x52, 0xC4, 0xC5, 0x62, + 0x63, 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0xE1, + 0xA8, 0xFF, 0xD7, 0xD9, 0x87, 0xE1, 0xB9, 0xFF, 0xF1, 0xD9, 0x87, 0xD9, 0x87, 0xD9, 0x87, 0xD9, + 0x87, 0xD9, 0x87, 0xFF, 0xFA, 0xD9, 0x87, 0xD9, 0x87, 0xE1, 0xEB, 0xE1, 0xEB, 0xD9, 0x87, 0xD9, + 0x87, 0xD9, 0x87, 0x21, 0x65, 0xC9, 0xA1, 0x00, 0x51, 0x69, 0xFD, 0xC1, 0x0C, 0xB2, 0x75, 0xFE, + 0xAE, 0x21, 0x7A, 0xFA, 0xA1, 0x00, 0x51, 0x6F, 0xFD, 0xD9, 0x01, 0xF1, 0xC4, 0xC5, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, + 0x74, 0x76, 0x77, 0x78, 0x7A, 0xD9, 0xA0, 0xFD, 0xC9, 0xFE, 0x60, 0xD9, 0xB4, 0xD9, 0xB4, 0xFE, + 0xDC, 0xFF, 0x2C, 0xD9, 0xB4, 0xD9, 0xB4, 0xD9, 0xB4, 0xFF, 0x6A, 0xD9, 0xB4, 0xD9, 0xB4, 0xD9, + 0xB4, 0xFF, 0x85, 0xFF, 0xED, 0xDD, 0xD7, 0xD9, 0xB4, 0xFF, 0xFB, 0xD9, 0xB4, 0xD9, 0xB4, 0xD9, + 0xB4, 0xD9, 0xB4, 0xD9, 0xB4, 0xD9, 0xB4, 0x5A, 0xC4, 0xC5, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x7A, 0xD7, 0x77, 0xD8, 0x78, 0xD9, 0x3F, 0xD9, 0xA7, 0xDA, 0x7B, 0xDC, 0x80, 0xDD, 0x34, + 0xDD, 0x44, 0xDD, 0x9C, 0xDD, 0xFC, 0xDE, 0x6F, 0xDE, 0x83, 0xDF, 0x6B, 0xDF, 0xBD, 0xE0, 0x1E, + 0xEA, 0x49, 0xED, 0xC7, 0xF6, 0x22, 0xF7, 0x53, 0xF8, 0xF2, 0xF9, 0xCD, 0xFB, 0x24, 0xDD, 0x44, + 0xFD, 0x27, 0xDD, 0x44, 0xFF, 0xB2, 0xA0, 0x14, 0x31, 0xA0, 0x15, 0x81, 0xA1, 0x14, 0x62, 0x2E, + 0xFD, 0x21, 0x2E, 0xF8, 0x25, 0x84, 0x9B, 0xBA, 0xBC, 0x82, 0xF8, 0xF8, 0xF8, 0xF8, 0xFD, 0xA1, + 0x15, 0x42, 0x2E, 0xEA, 0x21, 0x87, 0xFB, 0x36, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x6B, 0x6D, + 0x6E, 0x70, 0x73, 0x74, 0x7A, 0xC4, 0x2E, 0x68, 0x6A, 0x6C, 0x72, 0x76, 0x77, 0x78, 0xED, 0xE5, + 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xFD, 0xE2, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0xEA, 0xEA, 0x43, 0x85, 0x99, 0x87, 0xFF, 0xB2, 0xFF, 0xB2, 0xFF, 0xD3, 0x41, 0x7A, + 0xF9, 0x9F, 0x21, 0x63, 0xFC, 0xA1, 0x14, 0x31, 0x77, 0xFD, 0x21, 0xB3, 0xFB, 0xA0, 0x14, 0x42, + 0xC2, 0x14, 0x31, 0x69, 0x2E, 0xFF, 0xFD, 0xFF, 0x99, 0xA0, 0x14, 0x61, 0x42, 0x63, 0x2E, 0xFF, + 0xFD, 0xFF, 0x8D, 0x21, 0x87, 0xF9, 0x45, 0x9B, 0xBA, 0xBC, 0x82, 0x84, 0xFF, 0x86, 0xFF, 0x86, + 0xFF, 0x86, 0xFF, 0x8B, 0xFF, 0x8B, 0x43, 0x6D, 0x6E, 0x2E, 0xFF, 0xE3, 0xFF, 0xE3, 0xFF, 0x73, + 0x56, 0x63, 0xC4, 0xC5, 0x62, 0x64, 0x66, 0x67, 0x6B, 0x70, 0x73, 0x74, 0x7A, 0x6C, 0x2E, 0x68, + 0x6A, 0x6D, 0x6E, 0x72, 0x76, 0x77, 0x78, 0xFF, 0xD0, 0xFF, 0xE3, 0xFF, 0xE6, 0xFF, 0x6C, 0xFF, + 0x6C, 0xFF, 0x6C, 0xFF, 0x6C, 0xFF, 0x6C, 0xFF, 0x6C, 0xFF, 0x6C, 0xFF, 0x6C, 0xFF, 0x6C, 0xFF, + 0xF6, 0xFF, 0x69, 0xFF, 0x71, 0xFF, 0x71, 0xFF, 0x71, 0xFF, 0x71, 0xFF, 0x71, 0xFF, 0x71, 0xFF, + 0x71, 0xFF, 0x71, 0xA0, 0x00, 0xF1, 0x21, 0xBA, 0xFD, 0xC2, 0x14, 0x62, 0xC5, 0x2E, 0xFF, 0xFD, + 0xFF, 0x20, 0x41, 0x87, 0xFF, 0x1A, 0x45, 0x9B, 0xBC, 0xBA, 0x82, 0x84, 0xFF, 0x16, 0xFF, 0x16, + 0xFF, 0x29, 0xFF, 0x1B, 0xFF, 0x1B, 0x56, 0x64, 0xC4, 0xC5, 0x62, 0x63, 0x66, 0x67, 0x6B, 0x6C, + 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x77, 0x7A, 0x2E, 0x68, 0x6A, 0x72, 0x76, 0x78, 0xFF, 0xE3, 0xFF, + 0xEC, 0xFF, 0xF0, 0xFF, 0x06, 0xFF, 0x06, 0xFF, 0x06, 0xFF, 0x06, 0xFF, 0x06, 0xFF, 0x06, 0xFF, + 0x06, 0xFF, 0x06, 0xFF, 0x06, 0xFF, 0x06, 0xFF, 0x06, 0xFF, 0x06, 0xFF, 0x06, 0xFF, 0x03, 0xFF, + 0x0B, 0xFF, 0x0B, 0xFF, 0x0B, 0xFF, 0x0B, 0xFF, 0x0B, 0x45, 0x84, 0x9B, 0xBA, 0xBC, 0x82, 0xFE, + 0xC3, 0xFE, 0xC3, 0xFE, 0xC3, 0xFE, 0xC3, 0xFE, 0xD6, 0x56, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, + 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0x2E, 0x76, 0x78, + 0xFF, 0x99, 0xFF, 0xF0, 0xFE, 0xB3, 0xFE, 0xB3, 0xFE, 0xB3, 0xFE, 0xB3, 0xFE, 0xB3, 0xFE, 0xB3, + 0xFE, 0xB3, 0xFE, 0xB3, 0xFE, 0xB3, 0xFE, 0xB3, 0xFE, 0xB3, 0xFE, 0xB3, 0xFE, 0xB3, 0xFE, 0xB3, + 0xFE, 0xB3, 0xFE, 0xB3, 0xFE, 0xB3, 0xFE, 0xB0, 0xFE, 0xB8, 0xFE, 0xB8, 0x45, 0x82, 0x84, 0x9B, + 0xBA, 0xBC, 0xFE, 0x70, 0xFE, 0x70, 0xFE, 0x70, 0xFE, 0x70, 0xFE, 0x70, 0x56, 0xC4, 0xC5, 0x62, + 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, + 0x2E, 0x76, 0x78, 0xFF, 0x46, 0xFF, 0xF0, 0xFE, 0x60, 0xFE, 0x60, 0xFE, 0x60, 0xFE, 0x60, 0xFE, + 0x60, 0xFE, 0x60, 0xFE, 0x60, 0xFE, 0x60, 0xFE, 0x60, 0xFE, 0x60, 0xFE, 0x60, 0xFE, 0x60, 0xFE, + 0x60, 0xFE, 0x60, 0xFE, 0x60, 0xFE, 0x60, 0xFE, 0x60, 0xFE, 0x5D, 0xFE, 0x65, 0xFE, 0x65, 0x45, + 0x82, 0x84, 0x9B, 0xBA, 0xBC, 0xFE, 0x1D, 0xFE, 0x1D, 0xFE, 0x1D, 0xFE, 0x1D, 0xFE, 0x30, 0x56, + 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, + 0x77, 0x7A, 0x2E, 0x68, 0x76, 0x78, 0xFE, 0xF3, 0xFF, 0xF0, 0xFE, 0x0D, 0xFE, 0x0D, 0xFE, 0x0D, + 0xFE, 0x0D, 0xFE, 0x0D, 0xFE, 0x0D, 0xFE, 0x0D, 0xFE, 0x0D, 0xFE, 0x0D, 0xFE, 0x0D, 0xFE, 0x0D, + 0xFE, 0x0D, 0xFE, 0x0D, 0xFE, 0x0D, 0xFE, 0x0D, 0xFE, 0x0D, 0xFE, 0x0A, 0xFE, 0x12, 0xFE, 0x12, + 0xFE, 0x12, 0x45, 0x9B, 0xBA, 0x82, 0x84, 0xBC, 0xFE, 0x5E, 0xFE, 0xC4, 0xFF, 0x17, 0xFF, 0x6A, + 0xFF, 0xBD, 0x42, 0x6B, 0x2E, 0xFE, 0x27, 0xFD, 0xB7, 0xC1, 0x14, 0x82, 0x2E, 0xFD, 0xB0, 0x25, + 0x82, 0x84, 0x9B, 0xBA, 0xBC, 0xF3, 0xFA, 0xFA, 0xFA, 0xFA, 0x21, 0x87, 0xEF, 0xA0, 0x16, 0x43, + 0x21, 0x79, 0xFD, 0x21, 0x61, 0xFD, 0x21, 0x77, 0xFD, 0x21, 0x64, 0xFD, 0x21, 0x61, 0xFD, 0x45, + 0x6E, 0x2E, 0x7A, 0x64, 0x6F, 0xFD, 0xFA, 0xFD, 0x8A, 0xFD, 0x92, 0xFE, 0x64, 0xFF, 0xFD, 0xC1, + 0x15, 0x62, 0x2E, 0xFD, 0x7A, 0xA0, 0x16, 0x22, 0x21, 0x7A, 0xFD, 0x21, 0x75, 0xFD, 0x21, 0x61, + 0xFD, 0x21, 0x68, 0xFD, 0x21, 0x6B, 0xFD, 0x42, 0x2E, 0x6F, 0xFD, 0x62, 0xFF, 0xFD, 0x41, 0x68, + 0xFE, 0x35, 0x21, 0x74, 0xFC, 0xA0, 0x15, 0x93, 0x21, 0x7A, 0xFD, 0x21, 0x73, 0xFD, 0x41, 0x64, + 0xD9, 0xF0, 0x21, 0x6E, 0xFC, 0x21, 0x65, 0xFD, 0x21, 0x68, 0xFD, 0x23, 0x65, 0x66, 0x6B, 0xE7, + 0xF0, 0xFD, 0xA0, 0x04, 0xD3, 0x21, 0x75, 0xFD, 0x21, 0x6B, 0xFD, 0x21, 0x6F, 0xFD, 0xA0, 0x0B, + 0xB2, 0x21, 0x70, 0xFD, 0x21, 0x6F, 0xFD, 0x21, 0x6B, 0xFD, 0x21, 0x7A, 0xFD, 0xA0, 0x15, 0xC4, + 0xA1, 0x01, 0x22, 0x6D, 0xFD, 0x21, 0x73, 0xFB, 0x21, 0x65, 0xFD, 0x21, 0x6E, 0xFD, 0xA0, 0x16, + 0x02, 0x21, 0x6D, 0xFD, 0x21, 0x61, 0xFD, 0x21, 0x68, 0xFD, 0x21, 0x67, 0xFD, 0x21, 0x6E, 0xFD, + 0x21, 0x69, 0xFD, 0x21, 0x6D, 0xFD, 0x24, 0x6E, 0x73, 0x7A, 0x72, 0xC5, 0xD4, 0xE5, 0xFD, 0x41, + 0x61, 0xDB, 0x01, 0x21, 0x6D, 0xFC, 0x21, 0x73, 0xFD, 0x21, 0x65, 0xB5, 0x21, 0x6D, 0xFD, 0xA0, + 0x13, 0x02, 0xA1, 0x00, 0x71, 0x6D, 0xFD, 0x21, 0x73, 0xFB, 0x21, 0x73, 0xFD, 0x21, 0x65, 0xFD, + 0x21, 0x6E, 0xFD, 0x22, 0x7A, 0x69, 0xE9, 0xFD, 0xA0, 0x16, 0x72, 0x21, 0x6E, 0xFD, 0x21, 0x61, + 0xFD, 0x21, 0x70, 0xFD, 0x21, 0x7A, 0xFD, 0x21, 0x73, 0xFD, 0x22, 0x73, 0x6B, 0xE9, 0xFD, 0x5A, + 0xC5, 0xC4, 0x63, 0x64, 0x66, 0x67, 0x6B, 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x7A, 0x72, 0x62, 0x2E, + 0x68, 0x6A, 0x6C, 0x76, 0x77, 0x78, 0x65, 0x69, 0x6F, 0x75, 0xFF, 0x00, 0xFF, 0x0B, 0xFE, 0xFA, + 0xFE, 0xFA, 0xFE, 0xFA, 0xFE, 0xFA, 0xFE, 0xFA, 0xFE, 0xFA, 0xFE, 0xFA, 0xFE, 0xFA, 0xFE, 0xFA, + 0xFE, 0xFA, 0xFE, 0xFA, 0xFF, 0x20, 0xFF, 0x30, 0xFC, 0xAA, 0xFC, 0xB2, 0xFC, 0xB2, 0xFF, 0x48, + 0xFC, 0xB2, 0xFC, 0xB2, 0xFC, 0xB2, 0xFF, 0x6C, 0xFF, 0xB7, 0xFF, 0xC7, 0xFF, 0xFB, 0x45, 0x84, + 0x9B, 0xBA, 0xBC, 0x82, 0xFE, 0xAB, 0xFE, 0xAB, 0xFE, 0xAB, 0xFE, 0xAB, 0xFC, 0x63, 0xA0, 0x14, + 0x62, 0x21, 0x87, 0xFD, 0xC1, 0x00, 0xF1, 0x2E, 0xFC, 0x45, 0x25, 0x84, 0x9B, 0xBA, 0xBC, 0x82, + 0xF4, 0xF4, 0xF4, 0xF4, 0xFA, 0xC1, 0x00, 0xF1, 0x7A, 0xFC, 0x3C, 0xA0, 0x16, 0x91, 0x21, 0x74, + 0xFD, 0x21, 0x73, 0xFD, 0xD4, 0x02, 0x31, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x6B, 0x6D, + 0x6E, 0x70, 0x73, 0x74, 0x7A, 0x2E, 0x72, 0x77, 0x6A, 0x6C, 0x75, 0xFF, 0xDD, 0xFF, 0xE6, 0xFF, + 0xDA, 0xFF, 0xDA, 0xFF, 0xDA, 0xFF, 0xDA, 0xFF, 0xDA, 0xFF, 0xDA, 0xFF, 0xDA, 0xFF, 0xDA, 0xFF, + 0xDA, 0xFF, 0xDA, 0xFF, 0xDA, 0xFF, 0xDA, 0xFC, 0x25, 0xFF, 0xF1, 0xFF, 0xE0, 0xFC, 0xFF, 0xFC, + 0xFF, 0xFF, 0xFD, 0x44, 0x84, 0x9B, 0xBA, 0xBC, 0xFF, 0x9B, 0xFF, 0x9B, 0xFF, 0x9B, 0xFF, 0x9B, + 0xD0, 0x02, 0x31, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x73, + 0x74, 0x7A, 0x2E, 0xFF, 0x91, 0xFF, 0xF3, 0xFF, 0x8E, 0xFF, 0x8E, 0xFF, 0x8E, 0xFF, 0x8E, 0xFF, + 0x8E, 0xFF, 0x8E, 0xFF, 0x8E, 0xFF, 0x8E, 0xFF, 0x8E, 0xFF, 0x8E, 0xFF, 0x8E, 0xFB, 0xDC, 0xFF, + 0x8E, 0xFB, 0xD9, 0x41, 0x6C, 0xFE, 0x32, 0x21, 0x6C, 0xFC, 0x21, 0x65, 0xFD, 0x21, 0x77, 0xFD, + 0x21, 0x64, 0xFD, 0x21, 0x6C, 0xFD, 0xA0, 0x16, 0xA2, 0x21, 0x6E, 0xFD, 0x21, 0x6F, 0xFD, 0x21, + 0x7A, 0xFD, 0x21, 0x72, 0xFD, 0x58, 0xC4, 0xC5, 0x62, 0x64, 0x66, 0x67, 0x6B, 0x6C, 0x6D, 0x6E, + 0x70, 0x73, 0x74, 0x68, 0x7A, 0x63, 0x2E, 0x6A, 0x72, 0x76, 0x77, 0x78, 0x61, 0x75, 0xFD, 0xE5, + 0xFF, 0x29, 0xFD, 0xD4, 0xFD, 0xD4, 0xFD, 0xD4, 0xFD, 0xD4, 0xFD, 0xD4, 0xFD, 0xD4, 0xFD, 0xD4, + 0xFD, 0xD4, 0xFD, 0xD4, 0xFD, 0xD4, 0xFD, 0xD4, 0xFF, 0x5F, 0xFF, 0xAB, 0xFE, 0x0A, 0xFB, 0x84, + 0xFB, 0x8C, 0xFB, 0x8C, 0xFB, 0x8C, 0xFB, 0x8C, 0xFB, 0x8C, 0xFF, 0xEE, 0xFF, 0xFD, 0x41, 0x7A, + 0xFB, 0xAB, 0x43, 0x62, 0x73, 0x2E, 0xFB, 0xA7, 0xFF, 0xFC, 0xFB, 0x37, 0xA0, 0x14, 0xA2, 0x21, + 0x87, 0xFD, 0x24, 0x84, 0x9B, 0xBA, 0xBC, 0xFA, 0xFA, 0xFA, 0xFA, 0xCF, 0x02, 0x31, 0xC4, 0xC5, + 0x62, 0x63, 0x64, 0x66, 0x67, 0x6B, 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x7A, 0x2E, 0xFF, 0xF4, 0xFF, + 0xF7, 0xFF, 0xF1, 0xFF, 0xF1, 0xFF, 0xF1, 0xFF, 0xF1, 0xFF, 0xF1, 0xFF, 0xF1, 0xFF, 0xF1, 0xFF, + 0xF1, 0xFF, 0xF1, 0xFF, 0xF1, 0xFF, 0xF1, 0xFF, 0xF1, 0xFB, 0x1E, 0x45, 0x84, 0x9B, 0xBA, 0xBC, + 0x82, 0xFF, 0xC1, 0xFF, 0xC1, 0xFF, 0xC1, 0xFF, 0xC1, 0xE7, 0xF3, 0x42, 0x62, 0x6D, 0xDF, 0xFD, + 0xDF, 0xFD, 0x21, 0x7A, 0xF9, 0xD4, 0x02, 0x31, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x6B, + 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x7A, 0x2E, 0x6A, 0x6C, 0x72, 0x77, 0x65, 0xFF, 0xAA, 0xFF, 0xE6, + 0xFF, 0xA7, 0xFF, 0xA7, 0xFF, 0xA7, 0xFF, 0xA7, 0xFF, 0xA7, 0xFF, 0xA7, 0xFF, 0xA7, 0xFF, 0xA7, + 0xFF, 0xA7, 0xFF, 0xA7, 0xFF, 0xA7, 0xFF, 0xA7, 0xFA, 0xD4, 0xE7, 0xD9, 0xE7, 0xD9, 0xE7, 0xD9, + 0xE7, 0xD9, 0xFF, 0xFD, 0x45, 0x82, 0xBA, 0xBC, 0x84, 0x9B, 0xFF, 0x5E, 0xFF, 0x77, 0xFF, 0xC1, + 0xFC, 0xE5, 0xFC, 0xE5, 0xA0, 0x14, 0xC2, 0x21, 0x77, 0xFD, 0x21, 0x6F, 0xFD, 0xC2, 0x14, 0x82, + 0x69, 0x2E, 0xFF, 0xFD, 0xFA, 0x7C, 0x42, 0x2E, 0x77, 0xFA, 0x73, 0xE7, 0x78, 0x43, 0x6E, 0x2E, + 0x7A, 0xFA, 0xDC, 0xFA, 0x6C, 0xFF, 0xF9, 0xD0, 0x02, 0x31, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, + 0x67, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x7A, 0x2E, 0xFE, 0x1A, 0xFE, 0x7C, 0xFE, 0x17, + 0xFE, 0x17, 0xFE, 0x17, 0xFE, 0x17, 0xFE, 0x17, 0xFE, 0x17, 0xFE, 0x17, 0xFE, 0x17, 0xFE, 0x17, + 0xFE, 0x17, 0xFE, 0x17, 0xFE, 0x17, 0xFE, 0x17, 0xFA, 0x62, 0x41, 0x64, 0xDF, 0x60, 0x21, 0x6E, + 0xFC, 0x21, 0x61, 0xFD, 0x21, 0x6C, 0xFD, 0x21, 0x68, 0xFD, 0x21, 0x63, 0xFD, 0x21, 0x73, 0xFD, + 0x21, 0x74, 0xFD, 0x21, 0x75, 0xFD, 0x41, 0x74, 0xFC, 0xE8, 0x21, 0x73, 0xFC, 0x21, 0x61, 0xFD, + 0x21, 0x70, 0xFD, 0x21, 0x7A, 0xFD, 0x21, 0x73, 0xFD, 0x58, 0xC5, 0xC4, 0x62, 0x63, 0x66, 0x67, + 0x6B, 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x72, 0x7A, 0x64, 0x2E, 0x68, 0x6A, 0x6C, 0x76, 0x77, 0x78, + 0x65, 0x75, 0xFF, 0x6B, 0xFC, 0x61, 0xFC, 0x50, 0xFC, 0x50, 0xFC, 0x50, 0xFC, 0x50, 0xFC, 0x50, + 0xFC, 0x50, 0xFF, 0x84, 0xFC, 0x50, 0xFC, 0x50, 0xFC, 0x50, 0xFF, 0x94, 0xFF, 0x9E, 0xFC, 0x86, + 0xFA, 0x00, 0xFA, 0x08, 0xFA, 0x08, 0xFA, 0x08, 0xFA, 0x08, 0xFA, 0x08, 0xFA, 0x08, 0xFF, 0xEA, + 0xFF, 0xFD, 0x41, 0x87, 0xF9, 0xBF, 0x45, 0x82, 0x84, 0x9B, 0xBA, 0xBC, 0xF9, 0xBB, 0xF9, 0xBB, + 0xF9, 0xBB, 0xF9, 0xBB, 0xF9, 0xBB, 0x41, 0x6D, 0xD7, 0xBA, 0x21, 0x72, 0xFC, 0x21, 0x61, 0xFD, + 0x41, 0x6E, 0xFC, 0x6E, 0x21, 0x69, 0xFC, 0x21, 0x62, 0xFD, 0x22, 0x68, 0x7A, 0xF3, 0xFD, 0x21, + 0x73, 0xFB, 0xA0, 0x16, 0xC2, 0x21, 0x63, 0xFD, 0x21, 0x61, 0xFD, 0x21, 0x7A, 0xFD, 0x41, 0x72, + 0xFC, 0x07, 0x21, 0x6F, 0xFC, 0x21, 0x6C, 0xFD, 0x21, 0x6B, 0xFD, 0xA0, 0x16, 0xE3, 0x21, 0x74, + 0xFD, 0x21, 0x6F, 0xFD, 0x21, 0x7A, 0xFD, 0x21, 0x61, 0xFD, 0x21, 0x66, 0xFD, 0x44, 0x6B, 0x72, + 0x6C, 0x73, 0xD1, 0x98, 0xFF, 0xDE, 0xFF, 0xEB, 0xFF, 0xFD, 0x58, 0x63, 0x6B, 0x6D, 0x6E, 0x66, + 0x2E, 0xC4, 0xC5, 0x62, 0x64, 0x67, 0x68, 0x6A, 0x6C, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, + 0x7A, 0x69, 0x6F, 0xFB, 0x9F, 0xFB, 0x9F, 0xFB, 0x9F, 0xFB, 0x9F, 0xFB, 0xD5, 0xF9, 0x4F, 0xFF, + 0x98, 0xFF, 0x9C, 0xF9, 0x57, 0xF9, 0x57, 0xF9, 0x57, 0xF9, 0x57, 0xF9, 0x57, 0xF9, 0x57, 0xF9, + 0x57, 0xF9, 0x57, 0xF9, 0x57, 0xF9, 0x57, 0xF9, 0x57, 0xF9, 0x57, 0xF9, 0x57, 0xF9, 0x57, 0xFF, + 0xC5, 0xFF, 0xF3, 0x42, 0x62, 0x2E, 0xF9, 0x76, 0xF9, 0x06, 0x45, 0x82, 0x84, 0x9B, 0xBA, 0xBC, + 0xFF, 0xF9, 0xFB, 0x4F, 0xFB, 0x4F, 0xFB, 0x4F, 0xFB, 0x4F, 0xA0, 0x17, 0x12, 0x21, 0x6F, 0xFD, + 0x21, 0x6C, 0xFD, 0x21, 0x69, 0xFD, 0x21, 0x64, 0xFD, 0x21, 0x6E, 0xFD, 0x41, 0x74, 0xF4, 0x52, + 0x43, 0x2E, 0x61, 0x6F, 0xF8, 0xD9, 0xFF, 0xF9, 0xFF, 0xFC, 0x41, 0x74, 0xE5, 0xAD, 0x21, 0x65, + 0xFC, 0x41, 0x61, 0xD6, 0xC0, 0x21, 0x74, 0xFC, 0x21, 0x70, 0xFD, 0x22, 0x67, 0x6F, 0xF3, 0xFD, + 0x21, 0x64, 0xFB, 0xC1, 0x02, 0x02, 0x7A, 0xD1, 0x1E, 0x21, 0x73, 0xFA, 0x21, 0x66, 0xFD, 0x21, + 0x6C, 0xFD, 0x58, 0xC5, 0xC4, 0x62, 0x63, 0x64, 0x66, 0x6B, 0x6D, 0x70, 0x73, 0x74, 0x7A, 0x67, + 0x2E, 0x68, 0x6A, 0x6C, 0x6E, 0x72, 0x76, 0x77, 0x78, 0x61, 0x6F, 0xFF, 0xA8, 0xFB, 0x08, 0xFA, + 0xF7, 0xFA, 0xF7, 0xFA, 0xF7, 0xFA, 0xF7, 0xFA, 0xF7, 0xFA, 0xF7, 0xFA, 0xF7, 0xFA, 0xF7, 0xFA, + 0xF7, 0xFA, 0xF7, 0xFB, 0x2D, 0xF8, 0xA7, 0xF8, 0xAF, 0xF8, 0xAF, 0xF8, 0xAF, 0xF8, 0xAF, 0xFF, + 0xCE, 0xF8, 0xAF, 0xF8, 0xAF, 0xF8, 0xAF, 0xFF, 0xEE, 0xFF, 0xFD, 0x45, 0x82, 0x84, 0x9B, 0xBA, + 0xBC, 0xFA, 0xAE, 0xFA, 0xAE, 0xFA, 0xAE, 0xFA, 0xAE, 0xFA, 0xAE, 0x41, 0x7A, 0xFB, 0x26, 0x21, + 0x73, 0xFC, 0xA0, 0x17, 0x32, 0x21, 0x77, 0xFD, 0x21, 0x7A, 0xFD, 0x41, 0x79, 0xD6, 0x55, 0x21, + 0x65, 0xFC, 0x21, 0x6C, 0xFD, 0x22, 0x63, 0x78, 0xF3, 0xFD, 0x58, 0xC4, 0xC5, 0x62, 0x63, 0x64, + 0x66, 0x67, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0x68, 0x2E, 0x76, + 0x78, 0x69, 0x75, 0xFA, 0x90, 0xFF, 0xD1, 0xFA, 0x7F, 0xFA, 0x7F, 0xFA, 0x7F, 0xFA, 0x7F, 0xFA, + 0x7F, 0xFA, 0x7F, 0xFA, 0x7F, 0xFA, 0x7F, 0xFA, 0x7F, 0xFA, 0x7F, 0xFA, 0x7F, 0xFA, 0x7F, 0xFA, + 0x7F, 0xFA, 0x7F, 0xFA, 0x7F, 0xFA, 0x7F, 0xFA, 0xB5, 0xF8, 0x2F, 0xF8, 0x37, 0xF8, 0x37, 0xFF, + 0xE5, 0xFF, 0xFB, 0xA0, 0x05, 0x42, 0x21, 0x82, 0xFD, 0xC3, 0x14, 0x82, 0x2E, 0xC5, 0x72, 0xF7, + 0xE0, 0xFF, 0xFD, 0xFF, 0xFA, 0xA0, 0x17, 0x53, 0x22, 0x62, 0x6D, 0xFD, 0xFD, 0x21, 0x7A, 0xFB, + 0x21, 0x7A, 0xFD, 0x57, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6B, 0x6C, 0x6D, 0x6E, + 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0x6A, 0x2E, 0x76, 0x78, 0x61, 0xFA, 0x27, 0xFF, 0x68, 0xFA, + 0x16, 0xFA, 0x16, 0xFA, 0x16, 0xFA, 0x16, 0xFA, 0x16, 0xFA, 0x16, 0xFA, 0x16, 0xFA, 0x16, 0xFA, + 0x16, 0xFA, 0x16, 0xFA, 0x16, 0xFA, 0x16, 0xFA, 0x16, 0xFF, 0xE6, 0xFA, 0x16, 0xFA, 0x16, 0xFA, + 0x4C, 0xF7, 0xC6, 0xF7, 0xCE, 0xF7, 0xCE, 0xFF, 0xFD, 0xA0, 0x14, 0xE3, 0xA1, 0x14, 0x82, 0x74, + 0xFD, 0xC3, 0x14, 0x82, 0x7A, 0x2E, 0x74, 0xFF, 0xFB, 0xF7, 0x78, 0xF7, 0x80, 0x41, 0x6E, 0xFE, + 0x7D, 0x21, 0x6F, 0xFC, 0x21, 0x72, 0xFD, 0x41, 0x65, 0xFE, 0x73, 0x21, 0x68, 0xFC, 0x21, 0x75, + 0xFD, 0x22, 0x6B, 0x72, 0xF3, 0xFD, 0x21, 0x73, 0xFB, 0x21, 0x6C, 0xFD, 0x21, 0x72, 0xFD, 0x41, + 0x66, 0xE4, 0x4F, 0x21, 0x66, 0xFC, 0x21, 0x6F, 0xFD, 0x21, 0x68, 0xFD, 0x21, 0x68, 0xFD, 0x21, + 0x63, 0xFD, 0x21, 0x72, 0xFD, 0x41, 0x6D, 0xE6, 0x76, 0x21, 0x73, 0xFC, 0x21, 0x65, 0xFD, 0x21, + 0x72, 0xFD, 0x21, 0x67, 0xFD, 0x21, 0x6E, 0xFD, 0x59, 0xC5, 0xC4, 0x62, 0x63, 0x64, 0x66, 0x67, + 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x7A, 0x6B, 0x2E, 0x68, 0x6A, 0x6C, 0x72, 0x76, 0x77, 0x78, 0x61, + 0x69, 0x6F, 0xFE, 0x22, 0xF9, 0x82, 0xF9, 0x71, 0xF9, 0x71, 0xF9, 0x71, 0xF9, 0x71, 0xF9, 0x71, + 0xF9, 0x71, 0xF9, 0x71, 0xF9, 0x71, 0xFF, 0xA9, 0xF9, 0x71, 0xF9, 0x71, 0xF9, 0xA7, 0xF7, 0x21, + 0xF7, 0x29, 0xF7, 0x29, 0xF7, 0x29, 0xF7, 0x29, 0xF7, 0x29, 0xF7, 0x29, 0xF7, 0x29, 0xFF, 0xD4, + 0xFF, 0xEA, 0xFF, 0xFD, 0xA0, 0x14, 0xB1, 0x21, 0x77, 0xFD, 0x21, 0x64, 0xFD, 0x41, 0x66, 0xF9, + 0xEC, 0x21, 0x66, 0xFC, 0x21, 0x61, 0xFD, 0x21, 0x77, 0xFD, 0x21, 0x74, 0xFD, 0x41, 0x72, 0xFE, + 0x75, 0x21, 0x65, 0xFC, 0x21, 0x66, 0xFD, 0x21, 0x73, 0xFD, 0x22, 0x66, 0x6B, 0xF0, 0xFD, 0x41, + 0x6F, 0xF7, 0x84, 0x59, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6D, 0x6E, + 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0x6C, 0x2E, 0x76, 0x78, 0x65, 0x75, 0x79, 0xF9, 0x07, 0xFE, + 0x48, 0xF8, 0xF6, 0xF8, 0xF6, 0xF8, 0xF6, 0xF8, 0xF6, 0xF8, 0xF6, 0xF8, 0xF6, 0xF8, 0xF6, 0xF8, + 0xF6, 0xF8, 0xF6, 0xF8, 0xF6, 0xF8, 0xF6, 0xF8, 0xF6, 0xF8, 0xF6, 0xF8, 0xF6, 0xF8, 0xF6, 0xF8, + 0xF6, 0xF9, 0x2C, 0xF6, 0xA6, 0xF6, 0xAE, 0xF6, 0xAE, 0xFF, 0xD7, 0xFF, 0xF7, 0xFF, 0xFC, 0xA0, + 0x15, 0x13, 0xC2, 0x14, 0x82, 0x6E, 0x2E, 0xFF, 0xFD, 0xF6, 0x57, 0x41, 0x74, 0xFB, 0xC9, 0x41, + 0x6A, 0xFB, 0xC5, 0x22, 0x73, 0x7A, 0xF8, 0xFC, 0xC2, 0x14, 0x82, 0x65, 0x2E, 0xFF, 0xFB, 0xF6, + 0x41, 0x41, 0x6E, 0xFE, 0xB8, 0xC3, 0x14, 0x82, 0x6B, 0x2E, 0x74, 0xFF, 0xFC, 0xF6, 0x34, 0xF6, + 0x3C, 0x41, 0x82, 0xFC, 0xA1, 0x43, 0xC5, 0x6C, 0x6E, 0xFF, 0xFC, 0xFC, 0x9D, 0xFC, 0x9D, 0x21, + 0x7A, 0xF6, 0x21, 0x72, 0xFD, 0x41, 0x7A, 0xFD, 0xCD, 0x21, 0x73, 0xFC, 0x21, 0x61, 0xFD, 0x21, + 0x6D, 0xFD, 0x21, 0x7A, 0xFD, 0xA0, 0x17, 0x82, 0x21, 0x82, 0xFD, 0x22, 0xC5, 0x69, 0xFD, 0xFA, + 0x21, 0x7A, 0xFB, 0x21, 0x72, 0xFD, 0x22, 0x73, 0x65, 0xEC, 0xFD, 0x41, 0x6C, 0xD3, 0x22, 0x21, + 0x61, 0xFC, 0x21, 0x65, 0xFD, 0x21, 0x72, 0xFD, 0x21, 0x74, 0xFD, 0x41, 0x6B, 0xE2, 0xC5, 0x21, + 0x69, 0xFC, 0x21, 0x61, 0xFD, 0x22, 0x6E, 0x7A, 0xF3, 0xFD, 0xA0, 0x17, 0xA3, 0x21, 0x6C, 0xFD, + 0x21, 0x68, 0xFD, 0x21, 0x63, 0xFD, 0x21, 0x69, 0xFD, 0x21, 0x73, 0xFD, 0x21, 0x61, 0xFD, 0x21, + 0x7A, 0xFD, 0x21, 0x72, 0xFD, 0x5A, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, + 0x6C, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0x6D, 0x2E, 0x76, 0x78, 0x61, 0x69, 0x6F, 0x75, + 0xF8, 0x15, 0xFD, 0x56, 0xF8, 0x04, 0xF8, 0x04, 0xF8, 0x04, 0xF8, 0x04, 0xF8, 0x04, 0xF8, 0x04, + 0xF8, 0x04, 0xFF, 0x5D, 0xF8, 0x04, 0xFF, 0x73, 0xF8, 0x04, 0xF8, 0x04, 0xFF, 0x80, 0xF8, 0x04, + 0xF8, 0x04, 0xF8, 0x04, 0xF8, 0x3A, 0xF5, 0xB4, 0xF5, 0xBC, 0xF5, 0xBC, 0xFF, 0x9D, 0xFF, 0xC1, + 0xFF, 0xE0, 0xFF, 0xFD, 0xC2, 0x14, 0x82, 0x6E, 0x2E, 0xF5, 0xD5, 0xF5, 0x65, 0x41, 0x73, 0xEF, + 0xFD, 0x21, 0x77, 0xFC, 0x21, 0x6F, 0xFD, 0x21, 0x6B, 0xFD, 0x21, 0x82, 0xFD, 0x41, 0x76, 0xEF, + 0x40, 0x22, 0xC5, 0x72, 0xF9, 0xFC, 0x57, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, + 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x74, 0x77, 0x7A, 0x6E, 0x2E, 0x76, 0x78, 0x61, 0xF7, 0xA4, + 0xFC, 0xE5, 0xF7, 0x93, 0xF7, 0x93, 0xF7, 0x93, 0xF7, 0x93, 0xF7, 0x93, 0xF7, 0x93, 0xF7, 0x93, + 0xF7, 0x93, 0xF7, 0x93, 0xF7, 0x93, 0xF7, 0x93, 0xF7, 0x93, 0xF7, 0x93, 0xFF, 0xDE, 0xF7, 0x93, + 0xF7, 0x93, 0xF7, 0xC9, 0xF5, 0x43, 0xF5, 0x4B, 0xF5, 0x4B, 0xFF, 0xFB, 0x41, 0x75, 0xFA, 0x78, + 0xC2, 0x14, 0x82, 0x65, 0x2E, 0xFF, 0xFC, 0xF4, 0xF9, 0xA0, 0x14, 0x82, 0xC2, 0x14, 0x82, 0x7A, + 0x2E, 0xFF, 0xFD, 0xF4, 0xED, 0x42, 0x6E, 0x2E, 0xF5, 0x54, 0xF4, 0xE4, 0x41, 0x6C, 0xF5, 0xB7, + 0x21, 0x61, 0xFC, 0x21, 0x68, 0xFD, 0x41, 0x61, 0xF8, 0x12, 0x21, 0x70, 0xFC, 0x21, 0x7A, 0xFD, + 0x21, 0x73, 0xFD, 0x44, 0x2E, 0x7A, 0x63, 0x65, 0xF4, 0xC6, 0xF4, 0xCE, 0xFF, 0xF0, 0xFF, 0xFD, + 0x41, 0x72, 0xF7, 0x82, 0x21, 0x65, 0xFC, 0x21, 0x6D, 0xFD, 0x21, 0x61, 0xFD, 0x42, 0x61, 0x68, + 0xD2, 0xC6, 0xD2, 0xC3, 0x21, 0x63, 0xF9, 0x22, 0x6E, 0x73, 0xF3, 0xFD, 0x41, 0x69, 0xCD, 0x37, + 0x21, 0x6E, 0xFC, 0x21, 0x64, 0xFD, 0x21, 0x75, 0xFD, 0x21, 0x82, 0xFD, 0x41, 0x7A, 0xD2, 0x7C, + 0x21, 0x72, 0xFC, 0x21, 0x70, 0xFD, 0x21, 0x65, 0xFD, 0x21, 0x69, 0xFD, 0x21, 0x6E, 0xFD, 0x42, + 0x85, 0x99, 0xE1, 0x58, 0xE1, 0x58, 0x42, 0xC4, 0x69, 0xFF, 0xF9, 0xE1, 0x51, 0x21, 0x6E, 0xF9, + 0xA0, 0x17, 0xD4, 0x21, 0x68, 0xFD, 0x21, 0x74, 0xFD, 0x21, 0x75, 0xFD, 0x21, 0x6F, 0xFD, 0x21, + 0x6D, 0xFD, 0x41, 0x64, 0xEE, 0xF8, 0x21, 0x6E, 0xFC, 0x21, 0x61, 0xFD, 0x22, 0x73, 0x6C, 0xF3, + 0xFD, 0x21, 0x74, 0xFB, 0x41, 0x65, 0xD2, 0x3D, 0x21, 0x72, 0xFC, 0x42, 0x65, 0x75, 0xD4, 0xF0, + 0xFF, 0xFD, 0x21, 0x69, 0xF9, 0x41, 0x69, 0xCD, 0xBE, 0x21, 0x6E, 0xFC, 0x21, 0x64, 0xFD, 0x21, + 0x65, 0xFD, 0x21, 0x7A, 0xFD, 0x21, 0x73, 0xFD, 0x46, 0xC5, 0x64, 0x6D, 0x72, 0x6C, 0x77, 0xFF, + 0x91, 0xFF, 0xA4, 0xFF, 0xB5, 0xFF, 0xD9, 0xFF, 0xEA, 0xFF, 0xFD, 0x58, 0xC4, 0xC5, 0x62, 0x63, + 0x64, 0x66, 0x67, 0x6B, 0x6D, 0x6E, 0x73, 0x74, 0x7A, 0x6C, 0x70, 0x2E, 0x68, 0x6A, 0x72, 0x76, + 0x77, 0x78, 0x61, 0x6F, 0xF6, 0x6F, 0xF7, 0xB3, 0xF6, 0x5E, 0xF6, 0x5E, 0xF6, 0x5E, 0xF6, 0x5E, + 0xF6, 0x5E, 0xF6, 0x5E, 0xF6, 0x5E, 0xFF, 0x15, 0xFF, 0x21, 0xF6, 0x5E, 0xF6, 0x5E, 0xFF, 0x2A, + 0xF6, 0x94, 0xF4, 0x0E, 0xF4, 0x16, 0xF4, 0x16, 0xFF, 0x48, 0xF4, 0x16, 0xF4, 0x16, 0xF4, 0x16, + 0xFF, 0x6C, 0xFF, 0xED, 0xC2, 0x14, 0x82, 0x2E, 0x7A, 0xF3, 0xC5, 0xF3, 0xCD, 0x45, 0x82, 0x84, + 0x9B, 0xBA, 0xBC, 0xF3, 0xBF, 0xF7, 0x71, 0xF7, 0x71, 0xF7, 0x71, 0xF7, 0x71, 0xD3, 0x02, 0x31, + 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, + 0x74, 0x77, 0x2E, 0xF7, 0x64, 0xFF, 0xF0, 0xF7, 0x61, 0xF7, 0x61, 0xF7, 0x61, 0xF7, 0x61, 0xF7, + 0x61, 0xF7, 0x61, 0xF7, 0x61, 0xF7, 0x61, 0xF7, 0x61, 0xF7, 0x61, 0xF7, 0x61, 0xF7, 0x61, 0xF7, + 0x61, 0xF7, 0x61, 0xF7, 0x61, 0xF7, 0x61, 0xF3, 0xAC, 0x41, 0x6E, 0xF6, 0x1C, 0x21, 0x65, 0xFC, + 0x21, 0x67, 0xFD, 0x21, 0x74, 0xFD, 0x21, 0x6E, 0xFD, 0x41, 0x7A, 0xD1, 0x77, 0x21, 0x63, 0xFC, + 0x21, 0x6F, 0xFD, 0x21, 0x72, 0xFD, 0xA0, 0x18, 0x14, 0x21, 0x6B, 0xFD, 0x21, 0x63, 0xFD, 0x21, + 0x6F, 0xFD, 0x21, 0x74, 0xFD, 0x23, 0x65, 0x6B, 0x73, 0xE1, 0xEE, 0xFD, 0x57, 0xC4, 0xC5, 0x62, + 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x77, 0x7A, 0x72, + 0x2E, 0x76, 0x78, 0x6F, 0xF5, 0x9E, 0xFA, 0xDF, 0xF5, 0x8D, 0xF5, 0x8D, 0xF5, 0x8D, 0xF5, 0x8D, + 0xF5, 0x8D, 0xF5, 0x8D, 0xF5, 0x8D, 0xF5, 0x8D, 0xF5, 0x8D, 0xF5, 0x8D, 0xF5, 0x8D, 0xF5, 0x8D, + 0xFF, 0x78, 0xF5, 0x8D, 0xF5, 0x8D, 0xFF, 0x91, 0xF5, 0xC3, 0xF3, 0x3D, 0xF3, 0x45, 0xF3, 0x45, + 0xFF, 0xF9, 0x45, 0x82, 0xBA, 0xBC, 0x84, 0x9B, 0xF9, 0xF1, 0xF5, 0x47, 0xF5, 0x47, 0xF2, 0xFF, + 0xF2, 0xFF, 0x42, 0x2E, 0x7A, 0xF2, 0xE7, 0xF2, 0xEF, 0x46, 0x6B, 0x6E, 0x73, 0x2E, 0x72, 0x77, + 0xF3, 0x50, 0xF3, 0x50, 0xF7, 0xA5, 0xF2, 0xE0, 0xFF, 0xF9, 0xF2, 0xE8, 0x41, 0x9B, 0xF6, 0x82, + 0x42, 0x2E, 0x62, 0xF2, 0xC9, 0xF2, 0xD1, 0xA1, 0x14, 0x62, 0x7A, 0xF9, 0xC1, 0x14, 0x62, 0x6E, + 0xF3, 0x2D, 0x41, 0x6D, 0xF9, 0xC8, 0x21, 0x6C, 0xFC, 0x21, 0x6F, 0xFD, 0x21, 0x68, 0xFD, 0x21, + 0x6B, 0xFD, 0xC3, 0x14, 0x62, 0x2E, 0x72, 0x6F, 0xF2, 0xA7, 0xF2, 0xAF, 0xFF, 0xFD, 0xA0, 0x18, + 0x52, 0x21, 0x79, 0xFD, 0x21, 0x82, 0xFD, 0x21, 0xC5, 0xFD, 0x21, 0x7A, 0xFD, 0x21, 0x73, 0xFD, + 0x41, 0x67, 0xF5, 0x15, 0x21, 0x6E, 0xFC, 0x21, 0x6F, 0xFD, 0x21, 0x6C, 0xFD, 0x41, 0x87, 0xCA, + 0xC6, 0x21, 0xC4, 0xFC, 0x21, 0x9B, 0xFD, 0x22, 0x7A, 0xC5, 0xF3, 0xFD, 0x41, 0x73, 0xF9, 0x7E, + 0x21, 0x61, 0xFC, 0x21, 0x77, 0xFD, 0x21, 0x6B, 0xFD, 0x21, 0x6E, 0xFD, 0xD1, 0x02, 0x31, 0xC4, + 0xC5, 0x63, 0x66, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x77, 0x7A, 0x2E, 0x61, 0x65, 0x79, + 0xF6, 0x15, 0xFF, 0x90, 0xFF, 0x9B, 0xF6, 0x12, 0xF2, 0x60, 0xFF, 0xA0, 0xF6, 0x12, 0xF2, 0x60, + 0xF6, 0x12, 0xF6, 0x12, 0xFF, 0xB6, 0xF6, 0x12, 0xF6, 0x12, 0xF2, 0x5D, 0xFF, 0xD1, 0xFF, 0xEB, + 0xFF, 0xFD, 0x42, 0x2E, 0x68, 0xF2, 0x27, 0xF2, 0x2F, 0x41, 0x7A, 0xF2, 0x28, 0x41, 0x72, 0xFC, + 0x18, 0x21, 0x65, 0xFC, 0x21, 0x6E, 0xFD, 0x21, 0x6F, 0xFD, 0x21, 0x7A, 0xFD, 0x21, 0x72, 0xFD, + 0x43, 0x2E, 0x72, 0x6F, 0xF2, 0x09, 0xFF, 0xE9, 0xFF, 0xFD, 0x42, 0x2E, 0x72, 0xF1, 0xFF, 0xF2, + 0xD9, 0x41, 0x65, 0xD0, 0x0F, 0x21, 0x6C, 0xFC, 0x21, 0x74, 0xFD, 0x41, 0x7A, 0xCF, 0xE6, 0x21, + 0x69, 0xFC, 0x21, 0x77, 0xFD, 0x41, 0x74, 0xCF, 0xFB, 0x21, 0x70, 0xFC, 0x21, 0x6F, 0xFD, 0x41, + 0x6D, 0xCE, 0x7F, 0x21, 0x65, 0xFC, 0x21, 0x74, 0xFD, 0x22, 0x6E, 0x73, 0xF3, 0xFD, 0x59, 0xC5, + 0x62, 0x64, 0x66, 0x67, 0x73, 0x6E, 0x74, 0x7A, 0x2E, 0xC4, 0x63, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, + 0x70, 0x72, 0x76, 0x77, 0x78, 0x65, 0x6F, 0x79, 0xFE, 0xD4, 0xF4, 0x1B, 0xF4, 0x1B, 0xF4, 0x1B, + 0xF4, 0x1B, 0xF4, 0x1B, 0xF4, 0x14, 0xFE, 0xEB, 0xFF, 0x6E, 0xF1, 0xCB, 0xF8, 0x14, 0xFF, 0xA4, + 0xF1, 0xD3, 0xF1, 0xD3, 0xFF, 0xC2, 0xF1, 0xD3, 0xFF, 0xCC, 0xF1, 0xD3, 0xF1, 0xD3, 0xF1, 0xD3, + 0xF1, 0xD3, 0xF1, 0xD3, 0xFF, 0xDA, 0xFF, 0xE4, 0xFF, 0xFB, 0x43, 0x6B, 0x7A, 0x2E, 0xF1, 0xEF, + 0xFC, 0x9B, 0xF1, 0x7F, 0xA0, 0x18, 0x73, 0x21, 0x74, 0xFD, 0x21, 0x6F, 0xFD, 0x21, 0x79, 0xFD, + 0x41, 0x74, 0xE0, 0xAB, 0x21, 0x75, 0xFC, 0x21, 0x7A, 0xFD, 0x21, 0x72, 0xFD, 0x21, 0x64, 0xFD, + 0x21, 0x6F, 0xFD, 0x21, 0x6F, 0xFD, 0x21, 0x62, 0xFD, 0x21, 0x72, 0xFD, 0x41, 0x69, 0xCF, 0x45, + 0x21, 0x6E, 0xFC, 0x21, 0x64, 0xFD, 0x21, 0x6F, 0xFD, 0x21, 0x67, 0xFD, 0x59, 0xC4, 0xC5, 0x62, + 0x63, 0x64, 0x66, 0x67, 0x6B, 0x6D, 0x6E, 0x70, 0x73, 0x7A, 0x6C, 0x72, 0x74, 0x2E, 0x68, 0x6A, + 0x76, 0x77, 0x78, 0x6F, 0x75, 0x79, 0xF3, 0x9E, 0xF4, 0xE2, 0xF3, 0x8D, 0xF3, 0x8D, 0xF3, 0x8D, + 0xF3, 0x8D, 0xF3, 0x8D, 0xF3, 0x8D, 0xF3, 0x8D, 0xF3, 0x8D, 0xF3, 0x8D, 0xF3, 0x8D, 0xF3, 0x8D, + 0xFC, 0x59, 0xFF, 0xBE, 0xF3, 0xC3, 0xF1, 0x3D, 0xF1, 0x45, 0xF1, 0x45, 0xF1, 0x45, 0xF1, 0x45, + 0xF1, 0x45, 0xFF, 0xD1, 0xFF, 0xED, 0xFF, 0xFD, 0x41, 0x64, 0xF6, 0x6C, 0x41, 0x73, 0xF6, 0x68, + 0xC3, 0x14, 0x82, 0x61, 0x6F, 0x2E, 0xFF, 0xF8, 0xFF, 0xFC, 0xF0, 0xE9, 0x45, 0x82, 0x84, 0x9B, + 0xBA, 0xBC, 0xFF, 0xF4, 0xF3, 0x2D, 0xF3, 0x2D, 0xF3, 0x2D, 0xF3, 0x2D, 0x21, 0x61, 0xE0, 0xC2, + 0x14, 0x82, 0x7A, 0x2E, 0xFF, 0xFD, 0xF0, 0xCA, 0xA0, 0x18, 0xA3, 0x21, 0x64, 0xFD, 0x21, 0x6E, + 0xFD, 0x21, 0x65, 0xFD, 0x21, 0x6B, 0xFD, 0x42, 0x66, 0x6D, 0xEB, 0x53, 0xEB, 0x53, 0x21, 0x74, + 0xF9, 0x22, 0x65, 0x73, 0xF3, 0xFD, 0x57, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x6A, 0x6B, + 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x7A, 0x77, 0x2E, 0x68, 0x76, 0x78, 0x65, 0xF3, 0x04, + 0xFF, 0xC6, 0xF2, 0xF3, 0xFF, 0xD9, 0xF2, 0xF3, 0xF2, 0xF3, 0xF2, 0xF3, 0xF2, 0xF3, 0xF2, 0xF3, + 0xF2, 0xF3, 0xF2, 0xF3, 0xF2, 0xF3, 0xF2, 0xF3, 0xF2, 0xF3, 0xF2, 0xF3, 0xF2, 0xF3, 0xF2, 0xF3, + 0xF3, 0x29, 0xF0, 0xA3, 0xF0, 0xAB, 0xF0, 0xAB, 0xF0, 0xAB, 0xFF, 0xFB, 0x45, 0x9B, 0x82, 0x84, + 0xBA, 0xBC, 0xF2, 0xAD, 0xF0, 0x65, 0xF0, 0x65, 0xF0, 0x65, 0xF0, 0x65, 0xC4, 0x14, 0x82, 0x6B, + 0x6E, 0x2E, 0x72, 0xF0, 0xBD, 0xF0, 0xBD, 0xF0, 0x4D, 0xFD, 0x66, 0x41, 0x70, 0xEA, 0x32, 0x21, + 0x70, 0xFC, 0x57, 0xC4, 0xC5, 0x63, 0x64, 0x66, 0x6B, 0x70, 0x73, 0x74, 0x7A, 0x2E, 0x62, 0x67, + 0x68, 0x6A, 0x6C, 0x6D, 0x6E, 0x72, 0x76, 0x77, 0x78, 0x65, 0xF2, 0x98, 0xFF, 0xDA, 0xF2, 0x87, + 0xFF, 0xEA, 0xF2, 0x87, 0xF2, 0x87, 0xF2, 0x87, 0xF2, 0x87, 0xF2, 0x87, 0xF2, 0xBD, 0xF0, 0x37, + 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, + 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xFF, 0xFD, 0xA0, 0x15, 0xB3, 0x21, 0x73, 0xFD, 0x21, 0x6B, + 0xFD, 0x21, 0x6C, 0xFD, 0x57, 0x2E, 0xC4, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, + 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7A, 0x6F, 0xEF, 0xE5, 0xF6, 0x2E, + 0xF6, 0x32, 0xEF, 0xED, 0xEF, 0xED, 0xEF, 0xED, 0xEF, 0xED, 0xEF, 0xED, 0xEF, 0xED, 0xEF, 0xED, + 0xEF, 0xED, 0xEF, 0xED, 0xEF, 0xED, 0xEF, 0xED, 0xEF, 0xED, 0xEF, 0xED, 0xEF, 0xED, 0xEF, 0xED, + 0xEF, 0xED, 0xEF, 0xED, 0xEF, 0xED, 0xEF, 0xED, 0xFF, 0xFD, 0x56, 0x2E, 0xC4, 0xC5, 0x62, 0x63, + 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, 0x78, + 0x7A, 0xEF, 0x9F, 0xF5, 0xE8, 0xF5, 0xEC, 0xEF, 0xA7, 0xEF, 0xA7, 0xEF, 0xA7, 0xEF, 0xA7, 0xEF, + 0xA7, 0xEF, 0xA7, 0xEF, 0xA7, 0xEF, 0xA7, 0xEF, 0xA7, 0xEF, 0xA7, 0xEF, 0xA7, 0xEF, 0xA7, 0xEF, + 0xA7, 0xEF, 0xA7, 0xEF, 0xA7, 0xEF, 0xA7, 0xEF, 0xA7, 0xEF, 0xA7, 0xEF, 0xA7, 0xA0, 0x00, 0xD1, + 0xC6, 0x02, 0x61, 0x75, 0x79, 0x61, 0x65, 0x69, 0x6F, 0xFF, 0xFD, 0xFF, 0xFD, 0xF0, 0x33, 0xF0, + 0x33, 0xF0, 0x33, 0xF0, 0x33, 0xA0, 0x04, 0xF2, 0x21, 0x63, 0xFD, 0x21, 0x61, 0xFD, 0x21, 0x7A, + 0xFD, 0xA0, 0x04, 0xE2, 0x21, 0x7A, 0xFD, 0xA1, 0x00, 0xD1, 0x73, 0xFD, 0xC7, 0x02, 0x61, 0x72, + 0x75, 0x79, 0x61, 0x65, 0x69, 0x6F, 0xFF, 0xF2, 0xFF, 0xFB, 0xFF, 0xD1, 0xF0, 0x07, 0xF0, 0x07, + 0xF0, 0x07, 0xF0, 0x07, 0x22, 0x85, 0x99, 0xB9, 0xB9, 0x21, 0xB3, 0xB4, 0x41, 0x6B, 0xE9, 0xB1, + 0x21, 0x63, 0xFC, 0x21, 0x75, 0xFD, 0x21, 0x72, 0xFD, 0x21, 0x62, 0xFD, 0x21, 0x73, 0xFD, 0x41, + 0x63, 0xE9, 0x9E, 0x21, 0x75, 0xFC, 0x21, 0x72, 0xFD, 0x21, 0x62, 0xFD, 0x22, 0x6E, 0x73, 0xF0, + 0xFD, 0xC9, 0x02, 0x61, 0xC4, 0xC3, 0x61, 0x65, 0x69, 0x6F, 0x75, 0x79, 0x6E, 0xFF, 0xD3, 0xFF, + 0xD8, 0xFF, 0x8C, 0xFF, 0x8C, 0xFF, 0x8C, 0xFF, 0x8C, 0xFF, 0x8C, 0xFF, 0x8C, 0xFF, 0xFB, 0x41, + 0x72, 0xDB, 0xBC, 0x21, 0x74, 0xFC, 0x21, 0x73, 0xFD, 0x21, 0x69, 0xFD, 0x21, 0x6D, 0xFD, 0x21, + 0x68, 0xFD, 0x41, 0x65, 0xFC, 0xD3, 0x21, 0x73, 0xFC, 0x21, 0x66, 0xFD, 0xC8, 0x02, 0x61, 0x79, + 0x61, 0x63, 0x65, 0x66, 0x69, 0x6F, 0x75, 0xFF, 0x51, 0xEF, 0x87, 0xFF, 0xF3, 0xEF, 0x87, 0xFF, + 0xFD, 0xEF, 0x87, 0xEF, 0x87, 0xEF, 0x87, 0xC6, 0x02, 0x61, 0x79, 0x61, 0x65, 0x69, 0x6F, 0x75, + 0xFF, 0x36, 0xEF, 0x6C, 0xEF, 0x6C, 0xEF, 0x6C, 0xEF, 0x6C, 0xEF, 0x6C, 0xC5, 0x02, 0x61, 0x61, + 0x65, 0x69, 0x6F, 0x75, 0xEF, 0x57, 0xEF, 0x57, 0xEF, 0x57, 0xEF, 0x57, 0xEF, 0x57, 0x5D, 0x2E, + 0xC4, 0xC3, 0xC5, 0x62, 0x63, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, + 0x73, 0x74, 0x77, 0x7A, 0x76, 0x78, 0x61, 0x65, 0x69, 0x6F, 0x75, 0x79, 0xEE, 0x19, 0xEE, 0xB6, + 0xEE, 0xCC, 0xF0, 0xA4, 0xF1, 0xC1, 0xF2, 0xE7, 0xF4, 0x6B, 0xF5, 0x1C, 0xF5, 0xC4, 0xF6, 0x3C, + 0xF6, 0xA5, 0xF7, 0x4A, 0xF7, 0xC5, 0xF8, 0xB7, 0xF9, 0x28, 0xFA, 0x5D, 0xFB, 0x2E, 0xFC, 0xA0, + 0xFD, 0x2E, 0xFD, 0xC8, 0xFE, 0x34, 0xFE, 0x86, 0xFE, 0xCC, 0xFF, 0x12, 0xFF, 0x3E, 0xFF, 0x83, + 0xFF, 0xBE, 0xFF, 0xD9, 0xFF, 0xEE, +}; + +constexpr SerializedHyphenationPatterns pl_patterns = { + 0x3C4Eu, + pl_trie_data, + sizeof(pl_trie_data), +}; diff --git a/lib/Epub/Epub/hyphenation/generated/hyph-sv.trie.h b/lib/Epub/Epub/hyphenation/generated/hyph-sv.trie.h new file mode 100644 index 0000000000..0883c5344b --- /dev/null +++ b/lib/Epub/Epub/hyphenation/generated/hyph-sv.trie.h @@ -0,0 +1,1491 @@ +#pragma once + +#include +#include + +#include "Epub/hyphenation/SerializedHyphenationTrie.h" + +// Auto-generated by generate_hyphenation_trie.py. Do not edit manually. +alignas(4) constexpr uint8_t sv_trie_data[] = { + 0x18, 0x23, 0x21, 0x17, 0x19, 0x0E, 0x22, 0x2B, 0x2C, 0x16, 0x0F, 0x1F, 0x20, 0x21, 0x0E, 0x2D, + 0x35, 0x33, 0x17, 0x0E, 0x16, 0x0D, 0x37, 0x49, 0x16, 0x0B, 0x2A, 0x21, 0x0C, 0x36, 0x3F, 0x48, + 0x40, 0x4B, 0x41, 0x29, 0x15, 0x0E, 0x34, 0x4A, 0x2C, 0x0F, 0x3D, 0x01, 0x03, 0x01, 0x17, 0x04, + 0x22, 0x0D, 0x02, 0x0C, 0x0F, 0x0E, 0x0D, 0x0D, 0x0E, 0x02, 0x0B, 0x04, 0x0D, 0x01, 0x0C, 0x02, + 0x0D, 0x02, 0x0F, 0x05, 0x01, 0x0E, 0x04, 0x0B, 0x03, 0x0C, 0x02, 0x0D, 0x0C, 0x04, 0x0F, 0x02, + 0x0C, 0x0C, 0x03, 0x0E, 0x0C, 0x0B, 0x17, 0x0C, 0x20, 0x0D, 0x0F, 0x18, 0x05, 0x0C, 0x02, 0x18, + 0x19, 0x18, 0x0C, 0x0E, 0x20, 0x0F, 0x23, 0x0C, 0x37, 0x0E, 0x0C, 0x0D, 0x19, 0x0C, 0x18, 0x0D, + 0x2B, 0x0E, 0x02, 0x0D, 0x0E, 0x02, 0x0F, 0x0E, 0x05, 0x35, 0x05, 0x21, 0x2D, 0x0C, 0x3E, 0x16, + 0x0E, 0x0B, 0x0E, 0x23, 0x0E, 0x05, 0x17, 0x02, 0x0B, 0x0E, 0x02, 0x0B, 0x0C, 0x04, 0x21, 0x0E, + 0x02, 0x15, 0x2D, 0x0E, 0x04, 0x2C, 0x05, 0x0E, 0x18, 0x0F, 0x54, 0x18, 0x0E, 0x0D, 0x17, 0x04, + 0x0D, 0x0C, 0x0F, 0x0C, 0x05, 0x15, 0x0E, 0x0F, 0x02, 0x17, 0x34, 0x0D, 0x02, 0x1F, 0x02, 0x16, + 0x02, 0x0C, 0x0E, 0x02, 0x17, 0x0E, 0x04, 0x2D, 0x0E, 0x17, 0x05, 0x19, 0x2A, 0x0F, 0x18, 0x0B, + 0x36, 0x0D, 0x0B, 0x21, 0x2C, 0x0D, 0x1F, 0x0C, 0xA0, 0x00, 0x51, 0x21, 0x6C, 0xFD, 0xA0, 0x00, + 0x61, 0xA3, 0x00, 0x41, 0x69, 0x6F, 0x72, 0xF7, 0xFA, 0xFD, 0xA0, 0x00, 0x71, 0xA2, 0x00, 0x41, + 0x72, 0x73, 0xFD, 0xF1, 0xA0, 0x00, 0x82, 0xA0, 0x00, 0x81, 0x22, 0x61, 0x65, 0xFA, 0xFD, 0x21, + 0x72, 0xFB, 0x21, 0x6C, 0xF5, 0xA0, 0x00, 0xA1, 0x21, 0x72, 0xFD, 0x23, 0x65, 0x70, 0x75, 0xEC, + 0xFD, 0xDF, 0xA0, 0x00, 0xB1, 0x21, 0x6C, 0xFD, 0x23, 0x62, 0x70, 0x75, 0xF0, 0xFD, 0xDF, 0xA0, + 0x00, 0xC1, 0x21, 0x72, 0xFD, 0x21, 0x61, 0xFD, 0x21, 0x72, 0xFD, 0xA0, 0x00, 0xD2, 0x21, 0x73, + 0xFD, 0x42, 0x65, 0x6F, 0xFF, 0xF1, 0xFF, 0xA7, 0x44, 0x64, 0x65, 0x67, 0x73, 0xFF, 0xF0, 0xFF, + 0xF6, 0xFF, 0xF9, 0xFF, 0xA0, 0xA0, 0x00, 0xF1, 0x21, 0x70, 0xFD, 0x41, 0x74, 0xFF, 0x9F, 0xA1, + 0x01, 0x01, 0x65, 0xFC, 0x41, 0x6E, 0xFF, 0xA3, 0xC2, 0x00, 0xA1, 0x65, 0x69, 0xFF, 0xFC, 0xFF, + 0x92, 0x22, 0x6B, 0x74, 0xEE, 0xF7, 0x42, 0x61, 0x74, 0xFF, 0x91, 0xFF, 0x78, 0x41, 0x74, 0xFF, + 0x71, 0x21, 0x73, 0xFC, 0xA0, 0x00, 0x41, 0x21, 0x6C, 0xFD, 0xA0, 0x01, 0x12, 0x22, 0x61, 0x73, + 0xFA, 0xFD, 0x4D, 0x62, 0x63, 0x64, 0x67, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x75, 0x76, + 0xFF, 0x5F, 0xFF, 0x5C, 0xFF, 0x6B, 0xFF, 0x7D, 0xFF, 0x80, 0xFF, 0x89, 0xFF, 0x96, 0xFF, 0xB6, + 0xFF, 0xC6, 0xFF, 0xDF, 0xFF, 0xE4, 0xFF, 0xEF, 0xFF, 0xFB, 0xA0, 0x01, 0x31, 0x21, 0x73, 0xFD, + 0x21, 0x6B, 0xFD, 0x21, 0x6E, 0xFA, 0xA0, 0x01, 0x41, 0x21, 0x73, 0xFD, 0x21, 0x64, 0xFD, 0x21, + 0x6C, 0xFD, 0xA0, 0x01, 0x01, 0xA0, 0x01, 0x51, 0x21, 0x74, 0xFD, 0x22, 0x6B, 0x72, 0xF7, 0xFD, + 0xA4, 0x00, 0x41, 0x61, 0x65, 0x69, 0x6F, 0xE0, 0xE3, 0xEF, 0xFB, 0x41, 0x73, 0xFF, 0x44, 0x41, + 0x70, 0xFE, 0xF9, 0x21, 0x6F, 0xFC, 0x21, 0x6C, 0xFD, 0x21, 0x6B, 0xFD, 0x22, 0x69, 0x79, 0xEF, + 0xFD, 0x21, 0x72, 0xC5, 0x21, 0xA4, 0xFD, 0xA1, 0x00, 0x41, 0xC3, 0xFD, 0x41, 0x76, 0xFF, 0x49, + 0xA0, 0x01, 0x62, 0x41, 0x6E, 0xFF, 0x28, 0x22, 0x61, 0x69, 0xF9, 0xFC, 0x41, 0x74, 0xFE, 0xCC, + 0x41, 0xA4, 0xFF, 0x64, 0x22, 0x73, 0xC3, 0xF8, 0xFC, 0xA0, 0x01, 0x82, 0x21, 0x69, 0xFD, 0x43, + 0x64, 0x6C, 0x70, 0xFE, 0xD8, 0xFE, 0xBF, 0xFE, 0xB9, 0x21, 0x61, 0xF6, 0x41, 0x64, 0xFE, 0xCB, + 0x21, 0x61, 0xFC, 0xA1, 0x00, 0xA1, 0x72, 0xFD, 0xA2, 0x00, 0xD1, 0x6B, 0x74, 0xF1, 0xFB, 0x41, + 0x72, 0xFE, 0xAB, 0xA0, 0x01, 0xA1, 0x21, 0x6E, 0xFD, 0x21, 0x61, 0xFD, 0x48, 0x6B, 0x6C, 0x6E, + 0x72, 0x73, 0x74, 0x76, 0x78, 0xFF, 0xB0, 0xFF, 0xBB, 0xFF, 0xC8, 0xFF, 0xD0, 0xFF, 0xEC, 0xFF, + 0xF3, 0xFF, 0xFD, 0xFE, 0x92, 0x41, 0x72, 0xFE, 0xAD, 0x21, 0x62, 0xFC, 0x41, 0x6D, 0xFF, 0x4A, + 0x21, 0x73, 0xD3, 0x22, 0x61, 0x65, 0xF9, 0xFD, 0xA0, 0x01, 0xB1, 0x21, 0x6C, 0xFD, 0x21, 0x65, + 0xFD, 0x21, 0x67, 0xFD, 0x41, 0x6E, 0xFF, 0x41, 0x42, 0x61, 0x65, 0xFF, 0x3D, 0xFF, 0xFC, 0x21, + 0x72, 0xF9, 0x22, 0xA5, 0xB6, 0xEF, 0xFD, 0xA3, 0x00, 0x41, 0x65, 0x72, 0xC3, 0xD2, 0xDC, 0xFB, + 0x41, 0xA4, 0xFE, 0x65, 0x21, 0xC3, 0xFC, 0x42, 0x6C, 0x73, 0xFF, 0xFD, 0xFE, 0x6B, 0xA1, 0x00, + 0xD1, 0x75, 0xF9, 0x41, 0x6D, 0xFF, 0x0F, 0x41, 0x61, 0xFE, 0x21, 0x21, 0x73, 0xFC, 0x22, 0x65, + 0x75, 0xF5, 0xFD, 0x41, 0x70, 0xFE, 0x1B, 0x41, 0x65, 0xFE, 0x41, 0xA0, 0x01, 0xE1, 0xA0, 0x01, + 0xF2, 0xC6, 0x01, 0xC2, 0x61, 0x64, 0x67, 0x6B, 0x73, 0x74, 0xFE, 0xA3, 0xFE, 0x0D, 0xFF, 0xF6, + 0xFF, 0xFA, 0xFF, 0xFD, 0xFE, 0x0D, 0x42, 0x6B, 0x6F, 0xFF, 0xD1, 0xFE, 0x04, 0x45, 0x62, 0x6B, + 0x6D, 0x6E, 0x73, 0xFE, 0x18, 0xFE, 0x18, 0xFF, 0xD6, 0xFF, 0xE4, 0xFF, 0xF9, 0xA0, 0x02, 0x11, + 0x21, 0x6B, 0xFD, 0x21, 0x73, 0xFD, 0x21, 0x6E, 0xFD, 0x41, 0x69, 0xFD, 0xCF, 0x41, 0x74, 0xFF, + 0x63, 0x22, 0x6C, 0x72, 0xF8, 0xFC, 0xA0, 0x02, 0x31, 0xA1, 0x02, 0x21, 0x73, 0xFD, 0x21, 0x67, + 0xFB, 0x21, 0x6E, 0xFD, 0x21, 0x69, 0xFD, 0x41, 0x70, 0xFF, 0x49, 0x21, 0xB6, 0xFC, 0xA4, 0x00, + 0x41, 0x61, 0x6F, 0x72, 0xC3, 0xD8, 0xE3, 0xF6, 0xFD, 0x41, 0x72, 0xFE, 0x71, 0x21, 0x6B, 0xFC, + 0x21, 0x74, 0xF9, 0x21, 0x6B, 0xFD, 0x41, 0x74, 0xFE, 0x7C, 0x21, 0x73, 0xFC, 0xA3, 0x00, 0xD1, + 0x61, 0x65, 0x75, 0xF0, 0xF6, 0xFD, 0xA1, 0x01, 0xE1, 0x72, 0xB3, 0x21, 0x65, 0xFB, 0x21, 0x6B, + 0xFD, 0x21, 0x73, 0xFD, 0x41, 0x65, 0xFD, 0xA1, 0x21, 0x72, 0xFC, 0xA0, 0x02, 0x41, 0x21, 0x73, + 0xFD, 0x21, 0x69, 0xFD, 0x21, 0x6E, 0xFD, 0xA0, 0x02, 0x51, 0x21, 0x73, 0xFD, 0x21, 0x6B, 0xFD, + 0x21, 0x6C, 0xFD, 0x21, 0xB6, 0xFD, 0x21, 0xC3, 0xFD, 0x41, 0x73, 0xFF, 0x42, 0x21, 0x6E, 0xFC, + 0x41, 0x74, 0xFD, 0x8F, 0x42, 0x6E, 0x73, 0xFE, 0x25, 0xFF, 0xFC, 0x41, 0x6F, 0xFE, 0xA8, 0x21, + 0x6B, 0xFC, 0x21, 0x73, 0xFD, 0x21, 0x6E, 0xFD, 0xA0, 0x02, 0x61, 0x21, 0x72, 0xFD, 0x21, 0x6B, + 0xFD, 0x21, 0x72, 0xFD, 0x23, 0xA5, 0xA4, 0xB6, 0xE0, 0xF1, 0xFD, 0xC6, 0x00, 0xD1, 0x61, 0x65, + 0x69, 0x6A, 0x6F, 0xC3, 0xFF, 0xA6, 0xFF, 0xAD, 0xFF, 0xB9, 0xFF, 0xCB, 0xFF, 0xD2, 0xFF, 0xF9, + 0xA0, 0x02, 0x71, 0x21, 0x72, 0xFD, 0x41, 0x6E, 0xFD, 0x2F, 0x41, 0x72, 0xFE, 0x69, 0x21, 0x64, + 0xFC, 0x21, 0xB6, 0xFD, 0xA3, 0x00, 0x41, 0x65, 0x6F, 0xC3, 0xEF, 0xF2, 0xFD, 0x41, 0x75, 0xFD, + 0x58, 0x21, 0x6B, 0xFC, 0x42, 0x74, 0x76, 0xFC, 0xEA, 0xFC, 0xF6, 0xA0, 0x00, 0xD1, 0x44, 0x61, + 0x6F, 0x73, 0x75, 0xFF, 0xFD, 0xFF, 0xFD, 0xFD, 0x7C, 0xFC, 0xEC, 0x41, 0x6B, 0xFC, 0xFA, 0x41, + 0x73, 0xFD, 0x03, 0x21, 0x64, 0xFC, 0xA0, 0x02, 0x82, 0x41, 0x61, 0xFC, 0xD1, 0x21, 0x72, 0xFC, + 0x45, 0x63, 0x6B, 0x6C, 0x74, 0x76, 0xFC, 0xD7, 0xFF, 0xF6, 0xFC, 0xCA, 0xFF, 0xFD, 0xFC, 0xCA, + 0xA0, 0x02, 0x81, 0x49, 0x63, 0x6B, 0x6D, 0x6E, 0x6F, 0x72, 0x73, 0x74, 0x75, 0xFF, 0xBE, 0xFF, + 0xC1, 0xFF, 0xCB, 0xFF, 0xD8, 0xFC, 0xB7, 0xFF, 0xE0, 0xFF, 0xED, 0xFE, 0x0C, 0xFF, 0xFD, 0x42, + 0x65, 0x69, 0xFC, 0x8F, 0xFC, 0x89, 0x21, 0x74, 0xF9, 0x42, 0x70, 0x73, 0xFE, 0xCE, 0xFF, 0xFD, + 0x41, 0x74, 0xFE, 0xA9, 0x21, 0x73, 0xFC, 0xA0, 0x02, 0xA1, 0x21, 0x73, 0xFD, 0x21, 0x73, 0xFD, + 0x21, 0x65, 0xFD, 0x41, 0x61, 0xFC, 0x9F, 0x21, 0x6B, 0xFC, 0x21, 0x69, 0xFD, 0x21, 0x6C, 0xFD, + 0x21, 0x62, 0xFD, 0xA4, 0x00, 0x41, 0x61, 0x69, 0x72, 0x75, 0xD6, 0xE1, 0xED, 0xFD, 0x41, 0x65, + 0xFD, 0x34, 0x21, 0x74, 0xFC, 0x42, 0x67, 0x73, 0xFC, 0x73, 0xFF, 0xFD, 0x41, 0x73, 0xFE, 0x61, + 0x21, 0x6E, 0xFC, 0x41, 0x64, 0xFE, 0x28, 0x21, 0x6D, 0xFC, 0x41, 0x65, 0xFE, 0xFE, 0x21, 0x76, + 0xFC, 0x21, 0xB6, 0xFD, 0xA4, 0x00, 0xD1, 0x65, 0x75, 0x79, 0xC3, 0xE1, 0xEC, 0xF3, 0xFD, 0x41, + 0x6B, 0xFD, 0x03, 0x41, 0x67, 0xFD, 0xA2, 0x41, 0x6F, 0xFC, 0x11, 0x41, 0xB6, 0xFC, 0xFA, 0x21, + 0xC3, 0xFC, 0xA0, 0x02, 0x21, 0x21, 0x73, 0xFD, 0x21, 0x74, 0xFD, 0x21, 0x74, 0xFD, 0xA1, 0x00, + 0xA1, 0x6F, 0xFD, 0x41, 0x74, 0xFC, 0xD6, 0x21, 0x75, 0xFC, 0x41, 0x6D, 0xFD, 0xE1, 0x41, 0x6E, + 0xFC, 0xCB, 0xA0, 0x02, 0xB1, 0x21, 0x67, 0xFD, 0x21, 0x6E, 0xFD, 0x21, 0x69, 0xFD, 0xA3, 0x00, + 0xA1, 0x61, 0x65, 0x72, 0xEC, 0xF0, 0xFD, 0x41, 0x70, 0xFC, 0x0B, 0x21, 0x70, 0xFC, 0xA8, 0x00, + 0x41, 0x61, 0x65, 0x69, 0x6A, 0x6B, 0x6C, 0x74, 0x75, 0xB1, 0xB5, 0xB9, 0xC1, 0xD0, 0xD9, 0xF0, + 0xFD, 0x41, 0x6C, 0xFB, 0xBD, 0xC1, 0x00, 0xA1, 0x6C, 0xFC, 0x85, 0x22, 0x62, 0x6B, 0xF6, 0xFA, + 0x41, 0x74, 0xFF, 0x43, 0x21, 0x73, 0xFC, 0x41, 0x6C, 0xFB, 0xE8, 0x43, 0x67, 0x6C, 0x6F, 0xFD, + 0x2A, 0xFF, 0xFC, 0xFB, 0xA3, 0x41, 0x70, 0xFD, 0xE2, 0x42, 0x64, 0x73, 0xFF, 0x21, 0xFB, 0xC9, + 0x41, 0x6B, 0xFC, 0xF3, 0x21, 0xA4, 0xFC, 0x22, 0x65, 0xC3, 0xF2, 0xFD, 0xA5, 0x00, 0x41, 0x61, + 0x65, 0x69, 0x6F, 0x72, 0xCF, 0xD8, 0xDF, 0xE9, 0xFB, 0x41, 0x65, 0xFD, 0x62, 0x21, 0x67, 0xFC, + 0x42, 0x61, 0x73, 0xFC, 0x04, 0xFB, 0x6E, 0x41, 0x72, 0xFB, 0x80, 0x21, 0x65, 0xFC, 0xC3, 0x01, + 0xC2, 0x61, 0x72, 0x73, 0xFB, 0xF6, 0xFF, 0xFD, 0xFB, 0x5A, 0x46, 0x6B, 0x6C, 0x6E, 0x70, 0x72, + 0x74, 0xFB, 0x60, 0xFD, 0xB6, 0xFF, 0xE3, 0xFC, 0x38, 0xFF, 0xE6, 0xFF, 0xF4, 0x41, 0x6E, 0xFC, + 0xDB, 0x21, 0x65, 0xFC, 0x21, 0x74, 0xFD, 0x42, 0x72, 0x74, 0xFD, 0xE9, 0xFF, 0xFD, 0x41, 0x64, + 0xFB, 0xFF, 0xC1, 0x01, 0xE1, 0x73, 0xFC, 0x04, 0x21, 0x67, 0xFA, 0x21, 0xA4, 0xFD, 0xA3, 0x00, + 0xD1, 0x61, 0x65, 0xC3, 0xE9, 0xF0, 0xFD, 0x42, 0x61, 0x65, 0xFE, 0x34, 0xFB, 0xAD, 0x41, 0x67, + 0xFB, 0xE8, 0xA0, 0x02, 0xC2, 0x21, 0x73, 0xFD, 0xA0, 0x02, 0xE1, 0x21, 0x72, 0xFD, 0x21, 0x65, + 0xFD, 0x44, 0x6E, 0x72, 0x73, 0x74, 0xFF, 0xED, 0xFF, 0xF4, 0xFB, 0x8C, 0xFF, 0xFD, 0x41, 0x6F, + 0xFA, 0xF0, 0x21, 0x72, 0xFC, 0x23, 0xA5, 0xA4, 0xB6, 0xEC, 0xFD, 0xFD, 0x57, 0x61, 0x62, 0x63, + 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x78, 0x79, 0xC3, 0xFB, 0x86, 0xFB, 0xD4, 0xFB, 0xF0, 0xFB, 0xFB, 0xFC, 0x50, 0xFC, 0x9B, + 0xFC, 0xB2, 0xFC, 0xC2, 0xFC, 0xF1, 0xFD, 0x32, 0xFD, 0x51, 0xFD, 0xBF, 0xFD, 0xE8, 0xFE, 0x37, + 0xFE, 0x87, 0xFE, 0xB8, 0xFF, 0x12, 0xFF, 0x60, 0xFF, 0x8E, 0xFF, 0xC2, 0xFD, 0xFF, 0xFF, 0xCB, + 0xFF, 0xF9, 0x41, 0x75, 0xFB, 0x32, 0xC2, 0x00, 0xE1, 0x6C, 0x73, 0xFB, 0x95, 0xFB, 0x7C, 0xC1, + 0x02, 0x81, 0x61, 0xFA, 0x9B, 0x41, 0x72, 0xFA, 0xF6, 0x42, 0x63, 0x6F, 0xFA, 0x9E, 0xFA, 0x91, + 0x21, 0x69, 0xF9, 0x42, 0x63, 0x6B, 0xFB, 0x11, 0xFB, 0x11, 0xA0, 0x00, 0xE1, 0xA7, 0x02, 0x01, + 0x62, 0x65, 0x6C, 0x6F, 0x72, 0x73, 0x75, 0xD5, 0xD9, 0xE2, 0xE8, 0xF3, 0xF6, 0xFD, 0x41, 0x73, + 0xFA, 0xF6, 0x41, 0x6B, 0xFA, 0x5C, 0x41, 0x70, 0xFA, 0xF4, 0x24, 0x65, 0x69, 0x73, 0x75, 0xF4, + 0xF4, 0xF8, 0xFC, 0x21, 0x6B, 0xF7, 0x21, 0x67, 0xD4, 0x43, 0x6B, 0x6C, 0x70, 0xFF, 0xD1, 0xFF, + 0xD1, 0xFA, 0x5E, 0x41, 0x70, 0xFA, 0x47, 0x21, 0x6E, 0xC3, 0xA0, 0x02, 0xF1, 0xA1, 0x01, 0x91, + 0x73, 0xFD, 0x41, 0x6C, 0xFA, 0x38, 0x44, 0x61, 0x65, 0x69, 0x75, 0xFF, 0xF1, 0xFF, 0xF7, 0xFF, + 0xFC, 0xFA, 0x34, 0x46, 0x61, 0x65, 0x6A, 0x6F, 0x72, 0x73, 0xFF, 0xD3, 0xFF, 0xD6, 0xFA, 0x27, + 0xFF, 0xE0, 0xFF, 0xF3, 0xFD, 0x38, 0x41, 0x64, 0xFF, 0x94, 0xA0, 0x03, 0x01, 0x21, 0xA4, 0xFD, + 0x42, 0x6F, 0xC3, 0xFA, 0x94, 0xFF, 0xFD, 0xA0, 0x03, 0x12, 0x21, 0x69, 0xFD, 0x41, 0x72, 0xFA, + 0x87, 0x21, 0x6F, 0xFC, 0x23, 0x66, 0x72, 0x74, 0xEC, 0xF6, 0xFD, 0x41, 0x61, 0xFA, 0x0A, 0xA1, + 0x01, 0xD1, 0x72, 0xFC, 0xA0, 0x02, 0x01, 0xA1, 0x01, 0xD1, 0x2E, 0xFD, 0x41, 0x72, 0xFD, 0x24, + 0x41, 0x72, 0xFB, 0x1C, 0x41, 0x6F, 0xF9, 0xD6, 0xA0, 0x00, 0x91, 0x21, 0x72, 0xFD, 0x47, 0x61, + 0x65, 0x67, 0x6C, 0x6F, 0x72, 0x75, 0xFF, 0xE1, 0xFF, 0xE9, 0xFF, 0xEE, 0xFD, 0x12, 0xFF, 0xF2, + 0xFF, 0xF6, 0xFF, 0xFD, 0x21, 0x6A, 0xE4, 0xA0, 0x01, 0x91, 0x42, 0x62, 0x76, 0xF9, 0xCB, 0xFF, + 0xFD, 0xA0, 0x01, 0xD1, 0x21, 0x74, 0xD4, 0xA1, 0x01, 0x91, 0x72, 0xFD, 0x41, 0x6D, 0xF9, 0xAB, + 0x41, 0x62, 0xF9, 0x9A, 0x43, 0x61, 0x69, 0x6F, 0xFF, 0xF8, 0xFA, 0x59, 0xFF, 0xFC, 0x41, 0x61, + 0xFA, 0x16, 0x21, 0x74, 0xFC, 0x41, 0x67, 0xFF, 0x45, 0x41, 0x69, 0xF9, 0x81, 0x22, 0x69, 0x72, + 0xF8, 0xFC, 0x41, 0x69, 0xFE, 0xF8, 0x21, 0x72, 0xFC, 0x42, 0x61, 0x65, 0xFF, 0xFD, 0xF9, 0x71, + 0x42, 0x72, 0x74, 0xFE, 0xEA, 0xF9, 0x77, 0xA0, 0x03, 0x31, 0x22, 0xA5, 0xB6, 0xF6, 0xFD, 0x4B, + 0x61, 0x65, 0x69, 0x6E, 0x6F, 0x72, 0x73, 0x74, 0x75, 0x76, 0xC3, 0xFF, 0xB8, 0xFE, 0xDB, 0xFF, + 0xB2, 0xF9, 0x5B, 0xFF, 0xB2, 0xFF, 0xC5, 0xFF, 0xD3, 0xFF, 0xDE, 0xFF, 0xB2, 0xFF, 0xEA, 0xFF, + 0xFB, 0xC1, 0x01, 0xD1, 0x64, 0xFF, 0x9B, 0x41, 0x72, 0xFA, 0x0B, 0xC3, 0x02, 0x01, 0x2E, 0x65, + 0x73, 0xFE, 0xAF, 0xFF, 0x7C, 0xF9, 0x2F, 0x41, 0x6B, 0xF9, 0x11, 0x21, 0x69, 0xFC, 0x21, 0x74, + 0xFD, 0x23, 0x62, 0x6E, 0x73, 0xE6, 0xEA, 0xFD, 0x43, 0x61, 0x76, 0xC3, 0xFE, 0xAA, 0xFC, 0x23, + 0xFA, 0x38, 0x41, 0xA5, 0xF9, 0x08, 0x42, 0x73, 0xC3, 0xF9, 0x87, 0xFF, 0xFC, 0x41, 0x6B, 0xF9, + 0x32, 0x21, 0x73, 0xFC, 0x41, 0x74, 0xF9, 0x03, 0xA1, 0x01, 0xD1, 0x72, 0xFC, 0x41, 0x70, 0xFA, + 0xBA, 0x43, 0x72, 0x75, 0xC3, 0xF8, 0xE9, 0xF9, 0x73, 0xFA, 0x0F, 0xC1, 0x01, 0xD1, 0x73, 0xF8, + 0xCD, 0x41, 0x73, 0xF8, 0xCD, 0x4C, 0x61, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6F, 0x73, 0x74, 0x75, + 0x76, 0x79, 0xFF, 0x9C, 0xFF, 0xBC, 0xFF, 0x03, 0xFF, 0xC3, 0xFF, 0xD1, 0xFF, 0xDC, 0xFF, 0xE3, + 0xFF, 0xE8, 0xFF, 0xEC, 0xFF, 0xF6, 0xFF, 0xFC, 0xFF, 0x2C, 0x41, 0x66, 0xFE, 0xDE, 0x42, 0xA5, + 0xB6, 0xF9, 0x0D, 0xFE, 0xF9, 0x45, 0x61, 0x69, 0x70, 0x73, 0xC3, 0xFF, 0xF5, 0xF9, 0x2F, 0xFE, + 0xA8, 0xFB, 0xEB, 0xFF, 0xF9, 0x41, 0x6F, 0xF8, 0xB0, 0x41, 0x66, 0xF8, 0x91, 0x41, 0x6B, 0xF8, + 0x8D, 0x23, 0x62, 0x6C, 0x72, 0xF4, 0xF8, 0xFC, 0xC1, 0x00, 0x71, 0x69, 0xF9, 0x42, 0x41, 0x6B, + 0xF8, 0x89, 0x41, 0x6C, 0xFB, 0xF8, 0x41, 0x6E, 0xF8, 0xFE, 0x21, 0xA4, 0xFC, 0x24, 0x61, 0x65, + 0x75, 0xC3, 0xF1, 0xF5, 0xF9, 0xFD, 0x41, 0x73, 0xF8, 0x7F, 0x43, 0x65, 0x69, 0x72, 0xFF, 0xFC, + 0xF8, 0x60, 0xFB, 0xA6, 0x41, 0x75, 0xF8, 0x8B, 0x41, 0x72, 0xF8, 0x46, 0x43, 0x69, 0x6B, 0x70, + 0xF9, 0x26, 0xFE, 0x7C, 0xFE, 0x7C, 0x41, 0x65, 0xF8, 0x51, 0x41, 0x74, 0xF9, 0x0C, 0x21, 0x73, + 0xFC, 0x41, 0x75, 0xF8, 0x27, 0x41, 0x69, 0xF8, 0x29, 0x21, 0x61, 0xDF, 0xC2, 0x02, 0x81, 0x6F, + 0x79, 0xF8, 0xB8, 0xF8, 0xB8, 0x41, 0x72, 0xFD, 0xE5, 0x21, 0x61, 0xFC, 0x48, 0x63, 0x69, 0x6A, + 0x6B, 0x6C, 0x70, 0x74, 0x76, 0xFF, 0xDA, 0xFF, 0xE2, 0xF8, 0xA8, 0xFF, 0xE5, 0xFF, 0xE9, 0xFF, + 0xED, 0xFF, 0xF0, 0xFF, 0xFD, 0x41, 0x65, 0xF8, 0x8F, 0x42, 0x6A, 0x72, 0xF8, 0x8B, 0xFF, 0xFC, + 0x41, 0xB6, 0xFE, 0x47, 0x4D, 0x61, 0x63, 0x64, 0x65, 0x67, 0x69, 0x6B, 0x6F, 0x73, 0x74, 0x75, + 0x79, 0xC3, 0xFF, 0x6D, 0xFF, 0x74, 0xFF, 0x89, 0xFF, 0x46, 0xFF, 0x96, 0xFF, 0xA0, 0xFF, 0xA4, + 0xFF, 0xA8, 0xFF, 0xD8, 0xFF, 0xF5, 0xFE, 0x4D, 0xFD, 0x76, 0xFF, 0xFC, 0xA0, 0x03, 0x42, 0xC2, + 0x01, 0xD1, 0x2E, 0x6E, 0xFD, 0xE5, 0xFF, 0xFD, 0x41, 0x61, 0xFF, 0x4E, 0x41, 0x74, 0xFF, 0x6C, + 0x21, 0x73, 0xFC, 0x41, 0x61, 0xFD, 0x77, 0x21, 0x72, 0xFC, 0x42, 0x61, 0x73, 0xFF, 0xFD, 0xFE, + 0xB3, 0x43, 0x63, 0x66, 0x73, 0xF7, 0xA9, 0xF7, 0xA9, 0xFD, 0x29, 0x21, 0x69, 0xF6, 0xC3, 0x00, + 0xD1, 0x65, 0x6C, 0x70, 0xF7, 0x9C, 0xF7, 0x8A, 0xF7, 0x90, 0x41, 0x73, 0xF7, 0x7E, 0x41, 0xA4, + 0xFD, 0x0C, 0x4A, 0x65, 0x69, 0x6C, 0x6F, 0x70, 0x72, 0x73, 0x75, 0x79, 0xC3, 0xFF, 0xBD, 0xFD, + 0xDF, 0xFF, 0xC6, 0xFF, 0xCE, 0xFF, 0xD8, 0xFF, 0xE9, 0xFF, 0xEC, 0xFF, 0xF8, 0xFD, 0x08, 0xFF, + 0xFC, 0x41, 0x6E, 0xFD, 0x97, 0x41, 0x76, 0xFD, 0x93, 0xA2, 0x03, 0x61, 0x6E, 0x72, 0xF8, 0xFC, + 0xA0, 0x03, 0x61, 0xC3, 0x02, 0xF1, 0x69, 0x6F, 0x72, 0xFD, 0xF4, 0xFF, 0xFD, 0xFD, 0xF4, 0x42, + 0x72, 0x73, 0xF7, 0x4B, 0xF8, 0x6D, 0x41, 0x64, 0xFD, 0x72, 0x21, 0x6E, 0xFC, 0x41, 0x73, 0xF9, + 0x5C, 0x21, 0x65, 0xD0, 0xA1, 0x01, 0xD1, 0x67, 0xFD, 0x41, 0x6E, 0xF7, 0x25, 0x21, 0x61, 0xFC, + 0x43, 0x61, 0x6C, 0x72, 0xF7, 0x2A, 0xFF, 0xFD, 0xF7, 0x37, 0x42, 0x2E, 0x61, 0xFD, 0xBD, 0xF7, + 0xAD, 0xC1, 0x01, 0xD1, 0x62, 0xFD, 0x33, 0x42, 0x61, 0x6C, 0xF7, 0x2B, 0xF7, 0xD3, 0x43, 0x61, + 0x6B, 0x76, 0xFA, 0x1D, 0xFF, 0xF9, 0xFA, 0x1D, 0x41, 0x6F, 0xF7, 0x8C, 0x41, 0x70, 0xF7, 0xBE, + 0x43, 0x72, 0x73, 0x75, 0xFF, 0xF8, 0xFF, 0xFC, 0xFC, 0xFD, 0xC2, 0x03, 0x31, 0x72, 0x73, 0xFD, + 0x1E, 0xFC, 0x70, 0x41, 0x67, 0xF7, 0x71, 0x21, 0xA4, 0xFC, 0x21, 0xC3, 0xFD, 0x41, 0xA4, 0xFD, + 0x2A, 0x52, 0x61, 0x62, 0x64, 0x65, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6E, 0x6F, 0x70, 0x73, 0x74, + 0x75, 0x76, 0x79, 0xC3, 0xFF, 0x78, 0xFF, 0x82, 0xFF, 0x8E, 0xFF, 0x99, 0xFF, 0x9C, 0xFF, 0x7F, + 0xFF, 0xA3, 0xFF, 0xAF, 0xFD, 0x76, 0xFF, 0xB9, 0xFF, 0xC0, 0xFD, 0x76, 0xFF, 0xCD, 0xFF, 0xDF, + 0xFF, 0xE9, 0xFF, 0xF9, 0xFD, 0x26, 0xFF, 0xFC, 0x41, 0x65, 0xF6, 0xD7, 0x41, 0x74, 0xF7, 0x5E, + 0x21, 0x73, 0xFC, 0x41, 0x73, 0xF6, 0x97, 0x44, 0x69, 0x6F, 0x72, 0x75, 0xFF, 0xFC, 0xFC, 0xAD, + 0xFC, 0xC1, 0xF6, 0x93, 0x41, 0x67, 0xF6, 0x86, 0x42, 0x61, 0x69, 0xF6, 0x82, 0xFF, 0xFC, 0x41, + 0x70, 0xF6, 0xBC, 0x45, 0x6B, 0x6F, 0x70, 0x74, 0x75, 0xF9, 0x88, 0xFF, 0xFC, 0xF9, 0x88, 0xF9, + 0x88, 0xF7, 0x6C, 0xC1, 0x00, 0x71, 0x72, 0xFC, 0x53, 0x42, 0x6B, 0x6F, 0xFA, 0xF2, 0xF7, 0x21, + 0x42, 0x6B, 0x6C, 0xF6, 0x48, 0xFB, 0xDA, 0xC2, 0x00, 0x41, 0x61, 0x6F, 0xFF, 0xF9, 0xFA, 0x8A, + 0x41, 0xB6, 0xFA, 0xD7, 0x46, 0x61, 0x65, 0x69, 0x6F, 0x72, 0xC3, 0xFF, 0xDF, 0xFA, 0xD3, 0xFF, + 0xE5, 0xF6, 0x46, 0xFF, 0xF3, 0xFF, 0xFC, 0xC3, 0x01, 0x91, 0x6C, 0x6E, 0x74, 0xFC, 0x61, 0xFE, + 0xEF, 0xF9, 0x44, 0xA0, 0x03, 0x72, 0x42, 0xA5, 0xB6, 0xFF, 0xFD, 0xFC, 0x3E, 0x4E, 0x61, 0x62, + 0x63, 0x68, 0x69, 0x6B, 0x6C, 0x70, 0x73, 0x74, 0x75, 0x76, 0x79, 0xC3, 0xFE, 0xC3, 0xFF, 0x7B, + 0xFC, 0x74, 0xF9, 0x2E, 0xFF, 0x83, 0xFF, 0x8A, 0xF6, 0x2A, 0xFF, 0x9B, 0xFF, 0xA6, 0xFF, 0xD7, + 0xFF, 0xEA, 0xF6, 0x1D, 0xFC, 0x74, 0xFF, 0xF9, 0x41, 0x72, 0xF7, 0xBF, 0x41, 0xB6, 0xF5, 0xDC, + 0x21, 0xC3, 0xFC, 0x42, 0x6C, 0x72, 0xFC, 0x34, 0xFC, 0x84, 0xA0, 0x03, 0x92, 0x45, 0x61, 0x63, + 0x65, 0x6B, 0x73, 0xF5, 0xDD, 0xFC, 0x2A, 0xF5, 0xDD, 0xFB, 0x5D, 0xFC, 0x2A, 0xC1, 0x03, 0xB2, + 0x2E, 0xFB, 0xFB, 0xA4, 0x02, 0x01, 0x61, 0x65, 0x69, 0x6F, 0xE0, 0xE7, 0xEA, 0xFA, 0x41, 0x6B, + 0xFC, 0x30, 0x42, 0x63, 0x6B, 0xFB, 0x78, 0xF8, 0xC9, 0x44, 0x61, 0x6A, 0x6F, 0x73, 0xFF, 0xF9, + 0xF6, 0x3B, 0xFB, 0x45, 0xF5, 0xA5, 0x41, 0x67, 0xFB, 0xD2, 0x21, 0x6E, 0xFC, 0xC8, 0x01, 0xD1, + 0x61, 0x65, 0x69, 0x6A, 0x72, 0x73, 0x74, 0x75, 0xFF, 0xAB, 0xFB, 0x1D, 0xFF, 0xB3, 0xFB, 0xCB, + 0xFF, 0xD6, 0xFF, 0xE1, 0xFF, 0xEC, 0xFF, 0xFD, 0x41, 0x6D, 0xFB, 0x72, 0x43, 0x61, 0x6F, 0x73, + 0xF5, 0xBF, 0xFF, 0xFC, 0xF5, 0x6C, 0xC2, 0x03, 0x61, 0x62, 0x74, 0xF5, 0x81, 0xFF, 0xF6, 0xC1, + 0x03, 0xD2, 0x72, 0xFB, 0xC5, 0xA0, 0x03, 0xD2, 0xA0, 0x03, 0xF2, 0x21, 0xA4, 0xFD, 0x45, 0x61, + 0x67, 0x69, 0x72, 0xC3, 0xFF, 0xF1, 0xFB, 0x1C, 0xFF, 0xF7, 0xF5, 0x5C, 0xFF, 0xFD, 0x41, 0xA5, + 0xFA, 0xCC, 0x55, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, + 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0xC3, 0xFA, 0xCB, 0xFA, 0xF1, 0xFB, 0x21, 0xFB, 0x34, + 0xFB, 0x52, 0xFB, 0x7C, 0xFB, 0x92, 0xFB, 0x98, 0xFB, 0x9F, 0xFB, 0xED, 0xFC, 0x73, 0xFC, 0xA3, + 0xFD, 0x52, 0xFB, 0x9F, 0xFD, 0xC0, 0xFE, 0x6F, 0xFF, 0x2B, 0xFF, 0xAB, 0xFF, 0xD4, 0xFF, 0xEC, + 0xFF, 0xFC, 0x43, 0x69, 0x6F, 0x73, 0xF5, 0x92, 0xF5, 0x92, 0xF5, 0x98, 0x43, 0x6C, 0x6F, 0x75, + 0xF4, 0xEC, 0xF5, 0x88, 0xF5, 0x88, 0x41, 0x6C, 0xF5, 0xB4, 0x21, 0x6B, 0xFC, 0x42, 0x61, 0x75, + 0xF5, 0x08, 0xF4, 0xFA, 0x21, 0x74, 0xF9, 0xA4, 0x03, 0x01, 0x64, 0x6B, 0x6E, 0x73, 0xDB, 0xE5, + 0xF3, 0xFD, 0x42, 0x6B, 0x74, 0xFB, 0x06, 0xFB, 0x32, 0xC1, 0x00, 0x71, 0x65, 0xFA, 0xD4, 0xC5, + 0x03, 0x31, 0x61, 0x62, 0x6C, 0x72, 0x73, 0xFF, 0xF3, 0xF4, 0xE6, 0xFF, 0xFA, 0xFE, 0xEB, 0xFD, + 0xC9, 0x41, 0x72, 0xF5, 0xCF, 0x42, 0xA5, 0xB6, 0xF4, 0xB5, 0xF4, 0xC2, 0x44, 0x64, 0x75, 0x79, + 0xC3, 0xFB, 0x4B, 0xF4, 0xBB, 0xF4, 0xAE, 0xFF, 0xF9, 0x42, 0x67, 0xC3, 0xF4, 0xD6, 0xFB, 0x99, + 0x41, 0xB6, 0xF7, 0xE0, 0x21, 0xC3, 0xFC, 0x42, 0x61, 0x65, 0xF5, 0x1D, 0xF5, 0x1D, 0xC4, 0x02, + 0x81, 0x6C, 0x73, 0x74, 0x75, 0xF4, 0x8C, 0xF4, 0x7A, 0xFF, 0xF9, 0xF4, 0x99, 0x42, 0x72, 0x76, + 0xF4, 0x7D, 0xF4, 0x7D, 0xCA, 0x03, 0x01, 0x64, 0x65, 0x6B, 0x6C, 0x6E, 0x72, 0x73, 0x74, 0x75, + 0x78, 0xFF, 0xBD, 0xF4, 0x83, 0xF7, 0xBC, 0xFF, 0xC8, 0xFF, 0xD5, 0xFF, 0xE0, 0xFF, 0xEA, 0xFF, + 0xF9, 0xF4, 0x76, 0xFB, 0x13, 0xA0, 0x04, 0x32, 0xA0, 0x04, 0x52, 0x41, 0x76, 0xFA, 0xEC, 0x42, + 0x6F, 0x76, 0xF4, 0x3F, 0xF4, 0x58, 0x21, 0x6B, 0xF9, 0xC3, 0x03, 0x01, 0x64, 0x6E, 0x73, 0xF5, + 0x57, 0xFF, 0xF2, 0xFF, 0xFD, 0x41, 0x65, 0xFA, 0x82, 0x42, 0x72, 0x74, 0xF9, 0xB1, 0xF9, 0xB1, + 0xA0, 0x04, 0x71, 0x21, 0x61, 0xFD, 0x44, 0x6D, 0x6E, 0x72, 0x73, 0xFB, 0x8F, 0xF9, 0xA4, 0xFF, + 0xFD, 0xFA, 0x14, 0x42, 0x72, 0x73, 0xFA, 0x07, 0xFA, 0x07, 0x22, 0x64, 0x6B, 0xE6, 0xF9, 0x23, + 0x61, 0x65, 0x69, 0xDA, 0xE7, 0xFB, 0x41, 0x6C, 0xF7, 0x15, 0x41, 0x75, 0xF7, 0x46, 0x41, 0x65, + 0xF4, 0xBC, 0x21, 0x74, 0xFC, 0xC1, 0x02, 0xA1, 0x6C, 0xF4, 0x1D, 0x43, 0x69, 0x72, 0x73, 0xF4, + 0x0A, 0xF4, 0x17, 0xFF, 0xFA, 0x22, 0x73, 0x74, 0xED, 0xF6, 0xC1, 0x02, 0x81, 0x63, 0xF4, 0x6A, + 0xC7, 0x03, 0x01, 0x67, 0x6B, 0x6D, 0x6E, 0x72, 0x73, 0x79, 0xF9, 0xDD, 0xFF, 0xD6, 0xFF, 0xDA, + 0xFF, 0xB0, 0xFF, 0xF5, 0xFF, 0xFA, 0xF3, 0xC8, 0x41, 0x69, 0xFF, 0x70, 0x43, 0x66, 0x72, 0x74, + 0xFF, 0x6C, 0xFA, 0x5B, 0xFF, 0xFC, 0x41, 0xB6, 0xF9, 0x34, 0x45, 0x2E, 0x61, 0x65, 0x73, 0xC3, + 0xF9, 0xA0, 0xF9, 0xFD, 0xF9, 0xA0, 0xF9, 0xA0, 0xFF, 0xFC, 0x21, 0x6B, 0xF0, 0x41, 0x74, 0xF3, + 0xB8, 0x21, 0x73, 0xFC, 0x41, 0xB6, 0xF9, 0x86, 0x45, 0x61, 0x69, 0x75, 0x79, 0xC3, 0xFF, 0xD4, + 0xFF, 0xF2, 0xFF, 0xF9, 0xF9, 0x82, 0xFF, 0xFC, 0x42, 0x65, 0x68, 0xF9, 0x02, 0xF3, 0x82, 0x41, + 0x61, 0xFC, 0x12, 0xC1, 0x00, 0xA1, 0x6A, 0xF9, 0xA5, 0xC5, 0x03, 0xF2, 0x63, 0x6C, 0x6F, 0x70, + 0x74, 0xFF, 0xEF, 0xFF, 0xF6, 0xFA, 0xC1, 0xF9, 0x9F, 0xFF, 0xFA, 0x41, 0x64, 0xF4, 0x50, 0xC2, + 0x03, 0x01, 0x6E, 0x73, 0xFF, 0xFC, 0xF5, 0xBB, 0xC1, 0x03, 0x01, 0x72, 0xF3, 0x5F, 0xC2, 0x03, + 0x01, 0x6E, 0x74, 0xF8, 0x30, 0xF5, 0xEB, 0xC1, 0x03, 0x01, 0x72, 0xF5, 0xE2, 0x43, 0xA5, 0xA4, + 0xB6, 0xFF, 0xF1, 0xF9, 0x2D, 0xFF, 0xFA, 0xD5, 0x04, 0x12, 0x61, 0x62, 0x64, 0x65, 0x66, 0x68, + 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0x79, 0xC3, 0xFE, + 0x50, 0xFE, 0x68, 0xFD, 0xD1, 0xFE, 0xBD, 0xFE, 0xDE, 0xFE, 0xE1, 0xFE, 0xF2, 0xFE, 0xFE, 0xF9, + 0x80, 0xFF, 0x28, 0xFD, 0xD1, 0xFE, 0xDE, 0xFF, 0x59, 0xFD, 0xD1, 0xFF, 0xA1, 0xFF, 0xC2, 0xFD, + 0xD1, 0xFF, 0xD8, 0xF9, 0x80, 0xFF, 0xE1, 0xFF, 0xF6, 0x41, 0x70, 0xFE, 0xC7, 0x41, 0x74, 0xF3, + 0x15, 0x41, 0x72, 0xF8, 0xD9, 0x22, 0x73, 0x74, 0xF8, 0xFC, 0xC2, 0x04, 0x82, 0x6E, 0x75, 0xFF, + 0xFB, 0xFA, 0x7C, 0x41, 0x75, 0xF8, 0xC7, 0x41, 0x66, 0xF8, 0xC3, 0x41, 0x63, 0xFE, 0xA5, 0x41, + 0x72, 0xF4, 0xDE, 0x42, 0xA4, 0xB6, 0xF3, 0x96, 0xFF, 0xFC, 0x46, 0x2E, 0x61, 0x65, 0x6F, 0x74, + 0xC3, 0xF9, 0x5D, 0xFF, 0xE9, 0xFF, 0xED, 0xFF, 0xF1, 0xF9, 0x5D, 0xFF, 0xF9, 0x41, 0x70, 0xF2, + 0xE2, 0xC3, 0x02, 0xF1, 0x6C, 0x6D, 0x70, 0xF8, 0x01, 0xF3, 0x81, 0xFF, 0xFC, 0x41, 0x73, 0xF2, + 0xAA, 0xA1, 0x02, 0x81, 0x69, 0xFC, 0x43, 0x64, 0x67, 0x74, 0xFB, 0x2B, 0xF2, 0x94, 0xF8, 0xC2, + 0xA1, 0x01, 0x91, 0x72, 0xF6, 0xC1, 0x00, 0x71, 0x65, 0xF3, 0x0F, 0x41, 0x6C, 0xF5, 0xAE, 0x41, + 0xA4, 0xF2, 0x7B, 0x43, 0x61, 0x65, 0xC3, 0xF2, 0x77, 0xF2, 0x77, 0xFF, 0xFC, 0x42, 0xA4, 0xB6, + 0xF2, 0x7A, 0xF2, 0x6D, 0xCC, 0x03, 0x31, 0x61, 0x65, 0x69, 0x6A, 0x6C, 0x6E, 0x6F, 0x72, 0x73, + 0x75, 0x76, 0xC3, 0xF8, 0xB3, 0xF8, 0xB3, 0xF8, 0xB3, 0xF2, 0x73, 0xFF, 0xCD, 0xF2, 0x66, 0xFF, + 0xDC, 0xFF, 0xE1, 0xFF, 0xE7, 0xF5, 0x05, 0xFF, 0xEF, 0xFF, 0xF9, 0x41, 0x61, 0xF3, 0x17, 0x21, + 0x65, 0xFC, 0x42, 0x61, 0x6D, 0xF5, 0x49, 0xF2, 0xC2, 0xC1, 0x03, 0x31, 0x6F, 0xF4, 0xD0, 0xCB, + 0x02, 0x01, 0x61, 0x63, 0x65, 0x68, 0x69, 0x6B, 0x6C, 0x6F, 0x72, 0x73, 0x79, 0xFF, 0x3A, 0xF8, + 0x78, 0xFF, 0x4B, 0xFF, 0x6B, 0xFF, 0x82, 0xFF, 0xC5, 0xFF, 0xF0, 0xFF, 0xF3, 0xFF, 0xFA, 0xF8, + 0xC8, 0xF7, 0xEB, 0x41, 0x72, 0xF8, 0xA4, 0xC1, 0x03, 0x61, 0x6F, 0xFD, 0xD9, 0xC1, 0x04, 0x71, + 0xC3, 0xF8, 0xF5, 0x41, 0x2E, 0xF8, 0x94, 0x21, 0x64, 0xFC, 0xA0, 0x04, 0xA2, 0x42, 0x62, 0x74, + 0xF8, 0x8A, 0xF8, 0x8A, 0x42, 0x72, 0x74, 0xF2, 0x70, 0xF1, 0xD4, 0xCB, 0x03, 0x01, 0x2E, 0x64, + 0x67, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x74, 0x78, 0xFD, 0xB5, 0xFF, 0xD8, 0xF5, 0x04, 0xFF, + 0xDC, 0xF8, 0x5E, 0xFF, 0xE2, 0xFF, 0xEC, 0xFF, 0xEF, 0xFF, 0xF2, 0xFF, 0xF9, 0xF8, 0x7C, 0x41, + 0x6E, 0xF1, 0xE3, 0xA1, 0x03, 0x31, 0x65, 0xFC, 0x41, 0x73, 0xF7, 0xE0, 0x44, 0x61, 0x65, 0x69, + 0xC3, 0xF1, 0xAE, 0xF1, 0xAE, 0xF1, 0xAE, 0xFA, 0xD1, 0xC1, 0x00, 0xD1, 0x76, 0xF1, 0x95, 0xC6, + 0x03, 0x61, 0x64, 0x69, 0x6A, 0x6F, 0x72, 0x73, 0xF1, 0xB6, 0xF9, 0x37, 0xF7, 0xE8, 0xFF, 0xE9, + 0xFF, 0xED, 0xFF, 0xFA, 0xC1, 0x02, 0x82, 0x6F, 0xF8, 0x23, 0x41, 0x69, 0xF2, 0x40, 0x42, 0x61, + 0x74, 0xF2, 0x54, 0xFF, 0xFC, 0x43, 0x64, 0x73, 0x75, 0xF8, 0x12, 0xFF, 0xF9, 0xF8, 0x7F, 0x41, + 0xB6, 0xF2, 0xC4, 0x21, 0xC3, 0xFC, 0x42, 0x69, 0x6F, 0xFF, 0xFD, 0xF2, 0x3C, 0xA1, 0x00, 0x91, + 0x74, 0xF9, 0xC1, 0x00, 0xD1, 0x6C, 0xF1, 0x65, 0xC4, 0x04, 0x71, 0x6B, 0x6F, 0x73, 0x75, 0xF1, + 0xAD, 0xFF, 0xFA, 0xF4, 0xC8, 0xF1, 0xDC, 0xC3, 0x00, 0xD1, 0x65, 0x70, 0x74, 0xF1, 0x43, 0xF1, + 0x43, 0xF9, 0x0E, 0xC1, 0x00, 0x91, 0x72, 0xF1, 0x37, 0xC8, 0x04, 0xC2, 0x6B, 0x6C, 0x6E, 0x70, + 0x72, 0x73, 0x74, 0x78, 0xFF, 0xAB, 0xFF, 0xBC, 0xFF, 0xD4, 0xF2, 0x86, 0xFF, 0xDF, 0xFF, 0xEE, + 0xFF, 0xFA, 0xF7, 0xCE, 0x41, 0x72, 0xF4, 0x9F, 0x21, 0xB6, 0xFC, 0xA1, 0x03, 0xD2, 0xC3, 0xFD, + 0xC1, 0x03, 0xD2, 0x6C, 0xF7, 0x57, 0x41, 0x72, 0xF4, 0x15, 0x42, 0x61, 0x75, 0xF1, 0x00, 0xF1, + 0x0D, 0x41, 0x6F, 0xF1, 0x89, 0xC1, 0x03, 0x31, 0x70, 0xF9, 0x9B, 0x45, 0x66, 0x67, 0x72, 0x73, + 0x74, 0xF7, 0x8C, 0xFF, 0xF6, 0xF7, 0x8C, 0xFF, 0xFA, 0xF7, 0x8C, 0xC1, 0x02, 0x81, 0x64, 0xF1, + 0x69, 0x42, 0x6F, 0x72, 0xF0, 0xCD, 0xF1, 0x34, 0x41, 0x61, 0xF0, 0xC6, 0x42, 0x6F, 0x72, 0xF0, + 0xBC, 0xFF, 0xFC, 0x45, 0x63, 0x6A, 0x6B, 0x70, 0x74, 0xF0, 0xC7, 0xF1, 0x51, 0xFF, 0xEE, 0xF1, + 0x22, 0xFF, 0xF9, 0x41, 0x72, 0xF8, 0xB2, 0xC8, 0x03, 0x01, 0x61, 0x65, 0x67, 0x6B, 0x6E, 0x6F, + 0x73, 0x74, 0xF1, 0xA4, 0xF0, 0xCB, 0xFF, 0xAF, 0xFF, 0xB3, 0xFF, 0xC4, 0xFF, 0xD4, 0xFF, 0xEC, + 0xFF, 0xFC, 0x41, 0x72, 0xF6, 0xE5, 0x42, 0x70, 0x72, 0xF9, 0x96, 0xF6, 0x84, 0xA2, 0x03, 0x61, + 0x6F, 0x75, 0xF5, 0xF9, 0xA0, 0x04, 0xE3, 0xA0, 0x05, 0x12, 0xC1, 0x02, 0x01, 0x6F, 0xF0, 0x8D, + 0x42, 0x72, 0x73, 0xF7, 0x17, 0xF4, 0x4F, 0x41, 0x6B, 0xF0, 0xFD, 0x21, 0x61, 0xFC, 0x43, 0x64, + 0x69, 0x74, 0xFF, 0xE9, 0xF7, 0x09, 0xF7, 0x09, 0x41, 0x74, 0xF5, 0xE2, 0xC7, 0x03, 0x01, 0x6C, + 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x79, 0xFF, 0xDE, 0xFF, 0xE4, 0xFC, 0x34, 0xFF, 0xEF, 0xFF, 0xF2, + 0xFF, 0xFC, 0xF0, 0x5E, 0xA0, 0x05, 0x62, 0x41, 0x64, 0xF6, 0x90, 0x41, 0x62, 0xF5, 0xBF, 0x41, + 0x61, 0xF5, 0xBB, 0x21, 0x72, 0xFC, 0x21, 0x65, 0xFD, 0x21, 0x73, 0xFD, 0x41, 0x75, 0xF5, 0xAE, + 0x46, 0x64, 0x67, 0x6E, 0x72, 0x73, 0x74, 0xF6, 0x77, 0xFF, 0xE4, 0xFF, 0xE7, 0xFF, 0xEB, 0xFF, + 0xF9, 0xFF, 0xFC, 0x44, 0x6A, 0x6E, 0x73, 0x74, 0xF6, 0x07, 0xF6, 0x64, 0xFB, 0xED, 0xF6, 0x64, + 0x46, 0x63, 0x66, 0x67, 0x6B, 0x6E, 0x76, 0xF6, 0x38, 0xF5, 0xFA, 0xF6, 0x57, 0xFF, 0x87, 0xF6, + 0x57, 0xFF, 0xC4, 0x41, 0x70, 0xF5, 0xE7, 0xC1, 0x03, 0x31, 0x74, 0xF3, 0xDE, 0x44, 0x63, 0x70, + 0x72, 0x74, 0xF5, 0x6D, 0xFF, 0xF6, 0xF6, 0x3A, 0xFF, 0xFA, 0x42, 0x6E, 0x74, 0xF6, 0x2D, 0xF5, + 0xD0, 0x43, 0x6B, 0x6E, 0x74, 0xFF, 0xF9, 0xFB, 0xAF, 0xF6, 0x26, 0x42, 0xA4, 0xB6, 0xFF, 0xF6, + 0xF5, 0xBB, 0xA5, 0x05, 0x33, 0x61, 0x65, 0x69, 0x6F, 0xC3, 0x9E, 0xB1, 0xBE, 0xDB, 0xF9, 0xA0, + 0x05, 0x82, 0x21, 0x6E, 0xFD, 0x41, 0x68, 0xEF, 0xC2, 0xA1, 0x02, 0x01, 0x6E, 0xFC, 0xC1, 0x02, + 0x01, 0x6E, 0xF9, 0x15, 0x42, 0x66, 0x6E, 0xF5, 0xF3, 0xF0, 0x30, 0xC4, 0x01, 0x01, 0x65, 0x69, + 0x6C, 0x6E, 0xFF, 0xF9, 0xF5, 0xEC, 0xEF, 0x9F, 0xEF, 0xAC, 0x41, 0x74, 0xF0, 0x1A, 0xA1, 0x02, + 0x81, 0x6F, 0xFC, 0x41, 0xA5, 0xF5, 0xB5, 0x42, 0x6F, 0xC3, 0xF0, 0x0D, 0xFF, 0xFC, 0x41, 0xA5, + 0xEF, 0x89, 0x21, 0xC3, 0xFC, 0x42, 0x6C, 0x74, 0xEF, 0x75, 0xF4, 0xF5, 0xC1, 0x00, 0x41, 0x61, + 0xEF, 0xA3, 0x42, 0x67, 0x6E, 0xF4, 0xE8, 0xEF, 0x68, 0x41, 0x6F, 0xEF, 0x6E, 0x24, 0x61, 0x65, + 0x69, 0x72, 0xE8, 0xEF, 0xF5, 0xFC, 0x41, 0xB6, 0xF5, 0x6E, 0xD0, 0x03, 0x31, 0x61, 0x65, 0x66, + 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x73, 0x74, 0x75, 0x76, 0xC3, 0xFF, 0x98, 0xFF, + 0x9F, 0xF5, 0x7E, 0xFF, 0xA4, 0xF5, 0x6A, 0xFF, 0xB1, 0xFF, 0xC4, 0xFF, 0xCD, 0xFF, 0xD8, 0xF5, + 0x6A, 0xF5, 0x18, 0xF0, 0x66, 0xFF, 0xF3, 0xF5, 0x6A, 0xF2, 0x96, 0xFF, 0xFC, 0x41, 0x65, 0xEF, + 0x11, 0x21, 0x6C, 0xFC, 0x21, 0x62, 0xFD, 0x41, 0xB6, 0xEF, 0x20, 0xC3, 0x02, 0x81, 0x63, 0x74, + 0xC3, 0xF2, 0x20, 0xF7, 0x0A, 0xFF, 0xFC, 0xC5, 0x03, 0x01, 0x62, 0x70, 0x73, 0x74, 0x76, 0xFF, + 0xED, 0xF5, 0xA0, 0xFF, 0xF4, 0xF5, 0xA0, 0xF4, 0x5B, 0xC1, 0x03, 0xD2, 0x72, 0xF5, 0x3E, 0xC2, + 0x03, 0x01, 0x6B, 0x72, 0xF7, 0x29, 0xF7, 0xE9, 0x43, 0x67, 0x73, 0x74, 0xFA, 0xB8, 0xF7, 0x88, + 0xF5, 0x7F, 0x42, 0x67, 0x72, 0xF5, 0x75, 0xEF, 0xB0, 0x41, 0x73, 0xEF, 0xAC, 0xC4, 0x03, 0x01, + 0x64, 0x67, 0x70, 0x73, 0xFF, 0xFC, 0xF5, 0x6A, 0xF5, 0x6A, 0xFE, 0x6B, 0x44, 0xA5, 0xA4, 0xB6, + 0xA9, 0xFF, 0xDC, 0xFF, 0xE6, 0xFF, 0xF1, 0xEE, 0xD9, 0xD9, 0x02, 0xF1, 0x61, 0x62, 0x63, 0x64, + 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x79, 0x7A, 0xC3, 0xFC, 0xD2, 0xF7, 0x57, 0xFC, 0xFA, 0xFD, 0x16, 0xFD, 0x80, 0xFD, + 0xA2, 0xFD, 0xA7, 0xFA, 0x5F, 0xFD, 0xFE, 0xFE, 0x24, 0xFE, 0x2B, 0xFE, 0x2E, 0xF9, 0x4C, 0xF9, + 0x4C, 0xFE, 0x53, 0xF9, 0x4C, 0xFE, 0xE9, 0xFF, 0x61, 0xFA, 0x5C, 0xFF, 0xAE, 0xFF, 0xC0, 0xFA, + 0x5C, 0xFF, 0xC6, 0xF5, 0x4E, 0xFF, 0xF3, 0x41, 0x65, 0xF4, 0x7D, 0xC2, 0x01, 0xD1, 0x6B, 0x6D, + 0xFF, 0xFC, 0xF4, 0x8D, 0xC1, 0x02, 0x01, 0x69, 0xF4, 0x1E, 0xA1, 0x03, 0x31, 0x72, 0xFA, 0x41, + 0x66, 0xF1, 0x09, 0x21, 0x66, 0xFC, 0xA1, 0x01, 0x91, 0x69, 0xFD, 0xC3, 0x03, 0x31, 0x68, 0x69, + 0x6F, 0xFF, 0xFB, 0xEF, 0x30, 0xF4, 0x8C, 0x41, 0x6E, 0xFC, 0x81, 0x41, 0x75, 0xEE, 0x4A, 0x41, + 0x6C, 0xF3, 0xAB, 0x21, 0x61, 0xFC, 0xC1, 0x02, 0x81, 0x6F, 0xF1, 0x35, 0xA0, 0x05, 0xA2, 0x43, + 0x6B, 0x6C, 0x6F, 0xFF, 0xF7, 0xFF, 0xFD, 0xEE, 0x50, 0x41, 0xA5, 0xF4, 0x5E, 0xC7, 0x02, 0x01, + 0x61, 0x64, 0x69, 0x6A, 0x72, 0x73, 0xC3, 0xFF, 0xDA, 0xEE, 0x2B, 0xFF, 0xDE, 0xEE, 0x0D, 0xFF, + 0xE6, 0xFF, 0xF2, 0xFF, 0xFC, 0x42, 0x2E, 0x65, 0xF4, 0x23, 0xF4, 0x23, 0xC4, 0x01, 0xD1, 0x64, + 0x69, 0x6B, 0x6E, 0xF4, 0x08, 0xF4, 0x1C, 0xEE, 0x2F, 0xFF, 0xF9, 0x41, 0x65, 0xF3, 0xCF, 0xC2, + 0x01, 0xD1, 0x73, 0x74, 0xEE, 0x65, 0xFF, 0xFC, 0xC1, 0x01, 0x91, 0x6C, 0xEE, 0xAA, 0xC2, 0x00, + 0xD1, 0x61, 0x69, 0xF4, 0x19, 0xF3, 0x4C, 0x21, 0x72, 0xF7, 0xA1, 0x02, 0x81, 0x65, 0xFD, 0x42, + 0x6E, 0x74, 0xF3, 0xE9, 0xED, 0xC8, 0x41, 0x6E, 0xED, 0xB4, 0x43, 0x61, 0x69, 0x75, 0xFF, 0xF5, + 0xFF, 0xFC, 0xF3, 0x30, 0xC6, 0x01, 0xD1, 0x61, 0x65, 0x6C, 0x72, 0x73, 0xC3, 0xF3, 0xF3, 0xFF, + 0xD4, 0xFF, 0xE6, 0xFF, 0xF6, 0xED, 0x9A, 0xF8, 0x5A, 0xC1, 0x01, 0x01, 0x6E, 0xED, 0x9E, 0x42, + 0x68, 0x6B, 0xED, 0x98, 0xF3, 0xE2, 0x44, 0x67, 0x6B, 0x6E, 0x73, 0xFF, 0xF3, 0xF3, 0xD1, 0xF3, + 0xDB, 0xFF, 0xF9, 0x42, 0xA4, 0xB6, 0xF3, 0xC4, 0xF2, 0xF7, 0x43, 0x6F, 0x75, 0xC3, 0xF3, 0xC7, + 0xF3, 0xBD, 0xFF, 0xF9, 0xC2, 0x01, 0xD1, 0x61, 0x65, 0xED, 0xC7, 0xED, 0xF0, 0x42, 0x64, 0x72, + 0xEE, 0xE3, 0xED, 0x5D, 0xA1, 0x01, 0xD1, 0x72, 0xF9, 0x41, 0x2E, 0xED, 0xDB, 0x21, 0x74, 0xFC, + 0x42, 0x65, 0x6F, 0xFF, 0xFD, 0xED, 0x57, 0x42, 0x65, 0x69, 0xF3, 0x9A, 0xFA, 0xA6, 0x41, 0xA4, + 0xF3, 0x93, 0x4A, 0x61, 0x69, 0x6C, 0x6E, 0x6F, 0x72, 0x75, 0x76, 0x79, 0xC3, 0xF3, 0x85, 0xF3, + 0x8F, 0xFF, 0xD2, 0xED, 0x38, 0xFF, 0xE2, 0xFF, 0xEE, 0xF3, 0x8F, 0xFF, 0xF5, 0xF3, 0x8F, 0xFF, + 0xFC, 0x41, 0x74, 0xF0, 0x5F, 0x41, 0x62, 0xED, 0x9F, 0xA2, 0x01, 0xD1, 0x6B, 0x72, 0xF8, 0xFC, + 0x41, 0x2E, 0xF2, 0xFA, 0x41, 0x69, 0xED, 0xD2, 0x21, 0x72, 0xFC, 0x21, 0x74, 0xFD, 0x42, 0x62, + 0x6B, 0xEE, 0x77, 0xFF, 0xFD, 0x41, 0x72, 0xF3, 0x69, 0x41, 0x6B, 0xF4, 0xB8, 0x43, 0x69, 0x73, + 0xC3, 0xEC, 0xED, 0xEC, 0xE1, 0xFA, 0x72, 0xC1, 0x01, 0xD1, 0x62, 0xF3, 0x11, 0x41, 0x69, 0xEF, + 0xEE, 0x42, 0x67, 0x76, 0xEC, 0xE6, 0xF2, 0x59, 0x41, 0xA4, 0xF7, 0x6D, 0x4C, 0x61, 0x64, 0x65, + 0x66, 0x69, 0x6B, 0x6C, 0x6F, 0x70, 0x73, 0x75, 0xC3, 0xFF, 0xBD, 0xFF, 0xC4, 0xFF, 0xD2, 0xFF, + 0xD9, 0xFF, 0xDD, 0xED, 0xE4, 0xFF, 0xE1, 0xFF, 0xEB, 0xEC, 0xCE, 0xFF, 0xF1, 0xFF, 0xF5, 0xFF, + 0xFC, 0x41, 0x73, 0xF2, 0x29, 0x41, 0x73, 0xEF, 0x8B, 0x42, 0x6E, 0x72, 0xFF, 0xFC, 0xF3, 0xAB, + 0x41, 0x65, 0xEC, 0x88, 0x21, 0x6C, 0xFC, 0xC4, 0x01, 0xD1, 0x61, 0x69, 0x6F, 0x70, 0xFC, 0x31, + 0xFF, 0xEA, 0xFF, 0xF2, 0xFF, 0xFD, 0x42, 0x72, 0x76, 0xF3, 0x8E, 0xF2, 0x9E, 0x41, 0xB6, 0xEC, + 0x71, 0x21, 0xC3, 0xFC, 0x43, 0x64, 0x6B, 0x72, 0xF2, 0xA4, 0xF2, 0xA4, 0xFF, 0xFD, 0x41, 0xA4, + 0xEC, 0x79, 0x44, 0x6C, 0x6E, 0x72, 0xC3, 0xFD, 0x07, 0xEC, 0x68, 0xEC, 0x75, 0xFF, 0xFC, 0xC1, + 0x02, 0x61, 0x73, 0xEE, 0x87, 0x21, 0x67, 0xFA, 0x21, 0x6E, 0xFD, 0x21, 0x69, 0xFD, 0x41, 0x69, + 0xEF, 0x38, 0x41, 0xA5, 0xEC, 0xD2, 0x47, 0x69, 0x6B, 0x6D, 0x70, 0x74, 0x76, 0xC3, 0xEC, 0x44, + 0xFF, 0xAA, 0xED, 0x1C, 0xEF, 0x55, 0xEE, 0xBE, 0xFF, 0xF8, 0xFF, 0xFC, 0x42, 0x2E, 0x69, 0xEC, + 0x49, 0xEC, 0x22, 0x21, 0x74, 0xF9, 0xC3, 0x01, 0xC2, 0x61, 0x69, 0x75, 0xFF, 0xFD, 0xEC, 0x18, + 0xEC, 0x12, 0x42, 0x68, 0x72, 0xF2, 0x29, 0xFF, 0xF4, 0x4C, 0x61, 0x63, 0x65, 0x6A, 0x6B, 0x6E, + 0x6F, 0x73, 0x74, 0x75, 0x79, 0xC3, 0xFF, 0x8D, 0xF4, 0x0C, 0xFF, 0x9B, 0xF4, 0xB7, 0xFF, 0xA9, + 0xFF, 0xC2, 0xED, 0xDA, 0xFF, 0xCD, 0xFF, 0xF9, 0xFF, 0x68, 0xF4, 0xB7, 0xFF, 0x3F, 0xC3, 0x01, + 0xD1, 0x67, 0x69, 0x72, 0xF2, 0x06, 0xEC, 0x76, 0xF1, 0x6C, 0x42, 0x61, 0x65, 0xF2, 0x2D, 0xEB, + 0xED, 0xC1, 0x05, 0xC2, 0x74, 0xEC, 0x99, 0x21, 0x73, 0xFA, 0x41, 0x62, 0xEB, 0xC4, 0xC9, 0x03, + 0x61, 0x65, 0x69, 0x6C, 0x70, 0x72, 0x73, 0x74, 0x75, 0xC3, 0xF2, 0x23, 0xF2, 0x23, 0xFF, 0xEC, + 0xFF, 0xF9, 0xF2, 0x23, 0xEB, 0xCC, 0xF1, 0xCF, 0xFF, 0xFC, 0xFD, 0xBB, 0x42, 0x6B, 0x73, 0xEE, + 0xF4, 0xF2, 0x4B, 0x41, 0xA5, 0xF1, 0x3B, 0x43, 0x6C, 0x75, 0xC3, 0xEB, 0xBE, 0xEC, 0x2D, 0xFF, + 0xFC, 0x42, 0x66, 0x67, 0xF1, 0xC7, 0xEF, 0x84, 0xC3, 0x01, 0xD1, 0x62, 0x6E, 0x73, 0xF1, 0x12, + 0xFF, 0xF9, 0xF2, 0x76, 0x41, 0x6C, 0xFF, 0x3A, 0x41, 0xA4, 0xED, 0x95, 0x21, 0xC3, 0xFC, 0x41, + 0x61, 0xEB, 0x88, 0xC2, 0x01, 0xD1, 0x62, 0x6D, 0xF1, 0xC4, 0xF1, 0x91, 0x41, 0x65, 0xEE, 0x5A, + 0xC1, 0x00, 0x71, 0x65, 0xEB, 0x85, 0x43, 0x61, 0x65, 0x72, 0xEB, 0xEE, 0xEE, 0x75, 0xEB, 0x64, + 0x45, 0x63, 0x6B, 0x6C, 0x74, 0x76, 0xEB, 0x67, 0xFF, 0xEC, 0xFF, 0xF0, 0xFF, 0xF6, 0xEB, 0x5A, + 0xC1, 0x01, 0xD1, 0x6D, 0xF0, 0xCA, 0x42, 0xA5, 0xA4, 0xF1, 0x30, 0xF1, 0x9B, 0x4E, 0x61, 0x64, + 0x67, 0x69, 0x6B, 0x6C, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x75, 0x79, 0xC3, 0xFF, 0x8F, 0xEC, 0x53, + 0xFF, 0x9A, 0xFF, 0xAB, 0xFF, 0xB7, 0xFF, 0xBF, 0xFF, 0xC2, 0xFF, 0xC6, 0xEB, 0x58, 0xEE, 0x6C, + 0xFF, 0xE3, 0xFF, 0xF3, 0xF1, 0x8A, 0xFF, 0xF9, 0xC1, 0x02, 0x01, 0x6C, 0xEB, 0x1F, 0x41, 0x6D, + 0xEB, 0x0C, 0x22, 0x6C, 0x72, 0xF6, 0xFC, 0x41, 0x69, 0xEB, 0x8D, 0x42, 0x6E, 0x72, 0xF1, 0x2D, + 0xEB, 0x0C, 0x42, 0x6E, 0x72, 0xF5, 0x18, 0xEA, 0xF8, 0xC3, 0x00, 0xD1, 0x61, 0x65, 0x75, 0xFF, + 0xF2, 0xFF, 0xF9, 0xEB, 0x09, 0xC1, 0x01, 0xD1, 0x61, 0xF0, 0x91, 0xC1, 0x01, 0xD1, 0x6C, 0xEA, + 0xDF, 0x41, 0xA4, 0xEA, 0xC7, 0x21, 0xC3, 0xFC, 0x43, 0x6B, 0x6C, 0x74, 0xED, 0xE3, 0xFF, 0xFD, + 0xED, 0xE3, 0x41, 0x6C, 0xF1, 0x15, 0x41, 0x2E, 0xEA, 0xD1, 0x21, 0x6E, 0xFC, 0x42, 0x67, 0x6E, + 0xEF, 0x3C, 0xEA, 0xBD, 0x21, 0x72, 0xF2, 0x41, 0x72, 0xEA, 0xA1, 0x41, 0xB6, 0xEA, 0xCA, 0xC3, + 0x00, 0x41, 0x65, 0x75, 0xC3, 0xFF, 0xF8, 0xF0, 0xF8, 0xFF, 0xFC, 0x46, 0x61, 0x65, 0x69, 0x6F, + 0x72, 0xC3, 0xFF, 0xD7, 0xFF, 0xDF, 0xFF, 0xE2, 0xFF, 0xE9, 0xFF, 0xF4, 0xFC, 0x8E, 0x4D, 0x61, + 0x63, 0x65, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x70, 0x73, 0x74, 0x75, 0x79, 0xFF, 0x84, 0xF0, 0xE3, + 0xF3, 0x32, 0xFF, 0x89, 0xFC, 0x5D, 0xFF, 0x9B, 0xFF, 0xA7, 0xFD, 0xAF, 0xFF, 0xAD, 0xFF, 0xBA, + 0xFF, 0xED, 0xED, 0x9D, 0xF0, 0xE3, 0xC1, 0x00, 0xE1, 0xC3, 0xFD, 0xE7, 0x42, 0x2E, 0x73, 0xEF, + 0xDE, 0xEA, 0x5E, 0x42, 0x69, 0xC3, 0xFF, 0xF9, 0xF2, 0xCB, 0x41, 0x64, 0xEB, 0x28, 0xC6, 0x00, + 0xD1, 0x61, 0x6B, 0x6C, 0x6D, 0x70, 0x76, 0xFF, 0xFC, 0xF1, 0xFA, 0xEA, 0xA7, 0xEA, 0x40, 0xEC, + 0x19, 0xEA, 0xD6, 0x41, 0x69, 0xEA, 0x52, 0xA1, 0x01, 0xD1, 0x72, 0xFC, 0x42, 0x61, 0x75, 0xEA, + 0xB8, 0xEA, 0x3B, 0xC1, 0x01, 0xD1, 0x63, 0xEC, 0x3A, 0x21, 0xA4, 0xFA, 0x4B, 0x61, 0x69, 0x6F, + 0x72, 0x73, 0x74, 0x75, 0x76, 0x79, 0x7A, 0xC3, 0xFE, 0x4E, 0xFF, 0xBA, 0xF0, 0x75, 0xFF, 0xC7, + 0xFF, 0xD2, 0xF1, 0xCC, 0xFF, 0xEB, 0xFF, 0xF0, 0xF0, 0x75, 0xF2, 0xC4, 0xFF, 0xFD, 0x41, 0x2E, + 0xEF, 0x7C, 0xA0, 0x05, 0xE2, 0x41, 0x65, 0xFC, 0xA4, 0x41, 0x72, 0xFA, 0x90, 0x46, 0x6B, 0x6D, + 0x70, 0x72, 0x73, 0x74, 0xEA, 0x08, 0xFF, 0xF1, 0xFF, 0xF5, 0xF0, 0x8A, 0xFF, 0xF8, 0xFF, 0xFC, + 0x41, 0x6D, 0xF0, 0x08, 0x21, 0x72, 0xFC, 0xC3, 0x01, 0xD1, 0x61, 0x6A, 0x72, 0xFF, 0xFD, 0xF0, + 0x01, 0xE9, 0xD3, 0x42, 0x70, 0x74, 0xEF, 0xB7, 0xE9, 0xE5, 0x41, 0xA4, 0xF0, 0x5D, 0x56, 0x61, + 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, + 0x74, 0x75, 0x76, 0x78, 0xC3, 0xFB, 0x5D, 0xFB, 0x6C, 0xFB, 0x7D, 0xFB, 0xAF, 0xFB, 0xCE, 0xFB, + 0xE1, 0xFC, 0x16, 0xFC, 0x38, 0xFC, 0x4C, 0xFC, 0x84, 0xFC, 0xEE, 0xFD, 0x29, 0xFD, 0xAB, 0xFD, + 0xD0, 0xFD, 0xF0, 0xFE, 0x7F, 0xFF, 0x30, 0xFF, 0x9E, 0xFF, 0xCF, 0xFF, 0xE9, 0xFF, 0xF5, 0xFF, + 0xFC, 0xC1, 0x00, 0xA1, 0x6B, 0xFC, 0xDF, 0x41, 0x73, 0xF0, 0x10, 0x41, 0x62, 0xF0, 0x0C, 0x42, + 0x68, 0x74, 0xE9, 0x6B, 0xE9, 0xF5, 0x41, 0xB6, 0xE9, 0xEE, 0x21, 0xC3, 0xFC, 0xC6, 0x03, 0x01, + 0x63, 0x6E, 0x72, 0x73, 0x74, 0x76, 0xFF, 0xE4, 0xFF, 0xEA, 0xFF, 0xEE, 0xFF, 0xF2, 0xFF, 0xFD, + 0xEF, 0xFA, 0x42, 0x61, 0x6F, 0xE9, 0x36, 0xE9, 0x48, 0x21, 0x74, 0xF9, 0xC4, 0x03, 0x01, 0x66, + 0x6C, 0x73, 0x78, 0xEF, 0xDB, 0xEC, 0x4F, 0xFF, 0xFD, 0xEF, 0xDB, 0x41, 0x72, 0xF5, 0x33, 0x42, + 0xA4, 0xB6, 0xEF, 0x78, 0xFF, 0xFC, 0xC7, 0x03, 0xD2, 0x66, 0x6C, 0x6E, 0x6F, 0x72, 0x73, 0xC3, + 0xE9, 0x3F, 0xE9, 0x24, 0xE9, 0x24, 0xEF, 0x71, 0xE9, 0x24, 0xE9, 0x3F, 0xFF, 0xF9, 0xA0, 0x04, + 0xF2, 0x41, 0x67, 0xE8, 0xF7, 0xA1, 0x00, 0xD1, 0x69, 0xFC, 0x21, 0x72, 0xFB, 0x41, 0x6D, 0xE8, + 0xEB, 0x21, 0x73, 0xFC, 0x42, 0x61, 0x72, 0xEE, 0xBE, 0xE9, 0x1E, 0x21, 0x6B, 0xF9, 0xC5, 0x03, + 0x01, 0x62, 0x6C, 0x6E, 0x73, 0x74, 0xFF, 0xEC, 0xEF, 0x6B, 0xFF, 0xF3, 0xFF, 0xFD, 0xFC, 0x0F, + 0x41, 0x64, 0xEE, 0xEB, 0xA1, 0x02, 0xF1, 0x6F, 0xFC, 0xC1, 0x03, 0xF2, 0x61, 0xE8, 0xEC, 0xC1, + 0x01, 0x01, 0x6B, 0xEB, 0xB1, 0x41, 0x61, 0xEB, 0xD6, 0x41, 0x6D, 0xF0, 0x2C, 0x41, 0x74, 0xEA, + 0x38, 0xC6, 0x02, 0xF1, 0x66, 0x6C, 0x6D, 0x6E, 0x72, 0x73, 0xEF, 0x56, 0xFF, 0xEE, 0xF4, 0x67, + 0xFF, 0xF4, 0xFF, 0xF8, 0xFF, 0xFC, 0xC1, 0x01, 0x01, 0x70, 0xE9, 0x64, 0x21, 0x6D, 0xFA, 0xC1, + 0x00, 0x91, 0x69, 0xF4, 0x71, 0x42, 0x72, 0x73, 0xFF, 0xFA, 0xE8, 0xB0, 0x43, 0x2E, 0x73, 0x74, + 0xEE, 0xBC, 0xE9, 0x83, 0xF4, 0x64, 0x41, 0x61, 0xE9, 0x44, 0x21, 0x74, 0xFC, 0x21, 0x73, 0xFD, + 0x41, 0x74, 0xFD, 0xC7, 0x21, 0x73, 0xFC, 0x41, 0xA5, 0xE9, 0xCF, 0x26, 0x61, 0x65, 0x69, 0x6F, + 0x75, 0xC3, 0xD1, 0xDA, 0xE1, 0xF2, 0xF9, 0xFC, 0xC7, 0x04, 0x32, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, + 0x74, 0x76, 0xEB, 0x73, 0xEE, 0x90, 0xEE, 0x90, 0xEE, 0x90, 0xEE, 0x90, 0xEE, 0x90, 0xEE, 0x90, + 0xC4, 0x01, 0x91, 0x66, 0x6B, 0x70, 0x72, 0xEE, 0x78, 0xEE, 0x78, 0xEE, 0x78, 0xFE, 0x70, 0x42, + 0x72, 0x78, 0xE8, 0x56, 0xEE, 0x69, 0xC1, 0x01, 0x91, 0x6E, 0xEE, 0x62, 0x46, 0x61, 0x65, 0x69, + 0x6A, 0x74, 0x76, 0xEB, 0x3F, 0xF8, 0x9E, 0xE8, 0x6F, 0xE8, 0xB8, 0xE8, 0x49, 0xFD, 0x59, 0xC8, + 0x03, 0x61, 0x61, 0x65, 0x69, 0x6F, 0x72, 0x73, 0x74, 0x76, 0xFF, 0xD1, 0xFF, 0xE0, 0xFF, 0xE7, + 0xEE, 0x68, 0xF2, 0x3B, 0xFF, 0xED, 0xE8, 0x28, 0xEB, 0x61, 0x42, 0x73, 0x75, 0xF4, 0x08, 0xE8, + 0x0D, 0x41, 0x75, 0xE7, 0xF9, 0xA2, 0x03, 0x01, 0x72, 0x74, 0xF5, 0xFC, 0xC1, 0x04, 0x71, 0x6D, + 0xEE, 0x62, 0x41, 0x74, 0xFB, 0x6F, 0x41, 0x74, 0xF6, 0x64, 0xA1, 0x02, 0xF1, 0x73, 0xFC, 0x41, + 0x6E, 0xE8, 0xB3, 0x42, 0x6D, 0x75, 0xE7, 0xFF, 0xE7, 0xFF, 0x41, 0xB6, 0xEA, 0xB6, 0x47, 0x61, + 0x65, 0x69, 0x6B, 0x73, 0x74, 0xC3, 0xE8, 0xA4, 0xFF, 0xF1, 0xE8, 0xA4, 0xE7, 0xF4, 0xFF, 0xF5, + 0xE9, 0xDF, 0xFF, 0xFC, 0xA1, 0x03, 0x01, 0x72, 0xEA, 0x23, 0xA5, 0xA4, 0xB6, 0xC9, 0xD1, 0xFB, + 0xD4, 0x02, 0x01, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x6F, 0x70, + 0x72, 0x73, 0x74, 0x75, 0x76, 0x79, 0xC3, 0xFE, 0x4D, 0xF2, 0x48, 0xED, 0xF7, 0xFE, 0x6C, 0xFE, + 0x86, 0xFE, 0x9E, 0xED, 0x2A, 0xFE, 0xBE, 0xF3, 0x55, 0xFE, 0xD4, 0xFE, 0xD9, 0xFE, 0xF1, 0xF2, + 0x48, 0xFF, 0x3B, 0xFF, 0x48, 0xFF, 0x8F, 0xFF, 0xB5, 0xEE, 0x47, 0xFF, 0xBC, 0xFF, 0xF9, 0xA0, + 0x04, 0xC2, 0x41, 0x74, 0xEE, 0x05, 0xC2, 0x04, 0xC2, 0x6C, 0xC3, 0xEA, 0x89, 0xFA, 0xF8, 0x44, + 0x62, 0x6D, 0x6F, 0x74, 0xF0, 0x01, 0xED, 0xF8, 0xEA, 0x6C, 0xED, 0xF8, 0x42, 0x74, 0x75, 0xE7, + 0xD8, 0xE7, 0xD8, 0xA0, 0x06, 0x02, 0x21, 0x69, 0xFD, 0xC1, 0x00, 0x91, 0x73, 0xEC, 0xFE, 0x4B, + 0x62, 0x67, 0x6B, 0x6C, 0x6E, 0x72, 0x73, 0x74, 0x75, 0x76, 0x78, 0xEB, 0xC8, 0xFF, 0xD0, 0xFF, + 0xD3, 0xFF, 0xD7, 0xF0, 0x39, 0xFF, 0xE0, 0xFF, 0xED, 0xFF, 0xF7, 0xE8, 0x2C, 0xFF, 0xFA, 0xED, + 0xD8, 0xA0, 0x03, 0xB2, 0xA1, 0x03, 0x61, 0x72, 0xFD, 0xA0, 0x06, 0x22, 0xC1, 0x02, 0x01, 0x73, + 0xEC, 0xFE, 0xC1, 0x03, 0x01, 0x6E, 0xE6, 0xF6, 0x21, 0xA4, 0xFA, 0x44, 0x69, 0x73, 0x79, 0xC3, + 0xFF, 0xF1, 0xE8, 0x21, 0xE6, 0xED, 0xFF, 0xFD, 0x41, 0x70, 0xE7, 0x7C, 0x41, 0x6D, 0xE8, 0x47, + 0x42, 0x61, 0x65, 0xE7, 0x05, 0xED, 0x18, 0xA0, 0x04, 0x12, 0x4B, 0x61, 0x67, 0x69, 0x6A, 0x6D, + 0x6F, 0x73, 0x74, 0x76, 0x79, 0xC3, 0xFF, 0xEE, 0xE6, 0xCE, 0xFF, 0x75, 0xEC, 0xD0, 0xED, 0x7D, + 0xFF, 0xF2, 0xFF, 0xF6, 0xFF, 0xFD, 0xED, 0x7D, 0xE6, 0xED, 0xEC, 0xD3, 0xC1, 0x04, 0x12, 0x72, + 0xFD, 0x4F, 0x41, 0x6E, 0xE7, 0x78, 0x43, 0x61, 0x69, 0x73, 0xFF, 0xF6, 0xFF, 0x49, 0xFF, 0xFC, + 0x41, 0x65, 0xF2, 0x80, 0x43, 0x6F, 0x73, 0x74, 0xE7, 0x30, 0xE6, 0x94, 0xFF, 0x5F, 0x4B, 0x61, + 0x62, 0x66, 0x6A, 0x6C, 0x6D, 0x6E, 0x6F, 0x72, 0x73, 0x74, 0xE9, 0xAD, 0xE6, 0xA6, 0xEF, 0x42, + 0xFF, 0x8B, 0xFF, 0x9D, 0xEC, 0xCA, 0xFF, 0xBC, 0xE9, 0xAD, 0xFF, 0xE8, 0xFF, 0xF2, 0xFF, 0xF6, + 0xC1, 0x01, 0xD1, 0x70, 0xEC, 0xA8, 0x44, 0x6C, 0x6D, 0x74, 0x76, 0xEC, 0x85, 0xE6, 0x8F, 0xE7, + 0x8A, 0xE7, 0x8A, 0xC7, 0x03, 0x61, 0x61, 0x65, 0x67, 0x6C, 0x6F, 0x73, 0x75, 0xFF, 0xED, 0xEC, + 0xBE, 0xE6, 0x74, 0xE9, 0xAD, 0xF4, 0xB5, 0xFF, 0xF3, 0xEC, 0x95, 0xC1, 0x03, 0x61, 0x74, 0xEE, + 0x4A, 0xA0, 0x06, 0x42, 0x42, 0x6C, 0x74, 0xE6, 0x53, 0xFF, 0xFD, 0xA1, 0x00, 0xA1, 0x61, 0xF9, + 0x42, 0x65, 0x72, 0xE6, 0xC4, 0xFF, 0xFB, 0x42, 0x6E, 0x74, 0xE6, 0x40, 0xFF, 0xF9, 0x41, 0xB6, + 0xE9, 0x3D, 0xC4, 0x04, 0x12, 0x6F, 0x73, 0x76, 0xC3, 0xE9, 0x6E, 0xFF, 0xF5, 0xEC, 0x18, 0xFF, + 0xFC, 0xC1, 0x02, 0x01, 0x72, 0xEC, 0x09, 0x42, 0x6F, 0xC3, 0xFF, 0xFA, 0xEF, 0x36, 0x41, 0xB6, + 0xF1, 0xE2, 0xC3, 0x02, 0x01, 0x65, 0x6B, 0xC3, 0xF1, 0xDE, 0xE6, 0xC8, 0xFF, 0xFC, 0x43, 0x6E, + 0x72, 0x73, 0xF4, 0x4A, 0xEC, 0x53, 0xFF, 0xF4, 0x42, 0x67, 0x6D, 0xEC, 0x20, 0xF1, 0xC8, 0x21, + 0xB6, 0xF9, 0xC4, 0x03, 0x61, 0x61, 0x69, 0x6A, 0xC3, 0xFF, 0xEC, 0xEE, 0xA4, 0xEC, 0x85, 0xFF, + 0xFD, 0xC2, 0x03, 0xD2, 0x61, 0x6F, 0xF0, 0x35, 0xEB, 0xF3, 0x42, 0x73, 0x74, 0xE6, 0x60, 0xEC, + 0x6D, 0x43, 0x64, 0x6D, 0x74, 0xEE, 0x6F, 0xEC, 0x66, 0xEC, 0x66, 0xC5, 0x04, 0x12, 0x2E, 0x6C, + 0x6E, 0x72, 0x73, 0xEB, 0xAF, 0xEB, 0xAF, 0xFF, 0xEF, 0xFF, 0xF6, 0xEB, 0x87, 0xA0, 0x06, 0x82, + 0x41, 0x73, 0xF1, 0x80, 0x45, 0x66, 0x6C, 0x6D, 0x6E, 0x73, 0xEB, 0x96, 0xF1, 0x7C, 0xFF, 0xF9, + 0xFF, 0xFC, 0xEC, 0x43, 0x41, 0x74, 0xF1, 0x6C, 0x42, 0x63, 0x74, 0xF1, 0x68, 0xFF, 0xFC, 0x44, + 0x67, 0x6B, 0x70, 0x73, 0xEB, 0xD8, 0xF5, 0x08, 0xF1, 0x61, 0xEB, 0x7B, 0x42, 0x69, 0x76, 0xEA, + 0xFE, 0xE6, 0x56, 0x42, 0x6D, 0x73, 0xEC, 0x14, 0xEE, 0xD9, 0xC1, 0x00, 0x91, 0x2E, 0xF1, 0x46, + 0xC1, 0x00, 0xC1, 0x73, 0xF1, 0x40, 0x21, 0x6E, 0xFA, 0x22, 0xA5, 0xA4, 0xF1, 0xFD, 0xA6, 0x06, + 0x62, 0x61, 0x65, 0x69, 0x6F, 0x75, 0xC3, 0xB6, 0xCA, 0xD1, 0xDE, 0xE5, 0xFB, 0x42, 0x6E, 0x74, + 0xE8, 0x93, 0xF4, 0xEB, 0x41, 0x64, 0xE5, 0x61, 0x41, 0x75, 0xEB, 0x8F, 0x41, 0x66, 0xEA, 0xBE, + 0x45, 0x61, 0x69, 0x6E, 0x6F, 0x79, 0xFF, 0xFC, 0xE5, 0xC4, 0xE5, 0x3A, 0xF5, 0xAA, 0xEB, 0x87, + 0xC1, 0x02, 0x81, 0x65, 0xEB, 0x58, 0xC2, 0x00, 0x71, 0x69, 0xC3, 0xE5, 0xAE, 0xFB, 0xC0, 0xC1, + 0x00, 0x71, 0x72, 0xE5, 0xA5, 0x44, 0x6C, 0x6F, 0x72, 0x75, 0xE5, 0x15, 0xFF, 0xFA, 0xEC, 0xD1, + 0xE5, 0x15, 0x41, 0x6B, 0xEB, 0x55, 0x43, 0x6B, 0x6C, 0x72, 0xE5, 0x04, 0xE5, 0x04, 0xFF, 0xFC, + 0x42, 0x66, 0x6C, 0xEB, 0x47, 0xEA, 0xC2, 0x42, 0x61, 0x65, 0xE4, 0xF3, 0xE5, 0x0E, 0x41, 0x6D, + 0xEB, 0x39, 0x21, 0xA4, 0xFC, 0x47, 0x61, 0x65, 0x69, 0x6A, 0x6F, 0x72, 0xC3, 0xFF, 0xE1, 0xEC, + 0x71, 0xFF, 0xEB, 0xE4, 0xE5, 0xFA, 0x1D, 0xFF, 0xF2, 0xFF, 0xFD, 0xC3, 0x02, 0x81, 0x65, 0x69, + 0xC3, 0xEE, 0xEF, 0xE4, 0xCF, 0xEB, 0xC7, 0x41, 0xA4, 0xE8, 0x09, 0xD1, 0x03, 0x62, 0x61, 0x65, + 0x66, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x73, 0x74, 0x75, 0x76, 0x79, 0xC3, 0xFF, + 0x72, 0xF9, 0xF7, 0xEA, 0xED, 0xFF, 0x79, 0xFF, 0x7D, 0xFF, 0x85, 0xE8, 0x05, 0xFF, 0x95, 0xFF, + 0x9B, 0xEA, 0xE1, 0xFF, 0xAA, 0xE4, 0xBF, 0xFF, 0xDA, 0xEF, 0x1B, 0xFF, 0xF0, 0xE5, 0x20, 0xFF, + 0xFC, 0xC1, 0x00, 0xB1, 0x61, 0xE4, 0xA4, 0x42, 0x64, 0xC3, 0xFF, 0xFA, 0xFA, 0xC3, 0x41, 0x75, + 0xE4, 0x89, 0xC1, 0x03, 0x61, 0x62, 0xEA, 0xC5, 0xC7, 0x04, 0x12, 0x67, 0x6C, 0x6D, 0x70, 0x72, + 0x73, 0x74, 0xEB, 0x0F, 0xFF, 0xEF, 0xFB, 0xAD, 0xEB, 0x0F, 0xFF, 0xF6, 0xE7, 0x93, 0xFF, 0xFA, + 0x41, 0x6A, 0xE4, 0x82, 0x21, 0x74, 0xFC, 0xA1, 0x03, 0x01, 0x74, 0xFD, 0x41, 0x73, 0xE7, 0x0C, + 0x42, 0x64, 0x69, 0xFF, 0xFC, 0xEF, 0xF8, 0xA1, 0x04, 0x12, 0x72, 0xF9, 0x43, 0x6C, 0x72, 0x73, + 0xEA, 0x6C, 0xEA, 0x58, 0xE4, 0x59, 0x42, 0x6F, 0x74, 0xE4, 0x22, 0xEF, 0xE2, 0xC2, 0x04, 0x12, + 0x67, 0x72, 0xEA, 0xCA, 0xFF, 0xF9, 0x23, 0xA5, 0xA4, 0xB6, 0xE1, 0xE6, 0xF7, 0x57, 0x61, 0x62, + 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, + 0x75, 0x76, 0x77, 0x79, 0xC3, 0xFC, 0xE2, 0xEC, 0xC3, 0xFD, 0x07, 0xFD, 0x81, 0xEE, 0xB8, 0xFD, + 0xB6, 0xFD, 0xCE, 0xFD, 0xF5, 0xFE, 0x0A, 0xF3, 0x97, 0xFE, 0x35, 0xEE, 0xB8, 0xFE, 0x44, 0xFE, + 0x5E, 0xEE, 0xB8, 0xFE, 0xC1, 0xFF, 0x5E, 0xF5, 0x2C, 0xFF, 0xAB, 0xEE, 0xB8, 0xEA, 0xBA, 0xFF, + 0xCA, 0xFF, 0xF9, 0x41, 0xA5, 0xE3, 0xFF, 0x21, 0xC3, 0xFC, 0x43, 0x69, 0x73, 0x76, 0xE4, 0x5A, + 0xEB, 0x3B, 0xFF, 0xFD, 0x41, 0x73, 0xE5, 0x54, 0x21, 0x6C, 0xFC, 0x41, 0x6C, 0xE5, 0xD2, 0x22, + 0x65, 0x73, 0xF9, 0xFC, 0xA0, 0x06, 0xA2, 0x21, 0x61, 0xFD, 0x22, 0x64, 0x67, 0xF5, 0xFD, 0xC1, + 0x00, 0x41, 0x6C, 0xE4, 0x6B, 0x43, 0x63, 0x70, 0x74, 0xE4, 0x2F, 0xFF, 0xFA, 0xE3, 0x99, 0xC1, + 0x01, 0x01, 0x73, 0xE3, 0xC3, 0x48, 0x62, 0x67, 0x6C, 0x6D, 0x6E, 0x72, 0x73, 0x76, 0xE9, 0x5D, + 0xEB, 0x51, 0xFF, 0xC5, 0xEF, 0xFC, 0xFF, 0xE5, 0xF8, 0x1A, 0xFF, 0xF0, 0xFF, 0xFA, 0x41, 0xC3, + 0xE4, 0xA2, 0xC2, 0x02, 0x71, 0x74, 0x76, 0xE3, 0xA0, 0xE3, 0xA0, 0x21, 0x73, 0xF7, 0x44, 0x61, + 0x66, 0x6C, 0x74, 0xF3, 0xDC, 0xE9, 0x6F, 0xFF, 0xF0, 0xFF, 0xFD, 0x41, 0x73, 0xE7, 0x34, 0xC3, + 0x02, 0x01, 0x72, 0x73, 0x74, 0xE9, 0xF8, 0xFF, 0xFC, 0xE3, 0xE5, 0x41, 0x6C, 0xE4, 0x1E, 0x21, + 0xA4, 0xFC, 0x21, 0xC3, 0xFD, 0xC1, 0x03, 0x61, 0x65, 0xE9, 0x73, 0x41, 0x74, 0xE9, 0x59, 0xC2, + 0x03, 0x31, 0x61, 0x69, 0xE9, 0x55, 0xFF, 0xFC, 0x41, 0x6C, 0xE7, 0x0F, 0x42, 0x70, 0x73, 0xFF, + 0xFC, 0xE3, 0x22, 0x42, 0x70, 0x74, 0xE3, 0x1B, 0xE5, 0x46, 0x44, 0x6E, 0x70, 0x73, 0x77, 0xFE, + 0xA4, 0xFF, 0xF2, 0xFF, 0xF9, 0xE9, 0xBD, 0xC1, 0x00, 0xD1, 0x74, 0xE5, 0x62, 0x21, 0x73, 0xFA, + 0xC2, 0x00, 0xA1, 0x61, 0x65, 0xE2, 0xF8, 0xE4, 0x5F, 0x21, 0x74, 0xF7, 0x42, 0x67, 0x73, 0xF8, + 0x4B, 0xFF, 0xFD, 0xA0, 0x06, 0xC2, 0x21, 0x73, 0xFD, 0x21, 0x64, 0xFD, 0x21, 0x72, 0xFD, 0xC1, + 0x02, 0xA1, 0x73, 0xE7, 0xD9, 0x41, 0x6F, 0xE6, 0xCD, 0x22, 0x6C, 0x73, 0xF6, 0xFC, 0x41, 0x61, + 0xE2, 0xFA, 0x44, 0x6C, 0x72, 0x73, 0x76, 0xFF, 0xF7, 0xF8, 0xA1, 0xE2, 0xF3, 0xFF, 0xFC, 0x41, + 0x6E, 0xE2, 0xB9, 0xC2, 0x01, 0x01, 0x65, 0x72, 0xFF, 0xFC, 0xE3, 0x87, 0x41, 0x6E, 0xE4, 0x44, + 0xC1, 0x00, 0xA1, 0x74, 0xE5, 0xAA, 0xA3, 0x02, 0x01, 0x67, 0x72, 0x73, 0xED, 0xF6, 0xFA, 0x23, + 0xA5, 0xA4, 0xB6, 0xBD, 0xD3, 0xF7, 0xD3, 0x02, 0xF1, 0x61, 0x63, 0x64, 0x65, 0x67, 0x69, 0x6A, + 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x79, 0xC3, 0xFF, 0x0F, 0xE8, 0x24, + 0xE9, 0x41, 0xFF, 0x38, 0xE8, 0xF1, 0xFF, 0x49, 0xFF, 0x5C, 0xE8, 0xFB, 0xFF, 0x5F, 0xEB, 0x4A, + 0xFF, 0x69, 0xFF, 0x84, 0xE8, 0xF1, 0xF2, 0x76, 0xE8, 0xFB, 0xEB, 0x4A, 0xFF, 0x97, 0xFF, 0xA6, + 0xFF, 0xF9, 0xC5, 0x01, 0xD1, 0x66, 0x67, 0x6C, 0x73, 0x74, 0xE3, 0xBD, 0xE2, 0x68, 0xE7, 0xC0, + 0xF1, 0xF5, 0xE3, 0xBD, 0xA0, 0x06, 0xE2, 0x41, 0x69, 0xF4, 0x28, 0x22, 0x6C, 0x72, 0xF9, 0xFC, + 0x41, 0x2E, 0xE8, 0x78, 0x41, 0x64, 0xE2, 0xD0, 0x21, 0x72, 0xFC, 0x42, 0x6F, 0x75, 0xFF, 0xFD, + 0xE2, 0xCF, 0x45, 0x61, 0x65, 0x68, 0x6B, 0x6F, 0xE8, 0x85, 0xFF, 0xEE, 0xF1, 0xFD, 0xFF, 0xF9, + 0xE7, 0xB8, 0x41, 0x6E, 0xE5, 0x4D, 0xC1, 0x02, 0x81, 0x6F, 0xE2, 0x24, 0x42, 0xA5, 0xB6, 0xE8, + 0x6B, 0xE8, 0x4C, 0xC7, 0x02, 0x01, 0x65, 0x67, 0x6F, 0x72, 0x73, 0x75, 0xC3, 0xFF, 0xEF, 0xEA, + 0x12, 0xF8, 0x3D, 0xFF, 0xF3, 0xF0, 0x76, 0xEA, 0xAE, 0xFF, 0xF9, 0x41, 0x6E, 0xE7, 0xEF, 0x21, + 0xA5, 0xFC, 0xA1, 0x01, 0xD1, 0xC3, 0xFD, 0x43, 0x65, 0x6E, 0x72, 0xE2, 0xE4, 0xE7, 0x73, 0xFF, + 0xFB, 0x41, 0x6E, 0xE8, 0x86, 0x42, 0x62, 0x6A, 0xE7, 0xFF, 0xE1, 0xF2, 0xC4, 0x01, 0xD1, 0x61, + 0x65, 0x6C, 0x6E, 0xFF, 0xF5, 0xFF, 0xF9, 0xE5, 0x24, 0xE8, 0x08, 0x41, 0x72, 0xE8, 0x29, 0x41, + 0xA4, 0xE2, 0x35, 0x42, 0x6F, 0xC3, 0xE8, 0x14, 0xFF, 0xFC, 0x43, 0x62, 0x66, 0x73, 0xE7, 0x40, + 0xE1, 0xCD, 0xE1, 0xCD, 0x42, 0x65, 0x6F, 0xE1, 0xB6, 0xFF, 0xF6, 0xA0, 0x07, 0x02, 0x41, 0x6F, + 0xE6, 0x39, 0x22, 0x68, 0x6B, 0xF9, 0xFC, 0x43, 0x6C, 0x6D, 0x74, 0xE7, 0xF0, 0xE7, 0xF0, 0xE1, + 0xAD, 0x42, 0xA5, 0xB6, 0xE7, 0xE6, 0xE7, 0xE6, 0x4B, 0x61, 0x69, 0x6C, 0x6E, 0x6F, 0x72, 0x73, + 0x75, 0x76, 0x79, 0xC3, 0xFF, 0xC3, 0xE7, 0xE9, 0xFF, 0xCB, 0xE1, 0x92, 0xE7, 0xE9, 0xFF, 0xDC, + 0xFF, 0xEA, 0xFF, 0xEF, 0xE4, 0xD8, 0xE7, 0xDF, 0xFF, 0xF9, 0x41, 0x6E, 0xE7, 0x8A, 0x41, 0xA4, + 0xE5, 0xF9, 0x45, 0x61, 0x69, 0x73, 0x75, 0xC3, 0xE8, 0xEC, 0xF0, 0xF5, 0xE3, 0x4C, 0xE7, 0x58, + 0xFF, 0xFC, 0x41, 0x6E, 0xE4, 0x69, 0x21, 0x69, 0xFC, 0x41, 0x6A, 0xE4, 0x62, 0x41, 0x74, 0xFC, + 0xFF, 0xC2, 0x01, 0x91, 0x66, 0x70, 0xFF, 0xFC, 0xE7, 0x77, 0x4B, 0x61, 0x64, 0x69, 0x6A, 0x6B, + 0x6C, 0x6D, 0x6F, 0x74, 0x75, 0xC3, 0xE7, 0x97, 0xE9, 0x7E, 0xFF, 0xD0, 0xEC, 0xAA, 0xE1, 0x4D, + 0xFF, 0xD8, 0xFF, 0xEC, 0xE7, 0x97, 0xFF, 0xEF, 0xFF, 0xF7, 0xE9, 0xB4, 0x41, 0x72, 0xE2, 0x4D, + 0x42, 0x6D, 0x6F, 0xE1, 0x27, 0xE1, 0xA4, 0x43, 0xA5, 0xA4, 0xB6, 0xE6, 0x93, 0xE7, 0x60, 0xE6, + 0x93, 0x44, 0x62, 0x73, 0x75, 0xC3, 0xFF, 0xEB, 0xFF, 0xEF, 0xE7, 0x60, 0xFF, 0xF6, 0x41, 0x75, + 0xE7, 0x2A, 0x42, 0x6B, 0x74, 0xF6, 0x23, 0xE3, 0x17, 0x42, 0x73, 0x75, 0xFF, 0xF9, 0xE6, 0xB1, + 0x41, 0x2E, 0xE1, 0x05, 0x42, 0x2E, 0x73, 0xE1, 0x70, 0xFF, 0xFC, 0x41, 0x61, 0xEE, 0x42, 0x45, + 0x61, 0x65, 0x69, 0x6C, 0x73, 0xE1, 0x65, 0xFF, 0xF5, 0xE9, 0x4B, 0xFF, 0xFC, 0xEC, 0xE3, 0xC1, + 0x01, 0x91, 0x66, 0xE6, 0xF9, 0x41, 0x76, 0xE8, 0x81, 0x41, 0x68, 0xE6, 0x81, 0x21, 0x65, 0xFC, + 0x43, 0x65, 0x69, 0xC3, 0xEC, 0x90, 0xE6, 0x7A, 0xE6, 0xAD, 0x41, 0x6D, 0xE1, 0x3A, 0x41, 0xC3, + 0xEE, 0x31, 0x21, 0x72, 0xFC, 0x41, 0x6E, 0xEC, 0x7B, 0xA1, 0x02, 0xF1, 0x6C, 0xFC, 0x42, 0x65, + 0x72, 0xFF, 0xFB, 0xE0, 0xA9, 0x41, 0x6B, 0xE6, 0x85, 0x21, 0x6E, 0xFC, 0x43, 0x69, 0x72, 0xC3, + 0xFF, 0xFD, 0xED, 0xB7, 0xF4, 0x46, 0x47, 0x65, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x74, 0xFF, 0xD4, + 0xFF, 0xDC, 0xE0, 0x84, 0xE0, 0x9F, 0xE0, 0x84, 0xFF, 0xE8, 0xFF, 0xF6, 0xC1, 0x02, 0xF1, 0x61, + 0xE0, 0xF8, 0x43, 0x65, 0x72, 0x73, 0xE0, 0x75, 0xFF, 0xFA, 0xE0, 0x5C, 0xC1, 0x01, 0xD1, 0x6E, + 0xE6, 0x8C, 0x4D, 0x61, 0x64, 0x67, 0x69, 0x6A, 0x6B, 0x6E, 0x72, 0x73, 0x74, 0x75, 0x79, 0xC3, + 0xFF, 0x5C, 0xFF, 0x67, 0xFF, 0x7D, 0xFF, 0x8D, 0xE0, 0x65, 0xFF, 0x93, 0xFF, 0x9B, 0xFF, 0x9E, + 0xFF, 0xD4, 0xFF, 0xF0, 0xFF, 0xFA, 0xF5, 0x4C, 0xF3, 0x1C, 0xC1, 0x01, 0x91, 0x72, 0xE0, 0xBA, + 0xC1, 0x01, 0xD1, 0x69, 0xE0, 0x37, 0xC2, 0x01, 0x01, 0x6F, 0x73, 0xE6, 0x71, 0xE0, 0x4C, 0x4A, + 0x63, 0x67, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0xE5, 0x9B, 0xE6, 0x72, 0xFF, 0xEB, + 0xFF, 0xF1, 0xE5, 0x9B, 0xFF, 0xF7, 0xE6, 0x72, 0xE6, 0x72, 0xE6, 0x72, 0xE6, 0x72, 0x41, 0x69, + 0xE0, 0x09, 0x44, 0x65, 0x69, 0x6F, 0x70, 0xE6, 0x4F, 0xE6, 0x4F, 0xE0, 0xE9, 0xFF, 0xFC, 0xC1, + 0x01, 0xD1, 0x70, 0xDF, 0xDF, 0x46, 0x61, 0x65, 0x69, 0x6B, 0x6F, 0x75, 0xE6, 0x32, 0xEE, 0x33, + 0xE6, 0x3C, 0xDF, 0xD6, 0xFF, 0xFA, 0xE6, 0x3C, 0x41, 0x65, 0xE5, 0x52, 0x41, 0x70, 0xDF, 0xDB, + 0x41, 0x70, 0xE2, 0xF9, 0xC1, 0x00, 0x71, 0x6E, 0xE0, 0x50, 0xC5, 0x02, 0x01, 0x65, 0x6E, 0x6F, + 0x75, 0x79, 0xFF, 0xF2, 0xE1, 0x8D, 0xFF, 0xF6, 0xFF, 0xFA, 0xDF, 0xC0, 0x41, 0x6D, 0xE5, 0x2E, + 0x41, 0xA4, 0xF1, 0xF6, 0x22, 0x61, 0xC3, 0xF8, 0xFC, 0xC1, 0x06, 0xE2, 0x72, 0xF4, 0x9E, 0xA0, + 0x07, 0x22, 0x41, 0xA4, 0xDF, 0x8C, 0x22, 0x72, 0xC3, 0xF9, 0xFC, 0x44, 0x61, 0x65, 0x6E, 0x74, + 0xDF, 0x8F, 0xDF, 0x8F, 0xDF, 0x7D, 0xFF, 0xFB, 0x41, 0x73, 0xE5, 0xD9, 0x43, 0x6C, 0x6E, 0x74, + 0xE5, 0xD5, 0xFF, 0xFC, 0xE0, 0xA0, 0x42, 0x2E, 0x74, 0xDF, 0x81, 0xE5, 0xCB, 0x42, 0x6E, 0x73, + 0xFF, 0xF9, 0xDF, 0xF7, 0x41, 0x67, 0xDF, 0x73, 0x42, 0x67, 0x6E, 0xDF, 0x62, 0xFF, 0xFC, 0x42, + 0x2E, 0x65, 0xDF, 0x68, 0xDF, 0x68, 0x21, 0x72, 0xF9, 0x41, 0xA5, 0xE1, 0x64, 0x46, 0x61, 0x65, + 0x69, 0x6F, 0x72, 0xC3, 0xFF, 0xCF, 0xFF, 0xE0, 0xFF, 0xEB, 0xFF, 0xF9, 0xE3, 0x2A, 0xFF, 0xFC, + 0x4D, 0x63, 0x65, 0x68, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x76, 0x79, 0xC3, 0xFF, 0x68, + 0xE3, 0x87, 0xE2, 0x4B, 0xFF, 0x7A, 0xFF, 0x94, 0xDF, 0x3A, 0xDF, 0x3A, 0xFF, 0x99, 0xFF, 0xAB, + 0xFF, 0xED, 0xDF, 0x47, 0xE5, 0x87, 0xEF, 0xB3, 0x42, 0x69, 0x78, 0xE5, 0x40, 0xE5, 0x40, 0x42, + 0x6E, 0x73, 0xE4, 0x8B, 0xE5, 0x58, 0x42, 0x61, 0x69, 0xDF, 0x6E, 0xFF, 0xF9, 0x43, 0x6F, 0x72, + 0x75, 0xE8, 0x82, 0xFF, 0x62, 0xDF, 0x87, 0x41, 0xA5, 0xE8, 0xCC, 0xC6, 0x01, 0xD1, 0x63, 0x65, + 0x6A, 0x72, 0x74, 0xC3, 0xDE, 0xFC, 0xFF, 0xDD, 0xE5, 0x1D, 0xFF, 0xEB, 0xFF, 0xF2, 0xFF, 0xFC, + 0xC1, 0x01, 0xD1, 0x6B, 0xE4, 0xF4, 0x41, 0xA5, 0xE5, 0x2B, 0x45, 0x61, 0x69, 0x72, 0x73, 0xC3, + 0xFF, 0xF6, 0xFE, 0x72, 0xDE, 0xD0, 0xE1, 0xE1, 0xFF, 0xFC, 0xC1, 0x00, 0xD1, 0x75, 0xDE, 0xCD, + 0x21, 0x74, 0xFA, 0x41, 0xB6, 0xE5, 0x0E, 0x55, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x69, + 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0x78, 0xC3, 0xFC, 0x4B, 0xFC, + 0x64, 0xFC, 0x7B, 0xFC, 0x9C, 0xE9, 0x4E, 0xFC, 0xC0, 0xFC, 0xD5, 0xE5, 0x00, 0xFD, 0x21, 0xFD, + 0x73, 0xFD, 0xAA, 0xFE, 0x5B, 0xFE, 0x98, 0xFE, 0xBB, 0xFE, 0xCE, 0xFF, 0x79, 0xFF, 0xC4, 0xEC, + 0xC3, 0xFF, 0xE3, 0xFF, 0xF9, 0xFF, 0xFC, 0x41, 0x74, 0xF1, 0x69, 0xC3, 0x02, 0xF1, 0x6B, 0x72, + 0x73, 0xFF, 0xFC, 0xF5, 0x00, 0xDF, 0x64, 0x41, 0x79, 0xDE, 0xED, 0x21, 0x74, 0xFC, 0xC3, 0x03, + 0x61, 0x72, 0x73, 0x75, 0xDE, 0x5C, 0xFF, 0xFD, 0xE4, 0x8A, 0x41, 0x74, 0xF2, 0xD5, 0xC3, 0x02, + 0xF1, 0x61, 0x66, 0x73, 0xE1, 0x5D, 0xEA, 0x22, 0xFF, 0xFC, 0xC1, 0x02, 0xF1, 0x6E, 0xE4, 0xDD, + 0xC3, 0x03, 0x31, 0x6C, 0x6F, 0x76, 0xE4, 0x68, 0xE4, 0x87, 0xDE, 0x3A, 0x42, 0x6A, 0xC3, 0xE4, + 0xCB, 0xEF, 0x1B, 0xA0, 0x07, 0x42, 0x42, 0x69, 0x73, 0xE1, 0x10, 0xFF, 0xFD, 0x21, 0x64, 0xF9, + 0xC5, 0x02, 0x01, 0x62, 0x6B, 0x6C, 0x72, 0x75, 0xE4, 0x0A, 0xE4, 0x1D, 0xFF, 0xEC, 0xFF, 0xFD, + 0xE4, 0x0A, 0xC1, 0x03, 0x31, 0x6C, 0xE3, 0x88, 0xC4, 0x03, 0xD2, 0x61, 0x6B, 0x6D, 0x74, 0xE3, + 0x82, 0xE4, 0x30, 0xE5, 0xFD, 0xE5, 0xFD, 0xC1, 0x03, 0x61, 0x73, 0xDE, 0x0E, 0x42, 0x6F, 0x73, + 0xE3, 0x81, 0xDD, 0xE1, 0xC1, 0x00, 0xA1, 0x61, 0xDD, 0xD4, 0x43, 0x6B, 0x73, 0x74, 0xF3, 0x2D, + 0xDE, 0x15, 0xFF, 0xFA, 0x41, 0x74, 0xE3, 0xE7, 0x21, 0x73, 0xFC, 0xC5, 0x03, 0x62, 0x6B, 0x6C, + 0x72, 0x73, 0x74, 0xFF, 0xE2, 0xE3, 0x67, 0xE4, 0x6C, 0xFF, 0xEF, 0xFF, 0xFD, 0x41, 0x72, 0xE2, + 0xA5, 0x41, 0x61, 0xDD, 0xEE, 0x43, 0x6F, 0x70, 0x73, 0xDD, 0xA3, 0xFF, 0xF8, 0xFF, 0xFC, 0x41, + 0x6B, 0xDE, 0x77, 0x21, 0x73, 0xFC, 0x42, 0x6E, 0x73, 0xFF, 0xFD, 0xDE, 0x64, 0x22, 0x6C, 0x72, + 0xE8, 0xF9, 0x42, 0x72, 0x73, 0xE0, 0x37, 0xE0, 0x3E, 0x43, 0xA4, 0xB6, 0xA9, 0xFF, 0xF4, 0xFF, + 0xF9, 0xE9, 0x67, 0x53, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, + 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0xC3, 0xFF, 0x18, 0xE6, 0x2D, 0xFF, 0x2B, 0xFF, 0x3B, 0xE8, + 0x22, 0xE8, 0x25, 0xE4, 0x24, 0xFF, 0x47, 0xFF, 0x4D, 0xE8, 0x22, 0xE6, 0x2D, 0xE8, 0x22, 0xFF, + 0x6D, 0xFF, 0x7F, 0xE9, 0x32, 0xFF, 0x85, 0xFF, 0x94, 0xFF, 0xB8, 0xFF, 0xF6, 0x43, 0x2E, 0x65, + 0x72, 0xE3, 0x3D, 0xF0, 0x43, 0xDD, 0xD7, 0x41, 0xA4, 0xE9, 0x19, 0xA1, 0x03, 0x61, 0xC3, 0xFC, + 0x41, 0x69, 0xE3, 0x87, 0xA1, 0x03, 0x61, 0x74, 0xFC, 0x42, 0x6F, 0x73, 0xDD, 0x4C, 0xDD, 0x59, + 0x43, 0x66, 0x67, 0x6C, 0xE3, 0xC7, 0xE3, 0xC7, 0xFF, 0xF9, 0x42, 0x70, 0x72, 0xE3, 0x10, 0xE3, + 0x10, 0x43, 0x2E, 0x64, 0x6F, 0xE3, 0x09, 0xEB, 0x22, 0xE8, 0xEF, 0x41, 0x65, 0xFC, 0x6A, 0xC5, + 0x03, 0x61, 0x69, 0x6C, 0x70, 0x73, 0x74, 0xE2, 0xFB, 0xF1, 0x90, 0xDD, 0x29, 0xE6, 0x6D, 0xFF, + 0xFC, 0xC1, 0x03, 0x31, 0x65, 0xEC, 0x97, 0x41, 0x61, 0xE2, 0xE3, 0xC1, 0x03, 0x31, 0x73, 0xDD, + 0xAF, 0x42, 0x2E, 0x65, 0xE3, 0x86, 0xE3, 0x86, 0x49, 0x2E, 0x61, 0x62, 0x69, 0x6B, 0x6E, 0x70, + 0x74, 0x76, 0xE2, 0xD2, 0xDC, 0xE2, 0xFF, 0xE9, 0xDC, 0xEF, 0xE3, 0x7F, 0xFF, 0xEF, 0xFF, 0xF3, + 0xFF, 0xF9, 0xE3, 0x7F, 0xC2, 0x03, 0x01, 0x6B, 0x74, 0xDD, 0x50, 0xE4, 0x91, 0x42, 0x2E, 0x73, + 0xE2, 0xAD, 0xEF, 0xB3, 0xCE, 0x04, 0x12, 0x2E, 0x64, 0x66, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, + 0x70, 0x72, 0x73, 0x74, 0x75, 0xE2, 0xA6, 0xFF, 0x69, 0xFF, 0x77, 0xDC, 0xB6, 0xF8, 0x3A, 0xFF, + 0x80, 0xFF, 0x8C, 0xFF, 0x96, 0xFF, 0x9D, 0xFF, 0xAB, 0xFF, 0xD4, 0xFF, 0xF0, 0xFF, 0xF9, 0xE3, + 0x53, 0x41, 0x6D, 0xDC, 0xBE, 0xA1, 0x07, 0x63, 0x6F, 0xFC, 0x44, 0x2E, 0x61, 0x72, 0x73, 0xE5, + 0x26, 0xE5, 0x26, 0xDC, 0x80, 0xDC, 0x9B, 0x41, 0x75, 0xE5, 0x19, 0x42, 0x64, 0x73, 0xE3, 0x0C, + 0xDC, 0xA4, 0x41, 0x65, 0xE3, 0x05, 0x42, 0x73, 0xC3, 0xFF, 0xFC, 0xEC, 0xE8, 0xC1, 0x00, 0xD1, + 0x73, 0xDC, 0x51, 0xCA, 0x04, 0x12, 0x2E, 0x64, 0x65, 0x66, 0x6C, 0x6E, 0x70, 0x72, 0x73, 0x78, + 0xE2, 0x47, 0xFF, 0xD7, 0xE2, 0x5A, 0xFF, 0xE4, 0xFF, 0xE8, 0xFF, 0xF3, 0xE4, 0xFD, 0xFA, 0x58, + 0xFF, 0xFA, 0xE2, 0xF4, 0x41, 0x69, 0xDC, 0x5E, 0xA1, 0x01, 0xE1, 0x72, 0xFC, 0x21, 0xB6, 0xFB, + 0xA1, 0x03, 0xD2, 0xC3, 0xFD, 0xA0, 0x07, 0x93, 0x41, 0xA5, 0xE7, 0xF8, 0x21, 0xC3, 0xFC, 0x45, + 0x67, 0x6E, 0x73, 0x74, 0x75, 0xDD, 0x96, 0xFF, 0xB3, 0xE2, 0xB8, 0xE4, 0xC1, 0xDC, 0xA5, 0x49, + 0x64, 0x66, 0x67, 0x6B, 0x6C, 0x6D, 0x6E, 0x74, 0x76, 0xE3, 0x32, 0xE2, 0xA8, 0xE1, 0xCB, 0xE3, + 0xA7, 0xDE, 0xB1, 0xFF, 0xED, 0xFF, 0xF0, 0xE2, 0x0E, 0xE3, 0x32, 0x41, 0x6C, 0xE7, 0xC5, 0xC2, + 0x03, 0x31, 0x6F, 0xC3, 0xFF, 0xFC, 0xE5, 0x0E, 0x42, 0x61, 0x69, 0xE1, 0xFC, 0xDB, 0xFD, 0x41, + 0x67, 0xEE, 0xD1, 0x41, 0x73, 0xE1, 0xC7, 0x46, 0x67, 0x6D, 0x6E, 0x73, 0x74, 0x76, 0xE1, 0x93, + 0xFF, 0xF1, 0xFF, 0xF8, 0xFF, 0xFC, 0xE4, 0x79, 0xE7, 0xA9, 0xC1, 0x03, 0x61, 0x6A, 0xE1, 0xDA, + 0xA0, 0x07, 0xC2, 0x21, 0x72, 0xFD, 0xA1, 0x02, 0x01, 0x74, 0xFD, 0x44, 0x67, 0x6D, 0x70, 0x73, + 0xE4, 0x55, 0xE1, 0xC9, 0xE1, 0x9F, 0xFF, 0xFB, 0x42, 0x2E, 0x61, 0xE1, 0x22, 0xE7, 0x78, 0x21, + 0x6B, 0xF9, 0x42, 0x63, 0x73, 0xFF, 0xFD, 0xE1, 0x88, 0x42, 0x62, 0x6B, 0xE1, 0x51, 0xE2, 0x2E, + 0x42, 0x64, 0x67, 0xE1, 0x4A, 0xE7, 0x35, 0x21, 0xA4, 0xF9, 0xA6, 0x00, 0xD1, 0x61, 0x65, 0x69, + 0x6F, 0x75, 0xC3, 0xAD, 0xC0, 0xD1, 0xE8, 0xEF, 0xFD, 0x42, 0x6C, 0x70, 0xE1, 0x9F, 0xEB, 0x2B, + 0x42, 0x70, 0x76, 0xE7, 0x40, 0xEB, 0x24, 0xC1, 0x00, 0x91, 0x6B, 0xE0, 0xE3, 0xC4, 0x03, 0x62, + 0x61, 0x69, 0x75, 0x79, 0xFF, 0xEC, 0xFF, 0xF3, 0xEB, 0x17, 0xFF, 0xFA, 0x42, 0x65, 0x6C, 0xDB, + 0x5B, 0xE0, 0xCE, 0x43, 0x6E, 0x72, 0x73, 0xDB, 0x3B, 0xDB, 0xD1, 0xE3, 0x79, 0x41, 0x2E, 0xE7, + 0x13, 0x45, 0x61, 0x69, 0x6A, 0x74, 0x76, 0xE1, 0xD6, 0xF9, 0xE1, 0xE1, 0xD6, 0xF0, 0x86, 0xFF, + 0xFC, 0xC4, 0x02, 0xF1, 0x6D, 0x70, 0x72, 0x73, 0xE1, 0x19, 0xE6, 0xFF, 0xE6, 0xD4, 0xDB, 0x44, + 0x41, 0x74, 0xE1, 0x0A, 0xC4, 0x02, 0xF1, 0x66, 0x73, 0x74, 0x75, 0xE1, 0x06, 0xFF, 0xFC, 0xE1, + 0x06, 0xDB, 0x16, 0xC1, 0x03, 0x61, 0x65, 0xFF, 0x30, 0x41, 0x72, 0xE6, 0xDA, 0x21, 0x65, 0xFC, + 0xC4, 0x02, 0xF1, 0x67, 0x69, 0x72, 0x74, 0xE0, 0xEA, 0xDA, 0xFA, 0xFF, 0xF3, 0xFF, 0xFD, 0xC1, + 0x03, 0x01, 0x72, 0xDB, 0x75, 0x43, 0x6B, 0x6C, 0x74, 0xDA, 0xEF, 0xDA, 0xE5, 0xFF, 0xFA, 0xC9, + 0x02, 0x01, 0x63, 0x64, 0x67, 0x6C, 0x6D, 0x6E, 0x72, 0x73, 0x75, 0xE1, 0x78, 0xFF, 0x8D, 0xFF, + 0x94, 0xFF, 0xA2, 0xFF, 0xB2, 0xFF, 0xC5, 0xFF, 0xE1, 0xFF, 0xF6, 0xE5, 0x79, 0xA0, 0x07, 0xE2, + 0x21, 0x65, 0xFD, 0x41, 0x67, 0xE1, 0x54, 0x43, 0x66, 0x67, 0x6E, 0xE0, 0xA3, 0xFF, 0xF9, 0xFF, + 0xFC, 0x42, 0x72, 0x74, 0xE6, 0x82, 0xE3, 0x70, 0xA0, 0x08, 0x02, 0x21, 0x73, 0xFD, 0xC1, 0x02, + 0xF1, 0x73, 0xDB, 0x68, 0xA0, 0x08, 0x21, 0x21, 0x6B, 0xFD, 0x21, 0x73, 0xFD, 0x21, 0x67, 0xFD, + 0x44, 0x64, 0x67, 0x6E, 0x76, 0xFF, 0xEB, 0xFF, 0xEE, 0xFF, 0xFD, 0xE1, 0x27, 0xC1, 0x03, 0x01, + 0x73, 0xDD, 0x3B, 0x21, 0x70, 0xFA, 0x21, 0x70, 0xFD, 0x41, 0x64, 0xDA, 0x5F, 0x21, 0x61, 0xFC, + 0x21, 0x74, 0xFD, 0x21, 0x73, 0xFD, 0x41, 0x67, 0xE0, 0xB1, 0x42, 0x6B, 0x70, 0xDB, 0xE6, 0xFC, + 0xA7, 0x41, 0x64, 0xF0, 0x5D, 0x41, 0x6C, 0xDB, 0xAE, 0x44, 0x64, 0x6B, 0x6C, 0x74, 0xFF, 0xF8, + 0xFF, 0xFC, 0xE0, 0xEE, 0xE0, 0x9E, 0x22, 0xA5, 0xA4, 0xE4, 0xF3, 0xC7, 0x06, 0x62, 0x61, 0x65, + 0x69, 0x6F, 0x75, 0x79, 0xC3, 0xFF, 0x8C, 0xFF, 0x96, 0xFF, 0xB5, 0xFF, 0xCB, 0xFF, 0xD8, 0xFF, + 0xDB, 0xFF, 0xFB, 0x42, 0x6B, 0x73, 0xDB, 0xAD, 0xE4, 0x00, 0x41, 0x68, 0xDA, 0x20, 0x42, 0xA4, + 0xB6, 0xE0, 0x69, 0xE0, 0x69, 0xC4, 0x08, 0x32, 0x6C, 0x72, 0x76, 0xC3, 0xDA, 0x15, 0xEE, 0x9A, + 0xDA, 0x22, 0xFF, 0xF9, 0x41, 0x67, 0xF0, 0x0A, 0x43, 0x61, 0x69, 0x79, 0xFF, 0xFC, 0xDD, 0x13, + 0xDF, 0x82, 0x41, 0x76, 0xDD, 0xE3, 0xC2, 0x08, 0x52, 0x61, 0x69, 0xFF, 0xFC, 0xDB, 0x36, 0xC9, + 0x03, 0x61, 0x61, 0x63, 0x65, 0x6B, 0x6C, 0x6F, 0x70, 0x74, 0x75, 0xFF, 0xC4, 0xFF, 0xCB, 0xE0, + 0x1C, 0xFF, 0xD6, 0xFF, 0xE9, 0xE0, 0x05, 0xDF, 0xB3, 0xFF, 0xF7, 0xE0, 0x05, 0x41, 0x78, 0xDF, + 0xFB, 0x42, 0x6E, 0x73, 0xDF, 0xF7, 0xDF, 0xE3, 0x42, 0x67, 0x6E, 0xED, 0x28, 0xFF, 0xF9, 0x42, + 0x64, 0x6D, 0xDF, 0xD5, 0xDF, 0xD5, 0x43, 0x64, 0x67, 0x6C, 0xDF, 0x34, 0xD9, 0xC1, 0xD9, 0xB4, + 0x41, 0xA4, 0xE0, 0xB4, 0xC4, 0x02, 0x01, 0x65, 0x69, 0x6F, 0xC3, 0xD9, 0xA6, 0xEB, 0xF2, 0xFF, + 0xF2, 0xFF, 0xFC, 0x41, 0x74, 0xDC, 0xA8, 0x42, 0x67, 0x74, 0xDF, 0xC1, 0xDF, 0xAD, 0x41, 0x6C, + 0xDF, 0xBA, 0x21, 0xA4, 0xFC, 0xC8, 0x04, 0xA2, 0x65, 0x69, 0x6F, 0x72, 0x73, 0x74, 0x75, 0xC3, + 0xFF, 0xB8, 0xFF, 0xC3, 0xFF, 0xCA, 0xFF, 0xDF, 0xFF, 0xEE, 0xD9, 0x8F, 0xFF, 0xF2, 0xFF, 0xFD, + 0xC1, 0x03, 0x31, 0x6E, 0xDE, 0xEA, 0x43, 0x61, 0x64, 0xC3, 0xD9, 0x71, 0xE0, 0x01, 0xE5, 0xCE, + 0x41, 0x70, 0xD9, 0x4B, 0x42, 0x67, 0x6E, 0xDA, 0xDC, 0xE5, 0x2C, 0x41, 0x65, 0xE0, 0xDB, 0x42, + 0x6F, 0x73, 0xD9, 0xD5, 0xDF, 0x3B, 0xC1, 0x03, 0x01, 0x74, 0xDC, 0xCD, 0x27, 0x67, 0x6C, 0x6D, + 0x6E, 0x70, 0x72, 0x73, 0xD4, 0xDA, 0xE4, 0xE8, 0xEF, 0xF3, 0xFA, 0x41, 0x69, 0xDF, 0x1F, 0x44, + 0x65, 0x6E, 0x73, 0x74, 0xDE, 0xAB, 0xDF, 0x1B, 0xD9, 0x53, 0xDF, 0x1B, 0x41, 0x6F, 0xDF, 0x4C, + 0x23, 0x6C, 0x72, 0x74, 0xEB, 0xEF, 0xFC, 0x41, 0x65, 0xE1, 0xB9, 0x21, 0x74, 0xFC, 0xA1, 0x02, + 0x01, 0x6E, 0xFD, 0x41, 0x6E, 0xDE, 0xC7, 0x42, 0x6E, 0x72, 0xFF, 0xFC, 0xF2, 0x59, 0x41, 0x6C, + 0xDE, 0xEC, 0x42, 0x6C, 0x72, 0xFF, 0xFC, 0xDF, 0x4F, 0x42, 0xA5, 0xA4, 0xDF, 0x48, 0xFF, 0xF9, + 0xC5, 0x00, 0x41, 0x61, 0x65, 0x69, 0x6F, 0xC3, 0xFF, 0xD0, 0xFF, 0xDE, 0xFF, 0xE7, 0xDF, 0x18, + 0xFF, 0xF9, 0x41, 0x69, 0xE0, 0x64, 0x43, 0x64, 0x6C, 0x72, 0xD9, 0xA6, 0xFF, 0xFC, 0xF8, 0x3F, + 0x42, 0x6E, 0x73, 0xE4, 0xA0, 0xDE, 0xBA, 0x44, 0x6C, 0x6D, 0x6E, 0x72, 0xFC, 0x3A, 0xE5, 0xD2, + 0xFF, 0xF9, 0xFF, 0xC7, 0x41, 0x74, 0xDA, 0x0F, 0x21, 0x73, 0xFC, 0x42, 0x6C, 0x73, 0xD8, 0xE4, + 0xDC, 0xFC, 0x44, 0x67, 0x6B, 0x70, 0x72, 0xDF, 0x45, 0xFF, 0xF6, 0xFD, 0x6B, 0xFF, 0xF9, 0x22, + 0xA4, 0xB6, 0xD8, 0xF3, 0x57, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, + 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0x79, 0xC3, 0xFB, 0xE0, 0xE1, 0x3C, + 0xDF, 0x33, 0xFC, 0x11, 0xFC, 0x3F, 0xFC, 0x6C, 0xFC, 0x71, 0xF1, 0x85, 0xFC, 0x8B, 0xFC, 0xAB, + 0xE4, 0x41, 0xFD, 0x16, 0xE3, 0x31, 0xFD, 0x39, 0xFD, 0xBB, 0xE3, 0x31, 0xFE, 0x57, 0xFE, 0xAB, + 0xFF, 0x11, 0xFF, 0x58, 0xFF, 0xAC, 0xFF, 0xC2, 0xFF, 0xFB, 0x41, 0x2E, 0xDE, 0x10, 0x43, 0x65, + 0x6D, 0x72, 0xFF, 0xFC, 0xE0, 0xF2, 0xDE, 0xE9, 0x44, 0x64, 0x69, 0x6D, 0x72, 0xEB, 0x38, 0xDF, + 0xCE, 0xE4, 0x18, 0xD8, 0x36, 0x41, 0x6E, 0xFC, 0xF8, 0x41, 0x69, 0xFC, 0x5A, 0xC3, 0x03, 0x61, + 0x61, 0x69, 0x74, 0xFF, 0xF8, 0xE4, 0x03, 0xFF, 0xFC, 0x42, 0x65, 0x69, 0xEB, 0x17, 0xD8, 0x3C, + 0x21, 0x64, 0xF9, 0x41, 0x61, 0xE0, 0xBD, 0x21, 0x72, 0xFC, 0x21, 0x61, 0xFD, 0x21, 0x70, 0xFD, + 0x44, 0x62, 0x6E, 0x73, 0x74, 0xE0, 0xB0, 0xDD, 0xCA, 0xD7, 0xF8, 0xDE, 0xA7, 0xC1, 0x00, 0x41, + 0x65, 0xFC, 0xC0, 0x43, 0x68, 0x6B, 0x74, 0xD7, 0xEB, 0xDE, 0x94, 0xFF, 0xFA, 0x41, 0x69, 0xDF, + 0x89, 0x43, 0x2E, 0x72, 0x74, 0xDD, 0xA9, 0xD7, 0xF6, 0xFF, 0xFC, 0xC1, 0x03, 0x61, 0x75, 0xD7, + 0xEC, 0x4D, 0x2E, 0x64, 0x66, 0x67, 0x6B, 0x6C, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0xDD, + 0xC9, 0xFF, 0x8D, 0xE0, 0x7F, 0xFF, 0x97, 0xFF, 0xAC, 0xE8, 0x78, 0xFF, 0xBF, 0xFF, 0xCC, 0xFF, + 0xCF, 0xFF, 0xE2, 0xFF, 0xF0, 0xE0, 0x7F, 0xFF, 0xFA, 0x41, 0x72, 0xD8, 0xA2, 0x42, 0x61, 0x79, + 0xD7, 0xAD, 0xDD, 0x2D, 0x41, 0x61, 0xDA, 0x92, 0xC4, 0x03, 0x62, 0x65, 0x6A, 0x72, 0x73, 0xFF, + 0xF1, 0xDD, 0xEF, 0xFF, 0xF5, 0xFF, 0xFC, 0x42, 0x6C, 0x76, 0xDA, 0xA4, 0xD8, 0x1D, 0x41, 0xC3, + 0xEC, 0xDD, 0x21, 0x73, 0xFC, 0x41, 0x6C, 0xE3, 0x33, 0x41, 0x74, 0xE8, 0x64, 0x44, 0x2E, 0x6B, + 0x6E, 0x73, 0xDD, 0x6D, 0xD7, 0x6B, 0xDD, 0x6D, 0xFF, 0xFC, 0x41, 0x6C, 0xF5, 0xC1, 0xCC, 0x02, + 0xF1, 0x2E, 0x67, 0x69, 0x6B, 0x6D, 0x6E, 0x72, 0x73, 0x74, 0x75, 0x76, 0x78, 0xDD, 0x5C, 0xED, + 0x77, 0xF8, 0x06, 0xFF, 0xD9, 0xFF, 0xE4, 0xFF, 0xE7, 0xFF, 0xEF, 0xFF, 0xFC, 0xE7, 0xF4, 0xEC, + 0x60, 0xDC, 0xC4, 0xE0, 0x12, 0xC1, 0x00, 0xA1, 0x74, 0xD7, 0x52, 0xC3, 0x03, 0xD2, 0x6A, 0x6C, + 0x73, 0xDD, 0x59, 0xEE, 0x33, 0xFF, 0xFA, 0xC2, 0x03, 0x01, 0x6F, 0x73, 0xD7, 0xBD, 0xD7, 0x27, + 0xC1, 0x01, 0x01, 0x69, 0xD7, 0x37, 0x42, 0x6C, 0x73, 0xFF, 0xFA, 0xD7, 0x18, 0x41, 0x72, 0xE2, + 0xF3, 0x21, 0x65, 0xFC, 0x41, 0x2E, 0xDF, 0xBC, 0x44, 0x61, 0x6F, 0x72, 0x73, 0xFF, 0xFC, 0xD7, + 0xD2, 0xDD, 0xAF, 0xFE, 0x5C, 0x45, 0x64, 0x67, 0x69, 0x6A, 0x74, 0xDF, 0xAB, 0xFF, 0xF3, 0xDF, + 0xAB, 0xE2, 0xDB, 0xDF, 0xAB, 0x41, 0xB6, 0xD6, 0xF5, 0x21, 0xC3, 0xFC, 0x42, 0x61, 0x72, 0xD7, + 0x78, 0xFF, 0xFD, 0x42, 0x63, 0x74, 0xD6, 0xDB, 0xFF, 0xF9, 0x42, 0x6F, 0x73, 0xD7, 0x6A, 0xD9, + 0xC6, 0xCA, 0x02, 0xF1, 0x63, 0x66, 0x67, 0x6B, 0x6D, 0x6E, 0x6F, 0x70, 0x73, 0x76, 0xE7, 0x24, + 0xDC, 0xC9, 0xFF, 0xA6, 0xFF, 0xB5, 0xFF, 0xC0, 0xFF, 0xD4, 0xDA, 0x1F, 0xDF, 0x7F, 0xFF, 0xF2, + 0xFF, 0xF9, 0x41, 0x6B, 0xDC, 0xD2, 0x43, 0xA5, 0xA4, 0xB6, 0xDC, 0x34, 0xDD, 0x0B, 0xE6, 0x1C, + 0x44, 0x61, 0x6F, 0x75, 0xC3, 0xFF, 0xF2, 0xE4, 0xBA, 0xDC, 0x6A, 0xFF, 0xF6, 0xC2, 0x02, 0x01, + 0x61, 0xC3, 0xF7, 0x37, 0xDF, 0x11, 0xC1, 0x02, 0x01, 0x61, 0xEF, 0x7B, 0xC5, 0x03, 0xD2, 0x65, + 0x6A, 0x6C, 0x72, 0x74, 0xDC, 0xDB, 0xE6, 0x60, 0xFF, 0xF1, 0xFF, 0xFA, 0xD6, 0x8E, 0xC1, 0x00, + 0xA1, 0x72, 0xD6, 0x7C, 0x41, 0x62, 0xD6, 0x64, 0x41, 0x76, 0xD7, 0x32, 0xA1, 0x01, 0xD1, 0x6B, + 0xFC, 0x45, 0x61, 0x65, 0x6B, 0x6F, 0x76, 0xDD, 0xF5, 0xD9, 0x7A, 0xD9, 0x98, 0xD9, 0x7A, 0xDC, + 0xDD, 0x42, 0x69, 0x72, 0xDF, 0x72, 0xD6, 0x59, 0x41, 0x61, 0xD7, 0x1E, 0x21, 0x72, 0xFC, 0x21, + 0x74, 0xFD, 0xC2, 0x01, 0xD1, 0x6E, 0x73, 0xD6, 0x55, 0xFF, 0xFD, 0x41, 0x67, 0xD8, 0xCF, 0x21, + 0x67, 0xFC, 0xC1, 0x02, 0x11, 0x74, 0xD6, 0x45, 0x42, 0x64, 0x72, 0xDB, 0xB2, 0xFF, 0xFA, 0x22, + 0xA4, 0xB6, 0xF0, 0xF9, 0x4D, 0x61, 0x64, 0x65, 0x6B, 0x6C, 0x6F, 0x70, 0x73, 0x74, 0x75, 0x76, + 0x79, 0xC3, 0xDC, 0x7D, 0xFF, 0xAA, 0xFF, 0xB0, 0xD6, 0x26, 0xD9, 0x6C, 0xFF, 0xB8, 0xD6, 0x26, + 0xFF, 0xBD, 0xFF, 0xCD, 0xFF, 0xDE, 0xD6, 0x33, 0xDB, 0xA6, 0xFF, 0xFB, 0xC2, 0x04, 0xA2, 0x6F, + 0x73, 0xFC, 0x72, 0xD6, 0x5F, 0x41, 0x66, 0xD9, 0x06, 0x41, 0x6B, 0xE7, 0xC2, 0x43, 0x6C, 0x6F, + 0x73, 0xDC, 0x8A, 0xD6, 0x77, 0xD6, 0x70, 0x41, 0x2E, 0xD8, 0xF4, 0x21, 0x65, 0xFC, 0x41, 0x6A, + 0xDE, 0x82, 0x43, 0x64, 0x67, 0x73, 0xDC, 0x75, 0xDE, 0x7E, 0xD5, 0xF3, 0x48, 0x61, 0x63, 0x64, + 0x67, 0x6C, 0x6D, 0x72, 0x76, 0xFF, 0xD9, 0xFF, 0xDD, 0xFF, 0xE1, 0xFF, 0xEF, 0xFF, 0xF2, 0xDE, + 0x74, 0xFF, 0xF6, 0xDE, 0xCC, 0x41, 0x6B, 0xDB, 0xE3, 0x42, 0x61, 0xC3, 0xDB, 0x31, 0xE6, 0x9E, + 0x45, 0x61, 0x65, 0x69, 0x6C, 0x73, 0xFF, 0xF5, 0xDC, 0x01, 0xDC, 0x01, 0xFF, 0xF9, 0xE6, 0x1A, + 0x41, 0xA4, 0xDB, 0xC8, 0x42, 0x6F, 0xC3, 0xDB, 0xC4, 0xFF, 0xFC, 0x41, 0x73, 0xDE, 0x2A, 0x21, + 0x6E, 0xFC, 0x41, 0xC3, 0xDE, 0xAB, 0xC1, 0x01, 0x91, 0x70, 0xD7, 0x97, 0x42, 0xA5, 0xA4, 0xFF, + 0xFA, 0xDB, 0xCB, 0xC7, 0x02, 0x01, 0x65, 0x69, 0x6E, 0x6F, 0x72, 0x79, 0xC3, 0xFF, 0xEC, 0xDB, + 0xC4, 0xD5, 0x6B, 0xE5, 0x15, 0xFF, 0xEF, 0xDB, 0xC4, 0xFF, 0xF9, 0xC1, 0x00, 0x91, 0x6F, 0xD5, + 0xE9, 0x41, 0x79, 0xDC, 0x63, 0xC3, 0x02, 0x01, 0x65, 0x6C, 0x6F, 0xDB, 0xA2, 0xD5, 0x55, 0xDB, + 0x1D, 0xC1, 0x01, 0x91, 0x6B, 0xDB, 0x77, 0xC1, 0x00, 0x41, 0x72, 0xD5, 0x50, 0xC1, 0x01, 0x91, + 0x67, 0xDB, 0x6B, 0x43, 0xA5, 0xA4, 0xB6, 0xDB, 0x84, 0xDB, 0x84, 0xDA, 0xB7, 0xC5, 0x02, 0x01, + 0x61, 0x65, 0x6F, 0x79, 0xC3, 0xFF, 0xE4, 0xFF, 0xEA, 0xDB, 0x7A, 0xFF, 0xF0, 0xFF, 0xF6, 0xC1, + 0x02, 0x01, 0x72, 0xDA, 0x9B, 0xC1, 0x00, 0x91, 0x64, 0xD5, 0x22, 0xA1, 0x02, 0x01, 0x69, 0xFA, + 0xCC, 0x03, 0xD2, 0x63, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x75, 0x76, 0xC3, 0xDB, + 0x24, 0xFF, 0x74, 0xFF, 0x93, 0xEF, 0xC8, 0xFF, 0xAB, 0xFF, 0xB1, 0xFF, 0xB5, 0xD5, 0x17, 0xFF, + 0xDD, 0xFF, 0xEF, 0xFF, 0xFB, 0xE5, 0x83, 0x41, 0x75, 0xD5, 0xBB, 0x21, 0x74, 0xFC, 0x42, 0x66, + 0x68, 0xDB, 0x0A, 0xDB, 0x0A, 0x41, 0x74, 0xF4, 0xD9, 0x41, 0xB6, 0xDA, 0xFF, 0x43, 0x61, 0x65, + 0xC3, 0xFF, 0xF8, 0xDB, 0x27, 0xFF, 0xFC, 0xC7, 0x04, 0xA2, 0x61, 0x65, 0x69, 0x6F, 0x72, 0x73, + 0x75, 0xFF, 0xE4, 0xDC, 0x13, 0xFF, 0xE7, 0xE3, 0x11, 0xFF, 0xF6, 0xDC, 0x47, 0xD4, 0xDE, 0x41, + 0x74, 0xDC, 0x16, 0x41, 0x6C, 0xE2, 0xB0, 0xC1, 0x03, 0x61, 0x67, 0xD4, 0xCB, 0x42, 0x70, 0x75, + 0xDD, 0x43, 0xD5, 0x27, 0x41, 0x70, 0xEE, 0xE9, 0x42, 0x73, 0x74, 0xFF, 0xFC, 0xF9, 0x55, 0x42, + 0x62, 0x73, 0xDB, 0x28, 0xDB, 0x28, 0x47, 0x69, 0x6B, 0x6C, 0x6E, 0x70, 0x73, 0x74, 0xD4, 0x91, + 0xFF, 0xD9, 0xFF, 0xDD, 0xFF, 0xE1, 0xFF, 0xE7, 0xFF, 0xF2, 0xFF, 0xF9, 0xC1, 0x01, 0xD1, 0x72, + 0xEA, 0x94, 0x41, 0x72, 0xD8, 0x1A, 0xC1, 0x01, 0xD1, 0x76, 0xD6, 0x77, 0x21, 0xA4, 0xFA, 0xC7, + 0x03, 0x61, 0x61, 0x65, 0x69, 0x6F, 0x72, 0x73, 0xC3, 0xFF, 0xED, 0xFF, 0xF3, 0xDA, 0xB2, 0xE2, + 0xA9, 0xDA, 0xDA, 0xDA, 0x14, 0xFF, 0xFD, 0x41, 0x6B, 0xFB, 0x91, 0x43, 0x61, 0x72, 0x73, 0xE4, + 0xAF, 0xD4, 0x33, 0xD6, 0x23, 0x43, 0x65, 0x6E, 0x72, 0xDA, 0x25, 0xE0, 0x0B, 0xD4, 0xBF, 0x21, + 0x74, 0xF6, 0x23, 0x63, 0x67, 0x73, 0xE5, 0xE9, 0xFD, 0x41, 0x67, 0xF9, 0x85, 0x41, 0xA5, 0xD4, + 0x38, 0x42, 0x65, 0xC3, 0xD4, 0xD9, 0xFF, 0xFC, 0x42, 0x6B, 0x74, 0xD4, 0x2D, 0xFF, 0xF9, 0x44, + 0x2E, 0x67, 0x6E, 0x73, 0xDC, 0xB1, 0xD7, 0x30, 0xFF, 0xEA, 0xFF, 0xF9, 0x41, 0x73, 0xD9, 0xBE, + 0x41, 0x64, 0xFC, 0xE1, 0x22, 0x64, 0x67, 0xF8, 0xFC, 0x42, 0x61, 0x70, 0xD6, 0xDD, 0xD4, 0x0C, + 0x45, 0x63, 0x67, 0x6E, 0x73, 0x74, 0xDA, 0x87, 0xD6, 0x39, 0xFF, 0xF4, 0xFF, 0xF9, 0xD7, 0xE3, + 0x41, 0x65, 0xE0, 0xF1, 0x46, 0x6C, 0x6D, 0x6E, 0x72, 0x73, 0x76, 0xDA, 0x73, 0xDA, 0x73, 0xD9, + 0xC6, 0xFF, 0xFC, 0xD9, 0x96, 0xD5, 0x90, 0x44, 0xA5, 0xA4, 0xB6, 0xA9, 0xFF, 0xB8, 0xFF, 0xD9, + 0xFF, 0xED, 0xD9, 0xB3, 0x57, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, + 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0x79, 0xC3, 0xFB, 0xDD, 0xEC, 0xA5, + 0xE1, 0xC6, 0xFC, 0x14, 0xFC, 0x4A, 0xDE, 0x51, 0xFC, 0x77, 0xDC, 0x5C, 0xFC, 0xDD, 0xFD, 0x0C, + 0xFD, 0x28, 0xFD, 0x90, 0xFD, 0xB8, 0xDA, 0x0D, 0xFD, 0xE8, 0xFE, 0x0C, 0xDE, 0x54, 0xFE, 0xAC, + 0xFE, 0xF3, 0xFF, 0x32, 0xFF, 0x5B, 0xFF, 0x8E, 0xFF, 0xF3, 0x42, 0x6E, 0x73, 0xD3, 0x5E, 0xD3, + 0x5E, 0xA0, 0x08, 0x72, 0x42, 0x61, 0x6F, 0xD5, 0x47, 0xFF, 0xFD, 0xC1, 0x00, 0x81, 0x6B, 0xD6, + 0x45, 0x43, 0x64, 0x67, 0x69, 0xD3, 0x8E, 0xFF, 0xF3, 0xFF, 0xFA, 0xA0, 0x08, 0x92, 0x21, 0x69, + 0xFD, 0x41, 0x6F, 0xD3, 0x71, 0x43, 0x6F, 0x72, 0xC3, 0xD3, 0x39, 0xFF, 0xFC, 0xE4, 0x32, 0x44, + 0x68, 0x6B, 0x74, 0x76, 0xD3, 0xFB, 0xFF, 0xF6, 0xDB, 0x06, 0xD3, 0x56, 0xC8, 0x02, 0xF1, 0x66, + 0x67, 0x6A, 0x6B, 0x6C, 0x6E, 0x72, 0x73, 0xD7, 0xBB, 0xFF, 0xBE, 0xEE, 0xB2, 0xDA, 0xDC, 0xD9, + 0xAD, 0xFF, 0xD5, 0xFF, 0xE2, 0xFF, 0xF3, 0xC1, 0x03, 0x61, 0x73, 0xE2, 0xA0, 0xC4, 0x03, 0x61, + 0x61, 0x69, 0x6F, 0x72, 0xD9, 0x67, 0xD9, 0x3B, 0xD9, 0x3B, 0xEB, 0xF4, 0x42, 0x73, 0x75, 0xDB, + 0xA4, 0xD3, 0x88, 0x42, 0x6C, 0x6F, 0xD3, 0x81, 0xD3, 0x81, 0x43, 0x64, 0x6F, 0x75, 0xD9, 0x8D, + 0xD3, 0xB0, 0xD2, 0xFD, 0x43, 0x6B, 0x75, 0x79, 0xD2, 0xD4, 0xD2, 0xF3, 0xD2, 0xF3, 0x41, 0x6F, + 0xD3, 0xB4, 0x21, 0x6B, 0xFC, 0x21, 0x73, 0xFD, 0xC1, 0x00, 0xA1, 0x69, 0xD2, 0xD2, 0x42, 0x6F, + 0x74, 0xD3, 0x56, 0xFF, 0xFA, 0x42, 0x69, 0x6F, 0xD3, 0x2F, 0xD2, 0xB9, 0x42, 0x61, 0x72, 0xDB, + 0x64, 0xFF, 0xF9, 0xC9, 0x02, 0xF1, 0x64, 0x6B, 0x6C, 0x6E, 0x72, 0x73, 0x74, 0x75, 0x78, 0xFF, + 0xB9, 0xFF, 0xC0, 0xFF, 0xC7, 0xFF, 0xD1, 0xFF, 0xE2, 0xFF, 0xEB, 0xFF, 0xF9, 0xD2, 0xD2, 0xDB, + 0x5D, 0xC2, 0x03, 0xD2, 0x65, 0x6E, 0xE0, 0xE7, 0xD8, 0xC7, 0xA0, 0x08, 0xB3, 0x41, 0x6F, 0xD2, + 0xC2, 0xC1, 0x03, 0x31, 0x72, 0xD2, 0xA4, 0x45, 0x64, 0x67, 0x6B, 0x76, 0xC3, 0xDB, 0x29, 0xFF, + 0xF6, 0xFF, 0xFA, 0xD9, 0x20, 0xFB, 0x8E, 0xC3, 0x01, 0x01, 0x66, 0x70, 0x73, 0xD2, 0x80, 0xD2, + 0xFD, 0xDF, 0x86, 0x43, 0x65, 0x72, 0x74, 0xE5, 0x16, 0xD2, 0xF1, 0xD5, 0x8C, 0xC5, 0x02, 0xF1, + 0x64, 0x6C, 0x6E, 0x73, 0x74, 0xD9, 0x84, 0xD7, 0xB5, 0xFF, 0xDA, 0xFF, 0xEA, 0xFF, 0xF6, 0xC3, + 0x08, 0xE3, 0x65, 0x73, 0x75, 0xF7, 0xDA, 0xD3, 0x61, 0xF8, 0xBF, 0x43, 0x6D, 0x73, 0x76, 0xD8, + 0x59, 0xDF, 0x52, 0xD8, 0x6D, 0x41, 0xA5, 0xEF, 0xDF, 0xC6, 0x03, 0xD2, 0x61, 0x64, 0x67, 0x73, + 0x74, 0xC3, 0xFF, 0xF2, 0xD6, 0xBE, 0xD3, 0x47, 0xD9, 0x3B, 0xED, 0xB5, 0xFF, 0xFC, 0x41, 0x72, + 0xDA, 0xC2, 0x44, 0x61, 0x69, 0x75, 0x76, 0xD5, 0x29, 0xD9, 0xA4, 0xD2, 0xA2, 0xD2, 0x0C, 0xC6, + 0x02, 0xF1, 0x64, 0x69, 0x6D, 0x6E, 0x73, 0x74, 0xD8, 0x39, 0xD2, 0x95, 0xFF, 0xEF, 0xD5, 0x3A, + 0xD7, 0xA3, 0xFF, 0xF3, 0x42, 0x6B, 0x72, 0xD8, 0x10, 0xD8, 0x50, 0x43, 0x64, 0x6E, 0x74, 0xD1, + 0xEF, 0xF2, 0x1D, 0xD1, 0xEF, 0xC2, 0x02, 0x01, 0x61, 0x69, 0xFF, 0xF6, 0xE4, 0x31, 0x42, 0x6B, + 0x70, 0xD1, 0xF7, 0xD1, 0xE9, 0xC6, 0x03, 0xD2, 0x61, 0x6C, 0x6F, 0x70, 0x73, 0xC3, 0xFF, 0xDF, + 0xFF, 0xF0, 0xD2, 0xC6, 0xD1, 0xDF, 0xFF, 0xF9, 0xE2, 0x4E, 0x41, 0x65, 0xD7, 0xEE, 0x42, 0x61, + 0xC3, 0xF7, 0x58, 0xDF, 0x41, 0xC1, 0x02, 0x01, 0x69, 0xDA, 0x84, 0x43, 0x65, 0x6F, 0x72, 0xD3, + 0x90, 0xD8, 0x06, 0xFF, 0xFA, 0x41, 0xA4, 0xF1, 0xD7, 0xC6, 0x03, 0x31, 0x61, 0x6B, 0x6C, 0x6D, + 0x74, 0xC3, 0xF8, 0x15, 0xFF, 0xE1, 0xFF, 0xE5, 0xD4, 0xB2, 0xFF, 0xF2, 0xFF, 0xFC, 0x42, 0x6C, + 0x74, 0xD2, 0x5B, 0xD3, 0xDB, 0xA0, 0x09, 0x13, 0x42, 0x67, 0x6B, 0xFF, 0xFD, 0xD8, 0xED, 0x42, + 0x69, 0x74, 0xD7, 0x6B, 0xD4, 0xAA, 0x41, 0x6C, 0xD1, 0x8F, 0x21, 0x73, 0xFC, 0x47, 0x64, 0x6C, + 0x6D, 0x6E, 0x72, 0x73, 0x74, 0xD8, 0x0A, 0xFF, 0xE1, 0xDD, 0x43, 0xFF, 0xEB, 0xD7, 0x5D, 0xFF, + 0xF2, 0xFF, 0xFD, 0x41, 0x74, 0xD3, 0xD1, 0x42, 0x6E, 0x73, 0xD7, 0x13, 0xFF, 0xFC, 0x41, 0x74, + 0xF6, 0x0F, 0x42, 0x2E, 0x65, 0xD7, 0x08, 0xFF, 0xFC, 0x45, 0x67, 0x6C, 0x6E, 0x72, 0x73, 0xD1, + 0x76, 0xFF, 0xF9, 0xF6, 0x04, 0xD7, 0xDE, 0xD1, 0x9C, 0xC1, 0x02, 0xF1, 0x73, 0xD3, 0x44, 0xC1, + 0x02, 0xF1, 0x74, 0xE8, 0xA7, 0x46, 0x67, 0x6B, 0x6E, 0x72, 0x73, 0x74, 0xD7, 0xC2, 0xD1, 0x4D, + 0xFF, 0xF4, 0xF0, 0x90, 0xFF, 0xFA, 0xD6, 0xE5, 0x41, 0x6E, 0xF0, 0x28, 0x21, 0x65, 0xFC, 0x41, + 0x6B, 0xD5, 0x58, 0x46, 0x62, 0x67, 0x6A, 0x72, 0x73, 0x76, 0xFF, 0x93, 0xFF, 0xF9, 0xD6, 0xF7, + 0xFF, 0xFC, 0xD6, 0xF7, 0xD7, 0xA4, 0x23, 0xA5, 0xA4, 0xB6, 0xB3, 0xCF, 0xED, 0x56, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, + 0x75, 0x76, 0x79, 0xC3, 0xFD, 0xBF, 0xFD, 0xDA, 0xD9, 0x93, 0xFD, 0xE0, 0xFE, 0x36, 0xFE, 0x54, + 0xFE, 0x5D, 0xD9, 0x93, 0xFE, 0x90, 0xDB, 0x88, 0xDC, 0x98, 0xFE, 0xA2, 0xFE, 0xBC, 0xFE, 0xE2, + 0xFF, 0x18, 0xDB, 0x88, 0xFF, 0x4C, 0xDB, 0x88, 0xFF, 0x80, 0xDC, 0x98, 0xFF, 0x9A, 0xFF, 0xF9, + 0xC1, 0x03, 0x01, 0x73, 0xD0, 0xD2, 0xC1, 0x03, 0x01, 0x6F, 0xD0, 0xA4, 0xC3, 0x03, 0x61, 0x6F, + 0x72, 0x74, 0xD6, 0x8E, 0xFF, 0xFA, 0xD6, 0xF5, 0xC1, 0x03, 0x61, 0x6C, 0xDC, 0x68, 0x44, 0x66, + 0x67, 0x73, 0x75, 0xFF, 0xFA, 0xD7, 0x29, 0xD0, 0x80, 0xD3, 0x9D, 0x42, 0x62, 0x6E, 0xD5, 0xFF, + 0xDC, 0x55, 0x42, 0x64, 0x76, 0xDE, 0x81, 0xD7, 0x15, 0x45, 0x61, 0x62, 0x6B, 0x6D, 0x74, 0xE9, + 0x7F, 0xD9, 0x17, 0xD9, 0x17, 0xD7, 0x0E, 0xD9, 0x17, 0xCA, 0x02, 0xF1, 0x2E, 0x64, 0x66, 0x67, + 0x6B, 0x6C, 0x6D, 0x6E, 0x72, 0x73, 0xD6, 0x51, 0xFF, 0xB7, 0xD9, 0x07, 0xD4, 0xEE, 0xFF, 0xC3, + 0xFF, 0xD5, 0xFF, 0xE2, 0xFF, 0xE9, 0xFF, 0xF0, 0xE7, 0xA4, 0xC3, 0x02, 0x01, 0x61, 0x65, 0x69, + 0xD6, 0x8D, 0xD6, 0x8D, 0xD6, 0x8D, 0x41, 0x6B, 0xD0, 0x5F, 0xC3, 0x03, 0xD2, 0x68, 0x69, 0x79, + 0xFF, 0xF0, 0xD1, 0x21, 0xFF, 0xFC, 0x42, 0x6B, 0x76, 0xD6, 0x52, 0xD6, 0x52, 0xC1, 0x00, 0xE1, + 0x73, 0xD0, 0x11, 0x43, 0x6B, 0x73, 0x74, 0xD0, 0x24, 0xD0, 0x24, 0xD0, 0x17, 0xC1, 0x00, 0x71, + 0x6C, 0xD5, 0x8D, 0x42, 0x70, 0x73, 0xD6, 0x54, 0xD0, 0x14, 0x23, 0x61, 0x69, 0x6F, 0xE9, 0xF3, + 0xF9, 0x41, 0x61, 0xD0, 0x11, 0x44, 0x6B, 0x6E, 0x6F, 0x76, 0xFF, 0xFC, 0xCF, 0xF5, 0xD7, 0xA3, + 0xE5, 0x20, 0x41, 0xA5, 0xDD, 0x4B, 0xC7, 0x03, 0x61, 0x61, 0x64, 0x65, 0x69, 0x72, 0x73, 0xC3, + 0xFF, 0xC0, 0xD0, 0xFA, 0xFF, 0xC7, 0xF6, 0x58, 0xFF, 0xE4, 0xFF, 0xEF, 0xFF, 0xFC, 0x45, 0x69, + 0x6C, 0x72, 0x73, 0xC3, 0xD0, 0x56, 0xDB, 0xA2, 0xF0, 0x31, 0xCF, 0xC0, 0xE6, 0x68, 0xC1, 0x00, + 0xD1, 0x65, 0xDD, 0x1F, 0x21, 0x72, 0xFA, 0x41, 0x79, 0xCF, 0xC0, 0x41, 0x6C, 0xD6, 0x4C, 0x42, + 0x61, 0x69, 0xD0, 0x35, 0xCF, 0xB5, 0x42, 0x73, 0x74, 0xD0, 0x34, 0xFF, 0xF9, 0x41, 0x65, 0xCF, + 0x9D, 0x21, 0x72, 0xFC, 0xCB, 0x02, 0xF1, 0x2E, 0x64, 0x67, 0x6B, 0x6C, 0x6E, 0x72, 0x73, 0x74, + 0x75, 0x78, 0xD5, 0x86, 0xFF, 0xCA, 0xFF, 0xE0, 0xDD, 0x9F, 0xFF, 0xE3, 0xFF, 0xE7, 0xE6, 0x9D, + 0xFF, 0xF2, 0xFF, 0xFD, 0xE2, 0x7D, 0xD8, 0x3C, 0x41, 0x6C, 0xEB, 0x24, 0x21, 0x6C, 0xFC, 0xC2, + 0x08, 0xB3, 0x61, 0x69, 0xFF, 0xFD, 0xD2, 0x90, 0x41, 0x69, 0xD5, 0x90, 0x44, 0x2E, 0x64, 0x73, + 0x74, 0xD5, 0x8C, 0xD5, 0x8C, 0xD5, 0x8C, 0xFF, 0xFC, 0x43, 0x6E, 0x72, 0x74, 0xFF, 0xF3, 0xE5, + 0x77, 0xD5, 0x7F, 0xC2, 0x02, 0x01, 0x67, 0x73, 0xCF, 0x47, 0xCF, 0x62, 0xC2, 0x02, 0x01, 0x6D, + 0x72, 0xCF, 0x4B, 0xCF, 0x3E, 0x41, 0x64, 0xCF, 0x35, 0x42, 0x61, 0xC3, 0xFF, 0xFC, 0xFA, 0x60, + 0x41, 0x69, 0xE6, 0x2D, 0x41, 0x61, 0xD3, 0x5D, 0x45, 0x65, 0x6B, 0x70, 0x74, 0x76, 0xD5, 0x25, + 0xCF, 0x7D, 0xDE, 0x50, 0xFF, 0xF8, 0xFF, 0xFC, 0x41, 0xB6, 0xD7, 0xCE, 0xC8, 0x09, 0x42, 0x61, + 0x65, 0x69, 0x6C, 0x6F, 0x72, 0x73, 0xC3, 0xD5, 0x3F, 0xFF, 0xBD, 0xFF, 0xC7, 0xF0, 0xAB, 0xFF, + 0xD0, 0xFF, 0xDD, 0xFF, 0xEC, 0xFF, 0xFC, 0x41, 0x63, 0xCF, 0x00, 0xC2, 0x01, 0x51, 0x6B, 0x76, + 0xCF, 0xBB, 0xD0, 0x48, 0x21, 0x73, 0xF7, 0xA1, 0x03, 0x01, 0x67, 0xFD, 0xC1, 0x03, 0x31, 0x70, + 0xCE, 0xFC, 0x41, 0x72, 0xEE, 0xDC, 0x42, 0x65, 0x72, 0xFF, 0xFC, 0xD2, 0x5D, 0x21, 0x74, 0xF9, + 0x42, 0x6B, 0x74, 0xCE, 0xB8, 0xCE, 0xB8, 0x21, 0x73, 0xF9, 0xCA, 0x04, 0x12, 0x64, 0x65, 0x6B, + 0x6C, 0x6E, 0x6F, 0x70, 0x73, 0x74, 0x76, 0xD5, 0x5D, 0xFF, 0xCD, 0xE3, 0xBD, 0xEE, 0xC4, 0xFF, + 0xDD, 0xD2, 0x06, 0xFF, 0xE2, 0xFF, 0xF3, 0xDA, 0x07, 0xFF, 0xFD, 0x42, 0x6E, 0x73, 0xD4, 0xEC, + 0xCE, 0xBA, 0xC3, 0x03, 0xD2, 0x61, 0x75, 0xC3, 0xD4, 0xC9, 0xFF, 0xF9, 0xD7, 0xBB, 0xC1, 0x01, + 0xD1, 0x73, 0xEC, 0x42, 0x41, 0x79, 0xD4, 0xD3, 0x41, 0x74, 0xD1, 0x12, 0x21, 0x66, 0xFC, 0x44, + 0x61, 0x69, 0x6F, 0x75, 0xFF, 0xFD, 0xCE, 0x7B, 0xD4, 0xD2, 0xD2, 0x2D, 0x42, 0x6C, 0x70, 0xCE, + 0x7B, 0xCE, 0x6E, 0xC9, 0x03, 0x61, 0x61, 0x69, 0x6E, 0x6F, 0x72, 0x73, 0x74, 0x75, 0xC3, 0xEC, + 0x98, 0xFF, 0xDB, 0xFF, 0xE1, 0xD4, 0xBE, 0xFF, 0xEC, 0xFF, 0xF9, 0xF5, 0x8F, 0xD4, 0xBE, 0xEF, + 0xB0, 0x41, 0x74, 0xCF, 0x5F, 0xC5, 0x03, 0xD2, 0x64, 0x65, 0x69, 0x6B, 0x73, 0xCE, 0x45, 0xD4, + 0x92, 0xCF, 0x36, 0xCE, 0x45, 0xFF, 0xFC, 0x41, 0x6C, 0xD6, 0xD9, 0x42, 0x72, 0x73, 0xD6, 0xD5, + 0xCE, 0xBF, 0x42, 0x64, 0x67, 0xD6, 0xCE, 0xD6, 0xCE, 0x42, 0x61, 0x63, 0xCE, 0x2E, 0xCE, 0x2E, + 0xC7, 0x02, 0xF1, 0x64, 0x6B, 0x6C, 0x6D, 0x72, 0x73, 0x74, 0xFF, 0xE7, 0xCE, 0xA7, 0xF8, 0x3E, + 0xFF, 0xEB, 0xFF, 0xF2, 0xFF, 0xF9, 0xD3, 0x72, 0xC2, 0x00, 0xD1, 0x6E, 0x73, 0xD4, 0x5C, 0xE0, + 0x0D, 0xC3, 0x00, 0xD1, 0x61, 0x69, 0x6F, 0xE0, 0x45, 0xD4, 0x50, 0xCF, 0x4E, 0x42, 0x67, 0x73, + 0xE9, 0x9F, 0xCD, 0xFA, 0x21, 0x61, 0xF9, 0x41, 0x69, 0xD4, 0xED, 0x41, 0x63, 0xD4, 0x0D, 0x43, + 0x69, 0x6C, 0x6F, 0xD4, 0x32, 0xCD, 0xDB, 0xCD, 0xDB, 0x41, 0x73, 0xD4, 0x1E, 0x42, 0x6E, 0x70, + 0xFF, 0xFC, 0xD4, 0x1A, 0x42, 0x66, 0x67, 0xD4, 0x13, 0xCD, 0xC6, 0x42, 0x61, 0x69, 0xCE, 0x49, + 0xF7, 0x07, 0x41, 0x69, 0xCD, 0xA9, 0x47, 0x61, 0x65, 0x69, 0x72, 0x75, 0x76, 0x79, 0xFF, 0xE7, + 0xCE, 0x41, 0xFF, 0xEE, 0xFF, 0xF5, 0xCE, 0xA9, 0xFF, 0xFC, 0xE6, 0x9B, 0x41, 0xA4, 0xCE, 0xF3, + 0x43, 0x61, 0x69, 0xC3, 0xD3, 0xF1, 0xCD, 0x9A, 0xFF, 0xFC, 0xC9, 0x03, 0x31, 0x69, 0x6B, 0x6C, + 0x6D, 0x6F, 0x70, 0x73, 0x74, 0x76, 0xFF, 0x8E, 0xFF, 0x97, 0xFF, 0xAA, 0xFF, 0xAD, 0xFF, 0xB1, + 0xFF, 0xB5, 0xCE, 0xA6, 0xFF, 0xDC, 0xFF, 0xF6, 0x41, 0x72, 0xF7, 0xBD, 0xA0, 0x09, 0x62, 0x21, + 0x73, 0xFD, 0x21, 0x72, 0xFD, 0x41, 0x6E, 0xD4, 0xB5, 0x41, 0x62, 0xD7, 0x3A, 0x21, 0x6D, 0xFC, + 0x42, 0x61, 0x69, 0xD2, 0xDA, 0xCD, 0x5A, 0x45, 0x64, 0x68, 0x6B, 0x6C, 0x6D, 0xCD, 0x53, 0xD3, + 0xA0, 0xD3, 0xA0, 0xFF, 0xF9, 0xD2, 0xD3, 0x42, 0x70, 0x72, 0xCD, 0x43, 0xD3, 0x90, 0x43, 0x61, + 0x6E, 0x73, 0xCD, 0x3C, 0xCD, 0x3C, 0xCD, 0x3C, 0x41, 0x69, 0xD5, 0xC9, 0x42, 0x70, 0x72, 0xFF, + 0xFC, 0xD3, 0x5C, 0x45, 0x61, 0x65, 0x69, 0x6F, 0xC3, 0xFF, 0xD4, 0xFF, 0xE4, 0xFF, 0xEB, 0xFF, + 0xF9, 0xF8, 0x56, 0x41, 0x6F, 0xE2, 0x64, 0x44, 0x63, 0x65, 0x6B, 0x74, 0xCD, 0x07, 0xCD, 0x9D, + 0xFF, 0xFC, 0xD3, 0x16, 0x41, 0xC3, 0xDE, 0xF5, 0xC8, 0x03, 0xD2, 0x61, 0x65, 0x69, 0x6F, 0x72, + 0x73, 0x75, 0x76, 0xFF, 0x90, 0xFF, 0x9A, 0xFF, 0x9D, 0xFF, 0xA5, 0xFF, 0xDB, 0xFF, 0xEF, 0xD3, + 0x5C, 0xFF, 0xFC, 0x41, 0x74, 0xD0, 0x99, 0xC1, 0x03, 0x01, 0x73, 0xCD, 0xA3, 0xC1, 0x03, 0x61, + 0x70, 0xD3, 0x2A, 0x41, 0x62, 0xD5, 0x7D, 0x46, 0x66, 0x67, 0x69, 0x6D, 0x70, 0x74, 0xFF, 0xEC, + 0xF3, 0x69, 0xD2, 0xC3, 0xFF, 0xF0, 0xFF, 0xF6, 0xFF, 0xFC, 0x41, 0x67, 0xD1, 0x4D, 0x44, 0x2E, + 0x63, 0x6D, 0x74, 0xD3, 0x59, 0xD3, 0x59, 0xD2, 0xAC, 0xD2, 0xAC, 0xA0, 0x09, 0x82, 0xC1, 0x03, + 0x01, 0x61, 0xCD, 0x84, 0xC1, 0x00, 0xC1, 0x6B, 0xD8, 0xAA, 0x45, 0x67, 0x6A, 0x6B, 0x6C, 0x73, + 0xFF, 0xF1, 0xFF, 0xF4, 0xE1, 0xED, 0xD3, 0x3D, 0xFF, 0xFA, 0x43, 0xA5, 0xA4, 0xB6, 0xDA, 0x89, + 0xFF, 0xD4, 0xFF, 0xF0, 0x58, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, + 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0x79, 0x7A, 0xC3, 0xFC, 0x25, 0xE5, + 0x75, 0xFC, 0x56, 0xFC, 0xA2, 0xFC, 0xF0, 0xFD, 0x1B, 0xFD, 0x78, 0xD5, 0x2C, 0xFD, 0xC6, 0xFD, + 0xEE, 0xFE, 0x1F, 0xD7, 0x21, 0xD7, 0x21, 0xFE, 0x41, 0xFE, 0x6C, 0xD7, 0x21, 0xD7, 0x21, 0xFE, + 0xF6, 0xFF, 0x84, 0xFF, 0xB3, 0xD7, 0x21, 0xFF, 0xC6, 0xD2, 0x06, 0xFF, 0xF6, 0x41, 0x64, 0xD2, + 0x57, 0xA1, 0x01, 0xD1, 0x72, 0xFC, 0xA0, 0x09, 0xA2, 0xC3, 0x02, 0x01, 0x6A, 0x6C, 0x79, 0xFF, + 0xFD, 0xFC, 0xCF, 0xCC, 0x4C, 0xA0, 0x09, 0xC2, 0x43, 0x72, 0x73, 0x75, 0xFF, 0xFD, 0xD1, 0xBA, + 0xCC, 0x22, 0x21, 0x6B, 0xF6, 0x41, 0x69, 0xD1, 0xD5, 0x42, 0x61, 0x6F, 0xDD, 0xE6, 0xD2, 0x5E, + 0xC2, 0x00, 0xD1, 0x69, 0x75, 0xCC, 0x25, 0xCC, 0x17, 0x42, 0x6B, 0x74, 0xCC, 0x1C, 0xFF, 0xF7, + 0xC6, 0x02, 0x01, 0x65, 0x69, 0x6C, 0x72, 0x73, 0xC3, 0xCF, 0x1B, 0xD2, 0x0B, 0xFF, 0xE5, 0xFF, + 0xE9, 0xFF, 0xF9, 0xD5, 0x1D, 0xA0, 0x09, 0xE1, 0x21, 0xA5, 0xFD, 0x21, 0xC3, 0xFD, 0x21, 0x6D, + 0xFD, 0x21, 0x72, 0xFD, 0x21, 0xB6, 0xFD, 0x44, 0x66, 0x6C, 0x72, 0xC3, 0xD5, 0x39, 0xD2, 0x01, + 0xD2, 0x20, 0xFF, 0xFD, 0x42, 0x6F, 0x79, 0xD1, 0x46, 0xD1, 0x46, 0xC1, 0x02, 0x11, 0x74, 0xCC, + 0x7F, 0x21, 0x73, 0xFA, 0x21, 0x6F, 0xFD, 0x42, 0x69, 0xC3, 0xD1, 0xE1, 0xF6, 0xE2, 0x42, 0x65, + 0x74, 0xCB, 0xAC, 0xEC, 0x11, 0xC8, 0x01, 0xD1, 0x61, 0x67, 0x6A, 0x6C, 0x6E, 0x72, 0x73, 0xC3, + 0xD4, 0x40, 0xCC, 0xFA, 0xD1, 0xD3, 0xFF, 0xDF, 0xFF, 0xEF, 0xFF, 0xF2, 0xFF, 0xF9, 0xF6, 0x0B, + 0xC1, 0x01, 0xD1, 0x6C, 0xD1, 0xB8, 0x42, 0x6C, 0x75, 0xCB, 0x84, 0xCC, 0x0E, 0xC4, 0x01, 0xD1, + 0x6C, 0x6E, 0x73, 0x76, 0xFC, 0x1B, 0xCB, 0x7D, 0xFF, 0xF9, 0xD1, 0x97, 0xC2, 0x01, 0xD1, 0x6B, + 0x75, 0xD0, 0xEE, 0xCB, 0x7B, 0x41, 0xB6, 0xCD, 0x78, 0x21, 0xC3, 0xFC, 0x44, 0x61, 0x72, 0x75, + 0xC3, 0xCB, 0x5E, 0xCB, 0x52, 0xCB, 0xE8, 0xCC, 0x84, 0x42, 0x69, 0x6C, 0xCB, 0x6C, 0xE0, 0x7C, + 0x42, 0x73, 0xC3, 0xFF, 0xF9, 0xD8, 0xCF, 0x41, 0x76, 0xCB, 0x31, 0xA1, 0x01, 0xD1, 0x6B, 0xFC, + 0x41, 0xC3, 0xDE, 0xF2, 0xC2, 0x01, 0xD1, 0x67, 0x72, 0xD1, 0x64, 0xD1, 0x64, 0x42, 0xA5, 0xA4, + 0xCF, 0xBA, 0xD1, 0x84, 0x4D, 0x61, 0x66, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x73, 0x74, 0x75, + 0x79, 0xC3, 0xFF, 0xB8, 0xFF, 0xC5, 0xD0, 0xE6, 0xFF, 0xC8, 0xFF, 0xDC, 0xD2, 0xC2, 0xD2, 0x4D, + 0xFF, 0xE7, 0xD1, 0x9A, 0xFF, 0xEC, 0xFF, 0xF0, 0xD1, 0x7D, 0xFF, 0xF9, 0x41, 0x72, 0xE7, 0x82, + 0x41, 0x6E, 0xD1, 0x47, 0x41, 0x72, 0xD3, 0xB2, 0x42, 0x61, 0x6C, 0xCA, 0xFF, 0xCA, 0xF2, 0xC1, + 0x02, 0xF1, 0x61, 0xD1, 0x88, 0x41, 0xA4, 0xEF, 0xCB, 0x43, 0x6B, 0x74, 0xC3, 0xCE, 0x27, 0xD2, + 0xDC, 0xFF, 0xFC, 0x42, 0x72, 0x76, 0xCB, 0x61, 0xCA, 0xD7, 0x27, 0x62, 0x65, 0x6F, 0x70, 0x72, + 0x73, 0x74, 0xD2, 0xD6, 0xDA, 0xDE, 0xE5, 0xEF, 0xF9, 0x43, 0x69, 0x72, 0x73, 0xCA, 0xCE, 0xCE, + 0x07, 0xCF, 0x0E, 0x42, 0x6C, 0x72, 0xCA, 0xC4, 0xCA, 0xD2, 0x21, 0x65, 0xF9, 0x44, 0x63, 0x69, + 0x6D, 0x74, 0xCA, 0xA1, 0xCD, 0xD2, 0xCA, 0xA1, 0xFF, 0xFD, 0x42, 0x61, 0x65, 0xD4, 0x09, 0xCB, + 0x2A, 0x42, 0x72, 0x73, 0xFF, 0xF9, 0xCA, 0xB4, 0x43, 0xA5, 0xA4, 0xB6, 0xCA, 0x9F, 0xD0, 0xE9, + 0xD0, 0xDF, 0x49, 0x63, 0x67, 0x69, 0x6A, 0x6B, 0x73, 0x74, 0x79, 0xC3, 0xCA, 0x88, 0xFF, 0xC7, + 0xDC, 0x55, 0xCA, 0x88, 0xCD, 0xB4, 0xFF, 0xDB, 0xFF, 0xEF, 0xD0, 0xDF, 0xFF, 0xF6, 0x43, 0x64, + 0x6D, 0x72, 0xCA, 0xF6, 0xD2, 0xDC, 0xD0, 0xB9, 0x41, 0x6E, 0xEA, 0x90, 0x21, 0x69, 0xFC, 0xC1, + 0x00, 0x41, 0x65, 0xCA, 0x4F, 0x43, 0x6C, 0x72, 0x75, 0xFF, 0xFA, 0xCA, 0xDF, 0xCA, 0xDF, 0x47, + 0x65, 0x69, 0x6C, 0x70, 0x72, 0x73, 0xC3, 0xD0, 0xA2, 0xD0, 0xA2, 0xFF, 0xED, 0xFF, 0xF6, 0xED, + 0x11, 0xDA, 0xBB, 0xDC, 0x3A, 0x41, 0x67, 0xEC, 0x0E, 0xC3, 0x03, 0x31, 0x6B, 0x6E, 0x70, 0xD0, + 0x7E, 0xFF, 0xFC, 0xD0, 0x4B, 0x41, 0xA4, 0xFE, 0x00, 0x42, 0x6E, 0xC3, 0xCF, 0xE1, 0xFF, 0xFC, + 0x41, 0x68, 0xD0, 0x48, 0x41, 0x69, 0xD5, 0xEC, 0xA1, 0x02, 0xF1, 0x6E, 0xFC, 0x43, 0x61, 0x72, + 0xC3, 0xFF, 0xFB, 0xCA, 0x97, 0xDD, 0xC5, 0x41, 0x6E, 0xEE, 0xE9, 0xA1, 0x01, 0xD1, 0x65, 0xFC, + 0x42, 0x75, 0xC3, 0xCA, 0x84, 0xCB, 0x20, 0x42, 0x6C, 0x72, 0xCA, 0x7D, 0xCA, 0x00, 0x41, 0x69, + 0xE0, 0xE3, 0x42, 0x70, 0x74, 0xD0, 0x5C, 0xFF, 0xFC, 0xC2, 0x00, 0xD1, 0x65, 0x6F, 0xC9, 0xD5, + 0xC9, 0xD5, 0x42, 0x65, 0x72, 0xC9, 0xE5, 0xFF, 0xF7, 0x42, 0xA4, 0xB6, 0xD0, 0x28, 0xD0, 0x28, + 0x4F, 0x61, 0x64, 0x65, 0x67, 0x69, 0x6B, 0x6D, 0x6E, 0x6F, 0x70, 0x73, 0x74, 0x75, 0x79, 0xC3, + 0xFF, 0x99, 0xFF, 0xA9, 0xFF, 0xB0, 0xFF, 0xBD, 0xFF, 0xCB, 0xD0, 0x67, 0xE0, 0x6A, 0xFF, 0xD0, + 0xD0, 0x21, 0xFF, 0xD7, 0xFF, 0xE2, 0xFF, 0xF2, 0xD0, 0x21, 0xD0, 0x17, 0xFF, 0xF9, 0x41, 0xA4, + 0xE0, 0x90, 0x21, 0xC3, 0xFC, 0x41, 0x70, 0xCF, 0xEC, 0x42, 0x6C, 0x6F, 0xC9, 0xAC, 0xFF, 0xFC, + 0x41, 0x69, 0xEA, 0x24, 0xA0, 0x09, 0xF2, 0x42, 0x6B, 0x74, 0xCA, 0x0D, 0xFF, 0xFD, 0x43, 0x67, + 0x6B, 0x6C, 0xC9, 0x7C, 0xCE, 0x0D, 0xDB, 0x51, 0xC2, 0x00, 0x41, 0x6F, 0xC3, 0xE6, 0xA7, 0xD3, + 0x84, 0x43, 0x69, 0x72, 0x75, 0xFF, 0xED, 0xFF, 0xF7, 0xCF, 0x31, 0x46, 0x66, 0x6B, 0x6F, 0x70, + 0x73, 0x74, 0xFF, 0xC7, 0xFF, 0xCE, 0xE4, 0x73, 0xFF, 0xD5, 0xFF, 0xDC, 0xFF, 0xF6, 0x41, 0x61, + 0xE1, 0x71, 0x21, 0x6C, 0xFC, 0x43, 0x2E, 0x65, 0x6E, 0xCF, 0xE2, 0xCF, 0xE2, 0xCF, 0xE2, 0x42, + 0x6F, 0x75, 0xCE, 0xBB, 0xC9, 0xA5, 0x41, 0x76, 0xC9, 0x34, 0x43, 0x69, 0x72, 0x73, 0xC9, 0x3D, + 0xE5, 0xB4, 0xCA, 0x08, 0xC1, 0x01, 0xD1, 0x6E, 0xCE, 0xA6, 0x41, 0x6E, 0xCB, 0x33, 0x21, 0x69, + 0xFC, 0x42, 0xA5, 0xA4, 0xCE, 0x99, 0xCF, 0x66, 0x4A, 0x61, 0x69, 0x6F, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x79, 0xC3, 0xFF, 0xCA, 0xFF, 0xCD, 0xCF, 0x69, 0xFF, 0xD7, 0xFF, 0xDE, 0xFF, 0xE2, 0xFF, + 0xEC, 0xFF, 0xF6, 0xCF, 0x69, 0xFF, 0xF9, 0xC1, 0x03, 0x31, 0xC3, 0xF1, 0xFE, 0xA0, 0x0A, 0x12, + 0x21, 0x74, 0xFD, 0x45, 0x6E, 0x70, 0x72, 0x73, 0x74, 0xC9, 0x02, 0xC9, 0x02, 0xFF, 0xF4, 0xC9, + 0x71, 0xFF, 0xFD, 0xC1, 0x01, 0xD1, 0x6E, 0xC8, 0xF2, 0x43, 0x69, 0x6C, 0x6D, 0xC9, 0x5B, 0xC8, + 0xD1, 0xCB, 0x4B, 0x45, 0x61, 0x69, 0x72, 0x73, 0xC3, 0xFF, 0xF0, 0xCF, 0x1E, 0xC8, 0xC7, 0xFF, + 0xF6, 0xDB, 0x8B, 0x43, 0xA5, 0xA4, 0xB6, 0xCF, 0x04, 0xFD, 0xBD, 0xCF, 0x04, 0x59, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, + 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0xC3, 0xFC, 0x74, 0xFC, 0x7C, 0xFC, 0x95, 0xFC, 0xB3, 0xCF, + 0x04, 0xFC, 0xDA, 0xFD, 0x08, 0xFD, 0x23, 0xCF, 0x04, 0xFD, 0x30, 0xFD, 0x87, 0xFD, 0xDD, 0xFE, + 0x25, 0xFE, 0x41, 0xFE, 0x62, 0xCE, 0x2D, 0xFE, 0xE3, 0xFF, 0x4E, 0xFF, 0x9B, 0xFF, 0xC6, 0xFF, + 0xE6, 0xD4, 0x78, 0xC8, 0xBA, 0xCB, 0xBE, 0xFF, 0xF6, 0xC1, 0x00, 0xB1, 0x73, 0xCA, 0x74, 0x21, + 0x69, 0xFA, 0x43, 0x61, 0x73, 0xC3, 0xC8, 0x65, 0xC9, 0x18, 0xDB, 0xEC, 0x42, 0x64, 0x74, 0xD6, + 0x57, 0xC8, 0x6C, 0x43, 0x62, 0x6D, 0x73, 0xD0, 0xED, 0xCE, 0xE4, 0xC8, 0x3B, 0xC1, 0x03, 0x61, + 0x69, 0xC8, 0x4A, 0x42, 0x6B, 0x74, 0xFF, 0xFA, 0xCB, 0x48, 0xCA, 0x02, 0xF1, 0x66, 0x67, 0x6B, + 0x6C, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x75, 0xCE, 0xCD, 0xC8, 0x4B, 0xFF, 0xD5, 0xFF, 0xD8, 0xFF, + 0xE2, 0xCE, 0x20, 0xFF, 0xE9, 0xFF, 0xF9, 0xD5, 0x47, 0xC8, 0x30, 0xA0, 0x07, 0x63, 0x42, 0x69, + 0x6F, 0xC7, 0xFA, 0xC8, 0x34, 0x21, 0x72, 0xF9, 0x21, 0x74, 0xFD, 0x41, 0x69, 0xC8, 0x8F, 0x42, + 0x64, 0x73, 0xCE, 0x98, 0xFF, 0xFC, 0x43, 0x67, 0x6E, 0x74, 0xD3, 0xCA, 0xCD, 0xE4, 0xCA, 0x43, + 0x41, 0x6F, 0xCD, 0xDA, 0xC1, 0x03, 0x01, 0x6C, 0xC8, 0x01, 0x43, 0x62, 0x69, 0x73, 0xF6, 0x6C, + 0xFF, 0xF6, 0xFF, 0xFA, 0x47, 0x6B, 0x6C, 0x6D, 0x6E, 0x72, 0x74, 0x78, 0xFF, 0xD4, 0xFF, 0xDB, + 0xCE, 0x73, 0xFF, 0xE2, 0xFF, 0xF6, 0xDD, 0xE5, 0xCE, 0x73, 0x42, 0x61, 0x6F, 0xC7, 0xCD, 0xC7, + 0xCD, 0x42, 0x6F, 0x74, 0xC7, 0xC6, 0xFF, 0xF9, 0x45, 0x65, 0x67, 0x6F, 0x70, 0x73, 0xC8, 0x3F, + 0xCD, 0x72, 0xCA, 0xF8, 0xCD, 0xA2, 0xFF, 0xF9, 0x41, 0xA4, 0xEB, 0xCB, 0xA1, 0x02, 0x01, 0xC3, + 0xFC, 0xA0, 0x0A, 0x33, 0x42, 0x2E, 0x65, 0xD3, 0x6C, 0xCD, 0xC4, 0x43, 0x63, 0x6E, 0x72, 0xCD, + 0xBD, 0xFF, 0xF9, 0xFC, 0x95, 0x42, 0x76, 0x78, 0xCD, 0xD2, 0xCD, 0x75, 0x43, 0x63, 0x6B, 0x74, + 0xCD, 0x6E, 0xCD, 0x3E, 0xCE, 0x1B, 0x42, 0x6D, 0x70, 0xCD, 0x34, 0xCD, 0xC1, 0xC5, 0x02, 0x01, + 0x61, 0x65, 0x69, 0x6A, 0x6F, 0xFF, 0xDE, 0xFF, 0xE8, 0xFF, 0xEF, 0xCD, 0xBA, 0xFF, 0xF9, 0xC1, + 0x04, 0xA2, 0x69, 0xCD, 0xA8, 0x43, 0x69, 0x6A, 0x79, 0xEC, 0x3B, 0xCD, 0xF2, 0xC7, 0x7D, 0x41, + 0x67, 0xCF, 0xF1, 0xC1, 0x03, 0x01, 0x74, 0xC9, 0x24, 0xC1, 0x03, 0x31, 0xC3, 0xC8, 0x67, 0xC8, + 0x02, 0xF1, 0x61, 0x63, 0x66, 0x69, 0x6C, 0x72, 0x73, 0x76, 0xD3, 0x11, 0xCF, 0xE1, 0xCF, 0xE1, + 0xCA, 0x4C, 0xFF, 0xE6, 0xFF, 0xF0, 0xFF, 0xF4, 0xFF, 0xFA, 0x43, 0x72, 0x73, 0x78, 0xCD, 0x7A, + 0xCE, 0xA4, 0xCD, 0x4E, 0xC1, 0x01, 0xD1, 0x6E, 0xD5, 0x64, 0x42, 0x6E, 0x73, 0xC7, 0x10, 0xC7, + 0x1D, 0x42, 0x6E, 0x74, 0xC7, 0x09, 0xC7, 0x09, 0x43, 0xA5, 0xA4, 0xB6, 0xFF, 0xF9, 0xC7, 0x02, + 0xC7, 0x02, 0xC5, 0x02, 0x81, 0x61, 0x69, 0x75, 0x79, 0xC3, 0xC6, 0xF8, 0xFF, 0xE8, 0xC7, 0x05, + 0xC6, 0xF8, 0xFF, 0xF6, 0x42, 0x63, 0x66, 0xC6, 0xF3, 0xC6, 0xE6, 0xC5, 0x02, 0x81, 0x61, 0x69, + 0x75, 0x79, 0xC3, 0xC6, 0xDF, 0xC6, 0xDF, 0xC6, 0xDF, 0xC6, 0xDF, 0xD4, 0x64, 0xCC, 0x03, 0x61, + 0x61, 0x65, 0x69, 0x6A, 0x6C, 0x6F, 0x70, 0x72, 0x74, 0x75, 0x79, 0xC3, 0xFF, 0xAD, 0xCD, 0x1A, + 0xFF, 0xB7, 0xC6, 0xCD, 0xFF, 0xD5, 0xFF, 0xE7, 0xC7, 0xE3, 0xFF, 0xEE, 0xC8, 0x22, 0xCC, 0xE7, + 0xCC, 0x4D, 0xCD, 0xC5, 0xC1, 0x03, 0x61, 0x78, 0xD2, 0x7C, 0xC2, 0x00, 0xC1, 0x61, 0x6F, 0xC6, + 0x94, 0xC7, 0x60, 0xA1, 0x02, 0xF1, 0x74, 0xF7, 0x21, 0x73, 0xFB, 0x42, 0x63, 0x67, 0xCC, 0x7F, + 0xC7, 0x5B, 0x45, 0x67, 0x6B, 0x6C, 0x6E, 0x6F, 0xCC, 0xD5, 0xCC, 0xD5, 0xD2, 0x5E, 0xFF, 0xF9, + 0xD8, 0x5D, 0xC2, 0x03, 0x01, 0x67, 0x72, 0xC6, 0x6C, 0xCC, 0xC5, 0x41, 0x76, 0xCC, 0x5F, 0x43, + 0xA5, 0xA4, 0xB6, 0xCD, 0x08, 0xEA, 0x94, 0xFF, 0xFC, 0xA5, 0x05, 0x42, 0x61, 0x65, 0x69, 0x6F, + 0xC3, 0xBB, 0xCF, 0xD9, 0xE9, 0xF6, 0xC1, 0x02, 0x01, 0x6D, 0xCC, 0x44, 0x21, 0x6C, 0xFA, 0xA0, + 0x0A, 0x62, 0x21, 0x6F, 0xFD, 0x41, 0x61, 0xCC, 0x92, 0xC1, 0x03, 0x31, 0x64, 0xCC, 0x8E, 0x41, + 0xA4, 0xCE, 0xD6, 0xC2, 0x08, 0x52, 0x61, 0xC3, 0xF0, 0x82, 0xFF, 0xFC, 0xC8, 0x03, 0x61, 0x61, + 0x68, 0x6B, 0x6C, 0x6E, 0x6F, 0x74, 0xC3, 0xFF, 0xE0, 0xFF, 0xE6, 0xEC, 0xDF, 0xD9, 0x51, 0xFF, + 0xE9, 0xFF, 0xED, 0xFF, 0xF7, 0xD6, 0xDA, 0xC1, 0x03, 0xD2, 0x72, 0xE8, 0xD9, 0x41, 0x76, 0xE0, + 0x60, 0x21, 0x6F, 0xFC, 0x42, 0x6C, 0x74, 0xFF, 0xFD, 0xDB, 0x53, 0x42, 0x67, 0x6B, 0xD1, 0xD5, + 0xCB, 0xEF, 0xC4, 0x02, 0xF1, 0x67, 0x6C, 0x6E, 0x73, 0xCC, 0x95, 0xFF, 0xF2, 0xFF, 0xF9, 0xC6, + 0x7B, 0x41, 0x64, 0xCD, 0x97, 0x42, 0x6C, 0x72, 0xCB, 0xD5, 0xC9, 0xC2, 0x44, 0xA5, 0xA4, 0xB6, + 0xA9, 0xFF, 0xF5, 0xFF, 0xF9, 0xD3, 0xD7, 0xCB, 0xCE, 0x56, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0xC3, + 0xFD, 0xA1, 0xDE, 0xC0, 0xCE, 0x77, 0xFD, 0xC2, 0xFD, 0xFB, 0xD0, 0x6C, 0xD0, 0x6F, 0xCE, 0x77, + 0xFE, 0x1F, 0xFE, 0x33, 0xFE, 0x38, 0xFE, 0x64, 0xD0, 0x6C, 0xFE, 0x76, 0xFE, 0x96, 0xFF, 0x04, + 0xFF, 0x70, 0xFF, 0xA3, 0xFF, 0xBE, 0xFF, 0xD9, 0xD0, 0x6C, 0xFF, 0xF3, 0xC1, 0x00, 0x41, 0x65, + 0xCB, 0x7E, 0x21, 0x75, 0xFA, 0x41, 0x69, 0xC8, 0x2B, 0x43, 0x65, 0x72, 0x75, 0xD8, 0x77, 0xCC, + 0x1E, 0xC6, 0x0B, 0xA0, 0x0A, 0x82, 0x41, 0xA4, 0xCE, 0x1A, 0x21, 0xC3, 0xFC, 0x42, 0x66, 0x72, + 0xFF, 0xFD, 0xC5, 0x6D, 0x41, 0x6F, 0xC8, 0x77, 0xC1, 0x00, 0x91, 0x2E, 0xCB, 0x52, 0xA0, 0x03, + 0x33, 0x43, 0x65, 0x72, 0x73, 0xFF, 0xF7, 0xFF, 0xFD, 0xC5, 0x81, 0x41, 0x76, 0xCD, 0xF5, 0x22, + 0x64, 0x73, 0xF2, 0xFC, 0xC1, 0x03, 0x31, 0x61, 0xCB, 0x93, 0xCA, 0x03, 0x01, 0x2E, 0x62, 0x65, + 0x67, 0x6B, 0x6D, 0x6E, 0x73, 0x74, 0xC3, 0xCB, 0x6E, 0xCB, 0xDD, 0xCB, 0x6E, 0xCB, 0xDD, 0xCB, + 0x6E, 0xCB, 0xDD, 0xCB, 0x6E, 0xCB, 0x6E, 0xFF, 0xFA, 0xD6, 0x2D, 0xC1, 0x00, 0xD1, 0x65, 0xD8, + 0x15, 0xC2, 0x00, 0x91, 0x68, 0x74, 0xC5, 0x0D, 0xFF, 0xFA, 0x42, 0x69, 0x72, 0xFE, 0xA1, 0xCB, + 0x8F, 0xCF, 0x02, 0xF1, 0x2E, 0x63, 0x64, 0x65, 0x66, 0x69, 0x6B, 0x6C, 0x6E, 0x70, 0x72, 0x73, + 0x74, 0x76, 0x79, 0xCA, 0xF9, 0xFF, 0x84, 0xFF, 0x88, 0xFF, 0x92, 0xFF, 0x9C, 0xD2, 0x6C, 0xCD, + 0xAF, 0xFF, 0xA3, 0xFF, 0xBE, 0xCA, 0xD1, 0xFF, 0xC9, 0xFF, 0xF0, 0xFF, 0xF9, 0xCD, 0xAF, 0xD5, + 0xA8, 0x42, 0x66, 0x67, 0xCB, 0x07, 0xDA, 0x26, 0x41, 0x61, 0xFD, 0xC9, 0x43, 0xA5, 0xA4, 0xB6, + 0xCB, 0x1B, 0xCB, 0x1B, 0xD3, 0x1C, 0xC6, 0x03, 0x62, 0x61, 0x6A, 0x6F, 0x72, 0x75, 0xC3, 0xFF, + 0xEB, 0xCB, 0x11, 0xD3, 0x12, 0xFF, 0xF2, 0xEB, 0x38, 0xFF, 0xF6, 0x41, 0x75, 0xDB, 0x3C, 0xC1, + 0x03, 0x31, 0x6F, 0xD0, 0x81, 0x42, 0x72, 0x75, 0xC5, 0xBB, 0xC4, 0xB2, 0x42, 0x67, 0x6E, 0xCB, + 0x3B, 0xD7, 0x94, 0x41, 0x72, 0xC6, 0xB6, 0x42, 0x72, 0x74, 0xC7, 0xD9, 0xFF, 0xFC, 0x42, 0x64, + 0x75, 0xCB, 0x29, 0xC4, 0x8C, 0x42, 0x70, 0x73, 0xC4, 0x73, 0xCA, 0x75, 0x45, 0x2E, 0x69, 0x6B, + 0x6C, 0xC3, 0xCA, 0xAC, 0xCD, 0x24, 0xCD, 0x24, 0xCD, 0x24, 0xED, 0x89, 0x42, 0x2E, 0x6E, 0xCA, + 0x5E, 0xCA, 0x5E, 0x41, 0x6B, 0xC5, 0x27, 0x41, 0x69, 0xC7, 0xA9, 0x43, 0x6F, 0x73, 0x74, 0xCA, + 0x4F, 0xFF, 0xF8, 0xFF, 0xFC, 0x45, 0x2E, 0x65, 0x72, 0x79, 0xC3, 0xCA, 0x45, 0xDC, 0xED, 0xC9, + 0x59, 0xCA, 0xF2, 0xD4, 0xD9, 0x41, 0x69, 0xFC, 0xFA, 0xD1, 0x02, 0xF1, 0x2E, 0x61, 0x62, 0x63, + 0x64, 0x66, 0x67, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x72, 0x73, 0x74, 0x76, 0x78, 0xCA, 0x31, 0xFF, + 0x92, 0xC4, 0x41, 0xFF, 0x96, 0xFF, 0x9C, 0xDC, 0xD9, 0xFF, 0xA3, 0xFF, 0xAE, 0xFF, 0xB5, 0xFF, + 0xBC, 0xFF, 0xC3, 0xC4, 0x41, 0xFF, 0xD3, 0xFF, 0xE2, 0xFF, 0xEC, 0xFF, 0xFC, 0xCA, 0xDE, 0x41, + 0x72, 0xE7, 0xD5, 0x21, 0xB6, 0xFC, 0xA1, 0x03, 0xD2, 0xC3, 0xFD, 0x41, 0x74, 0xC4, 0xF8, 0xC2, + 0x03, 0xD2, 0x67, 0x73, 0xD5, 0xDD, 0xFF, 0xFC, 0x41, 0x64, 0xDF, 0xA4, 0x21, 0x6E, 0xFC, 0xA1, + 0x03, 0x61, 0x61, 0xFD, 0xC1, 0x03, 0x61, 0xC3, 0xD5, 0xD5, 0x43, 0x69, 0x72, 0x75, 0xC9, 0xD0, + 0xFF, 0xFA, 0xC9, 0xD0, 0x42, 0x73, 0x74, 0xC4, 0xAE, 0xE1, 0xD7, 0xC1, 0x03, 0x61, 0x73, 0xC3, + 0xF7, 0x42, 0x65, 0x72, 0xEB, 0x94, 0xC3, 0xF1, 0x45, 0x64, 0x67, 0x72, 0x73, 0x74, 0xFF, 0xF3, + 0xFF, 0xF9, 0xCC, 0x68, 0xCC, 0x68, 0xCC, 0x68, 0xC1, 0x02, 0x81, 0x74, 0xC9, 0xA2, 0x41, 0x6C, + 0xCB, 0x68, 0x41, 0xA4, 0xC6, 0xB9, 0x21, 0xC3, 0xFC, 0x21, 0x74, 0xFD, 0x41, 0x75, 0xD4, 0x0E, + 0x42, 0x69, 0x73, 0xC9, 0x2E, 0xC3, 0x8E, 0x4C, 0x61, 0x62, 0x66, 0x67, 0x6B, 0x6D, 0x6E, 0x6F, + 0x70, 0x73, 0x74, 0x76, 0xEA, 0x97, 0xCA, 0x30, 0xFF, 0xB3, 0xE8, 0x79, 0xFF, 0xBD, 0xCC, 0x91, + 0xFF, 0xD1, 0xFF, 0xE1, 0xFF, 0xE7, 0xFF, 0xF2, 0xFF, 0xF5, 0xFF, 0xF9, 0xC4, 0x03, 0x31, 0x69, + 0x6F, 0x75, 0xC3, 0xD1, 0xBC, 0xC9, 0xBB, 0xC8, 0xEE, 0xCF, 0xBA, 0x41, 0x6B, 0xC3, 0xC0, 0x42, + 0x6B, 0x73, 0xC9, 0x89, 0xC3, 0x83, 0x43, 0x61, 0x65, 0xC3, 0xF5, 0x83, 0xC6, 0x65, 0xEE, 0x83, + 0xC1, 0x01, 0xD1, 0x64, 0xC9, 0x78, 0x41, 0x72, 0xC8, 0xC4, 0x42, 0xA4, 0xB6, 0xC9, 0x97, 0xFF, + 0xFC, 0xC9, 0x03, 0x61, 0x61, 0x65, 0x69, 0x6C, 0x6E, 0x6F, 0x74, 0x75, 0xC3, 0xFF, 0xDA, 0xFF, + 0xDE, 0xC9, 0x90, 0xFF, 0xE5, 0xD0, 0xB4, 0xFF, 0xEF, 0xC4, 0x8E, 0xDC, 0xBF, 0xFF, 0xF9, 0x42, + 0x6B, 0x76, 0xD2, 0xE0, 0xC8, 0x9B, 0xC3, 0x03, 0xD2, 0x61, 0x64, 0x73, 0xFF, 0xF9, 0xDF, 0x79, + 0xE3, 0x46, 0x41, 0x62, 0xC9, 0x36, 0x21, 0x72, 0xFC, 0x41, 0x6A, 0xC3, 0x42, 0xC4, 0x03, 0xD2, + 0x61, 0x69, 0x73, 0x74, 0xFF, 0xF9, 0xE9, 0x71, 0xFF, 0xFC, 0xC7, 0x8A, 0x41, 0x6D, 0xC9, 0x08, + 0x42, 0x6B, 0x74, 0xC3, 0x05, 0xC3, 0x05, 0xC6, 0x03, 0xD2, 0x61, 0x67, 0x6B, 0x6F, 0x73, 0x74, + 0xC7, 0x30, 0xC3, 0xF9, 0xC6, 0x29, 0xFF, 0xF5, 0xFF, 0xF9, 0xC2, 0xE3, 0x41, 0x72, 0xCB, 0xCC, + 0x42, 0x6A, 0x6C, 0xCB, 0x70, 0xD8, 0x93, 0xC1, 0x00, 0xA1, 0x6E, 0xCE, 0x99, 0x21, 0x61, 0xFA, + 0x41, 0x75, 0xCE, 0x90, 0x43, 0x61, 0x64, 0x76, 0xFF, 0xFC, 0xE7, 0x79, 0xC2, 0xD1, 0x42, 0x6C, + 0x70, 0xC2, 0xAC, 0xC5, 0x4B, 0x45, 0x61, 0x64, 0x67, 0x69, 0x6E, 0xC3, 0x2F, 0xCB, 0x4B, 0xCB, + 0x4B, 0xE9, 0x92, 0xC8, 0x95, 0x43, 0x69, 0x6E, 0x76, 0xCA, 0x21, 0xC3, 0x1F, 0xC2, 0x89, 0x4A, + 0x62, 0x67, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0xC2, 0x8B, 0xFF, 0xBD, 0xD1, 0x87, + 0xFF, 0xC1, 0xFF, 0xCE, 0xFF, 0xD5, 0xFF, 0xDF, 0xFF, 0xE6, 0xFF, 0xF6, 0xCA, 0x47, 0x41, 0xC3, + 0xED, 0x9B, 0xC2, 0x03, 0xD2, 0x6C, 0xC3, 0xFF, 0xFC, 0xED, 0x97, 0x41, 0x69, 0xC4, 0xEC, 0x21, + 0x67, 0xFC, 0x21, 0x69, 0xFD, 0x42, 0x6C, 0x73, 0xFF, 0xFD, 0xC2, 0x8A, 0x42, 0x62, 0x6D, 0xC8, + 0x7C, 0xC8, 0x7C, 0xC1, 0x02, 0x81, 0x6B, 0xC3, 0x1F, 0xC8, 0x04, 0xA2, 0x61, 0x64, 0x65, 0x69, + 0x6B, 0x6F, 0x73, 0x75, 0xC5, 0x2D, 0xC2, 0x5C, 0xFF, 0xEC, 0xD2, 0x02, 0xC2, 0x4B, 0xFF, 0xF3, + 0xFF, 0xFA, 0xC8, 0x72, 0x42, 0x6C, 0x78, 0xCA, 0xE2, 0xC8, 0x54, 0x41, 0x74, 0xDE, 0x59, 0x43, + 0x6C, 0x73, 0x74, 0xC2, 0x33, 0xC2, 0xA5, 0xFF, 0xFC, 0x45, 0x69, 0x6E, 0x6F, 0x75, 0xC3, 0xFE, + 0xC7, 0xD1, 0x3F, 0xFF, 0xF6, 0xC8, 0x2B, 0xCA, 0x17, 0x41, 0x76, 0xC4, 0x82, 0x21, 0x73, 0xFC, + 0x21, 0x67, 0xFD, 0xA0, 0x0A, 0xA2, 0x21, 0xB6, 0xFD, 0x44, 0x61, 0x65, 0x6F, 0xC3, 0xFF, 0xF7, + 0xC8, 0x1F, 0xC8, 0x1F, 0xFF, 0xFD, 0x42, 0x61, 0xC3, 0xC8, 0xEE, 0xD5, 0x78, 0xC2, 0x01, 0xD1, + 0x6C, 0x6F, 0xC7, 0xF7, 0xC7, 0xF7, 0x42, 0x64, 0x69, 0xC1, 0xE1, 0xC7, 0x54, 0xC2, 0x00, 0x41, + 0x6B, 0x6E, 0xC7, 0x4D, 0xFF, 0xF9, 0x41, 0x6C, 0xC1, 0xDC, 0xC1, 0x00, 0xA1, 0xC3, 0xC9, 0xC6, + 0x46, 0x61, 0x65, 0x69, 0x6F, 0x72, 0x75, 0xC9, 0x3E, 0xFF, 0xED, 0xFF, 0xF6, 0xE1, 0x5C, 0xFF, + 0xFA, 0xC8, 0x07, 0x41, 0xA4, 0xC7, 0xC1, 0xC2, 0x01, 0xD1, 0x61, 0xC3, 0xCA, 0xBC, 0xFF, 0xFC, + 0xCB, 0x03, 0x61, 0x65, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x73, 0x74, 0x76, 0x79, 0xFF, 0x74, + 0xE0, 0x2A, 0xFF, 0x89, 0xFF, 0xA9, 0xCA, 0x98, 0xFF, 0xB6, 0xFF, 0xBD, 0xC2, 0xB0, 0xFF, 0xE0, + 0xFF, 0xF7, 0xC7, 0xF1, 0x41, 0x69, 0xC7, 0x90, 0x21, 0x74, 0xFC, 0x43, 0x66, 0x6B, 0x6E, 0xC7, + 0x89, 0xFF, 0xFD, 0xC1, 0xF9, 0x42, 0x69, 0xC3, 0xD1, 0x03, 0xCA, 0x88, 0xC6, 0x03, 0xD2, 0x61, + 0x69, 0x6F, 0x72, 0x74, 0x75, 0xFF, 0xEF, 0xD3, 0x2B, 0xD7, 0x84, 0xFF, 0xF9, 0xC1, 0x5E, 0xC7, + 0xB8, 0x42, 0x62, 0x72, 0xCC, 0x55, 0xC1, 0x49, 0xC1, 0x02, 0x71, 0x76, 0xC1, 0x6A, 0x21, 0x73, + 0xFA, 0x41, 0x6C, 0xE6, 0x3C, 0xC1, 0x01, 0xE1, 0x73, 0xC2, 0x8E, 0x21, 0x6E, 0xFA, 0x41, 0x70, + 0xC7, 0xC9, 0xC1, 0x01, 0x01, 0x61, 0xC1, 0x35, 0x21, 0x68, 0xFA, 0x41, 0x67, 0xCC, 0xF5, 0xC2, + 0x03, 0x61, 0x69, 0x72, 0xFF, 0xFC, 0xC7, 0x2C, 0x4B, 0x62, 0x64, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, + 0x73, 0x74, 0x76, 0xC3, 0xFF, 0xC9, 0xC9, 0x50, 0xFF, 0xD6, 0xFF, 0xD9, 0xD4, 0x08, 0xFF, 0xE3, + 0xFF, 0xE6, 0xFF, 0xF0, 0xFF, 0xF7, 0xD6, 0x0F, 0xDB, 0x06, 0x41, 0xA4, 0xC1, 0x31, 0x21, 0xC3, + 0xFC, 0x42, 0x6A, 0x6B, 0xC1, 0x73, 0xFF, 0xFD, 0xA1, 0x03, 0xD2, 0x73, 0xF9, 0x42, 0x64, 0x6F, + 0xC5, 0xA1, 0xC0, 0xEA, 0x41, 0x65, 0xE6, 0x81, 0x41, 0x67, 0xC1, 0xA1, 0x45, 0x67, 0x6C, 0x6E, + 0x72, 0x73, 0xFF, 0xF8, 0xC7, 0x6B, 0xFF, 0xFC, 0xC2, 0x9B, 0xC1, 0x51, 0x41, 0x6B, 0xC2, 0x44, + 0x42, 0x67, 0x73, 0xC1, 0x89, 0xE8, 0x04, 0xC3, 0x03, 0x31, 0x61, 0x73, 0x74, 0xC3, 0x9F, 0xC0, + 0xDB, 0xC2, 0xD2, 0x46, 0x63, 0x6B, 0x6D, 0x6E, 0x73, 0x76, 0xFF, 0xE9, 0xD9, 0x3F, 0xC7, 0x44, + 0xFF, 0xED, 0xFF, 0xF4, 0xC1, 0x6A, 0x43, 0x65, 0x72, 0x73, 0xCB, 0xA0, 0xC1, 0x54, 0xC0, 0xBC, + 0x41, 0x74, 0xC2, 0x9D, 0x21, 0x73, 0xFC, 0xC1, 0x03, 0x01, 0x73, 0xC0, 0xB8, 0xC1, 0x00, 0xA1, + 0x72, 0xC1, 0x49, 0x21, 0x74, 0xFA, 0x41, 0x72, 0xC6, 0xCB, 0x49, 0x64, 0x67, 0x69, 0x6B, 0x6E, + 0x70, 0x72, 0x73, 0x76, 0xFF, 0xDC, 0xC9, 0x16, 0xC6, 0xBD, 0xC3, 0x95, 0xFF, 0xEA, 0xC7, 0x0D, + 0xFF, 0xED, 0xFF, 0xF9, 0xFF, 0xFC, 0x43, 0xA5, 0xA4, 0xB6, 0xFF, 0x86, 0xFF, 0xAD, 0xFF, 0xE4, + 0x58, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x79, 0xC3, 0xFB, 0x41, 0xC8, 0xF0, 0xCA, 0xE5, 0xFB, + 0x86, 0xFC, 0x09, 0xFC, 0x46, 0xFC, 0x4F, 0xFC, 0x5F, 0xFC, 0xB7, 0xFC, 0xDC, 0xFD, 0x11, 0xFD, + 0x36, 0xFD, 0x4D, 0xFD, 0x67, 0xFD, 0xBF, 0xFD, 0xE2, 0xFE, 0x09, 0xFE, 0xB0, 0xFE, 0xEC, 0xFF, + 0x38, 0xFF, 0x68, 0xC6, 0x97, 0xFF, 0x6D, 0xFF, 0xF6, 0xA0, 0x0A, 0xC2, 0x45, 0x2E, 0x65, 0x6A, + 0x72, 0x73, 0xC5, 0xEE, 0xC5, 0xEE, 0xC6, 0x9B, 0xFF, 0xFD, 0xBF, 0xEC, 0x42, 0x72, 0x74, 0xC2, + 0x0D, 0xCA, 0x89, 0x41, 0x6E, 0xC3, 0xCF, 0x21, 0x61, 0xFC, 0xC3, 0x04, 0xC2, 0x61, 0x6D, 0x6F, + 0xC2, 0xF1, 0xFF, 0xFD, 0xCE, 0xDC, 0xC1, 0x03, 0x61, 0xC3, 0xC8, 0xF7, 0x41, 0x6C, 0xCE, 0xFC, + 0x44, 0x64, 0x67, 0x6C, 0x73, 0xC2, 0xEF, 0xC6, 0x67, 0xFF, 0xF6, 0xFF, 0xFC, 0xC1, 0x03, 0x61, + 0x2E, 0xC5, 0x3D, 0x46, 0x2E, 0x62, 0x6D, 0x6E, 0x74, 0x76, 0xCF, 0x71, 0xC8, 0x5D, 0xFF, 0xFA, + 0xC5, 0xA7, 0xC8, 0x5D, 0xC6, 0x54, 0x42, 0x2E, 0x75, 0xCB, 0x7A, 0xC0, 0x2E, 0xC1, 0x03, 0x61, + 0x6B, 0xC5, 0xEA, 0xCE, 0x02, 0xF1, 0x2E, 0x64, 0x66, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, + 0x73, 0x74, 0x75, 0x76, 0xC5, 0x87, 0xFF, 0x99, 0xC8, 0x3D, 0xBF, 0x97, 0xFF, 0xA9, 0xD0, 0x36, + 0xFF, 0xB7, 0xFF, 0xCD, 0xC8, 0x3D, 0xFF, 0xE0, 0xD6, 0x24, 0xFF, 0xF3, 0xFF, 0xFA, 0xCA, 0x32, + 0xC1, 0x02, 0xF1, 0x75, 0xC8, 0x10, 0x43, 0x6E, 0x72, 0x74, 0xC5, 0x24, 0xC5, 0x24, 0xC5, 0x24, + 0x4A, 0x2E, 0x61, 0x62, 0x65, 0x69, 0x6B, 0x6D, 0x70, 0x79, 0xC3, 0xC8, 0x00, 0xFF, 0xF0, 0xC5, + 0xF7, 0xFF, 0xF6, 0xC5, 0x1A, 0xC5, 0xF7, 0xC5, 0xF7, 0xC5, 0xF7, 0xC5, 0x4A, 0xCB, 0xC4, 0xC2, + 0x02, 0x01, 0x68, 0x69, 0xFF, 0xE1, 0xC1, 0x14, 0xC3, 0x00, 0xD1, 0x67, 0x6C, 0x72, 0xCA, 0xDD, + 0xC5, 0x22, 0xCE, 0x60, 0x43, 0x6C, 0x72, 0x74, 0xD2, 0x8C, 0xBF, 0x1A, 0xD4, 0x73, 0x42, 0x2E, + 0x79, 0xC5, 0x0C, 0xBF, 0x29, 0x41, 0xC3, 0xC7, 0x89, 0x21, 0x73, 0xFC, 0x41, 0x70, 0xC7, 0xB4, + 0xC9, 0x02, 0xF1, 0x61, 0x67, 0x6B, 0x6C, 0x6D, 0x6E, 0x72, 0x74, 0x78, 0xD1, 0xBD, 0xFF, 0xD8, + 0xFF, 0xE4, 0xFF, 0xEE, 0xBF, 0xE2, 0xD2, 0x00, 0xFF, 0xF9, 0xD2, 0x00, 0xFF, 0xFC, 0x41, 0x72, + 0xDC, 0xA2, 0x42, 0xA4, 0xB6, 0xFF, 0xFC, 0xC0, 0xC9, 0xA1, 0x03, 0xD2, 0xC3, 0xF9, 0x41, 0x77, + 0xD7, 0x95, 0x41, 0x73, 0xBF, 0x33, 0xC3, 0x03, 0x61, 0x61, 0x69, 0xC3, 0xFF, 0xF8, 0xFF, 0xFC, + 0xCB, 0x20, 0xC3, 0x04, 0x71, 0x72, 0x73, 0x74, 0xD3, 0xC5, 0xCE, 0x55, 0xE5, 0x31, 0xC1, 0x03, + 0x01, 0x74, 0xBF, 0x8B, 0x41, 0x72, 0xC2, 0x9E, 0x42, 0x65, 0x72, 0xFF, 0xFC, 0xBE, 0xDA, 0x42, + 0x6C, 0x76, 0xE3, 0x6E, 0xFF, 0xF9, 0xA0, 0x0A, 0xE2, 0x21, 0x73, 0xFD, 0x42, 0x65, 0x69, 0xFF, + 0xFD, 0xC4, 0x8E, 0xC1, 0x0B, 0x02, 0x74, 0xC4, 0xEE, 0x42, 0x2E, 0x72, 0xCA, 0x67, 0xC7, 0x37, + 0x46, 0x64, 0x66, 0x6E, 0x72, 0x73, 0x74, 0xC9, 0x25, 0xC9, 0x25, 0xFF, 0xEC, 0xC5, 0x27, 0xFF, + 0xF3, 0xFF, 0xF9, 0xC9, 0x02, 0xF1, 0x64, 0x65, 0x67, 0x6B, 0x6C, 0x6E, 0x6F, 0x73, 0x75, 0xC6, + 0xE7, 0xFF, 0xAF, 0xD7, 0x0C, 0xFF, 0xBB, 0xFF, 0xCC, 0xFF, 0xED, 0xC4, 0x67, 0xCA, 0xDA, 0xBE, + 0x92, 0xC1, 0x03, 0x61, 0x74, 0xC4, 0xA6, 0x21, 0x6B, 0xFA, 0xC2, 0x00, 0x91, 0x6B, 0x72, 0xCA, + 0x26, 0xC4, 0xED, 0x41, 0x6C, 0xC2, 0x32, 0x42, 0xA4, 0xB6, 0xFF, 0xFC, 0xC4, 0x33, 0xC5, 0x04, + 0x12, 0x61, 0x6E, 0x74, 0x75, 0xC3, 0xFF, 0xE9, 0xC4, 0xD9, 0xC4, 0xD9, 0xFF, 0xEC, 0xFF, 0xF9, + 0x42, 0x61, 0x6F, 0xD6, 0xBF, 0xC4, 0x44, 0x42, 0x66, 0x74, 0xDC, 0x24, 0xC3, 0xE3, 0xC1, 0x02, + 0x01, 0x2E, 0xC4, 0x0C, 0xC4, 0x02, 0xF1, 0x2E, 0x65, 0x69, 0x73, 0xC9, 0xEC, 0xD8, 0x80, 0xC4, + 0xB3, 0xBE, 0xF1, 0xC2, 0x03, 0x31, 0x61, 0x76, 0xC4, 0x35, 0xC9, 0xDD, 0x4A, 0x2E, 0x64, 0x66, + 0x67, 0x6C, 0x70, 0x72, 0x73, 0x74, 0x76, 0xC6, 0xA4, 0xFF, 0xD4, 0xFF, 0xDB, 0xC4, 0x2C, 0xFF, + 0xE2, 0xFF, 0xE8, 0xFF, 0xF7, 0xC4, 0x9B, 0xC4, 0x18, 0xC4, 0x2C, 0x44, 0x2E, 0x64, 0x6E, 0x70, + 0xC4, 0x7C, 0xD0, 0xD5, 0xEC, 0x1F, 0xCD, 0xE8, 0xC4, 0x00, 0x41, 0x66, 0x6E, 0x73, 0x76, 0xC3, + 0xC2, 0xC9, 0xA8, 0xCB, 0xDB, 0xC9, 0xA8, 0x42, 0x6F, 0x75, 0xE6, 0xA6, 0xC3, 0xB3, 0x42, 0x70, + 0x73, 0xBD, 0xC9, 0xC4, 0x09, 0xA1, 0x03, 0x31, 0x61, 0xF9, 0xC1, 0x04, 0x82, 0x73, 0xE2, 0xF9, + 0xC2, 0x02, 0xF1, 0x61, 0x6F, 0xC3, 0x9A, 0xC3, 0xD8, 0x41, 0x74, 0xC0, 0x87, 0x42, 0x70, 0x73, + 0xC3, 0xCB, 0xFF, 0xFC, 0x45, 0x2E, 0x67, 0x6C, 0x72, 0x74, 0xCD, 0x50, 0xFF, 0xE6, 0xFF, 0xEC, + 0xFF, 0xF9, 0xC3, 0x56, 0x42, 0x6E, 0x74, 0xD3, 0x8A, 0xC3, 0x76, 0x42, 0x74, 0x76, 0xBE, 0x09, + 0xC3, 0x6F, 0xC6, 0x02, 0xF1, 0x66, 0x67, 0x6E, 0x70, 0x73, 0x76, 0xC3, 0x68, 0xC3, 0xC5, 0xC9, + 0x4E, 0xC3, 0x68, 0xC2, 0xF8, 0xC3, 0x68, 0xC2, 0x00, 0x91, 0x62, 0x76, 0xC9, 0x39, 0xC3, 0x53, + 0x41, 0xA4, 0xCA, 0x8B, 0x46, 0x61, 0x65, 0x69, 0x6F, 0x75, 0xC3, 0xFF, 0xD0, 0xFF, 0xD7, 0xFF, + 0xDE, 0xC3, 0x13, 0xFF, 0xF3, 0xFF, 0xFC, 0x42, 0x6C, 0x70, 0xCD, 0x4C, 0xC3, 0x90, 0x41, 0x6B, + 0xC5, 0xE2, 0xC2, 0x04, 0x12, 0x6E, 0x72, 0xC3, 0x66, 0xFF, 0xFC, 0xC3, 0x02, 0xF1, 0x6C, 0x70, + 0x72, 0xC3, 0x5D, 0xE1, 0xF2, 0xC3, 0xCC, 0x41, 0x6B, 0xC8, 0xF9, 0x42, 0x6E, 0x72, 0xFF, 0xFC, + 0xF6, 0xB0, 0x22, 0xA5, 0xA4, 0xE9, 0xF9, 0x50, 0x2E, 0x61, 0x65, 0x68, 0x69, 0x6A, 0x6C, 0x6E, + 0x6F, 0x72, 0x73, 0x74, 0x75, 0x76, 0x79, 0xC3, 0xC3, 0xB0, 0xFF, 0x15, 0xFF, 0x34, 0xC3, 0xB0, + 0xFF, 0x41, 0xFF, 0x50, 0xFF, 0x5E, 0xC3, 0xB0, 0xFF, 0x7D, 0xFF, 0xBD, 0xBD, 0x13, 0xC5, 0xB9, + 0xFF, 0xD0, 0xD9, 0xCE, 0xFF, 0xDB, 0xFF, 0xFB, 0x43, 0x64, 0x67, 0x74, 0xC3, 0x2F, 0xD5, 0x77, + 0xC3, 0x10, 0x41, 0x2E, 0xC3, 0x25, 0x46, 0x2E, 0x64, 0x6E, 0x72, 0x73, 0x74, 0xC3, 0x71, 0xD2, + 0xD8, 0xFF, 0xF2, 0xFF, 0xFC, 0xC3, 0x71, 0xC3, 0x2B, 0x41, 0x76, 0xFE, 0xA5, 0x44, 0x63, 0x6E, + 0x73, 0x74, 0xC2, 0xEB, 0xBD, 0x8C, 0xC3, 0x5A, 0xC2, 0xD7, 0x42, 0x72, 0x74, 0xC2, 0x30, 0xC0, + 0x9E, 0xC1, 0x03, 0x31, 0x74, 0xC2, 0xF6, 0xC1, 0x03, 0x01, 0x6F, 0xBC, 0xBE, 0xC4, 0x02, 0x01, + 0x63, 0x66, 0x73, 0x74, 0xC2, 0xEA, 0xC2, 0xEA, 0xFF, 0xF4, 0xFF, 0xFA, 0x42, 0x2E, 0x72, 0xC2, + 0x7E, 0xF0, 0x5A, 0x46, 0x6B, 0x6D, 0x6E, 0x70, 0x72, 0x74, 0xC2, 0xB5, 0xC2, 0x07, 0xC2, 0x44, + 0xCC, 0x41, 0xC7, 0x25, 0xC2, 0xA1, 0x41, 0x6A, 0xD5, 0x09, 0x23, 0xA5, 0xA4, 0xB6, 0xE2, 0xE9, + 0xFC, 0xC6, 0x0B, 0x22, 0x61, 0x65, 0x69, 0x6F, 0x75, 0xC3, 0xFF, 0x95, 0xFF, 0xA8, 0xFF, 0xAC, + 0xFF, 0xB9, 0xFF, 0xCC, 0xFF, 0xF9, 0xC2, 0x02, 0x01, 0x2E, 0x74, 0xC2, 0x44, 0xC2, 0xA1, 0x42, + 0x6B, 0x6C, 0xFF, 0xF7, 0xC2, 0x65, 0x41, 0x2E, 0xC2, 0x5E, 0x21, 0x74, 0xFC, 0xC1, 0x02, 0x01, + 0x74, 0xDF, 0x4A, 0x42, 0x64, 0x74, 0xC2, 0x51, 0xFF, 0xFA, 0x43, 0x67, 0x6B, 0x73, 0xBC, 0xF0, + 0xBC, 0x58, 0xBC, 0x58, 0x43, 0x64, 0x6C, 0x73, 0xC2, 0x16, 0xC2, 0x16, 0xC2, 0xC3, 0x43, 0xA5, + 0xA4, 0xB6, 0xFF, 0xEC, 0xFF, 0xF6, 0xC9, 0x33, 0xC7, 0x03, 0x61, 0x61, 0x65, 0x69, 0x6A, 0x75, + 0x79, 0xC3, 0xFF, 0xC7, 0xFF, 0xD2, 0xFF, 0xDB, 0xC2, 0x5F, 0xFA, 0xF3, 0xFA, 0xF3, 0xFF, 0xF6, + 0x41, 0x74, 0xC2, 0x47, 0x45, 0x62, 0x63, 0x6D, 0x72, 0x73, 0xC1, 0xE6, 0xCB, 0xB0, 0xC2, 0x43, + 0xDC, 0x24, 0xFF, 0xFC, 0xC1, 0x03, 0x01, 0x74, 0xC1, 0xA6, 0x44, 0x62, 0x6C, 0x74, 0x76, 0xC1, + 0xD0, 0xC1, 0xD0, 0xFF, 0xFA, 0xC2, 0x2D, 0xC1, 0x00, 0x91, 0x72, 0xC7, 0xA9, 0x42, 0x63, 0x72, + 0xC7, 0xA3, 0xC1, 0xFB, 0x44, 0x2E, 0x67, 0x72, 0x73, 0xC1, 0xB6, 0xBC, 0x86, 0xC1, 0xB6, 0xBB, + 0xEE, 0x23, 0xA5, 0xA4, 0xB6, 0xE6, 0xEC, 0xF3, 0xC5, 0x0B, 0x43, 0x61, 0x65, 0x69, 0x75, 0xC3, + 0xFF, 0xBC, 0xF8, 0x6E, 0xFF, 0xD2, 0xE0, 0x98, 0xFF, 0xF9, 0xC1, 0x03, 0x01, 0x6B, 0xC7, 0x76, + 0x42, 0x6A, 0x73, 0xC4, 0x40, 0xBD, 0x7E, 0xC1, 0x03, 0x61, 0x6D, 0xC7, 0x69, 0xC1, 0x03, 0x01, + 0x73, 0xC7, 0xF0, 0x42, 0x72, 0x75, 0xD0, 0x0C, 0xBC, 0x11, 0x44, 0x2E, 0x64, 0x67, 0x6E, 0xC1, + 0x70, 0xFB, 0xC3, 0xC4, 0x26, 0xC1, 0x70, 0xC1, 0x03, 0x01, 0x74, 0xC2, 0x10, 0xC9, 0x02, 0xF1, + 0x63, 0x64, 0x69, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x74, 0xFF, 0xCD, 0xC4, 0x13, 0xC7, 0x43, 0xFF, + 0xD3, 0xFF, 0xDA, 0xFF, 0xE0, 0xFF, 0xE6, 0xFF, 0xED, 0xFF, 0xFA, 0x42, 0x6B, 0x76, 0xC1, 0x7D, + 0xC7, 0x25, 0xC1, 0x03, 0x31, 0x73, 0xC1, 0x95, 0x44, 0x6E, 0x72, 0x73, 0x74, 0xE3, 0x0D, 0xFF, + 0xF3, 0xFF, 0xFA, 0xD0, 0x8F, 0xC1, 0x05, 0x62, 0x73, 0xEB, 0x86, 0xC6, 0x02, 0xF1, 0x64, 0x6B, + 0x6C, 0x6E, 0x72, 0x74, 0xC1, 0xCC, 0xCA, 0xE9, 0xFF, 0xFA, 0xC3, 0xD5, 0xC3, 0xD5, 0xD5, 0x85, + 0x42, 0x6C, 0x72, 0xE2, 0x1E, 0xC1, 0x0A, 0xC2, 0x01, 0xD1, 0x6E, 0x74, 0xC1, 0x60, 0xED, 0x42, + 0xC2, 0x00, 0xC1, 0x6E, 0x74, 0xC1, 0x38, 0xC6, 0xE0, 0xC3, 0x03, 0x31, 0x61, 0x69, 0xC3, 0xFF, + 0xEE, 0xFF, 0xF7, 0xC3, 0x75, 0x42, 0x73, 0x74, 0xC5, 0x93, 0xC0, 0xE5, 0x42, 0xA5, 0xA4, 0xC0, + 0xDE, 0xDA, 0x49, 0x45, 0x65, 0x69, 0x6F, 0x79, 0xC3, 0xFF, 0x9F, 0xFF, 0xF2, 0xC3, 0x8D, 0xC1, + 0x34, 0xFF, 0xF9, 0xC2, 0x04, 0x82, 0x6E, 0x72, 0xC0, 0xC7, 0xC0, 0xC7, 0x43, 0xA5, 0xA4, 0xB6, + 0xFF, 0xF7, 0xDA, 0x29, 0xC0, 0xBE, 0xC7, 0x05, 0x42, 0x61, 0x65, 0x69, 0x6C, 0x72, 0x73, 0xC3, + 0xFF, 0x82, 0xFF, 0x95, 0xFF, 0xAA, 0xFF, 0xC3, 0xFF, 0xDD, 0xC1, 0x11, 0xFF, 0xF6, 0xC2, 0x00, + 0xD1, 0x6C, 0x75, 0xBA, 0xB9, 0xCC, 0xF8, 0x41, 0x67, 0xE4, 0xC0, 0x42, 0xA4, 0xB6, 0xBD, 0xB0, + 0xBD, 0xB0, 0xA2, 0x02, 0x81, 0x61, 0xC3, 0xF5, 0xF9, 0x41, 0x6E, 0xCC, 0xDD, 0xC1, 0x02, 0x01, + 0x69, 0xBA, 0x8D, 0xC9, 0x04, 0xA2, 0x61, 0x65, 0x69, 0x6B, 0x6C, 0x6E, 0x73, 0x75, 0x76, 0xC0, + 0x73, 0xCF, 0x01, 0xCC, 0x5C, 0xFF, 0xDB, 0xFF, 0xEF, 0xBD, 0xB6, 0xBA, 0xA2, 0xFF, 0xF6, 0xFF, + 0xFA, 0x41, 0x69, 0xD4, 0xBF, 0x42, 0x61, 0x69, 0xC0, 0x55, 0xC3, 0x0B, 0x22, 0x67, 0x6C, 0xF5, + 0xF9, 0x42, 0x2E, 0x6D, 0xC6, 0x2F, 0xC6, 0x2F, 0x41, 0x74, 0xC0, 0x12, 0x41, 0x64, 0xC6, 0x24, + 0x21, 0x61, 0xFC, 0x42, 0x6B, 0x74, 0xDF, 0x0A, 0xFF, 0xFD, 0x42, 0x65, 0x6C, 0xC0, 0x00, 0xC0, + 0x30, 0x4A, 0x2E, 0x63, 0x64, 0x66, 0x6C, 0x6D, 0x6E, 0x72, 0x74, 0x75, 0xC0, 0xD6, 0xC6, 0x0F, + 0xE1, 0x0A, 0xC0, 0x67, 0xFF, 0xDB, 0xFF, 0xE0, 0xFF, 0xE7, 0xFF, 0xF2, 0xFF, 0xF9, 0xBF, 0xF9, + 0x43, 0x2E, 0x6E, 0x74, 0xC0, 0x48, 0xC2, 0xC0, 0xC5, 0xF0, 0x42, 0x2E, 0x65, 0xC0, 0x00, 0xC0, + 0x00, 0x42, 0x65, 0x6D, 0xBF, 0xF9, 0xC5, 0xDF, 0x43, 0x61, 0x65, 0x73, 0xE2, 0xE5, 0xC9, 0xBC, + 0xFF, 0xF9, 0x42, 0x6E, 0x75, 0xC0, 0x73, 0xC0, 0x26, 0x43, 0x61, 0x69, 0x6E, 0xBF, 0xB1, 0xFF, + 0xF9, 0xCC, 0x12, 0x49, 0x2E, 0x61, 0x67, 0x6B, 0x6C, 0x6D, 0x6E, 0x72, 0x74, 0xC5, 0x95, 0xC0, + 0x84, 0xDE, 0xAA, 0xFF, 0xCD, 0xE0, 0x5B, 0xFF, 0xD7, 0xFF, 0xE5, 0xFF, 0xF6, 0xFF, 0x7E, 0xC1, + 0x03, 0x61, 0x2E, 0xBF, 0xBB, 0x41, 0x63, 0xBF, 0xB5, 0x49, 0x61, 0x62, 0x63, 0x64, 0x6B, 0x6C, + 0x6E, 0x73, 0x74, 0xC2, 0x67, 0xC2, 0x67, 0xD9, 0x2C, 0xC2, 0x67, 0xC2, 0x88, 0xFF, 0xF6, 0xD9, + 0x2C, 0xFF, 0xFC, 0xBF, 0x81, 0x42, 0x6C, 0x72, 0xBF, 0x95, 0xBF, 0x95, 0x21, 0xA4, 0xF9, 0xC2, + 0x03, 0x61, 0x75, 0xC3, 0xBF, 0x1B, 0xFF, 0xFD, 0xC1, 0x02, 0xF1, 0x6B, 0xC0, 0x2F, 0x41, 0x75, + 0xBB, 0x9F, 0x42, 0x65, 0x73, 0xFF, 0xFC, 0xC5, 0x5E, 0x42, 0x69, 0x73, 0xFF, 0xF9, 0xB9, 0xA9, + 0x44, 0x63, 0x6C, 0x6D, 0x72, 0xC5, 0x50, 0xFF, 0xE8, 0xC0, 0x17, 0xFF, 0xF9, 0x42, 0x69, 0x6F, + 0xC5, 0x1E, 0xBF, 0x5D, 0x42, 0x66, 0x74, 0xC6, 0x93, 0xFF, 0xF9, 0x44, 0x63, 0x6A, 0x6E, 0x72, + 0xBF, 0x4F, 0xBF, 0x4F, 0xB9, 0x5F, 0xBF, 0x1F, 0xC1, 0x02, 0xF1, 0x65, 0xC5, 0x28, 0x46, 0x61, + 0x64, 0x65, 0x66, 0x6B, 0x73, 0xC1, 0xF2, 0xFF, 0xFA, 0xEB, 0x19, 0xB9, 0xD6, 0xFE, 0xFA, 0xC0, + 0xD0, 0x41, 0x6D, 0xC1, 0xDF, 0xC2, 0x02, 0xF1, 0x6B, 0x6D, 0xBF, 0x25, 0xFF, 0xFC, 0x42, 0x63, + 0x6B, 0xBF, 0x79, 0xC5, 0x02, 0x42, 0x6B, 0x6C, 0xC4, 0xFB, 0xBF, 0x15, 0x41, 0x67, 0xBF, 0x0E, + 0x44, 0x63, 0x64, 0x6E, 0x76, 0xBF, 0x0A, 0xBF, 0xB7, 0xFF, 0xFC, 0xC4, 0xF0, 0x43, 0xA5, 0xA4, + 0xB6, 0xFF, 0xE8, 0xFF, 0xF3, 0xC3, 0x8B, 0x26, 0x61, 0x65, 0x69, 0x75, 0x79, 0xC3, 0x9D, 0xA4, + 0xB7, 0xCE, 0xD7, 0xF6, 0xA0, 0x0B, 0x73, 0xC1, 0x03, 0x31, 0x69, 0xEB, 0x22, 0xC1, 0x02, 0xF1, + 0x70, 0xC1, 0x93, 0xC2, 0x02, 0xF1, 0x67, 0x6C, 0xBF, 0x84, 0xC4, 0xBD, 0xC1, 0x02, 0xF1, 0x6C, + 0xBE, 0xCE, 0x43, 0xA5, 0xA4, 0xB6, 0xFF, 0xF1, 0xFF, 0xFA, 0xBE, 0x98, 0xCE, 0x02, 0x01, 0x2E, + 0x61, 0x63, 0x65, 0x69, 0x6A, 0x6D, 0x6F, 0x72, 0x73, 0x74, 0x76, 0x79, 0xC3, 0xC1, 0x74, 0xFE, + 0x95, 0xB8, 0xCE, 0xFE, 0xE7, 0xFF, 0x0D, 0xFF, 0x33, 0xC1, 0x74, 0xFF, 0x54, 0xFF, 0xCB, 0xFF, + 0xD8, 0xB8, 0xCE, 0xFF, 0xDB, 0xFF, 0xE1, 0xFF, 0xF6, 0x41, 0x65, 0xF8, 0x2D, 0xC4, 0x03, 0x61, + 0x2E, 0x64, 0x65, 0x67, 0xC4, 0x73, 0xFF, 0xFC, 0xC4, 0x73, 0xBE, 0x1D, 0xC2, 0x03, 0x61, 0x61, + 0x75, 0xC4, 0x64, 0xBB, 0x9F, 0xC2, 0x03, 0xD2, 0x6F, 0x72, 0xB9, 0x0F, 0xB9, 0x0F, 0xC8, 0x02, + 0xF1, 0x62, 0x67, 0x69, 0x6D, 0x6E, 0x70, 0x73, 0x74, 0xB9, 0x06, 0xBE, 0x6C, 0xB8, 0x7C, 0xBE, + 0x6C, 0xFF, 0xDF, 0xFF, 0xEE, 0xC4, 0x52, 0xFF, 0xF7, 0x42, 0x2E, 0x6E, 0xC4, 0x37, 0xBE, 0xAE, + 0x42, 0x73, 0x74, 0xB9, 0x26, 0xBE, 0x4A, 0x47, 0x67, 0x6B, 0x6D, 0x70, 0x72, 0x73, 0x74, 0xFF, + 0xF2, 0xC2, 0xF1, 0xC4, 0x29, 0xBE, 0xF0, 0xFF, 0xF9, 0xBE, 0xF0, 0xBE, 0xA0, 0x45, 0x63, 0x6E, + 0x70, 0x72, 0x73, 0xBE, 0xDA, 0xBE, 0x2D, 0xC4, 0x13, 0xC2, 0xDB, 0xBD, 0xBD, 0x44, 0x6C, 0x6E, + 0x73, 0x74, 0xC2, 0xCB, 0xE6, 0x6D, 0xBE, 0xCA, 0xC7, 0xCB, 0x42, 0x64, 0x72, 0xBD, 0xA0, 0xDE, + 0xF1, 0x41, 0x6D, 0xDC, 0xDC, 0x44, 0x6E, 0x72, 0x73, 0x74, 0xFE, 0xF7, 0xFF, 0xFC, 0xBE, 0x62, + 0xBE, 0x62, 0x22, 0xA5, 0xA4, 0xE8, 0xF3, 0xA4, 0x05, 0x42, 0x61, 0x65, 0x69, 0xC3, 0xB0, 0xC6, + 0xD6, 0xFB, 0xC1, 0x03, 0x01, 0x6B, 0xB7, 0xEC, 0xC1, 0x00, 0xA1, 0x65, 0xCD, 0x3F, 0xA1, 0x03, + 0x01, 0x74, 0xFA, 0xC1, 0x01, 0x01, 0x68, 0xB7, 0xF4, 0x46, 0x6B, 0x6C, 0x6E, 0x72, 0x73, 0x74, + 0xBE, 0x7E, 0xC3, 0xB7, 0xFF, 0xE9, 0xD2, 0xD9, 0xFF, 0xF5, 0xFF, 0xFA, 0x41, 0x64, 0xDE, 0xBB, + 0xC4, 0x02, 0xF1, 0x67, 0x6B, 0x6C, 0x6E, 0xC3, 0xA0, 0xBE, 0x67, 0xFF, 0xFC, 0xBC, 0xAE, 0x41, + 0x67, 0xC3, 0x69, 0xC1, 0x03, 0x01, 0x61, 0xBE, 0x54, 0xC6, 0x02, 0xF1, 0x64, 0x67, 0x6C, 0x70, + 0x73, 0x74, 0xBD, 0xDF, 0xFF, 0xF6, 0xBD, 0xDF, 0xC0, 0x57, 0xC3, 0x87, 0xFF, 0xFA, 0xC1, 0x03, + 0x61, 0x61, 0xBD, 0x1C, 0x42, 0x73, 0x74, 0xB9, 0x77, 0xC3, 0x41, 0xC6, 0x02, 0xF1, 0x64, 0x67, + 0x6B, 0x6C, 0x70, 0x72, 0xBE, 0x2C, 0xFF, 0xF3, 0xBE, 0xFA, 0xBE, 0x2C, 0xBE, 0x2C, 0xFF, 0xF9, + 0x23, 0xA5, 0xA4, 0xB6, 0xB0, 0xC9, 0xEB, 0x57, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0x79, 0xC3, 0xF7, + 0xDC, 0xBE, 0x10, 0xF8, 0x38, 0xC2, 0x11, 0xF8, 0x69, 0xF8, 0x92, 0xEF, 0xDA, 0xF8, 0x9F, 0xF8, + 0xFC, 0xF9, 0x37, 0xFA, 0x60, 0xFB, 0x0A, 0xFB, 0x61, 0xFB, 0xC1, 0xFC, 0x06, 0xFC, 0xAF, 0xC5, + 0x83, 0xFC, 0xEC, 0xFE, 0xA5, 0xFE, 0xF7, 0xFF, 0x70, 0xFF, 0x92, 0xFF, 0xF9, 0x41, 0x68, 0xBA, + 0x73, 0xA0, 0x0B, 0xA2, 0x43, 0x65, 0x69, 0x73, 0xCA, 0x1C, 0xBD, 0xC3, 0xFF, 0xFD, 0x41, 0x66, + 0xBF, 0xC2, 0x42, 0x69, 0x6F, 0xEF, 0xCD, 0xB7, 0x33, 0x43, 0x2E, 0x72, 0x74, 0xC2, 0xE7, 0xBE, + 0xCD, 0xFF, 0xF9, 0x41, 0x73, 0xD0, 0x5D, 0x42, 0x69, 0x73, 0xFF, 0xFC, 0xB7, 0xC3, 0x43, 0x66, + 0x6C, 0x76, 0xBD, 0x99, 0xFF, 0xF9, 0xBD, 0x99, 0x42, 0x65, 0x69, 0xBC, 0xE2, 0xBC, 0xE2, 0x41, + 0x65, 0xC9, 0xE1, 0x41, 0x61, 0xC2, 0x92, 0x45, 0x2E, 0x61, 0x64, 0x66, 0x6C, 0xBC, 0xD3, 0xC9, + 0xCE, 0xFF, 0xF8, 0xFF, 0xFC, 0xBD, 0x80, 0xA0, 0x0B, 0xC2, 0x41, 0x61, 0xE4, 0xB4, 0x22, 0x6C, + 0x70, 0xF9, 0xFC, 0x41, 0x76, 0xDA, 0xD8, 0xA1, 0x03, 0x31, 0x61, 0xFC, 0x47, 0x2E, 0x62, 0x6D, + 0x6E, 0x73, 0x74, 0x76, 0xBC, 0xAE, 0xBD, 0x5B, 0xCC, 0x87, 0xBC, 0xAE, 0xB6, 0xF3, 0xFF, 0xFB, + 0xBD, 0x5B, 0xC1, 0x03, 0x01, 0x72, 0xB9, 0xEE, 0x42, 0x6B, 0x74, 0xBD, 0x3F, 0xFF, 0xFA, 0xC3, + 0x01, 0x01, 0x61, 0x73, 0x74, 0xBE, 0x27, 0xB6, 0xC3, 0xBF, 0x41, 0x42, 0x2E, 0x6E, 0xC2, 0x65, + 0xBC, 0x7F, 0x42, 0x61, 0x6F, 0xFF, 0xF9, 0xBC, 0x78, 0xC3, 0x03, 0x61, 0x65, 0x6C, 0x73, 0xBD, + 0x1E, 0xFF, 0xF9, 0xB7, 0x59, 0xCF, 0x02, 0xF1, 0x2E, 0x63, 0x64, 0x66, 0x67, 0x6B, 0x6C, 0x6D, + 0x6E, 0x70, 0x72, 0x73, 0x74, 0x76, 0x78, 0xBC, 0x65, 0xFF, 0x48, 0xFF, 0x4F, 0xFF, 0x59, 0xD9, + 0x82, 0xFF, 0x64, 0xFF, 0x79, 0xFF, 0x83, 0xFF, 0x92, 0xFF, 0xA9, 0xFF, 0xB7, 0xFF, 0xD3, 0xFF, + 0xDA, 0xFF, 0xF4, 0xBC, 0x65, 0x42, 0x61, 0x65, 0xBC, 0x92, 0xBC, 0x92, 0xA1, 0x03, 0x61, 0x68, + 0xF9, 0xC1, 0x01, 0xC2, 0x65, 0xB6, 0x39, 0xA1, 0x03, 0x31, 0x72, 0xFA, 0xC1, 0x00, 0x71, 0x6E, + 0xC6, 0x9E, 0xC1, 0x03, 0x31, 0x73, 0xB7, 0x00, 0x42, 0x6B, 0x73, 0xC1, 0xF8, 0xC1, 0xF8, 0x21, + 0x69, 0xF9, 0x42, 0x6C, 0x6E, 0xB6, 0xA2, 0xFF, 0xFD, 0xA0, 0x0B, 0xE2, 0x21, 0xB6, 0xFD, 0x42, + 0x64, 0xC3, 0xBC, 0xA8, 0xFF, 0xFD, 0x43, 0x61, 0x6F, 0x75, 0xC1, 0xDA, 0xBC, 0xA1, 0xB6, 0x8E, + 0x42, 0xA4, 0xB6, 0xB6, 0x84, 0xBA, 0x87, 0x44, 0x67, 0x73, 0x74, 0xC3, 0xB6, 0x83, 0xEB, 0xDD, + 0xBD, 0xA1, 0xFF, 0xF9, 0x41, 0xC3, 0xCF, 0xDA, 0x48, 0x2E, 0x69, 0x6B, 0x6D, 0x6E, 0x73, 0x74, + 0x75, 0xC1, 0xB8, 0xFF, 0xFC, 0xB6, 0x72, 0xC1, 0xB8, 0xC1, 0xBB, 0xC1, 0xB8, 0xB5, 0xD6, 0xB6, + 0x6C, 0xC3, 0x04, 0x71, 0x65, 0x69, 0x75, 0xB5, 0xE4, 0xBD, 0x4D, 0xB5, 0xD6, 0x42, 0x2E, 0x74, + 0xC1, 0x93, 0xFF, 0xF4, 0x42, 0x69, 0x73, 0xF8, 0x93, 0xB5, 0xDE, 0x42, 0x61, 0x70, 0xBC, 0x4C, + 0xBE, 0x55, 0xCE, 0x04, 0xC2, 0x61, 0x62, 0x63, 0x67, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x72, + 0x73, 0x74, 0x78, 0xBB, 0x3C, 0xB6, 0xBE, 0xC1, 0x7E, 0xFF, 0x75, 0xFF, 0x7A, 0xFF, 0x80, 0xFF, + 0x90, 0xFF, 0x9D, 0xFF, 0xA4, 0xFF, 0xB5, 0xFF, 0xC6, 0xFF, 0xEB, 0xFF, 0xF2, 0xFF, 0xF9, 0xC1, + 0x03, 0x61, 0x65, 0xBE, 0x12, 0x41, 0xB6, 0xBC, 0x12, 0xC3, 0x03, 0x01, 0x65, 0x75, 0xC3, 0xC1, + 0x47, 0xB5, 0xFB, 0xFF, 0xFC, 0x45, 0x65, 0x68, 0x6F, 0x72, 0x74, 0xC1, 0x61, 0xBB, 0x55, 0xB5, + 0xEF, 0xB8, 0x76, 0xBB, 0x55, 0x43, 0x6C, 0x73, 0x75, 0xB5, 0x49, 0xBB, 0x45, 0xD9, 0x66, 0x43, + 0x73, 0x76, 0xC3, 0xDA, 0x31, 0xBB, 0x3B, 0xBB, 0x3E, 0xC2, 0x02, 0x01, 0x6A, 0x6C, 0xC1, 0x17, + 0xFF, 0xF6, 0x43, 0x64, 0x72, 0x74, 0xBD, 0xDE, 0xBD, 0xDE, 0xBD, 0xDE, 0x43, 0x64, 0x6E, 0x73, + 0xB5, 0xB8, 0xBB, 0x1E, 0xB8, 0x3F, 0xC2, 0x03, 0x01, 0x63, 0x6B, 0xBB, 0xC1, 0xC0, 0xFA, 0xC1, + 0x03, 0x01, 0x6E, 0xB5, 0xA5, 0x41, 0x74, 0xCE, 0x6B, 0x22, 0x61, 0x69, 0xF6, 0xFC, 0xCF, 0x02, + 0xF1, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x73, 0x76, 0xC3, + 0xDC, 0x10, 0xC0, 0xE2, 0xEA, 0xF6, 0xFF, 0x9B, 0xD2, 0xC6, 0xB7, 0x2F, 0xFF, 0xA7, 0xFF, 0xB7, + 0xFF, 0xCB, 0xCE, 0x62, 0xFF, 0xD4, 0xFF, 0xDE, 0xFF, 0xE8, 0xFF, 0xFB, 0xCE, 0xE0, 0x42, 0x62, + 0x75, 0xBB, 0x79, 0xBD, 0x82, 0x43, 0x6C, 0x6D, 0x6E, 0xBB, 0x72, 0xBB, 0x72, 0xBA, 0xC5, 0x21, + 0xA4, 0xF6, 0xC3, 0x02, 0x01, 0x65, 0x6F, 0xC3, 0xBB, 0x65, 0xFF, 0xEC, 0xFF, 0xFD, 0xC1, 0x07, + 0x93, 0x65, 0xB4, 0xDA, 0x42, 0x2E, 0x6A, 0xBB, 0x53, 0xBB, 0x53, 0x42, 0x72, 0x73, 0xBD, 0x55, + 0xBB, 0x4C, 0x41, 0x74, 0xCF, 0x12, 0x21, 0x65, 0xFC, 0xC1, 0x03, 0x31, 0x73, 0xB4, 0xC9, 0x41, + 0x74, 0xB4, 0xF6, 0x47, 0x61, 0x64, 0x69, 0x6D, 0x6E, 0x73, 0x74, 0xC1, 0xA6, 0xCA, 0x9B, 0xFF, + 0xF3, 0xFF, 0xF6, 0xBA, 0x87, 0xFF, 0xFC, 0xC2, 0xA0, 0x42, 0x6B, 0x74, 0xB4, 0x9C, 0xCA, 0x85, + 0x48, 0x64, 0x6B, 0x6C, 0x6D, 0x70, 0x72, 0x73, 0x76, 0xE4, 0xCB, 0xBA, 0x6A, 0xFF, 0xC4, 0xFF, + 0xCB, 0xBA, 0x94, 0xFF, 0xE3, 0xFF, 0xF9, 0xBA, 0xA8, 0xC1, 0x00, 0x91, 0x69, 0xBA, 0x51, 0x46, + 0x2E, 0x61, 0x65, 0x6F, 0x73, 0x74, 0xC4, 0x15, 0xBA, 0x89, 0xC4, 0x15, 0xC0, 0x31, 0xBA, 0x4B, + 0xBA, 0x89, 0xA0, 0x0C, 0x02, 0xA1, 0x03, 0x01, 0x61, 0xFD, 0x21, 0x73, 0xFB, 0x42, 0x2E, 0x6F, + 0xBA, 0x8A, 0xBA, 0x6B, 0xC6, 0x03, 0x61, 0x66, 0x6C, 0x6E, 0x72, 0x73, 0x74, 0xFF, 0xD5, 0xFF, + 0xDB, 0xFF, 0xF6, 0xBA, 0xD3, 0xF7, 0x5E, 0xFF, 0xF9, 0x42, 0x2E, 0x6E, 0xBA, 0xBE, 0xBA, 0xBE, + 0x41, 0x73, 0xF7, 0x42, 0x44, 0x67, 0x6E, 0x72, 0x74, 0xBA, 0xB3, 0xBA, 0xB3, 0xFF, 0xF5, 0xFF, + 0xFC, 0xC1, 0x01, 0xD1, 0x2E, 0xBA, 0x56, 0x21, 0x67, 0xFA, 0xC5, 0x03, 0x61, 0x62, 0x63, 0x64, + 0x65, 0x6E, 0xC1, 0x29, 0xF6, 0xDD, 0xB4, 0xCF, 0xC5, 0xD5, 0xFF, 0xFD, 0x41, 0x6B, 0xB9, 0x6E, + 0x42, 0x69, 0x6F, 0xFF, 0xFC, 0xBA, 0x37, 0x41, 0x69, 0xC1, 0xEC, 0x46, 0x63, 0x67, 0x6E, 0x70, + 0x73, 0x74, 0xF4, 0x42, 0xBA, 0x0D, 0xFF, 0xF5, 0xFF, 0xFC, 0xCE, 0x35, 0xD3, 0x3A, 0x41, 0x70, + 0xB9, 0xFA, 0xC1, 0x00, 0x91, 0x70, 0xB9, 0xB8, 0x43, 0x6D, 0x70, 0x73, 0xFF, 0xF6, 0xFF, 0xFA, + 0xCB, 0x42, 0xC1, 0x02, 0xF1, 0x6B, 0xD8, 0x7B, 0x41, 0x68, 0xBF, 0x88, 0x21, 0x67, 0xFC, 0x22, + 0x63, 0x67, 0xF3, 0xFD, 0x41, 0x6B, 0xBA, 0x43, 0xC1, 0x03, 0x01, 0x73, 0xB6, 0x23, 0xC1, 0x03, + 0x31, 0x6E, 0xB9, 0xE9, 0x46, 0x2E, 0x64, 0x66, 0x67, 0x6B, 0x6E, 0xBF, 0x6C, 0xFF, 0xF4, 0xB9, + 0x86, 0xB9, 0x86, 0xFF, 0xFA, 0xCA, 0xFB, 0x42, 0x6A, 0x74, 0xBF, 0x5C, 0xB9, 0xB1, 0x44, 0xA5, + 0xA4, 0xB6, 0xA9, 0xFF, 0xD6, 0xFF, 0xE6, 0xFF, 0xF9, 0xBF, 0x52, 0xC7, 0x06, 0x62, 0x61, 0x65, + 0x69, 0x6F, 0x75, 0x79, 0xC3, 0xFF, 0x39, 0xFF, 0x59, 0xFF, 0x6F, 0xFF, 0x90, 0xFF, 0xAD, 0xFF, + 0xC4, 0xFF, 0xF3, 0xA0, 0x03, 0x82, 0x21, 0x64, 0xFD, 0x43, 0x6E, 0x72, 0x74, 0xFF, 0xFD, 0xBA, + 0x5B, 0xCC, 0x38, 0xC3, 0x01, 0x91, 0x67, 0x6E, 0x78, 0xB9, 0x75, 0xB3, 0xD1, 0xB9, 0x75, 0x42, + 0x6C, 0x74, 0xC5, 0x10, 0xF7, 0x41, 0x41, 0x74, 0xE4, 0xB2, 0xC4, 0x00, 0xD1, 0x61, 0x69, 0x6C, + 0x6F, 0xFF, 0xF5, 0xB9, 0x87, 0xB3, 0x30, 0xFF, 0xFC, 0x41, 0xA4, 0xBA, 0xA5, 0x42, 0x6F, 0xC3, + 0xC2, 0xBB, 0xFF, 0xFC, 0x42, 0xA4, 0xB6, 0xB3, 0x16, 0xB9, 0x63, 0x21, 0xC3, 0xF9, 0xC1, 0x02, + 0x01, 0x72, 0xE3, 0xD7, 0x41, 0x66, 0xB3, 0x13, 0x21, 0x6C, 0xFC, 0x21, 0x6C, 0xFD, 0x42, 0x6C, + 0x6E, 0xB9, 0x49, 0xB9, 0x2A, 0x42, 0x61, 0x79, 0xB9, 0x0F, 0xB9, 0x23, 0xC7, 0x01, 0xD1, 0x65, + 0x69, 0x6A, 0x6F, 0x72, 0x75, 0x79, 0xDD, 0xAB, 0xFF, 0xEF, 0xB2, 0xEE, 0xFF, 0xF2, 0xFF, 0xF9, + 0xB9, 0x1F, 0xEF, 0xAA, 0xC1, 0x02, 0x01, 0x64, 0xB9, 0x23, 0xCB, 0x03, 0x61, 0x61, 0x65, 0x6B, + 0x6C, 0x6E, 0x6F, 0x70, 0x73, 0x74, 0x75, 0x79, 0xFF, 0x7F, 0xFF, 0x89, 0xFF, 0xA0, 0xFF, 0xB3, + 0xFF, 0xC1, 0xFF, 0xC4, 0xB8, 0x98, 0xB2, 0xEB, 0xFF, 0xE2, 0xFF, 0xFA, 0xB8, 0x50, 0x42, 0x63, + 0x75, 0xB8, 0xF9, 0xB8, 0xDA, 0x46, 0x64, 0x67, 0x6D, 0x6E, 0x73, 0x78, 0xB8, 0xD3, 0xDF, 0x3C, + 0xB8, 0xD3, 0xB3, 0x7D, 0xB2, 0xDA, 0xB8, 0xD3, 0x42, 0x6E, 0x70, 0xC0, 0xE0, 0xB8, 0xC0, 0x43, + 0x64, 0x6E, 0x74, 0xB2, 0x8B, 0xE3, 0x56, 0xB2, 0x8B, 0x44, 0x61, 0x65, 0x69, 0x79, 0xFF, 0xF6, + 0xB2, 0x81, 0xB2, 0x81, 0xB3, 0x0B, 0x43, 0x65, 0x69, 0x74, 0xB2, 0xFE, 0xB5, 0x85, 0xB8, 0xE8, + 0xC1, 0x02, 0x81, 0xC3, 0xC6, 0x22, 0x42, 0xA4, 0xB6, 0xB8, 0xB1, 0xC1, 0xCC, 0xCB, 0x03, 0x61, + 0x61, 0x65, 0x69, 0x6A, 0x6F, 0x72, 0x73, 0x75, 0x76, 0x79, 0xC3, 0xFF, 0xB1, 0xFF, 0xB8, 0xFF, + 0xCB, 0xB5, 0x8C, 0xB8, 0xB4, 0xFF, 0xDC, 0xFF, 0xE9, 0xDD, 0x20, 0xFF, 0xF3, 0xB8, 0xAA, 0xFF, + 0xF9, 0x41, 0x6E, 0xC1, 0xB6, 0x42, 0x61, 0x73, 0xB8, 0x25, 0xB2, 0x5D, 0x43, 0x64, 0x67, 0x6E, + 0xBA, 0xD4, 0xFF, 0xF9, 0xBE, 0x04, 0x43, 0x62, 0x76, 0xC3, 0xBA, 0xCA, 0xB8, 0x71, 0xBA, 0x2A, + 0x47, 0x67, 0x6E, 0x70, 0x72, 0x74, 0x76, 0xC3, 0xFF, 0xE1, 0xFF, 0xEC, 0xF3, 0x0C, 0xB9, 0xD6, + 0xFF, 0xF6, 0xB7, 0x72, 0xCC, 0x0E, 0x44, 0x67, 0x6E, 0x74, 0x76, 0xB8, 0x51, 0xF8, 0xE6, 0xB8, + 0x51, 0xB7, 0xF4, 0x42, 0x67, 0x6E, 0xB8, 0x44, 0xB7, 0xE7, 0x43, 0x6E, 0x72, 0x74, 0xB8, 0x3D, + 0xB2, 0xBF, 0xD6, 0xD6, 0x22, 0xA5, 0xA4, 0xEF, 0xF6, 0xC4, 0x03, 0x61, 0x61, 0x65, 0x69, 0xC3, + 0xB8, 0x38, 0xB8, 0x7E, 0xFF, 0xDD, 0xFF, 0xFB, 0x41, 0x64, 0xB7, 0xC2, 0x21, 0x67, 0xFC, 0xC1, + 0x03, 0x01, 0x69, 0xB1, 0xCB, 0x45, 0x64, 0x67, 0x6E, 0x70, 0x73, 0xC6, 0x4A, 0xD6, 0x88, 0xFF, + 0xF7, 0xFF, 0xFA, 0xBD, 0x9B, 0x43, 0x67, 0x73, 0x74, 0xB7, 0xA5, 0xB1, 0xEA, 0xB8, 0x52, 0x41, + 0x6B, 0xDF, 0x1E, 0x41, 0x6D, 0xB8, 0x44, 0x45, 0x63, 0x67, 0x6D, 0x72, 0x76, 0xFF, 0xF8, 0xC1, + 0x20, 0xB8, 0x40, 0xFF, 0xFC, 0xD8, 0xA7, 0xC1, 0x03, 0x32, 0x65, 0xB1, 0x81, 0xC1, 0x03, 0x31, + 0x69, 0xB1, 0xA8, 0x42, 0x65, 0x73, 0xBE, 0x9E, 0xB9, 0x47, 0x41, 0x61, 0xB9, 0x1C, 0x45, 0x64, + 0x67, 0x70, 0x72, 0x76, 0xFF, 0xE9, 0xB8, 0x19, 0xFF, 0xEF, 0xFF, 0xF5, 0xFF, 0xFC, 0x44, 0xA5, + 0xA4, 0xB6, 0xA9, 0xFF, 0xB7, 0xFF, 0xC9, 0xFF, 0xF0, 0xBD, 0x42, 0x58, 0x61, 0x62, 0x63, 0x64, + 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x79, 0x7A, 0xC3, 0xFA, 0xEA, 0xCA, 0x4E, 0xFB, 0x21, 0xE9, 0x50, 0xFB, 0xB7, 0xDE, 0xCF, + 0xE9, 0x50, 0xFB, 0xE4, 0xFC, 0x53, 0xFC, 0x97, 0xC0, 0xD9, 0xBD, 0x0A, 0xBB, 0xFA, 0xFC, 0xA3, + 0xFC, 0xE5, 0xBB, 0xFA, 0xFD, 0xF0, 0xFE, 0x8F, 0xFF, 0x02, 0xFF, 0x45, 0xFF, 0x7E, 0xFF, 0x9A, + 0xBA, 0x05, 0xFF, 0xF3, 0x41, 0x6C, 0xB3, 0x90, 0x41, 0x63, 0xB1, 0x12, 0x21, 0x69, 0xFC, 0xC4, + 0x02, 0x01, 0x61, 0x62, 0x6C, 0x6F, 0xB1, 0x23, 0xFF, 0xF5, 0xFF, 0xFD, 0xB7, 0x39, 0x42, 0x68, + 0x6C, 0xEA, 0xB7, 0xB6, 0x7C, 0xC1, 0x00, 0x71, 0x65, 0xC1, 0x65, 0xC6, 0x02, 0x01, 0x61, 0x65, + 0x72, 0x73, 0x75, 0x79, 0xDB, 0x3A, 0xB6, 0x6F, 0xFF, 0xFA, 0xB7, 0x00, 0xB7, 0x1D, 0xB7, 0x1D, + 0xC1, 0x01, 0xD1, 0x73, 0xB6, 0xF4, 0x42, 0x61, 0x6F, 0xB8, 0x60, 0xB1, 0x5E, 0x42, 0x66, 0x74, + 0xCD, 0x51, 0xFF, 0xF9, 0xC1, 0x00, 0xA1, 0x73, 0xB1, 0x86, 0x45, 0x61, 0x65, 0x67, 0x6E, 0x73, + 0xBE, 0xD0, 0xB7, 0x17, 0xB7, 0xE7, 0xFF, 0xFA, 0xB1, 0xD6, 0x41, 0x65, 0xF4, 0xB6, 0x44, 0x65, + 0x6E, 0x73, 0x74, 0xB6, 0x2C, 0xB7, 0x03, 0xB6, 0xF9, 0xFF, 0xFC, 0x41, 0x62, 0xB6, 0xB9, 0xC1, + 0x00, 0x91, 0x61, 0xB0, 0xA8, 0xC1, 0x01, 0xD1, 0x73, 0xB0, 0xCA, 0xC1, 0x00, 0xD1, 0x6B, 0xB4, + 0x6C, 0x41, 0x69, 0xB9, 0xF2, 0x43, 0x72, 0x73, 0xC3, 0xFF, 0xFC, 0xB0, 0x73, 0xB1, 0xAB, 0x49, + 0x65, 0x69, 0x6C, 0x6E, 0x6F, 0x73, 0x74, 0x75, 0x76, 0xFF, 0xDC, 0xB5, 0xFB, 0xFF, 0xE0, 0xB0, + 0x7B, 0xFF, 0xE6, 0xFF, 0xEC, 0xFF, 0xF6, 0xB6, 0xC8, 0xB0, 0x7B, 0x44, 0x69, 0x73, 0x75, 0xC3, + 0xB0, 0xE9, 0xB4, 0x5F, 0xB0, 0xE9, 0xC6, 0xFB, 0x41, 0xA4, 0xB9, 0x21, 0x42, 0x73, 0xC3, 0xD8, + 0xCD, 0xFF, 0xFC, 0x48, 0x61, 0x64, 0x6C, 0x6F, 0x73, 0x74, 0x75, 0xC3, 0xB6, 0x9E, 0xFF, 0xE8, + 0xFF, 0xF9, 0xB6, 0x9E, 0xB3, 0xBD, 0xBF, 0x43, 0xB6, 0x94, 0xE6, 0x76, 0x42, 0x6F, 0x74, 0xB0, + 0xB8, 0xB0, 0x49, 0x41, 0xB6, 0xBF, 0x8F, 0x44, 0x66, 0x73, 0x75, 0xC3, 0xCC, 0xA7, 0xFF, 0xF5, + 0xB6, 0x7A, 0xFF, 0xFC, 0x41, 0xB6, 0xB5, 0xD6, 0x21, 0xC3, 0xFC, 0x43, 0x6C, 0x73, 0x76, 0xBB, + 0xE5, 0xFF, 0xFD, 0xB5, 0xCF, 0x21, 0x72, 0xF6, 0x44, 0x65, 0x6F, 0x72, 0xC3, 0xFF, 0xFD, 0xCF, + 0x52, 0xAF, 0xF6, 0xC3, 0xBA, 0x41, 0x73, 0xB7, 0x68, 0x42, 0x66, 0x72, 0xCE, 0x42, 0xFF, 0xFC, + 0x44, 0x65, 0x69, 0x72, 0x73, 0xFF, 0xF9, 0xB1, 0x0C, 0xAF, 0xDE, 0xBD, 0x3D, 0x43, 0x6C, 0x6E, + 0x72, 0xAF, 0xD1, 0xAF, 0xD1, 0xB0, 0x67, 0x41, 0x6B, 0xB3, 0x19, 0xC1, 0x00, 0x41, 0x61, 0xDA, + 0xFA, 0x21, 0x72, 0xFA, 0x47, 0x64, 0x67, 0x69, 0x6B, 0x73, 0x74, 0x75, 0xFF, 0xC4, 0xFF, 0xDC, + 0xBC, 0xF3, 0xFF, 0xE9, 0xFF, 0xF3, 0xFF, 0xFD, 0xB5, 0x46, 0xC1, 0x01, 0xD1, 0x72, 0xB8, 0x47, + 0xC2, 0x02, 0x01, 0x65, 0x69, 0xF3, 0xB0, 0xB7, 0x1D, 0x42, 0x61, 0xC3, 0xB5, 0x61, 0xD2, 0x5E, + 0xC1, 0x00, 0x61, 0x70, 0xAF, 0x88, 0x46, 0x66, 0x67, 0x69, 0x6C, 0x72, 0x73, 0xD2, 0xA1, 0xB5, + 0x54, 0xB7, 0x20, 0xFF, 0xF3, 0xCF, 0xF9, 0xFF, 0xFA, 0x45, 0x65, 0x69, 0x6C, 0x70, 0x75, 0xFF, + 0xD1, 0xB5, 0xD8, 0xFF, 0xD7, 0xFF, 0xED, 0xB6, 0x8B, 0x41, 0x76, 0xAF, 0x7E, 0x42, 0x6B, 0x72, + 0xAF, 0x7A, 0xFF, 0xFC, 0xC2, 0x01, 0xD1, 0x62, 0x6D, 0xB5, 0x94, 0xB5, 0x94, 0x42, 0x69, 0xC3, + 0xCC, 0x92, 0xB0, 0x83, 0x21, 0x74, 0xF9, 0x46, 0x61, 0x65, 0x69, 0x6F, 0x73, 0x79, 0xFF, 0xE6, + 0xB5, 0xA0, 0xB5, 0xAA, 0xFF, 0xED, 0xFF, 0xFD, 0xB4, 0xD3, 0x42, 0x6B, 0x6E, 0xB5, 0x5A, 0xAF, + 0x58, 0x41, 0x68, 0xE8, 0xF4, 0xC1, 0x01, 0x91, 0x6E, 0xAF, 0x5D, 0xC5, 0x05, 0x82, 0x61, 0x6C, + 0x72, 0x79, 0xC3, 0xAF, 0x2F, 0xB5, 0xA3, 0xAF, 0xB9, 0xB4, 0xAF, 0xC2, 0xE7, 0x41, 0xC3, 0xC2, + 0xB1, 0xC1, 0x02, 0x01, 0x65, 0xC1, 0x65, 0x43, 0x67, 0x6B, 0x6E, 0xAF, 0x13, 0xB5, 0x60, 0xAF, + 0x20, 0x42, 0xA5, 0xA4, 0xB5, 0x37, 0xB5, 0x37, 0x44, 0x61, 0x69, 0x72, 0xC3, 0xB6, 0x0C, 0xFF, + 0xEF, 0xB2, 0xDF, 0xFF, 0xF9, 0x43, 0xA5, 0xA4, 0xB6, 0xB5, 0x23, 0xB5, 0x23, 0xB5, 0x0F, 0x4A, + 0x61, 0x63, 0x65, 0x6B, 0x6C, 0x6E, 0x70, 0x74, 0x76, 0xC3, 0xFF, 0xAB, 0xFF, 0xB2, 0xFF, 0xB6, + 0xFF, 0xBC, 0xFF, 0xCE, 0xAE, 0xEB, 0xFF, 0xD2, 0xFF, 0xE9, 0xAE, 0xEB, 0xFF, 0xF6, 0x42, 0x66, + 0x73, 0xB4, 0xFA, 0xAE, 0xC0, 0x43, 0x6B, 0x6C, 0xC3, 0xB0, 0xA6, 0xB4, 0x45, 0xC2, 0x48, 0x41, + 0xA4, 0xB9, 0x39, 0xA1, 0x00, 0x71, 0xC3, 0xFC, 0x41, 0x64, 0xCA, 0xEC, 0x21, 0x6E, 0xFC, 0x21, + 0x61, 0xFD, 0xC2, 0x01, 0xD1, 0x70, 0x73, 0xB4, 0xF5, 0xAE, 0x96, 0xC1, 0x00, 0x41, 0x70, 0xAE, + 0xAC, 0xC3, 0x00, 0x71, 0x65, 0x6F, 0x75, 0xB4, 0x9C, 0xFF, 0xFA, 0xB4, 0x59, 0x41, 0x64, 0xB7, + 0x33, 0xC1, 0x00, 0x71, 0xC3, 0xB4, 0x7C, 0x22, 0x69, 0x6C, 0xF6, 0xFA, 0xC1, 0x03, 0x61, 0x6A, + 0xAE, 0x99, 0xC1, 0x02, 0x81, 0x65, 0xF4, 0xB3, 0x41, 0xB6, 0xE5, 0x3E, 0x4D, 0x61, 0x62, 0x65, + 0x69, 0x6A, 0x6C, 0x6F, 0x72, 0x73, 0x74, 0x76, 0x79, 0xC3, 0xD8, 0xB9, 0xB4, 0x2E, 0xFF, 0xA2, + 0xFF, 0xA9, 0xFF, 0xB7, 0xFF, 0xC3, 0xFF, 0xC6, 0xFF, 0xD5, 0xFF, 0xEB, 0xFF, 0xF0, 0xFF, 0xF6, + 0xB3, 0xEE, 0xFF, 0xFC, 0xC3, 0x03, 0xD2, 0x61, 0x6A, 0xC3, 0xD7, 0x8E, 0xB4, 0x74, 0xD8, 0xAC, + 0x42, 0xA5, 0xB6, 0xB3, 0xBA, 0xB4, 0x87, 0x55, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x69, + 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x76, 0xC3, 0xB4, 0x8A, 0xFD, + 0x28, 0xFD, 0x37, 0xFD, 0x44, 0xFD, 0x59, 0xFD, 0x66, 0xFD, 0x73, 0xFD, 0x87, 0xB4, 0x80, 0xFD, + 0xB8, 0xFD, 0xEC, 0xFE, 0x10, 0xFE, 0x6D, 0xB4, 0x8A, 0xFE, 0xB2, 0xFE, 0xE0, 0xFF, 0x48, 0xFF, + 0xC5, 0xB3, 0xB3, 0xFF, 0xED, 0xFF, 0xF9, 0x41, 0x69, 0xB8, 0x8E, 0x21, 0x74, 0xFC, 0x44, 0x6B, + 0x6C, 0x73, 0x76, 0xAD, 0xE0, 0xC3, 0xB5, 0xBA, 0x4F, 0xB9, 0xC2, 0x44, 0x64, 0x70, 0x73, 0x74, + 0xBB, 0xE8, 0xB4, 0x7C, 0xBA, 0x42, 0xC3, 0x2C, 0x47, 0x62, 0x65, 0x69, 0x6B, 0x73, 0x74, 0x75, + 0xB6, 0x78, 0xB3, 0x66, 0xC0, 0x81, 0xB4, 0x6F, 0xAE, 0xAA, 0xB0, 0x21, 0xB1, 0x18, 0x41, 0x74, + 0xCD, 0x17, 0xC1, 0x03, 0x31, 0x69, 0xB9, 0x8E, 0x4C, 0x64, 0x67, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, + 0x72, 0x73, 0x74, 0x75, 0x76, 0xC3, 0xC1, 0xD4, 0xAB, 0xFF, 0xC3, 0xFF, 0xC6, 0xB9, 0x8B, 0xFF, + 0xD3, 0xB9, 0x88, 0xFF, 0xE0, 0xB1, 0x28, 0xFF, 0xF6, 0xB4, 0x4F, 0xFF, 0xFA, 0xC1, 0x00, 0xD1, + 0x65, 0xAD, 0x8D, 0x41, 0x64, 0xB4, 0x24, 0x41, 0xA4, 0xAE, 0x4F, 0x21, 0xC3, 0xFC, 0x21, 0x6B, + 0xFD, 0x44, 0x73, 0x74, 0x79, 0xC3, 0xFF, 0xFD, 0xD2, 0x7C, 0xAD, 0x79, 0xBE, 0x66, 0x42, 0x67, + 0x6B, 0xAD, 0x5A, 0xB3, 0x5C, 0xC2, 0x00, 0xA1, 0x70, 0x74, 0xAD, 0xA6, 0xB0, 0xAB, 0x44, 0x61, + 0x65, 0x73, 0x74, 0xB3, 0x4C, 0xB3, 0x4C, 0xAF, 0x29, 0xAE, 0x1F, 0xC8, 0x02, 0xF1, 0x63, 0x6B, + 0x6C, 0x6E, 0x70, 0x72, 0x73, 0x74, 0xB9, 0x25, 0xFF, 0xC2, 0xFF, 0xC8, 0xFF, 0xD6, 0xB3, 0xEC, + 0xFF, 0xE3, 0xFF, 0xEA, 0xFF, 0xF3, 0x42, 0x64, 0x74, 0xB0, 0x59, 0xAD, 0x4F, 0x41, 0x73, 0xCF, + 0x06, 0x42, 0x2E, 0x65, 0xB8, 0xFF, 0xB8, 0xFF, 0x21, 0x74, 0xF9, 0x46, 0x64, 0x67, 0x6B, 0x6F, + 0x73, 0x79, 0xC0, 0x15, 0xFF, 0xF2, 0xD4, 0x23, 0xB0, 0x30, 0xFF, 0xFD, 0xAD, 0x2C, 0xC1, 0x00, + 0x41, 0x61, 0xAD, 0x00, 0x45, 0x2E, 0x61, 0x68, 0x6B, 0x74, 0xB2, 0xF6, 0xAD, 0x13, 0xAC, 0xF4, + 0xB0, 0xE3, 0xFF, 0xFA, 0x41, 0x61, 0xB2, 0xF9, 0xC7, 0x00, 0x91, 0x63, 0x64, 0x6C, 0x6E, 0x73, + 0x74, 0x76, 0xAD, 0x7C, 0xB4, 0x19, 0xFF, 0xBE, 0xFF, 0xD3, 0xFF, 0xEC, 0xBB, 0xEE, 0xFF, 0xFC, + 0x41, 0x6F, 0xB3, 0x77, 0x41, 0x6B, 0xAF, 0x57, 0x21, 0x72, 0xFC, 0x21, 0xB6, 0xFD, 0xA1, 0x03, + 0xD2, 0xC3, 0xFD, 0x42, 0x64, 0x67, 0xB3, 0x64, 0xB5, 0x6D, 0xC4, 0x02, 0xF1, 0x6B, 0x6D, 0x72, + 0x73, 0xBA, 0xC9, 0xB5, 0x66, 0xFF, 0xF9, 0xAC, 0xDB, 0x41, 0x72, 0xCF, 0xBE, 0xC3, 0x03, 0x62, + 0x61, 0x65, 0x75, 0xEF, 0x8A, 0xFF, 0xFC, 0xB2, 0xFA, 0xC1, 0x08, 0xF2, 0x72, 0xEB, 0x2B, 0x41, + 0x63, 0xB2, 0x1B, 0xC3, 0x01, 0xD1, 0x65, 0x72, 0x79, 0xAD, 0x21, 0xBD, 0x1F, 0xFF, 0xFC, 0x41, + 0xC3, 0xB3, 0x83, 0xC8, 0x03, 0x61, 0x63, 0x6B, 0x6D, 0x6E, 0x6F, 0x74, 0x76, 0xC3, 0xB2, 0xB5, + 0xFF, 0xE6, 0xC1, 0x84, 0xCF, 0x4D, 0xB2, 0xA1, 0xFF, 0xF0, 0xFF, 0xFC, 0xBD, 0x33, 0xA0, 0x0C, + 0x22, 0x41, 0x64, 0xB2, 0xC0, 0x44, 0x64, 0x6E, 0x70, 0x74, 0xFF, 0xF9, 0xFF, 0xFC, 0xBB, 0xE2, + 0xB3, 0x02, 0x41, 0x67, 0xB0, 0x43, 0x43, 0x64, 0x69, 0x75, 0xB2, 0x44, 0xB2, 0xF1, 0xAC, 0x48, + 0x43, 0x6C, 0x6E, 0x72, 0xF1, 0xFC, 0xFF, 0xF2, 0xFF, 0xF6, 0xC1, 0x03, 0x01, 0x67, 0xAD, 0xC6, + 0xA0, 0x0C, 0x42, 0x21, 0x73, 0xFD, 0xA1, 0x00, 0xA1, 0x6C, 0xFD, 0x45, 0x64, 0x69, 0x6A, 0x6B, + 0x6C, 0xBE, 0x50, 0xDA, 0xBB, 0xB2, 0xCC, 0xB8, 0x05, 0xFA, 0x5D, 0x46, 0x67, 0x6C, 0x6E, 0x72, + 0x74, 0x78, 0xFF, 0xDF, 0xFF, 0xEB, 0xD3, 0x23, 0xFF, 0xF0, 0xB4, 0xC5, 0xB2, 0x0F, 0x43, 0x67, + 0x70, 0x72, 0xB2, 0xA9, 0xB2, 0xA9, 0xB1, 0xFC, 0x23, 0xA5, 0xA4, 0xB6, 0xB8, 0xE3, 0xF6, 0x57, + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x72, 0x73, 0x74, 0x75, 0x76, 0x79, 0xC3, 0xFE, 0x49, 0xC4, 0xEA, 0xB6, 0x96, 0xE3, 0xEC, 0xFE, + 0xAC, 0xB6, 0x96, 0xB6, 0x96, 0xB4, 0xA1, 0xFF, 0x09, 0xFF, 0x21, 0xBB, 0x75, 0xB6, 0x96, 0xFF, + 0x2F, 0xD9, 0x6B, 0xFF, 0x3B, 0xB6, 0x96, 0xFF, 0x4E, 0xFF, 0x74, 0xB6, 0x96, 0xFF, 0x96, 0xB6, + 0x96, 0xB1, 0xEB, 0xFF, 0xF9, 0xC1, 0x02, 0x01, 0x69, 0xAC, 0x8D, 0x41, 0x65, 0xAE, 0xC0, 0x41, + 0x61, 0xB1, 0xD9, 0x45, 0x61, 0x65, 0x68, 0x69, 0x6E, 0xB1, 0x67, 0xAE, 0xB8, 0xFF, 0xF2, 0xFF, + 0xF8, 0xFF, 0xFC, 0x41, 0x64, 0xD8, 0x2E, 0x21, 0x6E, 0xFC, 0x41, 0x70, 0xEB, 0xC2, 0x21, 0x6D, + 0xFC, 0x42, 0x69, 0xC3, 0xAC, 0x61, 0xBC, 0x02, 0xC7, 0x01, 0xD1, 0x61, 0x65, 0x69, 0x6B, 0x6C, + 0x73, 0x74, 0xFF, 0xEF, 0xFF, 0xF6, 0xB3, 0x1E, 0xAE, 0x93, 0xC1, 0x4B, 0xAC, 0x0C, 0xFF, 0xF9, + 0x41, 0x69, 0xB9, 0xB8, 0x42, 0x72, 0x73, 0xFF, 0xFC, 0xAB, 0xF0, 0xC1, 0x00, 0x91, 0x6E, 0xB0, + 0xDF, 0xC6, 0x02, 0x01, 0x61, 0x6F, 0x72, 0x73, 0x75, 0xC3, 0xFF, 0xFA, 0xB1, 0x87, 0xAB, 0x59, + 0xAB, 0x74, 0xB1, 0x87, 0xD6, 0x88, 0x42, 0x72, 0xC3, 0xAB, 0x38, 0xBE, 0xFC, 0x41, 0x70, 0xAB, + 0x58, 0x44, 0x61, 0x65, 0x67, 0x73, 0xB1, 0x90, 0xB1, 0x90, 0xFF, 0xF5, 0xFF, 0xFC, 0x41, 0x73, + 0xBA, 0xCA, 0x42, 0x69, 0x6F, 0xFF, 0xFC, 0xAB, 0x92, 0x44, 0x69, 0x6C, 0x6E, 0x6F, 0xB1, 0x78, + 0xFF, 0xF9, 0xAB, 0x21, 0xB1, 0x78, 0x41, 0x6A, 0xAB, 0x9E, 0x47, 0x61, 0x67, 0x69, 0x6B, 0x6C, + 0x6F, 0x74, 0xB1, 0x67, 0xFF, 0xFC, 0xB1, 0x5D, 0xAB, 0x1D, 0xFB, 0xF3, 0xB1, 0x67, 0xB1, 0x13, + 0x42, 0x6C, 0x6F, 0xAE, 0x0B, 0xB0, 0xFD, 0x42, 0x66, 0xC3, 0xFF, 0xF9, 0xBC, 0xE2, 0x42, 0x61, + 0x74, 0xAB, 0x76, 0xAB, 0x07, 0x43, 0x67, 0x6B, 0x73, 0xB2, 0x93, 0xAA, 0xD6, 0xFF, 0xF9, 0x42, + 0x72, 0x75, 0xB1, 0x28, 0xB0, 0x5B, 0x43, 0x65, 0x6F, 0x72, 0xB1, 0x2B, 0xB0, 0x54, 0xB1, 0x53, + 0x42, 0x75, 0x76, 0xAB, 0x54, 0xAA, 0xB8, 0x42, 0x6B, 0x74, 0xAA, 0xDE, 0xAA, 0xD0, 0xA0, 0x0C, + 0x62, 0x21, 0xA5, 0xFD, 0x47, 0x65, 0x69, 0x6B, 0x6F, 0x73, 0x74, 0xC3, 0xB2, 0x52, 0xB1, 0x0D, + 0xFF, 0xEC, 0xB1, 0x0D, 0xFF, 0xF3, 0xC6, 0x3A, 0xFF, 0xFD, 0x41, 0x6F, 0xB0, 0x20, 0x21, 0x68, + 0xFC, 0xC1, 0x00, 0x71, 0x6B, 0xBD, 0x48, 0x43, 0x61, 0x69, 0x72, 0xAA, 0x93, 0xFF, 0xFA, 0xB9, + 0xC1, 0x43, 0x63, 0x73, 0x74, 0xFF, 0xED, 0xD0, 0xF2, 0xFF, 0xF6, 0x42, 0x2E, 0x61, 0xB0, 0xAD, + 0xB0, 0xAD, 0x45, 0x61, 0x65, 0x6F, 0x74, 0x76, 0xD3, 0xC0, 0xFF, 0xF9, 0xB0, 0xCF, 0xB2, 0x26, + 0xAA, 0x85, 0x43, 0x61, 0x69, 0xC3, 0xB0, 0xB5, 0xB0, 0xB5, 0xB3, 0x8B, 0xD2, 0x03, 0x61, 0x61, + 0x62, 0x64, 0x65, 0x67, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x76, 0x77, + 0xC3, 0xB0, 0xB5, 0xFE, 0xF8, 0xFF, 0x05, 0xB0, 0xB5, 0xFF, 0x25, 0xB0, 0xB5, 0xFF, 0x3D, 0xFF, + 0x4E, 0xFF, 0x6B, 0xFF, 0x79, 0xFF, 0x83, 0xFF, 0x8A, 0xFF, 0xA8, 0xFF, 0xD5, 0xFF, 0xE6, 0xFF, + 0xF6, 0xAF, 0xDE, 0xB5, 0x12, 0xC1, 0x02, 0xF1, 0x72, 0xB3, 0x23, 0x41, 0x61, 0xAA, 0xAC, 0xA1, + 0x02, 0xF1, 0x6E, 0xFC, 0x48, 0x61, 0x65, 0x69, 0x6F, 0x70, 0x73, 0x75, 0x7A, 0xAF, 0xD6, 0xFF, + 0xF1, 0xAF, 0xD6, 0xFF, 0xFB, 0xB0, 0xB3, 0xAF, 0x96, 0xB0, 0x06, 0xDC, 0xE4, 0x42, 0x6A, 0x73, + 0xA9, 0xFD, 0xAE, 0x4A, 0xC1, 0x02, 0x81, 0x6C, 0xAB, 0xD7, 0x42, 0x6B, 0x74, 0xAA, 0x80, 0xA9, + 0xE4, 0x45, 0x61, 0x65, 0x6C, 0x73, 0xC3, 0xAD, 0x2F, 0xFF, 0xF3, 0xA9, 0xDD, 0xFF, 0xF9, 0xCA, + 0x98, 0x41, 0x61, 0xE8, 0xBA, 0x41, 0x72, 0xAB, 0x8F, 0x21, 0x74, 0xFC, 0x43, 0x69, 0x6C, 0x73, + 0xAD, 0x14, 0xFF, 0xF5, 0xFF, 0xFD, 0x41, 0x65, 0xB1, 0x9F, 0x41, 0x73, 0xB7, 0x13, 0x42, 0x65, + 0x74, 0xC4, 0x0F, 0xA9, 0xB0, 0x47, 0x61, 0x64, 0x69, 0x6B, 0x6C, 0x73, 0xC3, 0xAC, 0xFB, 0xFF, + 0xF1, 0xC8, 0x5D, 0xA9, 0xA9, 0xFF, 0xF5, 0xFF, 0xF9, 0xC4, 0xF2, 0xC1, 0x02, 0x81, 0x61, 0xAD, + 0x55, 0x42, 0x72, 0x75, 0xA9, 0xCE, 0xA9, 0xB4, 0x42, 0x74, 0x76, 0xA9, 0xC7, 0xA9, 0xC7, 0x22, + 0x64, 0x73, 0xF2, 0xF9, 0xC1, 0x00, 0xD1, 0x61, 0xA9, 0x93, 0xC2, 0x02, 0x81, 0x6C, 0xC3, 0xFF, + 0xFA, 0xC0, 0x1C, 0xA0, 0x0C, 0x82, 0xA1, 0x01, 0xE1, 0x74, 0xFD, 0x43, 0x6F, 0x72, 0x73, 0xA9, + 0x8A, 0xCB, 0xB6, 0xFF, 0xFB, 0x41, 0x76, 0xB5, 0x3B, 0x41, 0x69, 0xC5, 0xAB, 0x43, 0x61, 0x6C, + 0x76, 0xFF, 0xF8, 0xFF, 0xFC, 0xAA, 0x35, 0x46, 0x64, 0x65, 0x69, 0x6F, 0x73, 0xC3, 0xFF, 0xE4, + 0xA9, 0xE0, 0xAC, 0x99, 0xAD, 0xE0, 0xFF, 0xF6, 0xB3, 0x65, 0xC1, 0x00, 0xC1, 0x6B, 0xA9, 0x5E, + 0x44, 0x6B, 0x6E, 0x73, 0x74, 0xAB, 0xB4, 0xA9, 0x2E, 0xFF, 0xFA, 0xA9, 0x55, 0x42, 0x69, 0xC3, + 0xA9, 0x21, 0xB0, 0x25, 0x41, 0x6A, 0xA9, 0xFE, 0x44, 0x65, 0x72, 0x73, 0x74, 0xAB, 0x03, 0xFF, + 0xF5, 0xFF, 0xFC, 0xA9, 0xE5, 0x50, 0x61, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, + 0x6F, 0x70, 0x72, 0x73, 0x74, 0x76, 0xAC, 0x5B, 0xFF, 0x18, 0xAC, 0x5B, 0xAC, 0x5B, 0xFF, 0x2C, + 0xA9, 0x15, 0xFF, 0x47, 0xFF, 0x60, 0xFF, 0x76, 0xFF, 0x8A, 0xA9, 0x15, 0xFF, 0x95, 0xFF, 0xC2, + 0xFF, 0xDB, 0xFF, 0xF3, 0xAC, 0x5B, 0xC1, 0x03, 0x61, 0x6B, 0xD2, 0x72, 0x42, 0x73, 0x75, 0xA9, + 0x06, 0xA8, 0xF9, 0x42, 0x65, 0x74, 0xA8, 0xC5, 0xA8, 0xCB, 0xC4, 0x00, 0xD1, 0x64, 0x65, 0x72, + 0x73, 0xFF, 0xF2, 0xA9, 0xC1, 0xA8, 0xC4, 0xFF, 0xF9, 0xC1, 0x00, 0x61, 0x65, 0xA8, 0xDC, 0x46, + 0x61, 0x65, 0x67, 0x6C, 0x72, 0x73, 0xAC, 0x01, 0xAC, 0x01, 0xB0, 0x26, 0xA9, 0x16, 0xFF, 0xFA, + 0xB9, 0x9E, 0xC3, 0x03, 0x31, 0x69, 0x6E, 0x72, 0xAB, 0xEE, 0xA8, 0x9C, 0xA8, 0x9C, 0x41, 0x61, + 0xFD, 0x5F, 0x41, 0x67, 0xA8, 0xB3, 0x41, 0x67, 0xA9, 0x54, 0x21, 0x6F, 0xFC, 0x43, 0x65, 0x6B, + 0x6C, 0xFF, 0xF5, 0xFF, 0xFD, 0xBA, 0x5E, 0xA0, 0x05, 0xC2, 0x42, 0x72, 0x75, 0xFF, 0xFD, 0xA9, + 0x58, 0x45, 0x61, 0x70, 0x73, 0x74, 0x76, 0xAB, 0xBF, 0xFF, 0xDD, 0xFF, 0xEC, 0xFF, 0xF9, 0xBC, + 0x2D, 0x41, 0x70, 0xA8, 0x94, 0x41, 0x68, 0xAF, 0x02, 0x21, 0x67, 0xFC, 0x21, 0x69, 0xFD, 0x43, + 0x6C, 0x72, 0x73, 0xFF, 0xFD, 0xA8, 0x83, 0xEA, 0xBA, 0x42, 0x69, 0x73, 0xA9, 0x20, 0xA8, 0x79, + 0xC1, 0x00, 0xA1, 0x65, 0xA9, 0x0A, 0x43, 0x6C, 0x74, 0x76, 0xAB, 0x2A, 0xFF, 0xFA, 0xA8, 0x5F, + 0x21, 0x72, 0xB7, 0x46, 0x64, 0x67, 0x6E, 0x6F, 0x73, 0x74, 0xFF, 0xDC, 0xAA, 0x86, 0xFF, 0xE6, + 0xA8, 0xC1, 0xFF, 0xF3, 0xFF, 0xFD, 0x44, 0x65, 0x70, 0x72, 0x73, 0xA8, 0x24, 0xA8, 0x4F, 0xA8, + 0xAE, 0xB4, 0x87, 0x41, 0x72, 0xAB, 0xBB, 0x42, 0x6C, 0x72, 0xA8, 0xD3, 0xA8, 0x2E, 0xC1, 0x02, + 0x81, 0x62, 0xAA, 0x1F, 0x42, 0xA5, 0xB6, 0xA8, 0xDE, 0xA8, 0x21, 0x43, 0x69, 0x73, 0xC3, 0xAF, + 0x9B, 0xB5, 0x12, 0xFF, 0xF9, 0x45, 0x62, 0x6C, 0x70, 0x72, 0x73, 0xA7, 0xE3, 0xA8, 0x02, 0xA7, + 0xF5, 0xA8, 0x02, 0xA8, 0x02, 0x45, 0x69, 0x6B, 0x6F, 0x70, 0x76, 0xA8, 0xBD, 0xAF, 0x50, 0xA8, + 0xBD, 0xA8, 0x00, 0xA8, 0xBD, 0x41, 0x6E, 0xC2, 0x8F, 0x43, 0x61, 0x72, 0x73, 0xFF, 0xFC, 0xA8, + 0xA9, 0xA7, 0xF9, 0x49, 0x61, 0x62, 0x67, 0x69, 0x6B, 0x6E, 0x6F, 0x73, 0x74, 0xC0, 0xD5, 0xFF, + 0xB0, 0xFF, 0xB4, 0xFF, 0xBB, 0xA9, 0x81, 0xFF, 0xC8, 0xFF, 0xD2, 0xFF, 0xE2, 0xFF, 0xF6, 0x42, + 0x61, 0x69, 0xA7, 0x9F, 0xA7, 0x99, 0x42, 0x6B, 0x70, 0xA7, 0xBF, 0xA7, 0xBF, 0x43, 0x61, 0x72, + 0xC3, 0xA7, 0x91, 0xA7, 0xC5, 0xA8, 0xC3, 0xC4, 0x03, 0x31, 0x70, 0x73, 0x74, 0xC3, 0xFF, 0xE8, + 0xFF, 0xEF, 0xFF, 0xF6, 0xBB, 0x4B, 0x41, 0x6B, 0xAF, 0xB6, 0x45, 0x65, 0x6F, 0x72, 0x75, 0x76, + 0xA7, 0x6E, 0xFC, 0x43, 0xA7, 0xA8, 0xA7, 0x9B, 0xA7, 0x9B, 0xC4, 0x03, 0x61, 0x6F, 0x72, 0x73, + 0x74, 0xA7, 0x70, 0xAF, 0x2C, 0xFF, 0xEC, 0xFF, 0xF0, 0xC1, 0x02, 0x81, 0x6B, 0xAA, 0x72, 0x43, + 0x61, 0x69, 0x75, 0xFF, 0xFA, 0xA7, 0x5B, 0xA7, 0x68, 0x51, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67, + 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x76, 0xAA, 0x97, 0xAA, 0x62, 0xFE, + 0x6D, 0xFE, 0x81, 0xA7, 0x51, 0xFE, 0x96, 0xA7, 0x51, 0xB7, 0xF0, 0xFE, 0xA9, 0xFE, 0xD8, 0xFE, + 0xE8, 0xFF, 0x1A, 0xFF, 0x2D, 0xFF, 0x8A, 0xFF, 0xBE, 0xFF, 0xE1, 0xFF, 0xF6, 0x41, 0x76, 0xA7, + 0xA7, 0x43, 0x6B, 0x6C, 0x72, 0xA7, 0xA3, 0xA7, 0xA3, 0xFF, 0xFC, 0xC1, 0x01, 0x01, 0x65, 0xA7, + 0x03, 0xC7, 0x00, 0xD1, 0x61, 0x65, 0x69, 0x72, 0x73, 0x75, 0xC3, 0xFF, 0xF0, 0xAB, 0xF4, 0xAC, + 0x9D, 0xB6, 0x37, 0xFF, 0xFA, 0xA7, 0x93, 0xBD, 0xA5, 0xC2, 0x02, 0x81, 0x6B, 0x72, 0xA6, 0xDF, + 0xA6, 0xFE, 0xC1, 0x02, 0x81, 0x72, 0xA6, 0xF5, 0xC1, 0x01, 0x01, 0x65, 0xA7, 0x0A, 0x42, 0x69, + 0x6B, 0xA6, 0xD0, 0xA6, 0xD0, 0x48, 0x61, 0x64, 0x65, 0x67, 0x6C, 0x6E, 0x6F, 0x73, 0xFF, 0xE4, + 0xAC, 0x95, 0xFF, 0xED, 0xA7, 0x0A, 0xA7, 0x30, 0xFF, 0xF3, 0xAC, 0x95, 0xFF, 0xF9, 0x41, 0x76, + 0xA6, 0xD7, 0x42, 0x6F, 0x73, 0xA6, 0xB8, 0xFF, 0xFC, 0x41, 0x72, 0xC6, 0x01, 0xC1, 0x01, 0x01, + 0x6C, 0xA6, 0xA1, 0x44, 0x61, 0x69, 0x6E, 0x73, 0xFF, 0xF6, 0xA9, 0xED, 0xA6, 0x9B, 0xFF, 0xFA, + 0x42, 0x76, 0xC3, 0xA6, 0xB5, 0xBB, 0xEB, 0x44, 0x61, 0x6B, 0x70, 0xC3, 0xA9, 0xD9, 0xFF, 0xF9, + 0xA7, 0x6B, 0xBA, 0x27, 0x41, 0x6C, 0xA7, 0x5E, 0x42, 0x61, 0x6B, 0xDD, 0x62, 0xFF, 0xFC, 0x41, + 0x6D, 0xA9, 0x8C, 0x41, 0x65, 0xA6, 0x9F, 0x43, 0x6B, 0x6F, 0x74, 0xFF, 0xFC, 0xA6, 0x8E, 0xA7, + 0x7A, 0x43, 0x61, 0x6F, 0x73, 0xA6, 0xF6, 0xFF, 0xEE, 0xFF, 0xF6, 0xC1, 0x00, 0x71, 0x6C, 0xA6, + 0xE9, 0x42, 0x69, 0x6F, 0xA6, 0x47, 0xA6, 0x66, 0x45, 0x65, 0x69, 0x6C, 0x70, 0x72, 0xFF, 0xF3, + 0xA6, 0x52, 0xFF, 0xF9, 0xCD, 0x4B, 0xA6, 0xDC, 0x41, 0x64, 0xD6, 0xA5, 0xC1, 0x00, 0x71, 0x6B, + 0xA6, 0xC8, 0x22, 0x6E, 0x73, 0xF6, 0xFA, 0x41, 0x72, 0xA6, 0xC3, 0x41, 0x69, 0xA6, 0x8A, 0xC1, + 0x00, 0x71, 0x74, 0xAC, 0x2E, 0x44, 0x6E, 0x73, 0x74, 0x76, 0xFF, 0xF6, 0xFF, 0xFA, 0xA6, 0x25, + 0xDC, 0x39, 0x42, 0x67, 0x74, 0xA6, 0x18, 0xA6, 0x0C, 0xC4, 0x02, 0x81, 0x67, 0x6E, 0x72, 0x76, + 0xA6, 0x1E, 0xFF, 0xF9, 0xA5, 0xFF, 0xA5, 0xFF, 0xC1, 0x0C, 0xA2, 0x69, 0xA5, 0xF0, 0x42, 0x61, + 0x6C, 0xD4, 0x88, 0xFF, 0xFA, 0x42, 0x6C, 0x72, 0xA5, 0xE9, 0xA6, 0x50, 0x41, 0x61, 0xC0, 0x41, + 0x21, 0x6C, 0xFC, 0xA0, 0x0C, 0xA2, 0xC1, 0x00, 0x61, 0xC3, 0xA7, 0x9A, 0x22, 0x6B, 0x6C, 0xF7, + 0xFA, 0x42, 0x65, 0x73, 0xA5, 0xC7, 0xA6, 0x99, 0x41, 0x64, 0xA7, 0xE5, 0x42, 0xA4, 0xB6, 0xA6, + 0x29, 0xFF, 0xFC, 0x50, 0x61, 0x62, 0x64, 0x65, 0x67, 0x69, 0x6B, 0x6E, 0x6F, 0x70, 0x73, 0x74, + 0x75, 0x76, 0x79, 0xC3, 0xFF, 0x8F, 0xA5, 0xFC, 0xFF, 0x94, 0xFF, 0xA2, 0xA5, 0xBB, 0xFF, 0xB6, + 0xFF, 0xCB, 0xCD, 0xDA, 0xFF, 0xD2, 0xFF, 0xDD, 0xFF, 0xE9, 0xFF, 0xEE, 0xA6, 0x22, 0xAD, 0x75, + 0xA5, 0xBB, 0xFF, 0xF9, 0x41, 0x6B, 0xA8, 0xA7, 0x43, 0x6A, 0x6B, 0x70, 0xA5, 0xAD, 0xA6, 0x6A, + 0xA5, 0xAD, 0x42, 0x61, 0x76, 0xA5, 0x7C, 0xA5, 0xB0, 0x44, 0x61, 0x6E, 0x73, 0x74, 0xFF, 0xEB, + 0xA5, 0x75, 0xFF, 0xEF, 0xFF, 0xF9, 0x41, 0x6F, 0xA6, 0x34, 0x42, 0x6B, 0x74, 0xFF, 0xFC, 0xA5, + 0x8B, 0x22, 0x61, 0x73, 0xD3, 0xF9, 0xC1, 0x01, 0x51, 0x65, 0xB1, 0x3A, 0xA1, 0x00, 0xC1, 0x72, + 0xFA, 0x42, 0x61, 0x69, 0xA5, 0x4D, 0xA5, 0x4D, 0xC4, 0x02, 0x81, 0x65, 0x6A, 0x72, 0x73, 0xFF, + 0xF4, 0xA8, 0x63, 0xFF, 0xF9, 0xA8, 0x73, 0x4F, 0x61, 0x64, 0x65, 0x67, 0x69, 0x6A, 0x6B, 0x6C, + 0x6D, 0x6E, 0x70, 0x72, 0x73, 0x74, 0x76, 0xA8, 0x89, 0xFE, 0x3A, 0xA8, 0x89, 0xFE, 0x6E, 0xA8, + 0x89, 0xFE, 0x8B, 0xFE, 0x9C, 0xFE, 0xB0, 0xFE, 0xC1, 0xFE, 0xDA, 0xFE, 0xF1, 0xFF, 0x7C, 0xFF, + 0xC2, 0xFF, 0xDA, 0xFF, 0xF1, 0x44, 0xA5, 0xA4, 0xB6, 0xA9, 0xFC, 0x00, 0xFD, 0xC4, 0xFF, 0xD2, + 0xD5, 0x78, 0x5C, 0x2E, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, + 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xC3, 0xAA, + 0x1A, 0xAF, 0xC0, 0xB1, 0xD5, 0xB2, 0xDD, 0xB6, 0x57, 0xBB, 0x4C, 0xBD, 0x5E, 0xC0, 0xEB, 0xC2, + 0x64, 0xC6, 0x55, 0xC7, 0x81, 0xCC, 0x72, 0xD1, 0x52, 0xD4, 0x1B, 0xD8, 0x82, 0xDC, 0x5B, 0xDF, + 0x37, 0xDF, 0x80, 0xE4, 0xBE, 0xED, 0x95, 0xF3, 0xA9, 0xF6, 0xD5, 0xF9, 0x0D, 0xF9, 0x61, 0xF9, + 0x86, 0xFA, 0xAA, 0xFA, 0xF2, 0xFF, 0xF3, +}; + +constexpr SerializedHyphenationPatterns sv_patterns = { + 0x5BD2u, + sv_trie_data, + sizeof(sv_trie_data), +}; diff --git a/lib/FsHelpers/FsHelpers.cpp b/lib/FsHelpers/FsHelpers.cpp index 891190fd43..975b4b49cd 100644 --- a/lib/FsHelpers/FsHelpers.cpp +++ b/lib/FsHelpers/FsHelpers.cpp @@ -119,6 +119,8 @@ bool hasPngExtension(std::string_view fileName) { return checkFileExtension(file bool hasBmpExtension(std::string_view fileName) { return checkFileExtension(fileName, ".bmp"); } +bool hasPxcExtension(std::string_view fileName) { return checkFileExtension(fileName, ".pxc"); } + bool hasGifExtension(std::string_view fileName) { return checkFileExtension(fileName, ".gif"); } bool hasEpubExtension(std::string_view fileName) { return checkFileExtension(fileName, ".epub"); } diff --git a/lib/FsHelpers/FsHelpers.h b/lib/FsHelpers/FsHelpers.h index 56c2c9878f..fdffef524c 100644 --- a/lib/FsHelpers/FsHelpers.h +++ b/lib/FsHelpers/FsHelpers.h @@ -34,6 +34,9 @@ inline bool hasPngExtension(const String& fileName) { // Check for .bmp extension (case-insensitive) bool hasBmpExtension(std::string_view fileName); +// Check for .pxc extension (case-insensitive) +bool hasPxcExtension(std::string_view fileName); + // Check for .gif extension (case-insensitive) bool hasGifExtension(std::string_view fileName); inline bool hasGifExtension(const String& fileName) { diff --git a/lib/GfxRenderer/Bitmap.cpp b/lib/GfxRenderer/Bitmap.cpp index 776e52f3b2..6231cfc30f 100644 --- a/lib/GfxRenderer/Bitmap.cpp +++ b/lib/GfxRenderer/Bitmap.cpp @@ -1,5 +1,7 @@ #include "Bitmap.h" +#include + #include #include @@ -19,6 +21,33 @@ Bitmap::~Bitmap() { delete atkinsonDitherer; delete fsDitherer; + + free(readChunkBuf); +} + +int Bitmap::bufferedRead(uint8_t* dst, int n) const { + if (!readChunkBuf) { + readChunkBuf = static_cast(malloc(READ_CHUNK_SIZE)); + if (!readChunkBuf) { + LOG_ERR("BMP", "bufferedRead: malloc failed (%d bytes)", READ_CHUNK_SIZE); + return 0; + } + } + + int done = 0; + while (done < n) { + if (readChunkPos >= readChunkFill) { + readChunkFill = file.read(readChunkBuf, READ_CHUNK_SIZE); + readChunkPos = 0; + if (readChunkFill <= 0) break; + } + const int avail = readChunkFill - readChunkPos; + const int take = (avail < n - done) ? avail : n - done; + memcpy(dst + done, readChunkBuf + readChunkPos, take); + readChunkPos += take; + done += take; + } + return done; } uint16_t Bitmap::readLE16(FsFile& f) { @@ -180,7 +209,7 @@ BmpReaderError Bitmap::parseHeaders() { // packed 2bpp output, 0 = black, 1 = dark gray, 2 = light gray, 3 = white BmpReaderError Bitmap::readNextRow(uint8_t* data, uint8_t* rowBuffer) const { // Note: rowBuffer should be pre-allocated by the caller to size 'rowBytes' - if (file.read(rowBuffer, rowBytes) != rowBytes) return BmpReaderError::ShortReadRow; + if (bufferedRead(rowBuffer, rowBytes) != rowBytes) return BmpReaderError::ShortReadRow; prevRowY += 1; @@ -193,16 +222,16 @@ BmpReaderError Bitmap::readNextRow(uint8_t* data, uint8_t* rowBuffer) const { auto packPixel = [&](const uint8_t lum) { uint8_t color; if (atkinsonDitherer) { - color = atkinsonDitherer->processPixel(adjustPixel(lum), currentX); + color = atkinsonDitherer->processPixel(lum, currentX); } else if (fsDitherer) { - color = fsDitherer->processPixel(adjustPixel(lum), currentX); + color = fsDitherer->processPixel(lum, currentX); } else { if (nativePalette) { - // Palette matches native gray levels: direct mapping (still apply brightness/contrast/gamma) - color = static_cast(adjustPixel(lum) >> 6); + // Palette matches native gray levels: direct 2-bit mapping + color = static_cast(lum >> 6); } else { // Non-native palette with dithering disabled: simple quantization - color = quantize(adjustPixel(lum), currentX, prevRowY); + color = quantize(lum, currentX, prevRowY); } } currentOutByte |= (color << bitShift); @@ -287,6 +316,10 @@ BmpReaderError Bitmap::rewindToData() const { return BmpReaderError::SeekPixelDataFailed; } + // Invalidate chunk buffer — file position changed, buffered bytes are stale. + readChunkPos = 0; + readChunkFill = 0; + // Reset dithering when rewinding if (fsDitherer) fsDitherer->reset(); if (atkinsonDitherer) atkinsonDitherer->reset(); diff --git a/lib/GfxRenderer/Bitmap.h b/lib/GfxRenderer/Bitmap.h index bba4189f29..58abdb6faf 100644 --- a/lib/GfxRenderer/Bitmap.h +++ b/lib/GfxRenderer/Bitmap.h @@ -81,6 +81,10 @@ class Bitmap { static uint16_t readLE16(FsFile& f); static uint32_t readLE32(FsFile& f); + // Reads exactly n bytes from the internal chunk buffer, refilling from SD as needed. + // Returns bytes actually read (< n on EOF/error). + int bufferedRead(uint8_t* dst, int n) const; + FsFile& file; bool dithering = false; int width = 0; @@ -100,4 +104,10 @@ class Bitmap { mutable AtkinsonDitherer* atkinsonDitherer = nullptr; mutable FloydSteinbergDitherer* fsDitherer = nullptr; + + // SD read-ahead buffer: rows are served from here; refilled from SD in READ_CHUNK_SIZE chunks. + static constexpr int READ_CHUNK_SIZE = 4096; // 8 SD sectors per fill — enables CMD18 multi-block + mutable uint8_t* readChunkBuf = nullptr; + mutable int readChunkPos = 0; + mutable int readChunkFill = 0; }; diff --git a/lib/GfxRenderer/BitmapHelpers.cpp b/lib/GfxRenderer/BitmapHelpers.cpp index dca059ec9e..96a9135c13 100644 --- a/lib/GfxRenderer/BitmapHelpers.cpp +++ b/lib/GfxRenderer/BitmapHelpers.cpp @@ -5,11 +5,14 @@ #include "Bitmap.h" +// LUT-aware quantization profile: false = factory (default), true = differential +bool g_differentialQuantize = false; + // Brightness/Contrast adjustments: -constexpr bool USE_BRIGHTNESS = false; // true: apply brightness/gamma adjustments -constexpr int BRIGHTNESS_BOOST = 10; // Brightness offset (0-50) -constexpr bool GAMMA_CORRECTION = false; // Gamma curve (brightens midtones) -constexpr float CONTRAST_FACTOR = 1.15f; // Contrast multiplier (1.0 = no change, >1 = more contrast) +constexpr bool USE_BRIGHTNESS = true; // true: apply brightness/gamma adjustments +constexpr int BRIGHTNESS_BOOST = 0; // No boost — quality LUT already renders slightly lighter +constexpr bool GAMMA_CORRECTION = false; // Gamma curve (brightens midtones) +constexpr float CONTRAST_FACTOR = 1.2f; // Contrast boost for 1-bit thumbnails (applied inside Atkinson1BitDitherer) constexpr bool USE_NOISE_DITHERING = false; // Hash-based noise dithering // Integer approximation of gamma correction (brightens midtones) @@ -52,18 +55,21 @@ int adjustPixel(int gray) { return gray; } -// Simple quantization without dithering - divide into 4 levels -// The thresholds are fine-tuned to the X4 display +// Simple quantization without dithering. +// Factory LUT (fast/quality): evenly-spaced thresholds — softer, linear drive. +// Differential LUT: calibrated thresholds from upstream — narrow darkGrey band, +// biased toward lighter levels to compensate for more aggressive drive. uint8_t quantizeSimple(int gray) { - if (gray < 45) { - return 0; - } else if (gray < 70) { - return 1; - } else if (gray < 140) { - return 2; - } else { + if (g_differentialQuantize) { + if (gray < 45) return 0; + if (gray < 70) return 1; + if (gray < 140) return 2; return 3; } + if (gray < 43) return 0; + if (gray < 128) return 1; + if (gray < 213) return 2; + return 3; } // Hash-based noise dithering - survives downsampling without moiré artifacts diff --git a/lib/GfxRenderer/BitmapHelpers.h b/lib/GfxRenderer/BitmapHelpers.h index d9d2d85544..e95a393360 100644 --- a/lib/GfxRenderer/BitmapHelpers.h +++ b/lib/GfxRenderer/BitmapHelpers.h @@ -11,6 +11,10 @@ uint8_t quantizeSimple(int gray); uint8_t quantize1bit(int gray, int x, int y); int adjustPixel(int gray); +// Set true when rendering for differential LUT to use calibrated thresholds. +// Set false (default) for factory LUT (fast/quality) — uses evenly-spaced thresholds. +extern bool g_differentialQuantize; + enum class BmpRowOrder { BottomUp, TopDown }; // Populates a 1-bit BMP header in the provided memory. @@ -128,35 +132,38 @@ class AtkinsonDitherer { if (adjusted > 255) adjusted = 255; // Quantize to 4 levels + // Differential LUT: calibrated thresholds matching upstream (narrow darkGrey band, + // biased toward light to compensate for more aggressive drive). + // Factory LUT (fast/quality): evenly-spaced thresholds — softer drive, linear response. uint8_t quantized; int quantizedValue; - if (false) { // original thresholds - if (adjusted < 43) { + if (g_differentialQuantize) { + if (adjusted < 45) { quantized = 0; quantizedValue = 0; - } else if (adjusted < 128) { + } else if (adjusted < 70) { quantized = 1; quantizedValue = 85; - } else if (adjusted < 213) { + } else if (adjusted < 140) { quantized = 2; quantizedValue = 170; } else { quantized = 3; quantizedValue = 255; } - } else { // fine-tuned to X4 eink display - if (adjusted < 30) { + } else { + if (adjusted < 43) { quantized = 0; - quantizedValue = 15; - } else if (adjusted < 50) { + quantizedValue = 0; + } else if (adjusted < 128) { quantized = 1; - quantizedValue = 30; - } else if (adjusted < 140) { + quantizedValue = 85; + } else if (adjusted < 213) { quantized = 2; - quantizedValue = 80; + quantizedValue = 170; } else { quantized = 3; - quantizedValue = 210; + quantizedValue = 255; } } @@ -231,36 +238,36 @@ class FloydSteinbergDitherer { if (adjusted < 0) adjusted = 0; if (adjusted > 255) adjusted = 255; - // Quantize to 4 levels (0, 85, 170, 255) + // Quantize to 4 levels — see Atkinson ditherer comment for threshold rationale uint8_t quantized; int quantizedValue; - if (false) { // original thresholds - if (adjusted < 43) { + if (g_differentialQuantize) { + if (adjusted < 45) { quantized = 0; quantizedValue = 0; - } else if (adjusted < 128) { + } else if (adjusted < 70) { quantized = 1; quantizedValue = 85; - } else if (adjusted < 213) { + } else if (adjusted < 140) { quantized = 2; quantizedValue = 170; } else { quantized = 3; quantizedValue = 255; } - } else { // fine-tuned to X4 eink display - if (adjusted < 30) { + } else { + if (adjusted < 43) { quantized = 0; - quantizedValue = 15; - } else if (adjusted < 50) { + quantizedValue = 0; + } else if (adjusted < 128) { quantized = 1; - quantizedValue = 30; - } else if (adjusted < 140) { + quantizedValue = 85; + } else if (adjusted < 213) { quantized = 2; - quantizedValue = 80; + quantizedValue = 170; } else { quantized = 3; - quantizedValue = 210; + quantizedValue = 255; } } diff --git a/lib/GfxRenderer/GfxRenderer.cpp b/lib/GfxRenderer/GfxRenderer.cpp index 769402ef59..63c3f10a8f 100644 --- a/lib/GfxRenderer/GfxRenderer.cpp +++ b/lib/GfxRenderer/GfxRenderer.cpp @@ -1,5 +1,6 @@ #include "GfxRenderer.h" +#include #include #include #include @@ -8,6 +9,7 @@ #include +#include "BitmapHelpers.h" #include "FontCacheManager.h" namespace { @@ -21,6 +23,28 @@ const char* resolveVisualText(const char* text, std::string& visualBuffer, int p uint8_t resolveSdCardStyle(const SdCardFont& font, const EpdFontFamily::Style style) { return font.resolveStyle(static_cast(style)); } + +// Bundles every panel-level value derived from a caller-facing GrayscaleDriveMode, +// so the three grayscale entry points share one mapping instead of repeating ternaries. +struct GrayscaleDriveSpec { + GfxRenderer::RenderMode lsbMode; + GfxRenderer::RenderMode msbMode; + const unsigned char* lut; // nullptr for Differential + bool factoryMode; + bool differentialQuantize; +}; + +GrayscaleDriveSpec resolveGrayscaleDrive(GfxRenderer::GrayscaleDriveMode mode) { + switch (mode) { + case GfxRenderer::GrayscaleDriveMode::Differential: + return {GfxRenderer::GRAYSCALE_LSB, GfxRenderer::GRAYSCALE_MSB, nullptr, false, true}; + case GfxRenderer::GrayscaleDriveMode::FactoryFast: + return {GfxRenderer::GRAY2_LSB, GfxRenderer::GRAY2_MSB, lut_factory_fast, true, false}; + case GfxRenderer::GrayscaleDriveMode::FactoryQuality: + return {GfxRenderer::GRAY2_LSB, GfxRenderer::GRAY2_MSB, lut_factory_quality, true, false}; + } + return {GfxRenderer::GRAYSCALE_LSB, GfxRenderer::GRAYSCALE_MSB, nullptr, false, true}; +} } // namespace const uint8_t* GfxRenderer::getGlyphBitmap(const EpdFontData* fontData, const EpdGlyph* glyph) const { @@ -53,11 +77,22 @@ const uint8_t* GfxRenderer::getGlyphBitmap(const EpdFontData* fontData, const Ep void GfxRenderer::ensureSdCardFontReady(int fontId, const char* utf8Text, uint8_t styleMask) const { auto it = sdCardFonts_.find(fontId); + if (it != sdCardFonts_.end()) { + int missed = it->second->buildAdvanceTable(utf8Text, styleMask); + if (missed > 0) { + LOG_DBG("GFX", "ensureSdCardFontReady: %d glyph(s) not found", missed); + } + } +} + +void GfxRenderer::ensureSdCardFontReady(int fontId, const std::vector& words, bool includeHyphen, + uint8_t styleMask) const { + auto it = sdCardFonts_.find(fontId); if (it != sdCardFonts_.end()) { // Augment the persistent advance-only table for layout measurement. // The table survives across paragraphs/sections (capped per font), so // repeated indexing of the same SD font amortizes glyph-metric SD reads. - int missed = it->second->buildAdvanceTable(utf8Text, styleMask); + int missed = it->second->buildAdvanceTable(words, includeHyphen, styleMask); if (missed > 0) { LOG_DBG("GFX", "ensureSdCardFontReady: %d glyph(s) not found", missed); } @@ -183,7 +218,15 @@ static void renderCharImpl(const GfxRenderer& renderer, GfxRenderer::RenderMode // We have to flag pixels in reverse for the gray buffers, as 0 leave alone, 1 update renderer.drawPixel(screenX, screenY, false); } else if (renderMode == GfxRenderer::GRAYSCALE_LSB && bmpVal == 1) { - // Dark gray + // Differential LSB: mark dark gray pixels only + renderer.drawPixel(screenX, screenY, false); + } else if (renderMode == GfxRenderer::GRAY2_LSB && !(bmpVal & 1)) { + // Factory absolute LSB (BW RAM): set BW=1 for Black(0) and LightGrey(2) + // clearScreen(0x00) base; drawPixel(false) sets bit to 1 + renderer.drawPixel(screenX, screenY, false); + } else if (renderMode == GfxRenderer::GRAY2_MSB && bmpVal < 2) { + // Factory absolute MSB (RED RAM): set RED=1 for Black(0) and DarkGrey(1) + // clearScreen(0x00) base; drawPixel(false) sets bit to 1 renderer.drawPixel(screenX, screenY, false); } } @@ -206,7 +249,11 @@ static void renderCharImpl(const GfxRenderer& renderer, GfxRenderer::RenderMode const uint8_t bit_index = 7 - (pixelPosition & 7); if ((byte >> bit_index) & 1) { - renderer.drawPixel(screenX, screenY, pixelState); + // In GRAY2 modes the framebuffer convention is inverted vs BW: clearScreen(0x00) is + // background and drawPixel(false) marks active pixels. BW-convention callers pass + // pixelState=true for "black" — invert here so 1-bit UI glyphs stay visible. + const bool gray2 = renderMode == GfxRenderer::GRAY2_LSB || renderMode == GfxRenderer::GRAY2_MSB; + renderer.drawPixel(screenX, screenY, gray2 ? !pixelState : pixelState); } } } @@ -225,7 +272,7 @@ void GfxRenderer::drawPixel(const int x, const int y, const bool state) const { // Bounds checking against runtime panel dimensions if (phyX < 0 || phyX >= panelWidth || phyY < 0 || phyY >= panelHeight) { - LOG_ERR("GFX", "!! Outside range (%d, %d) -> (%d, %d)", x, y, phyX, phyY); + LOG_DBG("GFX", "!! Outside range (%d, %d) -> (%d, %d)", x, y, phyX, phyY); return; } @@ -235,11 +282,35 @@ void GfxRenderer::drawPixel(const int x, const int y, const bool state) const { if (state) { frameBuffer[byteIndex] &= ~(1 << bitPosition); // Clear bit + // Single-pass: erasing a pixel must also clear the MSB plane so UI white fills (e.g. button + // hint backgrounds drawn on top of a full-screen image) fully erase image bits from both + // planes. Without this, image pixels remain in RED RAM and bleed through white areas. + if (renderMode == GRAY2_LSB && secondaryFrameBuffer != nullptr) { + secondaryFrameBuffer[byteIndex] &= ~(1 << bitPosition); + } } else { frameBuffer[byteIndex] |= 1 << bitPosition; // Set bit + // Single-pass: all set-bit draws in GRAY2_LSB mode (1-bit UI elements, text, icons) are + // treated as fully black and mirrored to the MSB plane so they don't render as light gray. + // Image pixels skip drawPixel and go through drawPixelToBuffer directly (see drawBitmap), + // so this path is only hit by 1-bit rendering (renderChar, drawIcon, etc.). + if (renderMode == GRAY2_LSB && secondaryFrameBuffer != nullptr) { + secondaryFrameBuffer[byteIndex] |= 1 << bitPosition; + } } } +// Writes a single pixel (always state=false / set bit) to an arbitrary buffer using the same +// orientation transform as drawPixel. Used by single-pass grayscale to write the MSB plane +// simultaneously with the LSB plane during a single renderFn call. +void GfxRenderer::drawPixelToBuffer(uint8_t* buf, const int x, const int y) const { + int phyX = 0, phyY = 0; + rotateCoordinates(orientation, x, y, &phyX, &phyY, panelWidth, panelHeight); + if (phyX < 0 || phyX >= panelWidth || phyY < 0 || phyY >= panelHeight) return; + const uint32_t byteIndex = static_cast(phyY) * panelWidthBytes + (phyX / 8); + buf[byteIndex] |= 1 << (7 - (phyX % 8)); +} + int GfxRenderer::getTextWidth(const int fontId, const char* text, const EpdFontFamily::Style style) const { const auto fontIt = fontMap.find(fontId); if (fontIt == fontMap.end()) { @@ -321,19 +392,22 @@ void GfxRenderer::drawText(const int fontId, const int x, const int y, const cha void GfxRenderer::drawLine(int x1, int y1, int x2, int y2, const bool state) const { if (fontCacheManager_ && fontCacheManager_->isScanning()) return; + // In GRAY2 modes the framebuffer convention is inverted vs BW: clearScreen(0x00) is background + // and drawPixel(false) marks active pixels. BW-convention callers pass state=true for "black". + const bool s = (renderMode == GRAY2_LSB || renderMode == GRAY2_MSB) ? !state : state; if (x1 == x2) { if (y2 < y1) { std::swap(y1, y2); } for (int y = y1; y <= y2; y++) { - drawPixel(x1, y, state); + drawPixel(x1, y, s); } } else if (y1 == y2) { if (x2 < x1) { std::swap(x1, x2); } for (int x = x1; x <= x2; x++) { - drawPixel(x, y1, state); + drawPixel(x, y1, s); } } else { // Bresenham's line algorithm — integer arithmetic only @@ -346,7 +420,7 @@ void GfxRenderer::drawLine(int x1, int y1, int x2, int y2, const bool state) con int err = dx - dy; while (true) { - drawPixel(x1, y1, state); + drawPixel(x1, y1, s); if (x1 == x2 && y1 == y2) break; int e2 = 2 * err; if (e2 > -dy) { @@ -398,6 +472,8 @@ void GfxRenderer::drawArc(const int maxRadius, const int cx, const int cy, const const int outerRadiusSq = outerRadius * outerRadius; const int innerRadiusSq = innerRadius * innerRadius; + // Do NOT pre-invert state for GRAY2 here: fillRect→drawLine already handles the GRAY2 + // inversion. A pre-inversion here would double-invert (cancel out), rendering the wrong color. int xOuter = outerRadius; int xInner = innerRadius; @@ -500,22 +576,28 @@ void GfxRenderer::drawPixelDither(const int x, const int y) const template <> void GfxRenderer::drawPixelDither(const int x, const int y) const { - drawPixel(x, y, true); + const bool gray2 = renderMode == GRAY2_LSB || renderMode == GRAY2_MSB; + drawPixel(x, y, !gray2); } template <> void GfxRenderer::drawPixelDither(const int x, const int y) const { - drawPixel(x, y, false); + const bool gray2 = renderMode == GRAY2_LSB || renderMode == GRAY2_MSB; + drawPixel(x, y, gray2); } template <> void GfxRenderer::drawPixelDither(const int x, const int y) const { - drawPixel(x, y, x % 2 == 0 && y % 2 == 0); + const bool pix = x % 2 == 0 && y % 2 == 0; + const bool gray2 = renderMode == GRAY2_LSB || renderMode == GRAY2_MSB; + drawPixel(x, y, gray2 ? !pix : pix); } template <> void GfxRenderer::drawPixelDither(const int x, const int y) const { - drawPixel(x, y, (x + y) % 2 == 0); // TODO: maybe find a better pattern? + const bool pix = (x + y) % 2 == 0; // TODO: maybe find a better pattern? + const bool gray2 = renderMode == GRAY2_LSB || renderMode == GRAY2_MSB; + drawPixel(x, y, gray2 ? !pix : pix); } void GfxRenderer::fillRectDither(const int x, const int y, const int width, const int height, Color color) const { @@ -713,13 +795,12 @@ void GfxRenderer::drawIcon(const uint8_t bitmap[], const int x, const int y, con display.drawImageTransparent(bitmap, y, getScreenWidth() - width - x, height, width); } -void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, const int maxWidth, const int maxHeight, +bool GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, const int maxWidth, const int maxHeight, const float cropX, const float cropY) const { - if (fontCacheManager_ && fontCacheManager_->isScanning()) return; + if (fontCacheManager_ && fontCacheManager_->isScanning()) return false; // For 1-bit bitmaps, use optimized 1-bit rendering path (no crop support for 1-bit) if (bitmap.is1Bit() && cropX == 0.0f && cropY == 0.0f) { - drawBitmap1Bit(bitmap, x, y, maxWidth, maxHeight); - return; + return drawBitmap1Bit(bitmap, x, y, maxWidth, maxHeight); } float scale = 1.0f; @@ -761,15 +842,91 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con LOG_ERR("GFX", "!! Failed to allocate BMP row buffers"); free(outputRow); free(rowBytes); - return; + return false; + } + + // --- Pre-compute everything that is constant for the entire render --- + + // Orientation: collapse into 6 integer coefficients (same approach as DirectPixelWriter). + // phyX = phyXBase + screenY*phyXStepY + screenX*phyXStepX + // phyY = phyYBase + screenY*phyYStepY + screenX*phyYStepX + int phyXBase, phyYBase, phyXStepX, phyYStepX, phyXStepY, phyYStepY; + switch (orientation) { + case Portrait: + phyXBase = 0; + phyYBase = panelHeight - 1; + phyXStepX = 0; + phyYStepX = -1; + phyXStepY = 1; + phyYStepY = 0; + break; + case LandscapeClockwise: + phyXBase = panelWidth - 1; + phyYBase = panelHeight - 1; + phyXStepX = -1; + phyYStepX = 0; + phyXStepY = 0; + phyYStepY = -1; + break; + case PortraitInverted: + phyXBase = panelWidth - 1; + phyYBase = 0; + phyXStepX = 0; + phyYStepX = 1; + phyXStepY = -1; + phyYStepY = 0; + break; + case LandscapeCounterClockwise: + default: + phyXBase = 0; + phyYBase = 0; + phyXStepX = 1; + phyYStepX = 0; + phyXStepY = 0; + phyYStepY = 1; + break; + } + + // Per-val write masks (val is 2-bit: 0=black,1=darkGrey,2=lightGrey,3=white). + // Bit i of the mask is set when val==i should trigger a write. + // Evaluated once here; zero branch overhead inside the pixel loop. + uint8_t writeFbMask = 0; // which val values write to frameBuffer + uint8_t writeFb2Mask = 0; // which val values write to secondaryFrameBuffer (GRAY2_LSB single-pass only) + bool fbClearBit = false; // true = clear bit (BW black); false = set bit (all gray modes) + uint8_t* const fb2 = secondaryFrameBuffer; + + switch (renderMode) { + case BW: + writeFbMask = 0x3; + fbClearBit = true; + break; // val 0,1 (black+darkGrey) + case GRAYSCALE_MSB: + writeFbMask = 0x6; + break; // val 1,2 + case GRAYSCALE_LSB: + writeFbMask = 0x2; + break; // val 1 + case GRAY2_LSB: + writeFbMask = 0x5; // val 0,2 (LSB plane) + if (fb2) writeFb2Mask = 0x3; + break; // val 0,1 (MSB plane) + case GRAY2_MSB: + writeFbMask = 0x3; + break; // val 0,1 + default: + break; } + // Pre-computed for the unscaled incremental inner loop: stride through the physical Y axis per logical X step. + const int32_t byteIdxYStep = static_cast(phyYStepX) * static_cast(panelWidthBytes); + + // --- Outer row loop --- for (int bmpY = 0; bmpY < (bitmap.getHeight() - cropPixY); bmpY++) { // The BMP's (0, 0) is the bottom-left corner (if the height is positive, top-left if negative). // Screen's (0, 0) is the top-left corner. int screenY = -cropPixY + (bitmap.isTopDown() ? bmpY : bitmap.getHeight() - 1 - bmpY); if (isScaled) { - screenY = std::floor(screenY * scale); + screenY = static_cast(std::floor(screenY * scale)); } screenY += y; // the offset should not be scaled if (screenY >= getScreenHeight()) { @@ -780,7 +937,7 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con LOG_ERR("GFX", "Failed to read row %d from bitmap", bmpY); free(outputRow); free(rowBytes); - return; + return false; } if (screenY < 0) { @@ -792,36 +949,73 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con continue; } - for (int bmpX = cropPixX; bmpX < bitmap.getWidth() - cropPixX; bmpX++) { - int screenX = bmpX - cropPixX; - if (isScaled) { - screenX = std::floor(screenX * scale); - } - screenX += x; // the offset should not be scaled - if (screenX >= getScreenWidth()) { - break; - } - if (screenX < 0) { - continue; - } - - const uint8_t val = outputRow[bmpX / 4] >> (6 - ((bmpX * 2) % 8)) & 0x3; + // Pre-compute the Y-dependent portion of the physical coordinate transform once per row. + const int rowPhyXBase = phyXBase + screenY * phyXStepY; + const int rowPhyYBase = phyYBase + screenY * phyYStepY; - if (renderMode == BW && val < 3) { - drawPixel(screenX, screenY); - } else if (renderMode == GRAYSCALE_MSB && (val == 1 || val == 2)) { - drawPixel(screenX, screenY, false); - } else if (renderMode == GRAYSCALE_LSB && val == 1) { - drawPixel(screenX, screenY, false); + if (isScaled) { + // Scaled path: float accumulator replaces per-column multiply. + // Integer coordinate multiplies remain but are rare (scaled images only). + float screenXF = static_cast(x); + for (int bmpX = cropPixX; bmpX < bitmap.getWidth() - cropPixX; bmpX++, screenXF += scale) { + const int screenX = static_cast(screenXF); + if (screenX >= getScreenWidth()) break; + if (screenX < 0) continue; + + const uint8_t val = (outputRow[bmpX >> 2] >> (6 - (bmpX & 3) * 2)) & 0x3; + const bool doFb = (writeFbMask >> val) & 1; + const bool doFb2 = (writeFb2Mask >> val) & 1; + if (!doFb && !doFb2) continue; + + const int phyX = rowPhyXBase + screenX * phyXStepX; + const int phyY = rowPhyYBase + screenX * phyYStepX; + const uint32_t byteIdx = static_cast(phyY) * panelWidthBytes + (phyX >> 3); + const uint8_t bitMask = 1 << (7 - (phyX & 7)); + if (doFb) { + if (fbClearBit) + frameBuffer[byteIdx] &= ~bitMask; + else + frameBuffer[byteIdx] |= bitMask; + } + if (doFb2) fb2[byteIdx] |= bitMask; + } + } else { + // Unscaled path: fully incremental — zero multiplies, zero float in the pixel loop. + // curPhyX and curByteIdxY start at screenX=x (when bmpX=cropPixX) and advance by + // phyXStepX / byteIdxYStep per column. The for-increment fires on every iteration + // including continue, so running state stays in sync with bmpX even for skipped pixels. + int curPhyX = rowPhyXBase + x * phyXStepX; + int32_t curByteIdx = static_cast(rowPhyYBase + x * phyYStepX) * static_cast(panelWidthBytes); + for (int bmpX = cropPixX; bmpX < bitmap.getWidth() - cropPixX; + bmpX++, curPhyX += phyXStepX, curByteIdx += byteIdxYStep) { + const int screenX = bmpX - cropPixX + x; + if (screenX >= getScreenWidth()) break; + if (screenX < 0) continue; + + const uint8_t val = (outputRow[bmpX >> 2] >> (6 - (bmpX & 3) * 2)) & 0x3; + const bool doFb = (writeFbMask >> val) & 1; + const bool doFb2 = (writeFb2Mask >> val) & 1; + if (!doFb && !doFb2) continue; + + const uint32_t byteIdx = static_cast(curByteIdx) + static_cast(curPhyX >> 3); + const uint8_t bitMask = 1 << (7 - (curPhyX & 7)); + if (doFb) { + if (fbClearBit) + frameBuffer[byteIdx] &= ~bitMask; + else + frameBuffer[byteIdx] |= bitMask; + } + if (doFb2) fb2[byteIdx] |= bitMask; } } } free(outputRow); free(rowBytes); + return true; } -void GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y, const int maxWidth, +bool GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y, const int maxWidth, const int maxHeight) const { float scale = 1.0f; bool isScaled = false; @@ -843,7 +1037,7 @@ void GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y, LOG_ERR("GFX", "!! Failed to allocate 1-bit BMP row buffers"); free(outputRow); free(rowBytes); - return; + return false; } for (int bmpY = 0; bmpY < bitmap.getHeight(); bmpY++) { @@ -852,7 +1046,7 @@ void GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y, LOG_ERR("GFX", "Failed to read row %d from 1-bit bitmap", bmpY); free(outputRow); free(rowBytes); - return; + return false; } // Calculate screen Y based on whether BMP is top-down or bottom-up @@ -877,10 +1071,13 @@ void GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y, // Get 2-bit value (result of readNextRow quantization) const uint8_t val = outputRow[bmpX / 4] >> (6 - ((bmpX * 2) % 8)) & 0x3; - // For 1-bit source: 0 or 1 -> map to black (0,1,2) or white (3) - // val < 3 means black pixel (draw it) + // For 1-bit source: val < 3 = black, val == 3 = white if (val < 3) { - drawPixel(screenX, screenY, true); + if (renderMode == GRAY2_LSB || renderMode == GRAY2_MSB) { + drawPixel(screenX, screenY, false); + } else { + drawPixel(screenX, screenY, true); + } } // White pixels (val == 3) are not drawn (leave background) } @@ -888,6 +1085,7 @@ void GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y, free(outputRow); free(rowBytes); + return true; } void GfxRenderer::fillPolygon(const int* xPoints, const int* yPoints, int numPoints, bool state) const { @@ -958,6 +1156,11 @@ void GfxRenderer::clearScreen(const uint8_t color) const { display.clearScreen(color); } +void GfxRenderer::setScreenshotHook(ScreenshotHook hook, void* ctx) { + screenshotHook = hook; + screenshotHookCtx = ctx; +} + void GfxRenderer::invertScreen() const { for (uint32_t i = 0; i < frameBufferSize; i++) { frameBuffer[i] = ~frameBuffer[i]; @@ -967,7 +1170,28 @@ void GfxRenderer::invertScreen() const { void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const { auto elapsed = millis() - start_ms; LOG_DBG("GFX", "Time = %lu ms from clearScreen to displayBuffer", elapsed); - display.displayBuffer(refreshMode, fadingFix); + // After a factory LUT render, RED RAM still contains the grayscale MSB plane. + // Promote the first normal FAST refresh to HALF so both RAM banks are rebased + // before differential updates resume. + const bool afterFactoryLut = displayState == DisplayState::FactoryLut; + const auto effectiveRefreshMode = + afterFactoryLut && refreshMode == HalDisplay::FAST_REFRESH ? HalDisplay::HALF_REFRESH : refreshMode; + display.displayBuffer(effectiveRefreshMode, fadingFix); + displayState = DisplayState::BW; +} + +void GfxRenderer::displayBufferPrecondition(uint8_t color) const { + display.displayBufferPrecondition(color); + displayState = DisplayState::BW; +} + +void GfxRenderer::displayGrayBuffer(const unsigned char* lut, const bool factoryMode) const { + display.displayGrayBuffer(fadingFix, lut, factoryMode); + if (factoryMode) { + displayState = DisplayState::FactoryLut; + } else { + displayState = DisplayState::BW; + } } std::string GfxRenderer::truncatedText(const int fontId, const char* text, const int maxWidth, @@ -1274,7 +1498,252 @@ void GfxRenderer::copyGrayscaleLsbBuffers() const { display.copyGrayscaleLsbBuff void GfxRenderer::copyGrayscaleMsbBuffers() const { display.copyGrayscaleMsbBuffers(frameBuffer); } -void GfxRenderer::displayGrayBuffer() const { display.displayGrayBuffer(fadingFix); } +void GfxRenderer::renderGrayscale(GrayscaleDriveMode mode, void (*renderFn)(const GfxRenderer&, const void*), + const void* ctx, void (*preFlashOverlayFn)(const GfxRenderer&, const void*), + const void* preFlashCtx) { + const auto spec = resolveGrayscaleDrive(mode); + + if (spec.factoryMode) { + clearScreen(); + if (preFlashOverlayFn) preFlashOverlayFn(*this, preFlashCtx); + displayBuffer(HalDisplay::HALF_REFRESH); + } + + g_differentialQuantize = spec.differentialQuantize; + + clearScreen(0x00); + setRenderMode(spec.lsbMode); + renderFn(*this, ctx); + + uint8_t* lsbCopy = nullptr; + if (screenshotHook && spec.factoryMode) { + lsbCopy = static_cast(malloc(frameBufferSize)); + if (lsbCopy) { + memcpy(lsbCopy, frameBuffer, frameBufferSize); + } else { + // Allocation failed — disarm the one-shot hook so it doesn't fire on a future render. + screenshotHook = nullptr; + screenshotHookCtx = nullptr; + } + } + + // Match stock SPI order for factory mode: setCustomLUT + Border BEFORE the + // RAM writes. Differential path skips Setup (handled by displayGrayBuffer at + // the end). See docs/v559-disassembly-findings.md Difference #4. + if (spec.factoryMode) { + display.displayGrayBufferFactorySetup(spec.lut); + } + copyGrayscaleLsbBuffers(); + + clearScreen(0x00); + setRenderMode(spec.msbMode); + renderFn(*this, ctx); + copyGrayscaleMsbBuffers(); + + // Fire hook: LSB = lsbCopy, MSB = frameBuffer (still holds second-pass data). + if (screenshotHook && spec.factoryMode && lsbCopy) { + screenshotHook(lsbCopy, frameBuffer, panelWidth, panelHeight, screenshotHookCtx); + screenshotHook = nullptr; + screenshotHookCtx = nullptr; + } + if (lsbCopy) { + free(lsbCopy); + lsbCopy = nullptr; + } + + g_differentialQuantize = false; + + // Factory mode: differential path keeps the original combined call. Factory + // path uses the split SDK API so the LUT load happens BEFORE RAM writes — + // matches stock V5.5.9 SPI order. Same pattern as renderGrayscaleSinglePass. + if (spec.factoryMode) { + display.displayGrayBufferFactoryActivate(); + displayState = DisplayState::FactoryLut; + } else { + displayGrayBuffer(spec.lut, spec.factoryMode); + } + // Suppress the SDK's automatic grayscaleRevert on the next BW page turn. + // Caller is responsible for cleanup: restoreBwBuffer rebases RED RAM, and + // displayBuffer promotes the first post-factory FAST refresh to HALF. + display.clearGrayscaleModeFlag(); + setRenderMode(BW); +} + +void GfxRenderer::renderGrayscaleSinglePass(GrayscaleDriveMode mode, void (*renderFn)(const GfxRenderer&, const void*), + const void* ctx, void (*preFlashOverlayFn)(const GfxRenderer&, const void*), + const void* preFlashCtx, const HalDisplay::RefreshMode preFlashRefreshMode, + const uint8_t preFlashPasses) { + const auto spec = resolveGrayscaleDrive(mode); + + if (spec.factoryMode && preFlashPasses > 0) { + for (uint8_t pass = 0; pass < preFlashPasses; pass++) { + clearScreen(); + if (pass == 0 && preFlashOverlayFn) preFlashOverlayFn(*this, preFlashCtx); + displayBuffer(preFlashRefreshMode); + } + } + + g_differentialQuantize = spec.differentialQuantize; + + auto* secBuf = static_cast(malloc(frameBufferSize)); + if (!secBuf) { + LOG_ERR("GFX", "renderGrayscaleSinglePass: malloc failed (%lu bytes), falling back to two-pass", + static_cast(frameBufferSize)); + screenshotHook = nullptr; + screenshotHookCtx = nullptr; + clearScreen(0x00); + setRenderMode(spec.lsbMode); + renderFn(*this, ctx); + copyGrayscaleLsbBuffers(); + clearScreen(0x00); + setRenderMode(spec.msbMode); + renderFn(*this, ctx); + copyGrayscaleMsbBuffers(); + g_differentialQuantize = false; + displayGrayBuffer(spec.lut, spec.factoryMode); + // See note in renderGrayscale(). + display.clearGrayscaleModeFlag(); + setRenderMode(BW); + return; + } + memset(secBuf, 0x00, frameBufferSize); + secondaryFrameBuffer = secBuf; + + // Single pass: renderFn writes LSB plane to frameBuffer and MSB plane to secondaryFrameBuffer. + clearScreen(0x00); + setRenderMode(spec.lsbMode); + renderFn(*this, ctx); + + // One-shot screenshot hook: fired while both planes are still in software, before either is + // pushed to the controller. frameBuffer = LSB plane, secBuf = MSB plane. + if (screenshotHook && spec.factoryMode) { + screenshotHook(frameBuffer, secBuf, panelWidth, panelHeight, screenshotHookCtx); + screenshotHook = nullptr; + screenshotHookCtx = nullptr; + } + + // EXPERIMENT: match stock V5.5.9 SPI order: LUT load → RAM writes → activate. + // For factory mode, use the split SDK API so RAM data is written AFTER setCustomLUT + // and Border Waveform, BEFORE the MASTER_ACTIVATION. See docs/v559-disassembly-findings.md. + if (spec.factoryMode) { + display.displayGrayBufferFactorySetup(spec.lut); + copyGrayscaleLsbBuffers(); + memcpy(frameBuffer, secBuf, frameBufferSize); + copyGrayscaleMsbBuffers(); + free(secBuf); + secondaryFrameBuffer = nullptr; + g_differentialQuantize = false; + display.displayGrayBufferFactoryActivate(); + displayState = DisplayState::FactoryLut; + display.clearGrayscaleModeFlag(); + setRenderMode(BW); + return; + } + + // Differential path: original order (RAM writes then combined displayGrayBuffer). + copyGrayscaleLsbBuffers(); + memcpy(frameBuffer, secBuf, frameBufferSize); + copyGrayscaleMsbBuffers(); + + free(secBuf); + secondaryFrameBuffer = nullptr; + + g_differentialQuantize = false; + displayGrayBuffer(spec.lut, spec.factoryMode); + display.clearGrayscaleModeFlag(); + setRenderMode(BW); +} + +void GfxRenderer::displayXtchPlanes(const uint8_t* plane1, const uint8_t* plane2, const uint16_t pageWidth, + const uint16_t pageHeight, RenderHook overlayFn, const void* overlayCtx, + GrayscaleDriveMode mode, const bool preFlash, + const HalDisplay::RefreshMode preFlashRefreshMode, const uint8_t preFlashPasses) { + const size_t colBytes = (pageHeight + 7) / 8; + const uint16_t fbStride = panelWidthBytes; + + // Bounds check: each column c writes colBytes bytes at frameBuffer[c * fbStride]. + // Requires pageWidth <= panelHeight and colBytes <= panelWidthBytes. + if (pageWidth > static_cast(panelHeight) || colBytes > panelWidthBytes) { + LOG_ERR("GFX", "displayXtchPlanes: page %ux%u overflows framebuffer (%ux%u)", pageWidth, pageHeight, panelHeight, + panelWidth); + if (screenshotHook) { + screenshotHook = nullptr; + screenshotHookCtx = nullptr; + } + return; + } + + if (preFlash && preFlashPasses > 0) { + for (uint8_t pass = 0; pass < preFlashPasses; pass++) { + clearScreen(); + displayBuffer(preFlashRefreshMode); + } + } + + // Match stock V5.5.9 SPI order: setCustomLUT + Border BEFORE RAM writes. + // Resolve drive spec early so we can use Setup/Activate. See + // docs/v559-disassembly-findings.md Difference #4. + const auto spec = resolveGrayscaleDrive(mode); + display.displayGrayBufferFactorySetup(spec.lut); + + // Pass 1: plane1 (MSB) → BW RAM via copyGrayscaleLsbBuffers. + clearScreen(0x00); + for (uint16_t c = 0; c < pageWidth; c++) { + const uint8_t* srcCol = plane1 + static_cast(c) * colBytes; + uint8_t* dstRow = frameBuffer + static_cast(c) * fbStride; + for (uint16_t b = 0; b < colBytes; b++) { + dstRow[b] = srcCol[b]; + } + } + setRenderMode(GRAY2_LSB); + if (overlayFn) overlayFn(*this, overlayCtx); + + copyGrayscaleLsbBuffers(); + + // Pass 2: plane2 (LSB) → RED RAM via copyGrayscaleMsbBuffers. + clearScreen(0x00); + for (uint16_t c = 0; c < pageWidth; c++) { + const uint8_t* srcCol = plane2 + static_cast(c) * colBytes; + uint8_t* dstRow = frameBuffer + static_cast(c) * fbStride; + for (uint16_t b = 0; b < colBytes; b++) { + dstRow[b] = srcCol[b]; + } + } + setRenderMode(GRAY2_MSB); + if (overlayFn) overlayFn(*this, overlayCtx); + copyGrayscaleMsbBuffers(); + + // Fire hook: plane1 input IS already in framebuffer format (colBytes == fbStride for portrait + // pages), so pass it directly — no extra malloc needed. plane2 data is now in frameBuffer. + if (screenshotHook) { + screenshotHook(plane1, frameBuffer, panelWidth, panelHeight, screenshotHookCtx); + screenshotHook = nullptr; + screenshotHookCtx = nullptr; + } + + display.displayGrayBufferFactoryActivate(); + displayState = DisplayState::FactoryLut; + setRenderMode(BW); +} + +void GfxRenderer::displayXtcBwPage(const uint8_t* pageBuffer, const uint16_t pageWidth, const uint16_t pageHeight, + const HalDisplay::RefreshMode refreshMode, RenderHook overlayFn, + const void* overlayCtx) { + const size_t srcRowBytes = (pageWidth + 7) / 8; + + // 1-bit content has no AA — render as plain BW and use the standard differential fast-refresh + // LUT (same as menus/EPUB). No factory LUT needed; avoids all GRAY2 convention complexity. + clearScreen(); + for (uint16_t y = 0; y < pageHeight; y++) { + for (uint16_t x = 0; x < pageWidth; x++) { + if (!((pageBuffer[y * srcRowBytes + x / 8] >> (7 - (x % 8))) & 1)) { + drawPixel(x, y, true); + } + } + } + if (overlayFn) overlayFn(*this, overlayCtx); + displayBuffer(refreshMode); +} void GfxRenderer::freeBwBufferChunks() { for (auto& bwBufferChunk : bwBufferChunks) { diff --git a/lib/GfxRenderer/GfxRenderer.h b/lib/GfxRenderer/GfxRenderer.h index fd9b96dcc1..1c7197deda 100644 --- a/lib/GfxRenderer/GfxRenderer.h +++ b/lib/GfxRenderer/GfxRenderer.h @@ -19,7 +19,13 @@ enum Color : uint8_t { Clear = 0x00, White = 0x01, LightGray = 0x05, DarkGray = class GfxRenderer { public: - enum RenderMode { BW, GRAYSCALE_LSB, GRAYSCALE_MSB }; + enum RenderMode { + BW, // 1-bit black/white + GRAYSCALE_LSB, // Differential gray: mark pixels for LSB plane (clearScreen(0x00) + drawPixel(false)) + GRAYSCALE_MSB, // Differential gray: mark pixels for MSB plane (clearScreen(0x00) + drawPixel(false)) + GRAY2_LSB, // Factory absolute gray: encode BW RAM = bit0 (clearScreen(0x00) + drawPixel(false)) + GRAY2_MSB, // Factory absolute gray: encode RED RAM = bit1 (clearScreen(0x00) + drawPixel(false)) + }; // Logical screen orientation from the perspective of callers enum Orientation { @@ -29,6 +35,29 @@ class GfxRenderer { LandscapeCounterClockwise // 800x480 logical coordinates, native panel orientation }; + // Selects LUT and pixel-plane encoding for renderGrayscale() / renderGrayscaleSinglePass() / + // displayXtchPlanes(). Pre-flash policy is per-call, not part of the drive mode. + enum class GrayscaleDriveMode { + FactoryFast, // Factory absolute 2-bit (lut_factory_fast) + FactoryQuality, // Factory absolute 2-bit (lut_factory_quality) + Differential, // Differential 2-bit overlay (no LUT); requires prior BW state + }; + + // Display state — tracks whether the physical display was last updated via a factory LUT render. + // BW: frameBuffer mirrors the display (menus, EPUB reader). + // FactoryLut: display holds a grayscale image; frameBuffer has been reset to white by + // cleanupGrayscaleWithFrameBuffer() and no longer represents what is visually shown. + enum class DisplayState { BW, FactoryLut }; + + // One-shot hook fired in renderGrayscaleSinglePass after renderFn() writes both planes + // but before they are pushed to the controller. At that moment: + // lsbPlane = frameBuffer (LSB / BW RAM plane) + // msbPlane = secondaryFrameBuffer (MSB / RED RAM plane) + // Hook is cleared automatically after firing. + using ScreenshotHook = void (*)(const uint8_t* lsbPlane, const uint8_t* msbPlane, int physWidth, int physHeight, + void* ctx); + using RenderHook = void (*)(const GfxRenderer&, const void*); + private: static constexpr size_t BW_BUFFER_CHUNK_SIZE = 8000; // 8KB chunks to allow for non-contiguous memory @@ -37,12 +66,16 @@ class GfxRenderer { Orientation orientation; bool fadingFix; uint8_t* frameBuffer = nullptr; + uint8_t* secondaryFrameBuffer = nullptr; // MSB plane buffer for single-pass grayscale decode uint16_t panelWidth = HalDisplay::DISPLAY_WIDTH; uint16_t panelHeight = HalDisplay::DISPLAY_HEIGHT; uint16_t panelWidthBytes = HalDisplay::DISPLAY_WIDTH_BYTES; uint32_t frameBufferSize = HalDisplay::BUFFER_SIZE; std::vector bwBufferChunks; std::map fontMap; + mutable DisplayState displayState = DisplayState::BW; + ScreenshotHook screenshotHook = nullptr; + void* screenshotHookCtx = nullptr; // Mutable because ensureSdCardFontReady() is const (called from layout code // that holds a const GfxRenderer&) but triggers SD card reads and heap // allocation inside the SdCardFont objects. Same pragmatic compromise as @@ -61,6 +94,7 @@ class GfxRenderer { void drawPixelDither(int x, int y) const; template void fillArc(int maxRadius, int cx, int cy, int xDir, int yDir) const; + void drawPixelToBuffer(uint8_t* buf, int x, int y) const; public: explicit GfxRenderer(HalDisplay& halDisplay) @@ -94,6 +128,8 @@ class GfxRenderer { // (which holds a const GfxRenderer&) before measuring word widths. Safe to call on non-SD fonts (no-op). // styleMask: bitmask of styles to prepare (bit 0=regular, 1=bold, 2=italic, 3=bold-italic). void ensureSdCardFontReady(int fontId, const char* utf8Text, uint8_t styleMask = 0x0F) const; + void ensureSdCardFontReady(int fontId, const std::vector& words, bool includeHyphen, + uint8_t styleMask = 0x0F) const; // Orientation control (affects logical width/height and coordinate transforms) void setOrientation(const Orientation o) { orientation = o; } @@ -106,6 +142,10 @@ class GfxRenderer { int getScreenWidth() const; int getScreenHeight() const; void displayBuffer(HalDisplay::RefreshMode refreshMode = HalDisplay::FAST_REFRESH) const; + // Stock-V5.5.9 byte-match precondition flash (black or white). Fires CTRL2=0xF7 + // (full power-cycle, rails off after) and skips SINGLE_BUFFER_MODE post-RED-sync. + // See docs/v559-disassembly-findings.md. + void displayBufferPrecondition(uint8_t color) const; // EXPERIMENTAL: Windowed update - display only a rectangular region // void displayWindow(int x, int y, int width, int height) const; void invertScreen() const; @@ -130,9 +170,9 @@ class GfxRenderer { bool roundBottomLeft, bool roundBottomRight, Color color) const; void drawImage(const uint8_t bitmap[], int x, int y, int width, int height) const; void drawIcon(const uint8_t bitmap[], int x, int y, int width, int height) const; - void drawBitmap(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight, float cropX = 0, + bool drawBitmap(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight, float cropX = 0, float cropY = 0) const; - void drawBitmap1Bit(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight) const; + bool drawBitmap1Bit(const Bitmap& bitmap, int x, int y, int maxWidth, int maxHeight) const; void fillPolygon(const int* xPoints, const int* yPoints, int numPoints, bool state = true) const; // Text @@ -164,21 +204,61 @@ class GfxRenderer { EpdFontFamily::Style style = EpdFontFamily::REGULAR) const; int getTextHeight(int fontId) const; + DisplayState getDisplayState() const { return displayState; } + void setScreenshotHook(ScreenshotHook hook, void* ctx); + // Grayscale functions void setRenderMode(const RenderMode mode) { this->renderMode = mode; } RenderMode getRenderMode() const { return renderMode; } void copyGrayscaleLsbBuffers() const; void copyGrayscaleMsbBuffers() const; - void displayGrayBuffer() const; + void displayGrayBuffer(const unsigned char* lut = nullptr, bool factoryMode = false) const; bool storeBwBuffer(); // Returns true if buffer was stored successfully void restoreBwBuffer(); // Restore and free the stored buffer void cleanupGrayscaleWithFrameBuffer() const; + // Two-pass grayscale render. renderFn is called twice: once with the LSB render mode set + // (writes BW RAM plane), then with the MSB mode set (writes RED RAM plane). The method + // handles pre-flash (FactoryFast only), clearScreen, setRenderMode, buffer copies, + // displayGrayBuffer, and resets renderMode to BW on completion. + // storeBwBuffer / restoreBwBuffer remain the caller's responsibility. + // preFlashOverlayFn (optional): called after clearScreen() but before the pre-flash displayBuffer(), + // allowing callers to draw a loading indicator that appears during the pre-flash without an extra refresh. + void renderGrayscale(GrayscaleDriveMode mode, void (*renderFn)(const GfxRenderer&, const void*), const void* ctx, + void (*preFlashOverlayFn)(const GfxRenderer&, const void*) = nullptr, + const void* preFlashCtx = nullptr); + // Single-pass variant: calls renderFn once in GRAY2_LSB mode while simultaneously writing + // the MSB plane to a secondary buffer. Cuts SD card reads from 2 to 1 for file-backed renders. + // Falls back to two-pass on secondary buffer allocation failure. Factory modes pre-flash to + // white with HALF_REFRESH by default. preFlashPasses=0 skips the internal pre-flash so + // callers can run a custom conditioning sequence first. + void renderGrayscaleSinglePass(GrayscaleDriveMode mode, void (*renderFn)(const GfxRenderer&, const void*), + const void* ctx, void (*preFlashOverlayFn)(const GfxRenderer&, const void*) = nullptr, + const void* preFlashCtx = nullptr, + HalDisplay::RefreshMode preFlashRefreshMode = HalDisplay::HALF_REFRESH, + uint8_t preFlashPasses = 1); + + // Direct 2-bit XTCH plane blit using factory LUT. Caller supplies the two decoded bit planes + // (plane1 = BW RAM / LSB, plane2 = RED RAM / MSB) in column-major order matching XTCH encoding. + // Handles optional pre-flash, both RAM writes, factory LUT fire, and BW controller sync internally. + // mode selects the factory LUT: FactoryFast (default) or FactoryQuality; Differential is invalid here. + void displayXtchPlanes(const uint8_t* plane1, const uint8_t* plane2, uint16_t pageWidth, uint16_t pageHeight, + RenderHook overlayFn = nullptr, const void* overlayCtx = nullptr, + GrayscaleDriveMode mode = GrayscaleDriveMode::FactoryFast, bool preFlash = false, + HalDisplay::RefreshMode preFlashRefreshMode = HalDisplay::HALF_REFRESH, + uint8_t preFlashPasses = 1); + + // 1-bit XTC page via the same grayscale LUT pipeline. Row-major pageBuffer (XTC: 0=black, 1=white). + // BW and RED RAM receive identical data since there are no intermediate gray levels. + void displayXtcBwPage(const uint8_t* pageBuffer, uint16_t pageWidth, uint16_t pageHeight, + HalDisplay::RefreshMode refreshMode = HalDisplay::FAST_REFRESH, RenderHook overlayFn = nullptr, + const void* overlayCtx = nullptr); // Font helpers const uint8_t* getGlyphBitmap(const EpdFontData* fontData, const EpdGlyph* glyph) const; // Low level functions uint8_t* getFrameBuffer() const; + uint8_t* getSecondaryFrameBuffer() const { return secondaryFrameBuffer; } size_t getBufferSize() const; uint16_t getDisplayWidth() const { return panelWidth; } uint16_t getDisplayHeight() const { return panelHeight; } diff --git a/lib/I18n/translations/belarusian.yaml b/lib/I18n/translations/belarusian.yaml index f854cae866..e907950d26 100644 --- a/lib/I18n/translations/belarusian.yaml +++ b/lib/I18n/translations/belarusian.yaml @@ -143,6 +143,7 @@ STR_ALIGN_LEFT: "Па левым краі" STR_CENTER: "Па цэнтры" STR_ALIGN_RIGHT: "Па правым краі" STR_MIN_1: "1 хв" +STR_MIN_3: "3 хв" STR_MIN_5: "5 хв" STR_MIN_10: "10 хв" STR_MIN_15: "15 хв" @@ -267,6 +268,7 @@ STR_IMAGES_DISPLAY: "Паказваць" STR_IMAGES_PLACEHOLDER: "Запаўняльнік" STR_IMAGES_SUPPRESS: "Хаваць" STR_SHOW_HIDDEN_FILES: "Паказваць схаваныя файлы" +STR_MOVE_FINISHED_TO_READ: "Перамяшчаць прачытаныя кнігі ў тэчку Read" STR_SELECTED: "Выбрана" STR_SHOW: "Паказаць" STR_HIDE: "Схаваць" diff --git a/lib/I18n/translations/catalan.yaml b/lib/I18n/translations/catalan.yaml index 40b02ea04b..0961626c02 100644 --- a/lib/I18n/translations/catalan.yaml +++ b/lib/I18n/translations/catalan.yaml @@ -85,6 +85,7 @@ STR_PARA_ALIGNMENT: "Alineació de paràgrafs del lector" STR_HYPHENATION: "Partició de mots" STR_TIME_TO_SLEEP: "Temps per entrar en repòs" STR_SHOW_HIDDEN_FILES: "Mostra fitxers ocults" +STR_MOVE_FINISHED_TO_READ: "Mou els llibres acabats a la carpeta Read" STR_REFRESH_FREQ: "Freqüència de refresc" STR_KOREADER_SYNC: "Sincronització del KOReader" STR_CHECK_UPDATES: "Comprova si hi ha actualitzacions" @@ -151,6 +152,7 @@ STR_ALIGN_LEFT: "Esquerra" STR_CENTER: "Centre" STR_ALIGN_RIGHT: "Dreta" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" diff --git a/lib/I18n/translations/czech.yaml b/lib/I18n/translations/czech.yaml index 379bd69077..e03ea8afc5 100644 --- a/lib/I18n/translations/czech.yaml +++ b/lib/I18n/translations/czech.yaml @@ -80,6 +80,7 @@ STR_SCREEN_MARGIN: "Okraj obrazovky čtečky" STR_PARA_ALIGNMENT: "Zarovnání odstavců čtečky" STR_HYPHENATION: "Dělení slov" STR_TIME_TO_SLEEP: "Čas do uspání" +STR_MOVE_FINISHED_TO_READ: "Přesunout přečtené knihy do složky Read" STR_REFRESH_FREQ: "Frekvence obnovení" STR_KOREADER_SYNC: "KOReaderu Sync" STR_CHECK_UPDATES: "Zkontrolovat aktualizace" @@ -146,6 +147,7 @@ STR_ALIGN_LEFT: "Vlevo" STR_CENTER: "Na střed" STR_ALIGN_RIGHT: "Vpravo" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" diff --git a/lib/I18n/translations/danish.yaml b/lib/I18n/translations/danish.yaml index 9a1b979da8..56f3a05ff9 100644 --- a/lib/I18n/translations/danish.yaml +++ b/lib/I18n/translations/danish.yaml @@ -85,6 +85,7 @@ STR_PARA_ALIGNMENT: "Afsnitsjustering" STR_HYPHENATION: "Orddeling" STR_TIME_TO_SLEEP: "Tid til hvile" STR_SHOW_HIDDEN_FILES: "Vis skjulte filer" +STR_MOVE_FINISHED_TO_READ: "Flyt læste bøger til Read-mappen" STR_REFRESH_FREQ: "Opdateringsfrekvens" STR_KOREADER_SYNC: "KOReader Sync" STR_CHECK_UPDATES: "Søg efter opdateringer" @@ -151,6 +152,7 @@ STR_ALIGN_LEFT: "Venstre" STR_CENTER: "Centreret" STR_ALIGN_RIGHT: "Højre" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" diff --git a/lib/I18n/translations/dutch.yaml b/lib/I18n/translations/dutch.yaml index 12593f0aff..0f0c42ab54 100644 --- a/lib/I18n/translations/dutch.yaml +++ b/lib/I18n/translations/dutch.yaml @@ -85,6 +85,7 @@ STR_PARA_ALIGNMENT: "Uitlijning alinea lezer" STR_HYPHENATION: "Woordafbreking" STR_TIME_TO_SLEEP: "Tijd tot slaapstand" STR_SHOW_HIDDEN_FILES: "Toon verborgen bestanden" +STR_MOVE_FINISHED_TO_READ: "Voltooide boeken naar de Read-map verplaatsen" STR_REFRESH_FREQ: "Verversingsfrequentie" STR_KOREADER_SYNC: "KOReader Sync" STR_CHECK_UPDATES: "Controleren op updates" @@ -151,6 +152,7 @@ STR_ALIGN_LEFT: "Links" STR_CENTER: "Centreren" STR_ALIGN_RIGHT: "Rechts" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" diff --git a/lib/I18n/translations/english.yaml b/lib/I18n/translations/english.yaml index ab9917f101..1ec8388a0e 100644 --- a/lib/I18n/translations/english.yaml +++ b/lib/I18n/translations/english.yaml @@ -85,6 +85,7 @@ STR_PARA_ALIGNMENT: "Reader Paragraph Alignment" STR_HYPHENATION: "Hyphenation" STR_TIME_TO_SLEEP: "Time to Sleep" STR_SHOW_HIDDEN_FILES: "Show Hidden Files" +STR_MOVE_FINISHED_TO_READ: "Move Finished Books to Read Folder" STR_REFRESH_FREQ: "Refresh Frequency" STR_KOREADER_SYNC: "KOReader Sync" STR_CHECK_UPDATES: "Check for updates" @@ -131,6 +132,7 @@ STR_IGNORE: "Ignore" STR_SLEEP: "Sleep" STR_PAGE_TURN: "Page Turn" STR_FORCE_REFRESH: "Refresh Screen" +STR_ACTION_MENU: "Action Menu" STR_PORTRAIT: "Portrait" STR_LANDSCAPE_CW: "Landscape CW" STR_INVERTED: "Inverted" @@ -152,6 +154,7 @@ STR_ALIGN_LEFT: "Left" STR_CENTER: "Center" STR_ALIGN_RIGHT: "Right" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" @@ -230,6 +233,9 @@ STR_PREVIEW: "Preview" STR_TITLE: "Title" STR_BATTERY: "Battery" STR_XTC_STATUS_BAR: "XTC Status Bar" +STR_XTC_RENDER_QUALITY: "2-bit XTC" +STR_SPEED: "Speed" +STR_QUALITY: "Quality" STR_BOTTOM: "Bottom" STR_TOP: "Top" STR_UI_THEME: "UI Theme" diff --git a/lib/I18n/translations/finnish.yaml b/lib/I18n/translations/finnish.yaml index 93672291f0..6d625a07a8 100644 --- a/lib/I18n/translations/finnish.yaml +++ b/lib/I18n/translations/finnish.yaml @@ -80,6 +80,7 @@ STR_SCREEN_MARGIN: "Lukijan näyttömarginaali" STR_PARA_ALIGNMENT: "Lukijan kappaletasaus" STR_HYPHENATION: "Tavutus" STR_TIME_TO_SLEEP: "Aika lepotilaan" +STR_MOVE_FINISHED_TO_READ: "Siirrä luetut kirjat Read-kansioon" STR_REFRESH_FREQ: "Päivitystaajuus" STR_KOREADER_SYNC: "KOReader-synkronointi" STR_CHECK_UPDATES: "Tarkista päivitykset" @@ -146,6 +147,7 @@ STR_ALIGN_LEFT: "Vasen" STR_CENTER: "Keskitetty" STR_ALIGN_RIGHT: "Oikea" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" diff --git a/lib/I18n/translations/french.yaml b/lib/I18n/translations/french.yaml index 0f43e82b53..8e335f76b3 100644 --- a/lib/I18n/translations/french.yaml +++ b/lib/I18n/translations/french.yaml @@ -85,6 +85,7 @@ STR_PARA_ALIGNMENT: "Alignement du texte" STR_HYPHENATION: "Césure" STR_TIME_TO_SLEEP: "Mise en veille auto" STR_SHOW_HIDDEN_FILES: "Afficher les fichiers cachés" +STR_MOVE_FINISHED_TO_READ: "Déplacer les livres terminés vers le dossier Read" STR_REFRESH_FREQ: "Fréquence rafraîchissement" STR_KOREADER_SYNC: "Synchro KOReader" STR_CHECK_UPDATES: "Mise à jour" @@ -151,6 +152,7 @@ STR_ALIGN_LEFT: "Gauche" STR_CENTER: "Centré" STR_ALIGN_RIGHT: "Droite" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" diff --git a/lib/I18n/translations/german.yaml b/lib/I18n/translations/german.yaml index d2f8d0e66b..0f98eb6c03 100644 --- a/lib/I18n/translations/german.yaml +++ b/lib/I18n/translations/german.yaml @@ -151,6 +151,7 @@ STR_ALIGN_LEFT: "Links" STR_CENTER: "Zentriert" STR_ALIGN_RIGHT: "Rechts" STR_MIN_1: "1 Min" +STR_MIN_3: "3 Min" STR_MIN_5: "5 Min" STR_MIN_10: "10 Min" STR_MIN_15: "15 Min" @@ -302,6 +303,7 @@ STR_IMAGES_DISPLAY: "Darstellung" STR_IMAGES_PLACEHOLDER: "Platzhalter" STR_IMAGES_SUPPRESS: "Unterdrücken" STR_SHOW_HIDDEN_FILES: "Versteckte Dateien anzeigen" +STR_MOVE_FINISHED_TO_READ: "Gelesene Bücher in den Read-Ordner verschieben" STR_PAGE_OVERLAY: "Seiten-Overlay" STR_RECENTS: "Zuletzt" STR_MAPPING_REMOTE: "Externe Position zuordnen..." diff --git a/lib/I18n/translations/hungarian.yaml b/lib/I18n/translations/hungarian.yaml index 070f2a28c2..b5eb19f71a 100644 --- a/lib/I18n/translations/hungarian.yaml +++ b/lib/I18n/translations/hungarian.yaml @@ -82,6 +82,7 @@ STR_PARA_ALIGNMENT: "Olvasó szövegigazítás" STR_HYPHENATION: "Elválasztás" STR_TIME_TO_SLEEP: "Alvó mód aktiválása" STR_SHOW_HIDDEN_FILES: "Rejtett fájlok megjelenítése" +STR_MOVE_FINISHED_TO_READ: "Befejezett könyvek áthelyezése a Read mappába" STR_REFRESH_FREQ: "Frissítési frekvencia" STR_KOREADER_SYNC: "KOReader szinkronizálás" STR_CHECK_UPDATES: "Frissítések keresése" @@ -148,6 +149,7 @@ STR_ALIGN_LEFT: "Bal" STR_CENTER: "Közép" STR_ALIGN_RIGHT: "Jobb" STR_MIN_1: "1 perc" +STR_MIN_3: "3 perc" STR_MIN_5: "5 perc" STR_MIN_10: "10 perc" STR_MIN_15: "15 perc" diff --git a/lib/I18n/translations/italian.yaml b/lib/I18n/translations/italian.yaml index 4a180b4f0c..611aeab4f7 100644 --- a/lib/I18n/translations/italian.yaml +++ b/lib/I18n/translations/italian.yaml @@ -45,7 +45,7 @@ STR_OPEN_URL_HINT: "Aprire questo URL nel browser" STR_OR_HTTP_PREFIX: "o http://" STR_SCAN_QR_HINT: "oppure scansionare il codice QR col telefono:" STR_CALIBRE_WIRELESS: "Calibre wireless" -STR_CALIBRE_WEB_URL: "URL Web Calibre" +STR_CALIBRE_WEB_URL: "URL OPDS (Calibre)" STR_NETWORK_LEGEND: "* = Protetta | + = Salvata" STR_MAC_ADDRESS: "Indirizzo MAC:" STR_CHECKING_WIFI: "Verifica WiFi..." @@ -70,14 +70,13 @@ STR_IMAGES: "Immagini" STR_IMAGES_DISPLAY: "Visualizza" STR_IMAGES_PLACEHOLDER: "Segnaposto" STR_IMAGES_SUPPRESS: "Nascondi" -STR_SHORT_PWR_BTN: "Pressione breve tasto accensione" +STR_SHORT_PWR_BTN: "Pressione breve accensione" STR_ORIENTATION: "Orientamento lettura" STR_SIDE_BTN_LAYOUT: "Pulsanti laterali (lettore)" -STR_LONG_PRESS_BEHAVIOR: "Long-press button behavior" +STR_LONG_PRESS_BEHAVIOR: "Pressione lunga" STR_LONG_PRESS_BEHAVIOR_OFF: "OFF" -STR_LONG_PRESS_BEHAVIOR_SKIP: "Chapter skip" -STR_LONG_PRESS_BEHAVIOR_ORIENTATION: "Orientation change" -STR_LONG_PRESS_SKIP: "Pressione lunga: salta capitolo" +STR_LONG_PRESS_BEHAVIOR_SKIP: "Salta capitolo" +STR_LONG_PRESS_BEHAVIOR_ORIENTATION: "Orientamento" STR_FONT_FAMILY: "Font lettore" STR_FONT_SIZE: "Dimensione font lettore" STR_LINE_SPACING: "Interlinea lettore" @@ -86,6 +85,7 @@ STR_PARA_ALIGNMENT: "Allineamento paragrafo" STR_HYPHENATION: "Sillabazione" STR_TIME_TO_SLEEP: "Timeout sospensione" STR_SHOW_HIDDEN_FILES: "Mostra file nascosti" +STR_MOVE_FINISHED_TO_READ: "Sposta i libri finiti nella cartella Read" STR_REFRESH_FREQ: "Frequenza di aggiornamento" STR_KOREADER_SYNC: "Sincronizzazione KOReader" STR_CHECK_UPDATES: "Cerca aggiornamenti" @@ -100,7 +100,7 @@ STR_KOREADER_USERNAME: "Nome utente KOReader" STR_KOREADER_PASSWORD: "Password KOReader" STR_FILENAME: "Nome file" STR_BINARY: "Binario" -STR_SET_CREDENTIALS_FIRST: "Impostare prima le credenziali" +STR_SET_CREDENTIALS_FIRST: "Prima le credenziali" STR_WIFI_CONN_FAILED: "Connessione WiFi non riuscita" STR_AUTHENTICATING: "Autenticazione..." STR_AUTH_SUCCESS: "Autenticazione riuscita!" @@ -131,10 +131,11 @@ STR_ALWAYS: "Sempre" STR_IGNORE: "Ignora" STR_SLEEP: "Sospendi" STR_PAGE_TURN: "Cambio pagina" +STR_FORCE_REFRESH: "Refresh" STR_PORTRAIT: "Verticale" -STR_LANDSCAPE_CW: "Orizzontale ↻" -STR_INVERTED: "Invertito" -STR_LANDSCAPE_CCW: "Orizzontale ↺" +STR_LANDSCAPE_CW: "Orizzontale Dx" +STR_INVERTED: "Capovolto" +STR_LANDSCAPE_CCW: "Orizzontale Sx" STR_PREV_NEXT: "Prec/Succ" STR_NEXT_PREV: "Succ/Prec" STR_NOTO_SERIF: "Noto Serif" @@ -152,6 +153,7 @@ STR_ALIGN_LEFT: "Sinistra" STR_CENTER: "Centrato" STR_ALIGN_RIGHT: "Destra" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" @@ -171,6 +173,7 @@ STR_NO_UPDATE: "Nessun aggiornamento disponibile" STR_UPDATE_FAILED: "Aggiornamento non riuscito" STR_UPDATE_COMPLETE: "Aggiornamento completato" STR_POWER_ON_HINT: "Tenere premuto il tasto di accensione per riavviare" +STR_RESTARTING_HINT: "Riavvio... Se il dispositivo non si accende, tenere premuto il tasto per qualche secondo." STR_NO_ENTRIES: "Nessuna voce trovata" STR_DOWNLOADING: "Download..." STR_DOWNLOAD_FAILED: "Download non riuscito" @@ -179,6 +182,8 @@ STR_UNNAMED: "Senza nome" STR_NO_SERVER_URL: "Nessun Server configurato" STR_FETCH_FEED_FAILED: "Impossibile recuperare il feed" STR_PARSE_FEED_FAILED: "Impossibile analizzare il feed" +STR_NEXT_PAGE: "Pag. successiva »" +STR_PREV_PAGE: "« Pag. precedente" STR_NETWORK_PREFIX: "Rete: " STR_IP_ADDRESS_PREFIX: "Indirizzo IP: " STR_ERROR_GENERAL_FAILURE: "Errore: operazione non riuscita" @@ -226,13 +231,18 @@ STR_EXAMPLE_BOOK: "Titolo del libro" STR_PREVIEW: "Anteprima" STR_TITLE: "Titolo" STR_BATTERY: "Batteria" +STR_XTC_STATUS_BAR: "Barra di stato XTC" +STR_BOTTOM: "Basso" +STR_TOP: "Alto" STR_UI_THEME: "Tema interfaccia" STR_THEME_CLASSIC: "Classico" STR_THEME_LYRA: "Lyra" +STR_THEME_ROUNDEDRAFF: "RoundedRaff" STR_THEME_LYRA_EXTENDED: "Lyra esteso" STR_SUNLIGHT_FADING_FIX: "Correzione luce solare" STR_REMAP_FRONT_BUTTONS: "Rimappa pulsanti frontali" STR_OPDS_BROWSER: "Browser OPDS" +STR_SEARCH: "Cerca" STR_COVER_CUSTOM: "Copertina + Wallpaper" STR_MENU_RECENT_BOOKS: "Libri recenti" STR_NO_RECENT_BOOKS: "Nessun libro recente" @@ -244,15 +254,15 @@ STR_CALIBRE_SETUP: "Configurazione" STR_CALIBRE_STATUS: "Stato" STR_CLEAR_BUTTON: "Elimina" STR_DEFAULT_VALUE: "Predefinito" -STR_REMAP_PROMPT: "Premere un pulsante frontale per ogni funzione" +STR_REMAP_PROMPT: "Assegna premendo un pulsante frontale" STR_UNASSIGNED: "Non assegnato" STR_ALREADY_ASSIGNED: "Già assegnato" -STR_REMAP_RESET_HINT: "Laterale Su: ripristina layout predefinito" +STR_REMAP_RESET_HINT: "Laterale Su: ripristina predefiniti" STR_REMAP_CANCEL_HINT: "Laterale Giù: annulla rimappatura" -STR_HW_BACK_LABEL: "Indietro (1° pulsante)" -STR_HW_CONFIRM_LABEL: "Conferma (2° pulsante)" -STR_HW_LEFT_LABEL: "Sinistra (3° pulsante)" -STR_HW_RIGHT_LABEL: "Destra (4° pulsante)" +STR_HW_BACK_LABEL: "Indietro (1° pul.)" +STR_HW_CONFIRM_LABEL: "Conferma (2° pul.)" +STR_HW_LEFT_LABEL: "Sinistra (3° pul.)" +STR_HW_RIGHT_LABEL: "Destra (4° pul.)" STR_GO_TO_PERCENT: "Vai al %" STR_GO_HOME_BUTTON: "Vai alla home" STR_SYNC_PROGRESS: "Sincronizza avanzamento" @@ -283,17 +293,72 @@ STR_NO_REMOTE_MSG: "Nessun avanzamento remoto trovato" STR_UPLOAD_PROMPT: "Inviare la posizione attuale?" STR_UPLOAD_SUCCESS: "Avanzamenti inviati!" STR_SYNC_FAILED_MSG: "Sincronizzazione non riuscita" -STR_SAVE_PROGRESS_FAILED: "Impossibile salvare il progresso" +STR_SAVE_PROGRESS_FAILED: "Impossibile salvare avanzamenti" STR_SECTION_PREFIX: "Sezione " STR_UPLOAD: "Carica" STR_BOOK_S_STYLE: "Stile libro" STR_EMBEDDED_STYLE: "Stile integrato dell'epub" -STR_FOCUS_READING: "Lettura focalizzata" +STR_FOCUS_READING: "Lettura guidata" STR_OPDS_SERVER_URL: "Server OPDS" +STR_SET_SLEEP_COVER: "Imposta copertina" STR_FOOTNOTES: "Note a piè pagina" STR_NO_FOOTNOTES: "Nessuna nota in questa pagina" STR_LINK: "[link]" STR_SCREENSHOT_BUTTON: "Screenshot" +STR_ADD_SERVER: "Aggiungi server" +STR_SERVER_NAME: "Nome server" +STR_NO_SERVERS: "Nessun server OPDS configurato" +STR_DELETE_SERVER: "Elimina server" +STR_DELETE_CONFIRM: "Eliminare questo server?" +STR_OPDS_SERVERS: "Server OPDS" STR_AUTO_TURN_ENABLED: "Cambio pagina automatico: " STR_AUTO_TURN_PAGES_PER_MIN: "Cambio pagina automatico (pag/min)" -STR_TILT_PAGE_TURN: "Gira pagina con inclinazione" +STR_MANAGE_FONTS: "Gestisci font" +STR_FONT_BROWSER: "Sfoglia font" +STR_LOADING_FONT_LIST: "Elenco font..." +STR_NO_FONTS_AVAILABLE: "Nessun font disponibile" +STR_FONT_INSTALLED: "Font installato!" +STR_FONT_INSTALL_FAILED: "Installazione font non riuscita" +STR_INSTALLED: "Installato" +STR_CONFIRM_DOWNLOAD_PROMPT: "Scaricare?" +STR_SD_CARD_FULL: "Spazio insufficiente su SD" +STR_FILES_LABEL: "File: " +STR_SIZE_LABEL: "Dimensione: " +STR_REDOWNLOAD: "Scarica di nuovo" +STR_DOWNLOAD_ALL: "Scarica tutto" +STR_UPDATE_ALL: "Aggiorna tutto" +STR_ALL_FONTS_INSTALLED: "Tutti i font installati!" +STR_UPDATE_AVAILABLE: "Aggiorna" +STR_CRASH_TITLE: "Errore di sistema" +STR_CRASH_DESCRIPTION: "Un rapporto dettagliato è stato salvato in crash_report.txt. Includere il file per la segnalazione del problema." +STR_CRASH_REASON: "Causa dell'errore:" +STR_CRASH_NO_REASON: "(Nessuna causa registrata)" +STR_TILT_PAGE_TURN: "Inclina per cambio pagina" +STR_KB_HINT_MOVE_CURSOR: "SINISTRA o DESTRA per spostare il cursore" +STR_KB_HINT_RETURN_CURSOR: "SINISTRA per tornare alla posizione del cursore" +STR_KB_HINT_HIDE_PASSWORD: "Prima DESTRA e poi [***] per nascondere la password" +STR_KB_HINT_SHOW_PASSWORD: "Prima DESTRA e poi [abc] per mostrare la password" +STR_KB_HINT_TOGGLE_HIDE_PASSWORD: "Premere [***] per nascondere la password" +STR_KB_HINT_TOGGLE_SHOW_PASSWORD: "Premere [abc] per mostrare la password" +STR_KB_HINT_EDIT_ENTRY: "Tieni premuto SU per modificare la voce" +STR_KB_TIPS: "Suggerimenti:" +STR_KB_HINT_RETURN_KEYBOARD: "GIÙ per tornare alla tastiera" +STR_KB_HINT_EXIT_URL_MODE: "ABC per uscire dalla modalità URL" +STR_KB_HINT_CLEAR_TEXT: "Tieni spinto CANC per cancellare tutto" +STR_KB_HINT_SECONDARY_CHAR: "Tieni spinto SELEZ. per carattere secondario" +STR_KB_HINT_UPPER_SECONDARY: "Tieni spinto SELEZ. per MAIUS. o car. secondario" +STR_KB_HINT_LOWER_SECONDARY: "Tieni spinto SELEZ. per minus. o car. secondario" +STR_KB_HINT_URL_SNIPPETS: "Premi l'URL per le anteprime" +STR_SD_FIRMWARE_UPDATE: "Aggiornamento firmware da SD" +STR_SELECT_FIRMWARE_FILE: "Seleziona il firmware (.bin)" +STR_NO_BIN_FILES: "Nessun file .bin trovato" +STR_VALIDATING_FIRMWARE: "Convalida firmware..." +STR_INVALID_FIRMWARE: "File firmware non valido" +STR_FIRMWARE_TOO_LARGE: "Firmware troppo grande" +STR_FIRMWARE_TOO_SMALL: "Firmware troppo piccolo" +STR_FIRMWARE_UPDATE_PROMPT: "Aggiornare il firmware?" +STR_FIRMWARE_FILE_OPEN_FAILED: "Impossibile aprire il file" +STR_FIRMWARE_WRITE_FAILED: "Aggiornamento firmware non riuscito" +STR_FIRMWARE_UPDATE_DO_NOT_POWER_OFF: "Non spegnere il dispositivo!" +STR_RECOVERY_MODE: "Modalità ripristino" +STR_RECOVERY_MODE_HINT: "Metti il firmware.bin nella SD e selezionalo" diff --git a/lib/I18n/translations/kazakh.yaml b/lib/I18n/translations/kazakh.yaml index 5d9c03e95f..624bf197b5 100644 --- a/lib/I18n/translations/kazakh.yaml +++ b/lib/I18n/translations/kazakh.yaml @@ -76,6 +76,7 @@ STR_SCREEN_MARGIN: "Оқырман экран жиегі" STR_PARA_ALIGNMENT: "Оқырман абзац туралануы" STR_HYPHENATION: "Буын бөлу" STR_TIME_TO_SLEEP: "Ұйқы уақыты" +STR_MOVE_FINISHED_TO_READ: "Оқылған кітаптарды Read қалтасына жылжыту" STR_REFRESH_FREQ: "Жаңарту жиілігі" STR_KOREADER_SYNC: "KOReader синхронизациясы" STR_CHECK_UPDATES: "Жаңартуларды тексеру" @@ -142,6 +143,7 @@ STR_ALIGN_LEFT: "Солға" STR_CENTER: "Ортаға" STR_ALIGN_RIGHT: "Оңға" STR_MIN_1: "1 мин" +STR_MIN_3: "3 мин" STR_MIN_5: "5 мин" STR_MIN_10: "10 мин" STR_MIN_15: "15 мин" diff --git a/lib/I18n/translations/lithuanian.yaml b/lib/I18n/translations/lithuanian.yaml index d7619a1fbc..b73c86e7a8 100644 --- a/lib/I18n/translations/lithuanian.yaml +++ b/lib/I18n/translations/lithuanian.yaml @@ -82,6 +82,7 @@ STR_PARA_ALIGNMENT: "Lygiavimas" STR_HYPHENATION: "Skiemenuoti" STR_TIME_TO_SLEEP: "Užmigti po" STR_SHOW_HIDDEN_FILES: "Rod. paslėptus failus" +STR_MOVE_FINISHED_TO_READ: "Perkelti perskaitytas knygas į aplanką Read" STR_REFRESH_FREQ: "Atnaujinimo dažnis" STR_KOREADER_SYNC: "KOReader sinchr." STR_CHECK_UPDATES: "Atnaujinimai" @@ -148,6 +149,7 @@ STR_ALIGN_LEFT: "Kairė" STR_CENTER: "Centras" STR_ALIGN_RIGHT: "Dešinė" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" diff --git a/lib/I18n/translations/polish.yaml b/lib/I18n/translations/polish.yaml index 384dbac8a9..fffdb11453 100644 --- a/lib/I18n/translations/polish.yaml +++ b/lib/I18n/translations/polish.yaml @@ -85,6 +85,7 @@ STR_PARA_ALIGNMENT: "Wyjustowanie paragrafów" STR_HYPHENATION: "Dzielenie wyrazów" STR_TIME_TO_SLEEP: "Czas do uśpienia" STR_SHOW_HIDDEN_FILES: "Pokaż ukryte pliki" +STR_MOVE_FINISHED_TO_READ: "Przenoś przeczytane książki do folderu Read" STR_REFRESH_FREQ: "Częstotliwość odświeżania" STR_KOREADER_SYNC: "KOReader Sync" STR_CHECK_UPDATES: "Sprawdź uaktualnia" @@ -152,6 +153,7 @@ STR_ALIGN_LEFT: "Lewo" STR_CENTER: "Środek" STR_ALIGN_RIGHT: "Prawo" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" diff --git a/lib/I18n/translations/portuguese.yaml b/lib/I18n/translations/portuguese.yaml index 97b447b9eb..a0efb68c0f 100644 --- a/lib/I18n/translations/portuguese.yaml +++ b/lib/I18n/translations/portuguese.yaml @@ -80,6 +80,7 @@ STR_SCREEN_MARGIN: "Margens da tela" STR_PARA_ALIGNMENT: "Alinhamento parágrafo" STR_HYPHENATION: "Hifenização" STR_TIME_TO_SLEEP: "Tempo para repousar" +STR_MOVE_FINISHED_TO_READ: "Mover livros lidos para a pasta Read" STR_REFRESH_FREQ: "Frequência atualização" STR_KOREADER_SYNC: "Sincronização KOReader" STR_CHECK_UPDATES: "Verificar atualizações" @@ -146,6 +147,7 @@ STR_ALIGN_LEFT: "Esquerda" STR_CENTER: "Centralizar" STR_ALIGN_RIGHT: "Direita" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" diff --git a/lib/I18n/translations/romanian.yaml b/lib/I18n/translations/romanian.yaml index 84d7cac9c4..d567046721 100644 --- a/lib/I18n/translations/romanian.yaml +++ b/lib/I18n/translations/romanian.yaml @@ -85,6 +85,7 @@ STR_PARA_ALIGNMENT: "Aliniere paragrafe reader" STR_HYPHENATION: "Silabisire" STR_TIME_TO_SLEEP: "Timp până la repaus" STR_SHOW_HIDDEN_FILES: "Afişează fişierele ascunse" +STR_MOVE_FINISHED_TO_READ: "Mută cărţile terminate în folderul Read" STR_REFRESH_FREQ: "Frecvenţă reîmprospătare" STR_KOREADER_SYNC: "Sincronizare KOReader" STR_CHECK_UPDATES: "Căutaţi actualizări" @@ -151,6 +152,7 @@ STR_ALIGN_LEFT: "Stânga" STR_CENTER: "Centru" STR_ALIGN_RIGHT: "Dreapta" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" diff --git a/lib/I18n/translations/russian.yaml b/lib/I18n/translations/russian.yaml index 005a5eea2c..eadbc60b00 100644 --- a/lib/I18n/translations/russian.yaml +++ b/lib/I18n/translations/russian.yaml @@ -85,6 +85,7 @@ STR_PARA_ALIGNMENT: "Выравнивание абзаца" STR_HYPHENATION: "Перенос слов" STR_TIME_TO_SLEEP: "Сон через" STR_SHOW_HIDDEN_FILES: "Показать скрытые файлы" +STR_MOVE_FINISHED_TO_READ: "Перемещать прочитанные книги в папку Read" STR_REFRESH_FREQ: "Частота обновления" STR_KOREADER_SYNC: "Синхронизация KOReader" STR_CHECK_UPDATES: "Проверить обновления" @@ -130,6 +131,7 @@ STR_ALWAYS: "Всегда" STR_IGNORE: "Игнорировать" STR_SLEEP: "Сон" STR_PAGE_TURN: "Перелистывание" +STR_FORCE_REFRESH: "Обновление экрана" STR_PORTRAIT: "Портрет" STR_LANDSCAPE_CW: "Ландшафт (CW)" STR_INVERTED: "Инверсия" @@ -151,6 +153,7 @@ STR_ALIGN_LEFT: "По левому краю" STR_CENTER: "По центру" STR_ALIGN_RIGHT: "По правому краю" STR_MIN_1: "1 мин" +STR_MIN_3: "3 мин" STR_MIN_5: "5 мин" STR_MIN_10: "10 мин" STR_MIN_15: "15 мин" @@ -170,6 +173,7 @@ STR_NO_UPDATE: "Обновлений нет" STR_UPDATE_FAILED: "Ошибка обновления" STR_UPDATE_COMPLETE: "Обновление завершено" STR_POWER_ON_HINT: "Удерживайте кнопку питания для включения" +STR_RESTARTING_HINT: "Перезапуск... Если устройство не перезагружается, удерживайте кнопку питания несколько секунд" STR_NO_ENTRIES: "Записи не найдены" STR_DOWNLOADING: "Загрузка..." STR_DOWNLOAD_FAILED: "Ошибка загрузки" @@ -178,6 +182,8 @@ STR_UNNAMED: "Без имени" STR_NO_SERVER_URL: "URL сервера не настроен" STR_FETCH_FEED_FAILED: "Не удалось получить ленту" STR_PARSE_FEED_FAILED: "Не удалось обработать ленту" +STR_NEXT_PAGE: "Следующая страница »" +STR_PREV_PAGE: "« Предыдущая страница" STR_NETWORK_PREFIX: "Сеть: " STR_IP_ADDRESS_PREFIX: "IP-адрес: " STR_ERROR_GENERAL_FAILURE: "Ошибка: Общая ошибка" @@ -225,6 +231,9 @@ STR_EXAMPLE_BOOK: "Название книги" STR_PREVIEW: "Предпросмотр" STR_TITLE: "Заглавие" STR_BATTERY: "Батарея" +STR_XTC_STATUS_BAR: "Строка состояния XTC" +STR_BOTTOM: "Низ" +STR_TOP: "Верх" STR_UI_THEME: "Тема интерфейса" STR_THEME_CLASSIC: "Классическая" STR_THEME_LYRA: "Lyra" @@ -233,9 +242,7 @@ STR_THEME_LYRA_EXTENDED: "Lyra Extended" STR_SUNLIGHT_FADING_FIX: "Компенсация выцветания" STR_REMAP_FRONT_BUTTONS: "Переназначить передние кнопки" STR_OPDS_BROWSER: "OPDS браузер" -STR_FOOTNOTES: "Примечания" -STR_NO_FOOTNOTES: "На данной странице нет примечаний" -STR_LINK: "[ссылка]" +STR_SEARCH: "Поиск" STR_COVER_CUSTOM: "Обложка + Свой" STR_MENU_RECENT_BOOKS: "Недавние книги" STR_NO_RECENT_BOOKS: "Нет недавних книг" @@ -261,8 +268,8 @@ STR_GO_HOME_BUTTON: "На главную" STR_SYNC_PROGRESS: "Синхронизировать прогресс" STR_DELETE_CACHE: "Удалить кэш книги" STR_DELETE: "Удалить" -STR_CHAPTER_PREFIX: "Глава: " STR_DISPLAY_QR: "Показать страницу в виде QR-кода" +STR_CHAPTER_PREFIX: "Глава: " STR_PAGES_SEPARATOR: " стр. | " STR_BOOK_PREFIX: "Книга: " STR_CALIBRE_URL_HINT: "Для Calibre добавьте /opds к URL" @@ -293,13 +300,65 @@ STR_BOOK_S_STYLE: "Стиль книги" STR_EMBEDDED_STYLE: "Встроенный стиль" STR_FOCUS_READING: "Фокусное чтение" STR_OPDS_SERVER_URL: "URL OPDS сервера" +STR_SET_SLEEP_COVER: "Обложкой" +STR_FOOTNOTES: "Примечания" +STR_NO_FOOTNOTES: "На данной странице нет примечаний" +STR_LINK: "[ссылка]" STR_SCREENSHOT_BUTTON: "Сделать снимок экрана" -STR_AUTO_TURN_ENABLED: "Автоперелистывание: " -STR_AUTO_TURN_PAGES_PER_MIN: "Автоперелистывание (стр./мин)" -STR_TILT_PAGE_TURN: "Перелистывание наклоном" STR_ADD_SERVER: "Добавить сервер" STR_SERVER_NAME: "Имя сервера" STR_NO_SERVERS: "Нет настроенных серверов OPDS" STR_DELETE_SERVER: "Удалить сервер" STR_DELETE_CONFIRM: "Удалить этот сервер?" STR_OPDS_SERVERS: "Серверы OPDS" +STR_AUTO_TURN_ENABLED: "Автоперелистывание: " +STR_AUTO_TURN_PAGES_PER_MIN: "Автоперелистывание (стр./мин)" +STR_MANAGE_FONTS: "Управление шрифтами" +STR_FONT_BROWSER: "Обзор шрифтов" +STR_LOADING_FONT_LIST: "Загрузка списка шрифтов..." +STR_NO_FONTS_AVAILABLE: "Шрифты недоступны" +STR_FONT_INSTALLED: "Шрифт установлен!" +STR_FONT_INSTALL_FAILED: "Не удалоь установить шрифт" +STR_INSTALLED: "Установлен" +STR_CONFIRM_DOWNLOAD_PROMPT: "Загрузить?" +STR_SD_CARD_FULL: "Недостаточно места на SD-карте" +STR_FILES_LABEL: "Файлы: " +STR_SIZE_LABEL: "Размер: " +STR_REDOWNLOAD: "Скачать снова" +STR_DOWNLOAD_ALL: "Загрузить все" +STR_UPDATE_ALL: "Обновить всё" +STR_ALL_FONTS_INSTALLED: "Все шрифты установлены!" +STR_UPDATE_AVAILABLE: "Обновить" +STR_CRASH_TITLE: "Сбой системы" +STR_CRASH_DESCRIPTION: "Подробный отчёт сохранён в crash_report.txt. Пожалуйста, приложите этот файл к вашему отчёту об ошибке." +STR_CRASH_REASON: "Причина сбоя:" +STR_CRASH_NO_REASON: "(Причина не указана)" +STR_TILT_PAGE_TURN: "Перелистывание наклоном" +STR_KB_HINT_MOVE_CURSOR: "Нажмите ВЛЕВО или ВПРАВО для перемещения курсора" +STR_KB_HINT_RETURN_CURSOR: "Нажмите ВЛЕВО, чтобы вернуться к позиции курсора" +STR_KB_HINT_HIDE_PASSWORD: "Удерживайте ВПРАВО, затем нажмите [***], чтобы скрыть пароль" +STR_KB_HINT_SHOW_PASSWORD: "Удерживайте ВПРАВО, затем нажмите [abc], чтобы показать пароль" +STR_KB_HINT_TOGGLE_HIDE_PASSWORD: "Нажмите [***], чтобы скрыть пароль" +STR_KB_HINT_TOGGLE_SHOW_PASSWORD: "Нажмите [abc], чтобы показать пароль" +STR_KB_HINT_EDIT_ENTRY: "Удерживайте ВВЕРХ для редактирования записи" +STR_KB_TIPS: "Подсказки:" +STR_KB_HINT_RETURN_KEYBOARD: "Нажмите ВНИЗ, чтобы вернуться к клавиатуре" +STR_KB_HINT_EXIT_URL_MODE: "Нажмите ABC для выхода из режима URL" +STR_KB_HINT_CLEAR_TEXT: "Удерживайте <— чтобы очитисть весь текст" +STR_KB_HINT_SECONDARY_CHAR: "Удерживайте ВЫБРАТЬ для дополнительного символа" +STR_KB_HINT_UPPER_SECONDARY: "Удерживайте ВЫБРАТЬ для ВЕРХНЕГО РЕГИСТРА или дополнительного символа" +STR_KB_HINT_LOWER_SECONDARY: "Удерживайте ВЫБРАТЬ для нижнего регистра или дополнительного символа" +STR_KB_HINT_URL_SNIPPETS: "Нажмите URL для выбора шаблонов" +STR_SD_FIRMWARE_UPDATE: "Обновление системы с SD-карты" +STR_SELECT_FIRMWARE_FILE: "Выберите файл прошивки (.bin)" +STR_NO_BIN_FILES: ".bin файлы не найдены" +STR_VALIDATING_FIRMWARE: "Проверка файла прошивки..." +STR_INVALID_FIRMWARE: "Не подходящий файл прошивки" +STR_FIRMWARE_TOO_LARGE: "Прошивка слишком велика для раздела" +STR_FIRMWARE_TOO_SMALL: "Файл прошивки слишком мал" +STR_FIRMWARE_UPDATE_PROMPT: "Обновить прошивку?" +STR_FIRMWARE_FILE_OPEN_FAILED: "Не могу открыть файл" +STR_FIRMWARE_WRITE_FAILED: "Ошибка записи прошивки" +STR_FIRMWARE_UPDATE_DO_NOT_POWER_OFF: "Не выключайте питание!" +STR_RECOVERY_MODE: "Режим восстановления" +STR_RECOVERY_MODE_HINT: "Поместите firmware.bin в корень SD-карты и выберите его" diff --git a/lib/I18n/translations/slovenian.yaml b/lib/I18n/translations/slovenian.yaml index 7e506661bc..87d96817fe 100644 --- a/lib/I18n/translations/slovenian.yaml +++ b/lib/I18n/translations/slovenian.yaml @@ -82,6 +82,7 @@ STR_PARA_ALIGNMENT: "Poravnava odstavkov" STR_HYPHENATION: "Deljenje besed" STR_TIME_TO_SLEEP: "Čas do spanja" STR_SHOW_HIDDEN_FILES: "Prikaži skrite datoteke" +STR_MOVE_FINISHED_TO_READ: "Premakni prebrane knjige v mapo Read" STR_REFRESH_FREQ: "Pogostost osveževanja" STR_KOREADER_SYNC: "KOReader sinhronizacija" STR_CHECK_UPDATES: "Preveri posodobitve" @@ -148,6 +149,7 @@ STR_ALIGN_LEFT: "Levo" STR_CENTER: "Sredinsko" STR_ALIGN_RIGHT: "Desno" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" diff --git a/lib/I18n/translations/spanish.yaml b/lib/I18n/translations/spanish.yaml index 9b4af84300..cb7723a2c3 100644 --- a/lib/I18n/translations/spanish.yaml +++ b/lib/I18n/translations/spanish.yaml @@ -26,7 +26,7 @@ STR_LOADING: "Cargando..." STR_LOADING_POPUP: "Cargando" STR_WIFI_NETWORKS: "Redes Wi-Fi" STR_NO_NETWORKS: "No hay redes disponibles" -STR_NETWORKS_FOUND: "%zu redes encontradas" +STR_NETWORKS_FOUND: "%zu red(es) encontrada(s)" STR_SCANNING: "Buscando..." STR_CONNECTING: "Conectando..." STR_CONNECTED: "¡Conectado!" @@ -45,9 +45,9 @@ STR_OPEN_URL_HINT: "Abra esta dirección en su navegador" STR_OR_HTTP_PREFIX: "o http://" STR_SCAN_QR_HINT: "o escanee el código QR con su móvil:" STR_CALIBRE_WIRELESS: "Calibre inalámbrico" -STR_CALIBRE_WEB_URL: "OPDS URL" -STR_NETWORK_LEGEND: "* (Cifrado) | + (Guardado)" -STR_MAC_ADDRESS: "MAC Address:" +STR_CALIBRE_WEB_URL: "URL OPDS" +STR_NETWORK_LEGEND: "* (Con contraseña) | + (Guardada)" +STR_MAC_ADDRESS: "Dirección MAC:" STR_CHECKING_WIFI: "Verificando Wi-Fi..." STR_ENTER_WIFI_PASSWORD: "Introduzca la contraseña del Wi-Fi" STR_TO_PREFIX: "a " @@ -61,7 +61,7 @@ STR_CAT_DISPLAY: "Pantalla" STR_CAT_READER: "Lector" STR_CAT_CONTROLS: "Controles" STR_CAT_SYSTEM: "Sistema" -STR_SLEEP_SCREEN: "Pantalla de suspensión" +STR_SLEEP_SCREEN: "Fondo de pantalla de suspensión" STR_SLEEP_COVER_MODE: "Modo de pantalla de suspensión" STR_HIDE_BATTERY: "Ocultar % de batería" STR_EXTRA_SPACING: "Espaciado entre párrafos" @@ -70,13 +70,13 @@ STR_IMAGES: "Imágenes" STR_IMAGES_DISPLAY: "Mostrar" STR_IMAGES_PLACEHOLDER: "Reemplazar" STR_IMAGES_SUPPRESS: "Ocultar" -STR_SHORT_PWR_BTN: "Toque corto botón encendido" +STR_SHORT_PWR_BTN: "Toque corto del encendido" STR_ORIENTATION: "Orientación" STR_SIDE_BTN_LAYOUT: "Función botones laterales (lector)" -STR_LONG_PRESS_BEHAVIOR: "Comportamiento al mantener pulsado el botón" -STR_LONG_PRESS_BEHAVIOR_OFF: "Desactivado" +STR_LONG_PRESS_BEHAVIOR: "Al mantener pulsado un botón" +STR_LONG_PRESS_BEHAVIOR_OFF: "No hacer nada" STR_LONG_PRESS_BEHAVIOR_SKIP: "Saltar capítulo" -STR_LONG_PRESS_BEHAVIOR_ORIENTATION: "Cambio de orientación" +STR_LONG_PRESS_BEHAVIOR_ORIENTATION: "Cambiar orient." STR_FONT_FAMILY: "Tipografía" STR_FONT_SIZE: "Tamaño" STR_LINE_SPACING: "Interlineado" @@ -85,6 +85,7 @@ STR_PARA_ALIGNMENT: "Ajuste de párrafo" STR_HYPHENATION: "División de palabras" STR_TIME_TO_SLEEP: "Auto suspensión" STR_SHOW_HIDDEN_FILES: "Mostrar archivos ocultos" +STR_MOVE_FINISHED_TO_READ: "Mover libros terminados a la carpeta Read" STR_REFRESH_FREQ: "Frecuencia de refresco" STR_KOREADER_SYNC: "Sincronización de KOReader" STR_CHECK_UPDATES: "Verificar actualizaciones" @@ -130,6 +131,7 @@ STR_ALWAYS: "Siempre" STR_IGNORE: "Ignorar" STR_SLEEP: "Suspender" STR_PAGE_TURN: "Pasar página" +STR_FORCE_REFRESH: "Refrescar pant." STR_PORTRAIT: "Vertical" STR_LANDSCAPE_CW: "Horizontal (horario)" STR_INVERTED: "Invertido" @@ -151,6 +153,7 @@ STR_ALIGN_LEFT: "Izquierda" STR_CENTER: "Centro" STR_ALIGN_RIGHT: "Derecha" STR_MIN_1: "1 min." +STR_MIN_3: "3 min." STR_MIN_5: "5 min." STR_MIN_10: "10 min." STR_MIN_15: "15 min." @@ -169,7 +172,8 @@ STR_UPDATING: "Actualizando..." STR_NO_UPDATE: "No hay actualizaciones disponibles" STR_UPDATE_FAILED: "Fallo de actualización" STR_UPDATE_COMPLETE: "Actualización completada" -STR_POWER_ON_HINT: "Reinicie manteniendo pulsado botón de encendido" +STR_POWER_ON_HINT: "Reinicie manteniendo pulsado el encendido" +STR_RESTARTING_HINT: "Reiniciando... Si no se reinicia, mantenga pulsado el encendido unos segundos." STR_NO_ENTRIES: "No se encontraron elementos" STR_DOWNLOADING: "Descargando..." STR_DOWNLOAD_FAILED: "Fallo de descarga" @@ -178,12 +182,14 @@ STR_UNNAMED: "Sin nombre" STR_NO_SERVER_URL: "No se configuró URL de servidor" STR_FETCH_FEED_FAILED: "Fallo al obtener el feed" STR_PARSE_FEED_FAILED: "Fallo al procesar el feed" +STR_NEXT_PAGE: "Pág. siguiente »" +STR_PREV_PAGE: "« Pág. anterior" STR_NETWORK_PREFIX: "Red: " STR_IP_ADDRESS_PREFIX: "IP: " STR_ERROR_GENERAL_FAILURE: "Error: Fallo general" STR_ERROR_NETWORK_NOT_FOUND: "Error: Red no encontrada" STR_ERROR_CONNECTION_TIMEOUT: "Error: Tiempo de conexión agotado" -STR_SD_CARD: "Tarjeta microSD" +STR_SD_CARD: "Tarjeta SD" STR_BACK: "« Atrás" STR_EXIT: "« Salir" STR_HOME: "« Inicio" @@ -225,14 +231,18 @@ STR_EXAMPLE_BOOK: "Título del libro" STR_PREVIEW: "Previsualización" STR_TITLE: "Título" STR_BATTERY: "Batería" +STR_XTC_STATUS_BAR: "Barra de estado de XTC" +STR_BOTTOM: "Abajo" +STR_TOP: "Arriba" STR_UI_THEME: "Interfaz" STR_THEME_CLASSIC: "Clásico" STR_THEME_LYRA: "Lyra" -STR_THEME_LYRA_EXTENDED: "Lyra Extendido" STR_THEME_ROUNDEDRAFF: "RoundedRaff" +STR_THEME_LYRA_EXTENDED: "Lyra Extendido" STR_SUNLIGHT_FADING_FIX: "Corrección de desvanecimiento" STR_REMAP_FRONT_BUTTONS: "Reconfigurar botones frontales" STR_OPDS_BROWSER: "Navegador OPDS" +STR_SEARCH: "Buscar" STR_COVER_CUSTOM: "Portada + Pers." STR_MENU_RECENT_BOOKS: "Libros recientes" STR_NO_RECENT_BOOKS: "No hay libros recientes" @@ -290,10 +300,65 @@ STR_BOOK_S_STYLE: "Estilo del libro" STR_EMBEDDED_STYLE: "Estilo integrado" STR_FOCUS_READING: "Lectura enfocada" STR_OPDS_SERVER_URL: "URL del servidor OPDS" +STR_SET_SLEEP_COVER: "Pant. sus." STR_FOOTNOTES: "Pie de página" STR_NO_FOOTNOTES: "No hay notas al pie de esta página" STR_LINK: "[enlace]" STR_SCREENSHOT_BUTTON: "Tomar captura de pantalla" -STR_TILT_PAGE_TURN: "Pasar página inclinando" +STR_ADD_SERVER: "Agregar servidor" +STR_SERVER_NAME: "Nombre de servidor" +STR_NO_SERVERS: "No se configuraron servidores OPDS" +STR_DELETE_SERVER: "Borrar servidor" +STR_DELETE_CONFIRM: "¿Borrar este servidor?" +STR_OPDS_SERVERS: "Servidores OPDS" STR_AUTO_TURN_ENABLED: "Avance activado: " STR_AUTO_TURN_PAGES_PER_MIN: "Avance auto. (pág./min)" +STR_MANAGE_FONTS: "Gestionar tipografías" +STR_FONT_BROWSER: "Navegador de tipografías" +STR_LOADING_FONT_LIST: "Cargando lista de tipografías..." +STR_NO_FONTS_AVAILABLE: "No hay tipografías disponibles" +STR_FONT_INSTALLED: "¡Se instaló la tipografía!" +STR_FONT_INSTALL_FAILED: "Falló la instalación de tipografía" +STR_INSTALLED: "Instalada" +STR_CONFIRM_DOWNLOAD_PROMPT: "¿Descargar?" +STR_SD_CARD_FULL: "No hay espacio en la tarjeta SD" +STR_FILES_LABEL: "Archivos: " +STR_SIZE_LABEL: "Tamaño: " +STR_REDOWNLOAD: "Redescargar" +STR_DOWNLOAD_ALL: "Descargar todas" +STR_UPDATE_ALL: "Actualizar todas" +STR_ALL_FONTS_INSTALLED: "¡Se instalaron todas las tipografías!" +STR_UPDATE_AVAILABLE: "Actualizar" +STR_CRASH_TITLE: "Fallo del sistema" +STR_CRASH_DESCRIPTION: "Se guardó un informe detallado en crash_report.txt. Inclúyalo al avisar sobre el error." +STR_CRASH_REASON: "Razón del fallo:" +STR_CRASH_NO_REASON: "(No se registró una razón)." +STR_TILT_PAGE_TURN: "Pasar página inclinando" +STR_KB_HINT_MOVE_CURSOR: "Pulse IZQ. o DCHA. para mover el cursor" +STR_KB_HINT_RETURN_CURSOR: "Pulse IZQ. para volver a la posición del cursor" +STR_KB_HINT_HIDE_PASSWORD: "Pulse DCHA., luego [***] para ocultar la contraseña" +STR_KB_HINT_SHOW_PASSWORD: "Pulse DCHA., luego [abc] para mostrar la contraseña" +STR_KB_HINT_TOGGLE_HIDE_PASSWORD: "Pulse [***] para ocultar la contraseña" +STR_KB_HINT_TOGGLE_SHOW_PASSWORD: "Pulse [abc] para mostrar la contraseña" +STR_KB_HINT_EDIT_ENTRY: "Mantenga SUBIR para editar la entrada" +STR_KB_TIPS: "Consejos: " +STR_KB_HINT_RETURN_KEYBOARD: "Pulse BAJAR para volver al teclado" +STR_KB_HINT_EXIT_URL_MODE: "Pulse ABC para salir del modo URL" +STR_KB_HINT_CLEAR_TEXT: "Mantenga RETROCESO para borrar todo" +STR_KB_HINT_SECONDARY_CHAR: "Mantenga SELECC. para otros caracteres" +STR_KB_HINT_UPPER_SECONDARY: "Mantenga SELECC. para MAYÚS./otros caracteres" +STR_KB_HINT_LOWER_SECONDARY: "Mantenga SELECC. para minús./otros caracteres" +STR_KB_HINT_URL_SNIPPETS: "Pulse URL para ingresar fragmentos" +STR_SD_FIRMWARE_UPDATE: "Actualizar firmware por tarj. SD" +STR_SELECT_FIRMWARE_FILE: "Elija el archivo de firmware (.bin)" +STR_NO_BIN_FILES: "No se encontraron archivos .bin" +STR_VALIDATING_FIRMWARE: "Validando el firmware..." +STR_INVALID_FIRMWARE: "Archivo de firmware no válido" +STR_FIRMWARE_TOO_LARGE: "Firmware demasiado grande p/la partición" +STR_FIRMWARE_TOO_SMALL: "Firmware demasiado pequeño" +STR_FIRMWARE_UPDATE_PROMPT: "¿Actualizar el firmware?" +STR_FIRMWARE_FILE_OPEN_FAILED: "No se puede abrir el archivo" +STR_FIRMWARE_WRITE_FAILED: "Falló la escritura del firmware" +STR_FIRMWARE_UPDATE_DO_NOT_POWER_OFF: "¡No apague el dispositivo!" +STR_RECOVERY_MODE: "Modo de recuperación" +STR_RECOVERY_MODE_HINT: "Ponga firmware.bin en la raíz de la tarj. SD y selecciónelo" diff --git a/lib/I18n/translations/swedish.yaml b/lib/I18n/translations/swedish.yaml index 9a71fd3266..8d0957d345 100644 --- a/lib/I18n/translations/swedish.yaml +++ b/lib/I18n/translations/swedish.yaml @@ -85,6 +85,7 @@ STR_PARA_ALIGNMENT: "Eboksläsarens paragrafjustering" STR_HYPHENATION: "Avstavning" STR_TIME_TO_SLEEP: "Tid för att gå i vila" STR_SHOW_HIDDEN_FILES: "Visa dolda filer" +STR_MOVE_FINISHED_TO_READ: "Flytta lästa böcker till Read-mappen" STR_REFRESH_FREQ: "Uppdateringsfrekvens" STR_KOREADER_SYNC: "KOReader-synkronisering" STR_CHECK_UPDATES: "Kolla efter uppdateringar" @@ -152,6 +153,7 @@ STR_ALIGN_LEFT: "Vänster" STR_CENTER: "Mitten" STR_ALIGN_RIGHT: "Höger" STR_MIN_1: "1 min" +STR_MIN_3: "3 min" STR_MIN_5: "5 min" STR_MIN_10: "10 min" STR_MIN_15: "15 min" diff --git a/lib/I18n/translations/turkish.yaml b/lib/I18n/translations/turkish.yaml index 6e0784ce82..64a5828596 100644 --- a/lib/I18n/translations/turkish.yaml +++ b/lib/I18n/translations/turkish.yaml @@ -80,6 +80,7 @@ STR_PARA_ALIGNMENT: "Okuyucu Paragraf Hizalaması" STR_HYPHENATION: "Hecelerden Ayırma" STR_TIME_TO_SLEEP: "Uykuya Geçme Süresi" STR_SHOW_HIDDEN_FILES: "Gizli Dosyaları Göster" +STR_MOVE_FINISHED_TO_READ: "Biten kitapları Read klasörüne taşı" STR_REFRESH_FREQ: "Yenileme Sıklığı" STR_KOREADER_SYNC: "KOReader Senkronizasyonu" STR_CHECK_UPDATES: "Güncellemeleri denetle" @@ -146,6 +147,7 @@ STR_ALIGN_LEFT: "Sola Yasla" STR_CENTER: "Ortala" STR_ALIGN_RIGHT: "Sağa Yasla" STR_MIN_1: "1 dak" +STR_MIN_3: "3 dak" STR_MIN_5: "5 dak" STR_MIN_10: "10 dak" STR_MIN_15: "15 dak" diff --git a/lib/I18n/translations/ukrainian.yaml b/lib/I18n/translations/ukrainian.yaml index 2797f93148..bc2299a960 100644 --- a/lib/I18n/translations/ukrainian.yaml +++ b/lib/I18n/translations/ukrainian.yaml @@ -85,6 +85,7 @@ STR_PARA_ALIGNMENT: "Вирівнювання тексту" STR_HYPHENATION: "Перенесення слів" STR_TIME_TO_SLEEP: "Перехід в режим сну" STR_SHOW_HIDDEN_FILES: "Показати приховані файли" +STR_MOVE_FINISHED_TO_READ: "Переміщати прочитані книги до теки Read" STR_REFRESH_FREQ: "Частота оновлення екрану" STR_KOREADER_SYNC: "Синхронізація KOReader" STR_CHECK_UPDATES: "Перевірити оновлення системи" @@ -152,6 +153,7 @@ STR_ALIGN_LEFT: "За лівим краєм" STR_CENTER: "По центру" STR_ALIGN_RIGHT: "За правим краєм" STR_MIN_1: "1 хв" +STR_MIN_3: "3 хв" STR_MIN_5: "5 хв" STR_MIN_10: "10 хв" STR_MIN_15: "15 хв" diff --git a/lib/JpegToBmpConverter/JpegToBmpConverter.cpp b/lib/JpegToBmpConverter/JpegToBmpConverter.cpp index 0dd7872753..38b271b850 100644 --- a/lib/JpegToBmpConverter/JpegToBmpConverter.cpp +++ b/lib/JpegToBmpConverter/JpegToBmpConverter.cpp @@ -4,10 +4,10 @@ #include #include #include +#include #include #include -#include #include "BitmapHelpers.h" @@ -211,26 +211,27 @@ struct BmpConvertCtx { // Accumulates one MCU row (up to MAX_MCU_HEIGHT source rows × srcWidth pixels) // Filled column-by-column as JPEGDEC callbacks arrive for the same MCU row - uint8_t* mcuBuf; + std::unique_ptr mcuBuf; // Y-axis area averaging accumulators (needsScaling only) int currentOutY; uint32_t nextOutY_srcStart; // 16.16 fixed-point boundary for the next output row - uint32_t* rowAccum; - uint32_t* rowCount; + std::unique_ptr rowAccum; + std::unique_ptr rowCount; - uint8_t* bmpRow; + std::unique_ptr bmpRow; - AtkinsonDitherer* atkinsonDitherer; - FloydSteinbergDitherer* fsDitherer; - Atkinson1BitDitherer* atkinson1BitDitherer; + std::unique_ptr atkinsonDitherer; + std::unique_ptr fsDitherer; + std::unique_ptr atkinson1BitDitherer; bool error; + uint32_t deadline; // 0 = no limit }; // Write a fully-assembled output row (grayscale bytes, length outWidth) to BMP static void writeOutputRow(BmpConvertCtx* ctx, const uint8_t* srcRow, int outY) { - memset(ctx->bmpRow, 0, ctx->bytesPerRow); + memset(ctx->bmpRow.get(), 0, ctx->bytesPerRow); if (USE_8BIT_OUTPUT && !ctx->oneBit) { for (int x = 0; x < ctx->outWidth; x++) { @@ -245,14 +246,13 @@ static void writeOutputRow(BmpConvertCtx* ctx, const uint8_t* srcRow, int outY) if (ctx->atkinson1BitDitherer) ctx->atkinson1BitDitherer->nextRow(); } else { for (int x = 0; x < ctx->outWidth; x++) { - const uint8_t gray = adjustPixel(srcRow[x]); uint8_t twoBit; if (ctx->atkinsonDitherer) { - twoBit = ctx->atkinsonDitherer->processPixel(gray, x); + twoBit = ctx->atkinsonDitherer->processPixel(srcRow[x], x); } else if (ctx->fsDitherer) { - twoBit = ctx->fsDitherer->processPixel(gray, x); + twoBit = ctx->fsDitherer->processPixel(srcRow[x], x); } else { - twoBit = quantize(gray, x, outY); + twoBit = quantize(srcRow[x], x, outY); } ctx->bmpRow[(x * 2) / 8] |= (twoBit << (6 - ((x * 2) % 8))); } @@ -262,12 +262,12 @@ static void writeOutputRow(BmpConvertCtx* ctx, const uint8_t* srcRow, int outY) ctx->fsDitherer->nextRow(); } - ctx->bmpOut->write(ctx->bmpRow, ctx->bytesPerRow); + ctx->bmpOut->write(ctx->bmpRow.get(), ctx->bytesPerRow); } // Flush one scaled output row from Y-axis accumulators and advance currentOutY static void flushScaledRow(BmpConvertCtx* ctx) { - memset(ctx->bmpRow, 0, ctx->bytesPerRow); + memset(ctx->bmpRow.get(), 0, ctx->bytesPerRow); if (USE_8BIT_OUTPUT && !ctx->oneBit) { for (int x = 0; x < ctx->outWidth; x++) { @@ -284,7 +284,7 @@ static void flushScaledRow(BmpConvertCtx* ctx) { if (ctx->atkinson1BitDitherer) ctx->atkinson1BitDitherer->nextRow(); } else { for (int x = 0; x < ctx->outWidth; x++) { - const uint8_t gray = adjustPixel((ctx->rowCount[x] > 0) ? (ctx->rowAccum[x] / ctx->rowCount[x]) : 0); + const uint8_t gray = (ctx->rowCount[x] > 0) ? (ctx->rowAccum[x] / ctx->rowCount[x]) : 0; uint8_t twoBit; if (ctx->atkinsonDitherer) { twoBit = ctx->atkinsonDitherer->processPixel(gray, x); @@ -301,7 +301,7 @@ static void flushScaledRow(BmpConvertCtx* ctx) { ctx->fsDitherer->nextRow(); } - ctx->bmpOut->write(ctx->bmpRow, ctx->bytesPerRow); + ctx->bmpOut->write(ctx->bmpRow.get(), ctx->bytesPerRow); ctx->currentOutY++; } @@ -324,17 +324,23 @@ int bmpDrawCallback(JPEGDRAW* pDraw) { for (int r = 0; r < blockH && r < MAX_MCU_HEIGHT; r++) { const int copyW = (blockX + validW <= ctx->srcWidth) ? validW : (ctx->srcWidth - blockX); if (copyW <= 0) continue; - memcpy(ctx->mcuBuf + r * ctx->srcWidth + blockX, pixels + r * stride, copyW); + memcpy(ctx->mcuBuf.get() + r * ctx->srcWidth + blockX, pixels + r * stride, copyW); } // Wait for the last MCU column before processing any rows if (blockX + validW < ctx->srcWidth) return 1; + if (ctx->deadline != 0 && static_cast(millis() - ctx->deadline) >= 0) { + LOG_ERR("JPG", "Decode deadline exceeded at MCU row %d", blockY); + ctx->error = true; + return 0; + } + // Process each complete source row in this MCU row const int endRow = blockY + blockH; for (int y = blockY; y < endRow && y < ctx->srcHeight; y++) { - const uint8_t* srcRow = ctx->mcuBuf + (y - blockY) * ctx->srcWidth; + const uint8_t* srcRow = ctx->mcuBuf.get() + (y - blockY) * ctx->srcWidth; if (!ctx->needsScaling) { // 1:1 — outWidth == srcWidth, write directly @@ -364,8 +370,8 @@ int bmpDrawCallback(JPEGDRAW* pDraw) { flushScaledRow(ctx); ctx->nextOutY_srcStart = static_cast(ctx->currentOutY + 1) * ctx->scaleY_fp; if (srcY_fp >= ctx->nextOutY_srcStart) continue; - memset(ctx->rowAccum, 0, ctx->outWidth * sizeof(uint32_t)); - memset(ctx->rowCount, 0, ctx->outWidth * sizeof(uint32_t)); + memset(ctx->rowAccum.get(), 0, ctx->outWidth * sizeof(uint32_t)); + memset(ctx->rowCount.get(), 0, ctx->outWidth * sizeof(uint32_t)); } } } @@ -377,7 +383,7 @@ int bmpDrawCallback(JPEGDRAW* pDraw) { // Internal implementation with configurable target size and bit depth bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bmpOut, int targetWidth, int targetHeight, - bool oneBit, bool crop) { + bool oneBit, bool crop, uint32_t deadline) { LOG_DBG("JPG", "Converting JPEG to %s BMP (target: %dx%d)", oneBit ? "1-bit" : "2-bit", targetWidth, targetHeight); if (ESP.getFreeHeap() < MIN_FREE_HEAP) { @@ -387,19 +393,20 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm s_jpegFile = &jpegFile; - JPEGDEC* jpeg = new (std::nothrow) JPEGDEC(); + const auto jpeg = makeUniqueNoThrow(); if (!jpeg) { - LOG_ERR("JPG", "Failed to allocate JPEG decoder"); + LOG_ERR("JPG", "OOM: JPEG decoder"); return false; } int rc = jpeg->open("", bmpJpegOpen, bmpJpegClose, bmpJpegRead, bmpJpegSeek, bmpDrawCallback); if (rc != 1) { LOG_ERR("JPG", "JPEG open failed (err=%d)", jpeg->getLastError()); - delete jpeg; return false; } + const ScopedCleanup cleanup{[&jpeg]() { jpeg->close(); }}; + const int srcWidth = jpeg->getWidth(); const int srcHeight = jpeg->getHeight(); @@ -411,8 +418,6 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm if (srcWidth <= 0 || srcHeight <= 0 || srcWidth > MAX_IMAGE_WIDTH || srcHeight > MAX_IMAGE_HEIGHT) { LOG_DBG("JPG", "Image too large or invalid (%dx%d), max supported: %dx%d", srcWidth, srcHeight, MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT); - jpeg->close(); - delete jpeg; return false; } @@ -471,55 +476,51 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm ctx.scaleX_fp = scaleX_fp; ctx.scaleY_fp = scaleY_fp; ctx.error = false; - - // RAII guard: frees all heap resources on any return path - struct Cleanup { - BmpConvertCtx& ctx; - JPEGDEC* jpeg; - ~Cleanup() { - delete[] ctx.rowAccum; - delete[] ctx.rowCount; - delete ctx.atkinsonDitherer; - delete ctx.fsDitherer; - delete ctx.atkinson1BitDitherer; - free(ctx.mcuBuf); - free(ctx.bmpRow); - jpeg->close(); - delete jpeg; - } - } cleanup{ctx, jpeg}; + ctx.deadline = deadline; // MCU row buffer: MAX_MCU_HEIGHT rows × srcWidth columns of grayscale - ctx.mcuBuf = static_cast(malloc(MAX_MCU_HEIGHT * srcWidth)); + ctx.mcuBuf = makeUniqueNoThrow(MAX_MCU_HEIGHT * srcWidth); if (!ctx.mcuBuf) { - LOG_ERR("JPG", "Failed to allocate MCU buffer (%d bytes)", MAX_MCU_HEIGHT * srcWidth); + LOG_ERR("JPG", "OOM: MCU buffer (%d bytes)", MAX_MCU_HEIGHT * srcWidth); return false; } - memset(ctx.mcuBuf, 0, MAX_MCU_HEIGHT * srcWidth); + memset(ctx.mcuBuf.get(), 0, MAX_MCU_HEIGHT * srcWidth); - ctx.bmpRow = static_cast(malloc(bytesPerRow)); + ctx.bmpRow = makeUniqueNoThrow(bytesPerRow); if (!ctx.bmpRow) { - LOG_ERR("JPG", "Failed to allocate BMP row buffer"); + LOG_ERR("JPG", "OOM: BMP row buffer"); return false; } if (needsScaling) { - ctx.rowAccum = new (std::nothrow) uint32_t[outWidth](); - ctx.rowCount = new (std::nothrow) uint32_t[outWidth](); + ctx.rowAccum = makeUniqueNoThrow(outWidth); + ctx.rowCount = makeUniqueNoThrow(outWidth); if (!ctx.rowAccum || !ctx.rowCount) { - LOG_ERR("JPG", "Failed to allocate scaling buffers"); + LOG_ERR("JPG", "OOM: scaling buffers"); return false; } ctx.nextOutY_srcStart = scaleY_fp; } if (oneBit) { - ctx.atkinson1BitDitherer = new (std::nothrow) Atkinson1BitDitherer(outWidth); + ctx.atkinson1BitDitherer = makeUniqueNoThrow(outWidth); + if (!ctx.atkinson1BitDitherer) { + LOG_ERR("JPG", "OOM: Atkinson1BitDitherer"); + return false; + } } else if (!USE_8BIT_OUTPUT) { if (USE_ATKINSON) { - ctx.atkinsonDitherer = new (std::nothrow) AtkinsonDitherer(outWidth); + ctx.atkinsonDitherer = makeUniqueNoThrow(outWidth); + if (!ctx.atkinsonDitherer) { + LOG_ERR("JPG", "OOM: AtkinsonDitherer"); + return false; + } } else if (USE_FLOYD_STEINBERG) { - ctx.fsDitherer = new (std::nothrow) FloydSteinbergDitherer(outWidth); + ctx.fsDitherer = makeUniqueNoThrow(outWidth); + if (!ctx.fsDitherer) { + LOG_ERR("JPG", "OOM: FloydSteinbergDitherer"); + return false; + } } } @@ -542,17 +543,17 @@ bool JpegToBmpConverter::jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut, bo // Use runtime display dimensions (swapped for portrait cover sizing) const int targetWidth = display.getDisplayHeight(); const int targetHeight = display.getDisplayWidth(); - return jpegFileToBmpStreamInternal(jpegFile, bmpOut, targetWidth, targetHeight, false, crop); + return jpegFileToBmpStreamInternal(jpegFile, bmpOut, targetWidth, targetHeight, false, crop, 0); } // Convert with custom target size (for thumbnails, 2-bit) bool JpegToBmpConverter::jpegFileToBmpStreamWithSize(FsFile& jpegFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight) { - return jpegFileToBmpStreamInternal(jpegFile, bmpOut, targetMaxWidth, targetMaxHeight, false); + return jpegFileToBmpStreamInternal(jpegFile, bmpOut, targetMaxWidth, targetMaxHeight, false, false, 0); } // Convert to 1-bit BMP (black and white only, no grays) for fast home screen rendering bool JpegToBmpConverter::jpegFileTo1BitBmpStreamWithSize(FsFile& jpegFile, Print& bmpOut, int targetMaxWidth, - int targetMaxHeight) { - return jpegFileToBmpStreamInternal(jpegFile, bmpOut, targetMaxWidth, targetMaxHeight, true, true); + int targetMaxHeight, uint32_t deadline) { + return jpegFileToBmpStreamInternal(jpegFile, bmpOut, targetMaxWidth, targetMaxHeight, true, true, deadline); } diff --git a/lib/JpegToBmpConverter/JpegToBmpConverter.h b/lib/JpegToBmpConverter/JpegToBmpConverter.h index 66f77f6735..a80a66510d 100644 --- a/lib/JpegToBmpConverter/JpegToBmpConverter.h +++ b/lib/JpegToBmpConverter/JpegToBmpConverter.h @@ -7,12 +7,13 @@ class ZipFile; class JpegToBmpConverter { static bool jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bmpOut, int targetWidth, int targetHeight, - bool oneBit, bool crop = true); + bool oneBit, bool crop, uint32_t deadline); public: static bool jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut, bool crop = true); // Convert with custom target size (for thumbnails) static bool jpegFileToBmpStreamWithSize(FsFile& jpegFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight); // Convert to 1-bit BMP (black and white only, no grays) for fast home screen rendering - static bool jpegFileTo1BitBmpStreamWithSize(FsFile& jpegFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight); + static bool jpegFileTo1BitBmpStreamWithSize(FsFile& jpegFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight, + uint32_t deadline = 0); }; diff --git a/lib/KOReaderSync/KOReaderSyncClient.cpp b/lib/KOReaderSync/KOReaderSyncClient.cpp index e0bc410d19..1e4f512d96 100644 --- a/lib/KOReaderSync/KOReaderSyncClient.cpp +++ b/lib/KOReaderSync/KOReaderSyncClient.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -75,6 +74,11 @@ esp_http_client_handle_t createClient(const char* url, ResponseBuffer* buf, config.buffer_size_tx = HTTP_BUF_SIZE; config.crt_bundle_attach = esp_crt_bundle_attach; + // HTTP Basic Auth for Calibre-Web-Automated compatibility + config.username = KOREADER_STORE.getUsername().c_str(); + config.password = KOREADER_STORE.getPassword().c_str(); + config.auth_type = HTTP_AUTH_TYPE_BASIC; + esp_http_client_handle_t client = esp_http_client_init(&config); if (!client) return nullptr; @@ -87,16 +91,6 @@ esp_http_client_handle_t createClient(const char* url, ResponseBuffer* buf, return nullptr; } - // HTTP Basic Auth for Calibre-Web-Automated compatibility - std::string credentials = KOREADER_STORE.getUsername() + ":" + KOREADER_STORE.getPassword(); - String encoded = base64::encode(reinterpret_cast(credentials.data()), credentials.size()); - std::string authHeader = "Basic " + std::string(encoded.c_str()); - if (esp_http_client_set_header(client, "Authorization", authHeader.c_str()) != ESP_OK) { - LOG_ERR("KOSync", "Failed to set Authorization header"); - esp_http_client_cleanup(client); - return nullptr; - } - return client; } } // namespace diff --git a/lib/Memory/Memory.h b/lib/Memory/Memory.h new file mode 100644 index 0000000000..0093a8526e --- /dev/null +++ b/lib/Memory/Memory.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include +#include +#include + +// Nothrow versions of std::make_unique. Return nullptr on allocation failure +// instead of calling abort() (the default when exceptions are disabled on ESP32). +// +// Single object: +// auto obj = makeUniqueNoThrow(); +// if (!obj) { LOG_ERR("TAG", "OOM"); return false; } +// +// Array: +// auto buf = makeUniqueNoThrow(size); +// if (!buf) { LOG_ERR("TAG", "OOM"); return false; } +// buf[0] = 0xFF; +// someApi(buf.get(), size); +// + +template + requires(!std::is_array_v) +std::unique_ptr makeUniqueNoThrow(Args&&... args) { + return std::unique_ptr(new (std::nothrow) T(std::forward(args)...)); +} + +template + requires std::is_unbounded_array_v +std::unique_ptr makeUniqueNoThrow(size_t count) { + using Elem = std::remove_extent_t; + return std::unique_ptr(new (std::nothrow) Elem[count]()); +} + +// Helper struct to call a cleanup function on exit from any scope. +// Use with a lambda to avoid unnecessary allocations from std::function/std::bind: +// Example: +// auto jpeg = makeUniqueNoThrow(); +// ScopedCleanup cleanup{[&jpeg]{ jpeg->close(); }}; +// +template +struct [[nodiscard]] ScopedCleanup final { + const F fn; + explicit ScopedCleanup(F f) : fn{std::move(f)} {} + ScopedCleanup(const ScopedCleanup&) = delete; + ScopedCleanup& operator=(const ScopedCleanup&) = delete; + ScopedCleanup(ScopedCleanup&&) = delete; + ScopedCleanup& operator=(ScopedCleanup&&) = delete; + ~ScopedCleanup() { fn(); } +}; + +template +ScopedCleanup(F) -> ScopedCleanup; diff --git a/lib/PngToBmpConverter/PngToBmpConverter.cpp b/lib/PngToBmpConverter/PngToBmpConverter.cpp index 5a8c4752a4..3a9fc17fa8 100644 --- a/lib/PngToBmpConverter/PngToBmpConverter.cpp +++ b/lib/PngToBmpConverter/PngToBmpConverter.cpp @@ -396,7 +396,7 @@ static void convertScanlineToGray(const PngDecodeContext& ctx, uint8_t* grayRow) } bool PngToBmpConverter::pngFileToBmpStreamInternal(FsFile& pngFile, Print& bmpOut, int targetWidth, int targetHeight, - bool oneBit, bool crop) { + bool oneBit, bool crop, uint32_t deadline) { LOG_DBG("PNG", "Converting PNG to %s BMP (target: %dx%d)", oneBit ? "1-bit" : "2-bit", targetWidth, targetHeight); // Verify PNG signature @@ -666,6 +666,12 @@ bool PngToBmpConverter::pngFileToBmpStreamInternal(FsFile& pngFile, Print& bmpOu // Process each scanline for (uint32_t y = 0; y < height; y++) { + if (deadline != 0 && static_cast(millis() - deadline) >= 0) { + LOG_ERR("PNG", "Decode deadline exceeded at scanline %u", y); + success = false; + break; + } + // Decode one scanline if (!decodeScanline(ctx)) { LOG_ERR("PNG", "Failed to decode scanline %u", y); @@ -824,15 +830,15 @@ bool PngToBmpConverter::pngFileToBmpStream(FsFile& pngFile, Print& bmpOut, bool // Use runtime display dimensions (swapped for portrait cover sizing) const int targetWidth = display.getDisplayHeight(); const int targetHeight = display.getDisplayWidth(); - return pngFileToBmpStreamInternal(pngFile, bmpOut, targetWidth, targetHeight, false, crop); + return pngFileToBmpStreamInternal(pngFile, bmpOut, targetWidth, targetHeight, false, crop, 0); } bool PngToBmpConverter::pngFileToBmpStreamWithSize(FsFile& pngFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight) { - return pngFileToBmpStreamInternal(pngFile, bmpOut, targetMaxWidth, targetMaxHeight, false); + return pngFileToBmpStreamInternal(pngFile, bmpOut, targetMaxWidth, targetMaxHeight, false, false, 0); } bool PngToBmpConverter::pngFileTo1BitBmpStreamWithSize(FsFile& pngFile, Print& bmpOut, int targetMaxWidth, - int targetMaxHeight) { - return pngFileToBmpStreamInternal(pngFile, bmpOut, targetMaxWidth, targetMaxHeight, true, true); + int targetMaxHeight, uint32_t deadline) { + return pngFileToBmpStreamInternal(pngFile, bmpOut, targetMaxWidth, targetMaxHeight, true, true, deadline); } diff --git a/lib/PngToBmpConverter/PngToBmpConverter.h b/lib/PngToBmpConverter/PngToBmpConverter.h index bf9d3a2c69..c723ffa4bf 100644 --- a/lib/PngToBmpConverter/PngToBmpConverter.h +++ b/lib/PngToBmpConverter/PngToBmpConverter.h @@ -6,10 +6,11 @@ class Print; class PngToBmpConverter { static bool pngFileToBmpStreamInternal(FsFile& pngFile, Print& bmpOut, int targetWidth, int targetHeight, bool oneBit, - bool crop = true); + bool crop, uint32_t deadline); public: static bool pngFileToBmpStream(FsFile& pngFile, Print& bmpOut, bool crop = true); static bool pngFileToBmpStreamWithSize(FsFile& pngFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight); - static bool pngFileTo1BitBmpStreamWithSize(FsFile& pngFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight); + static bool pngFileTo1BitBmpStreamWithSize(FsFile& pngFile, Print& bmpOut, int targetMaxWidth, int targetMaxHeight, + uint32_t deadline = 0); }; diff --git a/lib/Xtc/Xtc.cpp b/lib/Xtc/Xtc.cpp index 5f0388d28f..1313bfe0b8 100644 --- a/lib/Xtc/Xtc.cpp +++ b/lib/Xtc/Xtc.cpp @@ -11,6 +11,16 @@ #include #include +static inline void computeSrcRange(uint32_t dstCoord, uint32_t scaleInv, uint32_t maxSrc, uint32_t& srcStart, + uint32_t& srcEnd) { + srcStart = (static_cast(dstCoord) * scaleInv) >> 16; + srcEnd = (static_cast(dstCoord + 1) * scaleInv) >> 16; + if (srcStart >= maxSrc) srcStart = maxSrc - 1; + if (srcEnd > maxSrc) srcEnd = maxSrc; + if (srcEnd <= srcStart) srcEnd = srcStart + 1; + if (srcEnd > maxSrc) srcEnd = maxSrc; +} + bool Xtc::load() { LOG_DBG("XTC", "Loading XTC: %s", filepath.c_str()); @@ -142,22 +152,150 @@ bool Xtc::generateCoverBmp() const { // Get bit depth const uint8_t bitDepth = parser->getBitDepth(); - // Allocate buffer for page data - // XTG (1-bit): Row-major, ((width+7)/8) * height bytes - // XTH (2-bit): Two bit planes, column-major, ((width * height + 7) / 8) * 2 bytes - size_t bitmapSize; + // --- 2-bit XTCH/XTH: two-pass plane loading to stay within heap limits --- + // Each plane is ~48KB (fits MaxAlloc); both planes together (~96KB) do not. if (bitDepth == 2) { - bitmapSize = ((static_cast(pageInfo.width) * pageInfo.height + 7) / 8) * 2; - } else { - bitmapSize = ((pageInfo.width + 7) / 8) * pageInfo.height; + const size_t planeSize = (static_cast(pageInfo.width) * pageInfo.height + 7) / 8; + const size_t colBytes = (pageInfo.height + 7) / 8; + const uint32_t rowSize2 = ((static_cast(pageInfo.width) * 2 + 31) / 32) * 4; + const std::string tempPath = cachePath + "/cover_tmp.bmp"; + + // Pass 1: load plane1, write raw 2-bit rows to temp file (bit2=0, pixel = bit1<<1) + { + uint8_t* plane1 = static_cast(malloc(planeSize)); + if (!plane1) { + LOG_ERR("XTC", "Failed to alloc plane1 (%lu bytes)", planeSize); + return false; + } + if (const_cast(parser.get())->loadPageMsb(0, plane1, planeSize) == 0) { + LOG_ERR("XTC", "Failed to load plane1 for cover"); + free(plane1); + return false; + } + FsFile tempFile; + if (!Storage.openFileForWrite("XTC", tempPath, tempFile)) { + LOG_ERR("XTC", "Failed to open temp cover file"); + free(plane1); + return false; + } + uint8_t rowBuf[256]; + for (uint16_t y = 0; y < pageInfo.height; y++) { + memset(rowBuf, 0, rowSize2); + for (uint16_t x = 0; x < pageInfo.width; x++) { + const size_t bo = (pageInfo.width - 1 - x) * colBytes + y / 8; + const uint8_t bit1 = (plane1[bo] >> (7 - (y % 8))) & 1; + rowBuf[x / 4] |= static_cast((bit1 << 1) << (6 - (x % 4) * 2)); + } + if (tempFile.write(rowBuf, rowSize2) != rowSize2) { + LOG_ERR("XTC", "Failed to write temp cover row %u", y); + tempFile.close(); + free(plane1); + Storage.remove(tempPath.c_str()); + return false; + } + } + tempFile.close(); + free(plane1); + } + + // Pass 2: load plane2, combine with pass1, write final 2-bit BMP + { + uint8_t* plane2 = static_cast(malloc(planeSize)); + if (!plane2) { + LOG_ERR("XTC", "Failed to alloc plane2 (%lu bytes)", planeSize); + Storage.remove(tempPath.c_str()); + return false; + } + if (const_cast(parser.get())->loadPageLsb(0, plane2, planeSize) == 0) { + LOG_ERR("XTC", "Failed to load plane2 for cover"); + free(plane2); + Storage.remove(tempPath.c_str()); + return false; + } + FsFile tempFile, coverFile; + if (!Storage.openFileForRead("XTC", tempPath, tempFile)) { + free(plane2); + Storage.remove(tempPath.c_str()); + return false; + } + if (!Storage.openFileForWrite("XTC", getCoverBmpPath(), coverFile)) { + tempFile.close(); + free(plane2); + Storage.remove(tempPath.c_str()); + return false; + } + // Write 2-bit BMP header + const uint32_t imageSize2 = rowSize2 * pageInfo.height; + const uint32_t fileSize2 = 14 + 40 + 16 + imageSize2; + static constexpr uint8_t bmpHeader2[74] = { + 'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, + 0xFF, 0xFF, 0xFF, 0x00, 0xAA, 0xAA, 0xAA, 0x00, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t hdr[74]; + memcpy(hdr, bmpHeader2, 74); + memcpy(hdr + 2, &fileSize2, 4); + const uint32_t doff2 = 14 + 40 + 16; + memcpy(hdr + 10, &doff2, 4); + int32_t ww2 = pageInfo.width; + memcpy(hdr + 18, &ww2, 4); + int32_t hh2 = -static_cast(pageInfo.height); + memcpy(hdr + 22, &hh2, 4); + memcpy(hdr + 34, &imageSize2, 4); + const uint32_t ppm2 = 2835; + memcpy(hdr + 38, &ppm2, 4); + memcpy(hdr + 42, &ppm2, 4); + if (coverFile.write(hdr, 74) != 74) { + LOG_ERR("XTC", "Failed to write 2-bit BMP header"); + coverFile.close(); + tempFile.close(); + free(plane2); + Storage.remove(tempPath.c_str()); + return false; + } + // For each row: read pass1 row (bit1 only), OR in bit2, write to final + uint8_t rowBuf[256]; + for (uint16_t y = 0; y < pageInfo.height; y++) { + memset(rowBuf, 0, rowSize2); + if (tempFile.read(rowBuf, rowSize2) != rowSize2) { + LOG_ERR("XTC", "Failed to read temp cover row %u", y); + coverFile.close(); + tempFile.close(); + free(plane2); + Storage.remove(tempPath.c_str()); + return false; + } + for (uint16_t x = 0; x < pageInfo.width; x++) { + const size_t bo = (pageInfo.width - 1 - x) * colBytes + y / 8; + const uint8_t bit2 = (plane2[bo] >> (7 - (y % 8))) & 1; + rowBuf[x / 4] |= static_cast(bit2 << (6 - (x % 4) * 2)); + } + if (coverFile.write(rowBuf, rowSize2) != rowSize2) { + LOG_ERR("XTC", "Failed to write cover row %u", y); + coverFile.close(); + tempFile.close(); + free(plane2); + Storage.remove(tempPath.c_str()); + return false; + } + } + coverFile.close(); + tempFile.close(); + free(plane2); + Storage.remove(tempPath.c_str()); + } + LOG_DBG("XTC", "Generated 2-bit cover BMP: %s", getCoverBmpPath().c_str()); + return true; } + + // 1-bit (XTC/XTG) path + const size_t bitmapSize = ((pageInfo.width + 7) / 8) * pageInfo.height; uint8_t* pageBuffer = static_cast(malloc(bitmapSize)); if (!pageBuffer) { LOG_ERR("XTC", "Failed to allocate page buffer (%lu bytes)", bitmapSize); return false; } - // Load first page (cover) size_t bytesRead = const_cast(parser.get())->loadPage(0, pageBuffer, bitmapSize); if (bytesRead == 0) { LOG_ERR("XTC", "Failed to load cover page"); @@ -165,7 +303,6 @@ bool Xtc::generateCoverBmp() const { return false; } - // Create BMP file FsFile coverBmp; if (!Storage.openFileForWrite("XTC", getCoverBmpPath(), coverBmp)) { LOG_DBG("XTC", "Failed to create cover BMP file"); @@ -173,29 +310,23 @@ bool Xtc::generateCoverBmp() const { return false; } - // Write 1-bit BMP header (top-down row order) BmpHeader bmpHeader; createBmpHeader(&bmpHeader, pageInfo.width, pageInfo.height, BmpRowOrder::TopDown); coverBmp.write(reinterpret_cast(&bmpHeader), sizeof(bmpHeader)); const uint32_t rowSize = ((pageInfo.width + 31) / 32) * 4; + const size_t srcRowSize = (pageInfo.width + 7) / 8; // Write bitmap data // BMP requires 4-byte row alignment - const size_t dstRowSize = (pageInfo.width + 7) / 8; // 1-bit destination row size + const size_t dstRowSize = (pageInfo.width + 7) / 8; if (bitDepth == 2) { - // XTH 2-bit mode: Two bit planes, column-major order - // - Columns scanned right to left (x = width-1 down to 0) - // - 8 vertical pixels per byte (MSB = topmost pixel in group) - // - First plane: Bit1, Second plane: Bit2 - // - Pixel value = (bit1 << 1) | bit2 const size_t planeSize = (static_cast(pageInfo.width) * pageInfo.height + 7) / 8; - const uint8_t* plane1 = pageBuffer; // Bit1 plane - const uint8_t* plane2 = pageBuffer + planeSize; // Bit2 plane - const size_t colBytes = (pageInfo.height + 7) / 8; // Bytes per column + const uint8_t* plane1 = pageBuffer; + const uint8_t* plane2 = pageBuffer + planeSize; + const size_t colBytes = (pageInfo.height + 7) / 8; - // Allocate a row buffer for 1-bit output uint8_t* rowBuffer = static_cast(malloc(dstRowSize)); if (!rowBuffer) { free(pageBuffer); @@ -203,32 +334,27 @@ bool Xtc::generateCoverBmp() const { } for (uint16_t y = 0; y < pageInfo.height; y++) { - memset(rowBuffer, 0xFF, dstRowSize); // Start with all white + memset(rowBuffer, 0xFF, dstRowSize); for (uint16_t x = 0; x < pageInfo.width; x++) { - // Column-major, right to left: column index = (width - 1 - x) const size_t colIndex = pageInfo.width - 1 - x; const size_t byteInCol = y / 8; - const size_t bitInByte = 7 - (y % 8); // MSB = topmost pixel + const size_t bitInByte = 7 - (y % 8); const size_t byteOffset = colIndex * colBytes + byteInCol; const uint8_t bit1 = (plane1[byteOffset] >> bitInByte) & 1; const uint8_t bit2 = (plane2[byteOffset] >> bitInByte) & 1; const uint8_t pixelValue = (bit1 << 1) | bit2; - // Threshold: 0=white (1); 1,2,3=black (0) if (pixelValue >= 1) { - // Set bit to 0 (black) in BMP format const size_t dstByte = x / 8; const size_t dstBit = 7 - (x % 8); rowBuffer[dstByte] &= ~(1 << dstBit); } } - // Write converted row coverBmp.write(rowBuffer, dstRowSize); - // Pad to 4-byte boundary uint8_t padding[4] = {0, 0, 0, 0}; size_t paddingSize = rowSize - dstRowSize; if (paddingSize > 0) { @@ -238,14 +364,9 @@ bool Xtc::generateCoverBmp() const { free(rowBuffer); } else { - // 1-bit source: write directly with proper padding - const size_t srcRowSize = (pageInfo.width + 7) / 8; - for (uint16_t y = 0; y < pageInfo.height; y++) { - // Write source row coverBmp.write(pageBuffer + y * srcRowSize, srcRowSize); - // Pad to 4-byte boundary uint8_t padding[4] = {0, 0, 0, 0}; size_t paddingSize = rowSize - srcRowSize; if (paddingSize > 0) { @@ -328,20 +449,141 @@ bool Xtc::generateThumbBmp(int height) const { LOG_DBG("XTC", "Generating thumb BMP: %dx%d -> %dx%d (scale: %.3f)", pageInfo.width, pageInfo.height, thumbWidth, thumbHeight, scale); - // Allocate buffer for page data - size_t bitmapSize; + // For 2-bit (XTCH): strip-based sequential plane loading → area-averaged Atkinson dithered 1-bit BMP. + // Loads each plane separately (~48KB) in strips to stay within memory constraints after reader sessions. + // Uses area-averaging (same formula as the 1-bit path) for accurate luminance computation. if (bitDepth == 2) { - bitmapSize = ((static_cast(pageInfo.width) * pageInfo.height + 7) / 8) * 2; - } else { - bitmapSize = ((pageInfo.width + 7) / 8) * pageInfo.height; + const size_t planeSize = (static_cast(pageInfo.width) * pageInfo.height + 7) / 8; + const size_t colBytes = (pageInfo.height + 7) / 8; + const uint32_t scaleInv_fp2 = static_cast(65536.0f / scale); + + uint8_t* planeBuffer = static_cast(malloc(planeSize)); + if (!planeBuffer) { + LOG_ERR("XTC", "Failed to alloc plane buffer (%lu bytes)", static_cast(planeSize)); + return false; + } + + const size_t stripBudget = (static_cast(thumbWidth) * thumbHeight + 7) / 8; + const int stripRows = std::min(static_cast(thumbHeight), static_cast(stripBudget / thumbWidth)); + + uint8_t* darkCount1Buf = static_cast(malloc(static_cast(stripRows) * thumbWidth)); + if (!darkCount1Buf) { + LOG_ERR("XTC", "Failed to alloc darkCount1 buffer (%lu bytes)", + static_cast(static_cast(stripRows) * thumbWidth)); + free(planeBuffer); + return false; + } + + FsFile thumbBmp; + if (!Storage.openFileForWrite("XTC", getThumbBmpPath(height), thumbBmp)) { + free(darkCount1Buf); + free(planeBuffer); + return false; + } + + BmpHeader bmpHeader; + createBmpHeader(&bmpHeader, thumbWidth, thumbHeight, BmpRowOrder::TopDown); + thumbBmp.write(reinterpret_cast(&bmpHeader), sizeof(bmpHeader)); + + const uint32_t rowSize = (thumbWidth + 31) / 32 * 4; + uint8_t* rowBuf = static_cast(malloc(rowSize)); + if (!rowBuf) { + free(darkCount1Buf); + free(planeBuffer); + thumbBmp.close(); + Storage.remove(getThumbBmpPath(height).c_str()); + return false; + } + + Atkinson1BitDitherer ditherer(thumbWidth); + + for (int stripStart = 0; stripStart < static_cast(thumbHeight); stripStart += stripRows) { + const int curRows = std::min(stripRows, static_cast(thumbHeight) - stripStart); + + // Pass 1: plane1 (bit1/MSB) — count dark pixels per output pixel + if (const_cast(parser.get())->loadPageMsb(0, planeBuffer, planeSize) == 0) { + LOG_ERR("XTC", "Failed to load plane1 for thumb"); + free(rowBuf); + free(darkCount1Buf); + free(planeBuffer); + thumbBmp.close(); + Storage.remove(getThumbBmpPath(height).c_str()); + return false; + } + for (int dy = 0; dy < curRows; dy++) { + const uint16_t dstY = static_cast(stripStart + dy); + for (uint16_t dstX = 0; dstX < thumbWidth; dstX++) { + uint32_t srcYS, srcYE, srcXS, srcXE; + computeSrcRange(dstY, scaleInv_fp2, pageInfo.height, srcYS, srcYE); + computeSrcRange(dstX, scaleInv_fp2, pageInfo.width, srcXS, srcXE); + uint32_t darkCount = 0; + for (uint32_t sy = srcYS; sy < srcYE; sy++) + for (uint32_t sx = srcXS; sx < srcXE; sx++) { + const size_t bo = (pageInfo.width - 1 - sx) * colBytes + sy / 8; + if (bo < planeSize) { + if ((planeBuffer[bo] >> (7 - (sy % 8))) & 1) darkCount++; + } + } + darkCount1Buf[static_cast(dy) * thumbWidth + dstX] = static_cast(darkCount); + } + } + + // Pass 2: plane2 (bit2/LSB) — combine with darkCount1 → area-average → dither → write BMP rows + if (const_cast(parser.get())->loadPageLsb(0, planeBuffer, planeSize) == 0) { + LOG_ERR("XTC", "Failed to load plane2 for thumb"); + free(rowBuf); + free(darkCount1Buf); + free(planeBuffer); + thumbBmp.close(); + Storage.remove(getThumbBmpPath(height).c_str()); + return false; + } + for (int dy = 0; dy < curRows; dy++) { + memset(rowBuf, 0xFF, rowSize); + const uint16_t dstY = static_cast(stripStart + dy); + for (uint16_t dstX = 0; dstX < thumbWidth; dstX++) { + uint32_t srcYS, srcYE, srcXS, srcXE; + computeSrcRange(dstY, scaleInv_fp2, pageInfo.height, srcYS, srcYE); + computeSrcRange(dstX, scaleInv_fp2, pageInfo.width, srcXS, srcXE); + uint32_t darkCount = 0, totalCount = 0; + for (uint32_t sy = srcYS; sy < srcYE; sy++) + for (uint32_t sx = srcXS; sx < srcXE; sx++) { + const size_t bo = (pageInfo.width - 1 - sx) * colBytes + sy / 8; + if (bo < planeSize) { + if ((planeBuffer[bo] >> (7 - (sy % 8))) & 1) darkCount++; + totalCount++; + } + } + const uint32_t dark1 = darkCount1Buf[static_cast(dy) * thumbWidth + dstX]; + const int lumSum = static_cast((totalCount - dark1) * 85 + (totalCount - darkCount) * 170); + const int avgLum = (totalCount > 0) ? (lumSum * 255 / totalCount) / 255 : 255; + const uint8_t bit = ditherer.processPixel(avgLum, dstX); + if (!bit) { + const size_t bi = dstX / 8; + if (bi < rowSize) rowBuf[bi] &= ~(1 << (7 - (dstX % 8))); + } + } + thumbBmp.write(rowBuf, rowSize); + ditherer.nextRow(); + } + } + + free(rowBuf); + free(darkCount1Buf); + free(planeBuffer); + thumbBmp.close(); + LOG_DBG("XTC", "Generated 1-bit thumb BMP with dithering (%dx%d): %s", thumbWidth, thumbHeight, + getThumbBmpPath(height).c_str()); + return true; } + + // 1-bit (XTC/XTG) path + const size_t bitmapSize = ((pageInfo.width + 7) / 8) * pageInfo.height; uint8_t* pageBuffer = static_cast(malloc(bitmapSize)); if (!pageBuffer) { LOG_ERR("XTC", "Failed to allocate page buffer (%lu bytes)", bitmapSize); return false; } - - // Load first page (cover) size_t bytesRead = const_cast(parser.get())->loadPage(0, pageBuffer, bitmapSize); if (bytesRead == 0) { LOG_ERR("XTC", "Failed to load cover page for thumb"); @@ -349,7 +591,6 @@ bool Xtc::generateThumbBmp(int height) const { return false; } - // Create thumbnail BMP file - use 1-bit format for fast home screen rendering (no gray passes) FsFile thumbBmp; if (!Storage.openFileForWrite("XTC", getThumbBmpPath(height), thumbBmp)) { LOG_DBG("XTC", "Failed to create thumb BMP file"); @@ -357,126 +598,56 @@ bool Xtc::generateThumbBmp(int height) const { return false; } - // Write 1-bit BMP header (top-down row order) BmpHeader bmpHeader; createBmpHeader(&bmpHeader, thumbWidth, thumbHeight, BmpRowOrder::TopDown); thumbBmp.write(reinterpret_cast(&bmpHeader), sizeof(bmpHeader)); const uint32_t rowSize = (thumbWidth + 31) / 32 * 4; - - // Allocate row buffer for 1-bit output uint8_t* rowBuffer = static_cast(malloc(rowSize)); if (!rowBuffer) { free(pageBuffer); return false; } - // Fixed-point scale factor (16.16) - uint32_t scaleInv_fp = static_cast(65536.0f / scale); - - // Pre-calculate plane info for 2-bit mode - const size_t planeSize = (bitDepth == 2) ? ((static_cast(pageInfo.width) * pageInfo.height + 7) / 8) : 0; - const uint8_t* plane1 = (bitDepth == 2) ? pageBuffer : nullptr; - const uint8_t* plane2 = (bitDepth == 2) ? pageBuffer + planeSize : nullptr; - const size_t colBytes = (bitDepth == 2) ? ((pageInfo.height + 7) / 8) : 0; - const size_t srcRowBytes = (bitDepth == 1) ? ((pageInfo.width + 7) / 8) : 0; + Atkinson1BitDitherer ditherer(thumbWidth); + const uint32_t scaleInv_fp = static_cast(65536.0f / scale); + const size_t srcRowBytes = (pageInfo.width + 7) / 8; for (uint16_t dstY = 0; dstY < thumbHeight; dstY++) { - memset(rowBuffer, 0xFF, rowSize); // Start with all white (bit 1) - - // Calculate source Y range with bounds checking - uint32_t srcYStart = (static_cast(dstY) * scaleInv_fp) >> 16; - uint32_t srcYEnd = (static_cast(dstY + 1) * scaleInv_fp) >> 16; - if (srcYStart >= pageInfo.height) srcYStart = pageInfo.height - 1; - if (srcYEnd > pageInfo.height) srcYEnd = pageInfo.height; - if (srcYEnd <= srcYStart) srcYEnd = srcYStart + 1; - if (srcYEnd > pageInfo.height) srcYEnd = pageInfo.height; + memset(rowBuffer, 0xFF, rowSize); + uint32_t srcYStart, srcYEnd; + computeSrcRange(dstY, scaleInv_fp, pageInfo.height, srcYStart, srcYEnd); for (uint16_t dstX = 0; dstX < thumbWidth; dstX++) { - // Calculate source X range with bounds checking - uint32_t srcXStart = (static_cast(dstX) * scaleInv_fp) >> 16; - uint32_t srcXEnd = (static_cast(dstX + 1) * scaleInv_fp) >> 16; - if (srcXStart >= pageInfo.width) srcXStart = pageInfo.width - 1; - if (srcXEnd > pageInfo.width) srcXEnd = pageInfo.width; - if (srcXEnd <= srcXStart) srcXEnd = srcXStart + 1; - if (srcXEnd > pageInfo.width) srcXEnd = pageInfo.width; - - // Area averaging: sum grayscale values (0-255 range) - uint32_t graySum = 0; - uint32_t totalCount = 0; + uint32_t srcXStart, srcXEnd; + computeSrcRange(dstX, scaleInv_fp, pageInfo.width, srcXStart, srcXEnd); + uint32_t graySum = 0, totalCount = 0; for (uint32_t srcY = srcYStart; srcY < srcYEnd && srcY < pageInfo.height; srcY++) { for (uint32_t srcX = srcXStart; srcX < srcXEnd && srcX < pageInfo.width; srcX++) { - uint8_t grayValue = 255; // Default: white - - if (bitDepth == 2) { - // XTH 2-bit mode: pixel value 0-3 - // Bounds check for column index - if (srcX < pageInfo.width) { - const size_t colIndex = pageInfo.width - 1 - srcX; - const size_t byteInCol = srcY / 8; - const size_t bitInByte = 7 - (srcY % 8); - const size_t byteOffset = colIndex * colBytes + byteInCol; - // Bounds check for buffer access - if (byteOffset < planeSize) { - const uint8_t bit1 = (plane1[byteOffset] >> bitInByte) & 1; - const uint8_t bit2 = (plane2[byteOffset] >> bitInByte) & 1; - const uint8_t pixelValue = (bit1 << 1) | bit2; - // Convert 2-bit (0-3) to grayscale: 0=black, 3=white - // pixelValue: 0=white, 1=light gray, 2=dark gray, 3=black (XTC polarity) - grayValue = (3 - pixelValue) * 85; // 0->255, 1->170, 2->85, 3->0 - } - } - } else { - // 1-bit mode - const size_t byteIdx = srcY * srcRowBytes + srcX / 8; - const size_t bitIdx = 7 - (srcX % 8); - // Bounds check for buffer access - if (byteIdx < bitmapSize) { - const uint8_t pixelBit = (pageBuffer[byteIdx] >> bitIdx) & 1; - // XTC 1-bit polarity: 0=black, 1=white (same as BMP palette) - grayValue = pixelBit ? 255 : 0; - } + const size_t byteIdx = srcY * srcRowBytes + srcX / 8; + if (byteIdx < bitmapSize) { + graySum += ((pageBuffer[byteIdx] >> (7 - (srcX % 8))) & 1) ? 255 : 0; + totalCount++; } - - graySum += grayValue; - totalCount++; } } - // Calculate average grayscale and quantize to 1-bit with noise dithering - uint8_t avgGray = (totalCount > 0) ? static_cast(graySum / totalCount) : 255; - - // Hash-based noise dithering for 1-bit output - uint32_t hash = static_cast(dstX) * 374761393u + static_cast(dstY) * 668265263u; - hash = (hash ^ (hash >> 13)) * 1274126177u; - const int threshold = static_cast(hash >> 24); // 0-255 - const int adjustedThreshold = 128 + ((threshold - 128) / 2); // Range: 64-192 - - // Quantize to 1-bit: 0=black, 1=white - uint8_t oneBit = (avgGray >= adjustedThreshold) ? 1 : 0; - - // Pack 1-bit value into row buffer (MSB first, 8 pixels per byte) - const size_t byteIndex = dstX / 8; - const size_t bitOffset = 7 - (dstX % 8); - // Bounds check for row buffer access - if (byteIndex < rowSize) { - if (oneBit) { - rowBuffer[byteIndex] |= (1 << bitOffset); // Set bit for white - } else { - rowBuffer[byteIndex] &= ~(1 << bitOffset); // Clear bit for black - } + const int avgGray = (totalCount > 0) ? static_cast(graySum * 255 / totalCount) / 255 : 255; + const uint8_t bit = ditherer.processPixel(avgGray, dstX); + if (!bit) { + const size_t bi = dstX / 8; + if (bi < rowSize) rowBuffer[bi] &= ~(1 << (7 - (dstX % 8))); } } - - // Write row (already padded to 4-byte boundary by rowSize) thumbBmp.write(rowBuffer, rowSize); + ditherer.nextRow(); } free(rowBuffer); free(pageBuffer); - - LOG_DBG("XTC", "Generated thumb BMP (%dx%d): %s", thumbWidth, thumbHeight, getThumbBmpPath(height).c_str()); + LOG_DBG("XTC", "Generated 1-bit thumb BMP with Atkinson dithering (%dx%d): %s", thumbWidth, thumbHeight, + getThumbBmpPath(height).c_str()); return true; } @@ -515,6 +686,20 @@ size_t Xtc::loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize) con return const_cast(parser.get())->loadPage(pageIndex, buffer, bufferSize); } +size_t Xtc::loadPageMsb(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize) const { + if (!loaded || !parser) { + return 0; + } + return const_cast(parser.get())->loadPageMsb(pageIndex, buffer, bufferSize); +} + +size_t Xtc::loadPageLsb(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize) const { + if (!loaded || !parser) { + return 0; + } + return const_cast(parser.get())->loadPageLsb(pageIndex, buffer, bufferSize); +} + xtc::XtcError Xtc::loadPageStreaming(uint32_t pageIndex, std::function callback, size_t chunkSize) const { diff --git a/lib/Xtc/Xtc.h b/lib/Xtc/Xtc.h index 3dbd160b4f..912f6ff162 100644 --- a/lib/Xtc/Xtc.h +++ b/lib/Xtc/Xtc.h @@ -82,6 +82,8 @@ class Xtc { * @return Number of bytes read */ size_t loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize) const; + size_t loadPageMsb(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize) const; + size_t loadPageLsb(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize) const; /** * Load page with streaming callback diff --git a/lib/Xtc/Xtc/XtcParser.cpp b/lib/Xtc/Xtc/XtcParser.cpp index 877d82370b..7cdd4df532 100644 --- a/lib/Xtc/Xtc/XtcParser.cpp +++ b/lib/Xtc/Xtc/XtcParser.cpp @@ -467,6 +467,134 @@ size_t XtcParser::loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSiz return bytesRead; } +size_t XtcParser::loadPageMsb(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize) { + if (m_bitDepth != 2) { + return loadPage(pageIndex, buffer, bufferSize); + } + + if (!m_isOpen) { + m_lastError = XtcError::FILE_NOT_FOUND; + return 0; + } + + if (pageIndex >= m_header.pageCount) { + m_lastError = XtcError::PAGE_OUT_OF_RANGE; + return 0; + } + + PageInfo page; + if (!readPageTableEntry(pageIndex, page)) { + m_lastError = XtcError::READ_ERROR; + return 0; + } + + if (!ensureFileOpen()) { + m_lastError = XtcError::FILE_NOT_FOUND; + return 0; + } + + if (!m_file.seek(page.offset)) { + LOG_DBG("XTC", "Failed to seek to page %u at offset %lu", pageIndex, page.offset); + m_lastError = XtcError::READ_ERROR; + return 0; + } + + XtgPageHeader pageHeader; + size_t headerRead = m_file.read(reinterpret_cast(&pageHeader), sizeof(XtgPageHeader)); + if (headerRead != sizeof(XtgPageHeader)) { + LOG_DBG("XTC", "Failed to read page header for page %u", pageIndex); + m_lastError = XtcError::READ_ERROR; + return 0; + } + + if (pageHeader.magic != XTH_MAGIC) { + LOG_DBG("XTC", "Invalid page magic for page %u: 0x%08X", pageIndex, pageHeader.magic); + m_lastError = XtcError::INVALID_MAGIC; + return 0; + } + + // Only plane1 (MSB): (width * height + 7) / 8 bytes + const size_t planeSize = (static_cast(pageHeader.width) * pageHeader.height + 7) / 8; + + if (bufferSize < planeSize) { + LOG_DBG("XTC", "Buffer too small for MSB plane: need %u, have %u", planeSize, bufferSize); + m_lastError = XtcError::MEMORY_ERROR; + return 0; + } + + size_t bytesRead = m_file.read(buffer, planeSize); + if (bytesRead != planeSize) { + LOG_DBG("XTC", "MSB plane read error: expected %u, got %u", planeSize, bytesRead); + m_lastError = XtcError::READ_ERROR; + return 0; + } + + m_lastError = XtcError::OK; + return bytesRead; +} + +size_t XtcParser::loadPageLsb(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize) { + if (m_bitDepth != 2) return loadPage(pageIndex, buffer, bufferSize); + + if (!m_isOpen) { + m_lastError = XtcError::FILE_NOT_FOUND; + return 0; + } + if (pageIndex >= m_header.pageCount) { + m_lastError = XtcError::PAGE_OUT_OF_RANGE; + return 0; + } + + PageInfo page; + if (!readPageTableEntry(pageIndex, page)) { + m_lastError = XtcError::READ_ERROR; + return 0; + } + + if (!ensureFileOpen()) { + m_lastError = XtcError::FILE_NOT_FOUND; + return 0; + } + + if (!m_file.seek(page.offset)) { + m_lastError = XtcError::READ_ERROR; + return 0; + } + + XtgPageHeader pageHeader; + if (m_file.read(reinterpret_cast(&pageHeader), sizeof(XtgPageHeader)) != sizeof(XtgPageHeader)) { + m_lastError = XtcError::READ_ERROR; + return 0; + } + if (pageHeader.magic != XTH_MAGIC) { + LOG_DBG("XTC", "loadPageLsb: invalid magic for page %u: 0x%08X", pageIndex, pageHeader.magic); + m_lastError = XtcError::INVALID_MAGIC; + return 0; + } + + const size_t planeSize = (static_cast(pageHeader.width) * pageHeader.height + 7) / 8; + const uint32_t plane2Offset = page.offset + sizeof(XtgPageHeader) + static_cast(planeSize); + + if (!m_file.seek(plane2Offset)) { + m_lastError = XtcError::READ_ERROR; + return 0; + } + + if (bufferSize < planeSize) { + LOG_DBG("XTC", "Buffer too small for LSB plane: need %u, have %u", planeSize, bufferSize); + m_lastError = XtcError::MEMORY_ERROR; + return 0; + } + + size_t bytesRead = m_file.read(buffer, planeSize); + if (bytesRead != planeSize) { + m_lastError = XtcError::READ_ERROR; + return 0; + } + m_lastError = XtcError::OK; + return bytesRead; +} + XtcError XtcParser::loadPageStreaming(uint32_t pageIndex, std::function callback, size_t chunkSize) { diff --git a/lib/Xtc/Xtc/XtcParser.h b/lib/Xtc/Xtc/XtcParser.h index b688d79350..3901a72873 100644 --- a/lib/Xtc/Xtc/XtcParser.h +++ b/lib/Xtc/Xtc/XtcParser.h @@ -57,6 +57,29 @@ class XtcParser { */ size_t loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize); + /** + * Load only plane1 (MSB) of a 2-bit page into buffer. + * For 1-bit pages behaves identically to loadPage. + * Requires only half the buffer of loadPage for 2-bit pages, fitting within heap limits. + * + * @param pageIndex Page index (0-based) + * @param buffer Output buffer (caller allocated, must hold planeSize bytes) + * @param bufferSize Buffer size + * @return Number of bytes read on success, 0 on failure + */ + size_t loadPageMsb(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize); + + /** + * Load only plane2 (LSB) of a 2-bit page into buffer. + * For 1-bit pages behaves identically to loadPage. + * + * @param pageIndex Page index (0-based) + * @param buffer Output buffer (caller allocated, must hold planeSize bytes) + * @param bufferSize Buffer size + * @return Number of bytes read on success, 0 on failure + */ + size_t loadPageLsb(uint32_t pageIndex, uint8_t* buffer, size_t bufferSize); + /** * Streaming page load * Memory-efficient method that reads page data in chunks. diff --git a/lib/ZipFile/ZipFile.cpp b/lib/ZipFile/ZipFile.cpp index fe59dfaa09..1730296ce8 100644 --- a/lib/ZipFile/ZipFile.cpp +++ b/lib/ZipFile/ZipFile.cpp @@ -441,7 +441,7 @@ uint8_t* ZipFile::readFileToMemory(const char* filename, size_t* size, const boo return data; } -bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t chunkSize) { +bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t chunkSize, uint32_t deadline) { const ScopedOpenClose zip{*this}; if (!zip) return false; @@ -465,6 +465,11 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch size_t remaining = inflatedDataSize; while (remaining > 0) { + if (deadline != 0 && static_cast(millis() - deadline) >= 0) { + LOG_ERR("ZIP", "Read deadline exceeded (stored)"); + free(buffer); + return false; + } const size_t dataRead = file.read(buffer, remaining < chunkSize ? remaining : chunkSize); if (dataRead == 0) { LOG_ERR("ZIP", "Could not read more bytes"); @@ -516,6 +521,10 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch size_t totalProduced = 0; while (true) { + if (deadline != 0 && static_cast(millis() - deadline) >= 0) { + LOG_ERR("ZIP", "Decompress deadline exceeded after %zu bytes", totalProduced); + break; + } size_t produced; const InflateStatus status = ctx.reader.readAtMost(outputBuffer, chunkSize, &produced); diff --git a/lib/ZipFile/ZipFile.h b/lib/ZipFile/ZipFile.h index 60c97a4cf9..a108d49594 100644 --- a/lib/ZipFile/ZipFile.h +++ b/lib/ZipFile/ZipFile.h @@ -68,5 +68,5 @@ class ZipFile { // Due to the memory required to run each of these, it is recommended to not preopen the zip file for multiple // These functions will open and close the zip as needed uint8_t* readFileToMemory(const char* filename, size_t* size = nullptr, bool trailingNullByte = false); - bool readFileToStream(const char* filename, Print& out, size_t chunkSize); + bool readFileToStream(const char* filename, Print& out, size_t chunkSize, uint32_t deadline = 0); }; diff --git a/lib/hal/HalDisplay.cpp b/lib/hal/HalDisplay.cpp index 665df5356b..d176c3de02 100644 --- a/lib/hal/HalDisplay.cpp +++ b/lib/hal/HalDisplay.cpp @@ -66,7 +66,7 @@ void HalDisplay::refreshDisplay(HalDisplay::RefreshMode mode, bool turnOffScreen einkDisplay.refreshDisplay(convertRefreshMode(mode), turnOffScreen); } -void HalDisplay::deepSleep() { einkDisplay.deepSleep(); } +void HalDisplay::deepSleep(const bool powerDownDisplay) { einkDisplay.deepSleep(powerDownDisplay); } uint8_t* HalDisplay::getFrameBuffer() const { return einkDisplay.getFrameBuffer(); } @@ -80,7 +80,17 @@ void HalDisplay::copyGrayscaleMsbBuffers(const uint8_t* msbBuffer) { einkDisplay void HalDisplay::cleanupGrayscaleBuffers(const uint8_t* bwBuffer) { einkDisplay.cleanupGrayscaleBuffers(bwBuffer); } -void HalDisplay::displayGrayBuffer(bool turnOffScreen) { einkDisplay.displayGrayBuffer(turnOffScreen); } +void HalDisplay::displayGrayBuffer(bool turnOffScreen, const unsigned char* lut, bool factoryMode) { + einkDisplay.displayGrayBuffer(turnOffScreen, lut, factoryMode); +} + +void HalDisplay::displayGrayBufferFactorySetup(const unsigned char* lut) { + einkDisplay.displayGrayBufferFactorySetup(lut); +} + +void HalDisplay::displayGrayBufferFactoryActivate() { einkDisplay.displayGrayBufferFactoryActivate(); } + +void HalDisplay::displayBufferPrecondition(uint8_t color) { einkDisplay.displayBufferPrecondition(color); } uint16_t HalDisplay::getDisplayWidth() const { return einkDisplay.getDisplayWidth(); } diff --git a/lib/hal/HalDisplay.h b/lib/hal/HalDisplay.h index a0a7f92083..fc8cee8c29 100644 --- a/lib/hal/HalDisplay.h +++ b/lib/hal/HalDisplay.h @@ -37,7 +37,7 @@ class HalDisplay { void refreshDisplay(RefreshMode mode = RefreshMode::FAST_REFRESH, bool turnOffScreen = false); // Power management - void deepSleep(); + void deepSleep(bool powerDownDisplay = true); // Access to frame buffer uint8_t* getFrameBuffer() const; @@ -47,7 +47,17 @@ class HalDisplay { void copyGrayscaleMsbBuffers(const uint8_t* msbBuffer); void cleanupGrayscaleBuffers(const uint8_t* bwBuffer); - void displayGrayBuffer(bool turnOffScreen = false); + void displayGrayBuffer(bool turnOffScreen = false, const unsigned char* lut = nullptr, bool factoryMode = false); + // Two-phase factory grayscale render — see EInkDisplay.h. + void displayGrayBufferFactorySetup(const unsigned char* lut); + void displayGrayBufferFactoryActivate(); + // Stock-V5.5.9 byte-match precondition (black/white full power-cycle flash). + void displayBufferPrecondition(uint8_t color); + + // Tell the SDK that grayscale state has been cleaned up by the consumer + // (RAM banks rebased + a follow-up FAST_REFRESH will handle pixel cleanup), + // so the next displayBuffer() should not run grayscaleRevert(). + void clearGrayscaleModeFlag() { einkDisplay.clearGrayscaleModeFlag(); } // Runtime geometry passthrough uint16_t getDisplayWidth() const; diff --git a/lib/hal/HalGPIO.cpp b/lib/hal/HalGPIO.cpp index 59b6eb72b1..b150dc8c75 100644 --- a/lib/hal/HalGPIO.cpp +++ b/lib/hal/HalGPIO.cpp @@ -223,6 +223,8 @@ bool HalGPIO::wasAnyReleased() const { return inputMgr.wasAnyReleased(); } unsigned long HalGPIO::getHeldTime() const { return inputMgr.getHeldTime(); } +unsigned long HalGPIO::getPowerButtonHeldTime() const { return inputMgr.getPowerButtonHeldTime(); } + void HalGPIO::startDeepSleep() { // Ensure that the power button has been released to avoid immediately turning back on if you're holding it while (inputMgr.isPressed(BTN_POWER)) { @@ -258,8 +260,8 @@ void HalGPIO::verifyPowerButtonWakeup(uint16_t requiredDurationMs, bool shortPre do { delay(10); inputMgr.update(); - } while (inputMgr.isPressed(BTN_POWER) && inputMgr.getHeldTime() < calibratedDuration); - if (inputMgr.getHeldTime() < calibratedDuration) { + } while (inputMgr.isPressed(BTN_POWER) && inputMgr.getPowerButtonHeldTime() < calibratedDuration); + if (inputMgr.getPowerButtonHeldTime() < calibratedDuration) { startDeepSleep(); } } else { diff --git a/lib/hal/HalGPIO.h b/lib/hal/HalGPIO.h index 6337cf9e80..94e9bcd711 100644 --- a/lib/hal/HalGPIO.h +++ b/lib/hal/HalGPIO.h @@ -70,6 +70,7 @@ class HalGPIO { bool wasReleased(uint8_t buttonIndex) const; bool wasAnyReleased() const; unsigned long getHeldTime() const; + unsigned long getPowerButtonHeldTime() const; // Setup wake up GPIO and enter deep sleep void startDeepSleep(); diff --git a/open-x4-sdk b/open-x4-sdk index a64a3c29be..a253cba48f 160000 --- a/open-x4-sdk +++ b/open-x4-sdk @@ -1 +1 @@ -Subproject commit a64a3c29bebc59b2ccdfe15492cfc4b5e4c26360 +Subproject commit a253cba48f76980287fe08ef369215d9aed5b7fd diff --git a/platformio.ini b/platformio.ini index 9d14b7145a..39a526d099 100644 --- a/platformio.ini +++ b/platformio.ini @@ -4,7 +4,7 @@ build_cache_dir = .cache extra_configs = platformio.local.ini [crosspoint] -version = 1.2.0 +version = 1.3.0 [base] platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.37/platform-espressif32.zip diff --git a/scripts/update_hyphenation.sh b/scripts/update_hyphenation.sh index ed12aef79b..1f8d643b15 100755 --- a/scripts/update_hyphenation.sh +++ b/scripts/update_hyphenation.sh @@ -23,3 +23,5 @@ process es process ru process it process uk +process pl +process sv diff --git a/src/CrossPointSettings.cpp b/src/CrossPointSettings.cpp index 44037690ec..527392f3aa 100644 --- a/src/CrossPointSettings.cpp +++ b/src/CrossPointSettings.cpp @@ -305,6 +305,8 @@ unsigned long CrossPointSettings::getSleepTimeoutMs() const { switch (sleepTimeout) { case SLEEP_1_MIN: return 1UL * 60 * 1000; + case SLEEP_3_MIN: + return 3UL * 60 * 1000; case SLEEP_5_MIN: return 5UL * 60 * 1000; case SLEEP_10_MIN: diff --git a/src/CrossPointSettings.h b/src/CrossPointSettings.h index 0b7690055b..b7080aa29c 100644 --- a/src/CrossPointSettings.h +++ b/src/CrossPointSettings.h @@ -63,6 +63,7 @@ class CrossPointSettings { XTC_STATUS_BAR_TOP = 2, XTC_STATUS_BAR_MODE_COUNT }; + enum XTC_RENDER_QUALITY { XTC_RENDER_FAST = 0, XTC_RENDER_QUALITY_HIGH = 1, XTC_RENDER_QUALITY_COUNT }; enum ORIENTATION { PORTRAIT = 0, // 480x800 logical coordinates (current default) @@ -119,6 +120,7 @@ class CrossPointSettings { SLEEP_10_MIN = 2, SLEEP_15_MIN = 3, SLEEP_30_MIN = 4, + SLEEP_3_MIN = 5, SLEEP_TIMEOUT_COUNT }; @@ -133,7 +135,7 @@ class CrossPointSettings { }; // Short power button press actions - enum SHORT_PWRBTN { IGNORE = 0, SLEEP = 1, PAGE_TURN = 2, FORCE_REFRESH = 3, SHORT_PWRBTN_COUNT }; + enum SHORT_PWRBTN { IGNORE = 0, SLEEP = 1, PAGE_TURN = 2, FORCE_REFRESH = 3, MENU = 4, SHORT_PWRBTN_COUNT }; // Hide battery percentage enum HIDE_BATTERY_PERCENTAGE { HIDE_NEVER = 0, HIDE_READER = 1, HIDE_ALWAYS = 2, HIDE_BATTERY_PERCENTAGE_COUNT }; @@ -169,6 +171,7 @@ class CrossPointSettings { uint8_t statusBarTitle = CHAPTER_TITLE; uint8_t statusBarBattery = 1; uint8_t xtcStatusBarMode = XTC_STATUS_BAR_HIDE; + uint8_t xtcRenderQuality = XTC_RENDER_FAST; // Text rendering settings uint8_t extraParagraphSpacing = 1; uint8_t textAntiAliasing = 1; @@ -219,6 +222,8 @@ class CrossPointSettings { char sdFontFamilyName[32] = ""; // Show hidden files/directories (starting with '.') in the file browser (0 = hidden, 1 = show) uint8_t showHiddenFiles = 0; + // Move epub to /Read/ folder on SD card when finished (0 = disabled, 1 = enabled) + uint8_t moveFinishedToReadFolder = 0; // Image rendering mode in EPUB reader uint8_t imageRendering = IMAGES_DISPLAY; // Tilt-based page turning (X3 only — requires QMI8658 IMU) diff --git a/src/CrossPointState.h b/src/CrossPointState.h index 4b18f3b1cd..8ca22ef6b5 100644 --- a/src/CrossPointState.h +++ b/src/CrossPointState.h @@ -15,6 +15,7 @@ class CrossPointState { uint8_t recentSleepFill = 0; // valid entries (0..SLEEP_RECENT_COUNT) uint8_t readerActivityLoadCount = 0; bool lastSleepFromReader = false; + uint8_t pendingMenuAction = 0xFF; // Returns true if idx was shown within the last checkCount picks. // Walks backwards from the most recently written slot. diff --git a/src/RecentBooksStore.cpp b/src/RecentBooksStore.cpp index b34f8523ba..7b95543340 100644 --- a/src/RecentBooksStore.cpp +++ b/src/RecentBooksStore.cpp @@ -53,6 +53,28 @@ void RecentBooksStore::updateBook(const std::string& path, const std::string& ti } } +void RecentBooksStore::updatePath(const std::string& oldPath, const std::string& newPath, + const std::string& oldCachePath, const std::string& newCachePath) { + auto it = std::find_if(recentBooks.begin(), recentBooks.end(), + [&](const RecentBook& book) { return book.path == oldPath; }); + if (it == recentBooks.end()) { + return; + } + it->path = newPath; + if (!oldCachePath.empty() && !it->coverBmpPath.empty() && it->coverBmpPath.rfind(oldCachePath, 0) == 0) { + it->coverBmpPath = newCachePath + it->coverBmpPath.substr(oldCachePath.size()); + } + saveToFile(); +} + +bool RecentBooksStore::isMissing(const RecentBook& book) { return !Storage.exists(book.path.c_str()); } + +bool RecentBooksStore::pruneMissing() { + const size_t before = recentBooks.size(); + recentBooks.erase(std::remove_if(recentBooks.begin(), recentBooks.end(), &isMissing), recentBooks.end()); + return recentBooks.size() != before; +} + bool RecentBooksStore::saveToFile() const { Storage.mkdir("/.crosspoint"); return JsonSettingsIO::saveRecentBooks(*this, RECENT_BOOKS_FILE_JSON); diff --git a/src/RecentBooksStore.h b/src/RecentBooksStore.h index 5d98ce833c..86264553a9 100644 --- a/src/RecentBooksStore.h +++ b/src/RecentBooksStore.h @@ -37,6 +37,18 @@ class RecentBooksStore { void updateBook(const std::string& path, const std::string& title, const std::string& author, const std::string& coverBmpPath); + // Repoint an entry's path (and coverBmpPath, if it lived under the old cache dir) after the + // backing file and cache dir were moved on disk. No-op if no entry matches oldPath. + // Persists on success. Keeps the entry's list position (does not reorder). + void updatePath(const std::string& oldPath, const std::string& newPath, const std::string& oldCachePath, + const std::string& newCachePath); + + // True if the book's backing file is no longer present on the SD card. + static bool isMissing(const RecentBook& book); + + // Remove entries whose backing file is no longer on the SD card. + // Returns true if any entry was removed. Does not persist — caller decides. + bool pruneMissing(); // Get the list of recent books (most recent first) const std::vector& getBooks() const { return recentBooks; } diff --git a/src/SdCardFontGlobals.h b/src/SdCardFontGlobals.h deleted file mode 100644 index fec123a081..0000000000 --- a/src/SdCardFontGlobals.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "SdCardFontSystem.h" - -class GfxRenderer; - -// Global SD card font system instance (defined in main.cpp). -extern SdCardFontSystem sdFontSystem; - -// Ensure the correct SD card font family is loaded for current settings. -// Defined in main.cpp; call before entering the reader or after settings change. -extern void ensureSdFontLoaded(); diff --git a/src/SdCardFontSystem.h b/src/SdCardFontSystem.h index f053534389..6b8aef7f10 100644 --- a/src/SdCardFontSystem.h +++ b/src/SdCardFontSystem.h @@ -50,3 +50,6 @@ class SdCardFontSystem { SdCardFontManager manager_; std::atomic registryDirty_{false}; }; + +// Global SD card font system instance (defined in main.cpp). +extern SdCardFontSystem sdFontSystem; diff --git a/src/SettingsList.h b/src/SettingsList.h index d8a118c372..5089a4ce7e 100644 --- a/src/SettingsList.h +++ b/src/SettingsList.h @@ -159,6 +159,8 @@ inline std::vector getSettingsList(const SdCardFontRegistry* regist SettingInfo::Enum(StrId::STR_IMAGES, &CrossPointSettings::imageRendering, {StrId::STR_IMAGES_DISPLAY, StrId::STR_IMAGES_PLACEHOLDER, StrId::STR_IMAGES_SUPPRESS}, "imageRendering", StrId::STR_CAT_READER), + SettingInfo::Enum(StrId::STR_XTC_RENDER_QUALITY, &CrossPointSettings::xtcRenderQuality, + {StrId::STR_SPEED, StrId::STR_QUALITY}, "xtcRenderQuality", StrId::STR_CAT_READER), // --- Controls --- SettingInfo::Enum(StrId::STR_SIDE_BTN_LAYOUT, &CrossPointSettings::sideButtonLayout, {StrId::STR_PREV_NEXT, StrId::STR_NEXT_PREV}, "sideButtonLayout", StrId::STR_CAT_CONTROLS), @@ -167,15 +169,19 @@ inline std::vector getSettingsList(const SdCardFontRegistry* regist StrId::STR_LONG_PRESS_BEHAVIOR_ORIENTATION}, "longPressButtonBehavior", StrId::STR_CAT_CONTROLS), SettingInfo::Enum(StrId::STR_SHORT_PWR_BTN, &CrossPointSettings::shortPwrBtn, - {StrId::STR_IGNORE, StrId::STR_SLEEP, StrId::STR_PAGE_TURN, StrId::STR_FORCE_REFRESH}, + {StrId::STR_IGNORE, StrId::STR_SLEEP, StrId::STR_PAGE_TURN, StrId::STR_FORCE_REFRESH, + StrId::STR_ACTION_MENU}, "shortPwrBtn", StrId::STR_CAT_CONTROLS), // --- System --- SettingInfo::Enum(StrId::STR_TIME_TO_SLEEP, &CrossPointSettings::sleepTimeout, - {StrId::STR_MIN_1, StrId::STR_MIN_5, StrId::STR_MIN_10, StrId::STR_MIN_15, StrId::STR_MIN_30}, + {StrId::STR_MIN_1, StrId::STR_MIN_3, StrId::STR_MIN_5, StrId::STR_MIN_10, StrId::STR_MIN_15, + StrId::STR_MIN_30}, "sleepTimeout", StrId::STR_CAT_SYSTEM), SettingInfo::Toggle(StrId::STR_SHOW_HIDDEN_FILES, &CrossPointSettings::showHiddenFiles, "showHiddenFiles", StrId::STR_CAT_SYSTEM), + SettingInfo::Toggle(StrId::STR_MOVE_FINISHED_TO_READ, &CrossPointSettings::moveFinishedToReadFolder, + "moveFinishedToReadFolder", StrId::STR_CAT_SYSTEM), // --- KOReader Sync (web-only, uses KOReaderCredentialStore) --- SettingInfo::DynamicString( diff --git a/src/SilentRestart.h b/src/SilentRestart.h new file mode 100644 index 0000000000..f94345c5ff --- /dev/null +++ b/src/SilentRestart.h @@ -0,0 +1,8 @@ +#pragma once + +// ESP.restart() with an RTC_NOINIT flag that survives the reboot, so setup() +// skips the boot splash and routes straight to a destination. Used to clear +// heap fragmentation accumulated during a wifi session. + +void silentRestart(); // home screen +void silentRestartToReader(); // currently-open EPUB (APP_STATE.openEpubPath) diff --git a/src/activities/Activity.h b/src/activities/Activity.h index 33a4495203..55595a0089 100644 --- a/src/activities/Activity.h +++ b/src/activities/Activity.h @@ -46,6 +46,11 @@ class Activity { virtual bool isReaderActivity() const { return false; } virtual ScreenshotInfo getScreenshotInfo() const { return {}; } + // Called when the screenshot combo is pressed and the display is in FactoryLut state. + // Activities that use renderGrayscaleSinglePass should override this to trigger a re-render, + // allowing the installed screenshot hook to capture both planes before they are pushed. + virtual void onScreenshotRequest() {} + // Start a new activity without destroying the current one // Note: requestUpdate() will be invoked automatically once resultHandler finishes void startActivityForResult(std::unique_ptr&& activity, ActivityResultHandler resultHandler); diff --git a/src/activities/ActivityManager.cpp b/src/activities/ActivityManager.cpp index c81e6b95b5..96c3c7d0a4 100644 --- a/src/activities/ActivityManager.cpp +++ b/src/activities/ActivityManager.cpp @@ -5,7 +5,6 @@ #include #include "OpdsServerStore.h" -#include "SdCardFontGlobals.h" #include "boot_sleep/BootActivity.h" #include "boot_sleep/SleepActivity.h" #include "browser/OpdsBookBrowserActivity.h" @@ -194,7 +193,6 @@ void ActivityManager::goToBrowser() { } void ActivityManager::goToReader(std::string path) { - ensureSdFontLoaded(); replaceActivity(std::make_unique(renderer, mappedInput, std::move(path))); } diff --git a/src/activities/ActivityManager.h b/src/activities/ActivityManager.h index a8d737b80b..3227bb97ad 100644 --- a/src/activities/ActivityManager.h +++ b/src/activities/ActivityManager.h @@ -97,6 +97,8 @@ class ActivityManager { // Note: if popActivity() on last activity on the stack, we will goHome() void popActivity(); + Activity* getCurrentActivity() const { return currentActivity.get(); } + bool preventAutoSleep() const; bool isReaderActivity() const; bool skipLoopDelay() const; diff --git a/src/activities/boot_sleep/BootActivity.cpp b/src/activities/boot_sleep/BootActivity.cpp index 9e59ed592b..864c181666 100644 --- a/src/activities/boot_sleep/BootActivity.cpp +++ b/src/activities/boot_sleep/BootActivity.cpp @@ -4,7 +4,7 @@ #include #include "fontIds.h" -#include "images/Logo120.h" +#include "images/CrossLarge.h" void BootActivity::onEnter() { Activity::onEnter(); @@ -13,9 +13,9 @@ void BootActivity::onEnter() { const auto pageHeight = renderer.getScreenHeight(); renderer.clearScreen(); - renderer.drawImage(Logo120, (pageWidth - 120) / 2, (pageHeight - 120) / 2, 120, 120); + renderer.drawImage(CrossLarge, (pageWidth - 128) / 2, (pageHeight - 128) / 2, 128, 128); renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 70, tr(STR_CROSSPOINT), true, EpdFontFamily::BOLD); - renderer.drawCenteredText(SMALL_FONT_ID, pageHeight / 2 + 95, tr(STR_BOOTING)); + renderer.drawCenteredText(SMALL_FONT_ID, pageHeight / 2 + 95, tr(STR_BOOTING), true, EpdFontFamily::BOLD); renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, CROSSPOINT_VERSION); renderer.displayBuffer(); } diff --git a/src/activities/boot_sleep/SleepActivity.cpp b/src/activities/boot_sleep/SleepActivity.cpp index 19f443b064..1fc0d21997 100644 --- a/src/activities/boot_sleep/SleepActivity.cpp +++ b/src/activities/boot_sleep/SleepActivity.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -10,21 +11,34 @@ #include "CrossPointSettings.h" #include "CrossPointState.h" +#include "Epub/converters/DirectPixelWriter.h" #include "activities/reader/ReaderUtils.h" -#include "components/UITheme.h" #include "fontIds.h" -#include "images/Logo120.h" +#include "images/CrossLarge.h" + +namespace { +constexpr uint8_t SLEEP_FACTORY_INTERNAL_PREFLASH_PASSES = 0; + +// Stock V5.5.9 byte-match: black flash then white flash, each via the new +// EInkDisplay::displayBufferPrecondition() path which fires CTRL2=0xF7 (full +// power cycle) and skips the SINGLE_BUFFER_MODE post-RED-sync. Matches stock's +// precondition function at firmware addr 0x42010096 — see +// docs/v559-disassembly-findings.md. +constexpr uint8_t FACTORY_SLEEP_PRECONDITION_COLORS[] = {0x00, 0xFF}; + +void runFactorySleepPrecondition(const GfxRenderer& renderer) { + for (const uint8_t color : FACTORY_SLEEP_PRECONDITION_COLORS) { + renderer.displayBufferPrecondition(color); + } +} +} // namespace void SleepActivity::onEnter() { Activity::onEnter(); - // Show popup with reader orientation only when going to sleep from reader if (APP_STATE.lastSleepFromReader) { ReaderUtils::applyOrientation(renderer, SETTINGS.orientation); - GUI.drawPopup(renderer, tr(STR_ENTERING_SLEEP)); renderer.setOrientation(GfxRenderer::Orientation::Portrait); - } else { - GUI.drawPopup(renderer, tr(STR_ENTERING_SLEEP)); } switch (SETTINGS.sleepScreen) { @@ -50,20 +64,38 @@ void SleepActivity::renderCustomSleepScreen() const { const char* sleepDir = nullptr; auto dir = Storage.open("/.sleep"); + // Check root for sleep.pxc (preferred) or sleep.bmp before scanning the directory. + if (Storage.exists("/sleep.pxc")) { + LOG_DBG("SLP", "Loading: /sleep.pxc"); + if (dir) dir.close(); + if (renderPxcSleepScreen("/sleep.pxc")) { + return; + } + renderDefaultSleepScreen(); + return; + } + // Look for sleep.bmp on the root of the sd card to determine if we should // render a custom sleep screen instead of the default. // This takes priority over the /sleep folder. - FsFile file; - if (Storage.openFileForRead("SLP", "/sleep.bmp", file)) { - Bitmap bitmap(file, true); - if (bitmap.parseHeaders() == BmpReaderError::Ok) { - LOG_DBG("SLP", "Loading: /sleep.bmp"); - renderBitmapSleepScreen(bitmap); + { + FsFile file; + if (Storage.openFileForRead("SLP", "/sleep.bmp", file)) { + Bitmap bitmap(file, true); + if (bitmap.parseHeaders() == BmpReaderError::Ok) { + LOG_DBG("SLP", "Loading: /sleep.bmp"); + if (bitmap.hasGreyscale() && + SETTINGS.sleepScreenCoverFilter == CrossPointSettings::SLEEP_SCREEN_COVER_FILTER::NO_FILTER) { + lastGrayscalePath = "/sleep.bmp"; + lastGrayscaleIsPxc = false; + } + renderBitmapSleepScreen(bitmap); + file.close(); + if (dir) dir.close(); + return; + } file.close(); - if (dir) dir.close(); - return; } - file.close(); } if (dir && dir.isDirectory()) { @@ -78,7 +110,7 @@ void SleepActivity::renderCustomSleepScreen() const { if (sleepDir) { std::vector files; char name[500]; - // collect all valid BMP files + // collect all valid BMP/PXC files for (auto dirFile = dir.openNextFile(); dirFile; dirFile = dir.openNextFile()) { if (dirFile.isDirectory()) { dirFile.close(); @@ -91,16 +123,35 @@ void SleepActivity::renderCustomSleepScreen() const { continue; } - if (!FsHelpers::hasBmpExtension(filename)) { - LOG_DBG("SLP", "Skipping non-.bmp file name: %s", name); + const bool isBmp = FsHelpers::hasBmpExtension(filename); + const bool isPxc = FsHelpers::hasPxcExtension(filename); + if (!isBmp && !isPxc) { + LOG_DBG("SLP", "Skipping non-BMP/PXC file: %s", name); dirFile.close(); continue; } - Bitmap bitmap(dirFile); - if (bitmap.parseHeaders() != BmpReaderError::Ok) { - LOG_DBG("SLP", "Skipping invalid BMP file: %s", name); - dirFile.close(); - continue; + if (isBmp) { + Bitmap bitmap(dirFile); + if (bitmap.parseHeaders() != BmpReaderError::Ok) { + LOG_DBG("SLP", "Skipping invalid BMP file: %s", name); + dirFile.close(); + continue; + } + } + if (isPxc) { + uint16_t w, h; + if (dirFile.read(&w, 2) != 2 || dirFile.read(&h, 2) != 2) { + LOG_DBG("SLP", "Skipping PXC with unreadable header: %s", name); + dirFile.close(); + continue; + } + const int sw = renderer.getScreenWidth(); + const int sh = renderer.getScreenHeight(); + if (w != sw || h != sh) { + LOG_DBG("SLP", "Skipping PXC size mismatch %dx%d (screen %dx%d): %s", w, h, sw, sh, name); + dirFile.close(); + continue; + } } files.emplace_back(filename); dirFile.close(); @@ -119,12 +170,24 @@ void SleepActivity::renderCustomSleepScreen() const { APP_STATE.pushRecentSleep(randomFileIndex); APP_STATE.saveToFile(); const auto filename = std::string(sleepDir) + "/" + files[randomFileIndex]; + LOG_DBG("SLP", "Randomly loading: %s/%s", sleepDir, files[randomFileIndex].c_str()); + delay(100); + if (FsHelpers::hasPxcExtension(files[randomFileIndex])) { + dir.close(); + if (!renderPxcSleepScreen(filename)) { + renderDefaultSleepScreen(); + } + return; + } FsFile randFile; if (Storage.openFileForRead("SLP", filename, randFile)) { - LOG_DBG("SLP", "Randomly loading: %s/%s", sleepDir, files[randomFileIndex].c_str()); - delay(100); Bitmap bitmap(randFile, true); if (bitmap.parseHeaders() == BmpReaderError::Ok) { + if (bitmap.hasGreyscale() && + SETTINGS.sleepScreenCoverFilter == CrossPointSettings::SLEEP_SCREEN_COVER_FILTER::NO_FILTER) { + lastGrayscalePath = filename; + lastGrayscaleIsPxc = false; + } renderBitmapSleepScreen(bitmap); randFile.close(); dir.close(); @@ -144,9 +207,9 @@ void SleepActivity::renderDefaultSleepScreen() const { const auto pageHeight = renderer.getScreenHeight(); renderer.clearScreen(); - renderer.drawImage(Logo120, (pageWidth - 120) / 2, (pageHeight - 120) / 2, 120, 120); + renderer.drawImage(CrossLarge, (pageWidth - 128) / 2, (pageHeight - 128) / 2, 128, 128); renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 70, tr(STR_CROSSPOINT), true, EpdFontFamily::BOLD); - renderer.drawCenteredText(SMALL_FONT_ID, pageHeight / 2 + 95, tr(STR_SLEEPING)); + renderer.drawCenteredText(SMALL_FONT_ID, pageHeight / 2 + 95, tr(STR_SLEEPING), true, EpdFontFamily::BOLD); // Make sleep screen dark unless light is selected in settings if (SETTINGS.sleepScreen != CrossPointSettings::SLEEP_SCREEN_MODE::LIGHT) { @@ -156,6 +219,73 @@ void SleepActivity::renderDefaultSleepScreen() const { renderer.displayBuffer(HalDisplay::HALF_REFRESH); } +bool SleepActivity::renderPxcSleepScreen(const std::string& path) const { + FsFile file; + if (!Storage.openFileForRead("SLP", path, file)) { + LOG_ERR("SLP", "Cannot open PXC: %s", path.c_str()); + return false; + } + + uint16_t pxcWidth, pxcHeight; + if (file.read(&pxcWidth, 2) != 2 || file.read(&pxcHeight, 2) != 2) { + LOG_ERR("SLP", "PXC header read failed: %s", path.c_str()); + file.close(); + return false; + } + + const int screenWidth = renderer.getScreenWidth(); + const int screenHeight = renderer.getScreenHeight(); + if (pxcWidth != screenWidth || pxcHeight != screenHeight) { + LOG_ERR("SLP", "PXC size %dx%d does not match screen %dx%d", pxcWidth, pxcHeight, screenWidth, screenHeight); + file.close(); + return false; + } + + const uint32_t dataOffset = file.position(); // right after the 4-byte header + + // PXC is always 2-bit grayscale - always use factory LUT + lastGrayscalePath = path; + lastGrayscaleIsPxc = true; + struct PxcCtx { + FsFile* file; + uint32_t dataOffset; + int width, height; + }; + PxcCtx ctx{&file, dataOffset, pxcWidth, pxcHeight}; + + runFactorySleepPrecondition(renderer); + renderer.renderGrayscaleSinglePass( + GfxRenderer::GrayscaleDriveMode::FactoryQuality, + [](const GfxRenderer& r, const void* raw) { + const auto* c = static_cast(raw); + c->file->seek(c->dataOffset); + + const int bpr = (c->width + 3) / 4; + uint8_t* rowBuf = static_cast(malloc(bpr)); + if (!rowBuf) { + LOG_ERR("SLP", "malloc failed for rowBuf (%d bytes, %dx%d)", bpr, c->width, c->height); + return; + } + + DirectPixelWriter pw; + pw.init(r); + + for (int row = 0; row < c->height; row++) { + if (c->file->read(rowBuf, bpr) != bpr) break; + pw.beginRow(row); + for (int col = 0; col < c->width; col++) { + const uint8_t pv = (rowBuf[col >> 2] >> (6 - (col & 3) * 2)) & 0x03; + pw.writePixel(pv); + } + } + free(rowBuf); + }, + &ctx, nullptr, nullptr, HalDisplay::FULL_REFRESH, SLEEP_FACTORY_INTERNAL_PREFLASH_PASSES); + + file.close(); + return true; +} + void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap) const { int x, y; const auto pageWidth = renderer.getScreenWidth(); @@ -197,34 +327,32 @@ void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap) const { } LOG_DBG("SLP", "drawing to %d x %d", x, y); - renderer.clearScreen(); const bool hasGreyscale = bitmap.hasGreyscale() && SETTINGS.sleepScreenCoverFilter == CrossPointSettings::SLEEP_SCREEN_COVER_FILTER::NO_FILTER; - renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY); - - if (SETTINGS.sleepScreenCoverFilter == CrossPointSettings::SLEEP_SCREEN_COVER_FILTER::INVERTED_BLACK_AND_WHITE) { - renderer.invertScreen(); - } - - renderer.displayBuffer(HalDisplay::HALF_REFRESH); - if (hasGreyscale) { - bitmap.rewindToData(); - renderer.clearScreen(0x00); - renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB); - renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY); - renderer.copyGrayscaleLsbBuffers(); - - bitmap.rewindToData(); - renderer.clearScreen(0x00); - renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB); + struct BitmapGrayCtx { + const Bitmap* bitmap; + int x, y, maxWidth, maxHeight; + float cropX, cropY; + }; + BitmapGrayCtx grayCtx{&bitmap, x, y, pageWidth, pageHeight, cropX, cropY}; + runFactorySleepPrecondition(renderer); + renderer.renderGrayscaleSinglePass( + GfxRenderer::GrayscaleDriveMode::FactoryQuality, + [](const GfxRenderer& r, const void* raw) { + const auto* c = static_cast(raw); + r.drawBitmap(*c->bitmap, c->x, c->y, c->maxWidth, c->maxHeight, c->cropX, c->cropY); + }, + &grayCtx, nullptr, nullptr, HalDisplay::FULL_REFRESH, SLEEP_FACTORY_INTERNAL_PREFLASH_PASSES); + } else { + renderer.clearScreen(); renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY); - renderer.copyGrayscaleMsbBuffers(); - - renderer.displayGrayBuffer(); - renderer.setRenderMode(GfxRenderer::BW); + if (SETTINGS.sleepScreenCoverFilter == CrossPointSettings::SLEEP_SCREEN_COVER_FILTER::INVERTED_BLACK_AND_WHITE) { + renderer.invertScreen(); + } + renderer.displayBuffer(HalDisplay::FULL_REFRESH); } } @@ -248,13 +376,73 @@ void SleepActivity::renderCoverSleepScreen() const { // Check if the current book is XTC, TXT, or EPUB if (FsHelpers::hasXtcExtension(APP_STATE.openEpubPath)) { - // Handle XTC file Xtc lastXtc(APP_STATE.openEpubPath, "/.crosspoint"); if (!lastXtc.load()) { LOG_ERR("SLP", "Failed to load last XTC"); return (this->*renderNoCoverSleepScreen)(); } + if (lastXtc.getBitDepth() == 2) { + const size_t planeSize = (static_cast(lastXtc.getPageWidth()) * lastXtc.getPageHeight() + 7) / 8; + uint8_t* plane1 = static_cast(malloc(planeSize)); + if (!plane1) { + LOG_ERR("SLP", "Failed to alloc plane1 for direct XTCH render (%lu bytes)", + static_cast(planeSize)); + return (this->*renderNoCoverSleepScreen)(); + } + uint8_t* plane2 = static_cast(malloc(planeSize)); + if (!plane2) { + LOG_ERR("SLP", "Failed to alloc plane2 for direct XTCH render (%lu bytes)", + static_cast(planeSize)); + free(plane1); + return (this->*renderNoCoverSleepScreen)(); + } + + if (lastXtc.loadPageMsb(0, plane1, planeSize) == 0) { + LOG_ERR("SLP", "Failed to load XTCH plane1 for sleep cover"); + free(plane1); + free(plane2); + return (this->*renderNoCoverSleepScreen)(); + } + if (lastXtc.loadPageLsb(0, plane2, planeSize) == 0) { + LOG_ERR("SLP", "Failed to load XTCH plane2 for sleep cover"); + free(plane1); + free(plane2); + return (this->*renderNoCoverSleepScreen)(); + } + + LOG_DBG("SLP", "Direct XTCH plane render: %ux%u", lastXtc.getPageWidth(), lastXtc.getPageHeight()); + runFactorySleepPrecondition(renderer); + renderer.displayXtchPlanes(plane1, plane2, lastXtc.getPageWidth(), lastXtc.getPageHeight(), nullptr, nullptr, + GfxRenderer::GrayscaleDriveMode::FactoryQuality, false); + free(plane1); + free(plane2); + return; + } + + if (lastXtc.getBitDepth() == 1) { + const size_t bufferSize = (static_cast(lastXtc.getPageWidth() + 7) / 8) * lastXtc.getPageHeight(); + uint8_t* pageBuffer = static_cast(malloc(bufferSize)); + if (!pageBuffer) { + LOG_ERR("SLP", "Failed to alloc page buffer for direct XTC render (%lu bytes)", + static_cast(bufferSize)); + return (this->*renderNoCoverSleepScreen)(); + } + if (lastXtc.loadPage(0, pageBuffer, bufferSize) == 0) { + LOG_ERR("SLP", "Failed to load XTC page for sleep cover"); + free(pageBuffer); + return (this->*renderNoCoverSleepScreen)(); + } + LOG_DBG("SLP", "Direct XTC page render: %ux%u", lastXtc.getPageWidth(), lastXtc.getPageHeight()); + if (!APP_STATE.lastSleepFromReader) { + renderer.clearScreen(); + renderer.displayBuffer(HalDisplay::HALF_REFRESH); + } + renderer.displayXtcBwPage(pageBuffer, lastXtc.getPageWidth(), lastXtc.getPageHeight()); + free(pageBuffer); + return; + } + if (!lastXtc.generateCoverBmp()) { LOG_ERR("SLP", "Failed to generate XTC cover bmp"); return (this->*renderNoCoverSleepScreen)(); @@ -299,6 +487,11 @@ void SleepActivity::renderCoverSleepScreen() const { Bitmap bitmap(file); if (bitmap.parseHeaders() == BmpReaderError::Ok) { LOG_DBG("SLP", "Rendering sleep cover: %s", coverBmpPath.c_str()); + if (bitmap.hasGreyscale() && + SETTINGS.sleepScreenCoverFilter == CrossPointSettings::SLEEP_SCREEN_COVER_FILTER::NO_FILTER) { + lastGrayscalePath = coverBmpPath; + lastGrayscaleIsPxc = false; + } renderBitmapSleepScreen(bitmap); return; } @@ -311,3 +504,24 @@ void SleepActivity::renderBlankSleepScreen() const { renderer.clearScreen(); renderer.displayBuffer(HalDisplay::HALF_REFRESH); } + +void SleepActivity::onScreenshotRequest() { + if (lastGrayscalePath.empty()) return; + if (lastGrayscaleIsPxc) { + if (!renderPxcSleepScreen(lastGrayscalePath)) { + renderDefaultSleepScreen(); + } + } else { + FsFile file; + if (Storage.openFileForRead("SLP", lastGrayscalePath.c_str(), file)) { + Bitmap bitmap(file, true); + if (bitmap.parseHeaders() == BmpReaderError::Ok) { + renderBitmapSleepScreen(bitmap); + } + file.close(); + } + } + // Device enters deep sleep next; on wake the new activity will full-refresh anyway. + renderer.clearScreen(); + renderer.cleanupGrayscaleWithFrameBuffer(); +} diff --git a/src/activities/boot_sleep/SleepActivity.h b/src/activities/boot_sleep/SleepActivity.h index 87df8ba19d..2952009341 100644 --- a/src/activities/boot_sleep/SleepActivity.h +++ b/src/activities/boot_sleep/SleepActivity.h @@ -1,4 +1,6 @@ #pragma once +#include + #include "../Activity.h" class Bitmap; @@ -8,11 +10,17 @@ class SleepActivity final : public Activity { explicit SleepActivity(GfxRenderer& renderer, MappedInputManager& mappedInput) : Activity("Sleep", renderer, mappedInput) {} void onEnter() override; + void onScreenshotRequest() override; private: void renderDefaultSleepScreen() const; void renderCustomSleepScreen() const; void renderCoverSleepScreen() const; void renderBitmapSleepScreen(const Bitmap& bitmap) const; + bool renderPxcSleepScreen(const std::string& path) const; void renderBlankSleepScreen() const; + + // Tracks the last factory-LUT render so onScreenshotRequest() can re-render the same image. + mutable std::string lastGrayscalePath; + mutable bool lastGrayscaleIsPxc = false; }; diff --git a/src/activities/browser/OpdsBookBrowserActivity.cpp b/src/activities/browser/OpdsBookBrowserActivity.cpp index 96e4e28c01..40eada071f 100644 --- a/src/activities/browser/OpdsBookBrowserActivity.cpp +++ b/src/activities/browser/OpdsBookBrowserActivity.cpp @@ -8,6 +8,7 @@ #include #include "MappedInputManager.h" +#include "SilentRestart.h" #include "activities/network/WifiSelectionActivity.h" #include "activities/util/KeyboardEntryActivity.h" #include "components/UITheme.h" @@ -40,9 +41,14 @@ void OpdsBookBrowserActivity::onEnter() { void OpdsBookBrowserActivity::onExit() { Activity::onExit(); - WiFi.mode(WIFI_OFF); entries.clear(); navigationHistory.clear(); + + if (WiFi.getMode() != WIFI_MODE_NULL) { + WiFi.disconnect(false); + delay(30); + silentRestart(); + } } void OpdsBookBrowserActivity::loop() { @@ -274,7 +280,7 @@ void OpdsBookBrowserActivity::downloadBook(const OpdsEntry& book) { downloadTotal = total; requestUpdate(true); }, - server.username, server.password); + nullptr, server.username, server.password); if (result == HttpDownloader::OK) { Epub(filename, "/.crosspoint").clearCache(); @@ -364,8 +370,7 @@ void OpdsBookBrowserActivity::onWifiSelectionComplete(const bool connected) { requestUpdate(true); fetchFeed(currentPath); } else { - WiFi.disconnect(); - WiFi.mode(WIFI_OFF); + // Leave WiFi up; onExit's silent reboot handles teardown without fragmenting. state = BrowserState::ERROR; errorMessage = tr(STR_WIFI_CONN_FAILED); requestUpdate(); diff --git a/src/activities/home/FileBrowserActivity.cpp b/src/activities/home/FileBrowserActivity.cpp index 870e93b6dc..5737fdca82 100644 --- a/src/activities/home/FileBrowserActivity.cpp +++ b/src/activities/home/FileBrowserActivity.cpp @@ -16,6 +16,11 @@ namespace { constexpr unsigned long GO_HOME_MS = 1000; + +bool isSupportedFile(std::string_view name) { + return FsHelpers::hasEpubExtension(name) || FsHelpers::hasXtcExtension(name) || FsHelpers::hasTxtExtension(name) || + FsHelpers::hasMarkdownExtension(name) || FsHelpers::hasBmpExtension(name) || FsHelpers::hasPxcExtension(name); +} } // namespace void FileBrowserActivity::loadFiles() { @@ -44,9 +49,7 @@ void FileBrowserActivity::loadFiles() { if (FsHelpers::checkFileExtension(filename, ".bin")) { files.emplace_back(filename); } - } else if (FsHelpers::hasEpubExtension(filename) || FsHelpers::hasXtcExtension(filename) || - FsHelpers::hasTxtExtension(filename) || FsHelpers::hasMarkdownExtension(filename) || - FsHelpers::hasBmpExtension(filename)) { + } else if (isSupportedFile(filename)) { files.emplace_back(filename); } } diff --git a/src/activities/network/CalibreConnectActivity.cpp b/src/activities/network/CalibreConnectActivity.cpp index a42ab16e2e..ca8b51992a 100644 --- a/src/activities/network/CalibreConnectActivity.cpp +++ b/src/activities/network/CalibreConnectActivity.cpp @@ -7,6 +7,7 @@ #include #include "MappedInputManager.h" +#include "SilentRestart.h" #include "WifiSelectionActivity.h" #include "components/UITheme.h" #include "fontIds.h" @@ -51,14 +52,11 @@ void CalibreConnectActivity::onEnter() { void CalibreConnectActivity::onExit() { Activity::onExit(); - stopWebServer(); - MDNS.end(); - - delay(50); - WiFi.disconnect(false); - delay(30); - WiFi.mode(WIFI_OFF); - delay(30); + if (WiFi.getMode() != WIFI_MODE_NULL) { + WiFi.disconnect(false); + delay(30); + silentRestart(); + } } void CalibreConnectActivity::onWifiSelectionComplete(const bool connected) { diff --git a/src/activities/network/CrossPointWebServerActivity.cpp b/src/activities/network/CrossPointWebServerActivity.cpp index 71f1bf4137..44ccfb5bcb 100644 --- a/src/activities/network/CrossPointWebServerActivity.cpp +++ b/src/activities/network/CrossPointWebServerActivity.cpp @@ -11,6 +11,7 @@ #include "MappedInputManager.h" #include "NetworkModeSelectionActivity.h" +#include "SilentRestart.h" #include "WifiSelectionActivity.h" #include "activities/network/CalibreConnectActivity.h" #include "components/UITheme.h" @@ -75,36 +76,16 @@ void CrossPointWebServerActivity::onExit() { state = WebServerActivityState::SHUTTING_DOWN; - // Stop the web server first (before disconnecting WiFi) - stopWebServer(); - - // Stop mDNS - MDNS.end(); - - // Stop DNS server if running (AP mode) - if (dnsServer) { - LOG_DBG("WEBACT", "Stopping DNS server..."); - dnsServer->stop(); - delete dnsServer; - dnsServer = nullptr; - } - - // Brief wait for LWIP stack to flush pending packets - delay(50); - - // Disconnect WiFi gracefully - if (isApMode) { - LOG_DBG("WEBACT", "Stopping WiFi AP..."); - WiFi.softAPdisconnect(true); - } else { - LOG_DBG("WEBACT", "Disconnecting WiFi (graceful)..."); - WiFi.disconnect(false); // false = don't erase credentials, send disconnect frame + // Skip reboot if WiFi was never activated (e.g. user backed out of mode selection). + if (WiFi.getMode() != WIFI_MODE_NULL) { + if (isApMode) { + WiFi.softAPdisconnect(true); + } else { + WiFi.disconnect(false); + } + delay(30); + silentRestart(); } - delay(30); // Allow disconnect frame to be sent - - LOG_DBG("WEBACT", "Setting WiFi mode OFF..."); - WiFi.mode(WIFI_OFF); - delay(30); // Allow WiFi hardware to power down LOG_DBG("WEBACT", "Free heap at onExit end: %d bytes", ESP.getFreeHeap()); } @@ -270,15 +251,6 @@ void CrossPointWebServerActivity::startWebServer() { } } -void CrossPointWebServerActivity::stopWebServer() { - if (webServer && webServer->isRunning()) { - LOG_DBG("WEBACT", "Stopping web server..."); - webServer->stop(); - LOG_DBG("WEBACT", "Web server stopped"); - } - webServer.reset(); -} - void CrossPointWebServerActivity::loop() { // Handle different states if (state == WebServerActivityState::SERVER_RUNNING) { diff --git a/src/activities/network/CrossPointWebServerActivity.h b/src/activities/network/CrossPointWebServerActivity.h index bc685c6b1c..557bf4437e 100644 --- a/src/activities/network/CrossPointWebServerActivity.h +++ b/src/activities/network/CrossPointWebServerActivity.h @@ -59,7 +59,6 @@ class CrossPointWebServerActivity final : public Activity { void onWifiSelectionComplete(bool connected); void startAccessPoint(); void startWebServer(); - void stopWebServer(); public: explicit CrossPointWebServerActivity(GfxRenderer& renderer, MappedInputManager& mappedInput) diff --git a/src/activities/network/WifiSelectionActivity.cpp b/src/activities/network/WifiSelectionActivity.cpp index e34403e377..d1c6e1d2b9 100644 --- a/src/activities/network/WifiSelectionActivity.cpp +++ b/src/activities/network/WifiSelectionActivity.cpp @@ -472,64 +472,63 @@ void WifiSelectionActivity::render(RenderLock&&) { renderer.clearScreen(); - const auto& metrics = UITheme::getInstance().getMetrics(); - const auto pageWidth = renderer.getScreenWidth(); - const auto pageHeight = renderer.getScreenHeight(); + auto& theme = UITheme::getInstance(); + auto metrics = theme.getMetrics(); + Rect screen = theme.getScreenSafeArea(renderer, true, false); // Draw header char countStr[32]; snprintf(countStr, sizeof(countStr), tr(STR_NETWORKS_FOUND), networks.size()); - GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_WIFI_NETWORKS), - countStr); - GUI.drawSubHeader(renderer, Rect{0, metrics.topPadding + metrics.headerHeight, pageWidth, metrics.tabBarHeight}, - cachedMacAddress.c_str()); + GUI.drawHeader(renderer, Rect{screen.x, screen.y + metrics.topPadding, screen.width, metrics.headerHeight}, + tr(STR_WIFI_NETWORKS), countStr); + GUI.drawSubHeader( + renderer, + Rect{screen.x, screen.y + metrics.topPadding + metrics.headerHeight, screen.width, metrics.tabBarHeight}, + cachedMacAddress.c_str()); switch (state) { case WifiSelectionState::AUTO_CONNECTING: - renderConnecting(); + renderConnecting(&screen, &metrics); break; case WifiSelectionState::SCANNING: - renderConnecting(); // Reuse connecting screen with different message + renderConnecting(&screen, &metrics); // Reuse connecting screen with different message break; case WifiSelectionState::NETWORK_LIST: - renderNetworkList(); + renderNetworkList(&screen, &metrics); break; case WifiSelectionState::CONNECTING: - renderConnecting(); + renderConnecting(&screen, &metrics); break; case WifiSelectionState::CONNECTED: - renderConnected(); + renderConnected(&screen, &metrics); break; case WifiSelectionState::SAVE_PROMPT: - renderSavePrompt(); + renderSavePrompt(&screen, &metrics); break; case WifiSelectionState::CONNECTION_FAILED: - renderConnectionFailed(); + renderConnectionFailed(&screen, &metrics); break; case WifiSelectionState::FORGET_PROMPT: - renderForgetPrompt(); + renderForgetPrompt(&screen, &metrics); break; } renderer.displayBuffer(); } -void WifiSelectionActivity::renderNetworkList() const { - const auto& metrics = UITheme::getInstance().getMetrics(); - const auto pageWidth = renderer.getScreenWidth(); - const auto pageHeight = renderer.getScreenHeight(); - +void WifiSelectionActivity::renderNetworkList(const Rect* screen, const ThemeMetrics* metrics) const { if (networks.empty()) { // No networks found or scan failed const auto height = renderer.getLineHeight(UI_10_FONT_ID); - const auto top = (pageHeight - height) / 2; - renderer.drawCenteredText(UI_10_FONT_ID, top, tr(STR_NO_NETWORKS)); - renderer.drawCenteredText(SMALL_FONT_ID, top + height + 10, tr(STR_PRESS_OK_SCAN)); + const auto top = screen->y + (screen->height - height) / 2; + UITheme::drawCenteredText(renderer, *screen, UI_10_FONT_ID, top, tr(STR_NO_NETWORKS)); + UITheme::drawCenteredText(renderer, *screen, SMALL_FONT_ID, top + height + 10, tr(STR_PRESS_OK_SCAN)); } else { - int contentTop = metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing; - int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing * 2; + int contentTop = + screen->y + metrics->topPadding + metrics->headerHeight + metrics->tabBarHeight + metrics->verticalSpacing; + int contentHeight = screen->height - contentTop - metrics->verticalSpacing * 2; GUI.drawList( - renderer, Rect{0, contentTop, pageWidth, contentHeight}, static_cast(networks.size()), + renderer, Rect{screen->x, contentTop, screen->width, contentHeight}, static_cast(networks.size()), selectedNetworkIndex, [this](int index) { return networks[index].ssid; }, nullptr, nullptr, [this](int index) { auto network = networks[index]; @@ -539,7 +538,7 @@ void WifiSelectionActivity::renderNetworkList() const { } GUI.drawHelpText(renderer, - Rect{0, pageHeight - metrics.buttonHintsHeight - metrics.contentSidePadding - 15, pageWidth, 20}, + Rect{screen->x, screen->y + screen->height - metrics->contentSidePadding - 15, screen->width, 20}, tr(STR_NETWORK_LEGEND)); const bool hasSavedPassword = !networks.empty() && networks[selectedNetworkIndex].hasSavedPassword; @@ -549,67 +548,64 @@ void WifiSelectionActivity::renderNetworkList() const { GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); } -void WifiSelectionActivity::renderConnecting() const { - const auto pageHeight = renderer.getScreenHeight(); +void WifiSelectionActivity::renderConnecting(const Rect* screen, const ThemeMetrics* metrics) const { const auto height = renderer.getLineHeight(UI_10_FONT_ID); - const auto top = (pageHeight - height) / 2; + const auto top = screen->y + (screen->height - height) / 2; if (state == WifiSelectionState::SCANNING) { - renderer.drawCenteredText(UI_10_FONT_ID, top, tr(STR_SCANNING)); + UITheme::drawCenteredText(renderer, *screen, UI_10_FONT_ID, top, tr(STR_SCANNING)); } else { - renderer.drawCenteredText(UI_12_FONT_ID, top - 40, tr(STR_CONNECTING), true, EpdFontFamily::BOLD); + UITheme::drawCenteredText(renderer, *screen, UI_12_FONT_ID, top - 40, tr(STR_CONNECTING), true, + EpdFontFamily::BOLD); std::string ssidInfo = std::string(tr(STR_TO_PREFIX)) + selectedSSID; if (ssidInfo.length() > 25) { ssidInfo.replace(22, ssidInfo.length() - 22, "..."); } - renderer.drawCenteredText(UI_10_FONT_ID, top, ssidInfo.c_str()); + UITheme::drawCenteredText(renderer, *screen, UI_10_FONT_ID, top, ssidInfo.c_str()); } } -void WifiSelectionActivity::renderConnected() const { - const auto pageHeight = renderer.getScreenHeight(); +void WifiSelectionActivity::renderConnected(const Rect* screen, const ThemeMetrics* metrics) const { const auto height = renderer.getLineHeight(UI_10_FONT_ID); - const auto top = (pageHeight - height * 4) / 2; + const auto top = screen->y + (screen->height - height * 4) / 2; - renderer.drawCenteredText(UI_12_FONT_ID, top - 30, tr(STR_CONNECTED), true, EpdFontFamily::BOLD); + UITheme::drawCenteredText(renderer, *screen, UI_12_FONT_ID, top - 30, tr(STR_CONNECTED), true, EpdFontFamily::BOLD); std::string ssidInfo = std::string(tr(STR_NETWORK_PREFIX)) + selectedSSID; if (ssidInfo.length() > 28) { ssidInfo.replace(25, ssidInfo.length() - 25, "..."); } - renderer.drawCenteredText(UI_10_FONT_ID, top + 10, ssidInfo.c_str()); + UITheme::drawCenteredText(renderer, *screen, UI_10_FONT_ID, top + 10, ssidInfo.c_str()); const std::string ipInfo = std::string(tr(STR_IP_ADDRESS_PREFIX)) + connectedIP; - renderer.drawCenteredText(UI_10_FONT_ID, top + 40, ipInfo.c_str()); + UITheme::drawCenteredText(renderer, *screen, UI_10_FONT_ID, top + 40, ipInfo.c_str()); // Use centralized button hints const auto labels = mappedInput.mapLabels("", tr(STR_DONE), "", ""); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); } -void WifiSelectionActivity::renderSavePrompt() const { - const auto pageWidth = renderer.getScreenWidth(); - const auto pageHeight = renderer.getScreenHeight(); +void WifiSelectionActivity::renderSavePrompt(const Rect* screen, const ThemeMetrics* metrics) const { const auto height = renderer.getLineHeight(UI_10_FONT_ID); - const auto top = (pageHeight - height * 3) / 2; + const auto top = screen->y + (screen->height - height * 3) / 2; - renderer.drawCenteredText(UI_12_FONT_ID, top - 40, tr(STR_CONNECTED), true, EpdFontFamily::BOLD); + UITheme::drawCenteredText(renderer, *screen, UI_12_FONT_ID, top - 40, tr(STR_CONNECTED), true, EpdFontFamily::BOLD); std::string ssidInfo = std::string(tr(STR_NETWORK_PREFIX)) + selectedSSID; if (ssidInfo.length() > 28) { ssidInfo.replace(25, ssidInfo.length() - 25, "..."); } - renderer.drawCenteredText(UI_10_FONT_ID, top, ssidInfo.c_str()); + UITheme::drawCenteredText(renderer, *screen, UI_10_FONT_ID, top, ssidInfo.c_str()); - renderer.drawCenteredText(UI_10_FONT_ID, top + 40, tr(STR_SAVE_PASSWORD)); + UITheme::drawCenteredText(renderer, *screen, UI_10_FONT_ID, top + 40, tr(STR_SAVE_PASSWORD)); // Draw Yes/No buttons const int buttonY = top + 80; constexpr int buttonWidth = 60; constexpr int buttonSpacing = 30; constexpr int totalWidth = buttonWidth * 2 + buttonSpacing; - const int startX = (pageWidth - totalWidth) / 2; + const int startX = screen->x + (screen->width - totalWidth) / 2; // Draw "Yes" button if (savePromptSelection == 0) { @@ -632,41 +628,40 @@ void WifiSelectionActivity::renderSavePrompt() const { GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); } -void WifiSelectionActivity::renderConnectionFailed() const { - const auto pageHeight = renderer.getScreenHeight(); +void WifiSelectionActivity::renderConnectionFailed(const Rect* screen, const ThemeMetrics* metrics) const { const auto height = renderer.getLineHeight(UI_10_FONT_ID); - const auto top = (pageHeight - height * 2) / 2; + const auto top = screen->y + (screen->height - height * 2) / 2; - renderer.drawCenteredText(UI_12_FONT_ID, top - 20, tr(STR_CONNECTION_FAILED), true, EpdFontFamily::BOLD); - renderer.drawCenteredText(UI_10_FONT_ID, top + 20, connectionError.c_str()); + UITheme::drawCenteredText(renderer, *screen, UI_12_FONT_ID, top - 20, tr(STR_CONNECTION_FAILED), true, + EpdFontFamily::BOLD); + UITheme::drawCenteredText(renderer, *screen, UI_10_FONT_ID, top + 20, connectionError.c_str()); // Use centralized button hints const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_DONE), "", ""); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); } -void WifiSelectionActivity::renderForgetPrompt() const { - const auto pageWidth = renderer.getScreenWidth(); - const auto pageHeight = renderer.getScreenHeight(); +void WifiSelectionActivity::renderForgetPrompt(const Rect* screen, const ThemeMetrics* metrics) const { const auto height = renderer.getLineHeight(UI_10_FONT_ID); - const auto top = (pageHeight - height * 3) / 2; + const auto top = screen->y + (screen->height - height * 3) / 2; - renderer.drawCenteredText(UI_12_FONT_ID, top - 40, tr(STR_FORGET_NETWORK), true, EpdFontFamily::BOLD); + UITheme::drawCenteredText(renderer, *screen, UI_12_FONT_ID, top - 40, tr(STR_FORGET_NETWORK), true, + EpdFontFamily::BOLD); std::string ssidInfo = std::string(tr(STR_NETWORK_PREFIX)) + selectedSSID; if (ssidInfo.length() > 28) { ssidInfo.replace(25, ssidInfo.length() - 25, "..."); } - renderer.drawCenteredText(UI_10_FONT_ID, top, ssidInfo.c_str()); + UITheme::drawCenteredText(renderer, *screen, UI_10_FONT_ID, top, ssidInfo.c_str()); - renderer.drawCenteredText(UI_10_FONT_ID, top + 40, tr(STR_FORGET_AND_REMOVE)); + UITheme::drawCenteredText(renderer, *screen, UI_10_FONT_ID, top + 40, tr(STR_FORGET_AND_REMOVE)); // Draw Cancel/Forget network buttons const int buttonY = top + 80; constexpr int buttonWidth = 120; constexpr int buttonSpacing = 30; constexpr int totalWidth = buttonWidth * 2 + buttonSpacing; - const int startX = (pageWidth - totalWidth) / 2; + const int startX = screen->x + (screen->width - totalWidth) / 2; // Draw "Cancel" button if (forgetPromptSelection == 0) { diff --git a/src/activities/network/WifiSelectionActivity.h b/src/activities/network/WifiSelectionActivity.h index 1ea7fc0a51..baacf4da22 100644 --- a/src/activities/network/WifiSelectionActivity.h +++ b/src/activities/network/WifiSelectionActivity.h @@ -9,6 +9,9 @@ #include "activities/Activity.h" #include "util/ButtonNavigator.h" +struct Rect; +struct ThemeMetrics; + // Structure to hold WiFi network information struct WifiNetworkInfo { std::string ssid; @@ -80,13 +83,13 @@ class WifiSelectionActivity final : public Activity { static constexpr unsigned long CONNECTION_TIMEOUT_MS = 15000; unsigned long connectionStartTime = 0; - void renderNetworkList() const; - void renderPasswordEntry() const; - void renderConnecting() const; - void renderConnected() const; - void renderSavePrompt() const; - void renderConnectionFailed() const; - void renderForgetPrompt() const; + void renderNetworkList(const Rect* screen, const ThemeMetrics* metrics) const; + void renderPasswordEntry(const Rect* screen, const ThemeMetrics* metrics) const; + void renderConnecting(const Rect* screen, const ThemeMetrics* metrics) const; + void renderConnected(const Rect* screen, const ThemeMetrics* metrics) const; + void renderSavePrompt(const Rect* screen, const ThemeMetrics* metrics) const; + void renderConnectionFailed(const Rect* screen, const ThemeMetrics* metrics) const; + void renderForgetPrompt(const Rect* screen, const ThemeMetrics* metrics) const; void startWifiScan(); void processWifiScanResults(); diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 7732762bd4..cebdc3229b 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -45,8 +46,76 @@ int clampPercent(int percent) { return percent; } +// SD card folder finished books are moved into. Single source of truth for the path. +// constexpr ⇒ lives in flash .rodata, no DRAM cost. +constexpr char READ_FOLDER[] = "/read"; + +// True if path is inside READ_FOLDER (starts with "/"). Non-allocating so +// it is cheap to call from loop(), and avoids reintroducing a separate "/Read/" literal. +bool isInReadFolder(const std::string& path) { + constexpr size_t n = sizeof(READ_FOLDER) - 1; // length of "/Read" (excludes NUL) + return path.size() > n && path.compare(0, n, READ_FOLDER) == 0 && path[n] == '/'; +} + +// Pick a non-colliding destination path inside /Read/ for a finished book. +// Mirrors the suffixing scheme used elsewhere: "name.epub" -> "name (2).epub", etc. +std::string buildReadFolderDestination(const std::string& srcPath) { + const size_t lastSlash = srcPath.rfind('/'); + const std::string filename = (lastSlash != std::string::npos) ? srcPath.substr(lastSlash + 1) : srcPath; + + Storage.mkdir(READ_FOLDER); + std::string dstPath = std::string(READ_FOLDER) + "/" + filename; + if (!Storage.exists(dstPath.c_str())) { + return dstPath; + } + + const size_t dotPos = filename.rfind('.'); + const std::string base = (dotPos != std::string::npos) ? filename.substr(0, dotPos) : filename; + const std::string ext = (dotPos != std::string::npos) ? filename.substr(dotPos) : ""; + int suffix = 2; + do { + dstPath = std::string(READ_FOLDER) + "/" + base + " (" + std::to_string(suffix) + ")" + ext; + suffix++; + } while (Storage.exists(dstPath.c_str()) && suffix < 100); + return dstPath; +} + +// Relocate a finished book and its cache dir into /read/, keep it in recents by +// repointing its entry to the new path, and repoint the resume pointer too. +// On rename failure: LOG_ERR and leave everything in place (no UI alert subsystem here). +void moveFinishedBookToReadFolder(const std::string& srcPath, const std::string& dstPath, + const std::string& oldCachePath) { + LOG_INF("ERS", "Moving finished epub: %s -> %s", srcPath.c_str(), dstPath.c_str()); + if (!Storage.rename(srcPath.c_str(), dstPath.c_str())) { + LOG_ERR("ERS", "Failed to move finished book to '/Read' folder"); + return; + } + + // Cache dir is keyed by hash of the epub path (see Epub ctor), so it must be re-keyed. + const std::string newCachePath = "/.crosspoint/epub_" + std::to_string(std::hash{}(dstPath)); + if (!oldCachePath.empty() && Storage.exists(oldCachePath.c_str())) { + if (!Storage.rename(oldCachePath.c_str(), newCachePath.c_str())) { + LOG_ERR("ERS", "Failed to rename cache dir %s -> %s (non-fatal)", oldCachePath.c_str(), newCachePath.c_str()); + } + } + + // Keep the book in recents (crossink behavior): repoint the entry to its new + // location instead of dropping it. updatePath persists on success. + RECENT_BOOKS.updatePath(srcPath, dstPath, oldCachePath, newCachePath); + if (APP_STATE.openEpubPath == srcPath) { + APP_STATE.openEpubPath = dstPath; + APP_STATE.saveToFile(); + } +} + } // namespace +void EpubReaderActivity::renderPageCallback(const GfxRenderer& r, const void* raw) { + const auto* c = static_cast(raw); + c->page->render(const_cast(r), c->fontId, c->left, c->top); + c->activity->renderStatusBar(); +} + void EpubReaderActivity::onEnter() { Activity::onEnter(); @@ -109,7 +178,15 @@ void EpubReaderActivity::onExit() { APP_STATE.readerActivityLoadCount = 0; APP_STATE.saveToFile(); section.reset(); - epub.reset(); + if (pendingReadFolderMove && epub) { + const std::string srcPath = epub->getPath(); + const std::string oldCachePath = epub->getCachePath(); + const std::string dstPath = buildReadFolderDestination(srcPath); + epub.reset(); // release the Epub (and any open handles) before renaming on the SD card + moveFinishedBookToReadFolder(srcPath, dstPath, oldCachePath); + } else { + epub.reset(); + } } void EpubReaderActivity::loop() { @@ -119,6 +196,15 @@ void EpubReaderActivity::loop() { return; } + // Being on the "End of Book" screen (currentSpineIndex == spine count) means the book is + // finished. Arm the move here so ANY exit path (Back, Home, file browser) relocates the + // book in onExit(); paging back off the end screen disarms it (book not actually finished). + if (currentSpineIndex > 0 && currentSpineIndex >= epub->getSpineItemsCount()) { + pendingReadFolderMove = SETTINGS.moveFinishedToReadFolder && !isInReadFolder(epub->getPath()); + } else { + pendingReadFolderMove = false; + } + if (automaticPageTurnActive) { if (mappedInput.wasReleased(MappedInputManager::Button::Confirm) || mappedInput.wasReleased(MappedInputManager::Button::Back)) { @@ -727,7 +813,12 @@ void EpubReaderActivity::render(RenderLock&& lock) { if (pendingScreenshot) { pendingScreenshot = false; - ScreenshotUtil::takeScreenshot(renderer); + if (lastPageWasFactoryGray) { + ScreenshotUtil::prepareFactoryLutScreenshot(renderer); + onScreenshotRequest(); + } else { + ScreenshotUtil::takeScreenshot(renderer); + } } } @@ -778,32 +869,16 @@ void EpubReaderActivity::renderContents(std::unique_ptr page, const int or scope.endScanAndPrewarm(); const auto tPrewarm = millis(); - // Force special handling for pages with images when anti-aliasing is on - bool imagePageWithAA = page->hasImages() && SETTINGS.textAntiAliasing; - page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop); renderStatusBar(); const auto tBwRender = millis(); - if (imagePageWithAA) { - // Double FAST_REFRESH with selective image blanking (pablohc's technique): - // HALF_REFRESH sets particles too firmly for the grayscale LUT to adjust. - // Instead, blank only the image area and do two fast refreshes. - // Step 1: Display page with image area blanked (text appears, image area white) - // Step 2: Re-render with images and display again (images appear clean) - int16_t imgX, imgY, imgW, imgH; - if (page->getImageBoundingBox(imgX, imgY, imgW, imgH)) { - renderer.fillRect(imgX + orientedMarginLeft, imgY + orientedMarginTop, imgW, imgH, false); - renderer.displayBuffer(HalDisplay::FAST_REFRESH); - - // Re-render page content to restore images into the blanked area - // Status bar is not re-rendered here to avoid reading stale dynamic values (e.g. battery %) - page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop); - renderer.displayBuffer(HalDisplay::FAST_REFRESH); - } else { - renderer.displayBuffer(HalDisplay::HALF_REFRESH); - } - // Double FAST_REFRESH handles ghosting for image pages; don't count toward full refresh cadence + const bool isImagePage = page->hasImages(); + const bool useFactoryGray = SETTINGS.textAntiAliasing && isImagePage; + lastPageWasFactoryGray = useFactoryGray; + if (useFactoryGray) { + lastFactoryMarginTop = orientedMarginTop; + lastFactoryMarginLeft = orientedMarginLeft; } else { ReaderUtils::displayWithRefreshCycle(renderer, pagesUntilFullRefresh); } @@ -814,35 +889,28 @@ void EpubReaderActivity::renderContents(std::unique_ptr page, const int or const auto tBwStore = millis(); // grayscale rendering - // TODO: Only do this if font supports it if (SETTINGS.textAntiAliasing) { - renderer.clearScreen(0x00); - renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB); - page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop); - renderer.copyGrayscaleLsbBuffers(); - const auto tGrayLsb = millis(); - - // Render and copy to MSB buffer - renderer.clearScreen(0x00); - renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB); - page->render(renderer, SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop); - renderer.copyGrayscaleMsbBuffers(); - const auto tGrayMsb = millis(); - - // display grayscale part - renderer.displayGrayBuffer(); - const auto tGrayDisplay = millis(); - renderer.setRenderMode(GfxRenderer::BW); - // restore the bw data + PageRenderCtx grayCtx{page.get(), SETTINGS.getReaderFontId(), orientedMarginLeft, orientedMarginTop, this}; + + const auto tGrayStart = millis(); + const auto grayMode = useFactoryGray ? GfxRenderer::GrayscaleDriveMode::FactoryQuality + : GfxRenderer::GrayscaleDriveMode::Differential; + renderer.renderGrayscale(grayMode, &renderPageCallback, &grayCtx); + const auto tGrayEnd = millis(); + fcm->logStats(useFactoryGray ? "gray_factory_quality" : "gray"); + + // restoreBwBuffer() copies the saved BW frame back AND rebases RED RAM + // via cleanupGrayscaleBuffers, which is sufficient cleanup for both + // differential and factory paths — no extra RED RAM write needed. renderer.restoreBwBuffer(); const auto tBwRestore = millis(); const auto tEnd = millis(); LOG_DBG("ERS", - "Page render: prewarm=%lums bw_render=%lums display=%lums bw_store=%lums " - "gray_lsb=%lums gray_msb=%lums gray_display=%lums bw_restore=%lums total=%lums", - tPrewarm - t0, tBwRender - tPrewarm, tDisplay - tBwRender, tBwStore - tDisplay, tGrayLsb - tBwStore, - tGrayMsb - tGrayLsb, tGrayDisplay - tGrayMsb, tBwRestore - tGrayDisplay, tEnd - t0); + "Page render (%s): prewarm=%lums bw_render=%lums display=%lums bw_store=%lums " + "gray=%lums bw_restore=%lums total=%lums", + useFactoryGray ? "factory" : "diff", tPrewarm - t0, tBwRender - tPrewarm, tDisplay - tBwRender, + tBwStore - tDisplay, tGrayEnd - tGrayStart, tBwRestore - tGrayEnd, tEnd - t0); } else { // restore the bw data renderer.restoreBwBuffer(); @@ -856,6 +924,22 @@ void EpubReaderActivity::renderContents(std::unique_ptr page, const int or } } +void EpubReaderActivity::onScreenshotRequest() { + if (!section || !lastPageWasFactoryGray) return; + + auto p = section->loadPageFromSectionFile(); + if (!p) return; + + // Preserve the BW page across the gray render so restoreBwBuffer's + // cleanupGrayscaleBuffers call rebases RED RAM to the actual page, not a + // cleared framebuffer. + if (!renderer.storeBwBuffer()) return; + + PageRenderCtx grayCtx{p.get(), SETTINGS.getReaderFontId(), lastFactoryMarginLeft, lastFactoryMarginTop, this}; + renderer.renderGrayscale(GfxRenderer::GrayscaleDriveMode::FactoryQuality, &renderPageCallback, &grayCtx); + renderer.restoreBwBuffer(); +} + void EpubReaderActivity::renderStatusBar() const { // Calculate progress in book const int currentPage = section->currentPage + 1; diff --git a/src/activities/reader/EpubReaderActivity.h b/src/activities/reader/EpubReaderActivity.h index 01de3fde45..be2f51ba30 100644 --- a/src/activities/reader/EpubReaderActivity.h +++ b/src/activities/reader/EpubReaderActivity.h @@ -31,6 +31,13 @@ class EpubReaderActivity final : public Activity { bool pendingSyncSaveError = false; bool skipNextButtonCheck = false; // Skip button processing for one frame after subactivity exit bool automaticPageTurnActive = false; + // Context saved from the last factory-gray image page render, used by onScreenshotRequest(). + bool lastPageWasFactoryGray = false; + int lastFactoryMarginTop = 0; + int lastFactoryMarginLeft = 0; + // Set when the reader is left at end-of-book and SETTINGS.moveFinishedToReadFolder is on. + // Consumed in onExit() to relocate the finished book into /Read/. + bool pendingReadFolderMove = false; // Footnote support std::vector currentPageFootnotes; @@ -42,6 +49,13 @@ class EpubReaderActivity final : public Activity { SavedPosition savedPositions[MAX_FOOTNOTE_DEPTH] = {}; int footnoteDepth = 0; + struct PageRenderCtx { + Page* page; + int fontId, left, top; + const EpubReaderActivity* activity; + }; + static void renderPageCallback(const GfxRenderer& r, const void* raw); + void renderContents(std::unique_ptr page, int orientedMarginTop, int orientedMarginRight, int orientedMarginBottom, int orientedMarginLeft); void renderStatusBar() const; @@ -65,6 +79,7 @@ class EpubReaderActivity final : public Activity { void onExit() override; void loop() override; void render(RenderLock&& lock) override; + void onScreenshotRequest() override; bool isReaderActivity() const override { return true; } ScreenshotInfo getScreenshotInfo() const override; }; diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp index ea68bd8f5d..0f085dcea6 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp @@ -9,22 +9,6 @@ int EpubReaderChapterSelectionActivity::getTotalItems() const { return epub->getTocItemsCount(); } -int EpubReaderChapterSelectionActivity::getPageItems() const { - // Layout constants used in renderScreen - constexpr int lineHeight = 30; - - const int screenHeight = renderer.getScreenHeight(); - const auto orientation = renderer.getOrientation(); - // In inverted portrait, the button hints are drawn near the logical top. - // Reserve vertical space so list items do not collide with the hints. - const bool isPortraitInverted = orientation == GfxRenderer::Orientation::PortraitInverted; - const int hintGutterHeight = isPortraitInverted ? 50 : 0; - const int startY = 60 + hintGutterHeight; - const int availableHeight = screenHeight - startY - lineHeight; - // Clamp to at least one item to avoid division by zero and empty paging. - return std::max(1, availableHeight / lineHeight); -} - void EpubReaderChapterSelectionActivity::onEnter() { Activity::onEnter(); @@ -44,7 +28,7 @@ void EpubReaderChapterSelectionActivity::onEnter() { void EpubReaderChapterSelectionActivity::onExit() { Activity::onExit(); } void EpubReaderChapterSelectionActivity::loop() { - const int pageItems = getPageItems(); + const int pageItems = UITheme::getInstance().getNumberOfItemsPerPage(renderer, true, false, true, false); const int totalItems = getTotalItems(); if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { @@ -89,46 +73,22 @@ void EpubReaderChapterSelectionActivity::loop() { void EpubReaderChapterSelectionActivity::render(RenderLock&&) { renderer.clearScreen(); - const auto pageWidth = renderer.getScreenWidth(); - const auto orientation = renderer.getOrientation(); - // Landscape orientation: reserve a horizontal gutter for button hints. - const bool isLandscapeCw = orientation == GfxRenderer::Orientation::LandscapeClockwise; - const bool isLandscapeCcw = orientation == GfxRenderer::Orientation::LandscapeCounterClockwise; - // Inverted portrait: reserve vertical space for hints at the top. - const bool isPortraitInverted = orientation == GfxRenderer::Orientation::PortraitInverted; - const int hintGutterWidth = (isLandscapeCw || isLandscapeCcw) ? 30 : 0; - // Landscape CW places hints on the left edge; CCW keeps them on the right. - const int contentX = isLandscapeCw ? hintGutterWidth : 0; - const int contentWidth = pageWidth - hintGutterWidth; - const int hintGutterHeight = isPortraitInverted ? 50 : 0; - const int contentY = hintGutterHeight; - const int pageItems = getPageItems(); - const int totalItems = getTotalItems(); - - // Manual centering to honor content gutters. - const int titleX = - contentX + (contentWidth - renderer.getTextWidth(UI_12_FONT_ID, tr(STR_SELECT_CHAPTER), EpdFontFamily::BOLD)) / 2; - renderer.drawText(UI_12_FONT_ID, titleX, 15 + contentY, tr(STR_SELECT_CHAPTER), true, EpdFontFamily::BOLD); + auto metrics = UITheme::getInstance().getMetrics(); + Rect screen = UITheme::getInstance().getScreenSafeArea(renderer, true, false); - const auto pageStartIndex = selectorIndex / pageItems * pageItems; - // Highlight only the content area, not the hint gutters. - renderer.fillRect(contentX, 60 + contentY + (selectorIndex % pageItems) * 30 - 2, contentWidth - 1, 30); + GUI.drawHeader(renderer, Rect{screen.x, screen.y + metrics.topPadding, screen.width, metrics.headerHeight}, + tr(STR_SELECT_CHAPTER)); - for (int i = 0; i < pageItems; i++) { - int itemIndex = pageStartIndex + i; - if (itemIndex >= totalItems) break; - const int displayY = 60 + contentY + i * 30; - const bool isSelected = (itemIndex == selectorIndex); + const int contentTop = screen.y + metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing; + const int contentHeight = screen.height - contentTop - metrics.verticalSpacing; - auto item = epub->getTocItem(itemIndex); - - // Indent per TOC level while keeping content within the gutter-safe region. - const int indentSize = contentX + 20 + (item.level - 1) * 15; - const std::string chapterName = - renderer.truncatedText(UI_10_FONT_ID, item.title.c_str(), contentWidth - 40 - indentSize); - - renderer.drawText(UI_10_FONT_ID, indentSize, displayY, chapterName.c_str(), !isSelected); - } + const int totalItems = getTotalItems(); + GUI.drawList(renderer, Rect{screen.x, contentTop, screen.width, contentHeight}, totalItems, selectorIndex, + [this](int index) { + auto item = epub->getTocItem(index); + std::string indent((item.level - 1) * 2, ' '); + return indent + item.title; + }); const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN)); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); diff --git a/src/activities/reader/EpubReaderMenuActivity.cpp b/src/activities/reader/EpubReaderMenuActivity.cpp index 1d95d9b7a1..23b3fafe8a 100644 --- a/src/activities/reader/EpubReaderMenuActivity.cpp +++ b/src/activities/reader/EpubReaderMenuActivity.cpp @@ -86,29 +86,12 @@ void EpubReaderMenuActivity::loop() { void EpubReaderMenuActivity::render(RenderLock&&) { renderer.clearScreen(); - const auto pageWidth = renderer.getScreenWidth(); - const auto orientation = renderer.getOrientation(); - // Landscape orientation: button hints are drawn along a vertical edge, so we - // reserve a horizontal gutter to prevent overlap with menu content. - const bool isLandscapeCw = orientation == GfxRenderer::Orientation::LandscapeClockwise; - const bool isLandscapeCcw = orientation == GfxRenderer::Orientation::LandscapeCounterClockwise; - // Inverted portrait: button hints appear near the logical top, so we reserve - // vertical space to keep the header and list clear. - const bool isPortraitInverted = orientation == GfxRenderer::Orientation::PortraitInverted; - const int hintGutterWidth = (isLandscapeCw || isLandscapeCcw) ? 30 : 0; - // Landscape CW places hints on the left edge; CCW keeps them on the right. - const int contentX = isLandscapeCw ? hintGutterWidth : 0; - const int contentWidth = pageWidth - hintGutterWidth; - const int hintGutterHeight = isPortraitInverted ? 50 : 0; - const int contentY = hintGutterHeight; - - // Title - const std::string truncTitle = - renderer.truncatedText(UI_12_FONT_ID, title.c_str(), contentWidth - 40, EpdFontFamily::BOLD); - // Manual centering so we can respect the content gutter. - const int titleX = - contentX + (contentWidth - renderer.getTextWidth(UI_12_FONT_ID, truncTitle.c_str(), EpdFontFamily::BOLD)) / 2; - renderer.drawText(UI_12_FONT_ID, titleX, 15 + contentY, truncTitle.c_str(), true, EpdFontFamily::BOLD); + + auto metrics = UITheme::getInstance().getMetrics(); + Rect screen = UITheme::getInstance().getScreenSafeArea(renderer, true, false); + + GUI.drawHeader(renderer, Rect{screen.x, screen.y + metrics.topPadding, screen.width, metrics.headerHeight}, + title.c_str()); // Progress summary std::string progressLine; @@ -117,37 +100,31 @@ void EpubReaderMenuActivity::render(RenderLock&&) { std::to_string(totalPages) + std::string(tr(STR_PAGES_SEPARATOR)); } progressLine += std::string(tr(STR_BOOK_PREFIX)) + std::to_string(bookProgressPercent) + "%"; - renderer.drawCenteredText(UI_10_FONT_ID, 45, progressLine.c_str()); - - // Menu Items - const int startY = 75 + contentY; - constexpr int lineHeight = 30; - - for (size_t i = 0; i < menuItems.size(); ++i) { - const int displayY = startY + (i * lineHeight); - const bool isSelected = (static_cast(i) == selectedIndex); - - if (isSelected) { - // Highlight only the content area so we don't paint over hint gutters. - renderer.fillRect(contentX, displayY, contentWidth - 1, lineHeight, true); - } - - renderer.drawText(UI_10_FONT_ID, contentX + 20, displayY, I18N.get(menuItems[i].labelId), !isSelected); - - if (menuItems[i].action == MenuAction::ROTATE_SCREEN) { - // Render current orientation value on the right edge of the content area. - const char* value = I18N.get(orientationLabels[pendingOrientation]); - const auto width = renderer.getTextWidth(UI_10_FONT_ID, value); - renderer.drawText(UI_10_FONT_ID, contentX + contentWidth - 20 - width, displayY, value, !isSelected); - } - - if (menuItems[i].action == MenuAction::AUTO_PAGE_TURN) { - // Render current page turn value on the right edge of the content area. - const auto value = pageTurnLabels[selectedPageTurnOption]; - const auto width = renderer.getTextWidth(UI_10_FONT_ID, value); - renderer.drawText(UI_10_FONT_ID, contentX + contentWidth - 20 - width, displayY, value, !isSelected); - } - } + GUI.drawSubHeader( + renderer, + Rect{screen.x, screen.y + metrics.topPadding + metrics.headerHeight, screen.width, metrics.tabBarHeight}, + progressLine.c_str()); + + const int contentTop = + screen.y + metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing; + const int contentHeight = screen.height - contentTop - metrics.verticalSpacing; + + GUI.drawList( + renderer, Rect{screen.x, contentTop, screen.width, contentHeight}, menuItems.size(), selectedIndex, + [this](int index) { return I18N.get(menuItems[index].labelId); }, nullptr, nullptr, + [this](int index) { + const auto value = menuItems[index].action; + if (value == MenuAction::ROTATE_SCREEN) { + // Render current orientation value on the right edge of the content area. + return I18N.get(orientationLabels[pendingOrientation]); + } else if (value == MenuAction::AUTO_PAGE_TURN) { + // Render current page turn value on the right edge of the content area. + return pageTurnLabels[selectedPageTurnOption]; + } else { + return ""; + } + }, + true); // Footer / Hints const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN)); diff --git a/src/activities/reader/EpubReaderPercentSelectionActivity.cpp b/src/activities/reader/EpubReaderPercentSelectionActivity.cpp index db4109f00a..78cb268339 100644 --- a/src/activities/reader/EpubReaderPercentSelectionActivity.cpp +++ b/src/activities/reader/EpubReaderPercentSelectionActivity.cpp @@ -58,18 +58,24 @@ void EpubReaderPercentSelectionActivity::loop() { void EpubReaderPercentSelectionActivity::render(RenderLock&&) { renderer.clearScreen(); - // Title and numeric percent value. - renderer.drawCenteredText(UI_12_FONT_ID, 15, tr(STR_GO_TO_PERCENT), true, EpdFontFamily::BOLD); + auto& theme = UITheme::getInstance(); + auto metrics = theme.getMetrics(); + Rect screen = theme.getScreenSafeArea(renderer, true, false); + + GUI.drawHeader(renderer, Rect{screen.x, screen.y + metrics.topPadding, screen.width, metrics.headerHeight}, + tr(STR_GO_TO_PERCENT)); + + const int contentTop = screen.y + metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing * 4; const std::string percentText = std::to_string(percent) + "%"; - renderer.drawCenteredText(UI_12_FONT_ID, 90, percentText.c_str(), true, EpdFontFamily::BOLD); + UITheme::drawCenteredText(renderer, screen, UI_12_FONT_ID, contentTop, percentText.c_str(), true, + EpdFontFamily::BOLD); // Draw slider track. - const int screenWidth = renderer.getScreenWidth(); constexpr int barWidth = 360; constexpr int barHeight = 16; - const int barX = (screenWidth - barWidth) / 2; - const int barY = 140; + const int barX = screen.x + (screen.width - barWidth) / 2; + const int barY = contentTop + metrics.verticalSpacing * 2; renderer.drawRect(barX, barY, barWidth, barHeight); @@ -84,7 +90,7 @@ void EpubReaderPercentSelectionActivity::render(RenderLock&&) { renderer.fillRect(knobX, barY - 4, 4, barHeight + 8, true); // Hint text for step sizes. - renderer.drawCenteredText(SMALL_FONT_ID, barY + 30, tr(STR_PERCENT_STEP_HINT), true); + UITheme::drawCenteredText(renderer, screen, SMALL_FONT_ID, barY + 30, tr(STR_PERCENT_STEP_HINT), true); // Button hints follow the current front button layout. const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), "-", "+"); diff --git a/src/activities/reader/KOReaderSyncActivity.cpp b/src/activities/reader/KOReaderSyncActivity.cpp index d445103608..834c2e6f5b 100644 --- a/src/activities/reader/KOReaderSyncActivity.cpp +++ b/src/activities/reader/KOReaderSyncActivity.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,7 @@ #include "KOReaderDocumentId.h" #include "MappedInputManager.h" #include "ReaderUtils.h" +#include "SilentRestart.h" #include "activities/ActivityManager.h" #include "activities/network/WifiSelectionActivity.h" #include "components/UITheme.h" @@ -47,15 +49,6 @@ void syncTimeWithNTP() { LOG_DBG("KOSync", "NTP sync timeout, using fallback"); } } -void wifiOff() { - if (esp_sntp_enabled()) { - esp_sntp_stop(); - } - WiFi.disconnect(false); - delay(100); - WiFi.mode(WIFI_OFF); - delay(100); -} } // namespace void KOReaderSyncActivity::ensureEpubLoaded() { @@ -269,8 +262,10 @@ void KOReaderSyncActivity::performUpload() { const auto result = KOReaderSyncClient::updateProgress(progress); + // Drop the radio while user reads the result; full teardown happens at silent reboot. + esp_wifi_stop(); + if (result != KOReaderSyncClient::OK) { - wifiOff(); { RenderLock lock(*this); state = SYNC_FAILED; @@ -280,7 +275,6 @@ void KOReaderSyncActivity::performUpload() { return; } - wifiOff(); { RenderLock lock(*this); state = UPLOAD_COMPLETE; @@ -299,6 +293,9 @@ void KOReaderSyncActivity::onEnter() { return; } + // Past this point every path uses WiFi. + wifiActivated = true; + // Check if already connected (e.g. from settings page auth) if (WiFi.status() == WL_CONNECTED) { LOG_DBG("KOSync", "Already connected to WiFi"); @@ -315,18 +312,28 @@ void KOReaderSyncActivity::onEnter() { void KOReaderSyncActivity::onExit() { Activity::onExit(); - wifiOff(); + if (wifiActivated) { + WiFi.disconnect(false); + delay(30); + silentRestartToReader(); + } } void KOReaderSyncActivity::render(RenderLock&&) { - const auto pageWidth = renderer.getScreenWidth(); - renderer.clearScreen(); - renderer.drawCenteredText(UI_12_FONT_ID, 15, tr(STR_KOREADER_SYNC), true, EpdFontFamily::BOLD); + auto metrics = UITheme::getInstance().getMetrics(); + Rect screen = UITheme::getInstance().getScreenSafeArea(renderer, true, false); + + GUI.drawHeader(renderer, Rect{screen.x, screen.y + metrics.topPadding, screen.width, metrics.headerHeight}, + tr(STR_KOREADER_SYNC)); + + int top = screen.y + screen.height / 2 - 40; if (state == NO_CREDENTIALS) { - renderer.drawCenteredText(UI_10_FONT_ID, 280, tr(STR_NO_CREDENTIALS_MSG), true, EpdFontFamily::BOLD); - renderer.drawCenteredText(UI_10_FONT_ID, 320, tr(STR_KOREADER_SETUP_HINT)); + UITheme::drawCenteredText(renderer, screen, UI_10_FONT_ID, top, tr(STR_NO_CREDENTIALS_MSG), true, + EpdFontFamily::BOLD); + UITheme::drawCenteredText(renderer, screen, UI_10_FONT_ID, top + 40, tr(STR_KOREADER_SETUP_HINT), true, + EpdFontFamily::BOLD); const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", ""); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); @@ -335,14 +342,15 @@ void KOReaderSyncActivity::render(RenderLock&&) { } if (state == SYNCING || state == UPLOADING) { - renderer.drawCenteredText(UI_10_FONT_ID, 300, statusMessage.c_str(), true, EpdFontFamily::BOLD); + UITheme::drawCenteredText(renderer, screen, UI_10_FONT_ID, top, statusMessage.c_str(), true, EpdFontFamily::BOLD); renderer.displayBuffer(); return; } if (state == SHOWING_RESULT) { // Show comparison - renderer.drawCenteredText(UI_10_FONT_ID, 120, tr(STR_PROGRESS_FOUND), true, EpdFontFamily::BOLD); + top = screen.y + metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing; + renderer.drawCenteredText(UI_10_FONT_ID, top, tr(STR_PROGRESS_FOUND), true, EpdFontFamily::BOLD); // Remote chapter name requires Epub (loaded lazily in performSync before this state). const int remoteTocIndex = epub->getTocIndexForSpineIndex(remotePosition.spineIndex); @@ -355,45 +363,47 @@ void KOReaderSyncActivity::render(RenderLock&&) { : (std::string(tr(STR_SECTION_PREFIX)) + std::to_string(currentSpineIndex + 1)); // Remote progress - chapter and page - renderer.drawText(UI_10_FONT_ID, 20, 160, tr(STR_REMOTE_LABEL), true); + renderer.drawText(UI_10_FONT_ID, screen.x + metrics.contentSidePadding, top + 40, tr(STR_REMOTE_LABEL), true); char remoteChapterStr[128]; snprintf(remoteChapterStr, sizeof(remoteChapterStr), " %s", remoteChapter.c_str()); - renderer.drawText(UI_10_FONT_ID, 20, 185, remoteChapterStr); + renderer.drawText(UI_10_FONT_ID, screen.x + metrics.contentSidePadding, top + 65, remoteChapterStr); char remotePageStr[64]; snprintf(remotePageStr, sizeof(remotePageStr), tr(STR_PAGE_OVERALL_FORMAT), remotePosition.pageNumber + 1, remoteProgress.percentage * 100); - renderer.drawText(UI_10_FONT_ID, 20, 210, remotePageStr); + renderer.drawText(UI_10_FONT_ID, screen.x + metrics.contentSidePadding, top + 90, remotePageStr); if (!remoteProgress.device.empty()) { char deviceStr[64]; snprintf(deviceStr, sizeof(deviceStr), tr(STR_DEVICE_FROM_FORMAT), remoteProgress.device.c_str()); - renderer.drawText(UI_10_FONT_ID, 20, 235, deviceStr); + renderer.drawText(UI_10_FONT_ID, screen.x + metrics.contentSidePadding, top + 115, deviceStr); } // Local progress - chapter and page - renderer.drawText(UI_10_FONT_ID, 20, 270, tr(STR_LOCAL_LABEL), true); + renderer.drawText(UI_10_FONT_ID, screen.x + metrics.contentSidePadding, top + 150, tr(STR_LOCAL_LABEL), true); char localChapterStr[128]; snprintf(localChapterStr, sizeof(localChapterStr), " %s", localChapter.c_str()); - renderer.drawText(UI_10_FONT_ID, 20, 295, localChapterStr); + renderer.drawText(UI_10_FONT_ID, screen.x + metrics.contentSidePadding, top + 175, localChapterStr); char localPageStr[64]; snprintf(localPageStr, sizeof(localPageStr), tr(STR_PAGE_TOTAL_OVERALL_FORMAT), currentPage + 1, totalPagesInSpine, localProgress.percentage * 100); - renderer.drawText(UI_10_FONT_ID, 20, 320, localPageStr); + renderer.drawText(UI_10_FONT_ID, screen.x + metrics.contentSidePadding, top + 200, localPageStr); - const int optionY = 350; + const int optionY = top + 230; const int optionHeight = 30; // Apply option if (selectedOption == 0) { - renderer.fillRect(0, optionY - 2, pageWidth - 1, optionHeight); + renderer.fillRect(screen.x, optionY - 2, screen.width - 1, optionHeight); } - renderer.drawText(UI_10_FONT_ID, 20, optionY, tr(STR_APPLY_REMOTE), selectedOption != 0); + renderer.drawText(UI_10_FONT_ID, screen.x + metrics.contentSidePadding, optionY, tr(STR_APPLY_REMOTE), + selectedOption != 0); // Upload option if (selectedOption == 1) { - renderer.fillRect(0, optionY + optionHeight - 2, pageWidth - 1, optionHeight); + renderer.fillRect(screen.x, optionY + optionHeight - 2, screen.width - 1, optionHeight); } - renderer.drawText(UI_10_FONT_ID, 20, optionY + optionHeight, tr(STR_UPLOAD_LOCAL), selectedOption != 1); + renderer.drawText(UI_10_FONT_ID, screen.x + metrics.contentSidePadding, optionY + optionHeight, + tr(STR_UPLOAD_LOCAL), selectedOption != 1); // Bottom button hints const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN)); @@ -403,8 +413,8 @@ void KOReaderSyncActivity::render(RenderLock&&) { } if (state == NO_REMOTE_PROGRESS) { - renderer.drawCenteredText(UI_10_FONT_ID, 280, tr(STR_NO_REMOTE_MSG), true, EpdFontFamily::BOLD); - renderer.drawCenteredText(UI_10_FONT_ID, 320, tr(STR_UPLOAD_PROMPT)); + UITheme::drawCenteredText(renderer, screen, UI_10_FONT_ID, top, tr(STR_NO_REMOTE_MSG), true, EpdFontFamily::BOLD); + UITheme::drawCenteredText(renderer, screen, UI_10_FONT_ID, top + 40, tr(STR_UPLOAD_PROMPT)); const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_UPLOAD), "", ""); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); @@ -413,7 +423,7 @@ void KOReaderSyncActivity::render(RenderLock&&) { } if (state == UPLOAD_COMPLETE) { - renderer.drawCenteredText(UI_10_FONT_ID, 300, tr(STR_UPLOAD_SUCCESS), true, EpdFontFamily::BOLD); + UITheme::drawCenteredText(renderer, screen, UI_10_FONT_ID, top, tr(STR_UPLOAD_SUCCESS), true, EpdFontFamily::BOLD); const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", ""); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); @@ -422,8 +432,8 @@ void KOReaderSyncActivity::render(RenderLock&&) { } if (state == SYNC_FAILED) { - renderer.drawCenteredText(UI_10_FONT_ID, 280, tr(STR_SYNC_FAILED_MSG), true, EpdFontFamily::BOLD); - renderer.drawCenteredText(UI_10_FONT_ID, 320, statusMessage.c_str()); + UITheme::drawCenteredText(renderer, screen, UI_10_FONT_ID, top, tr(STR_SYNC_FAILED_MSG), true, EpdFontFamily::BOLD); + UITheme::drawCenteredText(renderer, screen, UI_10_FONT_ID, top + 40, statusMessage.c_str()); const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", ""); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); diff --git a/src/activities/reader/KOReaderSyncActivity.h b/src/activities/reader/KOReaderSyncActivity.h index 1f07e4f7ec..7cc824ba2f 100644 --- a/src/activities/reader/KOReaderSyncActivity.h +++ b/src/activities/reader/KOReaderSyncActivity.h @@ -78,6 +78,12 @@ class KOReaderSyncActivity final : public Activity { // Selection in result screen (0=Apply, 1=Upload) int selectedOption = 0; + // Tracks whether this session activated WiFi. Set in onEnter past the credentials + // check; checked in onExit to decide whether to silent-reboot. Can't rely on + // WiFi.getMode() because performUpload() calls esp_wifi_stop() on the way out, + // which makes WiFi.getMode() return WIFI_MODE_NULL. + bool wifiActivated = false; + void onWifiSelectionComplete(bool success); void performSync(); void performUpload(); diff --git a/src/activities/reader/ReaderActivity.cpp b/src/activities/reader/ReaderActivity.cpp index 989e6d2231..bee81a087d 100644 --- a/src/activities/reader/ReaderActivity.cpp +++ b/src/activities/reader/ReaderActivity.cpp @@ -6,12 +6,14 @@ #include "CrossPointSettings.h" #include "Epub.h" #include "EpubReaderActivity.h" +#include "SdCardFontSystem.h" #include "Txt.h" #include "TxtReaderActivity.h" #include "Xtc.h" #include "XtcReaderActivity.h" #include "activities/util/BmpViewerActivity.h" #include "activities/util/FullScreenMessageActivity.h" +#include "activities/util/PxcViewerActivity.h" bool ReaderActivity::isXtcFile(const std::string& path) { return FsHelpers::hasXtcExtension(path); } @@ -22,6 +24,8 @@ bool ReaderActivity::isTxtFile(const std::string& path) { bool ReaderActivity::isBmpFile(const std::string& path) { return FsHelpers::hasBmpExtension(path); } +bool ReaderActivity::isPxcFile(const std::string& path) { return FsHelpers::hasPxcExtension(path); } + std::unique_ptr ReaderActivity::loadEpub(const std::string& path) { if (!Storage.exists(path.c_str())) { LOG_ERR("READER", "File does not exist: %s", path.c_str()); @@ -83,6 +87,10 @@ void ReaderActivity::onGoToBmpViewer(const std::string& path) { activityManager.replaceActivity(std::make_unique(renderer, mappedInput, path)); } +void ReaderActivity::onGoToPxcViewer(const std::string& path) { + activityManager.replaceActivity(std::make_unique(renderer, mappedInput, path)); +} + void ReaderActivity::onGoToXtcReader(std::unique_ptr xtc) { const auto xtcPath = xtc->getPath(); currentBookPath = xtcPath; @@ -103,9 +111,13 @@ void ReaderActivity::onEnter() { return; } + sdFontSystem.ensureLoaded(renderer); + currentBookPath = initialBookPath; if (isBmpFile(initialBookPath)) { onGoToBmpViewer(initialBookPath); + } else if (isPxcFile(initialBookPath)) { + onGoToPxcViewer(initialBookPath); } else if (isXtcFile(initialBookPath)) { auto xtc = loadXtc(initialBookPath); if (!xtc) { diff --git a/src/activities/reader/ReaderActivity.h b/src/activities/reader/ReaderActivity.h index f5c61a393d..e4cf6194b2 100644 --- a/src/activities/reader/ReaderActivity.h +++ b/src/activities/reader/ReaderActivity.h @@ -17,12 +17,14 @@ class ReaderActivity final : public Activity { static bool isXtcFile(const std::string& path); static bool isTxtFile(const std::string& path); static bool isBmpFile(const std::string& path); + static bool isPxcFile(const std::string& path); void goToLibrary(const std::string& fromBookPath = ""); void onGoToEpubReader(std::unique_ptr epub); void onGoToXtcReader(std::unique_ptr xtc); void onGoToTxtReader(std::unique_ptr txt); void onGoToBmpViewer(const std::string& path); + void onGoToPxcViewer(const std::string& path); void onGoBack(); diff --git a/src/activities/reader/ReaderUtils.h b/src/activities/reader/ReaderUtils.h index 1de6174b5a..b483358383 100644 --- a/src/activities/reader/ReaderUtils.h +++ b/src/activities/reader/ReaderUtils.h @@ -57,6 +57,7 @@ inline PageTurnResult detectPageTurn(const MappedInputManager& input) { inline void displayWithRefreshCycle(const GfxRenderer& renderer, int& pagesUntilFullRefresh) { if (pagesUntilFullRefresh <= 1) { renderer.displayBuffer(HalDisplay::HALF_REFRESH); + renderer.cleanupGrayscaleWithFrameBuffer(); pagesUntilFullRefresh = SETTINGS.getRefreshFrequency(); } else { renderer.displayBuffer(); diff --git a/src/activities/reader/TxtReaderActivity.cpp b/src/activities/reader/TxtReaderActivity.cpp index 6d95245d07..c4c8552222 100644 --- a/src/activities/reader/TxtReaderActivity.cpp +++ b/src/activities/reader/TxtReaderActivity.cpp @@ -192,6 +192,17 @@ bool TxtReaderActivity::loadPageAtOffset(size_t offset, std::vector } buffer[chunkSize] = '\0'; + // Prime the SD card font's advance table with this chunk's codepoints. + // Without this, every getTextAdvanceX() call in the wrap loop below triggers + // on-demand glyph loads through the 8-slot overflow ring buffer, which + // thrashes for any text with more than 8 unique chars (i.e. all English), + // floods the heap with short-lived bitmap allocations, and eventually + // corrupts FreeRTOS state. The advance table persists across calls per + // font, so the cost amortizes to ~ASCII-size after the first chunk. + if (renderer.isSdCardFont(cachedFontId)) { + renderer.ensureSdCardFontReady(cachedFontId, reinterpret_cast(buffer), /*styleMask=*/0x01); + } + // Parse lines from buffer size_t pos = 0; @@ -231,7 +242,7 @@ bool TxtReaderActivity::loadPageAtOffset(size_t offset, std::vector break; } - int lineWidth = renderer.getTextWidth(cachedFontId, line.c_str()); + int lineWidth = renderer.getTextAdvanceX(cachedFontId, line.c_str(), EpdFontFamily::REGULAR); if (lineWidth <= viewportWidth) { outLines.push_back(line); @@ -242,7 +253,8 @@ bool TxtReaderActivity::loadPageAtOffset(size_t offset, std::vector // Find break point size_t breakPos = line.length(); - while (breakPos > 0 && renderer.getTextWidth(cachedFontId, line.substr(0, breakPos).c_str()) > viewportWidth) { + while (breakPos > 0 && renderer.getTextAdvanceX(cachedFontId, line.substr(0, breakPos).c_str(), + EpdFontFamily::REGULAR) > viewportWidth) { // Try to break at space size_t spacePos = line.rfind(' ', breakPos - 1); if (spacePos != std::string::npos && spacePos > 0) { @@ -354,12 +366,12 @@ void TxtReaderActivity::renderPage() { // x already set to left margin break; case CrossPointSettings::CENTER_ALIGN: { - int textWidth = renderer.getTextWidth(cachedFontId, line.c_str()); + int textWidth = renderer.getTextAdvanceX(cachedFontId, line.c_str(), EpdFontFamily::REGULAR); x = cachedOrientedMarginLeft + (contentWidth - textWidth) / 2; break; } case CrossPointSettings::RIGHT_ALIGN: { - int textWidth = renderer.getTextWidth(cachedFontId, line.c_str()); + int textWidth = renderer.getTextAdvanceX(cachedFontId, line.c_str(), EpdFontFamily::REGULAR); x = cachedOrientedMarginLeft + contentWidth - textWidth; break; } diff --git a/src/activities/reader/XtcReaderActivity.cpp b/src/activities/reader/XtcReaderActivity.cpp index 897d3f52c2..0c0a4e1331 100644 --- a/src/activities/reader/XtcReaderActivity.cpp +++ b/src/activities/reader/XtcReaderActivity.cpp @@ -32,6 +32,10 @@ void XtcReaderActivity::onEnter() { xtc->setupCacheDir(); + // Pre-flash to white so the factory LUT can drive particles reliably from any prior state. + renderer.clearScreen(); + renderer.displayBuffer(HalDisplay::HALF_REFRESH); + // Load saved progress loadProgress(); @@ -61,6 +65,7 @@ void XtcReaderActivity::loop() { [this](const ActivityResult& result) { if (!result.isCancelled) { currentPage = std::get(result.data).page; + halfRefreshBeforeNextPage = xtc && xtc->getBitDepth() == 2; } }); } @@ -133,6 +138,10 @@ void XtcReaderActivity::render(RenderLock&&) { saveProgress(); } +void XtcReaderActivity::renderStatusBarOverlayCallback(const GfxRenderer&, const void* raw) { + const auto* activity = static_cast(raw); + activity->renderConfiguredStatusBarOverlay(); +} XtcReaderActivity::StatusBarInfo XtcReaderActivity::getStatusBarInfo() const { const int bookPageCount = static_cast(xtc->getPageCount()); const int bookPage = static_cast(currentPage) + 1; @@ -203,22 +212,82 @@ void XtcReaderActivity::renderStatusBarOverlay(const StatusBarOverlayPosition po GUI.drawStatusBar(renderer, progress, pageInfo.currentPage, pageInfo.pageCount, pageInfo.title, paddingBottom); } +void XtcReaderActivity::renderConfiguredStatusBarOverlay() const { + renderStatusBarOverlay(StatusBarOverlayPosition::Top); + renderStatusBarOverlay(StatusBarOverlayPosition::Bottom); +} void XtcReaderActivity::renderPage() { const uint16_t pageWidth = xtc->getPageWidth(); const uint16_t pageHeight = xtc->getPageHeight(); const uint8_t bitDepth = xtc->getBitDepth(); - // Calculate buffer size for one page - // XTG (1-bit): Row-major, ((width+7)/8) * height bytes - // XTH (2-bit): Two bit planes, column-major, ((width * height + 7) / 8) * 2 bytes - size_t pageBufferSize; if (bitDepth == 2) { - pageBufferSize = ((static_cast(pageWidth) * pageHeight + 7) / 8) * 2; - } else { - pageBufferSize = ((pageWidth + 7) / 8) * pageHeight; + // Load each XTCH plane separately to stay within heap limits. + // Combined size (~96KB) exceeds MaxAlloc; each plane (~48KB) fits. + const size_t planeSize = (static_cast(pageWidth) * pageHeight + 7) / 8; + + uint8_t* plane1 = static_cast(malloc(planeSize)); + if (!plane1) { + LOG_ERR("XTR", "Failed to allocate plane1 (%lu bytes)", planeSize); + renderer.clearScreen(); + renderer.drawCenteredText(UI_12_FONT_ID, 300, tr(STR_MEMORY_ERROR), true, EpdFontFamily::BOLD); + renderer.displayBuffer(); + return; + } + if (xtc->loadPageMsb(currentPage, plane1, planeSize) == 0) { + LOG_ERR("XTR", "Failed to load plane1 for page %lu", currentPage); + free(plane1); + renderer.clearScreen(); + renderer.drawCenteredText(UI_12_FONT_ID, 300, tr(STR_PAGE_LOAD_ERROR), true, EpdFontFamily::BOLD); + renderer.displayBuffer(); + return; + } + + uint8_t* plane2 = static_cast(malloc(planeSize)); + if (!plane2) { + LOG_ERR("XTR", "Failed to allocate plane2 (%lu bytes)", planeSize); + free(plane1); + renderer.clearScreen(); + renderer.drawCenteredText(UI_12_FONT_ID, 300, tr(STR_MEMORY_ERROR), true, EpdFontFamily::BOLD); + renderer.displayBuffer(); + return; + } + if (xtc->loadPageLsb(currentPage, plane2, planeSize) == 0) { + LOG_ERR("XTR", "Failed to load plane2 for page %lu", currentPage); + free(plane1); + free(plane2); + renderer.clearScreen(); + renderer.drawCenteredText(UI_12_FONT_ID, 300, tr(STR_PAGE_LOAD_ERROR), true, EpdFontFamily::BOLD); + renderer.displayBuffer(); + return; + } + + if (halfRefreshBeforeNextPage) { + halfRefreshBeforeNextPage = false; + pagesSinceClean = 0; + renderer.clearScreen(); + renderer.displayBuffer(HalDisplay::HALF_REFRESH); + } else if (++pagesSinceClean >= 32) { + // Periodic FULL_REFRESH resets DC balance; every 32 pages. + pagesSinceClean = 0; + renderer.clearScreen(); + renderer.displayBuffer(HalDisplay::FULL_REFRESH); + } + + const auto xtcGrayMode = SETTINGS.xtcRenderQuality == CrossPointSettings::XTC_RENDER_QUALITY_HIGH + ? GfxRenderer::GrayscaleDriveMode::FactoryQuality + : GfxRenderer::GrayscaleDriveMode::FactoryFast; + renderer.displayXtchPlanes(plane1, plane2, pageWidth, pageHeight, + &XtcReaderActivity::renderStatusBarOverlayCallback, this, xtcGrayMode); + free(plane1); + free(plane2); + + LOG_DBG("XTR", "Rendered page %lu/%lu (2-bit factory)", currentPage + 1, xtc->getPageCount()); + return; } - // Allocate page buffer + // 1-bit XTG path + const size_t pageBufferSize = ((pageWidth + 7) / 8) * pageHeight; uint8_t* pageBuffer = static_cast(malloc(pageBufferSize)); if (!pageBuffer) { LOG_ERR("XTR", "Failed to allocate page buffer (%lu bytes)", pageBufferSize); @@ -227,10 +296,7 @@ void XtcReaderActivity::renderPage() { renderer.displayBuffer(); return; } - - // Load page data - size_t bytesRead = xtc->loadPage(currentPage, pageBuffer, pageBufferSize); - if (bytesRead == 0) { + if (xtc->loadPage(currentPage, pageBuffer, pageBufferSize) == 0) { LOG_ERR("XTR", "Failed to load page %lu: bufferSize=%lu bitDepth=%u error=%s", currentPage, pageBufferSize, bitDepth, xtc::errorToString(xtc->getLastError())); free(pageBuffer); @@ -239,141 +305,22 @@ void XtcReaderActivity::renderPage() { renderer.displayBuffer(); return; } - - // Clear screen first - renderer.clearScreen(); - - // Copy page bitmap using GfxRenderer's drawPixel - // XTC/XTCH pages are pre-rendered with status bar included, so render full page - const uint16_t maxSrcY = pageHeight; - - if (bitDepth == 2) { - // XTH 2-bit mode: Two bit planes, column-major order - // - Columns scanned right to left (x = width-1 down to 0) - // - 8 vertical pixels per byte (MSB = topmost pixel in group) - // - First plane: Bit1, Second plane: Bit2 - // - Pixel value = (bit1 << 1) | bit2 - // - Grayscale: 0=White, 1=Dark Grey, 2=Light Grey, 3=Black - - const size_t planeSize = (static_cast(pageWidth) * pageHeight + 7) / 8; - const uint8_t* plane1 = pageBuffer; // Bit1 plane - const uint8_t* plane2 = pageBuffer + planeSize; // Bit2 plane - const size_t colBytes = (pageHeight + 7) / 8; // Bytes per column (100 for 800 height) - - // Lambda to get pixel value at (x, y) - auto getPixelValue = [&](uint16_t x, uint16_t y) -> uint8_t { - const size_t colIndex = pageWidth - 1 - x; - const size_t byteInCol = y / 8; - const size_t bitInByte = 7 - (y % 8); - const size_t byteOffset = colIndex * colBytes + byteInCol; - const uint8_t bit1 = (plane1[byteOffset] >> bitInByte) & 1; - const uint8_t bit2 = (plane2[byteOffset] >> bitInByte) & 1; - return (bit1 << 1) | bit2; - }; - - // Optimized grayscale rendering without storeBwBuffer (saves 48KB peak memory) - // Flow: BW display → LSB/MSB passes → grayscale display → re-render BW for next frame - - // Count pixel distribution for debugging - uint32_t pixelCounts[4] = {0, 0, 0, 0}; - for (uint16_t y = 0; y < pageHeight; y++) { - for (uint16_t x = 0; x < pageWidth; x++) { - pixelCounts[getPixelValue(x, y)]++; - } - } - LOG_DBG("XTR", "Pixel distribution: White=%lu, DarkGrey=%lu, LightGrey=%lu, Black=%lu", pixelCounts[0], - pixelCounts[1], pixelCounts[2], pixelCounts[3]); - - // Pass 1: BW buffer - draw all non-white pixels as black - for (uint16_t y = 0; y < pageHeight; y++) { - for (uint16_t x = 0; x < pageWidth; x++) { - if (getPixelValue(x, y) >= 1) { - renderer.drawPixel(x, y, true); - } - } - } - - ReaderUtils::displayWithRefreshCycle(renderer, pagesUntilFullRefresh); - - // Pass 2: LSB buffer - mark DARK gray only (XTH value 1) - // In LUT: 0 bit = apply gray effect, 1 bit = untouched - renderer.clearScreen(0x00); - for (uint16_t y = 0; y < pageHeight; y++) { - for (uint16_t x = 0; x < pageWidth; x++) { - if (getPixelValue(x, y) == 1) { // Dark grey only - renderer.drawPixel(x, y, false); - } - } - } - renderer.copyGrayscaleLsbBuffers(); - - // Pass 3: MSB buffer - mark LIGHT AND DARK gray (XTH value 1 or 2) - // In LUT: 0 bit = apply gray effect, 1 bit = untouched - renderer.clearScreen(0x00); - for (uint16_t y = 0; y < pageHeight; y++) { - for (uint16_t x = 0; x < pageWidth; x++) { - const uint8_t pv = getPixelValue(x, y); - if (pv == 1 || pv == 2) { // Dark grey or Light grey - renderer.drawPixel(x, y, false); - } - } - } - renderer.copyGrayscaleMsbBuffers(); - - // Display grayscale overlay - renderer.displayGrayBuffer(); - - // Pass 4: Re-render BW to framebuffer (restore for next frame, instead of restoreBwBuffer) - renderer.clearScreen(); - for (uint16_t y = 0; y < pageHeight; y++) { - for (uint16_t x = 0; x < pageWidth; x++) { - if (getPixelValue(x, y) >= 1) { - renderer.drawPixel(x, y, true); - } - } - } - - // Cleanup grayscale buffers with current frame buffer - renderer.cleanupGrayscaleWithFrameBuffer(); - - free(pageBuffer); - - LOG_DBG("XTR", "Rendered page %lu/%lu (2-bit grayscale)", currentPage + 1, xtc->getPageCount()); - return; - } else { - // 1-bit mode: 8 pixels per byte, MSB first - const size_t srcRowBytes = (pageWidth + 7) / 8; // 60 bytes for 480 width - - for (uint16_t srcY = 0; srcY < maxSrcY; srcY++) { - const size_t srcRowStart = srcY * srcRowBytes; - - for (uint16_t srcX = 0; srcX < pageWidth; srcX++) { - // Read source pixel (MSB first, bit 7 = leftmost pixel) - const size_t srcByte = srcRowStart + srcX / 8; - const size_t srcBit = 7 - (srcX % 8); - const bool isBlack = !((pageBuffer[srcByte] >> srcBit) & 1); // XTC: 0 = black, 1 = white - - if (isBlack) { - renderer.drawPixel(srcX, srcY, true); - } - } - } - } - // White pixels are already cleared by clearScreen() - + const bool doFullRefresh = pagesUntilFullRefresh <= 1; + renderer.displayXtcBwPage(pageBuffer, pageWidth, pageHeight, + doFullRefresh ? HalDisplay::HALF_REFRESH : HalDisplay::FAST_REFRESH, + &XtcReaderActivity::renderStatusBarOverlayCallback, this); free(pageBuffer); - - if (SETTINGS.xtcStatusBarMode == CrossPointSettings::XTC_STATUS_BAR_MODE::XTC_STATUS_BAR_TOP) { - renderStatusBarOverlay(StatusBarOverlayPosition::Top); + if (doFullRefresh) { + renderer.cleanupGrayscaleWithFrameBuffer(); + pagesUntilFullRefresh = SETTINGS.getRefreshFrequency(); } else { - renderStatusBarOverlay(StatusBarOverlayPosition::Bottom); + pagesUntilFullRefresh--; } - - ReaderUtils::displayWithRefreshCycle(renderer, pagesUntilFullRefresh); - - LOG_DBG("XTR", "Rendered page %lu/%lu (%u-bit)", currentPage + 1, xtc->getPageCount(), bitDepth); + LOG_DBG("XTR", "Rendered page %lu/%lu (1-bit)", currentPage + 1, xtc->getPageCount()); } +void XtcReaderActivity::onScreenshotRequest() { renderPage(); } + void XtcReaderActivity::saveProgress() const { FsFile f; if (Storage.openFileForWrite("XTR", xtc->getCachePath() + "/progress.bin", f)) { diff --git a/src/activities/reader/XtcReaderActivity.h b/src/activities/reader/XtcReaderActivity.h index f020b0b04a..734d4065e0 100644 --- a/src/activities/reader/XtcReaderActivity.h +++ b/src/activities/reader/XtcReaderActivity.h @@ -19,6 +19,8 @@ class XtcReaderActivity final : public Activity { uint32_t currentPage = 0; int pagesUntilFullRefresh = 0; + uint32_t pagesSinceClean = 0; + bool halfRefreshBeforeNextPage = false; enum class StatusBarOverlayPosition { Bottom, Top }; struct StatusBarInfo { @@ -27,8 +29,10 @@ class XtcReaderActivity final : public Activity { std::string title; }; + static void renderStatusBarOverlayCallback(const GfxRenderer& renderer, const void* raw); void renderPage(); void renderStatusBarOverlay(StatusBarOverlayPosition position) const; + void renderConfiguredStatusBarOverlay() const; StatusBarInfo getStatusBarInfo() const; void saveProgress() const; void loadProgress(); @@ -40,6 +44,7 @@ class XtcReaderActivity final : public Activity { void onExit() override; void loop() override; void render(RenderLock&&) override; + void onScreenshotRequest() override; bool isReaderActivity() const override { return true; } ScreenshotInfo getScreenshotInfo() const override; }; diff --git a/src/activities/settings/FontDownloadActivity.cpp b/src/activities/settings/FontDownloadActivity.cpp index 0acba06226..67f5cdf89d 100644 --- a/src/activities/settings/FontDownloadActivity.cpp +++ b/src/activities/settings/FontDownloadActivity.cpp @@ -9,7 +9,8 @@ #include #include "MappedInputManager.h" -#include "SdCardFontGlobals.h" +#include "SdCardFontSystem.h" +#include "SilentRestart.h" #include "activities/network/WifiSelectionActivity.h" #include "activities/util/ConfirmationActivity.h" #include "components/UITheme.h" @@ -30,10 +31,12 @@ void FontDownloadActivity::onEnter() { void FontDownloadActivity::onExit() { Activity::onExit(); - WiFi.disconnect(false); - delay(100); - WiFi.mode(WIFI_OFF); - delay(100); + + if (WiFi.getMode() != WIFI_MODE_NULL) { + WiFi.disconnect(false); + delay(30); + silentRestart(); + } } void FontDownloadActivity::onWifiSelectionComplete(const bool success) { @@ -172,10 +175,11 @@ bool FontDownloadActivity::fetchAndParseManifest() { // --- Download --- void FontDownloadActivity::downloadAll() { + cancelRequested_ = false; for (size_t i = 0; i < families_.size(); i++) { if (families_[i].installed) continue; downloadFamily(families_[i]); - if (state_ == ERROR) return; + if (state_ == ERROR || cancelRequested_) return; } { @@ -185,10 +189,11 @@ void FontDownloadActivity::downloadAll() { } void FontDownloadActivity::updateAll() { + cancelRequested_ = false; for (size_t i = 0; i < families_.size(); i++) { if (!families_[i].hasUpdate) continue; downloadFamily(families_[i]); - if (state_ == ERROR) return; + if (state_ == ERROR || cancelRequested_) return; } { @@ -264,10 +269,9 @@ void FontDownloadActivity::downloadFamily(ManifestFamily& family) { RenderLock lock(*this); state_ = DOWNLOADING; downloadingFamilyIndex_ = static_cast(&family - families_.data()); - currentFileIndex_ = 0; - currentFileTotal_ = family.files.size(); fileProgress_ = 0; fileTotal_ = 0; + cancelRequested_ = false; } requestUpdateAndWait(); @@ -283,7 +287,6 @@ void FontDownloadActivity::downloadFamily(ManifestFamily& family) { { RenderLock lock(*this); - currentFileIndex_ = i; fileProgress_ = 0; fileTotal_ = file.size; } @@ -294,11 +297,30 @@ void FontDownloadActivity::downloadFamily(ManifestFamily& family) { std::string url = baseUrl_ + file.name; - auto result = HttpDownloader::downloadToFile(url, destPath, [this](size_t downloaded, size_t total) { - fileProgress_ = downloaded; - fileTotal_ = total; - requestUpdate(true); - }); + auto result = HttpDownloader::downloadToFile( + url, destPath, + [this](size_t downloaded, size_t total) { + fileProgress_ = downloaded; + fileTotal_ = total; + mappedInput.update(); + if (mappedInput.isPressed(MappedInputManager::Button::Back) || + mappedInput.wasPressed(MappedInputManager::Button::Back)) { + cancelRequested_ = true; + } + requestUpdate(true); + }, + &cancelRequested_); + + if (result == HttpDownloader::ABORTED) { + fontInstaller_.deleteFamily(family.name.c_str()); + family.installed = false; + family.hasUpdate = false; + { + RenderLock lock(*this); + state_ = FAMILY_LIST; + } + return; + } if (result != HttpDownloader::OK) { LOG_ERR("FONT", "Download failed: %s (%d)", file.name.c_str(), result); @@ -344,6 +366,7 @@ void FontDownloadActivity::downloadFamily(ManifestFamily& family) { errorMessage_ = "Invalid font file: " + file.name; return; } + currentFileIndex_++; } fontInstaller_.refreshRegistry(); @@ -432,12 +455,25 @@ void FontDownloadActivity::loop() { if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { if (!families_.empty()) { if (isDownloadAllRow(selectedIndex_)) { + currentFileIndex_ = 0; + currentFileTotal_ = 0; + for (const auto& f : families_) { + if (!f.installed) currentFileTotal_ += f.files.size(); + } + downloadAll(); } else if (isUpdateAllRow(selectedIndex_)) { + currentFileIndex_ = 0; + currentFileTotal_ = 0; + for (const auto& f : families_) { + if (f.hasUpdate) currentFileTotal_ += f.files.size(); + } updateAll(); } else { auto& family = families_[familyIndexFromList(selectedIndex_)]; if (!family.installed || family.hasUpdate) { + currentFileIndex_ = 0; + currentFileTotal_ = family.files.size(); downloadFamily(family); } else { promptDeleteSelectedFamily(); @@ -571,6 +607,9 @@ void FontDownloadActivity::render(RenderLock&&) { renderer, Rect{metrics.contentSidePadding, barY, pageWidth - metrics.contentSidePadding * 2, metrics.progressBarHeight}, static_cast(progress * 100), 100); + + const auto labels = mappedInput.mapLabels(tr(STR_CANCEL), "", "", ""); + GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); } else if (state_ == COMPLETE) { renderer.drawCenteredText(UI_10_FONT_ID, centerY, tr(STR_FONT_INSTALLED), true, EpdFontFamily::BOLD); const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", ""); diff --git a/src/activities/settings/FontDownloadActivity.h b/src/activities/settings/FontDownloadActivity.h index 7f76e7c6a9..90d488a867 100644 --- a/src/activities/settings/FontDownloadActivity.h +++ b/src/activities/settings/FontDownloadActivity.h @@ -34,7 +34,13 @@ class FontDownloadActivity : public Activity { void onExit() override; void loop() override; void render(RenderLock&&) override; - bool preventAutoSleep() override { return state_ == LOADING_MANIFEST || state_ == DOWNLOADING; } + bool preventAutoSleep() override { + return state_ == LOADING_MANIFEST || state_ == DOWNLOADING || + // This is added because HTTPClient is a synchronous/blocking function, + // and blocks the main loop until the download is complete. + // So `activityManager.preventAutoSleep()` is never called during downloading + state_ == COMPLETE || state_ == ERROR; + } bool skipLoopDelay() override { return true; } private: @@ -79,6 +85,7 @@ class FontDownloadActivity : public Activity { size_t fileTotal_ = 0; int downloadingFamilyIndex_ = 0; std::string errorMessage_; + bool cancelRequested_ = false; void onWifiSelectionComplete(bool success); bool fetchAndParseManifest(); diff --git a/src/activities/settings/FontSelectionActivity.cpp b/src/activities/settings/FontSelectionActivity.cpp index 87b3f0f77b..1e5e568cd3 100644 --- a/src/activities/settings/FontSelectionActivity.cpp +++ b/src/activities/settings/FontSelectionActivity.cpp @@ -60,13 +60,26 @@ void FontSelectionActivity::loop() { return; } - buttonNavigator_.onNextRelease([this] { - selectedIndex_ = ButtonNavigator::nextIndex(selectedIndex_, static_cast(fonts_.size())); + const int listSize = static_cast(fonts_.size()); + const int pageItems = UITheme::getNumberOfItemsPerPage(renderer, true, false, true, false); + + buttonNavigator_.onNextRelease([this, listSize] { + selectedIndex_ = ButtonNavigator::nextIndex(selectedIndex_, listSize); + requestUpdate(); + }); + + buttonNavigator_.onPreviousRelease([this, listSize] { + selectedIndex_ = ButtonNavigator::previousIndex(selectedIndex_, listSize); + requestUpdate(); + }); + + buttonNavigator_.onNextContinuous([this, listSize, pageItems] { + selectedIndex_ = ButtonNavigator::nextPageIndex(selectedIndex_, listSize, pageItems); requestUpdate(); }); - buttonNavigator_.onPreviousRelease([this] { - selectedIndex_ = ButtonNavigator::previousIndex(selectedIndex_, static_cast(fonts_.size())); + buttonNavigator_.onPreviousContinuous([this, listSize, pageItems] { + selectedIndex_ = ButtonNavigator::previousPageIndex(selectedIndex_, listSize, pageItems); requestUpdate(); }); } diff --git a/src/activities/settings/LanguageSelectActivity.cpp b/src/activities/settings/LanguageSelectActivity.cpp index ab5fd02c8b..231cba5216 100644 --- a/src/activities/settings/LanguageSelectActivity.cpp +++ b/src/activities/settings/LanguageSelectActivity.cpp @@ -37,6 +37,8 @@ void LanguageSelectActivity::loop() { return; } + const int pageItems = UITheme::getNumberOfItemsPerPage(renderer, true, false, true, false); + // Handle navigation buttonNavigator.onNextRelease([this] { selectedIndex = ButtonNavigator::nextIndex(static_cast(selectedIndex), totalItems); @@ -47,6 +49,16 @@ void LanguageSelectActivity::loop() { selectedIndex = ButtonNavigator::previousIndex(static_cast(selectedIndex), totalItems); requestUpdate(); }); + + buttonNavigator.onNextContinuous([this, pageItems] { + selectedIndex = ButtonNavigator::nextPageIndex(static_cast(selectedIndex), totalItems, pageItems); + requestUpdate(); + }); + + buttonNavigator.onPreviousContinuous([this, pageItems] { + selectedIndex = ButtonNavigator::previousPageIndex(static_cast(selectedIndex), totalItems, pageItems); + requestUpdate(); + }); } void LanguageSelectActivity::handleSelection() { diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index adf99acde8..afd707c6bf 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -13,7 +13,7 @@ #include "MappedInputManager.h" #include "OpdsServerListActivity.h" #include "OtaUpdateActivity.h" -#include "SdCardFontGlobals.h" +#include "SdCardFontSystem.h" #include "SdFirmwareUpdateActivity.h" #include "SettingsList.h" #include "StatusBarSettingsActivity.h" diff --git a/src/activities/util/BmpViewerActivity.cpp b/src/activities/util/BmpViewerActivity.cpp index 0387bc5544..29d37d98b6 100644 --- a/src/activities/util/BmpViewerActivity.cpp +++ b/src/activities/util/BmpViewerActivity.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -104,18 +105,44 @@ void BmpViewerActivity::onEnter() { const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SET_SLEEP_COVER), (hasPrevious ? "<" : ""), (hasNext ? ">" : "")); - GUI.fillPopupProgress(renderer, popupRect, 50); - - renderer.clearScreen(); - // Assuming drawBitmap defaults to 0,0 crop if omitted, or pass explicitly: drawBitmap(bitmap, x, y, pageWidth, - // pageHeight, 0, 0) - renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, 0, 0); - - // Draw UI hints on the base layer - GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); - // Single pass for non-grayscale images - - renderer.displayBuffer(HalDisplay::FAST_REFRESH); + if (bitmap.hasGreyscale()) { + struct BmpGrayCtx { + Bitmap* bitmap; + int x, y, maxWidth, maxHeight; + MappedInputManager::Labels labels; + }; + BmpGrayCtx grayCtx{&bitmap, x, y, pageWidth, pageHeight, labels}; + renderer.renderGrayscaleSinglePass( + GfxRenderer::GrayscaleDriveMode::FactoryQuality, + [](const GfxRenderer& r, const void* raw) { + const auto* c = static_cast(raw); + r.drawBitmap(*c->bitmap, c->x, c->y, c->maxWidth, c->maxHeight, 0, 0); + GUI.drawButtonHints(const_cast(r), c->labels.btn1, c->labels.btn2, c->labels.btn3, + c->labels.btn4); + }, + &grayCtx, + [](const GfxRenderer& r, const void*) { + constexpr int margin = 15; + const char* msg = tr(STR_LOADING_POPUP); + const int y = static_cast(r.getScreenHeight() * 0.075f); + const int textWidth = r.getTextWidth(UI_12_FONT_ID, msg, EpdFontFamily::BOLD); + const int w = textWidth + margin * 2; + const int h = r.getLineHeight(UI_12_FONT_ID) + margin * 2; + const int x = (r.getScreenWidth() - w) / 2; + r.fillRect(x - 2, y - 2, w + 4, h + 4, true); + r.fillRect(x, y, w, h, false); + r.drawText(UI_12_FONT_ID, x + margin, y + margin - 2, msg, true, EpdFontFamily::BOLD); + }, + nullptr); + renderer.clearScreen(); + renderer.cleanupGrayscaleWithFrameBuffer(); + } else { + GUI.fillPopupProgress(renderer, popupRect, 50); + renderer.clearScreen(); + renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, 0, 0); + GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(HalDisplay::FAST_REFRESH); + } } else { // Handle file parsing error @@ -137,6 +164,74 @@ void BmpViewerActivity::onEnter() { } } +void BmpViewerActivity::renderGrayscaleImage() { + FsFile file; + if (!Storage.openFileForRead("BMP", filePath, file)) return; + + Bitmap bitmap(file, true); + if (bitmap.parseHeaders() != BmpReaderError::Ok || !bitmap.hasGreyscale()) { + file.close(); + return; + } + + const auto pageWidth = renderer.getScreenWidth(); + const auto pageHeight = renderer.getScreenHeight(); + int x, y; + if (bitmap.getWidth() > pageWidth || bitmap.getHeight() > pageHeight) { + float ratio = static_cast(bitmap.getWidth()) / static_cast(bitmap.getHeight()); + const float screenRatio = static_cast(pageWidth) / static_cast(pageHeight); + if (ratio > screenRatio) { + x = 0; + y = std::round((static_cast(pageHeight) - static_cast(pageWidth) / ratio) / 2); + } else { + x = std::round((static_cast(pageWidth) - static_cast(pageHeight) * ratio) / 2); + y = 0; + } + } else { + x = (pageWidth - bitmap.getWidth()) / 2; + y = (pageHeight - bitmap.getHeight()) / 2; + } + + const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SET_SLEEP_COVER), "", ""); + struct BmpGrayCtx { + Bitmap* bitmap; + int x, y, maxWidth, maxHeight; + MappedInputManager::Labels labels; + }; + BmpGrayCtx grayCtx{&bitmap, x, y, pageWidth, pageHeight, labels}; + + renderer.renderGrayscaleSinglePass( + GfxRenderer::GrayscaleDriveMode::FactoryQuality, + [](const GfxRenderer& r, const void* raw) { + const auto* c = static_cast(raw); + r.drawBitmap(*c->bitmap, c->x, c->y, c->maxWidth, c->maxHeight, 0, 0); + GUI.drawButtonHints(const_cast(r), c->labels.btn1, c->labels.btn2, c->labels.btn3, + c->labels.btn4); + }, + &grayCtx, + [](const GfxRenderer& r, const void*) { + constexpr int margin = 15; + const char* msg = tr(STR_LOADING_POPUP); + const int y = static_cast(r.getScreenHeight() * 0.075f); + const int textWidth = r.getTextWidth(UI_12_FONT_ID, msg, EpdFontFamily::BOLD); + const int w = textWidth + margin * 2; + const int h = r.getLineHeight(UI_12_FONT_ID) + margin * 2; + const int x = (r.getScreenWidth() - w) / 2; + r.fillRect(x - 2, y - 2, w + 4, h + 4, true); + r.fillRect(x, y, w, h, false); + r.drawText(UI_12_FONT_ID, x + margin, y + margin - 2, msg, true, EpdFontFamily::BOLD); + }, + nullptr); + + file.close(); +} + +void BmpViewerActivity::onScreenshotRequest() { + renderGrayscaleImage(); + renderer.clearScreen(); + renderer.cleanupGrayscaleWithFrameBuffer(); +} + void BmpViewerActivity::onExit() { Activity::onExit(); renderer.clearScreen(); @@ -214,4 +309,4 @@ void BmpViewerActivity::loop() { } return; } -} \ No newline at end of file +} diff --git a/src/activities/util/BmpViewerActivity.h b/src/activities/util/BmpViewerActivity.h index f805d3756e..7b2316205c 100644 --- a/src/activities/util/BmpViewerActivity.h +++ b/src/activities/util/BmpViewerActivity.h @@ -13,12 +13,14 @@ class BmpViewerActivity final : public Activity { void onEnter() override; void onExit() override; void loop() override; + void onScreenshotRequest() override; private: void loadSiblingImages(); void doSetSleepCover(); + void renderGrayscaleImage(); std::string filePath; std::vector siblingImages; int currentImageIndex = -1; -}; \ No newline at end of file +}; diff --git a/src/activities/util/PowerButtonMenuActivity.cpp b/src/activities/util/PowerButtonMenuActivity.cpp new file mode 100644 index 0000000000..5333ab410b --- /dev/null +++ b/src/activities/util/PowerButtonMenuActivity.cpp @@ -0,0 +1,97 @@ +#include "PowerButtonMenuActivity.h" + +#include +#include +#include +#include + +#include "CrossPointState.h" +#include "MappedInputManager.h" +#include "components/UITheme.h" +#include "fontIds.h" + +bool PowerButtonMenuActivity::isActive() { return s_isActive; } + +void PowerButtonMenuActivity::onEnter() { + Activity::onEnter(); + s_isActive = true; + selectedIndex = 0; + requestUpdate(); +} + +void PowerButtonMenuActivity::onExit() { + Activity::onExit(); + s_isActive = false; +} + +void PowerButtonMenuActivity::loop() { + buttonNavigator.onNext([this] { + selectedIndex = ButtonNavigator::nextIndex(selectedIndex, static_cast(items.size())); + requestUpdate(); + }); + + buttonNavigator.onPrevious([this] { + selectedIndex = ButtonNavigator::previousIndex(selectedIndex, static_cast(items.size())); + requestUpdate(); + }); + + if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { + APP_STATE.pendingMenuAction = static_cast(items[selectedIndex].action); + LOG_DBG("PWRMENU", "Selected action: %d", APP_STATE.pendingMenuAction); + finish(); + return; + } + + if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { + finish(); + return; + } +} + +void PowerButtonMenuActivity::render(RenderLock&&) { + const int screenWidth = renderer.getScreenWidth(); + const int screenHeight = renderer.getScreenHeight(); + + const int itemCount = static_cast(items.size()); + constexpr int innerPadding = 16; + constexpr int itemSpacing = 6; + constexpr int selectionHPadding = 8; + constexpr int selectionVPadding = 4; + + const int titleHeight = renderer.getLineHeight(UI_12_FONT_ID); + const int itemHeight = renderer.getLineHeight(UI_10_FONT_ID); + const int listHeight = itemHeight * itemCount + itemSpacing * (itemCount - 1); + const int contentHeight = titleHeight + 10 + listHeight; + const int dialogHeight = contentHeight + innerPadding * 2; + + int maxTextWidth = renderer.getTextWidth(UI_12_FONT_ID, tr(STR_ACTION_MENU), EpdFontFamily::BOLD); + for (const auto& item : items) { + const int w = renderer.getTextWidth(UI_10_FONT_ID, I18N.get(item.labelId), EpdFontFamily::BOLD); + if (w > maxTextWidth) { + maxTextWidth = w; + } + } + const int dialogWidth = std::min((maxTextWidth + innerPadding * 2) * 12 / 10, screenWidth - 20); + + const int dialogX = (screenWidth - dialogWidth) / 2; + const int dialogY = screenHeight * 2 / 5 - dialogHeight / 2; + + GUI.drawDialogBackground(renderer, Rect{dialogX, dialogY, dialogWidth, dialogHeight}); + + renderer.drawCenteredText(UI_12_FONT_ID, dialogY + innerPadding, tr(STR_ACTION_MENU), true, EpdFontFamily::BOLD); + + int y = dialogY + innerPadding + titleHeight + 10; + for (int i = 0; i < itemCount; i++) { + const int itemY = y + i * (itemHeight + itemSpacing); + const bool selected = (i == selectedIndex); + const char* labelText = I18N.get(items[i].labelId); + const int labelWidth = renderer.getTextWidth(UI_10_FONT_ID, labelText, EpdFontFamily::BOLD); + const int labelX = dialogX + (dialogWidth - labelWidth) / 2; + + Rect itemRect(labelX - selectionHPadding, itemY - selectionVPadding, labelWidth + selectionHPadding * 2, + itemHeight + selectionVPadding * 2); + GUI.drawPopupSelection(renderer, UI_10_FONT_ID, itemRect, labelText, selected); + } + + renderer.displayBuffer(HalDisplay::FAST_REFRESH); +} diff --git a/src/activities/util/PowerButtonMenuActivity.h b/src/activities/util/PowerButtonMenuActivity.h new file mode 100644 index 0000000000..7ededc672c --- /dev/null +++ b/src/activities/util/PowerButtonMenuActivity.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include + +#include "../Activity.h" +#include "CrossPointSettings.h" +#include "util/ButtonNavigator.h" + +class PowerButtonMenuActivity final : public Activity { + public: + enum class MenuAction : uint8_t { SLEEP, REFRESH_SCREEN, SCREENSHOT, NONE = 0xFF }; + + explicit PowerButtonMenuActivity(GfxRenderer& renderer, MappedInputManager& mappedInput) + : Activity("PowerButtonMenu", renderer, mappedInput) {} + + static bool isActive(); + + void onEnter() override; + void onExit() override; + void loop() override; + void render(RenderLock&& lock) override; + + private: + static inline bool s_isActive = false; + + struct MenuItem { + MenuAction action; + StrId labelId; + }; + + const std::vector items = { + {MenuAction::SLEEP, StrId::STR_SLEEP}, + {MenuAction::REFRESH_SCREEN, StrId::STR_FORCE_REFRESH}, + {MenuAction::SCREENSHOT, StrId::STR_SCREENSHOT_BUTTON}, + }; + + int selectedIndex = 0; + ButtonNavigator buttonNavigator; +}; diff --git a/src/activities/util/PxcViewerActivity.cpp b/src/activities/util/PxcViewerActivity.cpp new file mode 100644 index 0000000000..e3ba8cf340 --- /dev/null +++ b/src/activities/util/PxcViewerActivity.cpp @@ -0,0 +1,277 @@ +#include "PxcViewerActivity.h" + +#include +#include +#include +#include +#include + +#include "CrossPointSettings.h" +#include "Epub/converters/DirectPixelWriter.h" +#include "components/UITheme.h" +#include "fontIds.h" + +namespace { +struct PxcCtx { + FsFile* file; + uint32_t dataOffset; + int width, height; + MappedInputManager::Labels labels; +}; + +void pxcRenderCallback(const GfxRenderer& r, const void* raw) { + const auto* c = static_cast(raw); + c->file->seek(c->dataOffset); + + const int bytesPerRow = (c->width + 3) / 4; + uint8_t* rowBuf = static_cast(malloc(bytesPerRow)); + if (!rowBuf) { + LOG_ERR("PXC", "malloc failed for rowBuf (%d bytes, %dx%d)", bytesPerRow, c->width, c->height); + return; + } + + DirectPixelWriter pw; + pw.init(r); + + for (int row = 0; row < c->height; row++) { + if (c->file->read(rowBuf, bytesPerRow) != bytesPerRow) break; + pw.beginRow(row); + for (int col = 0; col < c->width; col++) { + const uint8_t pv = (rowBuf[col >> 2] >> (6 - (col & 3) * 2)) & 0x03; + pw.writePixel(pv); + } + } + free(rowBuf); + + GUI.drawButtonHints(const_cast(r), c->labels.btn1, c->labels.btn2, c->labels.btn3, c->labels.btn4); +} + +void pxcLoadingOverlay(const GfxRenderer& r, const void*) { + constexpr int margin = 15; + const char* msg = tr(STR_LOADING_POPUP); + const int y = static_cast(r.getScreenHeight() * 0.075f); + const int textWidth = r.getTextWidth(UI_12_FONT_ID, msg, EpdFontFamily::BOLD); + const int w = textWidth + margin * 2; + const int h = r.getLineHeight(UI_12_FONT_ID) + margin * 2; + const int x = (r.getScreenWidth() - w) / 2; + r.fillRect(x - 2, y - 2, w + 4, h + 4, true); + r.fillRect(x, y, w, h, false); + r.drawText(UI_12_FONT_ID, x + margin, y + margin - 2, msg, true, EpdFontFamily::BOLD); +} +} // namespace + +PxcViewerActivity::PxcViewerActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::string path) + : Activity("PxcViewer", renderer, mappedInput), filePath(std::move(path)) {} + +void PxcViewerActivity::loadSiblingImages() { + siblingImages.clear(); + currentImageIndex = -1; + + if (filePath.empty()) return; + + std::string dirPath = FsHelpers::extractFolderPath(filePath); + size_t lastSlash = filePath.find_last_of('/'); + std::string fileName = (lastSlash != std::string::npos) ? filePath.substr(lastSlash + 1) : filePath; + + auto dir = Storage.open(dirPath.c_str()); + if (!dir || !dir.isDirectory()) { + if (dir) dir.close(); + return; + } + + char name[500]; + for (auto file = dir.openNextFile(); file; file = dir.openNextFile()) { + if (!file.isDirectory()) { + file.getName(name, sizeof(name)); + if (name[0] != '.') { + std::string fname(name); + if (FsHelpers::hasPxcExtension(fname)) { + siblingImages.push_back(fname); + } + } + } + file.close(); + } + dir.close(); + + FsHelpers::sortFileList(siblingImages); + + for (size_t i = 0; i < siblingImages.size(); ++i) { + if (siblingImages[i] == fileName) { + currentImageIndex = static_cast(i); + break; + } + } +} + +void PxcViewerActivity::renderPxcToFramebuffer(FsFile& file, uint16_t width, uint16_t height, uint32_t dataOffset, + bool hasPrevious, bool hasNext) { + const auto labels = + mappedInput.mapLabels(tr(STR_BACK), tr(STR_SET_SLEEP_COVER), (hasPrevious ? "<" : ""), (hasNext ? ">" : "")); + PxcCtx ctx{&file, dataOffset, width, height, labels}; + renderer.renderGrayscaleSinglePass(GfxRenderer::GrayscaleDriveMode::FactoryQuality, &pxcRenderCallback, &ctx, + &pxcLoadingOverlay, nullptr); +} + +void PxcViewerActivity::onEnter() { + Activity::onEnter(); + + if (siblingImages.empty() && !filePath.empty()) { + loadSiblingImages(); + } + + const int screenWidth = renderer.getScreenWidth(); + const int screenHeight = renderer.getScreenHeight(); + FsFile file; + if (!Storage.openFileForRead("PXC", filePath, file)) { + renderer.clearScreen(); + renderer.drawCenteredText(UI_10_FONT_ID, screenHeight / 2, "Could not open file"); + const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", ""); + GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(HalDisplay::FULL_REFRESH); + return; + } + + uint16_t pxcWidth, pxcHeight; + if (file.read(&pxcWidth, 2) != 2 || file.read(&pxcHeight, 2) != 2) { + LOG_ERR("PXC", "Header read failed: %s", filePath.c_str()); + file.close(); + renderer.clearScreen(); + renderer.drawCenteredText(UI_10_FONT_ID, screenHeight / 2, "Invalid PXC file"); + const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", ""); + GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(HalDisplay::FULL_REFRESH); + return; + } + + if (pxcWidth > screenWidth || pxcHeight > screenHeight) { + LOG_ERR("PXC", "PXC size %dx%d does not match screen %dx%d", pxcWidth, pxcHeight, screenWidth, screenHeight); + file.close(); + renderer.clearScreen(); + renderer.drawCenteredText(UI_10_FONT_ID, screenHeight / 2, "PXC size mismatch"); + const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", ""); + GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(HalDisplay::FULL_REFRESH); + return; + } + + const uint32_t dataOffset = file.position(); + const bool hasPrevious = (siblingImages.size() > 1 && currentImageIndex > 0); + const bool hasNext = (siblingImages.size() > 1 && currentImageIndex != -1 && + currentImageIndex < static_cast(siblingImages.size()) - 1); + renderPxcToFramebuffer(file, pxcWidth, pxcHeight, dataOffset, hasPrevious, hasNext); + + file.close(); + + // Sync BW framebuffer state after factory-gray render so onExit's HALF_REFRESH + // does a correct differential (controller BW state = white, not stale gray planes). + renderer.clearScreen(); + renderer.cleanupGrayscaleWithFrameBuffer(); +} + +void PxcViewerActivity::renderGrayscaleImage() { + FsFile file; + if (!Storage.openFileForRead("PXC", filePath, file)) return; + + uint16_t pxcWidth, pxcHeight; + if (file.read(&pxcWidth, 2) != 2 || file.read(&pxcHeight, 2) != 2) { + file.close(); + return; + } + + const int screenWidth = renderer.getScreenWidth(); + const int screenHeight = renderer.getScreenHeight(); + if (pxcWidth > screenWidth || pxcHeight > screenHeight) { + file.close(); + return; + } + + const uint32_t dataOffset = file.position(); + renderPxcToFramebuffer(file, pxcWidth, pxcHeight, dataOffset, false, false); + + file.close(); +} + +void PxcViewerActivity::onScreenshotRequest() { + renderGrayscaleImage(); + renderer.clearScreen(); + renderer.cleanupGrayscaleWithFrameBuffer(); +} + +void PxcViewerActivity::onExit() { + Activity::onExit(); + renderer.clearScreen(); + renderer.displayBuffer(HalDisplay::HALF_REFRESH); +} + +void PxcViewerActivity::doSetSleepCover() { + GUI.drawPopup(renderer, tr(STR_LOADING_POPUP)); + + bool success = false; + FsFile inFile, outFile; + if (Storage.openFileForRead("PXC", filePath, inFile)) { + if (Storage.openFileForWrite("PXC", "/sleep.pxc", outFile)) { + char buffer[2048]; + int bytesRead; + success = true; + while ((bytesRead = inFile.read(buffer, sizeof(buffer))) > 0) { + if (outFile.write(buffer, bytesRead) != bytesRead) { + success = false; + break; + } + } + outFile.close(); + } + inFile.close(); + } + + if (success) { + SETTINGS.sleepScreen = CrossPointSettings::SLEEP_SCREEN_MODE::CUSTOM; + SETTINGS.saveToFile(); + GUI.drawPopup(renderer, tr(STR_DONE)); + } else { + GUI.drawPopup(renderer, tr(STR_FAILED_LOWER)); + } + + delay(1000); + onEnter(); +} + +void PxcViewerActivity::loop() { + Activity::loop(); + + if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { + activityManager.goToFileBrowser(filePath); + return; + } + + if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { + doSetSleepCover(); + return; + } + + if (mappedInput.wasReleased(MappedInputManager::Button::Left) || + mappedInput.wasReleased(MappedInputManager::Button::Up)) { + if (siblingImages.size() > 1 && currentImageIndex > 0) { + currentImageIndex--; + std::string dirPath = FsHelpers::extractFolderPath(filePath); + if (dirPath.back() != '/') dirPath += "/"; + filePath = dirPath + siblingImages[currentImageIndex]; + onEnter(); + } + return; + } + + if (mappedInput.wasReleased(MappedInputManager::Button::Right) || + mappedInput.wasReleased(MappedInputManager::Button::Down)) { + if (siblingImages.size() > 1 && currentImageIndex != -1 && + currentImageIndex < static_cast(siblingImages.size()) - 1) { + currentImageIndex++; + std::string dirPath = FsHelpers::extractFolderPath(filePath); + if (dirPath.back() != '/') dirPath += "/"; + filePath = dirPath + siblingImages[currentImageIndex]; + onEnter(); + } + return; + } +} diff --git a/src/activities/util/PxcViewerActivity.h b/src/activities/util/PxcViewerActivity.h new file mode 100644 index 0000000000..5df19fc509 --- /dev/null +++ b/src/activities/util/PxcViewerActivity.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include +#include +#include + +#include "../Activity.h" +#include "MappedInputManager.h" + +class PxcViewerActivity final : public Activity { + public: + PxcViewerActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, std::string filePath); + + void onEnter() override; + void onExit() override; + void loop() override; + void onScreenshotRequest() override; + + private: + std::string filePath; + std::vector siblingImages; + int currentImageIndex = -1; + + void loadSiblingImages(); + void doSetSleepCover(); + void renderGrayscaleImage(); + void renderPxcToFramebuffer(FsFile& file, uint16_t width, uint16_t height, uint32_t dataOffset, bool hasPrevious, + bool hasNext); +}; diff --git a/src/components/UITheme.cpp b/src/components/UITheme.cpp index 012ad26b3c..069c422d01 100644 --- a/src/components/UITheme.cpp +++ b/src/components/UITheme.cpp @@ -53,6 +53,7 @@ void UITheme::setTheme(CrossPointSettings::UI_THEME type) { int UITheme::getNumberOfItemsPerPage(const GfxRenderer& renderer, bool hasHeader, bool hasTabBar, bool hasButtonHints, bool hasSubtitle, int extraReservedHeight) { const ThemeMetrics& metrics = UITheme::getInstance().getMetrics(); + auto orientation = renderer.getOrientation(); int reservedHeight = metrics.topPadding; if (hasHeader) { reservedHeight += metrics.headerHeight + metrics.verticalSpacing; @@ -60,7 +61,8 @@ int UITheme::getNumberOfItemsPerPage(const GfxRenderer& renderer, bool hasHeader if (hasTabBar) { reservedHeight += metrics.tabBarHeight; } - if (hasButtonHints) { + if (hasButtonHints && orientation != GfxRenderer::Orientation::LandscapeClockwise && + orientation != GfxRenderer::Orientation::LandscapeCounterClockwise) { reservedHeight += metrics.verticalSpacing + metrics.buttonHintsHeight; } const int availableHeight = renderer.getScreenHeight() - reservedHeight - extraReservedHeight; @@ -68,6 +70,39 @@ int UITheme::getNumberOfItemsPerPage(const GfxRenderer& renderer, bool hasHeader return availableHeight / rowHeight; } +// Screen area excluding the button hints +Rect UITheme::getScreenSafeArea(const GfxRenderer& renderer, bool hasFrontButtonHints, bool hasSideButtonHints) { + auto orientation = renderer.getOrientation(); + const int screenWidth = renderer.getScreenWidth(); + const int screenHeight = renderer.getScreenHeight(); + Rect safeArea = Rect{0, 0, screenWidth, screenHeight}; + switch (orientation) { + case GfxRenderer::Orientation::Portrait: + if (hasFrontButtonHints) { + safeArea.height -= currentMetrics->buttonHintsHeight; + } + break; + case GfxRenderer::Orientation::LandscapeClockwise: + if (hasFrontButtonHints) { + safeArea.x += currentMetrics->buttonHintsHeight; + safeArea.width -= currentMetrics->buttonHintsHeight; + } + break; + case GfxRenderer::Orientation::PortraitInverted: + if (hasFrontButtonHints) { + safeArea.y += currentMetrics->buttonHintsHeight; + safeArea.height -= currentMetrics->buttonHintsHeight; + } + break; + case GfxRenderer::Orientation::LandscapeCounterClockwise: + if (hasFrontButtonHints) { + safeArea.width -= currentMetrics->buttonHintsHeight; + } + break; + } + return safeArea; +} + std::string UITheme::getCoverThumbPath(std::string coverBmpPath, int coverHeight) { size_t pos = coverBmpPath.find("[HEIGHT]", 0); if (pos != std::string::npos) { @@ -76,6 +111,8 @@ std::string UITheme::getCoverThumbPath(std::string coverBmpPath, int coverHeight return coverBmpPath; } +std::vector UITheme::getAllCoverHeights() { return {226, 400}; } + UIIcon UITheme::getFileIcon(const std::string& filename) { if (filename.back() == '/') { return Folder; @@ -86,7 +123,7 @@ UIIcon UITheme::getFileIcon(const std::string& filename) { if (FsHelpers::hasTxtExtension(filename) || FsHelpers::hasMarkdownExtension(filename)) { return Text; } - if (FsHelpers::hasBmpExtension(filename)) { + if (FsHelpers::hasBmpExtension(filename) || FsHelpers::hasPxcExtension(filename)) { return Image; } return File; @@ -111,3 +148,10 @@ int UITheme::getProgressBarHeight() { SETTINGS.statusBarProgressBar != CrossPointSettings::STATUS_BAR_PROGRESS_BAR::HIDE_PROGRESS; return (showProgressBar ? (((SETTINGS.statusBarProgressBarThickness + 1) * 2) + metrics.progressBarMarginTop) : 0); } + +// Centered text implementation that takes the safe area into account +void UITheme::drawCenteredText(const GfxRenderer& renderer, Rect screen, int fontId, int y, const char* text, + bool black, EpdFontFamily::Style style) { + const int x = screen.x + (screen.width - renderer.getTextWidth(fontId, text, style)) / 2; + renderer.drawText(fontId, x, y, text, black, style); +} diff --git a/src/components/UITheme.h b/src/components/UITheme.h index c4c37235c0..360b6904fc 100644 --- a/src/components/UITheme.h +++ b/src/components/UITheme.h @@ -1,7 +1,10 @@ #pragma once +#include + #include #include +#include #include "CrossPointSettings.h" #include "components/themes/BaseTheme.h" @@ -16,11 +19,16 @@ class UITheme { const ThemeMetrics& getMetrics() const { return *currentMetrics; } const BaseTheme& getTheme() const { return *currentTheme; } + Rect getScreenSafeArea(const GfxRenderer& renderer, bool hasFrontButtonHints = false, + bool hasSideButtonHints = false); + static void drawCenteredText(const GfxRenderer& renderer, Rect screen, int fontId, int y, const char* text, + bool black = true, EpdFontFamily::Style style = EpdFontFamily::REGULAR); void reload(); void setTheme(CrossPointSettings::UI_THEME type); static int getNumberOfItemsPerPage(const GfxRenderer& renderer, bool hasHeader, bool hasTabBar, bool hasButtonHints, bool hasSubtitle, int extraReservedHeight = 0); static std::string getCoverThumbPath(std::string coverBmpPath, int coverHeight); + static std::vector getAllCoverHeights(); static UIIcon getFileIcon(const std::string& filename); static int getStatusBarHeight(); static int getProgressBarHeight(); diff --git a/src/components/icons/cog.h b/src/components/icons/cog.h deleted file mode 100644 index 899d81a9fb..0000000000 --- a/src/components/icons/cog.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include - -// size: 32x32 -static const uint8_t CogIcon[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xBE, 0x7D, 0xFF, 0xFF, 0x1C, 0x38, - 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0x82, 0x41, 0xFF, 0xFF, 0x0E, 0x70, 0xFF, 0xF6, 0x3E, 0x7C, 0x6F, 0xE0, 0x7E, - 0x7E, 0x07, 0xF0, 0xFE, 0x7F, 0x0F, 0xF8, 0xFE, 0x7F, 0x1F, 0xF9, 0xFE, 0x7F, 0x9F, 0xF9, 0xF8, 0x1F, 0x9F, 0xF3, - 0xF8, 0x1F, 0xCF, 0xC3, 0xF3, 0xCF, 0xC3, 0xC3, 0xF1, 0x8F, 0xC3, 0xF3, 0xE1, 0x87, 0xCF, 0xF9, 0xC0, 0x03, 0x9F, - 0xF9, 0x0E, 0x70, 0x9F, 0xF8, 0x3F, 0xFC, 0x1F, 0xF0, 0x7F, 0xFE, 0x0F, 0xE0, 0x7F, 0xFE, 0x07, 0xF6, 0x3F, 0xFC, - 0x6F, 0xFF, 0x0F, 0xF0, 0xFF, 0xFF, 0x83, 0xC1, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0x1C, 0x38, 0xFF, 0xFF, 0xBE, - 0x7D, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; diff --git a/src/components/icons/settings.h b/src/components/icons/settings.h deleted file mode 100644 index 3c924be2d2..0000000000 --- a/src/components/icons/settings.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include - -// size: 32x32 -static const uint8_t SettingsIcon[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xE1, 0xFF, 0xFF, 0x03, 0xC0, - 0xFF, 0xFE, 0x30, 0x8C, 0x7F, 0xFE, 0x78, 0x1E, 0x7F, 0xFE, 0x7C, 0x7E, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, - 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0x7C, 0x3E, 0x3F, 0xF0, 0xF0, 0x0F, 0x07, 0xC1, 0xF3, 0xCF, 0x83, 0xC7, - 0xE7, 0xE7, 0xE3, 0xCF, 0xE7, 0xE7, 0xF3, 0xCF, 0xE7, 0xE7, 0xF3, 0xC7, 0xE7, 0xE7, 0xE3, 0xC1, 0xF3, 0xCF, 0x83, - 0xE0, 0xF0, 0x0F, 0x0F, 0xFC, 0x7C, 0x3E, 0x3F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, - 0x7F, 0xFE, 0x7E, 0x3E, 0x7F, 0xFE, 0x78, 0x1E, 0x7F, 0xFE, 0x31, 0x0C, 0x7F, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0x87, - 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; diff --git a/src/components/themes/BaseTheme.cpp b/src/components/themes/BaseTheme.cpp index 7fd4ab9eaf..95acba9d19 100644 --- a/src/components/themes/BaseTheme.cpp +++ b/src/components/themes/BaseTheme.cpp @@ -151,8 +151,6 @@ void BaseTheme::drawButtonHints(GfxRenderer& renderer, const char* btn1, const c // Only draw if the label is non-empty if (labels[i] != nullptr && labels[i][0] != '\0') { const int x = buttonPositions[i]; - renderer.fillRect(x, pageHeight - buttonY, buttonWidth, buttonHeight, false); - renderer.drawRect(x, pageHeight - buttonY, buttonWidth, buttonHeight); const int textWidth = renderer.getTextWidth(UI_10_FONT_ID, labels[i]); const int textX = x + (buttonWidth - 1 - textWidth) / 2; renderer.drawText(UI_10_FONT_ID, textX, pageHeight - buttonY + textYOffset, labels[i]); @@ -169,12 +167,10 @@ void BaseTheme::drawSideButtonHints(const GfxRenderer& renderer, const char* top constexpr int buttonMargin = 4; if (gpio.deviceIsX3()) { - // X3 layout: Up on left side, Down on right side, positioned higher constexpr int x3ButtonY = 155; if (topBtn != nullptr && topBtn[0] != '\0') { const int leftX = buttonMargin; - renderer.drawRect(leftX, x3ButtonY, buttonWidth, buttonHeight); const int textWidth = renderer.getTextWidth(SMALL_FONT_ID, topBtn); const int textHeight = renderer.getTextHeight(SMALL_FONT_ID); const int textX = leftX + (buttonWidth - textHeight) / 2; @@ -184,7 +180,6 @@ void BaseTheme::drawSideButtonHints(const GfxRenderer& renderer, const char* top if (bottomBtn != nullptr && bottomBtn[0] != '\0') { const int rightX = screenWidth - buttonMargin - buttonWidth; - renderer.drawRect(rightX, x3ButtonY, buttonWidth, buttonHeight); const int textWidth = renderer.getTextWidth(SMALL_FONT_ID, bottomBtn); const int textHeight = renderer.getTextHeight(SMALL_FONT_ID); const int textX = rightX + (buttonWidth - textHeight) / 2; @@ -192,28 +187,10 @@ void BaseTheme::drawSideButtonHints(const GfxRenderer& renderer, const char* top renderer.drawTextRotated90CW(SMALL_FONT_ID, textX, textY, bottomBtn); } } else { - // X4 layout: Both buttons stacked on right side constexpr int topButtonY = 345; const char* labels[] = {topBtn, bottomBtn}; const int x = screenWidth - buttonMargin - buttonWidth; - if (topBtn != nullptr && topBtn[0] != '\0') { - renderer.drawLine(x, topButtonY, x + buttonWidth - 1, topButtonY); - renderer.drawLine(x, topButtonY, x, topButtonY + buttonHeight - 1); - renderer.drawLine(x + buttonWidth - 1, topButtonY, x + buttonWidth - 1, topButtonY + buttonHeight - 1); - } - - if ((topBtn != nullptr && topBtn[0] != '\0') || (bottomBtn != nullptr && bottomBtn[0] != '\0')) { - renderer.drawLine(x, topButtonY + buttonHeight, x + buttonWidth - 1, topButtonY + buttonHeight); - } - - if (bottomBtn != nullptr && bottomBtn[0] != '\0') { - renderer.drawLine(x, topButtonY + buttonHeight, x, topButtonY + 2 * buttonHeight - 1); - renderer.drawLine(x + buttonWidth - 1, topButtonY + buttonHeight, x + buttonWidth - 1, - topButtonY + 2 * buttonHeight - 1); - renderer.drawLine(x, topButtonY + 2 * buttonHeight - 1, x + buttonWidth - 1, topButtonY + 2 * buttonHeight - 1); - } - for (int i = 0; i < 2; i++) { if (labels[i] != nullptr && labels[i][0] != '\0') { const int y = topButtonY + i * buttonHeight; @@ -266,7 +243,7 @@ void BaseTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount, // Draw selection int contentWidth = rect.width - 5; if (selectedIndex >= 0) { - renderer.fillRect(0, rect.y + selectedIndex % pageItems * rowHeight - 2, rect.width, rowHeight); + renderer.fillRect(rect.x, rect.y + selectedIndex % pageItems * rowHeight - 2, rect.width, rowHeight); } constexpr int maxValueWidth = 200; constexpr int minValueGap = 10; @@ -415,16 +392,17 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std: const bool hasContinueReading = !recentBooks.empty(); const bool bookSelected = hasContinueReading && selectorIndex == 0; - // --- Top "book" card for the current title (selectorIndex == 0) --- - // When there's no cover image, use fixed size (half screen) - // When there's cover image, adapt width to image aspect ratio, keep height fixed at 400px - const int baseHeight = rect.height; // Fixed height (400px) + LOG_DBG("THEME", "drawRecentBookCover: hasContinue=%d selected=%d coverRendered=%d bufferStored=%d bufferRestored=%d", + hasContinueReading, bookSelected, coverRendered, coverBufferStored, bufferRestored); + + const int baseHeight = rect.height; int bookWidth, bookX; bool hasCoverImage = false; - if (hasContinueReading && !recentBooks[0].coverBmpPath.empty()) { - // Try to get actual image dimensions from BMP header + const bool skipCover = hasContinueReading && recentBooks[0].coverDisabled; + + if (hasContinueReading && !recentBooks[0].coverBmpPath.empty() && !skipCover) { const std::string coverBmpPath = UITheme::getCoverThumbPath(recentBooks[0].coverBmpPath, BaseMetrics::values.homeCoverHeight); @@ -436,189 +414,95 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std: const int imgWidth = bitmap.getWidth(); const int imgHeight = bitmap.getHeight(); - // Calculate width based on aspect ratio, maintaining baseHeight if (imgWidth > 0 && imgHeight > 0) { const float aspectRatio = static_cast(imgWidth) / static_cast(imgHeight); bookWidth = static_cast(baseHeight * aspectRatio); - // Ensure width doesn't exceed reasonable limits (max 90% of screen width) const int maxWidth = static_cast(rect.width * 0.9f); if (bookWidth > maxWidth) { bookWidth = maxWidth; } } else { - bookWidth = rect.width / 2; // Fallback + bookWidth = baseHeight * 2 / 3; } } + file.close(); } } if (!hasCoverImage) { - // No cover: use half screen size - bookWidth = rect.width / 2; + bookWidth = baseHeight * 2 / 3; + if (bufferRestored) { + LOG_DBG("THEME", "drawRecentBookCover: clearing stale buffer (no cover, bufferRestored)"); + renderer.fillRect(rect.x, rect.y, rect.width, rect.height, false); + bufferRestored = false; + coverRendered = false; + coverBufferStored = false; + } } bookX = rect.x + (rect.width - bookWidth) / 2; const int bookY = rect.y; const int bookHeight = baseHeight; - // Bookmark dimensions (used in multiple places) - const int bookmarkWidth = bookWidth / 8; - const int bookmarkHeight = bookHeight / 5; - const int bookmarkX = bookX + bookWidth - bookmarkWidth - 10; - const int bookmarkY = bookY + 5; - - // Draw book card regardless, fill with message based on `hasContinueReading` { - // Draw cover image as background if available (inside the box) - // Only load from SD on first render, then use stored buffer - - if (hasContinueReading && !recentBooks[0].coverBmpPath.empty() && !coverRendered) { + if (hasContinueReading && !recentBooks[0].coverBmpPath.empty() && !coverRendered && !skipCover) { const std::string coverBmpPath = UITheme::getCoverThumbPath(recentBooks[0].coverBmpPath, BaseMetrics::values.homeCoverHeight); - // First time: load cover from SD and render FsFile file; if (Storage.openFileForRead("HOME", coverBmpPath, file)) { Bitmap bitmap(file); if (bitmap.parseHeaders() == BmpReaderError::Ok) { LOG_DBG("THEME", "Rendering bmp"); - // Draw the cover image (bookWidth and bookHeight already match image aspect ratio) - renderer.drawBitmap(bitmap, bookX, bookY, bookWidth, bookHeight); - - // Draw border around the card - renderer.drawRect(bookX, bookY, bookWidth, bookHeight); - - // No bookmark ribbon when cover is shown - it would just cover the art - - // Store the buffer with cover image for fast navigation - coverBufferStored = storeCoverBuffer(); - coverRendered = coverBufferStored; // Only consider it rendered if we successfully stored the buffer - - // First render: if selected, draw selection indicators now - if (bookSelected) { - LOG_DBG("THEME", "Drawing selection"); - renderer.drawRect(bookX + 1, bookY + 1, bookWidth - 2, bookHeight - 2); - renderer.drawRect(bookX + 2, bookY + 2, bookWidth - 4, bookHeight - 4); + if (renderer.drawBitmap(bitmap, bookX, bookY, bookWidth, bookHeight)) { + renderer.drawRect(bookX, bookY, bookWidth, bookHeight); + coverRendered = true; + coverBufferStored = storeCoverBuffer(); + + if (bookSelected) { + LOG_DBG("THEME", "Drawing selection"); + renderer.drawRect(bookX + 1, bookY + 1, bookWidth - 2, bookHeight - 2, true); + renderer.drawRect(bookX + 2, bookY + 2, bookWidth - 4, bookHeight - 4, true); + } + } else { + LOG_DBG("THEME", "drawBitmap failed, falling back to placeholder"); + hasCoverImage = false; + bookWidth = baseHeight * 2 / 3; + bookX = rect.x + (rect.width - bookWidth) / 2; } } + file.close(); } } if (!bufferRestored && !coverRendered) { - // No cover image: draw border or fill, plus bookmark as visual flair if (bookSelected) { renderer.fillRect(bookX, bookY, bookWidth, bookHeight); - } else { - renderer.drawRect(bookX, bookY, bookWidth, bookHeight); - } - - // Draw bookmark ribbon when no cover image (visual decoration) - if (hasContinueReading) { - const int notchDepth = bookmarkHeight / 3; - const int centerX = bookmarkX + bookmarkWidth / 2; - - const int xPoints[5] = { - bookmarkX, // top-left - bookmarkX + bookmarkWidth, // top-right - bookmarkX + bookmarkWidth, // bottom-right - centerX, // center notch point - bookmarkX // bottom-left - }; - const int yPoints[5] = { - bookmarkY, // top-left - bookmarkY, // top-right - bookmarkY + bookmarkHeight, // bottom-right - bookmarkY + bookmarkHeight - notchDepth, // center notch point - bookmarkY + bookmarkHeight // bottom-left - }; - - // Draw bookmark ribbon (inverted if selected) - renderer.fillPolygon(xPoints, yPoints, 5, !bookSelected); } } - // If buffer was restored, draw selection indicators if needed if (bufferRestored && bookSelected && coverRendered) { - // Draw selection border (no bookmark inversion needed since cover has no bookmark) - renderer.drawRect(bookX + 1, bookY + 1, bookWidth - 2, bookHeight - 2); - renderer.drawRect(bookX + 2, bookY + 2, bookWidth - 4, bookHeight - 4); - } else if (!coverRendered && !bufferRestored) { - // Selection border already handled above in the no-cover case + renderer.drawRect(bookX + 1, bookY + 1, bookWidth - 2, bookHeight - 2, true); + renderer.drawRect(bookX + 2, bookY + 2, bookWidth - 4, bookHeight - 4, true); } } if (hasContinueReading) { - const std::string& lastBookTitle = recentBooks[0].title; - const std::string& lastBookAuthor = recentBooks[0].author; - - // Invert text colors based on selection state: - // - With cover: selected = white text on black box, unselected = black text on white box - // - Without cover: selected = white text on black card, unselected = black text on white card + const char* continueText = tr(STR_CONTINUE_READING); + const int continueTextW = renderer.getTextWidth(UI_10_FONT_ID, continueText); - auto lines = renderer.wrappedText(UI_12_FONT_ID, lastBookTitle.c_str(), bookWidth - 40, 3); - - // Book title text - int totalTextHeight = renderer.getLineHeight(UI_12_FONT_ID) * static_cast(lines.size()); - if (!lastBookAuthor.empty()) { - totalTextHeight += renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2; + if (!hasCoverImage) { + BookCoverParams coverParams{recentBooks[0].title, recentBooks[0].author}; + drawClassicalBookCover(renderer, bookX, bookY, bookWidth, bookHeight, coverParams, bookSelected, continueTextW); + renderer.drawRect(bookX, bookY, bookWidth, bookHeight, 3, true); } - // Vertically center the title block within the card - int titleYStart = bookY + (bookHeight - totalTextHeight) / 2; - - const auto truncatedAuthor = lastBookAuthor.empty() - ? std::string{} - : renderer.truncatedText(UI_10_FONT_ID, lastBookAuthor.c_str(), bookWidth - 40); - - // If cover image was rendered, draw box behind title and author - if (coverRendered) { - constexpr int boxPadding = 8; - // Calculate the max text width for the box - int maxTextWidth = 0; - for (const auto& line : lines) { - const int lineWidth = renderer.getTextWidth(UI_12_FONT_ID, line.c_str()); - if (lineWidth > maxTextWidth) { - maxTextWidth = lineWidth; - } - } - if (!truncatedAuthor.empty()) { - const int authorWidth = renderer.getTextWidth(UI_10_FONT_ID, truncatedAuthor.c_str()); - if (authorWidth > maxTextWidth) { - maxTextWidth = authorWidth; - } - } - - const int boxWidth = maxTextWidth + boxPadding * 2; - const int boxHeight = totalTextHeight + boxPadding * 2; - const int boxX = rect.x + (rect.width - boxWidth) / 2; - const int boxY = titleYStart - boxPadding; - - // Draw box (inverted when selected: black box instead of white) - renderer.fillRect(boxX, boxY, boxWidth, boxHeight, bookSelected); - // Draw border around the box (inverted when selected: white border instead of black) - renderer.drawRect(boxX, boxY, boxWidth, boxHeight, !bookSelected); - } - - for (const auto& line : lines) { - renderer.drawCenteredText(UI_12_FONT_ID, titleYStart, line.c_str(), !bookSelected); - titleYStart += renderer.getLineHeight(UI_12_FONT_ID); - } - - if (!truncatedAuthor.empty()) { - titleYStart += renderer.getLineHeight(UI_10_FONT_ID) / 2; - renderer.drawCenteredText(UI_10_FONT_ID, titleYStart, truncatedAuthor.c_str(), !bookSelected); - } - - // "Continue Reading" label at the bottom - const int continueY = bookY + bookHeight - renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2; - if (coverRendered) { - // Draw box behind "Continue Reading" text (inverted when selected: black box instead of white) - const char* continueText = tr(STR_CONTINUE_READING); - const int continueTextWidth = renderer.getTextWidth(UI_10_FONT_ID, continueText); + const int continueY = bookY + bookHeight - renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2 - 2; + if (hasCoverImage) { constexpr int continuePadding = 6; - const int continueBoxWidth = continueTextWidth + continuePadding * 2; + const int continueBoxWidth = continueTextW + continuePadding * 2; const int continueBoxHeight = renderer.getLineHeight(UI_10_FONT_ID) + continuePadding; const int continueBoxX = rect.x + (rect.width - continueBoxWidth) / 2; const int continueBoxY = continueY - continuePadding / 2; @@ -626,14 +510,12 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std: renderer.drawRect(continueBoxX, continueBoxY, continueBoxWidth, continueBoxHeight, !bookSelected); renderer.drawCenteredText(UI_10_FONT_ID, continueY, continueText, !bookSelected); } else { - renderer.drawCenteredText(UI_10_FONT_ID, continueY, tr(STR_CONTINUE_READING), !bookSelected); + renderer.drawCenteredText(UI_10_FONT_ID, continueY, continueText, !bookSelected); } } else { - // No book to continue reading - const int y = - bookY + (bookHeight - renderer.getLineHeight(UI_12_FONT_ID) - renderer.getLineHeight(UI_10_FONT_ID)) / 2; - renderer.drawCenteredText(UI_12_FONT_ID, y, "No open book"); - renderer.drawCenteredText(UI_10_FONT_ID, y + renderer.getLineHeight(UI_12_FONT_ID), "Start reading below"); + renderer.drawRect(bookX, bookY, bookWidth, bookHeight, 3, true); + const int textLineH = renderer.getLineHeight(UI_12_FONT_ID); + renderer.drawCenteredText(UI_12_FONT_ID, bookY + (bookHeight - textLineH) / 2, tr(STR_NO_OPEN_BOOK), true); } } @@ -686,6 +568,24 @@ Rect BaseTheme::drawPopup(const GfxRenderer& renderer, const char* message) cons return Rect{x, y, w, h}; } +void BaseTheme::drawDialogBackground(const GfxRenderer& renderer, Rect rect) const { + constexpr int outline = 2; + renderer.fillRect(rect.x - outline, rect.y - outline, rect.width + outline * 2, rect.height + outline * 2, true); + renderer.fillRect(rect.x, rect.y, rect.width, rect.height, false); +} + +void BaseTheme::drawPopupSelection(const GfxRenderer& renderer, int fontId, Rect rect, const char* text, + bool selected) const { + if (selected) { + renderer.fillRect(rect.x, rect.y, rect.width, rect.height, true); + } + const int textWidth = renderer.getTextWidth(fontId, text); + const int textX = rect.x + (rect.width - textWidth) / 2; + const int textLineHeight = renderer.getLineHeight(fontId); + const int textY = rect.y + (rect.height - textLineHeight) / 2; + renderer.drawText(fontId, textX, textY, text, !selected); +} + void BaseTheme::fillPopupProgress(const GfxRenderer& renderer, const Rect& layout, const int progress) const { constexpr int barHeight = 4; const int barWidth = layout.width - 30; // twice the margin in drawPopup to match text width @@ -888,3 +788,87 @@ void BaseTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const ch renderer.drawText(SMALL_FONT_ID, rect.x + rect.width - secWidth - 1, rect.y, secondaryLabel, !invert); } } + +void BaseTheme::drawClassicalBookCover(GfxRenderer& renderer, int x, int y, int w, int h, const BookCoverParams& params, + bool inverted, int continueTextWidth) const { + renderer.fillRect(x + 1, y + 1, w - 2, h - 2, inverted); + + renderer.drawRect(x + 10, y + 10, 12, 12, !inverted); + renderer.drawRect(x + w - 22, y + 10, 12, 12, !inverted); + renderer.drawRect(x + 10, y + h - 22, 12, 12, !inverted); + renderer.drawRect(x + w - 22, y + h - 22, 12, 12, !inverted); + + const int innerL = x + 21; + const int innerR = x + w - 22; + const int innerT = y + 21; + const int innerB = y + h - 22; + const int innerCX = x + w / 2; + renderer.drawLine(innerL, innerT, innerR, innerT, !inverted); + renderer.drawLine(innerL, innerT, innerL, innerB, !inverted); + renderer.drawLine(innerR, innerT, innerR, innerB, !inverted); + const int textGapHalf = (continueTextWidth / 2) + 8; + renderer.drawLine(innerL, innerB, innerCX - textGapHalf, innerB, !inverted); + renderer.drawLine(innerCX + textGapHalf, innerB, innerR, innerB, !inverted); + + const int t = 2; + const int s = 30; + const int midY = y + h / 2; + + renderer.fillRect(x + 10, y + s, t, midY - y - s, !inverted); + renderer.fillRect(x + 10, y + s, s - 10 + t, t, !inverted); + renderer.fillRect(x + s, y + 10, t, s - 10, !inverted); + renderer.fillRect(x + s, y + 10, w - 2 * s, t, !inverted); + renderer.fillRect(x + w - 12, y + s, t, h - 2 * s, !inverted); + renderer.fillRect(x + w - 10 - (s - 10 + t), y + s, s - 10 + t, t, !inverted); + renderer.fillRect(x + w - 10 - (s - 10 + t), y + 10, t, s - 10, !inverted); + renderer.fillRect(x + w - 10 - (s - 10 + t), y + h - s - t, s - 10 + t, t, !inverted); + renderer.fillRect(x + w - 10 - (s - 10 + t), y + h - s, t, s - 10, !inverted); + renderer.fillRect(x + s, y + h - 12, w - 2 * s, t, !inverted); + renderer.fillRect(x + s, y + h - s, t, s - 10, !inverted); + renderer.fillRect(x + 10, y + h - s - t, s - 10 + t, t, !inverted); + renderer.fillRect(x + 10, midY, t, y + h - s - midY, !inverted); + + const int titleMaxW = w - 130; + auto titleLines = renderer.wrappedText(NOTOSERIF_12_FONT_ID, params.title.c_str(), titleMaxW, 3); + + const int lineH = renderer.getLineHeight(NOTOSERIF_12_FONT_ID); + const int gap = lineH / 2; + + std::vector authorLines; + int authorLineCount = 0; + if (!params.author.empty()) { + authorLines = renderer.wrappedText(NOTOSERIF_12_FONT_ID, params.author.c_str(), titleMaxW, 2); + authorLineCount = static_cast(authorLines.size()); + } + + int totalBlockH = (static_cast(titleLines.size()) + authorLineCount) * lineH + 4 * gap + 1; + + const int center = y + (innerB - innerT) * 45 / 100; + const int blockY = center - totalBlockH / 2; + + renderer.fillRect(x + 42, blockY, w - 84, totalBlockH + 16, false); + renderer.drawRect(x + 42, blockY, w - 84, totalBlockH + 16, 2, true); + renderer.drawRect(x + 50, blockY + 8, w - 100, totalBlockH, 1, true); + + int centerX = x + w / 2; + int textY = blockY + 8 + gap; + + for (const auto& line : titleLines) { + int tw = renderer.getTextWidth(NOTOSERIF_12_FONT_ID, line.c_str(), EpdFontFamily::BOLD); + renderer.drawText(NOTOSERIF_12_FONT_ID, centerX - tw / 2, textY, line.c_str(), true, EpdFontFamily::BOLD); + textY += lineH; + } + + textY += gap; + if (!authorLines.empty()) { + renderer.drawLine(centerX - 40, textY, centerX + 40, textY, true); + textY += 1; + } + textY += gap; + + for (const auto& line : authorLines) { + int aw = renderer.getTextWidth(NOTOSERIF_12_FONT_ID, line.c_str()); + renderer.drawText(NOTOSERIF_12_FONT_ID, centerX - aw / 2, textY, line.c_str(), true); + textY += lineH; + } +} diff --git a/src/components/themes/BaseTheme.h b/src/components/themes/BaseTheme.h index d21821ecb4..8cafbc4fe1 100644 --- a/src/components/themes/BaseTheme.h +++ b/src/components/themes/BaseTheme.h @@ -9,6 +9,11 @@ class GfxRenderer; struct RecentBook; +struct BookCoverParams { + std::string title; + std::string author; +}; + struct Rect { int x; int y; @@ -153,6 +158,9 @@ class BaseTheme { const std::function& buttonLabel, const std::function& rowIcon) const; virtual Rect drawPopup(const GfxRenderer& renderer, const char* message) const; + virtual void drawDialogBackground(const GfxRenderer& renderer, Rect rect) const; + virtual void drawPopupSelection(const GfxRenderer& renderer, int fontId, Rect rect, const char* text, + bool selected) const; virtual void fillPopupProgress(const GfxRenderer& renderer, const Rect& layout, const int progress) const; void drawStatusBar(GfxRenderer& renderer, const float bookProgress, const int currentPage, const int pageCount, std::string title, const int paddingBottom = 0, const int textYOffset = 0) const; @@ -163,6 +171,8 @@ class BaseTheme { const char* secondaryLabel = nullptr, KeyboardKeyType keyType = KeyboardKeyType::Normal, bool inactiveSelection = false) const; virtual bool showsFileIcons() const { return false; } + void drawClassicalBookCover(GfxRenderer& renderer, int x, int y, int w, int h, const BookCoverParams& params, + bool inverted = false, int continueTextWidth = 0) const; // Shared constants and helpers for battery drawing (used by all themes) static constexpr int batteryPercentSpacing = 4; diff --git a/src/components/themes/lyra/Lyra3CoversTheme.cpp b/src/components/themes/lyra/Lyra3CoversTheme.cpp index 68d8b2345f..2e294a4492 100644 --- a/src/components/themes/lyra/Lyra3CoversTheme.cpp +++ b/src/components/themes/lyra/Lyra3CoversTheme.cpp @@ -38,28 +38,34 @@ void Lyra3CoversTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, con if (coverPath.empty()) { hasCover = false; } else { - const std::string coverBmpPath = - UITheme::getCoverThumbPath(coverPath, Lyra3CoversMetrics::values.homeCoverHeight); - - // First time: load cover from SD and render - FsFile file; - if (Storage.openFileForRead("HOME", coverBmpPath, file)) { - Bitmap bitmap(file); - if (bitmap.parseHeaders() == BmpReaderError::Ok) { - float coverHeight = static_cast(bitmap.getHeight()); - float coverWidth = static_cast(bitmap.getWidth()); - float ratio = coverWidth / coverHeight; - const float tileRatio = static_cast(tileWidth - 2 * hPaddingInSelection) / - static_cast(Lyra3CoversMetrics::values.homeCoverHeight); - float cropX = 1.0f - (tileRatio / ratio); - - renderer.drawBitmap(bitmap, tileX + hPaddingInSelection, tileY + hPaddingInSelection, - tileWidth - 2 * hPaddingInSelection, Lyra3CoversMetrics::values.homeCoverHeight, - cropX); - } else { - hasCover = false; + const bool skipCover = recentBooks[i].coverDisabled; + if (skipCover) { + hasCover = false; + } else { + const std::string coverBmpPath = + UITheme::getCoverThumbPath(coverPath, Lyra3CoversMetrics::values.homeCoverHeight); + + FsFile file; + if (Storage.openFileForRead("HOME", coverBmpPath, file)) { + Bitmap bitmap(file); + if (bitmap.parseHeaders() == BmpReaderError::Ok) { + float coverHeight = static_cast(bitmap.getHeight()); + float coverWidth = static_cast(bitmap.getWidth()); + float ratio = coverWidth / coverHeight; + const float tileRatio = static_cast(tileWidth - 2 * hPaddingInSelection) / + static_cast(Lyra3CoversMetrics::values.homeCoverHeight); + float cropX = 1.0f - (tileRatio / ratio); + + if (!renderer.drawBitmap(bitmap, tileX + hPaddingInSelection, tileY + hPaddingInSelection, + tileWidth - 2 * hPaddingInSelection, + Lyra3CoversMetrics::values.homeCoverHeight, cropX)) { + hasCover = false; + } + } else { + hasCover = false; + } + file.close(); } - file.close(); } } // Draw either way diff --git a/src/components/themes/lyra/LyraTheme.cpp b/src/components/themes/lyra/LyraTheme.cpp index 7ee9ad84ae..cad0fc7c12 100644 --- a/src/components/themes/lyra/LyraTheme.cpp +++ b/src/components/themes/lyra/LyraTheme.cpp @@ -233,9 +233,9 @@ void LyraTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount, rect.width - (totalPages > 1 ? (LyraMetrics::values.scrollBarWidth + LyraMetrics::values.scrollBarRightOffset) : 1); if (selectedIndex >= 0) { - renderer.fillRoundedRect(LyraMetrics::values.contentSidePadding, rect.y + selectedIndex % pageItems * rowHeight, - contentWidth - LyraMetrics::values.contentSidePadding * 2, rowHeight, cornerRadius, - Color::LightGray); + renderer.fillRoundedRect( + rect.x + LyraMetrics::values.contentSidePadding, rect.y + selectedIndex % pageItems * rowHeight, + contentWidth - LyraMetrics::values.contentSidePadding * 2, rowHeight, cornerRadius, Color::LightGray); } int textX = rect.x + LyraMetrics::values.contentSidePadding + hPaddingInSelection; @@ -297,7 +297,7 @@ void LyraTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount, if (!valueText.empty()) { if (i == selectedIndex && highlightValue) { renderer.fillRoundedRect( - contentWidth - LyraMetrics::values.contentSidePadding - hPaddingInSelection - valueWidth, itemY, + rect.x + contentWidth - LyraMetrics::values.contentSidePadding - hPaddingInSelection - valueWidth, itemY, valueWidth + hPaddingInSelection, rowHeight, cornerRadius, Color::Black); } @@ -419,7 +419,8 @@ void LyraTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std: std::string coverPath = book.coverBmpPath; bool hasCover = true; int tileX = LyraMetrics::values.contentSidePadding; - if (coverPath.empty()) { + const bool skipCover = book.coverDisabled; + if (coverPath.empty() || skipCover) { hasCover = false; } else { const std::string coverBmpPath = UITheme::getCoverThumbPath(coverPath, LyraMetrics::values.homeCoverHeight); @@ -430,12 +431,16 @@ void LyraTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std: Bitmap bitmap(file); if (bitmap.parseHeaders() == BmpReaderError::Ok) { coverWidth = bitmap.getWidth(); - renderer.drawBitmap(bitmap, tileX + hPaddingInSelection, tileY + hPaddingInSelection, coverWidth, - LyraMetrics::values.homeCoverHeight); + if (!renderer.drawBitmap(bitmap, tileX + hPaddingInSelection, tileY + hPaddingInSelection, coverWidth, + LyraMetrics::values.homeCoverHeight)) { + hasCover = false; + } } else { hasCover = false; } file.close(); + } else { + hasCover = false; } } @@ -451,8 +456,8 @@ void LyraTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std: renderer.drawIcon(CoverIcon, tileX + hPaddingInSelection + 24, tileY + hPaddingInSelection + 24, 32, 32); } + coverRendered = true; coverBufferStored = storeCoverBuffer(); - coverRendered = coverBufferStored; // Only consider it rendered if we successfully stored the buffer } bool bookSelected = (selectorIndex == 0); @@ -559,6 +564,25 @@ Rect LyraTheme::drawPopup(const GfxRenderer& renderer, const char* message) cons return Rect{x, y, w, h}; } +void LyraTheme::drawDialogBackground(const GfxRenderer& renderer, Rect rect) const { + constexpr int outline = 2; + renderer.fillRoundedRect(rect.x - outline, rect.y - outline, rect.width + outline * 2, rect.height + outline * 2, + cornerRadius + outline, Color::Black); + renderer.fillRoundedRect(rect.x, rect.y, rect.width, rect.height, cornerRadius, Color::White); +} + +void LyraTheme::drawPopupSelection(const GfxRenderer& renderer, int fontId, Rect rect, const char* text, + bool selected) const { + const int textH = renderer.getLineHeight(fontId); + const int textW = renderer.getTextWidth(fontId, text); + const int textY = rect.y + (rect.height - textH) / 2; + const int textX = rect.x + (rect.width - textW) / 2; + if (selected) { + renderer.fillRoundedRect(rect.x, rect.y, rect.width, rect.height, cornerRadius, Color::LightGray); + } + renderer.drawText(fontId, textX, textY, text, true); +} + void LyraTheme::fillPopupProgress(const GfxRenderer& renderer, const Rect& layout, const int progress) const { constexpr int barHeight = 4; diff --git a/src/components/themes/lyra/LyraTheme.h b/src/components/themes/lyra/LyraTheme.h index d984019e17..068878b6e4 100644 --- a/src/components/themes/lyra/LyraTheme.h +++ b/src/components/themes/lyra/LyraTheme.h @@ -71,6 +71,9 @@ class LyraTheme : public BaseTheme { std::function storeCoverBuffer) const override; void drawEmptyRecents(const GfxRenderer& renderer, const Rect rect) const; Rect drawPopup(const GfxRenderer& renderer, const char* message) const override; + void drawDialogBackground(const GfxRenderer& renderer, Rect rect) const override; + void drawPopupSelection(const GfxRenderer& renderer, int fontId, Rect rect, const char* text, + bool selected) const override; void fillPopupProgress(const GfxRenderer& renderer, const Rect& layout, const int progress) const override; bool showsFileIcons() const override { return true; } }; diff --git a/src/components/themes/roundedraff/RoundedRaffTheme.cpp b/src/components/themes/roundedraff/RoundedRaffTheme.cpp index 3d5ea90ca2..7ce0650780 100644 --- a/src/components/themes/roundedraff/RoundedRaffTheme.cpp +++ b/src/components/themes/roundedraff/RoundedRaffTheme.cpp @@ -431,3 +431,22 @@ void RoundedRaffTheme::drawButtonHints(GfxRenderer& renderer, const char* btn1, renderer.setOrientation(origOrientation); } + +void RoundedRaffTheme::drawDialogBackground(const GfxRenderer& renderer, Rect rect) const { + constexpr int outline = 2; + renderer.fillRoundedRect(rect.x - outline, rect.y - outline, rect.width + outline * 2, rect.height + outline * 2, + kRowRadius + outline, Color::Black); + renderer.fillRoundedRect(rect.x, rect.y, rect.width, rect.height, kRowRadius, Color::White); +} + +void RoundedRaffTheme::drawPopupSelection(const GfxRenderer& renderer, int fontId, Rect rect, const char* text, + bool selected) const { + const int textH = renderer.getLineHeight(fontId); + const int textW = renderer.getTextWidth(fontId, text); + const int textY = rect.y + (rect.height - textH) / 2; + const int textX = rect.x + (rect.width - textW) / 2; + if (selected) { + renderer.fillRoundedRect(rect.x, rect.y, rect.width, rect.height, 6, Color::Black); + } + renderer.drawText(fontId, textX, textY, text, !selected); +} diff --git a/src/components/themes/roundedraff/RoundedRaffTheme.h b/src/components/themes/roundedraff/RoundedRaffTheme.h index b73a5b5555..f64a41490e 100644 --- a/src/components/themes/roundedraff/RoundedRaffTheme.h +++ b/src/components/themes/roundedraff/RoundedRaffTheme.h @@ -71,5 +71,8 @@ class RoundedRaffTheme : public BaseTheme { const std::function& rowDimmed = nullptr) const override; void drawButtonHints(GfxRenderer& renderer, const char* btn1, const char* btn2, const char* btn3, const char* btn4) const override; + void drawDialogBackground(const GfxRenderer& renderer, Rect rect) const override; + void drawPopupSelection(const GfxRenderer& renderer, int fontId, Rect rect, const char* text, + bool selected) const override; bool homeMenuShowsContinueReading() const { return true; } }; diff --git a/src/images/CrossLarge.h b/src/images/CrossLarge.h new file mode 100644 index 0000000000..86574c27e5 --- /dev/null +++ b/src/images/CrossLarge.h @@ -0,0 +1,112 @@ +#pragma once +#include + +const unsigned char CrossLarge[] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xf8, 0xfe, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xf1, 0xf0, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfb, 0x99, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1f, 0x0f, 0x87, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7e, 0x1e, 0x07, + 0x03, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7c, 0x1e, 0x07, 0x03, 0xc3, 0xf7, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x1e, 0x07, 0x03, 0xc7, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x30, 0x00, 0x00, 0x3e, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xef, 0xc1, 0xe0, 0xf0, 0x70, 0x3c, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc7, 0xc1, 0xe0, 0x60, 0x30, 0x38, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc1, 0xe0, + 0xf0, 0x30, 0x3c, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xa0, 0x80, 0x00, 0x00, + 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x36, 0x18, 0x00, 0x00, 0x01, 0xe1, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0x1c, 0x0e, 0x07, 0x03, 0x01, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0xf8, 0x1c, 0x0e, 0x07, 0x03, 0x01, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0x3e, 0x1e, 0x0d, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x63, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xc1, 0xe0, 0xf0, 0x70, + 0x00, 0x1e, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xc3, 0xc1, 0xe0, 0xf0, 0x30, 0x38, 0x1e, 0x1f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xc1, 0xe0, 0xf0, 0x70, 0x38, 0x1e, 0x1f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xe3, 0xf0, 0x90, 0x00, 0x00, 0x01, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0x7c, 0x3e, 0x1f, 0x0f, 0x02, 0x80, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7c, + 0x1c, 0x1e, 0x07, 0x03, 0x81, 0x80, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7c, 0x1c, 0x1e, 0x03, + 0x03, 0x81, 0x80, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0x3e, 0x1e, 0x01, 0x04, 0x80, 0x00, + 0x3f, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xe3, 0x30, 0x00, 0x80, 0x00, 0x00, 0x1f, 0xff, 0xff, + 0xff, 0xc1, 0xff, 0xff, 0xff, 0xdf, 0xc3, 0xe1, 0xe0, 0x00, 0x70, 0x38, 0x14, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0xff, + 0xff, 0xff, 0xcf, 0xc3, 0xc1, 0xe0, 0x00, 0x70, 0x38, 0x1c, 0x0f, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xff, 0xcf, + 0xc3, 0xe1, 0xe0, 0x00, 0x70, 0x38, 0x1c, 0x0f, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xef, 0xf3, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xfc, 0x7c, 0x3e, 0x00, 0x01, 0x07, 0x83, + 0x40, 0xf1, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xf8, 0x7c, 0x3e, 0x00, 0x01, 0x03, 0x81, 0xc0, 0xe0, 0xff, + 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xf8, 0x7c, 0x3e, 0x00, 0x01, 0x07, 0x81, 0xc0, 0xe1, 0xff, 0xff, 0xff, 0x80, + 0x03, 0xff, 0xff, 0xfc, 0xfe, 0x3e, 0x00, 0x01, 0x86, 0x82, 0x41, 0x31, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xcf, 0xc7, 0xe0, + 0x00, 0x00, 0x78, 0x38, 0x1c, 0x0f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0xcf, 0xc7, 0xe0, 0x00, 0x00, 0x70, + 0x38, 0x1c, 0x0f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xcf, 0xc7, 0xe0, 0x00, 0x00, 0x78, 0x38, 0x1c, 0x0f, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xcc, 0x40, 0x00, 0x1f, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x0f, 0xff, 0xfe, 0xfe, 0x00, 0x00, 0x03, 0x87, 0x83, 0xc1, 0xf1, 0xff, 0xff, 0xff, 0x80, 0x00, 0x07, + 0xff, 0xfc, 0x7c, 0x00, 0x00, 0x03, 0x07, 0x81, 0xc0, 0xe1, 0xff, 0xff, 0xff, 0x80, 0x00, 0x03, 0xff, 0xfc, 0x7c, + 0x00, 0x00, 0x07, 0x07, 0x83, 0xc0, 0xf1, 0xff, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x0f, + 0x87, 0xc3, 0x41, 0xfb, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x18, 0xc8, 0x64, 0x02, + 0x1f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xdf, 0xc0, 0x00, 0x00, 0x30, 0x78, 0x38, 0x1c, 0x1f, 0xff, 0xff, + 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xcf, 0xc0, 0x00, 0x00, 0x70, 0x70, 0x38, 0x1c, 0x1f, 0xff, 0xff, 0xff, 0xf0, 0x00, + 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x00, 0xf0, 0x78, 0x3c, 0x1e, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, + 0xc0, 0x00, 0x01, 0x9d, 0xcc, 0xc6, 0x23, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x07, 0xff, 0x80, 0x00, 0x03, + 0x0f, 0x87, 0x83, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x07, 0x0f, 0x07, 0x83, + 0xc1, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x0f, 0x0f, 0x87, 0x83, 0xc1, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x1f, 0x9f, 0x8f, 0xc3, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x31, 0xf8, 0xf8, 0x7c, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x61, 0xf0, 0x78, 0x38, 0x1f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf1, 0xf0, 0x78, 0x38, 0x1f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf1, 0xf8, 0xf8, + 0x7c, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xce, 0xc6, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3f, 0x0f, 0x87, 0xc3, 0xf3, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1f, 0x0f, 0x87, 0x83, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x00, 0x00, 0x00, 0x0f, 0x3f, 0x0f, 0x87, 0xc3, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, + 0x1f, 0xff, 0x9f, 0xcf, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x3f, 0xfb, 0xf8, + 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x73, 0xf1, 0xf0, 0xf8, 0x7e, 0x7f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0xf7, 0xf1, 0xf0, 0xf8, 0x7e, 0x7f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x01, 0xff, 0xff, 0xf9, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, + 0x07, 0xff, 0xff, 0x9f, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0x3f, + 0x9f, 0xcf, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x9f, 0xcf, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, + 0x00, 0x3f, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xf8, + 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xf0, 0x00, 0x3f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xc0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, + 0x00, 0x07, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, + 0xc0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xf0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0x00, 0x01, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x03, 0xff, + 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x0f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x03, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x7f, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xfc, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x01, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; diff --git a/src/main.cpp b/src/main.cpp index a273534c0a..b0081d1e7c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,6 +26,7 @@ #include "activities/Activity.h" #include "activities/ActivityManager.h" #include "activities/settings/SdFirmwareUpdateActivity.h" +#include "activities/util/PowerButtonMenuActivity.h" #include "components/UITheme.h" #include "fontIds.h" #include "util/ButtonNavigator.h" @@ -131,6 +132,29 @@ EpdFontFamily ui12FontFamily(&ui12RegularFont, &ui12BoldFont); unsigned long t1 = 0; unsigned long t2 = 0; +// Definitions for SilentRestart.h. RTC_NOINIT survives ESP.restart() but not power loss. +RTC_NOINIT_ATTR uint32_t silentRebootMagic; +RTC_NOINIT_ATTR uint32_t silentRebootTarget; +constexpr uint32_t SILENT_REBOOT_MAGIC = 0xC1EAB007; +constexpr uint32_t SILENT_REBOOT_TARGET_HOME = 0; +constexpr uint32_t SILENT_REBOOT_TARGET_READER = 1; + +void silentRestart() { + silentRebootTarget = SILENT_REBOOT_TARGET_HOME; + silentRebootMagic = SILENT_REBOOT_MAGIC; + LOG_DBG("MAIN", "Silent restart (target=home)"); + delay(50); + ESP.restart(); +} + +void silentRestartToReader() { + silentRebootTarget = SILENT_REBOOT_TARGET_READER; + silentRebootMagic = SILENT_REBOOT_MAGIC; + LOG_DBG("MAIN", "Silent restart (target=reader)"); + delay(50); + ESP.restart(); +} + // Verify power button press duration on wake-up from deep sleep // Pre-condition: isWakeupByPowerButton() == true void verifyPowerButtonDuration() { @@ -162,8 +186,8 @@ void verifyPowerButtonDuration() { do { delay(10); gpio.update(); - } while (gpio.isPressed(HalGPIO::BTN_POWER) && gpio.getHeldTime() < calibratedPressDuration); - abort = gpio.getHeldTime() < calibratedPressDuration; + } while (gpio.isPressed(HalGPIO::BTN_POWER) && gpio.getPowerButtonHeldTime() < calibratedPressDuration); + abort = gpio.getPowerButtonHeldTime() < calibratedPressDuration; } else { abort = true; } @@ -197,8 +221,6 @@ void enterDeepSleep() { powerManager.startDeepSleep(gpio); } -void ensureSdFontLoaded() { sdFontSystem.ensureLoaded(renderer); } - void setupDisplayAndFonts() { display.begin(); renderer.begin(); @@ -240,6 +262,15 @@ void setup() { t1 = millis(); HalSystem::begin(); + + // Read-and-clear so a panic later in setup() doesn't loop into silent reboot. + // Bound the target range too — RTC_NOINIT memory is uninitialized on cold boot. + const bool isSilentReboot = (silentRebootMagic == SILENT_REBOOT_MAGIC); + const uint32_t snapshotTarget = + (isSilentReboot && silentRebootTarget <= SILENT_REBOOT_TARGET_READER) ? silentRebootTarget : 0; + silentRebootMagic = 0; + silentRebootTarget = 0; + gpio.begin(); powerManager.begin(); halTiltSensor.begin(); @@ -317,7 +348,11 @@ void setup() { setupDisplayAndFonts(); - activityManager.goToBoot(); + // First paint after silent reboot is HALF_REFRESH (SDK forces it after begin()'s + // panel reset); subsequent paints FAST. + if (!isSilentReboot) { + activityManager.goToBoot(); + } APP_STATE.loadFromFile(); RECENT_BOOKS.loadFromFile(); @@ -329,6 +364,13 @@ void setup() { } else if (HalSystem::isRebootFromPanic()) { // If we rebooted from a panic, go to crash report screen to show the panic info activityManager.goToCrashReport(); + } else if (isSilentReboot && snapshotTarget == SILENT_REBOOT_TARGET_READER && !APP_STATE.openEpubPath.empty()) { + activityManager.goToReader(APP_STATE.openEpubPath); + } else if (isSilentReboot) { + // target == home (or reader with no open book): land on home — don't fall + // through to the sleep-wake "resume reader" logic, which fires on stale + // openEpubPath + lastSleepFromReader from a prior session. + activityManager.goHome(); } else if (APP_STATE.openEpubPath.empty() || !APP_STATE.lastSleepFromReader || mappedInputManager.isPressed(MappedInputManager::Button::Back) || APP_STATE.readerActivityLoadCount > 0) { // Boot to home screen if no book is open, last sleep was not from reader, back button is held, or reader activity @@ -396,7 +438,18 @@ void loop() { screenshotButtonsReleased = false; { RenderLock lock; - ScreenshotUtil::takeScreenshot(renderer); + if (renderer.getDisplayState() == GfxRenderer::DisplayState::FactoryLut) { + // Display shows a grayscale image held only as physical particle positions. + // frameBuffer has been reset to white — do NOT use the BW screenshot path. + // Only arm the hook when an activity exists to call onScreenshotRequest(). + Activity* activity = activityManager.getCurrentActivity(); + if (activity) { + ScreenshotUtil::prepareFactoryLutScreenshot(renderer); + activity->onScreenshotRequest(); + } + } else { + ScreenshotUtil::takeScreenshot(renderer); + } } } return; @@ -420,7 +473,7 @@ void loop() { return; } - if (gpio.isPressed(HalGPIO::BTN_POWER) && gpio.getHeldTime() > SETTINGS.getPowerButtonDuration()) { + if (gpio.isPressed(HalGPIO::BTN_POWER) && gpio.getPowerButtonHeldTime() > SETTINGS.getPowerButtonDuration()) { // If the screenshot combination is potentially being pressed, don't sleep if (gpio.isPressed(HalGPIO::BTN_DOWN)) { return; @@ -438,6 +491,40 @@ void loop() { renderer.displayBuffer(HalDisplay::HALF_REFRESH); } + // Dispatch pending action selected from power button action menu. + if (APP_STATE.pendingMenuAction != static_cast(PowerButtonMenuActivity::MenuAction::NONE)) { + const auto action = static_cast(APP_STATE.pendingMenuAction); + APP_STATE.pendingMenuAction = static_cast(PowerButtonMenuActivity::MenuAction::NONE); + switch (action) { + case PowerButtonMenuActivity::MenuAction::SLEEP: + LOG_DBG("MAIN", "Power button menu: sleep"); + enterDeepSleep(); + return; + case PowerButtonMenuActivity::MenuAction::REFRESH_SCREEN: + LOG_DBG("MAIN", "Power button menu: refresh screen"); + { + RenderLock lock; + renderer.displayBuffer(HalDisplay::HALF_REFRESH); + } + break; + case PowerButtonMenuActivity::MenuAction::SCREENSHOT: + LOG_DBG("MAIN", "Power button menu: screenshot"); + { + RenderLock lock; + ScreenshotUtil::takeScreenshot(renderer); + } + break; + default: + break; + } + } + + // Show power button action menu on short press when set to MENU mode. + if (SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::MENU && + mappedInputManager.wasReleased(MappedInputManager::Button::Power) && !PowerButtonMenuActivity::isActive()) { + activityManager.pushActivity(std::make_unique(renderer, mappedInputManager)); + } + // Refresh the battery icon when USB is plugged or unplugged. // Placed after sleep guards so we never queue a render that won't be processed. if (gpio.wasUsbStateChanged()) { diff --git a/src/network/CrossPointWebServer.cpp b/src/network/CrossPointWebServer.cpp index 60e4e9e21a..aeaad11e1d 100644 --- a/src/network/CrossPointWebServer.cpp +++ b/src/network/CrossPointWebServer.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -13,7 +14,6 @@ #include "CrossPointSettings.h" #include "FontInstaller.h" #include "OpdsServerStore.h" -#include "SdCardFontGlobals.h" #include "SdCardFontSystem.h" #include "SettingsList.h" #include "WebDAVHandler.h" @@ -375,6 +375,7 @@ void CrossPointWebServer::handleStatus() const { doc["rssi"] = apMode ? 0 : WiFi.RSSI(); doc["freeHeap"] = ESP.getFreeHeap(); doc["uptime"] = millis() / 1000; + doc["device"] = gpio.deviceIsX3() ? "X3" : "X4"; String json; serializeJson(doc, json); diff --git a/src/network/HttpDownloader.cpp b/src/network/HttpDownloader.cpp index b881c859c7..bd26a5ac17 100644 --- a/src/network/HttpDownloader.cpp +++ b/src/network/HttpDownloader.cpp @@ -16,13 +16,17 @@ namespace { class FileWriteStream final : public Stream { public: - FileWriteStream(FsFile& file, size_t total, HttpDownloader::ProgressCallback progress) - : file_(file), total_(total), progress_(std::move(progress)) {} + FileWriteStream(FsFile& file, size_t total, HttpDownloader::ProgressCallback progress, bool* cancelFlag) + : file_(file), total_(total), progress_(std::move(progress)), cancelFlag_(cancelFlag) {} size_t write(uint8_t byte) override { return write(&byte, 1); } size_t write(const uint8_t* buffer, size_t size) override { // Write-through stream for HTTPClient::writeToStream with progress tracking. + if (cancelFlag_ && *cancelFlag_) { + writeOk_ = false; + return 0; + } const size_t written = file_.write(buffer, size); if (written != size) { writeOk_ = false; @@ -48,6 +52,7 @@ class FileWriteStream final : public Stream { size_t downloaded_ = 0; bool writeOk_ = true; HttpDownloader::ProgressCallback progress_; + bool* cancelFlag_; }; } // namespace @@ -101,8 +106,8 @@ bool HttpDownloader::fetchUrl(const std::string& url, std::string& outContent, c } HttpDownloader::DownloadError HttpDownloader::downloadToFile(const std::string& url, const std::string& destPath, - ProgressCallback progress, const std::string& username, - const std::string& password) { + ProgressCallback progress, bool* cancelFlag, + const std::string& username, const std::string& password) { std::unique_ptr client; if (UrlUtils::isHttpsUrl(url)) { auto* secureClient = new NetworkClientSecure(); @@ -155,12 +160,17 @@ HttpDownloader::DownloadError HttpDownloader::downloadToFile(const std::string& } // Let HTTPClient handle chunked decoding and stream body bytes into the file. - FileWriteStream fileStream(file, contentLength, progress); + FileWriteStream fileStream(file, contentLength, progress, cancelFlag); const int writeResult = http.writeToStream(&fileStream); file.close(); http.end(); + if (cancelFlag && *cancelFlag) { + Storage.remove(destPath.c_str()); + return ABORTED; + } + if (writeResult < 0) { LOG_ERR("HTTP", "writeToStream error: %d", writeResult); Storage.remove(destPath.c_str()); diff --git a/src/network/HttpDownloader.h b/src/network/HttpDownloader.h index 216840a579..5913c895be 100644 --- a/src/network/HttpDownloader.h +++ b/src/network/HttpDownloader.h @@ -32,6 +32,6 @@ class HttpDownloader { * Download a file to the SD card with optional credentials. */ static DownloadError downloadToFile(const std::string& url, const std::string& destPath, - ProgressCallback progress = nullptr, const std::string& username = "", - const std::string& password = ""); + ProgressCallback progress = nullptr, bool* cancelFlag = nullptr, + const std::string& username = "", const std::string& password = ""); }; diff --git a/src/network/html/FilesPage.html b/src/network/html/FilesPage.html index 96014ee922..1220f08415 100644 --- a/src/network/html/FilesPage.html +++ b/src/network/html/FilesPage.html @@ -261,6 +261,7 @@ } .folder-link, .file-link { + word-break: break-word; color: var(--accent-color); text-decoration: none; cursor: pointer; @@ -1216,6 +1217,7 @@ font-size: 14px; } .card { + line-break: anywhere; padding: 12px; margin: 10px 0; } @@ -1537,7 +1539,7 @@

📤 Upload file

⚫ True-Grayscale - 📏 Max 480×800px + 📏 Max 480×800px 📦 85% JPEG 🔧 Fix SVG
@@ -1572,6 +1574,19 @@

📤 Upload file

--> + +
+
📱 Target Device
+
+
+ + + +
+
+
↻ Rotation Direction
@@ -2372,13 +2387,13 @@

📂 Move File

const isTiny = (dims.width < 200 && dims.height < 200); // Images that fit screen can only rotate, not split - const fitsScreen = (dims.width <= 480 && dims.height <= 800); - + const fitsScreen = (dims.width <= MAX_WIDTH && dims.height <= MAX_HEIGHT); + // Split capability - no upscaling allowed - // H-Split scales width to 800, so needs width >= 800 - // V-Split scales height to 800, so needs height >= 800 - const canHSplit = dims.width >= 800; - const canVSplit = dims.height >= 800; + // H-Split scales width to MAX_HEIGHT (long edge), so needs width >= MAX_HEIGHT + // V-Split scales height to MAX_HEIGHT, so needs height >= MAX_HEIGHT + const canHSplit = dims.width >= MAX_HEIGHT; + const canVSplit = dims.height >= MAX_HEIGHT; images.push({ path: path, @@ -2616,16 +2631,16 @@

📂 Move File

if (showSplitLines) { let finalWidth; if (state === 1) { - // H-Split: scale width to 800, rotate, then check width - const scaledH = Math.round(img.height * (800 / img.width)); + // H-Split: scale width to MAX_HEIGHT, rotate, then check width + const scaledH = Math.round(img.height * (MAX_HEIGHT / img.width)); finalWidth = scaledH; // After rotation, height becomes width } else { - // V-Split: scale height to 800, then check width - finalWidth = Math.round(img.width * (800 / img.height)); + // V-Split: scale height to MAX_HEIGHT, then check width + finalWidth = Math.round(img.width * (MAX_HEIGHT / img.height)); } - if (finalWidth > 480) { - const minOverlapPx = Math.round(480 * (OVERLAP_PERCENT / 100)); - const maxStep = 480 - minOverlapPx; + if (finalWidth > MAX_WIDTH) { + const minOverlapPx = Math.round(MAX_WIDTH * (OVERLAP_PERCENT / 100)); + const maxStep = MAX_WIDTH - minOverlapPx; numParts = Math.ceil((finalWidth - minOverlapPx) / maxStep); if (numParts < 2) numParts = 2; } @@ -2931,11 +2946,20 @@

📂 Move File

const convertOptions = document.getElementById('convertOptions'); fileInput.classList.toggle('has-files', files.length > 0); - // Show/hide convert options based on file selection - if (files.length > 0) { + // Show convert options only when at least one selected file is an EPUB. + const hasEpub = Array.from(files).some(f => f.name.toLowerCase().endsWith('.epub')); + if (files.length > 0 && hasEpub) { convertOptions.style.display = 'block'; } else { - clearImagePicker(); + convertOptions.style.display = 'none'; + // Clear stale checkbox state so the "Optimize & Upload" button doesn't linger + // when the user re-picks a non-EPUB after having ticked Optimize for an EPUB. + const cb = document.getElementById('convertBeforeUpload'); + if (cb && cb.checked) { + cb.checked = false; + toggleConvertOptions(); + } + if (files.length === 0) clearImagePicker(); } if (files.length > 0) { @@ -2944,6 +2968,11 @@

📂 Move File

const convertEnabled = document.getElementById('convertBeforeUpload').checked; if (advancedContent.classList.contains('visible') && files.length === 1 && convertEnabled && files[0].name.toLowerCase().endsWith('.epub')) { showImagePicker(files[0]).catch(err => console.error('Image picker error:', err)); + } else { + // New selection no longer matches single-EPUB-with-advanced-expanded — + // tear down any picker from a previous file so the grid and picker-mode + // layout don't linger. clearImagePicker is idempotent. + clearImagePicker(); } // If multiple files with conversion, inform user about batch mode @@ -2976,14 +3005,24 @@

📂 Move File

// EPUB Image Conversion Functions (from Baseline JPEG Converter) // ============================================================================ +// Device profiles (short edge × long edge in portrait orientation) +const DEVICE_PROFILES = { + X4: { width: 480, height: 800, label: 'X4' }, + X3: { width: 528, height: 792, label: 'X3' }, +}; + // Default conversion settings -const DEFAULT_MAX_WIDTH = 480; -const DEFAULT_MAX_HEIGHT = 800; +const DEFAULT_DEVICE = 'X4'; +const DEFAULT_MAX_WIDTH = DEVICE_PROFILES[DEFAULT_DEVICE].width; +const DEFAULT_MAX_HEIGHT = DEVICE_PROFILES[DEFAULT_DEVICE].height; const DEFAULT_JPEG_QUALITY = 85; const DEFAULT_ENABLE_GRAYSCALE = true; // Note: Overlap is now always centered distribution (min 5%) // Dynamic conversion settings (updated by UI) +let DEVICE_TARGET = 'auto'; // 'auto' | 'X4' | 'X3' +let DETECTED_DEVICE = null; // populated from /api/status +let ACTIVE_DEVICE = DEFAULT_DEVICE; let MAX_WIDTH = DEFAULT_MAX_WIDTH; let MAX_HEIGHT = DEFAULT_MAX_HEIGHT; let JPEG_QUALITY = DEFAULT_JPEG_QUALITY; @@ -3019,12 +3058,55 @@

📂 Move File

if (response.ok) { const data = await response.json(); crosspointVersion = data.version || 'Unknown'; + if (data.device === 'X3' || data.device === 'X4') { + DETECTED_DEVICE = data.device; + applyDeviceTarget(); + } } } catch (e) { console.error('Failed to fetch version:', e); } } +// Resolve DEVICE_TARGET ('auto' | 'X4' | 'X3') to a concrete profile and update UI. +function applyDeviceTarget() { + const resolved = DEVICE_TARGET === 'auto' ? (DETECTED_DEVICE || DEFAULT_DEVICE) : DEVICE_TARGET; + const profile = DEVICE_PROFILES[resolved] || DEVICE_PROFILES[DEFAULT_DEVICE]; + ACTIVE_DEVICE = resolved; + MAX_WIDTH = profile.width; + MAX_HEIGHT = profile.height; + + const summary = document.getElementById('convertSizeSummary'); + if (summary) { + summary.textContent = `📏 Max ${profile.width}×${profile.height}px`; + } + document.querySelectorAll('.device-btn').forEach(btn => { + btn.classList.toggle('active', btn.dataset.value === DEVICE_TARGET); + }); + const autoLabel = document.getElementById('deviceAutoLabel'); + if (autoLabel) { + autoLabel.textContent = DETECTED_DEVICE ? `Auto (${DETECTED_DEVICE})` : 'Auto'; + } + + // Recompute picker classification with new dimensions, then refresh grid. + if (Array.isArray(epubImagesCache) && epubImagesCache.length > 0) { + for (const img of epubImagesCache) { + img.fitsScreen = (img.width <= MAX_WIDTH && img.height <= MAX_HEIGHT); + img.canHSplit = img.width >= MAX_HEIGHT; + img.canVSplit = img.height >= MAX_HEIGHT; + } + const pickerSection = document.getElementById('imagePickerSection'); + if (pickerSection && pickerSection.style.display !== 'none' && typeof renderImageGrid === 'function') { + renderImageGrid(); + } + } +} + +function setDeviceTarget(value) { + DEVICE_TARGET = value; + applyDeviceTarget(); +} + // Batch logging system for multiple files let batchLogEntries = []; let batchStats = { filesProcessed: 0, filesSucceeded: 0, filesFailed: 0, totalImages: 0, totalSplits: 0, totalFixes: 0, totalErrors: 0, totalOriginalSize: 0, totalNewSize: 0 }; @@ -3181,7 +3263,7 @@

📂 Move File

} // Save current file's log to batch entries -function saveToFileBatchLog(fileName, succeeded) { +function saveToFileBatchLog(fileName, succeeded, originalSize = 0, newSize = 0) { if (!isBatchMode) return; const entries = Array.from(logContainer.querySelectorAll('.log-entry')); @@ -3203,6 +3285,10 @@

📂 Move File

batchStats.totalSplits += conversionStats.splits; batchStats.totalFixes += conversionStats.fixes; batchStats.totalErrors += conversionStats.errors; + // Defaults of 0 keep failure-path callers safe — files that never + // produced a converted blob contribute nothing to the totals. + batchStats.totalOriginalSize += originalSize; + batchStats.totalNewSize += newSize; // Clear for next file logContainer.innerHTML = ''; @@ -3235,6 +3321,22 @@

📂 Move File

}); }); + // Aggregate size totals: only emit rows when at least one file was successfully + // converted (totalOriginalSize stays 0 for batches where conversion was off or + // every file fell back to original upload). + const totalSaved = batchStats.totalOriginalSize - batchStats.totalNewSize; + const totalSavedPct = batchStats.totalOriginalSize > 0 + ? ((totalSaved / batchStats.totalOriginalSize) * 100).toFixed(1) + : '0.0'; + const sizeRowsHtml = batchStats.totalOriginalSize > 0 ? ` + Total original${formatBytes(batchStats.totalOriginalSize)} + Total optimised${formatBytes(batchStats.totalNewSize)} + Total saved${ + totalSaved > 0 + ? `${formatBytes(totalSaved)} (${totalSavedPct}%)` + : `+${formatBytes(-totalSaved)}` + }` : ''; + // Add batch summary const batchSummaryHtml = `
@@ -3246,7 +3348,7 @@

📂 Move File

Total images processed${batchStats.totalImages} Total splits${batchStats.totalSplits} Total fixes applied${batchStats.totalFixes} - ${batchStats.totalErrors > 0 ? `Total errors${batchStats.totalErrors}` : ''} + ${batchStats.totalErrors > 0 ? `Total errors${batchStats.totalErrors}` : ''}${sizeRowsHtml} Total time${batchTime.toFixed(1)}s
@@ -4178,8 +4280,6 @@

📂 Move File

async function convertEpubFile(file, progressCallback) { const startTime = Date.now(); const originalSize = file.size; - let totalImageSize = 0; - let totalNewSize = 0; // Initialize logging clearLog(); @@ -4263,9 +4363,6 @@

📂 Move File

const origFormat = path.split('.').pop(); logImage(imgName, meta.origW, meta.origH, origFormat, meta.origSize, meta.finalW, meta.finalH, meta.finalSize, meta.wasSplit, meta.splitCount || 0, parts, meta.imageState || 0); - totalImageSize += meta.origSize; - totalNewSize += meta.finalSize; - if (parts.length === 1 && parts[0].suffix === '') { const newPath = renamed[path] || path.replace(/\.[^.]+$/, newExt); out.file(newPath, parts[0].data, { compression: 'STORE', createFolders: false }); @@ -4314,10 +4411,6 @@

📂 Move File

const r2 = fixSvgWrappedImages(t); if (r2.fixed) { t = r2.c; logFix(`SVG images (${r2.count})`, xhtmlPath.split('/').pop()); } - for (const [o, n] of Object.entries(renamed)) { - t = t.split(o.split('/').pop()).join(n.split('/').pop()); - } - // Use DOMParser for all img modifications: remove width/height and handle split images try { const parser = new DOMParser(); @@ -4333,6 +4426,20 @@

📂 Move File

for (const img of allImgElements) { if (img.hasAttribute('width')) { img.removeAttribute('width'); modified = true; } if (img.hasAttribute('height')) { img.removeAttribute('height'); modified = true; } + + const src = img.getAttribute('src'); + if (src) { + const decodedSrc = decodeHref(src); + const resolvedSrc = resolvePath(xhtmlPath, decodedSrc); + + const match = Object.entries(renamed).find(([oldPath]) => resolvedSrc === oldPath); + + if (match) { + const [oldPath, newPath] = match; + img.setAttribute('src', decodedSrc.replace(oldPath.split('/').pop(), newPath.split('/').pop())); + modified = true; + } + } } // Handle split images with path collision prevention @@ -4506,7 +4613,7 @@

📂 Move File

// Log completion log('Conversion complete!', 'success', 'DONE'); - logSummary(totalImageSize > 0 ? totalImageSize : originalSize, totalNewSize > 0 ? totalNewSize : newSize, timeElapsed); + logSummary(originalSize, newSize, timeElapsed); // Auto-export only if NOT in batch mode (batch mode exports at the end) if (!isBatchMode && exportLogCheckbox && exportLogCheckbox.checked) { @@ -4775,6 +4882,8 @@

📂 Move File

const needsConversion = isEpub && convertEnabled; let conversionSucceeded = false; let conversionFailed = false; // Track if conversion actually failed + let convOriginalSize = 0; // Picked-file size; 0 unless conversion succeeded + let convNewSize = 0; // Generated blob size; 0 unless conversion succeeded const methodText = useWebSocket ? ' [WS]' : ' [HTTP]'; const stageText = needsConversion ? 'Converting & uploading' : 'Uploading'; @@ -4794,7 +4903,8 @@

📂 Move File

// Save file log to batch if in batch mode and this file was converted // Consider it successful only if conversion didn't fail if (useBatchLog && needsConversion) { - saveToFileBatchLog(file.name, !conversionFailed && conversionSucceeded); + const ok = !conversionFailed && conversionSucceeded; + saveToFileBatchLog(file.name, ok, ok ? convOriginalSize : 0, ok ? convNewSize : 0); } currentIndex++; @@ -4805,7 +4915,9 @@

📂 Move File

// Save failed file log to batch if in batch mode if (useBatchLog && needsConversion) { logError(`Upload failed: ${error}`); - saveToFileBatchLog(file.name, false); + // Preserve conversion size totals when the convert step succeeded but + // the upload failed; otherwise nothing was produced and 0/0 is correct. + saveToFileBatchLog(file.name, false, convOriginalSize, convNewSize); } failedFiles.push({ name: file.name, error: error, file: originalFile }); @@ -4850,6 +4962,10 @@

📂 Move File

showLog(); } + // Snapshot before the `file =` reassignment below, which swaps in the + // converted blob and makes file.size point at the optimised size. + const origFileSize = file.size; + try { const convertedBlob = await convertEpubFile(file, (percent) => { // Pass current quality setting to converter @@ -4860,6 +4976,8 @@

📂 Move File

file = new File([convertedBlob], file.name, { type: 'application/epub+zip' }); progressFill.style.backgroundColor = '#27ae60'; // Back to green for upload conversionSucceeded = true; + convOriginalSize = origFileSize; + convNewSize = convertedBlob.size; } catch (convError) { if (operationCancelled) { if (uploadGeneration === myGeneration) restoreAfterCancel(); return; } console.error('Conversion error:', convError); diff --git a/src/util/ScreenshotUtil.cpp b/src/util/ScreenshotUtil.cpp index df8704f7ea..69501683b9 100644 --- a/src/util/ScreenshotUtil.cpp +++ b/src/util/ScreenshotUtil.cpp @@ -67,6 +67,11 @@ void ScreenshotUtil::buildFilename(const ScreenshotInfo& info, char* buf, size_t } } +// Static storage for the pending grayscale filename. Lifetime: set by prepareFactoryLutScreenshot, +// consumed (read) inside grayscaleHookCallback when the hook fires. The buffer is never freed — +// it's a fixed-size static so it persists for the lifetime of the firmware. +static char s_pendingFilename[64]; + void ScreenshotUtil::takeScreenshot(GfxRenderer& renderer) { const uint8_t* fb = renderer.getFrameBuffer(); if (!fb) { @@ -180,3 +185,170 @@ bool ScreenshotUtil::saveFramebufferAsBmp(const char* filename, const uint8_t* f return true; } + +// --------------------------------------------------------------------------- +// Grayscale (factory LUT) screenshot — hook-based two-plane capture +// --------------------------------------------------------------------------- + +void ScreenshotUtil::prepareFactoryLutScreenshot(GfxRenderer& renderer) { + snprintf(s_pendingFilename, sizeof(s_pendingFilename), "/screenshots/screenshot-%lu.bmp", millis()); + renderer.setScreenshotHook(grayscaleHookCallback, s_pendingFilename); +} + +void ScreenshotUtil::grayscaleHookCallback(const uint8_t* lsbPlane, const uint8_t* msbPlane, int physWidth, + int physHeight, void* ctx) { + const char* filename = static_cast(ctx); + if (saveGrayscaleBmp(filename, lsbPlane, msbPlane, physWidth, physHeight)) { + LOG_DBG("SCR", "Grayscale screenshot saved: %s", filename); + } else { + LOG_ERR("SCR", "Failed to save grayscale screenshot"); + } +} + +bool ScreenshotUtil::saveGrayscaleBmp(const char* filename, const uint8_t* lsbPlane, const uint8_t* msbPlane, + int physWidth, int physHeight) { + // Logical output after 90° CCW rotation (same orientation as BW screenshots): + // outWidth = physHeight (BMP columns = physical rows) + // outHeight = physWidth (BMP rows = physical columns) + const int outWidth = physHeight; + const int outHeight = physWidth; + + // Ensure /screenshots directory exists. + if (!Storage.exists("/screenshots")) { + if (!Storage.mkdir("/screenshots")) { + return false; + } + } + + FsFile file; + if (!Storage.openFileForWrite("SCR", filename, file)) { + LOG_ERR("SCR", "Failed to open grayscale screenshot file"); + return false; + } + + // --- BMP file header (14 bytes) + DIB header (40 bytes) --- + // 8-bit palette BMP: pixel data offset = 14 + 40 + 256*4 = 1078 bytes. + const uint32_t rowSizePadded = (static_cast(outWidth) + 3u) & ~3u; + const uint32_t imageSize = rowSizePadded * static_cast(outHeight); + const uint32_t fileSize = 1078u + imageSize; + +#pragma pack(push, 1) + struct Bmp8Header { + // File header + uint16_t bfType; + uint32_t bfSize; + uint16_t bfReserved1; + uint16_t bfReserved2; + uint32_t bfOffBits; + // DIB header (BITMAPINFOHEADER) + uint32_t biSize; + int32_t biWidth; + int32_t biHeight; + uint16_t biPlanes; + uint16_t biBitCount; + uint32_t biCompression; + uint32_t biSizeImage; + int32_t biXPelsPerMeter; + int32_t biYPelsPerMeter; + uint32_t biClrUsed; + uint32_t biClrImportant; + }; +#pragma pack(pop) + + Bmp8Header hdr; + memset(&hdr, 0, sizeof(hdr)); + hdr.bfType = 0x4D42u; + hdr.bfSize = fileSize; + hdr.bfReserved1 = 0u; + hdr.bfReserved2 = 0u; + hdr.bfOffBits = 1078u; + hdr.biSize = 40u; + hdr.biWidth = outWidth; + hdr.biHeight = outHeight; // positive = bottom-up row order + hdr.biPlanes = 1u; + hdr.biBitCount = 8u; + hdr.biCompression = 0u; // BI_RGB (uncompressed) + hdr.biSizeImage = imageSize; + hdr.biXPelsPerMeter = 2835; + hdr.biYPelsPerMeter = 2835; + hdr.biClrUsed = 256u; + hdr.biClrImportant = 0u; + + bool write_error = false; + if (file.write(reinterpret_cast(&hdr), sizeof(hdr)) != sizeof(hdr)) { + write_error = true; + } + + if (!write_error) { + // Palette: 256 entries × 4 bytes = 1024 bytes. + // GRAY2_LSB encoding: index = lsb | (msb << 1) + // 0 → White (0xFF) lsb=0, msb=0 + // 1 → LightGrey lsb=1, msb=0 + // 2 → DarkGrey lsb=0, msb=1 + // 3 → Black (0x00) lsb=1, msb=1 + static constexpr uint8_t kPalette[16] = { + 0xFF, 0xFF, 0xFF, 0x00, // index 0: White + 0xAA, 0xAA, 0xAA, 0x00, // index 1: LightGrey + 0x55, 0x55, 0x55, 0x00, // index 2: DarkGrey + 0x00, 0x00, 0x00, 0x00, // index 3: Black + }; + if (file.write(kPalette, sizeof(kPalette)) != sizeof(kPalette)) { + write_error = true; + } + if (!write_error) { + // Write 252 zero entries to complete the 256-entry palette table. + uint8_t zeros[32] = {}; + uint32_t remaining = 252u * 4u; + while (remaining > 0u && !write_error) { + const uint32_t chunk = (remaining > sizeof(zeros)) ? static_cast(sizeof(zeros)) : remaining; + if (file.write(zeros, chunk) != chunk) write_error = true; + remaining -= chunk; + } + } + } + + if (write_error) { + file.close(); + Storage.remove(filename); + return false; + } + + // --- Pixel data: one byte per pixel (palette index 0–3), bottom-to-top rows --- + // Row buffer: outWidth bytes padded to 4-byte boundary (> 256 bytes; heap-allocated). + uint8_t* rowBuf = static_cast(malloc(rowSizePadded)); + if (!rowBuf) { + LOG_ERR("SCR", "saveGrayscaleBmp: malloc failed for row buffer (%u bytes)", rowSizePadded); + file.close(); + Storage.remove(filename); + return false; + } + + // physWidth pixels per physical row; each byte holds 8 pixels (1-bit planes). + const int bytesPerPhysRow = physWidth / 8; + + for (int outY = 0; outY < outHeight && !write_error; outY++) { + memset(rowBuf, 0, rowSizePadded); + for (int outX = 0; outX < outWidth; outX++) { + // 90° CCW rotation (same transform as BW saveFramebufferAsBmp): + // BMP rows are bottom-to-top, so outY=0 is the bottom of the logical image. + const int srcX = physWidth - 1 - outY; + const int srcY = physHeight - 1 - outX; + const int byteIdx = srcY * bytesPerPhysRow + (srcX / 8); + const int bitPos = 7 - (srcX % 8); + const uint8_t lsb = (lsbPlane[byteIdx] >> bitPos) & 1u; + const uint8_t msb = (msbPlane[byteIdx] >> bitPos) & 1u; + rowBuf[outX] = lsb | static_cast(msb << 1); + } + if (file.write(rowBuf, rowSizePadded) != rowSizePadded) write_error = true; + } + + free(rowBuf); + file.close(); + + if (write_error) { + Storage.remove(filename); + return false; + } + + return true; +} diff --git a/src/util/ScreenshotUtil.h b/src/util/ScreenshotUtil.h index 995d301f93..c819049da4 100644 --- a/src/util/ScreenshotUtil.h +++ b/src/util/ScreenshotUtil.h @@ -10,6 +10,15 @@ class ScreenshotUtil { static void takeScreenshot(GfxRenderer& renderer); static bool saveFramebufferAsBmp(const char* filename, const uint8_t* framebuffer, int width, int height); + // Called when displayState == FactoryLut. Installs a one-shot hook on the renderer; + // the caller must then call currentActivity->onScreenshotRequest() to trigger the re-render + // that fires the hook and captures both grayscale planes. + static void prepareFactoryLutScreenshot(GfxRenderer& renderer); + private: static void buildFilename(const ScreenshotInfo& info, char* buf, size_t bufSize); + static void grayscaleHookCallback(const uint8_t* lsbPlane, const uint8_t* msbPlane, int physWidth, int physHeight, + void* ctx); + static bool saveGrayscaleBmp(const char* filename, const uint8_t* lsbPlane, const uint8_t* msbPlane, int physWidth, + int physHeight); }; diff --git a/test/hyphenation_eval/HyphenationEvaluationTest.cpp b/test/hyphenation_eval/HyphenationEvaluationTest.cpp index a56467a91e..0ac7eabc77 100644 --- a/test/hyphenation_eval/HyphenationEvaluationTest.cpp +++ b/test/hyphenation_eval/HyphenationEvaluationTest.cpp @@ -44,6 +44,8 @@ const std::vector kSupportedLanguages = { {"russian", "test/hyphenation_eval/resources/russian_hyphenation_tests.txt", "ru"}, {"spanish", "test/hyphenation_eval/resources/spanish_hyphenation_tests.txt", "es"}, {"italian", "test/hyphenation_eval/resources/italian_hyphenation_tests.txt", "it"}, + {"polish", "test/hyphenation_eval/resources/polish_hyphenation_tests.txt", "pl"}, + {"swedish", "test/hyphenation_eval/resources/swedish_hyphenation_tests.txt", "sv"}, }; std::vector expectedPositionsFromAnnotatedWord(const std::string& annotated) { @@ -387,4 +389,4 @@ int main(int argc, char* argv[]) { } return 0; -} \ No newline at end of file +} diff --git a/test/hyphenation_eval/resources/polish_hyphenation_tests.txt b/test/hyphenation_eval/resources/polish_hyphenation_tests.txt new file mode 100644 index 0000000000..5bc8738f9c --- /dev/null +++ b/test/hyphenation_eval/resources/polish_hyphenation_tests.txt @@ -0,0 +1,5012 @@ +# Hyphenation Test Data +# Source: Władysław Stanisław Reymont, Chlopi.epub +# Language: pl_PL +# Min prefix: 2 +# Min suffix: 2 +# Total words: 5000 +# Format: word | hyphenated_form | frequency_in_source +# +# Hyphenation points are marked with '=' +# Example: Silbentrennung -> Sil=ben=tren=nung +# + +edytorski|edy=tor=ski|3556 +przypis|przy=pis|3556 +jeszcze|jesz=cze|1046 +wszystko|wszyst=ko|411 +któren|któ=ren|292 +będzie|bę=dzie|285 +ledwie|le=d=wie|267 +wszystkie|wszyst=kie|259 +chałupy|cha=łu=py|252 +ludzie|lu=dzie|245 +cięgiem|cię=giem|240 +dzieci|dzie=ci|239 +dobrze|do=brze|228 +siebie|sie=bie|218 +dopiero|do=pie=ro|212 +Mateusz|Ma=te=usz|210 +całkiem|cał=kiem|200 +Boryna|Bo=ry=na|199 +prawie|pra=wie|195 +wszystkich|wszyst=kich|191 +świecie|świe=cie|183 +dzisiaj|dzi=siaj|164 +choćby|choć=by|161 +roboty|ro=bo=ty|161 +chałupie|cha=łu=pie|158 +drzewa|drze=wa|153 +drugie|dru=gie|151 +słońce|słoń=ce|150 +powiedział|po=wie=dział|149 +wszyscy|wszy=scy|148 +Jagustynka|Ja=gu=styn=ka|146 +poszedł|po=szedł|145 +kobiety|ko=bie=ty|143 +ździebko|ździeb=ko|142 +ksiądz|ksiądz|140 +barzej|ba=rzej|139 +jakieś|ja=kieś|139 +między|mię=dzy|139 +niekiedy|nie=kie=dy|138 +oczami|ocza=mi|137 +chciał|chciał|134 +Jagusia|Ja=gu=sia|134 +ziemię|zie=mię|128 +chociaż|cho=ciaż|123 +więcej|wię=cej|122 +gdzieś|gdzieś|120 +ciężko|cięż=ko|117 +drodze|dro=dze|115 +wszystkim|wszyst=kim|115 +bowiem|bo=wiem|114 +stronę|stro=nę|113 +wielce|wiel=ce|113 +poszła|po=szła|111 +kościoła|ko=ścio=ła|109 +przecież|prze=cież|109 +często|czę=sto|107 +wiater|wia=ter|105 +czasem|cza=sem|103 +prosto|pro=sto|101 +rzucił|rzu=cił|101 +szepnął|szep=nął|101 +głowie|gło=wie|99 +jakoby|ja=ko=by|99 +Grzela|Grze=la|98 +potrza|po=trza|97 +zaczął|za=czął|97 +każden|każ=den|96 +Szymek|Szy=mek|96 +gdziesik|gdzie=sik|94 +gdzieniegdzie|gdzie=nie=gdzie|93 +Jambroży|Jam=bro=ży|93 +ściany|ścia=ny|93 +człowiek|czło=wiek|92 +Prawda|Praw=da|91 +ktosik|kto=sik|90 +prędko|pręd=ko|90 +ciebie|cie=bie|89 +karczmy|karcz=my|89 +Dominikowa|Do=mi=ni=ko=wa|88 +kościele|ko=ście=le|88 +pacierz|pa=cierz|88 +szepnęła|szep=nę=ła|88 +rzekła|rze=kła|87 +właśnie|wła=śnie|87 +dziedzic|dzie=dzic|86 +jednak|jed=nak|86 +prawda|praw=da|85 +drogach|dro=gach|84 +siedział|sie=dział|84 +miejsca|miej=sca|83 +drugich|dru=gich|82 +narodu|na=ro=du|82 +Pietrek|Pie=trek|82 +pilnie|pil=nie|80 +przódzi|przó=dzi|80 +zawołał|za=wo=łał|80 +ziemia|zie=mia|80 +głosem|gło=sem|79 +przeciek|prze=ciek|79 +srodze|sro=dze|79 +krzyknął|krzyk=nął|78 +oczyma|oczy=ma|78 +pewnie|pew=nie|78 +rychło|ry=chło|78 +lepiej|le=piej|77 +piersi|pier=si|77 +żałośnie|ża=ło=śnie|76 +niekaj|nie=kaj|75 +wszędy|wszę=dy|75 +trochę|tro=chę|74 +trzeba|trze=ba|74 +chałupach|cha=łu=pach|73 +pierwszy|pierw=szy|73 +wiedział|wie=dział|73 +gorąco|go=rą=co|72 +swojego|swo=je=go|72 +złości|zło=ści|72 +wskroś|wskroś|71 +karczmie|karcz=mie|69 +którym|któ=rym|69 +prędzej|prę=dzej|69 +płaczem|pła=czem|69 +wczoraj|wczo=raj|69 +dziwnie|dziw=nie|68 +Jagusi|Ja=gu=si|68 +zaczęła|za=czę=ła|68 +niezgorzej|nie=zgo=rzej|67 +swoich|swo=ich|67 +ślepiami|śle=pia=mi|67 +krzykiem|krzy=kiem|66 +musiał|mu=siał|66 +przeciech|prze=ciech|66 +przyszedł|przy=szedł|66 +słońcu|słoń=cu|66 +deszcz|deszcz|65 +oczach|oczach|65 +sielnie|siel=nie|65 +wyszedł|wy=szedł|65 +ziemniaki|ziem=nia=ki|64 +Borynów|Bo=ry=nów|63 +cichości|ci=cho=ści|63 +Dopiero|Do=pie=ro|63 +których|któ=rych|63 +podniósł|pod=niósł|63 +polach|po=lach|63 +słychać|sły=chać|63 +twarzy|twa=rzy|63 +chłopaki|chło=pa=ki|62 +dokoła|do=ko=ła|62 +drzewo|drze=wo|62 +Lipcach|Lip=cach|62 +WolneLektury|Wol=ne=Lek=tu=ry|62 +światła|świa=tła|62 +której|któ=rej|61 +spokojnie|spo=koj=nie|61 +starego|sta=re=go|61 +wesoło|we=so=ło|61 +widział|wi=dział|61 +wszystkiego|wszyst=kie=go|61 +głośno|gło=śno|60 +niekiej|nie=kiej|60 +śmierć|śmierć|60 +chciała|chcia=ła|59 +ciągle|cią=gle|59 +kobiet|ko=biet|59 +leżały|le=ża=ły|59 +bacząc|ba=cząc|58 +cichość|ci=chość|58 +samego|sa=me=go|58 +siedziała|sie=dzia=ła|58 +zawsze|za=wsze|58 +gospodarz|go=spo=darz|57 +nieraz|nie=raz|57 +nikogo|ni=ko=go|57 +sposób|spo=sób|57 +Słońce|Słoń=ce|57 +niecoś|nie=coś|56 +radośnie|ra=do=śnie|56 +strony|stro=ny|56 +trzęsły|trzę=sły|56 +wszyćko|wszyć=ko|56 +zapłać|za=płać|56 +chałupę|cha=łu=pę|55 +chłopy|chło=py|55 +niczego|ni=cze=go|55 +opłotkach|opłot=kach|55 +Pewnie|Pew=nie|55 +szeptał|szep=tał|55 +ciszej|ci=szej|54 +gospodarze|go=spo=da=rze|54 +jednego|jed=ne=go|54 +krzywdy|krzyw=dy|54 +niebie|nie=bie|54 +niejeden|nie=je=den|54 +stawem|sta=wem|54 +czerwone|czer=wo=ne|53 +Dominikowej|Do=mi=ni=ko=wej|53 +drugiej|dru=giej|53 +kobieta|ko=bie=ta|53 +opłotki|opłot=ki|53 +przyjdzie|przyj=dzie|53 +siedzieli|sie=dzie=li|53 +stojał|sto=jał|53 +strach|strach|53 +takiego|ta=kie=go|53 +chłopa|chło=pa|52 +ciężkie|cięż=kie|52 +księdza|księ=dza|52 +miasta|mia=sta|52 +chłopak|chło=pak|51 +długie|dłu=gie|51 +któryś|któ=ryś|51 +ruszył|ru=szył|51 +wieczór|wie=czór|51 +zawżdy|za=wż=dy|51 +śmierci|śmier=ci|51 +chałupą|cha=łu=pą|50 +chwili|chwi=li|50 +dobrodziej|do=bro=dziej|50 +powietrzu|po=wie=trzu|50 +pójdzie|pój=dzie|50 +robota|ro=bo=ta|50 +stronie|stro=nie|50 +trudno|trud=no|50 +trwożnie|trwoż=nie|50 +chodził|cho=dził|49 +Dobrze|Do=brze|49 +zacząć|za=cząć|49 +zaczęli|za=czę=li|49 +chłopów|chło=pów|48 +leciały|le=cia=ły|48 +osobna|osob=na|48 +pieniądze|pie=nią=dze|48 +wzięła|wzię=ła|48 +drugiego|dru=gie=go|47 +jeszczek|jesz=czek|47 +którego|któ=re=go|47 +mruknął|mruk=nął|47 +młynarz|mły=narz|47 +naprzeciw|na=prze=ciw|47 +poszli|po=szli|47 +powietrze|po=wie=trze|47 +swojej|swo=jej|47 +wiadomo|wia=do=mo|47 +wreszcie|wresz=cie|47 +zapytał|za=py=tał|47 +święta|świę=ta|47 +chciało|chcia=ło|46 +każdego|każ=de=go|46 +miejscu|miej=scu|46 +myślał|my=ślał|46 +podnosił|pod=no=sił|46 +powiedziała|po=wie=dzia=ła|46 +stajni|staj=ni|46 +wszedł|wszedł|46 +zarówno|za=rów=no|46 +dojrzał|doj=rzał|45 +dziecko|dziec=ko|45 +jakimś|ja=kimś|45 +Jeszcze|Jesz=cze|45 +każdym|każ=dym|45 +przysiadł|przy=siadł|45 +sadach|sa=dach|45 +siedzi|sie=dzi|45 +wesele|we=se=le|45 +drugimi|dru=gi=mi|44 +Kłębów|Kłę=bów|44 +ludźmi|ludź=mi|44 +pacierze|pa=cie=rze|44 +patrzeć|pa=trzeć|44 +poredzić|po=re=dzić|44 +Płoszka|Płosz=ka|44 +radości|ra=do=ści|44 +wiecie|wie=cie|44 +wszystek|wszy=stek|44 +zrobił|zro=bił|44 +złotych|zło=tych|44 +złością|zło=ścią|44 +śmiechem|śmie=chem|44 +bardziej|bar=dziej|43 +dziwota|dzi=wo=ta|43 +Jambroż|Jam=broż|43 +prawdę|praw=dę|43 +sadzie|sa=dzie|43 +zaczęły|za=czę=ły|43 +światem|świa=tem|43 +chodzi|cho=dzi|42 +cichuśko|ci=chuś=ko|42 +gospodarzy|go=spo=da=rzy|42 +każdemu|każ=de=mu|42 +krzyczał|krzy=czał|42 +leciał|le=ciał|42 +Michał|Mi=chał|42 +myślała|my=śla=ła|42 +mówili|mó=wi=li|42 +przyszła|przy=szła|42 +sprawy|spra=wy|42 +swojemu|swo=je=mu|42 +szukać|szu=kać|42 +słowem|sło=wem|42 +wszędzie|wszę=dzie|42 +świata|świa=ta|42 +światło|świa=tło|42 +drugim|dru=gim|41 +krzyczeć|krzy=czeć|41 +krzyki|krzy=ki|41 +leżała|le=ża=ła|41 +patrzył|pa=trzył|41 +patrząc|pa=trząc|41 +pieniędzy|pie=nię=dzy|41 +próżno|próż=no|41 +sprawa|spra=wa|41 +grosza|gro=sza|40 +Kozłowa|Ko=zło=wa|40 +lubością|lu=bo=ścią|40 +Maciej|Ma=ciej|40 +pięściami|pię=ścia=mi|40 +poleciał|po=le=ciał|40 +przyszło|przy=szło|40 +radością|ra=do=ścią|40 +skoczył|sko=czył|40 +ścianą|ścia=ną|40 +bliżej|bli=żej|39 +Jagusię|Ja=gu=się|39 +jestem|je=stem|39 +kominem|ko=mi=nem|39 +komory|ko=mo=ry|39 +krzyknęła|krzyk=nę=ła|39 +któraś|któ=raś|39 +niemało|nie=ma=ło|39 +powiadał|po=wia=dał|39 +radość|ra=dość|39 +szeroko|sze=ro=ko|39 +słońca|słoń=ca|39 +zawołała|za=wo=ła=ła|39 +śniegi|śnie=gi|39 +Boryny|Bo=ry=ny|38 +daleko|da=le=ko|38 +dworze|dwo=rze|38 +dzieje|dzie=je|38 +dziećmi|dzieć=mi|38 +groźnie|groź=nie|38 +jednej|jed=nej|38 +miejsce|miej=sce|38 +milczeniu|mil=cze=niu|38 +niczym|ni=czym|38 +potrzeba|po=trze=ba|38 +rzeczy|rze=czy|38 +strachu|stra=chu|38 +westchnął|wes=tchnął|38 +Wiecie|Wie=cie|38 +wiedząc|wie=dząc|38 +ziemniaków|ziem=nia=ków|38 +zrobić|zro=bić|38 +chałup|cha=łup|37 +chwila|chwi=la|37 +dobrego|do=bre=go|37 +każdej|każ=dej|37 +musiała|mu=sia=ła|37 +Nastka|Na=st=ka|37 +nowego|no=we=go|37 +podwórze|po=dwó=rze|37 +robotę|ro=bo=tę|37 +różnych|róż=nych|37 +stodoły|sto=do=ły|37 +słuchał|słu=chał|37 +zaglądał|za=glą=dał|37 +ziemie|zie=mie|37 +zwiesnę|zwie=snę|37 +bardzo|bar=dzo|36 +całego|ca=łe=go|36 +czasami|cza=sa=mi|36 +dojrzawszy|doj=rzaw=szy|36 +powiada|po=wia=da|36 +pośrodku|po=środ=ku|36 +strasznie|strasz=nie|36 +wszystkimi|wszyst=ki=mi|36 +wywarte|wy=war=te|36 +zajrzał|zaj=rzał|36 +Bogiem|Bo=giem|35 +chwilę|chwi=lę|35 +chłopaków|chło=pa=ków|35 +czarne|czar=ne|35 +cztery|czte=ry|35 +głupie|głu=pie|35 +jednym|jed=nym|35 +Ksiądz|Ksiądz|35 +morgów|mor=gów|35 +ostała|osta=ła|35 +pierwsze|pierw=sze|35 +poradzić|po=ra=dzić|35 +poredzi|po=re=dzi|35 +powiem|po=wiem|35 +powrotem|po=wro=tem|35 +prawił|pra=wił|35 +różności|róż=no=ści|35 +smutnie|smut=nie|35 +strachem|stra=chem|35 +szmaty|szma=ty|35 +słyszał|sły=szał|35 +takich|ta=kich|35 +takiej|ta=kiej|35 +trzęsła|trzę=sła|35 +zrobiło|zro=bi=ło|35 +ścianę|ścia=nę|35 +ślepie|śle=pie|35 +święty|świę=ty|35 +chyłkiem|chył=kiem|34 +czegoś|cze=goś|34 +dzieuchy|dzieu=chy|34 +dziewczyny|dziew=czy=ny|34 +galanto|ga=lan=to|34 +Jagusią|Ja=gu=sią|34 +nikomu|ni=ko=mu|34 +nogami|no=ga=mi|34 +patrzy|pa=trzy|34 +Tereska|Te=re=ska|34 +zawzięcie|za=wzię=cie|34 +zwyczajnie|zwy=czaj=nie|34 +śniegu|śnie=gu|34 +chleba|chle=ba|33 +czasie|cza=sie|33 +Jędrzych|Ję=drzych|33 +kulasy|ku=la=sy|33 +Mateusza|Ma=te=usza|33 +mówiła|mó=wi=ła|33 +niedzielę|nie=dzie=lę|33 +organista|or=ga=ni=sta|33 +parobek|pa=ro=bek|33 +podniesła|pod=nie=sła|33 +poleciała|po=le=cia=ła|33 +puścił|pu=ścił|33 +resztę|resz=tę|33 +rozglądając|roz=glą=da=jąc|33 +Właśnie|Wła=śnie|33 +chałupami|cha=łu=pa=mi|32 +czekał|cze=kał|32 +drzewami|drze=wa=mi|32 +kiejby|kiej=by|32 +kościołem|ko=ścio=łem|32 +muzyka|mu=zy=ka|32 +nieśmiało|nie=śmia=ło|32 +organistów|or=ga=ni=stów|32 +organiścina|or=ga=ni=ści=na|32 +owdzie|owdzie|32 +parobków|pa=rob=ków|32 +patrzał|pa=trzał|32 +powiedzieć|po=wie=dzieć|32 +prosił|pro=sił|32 +Przeciech|Prze=ciech|32 +ramiona|ra=mio=na|32 +rychtyk|rych=tyk|32 +Stacho|Sta=cho|32 +tylachna|ty=lach=na|32 +uciechy|ucie=chy|32 +wysoko|wy=so=ko|32 +wyszła|wy=szła|32 +Zdrowaś|Zdro=waś|32 +ziemią|zie=mią|32 +świętą|świę=tą|32 +gałęzie|ga=łę=zie|31 +głównie|głów=nie|31 +Jankiel|Jan=kiel|31 +kamień|ka=mień|31 +kościół|ko=ściół|31 +Kłębowa|Kłę=bo=wa|31 +miejscami|miej=sca=mi|31 +niesły|nie=sły|31 +ogniem|ogniem|31 +ruchać|ru=chać|31 +spiesznie|spiesz=nie|31 +stanął|sta=nął|31 +szeptała|szep=ta=ła|31 +wcześniej|wcze=śniej|31 +westchnęła|wes=tchnę=ła|31 +wrzask|wrzask|31 +wzdychał|wzdy=chał|31 +akuratnie|aku=rat=nie|30 +chodziła|cho=dzi=ła|30 +chycił|chy=cił|30 +ciepło|cie=pło|30 +garści|gar=ści|30 +gwiazdy|gwiaz=dy|30 +głęboko|głę=bo=ko|30 +kamienie|ka=mie=nie|30 +kominie|ko=mi=nie|30 +młynarza|mły=na=rza|30 +rzuciła|rzu=ci=ła|30 +widząc|wi=dząc|30 +wieczora|wie=czo=ra|30 +wiedziała|wie=dzia=ła|30 +wkrótce|wkrót=ce|30 +wrzaski|wrza=ski|30 +zajadle|za=ja=dle|30 +zarazem|za=ra=zem|30 +zdziebko|zdzieb=ko|30 +zmierzchu|zmierz=chu|30 +święte|świę=te|30 +buchnęła|buch=nę=ła|29 +Bylica|By=li=ca|29 +cienie|cie=nie|29 +ciągnął|cią=gnął|29 +czynił|czy=nił|29 +dobrodzieja|do=bro=dzie=ja|29 +galancie|ga=lan=cie|29 +godzinę|go=dzi=nę|29 +gorzałki|go=rzał=ki|29 +głośniej|gło=śniej|29 +kieliszek|kie=li=szek|29 +kolana|ko=la=na|29 +nasłuchując|na=słu=chu=jąc|29 +pazurami|pa=zu=ra=mi|29 +pięścią|pię=ścią|29 +podwórzu|po=dwó=rzu|29 +pojechał|po=je=chał|29 +poredziła|po=re=dzi=ła|29 +prosiła|pro=si=ła|29 +przystawał|przy=sta=wał|29 +robocie|ro=bo=cie|29 +sołtys|soł=tys|29 +spojrzał|spoj=rzał|29 +spytała|spy=ta=ła|29 +stanie|sta=nie|29 +stanęła|sta=nę=ła|29 +słuchać|słu=chać|29 +urągliwie|urą=gli=wie|29 +weźmie|weź=mie|29 +widziało|wi=dzia=ło|29 +wiedzą|wie=dzą|29 +wielkim|wiel=kim|29 +wrócił|wró=cił|29 +wzięli|wzię=li|29 +wójtowa|wój=to=wa|29 +zapamiętale|za=pa=mię=ta=le|29 +śpiewał|śpie=wał|29 +boleśnie|bo=le=śnie|28 +częściej|czę=ściej|28 +człowieka|czło=wie=ka|28 +drudzy|dru=dzy|28 +drzwiami|drzwia=mi|28 +dziesięć|dzie=sięć|28 +gospodyni|go=spo=dy=ni|28 +jeszczech|jesz=czech|28 +którzy|któ=rzy|28 +Macieju|Ma=cie=ju|28 +odrzekł|od=rzekł|28 +ozwała|ozwa=ła|28 +pierwsza|pierw=sza|28 +pierzynę|pie=rzy=nę|28 +pieski|pie=ski|28 +podnosząc|pod=no=sząc|28 +pokrótce|po=krót=ce|28 +przeszedł|prze=szedł|28 +przyleciał|przy=le=ciał|28 +spokój|spo=kój|28 +spowiedzi|spo=wie=dzi|28 +starszy|star=szy|28 +uciekać|ucie=kać|28 +wicher|wi=cher|28 +zwiesna|zwie=sna|28 +śmiała|śmia=ła|28 +śpiesznie|śpiesz=nie|28 +świnie|świ=nie|28 +dziewczyna|dziew=czy=na|27 +gorzałkę|go=rzał=kę|27 +głupia|głu=pia|27 +Jasiek|Ja=siek|27 +koniec|ko=niec|27 +koszuli|ko=szu=li|27 +Lipiec|Li=piec|27 +ludziach|lu=dziach|27 +naprzód|na=przód|27 +Nastusia|Na=stu=sia|27 +odrzekła|od=rze=kła|27 +pacierza|pa=cie=rza|27 +powiadali|po=wia=da=li|27 +przeciw|prze=ciw|27 +płacze|pła=cze|27 +Płoszkowa|Płosz=ko=wa|27 +sercem|ser=cem|27 +starym|sta=rym|27 +widziała|wi=dzia=ła|27 +wieczorem|wie=czo=rem|27 +Wszystkie|Wszyst=kie|27 +wykrzyknął|wy=krzyk=nął|27 +znowuj|zno=wuj|27 +świętej|świę=tej|27 +białych|bia=łych|26 +brakowało|bra=ko=wa=ło|26 +buchnął|buch=nął|26 +byście|by=ście|26 +będziesz|bę=dziesz|26 +chmury|chmu=ry|26 +dziedzica|dzie=dzi=ca|26 +dzisia|dzi=sia|26 +kapoty|ka=po=ty|26 +krzywda|krzyw=da|26 +obrazy|ob=ra=zy|26 +pomocy|po=mo=cy|26 +porwał|po=rwał|26 +proboszcz|pro=boszcz|26 +rzucał|rzu=cał|26 +sprawę|spra=wę|26 +szybko|szyb=ko|26 +twardo|twar=do|26 +wrzaskiem|wrza=skiem|26 +wychodził|wy=cho=dził|26 +zagony|za=go=ny|26 +zerwał|ze=rwał|26 +śmiechu|śmie=chu|26 +śmiechy|śmie=chy|26 +bezwolnie|bez=wol=nie|25 +cichym|ci=chym|25 +czerwonych|czer=wo=nych|25 +dookoła|do=oko=ła|25 +gotowa|go=to=wa|25 +głowami|gło=wa=mi|25 +komina|ko=mi=na|25 +krzywdę|krzyw=dę|25 +krzyżem|krzy=żem|25 +mrokach|mro=kach|25 +mruczał|mru=czał|25 +najbarzej|naj=ba=rzej|25 +nazajutrz|na=za=jutrz|25 +niespokojnie|nie=spo=koj=nie|25 +ostatnie|ostat=nie|25 +ostatnią|ostat=nią|25 +ostrożnie|ostroż=nie|25 +pamięci|pa=mię=ci|25 +patrzała|pa=trza=ła|25 +pewnikiem|pew=ni=kiem|25 +pierwszą|pierw=szą|25 +Pietrka|Pietr=ka|25 +przeżegnał|prze=że=gnał|25 +później|póź=niej|25 +reszta|resz=ta|25 +rozlegał|roz=le=gał|25 +sieniach|sie=niach|25 +Weronka|We=ron=ka|25 +wszystkiemu|wszyst=kie=mu|25 +wyrwał|wy=rwał|25 +zapaskę|za=pa=skę|25 +śniegiem|śnie=giem|25 +Bartek|Bar=tek|24 +bliska|bli=ska|24 +bronił|bro=nił|24 +buchały|bu=cha=ły|24 +cieniu|cie=niu|24 +cierpliwie|cier=pli=wie|24 +dzieciom|dzie=ciom|24 +dłużej|dłu=żej|24 +grzech|grzech|24 +indziej|in=dziej|24 +kochany|ko=cha=ny|24 +kożuch|ko=żuch|24 +kątach|ką=tach|24 +leciała|le=cia=ła|24 +lękliwie|lę=kli=wie|24 +niechby|niech=by|24 +ogromne|ogrom=ne|24 +poradzi|po=ra=dzi|24 +przystanął|przy=sta=nął|24 +przyszli|przy=szli|24 +robiła|ro=bi=ła|24 +rozumu|ro=zu=mu|24 +trzyma|trzy=ma|24 +trzymał|trzy=mał|24 +wielki|wiel=ki|24 +wisiało|wi=sia=ło|24 +wodzie|wo=dzie|24 +wprost|wprost|24 +wypowiedzieć|wy=po=wie=dzieć|24 +wójtów|wój=tów|24 +zabrał|za=brał|24 +ścianami|ścia=na=mi|24 +środku|środ=ku|24 +bieżyć|bie=żyć|23 +bociek|bo=ciek|23 +błocie|bło=cie|23 +chocia|cho=cia|23 +ciepły|cie=pły|23 +drzewiny|drze=wi=ny|23 +Jagustynki|Ja=gu=styn=ki|23 +jęknęła|jęk=nę=ła|23 +kochane|ko=cha=ne|23 +mocniej|moc=niej|23 +oglądać|oglą=dać|23 +organy|or=ga=ny|23 +ostatni|ostat=ni|23 +pacierzy|pa=cie=rzy|23 +papierosa|pa=pie=ro=sa|23 +pazury|pa=zu=ry|23 +portki|por=t=ki|23 +powrócił|po=wró=cił|23 +południe|po=łu=dnie|23 +przyniósł|przy=niósł|23 +płotem|pło=tem|23 +rzeknę|rzek=nę|23 +siarczyście|siar=czy=ście|23 +siedzą|sie=dzą|23 +stawie|sta=wie|23 +trzech|trzech|23 +twarze|twa=rze|23 +tydzień|ty=dzień|23 +wykrzyknęła|wy=krzyk=nę=ła|23 +wynosił|wy=no=sił|23 +wytrzymać|wy=trzy=mać|23 +zakrzyczał|za=krzy=czał|23 +zdołać|zdo=łać|23 +zdrowie|zdro=wie|23 +świeciło|świe=ci=ło|23 +świtania|świ=ta=nia|23 +Antkowi|Ant=ko=wi|22 +bronić|bro=nić|22 +chcieli|chcie=li|22 +czapkę|czap=kę|22 +dzwony|dzwo=ny|22 +gotowy|go=to=wy|22 +głosów|gło=sów|22 +głucho|głu=cho|22 +Głupiś|Głu=piś|22 +inaczej|ina=czej|22 +innego|in=ne=go|22 +inszego|in=sze=go|22 +kiedyś|kie=dyś|22 +kowala|ko=wa=la|22 +krzyczała|krzy=cza=ła|22 +kurzawy|ku=rza=wy|22 +Ludzie|Lu=dzie|22 +niechta|nie=chta|22 +niejednemu|nie=jed=ne=mu|22 +ojcowej|oj=co=wej|22 +organisty|or=ga=ni=sty|22 +pomiędzy|po=mię=dzy|22 +poredził|po=re=dził|22 +poszły|po=szły|22 +Prawdę|Praw=dę|22 +przodem|przo=dem|22 +przychodzi|przy=cho=dzi|22 +płotów|pło=tów|22 +roznosiły|roz=no=si=ły|22 +rychlej|ry=chlej|22 +również|rów=nież|22 +szkoda|szko=da|22 +topolowej|to=po=lo=wej|22 +wojska|woj=ska|22 +wołała|wo=ła=ła|22 +żadnej|żad=nej|22 +chodziły|cho=dzi=ły|21 +chorego|cho=re=go|21 +chycić|chy=cić|21 +chłopaka|chło=pa=ka|21 +czerwony|czer=wo=ny|21 +dobrym|do=brym|21 +Dominikową|Do=mi=ni=ko=wą|21 +działo|dzia=ło|21 +dziedzicem|dzie=dzi=cem|21 +gromadą|gro=ma=dą|21 +jakiejś|ja=kiejś|21 +jednako|jed=na=ko|21 +komorze|ko=mo=rze|21 +kręcił|krę=cił|21 +latały|la=ta=ły|21 +ludziom|lu=dziom|21 +nabożeństwo|na=bo=żeń=stwo|21 +nasłuchiwał|na=słu=chi=wał|21 +odpowiadał|od=po=wia=dał|21 +ogromny|ogrom=ny|21 +plebanię|ple=ba=nię|21 +począć|po=cząć|21 +poniektóre|po=nie=któ=re|21 +przerwał|prze=rwał|21 +przystając|przy=sta=jąc|21 +rozeznać|ro=ze=znać|21 +rozlegały|roz=le=ga=ły|21 +ruszyli|ru=szy=li|21 +skrzydłami|skrzy=dła=mi|21 +stawał|sta=wał|21 +uważnie|uważ=nie|21 +wargami|war=ga=mi|21 +wniebogłosy|wnie=bo=gło=sy|21 +wracają|wra=ca=ją|21 +wrzasnął|wrza=snął|21 +wrzasnęła|wrza=snę=ła|21 +wyniósł|wy=niósł|21 +wyraźnie|wy=raź=nie|21 +zagonach|za=go=nach|21 +zajrzeć|zaj=rzeć|21 +zapomnieć|za=po=mnieć|21 +śniegów|śnie=gów|21 +śpiewały|śpie=wa=ły|21 +świnia|świ=nia|21 +całował|ca=ło=wał|20 +chodzili|cho=dzi=li|20 +ciężki|cięż=ki|20 +czekać|cze=kać|20 +daleka|da=le=ka|20 +dalekie|da=le=kie|20 +dorzucił|do=rzu=cił|20 +dzieciątko|dzie=ciąt=ko|20 +gałęzi|ga=łę=zi|20 +historie|hi=sto=rie|20 +jakiego|ja=kie=go|20 +jarmarku|jar=mar=ku|20 +jaskółki|ja=skół=ki|20 +kapotę|ka=po=tę|20 +kiełbasy|kieł=ba=sy|20 +kolacji|ko=la=cji|20 +kowalowa|ko=wa=lo=wa|20 +krótko|krót=ko|20 +lecieć|le=cieć|20 +naczelnik|na=czel=nik|20 +nieustannie|nie=ustan=nie|20 +odwrócił|od=wró=cił|20 +oknami|okna=mi|20 +ostało|osta=ło|20 +pamięć|pa=mięć|20 +pijany|pi=ja=ny|20 +podnosiła|pod=no=si=ła|20 +podnosiły|pod=no=si=ły|20 +podwórza|po=dwó=rza|20 +pomagać|po=ma=gać|20 +pomarł|po=marł|20 +powieda|po=wie=da|20 +powstał|po=wstał|20 +południa|po=łu=dnia|20 +rozglądał|roz=glą=dał|20 +rękach|rę=kach|20 +skrzyni|skrzy=ni|20 +smętarz|smę=tarz|20 +sprawiedliwości|spra=wie=dli=wo=ści|20 +starczyło|star=czy=ło|20 +szukał|szu=kał|20 +topoli|to=po=li|20 +trzasnął|trza=snął|20 +trzydzieści|trzy=dzie=ści|20 +ukradkiem|ukrad=kiem|20 +uroczyście|uro=czy=ście|20 +wiedzieć|wie=dzieć|20 +Witkiem|Wit=kiem|20 +wodził|wo=dził|20 +wsiach|wsiach|20 +Wszystko|Wszyst=ko|20 +wyciągnął|wy=cią=gnął|20 +wójtem|wój=tem|20 +zaśmiał|za=śmiał|20 +zielone|zie=lo=ne|20 +Antkiem|Ant=kiem|19 +blisko|bli=sko|19 +borowy|bo=ro=wy|19 +buchał|bu=chał|19 +całować|ca=ło=wać|19 +Cichoj|Ci=choj|19 +cmentarz|cmen=tarz|19 +czterech|czte=rech|19 +czyste|czy=ste|19 +garście|gar=ście|19 +gdzież|gdzież|19 +gniewnie|gniew=nie|19 +godziny|go=dzi=ny|19 +Grzeli|Grze=li|19 +głuche|głu=che|19 +głuchy|głu=chy|19 +Jambroża|Jam=bro=ża|19 +kancelarii|kan=ce=la=rii|19 +Kobiety|Ko=bie=ty|19 +kreminale|kre=mi=na=le|19 +kroków|kro=ków|19 +kużden|kuż=den|19 +lipeckie|li=pec=kie|19 +Mateuszem|Ma=te=uszem|19 +Moiściewy|Mo=iście=wy|19 +młynem|mły=nem|19 +narodem|na=ro=dem|19 +Nastuś|Na=stuś|19 +nogach|no=gach|19 +obejrzał|obej=rzał|19 +obiedzie|obie=dzie|19 +pobiegła|po=bie=gła|19 +poczciwie|po=czci=wie|19 +poczuła|po=czu=ła|19 +polami|po=la=mi|19 +poniesła|po=nie=sła|19 +przebierać|prze=bie=rać|19 +przechodził|prze=cho=dził|19 +przedzie|prze=dzie|19 +przejmował|przej=mo=wał|19 +puszczą|pusz=czą|19 +płynął|pły=nął|19 +rozgłośnie|roz=gło=śnie|19 +rozległ|roz=legł|19 +rozmowy|roz=mo=wy|19 +rozpalone|roz=pa=lo=ne|19 +rękoma|rę=ko=ma|19 +samych|sa=mych|19 +serdecznie|ser=decz=nie|19 +skończyła|skoń=czy=ła|19 +starszych|star=szych|19 +turbacji|tur=ba=cji|19 +urzędu|urzę=du|19 +wichurą|wi=chu=rą|19 +widzieli|wi=dzie=li|19 +wiosna|wio=sna|19 +większy|więk=szy|19 +wymiarkować|wy=miar=ko=wać|19 +wyniesła|wy=nie=sła|19 +zajrzała|zaj=rza=ła|19 +zakrzyczała|za=krzy=cza=ła|19 +znajdzie|znaj=dzie|19 +zrobiła|zro=bi=ła|19 +łacniej|łac=niej|19 +ściskał|ści=skał|19 +śniegach|śnie=gach|19 +bierze|bie=rze|18 +Borynie|Bo=ry=nie|18 +błyskały|bły=ska=ły|18 +chcecie|chce=cie|18 +chłopami|chło=pa=mi|18 +cieniach|cie=niach|18 +ciągnęły|cią=gnę=ły|18 +czytał|czy=tał|18 +Dajcie|Daj=cie|18 +deliberować|de=li=be=ro=wać|18 +dobrodziejowi|do=bro=dzie=jo=wi|18 +dwadzieścia|dwa=dzie=ścia|18 +dworskie|dwor=skie|18 +dzwoniły|dzwo=ni=ły|18 +gorzały|go=rza=ły|18 +gorzej|go=rzej|18 +grontu|gron=tu|18 +Jagnie|Ja=gnie|18 +jakiegoś|ja=kie=goś|18 +Jantoś|Jan=toś|18 +książki|książ=ki|18 +księdzem|księ=dzem|18 +księżyc|księ=życ|18 +mojego|mo=je=go|18 +mruknęła|mruk=nę=ła|18 +musieli|mu=sie=li|18 +młynie|mły=nie|18 +należy|na=le=ży|18 +nieprawda|nie=praw=da|18 +obaczysz|oba=czysz|18 +oczymgnienie|oczym=gnie=nie|18 +odszedł|od=szedł|18 +ogarniał|ogar=niał|18 +otwarte|otwar=te|18 +papier|pa=pier|18 +patrzyła|pa=trzy=ła|18 +pierwszej|pierw=szej|18 +pierzyną|pie=rzy=ną|18 +pieśnie|pie=śnie|18 +pisarz|pi=sarz|18 +plecach|ple=cach|18 +poczuł|po=czuł|18 +Podlesie|Pod=le=sie|18 +Podlesiu|Pod=le=siu|18 +podniosła|pod=nio=sła|18 +pogadywał|po=ga=dy=wał|18 +pokornie|po=kor=nie|18 +powróci|po=wró=ci|18 +południu|po=łu=dniu|18 +progiem|pro=giem|18 +prosić|pro=sić|18 +Przecież|Prze=cież|18 +przejął|prze=jął|18 +przyjść|przyjść|18 +przysiadła|przy=sia=dła|18 +ptaszek|pta=szek|18 +pytała|py=ta=ła|18 +robiło|ro=bi=ło|18 +rzadka|rzad=ka|18 +rękami|rę=ka=mi|18 +skamlał|skam=lał|18 +stworzenie|stwo=rze=nie|18 +swoimi|swo=imi|18 +szczekał|szcze=kał|18 +szepty|szep=ty|18 +słuchali|słu=cha=li|18 +słyszała|sły=sza=ła|18 +trząsł|trząsł|18 +uciekła|ucie=kła|18 +uczynił|uczy=nił|18 +wesela|we=se=la|18 +wełniaki|weł=nia=ki|18 +widziały|wi=dzia=ły|18 +wielgachne|wiel=gach=ne|18 +wielkie|wiel=kie|18 +wlekły|wle=kły|18 +wyszło|wy=szło|18 +wzieni|wzie=ni|18 +zapomniał|za=po=mniał|18 +zapytała|za=py=ta=ła|18 +ziemiach|zie=miach|18 +zrywał|zry=wał|18 +ścierwy|ścier=wy|18 +środkiem|środ=kiem|18 +świece|świe=ce|18 +świętym|świę=tym|18 +żywego|ży=we=go|18 +bezwiednie|bez=wied=nie|17 +Borynowej|Bo=ry=no=wej|17 +Borynę|Bo=ry=nę|17 +Będzie|Bę=dzie|17 +chustkę|chust=kę|17 +chwilami|chwi=la=mi|17 +cisnąc|ci=snąc|17 +czekając|cze=ka=jąc|17 +dalejże|da=lej=że|17 +daruję|da=ru=ję|17 +dodała|do=da=ła|17 +dziecińskie|dzie=ciń=skie|17 +Dziedzic|Dzie=dzic|17 +dziwną|dziw=ną|17 +frasobliwie|fra=so=bli=wie|17 +gardziel|gar=dziel|17 +gardzieli|gar=dzie=li|17 +gospodynie|go=spo=dy=nie|17 +gromadzie|gro=ma=dzie|17 +huczał|hu=czał|17 +jarmark|jar=mark|17 +jesteście|je=ste=ście|17 +kamieniem|ka=mie=niem|17 +karczmę|karcz=mę|17 +kryjomo|kry=jo=mo|17 +krzykał|krzy=kał|17 +krótkie|krót=kie|17 +księży|księ=ży|17 +kłótni|kłót=ni|17 +ludzkie|ludz=kie|17 +mamrotał|mam=ro=tał|17 +myśląc|my=śląc|17 +najgorsze|naj=gor=sze|17 +niecierpliwie|nie=cier=pli=wie|17 +niełacno|nie=łac=no|17 +nijakiej|ni=ja=kiej|17 +ochotnie|ochot=nie|17 +ostanie|osta=nie|17 +ostatku|ostat=ku|17 +ołtarzem|oł=ta=rzem|17 +padały|pa=da=ły|17 +plebanii|ple=ba=nii|17 +podniesły|pod=nie=sły|17 +pognał|po=gnał|17 +poredzę|po=re=dzę|17 +posobnie|po=sob=nie|17 +poważnie|po=waż=nie|17 +powiadają|po=wia=da=ją|17 +Przeciek|Prze=ciek|17 +przeszło|prze=szło|17 +przykład|przy=kład|17 +rozeznał|ro=ze=znał|17 +ruszyć|ru=szyć|17 +skończyli|skoń=czy=li|17 +spoglądał|spo=glą=dał|17 +spozierając|spo=zie=ra=jąc|17 +sprawiedliwość|spra=wie=dli=wość|17 +stanęło|sta=nę=ło|17 +szczęścia|szczę=ścia|17 +słomiane|sło=mia=ne|17 +topolową|to=po=lo=wą|17 +trudem|tru=dem|17 +trwogą|trwo=gą|17 +urodna|urod=na|17 +Wieczór|Wie=czór|17 +wielkiej|wiel=kiej|17 +wisiały|wi=sia=ły|17 +wolniej|wol=niej|17 +wrzeszczała|wrzesz=cza=ła|17 +wszelkie|wszel=kie|17 +wszystkiej|wszyst=kiej|17 +wyciągał|wy=cią=gał|17 +wynosiły|wy=no=si=ły|17 +wyrzekła|wy=rze=kła|17 +wzdłuż|wzdłuż|17 +zaklął|za=klął|17 +zaśmiała|za=śmia=ła|17 +zbierać|zbie=rać|17 +zbierał|zbie=rał|17 +zbrakło|zbra=kło|17 +zielonych|zie=lo=nych|17 +śniadaniu|śnia=da=niu|17 +światłem|świa=tłem|17 +świeciły|świe=ci=ły|17 +żałości|ża=ło=ści|17 +ambony|am=bo=ny|16 +bezradnie|bez=rad=nie|16 +biedota|bie=do=ta|16 +Boryną|Bo=ry=ną|16 +broniła|bro=ni=ła|16 +bywało|by=wa=ło|16 +chłopi|chło=pi|16 +ciągnęli|cią=gnę=li|16 +czerwoną|czer=wo=ną|16 +człowieku|czło=wie=ku|16 +dojrzała|doj=rza=ła|16 +domowi|do=mo=wi|16 +długim|dłu=gim|16 +gospodarstwo|go=spo=dar=stwo|16 +granie|gra=nie|16 +grzechu|grze=chu|16 +gwałtownie|gwał=tow=nie|16 +głębokim|głę=bo=kim|16 +jakiej|ja=kiej|16 +kamieniami|ka=mie=nia=mi|16 +karczma|karcz=ma|16 +kałuże|ka=łu=że|16 +kochanie|ko=cha=nie|16 +kreminału|kre=mi=na=łu|16 +którymi|któ=ry=mi|16 +kwiaty|kwia=ty|16 +markotno|mar=kot=no|16 +Modlicy|Mo=dli=cy|16 +modlitwy|mo=dli=twy|16 +niebądź|nie=bądź|16 +odeszła|ode=szła|16 +opadły|opa=dły|16 +opowiadać|opo=wia=dać|16 +ostanę|osta=nę|16 +ostatniej|ostat=niej|16 +ołtarza|oł=ta=rza|16 +parobka|pa=rob=ka|16 +parobki|pa=rob=ki|16 +pierwszego|pierw=sze=go|16 +pierzyny|pie=rzy=ny|16 +pilnować|pil=no=wać|16 +pięknie|pięk=nie|16 +postawił|po=sta=wił|16 +pościeli|po=ście=li|16 +przeciągał|prze=cią=gał|16 +przyjacielstwa|przy=ja=ciel=stwa|16 +przyjdą|przyj=dą|16 +przyniesła|przy=nie=sła|16 +płachtą|płach=tą|16 +płótno|płót=no|16 +rankiem|ran=kiem|16 +rozmysłem|roz=my=słem|16 +rozumiesz|ro=zu=miesz|16 +ruszać|ru=szać|16 +siedziały|sie=dzia=ły|16 +sielny|siel=ny|16 +spoglądając|spo=glą=da=jąc|16 +stojała|sto=ja=ła|16 +strażników|straż=ni=ków|16 +szkołę|szko=łę|16 +trwogi|trwo=gi|16 +tłumaczył|tłu=ma=czył|16 +wiedli|wie=dli|16 +wodząc|wo=dząc|16 +wrzeszczał|wrzesz=czał|16 +wróble|wró=ble|16 +wychodzili|wy=cho=dzi=li|16 +wzięły|wzię=ły|16 +zachodu|za=cho=du|16 +zagadnął|za=gad=nął|16 +zapachy|za=pa=chy|16 +zatrząsł|za=trząsł|16 +zauważył|za=uwa=żył|16 +znaczenie|zna=cze=nie|16 +zważał|zwa=żał|16 +śpiewy|śpie=wy|16 +świtaniu|świ=ta=niu|16 +bierąc|bie=rąc|15 +boskiej|bo=skiej|15 +chałupa|cha=łu=pa|15 +chmura|chmu=ra|15 +Chodźcie|Chodź=cie|15 +chłopu|chło=pu|15 +ciemności|ciem=no=ści|15 +ciężkim|cięż=kim|15 +cudeńka|cu=deń=ka|15 +czekają|cze=ka=ją|15 +czekała|cze=ka=ła|15 +czysta|czy=sta|15 +dobrej|do=brej|15 +dobrością|do=bro=ścią|15 +dostał|do=stał|15 +drzewem|drze=wem|15 +drzwiach|drzwiach|15 +dzieuch|dzieuch|15 +dzieucha|dzieu=cha|15 +gankiem|gan=kiem|15 +gałęziami|ga=łę=zia=mi|15 +grdykę|grdy=kę|15 +grzechy|grze=chy|15 +Jagustynką|Ja=gu=styn=ką|15 +kapustę|ka=pu=stę|15 +kowalem|ko=wa=lem|15 +kromie|kro=mie|15 +krzepko|krzep=ko|15 +kulasami|ku=la=sa=mi|15 +kwiatów|kwia=tów|15 +Laboga|La=bo=ga|15 +laczego|la=cze=go|15 +maciorę|ma=cio=rę|15 +miarkując|miar=ku=jąc|15 +miedzach|mie=dzach|15 +milczenie|mil=cze=nie|15 +Muzyka|Mu=zy=ka|15 +najlepiej|naj=le=piej|15 +napity|na=pi=ty|15 +niedziele|nie=dzie=le|15 +niedługo|nie=dłu=go|15 +Niemcy|Niem=cy|15 +nigdzie|ni=g=dzie|15 +obejścia|obej=ścia|15 +odpust|od=pust|15 +ozorem|ozo=rem|15 +pacierzem|pa=cie=rzem|15 +palcami|pal=ca=mi|15 +patrzą|pa=trzą|15 +piaskiem|pia=skiem|15 +piersiach|pier=siach|15 +pociągał|po=cią=gał|15 +pogadywali|po=ga=dy=wa=li|15 +pokazał|po=ka=zał|15 +pomagał|po=ma=gał|15 +pomogło|po=mo=gło|15 +pomoże|po=mo=że|15 +porządnie|po=rząd=nie|15 +powiedają|po=wie=da=ją|15 +powiódł|po=wiódł|15 +profit|pro=fit|15 +przeciwić|prze=ciw=ić|15 +przejdzie|przej=dzie|15 +przeszła|prze=szła|15 +przyjdę|przyj=dę|15 +przykazał|przy=ka=zał|15 +przędła|przę=dła|15 +próżnicy|próż=ni=cy|15 +pustych|pu=stych|15 +północka|pół=noc=ka|15 +płaczu|pła=czu|15 +płakać|pła=kać|15 +płakała|pła=ka=ła|15 +płotami|pło=ta=mi|15 +radził|ra=dził|15 +ramionami|ra=mio=na=mi|15 +rwetes|rwe=tes|15 +rzekłem|rze=kłem|15 +sierota|sie=ro=ta|15 +sieroty|sie=ro=ty|15 +skończył|skoń=czył|15 +składowano|skła=do=wa=no|15 +spojrzała|spoj=rza=ła|15 +stając|sta=jąc|15 +staremu|sta=re=mu|15 +starsze|star=sze|15 +stojały|sto=ja=ły|15 +surowo|su=ro=wo|15 +słupach|słu=pach|15 +takiemu|ta=kie=mu|15 +tartaku|tar=ta=ku|15 +uciekł|uciekł|15 +warknęła|wark=nę=ła|15 +wełniak|weł=niak|15 +wiatru|wia=tru|15 +wpatrzony|wpa=trzo=ny|15 +wrzawa|wrza=wa|15 +wychodziła|wy=cho=dzi=ła|15 +wyciągać|wy=cią=gać|15 +wysokie|wy=so=kie|15 +zabawiali|za=ba=wia=li|15 +zabawy|za=ba=wy|15 +zabrała|za=bra=ła|15 +zachodzie|za=cho=dzie|15 +zadaszenie|za=da=sze=nie|15 +zaglądała|za=glą=da=ła|15 +zaprzeszłego|za=prze=szłe=go|15 +zdążył|zdą=żył|15 +zmiłowania|zmi=ło=wa=nia|15 +zwyczaju|zwy=cza=ju|15 +środka|środ=ka|15 +święto|świę=to|15 +alkierza|al=kie=rza|14 +baczenie|ba=cze=nie|14 +baczył|ba=czył|14 +Balcerkowa|Bal=cer=ko=wa|14 +białymi|bia=ły=mi|14 +bojała|bo=ja=ła|14 +brzega|brze=ga|14 +całych|ca=łych|14 +całymi|ca=ły=mi|14 +chodzą|cho=dzą|14 +chwiały|chwia=ły|14 +chłopakami|chło=pa=ka=mi|14 +ciekawie|cie=ka=wie|14 +ciołek|cio=łek|14 +cisnęła|ci=snę=ła|14 +cisnęły|ci=snę=ły|14 +czekali|cze=ka=li|14 +czynić|czy=nić|14 +człowiekowi|czło=wie=ko=wi|14 +dachów|da=chów|14 +dlaczego|dla=cze=go|14 +drogami|dro=ga=mi|14 +dziady|dzia=dy|14 +galanty|ga=lan=ty|14 +godnie|god=nie|14 +gorsze|gor=sze|14 +Gospodarz|Go=spo=darz|14 +gospodynią|go=spo=dy=nią|14 +gotowe|go=to=we|14 +groszy|gro=szy|14 +górnie|gór=nie|14 +gęściej|gę=ściej|14 +głodem|gło=dem|14 +innych|in=nych|14 +Jagusine|Ja=gu=si=ne|14 +jesienią|je=sie=nią|14 +jesteś|je=steś|14 +kapusty|ka=pu=sty|14 +kilkanaście|kil=ka=na=ście|14 +kobietę|ko=bie=tę|14 +krzywd|krzywd|14 +któremu|któ=re=mu|14 +kurzawa|ku=rza=wa|14 +kłótnie|kłót=nie|14 +lepsze|lep=sze|14 +liście|li=ście|14 +Loboga|Lo=bo=ga|14 +Miemcy|Miem=cy|14 +mieście|mie=ście|14 +modlił|mo=dlił|14 +mądrze|mą=drze|14 +młodych|mło=dych|14 +najbardziej|naj=bar=dziej|14 +narodowi|na=ro=do=wi|14 +Nastusi|Na=stu=si|14 +nauczał|na=uczał|14 +nawrotem|na=wro=tem|14 +niejedna|nie=jed=na|14 +niektóre|nie=któ=re|14 +nieprzytomny|nie=przy=tom=ny|14 +niesła|nie=sła|14 +odwieczerzu|od=wie=cze=rzu|14 +ogarnęła|ogar=nę=ła|14 +oglądając|oglą=da=jąc|14 +oglądał|oglą=dał|14 +oparte|opar=te|14 +ostały|osta=ły|14 +otworzył|otwo=rzył|14 +pięście|pię=ście|14 +pociekły|po=cie=kły|14 +podobno|po=dob=no|14 +pomyślał|po=my=ślał|14 +poniósł|po=niósł|14 +poruszył|po=ru=szył|14 +powietrza|po=wie=trza|14 +prawdzie|praw=dzie|14 +przebierał|prze=bie=rał|14 +przednówek|przed=nó=wek|14 +przestał|prze=stał|14 +prześmiechem|prze=śmie=chem|14 +przychodził|przy=cho=dził|14 +przycichło|przy=ci=chło|14 +przyszły|przy=szły|14 +puszczał|pusz=czał|14 +radzili|ra=dzi=li|14 +rozmyślał|roz=my=ślał|14 +rozpowiadać|roz=po=wia=dać|14 +ruszyła|ru=szy=ła|14 +ryknął|ryk=nął|14 +rzetelnie|rze=tel=nie|14 +rzewliwie|rzew=li=wie|14 +rzucić|rzu=cić|14 +senność|sen=ność|14 +siadła|sia=dła|14 +splunął|splu=nął|14 +spojrzenia|spoj=rze=nia|14 +społem|spo=łem|14 +sprzed|sprzed|14 +spytał|spy=tał|14 +srogie|sro=gie|14 +starczy|star=czy|14 +statki|stat=ki|14 +strasznym|strasz=nym|14 +szczęście|szczę=ście|14 +szczęśliwości|szczę=śli=wo=ści|14 +szkody|szko=dy|14 +słodko|słod=ko|14 +tamten|tam=ten|14 +toczyły|to=czy=ły|14 +tygodnie|ty=go=dnie|14 +tłukła|tłu=kła|14 +uciekał|ucie=kał|14 +utrudzenia|utru=dze=nia|14 +wiatrem|wia=trem|14 +wieczorami|wie=czo=ra=mi|14 +wielką|wiel=ką|14 +wlekła|wle=kła|14 +wpadła|wpa=dła|14 +wrychle|wry=chle|14 +wróciła|wró=ci=ła|14 +Wszyscy|Wszy=scy|14 +wszystką|wszyst=ką|14 +wychodzić|wy=cho=dzić|14 +wyjścia|wyj=ścia|14 +wykrzykiwał|wy=krzy=ki=wał|14 +zakręcił|za=krę=cił|14 +zapach|za=pach|14 +zapatrzona|za=pa=trzo=na|14 +zapomniała|za=po=mnia=ła|14 +zapraszał|za=pra=szał|14 +zawrócił|za=wró=cił|14 +zaśpiewały|za=śpie=wa=ły|14 +zbytnio|zbyt=nio|14 +ziarna|ziar=na|14 +zjawił|zja=wił|14 +zmiłowanie|zmi=ło=wa=nie|14 +zrobię|zro=bię|14 +zupełnie|zu=peł=nie|14 +ścierwo|ścier=wo|14 +śmiechów|śmie=chów|14 +śmiejąc|śmie=jąc|14 +święconą|świę=co=ną|14 +żeście|że=ście|14 +baczyć|ba=czyć|13 +bezustannie|bez=u=stan=nie|13 +biorąc|bio=rąc|13 +brzuch|brzuch|13 +buchnęły|buch=nę=ły|13 +bójcie|bój=cie|13 +ciasno|cia=sno|13 +ciemno|ciem=no|13 +cieniów|cie=niów|13 +ciągnęła|cią=gnę=ła|13 +ciągnęło|cią=gnę=ło|13 +ciężej|cię=żej|13 +ciężka|cięż=ka|13 +cofnął|cof=nął|13 +czerniały|czer=nia=ły|13 +czerwieniały|czer=wie=nia=ły|13 +czyniąc|czy=niąc|13 +dobrości|do=bro=ści|13 +drugiemu|dru=gie=mu|13 +dworem|dwo=rem|13 +Dzieci|Dzie=ci|13 +dziesiątkę|dzie=siąt=kę|13 +dziwno|dziw=no|13 +godzina|go=dzi=na|13 +gorzałka|go=rzał=ka|13 +gorzałką|go=rzał=ką|13 +gorące|go=rą=ce|13 +gospodarstwie|go=spo=dar=stwie|13 +grzbiet|grzbiet|13 +gęstwą|gę=stwą|13 +huczały|hu=cza=ły|13 +kijami|ki=ja=mi|13 +kolację|ko=la=cję|13 +koniom|ko=niom|13 +krzyczy|krzy=czy|13 +krótki|krót=ki|13 +książce|książ=ce|13 +kwiatem|kwia=tem|13 +lipeckich|li=pec=kich|13 +miłosierny|mi=ło=sier=ny|13 +mroków|mro=ków|13 +muzyki|mu=zy=ki|13 +najlepsze|naj=lep=sze|13 +namiętnie|na=mięt=nie|13 +nasienie|na=sie=nie|13 +niechętnie|nie=chęt=nie|13 +niedziela|nie=dzie=la|13 +niespodzianie|nie=spo=dzia=nie|13 +niestrudzenie|nie=stru=dze=nie|13 +niewymłócone|nie=wy=młó=co=ne|13 +niezgorszy|nie=zgor=szy|13 +niskie|ni=skie|13 +nocami|no=ca=mi|13 +nowina|no=wi=na|13 +obejściach|obej=ściach|13 +obejściu|obej=ściu|13 +oborze|obo=rze|13 +obrazów|ob=ra=zów|13 +odchodnym|od=chod=nym|13 +oderwać|ode=rwać|13 +odparła|od=par=ła|13 +ogromnym|ogrom=nym|13 +ogromną|ogrom=ną|13 +ojciec|oj=ciec|13 +ojcowe|oj=co=we|13 +oknach|oknach|13 +parobcy|pa=rob=cy|13 +Pańskiego|Pań=skie=go|13 +piekła|pie=kła|13 +piersiami|pier=sia=mi|13 +pochowek|po=cho=wek|13 +poganiał|po=ga=niał|13 +pomyśleć|po=my=śleć|13 +popadło|po=pa=dło|13 +poredzając|po=re=dza=jąc|13 +porwała|po=rwa=ła|13 +porządki|po=rząd=ki|13 +porządku|po=rząd=ku|13 +posypały|po=sy=pa=ły|13 +powlókł|po=wlókł|13 +przejęty|prze=ję=ty|13 +przyjechał|przy=je=chał|13 +przyodziewy|przy=odzie=wy|13 +przypiekało|przy=pie=ka=ło|13 +puścili|pu=ści=li|13 +puściła|pu=ści=ła|13 +płakał|pła=kał|13 +płotach|pło=tach|13 +płynęły|pły=nę=ły|13 +Rochem|Ro=chem|13 +rozeszli|ro=ze=szli|13 +rozlegało|roz=le=ga=ło|13 +rozmyślać|roz=my=ślać|13 +rozumiejąc|ro=zu=mie=jąc|13 +rzekli|rze=kli|13 +różnie|róż=nie|13 +samemu|sa=me=mu|13 +sennie|sen=nie|13 +Siadajcie|Sia=daj=cie|13 +siedzieć|sie=dzieć|13 +silnie|sil=nie|13 +skończy|skoń=czy|13 +smutek|smu=tek|13 +spieka|spie=ka|13 +sposobu|spo=so=bu|13 +spotkał|spo=tkał|13 +stadami|sta=da=mi|13 +strachliwie|stra=chli=wie|13 +straszne|strasz=ne|13 +strugi|stru=gi|13 +szerokie|sze=ro=kie|13 +Szymka|Szym=ka|13 +słoniny|sło=ni=ny|13 +słuchała|słu=cha=ła|13 +tartak|tar=tak|13 +trocha|tro=cha|13 +turkotał|tur=ko=tał|13 +twarzą|twa=rzą|13 +tysiące|ty=sią=ce|13 +tłumaczyła|tłu=ma=czy=ła|13 +waliła|wa=li=ła|13 +weselem|we=se=lem|13 +wiedzieli|wie=dzie=li|13 +wieprzka|wie=prz=ka|13 +wschodu|wscho=du|13 +wybuchnął|wy=buch=nął|13 +wzrokiem|wzro=kiem|13 +zaczęło|za=czę=ło|13 +zapamiętał|za=pa=mię=tał|13 +zauważyła|za=uwa=ży=ła|13 +zazdrość|za=zdrość|13 +ziarno|ziar=no|13 +zwiesny|zwie=sny|13 +zwłaszcza|zwłasz=cza|13 +zębach|zę=bach|13 +zębami|zę=ba=mi|13 +złodziej|zło=dziej|13 +złotówkę|zło=tów=kę|13 +złoście|zło=ście|13 +łakomie|ła=ko=mie|13 +ścierwa|ścier=wa|13 +śpiewać|śpie=wać|13 +światy|świa=ty|13 +świąteczne|świą=tecz=ne|13 +świętych|świę=tych|13 +żelazo|że=la=zo|13 +barłogu|bar=ło=gu|12 +beczki|becz=ki|12 +bełkotał|beł=ko=tał|12 +biedro|bie=dro|12 +będziecie|bę=dzie=cie|12 +będziemy|bę=dzie=my|12 +chcesz|chcesz|12 +chodzić|cho=dzić|12 +chytrze|chy=trze|12 +Chłopi|Chło=pi|12 +ciemnościach|ciem=no=ściach|12 +cisnął|ci=snął|12 +ciężkiej|cięż=kiej|12 +czując|czu=jąc|12 +Częstochowy|Czę=sto=cho=wy|12 +częstował|czę=sto=wał|12 +Człowiek|Czło=wiek|12 +dalekich|da=le=kich|12 +deszczu|desz=czu|12 +Dobrodziej|Do=bro=dziej|12 +domami|do=ma=mi|12 +dworowi|dwo=ro=wi|12 +dworskich|dwor=skich|12 +dziewczyn|dziew=czyn|12 +dziewka|dziew=ka|12 +dziewki|dziew=ki|12 +godzinie|go=dzi=nie|12 +gorąca|go=rą=ca|12 +gospodarzu|go=spo=da=rzu|12 +gwiazdami|gwiaz=da=mi|12 +głodny|głod=ny|12 +głucha|głu=cha|12 +głęboka|głę=bo=ka|12 +Idźcie|Idź=cie|12 +inwentarz|in=wen=tarz|12 +Jagata|Ja=ga=ta|12 +jękiem|ję=kiem|12 +kijaszkiem|ki=jasz=kiem|12 +komornice|ko=mor=ni=ce|12 +komorników|ko=mor=ni=ków|12 +koniczyny|ko=ni=czy=ny|12 +Kozioł|Ko=zioł|12 +krowie|kro=wie|12 +krwawe|krwa=we|12 +krzyczeli|krzy=cze=li|12 +krzywą|krzy=wą|12 +księdzu|księ=dzu|12 +kupować|ku=po=wać|12 +kurzawie|ku=rza=wie|12 +Lektur|Lek=tur|12 +Lektury|Lek=tu=ry|12 +ludzką|ludz=ką|12 +lśniły|lśni=ły|12 +mgnienie|mgnie=nie|12 +miedzami|mie=dza=mi|12 +Miemców|Miem=ców|12 +myśleć|my=śleć|12 +nagrzane|na=grza=ne|12 +najgłośniej|naj=gło=śniej|12 +najpierwsze|naj=pierw=sze|12 +Nastki|Na=st=ki|12 +niekajś|nie=kajś|12 +niezgorsze|nie=zgor=sze|12 +nozdrzach|noz=drzach|12 +obrządków|ob=rząd=ków|12 +oczywiście|oczy=wi=ście|12 +odmianę|od=mia=nę|12 +odpowiadała|od=po=wia=da=ła|12 +odpuście|od=pu=ście|12 +odwracając|od=wra=ca=jąc|12 +ogarniała|ogar=nia=ła|12 +okazji|oka=zji|12 +opłotków|opłot=ków|12 +orzydle|orzy=dle|12 +ostali|osta=li|12 +oszalałe|osza=la=łe|12 +otwarty|otwar=ty|12 +ołtarz|oł=tarz|12 +pacierzów|pa=cie=rzów|12 +paliły|pa=li=ły|12 +parobkami|pa=rob=ka=mi|12 +pierwszym|pierw=szym|12 +piorun|pio=run|12 +plecami|ple=ca=mi|12 +pochylił|po=chy=lił|12 +pochylone|po=chy=lo=ne|12 +pociągnął|po=cią=gnął|12 +poczęły|po=czę=ły|12 +podziwem|po=dzi=wem|12 +podłogę|pod=ło=gę|12 +pojechali|po=je=cha=li|12 +ponosiło|po=no=si=ło|12 +portkach|por=t=kach|12 +porządny|po=rząd=ny|12 +poszło|po=szło|12 +powiał|po=wiał|12 +powiedzą|po=wie=dzą|12 +powoli|po=wo=li|12 +powracał|po=wra=cał|12 +powrotu|po=wro=tu|12 +powstając|po=wsta=jąc|12 +położyła|po=ło=ży=ła|12 +pościele|po=ście=le|12 +prawić|pra=wić|12 +przeciwko|prze=ciw=ko|12 +przejść|przejść|12 +przeróżne|prze=róż=ne|12 +przychodziło|przy=cho=dzi=ło|12 +przychodziły|przy=cho=dzi=ły|12 +przygięte|przy=gię=te|12 +przyleciała|przy=le=cia=ła|12 +przystanęła|przy=sta=nę=ła|12 +ptactwo|ptac=two|12 +rozchodzić|roz=cho=dzić|12 +rozpowiadał|roz=po=wia=dał|12 +rozważał|roz=wa=żał|12 +skowronki|skow=ron=ki|12 +skręcił|skrę=cił|12 +spokoju|spo=ko=ju|12 +społecznie|spo=łecz=nie|12 +sprzedał|sprze=dał|12 +stanęły|sta=nę=ły|12 +stronami|stro=na=mi|12 +sygnaturka|sy=gna=tur=ka|12 +szykować|szy=ko=wać|12 +sąsiadów|są=sia=dów|12 +słodkim|słod=kim|12 +topole|to=po=le|12 +trzaskał|trza=skał|12 +twarzach|twa=rzach|12 +uderzył|ude=rzył|12 +uśmiechem|uśmie=chem|12 +wesołe|we=so=łe|12 +wespół|we=spół|12 +Wiater|Wia=ter|12 +wichry|wi=chry|12 +widzisz|wi=dzisz|12 +Widzisz|Wi=dzisz|12 +wieczerzy|wie=cze=rzy|12 +winowaty|wi=no=wa=ty|12 +większą|więk=szą|12 +Wolnych|Wol=nych|12 +wołali|wo=ła=li|12 +wrzasków|wrza=sków|12 +wrzało|wrza=ło|12 +wstawał|wsta=wał|12 +wstydu|wsty=du|12 +wyglądał|wy=glą=dał|12 +wyjdzie|wyj=dzie|12 +wyniesło|wy=nie=sło|12 +wynieśli|wy=nie=śli|12 +wyrozumieć|wy=ro=zu=mieć|12 +wyrwać|wy=rwać|12 +wyrzekał|wy=rze=kał|12 +wyrzekł|wy=rzekł|12 +wytrzymania|wy=trzy=ma=nia|12 +wywarła|wy=war=ła|12 +wzmagał|wzma=gał|12 +zabierając|za=bie=ra=jąc|12 +zachód|za=chód|12 +zagadywał|za=ga=dy=wał|12 +zagona|za=go=na|12 +zapadał|za=pa=dał|12 +zapaską|za=pa=ską|12 +zawziętość|za=wzię=tość|12 +zgrozy|zgro=zy|12 +zmilkła|zmil=kła|12 +zrobili|zro=bi=li|12 +zrozumieć|zro=zu=mieć|12 +zwalił|zwa=lił|12 +zwaliła|zwa=li=ła|12 +złapać|zła=pać|12 +złodzieje|zło=dzie=je|12 +śniadania|śnia=da=nia|12 +śniadanie|śnia=da=nie|12 +śpiewania|śpie=wa=nia|12 +świateł|świa=teł|12 +żałosne|ża=ło=sne|12 +Antków|Ant=ków|11 +barany|ba=ra=ny|11 +Borynowe|Bo=ry=no=we|11 +Bożego|Bo=że=go|11 +brakło|bra=kło|11 +brogiem|bro=giem|11 +brzaski|brza=ski|11 +bystro|by=stro|11 +całując|ca=łu=jąc|11 +chorągwie|cho=rą=gwie|11 +chwycił|chwy=cił|11 +chwytał|chwy=tał|11 +Chłopy|Chło=py|11 +Cichojta|Ci=choj=ta|11 +ciemna|ciem=na|11 +ciepnąć|ciep=nąć|11 +ciężarem|cię=ża=rem|11 +czerwieniły|czer=wie=ni=ły|11 +czystą|czy=stą|11 +dawała|da=wa=ła|11 +dawnego|daw=ne=go|11 +dobroci|do=bro=ci|11 +dochodził|do=cho=dził|11 +dorzuciła|do=rzu=ci=ła|11 +dygotał|dy=go=tał|11 +dziewucha|dzie=wu=cha|11 +elegancko|ele=ganc=ko|11 +gniewem|gnie=wem|11 +gniewu|gnie=wu|11 +gospodarka|go=spo=dar=ka|11 +gospodarza|go=spo=da=rza|11 +gruchnęła|gruch=nę=ła|11 +gąszczach|gąsz=czach|11 +głosami|gło=sa=mi|11 +głęboką|głę=bo=ką|11 +jajków|jaj=ków|11 +jakich|ja=kich|11 +jarzyły|ja=rzy=ły|11 +jechać|je=chać|11 +jesieni|je=sie=ni|11 +jękliwie|ję=kli=wie|11 +jęknął|jęk=nął|11 +karczmą|karcz=mą|11 +kazała|ka=za=ła|11 +kałdun|kał=dun|11 +kobietom|ko=bie=tom|11 +kochania|ko=cha=nia|11 +korale|ko=ra=le|11 +kożuchem|ko=żu=chem|11 +krzepki|krzep=ki|11 +krzyża|krzy=ża|11 +księże|księ=że|11 +kwardy|kwar=dy|11 +kwiatami|kwia=ta=mi|11 +kładły|kła=dły|11 +Kłębowej|Kłę=bo=wej|11 +ludzki|ludz=ki|11 +Macieja|Ma=cie=ja|11 +martwe|mar=twe|11 +Marysia|Ma=ry=sia|11 +medytował|me=dy=to=wał|11 +miarkować|miar=ko=wać|11 +miejscach|miej=scach|11 +modlitwę|mo=dli=twę|11 +morzył|mo=rzył|11 +możecie|mo=że=cie|11 +musiało|mu=sia=ło|11 +mówicie|mó=wi=cie|11 +młynowi|mły=no=wi|11 +najwięcej|naj=wię=cej|11 +naleźć|na=leźć|11 +naszego|na=sze=go|11 +niechcenia|nie=chce=nia|11 +niedaleko|nie=da=le=ko|11 +niemały|nie=ma=ły|11 +nieprzytomnie|nie=przy=tom=nie|11 +niewiela|nie=wie=la|11 +niewolił|nie=wo=lił|11 +nowinę|no=wi=nę|11 +obchodzić|ob=cho=dzić|11 +obcierając|ob=cie=ra=jąc|11 +obiadu|obia=du|11 +obzierając|obzie=ra=jąc|11 +odpoczywać|od=po=czy=wać|11 +odpowiedzi|od=po=wie=dzi|11 +odrobek|od=ro=bek|11 +odwróciła|od=wró=ci=ła|11 +ogniach|ogniach|11 +opowiadał|opo=wia=dał|11 +opowiadała|opo=wia=da=ła|11 +palcach|pal=cach|11 +pamiętać|pa=mię=tać|11 +pastwisk|pa=stwisk|11 +pazuchę|pa=zu=chę|11 +Pański|Pań=ski|11 +Pewnikiem|Pew=ni=kiem|11 +pilnował|pil=no=wał|11 +pluchy|plu=chy|11 +pobożne|po=boż=ne|11 +pobożnie|po=boż=nie|11 +począł|po=czął|11 +poglądał|po=glą=dał|11 +pogwary|po=gwa=ry|11 +pokoje|po=ko=je|11 +pomiarkował|po=miar=ko=wał|11 +ponieść|po=nieść|11 +poradzę|po=ra=dzę|11 +porządek|po=rzą=dek|11 +posłyszał|po=sły=szał|11 +powiedali|po=wie=da=li|11 +powiedzieli|po=wie=dzie=li|11 +powróciła|po=wró=ci=ła|11 +pozwoli|po=zwo=li|11 +połednie|po=łed=nie|11 +prawdy|praw=dy|11 +Proboszcz|Pro=boszcz|11 +przedzwonili|prze=dzwo=ni=li|11 +przemówić|prze=mó=wić|11 +przepijali|prze=pi=ja=li|11 +przeszłym|prze=szłym|11 +przynaglał|przy=na=glał|11 +przypomnienie|przy=po=mnie=nie|11 +przytajone|przy=ta=jo=ne|11 +przywarła|przy=war=ła|11 +przyzbie|przy=zbie|11 +ptaszki|ptasz=ki|11 +puścić|pu=ścić|11 +pójdziemy|pój=dzie=my|11 +płachty|płach=ty|11 +płachtę|płach=tę|11 +płaczów|pła=czów|11 +radosnym|ra=do=snym|11 +rajcowały|raj=co=wa=ły|11 +raźniej|raź=niej|11 +robotą|ro=bo=tą|11 +rodzone|ro=dzo=ne|11 +rodzony|ro=dzo=ny|11 +rolach|ro=lach|11 +rowach|ro=wach|11 +rozcież|roz=cież|11 +rozlewały|roz=le=wa=ły|11 +rozniesło|roz=nie=sło|11 +Rychtyk|Rych=tyk|11 +rzucając|rzu=ca=jąc|11 +rzucały|rzu=ca=ły|11 +rzędem|rzę=dem|11 +różnoście|róż=no=ście|11 +siedząc|sie=dząc|11 +sinych|si=nych|11 +skarżyła|skar=ży=ła|11 +skrzydła|skrzy=dła|11 +skrzypicy|skrzy=pi=cy|11 +skrzypki|skrzyp=ki|11 +skwapnie|skwap=nie|11 +sołtysem|soł=ty=sem|11 +spiekota|spie=ko=ta|11 +spodoba|spodo=ba|11 +sprawą|spra=wą|11 +starszym|star=szym|11 +stawała|sta=wa=ła|11 +stawiał|sta=wiał|11 +stodołę|sto=do=łę|11 +straszną|strasz=ną|11 +swarów|swa=rów|11 +sypały|sy=pa=ły|11 +Szymon|Szy=mon|11 +szynkwasie|szynk=wa=sie|11 +sądzie|są=dzie|11 +sąsiedzku|są=siedz=ku|11 +słodki|słod=ki|11 +tańcował|tań=co=wał|11 +trzeci|trze=ci|11 +trzymać|trzy=mać|11 +trzymała|trzy=ma=ła|11 +turbacja|tur=ba=cja|11 +turkot|tur=kot|11 +tymczasem|tym=cza=sem|11 +tłukły|tłu=kły|11 +urządzenie|urzą=dze=nie|11 +uspokajać|uspo=ka=jać|11 +wargach|war=gach|11 +wchodząc|wcho=dząc|11 +weselu|we=se=lu|11 +weszła|we=szła|11 +wichura|wi=chu=ra|11 +wielka|wiel=ka|11 +wierzcie|wierz=cie|11 +winien|wi=nien|11 +wrótnie|wrót=nie|11 +wsparłszy|wsparł=szy|11 +wspominki|wspo=min=ki|11 +wstęgi|wstę=gi|11 +wybrał|wy=brał|11 +wygnał|wy=gnał|11 +wyrywał|wy=ry=wał|11 +wyszli|wy=szli|11 +wzdychali|wzdy=cha=li|11 +wzgardliwie|wzgar=dli=wie|11 +Wójtowa|Wój=to=wa|11 +wójtowej|wój=to=wej|11 +zabawa|za=ba=wa|11 +zabrać|za=brać|11 +zaczną|za=czną|11 +zagadnęła|za=gad=nę=ła|11 +zagrały|za=gra=ły|11 +zapatrzony|za=pa=trzo=ny|11 +zapowiedzie|za=po=wie=dzie|11 +zapraszała|za=pra=sza=ła|11 +zasnął|za=snął|11 +zaszło|za=szło|11 +zatrzęsła|za=trzę=sła|11 +zatrzęsły|za=trzę=sły|11 +zebrała|ze=bra=ła|11 +zebrało|ze=bra=ło|11 +zerwała|ze=rwa=ła|11 +zgodzie|zgo=dzie|11 +zjedzą|zje=dzą|11 +zmroku|zmro=ku|11 +znajomków|zna=jom=ków|11 +znaleźć|zna=leźć|11 +zwrócił|zwró=cił|11 +ściana|ścia=na|11 +świętego|świę=te=go|11 +żałował|ża=ło=wał|11 +żałość|ża=łość|11 +Balcerek|Bal=ce=rek|10 +baldach|bal=dach|10 +biedzie|bie=dzie|10 +bokach|bo=kach|10 +bokiem|bo=kiem|10 +bratem|bra=tem|10 +bruzdach|bruz=dach|10 +brzęczały|brzę=cza=ły|10 +brzękiem|brzę=kiem|10 +chciały|chcia=ły|10 +chrzciny|chrzci=ny|10 +chórem|chó=rem|10 +Chłopaki|Chło=pa=ki|10 +chłopcy|chłop=cy|10 +chłopem|chło=pem|10 +Cichocie|Ci=cho=cie|10 +cichuśkim|ci=chuś=kim|10 +ciekły|cie=kły|10 +ciemnicy|ciem=ni=cy|10 +cienia|cie=nia|10 +ciepłe|cie=płe|10 +czarnych|czar=nych|10 +czarną|czar=ną|10 +Częstochowskiej|Czę=sto=chow=skiej|10 +dajcie|daj=cie|10 +daleki|da=le=ki|10 +deszcze|desz=cze|10 +dobrodziejem|do=bro=dzie=jem|10 +dobrych|do=brych|10 +dróżkę|dróż=kę|10 +dwojaków|dwo=ja=ków|10 +dzieuchami|dzieu=cha=mi|10 +długiej|dłu=giej|10 +Filipka|Fi=lip=ka|10 +Franek|Fra=nek|10 +gardło|gar=dło|10 +gospodarkę|go=spo=dar=kę|10 +gospodarski|go=spo=dar=ski|10 +gospodarstwa|go=spo=dar=stwa|10 +gotowego|go=to=we=go|10 +gromada|gro=ma=da|10 +gromady|gro=ma=dy|10 +grzechów|grze=chów|10 +Gulbasiak|Gul=ba=siak|10 +gąszcz|gąszcz|10 +gęstwę|gę=stwę|10 +głosować|gło=so=wać|10 +Głupia|Głu=pia|10 +huknął|huk=nął|10 +idźcie|idź=cie|10 +inszych|in=szych|10 +izbach|izbach|10 +jarmarek|jar=ma=rek|10 +jedzenie|je=dze=nie|10 +Jezusem|Je=zu=sem|10 +jąkała|ją=ka=ła|10 +jęczał|ję=czał|10 +Jędrek|Ję=drek|10 +kartofle|kar=to=fle|10 +karwas|kar=was|10 +kobietami|ko=bie=ta=mi|10 +kobietą|ko=bie=tą|10 +kokosz|ko=kosz|10 +kolebały|ko=le=ba=ły|10 +koszula|ko=szu=la|10 +koszulę|ko=szu=lę|10 +kowalowie|ko=wa=lo=wie|10 +Kozłową|Ko=zło=wą|10 +kredyt|kre=dyt|10 +krokiem|kro=kiem|10 +krzyczały|krzy=cza=ły|10 +krzycząc|krzy=cząc|10 +krzyże|krzy=że|10 +księża|księ=ża|10 +księżą|księ=żą|10 +któregoś|któ=re=goś|10 +kurzyło|ku=rzy=ło|10 +kądzielą|ką=dzie=lą|10 +leżało|le=ża=ło|10 +ludzkich|ludz=kich|10 +majaczyły|ma=ja=czy=ły|10 +mdlały|mdla=ły|10 +miałem|mia=łem|10 +miedzy|mie=dzy|10 +milczał|mil=czał|10 +morgach|mor=gach|10 +moście|mo=ście|10 +muzykę|mu=zy=kę|10 +Mówili|Mó=wi=li|10 +mądrala|mą=dra=la|10 +Młynarz|Mły=narz|10 +nadeszła|na=de=szła|10 +nadszedł|nad=szedł|10 +najlepszy|naj=lep=szy|10 +Nastką|Na=st=ką|10 +naszczekiwały|na=szcze=ki=wa=ły|10 +niemałym|nie=ma=łym|10 +nieobjęte|nie=ob=ję=te|10 +Nieprawda|Nie=praw=da|10 +nieszpory|nie=szpo=ry|10 +nowych|no=wych|10 +obcierał|ob=cie=rał|10 +Obejrzał|Obej=rzał|10 +obraza|ob=ra=za|10 +obrazami|ob=ra=za=mi|10 +odebrać|ode=brać|10 +odezwał|ode=zwał|10 +odezwała|ode=zwa=ła|10 +odpocząć|od=po=cząć|10 +odzywał|od=zy=wał|10 +ogarniając|ogar=nia=jąc|10 +ogonem|ogo=nem|10 +opadały|opa=da=ły|10 +organów|or=ga=nów|10 +osobno|osob=no|10 +pachnące|pach=ną=ce|10 +pachnący|pach=ną=cy|10 +paciorki|pa=cior=ki|10 +piasek|pia=sek|10 +pierwszych|pierw=szych|10 +Pietrkowi|Pietr=ko=wi|10 +Pietruś|Pie=truś|10 +Pietrze|Pie=trze|10 +piętnaście|pięt=na=ście|10 +pięści|pię=ści|10 +poczęli|po=czę=li|10 +poczęła|po=czę=ła|10 +podnieść|pod=nieść|10 +podobne|po=dob=ne|10 +podłodze|pod=ło=dze|10 +pogasły|po=ga=sły|10 +poglądając|po=glą=da=jąc|10 +pojedynkę|po=je=dyn=kę|10 +pokazywał|po=ka=zy=wał|10 +pokaże|po=ka=że|10 +pomiarkować|po=miar=ko=wać|10 +pomocą|po=mo=cą|10 +pomyślała|po=my=śla=ła|10 +ponuro|po=nu=ro|10 +porozchodzili|po=roz=cho=dzi=li|10 +Poszedł|Po=szedł|10 +potrzebuje|po=trze=bu=je|10 +Powiadali|Po=wia=da=li|10 +powiedz|po=wiedz|10 +powinien|po=wi=nien|10 +powstrzymać|po=wstrzy=mać|10 +procesji|pro=ce=sji|10 +przejmowała|przej=mo=wa=ła|10 +przekpinki|prze=kpin=ki|10 +przenikliwie|prze=ni=kli=wie|10 +przerażenia|prze=ra=że=nia|10 +przerwy|prze=rwy|10 +przesiaduje|prze=sia=du=je|10 +przychodziła|przy=cho=dzi=ła|10 +przyjdź|przyjdź|10 +przypołudnie|przy=po=łu=dnie|10 +przywieźli|przy=wieź=li|10 +psiachmać|psiach=mać|10 +płacić|pła=cić|10 +płakaniem|pła=ka=niem|10 +płomieniami|pło=mie=nia=mi|10 +radosne|ra=do=sne|10 +radosny|ra=do=sny|10 +radoście|ra=do=ście|10 +rozpowiadając|roz=po=wia=da=jąc|10 +rozpowiadała|roz=po=wia=da=ła|10 +rozważać|roz=wa=żać|10 +rośnie|ro=śnie|10 +rykiem|ry=kiem|10 +rymnął|rym=nął|10 +rzucili|rzu=ci=li|10 +różańca|ró=żań=ca|10 +schował|scho=wał|10 +siedziało|sie=dzia=ło|10 +Sikora|Si=ko=ra|10 +skoczyła|sko=czy=ła|10 +skończyło|skoń=czy=ło|10 +skądciś|skąd=ciś|10 +sobotę|so=bo=tę|10 +spadały|spa=da=ły|10 +spojrzeć|spoj=rzeć|10 +spostrzegł|spo=strzegł|10 +sprzeciw|sprze=ciw|10 +sprzedać|sprze=dać|10 +sprzęt|sprzęt|10 +spływały|spły=wa=ły|10 +stanęli|sta=nę=li|10 +starej|sta=rej|10 +starsi|star=si|10 +stodole|sto=do=le|10 +szarych|sza=rych|10 +szczerze|szcze=rze|10 +szeroką|sze=ro=ką|10 +szkoły|szko=ły|10 +szpitala|szpi=ta=la|10 +szumem|szu=mem|10 +słodką|słod=ką|10 +służył|słu=żył|10 +tańcowali|tań=co=wa=li|10 +tańcować|tań=co=wać|10 +Tereskę|Te=re=skę|10 +trumnę|trum=nę|10 +trzaskały|trza=ska=ły|10 +trzymają|trzy=ma=ją|10 +trzymając|trzy=ma=jąc|10 +trzymali|trzy=ma=li|10 +trzęsło|trzę=sło|10 +tuliła|tu=li=ła|10 +twarde|twar=de|10 +twardy|twar=dy|10 +uniesła|unie=sła|10 +urzędzie|urzę=dzie|10 +usiadł|usiadł|10 +uważać|uwa=żać|10 +uwierzyć|uwie=rzyć|10 +Wachnik|Wach=nik|10 +walili|wa=li=li|10 +waliły|wa=li=ły|10 +weszli|we=szli|10 +weźcie|weź=cie|10 +widniał|wid=niał|10 +widocznie|wi=docz=nie|10 +wisiał|wi=siał|10 +wnetki|wnet=ki|10 +wolność|wol=ność|10 +wozach|wo=zach|10 +wołania|wo=ła=nia|10 +wrzątku|wrząt=ku|10 +wschodzie|wscho=dzie|10 +wsparł|wsparł|10 +wstrzymał|wstrzy=mał|10 +wszelki|wszel=ki|10 +wybrany|wy=bra=ny|10 +wydzierał|wy=dzie=rał|10 +wydzierały|wy=dzie=ra=ły|10 +wyglądała|wy=glą=da=ła|10 +wyjrzała|wyj=rza=ła|10 +wyprawia|wy=pra=wia|10 +wyrabia|wy=ra=bia|10 +wyrwało|wy=rwa=ło|10 +wysoki|wy=so=ki|10 +wysunął|wy=su=nął|10 +wywarty|wy=war=ty|10 +zagadał|za=ga=dał|10 +zagonów|za=go=nów|10 +zagrała|za=gra=ła|10 +zalały|za=la=ły|10 +zapalił|za=pa=lił|10 +zapowietrzone|za=po=wie=trzo=ne|10 +zapłaci|za=pła=ci|10 +zaraza|za=ra=za|10 +zawracał|za=wra=cał|10 +zbożach|zbo=żach|10 +zbraknie|zbrak=nie|10 +zebrać|ze=brać|10 +zeźlony|ze=źlo=ny|10 +zgodnie|zgod=nie|10 +zielenią|zie=le=nią|10 +ziemiami|zie=mia=mi|10 +zważając|zwa=ża=jąc|10 +zwijała|zwi=ja=ła|10 +ścianie|ścia=nie|10 +ściągali|ścią=ga=li|10 +ślepiów|śle=piów|10 +śliczności|ślicz=no=ści|10 +śmiertelny|śmier=tel=ny|10 +śpiewali|śpie=wa=li|10 +śpiewań|śpie=wań|10 +świecił|świe=cił|10 +żałosnym|ża=ło=snym|10 +żałośliwie|ża=ło=śli=wie|10 +żegnał|że=gnał|10 +Bartka|Bart=ka|9 +białym|bia=łym|9 +bieliły|bie=li=ły|9 +bolały|bo=la=ły|9 +boleści|bo=le=ści|9 +Borynowa|Bo=ry=no=wa|9 +Borynową|Bo=ry=no=wą|9 +boskie|bo=skie|9 +bracie|bra=cie|9 +buchała|bu=cha=ła|9 +budzić|bu=dzić|9 +buzował|bu=zo=wał|9 +byłoby|by=ło=by|9 +Chciała|Chcia=ła|9 +chciałem|chcia=łem|9 +chciwie|chci=wie|9 +chmurzyska|chmu=rzy=ska|9 +Chodził|Cho=dził|9 +chusty|chu=s=ty|9 +chętliwie|chę=tli=wie|9 +chętnie|chęt=nie|9 +Chłopak|Chło=pak|9 +Cichość|Ci=chość|9 +cichych|ci=chych|9 +ciemię|cie=mię|9 +cieniami|cie=nia=mi|9 +cisnęli|ci=snę=li|9 +ciągnie|cią=gnie|9 +ciągną|cią=gną|9 +ciągotki|cią=got=ki|9 +ciężką|cięż=ką|9 +cudzego|cu=dze=go|9 +Czasem|Cza=sem|9 +Czemuż|Cze=muż|9 +czerwono|czer=wo=no|9 +czystym|czy=stym|9 +czytać|czy=tać|9 +człowiekowa|czło=wie=ko=wa|9 +dalekości|da=le=ko=ści|9 +dawnemu|daw=ne=mu|9 +dobrotliwie|do=bro=tli=wie|9 +dobrość|do=brość|9 +dojrzeć|doj=rzeć|9 +dostać|do=stać|9 +dosłyszał|do=sły=szał|9 +drewniane|drew=nia=ne|9 +drobny|drob=ny|9 +drużbowie|druż=bo=wie|9 +drzewach|drze=wach|9 +drzewinami|drze=wi=na=mi|9 +duszno|dusz=no|9 +dychać|dy=chać|9 +dziadów|dzia=dów|9 +dziękować|dzię=ko=wać|9 +długich|dłu=gich|9 +dźwigać|dźwi=gać|9 +figlów|fi=glów|9 +figury|fi=gu=ry|9 +figurą|fi=gu=rą|9 +garnki|garn=ki|9 +godzić|go=dzić|9 +gorący|go=rą=cy|9 +gospodarskie|go=spo=dar=skie|9 +gospodarsku|go=spo=dar=sku|9 +Gospodyni|Go=spo=dy=ni|9 +gotowi|go=to=wi|9 +grania|gra=nia|9 +gronta|gron=ta|9 +gruchnął|gruch=nął|9 +grzmoty|grzmo=ty|9 +głownie|głow=nie|9 +głupawy|głu=pa=wy|9 +Głupie|Głu=pie|9 +głębokie|głę=bo=kie|9 +herbatę|her=ba=tę|9 +jakbyś|jak=byś|9 +jastrząb|ja=strząb|9 +Jastrząb|Ja=strząb|9 +jednych|jed=nych|9 +jeździł|jeź=dził|9 +kapusta|ka=pu=sta|9 +klepisko|kle=pi=sko|9 +kobiece|ko=bie=ce|9 +koguty|ko=gu=ty|9 +kompanii|kom=pa=nii|9 +koniczynę|ko=ni=czy=nę|9 +kopyta|ko=py=ta|9 +kruchcie|kruch=cie|9 +krzyku|krzy=ku|9 +krzyków|krzy=ków|9 +krzywdą|krzyw=dą|9 +kudłów|ku=dłów|9 +kładła|kła=dła|9 +kłosami|kło=sa=mi|9 +Kłębiak|Kłę=biak|9 +Kłębową|Kłę=bo=wą|9 +lamenty|la=men=ty|9 +Ledwie|Le=d=wie|9 +Lipczaki|Lip=cza=ki|9 +lubości|lu=bo=ści|9 +Mateuszowi|Ma=te=uszo=wi|9 +miedzę|mie=dzę|9 +miejsc|miejsc|9 +miesiąc|mie=siąc|9 +minuty|mi=nu=ty|9 +miętko|mięt=ko|9 +miłowania|mi=ło=wa=nia|9 +modrym|mo=drym|9 +mrozie|mro=zie|9 +musiały|mu=sia=ły|9 +myślach|my=ślach|9 +myślałam|my=śla=łam|9 +mówcie|mów=cie|9 +młodzi|mło=dzi|9 +Naczelnik|Na=czel=nik|9 +naczelnika|na=czel=ni=ka|9 +naczynie|na=czy=nie|9 +nadział|na=dział|9 +nagich|na=gich|9 +nastał|na=stał|9 +Nastusią|Na=stu=sią|9 +natknął|na=tknął|9 +niechcący|nie=chcą=cy|9 +niejednego|nie=jed=ne=go|9 +niejedną|nie=jed=ną|9 +nieszczęście|nie=szczę=ście|9 +nieustępliwa|nie=ustę=pli=wa|9 +niewiele|nie=wie=le|9 +nosiła|no=si=ła|9 +nowiną|no=wi=ną|9 +obaczy|oba=czy|9 +obaczycie|oba=czy=cie|9 +obchodził|ob=cho=dził|9 +obejmując|obej=mu=jąc|9 +obejście|obej=ście|9 +obiecał|obie=cał|9 +odpowiedział|od=po=wie=dział|9 +ogarnął|ogar=nął|9 +ogrodach|ogro=dach|9 +ojcową|oj=co=wą|9 +okapem|oka=pem|9 +opowiedział|opo=wie=dział|9 +ostatka|ostat=ka|9 +ostatnich|ostat=nich|9 +otworzyć|otwo=rzyć|9 +pacierzu|pa=cie=rzu|9 +padało|pa=da=ło|9 +paskudne|pa=skud=ne|9 +Pańskie|Pań=skie|9 +piechty|piech=ty|9 +piekło|pie=kło|9 +pierwej|pier=wej|9 +piesek|pie=sek|9 +pieska|pie=ska|9 +pilnuj|pil=nuj|9 +pochwalił|po=chwa=lił|9 +pochylonych|po=chy=lo=nych|9 +pociechy|po=cie=chy|9 +poczciwy|po=czci=wy|9 +Poczekaj|Po=cze=kaj|9 +początku|po=cząt=ku|9 +podatki|po=dat=ki|9 +podała|po=da=ła|9 +podczas|pod=czas|9 +Podniesienia|Pod=nie=sie=nia|9 +podnosiło|pod=no=si=ło|9 +podobien|po=do=bien|9 +podziwu|po=dzi=wu|9 +pogadał|po=ga=dał|9 +poglądała|po=glą=da=ła|9 +pojadę|po=ja=dę|9 +pokazała|po=ka=za=ła|9 +pokoju|po=ko=ju|9 +pokryty|po=kry=ty|9 +poletę|po=le=tę|9 +pomstował|po=msto=wał|9 +popatrzeć|po=pa=trzeć|9 +popatrzył|po=pa=trzył|9 +poprzek|po=przek|9 +popłakując|po=pła=ku=jąc|9 +poradził|po=ra=dził|9 +poruszyć|po=ru=szyć|9 +postronku|po=stron=ku|9 +poszukać|po=szu=kać|9 +posłyszawszy|po=sły=szaw=szy|9 +potrzebny|po=trzeb=ny|9 +powiadam|po=wia=dam|9 +powtórzył|po=wtó=rzył|9 +poznał|po=znał|9 +prażył|pra=żył|9 +proboszcza|pro=bosz=cza|9 +procesją|pro=ce=sją|9 +prosiak|pro=siak|9 +przechodziły|prze=cho=dzi=ły|9 +przecierał|prze=cie=rał|9 +przecknęła|prze=ck=nę=ła|9 +przede|przede|9 +przegarniał|prze=gar=niał|9 +przejęte|prze=ję=te|9 +przeleciał|prze=le=ciał|9 +przemian|prze=mian|9 +przepijał|prze=pi=jał|9 +przepił|prze=pił|9 +przestając|prze=sta=jąc|9 +przestrzał|prze=strzał|9 +przeszły|prze=szły|9 +przełaj|prze=łaj|9 +przełazu|prze=ła=zu|9 +przygarnął|przy=gar=nął|9 +przyjacielstwo|przy=ja=ciel=stwo|9 +przykry|przy=kry|9 +przypomniał|przy=po=mniał|9 +przystawali|przy=sta=wa=li|9 +Próżno|Próż=no|9 +półgłosem|pół=gło=sem|9 +półkwaterki|pół=kwa=ter=ki|9 +płakania|pła=ka=nia|9 +płótna|płót=na|9 +radzić|ra=dzić|9 +rejwach|rej=wach|9 +rodzona|ro=dzo=na|9 +rosami|ro=sa=mi|9 +rozgłośniej|roz=gło=śniej|9 +rozległy|roz=le=gły|9 +rozmyślała|roz=my=śla=ła|9 +rozstajach|roz=sta=jach|9 +rychtować|rych=to=wać|9 +Rychło|Ry=chło|9 +ryczała|ry=cza=ła|9 +rzeźwe|rzeź=we|9 +rzęsisty|rzę=si=sty|9 +sercach|ser=cach|9 +sielna|siel=na|9 +siostry|sio=stry|9 +siostrą|sio=strą|9 +sięgnąć|się=gnąć|9 +skargi|skar=gi|9 +skargą|skar=gą|9 +skargę|skar=gę|9 +skwapliwie|skwa=pli=wie|9 +smutne|smut=ne|9 +smętarza|smę=ta=rza|9 +spadnie|spad=nie|9 +sparło|spar=ło|9 +spaśny|spa=śny|9 +spotkała|spo=tka=ła|9 +sprawie|spra=wie|9 +stamtąd|stam=tąd|9 +starych|sta=rych|9 +starzy|sta=rzy|9 +stawać|sta=wać|9 +stojący|sto=ją=cy|9 +Strach|Strach|9 +stracił|stra=cił|9 +straszna|strasz=na|9 +strasznego|strasz=ne=go|9 +straszny|strasz=ny|9 +stworzył|stwo=rzył|9 +stójka|stój=ka|9 +syknęła|syk=nę=ła|9 +szczekać|szcze=kać|9 +szczęściem|szczę=ściem|9 +Szczęściem|Szczę=ściem|9 +szybki|szyb=ki|9 +słowami|sło=wa=mi|9 +słońcem|słoń=cem|9 +słucha|słu=cha|9 +służbie|służ=bie|9 +słówkiem|słów=kiem|9 +tabaki|ta=ba=ki|9 +troskliwie|tro=skli=wie|9 +trzecią|trze=cią|9 +trzeszczały|trzesz=cza=ły|9 +turkotały|tur=ko=ta=ły|9 +twardym|twar=dym|9 +uciechą|ucie=chą|9 +ukradł|ukradł|9 +uniósł|uniósł|9 +ustami|usta=mi|9 +uśmiechał|uśmie=chał|9 +wchodził|wcho=dził|9 +wełniaków|weł=nia=ków|9 +wiatry|wia=try|9 +widziałem|wi=dzia=łem|9 +widzieć|wi=dzieć|9 +wieczory|wie=czo=ry|9 +wieków|wie=ków|9 +Wielki|Wiel=ki|9 +winowata|wi=no=wa=ta|9 +wlazło|wla=zło|9 +wolnelektury|wol=ne=lek=tu=ry|9 +wracał|wra=cał|9 +wrzeciono|wrze=cio=no|9 +wrzątkiem|wrząt=kiem|9 +wspierając|wspie=ra=jąc|9 +wstała|wsta=ła|9 +wstrzymać|wstrzy=mać|9 +wsunął|wsu=nął|9 +wszyćkie|wszyć=kie|9 +wtrącił|wtrą=cił|9 +wtrąciła|wtrą=ci=ła|9 +wybierać|wy=bie=rać|9 +wybierał|wy=bie=rał|9 +wyciągając|wy=cią=ga=jąc|9 +wyciągnąć|wy=cią=gnąć|9 +wyglądając|wy=glą=da=jąc|9 +wyjrzeć|wyj=rzeć|9 +wypadnie|wy=pad=nie|9 +wypominać|wy=po=mi=nać|9 +wypytywać|wy=py=ty=wać|9 +wyrobek|wy=ro=bek|9 +wyrzekania|wy=rze=ka=nia|9 +wzdychy|wzdy=chy|9 +wójtową|wój=to=wą|9 +Zaczęła|Za=czę=ła|9 +zamysły|za=my=sły|9 +zaniesła|za=nie=sła|9 +zapadła|za=pa=dła|9 +zapalczywie|za=pal=czy=wie|9 +zapłacę|za=pła=cę|9 +zapłakała|za=pła=ka=ła|9 +zaradzić|za=ra=dzić|9 +zazierać|za=zie=rać|9 +zbiera|zbie=ra|9 +zdumieniem|zdu=mie=niem|9 +zdumieniu|zdu=mie=niu|9 +zdumiony|zdu=mio=ny|9 +zeszło|ze=szło|9 +zeźlił|ze=źlił|9 +zieleni|zie=le=ni|9 +ziemniakami|ziem=nia=ka=mi|9 +zmówiny|zmó=wi=ny|9 +został|zo=stał|9 +zuchwale|zu=chwa=le|9 +zwarli|zwar=li|9 +zwiesnowy|zwie=sno=wy|9 +zwykle|zwy=kle|9 +złośliwie|zło=śli=wie|9 +łajdus|łaj=dus|9 +ławach|ła=wach|9 +łaziły|ła=zi=ły|9 +śmiało|śmia=ło|9 +śmiech|śmiech|9 +śmignął|śmi=gnął|9 +śpieszył|śpie=szył|9 +śpiewając|śpie=wa=jąc|9 +światłości|świa=tło=ści|9 +święcie|świę=cie|9 +żegnając|że=gna=jąc|9 +żółtych|żół=tych|9 +Alleluja|Al=le=lu=ja|8 +Antkową|Ant=ko=wą|8 +bacznie|bacz=nie|8 +batami|ba=ta=mi|8 +biczem|bi=czem|8 +biedoto|bie=do=to|8 +biegła|bie=gła|8 +broniąc|bro=niąc|8 +brzaskach|brza=skach|8 +brzucho|brzu=cho|8 +bydlątka|by=dląt=ka|8 +błocko|błoc=ko|8 +całunki|ca=łun=ki|8 +chwiał|chwiał|8 +chyciła|chy=ci=ła|8 +chłodzie|chło=dzie|8 +ciepłem|cie=płem|8 +ciepłych|cie=płych|8 +ciągał|cią=gał|8 +ciężkich|cięż=kich|8 +czajki|czaj=ki|8 +czapki|czap=ki|8 +Czekaj|Cze=kaj|8 +czerwonym|czer=wo=nym|8 +czerwonymi|czer=wo=ny=mi|8 +czwartek|czwar=tek|8 +czyniła|czy=ni=ła|8 +dachem|da=chem|8 +dawnej|daw=nej|8 +dawniej|daw=niej|8 +deszczem|desz=czem|8 +Dobranoc|Do=bra=noc|8 +Dołach|Do=łach|8 +druhny|druh=ny|8 +dysząc|dy=sząc|8 +dzieciak|dzie=ciak|8 +dzieciątka|dzie=ciąt=ka|8 +dziedzice|dzie=dzi=ce|8 +dziedzicowi|dzie=dzi=co=wi|8 +dziedziczka|dzie=dzicz=ka|8 +dziedziców|dzie=dzi=ców|8 +dziesięciu|dzie=się=ciu|8 +dziewkę|dziew=kę|8 +dzikim|dzi=kim|8 +dziwny|dziw=ny|8 +dziwował|dzi=wo=wał|8 +dzwonił|dzwo=nił|8 +Dębicy|Dę=bi=cy|8 +dłonią|dło=nią|8 +garnków|garn=ków|8 +godzinami|go=dzi=na=mi|8 +gorączkowo|go=rącz=ko=wo|8 +gospodarce|go=spo=dar=ce|8 +gołymi|go=ły=mi|8 +goście|go=ście|8 +granatowe|gra=na=to=we|8 +gryzły|gry=zły|8 +Grzelą|Grze=lą|8 +gwarno|gwar=no|8 +gwiazd|gwiazd|8 +gwiazda|gwiaz=da|8 +głuchym|głu=chym|8 +huczała|hu=cza=ła|8 +huczało|hu=cza=ło|8 +Jeszczech|Jesz=czech|8 +Jezusowi|Je=zu=so=wi|8 +jęczała|ję=cza=ła|8 +jęczmiona|jęcz=mio=na|8 +kamieni|ka=mie=ni|8 +kamionki|ka=mion=ki|8 +kieliszki|kie=lisz=ki|8 +kluski|klu=ski|8 +kobiecie|ko=bie=cie|8 +Kobusowa|Ko=bu=so=wa|8 +Kozłów|Ko=złów|8 +kołtuny|koł=tu=ny|8 +kościach|ko=ściach|8 +krajach|kra=jach|8 +krwawym|krwa=wym|8 +krzyżów|krzy=żów|8 +książką|książ=ką|8 +Księżyc|Księ=życ|8 +Któren|Któ=ren|8 +kulasów|ku=la=sów|8 +kupami|ku=pa=mi|8 +kupili|ku=pi=li|8 +kwikiem|kwi=kiem|8 +kłopot|kło=pot|8 +kłócić|kłó=cić|8 +latała|la=ta=ła|8 +ludzkiej|ludz=kiej|8 +maciory|ma=cio=ry|8 +miarkuję|miar=ku=ję|8 +mieniło|mie=ni=ło|8 +mierziło|mier=zi=ło|8 +migotały|mi=go=ta=ły|8 +Milczeli|Mil=cze=li|8 +miodem|mio=dem|8 +miłosierdzia|mi=ło=sier=dzia|8 +miłosierdzie|mi=ło=sier=dzie|8 +mlekiem|mle=kiem|8 +mniejsze|mniej=sze|8 +Moiście|Mo=iście|8 +myśleli|my=śle=li|8 +mówiłem|mó=wi=łem|8 +mówiły|mó=wi=ły|8 +młynarzowa|mły=na=rzo=wa|8 +młynicy|mły=ni=cy|8 +nabierał|na=bie=rał|8 +nabrane|na=bra=ne|8 +naciskiem|na=ci=skiem|8 +najpierw|naj=pierw|8 +największy|naj=więk=szy|8 +namawiał|na=ma=wiał|8 +narządziła|na=rzą=dzi=ła|8 +Nastkę|Na=st=kę|8 +naszej|na=szej|8 +naszemu|na=sze=mu|8 +nasłuchiwała|na=słu=chi=wa=ła|8 +Nazajutrz|Na=za=jutrz|8 +niebem|nie=bem|8 +niecierpliwiej|nie=cier=pli=wiej|8 +niedawno|nie=daw=no|8 +niedziel|nie=dziel|8 +niepokój|nie=po=kój|8 +nieznacznie|nie=znacz=nie|8 +nijakiego|ni=ja=kie=go|8 +nijako|ni=ja=ko|8 +nikogój|ni=ko=gój|8 +obaczę|oba=czę|8 +obcych|ob=cych|8 +objęła|ob=ję=ła|8 +obleczenie|ob=le=cze=nie|8 +obronie|obro=nie|8 +obronę|obro=nę|8 +obzierał|obzie=rał|8 +ochoty|ocho=ty|8 +odburknął|od=burk=nął|8 +odparł|od=parł|8 +opadał|opa=dał|8 +opiekę|opie=kę|8 +Organista|Or=ga=ni=sta|8 +ostawił|osta=wił|8 +Ostańcie|Ostań=cie|8 +pachniało|pach=nia=ło|8 +pachnącym|pach=ną=cym|8 +palące|pa=lą=ce|8 +papiery|pa=pie=ry|8 +parafii|pa=ra=fii|8 +parobku|pa=rob=ku|8 +patrzyły|pa=trzy=ły|8 +pełnymi|peł=ny=mi|8 +piasku|pia=sku|8 +pieniądz|pie=niądz|8 +pierwsi|pierw=si|8 +piorunami|pio=ru=na=mi|8 +Pisarz|Pi=sarz|8 +pisarza|pi=sa=rza|8 +pięćdziesiąt|pięć=dzie=siąt|8 +placek|pla=cek|8 +placka|plac=ka|8 +plucha|plu=cha|8 +pobiegł|po=biegł|8 +pochwalony|po=chwa=lo=ny|8 +pochylał|po=chy=lał|8 +pociemniało|po=ciem=nia=ło|8 +poczciwe|po=czci=we|8 +poczciwości|po=czci=wo=ści|8 +poczekać|po=cze=kać|8 +poczerniałe|po=czer=nia=łe|8 +podając|po=da=jąc|8 +podniosły|pod=nio=sły|8 +podoba|po=do=ba|8 +podsunął|pod=su=nął|8 +poglądali|po=glą=da=li|8 +pogrzeb|po=grzeb|8 +pokrzyki|po=krzy=ki|8 +pokrzykując|po=krzy=ku=jąc|8 +polecę|po=le=cę|8 +Polska|Pol=ska|8 +pomogę|po=mo=gę|8 +pomsty|po=msty|8 +ponosi|po=no=si|8 +poratunku|po=ra=tun=ku|8 +poredzali|po=re=dza=li|8 +porwały|po=rwa=ły|8 +Poszli|Po=szli|8 +Poszła|Po=szła|8 +posłuchać|po=słu=chać|8 +potężnie|po=tęż=nie|8 +powiadacie|po=wia=da=cie|8 +powiecie|po=wie=cie|8 +Powiem|Po=wiem|8 +powodu|po=wo=du|8 +powrocie|po=wro=cie|8 +powstrzymując|po=wstrzy=mu=jąc|8 +powtarzał|po=wta=rzał|8 +powtarzała|po=wta=rza=ła|8 +poznać|po=znać|8 +pozwolą|po=zwo=lą|8 +połednia|po=łed=nia|8 +położył|po=ło=żył|8 +połyskiwały|po=ły=ski=wa=ły|8 +Prawie|Pra=wie|8 +procesja|pro=ce=sja|8 +prosili|pro=si=li|8 +prostował|pro=sto=wał|8 +przechwalał|prze=chwa=lał|8 +przecknął|prze=ck=nął|8 +przedzierał|prze=dzie=rał|8 +przedzwaniali|prze=dzwa=nia=li|8 +przejmujący|przej=mu=ją=cy|8 +przejęła|prze=ję=ła|8 +przekąsem|prze=ką=sem|8 +przemóc|prze=móc|8 +przenieść|prze=nieść|8 +przepadł|prze=padł|8 +przepuszczając|prze=pusz=cza=jąc|8 +przerwała|prze=rwa=ła|8 +przeszli|prze=szli|8 +przewalał|prze=wa=lał|8 +przewiady|prze=wia=dy|8 +przełazie|prze=ła=zie|8 +przygotowań|przy=go=to=wań|8 +przyjacielsko|przy=ja=ciel=sko|8 +przymrozek|przy=mro=zek|8 +przypilnuję|przy=pil=nu=ję|8 +przypominki|przy=po=min=ki|8 +przystąpił|przy=stą=pił|8 +przysunął|przy=su=nął|8 +Przyszedł|Przy=szedł|8 +przysłaniały|przy=sła=nia=ły|8 +przywarte|przy=war=te|8 +przywierając|przy=wie=ra=jąc|8 +przyźbie|przy=źbie|8 +próbował|pró=bo=wał|8 +psiekrwie|psie=kr=wie|8 +ptaków|pta=ków|8 +pustym|pu=stym|8 +puszczając|pusz=cza=jąc|8 +puszył|pu=szył|8 +płaczliwie|płacz=li=wie|8 +płomieniem|pło=mie=niem|8 +Płoszków|Płosz=ków|8 +raptem|rap=tem|8 +robiły|ro=bi=ły|8 +rozebrać|ro=ze=brać|8 +rozmawiać|roz=ma=wiać|8 +roznosił|roz=no=sił|8 +rozpacznie|roz=pacz=nie|8 +rozpierała|roz=pie=ra=ła|8 +rozpytywać|roz=py=ty=wać|8 +rozumiała|ro=zu=mia=ła|8 +ruchał|ru=chał|8 +Rzekliście|Rze=kli=ście|8 +rządzi|rzą=dzi|8 +róbcie|rób=cie|8 +różaniec|ró=ża=niec|8 +samotne|sa=mot=ne|8 +samotnie|sa=mot=nie|8 +serdecznym|ser=decz=nym|8 +siarczyste|siar=czy=ste|8 +Siedział|Sie=dział|8 +Siedzieli|Sie=dzie=li|8 +sielne|siel=ne|8 +Sielny|Siel=ny|8 +sienie|sie=nie|8 +sięgał|się=gał|8 +skrzybot|skrzy=bot|8 +skrzypiały|skrzy=pia=ły|8 +smutna|smut=na|8 +spadły|spa=dły|8 +sposobną|spo=sob=ną|8 +spostrzegli|spo=strze=gli|8 +spuścić|spu=ścić|8 +srogiej|sro=giej|8 +srożył|sro=żył|8 +stawały|sta=wa=ły|8 +stojało|sto=ja=ło|8 +Strasznie|Strasz=nie|8 +straszno|strasz=no|8 +strażniki|straż=ni=ki|8 +stróżował|stró=żo=wał|8 +szczeka|szcze=ka|8 +szeroki|sze=ro=ki|8 +szkopek|szko=pek|8 +szkoła|szko=ła|8 +szkołach|szko=łach|8 +szukając|szu=ka=jąc|8 +szukały|szu=ka=ły|8 +szumiały|szu=mia=ły|8 +szybach|szy=bach|8 +słuchaj|słu=chaj|8 +słyszeli|sły=sze=li|8 +taczki|tacz=ki|8 +tknęło|tknę=ło|8 +tocząc|to=cząc|8 +topieli|to=pie=li|8 +topolami|to=po=la=mi|8 +torbeczki|tor=becz=ki|8 +trafił|tra=fił|8 +trupem|tru=pem|8 +Trzeba|Trze=ba|8 +trzeciego|trze=cie=go|8 +trzymam|trzy=mam|8 +tupoty|tu=po=ty|8 +turbacje|tur=ba=cje|8 +turkoty|tur=ko=ty|8 +tęskliwie|tę=skli=wie|8 +tłukąc|tłu=kąc|8 +tłukło|tłu=kło|8 +tłusto|tłu=sto|8 +urwała|urwa=ła|8 +uspokoić|uspo=ko=ić|8 +uspokoiło|uspo=ko=iło|8 +uszach|uszach|8 +utrzymać|utrzy=mać|8 +wagować|wa=go=wać|8 +westchnieniem|wes=tchnie=niem|8 +wetknęła|we=tknę=ła|8 +widziałam|wi=dzia=łam|8 +wierzył|wie=rzył|8 +wietrze|wie=trze|8 +Wilczych|Wil=czych|8 +wilgotny|wil=got=ny|8 +wionął|wio=nął|8 +wiosenny|wio=sen=ny|8 +wisiała|wi=sia=ła|8 +wiszące|wi=szą=ce|8 +wlekąc|wle=kąc|8 +wnątrzu|wną=trzu|8 +wodziła|wo=dzi=ła|8 +Wojtek|Woj=tek|8 +wracali|wra=ca=li|8 +wrzeciona|wrze=cio=na|8 +wsparła|wspar=ła|8 +wspomożenie|wspo=mo=że=nie|8 +wszelaki|wsze=la=ki|8 +wszyćkim|wszyć=kim|8 +wtykał|wty=kał|8 +wybrane|wy=bra=ne|8 +wychodząc|wy=cho=dząc|8 +wyciągały|wy=cią=ga=ły|8 +wyciągnęła|wy=cią=gnę=ła|8 +wyganiać|wy=ga=niać|8 +wyjściu|wyj=ściu|8 +wyniośle|wy=nio=śle|8 +wypominał|wy=po=mi=nał|8 +wypominki|wy=po=min=ki|8 +wyprostował|wy=pro=sto=wał|8 +wystąpił|wy=stą=pił|8 +wytrząchając|wy=trzą=cha=jąc|8 +wzdychała|wzdy=cha=ła|8 +wątpiach|wąt=piach|8 +wściekły|wście=kły|8 +zabaczyć|za=ba=czyć|8 +zabawę|za=ba=wę|8 +zabiega|za=bie=ga|8 +zacinał|za=ci=nał|8 +zaczynać|za=czy=nać|8 +Zaczęli|Za=czę=li|8 +zaglądając|za=glą=da=jąc|8 +zakotłowało|za=ko=tło=wa=ło|8 +zakończył|za=koń=czył|8 +zaledwie|za=le=d=wie|8 +zamieszanie|za=mie=sza=nie|8 +zapaski|za=pa=ski|8 +zapatrzyła|za=pa=trzy=ła|8 +zapierało|za=pie=ra=ło|8 +zapisał|za=pi=sał|8 +zapowietrzona|za=po=wie=trzo=na|8 +zatracenie|za=tra=ce=nie|8 +zawiewał|za=wie=wał|8 +zazierając|za=zie=ra=jąc|8 +zazwyczaj|za=zwy=czaj|8 +zgrozą|zgro=zą|8 +zjedli|zje=dli|8 +zmyślnie|zmyśl=nie|8 +znalazł|zna=lazł|8 +zresztą|zresz=tą|8 +zrobią|zro=bią|8 +zrywać|zry=wać|8 +zwierz|zwierz|8 +zwiesną|zwie=sną|8 +zziajany|zzia=ja=ny|8 +łagodnie|ła=god=nie|8 +Ścierwy|Ścier=wy|8 +ściągać|ścią=gać|8 +śmiały|śmia=ły|8 +środek|śro=dek|8 +świadków|świad=ków|8 +Święty|Świę=ty|8 +żadnego|żad=ne=go|8 +żałosny|ża=ło=sny|8 +żałoście|ża=ło=ście|8 +żołnierka|żoł=nier=ka|8 +żółciły|żół=ci=ły|8 +akurat|aku=rat|7 +alkierz|al=kierz|7 +Antkowa|Ant=ko=wa|7 +baczyła|ba=czy=ła|7 +bawiły|ba=wi=ły|7 +bezmyślnie|bez=myśl=nie|7 +białawe|bia=ła=we|7 +białej|bia=łej|7 +biedoty|bie=do=ty|7 +bielały|bie=la=ły|7 +bladym|bla=dym|7 +bogacz|bo=gacz|7 +bolesny|bo=le=sny|7 +borgować|bor=go=wać|7 +brakuje|bra=ku=je|7 +bruzdami|bruz=da=mi|7 +brzasków|brza=sków|7 +brzegi|brze=gi|7 +brzozy|brzo=zy|7 +budynki|bu=dyn=ki|7 +budził|bu=dził|7 +błogosławił|bło=go=sła=wił|7 +błotem|bło=tem|7 +błyskawice|bły=ska=wi=ce|7 +chceta|chce=ta|7 +chleby|chle=by|7 +chlewów|chle=wów|7 +chlustały|chlu=sta=ły|7 +chmurny|chmur=ny|7 +chodźcie|chodź=cie|7 +chojary|cho=ja=ry|7 +choroba|cho=ro=ba|7 +choroby|cho=ro=by|7 +Choćby|Choć=by|7 +chudziaku|chu=dzia=ku|7 +chwycić|chwy=cić|7 +ciasto|cia=sto|7 +cichej|ci=chej|7 +cichoj|ci=choj|7 +cichością|ci=cho=ścią|7 +ciekawe|cie=ka=we|7 +ciemne|ciem=ne|7 +ciepał|cie=pał|7 +ciesząc|cie=sząc|7 +ciągiem|cią=giem|7 +cofnęła|cof=nę=ła|7 +cudności|cud=no=ści|7 +czerwonej|czer=wo=nej|7 +czterdzieści|czter=dzie=ści|7 +Cztery|Czte=ry|7 +czubami|czu=ba=mi|7 +czyniło|czy=ni=ło|7 +czystej|czy=stej|7 +człowieczą|czło=wie=czą|7 +daleką|da=le=ką|7 +dalszych|dal=szych|7 +deszczów|desz=czów|7 +dniach|dniach|7 +dochodziły|do=cho=dzi=ły|7 +dostaniesz|do=sta=niesz|7 +dostała|do=sta=ła|7 +doszedł|do=szedł|7 +dowiedzieć|do=wie=dzieć|7 +dołkach|doł=kach|7 +dołożę|do=ło=żę|7 +drabiny|dra=bi=ny|7 +drzewin|drze=win|7 +dufności|duf=no=ści|7 +duszach|du=szach|7 +dziada|dzia=da|7 +dzieckiem|dziec=kiem|7 +dzikie|dzi=kie|7 +dzwonki|dzwon=ki|7 +długości|dłu=go=ści|7 +flachę|fla=chę|7 +flaszkę|flasz=kę|7 +gadali|ga=da=li|7 +gadała|ga=da=ła|7 +garściach|gar=ściach|7 +gmerały|gme=ra=ły|7 +gniazd|gniazd|7 +gniewy|gnie=wy|7 +gorzkie|gorz=kie|7 +gorączce|go=rącz=ce|7 +gospodarzem|go=spo=da=rzem|7 +gospodarzom|go=spo=da=rzom|7 +Gospodarzu|Go=spo=da=rzu|7 +gotowane|go=to=wa=ne|7 +Gołębianka|Go=łę=bian=ka|7 +gołębie|go=łę=bie|7 +grubym|gru=bym|7 +gwarzyć|gwa=rzyć|7 +głębiej|głę=biej|7 +głęboki|głę=bo=ki|7 +głębokiej|głę=bo=kiej|7 +innymi|in=ny=mi|7 +intencję|in=ten=cję|7 +jadłem|ja=dłem|7 +jakbym|jak=bym|7 +jakichś|ja=kichś|7 +Jambrożym|Jam=bro=żym|7 +jamory|ja=mo=ry|7 +jarzącymi|ja=rzą=cy=mi|7 +Jasiem|Ja=siem|7 +jasnym|ja=snym|7 +jechał|je=chał|7 +jenszy|jen=szy|7 +Jezusowe|Je=zu=so=we|7 +kajdany|kaj=da=ny|7 +katolickim|ka=to=lic=kim|7 +Każden|Każ=den|7 +kiecki|kiec=ki|7 +kiejście|kiej=ście|7 +klaczy|kla=czy|7 +kogutka|ko=gut=ka|7 +kopania|ko=pa=nia|7 +kopytami|ko=py=ta=mi|7 +korali|ko=ra=li|7 +kołowały|ko=ło=wa=ły|7 +kołysał|ko=ły=sał|7 +kołysały|ko=ły=sa=ły|7 +kończyna|koń=czy=na|7 +krajów|kra=jów|7 +krzami|krza=mi|7 +krzyknąć|krzyk=nąć|7 +krótką|krót=ką|7 +książkę|książ=kę|7 +księżego|księ=że=go|7 +Któregoś|Któ=re=goś|7 +kurzawą|ku=rza=wą|7 +kurzył|ku=rzył|7 +kwiatach|kwia=tach|7 +kądzieli|ką=dzie=li|7 +kłonicą|kło=ni=cą|7 +kłosów|kło=sów|7 +lecieli|le=cie=li|7 +lekciej|lek=ciej|7 +litanię|li=ta=nię|7 +lśniące|lśnią=ce|7 +marnego|mar=ne=go|7 +martwy|mar=twy|7 +matczyne|mat=czy=ne|7 +matula|ma=tu=la|7 +miarkujecie|miar=ku=je=cie|7 +miedzą|mie=dzą|7 +Miemce|Miem=ce|7 +minucie|mi=nu=cie|7 +minutę|mi=nu=tę|7 +miotał|mio=tał|7 +mocarz|mo=carz|7 +molestować|mo=le=sto=wać|7 +motyle|mo=ty=le|7 +możesz|mo=żesz|7 +mroczało|mro=cza=ło|7 +myślałem|my=śla=łem|7 +mógłby|mógł=by|7 +młodego|mło=de=go|7 +młodszy|młod=szy|7 +młynarzem|mły=na=rzem|7 +młynarzowego|mły=na=rzo=we=go|7 +młynarzów|mły=na=rzów|7 +nabrzmiałe|na=brzmia=łe|7 +nadzieją|na=dzie=ją|7 +Najpierw|Naj=pierw|7 +najpierwsi|naj=pierw=si|7 +nalazł|na=lazł|7 +namawiać|na=ma=wiać|7 +nasienia|na=sie=nia|7 +naszło|na=szło|7 +natomiast|na=to=miast|7 +niebieskie|nie=bie=skie|7 +nieboszczyka|nie=bosz=czy=ka|7 +niechaj|nie=chaj|7 +Niechby|Niech=by|7 +niektórzy|nie=któ=rzy|7 +niemałą|nie=ma=łą|7 +nienawiścią|nie=na=wi=ścią|7 +niesło|nie=sło|7 +Niewiela|Nie=wie=la|7 +nosili|no=si=li|7 +nowiny|no=wi=ny|7 +obcasami|ob=ca=sa=mi|7 +obertelek|obe=r=te=lek|7 +oberwać|obe=rwać|7 +obficie|ob=fi=cie|7 +obiecywał|obie=cy=wał|7 +obsiadły|ob=sia=dły|7 +ochotę|ocho=tę|7 +odchodzi|od=cho=dzi|7 +odchodził|od=cho=dził|7 +odchodząc|od=cho=dząc|7 +odetchnąć|ode=tchnąć|7 +odpowiedziała|od=po=wie=dzia=ła|7 +odzipnąć|od=zip=nąć|7 +oglądali|oglą=da=li|7 +ogniska|ogni=ska|7 +ogrodu|ogro=du|7 +ogrody|ogro=dy|7 +ogromnych|ogrom=nych|7 +opuszczenie|opusz=cze=nie|7 +opłatek|opła=tek|7 +opłotkami|opłot=ka=mi|7 +ostatnia|ostat=nia|7 +ostawał|osta=wał|7 +ostawiając|osta=wia=jąc|7 +ostawiła|osta=wi=ła|7 +ozorami|ozo=ra=mi|7 +ołtarze|oł=ta=rze|7 +pachnie|pach=nie|7 +padnie|pad=nie|7 +panowie|pa=no=wie|7 +paradą|pa=ra=dą|7 +Parobek|Pa=ro=bek|7 +patrzę|pa=trzę|7 +pazurów|pa=zu=rów|7 +Pańskiej|Pań=skiej|7 +pedzieć|pe=dzieć|7 +pełnej|peł=nej|7 +pełnym|peł=nym|7 +piesków|pie=sków|7 +pieśnią|pie=śnią|7 +Pijcie|Pij=cie|7 +pilnowała|pil=no=wa=ła|7 +pioruny|pio=ru=ny|7 +piosneczki|pio=snecz=ki|7 +piskiem|pi=skiem|7 +piąciu|pią=ciu|7 +plebanią|ple=ba=nią|7 +pluchę|plu=chę|7 +pobożny|po=boż=ny|7 +pochylały|po=chy=la=ły|7 +poczekaj|po=cze=kaj|7 +poczerwieniała|po=czer=wie=nia=ła|7 +pocznę|po=cznę|7 +podawać|po=da=wać|7 +podjął|pod=jął|7 +podnieśli|pod=nie=śli|7 +podobnie|po=dob=nie|7 +podobny|po=dob=ny|7 +podziw|po=dziw|7 +pogadując|po=ga=du=jąc|7 +pognała|po=gna=ła|7 +pojmować|poj=mo=wać|7 +pokazać|po=ka=zać|7 +pokojach|po=ko=jach|7 +Pokrótce|Po=krót=ce|7 +pokręciło|po=krę=ci=ło|7 +Poleciała|Po=le=cia=ła|7 +pomaga|po=ma=ga|7 +pomagała|po=ma=ga=ła|7 +pomstą|po=mstą|7 +pomyślenie|po=my=śle=nie|7 +pomógł|po=mógł|7 +pomówić|po=mó=wić|7 +poniesie|po=nie=sie|7 +poniesą|po=nie=są|7 +popijał|po=pi=jał|7 +poprawił|po=pra=wił|7 +popuszczę|po=pusz=czę|7 +poredzać|po=re=dzać|7 +poredzą|po=re=dzą|7 +poruszać|po=ru=szać|7 +porządków|po=rząd=ków|7 +poręby|po=rę=by|7 +porębę|po=rę=bę|7 +pospólnie|po=spól=nie|7 +postać|po=stać|7 +postronek|po=stro=nek|7 +posłuch|po=słuch|7 +posłyszeć|po=sły=szeć|7 +potaczał|po=ta=czał|7 +potrafi|po=tra=fi|7 +potrzeby|po=trze=by|7 +powiadać|po=wia=dać|7 +powiatu|po=wia=tu|7 +powiedam|po=wie=dam|7 +Powiedział|Po=wie=dział|7 +powraca|po=wra=ca|7 +powrócą|po=wró=cą|7 +powywierane|po=wy=wie=ra=ne|7 +pozostał|po=zo=stał|7 +pozwolić|po=zwo=lić|7 +połowa|po=ło=wa|7 +pośmiewisko|po=śmie=wi=sko|7 +pracował|pra=co=wał|7 +prosiaki|pro=sia=ki|7 +proszę|pro=szę|7 +prowadził|pro=wa=dził|7 +przechodziła|prze=cho=dzi=ła|7 +przedać|przedać|7 +przejmujące|przej=mu=ją=ce|7 +przejęły|prze=ję=ły|7 +przekpiwał|prze=kpi=wał|7 +przekładać|prze=kła=dać|7 +przenikał|prze=ni=kał|7 +przepijając|prze=pi=ja=jąc|7 +przestanku|prze=stan=ku|7 +Przeszedł|Prze=szedł|7 +przewiny|prze=wi=ny|7 +przewodził|prze=wo=dził|7 +przełaz|prze=łaz|7 +prześmiech|prze=śmiech|7 +przychodzą|przy=cho=dzą|7 +przychodź|przy=chodź|7 +przyczajone|przy=cza=jo=ne|7 +przydrożne|przy=droż=ne|7 +przyginały|przy=gi=na=ły|7 +przyglądał|przy=glą=dał|7 +Przyjdę|Przyj=dę|7 +przyjedzie|przy=je=dzie|7 +przynieść|przy=nieść|7 +przyobiecał|przy=obie=cał|7 +przypominając|przy=po=mi=na=jąc|7 +przysiedli|przy=sie=dli|7 +przysiąść|przy=siąść|7 +przyszedłem|przy=sze=dłem|7 +przywieść|przy=wieść|7 +przywiózł|przy=wiózł|7 +przyzba|przy=zba|7 +przyśpiewując|przy=śpie=wu=jąc|7 +próbowała|pró=bo=wa=ła|7 +Psiachmać|Psiach=mać|7 +ptactwa|ptac=twa|7 +ptasie|pta=sie|7 +płachta|płach=ta|7 +pławiły|pła=wi=ły|7 +płomienie|pło=mie=nie|7 +płomień|pło=mień|7 +radosną|ra=do=sną|7 +ratunek|ra=tu=nek|7 +rejenta|re=jen=ta|7 +robicie|ro=bi=cie|7 +robili|ro=bi=li|7 +robotny|ro=bot=ny|7 +rosach|ro=sach|7 +rozbierała|roz=bie=ra=ła|7 +rozbłysły|roz=bły=sły|7 +rozebrało|ro=ze=bra=ło|7 +rozgorzały|roz=go=rza=ły|7 +rozniesły|roz=nie=sły|7 +rozpalonymi|roz=pa=lo=ny=mi|7 +rozpiera|roz=pie=ra|7 +rozpoznał|roz=po=znał|7 +rozrosłe|roz=ro=słe|7 +rozumiał|ro=zu=miał|7 +rozumieć|ro=zu=mieć|7 +rozważając|roz=wa=ża=jąc|7 +rozłożył|roz=ło=żył|7 +ruszyły|ru=szy=ły|7 +Rzekłem|Rze=kłem|7 +Rzepek|Rze=pek|7 +rzęsiście|rzę=si=ście|7 +różańcem|ró=żań=cem|7 +samymi|sa=my=mi|7 +serdecznej|ser=decz=nej|7 +serdeczny|ser=decz=ny|7 +siadając|sia=da=jąc|7 +siekierą|sie=kie=rą|7 +Sikorzyna|Si=ko=rzy=na|7 +skraju|skra=ju|7 +skrzat|skrzat|7 +skrzyczał|skrzy=czał|7 +skrzypiał|skrzy=piał|7 +skrzypice|skrzy=pi=ce|7 +smętarzu|smę=ta=rzu|7 +snopki|snop=ki|7 +Sochowa|So=cho=wa|7 +sołtysa|soł=ty=sa|7 +spieki|spie=ki|7 +spodział|spo=dział|7 +spodziewając|spo=dzie=wa=jąc|7 +spojrzeniem|spoj=rze=niem|7 +spojrzy|spoj=rzy|7 +spostrzegając|spo=strze=ga=jąc|7 +spozierał|spo=zie=rał|7 +srebrne|srebr=ne|7 +srogich|sro=gich|7 +Stacha|Sta=cha|7 +stadko|stad=ko|7 +stawali|sta=wa=li|7 +stojali|sto=ja=li|7 +stojącą|sto=ją=cą|7 +straciła|stra=ci=ła|7 +strawy|stra=wy|7 +strażnikami|straż=ni=ka=mi|7 +strażnikom|straż=ni=kom|7 +struchlałe|stru=chla=łe|7 +strzegli|strze=gli|7 +strzelbę|strzel=bę|7 +stworzenia|stwo=rze=nia|7 +swobodnie|swo=bod=nie|7 +szarym|sza=rym|7 +szczekania|szcze=ka=nia|7 +szukała|szu=ka=ła|7 +słodkie|słod=kie|7 +Słyszeliście|Sły=sze=li=ście|7 +słyszysz|sły=szysz|7 +tabaką|ta=ba=ką|7 +tamtego|tam=te=go|7 +tatulu|ta=tu=lu|7 +toczył|to=czył|7 +trepami|tre=pa=mi|7 +trumny|trum=ny|7 +trwała|trwa=ła|7 +trzaskając|trza=ska=jąc|7 +trzasnęła|trza=snę=ła|7 +trzepały|trze=pa=ły|7 +tumany|tu=ma=ny|7 +tysiąc|ty=siąc|7 +ubrany|ubra=ny|7 +uciekały|ucie=ka=ły|7 +ucieszne|uciesz=ne|7 +uderzyły|ude=rzy=ły|7 +udręki|udrę=ki|7 +ujadały|uja=da=ły|7 +ujrzawszy|uj=rzaw=szy|7 +ująwszy|ująw=szy|7 +umiała|umia=ła|7 +umyślnie|umyśl=nie|7 +unosząc|uno=sząc|7 +upodoby|upodo=by|7 +urzędnik|urzęd=nik|7 +uspokoił|uspo=ko=ił|7 +usypany|usy=pa=ny|7 +uszami|usza=mi|7 +usłyszał|usły=szał|7 +uwierzy|uwie=rzy|7 +uwierzył|uwie=rzył|7 +uwięzi|uwię=zi|7 +uśmiechnął|uśmiech=nął|7 +warczały|war=cza=ły|7 +warkocze|war=ko=cze|7 +warowała|wa=ro=wa=ła|7 +waszych|wa=szych|7 +Weronki|We=ron=ki|7 +westchnienia|wes=tchnie=nia|7 +wiatrak|wia=trak|7 +wiecznie|wiecz=nie|7 +wiedła|wie=dła|7 +wiejskiej|wiej=skiej|7 +wierciło|wier=ci=ło|7 +wierzchu|wierz=chu|7 +wiośniane|wio=śnia=ne|7 +wiośnie|wio=śnie|7 +witając|wi=ta=jąc|7 +wiązać|wią=zać|7 +wojnie|woj=nie|7 +wolniuśko|wol=niuś=ko|7 +wozami|wo=za=mi|7 +wołały|wo=ła=ły|7 +wracając|wra=ca=jąc|7 +Wrzask|Wrzask|7 +wrzawą|wrza=wą|7 +wrzała|wrza=ła|7 +wrzeszczały|wrzesz=cza=ły|7 +wrócili|wró=ci=li|7 +wrótniami|wrót=nia=mi|7 +wschodem|wscho=dem|7 +wskazując|wska=zu=jąc|7 +współczuciem|współ=czu=ciem|7 +wstawać|wsta=wać|7 +wstąpił|wstą=pił|7 +wstążkę|wstąż=kę|7 +wybiera|wy=bie=ra|7 +wychylały|wy=chy=la=ły|7 +wydziera|wy=dzie=ra|7 +wygrażał|wy=gra=żał|7 +wyjrzał|wyj=rzał|7 +wykrzykiwać|wy=krzy=ki=wać|7 +wypomina|wy=po=mi=na|7 +wyrozumie|wy=ro=zu=mie|7 +wyrywać|wy=ry=wać|7 +wyrzekać|wy=rze=kać|7 +wystraszony|wy=stra=szo=ny|7 +wywalili|wy=wa=li=li|7 +wyzierając|wy=zie=ra=jąc|7 +wzburzony|wzbu=rzo=ny|7 +wzdychając|wzdy=cha=jąc|7 +wzdychów|wzdy=chów|7 +wznosił|wzno=sił|7 +wzruszenia|wzru=sze=nia|7 +wątroba|wą=tro=ba|7 +wściekłe|wście=kłe|7 +wściekłością|wście=kło=ścią|7 +zabiegał|za=bie=gał|7 +zabierać|za=bie=rać|7 +zachciało|za=chcia=ło|7 +zaczynał|za=czy=nał|7 +zaczynały|za=czy=na=ły|7 +zaglądać|za=glą=dać|7 +zaglądały|za=glą=da=ły|7 +zagonie|za=go=nie|7 +Zajrzała|Zaj=rza=ła|7 +zajęta|za=ję=ta|7 +zakołysał|za=ko=ły=sał|7 +zakrystii|za=kry=stii|7 +zakrzyczały|za=krzy=cza=ły|7 +zamedytował|za=me=dy=to=wał|7 +zamilkł|za=milkł|7 +zamknięty|za=mknię=ty|7 +zapamiętałością|za=pa=mię=ta=ło=ścią|7 +zapisu|za=pi=su|7 +zapodział|za=po=dział|7 +zapomnieli|za=po=mnie=li|7 +zapraszać|za=pra=szać|7 +zapłacić|za=pła=cić|7 +zarzewie|za=rze=wie|7 +zarzewiem|za=rze=wiem|7 +zasiadł|za=siadł|7 +zasnute|za=snu=te|7 +zasnęła|za=snę=ła|7 +zawodziły|za=wo=dzi=ły|7 +zaśpiewał|za=śpie=wał|7 +zbożem|zbo=żem|7 +zdechła|zde=chła|7 +zdrowy|zdro=wy|7 +zdumienia|zdu=mie=nia|7 +zdążyć|zdą=żyć|7 +zdążyła|zdą=ży=ła|7 +zerwały|ze=rwa=ły|7 +zgodził|zgo=dził|7 +ziarnem|ziar=nem|7 +zipiąc|zi=piąc|7 +zmartwiała|zmar=twia=ła|7 +zmarło|zmar=ło|7 +zmówić|zmó=wić|7 +znaczy|zna=czy|7 +znikąd|zni=kąd|7 +zrywała|zry=wa=ła|7 +zwyczajem|zwy=cza=jem|7 +złocie|zło=cie|7 +złodzieja|zło=dzie=ja|7 +ławkach|ław=kach|7 +łaziła|ła=zi=ła|7 +łąkach|łą=kach|7 +łęgach|łę=gach|7 +ścianach|ścia=nach|7 +Ścierwa|Ścier=wa|7 +ścisnął|ści=snął|7 +ścisnęło|ści=snę=ło|7 +ściółkę|ściół=kę|7 +śledzia|śle=dzia|7 +śmigały|śmi=ga=ły|7 +świecami|świe=ca=mi|7 +świeżo|świe=żo|7 +święci|świę=ci|7 +żałowała|ża=ło=wa=ła|7 +żałością|ża=ło=ścią|7 +życiem|ży=ciem|7 +Żydzie|Ży=dzie|7 +żywota|ży=wo=ta|7 +alkierzu|al=kie=rzu|6 +Antkowie|Ant=ko=wie|6 +Antoni|An=to=ni|6 +baczysz|ba=czysz|6 +barana|ba=ra=na|6 +baraszkował|ba=rasz=ko=wał|6 +baraszkowały|ba=rasz=ko=wa=ły|6 +bekiem|be=kiem|6 +bełkotem|beł=ko=tem|6 +biegali|bie=ga=li|6 +bierzcie|bierz=cie|6 +bieżyj|bie=żyj|6 +bijące|bi=ją=ce|6 +bijącym|bi=ją=cym|6 +bochen|bo=chen|6 +bogactwa|bo=gac=twa|6 +bogacze|bo=ga=cze|6 +bolesne|bo=le=sne|6 +borowego|bo=ro=we=go|6 +Borynowego|Bo=ry=no=we=go|6 +Borynowy|Bo=ry=no=wy|6 +Borynowym|Bo=ry=no=wym|6 +brzaskami|brza=ska=mi|6 +brzegu|brze=gu|6 +brzęki|brzę=ki|6 +buchało|bu=cha=ło|6 +burych|bu=rych|6 +bywały|by=wa=ły|6 +byłaby|by=ła=by|6 +Byście|By=ście|6 +Całkiem|Cał=kiem|6 +całowali|ca=ło=wa=li|6 +całowała|ca=ło=wa=ła|6 +cepami|ce=pa=mi|6 +Chciał|Chciał|6 +chlebem|chle=bem|6 +chlipanie|chli=pa=nie|6 +chmurzyskami|chmu=rzy=ska=mi|6 +chmurą|chmu=rą|6 +chodźmy|chodź=my|6 +Chodźta|Chodź=ta|6 +chorej|cho=rej|6 +choćbyś|choć=byś|6 +Chrystus|Chry=stus|6 +chrzęstem|chrzę=stem|6 +chwalił|chwa=lił|6 +chwasty|chwa=sty|6 +chwytając|chwy=ta=jąc|6 +chłodu|chło=du|6 +chłopskich|chłop=skich|6 +cielak|cie=lak|6 +ciemny|ciem=ny|6 +cieple|cie=ple|6 +ciepnął|ciep=nął|6 +ciepłym|cie=płym|6 +cieszyć|cie=szyć|6 +cieszył|cie=szył|6 +ciołak|cio=łak|6 +ciołka|cioł=ka|6 +ciurkiem|ciur=kiem|6 +ciągnąć|cią=gnąć|6 +ciągłe|cią=głe|6 +ciężkimi|cięż=ki=mi|6 +ciżbie|ciż=bie|6 +coście|co=ście|6 +czasownika|cza=sow=ni=ka|6 +czegóż|cze=góż|6 +czołem|czo=łem|6 +czujące|czu=ją=ce|6 +czynnością|czyn=no=ścią|6 +człowiecze|czło=wie=cze|6 +córuchno|có=ruch=no|6 +dachach|da=chach|6 +dalekim|da=le=kim|6 +dalekościach|da=le=ko=ściach|6 +dawali|da=wa=li|6 +deliberował|de=li=be=ro=wał|6 +diabli|dia=bli|6 +dlatego|dla=te=go|6 +dobremu|do=bre=mu|6 +dobytek|do=by=tek|6 +dochtory|do=chto=ry|6 +doczekać|do=cze=kać|6 +dojrzały|doj=rza=ły|6 +dokładnie|do=kład=nie|6 +dopraszam|do=pra=szam|6 +dostanie|do=sta=nie|6 +dosłyszawszy|do=sły=szaw=szy|6 +dowodził|do=wo=dził|6 +dołoży|do=ło=ży|6 +drapać|dra=pać|6 +dreszcz|dreszcz|6 +drewek|dre=wek|6 +drgały|drga=ły|6 +drzewina|drze=wi=na|6 +dróżce|dróż=ce|6 +drżące|drżą=ce|6 +dwojaki|dwo=ja=ki|6 +dygotała|dy=go=ta=ła|6 +dygotało|dy=go=ta=ło|6 +dygotem|dy=go=tem|6 +dymach|dy=mach|6 +działach|dzia=łach|6 +działy|dzia=ły|6 +dzieciach|dzie=ciach|6 +dziedzicowy|dzie=dzi=co=wy|6 +dziobem|dzio=bem|6 +dzioby|dzio=by|6 +dziwna|dziw=na|6 +Dziwowali|Dzi=wo=wa=li|6 +dzwoniła|dzwo=ni=ła|6 +długachne|dłu=gach=ne|6 +dłuższą|dłuż=szą|6 +dłużył|dłu=żył|6 +dźwigając|dźwi=ga=jąc|6 +farbami|far=ba=mi|6 +gadanie|ga=da=nie|6 +galopem|ga=lo=pem|6 +garnek|gar=nek|6 +gałęziach|ga=łę=ziach|6 +gałęzią|ga=łę=zią|6 +giezło|gie=zło|6 +gorszego|gor=sze=go|6 +gorzko|gorz=ko|6 +gorącymi|go=rą=cy=mi|6 +gospodarki|go=spo=dar=ki|6 +gospodarzami|go=spo=da=rza=mi|6 +gospodarzowi|go=spo=da=rzo=wi|6 +gospodyń|go=spo=dyń|6 +gołębi|go=łę=bi|6 +gościniec|go=ści=niec|6 +grobli|gro=bli|6 +grochem|gro=chem|6 +gromadę|gro=ma=dę|6 +gromnicę|grom=ni=cę|6 +groszem|gro=szem|6 +groziła|gro=zi=ła|6 +groźby|groź=by|6 +groźna|groź=na|6 +grubachne|gru=bach=ne|6 +grusze|gru=sze|6 +grzeszne|grzesz=ne|6 +gwarząc|gwa=rząc|6 +gwiezdne|gwiezd=ne|6 +gąsków|gą=sków|6 +gęsiego|gę=sie=go|6 +gęstniał|gęst=niał|6 +gęstwa|gę=stwa|6 +głaskać|gła=skać|6 +głaskał|gła=skał|6 +głupiego|głu=pie=go|6 +Hameryki|Ha=me=ry=ki|6 +hamował|ha=mo=wał|6 +hardość|har=dość|6 +historię|hi=sto=rię|6 +idziecie|idzie=cie|6 +indory|in=do=ry|6 +izdebki|iz=deb=ki|6 +jabłek|ja=błek|6 +Jagusina|Ja=gu=si=na|6 +Jankla|Jan=kla|6 +jasnością|ja=sno=ścią|6 +jazgoty|ja=zgo=ty|6 +Jaśkiem|Jaś=kiem|6 +jaśniały|ja=śnia=ły|6 +jechali|je=cha=li|6 +jedzie|je=dzie|6 +Jeszczek|Jesz=czek|6 +Jezusowego|Je=zu=so=we=go|6 +jeździli|jeź=dzi=li|6 +jeżeli|je=że=li|6 +Jędrzycha|Ję=drzy=cha|6 +jękliwe|ję=kli=we|6 +jękliwym|ję=kli=wym|6 +języka|ję=zy=ka|6 +kancelarią|kan=ce=la=rią|6 +kapały|ka=pa=ły|6 +kapocie|ka=po=cie|6 +karczmach|karcz=mach|6 +kawale|ka=wa=le|6 +kawałki|ka=wał=ki|6 +Kiedyż|Kie=dyż|6 +kieliszka|kie=lisz=ka|6 +kieszeni|kie=sze=ni|6 +kiełbasa|kieł=ba=sa|6 +kiełbasę|kieł=ba=sę|6 +kijaszek|ki=ja=szek|6 +klęczała|klę=cza=ła|6 +kobieto|ko=bie=to|6 +kobyłę|ko=by=łę|6 +kochana|ko=cha=na|6 +kokoty|ko=ko=ty|6 +komisarza|ko=mi=sa=rza|6 +kompanią|kom=pa=nią|6 +koniecznie|ko=niecz=nie|6 +konstrukcja|kon=struk=cja|6 +Kozłowej|Ko=zło=wej|6 +kołujący|ko=łu=ją=cy|6 +końcówką|koń=ców=ką|6 +końskie|koń=skie|6 +kościołowi|ko=ścio=ło=wi|6 +Kościół|Ko=ściół|6 +krewniaki|krew=nia=ki|6 +krewniaków|krew=nia=ków|6 +krzepciej|krzep=ciej|6 +krzyczą|krzy=czą|6 +krzyżu|krzy=żu|6 +królach|kró=lach|6 +kręcić|krę=cić|6 +kręciły|krę=ci=ły|6 +krętanina|krę=ta=ni=na|6 +kumami|ku=ma=mi|6 +kuntentność|kun=tent=ność|6 +kuropatki|ku=ro=pat=ki|6 +Kużden|Kuż=den|6 +kwiliły|kwi=li=ły|6 +lament|la=ment|6 +lasach|la=sach|6 +leciało|le=cia=ło|6 +leniwie|le=ni=wie|6 +lepszego|lep=sze=go|6 +lepszy|lep=szy|6 +lewentarz|le=wen=tarz|6 +leżących|le=żą=cych|6 +Lipcami|Lip=ca=mi|6 +Maciejowi|Ma=cie=jo=wi|6 +mamrotać|mam=ro=tać|6 +markotnie|mar=kot=nie|6 +matczynych|mat=czy=nych|6 +miarkował|miar=ko=wał|6 +miarkujcie|miar=kuj=cie|6 +migotał|mi=go=tał|6 +milcząca|mil=czą=ca|6 +mocniejszy|moc=niej=szy|6 +modlić|mo=dlić|6 +modliła|mo=dli=ła|6 +mrowiły|mro=wi=ły|6 +mruczała|mru=cza=ła|6 +mrówki|mrów=ki|6 +musiałem|mu=sia=łem|6 +musisz|mu=sisz|6 +mówiłam|mó=wi=łam|6 +młynarczyk|mły=nar=czyk|6 +nabożeństwa|na=bo=żeń=stwa|6 +nabrzmiały|na=brzmia=ły|6 +nadchodził|nad=cho=dził|6 +naokół|na=okół|6 +napisane|na=pi=sa=ne|6 +naprawdę|na=praw=dę|6 +narodził|na=ro=dził|6 +Nastce|Na=st=ce|6 +Nastusię|Na=stu=się|6 +naszczekiwał|na=szcze=ki=wał|6 +naszych|na=szych|6 +natknęła|na=tknę=ła|6 +niczegój|ni=cze=gój|6 +niczemu|ni=cze=mu|6 +niechże|niech=że|6 +niedzieli|nie=dzie=li|6 +niektóry|nie=któ=ry|6 +nieletko|nie=let=ko|6 +niemocy|nie=mo=cy|6 +niepowstrzymanie|nie=po=wstrzy=ma=nie|6 +nieprzyjacioły|nie=przy=ja=cio=ły|6 +nierad|nie=rad|6 +nierada|nie=ra=da|6 +niesie|nie=sie|6 +niesprawiedliwość|nie=spra=wie=dli=wość|6 +niesąc|nie=sąc|6 +nieustępliwą|nie=ustę=pli=wą|6 +niezadługo|nie=za=dłu=go|6 +Niezgorzej|Nie=zgo=rzej|6 +niosąc|nio=sąc|6 +niosły|nio=sły|6 +obaczył|oba=czył|6 +obejmował|obej=mo=wał|6 +oberwał|obe=rwał|6 +objaśniał|ob=ja=śniał|6 +objaśniała|ob=ja=śnia=ła|6 +obleczenia|ob=le=cze=nia|6 +obleczeniu|ob=le=cze=niu|6 +obmierzły|ob=mier=z=ły|6 +obrazem|ob=ra=zem|6 +obrony|obro=ny|6 +obzierać|obzie=rać|6 +ochfiarowała|ochfia=ro=wa=ła|6 +ociężale|ocię=ża=le|6 +oczekując|ocze=ku=jąc|6 +oddała|od=da=ła|6 +oddech|od=dech|6 +oddechy|od=de=chy|6 +odebrał|ode=brał|6 +odeszli|ode=szli|6 +odmówienie|od=mó=wie=nie|6 +odpowie|od=po=wie|6 +odsunął|od=su=nął|6 +odwracał|od=wra=cał|6 +odwracała|od=wra=ca=ła|6 +oganiając|oga=nia=jąc|6 +ogiery|ogie=ry|6 +ogniste|ogni=ste|6 +ogrodzie|ogro=dzie|6 +ojcowego|oj=co=we=go|6 +okrutnie|okrut=nie|6 +okręcił|okrę=cił|6 +omacku|omac=ku|6 +opadła|opa=dła|6 +opierał|opie=rał|6 +opowiadając|opo=wia=da=jąc|6 +opowiedzieć|opo=wie=dzieć|6 +oprzytomniał|oprzy=tom=niał|6 +organistą|or=ga=ni=stą|6 +Organiścina|Or=ga=ni=ści=na|6 +ostrzej|ostrzej|6 +otwarcie|otwar=cie|6 +otwierać|otwie=rać|6 +otwierało|otwie=ra=ło|6 +otwierały|otwie=ra=ły|6 +ozorach|ozo=rach|6 +ozwarł|ozwarł|6 +oścież|oścież|6 +ożenić|oże=nić|6 +paciorków|pa=cior=ków|6 +padała|pa=da=ła|6 +palcem|pal=cem|6 +pamięta|pa=mię=ta|6 +Panajezusowe|Pa=na=je=zu=so=we|6 +panuje|pa=nu=je|6 +papierosy|pa=pie=ro=sy|6 +papieru|pa=pie=ru|6 +pasieki|pa=sie=ki|6 +paśniki|pa=śni=ki|6 +pedział|pe=dział|6 +piekle|pie=kle|6 +piesneczki|pie=snecz=ki|6 +Pietrkiem|Pietr=kiem|6 +Pietrusia|Pie=tru=sia|6 +pieściwie|pie=ści=wie|6 +pieśni|pie=śni|6 +pilnuje|pil=nu=je|6 +pobili|po=bi=li|6 +pochowku|po=chow=ku|6 +pociecha|po=cie=cha|6 +pociechę|po=cie=chę|6 +pociągając|po=cią=ga=jąc|6 +pociągnęła|po=cią=gnę=ła|6 +poczęstunek|po=czę=stu=nek|6 +podjeść|pod=jeść|6 +Podlesia|Pod=le=sia|6 +podmurówki|pod=mu=rów=ki|6 +Podniesła|Pod=nie=sła|6 +podniesło|pod=nie=sło|6 +Podniósł|Pod=niósł|6 +podsuwając|pod=su=wa=jąc|6 +podszedł|pod=szedł|6 +poduszki|po=dusz=ki|6 +podzielić|po=dzie=lić|6 +pogadywać|po=ga=dy=wać|6 +pogrzebie|po=grze=bie|6 +pojechała|po=je=cha=ła|6 +pojękiwał|po=ję=ki=wał|6 +pokazało|po=ka=za=ło|6 +pokazały|po=ka=za=ły|6 +polśniewał|po=lśnie=wał|6 +polśniewały|po=lśnie=wa=ły|6 +pomdlałe|po=mdla=łe|6 +pomieścić|po=mie=ścić|6 +Poniechajcie|Po=nie=chaj=cie|6 +poniektórych|po=nie=któ=rych|6 +poniesły|po=nie=sły|6 +ponieśli|po=nie=śli|6 +ponosił|po=no=sił|6 +popuszczał|po=pusz=czał|6 +popłakiwała|po=pła=ki=wa=ła|6 +poredzili|po=re=dzi=li|6 +porykiwania|po=ry=ki=wa=nia|6 +posiał|po=siał|6 +postawili|po=sta=wi=li|6 +postało|po=sta=ło|6 +postronki|po=stron=ki|6 +postękiwał|po=stę=ki=wał|6 +poszumem|po=szu=mem|6 +posłucha|po=słu=cha|6 +potoczył|po=to=czył|6 +powiadaj|po=wia=daj|6 +powinna|po=win=na|6 +pozdrowienia|po=zdro=wie=nia|6 +pozwolili|po=zwo=li=li|6 +pościel|po=ściel|6 +pośpiechu|po=śpie=chu|6 +pożogą|po=żo=gą|6 +pożyczyć|po=ży=czyć|6 +prawdziwie|praw=dzi=wie|6 +prawdziwy|praw=dzi=wy|6 +prawej|pra=wej|6 +prosząc|pro=sząc|6 +prosząco|pro=szą=co|6 +prośby|proś=by|6 +Pryczek|Pry=czek|6 +przeciwił|prze=ciw=ił|6 +przeciwiła|prze=ciw=i=ła|6 +przeciągle|prze=cią=gle|6 +przedostawać|prze=do=sta=wać|6 +przekradać|prze=kra=dać|6 +przemawiał|prze=ma=wiał|6 +przemieni|prze=mie=ni|6 +przemówił|prze=mó=wił|6 +przeniósł|prze=niósł|6 +przepadła|prze=pa=dła|6 +Przepili|Prze=pi=li|6 +przepomnieć|prze=po=mnieć|6 +przepuści|prze=pu=ści|6 +przepychać|prze=py=chać|6 +przerażających|prze=ra=ża=ją=cych|6 +przeróżnych|prze=róż=nych|6 +przetaczało|prze=ta=cza=ło|6 +przeto|prze=to|6 +przetrzymać|prze=trzy=mać|6 +przewalała|prze=wa=la=ła|6 +przewalały|prze=wa=la=ły|6 +prześpiegi|prze=śpie=gi|6 +przychodzę|przy=cho=dzę|6 +przycichła|przy=ci=chła|6 +przyciszać|przy=ci=szać|6 +przyginał|przy=gi=nał|6 +przygiął|przy=giął|6 +przyjacielstwie|przy=ja=ciel=stwie|6 +przyjacioły|przy=ja=cio=ły|6 +przyjaźnie|przy=jaź=nie|6 +Przyjdzie|Przyj=dzie|6 +przyjrzał|przyj=rzał|6 +przykazywał|przy=ka=zy=wał|6 +przyklęknął|przy=klęk=nął|6 +przymierzać|przy=mie=rzać|6 +przyniesie|przy=nie=sie|6 +przyniesę|przy=nie=sę|6 +przyniewalać|przy=nie=wa=lać|6 +przyodziane|przy=odzia=ne|6 +przyodziać|przy=odziać|6 +przyodziała|przy=odzia=ła|6 +przypiecku|przy=piec=ku|6 +przypominał|przy=po=mi=nał|6 +przystał|przy=stał|6 +przystało|przy=sta=ło|6 +przysłoniła|przy=sło=ni=ła|6 +przytrafić|przy=tra=fić|6 +przytwierdzał|przy=twier=dzał|6 +przytwierdzała|przy=twier=dza=ła|6 +przywarł|przy=warł|6 +przywierała|przy=wie=ra=ła|6 +przyziemnych|przy=ziem=nych|6 +przyłożył|przy=ło=żył|6 +Przyłęka|Przy=łę=ka|6 +przędziwem|przę=dzi=wem|6 +przędzy|przę=dzy|6 +próbując|pró=bu=jąc|6 +psiakrew|psia=krew|6 +pszczelnym|psz=czel=nym|6 +pszczoły|psz=czo=ły|6 +pszenicy|psze=ni=cy|6 +ptaszka|ptasz=ka|6 +ptaszków|ptasz=ków|6 +puszcza|pusz=cza|6 +puszczały|pusz=cza=ły|6 +puszczę|pusz=czę|6 +puściły|pu=ści=ły|6 +pyskiem|py=skiem|6 +pyskuje|py=sku=je|6 +płacił|pła=cił|6 +płakali|pła=ka=li|6 +płakały|pła=ka=ły|6 +płonęły|pło=nę=ły|6 +Płoszki|Płosz=ki|6 +Płoszkową|Płosz=ko=wą|6 +płynie|pły=nie|6 +robaki|ro=ba=ki|6 +robotach|ro=bo=tach|6 +rodzonego|ro=dzo=ne=go|6 +rogate|ro=ga=te|6 +rozchodzili|roz=cho=dzi=li|6 +rozchodził|roz=cho=dził|6 +rozeszły|ro=ze=szły|6 +rozgorzałe|roz=go=rza=łe|6 +rozgorzałymi|roz=go=rza=ły=mi|6 +rozkołysane|roz=ko=ły=sa=ne|6 +rozlewając|roz=le=wa=jąc|6 +Rozmyślała|Roz=my=śla=ła|6 +roznosiło|roz=no=si=ło|6 +rozpaczliwie|roz=pacz=li=wie|6 +rozpaczy|roz=pa=czy|6 +rozpaczą|roz=pa=czą|6 +rozpalonym|roz=pa=lo=nym|6 +rozpozna|roz=po=zna|6 +rozpłakała|roz=pła=ka=ła|6 +roztrzęsiona|roz=trzę=sio=na|6 +rozwodząc|roz=wo=dząc|6 +ruchem|ru=chem|6 +ruchomą|ru=cho=mą|6 +ruszali|ru=sza=li|6 +rzeczach|rze=czach|6 +rzewnie|rzew=nie|6 +rzucali|rzu=ca=li|6 +rzutem|rzu=tem|6 +rzędami|rzę=da=mi|6 +różnościach|róż=no=ściach|6 +rączków|rącz=ków|6 +sadami|sa=da=mi|6 +sadzić|sa=dzić|6 +saniach|sa=niach|6 +saniami|sa=nia=mi|6 +schodzić|scho=dzić|6 +schować|scho=wać|6 +schowała|scho=wa=ła|6 +sennym|sen=nym|6 +siedzeniu|sie=dze=niu|6 +siedząca|sie=dzą=ca|6 +sieroto|sie=ro=to|6 +silniej|sil=niej|6 +siwiły|si=wi=ły|6 +sięgając|się=ga=jąc|6 +skamlała|skam=la=ła|6 +skamlały|skam=la=ły|6 +skarżąc|skar=żąc|6 +skowronkowe|skow=ron=ko=we|6 +skowytem|sko=wy=tem|6 +skończyć|skoń=czyć|6 +skończą|skoń=czą|6 +skropił|skro=pił|6 +skrzypkach|skrzyp=kach|6 +skrzyły|skrzy=ły|6 +skręcał|skrę=cał|6 +skręcie|skrę=cie|6 +smakuje|sma=ku=je|6 +smutki|smut=ki|6 +smutkiem|smut=kiem|6 +smutno|smut=no|6 +smutny|smut=ny|6 +Sołtys|Soł=tys|6 +spadła|spa=dła|6 +spluwał|splu=wał|6 +spoglądali|spo=glą=da=li|6 +spoglądać|spo=glą=dać|6 +spokoić|spo=ko=ić|6 +spokojności|spo=koj=no=ści|6 +sponiewierał|spo=nie=wie=rał|6 +spostrzegła|spo=strze=gła|6 +spotkać|spo=tkać|6 +spozierać|spo=zie=rać|6 +Sprawa|Spra=wa|6 +sprawiedliwie|spra=wie=dli=wie|6 +Sprawiedliwie|Spra=wie=dli=wie|6 +sprawiedliwością|spra=wie=dli=wo=ścią|6 +sprawić|spra=wić|6 +sprawię|spra=wię|6 +sprawił|spra=wił|6 +sprawnie|spraw=nie|6 +spuścił|spu=ścił|6 +spólnie|spól=nie|6 +spółki|spół=ki|6 +spółkę|spół=kę|6 +spłaty|spła=ty|6 +Stachowi|Sta=cho=wi|6 +stajanie|sta=ja=nie|6 +Starszy|Star=szy|6 +staruchy|sta=ru=chy|6 +stawiać|sta=wiać|6 +sterczały|ster=cza=ły|6 +stodołami|sto=do=ła=mi|6 +stodołą|sto=do=łą|6 +stodół|sto=dół|6 +stojące|sto=ją=ce|6 +stojących|sto=ją=cych|6 +stosunku|sto=sun=ku|6 +stołem|sto=łem|6 +strata|stra=ta|6 +strażnik|straż=nik|6 +straży|stra=ży|6 +strwożeni|str=wo=że=ni|6 +strzech|strzech|6 +stróżujące|stró=żu=ją=ce|6 +studnie|stud=nie|6 +studnią|stud=nią|6 +szarej|sza=rej|6 +szarości|sza=ro=ści|6 +szarzały|sza=rza=ły|6 +szczerym|szcze=rym|6 +szczękały|szczę=ka=ły|6 +szerokim|sze=ro=kim|6 +szkodę|szko=dę|6 +szkołą|szko=łą|6 +szmatami|szma=ta=mi|6 +sznury|sznu=ry|6 +szumnie|szum=nie|6 +szydziła|szy=dzi=ła|6 +szykowali|szy=ko=wa=li|6 +Szymkiem|Szym=kiem|6 +szynkwasem|szynk=wa=sem|6 +sądach|są=dach|6 +sędzia|sę=dzia|6 +słodkich|słod=kich|6 +słodkiej|słod=kiej|6 +słodkością|słod=ko=ścią|6 +słoneczny|sło=necz=ny|6 +słuchając|słu=cha=jąc|6 +Słuchali|Słu=cha=li|6 +Słuchała|Słu=cha=ła|6 +słyszy|sły=szy|6 +tamtej|tam=tej|6 +targał|tar=gał|6 +Tereski|Te=re=ski|6 +trusia|tru=sia|6 +trzask|trzask|6 +trzewiki|trze=wi=ki|6 +trzymaj|trzy=maj|6 +tumanach|tu=ma=nach|6 +twojej|two=jej|6 +tygodnia|ty=go=dnia|6 +tylachny|ty=lach=ny|6 +tęskliwe|tę=skli=we|6 +tęsknicy|tę=sk=ni=cy|6 +tęsknie|tę=sk=nie|6 +tęskności|tę=sk=no=ści|6 +tęskność|tę=sk=ność|6 +tłucze|tłu=cze|6 +tłumaczyć|tłu=ma=czyć|6 +tłusty|tłu=sty|6 +ubranie|ubra=nie|6 +uchwalić|uchwa=lić|6 +uciecha|ucie=cha|6 +uciekała|ucie=ka=ła|6 +udźwignie|udźwi=gnie|6 +ukrzywdził|ukrzyw=dził|6 +Ulisia|Uli=sia|6 +uniosła|unio=sła|6 +upadek|upa=dek|6 +uparcie|upar=cie|6 +upominał|upo=mi=nał|6 +uradzi|ura=dzi|6 +uroczyste|uro=czy=ste|6 +urodny|urod=ny|6 +urodzić|uro=dzić|6 +Urzędnik|Urzęd=nik|6 +ustawili|usta=wi=li|6 +utrapień|utra=pień|6 +utrudzony|utru=dzo=ny|6 +utrzymanie|utrzy=ma=nie|6 +uwidzi|uwi=dzi|6 +uwijał|uwi=jał|6 +ułapiło|uła=pi=ło|6 +Wachników|Wach=ni=ków|6 +wagował|wa=go=wał|6 +ważnie|waż=nie|6 +Wczoraj|Wczo=raj|6 +wczorajszej|wczo=raj=szej|6 +weselej|we=se=lej|6 +weselne|we=sel=ne|6 +Widziałem|Wi=dzia=łem|6 +widłami|wi=dła=mi|6 +wieczornych|wie=czor=nych|6 +wiedziały|wie=dzia=ły|6 +wielgachnych|wiel=gach=nych|6 +wielkich|wiel=kich|6 +wierząc|wie=rząc|6 +wilgotne|wil=got=ne|6 +większość|więk=szość|6 +wokoło|wo=ko=ło|6 +wołają|wo=ła=ją|6 +wpatrzona|wpa=trzo=na|6 +wpierając|wpie=ra=jąc|6 +wracać|wra=cać|6 +wraził|wra=ził|6 +wrzasku|wrza=sku|6 +wrzawie|wrza=wie|6 +wrzawy|wrza=wy|6 +wrzeszczeli|wrzesz=cze=li|6 +wrzeszczeć|wrzesz=czeć|6 +wrzątek|wrzą=tek|6 +wsadził|wsa=dził|6 +wstąpiła|wstą=pi=ła|6 +Wszyćko|Wszyć=ko|6 +wybiegając|wy=bie=ga=jąc|6 +wybojach|wy=bo=jach|6 +wybrała|wy=bra=ła|6 +wybuchnęła|wy=buch=nę=ła|6 +wychodziły|wy=cho=dzi=ły|6 +wydała|wy=da=ła|6 +wydało|wy=da=ło|6 +wykrztusiła|wy=krztu=si=ła|6 +wykrzykiwała|wy=krzy=ki=wa=ła|6 +wykręcał|wy=krę=cał|6 +wylazł|wy=lazł|6 +wynosili|wy=no=si=li|6 +wynosić|wy=no=sić|6 +wypadła|wy=pa=dła|6 +wypatruje|wy=pa=tru=je|6 +wypatrując|wy=pa=tru=jąc|6 +wyprawiała|wy=pra=wia=ła|6 +wyprowadził|wy=pro=wa=dził|6 +wypuścił|wy=pu=ścił|6 +wypytywał|wy=py=ty=wał|6 +wyrzekając|wy=rze=ka=jąc|6 +wyschła|wy=schła|6 +wysiedzieć|wy=sie=dzieć|6 +wysokościach|wy=so=ko=ściach|6 +wystraszona|wy=stra=szo=na|6 +wyszły|wy=szły|6 +wytrzyma|wy=trzy=ma|6 +wywartych|wy=war=tych|6 +wywiódł|wy=wiódł|6 +wywodzić|wy=wo=dzić|6 +wywrzeć|wy=wrzeć|6 +wyzdrowiał|wy=zdro=wiał|6 +Wyście|Wy=ście|6 +wyżalić|wy=ża=lić|6 +wzburzona|wzbu=rzo=na|6 +wzburzone|wzbu=rzo=ne|6 +wzgórze|wzgó=rze|6 +Wzieni|Wzie=ni|6 +Wzięła|Wzię=ła|6 +wątpia|wąt=pia|6 +węgieł|wę=gieł|6 +węzełek|wę=ze=łek|6 +własne|wła=sne|6 +włosach|wło=sach|6 +zabawiał|za=ba=wiał|6 +zabierał|za=bie=rał|6 +zabite|za=bi=te|6 +zachodził|za=cho=dził|6 +zachorzał|za=cho=rzał|6 +zachrapał|za=chra=pał|6 +zaczerwienione|za=czer=wie=nio=ne|6 +zaczynało|za=czy=na=ło|6 +zadyszana|za=dy=sza=na|6 +zadzie|za=dzie|6 +zagadać|za=ga=dać|6 +zagadując|za=ga=du=jąc|6 +zajadlej|za=ja=dlej|6 +zajrzy|zaj=rzy|6 +zajrzyj|zaj=rzyj|6 +zajączka|za=jącz=ka|6 +zakatrupię|za=ka=tru=pię|6 +zakolebały|za=ko=le=ba=ły|6 +zakładał|za=kła=dał|6 +zaległo|za=le=gło|6 +zamamrotał|za=mam=ro=tał|6 +zamknął|za=mknął|6 +zamrze|za=mrze|6 +zapachem|za=pa=chem|6 +zapadała|za=pa=da=ła|6 +zapadł|za=padł|6 +zapalili|za=pa=li=li|6 +zapartym|za=par=tym|6 +zapatrzył|za=pa=trzył|6 +zapowiadał|za=po=wia=dał|6 +zapowiedzi|za=po=wie=dzi|6 +zaprzestał|za=prze=stał|6 +zapłacił|za=pła=cił|6 +zarobić|za=ro=bić|6 +zaroiły|za=ro=iły|6 +zarzewia|za=rze=wia|6 +zasiedli|za=sie=dli|6 +zaszczekał|za=szcze=kał|6 +zawarczał|za=war=czał|6 +zawarty|za=war=ty|6 +zawiał|za=wiał|6 +Zawrzyj|Za=wrzyj|6 +zawziął|za=wziął|6 +zawziętości|za=wzię=to=ści|6 +Zawżdy|Za=wż=dy|6 +zaśpiewali|za=śpie=wa=li|6 +zaśpiewała|za=śpie=wa=ła|6 +zbierało|zbie=ra=ło|6 +zdawało|zda=wa=ło|6 +zdrowe|zdro=we|6 +zdumiał|zdu=miał|6 +zebrali|ze=bra=li|6 +zebranie|ze=bra=nie|6 +zechce|ze=chce|6 +zestrachane|ze=stra=cha=ne|6 +zeszedł|ze=szedł|6 +zeszli|ze=szli|6 +zeszły|ze=szły|6 +zginęło|zgi=nę=ło|6 +zgodzić|zgo=dzić|6 +zgromiła|zgro=mi=ła|6 +zielonym|zie=lo=nym|6 +zieloną|zie=lo=ną|6 +zięcia|zię=cia|6 +zjadliwie|zja=dli=wie|6 +zmartwienie|zmar=twie=nie|6 +znalazła|zna=la=zła|6 +zobaczy|zo=ba=czy|6 +zostanie|zo=sta=nie|6 +zrozumiał|zro=zu=miał|6 +zrywały|zry=wa=ły|6 +zwlókł|zwlókł|6 +zwoził|zwo=ził|6 +zwyczajny|zwy=czaj=ny|6 +złotem|zło=tem|6 +łajdusy|łaj=du=sy|6 +łańcuchem|łań=cu=chem|6 +łańcuchu|łań=cu=chu|6 +ścierpieć|ścier=pieć|6 +ścieżaj|ście=żaj|6 +ściszone|ści=szo=ne|6 +śledzie|śle=dzie|6 +śmiałości|śmia=ło=ści|6 +śmielej|śmie=lej|6 +śmiercią|śmier=cią|6 +śmiertelne|śmier=tel=ne|6 +śpiewa|śpie=wa|6 +śpiewają|śpie=wa=ją|6 +śpiewki|śpiew=ki|6 +śpiewów|śpie=wów|6 +świadkach|świad=kach|6 +światełka|świa=teł=ka|6 +światu|świa=tu|6 +światłość|świa=tłość|6 +świetle|świe=tle|6 +świątecznie|świą=tecz=nie|6 +święconego|świę=co=ne=go|6 +Święta|Świę=ta|6 +świętami|świę=ta=mi|6 +świętości|świę=to=ści|6 +źrebak|źre=bak|6 +żarliwie|żar=li=wie|6 +żartował|żar=to=wał|6 +żałosną|ża=ło=sną|6 +Żydowi|Ży=do=wi|6 +żółtym|żół=tym|6 +żółtymi|żół=ty=mi|6 +ambonie|am=bo=nie|5 +Ambroży|Am=bro=ży|5 +baczycie|ba=czy=cie|5 +Balcerków|Bal=cer=ków|5 +beczkę|becz=kę|5 +bezładnie|bez=ład=nie|5 +bełkot|beł=kot|5 +białego|bia=łe=go|5 +biedny|bied=ny|5 +biedotę|bie=do=tę|5 +bieganina|bie=ga=ni=na|5 +biegał|bie=gał|5 +biegała|bie=ga=ła|5 +biegnącej|bie=gną=cej|5 +biegnącą|bie=gną=cą|5 +bielmem|biel=mem|5 +bielone|bie=lo=ne|5 +bijatyki|bi=ja=ty=ki|5 +bladych|bla=dych|5 +bolenia|bo=le=nia|5 +bolesna|bo=le=sna|5 +boskiego|bo=skie=go|5 +brewiarz|bre=wiarz|5 +brzemię|brze=mię|5 +brzózek|brzó=zek|5 +bródkę|bród=kę|5 +budziła|bu=dzi=ła|5 +bujnie|buj=nie|5 +burknął|burk=nął|5 +butach|bu=tach|5 +butelkę|bu=tel=kę|5 +bydlątko|by=dląt=ko|5 +bydłem|by=dłem|5 +Bylicą|By=li=cą|5 +Byliście|By=li=ście|5 +Bójcie|Bój=cie|5 +błyskawica|bły=ska=wi=ca|5 +błyszczący|błysz=czą=cy|5 +całunkami|ca=łun=ka=mi|5 +Chcesz|Chcesz|5 +Chodźmy|Chodź=my|5 +chorobę|cho=ro=bę|5 +chorzał|cho=rzał|5 +chroniąc|chro=niąc|5 +chrzcie|chrzcie|5 +chudziaczek|chu=dzia=czek|5 +chwaci|chwa=ci|5 +chwała|chwa=ła|5 +chwile|chwi=le|5 +chwilą|chwi=lą|5 +chwyciła|chwy=ci=ła|5 +chybciej|chyb=ciej|5 +chybcikiem|chyb=ci=kiem|5 +chyliły|chy=li=ły|5 +chylące|chy=lą=ce|5 +chytał|chy=tał|5 +chłodny|chłod=ny|5 +chłopakom|chło=pa=kom|5 +chłopakowi|chło=pa=ko=wi|5 +chłopski|chłop=ski|5 +chłopskiego|chłop=skie=go|5 +chłopskiej|chłop=skiej|5 +ciekawość|cie=ka=wość|5 +ciemnica|ciem=ni=ca|5 +ciepła|cie=pła|5 +cieszy|cie=szy|5 +ciągnąc|cią=gnąc|5 +Cięgiem|Cię=giem|5 +ciężkiego|cięż=kie=go|5 +cmentarza|cmen=ta=rza|5 +cudzych|cu=dzych|5 +cudzym|cu=dzym|5 +czająco|cza=ją=co|5 +czarny|czar=ny|5 +czarnymi|czar=ny=mi|5 +czasach|cza=sach|5 +czekam|cze=kam|5 +czekanie|cze=ka=nie|5 +czekałam|cze=ka=łam|5 +czekały|cze=ka=ły|5 +czemuś|cze=muś|5 +czemuż|cze=muż|5 +czerwona|czer=wo=na|5 +czworakach|czwo=ra=kach|5 +czynili|czy=ni=li|5 +czyniły|czy=ni=ły|5 +czynności|czyn=no=ści|5 +czysto|czy=sto|5 +czyścu|czy=ś=cu|5 +człowieczy|czło=wie=czy|5 +dalach|da=lach|5 +dawnych|daw=nych|5 +deskami|de=ska=mi|5 +Deszcz|Deszcz|5 +diabeł|dia=beł|5 +dobrocią|do=bro=cią|5 +doczekawszy|do=cze=kaw=szy|5 +doczekał|do=cze=kał|5 +dokumentnie|do=ku=ment=nie|5 +dorznąć|do=rznąć|5 +dorzucał|do=rzu=cał|5 +dostało|do=sta=ło|5 +doszło|do=szło|5 +dotykał|do=ty=kał|5 +dowiedział|do=wie=dział|5 +drapał|dra=pał|5 +drewniany|drew=nia=ny|5 +Drugie|Dru=gie|5 +drwiąco|drwią=co|5 +Drzewa|Drze=wa|5 +drzewie|drze=wie|5 +dufnością|duf=no=ścią|5 +dufność|duf=ność|5 +dusili|du=si=li|5 +dworska|dwor=ska|5 +dworów|dwo=rów|5 +dychanie|dy=cha=nie|5 +dychał|dy=chał|5 +dygować|dy=go=wać|5 +dymiły|dy=mi=ły|5 +dziadku|dziad=ku|5 +dziadówka|dzia=dów=ka|5 +działów|dzia=łów|5 +dzieciska|dzie=ci=ska|5 +dzieciński|dzie=ciń=ski|5 +dziedzicowym|dzie=dzi=co=wym|5 +dziedziczki|dzie=dzicz=ki|5 +dziesiąte|dzie=sią=te|5 +dziesiątku|dzie=siąt=ku|5 +dzieuchom|dzieu=chom|5 +Dzieuchy|Dzieu=chy|5 +dzieuszyne|dzie=uszy=ne|5 +dzikich|dzi=kich|5 +dziwne|dziw=ne|5 +dziwnych|dziw=nych|5 +dziwnym|dziw=nym|5 +dziwowali|dzi=wo=wa=li|5 +dzwonienie|dzwo=nie=nie|5 +dzwonią|dzwo=nią|5 +dzwonić|dzwo=nić|5 +dzwonów|dzwo=nów|5 +dłuższe|dłuż=sze|5 +fajeczkę|fa=jecz=kę|5 +Filipki|Fi=lip=ki|5 +fleciku|fle=ci=ku|5 +frasunki|fra=sun=ki|5 +Fundacja|Fun=da=cja|5 +gadzina|ga=dzi=na|5 +galante|ga=lan=te|5 +gardziele|gar=dzie=le|5 +gardła|gar=dła|5 +garnczek|garn=czek|5 +garnka|garn=ka|5 +garnuszek|gar=nu=szek|5 +gałązek|ga=łą=zek|5 +gdakały|gda=ka=ły|5 +gmerał|gme=rał|5 +gniazda|gniaz=da|5 +gniazdach|gniaz=dach|5 +gniewał|gnie=wał|5 +gorsza|gor=sza|5 +gorzałce|go=rzał=ce|5 +gorącością|go=rą=co=ścią|5 +gorącość|go=rą=cość|5 +gorącym|go=rą=cym|5 +gorącą|go=rą=cą|5 +Gospodarze|Go=spo=da=rze|5 +gospodynię|go=spo=dy=nię|5 +Gołębiów|Go=łę=biów|5 +granuli|gra=nu=li|5 +grdyką|grdy=ką|5 +grobie|gro=bie|5 +groził|gro=ził|5 +grożąc|gro=żąc|5 +grubachny|gru=bach=ny|5 +gruntu|grun=tu|5 +grzbiety|grzbie=ty|5 +gwarem|gwa=rem|5 +gwarów|gwa=rów|5 +gąszczów|gąsz=czów|5 +gębusię|gę=bu=się|5 +gęgoty|gę=go=ty|5 +gęstwy|gę=stwy|5 +gęstych|gę=stych|5 +głodne|głod=ne|5 +głowach|gło=wach|5 +głowiny|gło=wi=ny|5 +głośne|gło=śne|5 +głupiemu|głu=pie=mu|5 +głębin|głę=bin|5 +hukiem|hu=kiem|5 +hukliwie|hu=kli=wie|5 +huknęli|huk=nę=li|5 +huknęły|huk=nę=ły|5 +hurkotał|hur=ko=tał|5 +idących|idą=cych|5 +inszej|in=szej|5 +Jagustynce|Ja=gu=styn=ce|5 +Jagustynkę|Ja=gu=styn=kę|5 +Jakieś|Ja=kieś|5 +jarzące|ja=rzą=ce|5 +jarzących|ja=rzą=cych|5 +jastrzębie|ja=strzę=bie|5 +jazgotliwe|ja=zgo=tli=we|5 +jałowców|ja=łow=ców|5 +jechała|je=cha=ła|5 +jednemu|jed=ne=mu|5 +jedyna|je=dy=na|5 +jedyny|je=dy=ny|5 +jensze|jen=sze|5 +jesienne|je=sien=ne|5 +jesiennych|je=sien=nych|5 +Jesień|Je=sień|5 +Jezusa|Je=zu=sa|5 +jęczały|ję=cza=ły|5 +jękliwy|ję=kli=wy|5 +kalkulował|kal=ku=lo=wał|5 +kamienia|ka=mie=nia|5 +kamionek|ka=mio=nek|5 +kapelusz|ka=pe=lusz|5 +kazali|ka=za=li|5 +kałduny|kał=du=ny|5 +Każdemu|Każ=de=mu|5 +kiełbas|kieł=bas|5 +kilkadziesiąt|kil=ka=dzie=siąt|5 +klepisku|kle=pi=sku|5 +klucze|klu=cze|5 +klątwy|klą=twy|5 +klęczał|klę=czał|5 +klęczek|klę=czek|5 +kobiecych|ko=bie=cych|5 +kolanach|ko=la=nach|5 +kolanami|ko=la=na=mi|5 +kolebać|ko=le=bać|5 +kolebał|ko=le=bał|5 +kolorowych|ko=lo=ro=wych|5 +kominów|ko=mi=nów|5 +komornicy|ko=mor=ni=cy|5 +komorniki|ko=mor=ni=ki|5 +koników|ko=ni=ków|5 +konisko|ko=ni=sko|5 +kopcach|kop=cach|5 +korzeniami|ko=rze=nia=mi|5 +korzeń|ko=rzeń|5 +kostki|kost=ki|5 +kołkami|koł=ka=mi|5 +kołować|ko=ło=wać|5 +kożucha|ko=żu=cha|5 +kreminał|kre=mi=nał|5 +kropidło|kro=pi=dło|5 +krowami|kro=wa=mi|5 +krwawy|krwa=wy|5 +krwawych|krwa=wych|5 +kryjąc|kry=jąc|5 +kryminale|kry=mi=na=le|5 +kryminał|kry=mi=nał|5 +krzach|krzach|5 +krzaki|krza=ki|5 +krzykać|krzy=kać|5 +krzątając|krzą=ta=jąc|5 +krążyły|krą=ży=ły|5 +kręciła|krę=ci=ła|5 +kręciło|krę=ci=ło|5 +kręgiem|krę=giem|5 +którejś|któ=rejś|5 +Kubowa|Ku=bo=wa|5 +kujnął|kuj=nął|5 +kulasa|ku=la=sa|5 +kużdego|kuż=de=go|5 +kwardo|kwar=do|5 +kwietne|kwiet=ne|5 +kępami|kę=pa=mi|5 +kłoniły|kło=ni=ły|5 +kłócili|kłó=ci=li|5 +Kłębem|Kłę=bem|5 +lakudra|la=ku=dra|5 +lampki|lamp=ki|5 +latach|la=tach|5 +latego|la=te=go|5 +lepsza|lep=sza|5 +lepszych|lep=szych|5 +licząca|li=czą=ca|5 +Lipcom|Lip=com|5 +Lipczaków|Lip=cza=ków|5 +litery|li=te=ry|5 +litości|li=to=ści|5 +loboga|lo=bo=ga|5 +lękiem|lę=kiem|5 +machorki|ma=chor=ki|5 +Maciuś|Ma=ciuś|5 +macochą|ma=co=chą|5 +Magdzie|Mag=dzie|5 +majstrował|maj=stro=wał|5 +makiem|ma=kiem|5 +mamrotała|mam=ro=ta=ła|5 +marnacji|mar=na=cji|5 +Marysi|Ma=ry=si|5 +marzenia|ma=rze=nia|5 +marzeń|ma=rzeń|5 +masłem|ma=słem|5 +matczynej|mat=czy=nej|5 +matuli|ma=tu=li|5 +medytować|me=dy=to=wać|5 +miarkuje|miar=ku=je|5 +miasteczka|mia=stecz=ka|5 +miasto|mia=sto|5 +Michała|Mi=cha=ła|5 +mierzi|mier=zi|5 +mieszkania|miesz=ka=nia|5 +mieszkał|miesz=kał|5 +mignęła|mi=gnę=ła|5 +miłowanie|mi=ło=wa=nie|5 +miłował|mi=ło=wał|5 +miłościwy|mi=ło=ści=wy|5 +mocnym|moc=nym|5 +modrawych|mo=dra=wych|5 +modrawą|mo=dra=wą|5 +modrych|mo=drych|5 +modrzały|mo=drza=ły|5 +mogłaby|mo=gła=by|5 +moiściewy|mo=iście=wy|5 +motyczkami|mo=tycz=ka=mi|5 +możemy|mo=że=my|5 +mrocznej|mrocz=nej|5 +mroczno|mrocz=no|5 +mrokiem|mro=kiem|5 +muzykanci|mu=zy=kan=ci|5 +muzyką|mu=zy=ką|5 +mąciło|mą=ci=ło|5 +młodym|mło=dym|5 +młotem|mło=tem|5 +młynarczyka|mły=nar=czy=ka|5 +nabożnym|na=boż=nym|5 +nabrał|na=brał|5 +naczynia|na=czy=nia|5 +nadziei|na=dziei|5 +naglądać|na=glą=dać|5 +nagrzany|na=grza=ny|5 +nagłym|na=głym|5 +najczęściej|naj=czę=ściej|5 +najmilejsza|naj=mi=lej=sza|5 +najmniej|naj=mniej|5 +najpierwej|naj=pier=wej|5 +najspokojniej|naj=spo=koj=niej|5 +największe|naj=więk=sze|5 +największą|naj=więk=szą|5 +namyśle|na=my=śle|5 +naprędce|na=pręd=ce|5 +naradę|na=ra=dę|5 +narobiła|na=ro=bi=ła|5 +Narodzie|Na=ro=dzie|5 +narządzić|na=rzą=dzić|5 +nastawał|na=sta=wał|5 +naszczekiwania|na=szcze=ki=wa=nia|5 +natknąwszy|na=tknąw=szy|5 +nawrócił|na=wró=cił|5 +niebieską|nie=bie=ską|5 +nieboszczyk|nie=bosz=czyk|5 +niedaleczko|nie=da=lecz=ko|5 +Niedługo|Nie=dłu=go|5 +niegdzie|nie=gdzie|5 +niejedni|nie=jed=ni|5 +nienawiści|nie=na=wi=ści|5 +nienawiść|nie=na=wiść|5 +nieodstępnie|nie=od=stęp=nie|5 +niepamięci|nie=pa=mię=ci|5 +niepomiernie|nie=po=mier=nie|5 +nieprzejrzane|nie=przej=rza=ne|5 +nieprzerwanym|nie=prze=rwa=nym|5 +nieprzytomnym|nie=przy=tom=nym|5 +nieskończone|nie=skoń=czo=ne|5 +nieskończonym|nie=skoń=czo=nym|5 +niesporo|nie=spo=ro|5 +nieszczęsna|nie=szczę=sna|5 +nieszczęścia|nie=szczę=ścia|5 +nieszporach|nie=szpo=rach|5 +nieubłaganą|nie=ubła=ga=ną|5 +nieustępliwie|nie=ustę=pli=wie|5 +nieustępliwy|nie=ustę=pli=wy|5 +niewola|nie=wo=la|5 +niezgorsza|nie=zgor=sza|5 +niezgłębioną|nie=zgłę=bio=ną|5 +niezmierną|nie=zmier=ną|5 +nikiej|ni=kiej|5 +nowinki|no=win=ki|5 +Nowoczesna|No=wo=cze=sna|5 +Obaczcie|Obacz=cie|5 +Obaczycie|Oba=czy=cie|5 +Obejrzała|Obej=rza=ła|5 +obrazik|ob=ra=zik|5 +obrazu|ob=ra=zu|5 +obroku|ob=ro=ku|5 +obrosłe|ob=ro=słe|5 +obszedł|ob=szedł|5 +obwisłe|ob=wi=słe|5 +obwisłymi|ob=wi=sły=mi|5 +obłożony|ob=ło=żo=ny|5 +ocierając|ocie=ra=jąc|5 +oczymgnieniu|oczym=gnie=niu|5 +odbierze|od=bie=rze|5 +oddawał|od=da=wał|5 +odejściu|odej=ściu|5 +oderwał|ode=rwał|5 +odgłosy|od=gło=sy|5 +odjechał|od=je=chał|5 +odkrzyknęła|od=krzyk=nę=ła|5 +odmawiać|od=ma=wiać|5 +odmawiał|od=ma=wiał|5 +odprawiała|od=pra=wia=ła|5 +odwracały|od=wra=ca=ły|5 +odzywała|od=zy=wa=ła|5 +odzywały|od=zy=wa=ły|5 +odświętnie|od=święt=nie|5 +oganiać|oga=niać|5 +ogląda|oglą=da|5 +ogniami|ognia=mi|5 +ognisty|ogni=sty|5 +ogrodzenie|ogro=dze=nie|5 +ogromna|ogrom=na|5 +ojcowa|oj=co=wa|5 +ojcowy|oj=co=wy|5 +okolicach|oko=li=cach|5 +okresach|okre=sach|5 +okrwawiony|okrwa=wio=ny|5 +oktawę|okta=wę|5 +okwiat|okwiat|5 +omijali|omi=ja=li|5 +opamiętała|opa=mię=ta=ła|5 +oparcie|opar=cie|5 +opowiadań|opo=wia=dań|5 +oprócz|oprócz|5 +orzydla|orzy=dla|5 +ostaje|osta=je|5 +ostaniesz|osta=niesz|5 +ostatek|osta=tek|5 +ostatniego|ostat=nie=go|5 +ostrym|ostrym|5 +oszroniałych|oszro=nia=łych|5 +otwartych|otwar=tych|5 +otwierając|otwie=ra=jąc|5 +otworzyła|otwo=rzy=ła|5 +ozewrzeć|ozew=rzeć|5 +ozimin|ozi=min|5 +oziminy|ozi=mi=ny|5 +oślepłe|ośle=płe|5 +paczkę|pacz=kę|5 +padając|pa=da=jąc|5 +palmami|pal=ma=mi|5 +pamiętajcie|pa=mię=taj=cie|5 +pamiętam|pa=mię=tam|5 +Panienka|Pa=nien=ka|5 +papierem|pa=pie=rem|5 +parafia|pa=ra=fia|5 +parszywego|par=szy=we=go|5 +parzył|pa=rzył|5 +parzyła|pa=rzy=ła|5 +pasiastych|pa=sia=stych|5 +paskudny|pa=skud=ny|5 +pastwiska|pa=stwi=ska|5 +patrzeli|pa=trze=li|5 +patrzyli|pa=trzy=li|5 +pewnością|pew=no=ścią|5 +pełzały|peł=za=ły|5 +pierun|pie=run|5 +pierzyna|pie=rzy=na|5 +piesku|pie=sku|5 +Pietras|Pie=tras|5 +pijani|pi=ja=ni|5 +pijanica|pi=ja=ni=ca|5 +pijcie|pij=cie|5 +pilnujcie|pil=nuj=cie|5 +pisane|pi=sa=ne|5 +pisarzem|pi=sa=rzem|5 +piskorz|pi=skorz|5 +piszczy|pisz=czy|5 +pięciu|pię=ciu|5 +piękna|pięk=na|5 +Piękny|Pięk=ny|5 +plątała|plą=ta=ła|5 +plątały|plą=ta=ły|5 +pobladły|po=bla=dły|5 +pocałowała|po=ca=ło=wa=ła|5 +pochylając|po=chy=la=jąc|5 +pociągnęli|po=cią=gnę=li|5 +poczciwa|po=czci=wa|5 +poczeka|po=cze=ka|5 +poczerwieniał|po=czer=wie=niał|5 +poczynało|po=czy=na=ło|5 +poczynały|po=czy=na=ły|5 +podatek|po=da=tek|5 +podawał|po=da=wał|5 +podjadł|pod=jadł|5 +Podniesienie|Pod=nie=sie=nie|5 +podnosili|pod=no=si=li|5 +podobna|po=dob=na|5 +podorędziu|po=do=rę=dziu|5 +podrapał|po=dra=pał|5 +podtykała|pod=ty=ka=ła|5 +podzieje|po=dzie=je|5 +podzieję|po=dzie=ję|5 +podzięce|po=dzię=ce|5 +pogadywała|po=ga=dy=wa=ła|5 +pogadywały|po=ga=dy=wa=ły|5 +pogardliwie|po=gar=dli=wie|5 +Pogoda|Po=go=da|5 +pogroza|po=gro=za|5 +pogrozy|po=gro=zy|5 +pogwizdywał|po=gwiz=dy=wał|5 +pogłaskał|po=gła=skał|5 +pojadał|po=ja=dał|5 +Pokażcie|Po=każ=cie|5 +pokosy|po=ko=sy|5 +pokrako|po=kra=ko|5 +pokryte|po=kry=te|5 +pokrywał|po=kry=wał|5 +pokrzykiwał|po=krzy=ki=wał|5 +pokręcił|po=krę=cił|5 +pokutę|po=ku=tę|5 +pokładali|po=kła=da=li|5 +polazł|po=lazł|5 +poleci|po=le=ci|5 +pomagając|po=ma=ga=jąc|5 +pomagało|po=ma=ga=ło|5 +pomarli|po=mar=li|5 +pomarła|po=mar=ła|5 +pomarłych|po=mar=łych|5 +pomiarkowali|po=miar=ko=wa=li|5 +pomiarkuj|po=miar=kuj|5 +pomogły|po=mo=gły|5 +pomstować|po=msto=wać|5 +pomstowała|po=msto=wa=ła|5 +poniechaj|po=nie=chaj|5 +poniechali|po=nie=cha=li|5 +popołudnie|po=po=łu=dnie|5 +poprowadzi|po=pro=wa=dzi|5 +popuścić|po=pu=ścić|5 +portek|por=tek|5 +porwali|po=rwa=li|5 +Porwał|Po=rwał|5 +porywając|po=ry=wa=jąc|5 +porębie|po=rę=bie|5 +postawi|po=sta=wi|5 +postawią|po=sta=wią|5 +postawiła|po=sta=wi=ła|5 +postąpił|po=stą=pił|5 +posypał|po=sy=pał|5 +Poszłabym|Po=szła=bym|5 +posępne|po=sęp=ne|5 +posępnie|po=sęp=nie|5 +posłać|po=słać|5 +posłuchu|po=słu=chu|5 +potrafiła|po=tra=fi=ła|5 +potrzebie|po=trze=bie|5 +potężne|po=tęż=ne|5 +Powiadają|Po=wia=da=ją|5 +Powiadam|Po=wia=dam|5 +Powiadał|Po=wia=dał|5 +Powiedają|Po=wie=da=ją|5 +powiedając|po=wie=da=jąc|5 +Powiedali|Po=wie=da=li|5 +powiedzcie|po=wiedz=cie|5 +powiedzenie|po=wie=dze=nie|5 +Powiedziałem|Po=wie=dzia=łem|5 +powiekami|po=wie=ka=mi|5 +powiesić|po=wie=sić|5 +powiew|po=wiew|5 +powinno|po=win=no|5 +powinny|po=win=ny|5 +powlekła|po=wle=kła|5 +powrósła|po=wró=sła|5 +powstały|po=wsta=ły|5 +pozdrawiał|po=zdra=wiał|5 +poznali|po=zna=li|5 +pozostać|po=zo=stać|5 +pozwalał|po=zwa=lał|5 +pozwolił|po=zwo=lił|5 +pozwolę|po=zwo=lę|5 +połcie|po=łcie|5 +połowę|po=ło=wę|5 +Południe|Po=łu=dnie|5 +pożaru|po=ża=ru|5 +pożywi|po=ży=wi|5 +pradziada|pra=dzia=da|5 +prażyło|pra=ży=ło|5 +proboszczem|pro=bosz=czem|5 +progach|pro=gach|5 +prosiaka|pro=sia=ka|5 +prosięta|pro=się=ta|5 +prosiętami|pro=się=ta=mi|5 +proste|pro=ste|5 +Prosto|Pro=sto|5 +prostowała|pro=sto=wa=ła|5 +prosty|pro=sty|5 +proszalne|pro=szal=ne|5 +proszonym|pro=szo=nym|5 +przebierały|prze=bie=ra=ły|5 +przebrał|prze=brał|5 +przechylił|prze=chy=lił|5 +przecie|prze=cie|5 +przeciągały|prze=cią=ga=ły|5 +przeciągnął|prze=cią=gnął|5 +przeczytał|prze=czy=tał|5 +przednim|przed=nim|5 +przegryźć|prze=gryźć|5 +przejmowały|przej=mo=wa=ły|5 +przejrzyste|przej=rzy=ste|5 +przekładał|prze=kła=dał|5 +przelewa|prze=le=wa|5 +przemawiać|prze=ma=wiać|5 +przemienił|prze=mie=nił|5 +przemogła|prze=mo=gła|5 +przemoże|prze=mo=że|5 +przemyślnie|prze=myśl=nie|5 +przeniesła|prze=nie=sła|5 +przenikliwy|prze=ni=kli=wy|5 +przenosiny|prze=no=si=ny|5 +Przepijcie|Prze=pij=cie|5 +przepiórki|prze=piór=ki|5 +przepomniał|prze=po=mniał|5 +przepomniała|prze=po=mnia=ła|5 +przepraszać|prze=pra=szać|5 +przeraźliwie|prze=raź=li=wie|5 +przerywając|prze=ry=wa=jąc|5 +przeschnie|prze=schnie|5 +przesiadywał|prze=sia=dy=wał|5 +przesiedział|prze=sie=dział|5 +przestała|prze=sta=ła|5 +przetak|prze=tak|5 +Przewrotny|Prze=wrot=ny|5 +przezwiska|prze=zwi=ska|5 +przezwisko|prze=zwi=sko|5 +przełknąć|prze=łknąć|5 +prześmiewał|prze=śmie=wał|5 diff --git a/test/hyphenation_eval/resources/swedish_hyphenation_tests.txt b/test/hyphenation_eval/resources/swedish_hyphenation_tests.txt new file mode 100644 index 0000000000..fde671b132 --- /dev/null +++ b/test/hyphenation_eval/resources/swedish_hyphenation_tests.txt @@ -0,0 +1,5012 @@ +# Hyphenation Test Data +# Source: Uppdrag Hail Mary - Andy Weir.epub +# Language: sv_SE +# Min prefix: 2 +# Min suffix: 2 +# Total words: 5000 +# Format: word | hyphenated_form | frequency_in_source +# +# Hyphenation points are marked with '=' +# Example: Silbentrennung -> Sil=ben=tren=nung +# + +skulle|skul=le|629 +kommer|kom=mer|479 +mycket|myck=et|437 +Flinta|Flin=ta|392 +skeppet|skep=pet|263 +Stratt|Stratt|224 +astrofager|ast=ro=fa=ger|213 +tillbaka|till=ba=ka|206 +behöver|be=hö=ver|193 +jorden|jor=den|167 +håller|hål=ler|161 +kanske|kanske|160 +Varför|Var=för|157 +ungefär|un=ge=fär|139 +astrofagerna|ast=ro=fa=ger=na|135 +fortfarande|fort=fa=ran=de|118 +labbet|lab=bet|108 +aldrig|ald=rig|100 +mindre|mind=re|96 +skärmen|skär=men|96 +tunneln|tun=neln|95 +människor|män=ni=skor|94 +gjorde|gjor=de|93 +problem|pro=blem|91 +igenom|ige=nom|90 +ingenting|ing=en=ting|90 +gånger|gång=er|89 +enkelt|en=kelt|88 +första|förs=ta|88 +nästan|näs=tan|88 +precis|pre=cis|87 +huvudet|hu=vu=det|86 +sitter|sit=ter|85 +tittar|tit=tar|85 +längre|läng=re|83 +kontrollrummet|kon=troll=rum=met|82 +tänker|tän=ker|82 +faktiskt|fak=tiskt|81 +grader|gra=der|81 +sätter|sät=ter|81 +gången|gång=en|80 +luftslussen|luft=slus=sen|79 +energi|ener=gi|78 +känner|kän=ner|78 +skrovet|skro=vet|78 +väggen|väg=gen|78 +förmodligen|för=mod=li=gen|77 +ligger|lig=ger|77 +Objekt|Ob=jekt|77 +Kanske|Kanske|76 +åtminstone|åt=min=sto=ne|76 +rymden|rym=den|75 +händer|hän=der|73 +bättre|bätt=re|72 +Flintas|Flin=tas|72 +svävar|svä=var|72 +taumöbor|tau=mö=bor|71 +tillräckligt|till=räck=ligt|71 +verkligen|verk=li=gen|71 +börjar|bör=jar|70 +varför|var=för|70 +alltid|all=tid|69 +fungerar|fun=ge=rar|69 +tvungen|tvung=en|69 +handen|han=den|68 +använder|an=vän=der|67 +sekunder|se=kun=der|67 +timmar|tim=mar|67 +Förmodligen|För=mod=li=gen|66 +omkring|om=kring|66 +någonting|nå=gon=ting|65 +eridier|eri=di=er|64 +förstås|för=stås|64 +mellan|mel=lan|64 +rummet|rum=met|64 +därför|där=för|63 +händerna|hän=der=na|63 +snabbt|snabbt|63 +xenonit|xe=no=nit|63 +Adrian|Ad=ri=an|62 +använda|an=vän=da|62 +gravitation|gra=vi=ta=tion|62 +procent|pro=cent|62 +betyder|be=ty=der|60 +väldigt|väl=digt|60 +eftersom|ef=ter=som|59 +frågade|frå=ga=de|59 +minuter|mi=nu=ter|59 +vatten|vat=ten|59 +kilometer|ki=lo=me=ter|58 +öppnar|öpp=nar|58 +befinner|be=fin=ner|56 +bränsle|brän=sle|56 +luften|luf=ten|56 +stället|stäl=let|56 +ögonblick|ögon=blick|54 +försöker|för=sö=ker|53 +golvet|gol=vet|53 +ögonen|ögo=nen|53 +förstår|för=står|52 +hastighet|has=tig=het|52 +lägger|läg=ger|52 +koldioxid|kol=di=ox=id|51 +motorerna|mo=to=rer=na|51 +större|stör=re|51 +ljuset|lju=set|50 +verkar|ver=kar|49 +atmosfär|at=mo=sfär|48 +själva|själ=va|48 +astrofag|ast=ro=fag|47 +hittar|hit=tar|47 +närmare|när=ma=re|47 +ombord|om=bord|47 +stjärna|stjär=na|47 +system|sys=tem|47 +datorn|da=torn|46 +fullständigt|full=stän=digt|46 +fungera|fun=ge=ra|46 +luckan|luck=an|46 +någonsin|nå=gon=sin|45 +samtidigt|sam=ti=digt|45 +särskilt|sär=skilt|45 +trycker|tryck=er|45 +varandra|var=and=ra|45 +planeten|pla=ne=ten|44 +sovsalen|sov=sa=len|44 +bordet|bor=det|43 +dessutom|dess=utom|43 +vidare|vi=da=re|43 +allihop|al=li=hop|42 +behövde|be=höv=de|42 +information|in=for=ma=tion|42 +planet|pla=net|42 +skeppets|skep=pets|42 +överleva|över=le=va|42 +Dimitrij|Di=mit=rij|41 +rymdskepp|rymd=skepp|41 +senare|se=na=re|41 +vilken|vil=ken|41 +DuBois|Du=Bo=is|40 +sekund|se=kund|40 +Uppdrag|Upp=drag|40 +forskare|fors=ka=re|39 +klarar|kla=rar|39 +Petrovaskopet|Pe=tro=vas=ko=pet|39 +allting|all=ting|38 +hoppas|hop=pas|38 +klättrar|klätt=rar|38 +Mycket|Myck=et|38 +omloppsbana|om=lopps=ba=na|38 +skalbaggarna|skal=bag=gar=na|38 +framför|fram=för|37 +hantera|han=te=ra|37 +Skeppet|Skep=pet|37 +sträcker|sträck=er|37 +säkert|sä=kert|37 +extremt|ex=tremt|36 +faller|fal=ler|36 +framåt|fram=åt|36 +hundra|hun=dra|36 +Lokken|Lok=ken|36 +långsamt|lång=samt|36 +snabbare|snab=ba=re|36 +tidigare|ti=di=ga=re|36 +tunnel|tun=nel|36 +väntar|vän=tar|36 +Celsius|Cel=si=us|35 +doktor|dok=tor|35 +finnas|fin=nas|35 +Iljuchina|Iljuchi=na|35 +taumöborna|tau=mö=bor=na|35 +alltihop|allt=i=hop|34 +atmosfären|at=mo=sfä=ren|34 +behöva|be=hö=va|34 +består|be=står|34 +besättningen|be=sätt=ning=en|34 +centimeter|cen=ti=me=ter|34 +cylindern|cy=lin=dern|34 +dörren|dör=ren|34 +Ingenting|Ing=en=ting|34 +mitten|mit=ten|34 +någonstans|nå=gon=stans|34 +stolen|sto=len|34 +stänger|stäng=er|34 +Taumöba|Tau=mö=ba|34 +tittade|tit=ta=de|34 +världen|värl=den|34 +armarna|ar=mar=na|33 +blivit|bli=vit|33 +Eridier|Eri=di=er|33 +fortsätter|fort=sät=ter|33 +Precis|Pre=cis|33 +vilket|vil=ket|33 +Astrofagerna|Ast=ro=fa=ger=na|32 +Förstår|För=står|32 +jordens|jor=dens|32 +kedjan|ked=jan|32 +kommit|kom=mit|32 +miljoner|mil=jo=ner|32 +mänskligheten|mänsk=lig=he=ten|32 +möjligt|möj=ligt|32 +Petrovalinjen|Pe=tro=va=lin=jen|32 +systemet|sys=te=met|32 +Adrians|Ad=ri=ans|31 +dräkten|dräk=ten|31 +konstant|kon=stant|31 +resten|res=ten|31 +trodde|trod=de|31 +alldeles|all=de=les|30 +behövs|be=hövs|30 +experiment|ex=pe=ri=ment|30 +förstå|för=stå|30 +infraröda|in=fra=rö=da|30 +lyckas|lyck=as|30 +pekade|pe=ka=de|30 +Skulle|Skul=le|30 +varenda|var=en=da|30 +vetenskap|ve=ten=skap|30 +bredvid|bred=vid|29 +handlar|hand=lar|29 +material|ma=te=ri=al|29 +räcker|räck=er|29 +släpper|släp=per|29 +sättet|sät=tet|29 +sönder|sön=der|29 +Doktor|Dok=tor|28 +eridiska|eri=dis=ka|28 +griper|gri=per|28 +klockan|klock=an|28 +kollar|kol=lar|28 +riktigt|rik=tigt|28 +stegen|ste=gen|28 +arbeta|ar=be=ta|27 +flesta|fles=ta|27 +frågar|frå=gar|27 +heller|hel=ler|27 +människa|män=ni=ska|27 +perfekt|per=fekt|27 +tillverka|till=ver=ka|27 +trycket|tryck=et|27 +vetenskapliga|ve=ten=skap=li=ga|27 +ytterligare|yt=ter=li=ga=re|27 +annars|an=nars|26 +förmodar|för=mo=dar|26 +knackar|knack=ar|26 +kroppen|krop=pen|26 +minsta|mins=ta|26 +Människor|Män=ni=skor|26 +nickade|nick=a=de|26 +senaste|se=nas=te|26 +vänster|väns=ter|26 +försöka|för=sö=ka|25 +gillar|gil=lar|25 +infrarött|in=fra=rött|25 +klocka|klocka|25 +luftsluss|luft=sluss|25 +lämnar|läm=nar|25 +sekunden|se=kun=den|25 +spindriften|spindrif=ten|25 +temperaturen|tem=pe=ra=tu=ren|25 +ansiktet|an=sik=tet|24 +avstånd|av=stånd|24 +definitivt|de=fi=ni=tivt|24 +egentligen|egent=li=gen|24 +eridisk|eri=disk|24 +gravitationen|gra=vi=ta=tio=nen|24 +hennes|hen=nes|24 +hälften|hälf=ten|24 +klotet|klo=tet|24 +livsuppehållande|livs=up=pe=hål=lan=de|24 +motorer|mo=to=rer|24 +månader|må=na=der|24 +omedelbart|ome=del=bart|24 +papper|pap=per|24 +sticker|stick=er|24 +största|störs=ta|24 +tankarna|tan=kar=na|24 +Vilket|Vil=ket|24 +väntat|vän=tat|24 +Astrofager|Ast=ro=fa=ger|23 +diameter|dia=me=ter|23 +följer|föl=jer|23 +levande|le=van=de|23 +lämnade|läm=na=de|23 +måttbandet|mått=ban=det|23 +normalt|nor=malt|23 +närheten|när=he=ten|23 +personer|per=so=ner|23 +rotera|ro=te=ra|23 +stjärnor|stjär=nor|23 +tanken|tan=ken|23 +Ungefär|Un=ge=fär|23 +utrustning|ut=rust=ning|23 +verket|ver=ket|23 +visste|viss=te|23 +Allting|All=ting|22 +ammoniak|am=mo=ni=ak|22 +avgjort|av=gjort|22 +axlarna|ax=lar=na|22 +behållare|be=hål=la=re|22 +färdas|fär=das|22 +färden|fär=den|22 +förklara|för=kla=ra|22 +försvinner|för=svin=ner|22 +ganska|gans=ka|22 +Kommer|Kom=mer|22 +kontrollerar|kon=trol=le=rar|22 +plockar|plock=ar|22 +provet|pro=vet|22 +roterar|ro=te=rar|22 +rymddräkten|rymd=dräk=ten|22 +räknar|räk=nar|22 +skakade|ska=ka=de|22 +sängen|säng=en|22 +vinkel|vin=kel|22 +Åtminstone|Åt=min=sto=ne|22 +överallt|över=allt|22 +besättning|be=sätt=ning|21 +betydligt|be=tyd=ligt|21 +celler|cel=ler|21 +dåligt|då=ligt|21 +genast|ge=nast|21 +handtag|hand=tag|21 +intressant|in=tres=sant|21 +lättare|lät=ta=re|21 +magnetfält|mag=net=fält|21 +omöjligt|omöj=ligt|21 +plötsligt|plöts=ligt|21 +slutar|slu=tar|21 +stirrade|stir=ra=de|21 +sådant|så=dant|21 +tillsammans|till=sam=mans|21 +tvungna|tvung=na|21 +visade|vi=sa=de|21 +vrider|vri=der|21 +andetag|an=de=tag|20 +befann|be=fann|20 +bokstavligen|bok=stav=li=gen|20 +började|bör=ja=de|20 +Dessutom|Dess=utom|20 +innehåller|in=ne=hål=ler|20 +knappt|knappt|20 +känsla|käns=la|20 +lösning|lös=ning|20 +misstänker|miss=tän=ker|20 +närmaste|när=mas=te|20 +planeter|pla=ne=ter|20 +snurrar|snur=rar|20 +strålning|strål=ning|20 +upprepar|upp=re=par|20 +utanför|ut=an=för|20 +vakuum|va=ku=um|20 +vänder|vän=der|20 +åstadkomma|åstad=kom=ma|20 +blicken|blick=en|19 +direkt|di=rekt|19 +energin|ener=gin|19 +främmande|främ=man=de|19 +historia|his=to=ria|19 +hittade|hit=ta=de|19 +innebär|in=ne=bär|19 +kamera|ka=me=ra|19 +kontrollera|kon=trol=le=ra|19 +likadant|li=ka=dant|19 +lyckades|lyck=a=des|19 +pilotstolen|pi=lot=sto=len|19 +rejält|re=jält|19 +rymddräkt|rymd=dräkt|19 +sjunker|sjun=ker|19 +stanna|stan=na|19 +starkt|starkt|19 +temperatur|tem=pe=ra=tur|19 +Trevärlden|Tre=värl=den|19 +acceleration|ac=ce=le=ra=tion|18 +använde|an=vän=de|18 +arbetar|ar=be=tar|18 +behållaren|be=hål=la=ren|18 +början|bör=jan|18 +centrifug|cen=tri=fug|18 +Därför|Där=för|18 +Eridani|Eri=da=ni|18 +fortplantar|fort=plan=tar|18 +hjälpa|hjäl=pa|18 +liksom|lik=som|18 +ljusår|ljus=år|18 +lutade|lu=ta=de|18 +metall|me=tall|18 +mumlar|mum=lar|18 +pannan|pan=nan|18 +problemet|pro=ble=met|18 +rimligt|rim=ligt|18 +teknik|tek=nik|18 +uppenbart|uppen=bart|18 +utvecklats|ut=veck=lats|18 +finger|fing=er|17 +förresten|för=res=ten|17 +förseglar|för=seg=lar|17 +hastigheten|has=tig=he=ten|17 +hittat|hit=tat|17 +hämtar|häm=tar|17 +Intressant|In=tres=sant|17 +kallas|kal=las|17 +marken|mar=ken|17 +resultat|re=sul=tat|17 +ryckte|ryck=te|17 +Shapiro|Sha=pi=ro|17 +skakar|ska=kar|17 +stannar|stan=nar|17 +starkare|star=ka=re|17 +stirrar|stir=rar|17 +talade|ta=la=de|17 +uppdraget|upp=dra=get|17 +varken|var=ken|17 +Vilken|Vil=ken|17 +vinklar|vink=lar|17 +vänner|vän=ner|17 +xenoniten|xe=no=ni=ten|17 +absolut|ab=so=lut|16 +Alltså|Allt=så|16 +bränslet|brän=slet|16 +driver|dri=ver|16 +därefter|där=ef=ter|16 +Dåligt|Då=ligt|16 +fingrar|fing=rar|16 +fingret|fing=ret|16 +flyttar|flyt=tar|16 +fortplanta|fort=plan=ta|16 +fungerade|fun=ge=ra=de|16 +försökte|för=sök=te|16 +genomskinliga|ge=nom=skin=li=ga|16 +hittills|hit=tills|16 +informationen|in=for=ma=tio=nen|16 +knappast|knap=past|16 +kvävet|kvä=vet|16 +livsform|livs=form|16 +munnen|mun=nen|16 +pansaret|pan=sa=ret|16 +praktiskt|prak=tiskt|16 +pratar|pra=tar|16 +skillnad|skill=nad|16 +skriver|skri=ver|16 +snarare|sna=ra=re|16 +solsystem|sol=sys=tem|16 +stjärnan|stjär=nan|16 +studsar|stud=sar|16 +svarta|svar=ta|16 +sådana|så=da=na|16 +träffa|träf=fa|16 +verktyg|verk=tyg|16 +äntligen|änt=li=gen|16 +återvänder|åter=vän=der|16 +atmosfärer|at=mo=sfä=rer|15 +beredd|be=redd|15 +bilden|bil=den|15 +centrifugen|cen=tri=fu=gen|15 +Datorn|Da=torn|15 +Eftersom|Ef=ter=som|15 +experimentet|ex=pe=ri=men=tet|15 +fortsatte|fort=sat=te|15 +föremål|fö=re=mål|15 +gammal|gam=mal|15 +George|Ge=or=ge|15 +glaset|gla=set|15 +gäller|gäl=ler|15 +jordiska|jor=dis=ka|15 +kallar|kal=lar|15 +kinesiska|ki=ne=sis=ka|15 +laboratoriebänken|la=bo=ra=to=rie=bän=ken|15 +linjen|lin=jen|15 +längst|längst|15 +mängder|mäng=der|15 +naturligtvis|na=tur=ligt=vis|15 +Någonting|Nå=gon=ting|15 +ordentligt|or=dent=ligt|15 +prover|pro=ver|15 +självmordsuppdrag|själv=mordsupp=drag|15 +skicka|skicka|15 +slussen|slus=sen|15 +smälta|smäl=ta|15 +studera|stu=de=ra|15 +ställer|stäl=ler|15 +Taumöborna|Tau=mö=bor=na|15 +trettio|tret=tio|15 +tycker|tyck=er|15 +uppför|upp=för|15 +uppleva|upp=le=va|15 +upptäcka|upp=täcka|15 +upptäckte|upp=täck=te|15 +utstrålar|ut=strå=lar|15 +vaknar|vak=nar|15 +ögonblicket|ögon=blick=et|15 +Armarna|Ar=mar=na|14 +besättningsdelen|be=sätt=nings=de=len|14 +börjat|bör=jat|14 +diagram|dia=gram|14 +elever|ele=ver|14 +enligt|en=ligt|14 +flyger|fly=ger|14 +framsteg|fram=steg|14 +frågor|frå=gor|14 +förseglade|för=seg=la=de|14 +försök|för=sök|14 +generatorn|ge=ne=ra=torn|14 +hejdar|hej=dar|14 +hjärna|hjär=na|14 +Jorden|Jor=den|14 +kontroller|kon=trol=ler|14 +kräver|krä=ver|14 +laptop|lap=top|14 +Leclerc|Leclerc|14 +millimeter|mil=li=me=ter|14 +minskar|mins=kar|14 +mänskliga|mänsk=li=ga|14 +neutriner|ne=u=tri=ner|14 +objekt|ob=jekt|14 +panelen|pa=ne=len|14 +prickarna|prick=ar=na|14 +primära|pri=mä=ra|14 +princip|prin=cip|14 +provtagaren|prov=ta=ga=ren|14 +rullar|rul=lar|14 +räckte|räck=te|14 +Självklart|Själv=klart|14 +skaffa|skaf=fa|14 +spelar|spe=lar|14 +stabil|sta=bil|14 +stjärnorna|stjär=nor=na|14 +stoppuret|stopp=uret|14 +stämmer|stäm=mer|14 +svarar|sva=rar|14 +svaret|sva=ret|14 +Taumöbor|Tau=mö=bor|14 +tredje|tred=je|14 +upplever|upp=le=ver|14 +utomjordiska|ut=om=jor=dis=ka|14 +vinkar|vin=kar|14 +väggarna|väg=gar=na|14 +världens|värl=dens|14 +öppnade|öpp=na=de|14 +accelererar|ac=ce=le=re=rar|13 +alltså|allt=så|13 +aluminium|alu=mi=ni=um|13 +anteckningar|an=teck=ning=ar|13 +Astrofag|Ast=ro=fag|13 +astrofagernas|ast=ro=fa=ger=nas|13 +astronauter|ast=ro=nau=ter|13 +cirkel|cir=kel|13 +externa|ex=ter=na|13 +fantastiskt|fan=tas=tiskt|13 +förrän|förr=än|13 +förtjust|för=tjust|13 +förvissa|för=vis=sa|13 +gesten|ges=ten|13 +gjorda|gjor=da|13 +handtaget|hand=ta=get|13 +kameran|ka=me=ran|13 +kontrollerna|kon=trol=ler=na|13 +ljudet|lju=det|13 +mikron|mik=ron|13 +mikroskopet|mik=ro=sko=pet|13 +misstag|miss=tag|13 +normala|nor=ma=la|13 +nummer|num=mer|13 +nödvändigt|nöd=vän=digt|13 +paddan|pad=dan|13 +Petrovafrekvensen|Pe=tro=va=f=re=kven=sen|13 +platta|plat=ta|13 +Projekt|Pro=jekt|13 +prylar|pry=lar|13 +ryggen|ryg=gen|13 +rymdpromenad|rymd=pro=me=nad|13 +rörelse|rö=rel=se|13 +slutet|slu=tet|13 +solens|so=lens|13 +sonden|son=den|13 +spänner|spän=ner|13 +stoppar|stop=par|13 +ställe|stäl=le|13 +svarade|sva=ra=de|13 +timmarna|tim=mar=na|13 +ursprungliga|ur=sprung=li=ga|13 +Ursäkta|Ur=säk=ta|13 +utveckla|ut=veck=la|13 +vinschen|vin=schen|13 +väntade|vän=ta=de|13 +våglängder|våg=läng=der|13 +önskar|öns=kar|13 +Allihop|Al=li=hop|12 +avgöra|av=gö=ra|12 +bestämt|be=stämt|12 +botten|bot=ten|12 +bubbla|bubb=la|12 +diagrammet|dia=gram=met|12 +engelska|eng=els=ka|12 +Enligt|En=ligt|12 +enormt|enormt|12 +fattar|fat=tar|12 +flytande|fly=tan=de|12 +fönster|föns=ter|12 +fönstret|fönst=ret|12 +förklarar|för=kla=rar|12 +förseglad|för=seg=lad|12 +gissar|gis=sar|12 +grimas|gri=mas|12 +hangarfartyg|han=gar=far=tyg|12 +hänger|häng=er|12 +iakttar|iakt=tar|12 +klarade|kla=ra=de|12 +knyter|kny=ter|12 +minska|mins=ka|12 +pumpar|pum=par|12 +påminner|på=min=ner|12 +riktad|rik=tad|12 +rotation|ro=ta=tion|12 +räknade|räk=na=de|12 +självklart|själv=klart|12 +skalbagge|skal=bag=ge|12 +skärmar|skär=mar|12 +strunt|strunt|12 +tecknade|teck=na=de|12 +tilltalande|till=ta=lan=de|12 +tjocka|tjocka|12 +tänkbara|tänk=ba=ra|12 +utomjordisk|ut=om=jor=disk|12 +vänstra|vänst=ra|12 +öppnas|öpp=nas|12 +överst|överst|12 +absurt|ab=surt|11 +amerikanska|ame=ri=kans=ka|11 +anledning|an=led=ning|11 +annorlunda|an=nor=lun=da|11 +ansikte|an=sik=te|11 +använt|an=vänt|11 +apparat|ap=pa=rat|11 +arbete|ar=be=te|11 +ArcLight|Ar=c=Light|11 +atmosfärers|at=mo=sfä=rers|11 +bibehålla|bi=be=hål=la|11 +bränsletankar|brän=sle=tan=kar|11 +byggde|bygg=de|11 +drämmer|dräm=mer|11 +fortsätta|fort=sät=ta|11 +fundera|fun=de=ra|11 +funderar|fun=de=rar|11 +följande|föl=jan=de|11 +förblir|för=blir|11 +generator|ge=ne=ra=tor|11 +genomskinlig|ge=nom=skin=lig|11 +handlade|hand=la=de|11 +Herregud|Her=re=gud|11 +intelligens|in=tel=li=gens|11 +komplicerat|kom=pli=ce=rat|11 +konstruerat|kon=stru=e=rat|11 +korrekt|kor=rekt|11 +kraften|kraf=ten|11 +kvalificerade|kva=li=fi=ce=ra=de|11 +lagrar|lag=rar|11 +livsformer|livs=for=mer|11 +lyckats|lyck=ats|11 +lämnat|läm=nat|11 +länkar|län=kar|11 +miljarder|mil=jar=der|11 +mittväggen|mitt=väg=gen|11 +nedför|ned=för|11 +normal|nor=mal|11 +ordning|ord=ning|11 +overallen|ove=ral=len|11 +partiklar|par=tik=lar|11 +position|po=si=tion|11 +riktning|rikt=ning|11 +rycker|ryck=er|11 +ryggskölden|rygg=sköl=den|11 +Ryland|Ry=land|11 +skruvar|skru=var|11 +sliter|sli=ter|11 +spaken|spa=ken|11 +suckar|suck=ar|11 +taumöba|tau=mö=ba|11 +tjugosex|tju=go=sex|11 +torkar|tor=kar|11 +tydligen|tyd=li=gen|11 +undrar|und=rar|11 +upphör|upp=hör|11 +upptäcker|upp=täck=er|11 +utomjordingar|ut=om=jor=ding=ar|11 +utomjordiskt|ut=om=jor=diskt|11 +verkade|ver=ka=de|11 +verkligt|verk=ligt|11 +vickar|vick=ar|11 +viftar|vif=tar|11 +Xenonit|Xe=no=nit|11 +Alltihop|Allt=i=hop|10 +automatiskt|au=to=ma=tiskt|10 +avståndet|av=stån=det|10 +befinna|be=fin=na|10 +bestämmer|be=stäm=mer|10 +betyda|be=ty=da|10 +bollen|bol=len|10 +bröstet|brös=tet|10 +Bättre|Bätt=re|10 +cylinder|cy=lin=der|10 +decimeter|de=ci=me=ter|10 +dragkraft|drag=kraft|10 +enbart|en=bart|10 +enheter|en=he=ter|10 +enorma|enor=ma|10 +eridiskt|eri=diskt|10 +femtio|fem=tio|10 +ficklampa|fick=lam=pa|10 +fjorton|fjor=ton|10 +glider|gli=der|10 +gnider|gni=der|10 +graders|gra=ders|10 +harklade|hark=la=de|10 +högsta|högs=ta|10 +ingenjör|in=gen=jör|10 +instrument|in=stru=ment|10 +intelligenta|in=tel=li=gen=ta|10 +jobbar|job=bar|10 +Jösses|Jös=ses|10 +kanten|kan=ten|10 +klättra|klätt=ra|10 +kvinna|kvin=na|10 +Labbet|Lab=bet|10 +livlinan|liv=li=nan|10 +ljushastigheten|ljus=h=as=tig=he=ten|10 +mackapären|mack=a=pä=ren|10 +mellanväggen|mel=lan=väg=gen|10 +mikroskop|mik=ro=skop|10 +miljon|mil=jon|10 +mitokondrier|mi=to=kond=ri=er|10 +motorn|mo=torn|10 +mänsklig|mänsk=lig|10 +möjliga|möj=li=ga|10 +mörker|mör=ker|10 +nuvarande|nu=va=ran=de|10 +närvarande|när=va=ran=de|10 +objektglas|ob=jekt=glas|10 +odlingstankarna|od=lingstan=kar=na|10 +område|om=rå=de|10 +området|om=rå=det|10 +plockade|plock=a=de|10 +processen|pro=ces=sen|10 +projektet|pro=jek=tet|10 +resultatet|re=sul=ta=tet|10 +riskera|ris=ke=ra|10 +räknat|räk=nat|10 +sjunka|sjun=ka|10 +skador|ska=dor|10 +skickade|skick=a=de|10 +skälet|skä=let|10 +skärmarna|skär=mar=na|10 +slippa|slip=pa|10 +släppte|släpp=te|10 +spindrift|spindrift|10 +stilen|sti=len|10 +symbolen|sym=bo=len|10 +tankar|tan=kar|10 +tejpar|tej=par|10 +testade|tes=ta=de|10 +tillfället|till=fäl=let|10 +tillverkade|till=ver=ka=de|10 +tillverkar|till=ver=kar|10 +tretton|tret=ton|10 +ungarna|ung=ar=na|10 +utrymmet|ut=rym=met|10 +vanligt|van=ligt|10 +Varenda|Var=en=da|10 +varmare|var=ma=re|10 +vattnet|vatt=net|10 +vinkeln|vin=keln|10 +väljer|väl=jer|10 +värmen|vär=men|10 +våglängd|våg=längd|10 +återgår|åter=går|10 +absorberar|ab=sor=be=rar|9 +alternativ|al=ter=na=tiv|9 +amerikansk|ame=ri=kansk|9 +Antingen|An=ting=en|9 +apropå|apro=på|9 +bekräftar|be=kräf=tar|9 +beredda|be=red=da|9 +besättningskamrater|be=sätt=nings=kam=ra=ter|9 +blinkar|blin=kar|9 +blängde|bläng=de|9 +Browne|Brow=ne|9 +chansen|chan=sen|9 +Cylindern|Cy=lin=dern|9 +därifrån|där=i=från|9 +effektivt|ef=fek=tivt|9 +eridierna|eri=di=er=na|9 +fallet|fal=let|9 +flyttade|flyt=ta=de|9 +frekvenser|fre=kven=ser|9 +fyller|fyl=ler|9 +fyrtio|fyr=tio|9 +förhållande|för=hål=lan=de|9 +förrådet|för=rå=det|9 +förrådsutrymmet|för=råds=ut=rym=met|9 +försiktigt|för=sik=tigt|9 +fötter|föt=ter|9 +generation|ge=ne=ra=tion|9 +hexagonen|hexa=go=nen|9 +hållet|hål=let|9 +hårdare|hår=da=re|9 +hörnet|hör=net|9 +identiska|iden=tis=ka|9 +imponerande|im=po=ne=ran=de|9 +irriterande|ir=ri=te=ran=de|9 +jobbet|job=bet|9 +jordisk|jor=disk|9 +justerar|ju=ste=rar|9 +klickar|klick=ar|9 +klorna|klor=na|9 +kläder|klä=der|9 +kompis|kom=pis|9 +kontakten|kon=tak=ten|9 +kontroll|kon=troll|9 +kryper|kry=per|9 +laboratorium|la=bo=ra=to=ri=um|9 +ljusets|lju=sets|9 +lossar|los=sar|9 +läcker|läck=er|9 +lärare|lä=ra=re|9 +långsammare|lång=sam=ma=re|9 +medvetslös|med=vets=lös|9 +miniodlingarna|mi=ni=od=ling=ar=na|9 +Minsann|Min=sann|9 +modell|mo=dell|9 +människorna|män=ni=skor=na|9 +mänsklighetens|mänsk=lig=he=tens|9 +måltid|mål=tid|9 +närmast|när=mast|9 +Nästan|Näs=tan|9 +observera|ob=ser=ve=ra|9 +oerhört|oer=hört|9 +omloppsbanan|om=lopps=ba=nan|9 +omsorgsfullt|om=sorgs=fullt|9 +organismer|or=ga=nis=mer|9 +otroligt|otro=ligt|9 +pansar|pan=sar|9 +Petrovalinje|Pe=tro=va=lin=je|9 +placerade|pla=ce=ra=de|9 +Plötsligt|Plöts=ligt|9 +reagerar|re=a=ge=rar|9 +Redell|Re=dell|9 +relativt|re=la=tivt|9 +risken|ris=ken|9 +risker|ris=ker|9 +rotationen|ro=ta=tio=nen|9 +ryssarna|rys=sar=na|9 +samlar|sam=lar|9 +samtal|sam=tal|9 +senast|se=nast|9 +skjuter|skju=ter|9 +slumpmässigt|slump=mäs=sigt|9 +snurra|snur=ra|9 +starka|star=ka|9 +status|sta=tus|9 +stönar|stö=nar|9 +säkerhets|sä=ker=hets|9 +Tunneln|Tun=neln|9 +tunnelväggen|tun=nel=väg=gen|9 +tyckte|tyck=te|9 +uppgift|upp=gift|9 +uppgiften|upp=gif=ten|9 +uppriktigt|upp=rik=tigt|9 +upptäckt|upp=täckt|9 +utomjording|ut=om=jor=ding|9 +utrymme|ut=rym=me|9 +utvecklas|ut=veck=las|9 +varelse|va=rel=se|9 +veckor|veck=or|9 +vetenskaplig|ve=ten=skap=lig|9 +viktigaste|vik=ti=gas=te|9 +yttersta|yt=ters=ta|9 +återstående|åter=stå=en=de|9 +återvända|åter=vän=da|9 +allvar|all=var|8 +ansträngning|an=sträng=ning|8 +Antarktis|Ant=ark=tis|8 +atomer|ato=mer|8 +Bajkonur|Baj=ko=nur|8 +behålla|be=hål=la|8 +behållarna|be=hål=lar=na|8 +biologi|bio=lo=gi|8 +brinna|brin=na|8 +bränsletankarna|brän=sle=tan=kar=na|8 +dagarna|da=gar=na|8 +effekt|ef=fekt|8 +elektricitet|el=ekt=ri=ci=tet|8 +enastående|ena=stå=en=de|8 +Faktiskt|Fak=tiskt|8 +farligt|far=ligt|8 +fjärde|fjär=de|8 +flytta|flyt=ta|8 +formen|for=men|8 +forskarna|fors=kar=na|8 +följaktligen|följ=akt=li=gen|8 +förbaskat|för=bas=kat|8 +Förenta|För=en=ta|8 +föreställa|fö=re=stäl=la|8 +förmåga|för=må=ga|8 +förråd|för=råd|8 +genomföra|ge=nom=fö=ra|8 +gläder|glä=der|8 +grundläggande|grund=läg=gan=de|8 +gränser|grän=ser|8 +handtagen|hand=ta=gen|8 +helvete|hel=ve=te|8 +hjälper|hjäl=per|8 +häpnadsväckande|häp=nads=väck=an=de|8 +jazzhänder|jazzhän=der|8 +kammaren|kam=ma=ren|8 +kastade|kas=ta=de|8 +knappen|knap=pen|8 +konstigt|kons=tigt|8 +kunnat|kun=nat|8 +laptoppen|lap=top=pen|8 +leende|le=en=de|8 +livlina|liv=li=na|8 +livlinor|liv=li=nor|8 +locket|lock=et|8 +lossnar|loss=nar|8 +luktar|luk=tar|8 +lycklig|lyck=lig|8 +maskinen|ma=ski=nen|8 +menade|me=na=de|8 +minnas|min=nas|8 +modellen|mo=del=len|8 +mojäng|mo=jäng|8 +nacken|nack=en|8 +naturliga|na=tur=li=ga|8 +navigationskonsolen|na=vi=ga=tions=kon=so=len|8 +omvandlar|om=vand=lar|8 +operationen|ope=ra=tio=nen|8 +Petrovaskop|Pe=tro=vas=kop|8 +Poängen|Po=äng=en|8 +provbehållaren|prov=be=hål=la=ren|8 +provrör|prov=rör|8 +påskriften|på=skrif=ten|8 +radion|ra=di=on|8 +reflekterar|re=flek=te=rar|8 +robotarmarna|ro=bot=armar=na|8 +ruskar|rus=kar|8 +rörelser|rö=rel=ser|8 +saktar|sak=tar|8 +samlat|sam=lat|8 +sextio|sex=tio|8 +sjukdomar|sjuk=do=mar|8 +sjutton|sjut=ton|8 +skeppen|skep=pen|8 +skickar|skick=ar|8 +skriva|skri=va|8 +sluter|slu=ter|8 +slänga|slänga|8 +slängde|släng=de|8 +slänger|släng=er|8 +smäller|smäl=ler|8 +smärtstillande|smärt=stil=lan=de|8 +sparkar|spar=kar|8 +stilla|stil=la|8 +struntar|strun=tar|8 +stänga|stänga|8 +suckade|suck=a=de|8 +svänger|sväng=er|8 +teleskopet|te=le=sko=pet|8 +texten|tex=ten|8 +tillfälle|till=fäl=le|8 +tillgång|till=gång|8 +timmen|tim=men|8 +tjugotre|tju=go=tre|8 +Trevärldens|Tre=värl=dens|8 +tryggt|tryggt|8 +träffas|träf=fas|8 +Tydligen|Tyd=li=gen|8 +täcker|täck=er|8 +uppfatta|upp=fat=ta|8 +uppfattning|upp=fatt=ning|8 +uppfunnit|upp=fun=nit|8 +urskilja|ur=skil=ja|8 +utföra|ut=fö=ra|8 +utvecklade|ut=veck=la=de|8 +vaknade|vak=na=de|8 +vanliga|van=li=ga|8 +vartenda|vart=en=da|8 +viktiga|vik=ti=ga|8 +viktigt|vik=tigt|8 +vägrar|väg=rar|8 +zoomar|zoo=mar|8 +Återigen|Åter=i=gen|8 +Överallt|Över=allt|8 +överlevde|över=lev=de|8 +överlever|över=le=ver|8 +överväldigande|över=väl=di=gan=de|8 +Absolut|Ab=so=lut|7 +absorbera|ab=sor=be=ra|7 +aktern|ak=tern|7 +aktiverar|ak=ti=ve=rar|7 +analys|ana=lys|7 +användas|an=vän=das|7 +apparaten|ap=pa=ra=ten|7 +astronauterna|ast=ro=nau=ter=na|7 +auktoritet|auk=to=ri=tet|7 +avsiktligt|av=sikt=ligt|7 +begriper|be=gri=per|7 +bekräfta|be=kräf=ta|7 +bekväm|be=kväm|7 +biljoner|bil=jo=ner|7 +blåste|blås=te|7 +brukar|bru=kar|7 +bränslekapsel|brän=s=le=kap=sel|7 +bränslekapslar|brän=s=le=kaps=lar|7 +bänken|bän=ken|7 +datorer|da=to=rer|7 +domaren|do=ma=ren|7 +dramatiskt|dra=ma=tiskt|7 +dricker|drick=er|7 +dräller|dräl=ler|7 +dödade|dö=da=de|7 +effektiva|ef=fek=ti=va|7 +elegant|ele=gant|7 +Eridierna|Eri=di=er=na|7 +Eridisk|Eri=disk|7 +evolutionen|evo=lu=tio=nen|7 +fastsatt|fast=satt|7 +femton|fem=ton|7 +flämtar|fläm=tar|7 +flåsar|flå=sar|7 +Fortfarande|Fort=fa=ran=de|7 +frekvenserna|fre=kven=ser=na|7 +frukost|fru=kost|7 +frågan|frå=gan|7 +Frånsett|Från=sett|7 +funderade|fun=de=ra=de|7 +fångar|fång=ar|7 +följde|följ=de|7 +gastar|gas=tar|7 +generna|ge=ner=na|7 +genomför|ge=nom=för|7 +genomskinligt|ge=nom=skin=ligt|7 +glasskivan|glas=ski=van|7 +grabbar|grab=bar|7 +gradvis|grad=vis|7 +Gravitationen|Gra=vi=ta=tio=nen|7 +hettan|het=tan|7 +hinner|hin=ner|7 +hälfter|hälf=ter|7 +identifiera|iden=ti=fi=e=ra|7 +infekterad|in=fek=te=rad|7 +inifrån|in=i=från|7 +Instämmer|In=stäm=mer|7 +interstellär|in=ter=stel=lär|7 +intill|in=till|7 +Jordens|Jor=dens|7 +jordiskt|jor=diskt|7 +jämförelse|jäm=fö=rel=se|7 +kallare|kal=la=re|7 +kandidater|kan=di=da=ter|7 +katastrof|ka=ta=strof|7 +klarat|kla=rat|7 +kliver|kli=ver|7 +klumpiga|klum=pi=ga|7 +klyftig|klyf=tig|7 +knackade|knack=a=de|7 +knogarna|kno=gar=na|7 +kolossalt|ko=los=salt|7 +komplicerad|kom=pli=ce=rad|7 +kontakt|kon=takt|7 +kritan|kri=tan|7 +lampor|lam=por|7 +likadan|li=ka=dan|7 +Luften|Luf=ten|7 +luftslussens|luft=slus=sens|7 +Lyckligtvis|Lyck=ligt=vis|7 +läkare|lä=ka=re|7 +massor|mas=sor|7 +meningen|me=ning=en|7 +modeller|mo=del=ler|7 +Motorerna|Mo=to=rer=na|7 +motsatta|mot=sat=ta|7 +motsvarar|mot=sva=rar|7 +musklerna|musk=ler=na|7 +mängden|mäng=den|7 +märkligt|märk=ligt|7 +möjlighet|möj=lig=het|7 +Naturligtvis|Na=tur=ligt=vis|7 +närmar|när=mar|7 +omgiven|om=gi=ven|7 +Orlandräkten|Or=landräk=ten|7 +panorerar|pa=no=re=rar|7 +person|per=son|7 +placerar|pla=ce=rar|7 +plötslig|plöts=lig|7 +protoner|pro=to=ner|7 +proverna|pro=ver=na|7 +pärlor|pär=lor|7 +radarskärmen|ra=dar=skär=men|7 +reflekteras|re=flek=te=ras|7 +Robotarmarna|Ro=bot=armar=na|7 +roboten|ro=bo=ten|7 +rymdfarkost|rymd=far=kost|7 +rymdpromenader|rymd=pro=me=na=der|7 +samtliga|samt=li=ga|7 +sannolikt|san=no=likt|7 +separat|se=pa=rat|7 +sexton|sex=ton|7 +siffror|siff=ror|7 +sjukdom|sjuk=dom|7 +Skalbaggarna|Skal=bag=gar=na|7 +skickat|skick=at|7 +skrapar|skra=par|7 +skrattade|skrat=ta=de|7 +skrattar|skrat=tar|7 +Skärmen|Skär=men|7 +slutsatser|slut=sat=ser|7 +smälter|smäl=ter|7 +snabba|snab=ba|7 +somliga|som=li=ga|7 +somnar|som=nar|7 +specifika|spe=ci=fi=ka|7 +spektrat|spekt=rat|7 +startar|star=tar|7 +Status|Sta=tus|7 +Stratts|Stratts|7 +stycken|styck=en|7 +styrka|styr=ka|7 +ställt|ställt|7 +stängde|stäng=de|7 +synfält|syn=fält|7 +synliga|syn=li=ga|7 +synligt|syn=ligt|7 +synvinkel|syn=vin=kel|7 +tappar|tap=par|7 +tecken|teck=en|7 +testat|tes=tat|7 +tidigt|ti=digt|7 +tillstånd|till=stånd|7 +tjockt|tjockt|7 +troligen|tro=li=gen|7 +trycka|trycka|7 +träffar|träf=far|7 +tvåhundra|två=hun=dra|7 +Tänker|Tän=ker|7 +uppsättning|upp=sätt=ning|7 +utifrån|ut=i=från|7 +utmärkt|ut=märkt|7 +vanlig|van=lig|7 +varsin|var=sin|7 +Vatten|Vat=ten|7 +villebråd|vil=le=bråd|7 +värsta|värs=ta|7 +vätska|väts=ka|7 +ägnade|äg=na=de|7 +ändras|änd=ras|7 +åstadkommer|åstad=kom=mer|7 +öppningen|öpp=ning=en|7 +överlevande|över=le=van=de|7 +överlevt|över=levt|7 +accelerationen|ac=ce=le=ra=tio=nen|6 +accelerera|ac=ce=le=re=ra|6 +Afrika|Af=ri=ka|6 +alltför|allt=för|6 +alternativet|al=ter=na=ti=vet|6 +Ammoniak|Am=mo=ni=ak|6 +aningen|aning=en|6 +antaganden|an=ta=gan=den|6 +antingen|an=ting=en|6 +Använd|An=vänd|6 +användbart|an=vänd=bart|6 +arbetade|ar=be=ta=de|6 +arbetsbänk|ar=bets=bänk|6 +asteroid|as=te=ro=id|6 +Astronauter|Ast=ro=nau=ter|6 +avancerad|avan=ce=rad|6 +avgörande|av=gö=ran=de|6 +avläsning|av=läs=ning|6 +avläsningar|av=läs=ning=ar|6 +avsedd|av=sedd|6 +behövt|be=hövt|6 +beräkna|be=räk=na|6 +beräkningar|be=räk=ning=ar|6 +Berätta|Be=rät=ta|6 +berättat|be=rät=tat|6 +beslut|be=slut|6 +Besättningen|Be=sätt=ning=en|6 +bisarra|bi=sar=ra|6 +bitarna|bi=tar=na|6 +bläddrade|blädd=ra=de|6 +brytning|bryt=ning|6 +brännmärken|bränn=mär=ken|6 +bränslekapslarna|brän=s=le=kaps=lar=na|6 +burriton|bur=ri=ton|6 +cellerna|cel=ler=na|6 +decennier|de=cen=ni=er|6 +delade|de=la=de|6 +detalj|de=talj|6 +dubbelt|dub=belt|6 +Därefter|Där=ef=ter|6 +enstaka|en=sta=ka|6 +erbjuder|er=bju=der|6 +ersättare|er=sät=ta=re|6 +evighet|evig=het|6 +expeditionen|ex=pe=di=tio=nen|6 +fantastisk|fan=tas=tisk|6 +fantastiska|fan=tas=tis=ka|6 +farkosten|far=kos=ten|6 +farten|far=ten|6 +farväl|far=väl|6 +fastsatta|fast=sat=ta|6 +femhundra|fem=hun=dra|6 +former|for=mer|6 +forskning|forsk=ning|6 +frivillig|fri=vil=lig|6 +funktion|funk=tion|6 +funktioner|funk=tio=ner|6 +fysisk|fy=sisk|6 +färger|fär=ger|6 +fäster|fäs=ter|6 +förbli|för=bli|6 +föreställer|fö=re=stäl=ler|6 +förflytta|för=flyt=ta|6 +förhållanden|för=hål=lan=den|6 +förklarade|för=kla=ra=de|6 +förklaring|för=kla=ring|6 +förlora|för=lo=ra|6 +försedd|för=sedd|6 +försegla|för=seg=la|6 +förstod|för=stod|6 +Försök|För=sök|6 +försöket|för=sö=ket|6 +förändras|för=änd=ras|6 +fötterna|föt=ter=na|6 +gemensamt|ge=men=samt|6 +giftigt|gif=tigt|6 +halvvägs|halv=vägs|6 +Hjärtat|Hjär=tat|6 +hoppar|hop=par|6 +hundratals|hun=dra=tals|6 +härifrån|här=i=från|6 +Håller|Hål=ler|6 +hållit|hål=lit|6 +Ibland|Ibland|6 +Iljuchinas|Iljuchi=nas|6 +improviserade|im=pro=vi=se=ra=de|6 +impulsen|im=pul=sen|6 +innanför|in=nan=för|6 +interstellära|in=ter=stel=lä=ra|6 +isolera|iso=le=ra|6 +Javisst|Ja=visst|6 +jobbade|job=ba=de|6 +jämfört|jäm=fört|6 +kablarna|kab=lar=na|6 +kamerorna|ka=me=ror=na|6 +killar|kil=lar|6 +knappar|knap=par|6 +komagegga|ko=ma=geg=ga|6 +kommunicera|kom=mu=ni=ce=ra|6 +komplicerade|kom=pli=ce=ra=de|6 +konstruera|kon=stru=e=ra|6 +konstruktionen|kon=struk=tio=nen|6 +kontrolleras|kon=trol=le=ras|6 +Kraften|Kraf=ten|6 +kubikmeter|ku=bik=me=ter|6 +lagrad|lag=rad|6 +liknar|lik=nar|6 +listan|lis=tan|6 +livsviktiga|livs=vik=ti=ga|6 +ljuskälla|lju=s=käl=la|6 +Luckan|Luck=an|6 +lådorna|lå=dor=na|6 +löjligt|löj=ligt|6 +madrassen|mad=ras=sen|6 +manuella|ma=nu=el=la|6 +massan|mas=san|6 +Massor|Mas=sor|6 +materialet|ma=te=ri=a=let|6 +medicinska|me=di=cins=ka|6 +meningslöst|me=nings=löst|6 +Merkurius|Mer=ku=ri=us|6 +miljontals|mil=jon=tals|6 +minnet|min=net|6 +misslyckas|miss=lyck=as|6 +mobilen|mo=bi=len|6 +montera|mon=te=ra|6 +monterade|mon=te=ra=de|6 +morgon|mor=gon|6 +muttrade|mutt=ra=de|6 +namnet|nam=net|6 +nanogram|na=n=o=gram|6 +Någonstans|Nå=gon=stans|6 +objektet|ob=jek=tet|6 +objektglaset|ob=jekt=gla=set|6 +observationer|ob=ser=va=tio=ner|6 +observationsrummet|ob=ser=va=tions=rum=met|6 +odlingarna|od=ling=ar=na|6 +overall|ove=rall|6 +oväntat|ovän=tat|6 +papperet|pap=pe=ret|6 +partiklarna|par=tik=lar=na|6 +passerar|pas=se=rar|6 +perfekta|per=fek=ta|6 +Petrovavåglängden|Pe=tro=va=våg=läng=den|6 +Planeten|Pla=ne=ten|6 +planeterna|pla=ne=ter=na|6 +platser|plat=ser|6 +plocka|plocka|6 +populationen|po=pu=la=tio=nen|6 +predatorer|pre=da=to=rer|6 +Problemet|Pro=ble=met|6 +producera|pro=du=ce=ra|6 +program|pro=gram|6 +provbehållare|prov=be=hål=la=re|6 +påverkar|på=ver=kar|6 +rapporterar|rap=por=te=rar|6 +relation|re=la=tion|6 +reportern|re=por=tern|6 +resurser|re=sur=ser|6 +riktade|rik=ta=de|6 +riktig|rik=tig|6 +ryggpansar|rygg=pan=sar|6 +Ryssland|Ryss=land|6 +räddar|räd=dar|6 +rösten|rös=ten|6 +samman|sam=man|6 +siktar|sik=tar|6 +situationen|si=tu=a=tio=nen|6 +Skalbaggar|Skal=bag=gar|6 +skalbaggarnas|skal=bag=gar=nas|6 +skenor|ske=nor|6 +skivor|ski=vor|6 +skrivit|skri=vit|6 +slipper|slip=per|6 +slungar|slung=ar|6 +släppa|släp=pa|6 +smetar|sme=tar|6 +smärta|smär=ta|6 +soldaten|sol=da=ten|6 +solida|so=li=da|6 +solsystemet|sol=sys=te=met|6 +speciell|spe=ci=ell|6 +spjärn|spjärn|6 +spänna|spän=na|6 +stenar|ste=nar|6 +stiger|sti=ger|6 +stoppade|stop=pa=de|6 +struktur|struk=tur|6 +studsa|stud=sa|6 +stängs|stängs|6 +stängt|stängt|6 +svagare|sva=ga=re|6 +svartceller|svart=cel=ler|6 +svänga|svänga|6 +särskild|sär=skild|6 +tappade|tap=pa=de|6 +Tillbaka|Till=ba=ka|6 +tillnärmelsevis|till=när=mel=se=vis|6 +tillverkat|till=ver=kat|6 +toppen|top=pen|6 +trasig|tra=sig|6 +triangel|tri=ang=el|6 +Trycket|Tryck=et|6 +tungmetaller|tung=me=tal=ler|6 +tunnan|tun=nan|6 +tupplur|tupp=lur|6 +tusentals|tu=sen=tals|6 +tvivlar|tviv=lar|6 +tvåtusen|två=tu=sen|6 +tänkte|tänk=te|6 +upphöjt|upp=höjt|6 +uppmärksamhet|upp=märk=sam=het|6 +uppmärksamheten|upp=märk=sam=he=ten|6 +uppstå|upp=stå|6 +uppstår|upp=står|6 +utanpå|ut=an=på|6 +utblåsningen|ut=blås=ning=en|6 +utnyttjar|ut=nytt=jar|6 +utrustningen|ut=rust=ning=en|6 +vakuumkammare|va=ku=um=kam=ma=re|6 +veckorna|veck=or=na|6 +verktyget|verk=ty=get|6 +verktygsbältet|verk=tygs=bäl=tet|6 +viktigare|vik=ti=ga=re|6 +villiga|vil=li=ga|6 +vokabulär|vo=ka=bu=lär|6 +värmeenergi|vär=me=ener=gi|6 +väsande|vä=san=de|6 +Äntligen|Änt=li=gen|6 +återgäldar|åter=gäl=dar|6 +återstår|åter=står|6 +ögonbrynen|ögon=bry=nen|6 +öronen|öro=nen|6 +översta|övers=ta|6 +acceptera|ac=cep=te=ra|5 +ackord|ac=kord|5 +ansvaret|an=sva=ret|5 +antalet|an=ta=let|5 +artigt|ar=tigt|5 +avbryta|av=bry=ta|5 +avläsningarna|av=läs=ning=ar=na|5 +bandet|ban=det|5 +barnen|bar=nen|5 +bassängen|bas=säng=en|5 +befunnit|be=fun=nit|5 +begrepp|be=grepp|5 +beklagar|be=kla=gar|5 +betrakta|be=trak=ta|5 +beträffar|be=träf=far|5 +bilderna|bil=der=na|5 +biosfär|bio=sfär|5 +bläddrar|blädd=rar|5 +blåser|blå=ser|5 +bryter|bry=ter|5 +bränner|brän=ner|5 +bränsletank|brän=sle=tank|5 +bygger|byg=ger|5 +byggnad|bygg=nad|5 +bältet|bäl=tet|5 +böcker|böck=er|5 +bönpåse|bön=på=se|5 +centrifugskärmen|cen=tri=fug=skär=men|5 +centrum|cen=trum|5 +cirkeln|cir=keln|5 +delarna|de=lar=na|5 +densamma|den=sam=ma|5 +detaljer|de=tal=jer|5 +detsamma|det=sam=ma|5 +djuren|dju=ren|5 +dragit|dra=git|5 +därmed|där=med|5 +döende|dö=en=de|5 +Dörren|Dör=ren|5 +Easton|Eas=ton|5 +element|ele=ment|5 +Enkelt|En=kelt|5 +enklare|enk=la=re|5 +europeiska|eu=ro=pe=is=ka|5 +exakta|ex=ak=ta|5 +exempel|ex=em=pel|5 +expert|ex=pert|5 +experter|ex=per=ter|5 +fastnar|fast=nar|5 +filtren|filt=ren|5 +fingrarna|fing=rar=na|5 +fjärran|fjär=ran|5 +forsar|for=sar|5 +framgång|fram=gång|5 +framgångsrikt|fram=gångs=rikt|5 +Francisco|Fran=ci=sco|5 +frekvensen|fre=kven=sen|5 +frånsett|från=sett|5 +fulländat|full=än=dat|5 +Fungerar|Fun=ge=rar|5 +fysiskt|fy=siskt|5 +färdigheter|fär=dig=he=ter|5 +färgen|fär=gen|5 +förekommer|fö=re=kom=mer|5 +Förhoppningsvis|För=hopp=nings=vis|5 +förklarat|för=kla=rat|5 +förlorat|för=lo=rat|5 +försiktig|för=sik=tig|5 +Förstås|För=stås|5 +försvinna|för=svin=na|5 +Försökte|För=sök=te|5 +förtjänar|för=tjä=nar|5 +förvånad|för=vå=nad|5 +förvånar|för=vå=nar|5 +förändrats|för=änd=rats|5 +förånga|för=ånga|5 +förångas|för=ång=as|5 +garantera|ga=ran=te=ra|5 +garderoben|gar=de=ro=ben|5 +gissning|giss=ning|5 +grimaserar|gri=ma=se=rar|5 +hamnar|ham=nar|5 +handbojorna|hand=bo=jor=na|5 +handflatan|hand=fla=tan|5 +Hejsan|Hej=san|5 +hemvärld|hem=värld|5 +himlade|him=la=de|5 +hindra|hind=ra|5 +hjälpte|hjälp=te|5 +hjärnan|hjär=nan|5 +Hoppas|Hop=pas|5 +hungrig|hung=rig|5 +hysteriskt|hy=ste=riskt|5 +häftigt|häf=tigt|5 +höljet|höl=jet|5 +infekterade|in=fek=te=ra=de|5 +ingenstans|ing=en=stans|5 +installerade|in=stal=le=ra=de|5 +installerat|in=stal=le=rat|5 +inställningen|in=ställ=ning=en|5 +intelligent|in=tel=li=gent|5 +interagera|in=ter=ag=e=ra|5 +internationell|in=ter=na=tio=nell|5 +intresserad|in=tres=se=rad|5 +isolerade|iso=le=ra=de|5 +jobbigt|job=bigt|5 +Jordiska|Jor=dis=ka|5 +jösses|jös=ses|5 +kanterna|kan=ter=na|5 +kastar|kas=tar|5 +katedern|ka=te=dern|5 +kemikalier|ke=mi=ka=li=er|5 +kemisk|ke=misk|5 +kilogram|ki=lo=gram|5 +kinesisk|ki=ne=sisk|5 +klyftiga|klyf=ti=ga|5 +kolliderar|kol=li=de=rar|5 +kommunikation|kom=mu=ni=ka=tion|5 +komplett|kom=plett|5 +komplexa|kom=plexa|5 +komplext|kom=plext|5 +konferensrum|kon=fe=rens=rum|5 +kopiera|ko=pi=e=ra|5 +korkad|kor=kad|5 +kosmiska|kos=mis=ka|5 +kravlar|krav=lar|5 +kritiska|kri=tis=ka|5 +kroppar|krop=par|5 +kräkas|krä=kas|5 +kvadratmeter|kvad=rat=me=ter|5 +kvalificerad|kva=li=fi=ce=rad|5 +kämpar|käm=par|5 +känsliga|käns=li=ga|5 +laboratorier|la=bo=ra=to=ri=er|5 +laboratorieutrustning|la=bo=ra=to=rie=u=t=rust=ning|5 +lampan|lam=pan|5 +lamporna|lam=por=na|5 +lediga|le=di=ga|5 +ledningar|led=ning=ar|5 +ledsen|led=sen|5 +likadana|li=ka=da=na|5 +liknande|lik=nan=de|5 +livlinorna|liv=li=nor=na|5 +ljuden|lju=den|5 +ljusblixt|ljus=blixt|5 +Ljuset|Lju=set|5 +ljusstark|ljus=stark|5 +lugnar|lug=nar|5 +lukten|luk=ten|5 +lutning|lut=ning|5 +Lycklig|Lyck=lig|5 +lyfter|lyf=ter|5 +länkarna|län=kar=na|5 +långsam|lång=sam|5 +manuell|ma=nu=ell|5 +marginal|mar=gi=nal|5 +maskin|ma=skin|5 +medvetna|med=vet=na|5 +meters|me=ters|5 +mikrober|mik=ro=ber|5 +mikrometer|mik=ro=me=ter|5 +mikroskopiska|mik=ro=sko=pis=ka|5 +miljön|mil=jön|5 +minskat|mins=kat|5 +mittpunkt|mitt=punkt|5 +molekyler|mo=le=ky=ler|5 +morrhår|morr=hår|5 +muskler|musk=ler|5 +mänskligt|mänsk=ligt|5 +märker|mär=ker|5 +Måttbandet|Mått=ban=det|5 +mönster|möns=ter|5 +natten|nat=ten|5 +naturen|na=tu=ren|5 +navigationspanelen|na=vi=ga=tions=pa=ne=len|5 +Newton|Newton|5 +nickar|nick=ar|5 +numera|nu=me=ra|5 +nyheter|ny=he=ter|5 +nämnvärt|nämn=värt|5 +oregelbunden|ore=gel=bun=den|5 +osannolikt|osan=no=likt|5 +parallellt|pa=ral=lellt|5 +partner|part=ner|5 +pengar|peng=ar|5 +Petrovaproblemet|Pe=tro=va=pro=ble=met|5 +pillar|pil=lar|5 +pinnen|pin=nen|5 +planerat|pla=ne=rat|5 +porten|por=ten|5 +pratade|pra=ta=de|5 +predator|pre=da=tor|5 +prickar|prick=ar|5 +proteiner|pro=te=i=ner|5 +protonerna|pro=to=ner=na|5 +provröret|prov=rö=ret|5 +prylarna|pry=lar=na|5 +pålitlig|på=lit=lig|5 +påverka|på=ver=ka|5 +radarn|ra=darn|5 +rapporten|rap=por=ten|5 +reagera|re=a=ge=ra|5 +realtid|re=al=tid|5 +reparera|re=pa=re=ra|5 +respektive|re=spek=ti=ve|5 +riktar|rik=tar|5 +riskerna|ris=ker=na|5 +ropade|ro=pa=de|5 +Rummet|Rum=met|5 +rumstemperatur|rums=tem=pe=ra=tur|5 +ruskade|rus=ka=de|5 +rymddräkter|rymd=dräk=ter|5 +Rymden|Rym=den|5 +saknar|sak=nar|5 +samling|sam=ling|5 +siffrorna|siff=ror=na|5 +självfallet|själv=fal=let|5 +Självfallet|Själv=fal=let|5 +sjätte|sjät=te|5 +skadad|ska=dad|5 +skadat|ska=dat|5 +skalbaggar|skal=bag=gar|5 +skillnaden|skill=na=den|5 +skjuta|skju=ta|5 +Skrovet|Skro=vet|5 +skälver|skäl=ver|5 +skåpet|skå=pet|5 +sköter|skö=ter|5 +slocknar|slock=nar|5 +slumpmässiga|slump=mäs=si=ga|5 +slussdörren|sluss=dör=ren|5 +slussporten|sluss=por=ten|5 +släpar|slä=par|5 +smartare|smar=ta=re|5 +smyger|smy=ger|5 +snurrade|snur=ra=de|5 +snyftar|snyf=tar|5 +solenergi|so=l=ener=gi|5 +solljus|sol=ljus|5 +sovrummet|sov=rum=met|5 +speciellt|spe=ci=ellt|5 +spektralsignatur|spekt=ral=sig=na=tur|5 +Spindrift|Spindrift|5 +spolar|spo=lar|5 +spolarna|spo=lar=na|5 +sprickan|sprick=an|5 +spruta|spru=ta|5 +spännande|spän=nan=de|5 +staterna|sta=ter=na|5 +stirra|stir=ra|5 +storlek|stor=lek|5 +sträckte|sträck=te|5 +ställde|ställ=de|5 +ställning|ställ=ning|5 +stämde|stäm=de|5 +Svaret|Sva=ret|5 +svårare|svå=ra=re|5 +svårighet|svå=rig=het|5 +symbol|sym=bol|5 +synnerhet|syn=ner=het|5 +syssla|syss=la|5 +sänder|sän=der|5 +tabletterna|ta=blet=ter=na|5 +takten|tak=ten|5 +teleskopskärmen|te=le=skop=skär=men|5 +testar|tes=tar|5 +tillbringa|till=bringa|5 +Tillräckligt|Till=räck=ligt|5 +Tillsammans|Till=sam=mans|5 +Tjatte|Tjat=te|5 +totala|to=ta=la|5 +totalt|to=talt|5 +trycks|trycks|5 +tryckte|tryck=te|5 +tunnelväggarna|tun=nel=väg=gar=na|5 +tvinga|tvinga|5 +tystnad|tyst=nad|5 +tänder|tän=der|5 +universum|uni=ver=sum|5 +Uppfattat|Upp=fat=tat|5 +upphetsad|upp=het=sad|5 +upplevt|upp=levt|5 +upprepade|upp=re=pa=de|5 +uppskattar|upp=skat=tar|5 +ursäkt|ur=säkt|5 +utomjordingarna|ut=om=jor=ding=ar=na|5 +uttråkad|ut=trå=kad|5 +utvecklat|ut=veck=lat|5 +vakuumkammaren|va=ku=um=kam=ma=ren|5 +vardera|var=de=ra|5 +ventiler|ven=ti=ler|5 +verkstad|verk=stad|5 +verktygen|verk=ty=gen|5 +viktig|vik=tig|5 +vinkade|vin=ka=de|5 +Vinkelanomali|Vin=ke=la=no=ma=li|5 +volymen|vo=ly=men|5 +Väggarna|Väg=gar=na|5 +Välkommen|Väl=kom=men|5 +väteatomer|vä=te=ato=mer|5 +växter|väx=ter|5 +våglängden|våg=läng=den|5 +walkie|wal=kie|5 +Zeeland|Zee=land|5 +älskar|äls=kar|5 +öppning|öpp=ning|5 +överens|över=ens|5 +överenskommelse|över=ens=kom=mel=se|5 +aktivera|ak=ti=ve=ra|4 +aktivt|ak=tivt|4 +allvarlig|all=var=lig|4 +allvarligt|all=var=ligt|4 +alternativen|al=ter=na=ti=ven|4 +amerikan|ame=ri=kan|4 +analysen|ana=ly=sen|4 +analysera|ana=ly=se=ra|4 +analyserar|ana=ly=se=rar|4 +anstränga|an=stränga|4 +antagligen|an=tag=li=gen|4 +Antagligen|An=tag=li=gen|4 +anteckning|an=teck=ning|4 +användes|an=vän=des|4 +används|an=vänds|4 +apokalypsen|apo=ka=lyp=sen|4 +arbetat|ar=be=tat|4 +artificiella|ar=ti=fi=ci=el=la|4 +astrofagdrivet|ast=ro=fag=dri=vet|4 +astrofagen|ast=ro=fa=gen|4 +Astrofagernas|Ast=ro=fa=ger=nas|4 +astronomisk|ast=ro=no=misk|4 +avsedda|av=sed=da|4 +avslutad|av=slu=tad|4 +bakgrunden|bak=grun=den|4 +bakterier|bak=te=ri=er|4 +befogenheter|be=fo=gen=he=ter|4 +befälhavare|be=fäl=ha=va=re|4 +begripa|be=gri=pa|4 +begränsad|be=grän=sad|4 +begränsade|be=grän=sa=de|4 +behövdes|be=höv=des|4 +bekräftat|be=kräf=tat|4 +bekvämt|be=kvämt|4 +berodde|be=rod=de|4 +beroende|be=ro=en=de|4 +berätta|be=rät=ta|4 +besättningsmedlem|be=sätt=nings=med=lem|4 +biblioteket|bib=li=o=te=ket|4 +bildar|bil=dar|4 +Bilden|Bil=den|4 +bilder|bil=der|4 +biologiska|bio=lo=gis=ka|4 +biologiskt|bio=lo=giskt|4 +blinkande|blin=kan=de|4 +blottar|blot=tar|4 +bokstäver|bok=stä=ver|4 +borren|bor=ren|4 +brantare|bran=ta=re|4 +brittiska|brit=tis=ka|4 +bränna|brän=na|4 +bränslekapseln|brän=s=le=kap=seln|4 +bråkdels|bråk=dels|4 +bubblan|bubb=lan|4 +burrito|bur=ri=to|4 +civilisation|ci=vi=li=sa=tion|4 +cockpiten|cock=pi=ten|4 +cykeln|cy=keln|4 +cylinderns|cy=lin=derns|4 +Cáceres|Cá=ce=res|4 +dagliga|dag=li=ga|4 +densitet|den=si=tet|4 +detaljerad|de=tal=je=rad|4 +digitalt|di=gi=talt|4 +Dimitrijs|Di=mit=rijs|4 +diverse|di=ver=se|4 +dollar|dol=lar|4 +dricka|dricka|4 +droppe|drop=pe|4 +dröjer|drö=jer|4 +dämpat|däm=pat|4 +dödande|dö=dan=de|4 +dörrar|dör=rar|4 +dörrarna|dör=rar=na|4 +effekten|ef=fek=ten|4 +effekter|ef=fek=ter|4 +effektiv|ef=fek=tiv|4 +eleganta|ele=gan=ta|4 +Enbart|En=bart|4 +encelliga|encel=li=ga|4 +eridiernas|eri=di=er=nas|4 +exploderar|ex=plo=de=rar|4 +explosion|ex=plo=sion|4 +explosionen|ex=plo=sio=nen|4 +faktum|fak=tum|4 +Faktum|Fak=tum|4 +farkost|far=kost|4 +fickan|fick=an|4 +filtret|filt=ret|4 +flagga|flag=ga|4 +flämtade|fläm=ta=de|4 +Fnatte|Fnat=te|4 +fokuserar|fo=ku=se=rar|4 +formar|for=mar|4 +format|for=mat|4 +Forrester|For=res=ter|4 +fruktansvärt|fruk=tans=värt|4 +främst|främst|4 +fullbordad|full=bor=dad|4 +funderat|fun=de=rat|4 +fyrtiofem|fyr=tio=fem|4 +färdiga|fär=di=ga|4 +föddes|föd=des|4 +fönstren|fönst=ren|4 +förankrad|för=ank=rad|4 +förbereda|för=be=re=da|4 +förbundna|för=bund=na|4 +fördel|för=del|4 +förfader|för=fa=der|4 +förmågan|för=må=gan|4 +förstöra|för=stö=ra|4 +förstörd|för=störd|4 +försvann|för=svann|4 +förteckning|för=teck=ning|4 +förutsätter|för=ut=sät=ter|4 +förvirrad|för=vir=rad|4 +förväg|för=väg|4 +förvånande|för=vå=nan=de|4 +förvåning|för=vå=ning|4 +gapade|ga=pa=de|4 +genetiska|ge=ne=tis=ka|4 +genever|ge=ne=ver|4 +genomfört|ge=nom=fört|4 +glödlampa|glöd=lam=pa|4 +gnuggar|gnug=gar|4 +gnutta|gnut=ta|4 +Gravitation|Gra=vi=ta=tion|4 +grejor|gre=jor|4 +grupper|grup=per|4 +halsband|hals=band|4 +halsen|hal=sen|4 +hammaren|ham=ma=ren|4 +handskar|hands=kar|4 +handskarna|hands=kar=na|4 +hangarfartyget|han=gar=far=ty=get|4 +hangarfartygets|han=gar=far=ty=gets|4 +HASTIGHET|HAS=TIG=HET|4 +Hastigheten|Has=tig=he=ten|4 +hejdade|hej=da=de|4 +helikopter|he=li=kop=ter|4 +helikoptern|he=li=kop=tern|4 +hellre|hell=re|4 +helsike|hel=si=ke|4 +helvetet|hel=ve=tet|4 +hemskt|hemskt|4 +Hennes|Hen=nes|4 +heroin|he=ro=in|4 +hexagonerna|hexa=go=ner=na|4 +himlen|him=len|4 +hjulet|hju=let|4 +hjälpt|hjälpt|4 +hjälte|hjäl=te|4 +hoppades|hop=pa=des|4 +hopplöst|hopp=löst|4 +hundraprocentigt|hun=dra=pro=cen=tigt|4 +hundratusen|hun=dra=tu=sen|4 +hunnit|hun=nit|4 +huvudskärmen|hu=vud=skär=men|4 +hälfterna|hälf=ter=na|4 +hängde|häng=de|4 +hållning|håll=ning|4 +iaktta|iakt=ta|4 +ifrågasätta|ifrå=ga=sät=ta|4 +imponerad|im=po=ne=rad|4 +inbyggda|in=bygg=da|4 +infektera|in=fek=te=ra|4 +Information|In=for=ma=tion|4 +infraröd|in=fra=röd|4 +ingenjörer|in=gen=jö=rer|4 +ingående|in=gå=en=de|4 +inklusive|in=klu=si=ve|4 +innebar|in=ne=bar|4 +innehålla|in=ne=hål=la|4 +innehöll|in=ne=höll|4 +insamlingsenheten|in=sam=lings=en=he=ten|4 +installerar|in=stal=le=rar|4 +intervall|in=ter=vall|4 +intresserar|in=tres=se=rar|4 +inträffa|in=träf=fa|4 +inverkan|in=ver=kan|4 +irriterade|ir=ri=te=ra=de|4 +jetplan|jet=plan|4 +jobbat|job=bat|4 +kalkylblad|kal=kyl=blad|4 +kapsel|kap=sel|4 +kapseln|kap=seln|4 +kapslar|kaps=lar|4 +kapslarna|kaps=lar=na|4 +kapten|kap=ten|4 +karantänzonen|ka=ran=tänzo=nen|4 +kastas|kas=tas|4 +kilometers|ki=lo=me=ters|4 +klassrum|klass=rum|4 +klickande|klick=an=de|4 +Klockan|Klock=an|4 +klämma|kläm=ma|4 +klämman|kläm=man|4 +Knatte|Knat=te|4 +koldioxiden|kol=di=ox=i=den|4 +kollegor|kol=le=gor|4 +kollidera|kol=li=de=ra|4 +kolsvart|kol=svart|4 +komaresistent|ko=ma=re=sis=tent|4 +kombination|kom=bi=na=tion|4 +kommendör|kom=men=dör|4 +koncentrera|kon=cen=tre=ra|4 +koncentrerar|kon=cen=tre=rar|4 +konstiga|kons=ti=ga|4 +konstruerade|kon=stru=e=ra=de|4 +konstruerar|kon=stru=e=rar|4 +konsumerar|kon=su=me=rar|4 +kontrollen|kon=trol=len|4 +kontrollerade|kon=trol=le=ra=de|4 +kontrollrum|kon=troll=rum|4 +kontrollskärmen|kon=troll=skär=men|4 +koppla|kopp=la|4 +korridoren|kor=ri=do=ren|4 +krafter|kraf=ter|4 +krafterna|kraf=ter=na|4 +kragen|kra=gen|4 +kramar|kra=mar|4 +kretsar|kret=sar|4 +kroppsspråk|kropps=språk|4 +krävdes|kräv=des|4 +kunskaper|kun=ska=per|4 +kursen|kur=sen|4 +kusligt|kus=ligt|4 +kvadrat|kvad=rat|4 +kvinnor|kvin=nor|4 +kväveresistenta|kvä=ve=re=sis=ten=ta|4 +laboratoriet|la=bo=ra=to=ri=et|4 +landade|lan=da=de|4 +ledning|led=ning|4 +ledtråd|led=tråd|4 +Likadant|Li=ka=dant|4 +linserna|lin=ser=na|4 +livscykel|livs=cy=kel|4 +livsmedel|livs=me=del|4 +lossad|los=sad|4 +Luftslussen|Luft=slus=sen|4 +lysdioder|lys=dio=der|4 +lyssna|lyss=na|4 +lyssnar|lyss=nar|4 +läckor|läck=or|4 +lägenhet|lä=gen=het|4 +längdaxel|längd=ax=el|4 +läskigt|läs=kigt|4 +långsamma|lång=sam=ma|4 +magiska|ma=gis=ka|4 +magneter|mag=ne=ter|4 +mannen|man=nen|4 +manuellt|ma=nu=ellt|4 +markörer|mar=kö=rer|4 +Martin|Martin|4 +medicinsk|me=di=cinsk|4 +medicinskt|me=di=cinskt|4 +medvetande|med=ve=tan=de|4 +medvetandet|med=ve=tan=det|4 +mejlet|mej=let|4 +mejseln|mej=seln|4 +mekaniska|me=ka=nis=ka|4 +Meknikov|Mek=ni=kov|4 +mellanrum|mel=lan=rum|4 +mening|me=ning|4 +metanet|me=ta=net|4 +Michael|Mi=chael|4 +migrerar|mi=gre=rar|4 +Miljarder|Mil=jar=der|4 +milligram|mil=li=gram|4 +milliliter|mil=li=li=ter|4 +minimera|mi=ni=me=ra|4 +minimum|mi=ni=mum|4 +misstänkte|miss=tänk=te|4 +missväxt|miss=växt|4 +mojängen|mo=jäng=en|4 +monterad|mon=te=rad|4 +morgonen|mor=go=nen|4 +muskulösa|mus=ku=lö=sa|4 +muttrar|mutt=rar|4 +mysterium|mys=te=ri=um|4 +mystiska|mys=tis=ka|4 +Människors|Män=ni=skors|4 +måltiden|mål=ti=den|4 +måttband|mått=band|4 +möjligen|möj=li=gen|4 +nederst|ne=derst|4 +nyfiken|ny=fi=ken|4 +nyheten|ny=he=ten|4 +närmade|när=ma=de|4 +nätverk|nät=verk|4 +observationsstatus|ob=ser=va=tions=sta=tus|4 +observerat|ob=ser=ve=rat|4 +odlingstankar|od=lingstan=kar|4 +oförändrad|oför=änd=rad|4 +Olesija|Ole=si=ja|4 +olycka|olycka|4 +olyckan|olyck=an|4 +omständigheter|om=stän=dig=he=ter|4 +omvandla|om=vand=la|4 +ordbok|ord=bok|4 +ordboken|ord=bo=ken|4 +ordnar|ord=nar|4 +orimligt|orim=ligt|4 +orsakar|or=sa=kar|4 +ovanför|ovan=för|4 +ovanligt|ovan=ligt|4 +ovanpå|ovan=på|4 +Panelen|Pa=ne=len|4 +papperen|pap=pe=ren|4 +pappersark|pap=pers=ark|4 +parallelltrapets|pa=ral=lell=tra=pets|4 +personliga|per=son=li=ga|4 +personligen|per=son=li=gen|4 +Petrova|Pe=tro=va|4 +placera|pla=ce=ra|4 +planetens|pla=ne=tens|4 +plockat|plock=at|4 +plågsamt|plåg=samt|4 +plötsliga|plöts=li=ga|4 +portabla|por=tab=la|4 +poängen|po=äng=en|4 +Praktiskt|Prak=tiskt|4 +pratat|pra=tat|4 +predatorn|pre=da=torn|4 +primater|pri=ma=ter|4 +primär|pri=mär|4 +process|pro=cess|4 +producerar|pro=du=ce=rar|4 +programmet|pro=gram=met|4 +pytteliten|pyt=te=li=ten|4 +pågick|på=gick|4 +rektangulär|rek=tan=gu=lär|4 +relativa|re=la=ti=va|4 +Reportern|Re=por=tern|4 +reserv|re=serv|4 +Resten|Res=ten|4 +resultaten|re=sul=ta=ten|4 +ribborna|rib=bor=na|4 +riktiga|rik=ti=ga|4 +riktningar|rikt=ning=ar|4 +rimlig|rim=lig|4 +ringer|ring=er|4 +Roboten|Ro=bo=ten|4 +Roskosmos|Roskos=mos|4 +roterande|ro=te=ran=de|4 +rubriken|ru=bri=ken|4 +rullade|rul=la=de|4 +rummen|rum=men|4 +ryggade|ryg=ga=de|4 +rymdstationen|rymd=sta=tio=nen|4 +Ryssarna|Rys=sar=na|4 +räckhåll|räck=håll|4 +räddning|rädd=ning|4 +saboterar|sa=bo=te=rar|4 +Sahara|Sa=ha=ra|4 +Saharaöknen|Sa=ha=ra=ök=nen|4 +saknade|sak=na=de|4 +samlade|sam=la=de|4 +sammansatt|sam=man=satt|4 +samtalet|sam=ta=let|4 +Samtidigt|Sam=ti=digt|4 +sekundkvadrat|se=kund=kvad=rat|4 +sekvensen|se=kven=sen|4 +sidorna|si=dor=na|4 +siffran|siff=ran|4 +silvertejp|sil=ver=tejp|4 +situation|si=tu=a=tion|4 +sjutusen|sju=tu=sen|4 +skadade|ska=da=de|4 +skalan|ska=lan|4 +skallen|skal=len|4 +skapar|ska=par|4 +skilda|skil=da|4 +skilja|skil=ja|4 +skogen|sko=gen|4 +skrovrobot|skrov=ro=bot|4 +skruva|skru=va|4 +skruven|skru=ven|4 +skydda|skyd=da|4 +skyddade|skyd=da=de|4 +skynda|skyn=da|4 +skyndar|skyn=dar|4 +slocknade|slock=na=de|4 +slutade|slu=ta=de|4 +slutat|slu=tat|4 +släkte|släk=te|4 +smakar|sma=kar|4 +Smärtan|Smär=tan|4 +Snarare|Sna=ra=re|4 +Soldaten|Sol=da=ten|4 +Somliga|Som=li=ga|4 +sovsal|sov=sal|4 +specialist|spe=ci=a=list|4 +specifikt|spe=ci=fikt|4 +spekulera|spe=ku=le=ra|4 +Spencer|Spencer|4 +spindel|spin=del|4 +splitter|split=ter|4 +sprider|spri=der|4 +sprutar|spru=tar|4 +spränga|spränga|4 +stannade|stan=na=de|4 +starta|star=ta|4 +stegpinne|steg=pin=ne|4 +steriliserar|ste=ri=li=se=rar|4 +stjärnsystem|stjärn=sys=tem|4 +stoppa|stop=pa|4 +stoppur|stopp=ur|4 +streck|streck|4 +Strunt|Strunt|4 +strålningen|strål=ning=en|4 +strömbrytare|ström=bry=ta=re|4 +studerar|stu=de=rar|4 +studie|stu=die|4 +styrbords|styr=bords|4 +ställa|stäl=la|4 +Stämmer|Stäm=mer|4 +svajar|sva=jar|4 +svälta|sväl=ta|4 +Svårare|Svå=ra=re|4 +syftet|syf=tet|4 +synlig|syn=lig|4 +sällsynta|säll=syn=ta|4 +sängar|säng=ar|4 +Såvitt|Så=vitt|4 +sörjan|sör=jan|4 +tabletter|ta=blet=ter|4 +talkie|tal=kie|4 +taumöbabajs|tau=mö=ba=bajs|4 +taumöbalarmet|tau=mö=ba=larm=et|4 +tejpade|tej=pa=de|4 +tekniken|tek=ni=ken|4 +teknologi|tek=no=lo=gi|4 +termisk|ter=misk|4 +Texten|Tex=ten|4 +tillbringat|till=bring=at|4 +tillräcklig|till=räck=lig|4 +tiotusentals|tio=tu=sen=tals|4 +toaletten|toa=let=ten|4 +trassla|trass=la|4 +Trettio|Tret=tio|4 +Trevligt|Trev=ligt|4 +triangeln|tri=ang=eln|4 +trummade|trum=ma=de|4 +träffat|träf=fat|4 +tränga|tränga|4 +träning|trä=ning|4 +trådar|trå=dar|4 +tråkigt|trå=kigt|4 +tummen|tum=men|4 +turbin|tur=bin|4 +tvingar|tving=ar|4 +tyvärr|ty=värr|4 +tänkas|tän=kas|4 +tänkbart|tänk=bart|4 +undrade|und=ra=de|4 +undvika|und=vi=ka|4 +Ungarna|Ung=ar=na|4 +uniform|uni=form|4 +uniformer|uni=for=mer|4 +uppdrag|upp=drag|4 +uppfinna|upp=fin=na|4 +upphöjda|upp=höj=da|4 +uppmärksam|upp=märk=sam|4 +upprepas|upp=re=pas|4 +Uppriktigt|Upp=rik=tigt|4 +upprörd|upp=rörd|4 +uppsatsen|upp=sat=sen|4 +upptagen|upp=ta=gen|4 +utforska|ut=fors=ka|4 +utplåning|ut=plå=ning|4 +utsatt|ut=satt|4 +utspridda|ut=sprid=da|4 +utsättas|ut=sät=tas|4 +uttrycka|ut=trycka|4 +utvecklades|ut=veck=la=des|4 +Utöver|Ut=över|4 +vacker|vack=er|4 +Varifrån|Var=i=från|4 +varning|var=ning|4 +ventil|ven=til|4 +ventilerna|ven=ti=ler=na|4 +verktygsbälte|verk=tygs=bäl=te|4 +vertikala|ver=ti=ka=la|4 +vetenskapligt|ve=ten=skap=ligt|4 +vickade|vick=a=de|4 +vidgas|vid=gas|4 +viktigast|vik=ti=gast|4 +vinkla|vink=la|4 +Vinschen|Vin=schen|4 +visarna|vi=sar=na|4 +vägrade|väg=ra=de|4 +väller|väl=ler|4 +värdelös|vär=de=lös|4 +världar|värl=dar|4 +värmer|vär=mer|4 +väskan|väs=kan|4 +växande|väx=an=de|4 +whisky|whis=ky|4 +xenonitbehållare|xe=no=nit=be=hål=la=re|4 +ändrar|änd=rar|4 +åratal|åra=tal|4 +återgå|åter=gå|4 +överlevare|över=le=va=re|4 +Överst|Överst|4 +övervaka|över=va=ka|4 +absorberas|ab=sor=be=ras|3 +absurd|ab=surd|3 +absurda|ab=sur=da|3 +aggressiv|ag=gres=siv|3 +akademiska|aka=de=mis=ka|3 +aktiva|ak=ti=va|3 +aktiverade|ak=ti=ve=ra=de|3 +aktiveras|ak=ti=ve=ras|3 +Aldrig|Ald=rig|3 +Alltid|All=tid|3 +Alternativ|Al=ter=na=tiv|3 +amerikanerna|ame=ri=ka=ner=na|3 +analog|ana=log|3 +anläggning|an=lägg=ning|3 +anmält|an=mält|3 +annanstans|an=nan=stans|3 +anpassa|an=pas=sa|3 +anrikade|an=ri=ka=de|3 +anstränger|an=sträng=er|3 +antecknar|an=teck=nar|3 +antennen|an=ten=nen|3 +antibiotika|an=ti=bi=o=ti=ka|3 +antydan|an=ty=dan|3 +användbar|an=vänd=bar|3 +Använder|An=vän=der|3 +Apparat|Ap=pa=rat|3 +Apropå|Apro=på|3 +arbetet|ar=be=tet|3 +arbetsbänken|ar=bets=bän=ken|3 +artificiell|ar=ti=fi=ci=ell|3 +astrofagens|ast=ro=fa=gens|3 +astrofagpopulationen|ast=ro=fag=po=pu=la=tio=nen|3 +astrofagprover|ast=ro=fag=pro=ver|3 +astronaut|ast=ro=naut|3 +astronomer|ast=ro=no=mer|3 +astronomiska|ast=ro=no=mis=ka|3 +atmosfärs|at=mo=sfärs|3 +atmosfärtryck|at=mo=sfär=tryck|3 +Avbryt|Av=bryt|3 +avbröt|av=bröt|3 +avlägsna|av=lägs=na|3 +avslutar|av=slu=tar|3 +avstängda|av=stäng=da|3 +Avståndet|Av=stån=det|3 +avviker|av=vi=ker|3 +avvisas|av=vi=sas|3 +babords|ba=bords|3 +backar|back=ar|3 +badrum|bad=rum|3 +baktill|bak=till|3 +bandage|ban=da=ge|3 +batteri|bat=te=ri|3 +Beatles|Be=at=les|3 +bedöma|be=dö=ma|3 +bedömer|be=dö=mer|3 +behagligt|be=hag=ligt|3 +behandskade|be=hands=ka=de|3 +behåller|be=hål=ler|3 +behållit|be=hål=lit|3 +Behöver|Be=hö=ver|3 +belysning|be=lys=ning|3 +berättade|be=rät=ta=de|3 +beskriva|be=skri=va|3 +beskrivning|be=skriv=ning|3 +bestod|be=stod|3 +bestämd|be=stämd|3 +besväret|be=svä=ret|3 +besynnerligt|be=syn=ner=ligt|3 +besättningsavdelningen|be=sätt=nings=av=del=ning=en|3 +besättningsmedlemmarna|be=sätt=nings=med=lem=mar=na|3 +besöka|be=sö=ka|3 +betydande|be=ty=dan=de|3 +betydde|be=tyd=de|3 +betydelse|be=ty=del=se|3 +Betydligt|Be=tyd=ligt|3 +bevisa|be=vi=sa|3 +bevisar|be=vi=sar|3 +bisarrt|bi=sarrt|3 +Blandar|Blan=dar|3 +blodet|blo=det|3 +blänkande|blän=kan=de|3 +Bollen|Bol=len|3 +bollens|bol=lens|3 +bombarderas|bom=bar=de=ras|3 +bordets|bor=dets|3 +borrhuvudet|borr=hu=vu=det|3 +bortom|bort=om|3 +brinner|brin=ner|3 +brukade|bru=ka=de|3 +brydde|bryd=de|3 +brännskador|bränn=ska=dor|3 +Bränsle|Brän=sle|3 +bränsleenheter|brän=s=le=en=he=ter|3 +bränsleförrådet|brän=s=le=för=rå=det|3 +Bränslet|Brän=slet|3 +bränsletanken|brän=sle=tan=ken|3 +bulten|bul=ten|3 +byggnaden|bygg=na=den|3 +byggts|byggts|3 +bänkar|bän=kar|3 +bönpåsar|bön=på=sar|3 +Canton|Can=ton|3 +cellen|cel=len|3 +centrifugering|cen=tri=fu=ge=ring|3 +centripetalkraften|cen=tri=pe=tal=kraf=ten|3 +cirklar|cirk=lar|3 +citronsyracykeln|ci=tron=sy=ra=cy=keln|3 +cylindrarna|cy=lind=rar=na|3 +Dagens|Da=gens|3 +dagens|da=gens|3 +dammar|dam=mar|3 +datorskärmen|da=tor=skär=men|3 +decimeters|de=ci=me=ters|3 +delvis|del=vis|3 +desperata|de=spe=ra=ta|3 +dialogrutor|dia=lo=gru=tor|3 +diamant|dia=mant|3 +digital|di=gi=tal|3 +diskutera|dis=ku=te=ra|3 +djungeln|djung=eln|3 +djupare|dju=pa=re|3 +domare|do=ma=re|3 +dominerande|do=mi=ne=ran=de|3 +drabbas|drab=bas|3 +Driver|Dri=ver|3 +drivkraft|driv=kraft|3 +droppar|drop=par|3 +dräktens|dräk=tens|3 +dubbelkollar|dub=bel=kol=lar|3 +dubbla|dubb=la|3 +dubblas|dubb=las|3 +dunkar|dun=kar|3 +däcket|däck=et|3 +däremot|där=emot|3 +efteråt|ef=ter=åt|3 +egenskaper|egen=ska=per|3 +Egentligen|Egent=li=gen|3 +ekologi|eko=lo=gi|3 +elementen|ele=men=ten|3 +enerverande|ener=ve=ran=de|3 +ensamhet|en=sam=het|3 +enskild|en=skild|3 +Eridiskt|Eri=diskt|3 +ersatt|er=satt|3 +etiketterade|eti=ket=te=ra=de|3 +Evolutionen|Evo=lu=tio=nen|3 +evolutionära|evo=lu=tio=nä=ra|3 +existerar|ex=i=ste=rar|3 +experimenten|ex=pe=ri=men=ten|3 +exponentiell|ex=po=nen=ti=ell|3 +exponentiellt|ex=po=nen=ti=ellt|3 +extrem|ex=trem|3 +fallen|fal=len|3 +fanken|fan=ken|3 +fartyg|far=tyg|3 +fastskruvade|fast=skru=va=de|3 +felaktiga|fel=ak=ti=ga|3 +felsteg|fel=steg|3 +fiende|fi=en=de|3 +filten|fil=ten|3 +finner|fin=ner|3 +fjärrkontroll|fjärr=kon=troll|3 +fläckar|fläck=ar|3 +fläckigt|fläck=igt|3 +fnyste|fnys=te|3 +fokuserad|fo=ku=se=rad|3 +forskargrupp|fors=kar=grupp|3 +forskningsrapporter|forsk=nings=rap=por=ter|3 +fotoner|fo=to=ner|3 +framme|fram=me|3 +framtid|fram=tid|3 +fruktansvärd|fruk=tans=värd|3 +frusen|fru=sen|3 +främre|främ=re|3 +fräsen|frä=sen|3 +frånvarande|från=va=ran=de|3 +fumlar|fum=lar|3 +funkade|fun=ka=de|3 +funkar|fun=kar|3 +funktionell|funk=tio=nell|3 +funnits|fun=nits|3 +fyratusen|fy=ra=tu=sen|3 +fyrkantigt|fyr=kan=tigt|3 +fängelse|fäng=el=se|3 +fängelsecell|fäng=el=se=cell|3 +färder|fär=der|3 +färdigt|fär=digt|3 +färgerna|fär=ger=na|3 +fästad|fäs=tad|3 +förberedde|för=be=red=de|3 +förbinder|för=bin=der|3 +förbluffande|för=bluf=fan=de|3 +fördömda|för=döm=da|3 +fördömt|för=dömt|3 +föredrar|fö=re=drar|3 +föremålen|fö=re=må=len|3 +föreställde|fö=re=ställ=de|3 +företag|fö=re=tag|3 +förhoppningsvis|för=hopp=nings=vis|3 +Förklara|För=kla=ra|3 +förlorar|för=lo=rar|3 +förpackningen|för=pack=ning=en|3 +förslag|för=slag|3 +Första|Förs=ta|3 +förstoring|för=sto=ring|3 +försäkrar|för=säk=rar|3 +försökt|för=sökt|3 +Förtjust|För=tjust|3 +förtjusta|för=tju=sta|3 +förtvivlat|för=tviv=lat|3 +förvarar|för=va=rar|3 +förvarning|för=var=ning|3 +förvirrande|för=vir=ran=de|3 +förändrade|för=änd=ra=de|3 +förökar|för=ö=kar|3 +gemensam|ge=men=sam|3 +generationen|ge=ne=ra=tio=nen|3 +generationer|ge=ne=ra=tio=ner|3 +generera|ge=ne=re=ra|3 +genomförde|ge=nom=för=de|3 +genomsnitt|ge=nom=snitt|3 +genomsnittliga|ge=nom=snitt=li=ga|3 +Genève|Genève|3 +gester|ges=ter|3 +gigantisk|gi=gan=tisk|3 +gissningar|giss=ning=ar|3 +gissningsvis|giss=nings=vis|3 +gjordes|gjor=des|3 +Glaset|Gla=set|3 +glasögonen|glas=ögo=nen|3 +global|glo=bal|3 +globala|glo=ba=la|3 +glöder|glö=der|3 +glömma|glöm=ma|3 +grannar|gran=nar|3 +granskar|grans=kar|3 +Grejen|Gre=jen|3 +grejen|gre=jen|3 +grekiska|gre=kis=ka|3 +grundligt|grund=ligt|3 +gummit|gum=mit|3 +gällande|gäl=lan=de|3 +gänget|gäng=et|3 +halsbandet|hals=ban=det|3 +Halvvägs|Halv=vägs|3 +hammare|ham=ma=re|3 +hamnat|ham=nat|3 +handfull|hand=full|3 +handla|hand=la|3 +handleden|hand=le=den|3 +hangardäcket|han=gar=däck=et|3 +hanterar|han=te=rar|3 +harmlöst|harm=löst|3 +hasade|ha=sa=de|3 +hastigt|has=tigt|3 +Hawaii|Ha=waii|3 +Helikoptern|He=li=kop=tern|3 +helium|he=li=um|3 +heltäckande|hel=täck=an=de|3 +hemfärden|hem=fär=den|3 +hemresan|hem=re=san|3 +herregud|her=re=gud|3 +hetare|he=ta=re|3 +Hettan|Het=tan|3 +hettar|het=tar|3 +hexagoner|hexa=go=ner|3 +hexagonväggen|hexa=gon=väg=gen|3 +hindrar|hind=rar|3 +Hittills|Hit=tills|3 +hjärnor|hjär=nor|3 +hoppats|hop=pats|3 +Hopplöst|Hopp=löst|3 +Hoppsan|Hopp=san|3 +huvudmotorerna|hu=vud=mo=to=rer=na|3 +huvudsak|hu=vud=sak|3 +huvudände|hu=vud=än=de|3 +hylsnyckeln|hyls=nyck=eln|3 +hällde|häll=de|3 +häller|häl=ler|3 +hänsyn|hän=syn|3 +Härifrån|Här=i=från|3 +hårddiskar|hård=dis=kar|3 +höfterna|höf=ter=na|3 +högljudd|hög=ljudd|3 +högstadielärare|hög=sta=die=lä=ra=re|3 +högupplöst|hö=gupp=löst|3 +höjden|höj=den|3 +hördes|hör=des|3 +ibland|ibland|3 +idealiska|ide=a=lis=ka|3 +identisk|iden=tisk|3 +inblandade|in=blan=da=de|3 +infekterades|in=fek=te=ra=des|3 +infekterats|in=fek=te=rats|3 +ingången|in=gång=en|3 +innehåll|in=ne=håll|3 +insekt|in=sekt|3 +insisterade|in=si=ste=ra=de|3 +installera|in=stal=le=ra|3 +instruktioner|in=struk=tio=ner|3 +instämmer|in=stäm=mer|3 +internationella|in=ter=na=tio=nel=la|3 +intressanta|in=tres=san=ta|3 +intresse|in=tres=se|3 +invändningar|in=vänd=ning=ar|3 +irriterar|ir=ri=te=rar|3 +isolering|iso=le=ring|3 +japanska|ja=pans=ka|3 +Justera|Ju=ste=ra|3 +justerade|ju=ste=ra=de|3 +jämför|jäm=för|3 +kaffet|kaf=fet|3 +kalkylbladet|kal=kyl=bla=det|3 +kamerabild|ka=me=ra=bild|3 +kanadensare|ka=na=den=sa=re|3 +kandidaterna|kan=di=da=ter=na|3 +kanter|kan=ter|3 +karriär|kar=ri=är|3 +kartan|kar=tan|3 +Kassera|Kas=se=ra|3 +katalog|ka=ta=log|3 +katalogiserar|ka=ta=lo=gi=se=rar|3 +kateter|ka=te=ter|3 +Kedjan|Ked=jan|3 +kemiska|ke=mis=ka|3 +kinesiskt|ki=ne=siskt|3 +klagar|kla=gar|3 +klassen|klas=sen|3 +klimatolog|kli=ma=to=log|3 +klistret|klist=ret|3 +kloten|klo=ten|3 +klyftigare|klyf=ti=ga=re|3 +klämmer|kläm=mer|3 +knäpper|knäp=per|3 +koldioxidens|kol=di=ox=i=dens|3 +kolmörkt|kol=mörkt|3 +komaresistens|ko=ma=re=sis=tens|3 +komaresistenta|ko=ma=re=sis=ten=ta|3 +kompatibla|kom=pa=tib=la|3 +komponenterna|kom=po=nen=ter=na|3 +konstanta|kon=stan=ta|3 +konstruerats|kon=stru=e=rats|3 +konstruktion|kon=struk=tion|3 +kontor|kon=tor|3 +KONTROLL|KON=TROLL|3 +Kontrollrummet|Kon=troll=rum=met|3 +kontrollspaken|kon=troll=spa=ken|3 +kopior|ko=pi=or|3 +kopplar|kopp=lar|3 +kopplat|kopp=lat|3 +kroppens|krop=pens|3 +kroppstemperatur|kropps=tem=pe=ra=tur|3 +kränger|kräng=er|3 +krävde|kräv=de|3 +kubikroten|ku=bik=ro=ten|3 +kulorna|ku=lor=na|3 +kultur|kul=tur|3 +kunskap|kun=skap|3 +kvadratsekund|kvad=rat=se=kund|3 +kvarts|kvarts|3 +kvinnan|kvin=nan|3 +kännas|kän=nas|3 +känslan|käns=lan|3 +kärnreaktor|kärn=re=ak=tor|3 +labbtaket|labb=ta=ket|3 +labbutrustningen|lab=b=ut=rust=ning=en|3 +landar|lan=dar|3 +laterala|la=te=ra=la|3 +ledande|le=dan=de|3 +ledigt|le=digt|3 +lektionen|lek=tio=nen|3 +lindar|lin=dar|3 +lindrigt|lind=rigt|3 +livsformen|livs=for=men|3 +ljusare|lju=sa=re|3 +ljusasken|lju=sas=ken|3 +ljusenergi|ljusener=gi|3 +ljusfläck|ljus=fläck|3 +ljusglimt|ljus=glimt|3 +ljusvåglängder|ljus=våg=läng=der|3 +luftflöde|luft=flö=de|3 +luftslussdörren|luft=sluss=dör=ren|3 +lufttryck|luft=tryck|3 +lufttätt|luft=tätt|3 +Lukten|Luk=ten|3 +lungor|lung=or|3 +lungorna|lung=or=na|3 +Lungorna|Lung=or=na|3 +Luther|Lut=her|3 +lysande|ly=san=de|3 +lysdiod|lys=diod|3 +lyssnade|lyss=na=de|3 +lämplig|lämp=lig|3 +länkade|län=ka=de|3 +lättnad|lätt=nad|3 +låtsas|låt=sas|3 +lömskt|lömskt|3 +lösningar|lös=ning=ar|3 +magneterna|mag=ne=ter=na|3 +MANUELL|MA=NU=ELL|3 +manövern|ma=nö=vern|3 +Marissa|Ma=ris=sa|3 +markerar|mar=ke=rar|3 +markeringarna|mar=ke=ring=ar=na|3 +massacentrum|mas=sa=cen=trum|3 +massiva|mas=si=va|3 +materia|ma=te=ria|3 +maximal|max=i=mal|3 +meddelar|med=de=lar|3 +medicin|me=di=cin|3 +mentala|men=ta=la|3 +metallegeringar|me=tal=le=ge=ring=ar|3 +metaller|me=tal=ler|3 +metallplatta|me=tall=plat=ta|3 +metallrör|me=tall=rör|3 +metallskenan|me=tall=s=ke=nan|3 +metamorfa|me=ta=mor=fa|3 +metoder|me=to=der|3 +metriskt|met=riskt|3 +middag|mid=dag|3 +mikrobiolog|mik=ro=bi=o=log|3 +mikrogram|mik=ro=gram|3 +mikrovågor|mik=ro=vå=gor|3 +Mindre|Mind=re|3 +mineraler|mi=ne=ra=ler|3 +minimal|mi=ni=mal|3 +miniodlingar|mi=ni=od=ling=ar|3 +Miniodlingarna|Mi=ni=od=ling=ar=na|3 +minister|mi=nis=ter|3 +minnen|min=nen|3 +Minska|Mins=ka|3 +minskas|mins=kas|3 +missat|mis=sat|3 +Misslyckades|Miss=lyck=a=des|3 +misslyckande|miss=lyck=an=de|3 +mittlinje|mitt=lin=je|3 +mittpunkten|mitt=punk=ten|3 +modifiera|mo=di=fi=e=ra|3 +molekylerna|mo=le=ky=ler=na|3 +monumentalt|mo=nu=men=talt|3 +morrhåren|morr=hå=ren|3 +motorcykel|mo=tor=cy=kel|3 +motsatsen|mot=sat=sen|3 +motstår|mot=står|3 +motsvarande|mot=sva=ran=de|3 +motvikt|mot=vikt|3 +männen|män=nen|3 +Mänskligheten|Mänsk=lig=he=ten|3 +märklig|märk=lig|3 +märkliga|märk=li=ga|3 +måttenheter|måt=ten=he=ter|3 +möjligheten|möj=lig=he=ten|3 +Möjligt|Möj=ligt|3 +mörkare|mör=ka=re|3 +mörkret|mörk=ret|3 +nackstödet|nack=stö=det|3 +namnen|nam=nen|3 +nanometer|na=no=me=ter|3 +nationella|na=tio=nel=la|3 +naturligt|na=tur=ligt|3 +naturvetenskap|na=tur=ve=ten=skap|3 +navigation|na=vi=ga=tion|3 +Navigation|Na=vi=ga=tion|3 +navigera|na=vi=ge=ra|3 +nedanför|ne=dan=för|3 +Neutriner|Ne=u=tri=ner|3 +nittionio|nit=tio=nio|3 +Nitton|Nit=ton|3 +noskon|no=s=kon|3 +nyanser|ny=an=ser|3 +nödventilen|nöd=ven=ti=len|3 +nödvändig|nöd=vän=dig|3 +obehagliga|obe=hag=li=ga|3 +obehagligt|obe=hag=ligt|3 +objektets|ob=jek=tets|3 +observerad|ob=ser=ve=rad|3 +observerar|ob=ser=ve=rar|3 +odlingar|od=ling=ar|3 +Odlingarna|Od=ling=ar=na|3 +ogenomskinliga|oge=nom=skin=li=ga|3 +omedelbar|ome=del=bar|3 +omfattande|om=fat=tan=de|3 +omkrets|om=krets|3 +områden|om=rå=den|3 +omtänksamt|om=tänk=samt|3 +ordnat|ord=nat|3 +oregelbundna|ore=gel=bund=na|3 +oroligt|oro=ligt|3 +oräkneliga|oräk=ne=li=ga|3 +osannolik|osan=no=lik|3 +otrolig|otro=lig|3 +outtalad|out=ta=lad|3 +Ovanför|Ovan=för|3 +oxider|ox=i=der|3 +paneler|pa=ne=ler|3 +paniken|pa=ni=ken|3 +panorera|pa=no=re=ra|3 +passande|pas=san=de|3 +passar|pas=sar|3 +passera|pas=se=ra|3 +passerat|pas=se=rat|3 +pendeln|pen=deln|3 +pendlingar|pend=ling=ar|3 +pennan|pen=nan|3 +Petrovaskopets|Pe=tro=vas=ko=pets|3 +pilade|pi=la=de|3 +Pilatus|Pi=la=tus|3 +pillade|pil=la=de|3 +piloten|pi=lo=ten|3 +pilotstol|pi=lot=stol|3 +pipetter|pi=pet=ter|3 +placerad|pla=ce=rad|3 +placerat|pla=ce=rat|3 +planen|pla=nen|3 +Planet|Pla=net|3 +plastbehållare|plast=be=hål=la=re|3 +plattan|plat=tan|3 +pluggen|plug=gen|3 +polare|po=la=re|3 +positivt|po=si=tivt|3 +praktiska|prak=tis=ka|3 +Predator|Pre=da=tor|3 +present|pre=sent|3 +president|pre=si=dent|3 +Presidenten|Pre=si=den=ten|3 +presidenten|pre=si=den=ten|3 +primärbesättningen|pri=mär=be=sätt=ning=en|3 +privat|pri=vat|3 +procedur|pro=ce=dur|3 +procents|pro=cents|3 +produceras|pro=du=ce=ras|3 +programvara|pro=gram=va=ra|3 +provglas|prov=glas|3 +provlådan|prov=lå=dan|3 +prövade|prö=va=de|3 +prövar|prö=var|3 +pumpade|pum=pa=de|3 +pumpas|pum=pas|3 +pumpen|pum=pen|3 +pålitliga|på=lit=li=ga|3 +påverkade|på=ver=ka=de|3 +påverkas|på=ver=kas|3 +påverkats|på=ver=kats|3 +radien|ra=di=en|3 +radiosignal|ra=dio=sig=nal|3 +Rapportera|Rap=por=te=ra|3 +rastrummet|ra=strum=met|3 +reaktion|re=ak=tion|3 +reaktionstid|re=ak=tions=tid|3 +regionen|re=gi=o=nen|3 +regler|reg=ler|3 +rensar|ren=sar|3 +respekt|re=spekt|3 +respons|re=spons|3 +riktat|rik=tat|3 +rimligtvis|rim=ligt=vis|3 +riskabelt|ris=ka=belt|3 +ritningen|rit=ning=en|3 +ritual|ri=tu=al|3 +rotationshuvudet|ro=ta=tions=hu=vu=det|3 +roteras|ro=te=ras|3 +rotorn|ro=torn|3 +ruttna|rutt=na|3 +ryckning|ryck=ning|3 +ryggluckan|rygg=luck=an|3 +ryggpansaret|rygg=pan=sa=ret|3 +ryggsköld|rygg=sköld|3 +rymdens|rym=dens|3 +rymdskeppet|rymd=skep=pet|3 +rymdstationerna|rymd=sta=tio=ner=na|3 +rynkade|ryn=ka=de|3 +ryssar|rys=sar|3 +Ryssen|Rys=sen|3 +räckvidd|räck=vidd|3 +räddade|räd=da=de|3 +räddare|räd=da=re|3 +räkning|räk=ning|3 +rättare|rät=ta=re|3 +röntgenspektrometer|rönt=gen=spekt=ro=me=ter|3 +rörliga|rör=li=ga|3 +sabotera|sa=bo=te=ra|3 +samfundet|sam=fun=det|3 +sanningen|san=ning=en|3 +Sarkasm|Sar=kasm|3 +Saskatchewan|Sas=kat=chewan|3 +sekunderna|se=kun=der=na|3 +sekunders|se=kun=ders|3 +sensorer|sen=so=rer|3 +sexuella|sex=u=el=la|3 +signal|sig=nal|3 +Situationen|Si=tu=a=tio=nen|3 +situationer|si=tu=a=tio=ner|3 +Själva|Själ=va|3 +Skaffa|Skaf=fa|3 +skiftnyckel|skift=nyck=el|3 +skiljer|skil=jer|3 +skjortan|skjor=tan|3 +skopet|sko=pet|3 +skottet|skot=tet|3 +skrapa|skra=pa|3 +skriker|skri=ker|3 +skrivbord|skriv=bord|3 +skrivtecken|skriv=teck=en|3 +Skrovroboten|Skrov=ro=bo=ten|3 +skruvhålen|skruv=hå=len|3 +skruvmejsel|skruv=mej=sel|3 +skrymsle|skryms=le|3 +skräckinjagande|skräck=in=ja=gan=de|3 +skräpet|skrä=pet|3 +skyddat|skyd=dat|3 +skyddsdräkten|skydds=dräk=ten|3 +skyldig|skyl=dig|3 +skämtar|skäm=tar|3 +skölden|sköl=den|3 +sköljer|sköl=jer|3 +slangar|slang=ar|3 +slangarna|slang=ar=na|3 +slappna|slapp=na|3 +slingrar|sling=rar|3 +slumpmässig|slump=mäs=sig|3 +Slutet|Slu=tet|3 +släppt|släppt|3 +slöseri|slö=se=ri|3 +smarta|smar=ta|3 +Snabbt|Snabbt|3 +sneglar|sneg=lar|3 +snurrande|snur=ran=de|3 +snälla|snäl=la|3 +snöret|snö=ret|3 +social|so=ci=al|3 +soffan|sof=fan|3 +solfläckar|sol=fläck=ar|3 +solljuset|sol=lju=set|3 +solskivans|sol=ski=vans|3 +sortens|sor=tens|3 +specifik|spe=ci=fik|3 +spektrometern|spekt=ro=me=tern|3 +spelade|spe=la=de|3 +spelat|spe=lat|3 +Spindriften|Spindrif=ten|3 +spindriftskontrollerna|spindrifts=kon=trol=ler=na|3 +sponken|spon=ken|3 +spricka|spricka|3 +sprickor|sprick=or|3 +springa|springa|3 +sprutan|spru=tan|3 +spårgaser|spår=ga=ser|3 +stabilisera|sta=bi=li=se=ra|3 +stadig|sta=dig|3 +stammen|stam=men|3 +starten|star=ten|3 +staternas|sta=ter=nas|3 +statisk|sta=tisk|3 +steniga|ste=ni=ga|3 +sticka|sticka|3 +stimulus|sti=mu=lus|3 +stjärnans|stjär=nans|3 +Stjärnor|Stjär=nor|3 +stoftpartiklar|stoft=par=tik=lar|3 +stolarna|sto=lar=na|3 +Stolen|Sto=len|3 +struntade|strun=ta=de|3 +sträcka|sträcka|3 +strålar|strå=lar|3 +studier|stu=di=er|3 +styrkan|styr=kan|3 +styrsystemet|styr=sys=te=met|3 +ständigt|stän=digt|3 +stålliknande|stål=lik=nan=de|3 +stållådan|stållå=dan|3 +stöter|stö=ter|3 +superdatorer|su=per=da=to=rer|3 +svalnar|sval=nar|3 +svartcellerna|svart=cel=ler=na|3 +svaveldioxid|sva=vel=di=ox=id|3 +svider|svi=der|3 +svordomar|svor=do=mar|3 +sväljer|sväl=jer|3 +svärtan|svär=tan|3 +svävande|svä=van=de|3 +svåraste|svå=ras=te|3 +symboler|sym=bo=ler|3 +symbolerna|sym=bo=ler=na|3 +Synligt|Syn=ligt|3 +synnerligen|syn=ner=li=gen|3 +Systemet|Sys=te=met|3 +säkerhet|sä=ker=het|3 +sällan|säl=lan|3 +sällskap|säll=skap|3 +sämsta|säms=ta|3 +sängarna|säng=ar=na|3 +sängkläderna|säng=klä=der=na|3 +Särskilt|Sär=skilt|3 +Sätter|Sät=ter|3 +Sådana|Så=da=na|3 +såvida|så=vi=da|3 +sökning|sök=ning|3 +Tanken|Tan=ken|3 +tauljus|tau=ljus|3 +tauljuset|tau=lju=set|3 +taumöbainfektion|tau=mö=ba=in=fek=tion|3 +taumöbornas|tau=mö=bor=nas|3 +teamet|tea=met|3 +tekniker|tek=ni=ker|3 +teknikerna|tek=ni=ker=na|3 +teleskop|te=le=skop|3 +temperaturer|tem=pe=ra=tu=rer|3 +tennisboll|ten=nis=boll|3 +terabyte|te=ra=by=te|3 +tester|tes=ter|3 +testet|tes=tet|3 +tickar|tick=ar|3 +tidsdilation|tids=di=la=tion|3 +tidsdilationen|tids=di=la=tio=nen|3 +tillbringade|till=bring=a=de|3 +tillfredsställande|till=freds=stäl=lan=de|3 +tillgängliga|till=gäng=li=ga|3 +tillgängligt|till=gäng=ligt|3 +tingesten|ting=es=ten|3 +tjugofem|tju=go=fem|3 +Tjugonio|Tju=go=nio|3 +tjugoniotusen|tju=go=nio=tu=sen|3 +Tjugosex|Tju=go=sex|3 +tonerna|to=ner=na|3 +tornet|tor=net|3 +Totalt|To=talt|3 +trakten|trak=ten|3 +trappan|trap=pan|3 +trasslar|trass=lar|3 +tredjedel|tred=je=del|3 +tryckt|tryckt|3 +trygga|tryg=ga|3 +tråden|trå=den|3 +Tråkigt|Trå=kigt|3 +trångt|trångt|3 +tröghet|trög=het|3 +tuggar|tug=gar|3 +tunnelns|tun=nelns|3 +tunnlar|tunn=lar|3 +tursamt|tur=samt|3 +tusendel|tu=sen=del|3 +tvingas|tving=as|3 +tvätta|tvät=ta|3 +tvåhundrasexton|två=hund=ra=sex=ton|3 +tydligare|tyd=li=ga=re|3 +tydligt|tyd=ligt|3 +tyngdlös|tyngd=lös|3 +tyngre|tyng=re|3 +täckta|täck=ta|3 +tänkande|tän=kan=de|3 +tänkmaskin|tänk=ma=skin|3 +Tårarna|Tå=rar=na|3 +ultraviolett|ult=ra=vi=o=lett|3 +underbara|un=der=ba=ra|3 +undersöker|un=der=sö=ker|3 +uppenbara|uppen=ba=ra|3 +uppenbarligen|uppen=bar=li=gen|3 +Uppenbarligen|Uppen=bar=li=gen|3 +uppfann|upp=fann|3 +uppfinning|upp=fin=ning|3 +uppföra|upp=fö=ra|3 +uppgifter|upp=gif=ter|3 +uppifrån|upp=i=från|3 +upplyst|upp=lyst|3 +uppoffring|upp=off=ring|3 +upprepa|upp=re=pa|3 +uppskattningar|upp=skatt=ning=ar|3 +Uppskjutningen|Upp=skjut=ning=en|3 +upptagna|upp=tag=na|3 +upptäckter|upp=täck=ter|3 +utbrast|ut=brast|3 +utdata|ut=da=ta|3 +utlovat|ut=lo=vat|3 +utmaning|ut=ma=ning|3 +Utmärkt|Ut=märkt|3 +Utomjordingar|Ut=om=jor=ding=ar|3 +uträkning|ut=räk=ning|3 +utsikt|ut=sikt|3 +utskrifter|ut=skrif=ter|3 +utsträckta|ut=sträck=ta|3 +utstrålade|ut=strå=la=de|3 +utsätta|ut=sät=ta|3 +utsätts|ut=sätts|3 +utsöndrar|ut=sönd=rar|3 +uttryckt|ut=tryckt|3 +utvalda|ut=val=da|3 +utvecklad|ut=veck=lad|3 +utvecklar|ut=veck=lar|3 +utöver|ut=över|3 +vackert|vack=ert|3 +vakter|vak=ter|3 +vakterna|vak=ter=na|3 +Vakterna|Vak=ter=na|3 +valsång|val=sång|3 +varannan|var=an=nan|3 +varelser|va=rel=ser|3 +variant|va=ri=ant|3 +variation|va=ri=a=tion|3 +varierar|va=ri=e=rar|3 +varifrån|var=i=från|3 +varvet|var=vet|3 +vattnets|vatt=nets|3 +veckan|veck=an|3 +verkliga|verk=li=ga|3 +version|ver=sion|3 +vetenskapen|ve=ten=ska=pen|3 +vettigt|vet=tigt|3 +vettlöst|vett=löst|3 +viftade|vif=ta=de|3 +vilade|vi=la=de|3 +VINKELANOMALI|VIN=KE=LA=NO=MA=LI|3 +vinklade|vink=la=de|3 +Väggen|Väg=gen|3 +välbekanta|väl=be=kan=ta|3 +värden|vär=den|3 +värmekälla|vär=me=käl=la|3 +väsentligt|vä=sent=ligt|3 +väskor|väsk=or|3 +vätskor|väts=kor|3 +xenonitväggarna|xe=no=nit=väg=gar=na|3 +ynkrygg|ynk=rygg|3 +ytterdörren|yt=ter=dör=ren|3 +Ytterligare|Yt=ter=li=ga=re|3 +ytterluckan|yt=ter=luck=an|3 +ytterporten|yt=ter=por=ten|3 +äcklig|äck=lig|3 +äckligt|äck=ligt|3 +ändarna|än=dar=na|3 +ärligt|är=ligt|3 +Ärligt|Är=ligt|3 +återfinns|åter=finns|3 +ÅTERSTÅENDE|ÅTER=STÅ=EN=DE|3 +ödemark|öde=mark|3 +Ögonen|Ögo=nen|3 +önskemål|öns=ke=mål|3 +öppnades|öpp=na=des|3 +öppningar|öpp=ning=ar|3 +överflöd|över=flöd|3 +översätter|över=sät=ter|3 +absoluta|ab=so=lu=ta|2 +abstrakt|ab=strakt|2 +Absurt|Ab=surt|2 +Accelerationen|Ac=ce=le=ra=tio=nen|2 +accelererade|ac=ce=le=re=ra=de|2 +accepterar|ac=cep=te=rar|2 +adenosintrifosfat|ade=no=sintri=fos=fat|2 +administratör|ad=mi=ni=stra=tör|2 +Adrianmiljö|Ad=ri=an=mil=jö|2 +agerar|ag=e=rar|2 +akterdelen|ak=ter=de=len|2 +aktiverad|ak=ti=ve=rad|2 +Alldeles|All=de=les|2 +allmänna|all=män=na|2 +allmänt|all=mänt|2 +allvarliga|all=var=li=ga|2 +aluminiumplåt|alu=mi=ni=ump=låt|2 +andningsmask|and=nings=mask|2 +angrepp|an=grepp|2 +anmäla|an=mä=la|2 +anmälde|an=mäl=de|2 +Annars|An=nars|2 +anrika|an=ri=ka|2 +ansvarig|an=sva=rig|2 +antagit|an=ta=git|2 +anteckningsblock|an=teck=nings=block|2 +Antibiotika|An=ti=bi=o=ti=ka|2 +antika|an=ti=ka|2 +antimateria|an=ti=ma=te=ria|2 +antyder|an=ty=der|2 +använts|an=vänts|2 +apoapsis|apo=apsis|2 +apparater|ap=pa=ra=ter|2 +apparaterna|ap=pa=ra=ter=na|2 +Arbeta|Ar=be=ta|2 +Arbetar|Ar=be=tar|2 +arrangerade|ar=ran=ge=ra=de|2 +artighet|ar=tig=het|2 +asteroider|as=te=ro=i=der|2 +astrofagbränsle|ast=ro=fag=brän=sle|2 +Astrofagen|Ast=ro=fa=gen|2 +astrofagfyllda|ast=ro=fag=fyll=da|2 +astrofagglas|ast=ro=fagg=las|2 +astrofagpanelen|ast=ro=fag=pa=ne=len|2 +astrofagproblemet|ast=ro=fag=pro=ble=met|2 +astrofagsvets|ast=ro=fagsvets|2 +astrofagsvetsen|ast=ro=fagsvet=sen|2 +astronom|ast=ro=nom|2 +astronomerna|ast=ro=no=mer=na|2 +astronomi|ast=ro=no=mi|2 +atomerna|ato=mer=na|2 +attityd|at=ti=tyd|2 +attraherar|at=tra=he=rar|2 +autentiskt|au=ten=tiskt|2 +AUTOKORRIGERAS|AU=TO=KOR=RI=GE=RAS|2 +automatiska|au=to=ma=tis=ka|2 +avbalkning|av=balk=ning|2 +avbalkningar|av=balk=ning=ar|2 +avbrott|av=brott|2 +avbryter|av=bry=ter|2 +avfärdande|av=fär=dan=de|2 +avfärdar|av=fär=dar|2 +Avgjort|Av=gjort|2 +avklarat|av=kla=rat|2 +Avläsningarna|Av=läs=ning=ar=na|2 +avläsningen|av=läs=ning=en|2 +avlång|av=lång|2 +avrundade|av=run=da=de|2 +avsevärt|av=se=värt|2 +avskuren|av=sku=ren|2 +avskyr|av=skyr|2 +avslutat|av=slu=tat|2 +avstängd|av=stängd|2 +avstängningsventiler|av=stäng=nings=ven=ti=ler|2 +avtryckare|av=tryck=a=re|2 +avvara|av=va=ra|2 +backup|back=up|2 +backupsystem|back=up=sys=tem|2 +badrummet|bad=rum=met|2 +bakifrån|bak=i=från|2 +baksida|bak=si=da|2 +baksidan|bak=si=dan|2 +balans|ba=lans|2 +balansen|ba=lan=sen|2 +balansera|ba=lan=se=ra|2 +bandagen|ban=da=gen|2 +bandagerade|ban=da=ge=ra=de|2 +barnsliga|barns=li=ga|2 +baseras|ba=se=ras|2 +baserat|ba=se=rat|2 +batteriet|bat=te=ri=et|2 +beakta|be=ak=ta|2 +beboeliga|be=bo=e=li=ga|2 +bedrövligt|be=dröv=ligt|2 +beetle|be=et=le|2 +beetles|be=et=les|2 +Beetles|Be=et=les|2 +Befann|Be=fann|2 +befolkningen|be=folk=ning=en|2 +befälet|be=fä=let|2 +begagnar|be=gag=nar|2 +begränsa|be=grän=sa|2 +behandla|be=hand=la|2 +behandling|be=hand=ling|2 +behövas|be=hö=vas|2 +Beklagar|Be=kla=gar|2 +bekräftade|be=kräf=ta=de|2 +bekräftelse|be=kräf=tel=se|2 +bekväma|be=kvä=ma|2 +bekvämare|be=kvä=ma=re|2 +belysningen|be=lys=ning=en|2 +beläget|be=lä=get|2 +beordrar|be=ord=rar|2 +Beroende|Be=ro=en=de|2 +beräknade|be=räk=na=de|2 +beräkning|be=räk=ning|2 +berörd|be=rörd|2 +besannas|be=san=nas|2 +Beslutet|Be=slu=tet|2 +bestämda|be=stäm=da|2 +bestämde|be=stäm=de|2 +bestämma|be=stäm=ma|2 +besvarar|be=sva=rar|2 +besättningsenheten|be=sätt=nings=en=he=ten|2 +Besättningsenhetens|Be=sätt=nings=en=he=tens|2 +besättningskamrat|be=sätt=nings=kam=rat|2 +besättningsutrymmet|be=sätt=nings=ut=rym=met|2 +beteendet|be=te=en=det|2 +betjänar|be=tjä=nar|2 +betraktade|be=trak=ta=de|2 +betraktar|be=trak=tar|2 +betydelsefull|be=ty=del=se=full|2 +betydelsefullt|be=ty=del=se=fullt|2 +betydelselös|be=ty=del=se=lös|2 +Betyder|Be=ty=der|2 +bevisade|be=vi=sa=de|2 +bibehåller|bi=be=hål=ler|2 +biljett|bil=jett|2 +binder|bin=der|2 +biologer|bio=lo=ger|2 +bisarr|bi=sarr|2 +bjuder|bju=der|2 +blanka|blan=ka|2 +blekgröna|blek=grö=na|2 +bleknade|blek=na=de|2 +blickstilla|blick=stil=la|2 +blinka|blin=ka|2 +blinkade|blin=ka=de|2 +Blixten|Blix=ten|2 +blockerar|block=e=rar|2 +blodprov|blod=prov|2 +blotta|blot=ta|2 +blygsam|blyg=sam|2 +bländande|blän=dan=de|2 +bokade|bo=ka=de|2 +bokstaven|bok=sta=ven|2 +bomullspinne|bom=ull=s=pin=ne|2 +bomullspinnen|bom=ull=s=pin=nen|2 +Bomullspinnen|Bom=ull=s=pin=nen|2 +bostäder|bo=stä=der|2 +bredast|bre=dast|2 +Bredvid|Bred=vid|2 +brickor|brick=or|2 +British|Bri=tish|2 +britsen|brit=sen|2 +Brukar|Bru=kar|2 +brutal|bru=tal|2 +brutala|bru=ta=la|2 +brutalt|bru=talt|2 +brännsåren|bränn=så=ren|2 +Bränslekapslarna|Brän=s=le=kaps=lar=na|2 +bränsleledning|brän=s=le=led=ning|2 +bränsleledningar|brän=s=le=led=ning=ar|2 +bränslesystemet|brän=sle=sys=te=met|2 +Bränsletankarna|Brän=sle=tan=kar=na|2 +brådska|bråds=ka|2 +bröder|brö=der|2 +buckla|buck=la|2 +bultarna|bul=tar=na|2 +bunker|bun=ker|2 +bunten|bun=ten|2 +butter|but=ter|2 +bökiga|bö=ki=ga|2 +Börjar|Bör=jar|2 +Centauri|Cent=au=ri|2 +centimeters|cen=ti=me=ters|2 +Centrifug|Cen=tri=fug|2 +centrifugalgravitation|cen=tri=fu=gal=gra=vi=ta=tion|2 +centrifugalkonfiguration|cen=tri=fu=gal=kon=fi=gu=ra=tion|2 +Centrifugalkraften|Cen=tri=fu=gal=kraf=ten|2 +centrifugkonfiguration|cen=tri=fug=kon=fi=gu=ra=tion|2 +centrifugkonfigurationen|cen=tri=fug=kon=fi=gu=ra=tio=nen|2 +centripetalkraft|cen=tri=pe=tal=kraft|2 +chefsforskarna|chefs=fors=kar=na|2 +chockad|chock=ad|2 +cirklarna|cirk=lar=na|2 +cirkulationssystem|cir=ku=la=tions=sys=tem|2 +cirkulationssystemet|cir=ku=la=tions=sys=te=met|2 +Columbia|Co=lum=bia|2 +coolaste|coo=las=te|2 +cylindrar|cy=lind=rar|2 +cylindrisk|cy=lind=risk|2 +datorerna|da=to=rer=na|2 +datorprogram|da=tor=pro=gram|2 +decelererar|de=ce=le=re=rar|2 +decennium|de=cen=ni=um|2 +definierar|de=fi=ni=e=rar|2 +degenerera|de=ge=ne=re=ra|2 +depression|de=pres=sion|2 +detaljerade|de=tal=je=ra=de|2 +detaljerna|de=tal=jer=na|2 +Diagrammet|Dia=gram=met|2 +dialekt|dia=lekt|2 +dialogruta|dia=lo=gru=ta|2 +digitala|di=gi=ta=la|2 +dingla|ding=la|2 +diplomaten|dip=lo=ma=ten|2 +diskuterade|dis=ku=te=ra=de|2 +djungel|djung=el|2 +djupanalyser|dju=p=ana=ly=ser|2 +djurens|dju=rens|2 +doktorander|dok=to=ran=der|2 +dokument|do=ku=ment|2 +Domaren|Do=ma=ren|2 +domstolsbetjänten|dom=stols=be=tjän=ten|2 +drabbar|drab=bar|2 +drabbats|drab=bats|2 +dragkraften|drag=kraf=ten|2 +dragningskraft|drag=nings=kraft|2 +drivmedel|driv=me=del|2 +drivmetod|driv=me=tod|2 +Dräkten|Dräk=ten|2 +dräkterna|dräk=ter=na|2 +dräktradion|dräkt=ra=di=on|2 +drämde|dräm=de|2 +dubbel|dub=bel|2 +duktig|duk=tig|2 +dunsar|dun=sar|2 +dussin|dus=sin|2 +dvärgbrytare|dvärg=bry=ta=re|2 +dygnen|dyg=nen|2 +dystert|dys=tert|2 +dystra|dyst=ra|2 +dåliga|då=li=ga|2 +dödlig|död=lig|2 +dödsfallen|döds=fal=len|2 +eftermiddag|ef=ter=mid=dag|2 +Efteråt|Ef=ter=åt|2 +egenskap|egen=skap|2 +egentlig|egent=lig|2 +egentliga|egent=li=ga|2 +Einstein|Ein=stein|2 +ekolokalisering|eko=lo=ka=li=se=ring|2 +ekosystemet|eko=sys=te=met|2 +elektrisk|el=ekt=risk|2 +elektriskt|el=ekt=riskt|2 +elektromagnetiska|el=ekt=ro=mag=ne=tis=ka|2 +elektron|el=ekt=ron|2 +elektronik|el=ekt=ro=nik|2 +elementär|ele=men=tär|2 +elliptiska|el=lip=tis=ka|2 +elände|elän=de|2 +emissioner|emis=sio=ner|2 +enades|ena=des|2 +Encelliga|Encel=li=ga|2 +endera|en=de=ra|2 +energilagringsmedium|ener=gi=lag=rings=me=di=um|2 +energimängder|ener=gi=m=äng=der|2 +enfald|en=fald|2 +engagerad|en=ga=ge=rad|2 +engelskt|eng=elskt|2 +engelsman|eng=els=man|2 +enheten|en=he=ten|2 +ensamma|en=sam=ma|2 +entusiastisk|en=tu=si=as=tisk|2 +epoxilimmar|epox=i=lim=mar|2 +erbjöd|er=bjöd|2 +erfarenhet|er=fa=ren=het|2 +ERFORDRAS|ER=FORD=RAS|2 +Eridanis|Eri=da=nis|2 +ersätta|er=sät=ta|2 +etikett|eti=kett|2 +etthundrasjuttiotre|ett=hund=ra=sjut=tio=tre|2 +Europa|Eu=ro=pa|2 +existera|ex=i=ste=ra|2 +exoplaneter|ex=o=pla=ne=ter|2 +expedition|ex=pe=di=tion|2 +Experiment|Ex=pe=ri=ment|2 +experimentera|ex=pe=ri=men=te=ra|2 +Experimentet|Ex=pe=ri=men=tet|2 +experten|ex=per=ten|2 +Explosion|Ex=plo=sion|2 +exponentiella|ex=po=nen=ti=el=la|2 +Faller|Fal=ler|2 +fallerar|fal=le=rar|2 +falnar|fal=nar|2 +Fantastiskt|Fan=tas=tiskt|2 +farlig|far=lig|2 +Farligt|Far=ligt|2 +Farväl|Far=väl|2 +fascinerande|fa=sci=ne=ran=de|2 +fastgjord|fast=gjord|2 +fastnat|fast=nat|2 +fattat|fat=tat|2 +FELAKTIG|FEL=AK=TIG|2 +felmarginalen|fel=mar=gi=na=len|2 +femtedel|fem=te=del|2 +Femtio|Fem=tio|2 +fenomenet|fe=no=me=net|2 +fiender|fi=en=der|2 +filter|fil=ter|2 +fingertopparna|fing=er=top=par=na|2 +fininställt|fin=in=ställt|2 +fjärdedel|fjär=de=del|2 +flammande|flam=man=de|2 +flammiga|flam=mi=ga|2 +flaska|flas=ka|2 +flinade|fli=na=de|2 +flockinstinkt|flock=in=stinkt|2 +flotta|flot=ta|2 +flygande|fly=gan=de|2 +flygdäck|flyg=däck|2 +flygvapnet|flyg=vap=net|2 +flygvapnets|flyg=vap=nets|2 +flyktvektor|flykt=vek=tor|2 +flyttat|flyt=tat|2 +fläckarna|fläck=ar=na|2 +fläcken|fläck=en|2 +Fläcken|Fläck=en|2 +flämtningar|flämt=ning=ar|2 +fokusera|fo=ku=se=ra|2 +foldern|fol=dern|2 +folien|fo=li=en|2 +formad|for=mad|2 +formeln|for=meln|2 +Forskare|Fors=ka=re|2 +forskaren|fors=ka=ren|2 +forskarvärlden|fors=kar=värl=den|2 +Forskningscentret|Forsk=nings=cen=tret|2 +forskningsrapport|forsk=nings=rap=port|2 +fortplantningen|fort=plant=ning=en|2 +fortplantningszon|fort=plant=nings=zon|2 +Fortsätt|Fort=sätt|2 +Framgång|Fram=gång|2 +Framme|Fram=me|2 +Framsteg|Fram=steg|2 +framstående|fram=stå=en=de|2 +frekvens|fre=kvens|2 +frigör|fri=gör|2 +friska|fris=ka|2 +frivilliga|fri=vil=li=ga|2 +frivilligt|fri=vil=ligt|2 +frukostburrito|fru=kost=bur=ri=to|2 +frustrerad|fru=stre=rad|2 +frustrerande|fru=stre=ran=de|2 +Frågan|Frå=gan|2 +frågat|frå=gat|2 +fullborda|full=bor=da|2 +fullbordar|full=bor=dar|2 +fullgjord|full=gjord|2 +fullkomligt|full=kom=ligt|2 +Fullständigt|Full=stän=digt|2 +fullända|full=än=da|2 +fulländade|full=än=da=de|2 +Fungerade|Fun=ge=ra=de|2 +fungerande|fun=ge=ran=de|2 +fungerat|fun=ge=rat|2 +funktionella|funk=tio=nel=la|2 +funnit|fun=nit|2 +futtiga|fut=ti=ga|2 +fyllda|fyll=da|2 +fyrbråk|fyr=bråk|2 +fyrkantig|fyr=kan=tig|2 +fyrtiosex|fyr=tio=sex|2 +fyrtiotvå|fyr=tio=två|2 +fysiologi|fy=si=o=lo=gi|2 +fängelsets|fäng=el=sets|2 +Färden|Fär=den|2 +färdig|fär=dig|2 +färdriktning|färd=rikt=ning|2 +Färgen|Fär=gen|2 +färska|färs=ka|2 +fånigt|få=nigt|2 +Följaktligen|Följ=akt=li=gen|2 +följas|föl=jas|2 +förbaskade|för=bas=ka=de|2 +förbenat|för=be=nat|2 +förbigår|för=bi=går|2 +förblev|för=blev|2 +Förbluffande|För=bluf=fan=de|2 +fördubblas|för=dubb=las|2 +föredragit|fö=re=dra=git|2 +föregående|fö=re=gå=en=de|2 +förekomma|fö=re=kom=ma|2 +förekommande|fö=re=kom=man=de|2 +föremålet|fö=re=må=let|2 +Föremålet|Fö=re=må=let|2 +förenar|för=enar|2 +förenkla|för=enk=la|2 +förestående|fö=re=stå=en=de|2 +företa|fö=re=ta|2 +förfärad|för=fä=rad|2 +förgäves|för=gä=ves|2 +förhandling|för=hand=ling|2 +förhandlingen|för=hand=ling=en|2 +förhållandet|för=hål=lan=det|2 +förklaringen|för=kla=ring=en|2 +förlist|för=list|2 +förlängningssladdar|för=läng=nings=slad=dar|2 +Förlåt|För=låt|2 +förlåt|för=låt|2 +förmedlar|för=med=lar|2 +förmodade|för=mo=da=de|2 +förmår|för=mår|2 +förnamn|för=namn|2 +förnuft|för=nuft|2 +förnybar|för=ny=bar|2 +förrådsrum|för=råds=rum|2 +förrådsrummet|för=råds=rum=met|2 +förrådsskåpet|för=råds=skå=pet|2 +församlade|för=sam=la=de|2 +Försegla|För=seg=la|2 +förseglingarna|för=seg=ling=ar=na|2 +förseglingen|för=seg=ling=en|2 +försett|för=sett|2 +förskingrade|för=sking=ra=de|2 +förskingrat|för=sking=rat|2 +Förstå|För=stå|2 +förstått|för=stått|2 +försvagas|för=sva=gas|2 +försvagningen|för=svag=ning=en|2 +försvar|för=svar|2 +försvaret|för=sva=ret|2 +försvarets|för=sva=rets|2 +Försöker|För=sö=ker|2 +försöksdjur|för=söks=djur|2 +FÖRUTSEDD|FÖR=UT=SEDD|2 +förutsägelser|för=ut=sä=gel=ser|2 +förvandlas|för=vand=las|2 +förvara|för=va=ra|2 +förvaringslådor|för=va=rings=lå=dor|2 +förverkliga|för=verk=li=ga|2 +förvirrade|för=vir=ra=de|2 +förvirringen|för=vir=ring=en|2 +förvisso|för=vis=so|2 +förväntningarna|för=vänt=ning=ar=na|2 +förvånansvärt|för=vå=nans=värt|2 +föräldrar|för=äld=rar|2 +förändra|för=änd=ra|2 +förändring|för=änd=ring|2 +förändringar|för=änd=ring=ar|2 +förångar|för=ång=ar|2 +förödande|för=ödan=de|2 +galaxen|ga=lax=en|2 +gammalt|gam=malt|2 +gapande|ga=pan=de|2 +garanterar|ga=ran=te=rar|2 +gascylindrar|ga=scy=lind=rar|2 +gasform|gas=form|2 +gaskromatografen|ga=skro=ma=to=gra=fen|2 +geggan|geg=gan|2 +gemensamma|ge=men=sam=ma|2 +generatorer|ge=ne=ra=to=rer|2 +Generatorn|Ge=ne=ra=torn|2 +genombrott|ge=nom=brott|2 +genombrutet|ge=nom=bru=tet|2 +genombrutna|ge=nom=brut=na|2 +genomförd|ge=nom=förd|2 +genomlida|ge=nom=li=da|2 +genomsnittstemperaturen|ge=nom=snitt=s=tem=pe=ra=tu=ren|2 +genomsyra|ge=nom=sy=ra|2 +genomträngande|ge=nom=träng=an=de|2 +genuint|ge=nu=int|2 +giftig|gif=tig|2 +gillade|gil=la=de|2 +girmotor|gir=mo=tor|2 +gissade|gis=sa=de|2 +gissat|gis=sat|2 +glasfönster|glas=föns=ter|2 +glasspinnesiffrorna|glass=pin=ne=siff=ror=na|2 +glasögon|glas=ögon|2 +glädje|gläd=je|2 +glänsande|glän=san=de|2 +glöden|glö=den|2 +glömde|glöm=de|2 +gnager|gna=ger|2 +grammatik|gram=ma=tik|2 +granne|gran=ne|2 +granskade|grans=ka=de|2 +granskning|gransk=ning|2 +grimaserade|gri=ma=se=ra=de|2 +gripverktyget|grip=verk=ty=get|2 +grumlar|grum=lar|2 +grunden|grun=den|2 +grundämne|grund=äm=ne|2 +grundämnen|grund=äm=nen|2 +gruppen|grup=pen|2 +gränslöst|gräns=löst|2 +gräver|grä=ver|2 +gråter|grå=ter|2 +Guinness|Gu=in=ness|2 +Guldlockszonen|Guld=locks=zo=nen|2 +gäspar|gäs=par|2 +gångerna|gång=er=na|2 +gångjärn|gång=järn|2 +gångjärnen|gång=jär=nen|2 +haltar|hal=tar|2 +halvmeter|halv=me=ter|2 +halvorna|hal=vor=na|2 +handflatorna|hand=fla=tor=na|2 +handhållna|hand=håll=na|2 +Hangarfartyg|Han=gar=far=tyg|2 +Harrison|Har=ri=son|2 +Hastighet|Has=tig=het|2 +hastigheter|has=tig=he=ter|2 +havsvatten|havs=vat=ten|2 +hejdat|hej=dat|2 +hektopascal|hek=to=pa=scal|2 +helhet|hel=het|2 +helikopterplatta|he=li=kop=ter=plat=ta|2 +hemligheter|hem=lig=he=ter|2 +hemska|hems=ka|2 +hemsystem|hem=sys=tem|2 +hermetiskt|her=me=tiskt|2 +Heroin|He=ro=in|2 +herrar|her=rar|2 +heterosexuella|he=te=ro=sex=u=el=la|2 +himlakroppar|him=la=krop=par|2 +historiska|his=to=ris=ka|2 +Hittat|Hit=tat|2 +hjälmen|hjäl=men|2 +holländska|hol=länds=ka|2 +hopknölade|hop=knö=la=de|2 +hoppade|hop=pa=de|2 +hoppat|hop=pat|2 +hoppet|hop=pet|2 +hopplös|hopp=lös|2 +hopsjunken|hop=sjun=ken|2 +hostar|hos=tar|2 +Houston|Hous=ton|2 +Hundra|Hun=dra|2 +hundratusentals|hun=dra=tu=sen=tals|2 +huvudförhandling|hu=vud=för=hand=ling|2 +huvudräkning|hu=vud=räk=ning|2 +huvudsakliga|hu=vud=sak=li=ga|2 +Huvudsakligen|Hu=vud=sak=li=gen|2 +huvudsakligen|hu=vud=sak=li=gen|2 +hyfsad|hyf=sad|2 +hylsan|hyl=san|2 +hyperventilerar|hy=per=ven=ti=le=rar|2 +hypotes|hy=po=tes|2 +hysterisk|hy=ste=risk|2 +häftig|häf=tig|2 +Hälften|Hälf=ten|2 +hämtat|häm=tat|2 +händelse|hän=del=se|2 +Häpnadsväckande|Häp=nads=väck=an=de|2 +härdar|här=dar|2 +härnäst|här=näst|2 +hävdade|häv=da=de|2 +hållas|hål=las|2 +hållen|hål=len|2 +hårdhänt|hård=hänt|2 +högljutt|hög=ljutt|2 +högtalare|hög=ta=la=re|2 +högteknologisk|hög=tek=no=lo=gisk|2 +höljena|höl=je=na|2 +höljets|höl=jets|2 +hörsel|hör=sel|2 +iakttagit|iakt=ta=git|2 +iakttog|iakt=tog|2 +identifierar|iden=ti=fi=e=rar|2 +identifierat|iden=ti=fi=e=rat|2 +idioten|idi=o=ten|2 +idiotisk|idi=o=tisk|2 +idiotiska|idi=o=tis=ka|2 +idiotiskt|idi=o=tiskt|2 +ifrågasätter|ifrå=ga=sät=ter|2 +ignorera|ig=no=re=ra|2 +ihålig|ihå=lig|2 +illamående|il=la=må=en=de|2 +imiterar|imi=te=rar|2 +Immaterialrättsalliansen|Im=ma=te=ri=al=rätt=s=al=li=an=sen|2 +immunsystem|im=mun=sys=tem|2 +improviserat|im=pro=vi=se=rat|2 +inbillade|in=bil=la=de|2 +inblandad|in=blan=dad|2 +inbromsningen|in=broms=ning=en|2 +indelat|in=de=lat|2 +individuella|in=di=vi=du=el=la|2 +inducera|in=du=ce=ra|2 +industriella|in=dust=ri=el=la|2 +inexakt|in=ex=akt|2 +infektion|in=fek=tion|2 +infektionen|in=fek=tio=nen|2 +informera|in=for=me=ra|2 +informerad|in=for=me=rad|2 +infrastruktur|in=fra=struk=tur|2 +ingenjörerna|in=gen=jö=rer=na|2 +ingick|in=gick|2 +ingång|in=gång|2 +initiera|ini=ti=e=ra|2 +injektionsspruta|in=jek=tions=spru=ta|2 +inkonsekvent|in=kon=se=kvent|2 +inledande|in=le=dan=de|2 +inleder|in=le=der|2 +inlett|in=lett|2 +inlåst|in=låst|2 +Innanför|In=nan=för|2 +innebära|in=ne=bä=ra|2 +innehållet|in=ne=hål=let|2 +innerdörren|in=ner=dör=ren|2 +innervägg|in=ner=vägg|2 +innesluten|in=ne=slu=ten|2 +inneslutet|in=ne=slu=tet|2 +inneslutna|in=ne=slut=na|2 +inrättat|in=rät=tat|2 +insida|in=si=da|2 +insisterar|in=si=ste=rar|2 +inspektera|in=spek=te=ra|2 +intakt|in=takt|2 +intakta|in=tak=ta|2 +intelligenser|in=tel=li=gen=ser|2 +intensiv|in=ten=siv|2 +interaktion|in=ter=ak=tion|2 +Internationella|In=ter=na=tio=nel=la|2 +interplanetarisk|in=ter=pla=ne=ta=risk|2 +interstellärt|in=ter=stel=lärt|2 +Intervallet|In=ter=val=let|2 +intighet|in=tig=het|2 +intravenös|in=tra=ve=nös|2 +intravenöst|in=tra=ve=nöst|2 +intresserade|in=tres=se=ra=de|2 +intresserat|in=tres=se=rat|2 +invändig|in=vän=dig|2 +Invändigt|In=vän=digt|2 +invändigt|in=vän=digt|2 +irriterad|ir=ri=te=rad|2 +isolator|iso=la=tor|2 +isolerad|iso=le=rad|2 +isolerat|iso=le=rat|2 +isvatten|is=vat=ten|2 +iögonfallande|iögon=fal=lan=de|2 +Jagare|Ja=ga=re|2 +jagburgare|jag=bur=ga=re|2 +jaktplan|jakt=plan|2 +japansk|ja=pansk|2 +jobbig|job=big|2 +joniseras|jo=ni=se=ras|2 +jordbruket|jord=bru=ket|2 +jordbruksmark|jord=bruks=mark|2 +jordbävning|jord=bäv=ning|2 +jordgravitation|jord=gra=vi=ta=tion|2 +jordsekunder|jord=se=kun=der|2 +Jupiter|Ju=pi=ter|2 +justera|ju=ste=ra|2 +justeringar|ju=ste=ring=ar|2 +justeringsmotorerna|ju=ste=rings=mo=to=rer=na|2 +jämförelsevis|jäm=fö=rel=se=vis|2 +Kabelskydd|Ka=bel=skydd|2 +kablar|kab=lar|2 +Kablarna|Kab=lar=na|2 +kalkylatorn|kal=ky=la=torn|2 +kallade|kal=la=de|2 +kalorier|ka=lo=ri=er|2 +Kamera|Ka=me=ra|2 +kamerans|ka=me=rans|2 +kamrater|kam=ra=ter|2 +kanadensarna|ka=na=den=sar=na|2 +kandidaten|kan=di=da=ten|2 +kapitulerade|ka=pi=tu=le=ra=de|2 +kardborrar|kard=bor=rar|2 +kartong|kar=tong|2 +katastrofalt|ka=ta=stro=falt|2 +katetern|ka=te=tern|2 +kazakhstanska|ka=zakh=stans=ka|2 +kedjans|ked=jans|2 +kedjelänk|ked=je=länk|2 +kedjelänkar|ked=je=län=kar|2 +kedjor|ked=jor|2 +kemikalie|ke=mi=ka=lie|2 +kemoterapi|ke=mo=te=ra=pi|2 +kinderna|kin=der=na|2 +Kineserna|Ki=ne=ser=na|2 +kinetisk|kin=e=tisk|2 +kinetiska|kin=e=tis=ka|2 +klagade|kla=ga=de|2 +klappar|klap=par|2 +klarare|kla=ra=re|2 +klassrummet|klass=rum=met|2 +kletiga|kle=ti=ga|2 +klickade|klick=a=de|2 +klimatförändringen|kli=mat=för=änd=ring=en|2 +klimatologer|kli=ma=to=lo=ger|2 +klingande|kling=an=de|2 +klister|klis=ter|2 +klistrar|klist=rar|2 +klumpig|klum=pig|2 +klumpigt|klum=pigt|2 +klämmor|kläm=mor|2 +knacka|knacka|2 +Knappt|Knappt|2 +knutit|knu=tit|2 +knäppa|knäp=pa|2 +knäppte|knäpp=te|2 +kokpunkt|kok=punkt|2 +kollade|kol=la=de|2 +kollat|kol=lat|2 +kollisioner|kol=li=sio=ner|2 +kolonier|ko=lo=ni=er|2 +komasörja|ko=ma=sör=ja|2 +kommande|kom=man=de|2 +kommandomodulen|kom=man=do=mo=du=len|2 +Kommendör|Kom=men=dör|2 +kommersiell|kom=mer=si=ell|2 +kommersiella|kom=mer=si=el=la|2 +kompensera|kom=pen=se=ra|2 +komplexitet|kom=plex=i=tet|2 +konferensrummet|kon=fe=rens=rum=met|2 +konflikt|kon=flikt|2 +konformade|kon=for=ma=de|2 +konsistens|kon=si=stens|2 +konstaterar|kon=sta=te=rar|2 +konstig|kons=tig|2 +Konstigare|Kons=ti=ga=re|2 +konstruktionsfel|kon=struk=tions=fel|2 +kontakter|kon=tak=ter|2 +kontinenten|kon=ti=nen=ten|2 +kontinuerliga|kon=ti=nu=er=li=ga|2 +kontrollpanel|kon=troll=pa=nel|2 +kontrollpanelerna|kon=troll=pa=ne=ler=na|2 +kontrollrumsbubbla|kon=troll=rums=bubb=la|2 +kontur|kon=tur|2 +kopierat|ko=pi=e=rat|2 +kopiösa|ko=pi=ö=sa|2 +kopplad|kopp=lad|2 +kopplade|kopp=la=de|2 +korkat|kor=kat|2 +Korrekt|Kor=rekt|2 +korridorer|kor=ri=do=rer|2 +kortare|kor=ta=re|2 +kortaste|kor=tas=te|2 +kostym|ko=stym|2 +krafsade|kraf=sa=de|2 +kriget|kri=get|2 +kringgå|kring=gå|2 +krisen|kri=sen|2 +krokar|kro=kar|2 +kropparna|krop=par=na|2 +kroppsöppning|kropp=söpp=ning|2 +kryssar|krys=sar|2 +kryssningshastighet|kryss=nings=has=tig=het|2 +kulturella|kul=tu=rel=la|2 +kulturen|kul=tu=ren|2 +kunnig|kun=nig|2 +kupolen|ku=po=len|2 +kupolens|ku=po=lens|2 +Kustlinjen|Kust=lin=jen|2 +kvadratkilometer|kvad=rat=ki=lo=me=ter|2 +kvicksilver|kvick=sil=ver|2 +kväveprocent|kvä=ve=pro=cent|2 +kväveresistens|kvä=ve=re=sis=tens|2 +kändes|kän=des|2 +Känner|Kän=ner|2 +känsel|kän=sel|2 +känslig|käns=lig|2 +känsligt|käns=ligt|2 +käppen|käp=pen|2 +käpprätt|käpp=rätt|2 +kärnvapen|kärn=va=pen|2 +köttet|köt=tet|2 +labben|lab=ben|2 +labbets|lab=bets|2 +labbrock|labb=rock|2 +labbrockar|labb=rock=ar|2 +labbstolen|labb=sto=len|2 +labbutrustning|lab=b=ut=rust=ning|2 +laboratoriebänk|la=bo=ra=to=rie=bänk|2 +laboratoriets|la=bo=ra=to=ri=ets|2 +laboratorieugn|la=bo=ra=to=rieu=gn|2 +labyrint|la=by=rint|2 +lagrade|lag=ra=de|2 +lagret|lag=ret|2 +lagringskapacitet|lag=rings=ka=pa=ci=tet|2 +lakanen|la=ka=nen|2 +Lamais|La=mais|2 +Lampan|Lam=pan|2 +landare|lan=da=re|2 +landat|lan=dat|2 +lappar|lap=par|2 +laptoppar|lap=top=par|2 +laptopparna|lap=top=par=na|2 +lastbil|last=bil|2 +lateralt|la=te=ralt|2 +latitud|la=ti=tud|2 +Leclercs|Leclercs|2 +ledningen|led=ning=en|2 +legering|le=ge=ring|2 +leksaker|lek=sa=ker|2 +leverera|le=ve=re=ra|2 +Liberia|Li=be=ria|2 +lidande|li=dan=de|2 +liggsår|ligg=sår|2 +likartade|lik=ar=ta=de|2 +Liksom|Lik=som|2 +limmet|lim=met|2 +linjer|lin=jer|2 +livlinefäste|liv=li=ne=fäs=te|2 +livsmedelsproduktion|livs=me=dels=pro=duk=tion|2 +LIVSUPPEHÅLL|LIVS=UP=PE=HÅLL|2 +ljudvågorna|ljud=vå=gor=na|2 +ljusblänk|ljus=blänk|2 +ljusbrunt|ljus=brunt|2 +ljusfiltren|ljus=filt=ren|2 +ljusglimten|ljus=glim=ten|2 +ljusminut|ljus=mi=nut|2 +ljusstyrka|ljus=styr=ka|2 +ljussvagare|ljus=sva=ga=re|2 +ljussäker|ljus=sä=ker|2 +lovande|lo=van=de|2 +luckans|luck=ans|2 +luckorna|luck=or=na|2 +luftslangen|luft=slang=en|2 +Luftslussporten|Luft=sluss=por=ten|2 +luftslussväggen|luft=sluss=väg=gen|2 +luftströmmen|luft=ström=men|2 +lufttemperatur|luft=tem=pe=ra=tur|2 +Lufttrycket|Luft=tryck=et|2 +lufttrycket|luft=tryck=et|2 +lufttät|luft=tät|2 +lufttäta|luft=tä=ta|2 +lugnande|lug=nan=de|2 +luktade|luk=ta=de|2 +Lyckas|Lyck=as|2 +Lysdioder|Lys=dio=der|2 +lägsta|lägs=ta|2 +läkande|lä=kan=de|2 +lämpad|läm=pad|2 +lämpligt|lämp=ligt|2 +länder|län=der|2 +länken|län=ken|2 +läpparna|läp=par=na|2 +läskig|läs=kig|2 +lättad|lät=tad|2 +lättast|lät=tast|2 +lätthet|lätt=het|2 +Långsamt|Lång=samt|2 +lökformiga|lök=for=mi=ga|2 +lösgör|lös=gör|2 +maggropen|maggro=pen|2 +magiskt|ma=giskt|2 +Magmatiska|Mag=ma=tis=ka|2 +magneten|mag=ne=ten|2 +magnetisk|mag=ne=tisk|2 +makaroner|ma=ka=ro=ner|2 +makter|mak=ter|2 +manliga|man=li=ga|2 +manöver|ma=nö=ver|2 +manövrera|ma=növ=re=ra|2 +manövrerar|ma=növ=re=rar|2 +marinhelikopter|ma=rin=he=li=kop=ter|2 +marinkåren|ma=rin=kåren|2 +markant|mar=kant|2 +markerad|mar=ke=rad|2 +masken|mas=ken|2 +maskiner|ma=ski=ner|2 +massivt|mas=sivt|2 +massproducera|mass=pro=du=ce=ra|2 +massvis|mass=vis|2 +matematiska|ma=te=ma=tis=ka|2 +matsmältningssystem|mat=smält=nings=sys=tem|2 +meddelade|med=de=la=de|2 +medför|med=för|2 +medhjälpare|med=hjäl=pa=re|2 +medicinering|me=di=ci=ne=ring|2 +medurs|med=urs|2 +medveten|med=ve=ten|2 +megajoule|me=ga=jou=le|2 +mejsel|mej=sel|2 +mekanisk|me=ka=nisk|2 +mellansträv|mel=lan=sträv|2 +meningsfullt|me=nings=fullt|2 +meningslös|me=nings=lös|2 +mentalt|men=talt|2 +merparten|mer=par=ten|2 +metallen|me=tal=len|2 +metallklot|me=tall=klot|2 +metallremsan|me=tall=rem=san|2 +metallskiva|me=tall=ski=va|2 +meterbreda|me=ter=bre=da|2 +migrera|mi=gre=ra|2 +mikrofon|mik=ro=fon|2 +mikrosekunder|mik=ro=se=kun=der|2 +mikroskopets|mik=ro=sko=pets|2 +militärerna|mi=li=tä=rer=na|2 +miljard|mil=jard|2 +miljöer|mil=jö=er|2 +miljöproblem|mil=jö=pro=blem|2 +minimalt|mi=ni=malt|2 +miniodlingen|mi=ni=od=ling=en|2 +miniräknare|mi=ni=räk=na=re|2 +minnesförlusten|min=nes=för=lus=ten|2 +minskade|mins=ka=de|2 +minskning|minsk=ning|2 +minskningen|minsk=ning=en|2 +mirakel|mi=ra=kel|2 +mischmasch|misch=masch|2 +missar|mis=sar|2 +misslyckades|miss=lyck=a=des|2 +Misslyckats|Miss=lyck=ats|2 +misstanke|miss=tan=ke|2 +misstänkt|miss=tänkt|2 +mittskärmen|mitt=skär=men|2 +modifierade|mo=di=fi=e=ra=de|2 +modifierat|mo=di=fi=e=rat|2 +modulerna|mo=du=ler=na|2 +molekyl|mo=le=kyl|2 +molnslöjor|moln=slö=jor|2 +monitor|mo=ni=tor|2 +monoton|mo=no=ton|2 +monterar|mon=te=rar|2 +Moskvatid|Mos=k=va=tid|2 +motoreffekt|mo=tor=ef=fekt|2 +Motorer|Mo=to=rer|2 +motorutblåsningen|mo=tor=ut=blås=ning=en|2 +motståndskraftiga|mot=stånds=kraf=ti=ga|2 +motståndslöst|mot=stånds=löst|2 +motsvarighet|mot=sva=rig=het|2 +mottagare|mot=ta=ga=re|2 +motverka|mot=ver=ka|2 +munter|mun=ter|2 +mängderna|mäng=der=na|2 +Människa|Män=ni=ska|2 +människan|män=ni=skan|2 +människokropp|män=ni=sko=kropp|2 +Människokroppen|Män=ni=sko=krop=pen|2 +människors|män=ni=skors|2 +människoskeppet|män=ni=sko=skep=pet|2 +Mänskliga|Mänsk=li=ga|2 +Mänsklighetens|Mänsk=lig=he=tens|2 +märkbar|märk=bar|2 +märkte|märk=te|2 +märkvärdigt|märk=vär=digt|2 +mätbar|mät=bar|2 +månaders|må=na=ders|2 +mångarmade|mång=ar=ma=de|2 +månlandningen|mån=land=ning=en|2 +möjlig|möj=lig|2 +mördande|mör=dan=de|2 +mördar|mör=dar|2 +mötesrummen|mö=tes=rum=men|2 +mötesrummet|mö=tes=rum=met|2 +namnlapp|namn=lapp|2 +nanoinjektionssprutor|na=noin=jek=tions=spru=tor|2 +naturkunskap|na=tur=kun=skap|2 +naturlig|na=tur=lig|2 +naturvetenskapslärare|na=tur=ve=ten=skaps=lä=ra=re|2 +nebulosor|ne=bu=lo=sor|2 +nedersta|ne=ders=ta|2 +nedräkningen|ned=räk=ning=en|2 +nedsänkt|ned=sänkt|2 +nedsänkta|ned=sänk=ta|2 +nerver|ner=ver|2 +neuralt|neu=ralt|2 +nittio|nit=tio|2 +nittionde|nit=tion=de|2 +nittiosex|nit=tio=sex|2 +nitton|nit=ton|2 +njutning|njut=ning|2 +Nobelpris|No=bel=pris|2 +Nordamerika|Nord=ame=ri=ka|2 +nordpol|nord=pol|2 +Normalt|Nor=malt|2 +normaltemperatur|nor=mal=tem=pe=ra=tur|2 +normalvarma|nor=mal=var=ma|2 +norskan|nors=kan|2 +noskonen|no=s=ko=nen|2 +Noterat|No=te=rat|2 +nuförtiden|nu=för=ti=den|2 +nyckeln|nyck=eln|2 +nyligen|ny=li=gen|2 +Nynnandet|Nyn=nan=det|2 +näringskedjan|nä=rings=ked=jan|2 +Näringstilldelningen|Nä=rings=till=del=ning=en|2 +nävarna|nä=var=na|2 +någorlunda|nå=gor=lun=da|2 +nödsituation|nöd=si=tu=a=tion|2 +nödsystemet|nöd=sys=te=met|2 +nödventil|nöd=ven=til|2 +oaktsamhet|oakt=sam=het|2 +oavsett|oav=sett|2 +oavsiktliga|oav=sikt=li=ga|2 +obefintlig|obe=fint=lig|2 +obegränsade|obe=grän=sa=de|2 +obegränsat|obe=grän=sat|2 +obehindrat|obe=hind=rat|2 +obemannad|obe=man=nad|2 +oberoende|obe=ro=en=de|2 +Oberoende|Obe=ro=en=de|2 +obetydligt|obe=tyd=ligt|2 +Objektets|Ob=jek=tets|2 +Objektglaset|Ob=jekt=gla=set|2 +observation|ob=ser=va=tion|2 +oddsen|odd=sen|2 +odelade|ode=la=de|2 +odlade|od=la=de|2 +odlingen|od=ling=en|2 +Odlingstank|Od=lingstank|2 +odlingstanken|od=lingstan=ken|2 +ofarligt|ofar=ligt|2 +offentliggjorde|of=fent=lig=gjor=de|2 +officerare|of=fi=ce=ra=re|2 +offrade|off=ra=de|2 +oftare|of=ta=re|2 +oförstående|oför=stå=en=de|2 +oförstörbart|oför=stör=bart|2 +oförutsebart|oför=ut=se=bart|2 +oinskränkt|oin=skränkt|2 +oinstallerade|oin=stal=le=ra=de|2 +ojämna|ojäm=na|2 +okontrollerat|okon=trol=le=rat|2 +oktaedern|ok=ta=e=dern|2 +oktaver|ok=ta=ver|2 +okularen|oku=la=ren|2 +okända|okän=da|2 +omfång|om=fång|2 +omgivande|om=gi=van=de|2 +omloppsbanehastighet|om=lopps=ba=ne=has=tig=het|2 +omringades|om=ring=a=des|2 +Området|Om=rå=det|2 +omsorgsfull|om=sorgs=full|2 +omvandlas|om=vand=las|2 +omärkligt|omärk=ligt|2 +Omöjligt|Omöj=ligt|2 +oorganiska|oor=ga=nis=ka|2 +operation|ope=ra=tion|2 +operationer|ope=ra=tio=ner|2 +optimala|op=ti=ma=la|2 +opålitliga|opå=lit=li=ga|2 +orange|oran=ge|2 +ordalag|or=da=lag|2 +ordentlig|or=dent=lig|2 +oregelbundet|ore=gel=bun=det|2 +organeller|or=ga=nel=ler|2 +organism|or=ga=nism|2 +orienterar|ori=en=te=rar|2 +oroade|oro=a=de|2 +oroande|oro=an=de|2 +orolig|oro=lig|2 +orsakats|or=sa=kats|2 +orsaken|or=sa=ken|2 +orörlig|orör=lig|2 +oskarp|oskarp|2 +ostadig|osta=dig|2 +otaliga|ota=li=ga|2 +otydligt|otyd=ligt|2 +otäcka|otäcka|2 +ovanliga|ovan=li=ga|2 +ovetenskapligt|ove=ten=skap=ligt|2 +oväsendet|ovä=sen=det|2 +packningen|pack=ning=en|2 +pallen|pal=len|2 +Pappskalle|Papp=skal=le|2 +Paraguay|Pa=ra=gu=ay|2 +parallelltrapetsen|pa=ral=lell=tra=pet=sen|2 +parbildning|par=bild=ning|2 +parkeringsplatsen|par=ke=rings=plat=sen|2 +passagerarplan|pas=sa=ge=rar=plan|2 +passerade|pas=se=ra=de|2 +passning|pass=ning|2 +patenterade|pa=ten=te=ra=de|2 +patient|pa=ti=ent|2 +Patienten|Pa=ti=en=ten|2 +patienten|pa=ti=en=ten|2 +patienter|pa=ti=en=ter|2 +pendel|pen=del|2 +pendelrörelser|pen=del=rö=rel=ser|2 +pentagon|pen=ta=gon|2 +pentagonalt|pen=ta=go=nalt|2 +pentagoner|pen=ta=go=ner|2 +periapsis|pe=ri=apsis|2 +periodiska|pe=ri=o=dis=ka|2 +permanent|per=ma=nent|2 +personalen|per=so=na=len|2 +personen|per=so=nen|2 +personerna|per=so=ner=na|2 +personers|per=so=ners|2 +personlighet|per=son=lig=het|2 +petade|pe=ta=de|2 +Petrovakommittén|Pe=tro=va=kom=mit=tén|2 +Petrovalinjens|Pe=tro=va=lin=jens|2 +Petrovalinjer|Pe=tro=va=lin=jer|2 +Petrovaljus|Pe=tro=va=ljus|2 +Petrovaskopskärmen|Pe=tro=vas=kop=skär=men|2 +piggnar|pigg=nar|2 +pistol|pi=stol|2 +Planen|Pla=nen|2 +planer|pla=ner|2 +planerade|pla=ne=ra=de|2 +Planeter|Pla=ne=ter|2 +planets|pla=nets|2 +plastcirklar|plast=cirk=lar|2 +plasten|plas=ten|2 +plastlådor|plast=lå=dor|2 +plastlådorna|plast=lå=dor=na|2 +plastpåse|plast=på=se|2 +pluggade|plug=ga=de|2 +pluggar|plug=gar|2 +plågsamma|plåg=sam=ma|2 +plåten|plå=ten|2 +politiker|po=li=ti=ker|2 +population|po=pu=la=tion|2 +Populationen|Po=pu=la=tio=nen|2 +portal|por=tal|2 +portfölj|port=följ|2 +portföljen|port=föl=jen|2 +positiv|po=si=tiv|2 +potent|po=tent|2 +potentiell|po=ten=ti=ell|2 +potentiella|po=ten=ti=el=la|2 +poänglöst|po=äng=löst|2 +precision|pre=ci=sion|2 +Predatorn|Pre=da=torn|2 +presenter|pre=sen=ter|2 +pressas|pres=sas|2 +prickade|prick=a=de|2 +Prickarna|Prick=ar=na|2 +pricken|prick=en|2 +privata|pri=va=ta|2 +privilegier|pri=vi=le=gi=er|2 +procenten|pro=cen=ten|2 +produkter|pro=duk=ter|2 +progression|pro=gres=sion|2 +projektsymbolen|pro=jekt=sym=bo=len|2 +pronomen|pro=no=men|2 +proportionerna|pro=por=tio=ner=na|2 +proppfull|propp=full|2 +proton|pro=ton|2 +protonernas|pro=to=ner=nas|2 +Provet|Pro=vet|2 +Provtagaren|Prov=ta=ga=ren|2 +Provtagarens|Prov=ta=ga=rens|2 +prylen|pry=len|2 +psykologiska|psy=ko=lo=gis=ka|2 +publicerats|pu=bli=ce=rats|2 +pulver|pul=ver|2 +Pumpen|Pum=pen|2 +punkter|punk=ter|2 +pyttelilla|pyt=te=lil=la|2 +pyttesmå|pyt=te=små|2 +påfrestningar|på=frest=ning=ar|2 +radarpanelen|ra=dar=pa=ne=len|2 +radarsystem|ra=dar=sys=tem|2 +radiosändare|ra=dio=sän=da=re|2 +ramlade|ram=la=de|2 +Random|Ran=dom|2 +rapporter|rap=por=ter|2 +rapportera|rap=por=te=ra|2 +rationellt|ra=tio=nellt|2 +reagerade|re=a=ge=ra=de|2 +reaktionen|re=ak=tio=nen|2 +referensmaterial|re=fe=rens=ma=te=ri=al|2 +referenspunkt|re=fe=rens=punkt|2 +reflekterade|re=flek=te=ra=de|2 +reflekterat|re=flek=te=rat|2 +regelbundet|re=gel=bun=det|2 +regering|re=ge=ring|2 +regeringar|re=ge=ring=ar|2 +regimerna|re=gi=mer=na|2 +rekalibrering|re=ka=lib=re=ring|2 +rektangel|rek=tang=el|2 +rektangeln|rek=tang=eln|2 +rektanglar|rek=tang=lar|2 +RELATIV|RE=LA=TIV|2 +relativistisk|re=la=ti=vis=tisk|2 +relativiteten|re=la=ti=vi=te=ten|2 +relevant|re=le=vant|2 +relevanta|re=le=van=ta|2 +religion|re=li=gi=on|2 +remmar|rem=mar|2 +rensade|ren=sa=de|2 +reparerar|re=pa=re=rar|2 +repareras|re=pa=re=ras|2 +reparerat|re=pa=re=rat|2 +representerar|re=pre=sen=te=rar|2 +resenär|re=se=när|2 +Resultat|Re=sul=tat|2 +Resultatet|Re=sul=ta=tet|2 +revolutionen|re=vo=lu=tio=nen|2 +ribbor|rib=bor|2 +ringde|ring=de|2 +ringen|ring=en|2 +ritning|rit=ning|2 +Robert|Robert|2 +robotarmar|ro=bot=armar|2 +robotens|ro=bo=tens|2 +Rotationen|Ro=ta=tio=nen|2 +rotationscentrum|ro=ta=tions=cen=trum|2 +rotationshastighet|ro=ta=tions=has=tig=het|2 +Rotera|Ro=te=ra|2 +roterade|ro=te=ra=de|2 +rudimentärt|ru=di=men=tärt|2 +rullning|rull=ning|2 +rumskompis|rums=kom=pis|2 +rumstempererad|rums=tem=pe=re=rad|2 +ruttnande|rutt=nan=de|2 +ryggar|ryg=gar|2 +ryktbart|rykt=bart|2 +rymdalger|rym=dal=ger|2 +Rymddräkten|Rymd=dräk=ten|2 +rymddräktshandskar|rymd=dräkts=hands=kar|2 +rymdfarande|rymd=fa=ran=de|2 +rymdfart|rymd=fart|2 +rymdprogram|rymd=pro=gram|2 +rymdpromenaden|rymd=pro=me=na=den|2 +rymdstoft|rymd=stoft|2 +rymmer|rym=mer|2 +rynkar|ryn=kar|2 +ryssen|rys=sen|2 +rädsla|räds=la|2 +rädslan|räds=lan|2 +Räknar|Räk=nar|2 +räknare|räk=na=re|2 +ränder|rän=der|2 +rättar|rät=tar|2 +rättegången|rät=te=gång=en|2 +rättframt|rätt=framt|2 +rättssalen|rätts=sa=len|2 +rättvis|rätt=vis|2 +rättvisans|rätt=vi=sans|2 +rättvist|rätt=vist|2 +röntgenstrålar|rönt=gen=strå=lar|2 +rörande|rö=ran=de|2 +RÖRELSE|RÖ=REL=SE|2 +rörelsemängd|rö=rel=se=mängd|2 +röstläge|röst=lä=ge|2 +sakerna|sa=ker=na|2 +Saktar|Sak=tar|2 +samarbeta|sam=ar=be=ta|2 +samarbetade|sam=ar=be=ta=de|2 +samlingen|sam=ling=en|2 +sammanbundna|sam=man=bund=na|2 +sammanhang|sam=man=hang|2 +sammanhållet|sam=man=hål=let|2 +sammanlänkande|sam=man=län=kan=de|2 +Samtalet|Sam=ta=let|2 +Samtliga|Samt=li=ga|2 +sannolika|san=no=li=ka|2 +sarkasm|sar=kasm|2 +satsar|sat=sar|2 +sattes|sat=tes|2 +Saturnus|Sa=tur=nus|2 +scenariot|sce=na=ri=ot|2 +scheman|sche=man|2 +schemat|sche=mat|2 +schyst|schyst|2 +Schyst|Schyst|2 +sedimentära|se=di=men=tä=ra|2 +sektionen|sek=tio=nen|2 +sekunds|se=kunds|2 +sekundär|se=kun=där|2 +sekundära|se=kun=dä=ra|2 +sekvens|se=kvens|2 +semester|se=mes=ter|2 +Senare|Se=na=re|2 +separation|se=pa=ra=tion|2 +separerade|se=pa=re=ra=de|2 +seriös|se=ri=ös|2 +servering|ser=ve=ring|2 +servitrisen|ser=vi=tri=sen|2 +sexhundra|sex=hun=dra|2 +Sextiotusen|Sex=tio=tu=sen|2 +signalen|sig=na=len|2 +signalerar|sig=na=le=rar|2 +signatur|sig=na=tur|2 +silversked|sil=ver=sked|2 +simulera|si=mu=le=ra|2 +simulerar|si=mu=le=rar|2 +sinnade|sin=na=de|2 +sinnessjuk|sin=nes=sjuk|2 +Sirius|Si=ri=us|2 +Sitter|Sit=ter|2 +sjuhundra|sju=hun=dra|2 +Sjukdom|Sjuk=dom|2 +sjukdomen|sjuk=do=men|2 +sjunkande|sjun=kan=de|2 +sjuttiofem|sjut=tio=fem|2 +sjuttiotvå|sjut=tio=två|2 +Sjutton|Sjut=ton|2 +självbelåtet|själv=be=lå=tet|2 +självmord|själv=mord|2 +självmordsuppdraget|själv=mordsupp=dra=get|2 +självständigt|själv=stän=digt|2 +sjöfarare|sjö=fa=ra=re|2 +sjömännen|sjö=män=nen|2 +skaffade|skaf=fa=de|2 +skaffat|skaf=fat|2 +skalbaggen|skal=bag=gen|2 +skalbaggssonderna|skal=baggs=son=der=na|2 +skannar|skan=nar|2 +skapat|ska=pat|2 +skarpare|skar=pa=re|2 +skarpt|skarpt|2 +skelett|ske=lett|2 +skenbenet|sken=be=net|2 +skeppsingenjör|skepps=in=gen=jör|2 +skickligt|skick=ligt|2 +skildes|skil=des|2 +skjutas|skju=tas|2 +skjutit|skju=tit|2 +skolan|sko=lan|2 +skramlar|skram=lar|2 +skrapade|skra=pa=de|2 +skratt|skratt|2 +skriftspråk|skrift=språk|2 +skript|skript|2 +skrivet|skri=vet|2 +skrockade|skrock=a=de|2 +skrovliga|skrov=li=ga|2 +skrovmaterial|skrov=ma=te=ri=al|2 +skräck|skräck|2 +skräckslagen|skräck=sla=gen|2 +skurit|sku=rit|2 +skuttar|skut=tar|2 +skyddet|skyd=det|2 +skyddsdräkter|skydds=dräk=ter|2 +Skynda|Skyn=da|2 +Skälet|Skä=let|2 +skänkt|skänkt|2 +skärmens|skär=mens|2 +skärskådar|skär=skå=dar|2 +skörda|skör=da|2 +skötte|sköt=te|2 +slagit|sla=git|2 +slangen|slang=en|2 +slarvig|slar=vig|2 +slingra|sling=ra|2 +slipat|sli=pat|2 +slokar|slo=kar|2 +slumpartade|slump=ar=ta=de|2 +slumpen|slum=pen|2 +slunga|slunga|2 +slungas|slung=as|2 +sluppit|slup=pit|2 +slussar|slus=sar|2 +slussportarna|sluss=por=tar=na|2 +slutgiltiga|slut=gil=ti=ga|2 +slutna|slut=na|2 +slutresultatet|slut=re=sul=ta=tet|2 +släktet|släk=tet|2 +släktingar|släk=ting=ar|2 +slängt|slängt|2 +släpat|slä=pat|2 +släpps|släpps|2 +smattrar|smatt=rar|2 +smiter|smi=ter|2 +smockar|smock=ar|2 +smutsiga|smut=si=ga|2 +smuttade|smut=ta=de|2 +smällare|smäl=la=re|2 +smällde|smäll=de|2 +smältpunkt|smält=punkt|2 +smärtan|smär=tan|2 +smärtfritt|smärt=fritt|2 +smörjan|smör=jan|2 +Snabbare|Snab=ba=re|2 +snavade|sna=va=de|2 +sneglade|sneg=la=de|2 +sniffar|snif=far|2 +snillrik|snill=rik|2 +snillrika|snill=ri=ka|2 +Snurrar|Snur=rar|2 +snyggt|snyggt|2 +Snälla|Snäl=la|2 +sockerarter|sock=er=ar=ter|2 +soldater|sol=da=ter|2 +Soldaterna|Sol=da=ter=na|2 +solenergin|so=l=ener=gin|2 +solfläckarna|sol=fläck=ar=na|2 +Solfläckarna|Sol=fläck=ar=na|2 +solitt|so=litt|2 +solpartiklarna|sol=par=tik=lar=na|2 +solstrålningen|sol=strål=ning=en|2 +sonder|son=der|2 +sonderna|son=der=na|2 +sorgen|sor=gen|2 +sorter|sor=ter|2 +sortera|sor=te=ra|2 +Sovjet|Sov=jet|2 +spaghetti|spa=ghet=ti|2 +spalter|spal=ter|2 +Spanien|Spa=ni=en|2 +sparat|spa=rat|2 +Specificera|Spe=ci=fi=ce=ra|2 +speglar|speg=lar|2 +spekulativa|spe=ku=la=ti=va|2 +Spelar|Spe=lar|2 +spillprodukter|spill=pro=duk=ter|2 +spindriftmotorer|spindrift=mo=to=rer|2 +spindriftskonsolen|spindrifts=kon=so=len|2 +spindriftsmotorer|spindrift=smo=to=rer|2 +splitsning|splits=ning|2 +spotta|spot=ta|2 +sprida|spri=da|2 +spruckna|spruck=na|2 +sprängde|spräng=de|2 +sprängdes|spräng=des|2 +spänns|spänns|2 +spärrar|spär=rar|2 +stammade|stam=ma=de|2 +Stanna|Stan=na|2 +stapplande|stapp=lan=de|2 +starkaste|star=kas=te|2 +startade|star=ta=de|2 +Startar|Star=tar|2 +staten|sta=ten|2 +stater|sta=ter|2 +STATUS|STA=TUS|2 +stavar|sta=var|2 +stegade|ste=ga=de|2 +steget|ste=get|2 +stegpinnarna|steg=pin=nar=na|2 +stenarna|ste=nar=na|2 +steril|ste=ril|2 +stinker|stin=ker|2 +stjälk|stjälk|2 +Stjärnorna|Stjär=nor=na|2 +stolar|sto=lar|2 +stoppat|stop=pat|2 +strecket|streck=et|2 +strimma|strim=ma|2 +strukturerade|struk=tu=re=ra=de|2 +strukturskärm|struk=tur=skärm|2 +strunta|strun=ta|2 +Strupen|Stru=pen|2 +strupen|stru=pen|2 +sträng|sträng|2 +stråla|strå=la|2 +stråle|strå=le|2 +strålkastare|strål=kas=ta=re|2 +Strålning|Strål=ning|2 +Strålningen|Strål=ning=en|2 +strålningssjuka|strål=nings=sju=ka|2 +ströva|strö=va|2 +studerade|stu=de=ra=de|2 +stunds|stunds|2 +städat|stä=dat|2 +städer|stä=der|2 +ställen|stäl=len|2 +stämband|stäm=band|2 +stängd|stängd|2 +stängdes|stäng=des|2 +stållåda|stållå=da|2 +stöder|stö=der|2 +stödribbor|stöd=rib=bor|2 +störningar|stör=ning=ar|2 +Större|Stör=re|2 +störtar|stör=tar|2 +stötte|stöt=te|2 +substans|sub=stans|2 +sugrör|sug=rör|2 +supertaumöbor|su=per=t=au=mö=bor|2 +surrande|sur=ran=de|2 +svajande|sva=jan=de|2 +svalde|sval=de|2 +svalna|sval=na|2 +svällande|sväl=lan=de|2 +svälter|sväl=ter|2 +svängningar|sväng=ning=ar|2 +svängningstiden|sväng=nings=ti=den|2 +symmetrisk|sym=me=trisk|2 +synfältet|syn=fäl=tet|2 +synpunkter|syn=punk=ter|2 +sysslar|syss=lar|2 +säckar|säck=ar|2 +säkerhetsbältet|sä=ker=hets=bäl=tet|2 +säkrare|säk=ra=re|2 +sällsynt|säll=synt|2 +Sängen|Säng=en|2 +sängkläder|säng=klä=der|2 +sänker|sän=ker|2 +särdrag|sär=drag|2 +säregen|sär=egen|2 +säregna|sär=eg=na|2 +särskilda|sär=skil=da|2 +Sådant|Så=dant|2 +Såvida|Så=vi=da|2 +sökmönster|sök=möns=ter|2 +tabell|ta=bell|2 +tackar|tack=ar|2 +tafatt|ta=fatt|2 +takbubbla|tak=bubb=la|2 +Tankarna|Tan=kar=na|2 +taumöbalarm|tau=mö=ba=larm|2 +taumöbaodlingarna|tau=mö=ba=od=ling=ar=na|2 +taumöbapopulationen|tau=mö=bapo=pu=la=tio=nen|2 +taumöbastam|tau=mö=bastam|2 +taumöbatankarna|tau=mö=ba=tan=kar=na|2 +tecknad|teck=nad|2 +tecknar|teck=nar|2 +tejpat|tej=pat|2 +Teknikerna|Tek=ni=ker=na|2 +tekniska|tek=nis=ka|2 +Teleskopet|Te=le=sko=pet|2 +television|te=le=vi=sion|2 +Temperaturen|Tem=pe=ra=tu=ren|2 +temperaturkänsliga|tem=pe=ra=tur=käns=li=ga|2 +temporära|tem=po=rä=ra|2 +tenderar|ten=de=rar|2 +Thailand|Thai=land|2 +Theresa|The=re=sa|2 +tidsdilatation|tids=di=la=ta=tion|2 +tidsenhet|tids=en=het|2 +tillfällen|till=fäl=len|2 +tillföra|till=fö=ra|2 +tillgänglig|till=gäng=lig|2 +tillgången|till=gång=en|2 +tillhandahålla|till=han=da=hål=la|2 +tillhandahåller|till=han=da=hål=ler|2 +tillhörde|till=hör=de|2 +tillräckliga|till=räck=li=ga|2 +tillträde|till=trä=de|2 +tillverkas|till=ver=kas|2 +tillverkats|till=ver=kats|2 +timmars|tim=mars|2 +tingest|ting=est|2 +tingestarna|ting=es=tar=na|2 +tinningarna|tin=ning=ar=na|2 +tiondels|ti=on=dels|2 +tiotusen|tio=tu=sen|2 +tittat|tit=tat|2 +tjockare|tjock=a=re|2 +tjugondedel|tju=gon=de=del|2 +tjugonio|tju=go=nio|2 +tjugoniondedel|tju=go=ni=on=de=del|2 +tjugotredje|tju=go=tred=je|2 +tjugotvå|tju=go=två|2 +tjuter|tju=ter|2 +tjänst|tjänst|2 +tjänstgjorde|tjänst=gjor=de|2 +toalett|toa=lett|2 +tolkar|tol=kar|2 +tomrummet|tom=rum=met|2 +tonhöjd|ton=höjd|2 +torkade|tor=ka=de|2 +torkat|tor=kat|2 +transistorer|tran=sis=to=rer|2 +transparent|trans=pa=rent|2 +transportera|trans=por=te=ra|2 +trasiga|tra=si=ga|2 +trasigt|tra=sigt|2 +traska|tras=ka|2 +traskar|tras=kar|2 +trauma|trau=ma|2 +traven|tra=ven|2 +tredubbla|tre=dubb=la|2 +trehundra|tre=hun=dra|2 +trerövade|trer=ö=va=de|2 +trettioen|tret=tio=en|2 +trettiosex|tret=tio=sex|2 +trettiotvå|tret=tio=två|2 +trevar|tre=var|2 +trevligt|trev=ligt|2 +triangulär|tri=an=gu=lär|2 +triangulära|tri=an=gu=lä=ra|2 +trillar|tril=lar|2 +troligtvis|tro=ligt=vis|2 +tryckas|tryck=as|2 +tryckbehållare|tryck=be=hål=la=re|2 +tryckkammare|tryck=kam=ma=re|2 +tryckkraft|tryck=kraft|2 +tryckkärlet|tryck=kär=let|2 +tryckluft|tryck=luft|2 +träffades|träf=fa=des|2 +tränger|träng=er|2 +träpinnar|trä=pin=nar|2 +trådarna|trå=dar=na|2 +tröghetsreferensram|trög=hets=re=fe=rens=ram|2 +tummarna|tum=mar=na|2 +tungan|tung=an|2 +tunnare|tun=na=re|2 +tunneldel|tun=nel=del|2 +tunnelsystem|tun=nel=sys=tem|2 +tunnlarna|tunn=lar=na|2 +turbulens|tur=bu=lens|2 +tvekar|tve=kar|2 +tveklöst|tvek=löst|2 +tvingade|tving=a=de|2 +tvingades|tving=a=des|2 +tvingat|tving=at|2 +tvättar|tvät=tar|2 +tvättäkta|tvätt=äk=ta|2 +tvåhundratusen|två=hun=dra=tu=sen|2 +Tycker|Tyck=er|2 +tydlig|tyd=lig|2 +tyngden|tyng=den|2 +typiska|ty=pis=ka|2 +tystnade|tyst=na=de|2 +tätare|tä=ta=re|2 +tålamod|tå=la=mod|2 +underhåll|un=der=håll|2 +underhållning|un=der=håll=ning|2 +underifrån|un=der=i=från|2 +underliggande|un=der=lig=gan=de|2 +undermedvetna|un=der=med=vet=na|2 +undervisa|un=der=vi=sa|2 +undrat|und=rat|2 +ungarnas|ung=ar=nas|2 +ungefärliga|un=ge=fär=li=ga|2 +universitetet|uni=ver=si=te=tet|2 +UPPDRAG|UPP=DRAG|2 +uppdragets|upp=dra=gets|2 +uppdragssymbol|upp=drags=sym=bol|2 +uppenbarelse|uppen=ba=rel=se|2 +uppfattades|upp=fat=ta=des|2 +uppfattar|upp=fat=tar|2 +uppfostrad|upp=fost=rad|2 +upphetsning|upp=hets=ning|2 +upphov|upp=hov|2 +uppkopplade|upp=kopp=la=de|2 +upplevde|upp=lev=de|2 +upplevelse|upp=le=vel=se|2 +upplysande|upp=ly=san=de|2 +UPPMÄTT|UPP=MÄTT|2 +uppmätt|upp=mätt|2 +uppnådd|upp=nådd|2 +uppnått|upp=nått|2 +upprörda|upp=rör=da|2 +uppsats|upp=sats|2 +uppskattad|upp=skat=tad|2 +uppskattning|upp=skatt=ning|2 +uppskjutning|upp=skjut=ning|2 +uppskjutningen|upp=skjut=ning=en|2 +uppspelt|upp=spelt|2 +uppstått|upp=stått|2 +uppsättningar|upp=sätt=ning=ar|2 +uppsättningen|upp=sätt=ning=en|2 +upptar|upp=tar|2 +uppvisar|upp=vi=sar|2 +urkopplad|ur=kopp=lad|2 +Ursprungligen|Ur=sprung=li=gen|2 +urtavlan|ur=tav=lan|2 +urusla|ur=usla|2 +Utanför|Ut=an=för|2 +utbilda|ut=bil=da|2 +utbrister|ut=bris=ter|2 +utbytbara|ut=byt=ba=ra|2 +uteslutande|ute=slu=tan=de|2 +utformade|ut=for=ma=de|2 +utformades|ut=for=ma=des|2 +utforskat|ut=fors=kat|2 +utgick|ut=gick|2 +utgjorde|ut=gjor=de|2 +utgångar|ut=gång=ar|2 +utgångspunkt|ut=gångs=punkt|2 +utgörs|ut=görs|2 +Utifrån|Ut=i=från|2 +utjämnat|ut=jäm=nat|2 +utmattad|ut=mat=tad|2 +utnyttja|ut=nytt=ja|2 +Utomjordingen|Ut=om=jor=ding=en|2 +Utomjordingens|Ut=om=jor=ding=ens|2 +utrota|ut=ro=ta|2 +uträkningar|ut=räk=ning=ar|2 +utsidan|ut=si=dan|2 +utstråla|ut=strå=la|2 +utstrålas|ut=strå=las|2 +utstrålning|ut=strål=ning|2 +utsökt|ut=sökt|2 +uttalade|ut=ta=la=de|2 +uttalas|ut=ta=las|2 +uttryck|ut=tryck|2 +utvidgas|ut=vid=gas|2 +utvilad|ut=vi=lad|2 +vakuumbehållare|va=ku=um=be=hål=la=re|2 +vakuumbehållaren|va=ku=um=be=hål=la=ren|2 +valvbåge|valv=bå=ge|2 +vanligast|van=li=gast|2 +vanligtvis|van=ligt=vis|2 +vansinne|van=sin=ne|2 +vansinnet|van=sin=net|2 +varandras|var=and=ras|2 +variationer|va=ri=a=tio=ner|2 +variera|va=ri=e=ra|2 +varierande|va=ri=e=ran=de|2 +varnande|var=nan=de|2 +varnar|var=nar|2 +varningen|var=ning=en|2 +varsitt|var=sitt|2 +Varsågod|Var=så=god|2 +Vartenda|Vart=en=da|2 +vattenbaserade|vat=ten=ba=se=ra=de|2 +vattnas|vatt=nas|2 +vektorerna|vek=to=rer=na|2 +Verktyg|Verk=tyg|2 +verktygslådan|verk=tygs=lå=dan|2 +Vetenskap|Ve=ten=skap|2 +vetenskapsexpert|ve=ten=skap=s=ex=pert|2 +vetenskapsman|ve=ten=skaps=man|2 +vetenskapsmänniska|ve=ten=skaps=män=ni=ska|2 +vetenskapsutrustning|ve=ten=skaps=ut=rust=ning|2 +vetskapen|vet=ska=pen|2 +vetter|vet=ter|2 +vettet|vet=tet|2 +vettig|vet=tig|2 +vibrationer|vib=ra=tio=ner|2 +Vidare|Vi=da=re|2 +videon|vi=de=on|2 +villkor|vill=kor|2 +vinddraget|vind=dra=get|2 +vindlande|vind=lan=de|2 +Vinkeln|Vin=keln|2 +vinner|vin=ner|2 +vippströmbrytaren|vipp=ström=bry=ta=ren|2 +visades|vi=sa=des|2 +visserligen|vis=ser=li=gen|2 +Visstja|Vis=s=tja|2 +vittnar|vitt=nar|2 +vodkaglas|vod=kag=las|2 +vodkan|vod=kan|2 +vokabulären|vo=ka=bu=lä=ren|2 +votering|vo=te=ring|2 +vridning|vrid=ning|2 +vridningen|vrid=ning=en|2 +vrålar|vrå=lar|2 +väderförhållanden|vä=der=för=hål=lan=den|2 +vädermönstren|vä=der=mönst=ren|2 +vädret|väd=ret|2 +väggar|väg=gar|2 +väggfästen|vägg=fäs=ten|2 +välbekant|väl=be=kant|2 +väldig|väl=dig|2 +väldiga|väl=di=ga|2 +Väldigt|Väl=digt|2 +välförsett|väl=för=sett|2 +välklädda|väl=kläd=da|2 +VÄLKOMMEN|VÄL=KOM=MEN|2 +vänligt|vän=ligt|2 +väntan|vän=tan|2 +väntande|vän=tan=de|2 +Väntat|Vän=tat|2 +värdena|vär=de=na|2 +värker|vär=ker|2 +Världen|Värl=den|2 +världsbefolkningen|världs=be=folk=ning=en|2 +världsledare|världs=le=da=re|2 +värmeelementet|vär=me=ele=men=tet|2 +värmeenergin|vär=me=ener=gin|2 +värmesystemet|vär=me=sys=te=met|2 +väsandet|vä=san=det|2 +västra|väst=ra|2 +vätebomb|vä=te=bomb|2 +vätejoner|vä=te=jo=ner|2 +vätskan|väts=kan|2 +växthusgas|växt=hus=gas|2 +växthusgaser|växt=hus=ga=ser|2 +våglängderna|våg=läng=der=na|2 +vårdkoj|vård=koj|2 +whiskyglas|whis=kyg=las|2 +Wikipedia|Wiki=pe=dia|2 +xenonitbubbla|xe=no=nit=bubb=la|2 +Xenoniten|Xe=no=ni=ten|2 +xenonitväggen|xe=no=nit=väg=gen|2 +yrkanden|yr=kan=den|2 +ytterdörr|yt=ter=dörr|2 +ytterhöljet|yt=ter=höl=jet|2 +ytterst|yt=terst|2 +ädelgas|ädel=gas|2 +äldsta|älds=ta|2 +ätliga|ät=li=ga|2 +äventyr|även=tyr|2 +århundradets|år=hun=dra=dets|2 +åstadkommit|åstad=kom=mit|2 +återgått|åter=gått|2 +återkommer|åter=kom=mer|2 +återstoden|åter=sto=den|2 +ÅTGÄRD|ÅT=GÄRD|2 +åtskilliga|åt=skil=li=ga|2 +Ögonlocken|Ögon=lock=en|2 +ökningen|ök=ning=en|2 +öppnat|öpp=nat|2 +öppningarna|öpp=ning=ar=na|2 +överdos|över=dos|2 +överdrivna|över=driv=na|2 +överenskommelsen|över=ens=kom=mel=sen|2 +övergick|över=gick|2 +överlevnad|över=lev=nad|2 +överlägset|över=läg=set|2 +överlämnar|över=läm=nar|2 +överraskning|över=rask=ning|2 +överraskningar|över=rask=ning=ar|2 +översätta|över=sät=ta|2 +översållat|över=sål=lat|2 +övertryck|över=tryck|2 +övertyga|över=ty=ga|2 +övriga|öv=ri=ga|2 +övrigt|öv=rigt|2 +илюхина|илюхина|2 +abnorma|ab=nor=ma|1 +accelerationerna|ac=ce=le=ra=tio=ner=na|1 +accelerationskraften|ac=ce=le=ra=tions=kraf=ten|1 +accelerationsläge|ac=ce=le=ra=tions=lä=ge|1 +accelerationslängd|ac=ce=le=ra=tions=längd|1 +accelerationsäventyr|ac=ce=le=ra=tions=även=tyr|1 +Accelerera|Ac=ce=le=re=ra|1 +accelereration|ac=ce=le=re=ra=tion|1 +accelerometer|ac=ce=le=ro=me=ter|1 +accent|ac=cent|1 +acceptabel|ac=cep=ta=bel|1 +acceptabelt|ac=cep=ta=belt|1 +accepteras|ac=cep=te=ras|1 +acklimatiseras|ac=kli=ma=ti=se=ras|1 +ackorden|ac=kor=den|1 +ackordet|ac=kor=det|1 +adderar|ad=de=rar|1 +administratörer|ad=mi=ni=stra=tö=rer|1 +adrenalinrusningen|ad=re=nal=in=rus=ning=en|1 +Adrianliv|Ad=ri=an=liv|1 +Adriansken|Ad=ri=ans=ken|1 +Adrianäventyr|Ad=ri=a=nä=ven=tyr|1 +advokat|ad=vo=kat|1 +advokaten|ad=vo=ka=ten|1 +aerodynamik|aero=dy=na=mik|1 +aerodynamikens|aero=dy=na=mi=kens|1 +afrikansk|af=ri=kansk|1 +afrikanske|af=ri=kans=ke|1 +Afrikas|Af=ri=kas|1 +agapaddorna|aga=pad=dor=na|1 +agenterna|ag=en=ter=na|1 +aggregaten|ag=gre=ga=ten|1 +aggregationstillståndsföränderligt|ag=gre=ga=tions=till=stånds=för=än=der=ligt|1 +aggressiva|ag=gres=si=va|1 +aggressivt|ag=gres=sivt|1 +akronym|akro=nym|1 +aktuellt|ak=tu=ellt|1 +Albert|Al=bert|1 +alfabeten|al=fa=be=ten|1 +Algerna|Al=ger=na|1 +ALLDELES|ALL=DE=LES|1 +allierade|al=li=e=ra=de|1 +allmän|all=män|1 +allmänhet|all=män=het|1 +allmänheten|all=män=he=ten|1 +alstrar|alst=rar|1 +alstras|alst=ras|1 +alstringen|alst=ring=en|1 +alternativa|al=ter=na=ti=va|1 +alternativknapparna|al=ter=na=tiv=knap=par=na|1 +Aluminium|Alu=mi=ni=um|1 +aluminiumblock|alu=mi=ni=um=block|1 +aluminiumfolie|alu=mi=ni=um=fo=lie|1 +Aluminiumplåt|Alu=mi=ni=ump=låt|1 +aluminiumplåten|alu=mi=ni=ump=lå=ten|1 +aluminiumskrov|alu=mi=ni=um=skrov|1 +aluminiumspånen|alu=mi=ni=um=spå=nen|1 +Amaterasu|Ama=te=ra=su|1 +amatör|ama=tör|1 +amatörastronomer|ama=tö=rast=ro=no=mer|1 +amatörerna|ama=tö=rer=na|1 +amatörgenererade|ama=tör=ge=ne=re=ra=de|1 +amatörmässiga|ama=tör=mäs=si=ga|1 +Ambulerande|Am=bu=le=ran=de|1 +Amerika|Ame=ri=ka|1 +amerikanen|ame=ri=ka=nen|1 +amerikaner|ame=ri=ka=ner|1 +amerikanske|ame=ri=kans=ke|1 +ammoniakatmosfär|am=mo=ni=a=kat=mo=sfär|1 +ammoniaken|am=mo=ni=a=ken|1 +ammoniakhalsbanden|am=mo=ni=ak=hals=ban=den|1 +ammoniaklukt|am=mo=nia=klukt|1 +ammoniaklukten|am=mo=nia=kluk=ten|1 +Ammoniaklukten|Am=mo=nia=kluk=ten|1 +ammunitionen|am=mu=ni=tio=nen|1 +amputerat|am=pu=te=rat|1 +Amundsen|Amund=sen|1 +amöbaliknande|amö=ba=lik=nan=de|1 +amöbalivsform|amö=ba=livs=form|1 +anakronism|ana=kro=nism|1 +analogi|ana=lo=gi|1 +analyser|ana=ly=ser|1 +Analyserade|Ana=ly=se=ra=de|1 +analyserades|ana=ly=se=ra=des|1 +andades|an=da=des|1 +andedräkt|an=de=dräkt|1 +andhämtning|and=hämt=ning|1 +andning|and=ning|1 +andningshål|and=nings=hål|1 +Andningssvårigheter|And=nings=svå=rig=he=ter|1 +andras|andras|1 +Andrea|Andrea|1 +Andrew|And=rew|1 +anfäder|an=fä=der|1 +Angeles|Ang=e=les|1 +angelägna|an=ge=läg=na|1 +angivit|an=gi=vit|1 +angivningen|an=giv=ning=en|1 +angripa|an=gri=pa|1 +anhalt|an=halt|1 +ankarpunkter|an=kar=punk=ter|1 +anklagas|an=kla=gas|1 +ankrad|ank=rad|1 +ankrade|ank=ra=de|1 +ankrar|ank=rar|1 +anlita|an=li=ta|1 +Anodisera|Ano=di=se=ra|1 +anodisera|ano=di=se=ra|1 +anomal|ano=mal|1 +anomalier|ano=ma=li=er|1 +anomalin|ano=ma=lin|1 +anonym|ano=nym|1 +anonymt|ano=nymt|1 +anpassade|an=pas=sa=de|1 +anpassat|an=pas=sat|1 +ansamlades|an=sam=la=des|1 +Ansiktet|An=sik=tet|1 +ansiktsuttryck|an=sikts=ut=tryck|1 +ansiktsvinylrutan|an=sikts=vi=nyl=ru=tan|1 +ansiktsöppning|an=sikts=öpp=ning|1 +anslående|an=slå=en=de|1 +anspråk|an=språk|1 +ansträngde|an=sträng=de|1 +anställda|an=ställ=da|1 +ansvar|an=svar|1 +ansvarar|an=sva=rar|1 +antagande|an=ta=gan=de|1 +antagandet|an=ta=gan=det|1 +anteckna|an=teck=na|1 +antecknat|an=teck=nat|1 +antenn|an=tenn|1 +Antennen|An=ten=nen|1 +antiamerikanska|an=ti=a=me=ri=kans=ka|1 +antibiotikan|an=ti=bi=o=ti=kan|1 +antiklimax|an=tik=li=max|1 +antikrigsaktivist|an=ti=krigs=ak=ti=vist|1 +antikverad|an=tik=ve=rad|1 +antipartikel|an=ti=par=ti=kel|1 +antogs|an=togs|1 +antropomorfierar|an=tro=po=mor=fi=e=rar|1 +antydde|an=tyd=de|1 +antydningar|an=tyd=ning=ar|1 +anvisade|an=vi=sa=de|1 +anvisningar|an=vis=ning=ar|1 +använd|an=vänd|1 +användaren|an=vän=da=ren|1 +användargränssnitt|an=vän=dar=gräns=snitt|1 +användargränssnittsknapparna|an=vän=dar=gräns=snittsknap=par=na|1 +användbara|an=vänd=ba=ra|1 +användning|an=vänd=ning|1 +användningsmöjligheter|an=vänd=nings=möj=lig=he=ter|1 +apelsin|apel=sin|1 +apokalyptisk|apo=ka=lyp=tisk|1 +Apollorymdskeppet|Apol=lorymd=skep=pet|1 +Apparaten|Ap=pa=ra=ten|1 +apparaturen|ap=pa=ra=tu=ren|1