Compare commits

...

23 Commits

Author SHA1 Message Date
Jonas Diemer
063a1df851
Bugfix for #46: don't look at previous chapters if in chapter 0. (#48)
Some checks are pending
CI / build (push) Waiting to run
Fixes #46
2025-12-18 06:28:06 +11:00
Dave Allie
d429966dd4
Rename Screens to Activities and restructure files (#44)
## Summary

* This PR drastically reshapes the structure of the codebase, moving
from the concept of "Screens" to "Activities", restructing the files and
setting up the concept of subactivities.
* This should help with keep the main file clean and containing all
functional logic in the relevant activity.
* CrossPointState is now also a global singleton which should help with
accessing it from within activities.

## Additional Context

* This is probably going to be a bit disruptive for people with open
PRs, sorry 😞
2025-12-17 23:32:18 +11:00
Jonas Diemer
c78f2a9840
Calculate the progress in the book by file sizes of each chapter. (#38)
## Summary

Addresses #35.

Maybe it could be wise to do some caching of the spine sizes (but
performance isn't too bad).
2025-12-17 23:05:24 +11:00
Dave Allie
11f01d3a41
Add home screen (#42)
Some checks are pending
CI / build (push) Waiting to run
## Summary

* Add home screen
* Sits as new root screen, allows for navigation to settings or file
list
2025-12-17 20:47:43 +11:00
Arthur Tazhitdinov
973d372521
TOC location fix (#25)
## Summary

* Rely on media-type="application/x-dtbncx+xml" to find TOC instead of
hardcoded values

## Additional Context

* Most of my epubs don't have id==ncx for toc file location. I think
this media-type is EPUB standard

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-17 18:49:45 +11:00
Dave Allie
67da8139b3
Use 6x8kB chunks instead of 1x48kB chunk for secondary display buffer (#36)
Some checks are pending
CI / build (push) Waiting to run
## Summary

- When allocating the `bwBuffer` required to restore the RED RAM in the
EPD, we were previously allocating the whole frame buffer in one
contiguous memory chunk (48kB)
- Depending on the state of memory fragmentation at the time of this
call, it may not be possible to allocate all that memory
- Instead, we now allocate 6 blocks of 8kB instead of the full 48kB,
this should mean the display updates are more resilient to different
memory conditions

## Additional Context
2025-12-17 01:39:22 +11:00
Dave Allie
c287aa03a4
Use single buffer mode for EInkDisplay (#34)
## Summary

* Frees up 48kB of statically allocated RAM in exchange for 48kB just
when grayscale rendering is needed

## Additional Context

* Upstream changes:
https://github.com/open-x4-epaper/community-sdk/pull/7
2025-12-17 00:17:49 +11:00
Dave Allie
5d68c8b305
Cut release 0.6.0 2025-12-16 23:15:47 +11:00
Jonas Diemer
def7abbd60
Improve indent (#28)
* add horizontal indent in first line of paragraph in case Extra Paragraph Spacing is OFF

* Treat tabs as whitespace (so they are properly stripped)

* Changed size of indent to 1 em.

* Fixed calculation of space when indenting (avoiding squeezed text).

* Source code formatting
2025-12-16 23:02:32 +11:00
Jonas Diemer
9ad8111ce7
Wrap-around navigation in Settings. (#31) 2025-12-16 22:54:16 +11:00
Arthur Tazhitdinov
57d1939be7
Add Cyrillic range to fonts (#27)
* Enhance TOC parsing and chapter selection logic

- Update .gitignore to include additional paths
- Refactor Epub::parseContentOpf to improve NCX item retrieval
- Modify ContentOpfParser to store media type in ManifestItem
- Implement rebuildVisibleSpineIndices in EpubReaderChapterSelectionScreen for better chapter navigation
- Adjust rendering logic to handle empty chapter lists gracefully

* Refactor TOC parsing logic to streamline cover image and NCX item retrieval

* add cyrillic ranges

* revert

* clang format fix
2025-12-16 22:52:49 +11:00
Jonas Diemer
012992f904
Feature/auto poweroff (#32)
* Automatically deep sleep after 10 minutes of inactivity.

* formatting.
2025-12-16 22:49:31 +11:00
Dave Allie
c262f222de
Parse cover image path from content.opf file (#24)
Some checks are pending
CI / build (push) Waiting to run
2025-12-16 03:15:54 +11:00
Dave Allie
449b3ca161
Fixed light gray text rendering 2025-12-16 02:16:38 +11:00
Dave Allie
6989035ef8
Run CI action on PR as well as push 2025-12-15 23:17:35 +11:00
Dave Allie
108cf57202
Fix formatting 2025-12-15 23:17:23 +11:00
Jonas Diemer
a640fbecf8
Settings Screen and first 2 settings (#18)
* white sleep screen

* quicker pwr button

* no extra spacing between paragraphs

* Added settings class with de/serialization and whiteSleepScreen setting to control inverting the sleep screen

* Added Settings screen for real, made settings a global singleton

* Added setting for extra paragraph spacing.

* fixed typo

* Rework after feedback

* Fixed type from bool to uint8
2025-12-15 23:16:46 +11:00
Dave Allie
7a5719b46d
Upgrade open-x4-sdk to fix white streaks on sleep screen (#21)
https://github.com/open-x4-epaper/community-sdk/pull/6 fixes a power down issue with the display which was causing streaks to appear on the sleep screen
2025-12-15 22:27:27 +11:00
Dave Allie
8c3576e397
Add Github Action to build release firmware on tag (#20)
Some checks are pending
CI / build (push) Waiting to run
2025-12-15 20:00:34 +11:00
Dave Allie
fdb5634ea6
Add cppcheck and formatter to CI (#19)
* Add cppcheck and formatter to CI

* Checkout submodules

* Install matching clang-format version in CI
2025-12-15 19:46:52 +11:00
Dave Allie
5cabba7712
Add Github templates
Added Github templates for PRs and bugs
Also added one for funding, please do not feel obligated to
donate to the project, this is not a for-profit endevour, I
just had someone ask where they could send a few dollars so
I have set it up
2025-12-15 08:16:59 +11:00
Dave Allie
a86d405fb0
Add comparison images 2025-12-14 13:46:15 +11:00
Dave Allie
e4b5dc0e6a
Update contribution instructions 2025-12-14 13:46:03 +11:00
68 changed files with 20181 additions and 11330 deletions

2
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,2 @@
github: [daveallie]
ko_fi: daveallie

54
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@ -0,0 +1,54 @@
name: Bug Report
description: Report an issue or unexpected behavior
title: "Short, descriptive title of the issue"
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to report this bug! Please fill out the details below.
- type: input
id: version
attributes:
label: Affected Version
description: What version of the project/library are you using? (e.g., v1.2.3, master branch commit SHA)
placeholder: Ex. v1.2.3
validations:
required: true
- type: textarea
id: bug-description
attributes:
label: Describe the Bug
description: A clear and concise description of what the bug is.
placeholder:
validations:
required: true
- type: textarea
id: steps-to-reproduce
attributes:
label: Steps to Reproduce
description: Clearly list the steps necessary to reproduce the unexpected behavior.
placeholder: |
1. Go to '...'
2. Select '...'
3. Crash
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant Log Output/Screenshots
description: If applicable, error messages, or log output to help explain your problem. You can drag and drop images here.
render: shell

9
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,9 @@
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user authentication module, Implements the new feature for
file uploading.)
* **What changes are included?**
## Additional Context
* Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks, specific areas to focus on).

43
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,43 @@
name: CI
'on':
push:
branches: [master]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- uses: actions/cache@v5
with:
path: |
~/.cache/pip
~/.platformio/.cache
key: ${{ runner.os }}-pio
- uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: Install PlatformIO Core
run: pip install --upgrade platformio
- name: Install clang-format-21
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 21
sudo apt-get update
sudo apt-get install -y clang-format-21
- name: Run cppcheck
run: pio check --fail-on-defect medium --fail-on-defect high
- name: Run clang-format
run: PATH="/usr/lib/llvm-21/bin:$PATH" ./bin/clang-format-fix && git diff --exit-code || (echo "Please run 'bin/clang-format-fix' to fix formatting issues" && exit 1)
- name: Build CrossPoint
run: pio run

40
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: Compile Release
on:
push:
tags:
- '*'
jobs:
build-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- uses: actions/cache@v5
with:
path: |
~/.cache/pip
~/.platformio/.cache
key: ${{ runner.os }}-pio
- uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: Install PlatformIO Core
run: pip install --upgrade platformio
- name: Build CrossPoint
run: pio run -e gh_release
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: CrossPoint-${{ github.ref_name }}
path: |
.pio/build/gh_release/bootloader.bin
.pio/build/gh_release/firmware.bin
.pio/build/gh_release/firmware.elf
.pio/build/gh_release/firmware.map
.pio/build/gh_release/partitions.bin

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.pio
.idea
.DS_Store
.vscode
lib/EpdFont/fontsrc

View File

@ -6,7 +6,7 @@ Built using **PlatformIO** and targeting the **ESP32-C3** microcontroller.
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.
![](./docs/cover.jpg)
![](./docs/images/cover.jpg)
## Motivation
@ -131,6 +131,9 @@ EPUB file will reset the reading progress.
Contributions are very welcome!
If you're looking for a way to help out, take a look at the [ideas discussion board](https://github.com/daveallie/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.
### To submit a contribution:
1. Fork the repo

19
docs/comparison.md Normal file
View File

@ -0,0 +1,19 @@
# CrossPoint vs XTOS
Below is like for like comparison of CrossPoint (version 0.5.1) and XTOS (version 3.1.1). CrossPoint is on the left,
XTOS is on the right. CrossPoint does not currently support all features of XTOS, so this comparison is just of key
features which both firmwares support.
## EPUB reading
![](./images/comparison/reading-1.jpg)
![](./images/comparison/reading-2.jpg)
![](./images/comparison/reading-3.jpg)
## Menus
![](./images/comparison/menu.jpg)
![](./images/comparison/chapter-menu.jpg)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 2.2 MiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
#pragma once
#include "EpdFontData.h"
static const uint8_t pixelarial14Bitmaps[1145] = {
static const uint8_t pixelarial14Bitmaps[8296] = {
0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0x1C, 0x63, 0x8C, 0xF7, 0x98, 0xCF, 0xFF, 0xFF, 0xDC, 0xE7, 0xFE, 0xFF,
0xFF, 0xFB, 0x9C, 0x63, 0x0C, 0x60, 0x30, 0xF3, 0xFF, 0xBF, 0x1F, 0x9F, 0x9B, 0x37, 0xEF, 0xFB, 0xE3, 0x00, 0x70,
0x67, 0xCF, 0x37, 0x61, 0xBB, 0x0D, 0xF0, 0x7D, 0x81, 0xDD, 0xC0, 0xDF, 0x07, 0x98, 0xFC, 0xC7, 0x66, 0x7B, 0xF3,
@ -67,11 +67,392 @@ static const uint8_t pixelarial14Bitmaps[1145] = {
0x66, 0x66, 0x7E, 0x3C, 0x3C, 0x7E, 0x66, 0xE7, 0xC3, 0xC1, 0xE0, 0xF0, 0x7C, 0x76, 0x33, 0xB8, 0xD8, 0x6C, 0x36,
0x1F, 0x07, 0x03, 0x81, 0xC3, 0xE1, 0xC0, 0xFF, 0xFF, 0x06, 0x1E, 0x1C, 0x1C, 0x30, 0x30, 0x70, 0xFF, 0xFF, 0x37,
0x66, 0x66, 0x6E, 0xCE, 0x66, 0x66, 0x67, 0x30, 0xFF, 0xFF, 0xFF, 0xC0, 0xCE, 0x66, 0x66, 0x67, 0x37, 0x66, 0x66,
0x6E, 0xC0, 0xC3, 0x9B, 0xFF, 0xF9, 0xB8, 0x30, 0xDB, 0x66, 0xC0, 0x6D, 0xBD, 0x80, 0x7F, 0xEF, 0x3C, 0xF3, 0xC0,
0x7D, 0xF7, 0xDF, 0xF3, 0xC0,
0x6E, 0xC0, 0xC3, 0x9B, 0xFF, 0xF9, 0xB8, 0x30, 0xFC, 0x0D, 0xBF, 0xFF, 0xF0, 0x1C, 0x1C, 0x3E, 0x7E, 0xE0, 0xE0,
0xE0, 0xE0, 0xE0, 0x7A, 0x3E, 0x1C, 0x1C, 0x3F, 0x3B, 0x70, 0x70, 0x70, 0x70, 0xFE, 0x70, 0x70, 0x70, 0x60, 0x7F,
0x61, 0xBF, 0xDF, 0xCC, 0x66, 0x33, 0x19, 0xFC, 0xFF, 0x61, 0x80, 0xE1, 0xD8, 0xE7, 0x30, 0xDC, 0x3E, 0x07, 0x87,
0xF8, 0x30, 0x0C, 0x1F, 0xE0, 0xC0, 0x30, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0x3F, 0x70, 0x60, 0x70, 0x7C, 0x6F,
0xE3, 0xE3, 0x7F, 0x3E, 0x07, 0x07, 0x6E, 0xFE, 0xEF, 0xB0, 0x1F, 0x87, 0x1C, 0x66, 0x6D, 0xFF, 0xD8, 0x3F, 0x83,
0xD8, 0x3D, 0x83, 0xDF, 0xF6, 0x66, 0x71, 0xE1, 0xF8, 0x7D, 0x37, 0xFB, 0xED, 0xF0, 0x3B, 0x77, 0x7E, 0xEE, 0x7E,
0x77, 0x3B, 0xFF, 0x80, 0xC0, 0x60, 0x30, 0x18, 0xF8, 0x1F, 0x87, 0x1C, 0x60, 0x6D, 0xF7, 0xDB, 0xBD, 0xBB, 0xDF,
0x3D, 0xB3, 0xD9, 0xF6, 0x06, 0x71, 0xE1, 0xF8, 0xFC, 0x7B, 0xEC, 0xFE, 0x78, 0x0C, 0x06, 0x03, 0x1F, 0xF0, 0xC0,
0x60, 0x30, 0x00, 0x00, 0x7F, 0xC0, 0xFB, 0x61, 0x8E, 0x71, 0x8F, 0xC0, 0xF9, 0x61, 0x9E, 0x1F, 0x7F, 0x80, 0x6E,
0xC0, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xE7, 0xF7, 0xFF, 0xC0, 0xC0, 0xC0, 0x3F, 0xDF, 0x77, 0xDF, 0xF7, 0xFD,
0xDF, 0x77, 0xDC, 0x77, 0x0D, 0xC3, 0x70, 0xDC, 0x37, 0x0D, 0xC3, 0x70, 0xDC, 0x77, 0x67, 0xF0, 0x73, 0x8C, 0x63,
0x18, 0xC0, 0x7C, 0xDF, 0x9F, 0x36, 0xEF, 0x80, 0xEC, 0x6E, 0x77, 0x3F, 0x77, 0x6E, 0xEC, 0x70, 0x70, 0xE0, 0xC0,
0xC3, 0x81, 0x86, 0x03, 0x18, 0x06, 0x73, 0x8C, 0xCF, 0x03, 0x9E, 0x06, 0x6C, 0x1C, 0xFC, 0x30, 0x30, 0xE0, 0x60,
0x70, 0x60, 0xE1, 0xC0, 0xC3, 0x01, 0x8E, 0x03, 0x18, 0x06, 0x7F, 0x8C, 0xDB, 0x03, 0x06, 0x0E, 0x1C, 0x18, 0x70,
0x71, 0xC0, 0xC3, 0xE0, 0xF8, 0x70, 0xB0, 0xC0, 0x63, 0x83, 0xC6, 0x01, 0xDC, 0x1B, 0xB3, 0xBE, 0xEF, 0x01, 0x9E,
0x07, 0x6C, 0x1C, 0xFC, 0x30, 0x30, 0xE0, 0x60, 0x38, 0x70, 0x00, 0x01, 0x87, 0x0E, 0x38, 0xE1, 0xC3, 0xFB, 0xF0,
0x1C, 0x01, 0xE0, 0x06, 0x00, 0x00, 0x0E, 0x00, 0xE0, 0x1F, 0x01, 0xB0, 0x1B, 0x83, 0xB8, 0x31, 0xC7, 0x1C, 0x7F,
0xC6, 0x0E, 0xE0, 0xEE, 0x06, 0x03, 0x00, 0xF0, 0x0E, 0x00, 0x00, 0x0E, 0x00, 0xE0, 0x1F, 0x01, 0xB0, 0x1B, 0x83,
0xB8, 0x31, 0xC7, 0x1C, 0x7F, 0xC6, 0x0E, 0xE0, 0xEE, 0x06, 0x0E, 0x01, 0xF0, 0x1B, 0x00, 0x00, 0x0E, 0x00, 0xE0,
0x1F, 0x01, 0xB0, 0x1B, 0x83, 0xB8, 0x31, 0xC7, 0x1C, 0x7F, 0xC6, 0x0E, 0xE0, 0xEE, 0x06, 0x1F, 0x81, 0xF0, 0x00,
0x00, 0x00, 0x0E, 0x00, 0xE0, 0x1F, 0x01, 0xB0, 0x1B, 0x83, 0xB8, 0x31, 0xC7, 0x1C, 0x7F, 0xC6, 0x0E, 0xE0, 0xEE,
0x06, 0x1B, 0x81, 0xB8, 0x00, 0x00, 0xE0, 0x0E, 0x01, 0xF0, 0x1B, 0x01, 0xB8, 0x3B, 0x83, 0x1C, 0x71, 0xC7, 0xFC,
0x60, 0xEE, 0x0E, 0xE0, 0x60, 0x0E, 0x01, 0xF0, 0x0F, 0x00, 0xE0, 0x0F, 0x01, 0xF0, 0x1B, 0x01, 0xB8, 0x3B, 0x83,
0x1C, 0x71, 0xC7, 0xFC, 0x60, 0xEE, 0x0E, 0xE0, 0x60, 0x03, 0xFE, 0x03, 0xC0, 0x07, 0xC0, 0x06, 0xC0, 0x0E, 0xC0,
0x1C, 0xFE, 0x18, 0xC0, 0x38, 0xC0, 0x3F, 0xC0, 0x70, 0xC0, 0xE0, 0xC0, 0xE0, 0xFF, 0x02, 0x03, 0xF8, 0xF3, 0x38,
0x07, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0E, 0x01, 0xC0, 0x1E, 0x61, 0xFC, 0x0E, 0x01, 0xC0, 0x78, 0x38, 0x1E,
0x07, 0x00, 0x0F, 0xF7, 0x03, 0x81, 0xC0, 0xE0, 0x7F, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xFF, 0x0E, 0x0F, 0x06,
0x00, 0x0F, 0xF7, 0x03, 0x81, 0xC0, 0xE0, 0x7F, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xFF, 0x18, 0x1E, 0x19, 0x80,
0x0F, 0xF7, 0x03, 0x81, 0xC0, 0xE0, 0x7F, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xFF, 0x7E, 0x3F, 0x00, 0x1F, 0xEE,
0x07, 0x03, 0x81, 0xC0, 0xFE, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0xFE, 0xCF, 0x70, 0x77, 0x77, 0x77, 0x77, 0x77,
0x77, 0x6E, 0xC0, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x31, 0xE6, 0xC0, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x8E, 0x38,
0xE3, 0x8E, 0xEF, 0xB0, 0x0E, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x80, 0x7F, 0x87, 0x3C, 0x70, 0xE7,
0x06, 0x70, 0x7F, 0xC7, 0x70, 0x77, 0x07, 0x70, 0x67, 0x0E, 0x73, 0xC7, 0xF8, 0x3F, 0x0F, 0xC0, 0x00, 0x00, 0xE0,
0xF8, 0x3F, 0x0F, 0xE3, 0xEC, 0xFB, 0x3E, 0x6F, 0x9B, 0xE3, 0xF8, 0x7E, 0x1F, 0x83, 0x0E, 0x00, 0x78, 0x00, 0xC0,
0x00, 0x01, 0xFC, 0x1E, 0xF1, 0xC1, 0xCE, 0x06, 0x60, 0x3B, 0x01, 0xD8, 0x0E, 0xC0, 0x77, 0x03, 0x38, 0x38, 0xF7,
0x83, 0xF8, 0x03, 0x80, 0x3C, 0x01, 0xC0, 0x00, 0x01, 0xFC, 0x1E, 0xF1, 0xC1, 0xCE, 0x06, 0x60, 0x3B, 0x01, 0xD8,
0x0E, 0xC0, 0x77, 0x03, 0x38, 0x38, 0xF7, 0x83, 0xF8, 0x07, 0x00, 0x7C, 0x03, 0x60, 0x00, 0x01, 0xFC, 0x1E, 0xF1,
0xC1, 0xCE, 0x06, 0x60, 0x3B, 0x01, 0xD8, 0x0E, 0xC0, 0x77, 0x03, 0x38, 0x38, 0xF7, 0x83, 0xF8, 0x0F, 0xC0, 0x7C,
0x00, 0x00, 0x00, 0x01, 0xFC, 0x1E, 0xF1, 0xC1, 0xCE, 0x06, 0x60, 0x3B, 0x01, 0xD8, 0x0E, 0xC0, 0x77, 0x03, 0x38,
0x38, 0xF7, 0x83, 0xF8, 0x0D, 0xC0, 0x6E, 0x00, 0x00, 0x3F, 0x83, 0xDE, 0x38, 0x39, 0xC0, 0xCC, 0x07, 0x60, 0x3B,
0x01, 0xD8, 0x0E, 0xE0, 0x67, 0x07, 0x1E, 0xF0, 0x7F, 0x00, 0x42, 0xEE, 0x7E, 0x3C, 0x7E, 0xEE, 0x42, 0x1F, 0xF1,
0xEF, 0x9C, 0x3C, 0xE3, 0xE6, 0x3B, 0xB1, 0x9D, 0x9C, 0xED, 0xC7, 0x7C, 0x33, 0xE3, 0x8F, 0x78, 0xFF, 0x80, 0x18,
0x07, 0x00, 0xC0, 0x00, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xE1, 0xF8, 0x67, 0xF8, 0xFC,
0x06, 0x03, 0x80, 0xC0, 0x00, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xE1, 0xF8, 0x67, 0xF8,
0xFC, 0x0C, 0x07, 0x83, 0x20, 0x00, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xE1, 0xF8, 0x67,
0xF8, 0xFC, 0x3F, 0x0F, 0xC0, 0x03, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x87, 0xE1, 0x9F,
0xE3, 0xF0, 0x06, 0x01, 0xC0, 0x30, 0x00, 0x0E, 0x1D, 0xC3, 0x9C, 0xE1, 0xDC, 0x3F, 0x03, 0xC0, 0x78, 0x06, 0x00,
0xC0, 0x18, 0x03, 0x00, 0x60, 0xE0, 0x70, 0x3F, 0x9D, 0xEE, 0x3F, 0x0F, 0x87, 0xC7, 0xEF, 0x7F, 0x38, 0x1C, 0x00,
0x7E, 0x7B, 0xB9, 0xD8, 0xEC, 0xE6, 0xE3, 0x71, 0x9E, 0xC7, 0xE0, 0xF0, 0x7B, 0x7D, 0xF0, 0x38, 0x3C, 0x0C, 0x00,
0x7E, 0x2F, 0x03, 0x7F, 0x77, 0xE3, 0xE3, 0x73, 0x7F, 0x0E, 0x1E, 0x18, 0x00, 0x7E, 0x2F, 0x03, 0x7F, 0x77, 0xE3,
0xE3, 0x73, 0x7F, 0x1C, 0x3E, 0x36, 0x00, 0x7E, 0x2F, 0x03, 0x7F, 0x77, 0xE3, 0xE3, 0x73, 0x7F, 0x3F, 0x7E, 0x00,
0x00, 0x7E, 0x2F, 0x03, 0x7F, 0x77, 0xE3, 0xE3, 0x73, 0x7F, 0x36, 0x36, 0x00, 0x7E, 0x2F, 0x03, 0x7F, 0x77, 0xE3,
0xE3, 0x73, 0x7F, 0x1C, 0x36, 0x36, 0x1C, 0x00, 0x7E, 0x2F, 0x03, 0x7F, 0x77, 0xE3, 0xE3, 0x73, 0x7F, 0x7F, 0xF8,
0xBF, 0xF0, 0x79, 0xC0, 0xC3, 0x7F, 0xFF, 0xDC, 0x0E, 0x38, 0x1D, 0xF6, 0x7F, 0xF8, 0x3F, 0x7A, 0x60, 0x60, 0xE0,
0x60, 0x60, 0x7B, 0x3F, 0x0C, 0x0E, 0x1C, 0x18, 0x0E, 0x03, 0x00, 0x03, 0xF3, 0xF9, 0x8E, 0xC7, 0xFF, 0xB0, 0x18,
0x0F, 0x63, 0xF0, 0x06, 0x07, 0x03, 0x00, 0x03, 0xF3, 0xF9, 0x8E, 0xC7, 0xFF, 0xB0, 0x18, 0x0F, 0x63, 0xF0, 0x0C,
0x0F, 0x0C, 0x80, 0x03, 0xF3, 0xF9, 0x8E, 0xC7, 0xFF, 0xB0, 0x18, 0x0F, 0x63, 0xF0, 0x3F, 0x1F, 0x80, 0x07, 0xE7,
0xF3, 0x1D, 0x8F, 0xFF, 0x60, 0x30, 0x1E, 0xC7, 0xE0, 0xCE, 0x60, 0x66, 0x66, 0x66, 0x66, 0x60, 0x6E, 0xC0, 0xCC,
0xCC, 0xCC, 0xCC, 0xC0, 0x31, 0xE6, 0xC0, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xFF, 0xF0, 0x0C, 0x30, 0xC3,
0x0C, 0x30, 0xC3, 0x0C, 0x0F, 0xC3, 0xF0, 0xF8, 0x0E, 0x01, 0x8F, 0xE7, 0xF9, 0x86, 0xE1, 0x98, 0x66, 0x39, 0xFC,
0x3F, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0xFE, 0xEE, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0x18, 0x07, 0x00, 0xC0,
0x00, 0x3F, 0x1F, 0xE6, 0x19, 0x86, 0xE1, 0xD8, 0x66, 0x19, 0xFE, 0x3F, 0x00, 0x06, 0x03, 0x80, 0xC0, 0x00, 0x3F,
0x1F, 0xE6, 0x19, 0x86, 0xE1, 0xD8, 0x66, 0x19, 0xFE, 0x3F, 0x00, 0x0C, 0x07, 0x83, 0x30, 0x00, 0x3F, 0x1F, 0xE6,
0x19, 0x86, 0xE1, 0xD8, 0x66, 0x19, 0xFE, 0x3F, 0x00, 0x3F, 0x0F, 0xC0, 0x00, 0x00, 0x3F, 0x1F, 0xE6, 0x19, 0x86,
0xE1, 0xD8, 0x66, 0x19, 0xFE, 0x3F, 0x00, 0x3F, 0x0F, 0xC0, 0x00, 0xFC, 0x7F, 0x98, 0x66, 0x1B, 0x87, 0x61, 0x98,
0x67, 0xF8, 0xFC, 0x1C, 0x0E, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x38, 0x1C, 0x00, 0x3F, 0x9F, 0xE6, 0x79, 0xBE,
0xED, 0xDF, 0x67, 0x99, 0xFE, 0x7F, 0x00, 0x30, 0x38, 0x18, 0x00, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xE7, 0xF7,
0x7F, 0x0C, 0x1C, 0x18, 0x00, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xE7, 0xF7, 0x7F, 0x18, 0x3C, 0x6C, 0x00, 0xC7,
0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xE7, 0xF7, 0x7F, 0x7E, 0x7E, 0x00, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xE7, 0xF7,
0x7F, 0x0E, 0x0F, 0x06, 0x00, 0x0E, 0x37, 0x19, 0x9C, 0xCE, 0x76, 0x1B, 0x0F, 0x83, 0x81, 0xC0, 0xE2, 0xE1, 0xE0,
0xC0, 0x60, 0x30, 0x18, 0x0F, 0xE7, 0x7B, 0x0D, 0x86, 0xC3, 0xE1, 0xB0, 0xDF, 0xEF, 0xE6, 0x03, 0x01, 0x80, 0x36,
0x1B, 0x00, 0x1C, 0x6E, 0x33, 0x39, 0x9C, 0xEC, 0x36, 0x1F, 0x07, 0x03, 0x81, 0xC5, 0xC3, 0xC0, 0x1F, 0x00, 0x00,
0x00, 0x00, 0xE0, 0x0E, 0x01, 0xF0, 0x1B, 0x01, 0xB8, 0x3B, 0x83, 0x1C, 0x71, 0xC7, 0xFC, 0x60, 0xEE, 0x0E, 0xE0,
0x60, 0x3E, 0x00, 0x00, 0x7E, 0x2F, 0x03, 0x7F, 0x77, 0xE3, 0xE3, 0x73, 0x7F, 0x1B, 0x01, 0xF0, 0x00, 0x00, 0xE0,
0x0E, 0x01, 0xF0, 0x1B, 0x01, 0xB8, 0x3B, 0x83, 0x1C, 0x71, 0xC7, 0xFC, 0x60, 0xEE, 0x0E, 0xE0, 0x60, 0x36, 0x3E,
0x00, 0x7E, 0x2F, 0x03, 0x7F, 0x77, 0xE3, 0xE3, 0x73, 0x7F, 0x0E, 0x00, 0xE0, 0x1F, 0x01, 0xB0, 0x1B, 0x83, 0xB8,
0x31, 0xC7, 0x1C, 0x7F, 0xC6, 0x0E, 0xE0, 0xEE, 0x06, 0x00, 0xE0, 0x0C, 0x00, 0xF0, 0x7E, 0x2F, 0x03, 0x7F, 0x77,
0xE3, 0xE3, 0x73, 0x7F, 0x06, 0x0E, 0x0F, 0x03, 0x00, 0xE0, 0x18, 0x01, 0x01, 0xFC, 0x79, 0x9C, 0x03, 0x80, 0x60,
0x0C, 0x01, 0x80, 0x30, 0x07, 0x00, 0xE0, 0x0F, 0x30, 0xFE, 0x06, 0x0E, 0x0C, 0x00, 0x3F, 0x7A, 0x60, 0x60, 0xE0,
0x60, 0x60, 0x7B, 0x3F, 0x06, 0x01, 0xE0, 0x36, 0x01, 0x01, 0xFC, 0x79, 0x9C, 0x03, 0x80, 0x60, 0x0C, 0x01, 0x80,
0x30, 0x07, 0x00, 0xE0, 0x0F, 0x30, 0xFE, 0x0C, 0x1E, 0x32, 0x00, 0x3F, 0x7A, 0x60, 0x60, 0xE0, 0x60, 0x60, 0x7B,
0x3F, 0x07, 0x00, 0xE0, 0x08, 0x0F, 0xE3, 0xCC, 0xE0, 0x1C, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x38, 0x07, 0x00,
0x79, 0x87, 0xF0, 0x0C, 0x0C, 0x00, 0x3F, 0x7A, 0x60, 0x60, 0xE0, 0x60, 0x60, 0x7B, 0x3F, 0x0D, 0x81, 0xE0, 0x18,
0x01, 0x01, 0xFC, 0x79, 0x9C, 0x03, 0x80, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x07, 0x00, 0xE0, 0x0F, 0x30, 0xFE, 0x32,
0x1E, 0x0C, 0x00, 0x3F, 0x7A, 0x60, 0x60, 0xE0, 0x60, 0x60, 0x7B, 0x3F, 0x36, 0x07, 0xC0, 0x70, 0x00, 0x0F, 0xF1,
0xCF, 0x38, 0x77, 0x0E, 0xE0, 0xDC, 0x1F, 0x83, 0xF0, 0x6E, 0x1D, 0xC3, 0xB9, 0xE7, 0xF8, 0x01, 0xF0, 0x1F, 0x01,
0xF0, 0x1E, 0x3F, 0x87, 0xF8, 0x61, 0x86, 0x18, 0xE1, 0x86, 0x18, 0x61, 0x87, 0xB8, 0x3F, 0x80, 0x7F, 0x87, 0x3C,
0x70, 0xE7, 0x06, 0x70, 0x7F, 0xC7, 0x70, 0x77, 0x07, 0x70, 0x67, 0x0E, 0x73, 0xC7, 0xF8, 0x01, 0x80, 0x60, 0xFC,
0x06, 0x3F, 0x9F, 0xE6, 0x19, 0x86, 0xE1, 0x98, 0x66, 0x19, 0xEE, 0x3F, 0x80, 0x7E, 0x00, 0x00, 0x1F, 0xEE, 0x07,
0x03, 0x81, 0xC0, 0xFE, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0xFE, 0x3F, 0x00, 0x00, 0x07, 0xE7, 0xF3, 0x1D, 0x8F,
0xFF, 0x60, 0x30, 0x1E, 0xC7, 0xE0, 0x7E, 0x1E, 0x00, 0x1F, 0xEE, 0x07, 0x03, 0x81, 0xC0, 0xFE, 0x70, 0x38, 0x1C,
0x0E, 0x07, 0x03, 0xFE, 0x36, 0x0F, 0x00, 0x07, 0xE7, 0xF3, 0x1D, 0x8F, 0xFF, 0x60, 0x30, 0x1E, 0xC7, 0xE0, 0x18,
0x0C, 0x00, 0x1F, 0xEE, 0x07, 0x03, 0x81, 0xC0, 0xFE, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0xFE, 0x0C, 0x06, 0x00,
0x07, 0xE7, 0xF3, 0x1D, 0x8F, 0xFF, 0x60, 0x30, 0x1E, 0xC7, 0xE0, 0xFF, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0xF3, 0x81,
0xC0, 0xE0, 0x70, 0x38, 0x1F, 0xF0, 0x70, 0x30, 0x1E, 0x3F, 0x3F, 0x98, 0xEC, 0x7F, 0xFB, 0x01, 0x80, 0xF6, 0x3F,
0x03, 0x83, 0x80, 0xE0, 0x64, 0x1E, 0x06, 0x00, 0x0F, 0xF7, 0x03, 0x81, 0xC0, 0xE0, 0x7F, 0x38, 0x1C, 0x0E, 0x07,
0x03, 0x81, 0xFF, 0x32, 0x0F, 0x03, 0x00, 0x00, 0x01, 0xF9, 0xFC, 0xC7, 0x63, 0xFF, 0xD8, 0x0C, 0x07, 0xB1, 0xF8,
0x07, 0x01, 0xF0, 0x36, 0x00, 0x01, 0xFC, 0x7B, 0x9C, 0x03, 0x80, 0x60, 0x0C, 0x01, 0x83, 0xB0, 0x77, 0x0E, 0xE1,
0xCF, 0x38, 0xFF, 0x0C, 0x0F, 0x06, 0xC0, 0x03, 0xFB, 0xDD, 0x8E, 0xC7, 0xE3, 0xF1, 0xD8, 0xEF, 0xF3, 0xF8, 0x1D,
0xDC, 0xFE, 0x0D, 0x81, 0xF0, 0x00, 0x0F, 0xE3, 0xDC, 0xE0, 0x1C, 0x03, 0x00, 0x60, 0x0C, 0x1D, 0x83, 0xB8, 0x77,
0x0E, 0x79, 0xC7, 0xF8, 0x1F, 0x0F, 0x00, 0x07, 0xF7, 0xBB, 0x1D, 0x8F, 0xC7, 0xE3, 0xB1, 0xDF, 0xE7, 0xF0, 0x3B,
0xB9, 0xFC, 0x07, 0x00, 0xE0, 0x00, 0x0F, 0xE3, 0xDC, 0xE0, 0x1C, 0x03, 0x00, 0x60, 0x0C, 0x1D, 0x83, 0xB8, 0x77,
0x0E, 0x79, 0xC7, 0xF8, 0x0C, 0x06, 0x00, 0x07, 0xF7, 0xBB, 0x1D, 0x8F, 0xC7, 0xE3, 0xB1, 0xDF, 0xE7, 0xF0, 0x3B,
0xB9, 0xFC, 0x1F, 0xC7, 0xB9, 0xC0, 0x38, 0x06, 0x00, 0xC0, 0x18, 0x3B, 0x07, 0x70, 0xEE, 0x1C, 0xF3, 0x8F, 0xF0,
0x00, 0x0E, 0x03, 0x80, 0x06, 0x07, 0x03, 0x00, 0x03, 0xFB, 0xDD, 0x8E, 0xC7, 0xE3, 0xF1, 0xD8, 0xEF, 0xF3, 0xF8,
0x1D, 0xDC, 0xFE, 0x0C, 0x07, 0x83, 0x30, 0x00, 0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xE1, 0xFF, 0xFE, 0x1F, 0x87, 0xE1,
0xF8, 0x7E, 0x1F, 0x87, 0x78, 0x3C, 0x00, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xFE, 0x77, 0x31, 0xD8, 0xEC, 0x76, 0x3B,
0x1D, 0x8E, 0xC7, 0x70, 0x63, 0x83, 0x3F, 0xFE, 0xE0, 0xC7, 0x06, 0x3F, 0xF1, 0xC1, 0x8E, 0x0C, 0x70, 0x63, 0x83,
0x1C, 0x18, 0xE0, 0xC0, 0x60, 0x30, 0x3F, 0x0C, 0x07, 0xF3, 0xB9, 0x8E, 0xC7, 0x63, 0xB1, 0xD8, 0xEC, 0x76, 0x38,
0x7D, 0xF8, 0x00, 0x03, 0x87, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x1C, 0xFF, 0xF0, 0x00, 0x30, 0xC3,
0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xFC, 0x00, 0x0E, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x80, 0xFC, 0x00,
0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0xDF, 0x80, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xC0, 0x7D, 0xE0,
0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0xEC, 0xF0, 0x66, 0x00, 0x66, 0x66,
0x66, 0x66, 0x6E, 0xCF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xC0, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E,
0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C, 0x1F, 0xB7, 0xF7, 0xE0, 0xCF, 0x9C, 0x00, 0x0C, 0xF9, 0xF3, 0xE7, 0xCF,
0x9F, 0x3E, 0x7C, 0xE1, 0xC3, 0x1E, 0x06, 0x07, 0x83, 0x60, 0x00, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0,
0xE0, 0x60, 0x33, 0xB9, 0xF8, 0x18, 0x78, 0xD8, 0x01, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x0E, 0x38,
0xE3, 0xB9, 0xCE, 0xF3, 0xF8, 0xFC, 0x3E, 0x0F, 0xC3, 0xF8, 0xEF, 0x39, 0xCE, 0x3B, 0x87, 0x00, 0x07, 0x03, 0xC0,
0xC0, 0xC0, 0xC0, 0xC0, 0xCE, 0xCE, 0xDC, 0xF8, 0xF8, 0xFC, 0xDC, 0xCE, 0xC7, 0x00, 0x38, 0x78, 0xC7, 0xCE, 0xDC,
0xF8, 0xF8, 0xFC, 0xDE, 0xCE, 0xC7, 0x30, 0xF0, 0xE0, 0x00, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
0xE0, 0xE0, 0xFF, 0xEE, 0x0C, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xEF, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
0xE0, 0xE0, 0xE0, 0xFF, 0x00, 0x18, 0x38, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xE7, 0x81, 0xDC, 0xFC, 0xF8,
0xF8, 0xF8, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xFF, 0xDE, 0xF7, 0xBC, 0x63, 0x18, 0xC6, 0x31, 0xCF, 0x00,
0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xEE, 0xEE, 0xE0, 0xE0, 0xE0, 0xE0, 0xFF, 0xC3, 0x0C, 0x30, 0xC3, 0x0D, 0xF7, 0xC3,
0x0C, 0x38, 0xF0, 0x38, 0x0E, 0x03, 0x80, 0xE0, 0x3E, 0x0F, 0x07, 0x81, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0xFF, 0x73,
0x9C, 0xE7, 0xBF, 0xDE, 0x73, 0x9C, 0xE3, 0x80, 0x06, 0x03, 0x80, 0xC0, 0x00, 0xE0, 0xF8, 0x3F, 0x0F, 0xE3, 0xEC,
0xFB, 0x3E, 0x6F, 0x9B, 0xE3, 0xF8, 0x7E, 0x1F, 0x83, 0x0C, 0x1C, 0x18, 0x00, 0xFE, 0xEE, 0xC7, 0xC7, 0xC7, 0xC7,
0xC7, 0xC7, 0xC7, 0xE0, 0xF8, 0x3F, 0x0F, 0xE3, 0xEC, 0xFB, 0x3E, 0x6F, 0x9B, 0xE3, 0xF8, 0x7E, 0x1F, 0x83, 0x00,
0x03, 0x01, 0xC0, 0xFE, 0xEE, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0x00, 0x18, 0x38, 0x1B, 0x07, 0x80, 0xC0,
0x00, 0xE0, 0xF8, 0x3F, 0x0F, 0xE3, 0xEC, 0xFB, 0x3E, 0x6F, 0x9B, 0xE3, 0xF8, 0x7E, 0x1F, 0x83, 0x66, 0x3C, 0x18,
0x00, 0xFE, 0xEE, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xE0, 0x70, 0x30, 0x18, 0x00, 0x03, 0xF9, 0xDC, 0xC7,
0x63, 0xB1, 0xD8, 0xEC, 0x76, 0x3B, 0x1C, 0xE0, 0xF8, 0x3F, 0x0F, 0xE3, 0xEC, 0xFB, 0x3E, 0x6F, 0x9B, 0xE3, 0xF8,
0x7E, 0x1F, 0x83, 0x00, 0xC0, 0x70, 0x3C, 0xFE, 0xEE, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0x07, 0x07, 0x0E,
0x0F, 0x80, 0x00, 0x00, 0x00, 0x3F, 0x83, 0xDE, 0x38, 0x39, 0xC0, 0xCC, 0x07, 0x60, 0x3B, 0x01, 0xD8, 0x0E, 0xE0,
0x67, 0x07, 0x1E, 0xF0, 0x7F, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xFC, 0x7F, 0x98, 0x66, 0x1B, 0x87, 0x61, 0x98, 0x67,
0xF8, 0xFC, 0x0D, 0x80, 0x7C, 0x00, 0x00, 0x3F, 0x83, 0xDE, 0x38, 0x39, 0xC0, 0xCC, 0x07, 0x60, 0x3B, 0x01, 0xD8,
0x0E, 0xE0, 0x67, 0x07, 0x1E, 0xF0, 0x7F, 0x00, 0x3F, 0x07, 0x80, 0x00, 0xFC, 0x7F, 0x98, 0x66, 0x1B, 0x87, 0x61,
0x98, 0x67, 0xF8, 0xFC, 0x07, 0xC0, 0x7E, 0x03, 0x60, 0x00, 0x01, 0xFC, 0x1E, 0xF1, 0xC1, 0xCE, 0x06, 0x60, 0x3B,
0x01, 0xD8, 0x0E, 0xC0, 0x77, 0x03, 0x38, 0x38, 0xF7, 0x83, 0xF8, 0x0D, 0x87, 0xE1, 0xB0, 0x00, 0x3F, 0x1F, 0xE6,
0x19, 0x86, 0xE1, 0xD8, 0x66, 0x19, 0xFE, 0x3F, 0x00, 0x1F, 0xFF, 0x1F, 0x70, 0x1C, 0x38, 0x0E, 0x1C, 0x06, 0x0E,
0x03, 0x07, 0xF9, 0x83, 0x80, 0xC1, 0xC0, 0x70, 0xE0, 0x38, 0x70, 0x0F, 0xB8, 0x03, 0xFF, 0xF0, 0x3F, 0x7C, 0x7F,
0xEE, 0x61, 0xC6, 0x61, 0xC7, 0xE1, 0xFF, 0x61, 0xC0, 0x61, 0xC0, 0x7F, 0xF6, 0x3F, 0x7E, 0x0C, 0x07, 0x01, 0x80,
0x00, 0xFF, 0x3B, 0xEE, 0x3B, 0x8E, 0xE3, 0xBB, 0xEF, 0xF3, 0xB8, 0xE7, 0x38, 0xEE, 0x3B, 0x87, 0x18, 0xE3, 0x00,
0xFF, 0xAC, 0x30, 0xC3, 0x0C, 0x30, 0xC0, 0xFF, 0x3B, 0xEE, 0x3B, 0x8E, 0xE3, 0xBB, 0xEF, 0xF3, 0xB8, 0xE7, 0x38,
0xEE, 0x3B, 0x87, 0x00, 0x07, 0x03, 0x80, 0x7E, 0xE9, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x01, 0x87, 0x00, 0x66,
0x0F, 0x01, 0x80, 0x00, 0xFF, 0x3B, 0xEE, 0x3B, 0x8E, 0xE3, 0xBB, 0xEF, 0xF3, 0xB8, 0xE7, 0x38, 0xEE, 0x3B, 0x87,
0xC9, 0xE3, 0x00, 0xFF, 0xAC, 0x30, 0xC3, 0x0C, 0x30, 0xC0, 0x06, 0x0F, 0x07, 0x00, 0x03, 0xF3, 0xBB, 0x81, 0xC0,
0x70, 0x1E, 0x03, 0xC0, 0x70, 0x38, 0x1F, 0x9F, 0xFE, 0x0C, 0x38, 0x60, 0x07, 0xEE, 0xF8, 0x38, 0x3C, 0x1C, 0x1B,
0x7F, 0xE0, 0x0C, 0x0F, 0x0D, 0x80, 0x03, 0xF3, 0xBB, 0x81, 0xC0, 0x70, 0x1E, 0x03, 0xC0, 0x70, 0x38, 0x1F, 0x9F,
0xFE, 0x18, 0x79, 0x90, 0x07, 0xEE, 0xF8, 0x38, 0x3C, 0x1C, 0x1B, 0x7F, 0xE0, 0x3F, 0x3B, 0xB8, 0x1C, 0x07, 0x01,
0xE0, 0x3C, 0x07, 0x03, 0x81, 0xF9, 0xFF, 0xE1, 0xC0, 0xE0, 0xF0, 0x7E, 0xEF, 0x83, 0x83, 0xC1, 0xC1, 0xB7, 0xFE,
0x70, 0xE1, 0xC0, 0x36, 0x0F, 0x03, 0x00, 0x03, 0xF3, 0xBB, 0x81, 0xC0, 0x70, 0x1E, 0x03, 0xC0, 0x70, 0x38, 0x1F,
0x9F, 0xFE, 0x6C, 0x78, 0x60, 0x07, 0xEE, 0xF8, 0x38, 0x3C, 0x1C, 0x1B, 0x7F, 0xE0, 0xFF, 0xC3, 0x00, 0xC0, 0x30,
0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x1C, 0x07, 0x03, 0xC0, 0xC3, 0x0C, 0x3F, 0xC3, 0x0C,
0x30, 0xC3, 0x0E, 0xDF, 0x30, 0xE7, 0x80, 0x36, 0x07, 0x80, 0xC0, 0x00, 0xFF, 0xC3, 0x00, 0xC0, 0x30, 0x0C, 0x03,
0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x1B, 0x6D, 0xB0, 0xFF, 0x0C, 0x30, 0xC3, 0x0C, 0x38, 0x7C, 0xFF,
0xC3, 0x00, 0xC0, 0x30, 0x0C, 0x1F, 0xC0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0xC3, 0x0C, 0x3F, 0xC3, 0x0C,
0x3F, 0xC3, 0x0E, 0x1F, 0x3F, 0x0F, 0xC0, 0x00, 0x00, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07,
0xE1, 0xF8, 0x67, 0xF8, 0xFC, 0x7E, 0x7E, 0x00, 0x00, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xE7, 0xF7, 0x7F, 0x3F,
0x00, 0x00, 0x03, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x87, 0xE1, 0x9F, 0xE3, 0xF0, 0x7E,
0x00, 0x00, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xE7, 0xF7, 0x7F, 0x3E, 0x07, 0x80, 0x03, 0x07, 0xC1, 0xF0, 0x7C,
0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x87, 0xE1, 0x9F, 0xE3, 0xF0, 0x7C, 0x3C, 0x00, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7,
0xC7, 0xE7, 0xF7, 0x7F, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x00, 0x30, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07,
0xC1, 0xF8, 0x7E, 0x19, 0xFE, 0x3F, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xE7,
0xF7, 0x7F, 0x0F, 0x87, 0xE1, 0xF0, 0x00, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xE1, 0xF8,
0x67, 0xF8, 0xFC, 0x1F, 0x3F, 0x3C, 0x00, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xE7, 0xF7, 0x7F, 0xC1, 0xF0, 0x7C,
0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xE1, 0xF8, 0x67, 0xF8, 0xFC, 0x0E, 0x03, 0x00, 0xE0, 0xC7, 0xC7, 0xC7,
0xC7, 0xC7, 0xC7, 0xE7, 0xF7, 0x7F, 0x0F, 0x0E, 0x0F, 0x01, 0x80, 0x03, 0xC0, 0x06, 0x40, 0x00, 0x00, 0xE0, 0x07,
0xE1, 0x86, 0xE3, 0xC6, 0x63, 0xC6, 0x73, 0xCE, 0x77, 0xCE, 0x76, 0xEC, 0x36, 0x6C, 0x3E, 0x7C, 0x3C, 0x7C, 0x3C,
0x38, 0x1C, 0x38, 0x07, 0x00, 0x7C, 0x03, 0x60, 0x00, 0x0E, 0x71, 0xF3, 0x9D, 0x9C, 0xEC, 0xF6, 0x7D, 0xB3, 0xEF,
0x8F, 0x78, 0x79, 0xC1, 0x8E, 0x00, 0x0C, 0x03, 0xC0, 0x4C, 0x00, 0x0E, 0x1D, 0xC3, 0x9C, 0xE1, 0xDC, 0x3F, 0x03,
0xC0, 0x78, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x1C, 0x1F, 0x0D, 0x80, 0x0E, 0x37, 0x19, 0x9C, 0xCE, 0x76,
0x1B, 0x0F, 0x83, 0x81, 0xC0, 0xE2, 0xE1, 0xE0, 0x3F, 0x07, 0xE0, 0x00, 0x70, 0xEE, 0x1C, 0xE7, 0x0E, 0xE1, 0xF8,
0x1E, 0x03, 0xC0, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x06, 0x03, 0x80, 0xC0, 0x00, 0xFF, 0x80, 0xE0, 0x38,
0x1C, 0x0E, 0x07, 0x01, 0xC0, 0xE0, 0x70, 0x1C, 0x0E, 0x03, 0xFF, 0x0C, 0x1C, 0x18, 0x00, 0xFF, 0x0E, 0x0E, 0x1C,
0x38, 0x38, 0x70, 0xE0, 0xFF, 0x0C, 0x03, 0x00, 0x03, 0xFE, 0x03, 0x80, 0xE0, 0x70, 0x38, 0x1C, 0x07, 0x03, 0x81,
0xC0, 0x70, 0x38, 0x0F, 0xFC, 0x18, 0x18, 0x00, 0xFF, 0x0E, 0x0E, 0x1C, 0x38, 0x38, 0x70, 0xE0, 0xFF, 0x33, 0x07,
0x80, 0xC0, 0x00, 0xFF, 0x80, 0xE0, 0x38, 0x1C, 0x0E, 0x07, 0x01, 0xC0, 0xE0, 0x70, 0x1C, 0x0E, 0x03, 0xFF, 0x66,
0x3C, 0x18, 0x00, 0xFF, 0x0E, 0x0E, 0x1C, 0x38, 0x38, 0x70, 0xE0, 0xFF, 0x1D, 0xFE, 0x30, 0xC3, 0x0C, 0x30, 0xC3,
0x0C, 0x30, 0xC3, 0x00, 0x79, 0xF0, 0x38, 0x1E, 0x07, 0x00, 0x0F, 0xF7, 0x03, 0x81, 0xC0, 0xE0, 0x7F, 0x38, 0x1C,
0x0E, 0x07, 0x03, 0x81, 0xFF, 0x7E, 0x3F, 0x00, 0x1F, 0xEE, 0x07, 0x03, 0x81, 0xC0, 0xFE, 0x70, 0x38, 0x1C, 0x0E,
0x07, 0x03, 0xFE, 0xFF, 0xC0, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0F, 0xF0, 0x7B, 0xC3, 0x86, 0x1C, 0x38, 0xE1,
0x87, 0x1C, 0x3B, 0xC0, 0x0C, 0x1C, 0x18, 0x00, 0xFF, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
0xE0, 0x1F, 0xC7, 0x99, 0xC0, 0x38, 0x06, 0x00, 0xFE, 0x18, 0x03, 0x00, 0x70, 0x0E, 0x00, 0xF3, 0x0F, 0xE0, 0x3F,
0x3B, 0xB8, 0x1C, 0x07, 0x01, 0xE0, 0x3C, 0x07, 0x03, 0x81, 0xF9, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xEF,
0xB0, 0x0E, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x80, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x06, 0x06, 0xEE, 0xFC, 0x1F, 0xE0, 0x07, 0x38, 0x01, 0xCE, 0x00, 0x73, 0x80, 0x1C, 0xE0, 0x07, 0x3F, 0xC1, 0xCE,
0x78, 0x63, 0x86, 0x18, 0xE1, 0xCE, 0x38, 0x67, 0x0E, 0x7B, 0x83, 0xFC, 0x00, 0x00, 0x00, 0xE1, 0xC0, 0xE1, 0xC0,
0xE1, 0xC0, 0xE1, 0xC0, 0xE1, 0xC0, 0xFF, 0xFE, 0xE1, 0xDF, 0xE1, 0xC7, 0xE1, 0xC3, 0xE1, 0xC7, 0xE1, 0xCF, 0xE1,
0xFE, 0xFF, 0xC1, 0xC0, 0x1C, 0x01, 0xC0, 0x1C, 0x01, 0xFE, 0x1F, 0xF1, 0xC7, 0x1C, 0x31, 0xC3, 0x1C, 0x31, 0xC3,
0x0E, 0x07, 0x81, 0xC0, 0x00, 0xE3, 0xB9, 0xCE, 0xF3, 0xF8, 0xFC, 0x3E, 0x0F, 0xC3, 0xF8, 0xEF, 0x39, 0xCE, 0x3B,
0x87, 0x18, 0x07, 0x00, 0xE0, 0x00, 0xE0, 0xF8, 0x7E, 0x3F, 0x9F, 0xE6, 0xFB, 0xBE, 0xCF, 0xE3, 0xF8, 0xFC, 0x3E,
0x0F, 0x83, 0x3B, 0x07, 0xC0, 0x03, 0x87, 0xE1, 0xDC, 0x77, 0x18, 0xEE, 0x3B, 0x07, 0xC1, 0xF0, 0x38, 0x0E, 0x17,
0x0F, 0x80, 0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1F, 0xFF, 0x0C, 0x03,
0x00, 0xC0, 0x0E, 0x00, 0xE0, 0x1F, 0x01, 0xB0, 0x1B, 0x83, 0xB8, 0x31, 0xC7, 0x1C, 0x7F, 0xC6, 0x0E, 0xE0, 0xEE,
0x06, 0xFF, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0xFB, 0xBF, 0xC7, 0xE1, 0xF1, 0xF9, 0xFF, 0xE0, 0xFF, 0x3B, 0xEE, 0x3B,
0x8E, 0xE7, 0xBF, 0xCE, 0x7B, 0x86, 0xE1, 0xB8, 0x6E, 0x7B, 0xFC, 0xFF, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
0xE0, 0xE0, 0xE0, 0xE0, 0x1F, 0xE1, 0xCE, 0x1C, 0xE1, 0xCE, 0x1C, 0xE1, 0xCE, 0x18, 0xE1, 0x8E, 0x38, 0xE3, 0x8E,
0x70, 0xEF, 0xFF, 0xC0, 0x3C, 0x03, 0xC0, 0x30, 0xFF, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0xF3, 0x81, 0xC0, 0xE0, 0x70,
0x38, 0x1F, 0xF0, 0xF3, 0x8E, 0xE7, 0x38, 0xEE, 0xE0, 0xFF, 0x80, 0xFF, 0x00, 0xFC, 0x03, 0xFC, 0x0D, 0xDC, 0x3B,
0x98, 0xE7, 0x39, 0xCE, 0x3F, 0x1C, 0x70, 0x7F, 0x3B, 0x80, 0xE0, 0x70, 0xF1, 0xF8, 0x3E, 0x07, 0x01, 0x81, 0xF9,
0xFF, 0xE0, 0xE0, 0xF8, 0x7E, 0x3F, 0x9F, 0xE6, 0xFB, 0xBE, 0xCF, 0xE3, 0xF8, 0xFC, 0x3E, 0x0F, 0x83, 0x3F, 0x07,
0xC0, 0x03, 0x83, 0xE1, 0xF8, 0xFE, 0x7F, 0x9B, 0xEE, 0xFB, 0x3F, 0x8F, 0xE3, 0xF0, 0xF8, 0x3E, 0x0C, 0xE3, 0xB9,
0xCE, 0xF3, 0xF8, 0xFC, 0x3E, 0x0F, 0xC3, 0xF8, 0xEF, 0x39, 0xCE, 0x3B, 0x87, 0x1F, 0xE3, 0x9C, 0x73, 0x8E, 0x71,
0xCE, 0x39, 0xC7, 0x38, 0xC7, 0x18, 0xE7, 0x1D, 0xC3, 0xF0, 0x70, 0x60, 0x37, 0x83, 0xBC, 0x1D, 0xF1, 0xFD, 0x8F,
0xE4, 0xDF, 0x36, 0xF9, 0xA7, 0xC7, 0x3E, 0x38, 0xF0, 0x07, 0x80, 0x30, 0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xE1, 0xFF,
0xFE, 0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0x1F, 0xC1, 0xEF, 0x1C, 0x1C, 0xE0, 0x66, 0x03, 0xB0, 0x1D, 0x80,
0xEC, 0x07, 0x70, 0x33, 0x83, 0x8F, 0x78, 0x3F, 0x80, 0xFF, 0xF8, 0x7E, 0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1F, 0x87,
0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xFE, 0x77, 0xB8, 0xFC, 0x3E, 0x1F, 0x1F, 0xBD, 0xFC, 0xE0, 0x70, 0x38, 0x1C, 0x00,
0x02, 0x03, 0xF8, 0xF3, 0x38, 0x07, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0E, 0x01, 0xC0, 0x1E, 0x61, 0xFC, 0xFF,
0xC3, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0xE1, 0xF8, 0x77, 0x1D, 0xC6,
0x3B, 0x8E, 0xC1, 0xF0, 0x7C, 0x0E, 0x03, 0x85, 0xC3, 0xE0, 0x03, 0x80, 0x7F, 0x83, 0xBF, 0x9C, 0xE6, 0x63, 0x9D,
0x8E, 0x76, 0x38, 0xD8, 0xE7, 0x63, 0x9D, 0xCE, 0x63, 0xBF, 0x87, 0xFC, 0x03, 0x80, 0xE1, 0xCE, 0x38, 0xEE, 0x1F,
0x81, 0xF0, 0x1C, 0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x71, 0xC7, 0x70, 0x70, 0xE1, 0xDC, 0x3B, 0x87, 0x70, 0xEE, 0x1D,
0xC3, 0xB8, 0x77, 0x0E, 0xE1, 0xDC, 0x3B, 0x87, 0x7F, 0xF0, 0x06, 0x00, 0xC0, 0x18, 0x61, 0xD8, 0x76, 0x1D, 0x87,
0x61, 0xD8, 0x77, 0xBC, 0xFF, 0x01, 0xC0, 0x70, 0x1C, 0x07, 0xE3, 0x8F, 0xC7, 0x1F, 0x8E, 0x3F, 0x1C, 0x7E, 0x38,
0xFC, 0x71, 0xF8, 0xE3, 0xF1, 0xC7, 0xE3, 0x8F, 0xC7, 0x1F, 0x8E, 0x3F, 0xFF, 0xF0, 0xE3, 0x8E, 0xE3, 0x8E, 0xE3,
0x8E, 0xE3, 0x8E, 0xE3, 0x8E, 0xE3, 0x8E, 0xE3, 0x8E, 0xE3, 0x8E, 0xE3, 0x8E, 0xE3, 0x8E, 0xE3, 0x8E, 0xFF, 0xFF,
0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0xF8, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0xFE, 0x19, 0xF1, 0x87, 0x18,
0x31, 0x87, 0x19, 0xF1, 0xFE, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xFF, 0x9F, 0xBE, 0xFC, 0x77, 0xE3,
0xBF, 0x1D, 0xFB, 0xEF, 0xFE, 0x70, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0xFB, 0xBF, 0xC7, 0xE1, 0xF1, 0xFB, 0xFF,
0xE0, 0xFE, 0x3B, 0xE0, 0x38, 0x07, 0x01, 0xCF, 0xF0, 0x1C, 0x07, 0x01, 0xC0, 0xEC, 0x7B, 0xF8, 0xE1, 0xF8, 0xE3,
0xDC, 0xE7, 0x0E, 0xE6, 0x07, 0xEE, 0x07, 0xFE, 0x07, 0xEE, 0x07, 0xE6, 0x07, 0xE6, 0x07, 0xE7, 0x0E, 0xE3, 0xDE,
0xE1, 0xF8, 0x3F, 0xDE, 0x76, 0x1D, 0x87, 0x61, 0xDE, 0x73, 0xFC, 0xE7, 0x39, 0xDC, 0x77, 0x1F, 0x87, 0x7E, 0x2F,
0x03, 0x7F, 0x77, 0xE3, 0xE3, 0x73, 0x7F, 0x1F, 0x3F, 0x18, 0x1C, 0x0F, 0xE7, 0xBB, 0x0D, 0x87, 0xC3, 0xE1, 0xF8,
0xDE, 0xE7, 0xE0, 0xFE, 0xCE, 0xC7, 0xCE, 0xFE, 0xCF, 0xC3, 0xCF, 0xFE, 0xFF, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0,
0x3F, 0x8E, 0x63, 0x98, 0xE6, 0x31, 0x8C, 0x67, 0x19, 0xC6, 0xFF, 0xF0, 0x3C, 0x0C, 0x3F, 0x3F, 0x98, 0xEC, 0x7F,
0xFB, 0x01, 0x80, 0xF6, 0x3F, 0x00, 0x67, 0x33, 0xBB, 0x8F, 0xF8, 0x3F, 0x81, 0xFC, 0x0F, 0xE0, 0xDD, 0x8C, 0xE6,
0xE7, 0x38, 0x7E, 0x6E, 0x07, 0x0E, 0x3E, 0x0F, 0x07, 0x6F, 0xFE, 0xC7, 0xC7, 0xCF, 0xCF, 0xDB, 0xF3, 0xF3, 0xE3,
0xE3, 0x7E, 0x3C, 0x00, 0xC7, 0xC7, 0xCF, 0xCF, 0xDB, 0xF3, 0xF3, 0xE3, 0xE3, 0xC7, 0xCE, 0xDC, 0xF8, 0xF8, 0xFC,
0xDE, 0xCE, 0xC7, 0x3F, 0x9C, 0xCE, 0x67, 0x33, 0x99, 0x8C, 0xC6, 0xE3, 0xE1, 0x80, 0xE1, 0xDC, 0x3B, 0xC7, 0x69,
0xED, 0xBD, 0xBD, 0xF3, 0xBE, 0x67, 0xC0, 0xE0, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0x3F, 0x1F,
0xE6, 0x19, 0x86, 0xE1, 0xD8, 0x66, 0x19, 0xFE, 0x3F, 0x00, 0xFF, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7,
0xFE, 0x77, 0xB0, 0xD8, 0x6C, 0x3E, 0x1B, 0x0D, 0xFE, 0xFE, 0x60, 0x30, 0x18, 0x00, 0x3F, 0x7A, 0x60, 0x60, 0xE0,
0x60, 0x60, 0x7B, 0x3F, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xE3, 0x71, 0x99, 0xCC, 0xE7, 0x61,
0xB0, 0xF8, 0x38, 0x1C, 0x0E, 0x2E, 0x1E, 0x00, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x1F, 0x03, 0xFE, 0x3F, 0xF9, 0xDC,
0xCC, 0xE7, 0xE7, 0x3B, 0x39, 0x99, 0xCC, 0xFF, 0xE3, 0xFE, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0xE3, 0x3B, 0x8F, 0x87,
0x81, 0xC1, 0xF1, 0xF8, 0xCE, 0xE3, 0x80, 0xC7, 0x63, 0xB1, 0xD8, 0xEC, 0x76, 0x3B, 0x1D, 0x8E, 0xFF, 0x80, 0xC0,
0x60, 0xE3, 0xE3, 0xE3, 0xE3, 0x7F, 0x3F, 0x03, 0x03, 0x03, 0xC6, 0x3C, 0x63, 0xC6, 0x3C, 0x63, 0xC6, 0x3C, 0x63,
0xC6, 0x3C, 0x63, 0xFF, 0xF0, 0xC6, 0x36, 0x31, 0xB1, 0x8D, 0x8C, 0x6C, 0x63, 0x63, 0x1B, 0x18, 0xD8, 0xC6, 0xFF,
0xF8, 0x00, 0xC0, 0x06, 0xF8, 0x0E, 0x03, 0x80, 0xFE, 0x3B, 0xCE, 0x33, 0x8C, 0xEF, 0x3F, 0x80, 0xC0, 0xF8, 0x1F,
0x03, 0xFF, 0x7E, 0xEF, 0x8F, 0xF1, 0xFE, 0x77, 0xFE, 0xE0, 0xC0, 0xC0, 0xC0, 0xFE, 0xEF, 0xC7, 0xC7, 0xCF, 0xFE,
0x7C, 0x6E, 0x07, 0x07, 0x3F, 0x07, 0x07, 0xDE, 0xFC, 0xC7, 0xEC, 0xFE, 0xCC, 0x7C, 0xC3, 0xFC, 0x3D, 0xC3, 0xCC,
0x7C, 0xFE, 0xC7, 0xE0, 0x3F, 0x73, 0x63, 0x63, 0x73, 0x3F, 0x33, 0x73, 0xE3, 0x18, 0x0E, 0x03, 0x00, 0x03, 0xF3,
0xF9, 0x8E, 0xC7, 0xFF, 0xB0, 0x18, 0x0F, 0x63, 0xF0, 0x3F, 0x1F, 0x80, 0x07, 0xE7, 0xF3, 0x1D, 0x8F, 0xFF, 0x60,
0x30, 0x1E, 0xC7, 0xE0, 0x60, 0x30, 0x3F, 0x0C, 0x07, 0xF3, 0xB9, 0x8E, 0xC7, 0x63, 0xB1, 0xD8, 0xEC, 0x76, 0x38,
0x1C, 0x0E, 0x0E, 0x1C, 0xF3, 0x80, 0xFF, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, 0x3F, 0x7B, 0x60, 0x60, 0xFE, 0x60,
0x60, 0x7B, 0x3F, 0x7E, 0xEF, 0x83, 0x83, 0xC1, 0xC1, 0xB7, 0xFE, 0xD8, 0x0D, 0xB6, 0xDB, 0x6C, 0xFF, 0xF0, 0x0C,
0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x18, 0x60, 0x00, 0x18, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x63, 0x9C, 0x3F,
0x80, 0x73, 0x00, 0xE6, 0x01, 0xCF, 0xE3, 0x99, 0xC6, 0x31, 0xCC, 0x63, 0xB8, 0xCE, 0xE1, 0xFC, 0xC3, 0x06, 0x18,
0x30, 0xC1, 0xFF, 0xEC, 0x33, 0xE1, 0x8F, 0x0C, 0x78, 0x67, 0xC3, 0xF0, 0x60, 0x30, 0x3F, 0x0C, 0x07, 0xF3, 0xB9,
0x8E, 0xC7, 0x63, 0xB1, 0xD8, 0xEC, 0x76, 0x38, 0x0C, 0x1C, 0x18, 0x00, 0xC7, 0xCE, 0xDC, 0xF8, 0xF8, 0xFC, 0xDE,
0xCE, 0xC7, 0x30, 0x38, 0x18, 0x00, 0xC7, 0xC7, 0xCF, 0xCF, 0xDB, 0xF3, 0xF3, 0xE3, 0xE3, 0x36, 0x1F, 0x00, 0x1C,
0x6E, 0x33, 0x39, 0x9C, 0xEC, 0x36, 0x1F, 0x07, 0x03, 0x81, 0xC5, 0xC3, 0xC0, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7,
0xC7, 0xC7, 0xFF, 0x18, 0x18, 0x18, 0x01, 0x80, 0xFF, 0x81, 0x80, 0x18, 0x01, 0x80, 0x1F, 0xE1, 0x9F, 0x18, 0x71,
0x83, 0x18, 0x71, 0x9F, 0x1F, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0xE0, 0xFF, 0x0E, 0x03, 0x80, 0xFE, 0x3B, 0xCE, 0x33,
0x8C, 0xEF, 0x3F, 0x80, 0x1F, 0xC1, 0xE7, 0x1C, 0x1C, 0xE0, 0x66, 0x03, 0xBF, 0xFD, 0xDF, 0xEC, 0x07, 0x70, 0x33,
0x83, 0x8F, 0x38, 0x3F, 0x80, 0x3F, 0x1F, 0xE6, 0x19, 0xF6, 0xFF, 0xD8, 0x66, 0x19, 0xCE, 0x3F, 0x00, 0xE0, 0x7B,
0x83, 0xE6, 0x0C, 0x1C, 0x70, 0x71, 0xC0, 0xC6, 0x03, 0xB8, 0x0E, 0xE0, 0x1F, 0x00, 0x7C, 0x00, 0xE0, 0x03, 0x80,
0xE3, 0xF8, 0xC6, 0x71, 0x98, 0x76, 0x0F, 0x83, 0xC0, 0xF0, 0x1C, 0x00, 0x3F, 0x01, 0xE0, 0x00, 0x0E, 0x0C, 0xE1,
0xCE, 0x3C, 0xE7, 0xCE, 0x6C, 0xEE, 0xCE, 0xCC, 0xF8, 0xCF, 0x8C, 0xF0, 0xCE, 0x0C, 0xE0, 0xF0, 0x07, 0x00, 0xE0,
0x0E, 0x7E, 0x0F, 0x00, 0x03, 0x1C, 0xC7, 0x33, 0xCC, 0xF3, 0x6C, 0xF3, 0x3C, 0xCE, 0x33, 0x8F, 0x01, 0xC0, 0xE0,
0x38, 0x70, 0x1F, 0x81, 0xC0, 0x38, 0x07, 0x00, 0xFF, 0x1D, 0xF3, 0x8E, 0x70, 0xCE, 0x19, 0xC7, 0x39, 0xE7, 0xF8,
0x70, 0x38, 0x3F, 0x0E, 0x07, 0xF3, 0xBD, 0xCE, 0xEF, 0x7F, 0x00, 0xFE, 0x77, 0xB8, 0xFC, 0x3E, 0x9F, 0xFF, 0xBF,
0xFE, 0xE7, 0x71, 0xB8, 0x1C, 0x00, 0xFE, 0x77, 0xB0, 0xD8, 0x6C, 0x3E, 0x1B, 0x7D, 0xFE, 0xFE, 0x63, 0x30, 0xD8,
0x00, 0x07, 0x07, 0xFF, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x0C, 0x3F, 0xF0, 0xC3,
0x0C, 0x30, 0xC3, 0x0C, 0x00, 0x7F, 0xB8, 0x1C, 0x0E, 0x07, 0x07, 0xE1, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x00,
0x7E, 0xE1, 0xC3, 0x8F, 0xCE, 0x1C, 0x38, 0x70, 0xFF, 0x70, 0x38, 0x1C, 0x0F, 0xE7, 0x3B, 0x8F, 0xC3, 0xE1, 0xF0,
0xF8, 0x7C, 0x30, 0x38, 0x38, 0x78, 0xFE, 0xC0, 0xC0, 0xFE, 0xEE, 0xC7, 0xC3, 0xC3, 0xC7, 0x07, 0x0E, 0x1E, 0xF3,
0x8E, 0x73, 0x9C, 0x3B, 0xB8, 0x1F, 0xF0, 0x0F, 0xF0, 0x07, 0xE0, 0x0F, 0xF0, 0x1B, 0xB0, 0x3B, 0x98, 0x73, 0x9C,
0x73, 0x8C, 0xE3, 0x8F, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x67, 0x31, 0xDD, 0xC3, 0xFE, 0x07, 0xF0, 0x1F, 0x80,
0x7F, 0x03, 0x7E, 0x19, 0xDC, 0xE7, 0x3C, 0x00, 0x70, 0x01, 0xC0, 0x7F, 0x3B, 0x80, 0xE0, 0x70, 0xF1, 0xF8, 0x3E,
0x07, 0x01, 0x81, 0xF9, 0xFF, 0xE1, 0xC0, 0xE0, 0xF0, 0x7E, 0x6E, 0x07, 0x0E, 0x3E, 0x0F, 0x07, 0x6F, 0xFE, 0x18,
0x1C, 0x38, 0xE3, 0x9C, 0xE3, 0x98, 0x76, 0x0F, 0xC1, 0xF0, 0x3E, 0x07, 0x60, 0xEE, 0x1C, 0xE3, 0x8E, 0x70, 0xE0,
0x0C, 0x01, 0x80, 0x30, 0xC7, 0x67, 0x37, 0x1F, 0x0F, 0x06, 0xC3, 0x71, 0x9C, 0xC7, 0x81, 0xC0, 0xE0, 0x70, 0xE0,
0xFC, 0x3B, 0xEE, 0x7F, 0x8F, 0xE1, 0xF8, 0x3F, 0x87, 0xF8, 0xFB, 0x9C, 0x33, 0x87, 0x70, 0x70, 0xC3, 0xB1, 0xCD,
0xE3, 0x78, 0xFC, 0x37, 0x8D, 0xF3, 0x0E, 0xC1, 0x80, 0x71, 0xFF, 0x79, 0xDE, 0x3F, 0x87, 0xE0, 0xF8, 0x1F, 0x83,
0xF8, 0x77, 0x8E, 0x79, 0xC7, 0x38, 0x70, 0x73, 0xBF, 0xC7, 0xE1, 0xF0, 0x7C, 0x1F, 0x87, 0x71, 0xCE, 0x73, 0x80,
0xF8, 0x70, 0xC7, 0x06, 0x70, 0x37, 0x01, 0xF0, 0x0F, 0x80, 0x7E, 0x03, 0x78, 0x19, 0xE0, 0xC7, 0x06, 0x1C, 0x30,
0x70, 0xF9, 0xC7, 0x70, 0xFC, 0x1F, 0x03, 0xE0, 0x7E, 0x0F, 0xE1, 0xDE, 0x39, 0xC0, 0xE1, 0xDC, 0x3B, 0x87, 0x70,
0xEE, 0x1D, 0xFF, 0xB8, 0x77, 0x0E, 0xE1, 0xDC, 0x3B, 0x87, 0x70, 0xF0, 0x06, 0x00, 0xC0, 0x18, 0xC3, 0x61, 0xB0,
0xD8, 0x6F, 0xF6, 0x1B, 0x0D, 0x86, 0xC3, 0x80, 0xC0, 0x60, 0xE1, 0xFF, 0x0E, 0x38, 0x71, 0xC3, 0x8E, 0x1C, 0x7F,
0xE3, 0x87, 0x1C, 0x38, 0xE1, 0xC7, 0x0E, 0x38, 0x71, 0xC3, 0x80, 0xC3, 0xF0, 0xCC, 0x33, 0x0C, 0xFF, 0x30, 0xCC,
0x33, 0x0C, 0xC3, 0x00, 0xFF, 0xC0, 0xE1, 0xC0, 0xE1, 0xC0, 0xE1, 0xC0, 0xE1, 0xFC, 0xE1, 0xFE, 0xE1, 0xC7, 0xE1,
0xC3, 0xE1, 0xC3, 0xE1, 0xC3, 0xE1, 0xC3, 0xE1, 0xC7, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x3C, 0xFF, 0x03, 0x1C, 0x0C,
0x70, 0x31, 0xFC, 0xC7, 0x7B, 0x1C, 0x6C, 0x71, 0xB1, 0xC7, 0xC7, 0x18, 0x00, 0x60, 0x03, 0x80, 0x3C, 0x1F, 0xC1,
0xE6, 0x1C, 0x00, 0xE0, 0x06, 0x1E, 0x31, 0xF9, 0x9C, 0xEC, 0xE7, 0x77, 0x3B, 0xB9, 0x8F, 0xDC, 0x3F, 0xC0, 0x38,
0x00, 0xF0, 0x03, 0xC0, 0x3E, 0x1E, 0x06, 0x79, 0xBF, 0xEC, 0xDB, 0x36, 0xDD, 0xFE, 0x3F, 0x01, 0xE0, 0x3C, 0x02,
0x03, 0xF8, 0xF3, 0x38, 0x07, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0E, 0x01, 0xC0, 0x1E, 0x61, 0xFC, 0x0E, 0x01,
0xC0, 0x78, 0x3F, 0x7A, 0x60, 0x60, 0xE0, 0x60, 0x60, 0x7B, 0x3F, 0x0C, 0x0E, 0x1C, 0xFF, 0xC3, 0x00, 0xC0, 0x30,
0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x3C, 0x07, 0x01, 0xC0, 0x70, 0xFF, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x1C, 0x0C, 0x0C, 0xE1, 0xDC, 0x39, 0xCE, 0x1D, 0xC3, 0xF0, 0x3C, 0x07, 0x80, 0x60, 0x0C, 0x01,
0x80, 0x30, 0x06, 0x00, 0xE3, 0xF1, 0x99, 0xCC, 0xE7, 0x61, 0xF0, 0xF8, 0x78, 0x1C, 0x0C, 0x06, 0x03, 0x00, 0xE1,
0xDC, 0x39, 0xCE, 0x19, 0xC3, 0xF0, 0x3C, 0x07, 0x83, 0xFC, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xE3, 0xF1, 0x99,
0xCE, 0xE7, 0x61, 0xF0, 0xF8, 0x78, 0x7F, 0x0C, 0x06, 0x03, 0x00, 0xE1, 0xCE, 0x38, 0xEE, 0x1F, 0x81, 0xF0, 0x1C,
0x07, 0x80, 0xF8, 0x3B, 0x8E, 0x71, 0xC7, 0x70, 0x70, 0x06, 0x00, 0xC0, 0x18, 0xE3, 0x3B, 0x8F, 0x87, 0x81, 0xC1,
0xF1, 0xF8, 0xCE, 0xE3, 0x80, 0xC0, 0x60, 0xFF, 0x98, 0x38, 0x30, 0x70, 0x60, 0xE0, 0xC1, 0xC1, 0x83, 0x83, 0x07,
0x06, 0x0E, 0x0C, 0x1C, 0x18, 0x38, 0x30, 0x70, 0x60, 0xFF, 0xF0, 0x00, 0xE0, 0x01, 0xC0, 0x03, 0x80, 0xFE, 0xC7,
0x18, 0xE3, 0x1C, 0x63, 0x8C, 0x71, 0x8E, 0x31, 0xC6, 0x3F, 0xE0, 0x0C, 0x01, 0x80, 0x61, 0xCC, 0x39, 0x87, 0x30,
0xE6, 0x1C, 0xC3, 0x9E, 0xF1, 0xFE, 0x01, 0xC0, 0x38, 0x07, 0x00, 0xF0, 0x06, 0x00, 0xC0, 0x18, 0x03, 0xE3, 0x71,
0xB8, 0xDC, 0x67, 0xF1, 0xF8, 0x0C, 0x06, 0x03, 0x80, 0xC0, 0x60, 0x61, 0xD8, 0x76, 0x1D, 0x87, 0x61, 0xDB, 0x77,
0xFC, 0xFF, 0x0D, 0xC3, 0x70, 0x1C, 0x07, 0xE3, 0xE3, 0xFB, 0xFB, 0x7F, 0x7F, 0x1B, 0x1B, 0x03, 0xE0, 0x70, 0x38,
0x1C, 0x0F, 0xF7, 0xBF, 0x8F, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C, 0x30, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0xEE, 0xC7, 0xC7,
0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0x07, 0xF0, 0x3F, 0xE0, 0xC3, 0xB7, 0x06, 0xFC, 0x1D, 0xFF, 0xF1, 0x80, 0x07, 0x00,
0x1C, 0x00, 0x30, 0x00, 0xF3, 0x81, 0xFE, 0x0F, 0xC3, 0xBB, 0x63, 0xFC, 0x7F, 0xFE, 0x70, 0x06, 0x00, 0xF6, 0x0F,
0xC0, 0x07, 0xF0, 0x3F, 0xE0, 0xC3, 0xB7, 0x06, 0xFC, 0x1D, 0xFF, 0xF1, 0x80, 0x07, 0x00, 0x1C, 0x00, 0x30, 0x00,
0xF3, 0x81, 0xFE, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x0F, 0xC3, 0xBB, 0x63, 0xFC, 0x7F, 0xFE, 0x70, 0x06, 0x00,
0xF6, 0x0F, 0xC0, 0x60, 0x0C, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x06, 0xE0, 0x0F, 0x80, 0x00, 0x07, 0x9C, 0x77,
0x39, 0xC7, 0x77, 0x07, 0xFC, 0x07, 0xF8, 0x07, 0xE0, 0x1F, 0xE0, 0x6E, 0xE1, 0xDC, 0xC7, 0x39, 0xCE, 0x71, 0xF8,
0xE3, 0x80, 0x0D, 0x80, 0x7C, 0x00, 0x00, 0xCE, 0x67, 0x77, 0x1F, 0xF0, 0x7F, 0x03, 0xF8, 0x1F, 0xC1, 0xBB, 0x19,
0xCD, 0xCE, 0x70, 0xE3, 0xF3, 0xBB, 0x9F, 0x8F, 0xC7, 0xF3, 0xBD, 0xC7, 0xE1, 0xF0, 0xF8, 0x7C, 0x30, 0x38, 0xF8,
0x78, 0xC7, 0xCE, 0xDC, 0xF8, 0xFE, 0xDE, 0xC7, 0xC3, 0xC3, 0x07, 0x0E, 0x1E, 0x1F, 0xE0, 0xE7, 0x07, 0x38, 0x39,
0xC1, 0xCE, 0x0E, 0x70, 0x73, 0x83, 0x1C, 0x18, 0xE1, 0xC7, 0x1C, 0x39, 0xC1, 0xE0, 0x03, 0x00, 0x38, 0x01, 0x80,
0x3F, 0x87, 0x30, 0xE6, 0x1C, 0xC3, 0x98, 0x63, 0x0C, 0x63, 0x8C, 0xE1, 0xE0, 0x1C, 0x07, 0x00, 0xE0, 0xE1, 0xF8,
0x7E, 0x1F, 0x87, 0xE1, 0xFF, 0xFE, 0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0x01, 0xC0, 0x70, 0x38, 0xC3, 0xC3,
0xC3, 0xC3, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0x03, 0x07, 0x0E, 0xE1, 0xCE, 0x1C, 0xE1, 0xCE, 0x1C, 0xE1, 0xCF, 0xFC,
0xE1, 0xCE, 0x1C, 0xE1, 0xCE, 0x1C, 0xE1, 0xCE, 0x1E, 0x00, 0x60, 0x0E, 0x00, 0xC0, 0xC3, 0x30, 0xCC, 0x33, 0x0C,
0xFF, 0x30, 0xCC, 0x33, 0x0C, 0xC3, 0x80, 0x60, 0x38, 0x0C, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0xDE, 0xFF,
0x03, 0x81, 0xC0, 0xE0, 0xF0, 0x60, 0x30, 0x18, 0xE3, 0xE3, 0xE3, 0xE3, 0x7F, 0x3F, 0x03, 0x03, 0x0F, 0x0E, 0x0E,
0x60, 0x31, 0xE0, 0xE3, 0xC1, 0xC7, 0xC7, 0xCD, 0x8F, 0x99, 0x37, 0x33, 0x6E, 0x66, 0x9C, 0xC7, 0x39, 0x8E, 0x33,
0x00, 0x66, 0x00, 0xF0, 0x00, 0xC0, 0x03, 0x80, 0x06, 0x00, 0xE1, 0xCE, 0x1C, 0xF1, 0xCD, 0x3C, 0xDB, 0xCD, 0xEE,
0xCE, 0xEC, 0xCE, 0xC0, 0xF0, 0x07, 0x00, 0x70, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x1B, 0x01, 0xF0, 0x00, 0x00,
0xE0, 0x0E, 0x01, 0xF0, 0x1B, 0x01, 0xB8, 0x3B, 0x83, 0x1C, 0x71, 0xC7, 0xFC, 0x60, 0xEE, 0x0E, 0xE0, 0x60, 0x36,
0x3E, 0x00, 0x7E, 0x2F, 0x03, 0x7F, 0x77, 0xE3, 0xE3, 0x73, 0x7F, 0x1B, 0x81, 0xB8, 0x00, 0x00, 0xE0, 0x0E, 0x01,
0xF0, 0x1B, 0x01, 0xB8, 0x3B, 0x83, 0x1C, 0x71, 0xC7, 0xFC, 0x60, 0xEE, 0x0E, 0xE0, 0x60, 0x36, 0x36, 0x00, 0x7E,
0x2F, 0x03, 0x7F, 0x77, 0xE3, 0xE3, 0x73, 0x7F, 0x03, 0xFE, 0x03, 0xC0, 0x07, 0xC0, 0x06, 0xC0, 0x0E, 0xC0, 0x1C,
0xFE, 0x18, 0xC0, 0x38, 0xC0, 0x3F, 0xC0, 0x70, 0xC0, 0xE0, 0xC0, 0xE0, 0xFF, 0x7F, 0xF8, 0xBF, 0xF0, 0x79, 0xC0,
0xC3, 0x7F, 0xFF, 0xDC, 0x0E, 0x38, 0x1D, 0xF6, 0x7F, 0xF8, 0x7E, 0x1E, 0x00, 0x1F, 0xEE, 0x07, 0x03, 0x81, 0xC0,
0xFE, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0xFE, 0x3F, 0x0F, 0x00, 0x07, 0xE7, 0xF3, 0x1D, 0x8F, 0xFF, 0x60, 0x30,
0x1E, 0xC7, 0xE0, 0x3F, 0x86, 0x78, 0x03, 0x80, 0x70, 0x06, 0x00, 0xDF, 0xFB, 0x03, 0x60, 0xEE, 0x1C, 0xEF, 0x0F,
0xC0, 0x7E, 0x37, 0x80, 0xE0, 0x7F, 0xFB, 0x1D, 0x8E, 0xFE, 0x3E, 0x00, 0x1B, 0x83, 0x70, 0x00, 0x1F, 0xC3, 0x3C,
0x01, 0xC0, 0x38, 0x03, 0x00, 0x6F, 0xFD, 0x81, 0xB0, 0x77, 0x0E, 0x77, 0x87, 0xE0, 0x37, 0x1B, 0x80, 0x0F, 0xC6,
0xF0, 0x1C, 0x0F, 0xFF, 0x63, 0xB1, 0xDF, 0xC7, 0xC0, 0x06, 0xE0, 0x0D, 0xC0, 0x00, 0x07, 0x9C, 0x77, 0x39, 0xC7,
0x77, 0x07, 0xFC, 0x07, 0xF8, 0x07, 0xE0, 0x1F, 0xE0, 0x6E, 0xE1, 0xDC, 0xC7, 0x39, 0xCE, 0x71, 0xF8, 0xE3, 0x80,
0x0D, 0x80, 0x6C, 0x00, 0x00, 0xCE, 0x67, 0x77, 0x1F, 0xF0, 0x7F, 0x03, 0xF8, 0x1F, 0xC1, 0xBB, 0x19, 0xCD, 0xCE,
0x70, 0x76, 0x3B, 0x00, 0x0F, 0xE7, 0x70, 0x1C, 0x0E, 0x1E, 0x3F, 0x07, 0xC0, 0xE0, 0x30, 0x3F, 0x3F, 0xFC, 0x7E,
0x7E, 0x00, 0x7E, 0x6E, 0x07, 0x0E, 0x3E, 0x0F, 0x07, 0x6F, 0xFE, 0x7F, 0x83, 0x81, 0xC1, 0xC1, 0xC0, 0xF8, 0x3E,
0x07, 0x01, 0x81, 0xF9, 0xFF, 0xE0, 0x7F, 0x03, 0x81, 0x81, 0xC0, 0xC0, 0xF0, 0x3C, 0x07, 0x03, 0x81, 0xDB, 0xCF,
0xC0, 0x3F, 0x00, 0x00, 0x03, 0x83, 0xE1, 0xF8, 0xFE, 0x7F, 0x9B, 0xEE, 0xFB, 0x3F, 0x8F, 0xE3, 0xF0, 0xF8, 0x3E,
0x0C, 0x7E, 0x00, 0x00, 0xC7, 0xC7, 0xCF, 0xCF, 0xDB, 0xF3, 0xF3, 0xE3, 0xE3, 0x3F, 0x0F, 0xC0, 0x03, 0x83, 0xE1,
0xF8, 0xFE, 0x7F, 0x9B, 0xEE, 0xFB, 0x3F, 0x8F, 0xE3, 0xF0, 0xF8, 0x3E, 0x0C, 0x7E, 0x7E, 0x00, 0xC7, 0xC7, 0xCF,
0xCF, 0xDB, 0xF3, 0xF3, 0xE3, 0xE3, 0x0D, 0xC0, 0x6E, 0x00, 0x00, 0x3F, 0x83, 0xDE, 0x38, 0x39, 0xC0, 0xCC, 0x07,
0x60, 0x3B, 0x01, 0xD8, 0x0E, 0xE0, 0x67, 0x07, 0x1E, 0xF0, 0x7F, 0x00, 0x3F, 0x0F, 0xC0, 0x00, 0xFC, 0x7F, 0x98,
0x66, 0x1B, 0x87, 0x61, 0x98, 0x67, 0xF8, 0xFC, 0x1F, 0xC1, 0xEF, 0x1C, 0x1C, 0xE0, 0x66, 0x03, 0xBF, 0xFD, 0x80,
0xEC, 0x07, 0x70, 0x73, 0x83, 0x8F, 0x78, 0x3F, 0x80, 0x3F, 0x1F, 0xE6, 0x19, 0x86, 0xFF, 0xD8, 0x66, 0x19, 0xFE,
0x3F, 0x00, 0x0D, 0xC0, 0x6E, 0x00, 0x00, 0x3F, 0x83, 0xDE, 0x38, 0x39, 0xC0, 0xCC, 0x07, 0x7F, 0xFB, 0x01, 0xD8,
0x0E, 0xE0, 0xE7, 0x07, 0x1E, 0xF0, 0x7F, 0x00, 0x3F, 0x0F, 0xC0, 0x00, 0xFC, 0x7F, 0x98, 0x66, 0x1B, 0xFF, 0x61,
0x98, 0x67, 0xF8, 0xFC, 0x76, 0x1D, 0x80, 0x03, 0xF8, 0xEF, 0x80, 0xE0, 0x1C, 0x07, 0x3F, 0xC0, 0x70, 0x1C, 0x07,
0x03, 0xB1, 0xEF, 0xE0, 0x6C, 0x6C, 0x00, 0x7C, 0x6E, 0x07, 0x07, 0x3F, 0x07, 0x07, 0xDE, 0xFC, 0x3F, 0x00, 0x00,
0x03, 0x87, 0xE1, 0xDC, 0x77, 0x18, 0xEE, 0x3B, 0x07, 0xC1, 0xF0, 0x38, 0x0E, 0x17, 0x0F, 0x80, 0x3E, 0x00, 0x00,
0x1C, 0x6E, 0x33, 0x39, 0x9C, 0xEC, 0x36, 0x1F, 0x07, 0x03, 0x81, 0xC5, 0xC3, 0xC0, 0x3B, 0x0E, 0xC0, 0x03, 0x87,
0xE1, 0xDC, 0x77, 0x18, 0xEE, 0x3B, 0x07, 0xC1, 0xF0, 0x38, 0x0E, 0x17, 0x0F, 0x80, 0x36, 0x1B, 0x00, 0x1C, 0x6E,
0x33, 0x39, 0x9C, 0xEC, 0x36, 0x1F, 0x07, 0x03, 0x81, 0xC5, 0xC3, 0xC0, 0x0D, 0x87, 0xE1, 0xB0, 0x00, 0xE1, 0xF8,
0x77, 0x1D, 0xC6, 0x3B, 0x8E, 0xC1, 0xF0, 0x7C, 0x0E, 0x03, 0x85, 0xC3, 0xE0, 0x1B, 0x1F, 0x8D, 0x80, 0x0E, 0x37,
0x19, 0x9C, 0xCE, 0x76, 0x1B, 0x0F, 0x83, 0x81, 0xC0, 0xE2, 0xE1, 0xE0, 0x3B, 0x0E, 0xC0, 0x01, 0x87, 0x61, 0xD8,
0x76, 0x1D, 0x87, 0x61, 0xDE, 0xF3, 0xFC, 0x07, 0x01, 0xC0, 0x70, 0x1C, 0x76, 0x76, 0x00, 0xE3, 0xE3, 0xE3, 0xE3,
0x7F, 0x3F, 0x03, 0x03, 0x03, 0xFF, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xF0, 0x30, 0x30,
0x30, 0xFF, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xF1, 0xC7, 0x00, 0x1D, 0x80, 0xEC, 0x00, 0x01, 0xC0, 0x7E, 0x03, 0xF0,
0x1F, 0x80, 0xFC, 0x07, 0xFF, 0x3F, 0x7D, 0xF8, 0xEF, 0xC7, 0x7E, 0x3B, 0xF7, 0xDF, 0xFC, 0xE0, 0x1B, 0x03, 0x60,
0x00, 0x60, 0x7C, 0x0F, 0x81, 0xFF, 0xBF, 0x77, 0xC7, 0xF8, 0xFF, 0x3B, 0xFF, 0x70, 0x7F, 0xC0, 0x7F, 0xFF, 0xC0,
0x7F, 0xFF, 0xC0, 0xDB, 0x66, 0xC0, 0x6D, 0xBD, 0x80, 0x6F, 0xF0, 0x7F, 0xEF, 0x3C, 0xF3, 0xC0, 0x7D, 0xF7, 0xDF,
0xF3, 0xC0, 0x6C, 0xDB, 0xB7, 0xE0, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x79, 0xF7, 0xDE, 0xE3,
0x8F, 0xC7, 0x1C, 0x7C, 0x70, 0x03, 0x67, 0x00, 0x3B, 0xB8, 0x01, 0xDF, 0x80, 0x06, 0xD8, 0x00, 0x3F, 0xC0, 0x00,
0x0D, 0xE7, 0xC0, 0xFF, 0xFE, 0x06, 0xCF, 0x30, 0x76, 0x79, 0x83, 0x3F, 0xFC, 0x38, 0xF3, 0xE0, 0x3B, 0x9D, 0xC7,
0x38, 0xE0, 0xE3, 0x1C, 0x77, 0x33, 0x80, 0x03, 0x83, 0x81, 0x81, 0xC0, 0xC0, 0xE0, 0x60, 0x70, 0x30, 0x38, 0x38,
0x18, 0x00, 0x0F, 0x87, 0xE3, 0x80, 0xE0, 0xFF, 0x0C, 0x03, 0x03, 0xFC, 0x38, 0x0E, 0x01, 0xDC, 0x3E, 0xFF, 0x86,
0x03, 0x01, 0xE1, 0xF3, 0xE1, 0xBC, 0x3E, 0x7C, 0x36, 0x03, 0x01, 0x80, 0x08, 0x1F, 0x89, 0xC0, 0x70, 0x3F, 0xFC,
0x38, 0x78, 0xFF, 0xB0, 0x18, 0x0E, 0x33, 0xF8, 0x60, 0xFF, 0x8F, 0x03, 0x9F, 0xE0, 0xE1, 0xE3, 0xE1, 0xC0, 0x70,
0x1C, 0x07, 0x03, 0x80, 0x7E, 0x1B, 0xC0, 0x38, 0x06, 0x01, 0x8F, 0xE7, 0xB9, 0x86, 0xE1, 0xB8, 0x6E, 0x39, 0xDC,
0x3E, 0x00, 0x0E, 0x01, 0xC0, 0x7C, 0x0D, 0x83, 0xB8, 0x63, 0x0C, 0x73, 0x8E, 0x60, 0xDC, 0x1F, 0x83, 0xFF, 0xF0,
0xFF, 0xF8, 0x7E, 0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xE1, 0xF8, 0x7E, 0x1F, 0x87, 0xE1, 0xC0, 0xFF, 0xF0,
0x1C, 0x07, 0x03, 0x80, 0xE0, 0x30, 0x38, 0x38, 0x1C, 0x1C, 0x0E, 0x0E, 0x07, 0xFC, 0xFF, 0x80, 0x03, 0x83, 0x81,
0x81, 0xC0, 0xC0, 0xE0, 0x60, 0x70, 0x30, 0x38, 0x38, 0x18, 0x00, 0x77, 0x00, 0xC0, 0x70, 0x18, 0x06, 0x01, 0x80,
0xEF, 0x33, 0xCC, 0x3F, 0x07, 0x81, 0xE0, 0x78, 0x0C, 0x00, 0x7F, 0xBF, 0xFC, 0xCF, 0xFF, 0x7F, 0x80, 0x1E, 0x70,
0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x1C, 0x70, 0x7D, 0xFF, 0xC0, 0x00, 0x07, 0xDF, 0xFC,
0x03, 0x03, 0xBF, 0xE1, 0x81, 0xC7, 0xFC, 0xC0, 0x60, 0x03, 0x87, 0x9F, 0x0E, 0x03, 0xC0, 0x78, 0x0E, 0x00, 0xFF,
0x80, 0x70, 0x3E, 0x03, 0xC0, 0x70, 0xF3, 0xE1, 0xC0, 0x00, 0xFF, 0x80,
};
static const EpdGlyph pixelarial14Glyphs[] = {
{0, 0, 0, 0, 0, 0, 0}, //
{0, 0, 0, 0, 0, 0, 0}, // 
{0, 0, 4, 0, 0, 0, 0}, //
{0, 0, 4, 0, 0, 0, 0}, //
{0, 0, 0, 0, 0, 0, 0}, // 
{0, 0, 4, 0, 0, 0, 0}, //
{2, 13, 3, 0, 13, 4, 0}, // !
{4, 6, 5, 0, 13, 3, 4}, // "
@ -167,18 +548,494 @@ static const EpdGlyph pixelarial14Glyphs[] = {
{2, 13, 3, 0, 13, 4, 1110}, // |
{4, 17, 5, 0, 13, 9, 1114}, // }
{11, 4, 12, 0, 9, 6, 1123}, // ~
{3, 6, 4, 0, 13, 3, 1129}, //
{3, 6, 4, 0, 13, 3, 1132}, //
{6, 6, 6, 0, 13, 5, 1135}, // “
{6, 6, 6, 0, 13, 5, 1140}, // ”
{0, 0, 4, 0, 0, 0, 1129}, //  
{3, 12, 5, 1, 9, 5, 1129}, // ¡
{8, 13, 10, 1, 11, 13, 1134}, // ¢
{8, 12, 10, 1, 12, 12, 1147}, // £
{9, 9, 10, 0, 11, 11, 1159}, // ¤
{10, 12, 10, 0, 12, 15, 1170}, // ¥
{3, 16, 5, 1, 13, 6, 1185}, // ¦
{8, 14, 8, 0, 13, 14, 1191}, // §
{6, 2, 6, 0, 12, 2, 1205}, // ¨
{12, 12, 14, 1, 12, 18, 1207}, // ©
{6, 6, 7, 0, 12, 5, 1225}, // ª
{8, 7, 8, 0, 8, 7, 1230}, // «
{9, 5, 10, 0, 6, 6, 1237}, // ¬
{5, 1, 5, 0, 5, 1, 1243}, // ­
{12, 12, 14, 1, 12, 18, 1244}, // ®
{6, 1, 6, 0, 12, 1, 1262}, // ¯
{6, 5, 6, 0, 13, 4, 1263}, // °
{9, 10, 10, 0, 10, 12, 1267}, // ±
{6, 7, 6, 0, 12, 6, 1279}, // ²
{6, 7, 6, 0, 12, 6, 1285}, // ³
{4, 3, 6, 2, 13, 2, 1291}, // ´
{8, 12, 10, 1, 9, 12, 1293}, // µ
{10, 15, 11, 0, 12, 19, 1305}, // ¶
{4, 2, 4, 0, 6, 1, 1324}, // ·
{4, 3, 6, 1, 0, 2, 1325}, // ¸
{5, 7, 6, 0, 12, 5, 1327}, // ¹
{7, 6, 8, 0, 12, 6, 1332}, // º
{8, 7, 8, 0, 8, 7, 1338}, // »
{15, 12, 15, 0, 12, 23, 1345}, // ¼
{15, 12, 15, 0, 12, 23, 1368}, // ½
{15, 12, 15, 0, 12, 23, 1391}, // ¾
{7, 12, 7, 0, 9, 11, 1414}, // ¿
{12, 16, 11, 0, 16, 24, 1425}, // À
{12, 16, 11, 0, 16, 24, 1449}, // Á
{12, 16, 11, 0, 16, 24, 1473}, // Â
{12, 16, 11, 0, 16, 24, 1497}, // Ã
{12, 15, 11, 0, 15, 23, 1521}, // Ä
{12, 15, 11, 0, 15, 23, 1544}, // Å
{16, 12, 16, 0, 12, 24, 1567}, // Æ
{11, 16, 11, 0, 13, 22, 1591}, // Ç
{9, 16, 10, 1, 16, 18, 1613}, // È
{9, 16, 10, 1, 16, 18, 1631}, // É
{9, 16, 10, 1, 16, 18, 1649}, // Ê
{9, 15, 10, 1, 15, 17, 1667}, // Ë
{4, 16, 5, 0, 16, 8, 1684}, // Ì
{4, 16, 5, 1, 16, 8, 1692}, // Í
{6, 16, 5, -1, 16, 12, 1700}, // Î
{6, 15, 5, -1, 15, 12, 1712}, // Ï
{12, 12, 12, 0, 12, 18, 1724}, // Ð
{10, 16, 12, 1, 16, 20, 1742}, // Ñ
{13, 16, 13, 0, 16, 26, 1762}, // Ò
{13, 16, 13, 0, 16, 26, 1788}, // Ó
{13, 16, 13, 0, 16, 26, 1814}, // Ô
{13, 16, 13, 0, 16, 26, 1840}, // Õ
{13, 15, 13, 0, 15, 25, 1866}, // Ö
{8, 7, 10, 1, 9, 7, 1891}, // ×
{13, 12, 13, 0, 12, 20, 1898}, // Ø
{10, 16, 12, 1, 16, 20, 1918}, // Ù
{10, 16, 12, 1, 16, 20, 1938}, // Ú
{10, 16, 12, 1, 16, 20, 1958}, // Û
{10, 15, 12, 1, 15, 19, 1978}, // Ü
{11, 16, 10, 0, 16, 22, 1997}, // Ý
{9, 12, 10, 1, 12, 14, 2019}, // Þ
{9, 13, 11, 1, 13, 15, 2033}, // ß
{8, 13, 9, 0, 13, 13, 2048}, // à
{8, 13, 9, 0, 13, 13, 2061}, // á
{8, 13, 9, 0, 13, 13, 2074}, // â
{8, 13, 9, 0, 13, 13, 2087}, // ã
{8, 12, 9, 0, 12, 12, 2100}, // ä
{8, 14, 9, 0, 14, 14, 2112}, // å
{14, 9, 15, 0, 9, 16, 2126}, // æ
{8, 12, 8, 0, 9, 12, 2142}, // ç
{9, 13, 10, 0, 13, 15, 2154}, // è
{9, 13, 10, 0, 13, 15, 2169}, // é
{9, 13, 10, 0, 13, 15, 2184}, // ê
{9, 12, 10, 0, 12, 14, 2199}, // ë
{4, 13, 4, 0, 13, 7, 2213}, // ì
{4, 13, 4, 1, 13, 7, 2220}, // í
{6, 13, 4, -1, 13, 10, 2227}, // î
{6, 12, 4, -1, 12, 9, 2237}, // ï
{10, 13, 10, 0, 13, 17, 2246}, // ð
{8, 13, 10, 1, 13, 13, 2263}, // ñ
{10, 13, 10, 0, 13, 17, 2276}, // ò
{10, 13, 10, 0, 13, 17, 2293}, // ó
{10, 13, 10, 0, 13, 17, 2310}, // ô
{10, 13, 10, 0, 13, 17, 2327}, // õ
{10, 12, 10, 0, 12, 15, 2344}, // ö
{9, 9, 10, 0, 9, 11, 2359}, // ÷
{10, 9, 10, 0, 9, 12, 2370}, // ø
{8, 13, 10, 1, 13, 13, 2382}, // ù
{8, 13, 10, 1, 13, 13, 2395}, // ú
{8, 13, 10, 1, 13, 13, 2408}, // û
{8, 12, 10, 1, 12, 12, 2421}, // ü
{9, 16, 8, 0, 13, 18, 2433}, // ý
{9, 16, 10, 1, 13, 18, 2451}, // þ
{9, 15, 8, 0, 12, 17, 2469}, // ÿ
{12, 15, 11, 0, 15, 23, 2486}, // Ā
{8, 12, 9, 0, 12, 12, 2509}, // ā
{12, 15, 11, 0, 15, 23, 2521}, // Ă
{8, 12, 9, 0, 12, 12, 2544}, // ă
{12, 15, 11, 0, 12, 23, 2556}, // Ą
{8, 12, 9, 0, 9, 12, 2579}, // ą
{11, 16, 11, 0, 16, 22, 2591}, // Ć
{8, 13, 8, 0, 13, 13, 2613}, // ć
{11, 16, 11, 0, 16, 22, 2626}, // Ĉ
{8, 13, 8, 0, 13, 13, 2648}, // ĉ
{11, 15, 11, 0, 15, 21, 2661}, // Ċ
{8, 12, 8, 0, 12, 12, 2682}, // ċ
{11, 16, 11, 0, 16, 22, 2694}, // Č
{8, 13, 8, 0, 13, 13, 2716}, // č
{11, 16, 12, 1, 16, 22, 2729}, // Ď
{12, 13, 11, 0, 13, 20, 2751}, // ď
{12, 12, 12, 0, 12, 18, 2771}, // Đ
{10, 13, 10, 0, 13, 17, 2789}, // đ
{9, 15, 10, 1, 15, 17, 2806}, // Ē
{9, 12, 10, 0, 12, 14, 2823}, // ē
{9, 15, 10, 1, 15, 17, 2837}, // Ĕ
{9, 12, 10, 0, 12, 14, 2854}, // ĕ
{9, 15, 10, 1, 15, 17, 2868}, // Ė
{9, 12, 10, 0, 12, 14, 2885}, // ė
{9, 15, 10, 1, 12, 17, 2899}, // Ę
{9, 12, 10, 0, 9, 14, 2916}, // ę
{9, 16, 10, 1, 16, 18, 2930}, // Ě
{9, 14, 10, 0, 14, 16, 2948}, // ě
{11, 16, 11, 0, 16, 22, 2964}, // Ĝ
{9, 16, 10, 0, 13, 18, 2986}, // ĝ
{11, 15, 11, 0, 15, 21, 3004}, // Ğ
{9, 15, 10, 0, 12, 17, 3025}, // ğ
{11, 15, 11, 0, 15, 21, 3042}, // Ġ
{9, 15, 10, 0, 12, 17, 3063}, // ġ
{11, 15, 11, 0, 12, 21, 3080}, // Ģ
{9, 16, 10, 0, 13, 18, 3101}, // ģ
{10, 16, 12, 1, 16, 20, 3119}, // Ĥ
{9, 16, 10, 0, 16, 18, 3139}, // ĥ
{13, 12, 12, 0, 12, 20, 3157}, // Ħ
{9, 13, 10, 0, 13, 15, 3177}, // ħ
{7, 16, 5, -1, 16, 14, 3192}, // Ĩ
{6, 13, 4, -1, 13, 10, 3206}, // ĩ
{6, 15, 5, -1, 15, 12, 3216}, // Ī
{6, 12, 4, -1, 12, 9, 3228}, // ī
{5, 15, 5, 0, 15, 10, 3237}, // Ĭ
{6, 12, 4, -1, 12, 9, 3247}, // ĭ
{4, 15, 5, 0, 12, 8, 3256}, // Į
{4, 16, 4, 0, 13, 8, 3264}, // į
{3, 15, 5, 1, 15, 6, 3272}, // İ
{2, 9, 4, 1, 9, 3, 3278}, // ı
{11, 12, 13, 1, 12, 17, 3281}, // IJ
{7, 16, 9, 1, 13, 14, 3298}, // ij
{9, 16, 9, 0, 16, 18, 3312}, // Ĵ
{7, 16, 4, -2, 13, 14, 3330}, // ĵ
{10, 15, 11, 1, 12, 19, 3344}, // Ķ
{8, 16, 9, 1, 13, 16, 3363}, // ķ
{8, 9, 9, 1, 9, 9, 3379}, // ĸ
{8, 16, 9, 1, 16, 16, 3388}, // Ĺ
{4, 16, 5, 1, 16, 8, 3404}, // ĺ
{8, 15, 9, 1, 12, 15, 3412}, // Ļ
{5, 16, 5, 0, 13, 10, 3427}, // ļ
{8, 12, 9, 1, 12, 12, 3437}, // Ľ
{5, 13, 5, 1, 13, 9, 3449}, // ľ
{8, 12, 9, 1, 12, 12, 3458}, // Ŀ
{6, 13, 6, 1, 13, 10, 3470}, // ŀ
{10, 12, 9, -1, 12, 15, 3480}, // Ł
{5, 13, 5, 0, 13, 9, 3495}, // ł
{10, 16, 12, 1, 16, 20, 3504}, // Ń
{8, 13, 10, 1, 13, 13, 3524}, // ń
{10, 15, 12, 1, 12, 19, 3537}, // Ņ
{8, 12, 10, 1, 9, 12, 3556}, // ņ
{10, 16, 12, 1, 16, 20, 3568}, // Ň
{8, 13, 10, 1, 13, 13, 3588}, // ň
{9, 14, 10, 0, 14, 16, 3601}, // ʼn
{10, 15, 12, 1, 12, 19, 3617}, // Ŋ
{8, 12, 10, 1, 9, 12, 3636}, // ŋ
{13, 15, 13, 0, 15, 25, 3648}, // Ō
{10, 12, 10, 0, 12, 15, 3673}, // ō
{13, 15, 13, 0, 15, 25, 3688}, // Ŏ
{10, 12, 10, 0, 12, 15, 3713}, // ŏ
{13, 16, 13, 0, 16, 26, 3728}, // Ő
{10, 13, 10, 0, 13, 17, 3754}, // ő
{17, 12, 17, 0, 12, 26, 3771}, // Œ
{16, 9, 16, 0, 9, 18, 3797}, // œ
{10, 16, 11, 1, 16, 20, 3815}, // Ŕ
{6, 13, 7, 1, 13, 10, 3835}, // ŕ
{10, 15, 11, 1, 12, 19, 3845}, // Ŗ
{7, 12, 7, 0, 9, 11, 3864}, // ŗ
{10, 16, 11, 1, 16, 20, 3875}, // Ř
{6, 13, 7, 1, 13, 10, 3895}, // ř
{9, 16, 9, 0, 16, 18, 3905}, // Ś
{7, 13, 8, 0, 13, 12, 3923}, // ś
{9, 16, 9, 0, 16, 18, 3935}, // Ŝ
{7, 13, 8, 0, 13, 12, 3953}, // ŝ
{9, 15, 9, 0, 12, 17, 3965}, // Ş
{7, 12, 8, 0, 9, 11, 3982}, // ş
{9, 16, 9, 0, 16, 18, 3993}, // Š
{7, 13, 8, 0, 13, 12, 4011}, // š
{10, 15, 10, 0, 12, 19, 4023}, // Ţ
{6, 15, 7, 1, 12, 12, 4042}, // ţ
{10, 16, 10, 0, 16, 20, 4054}, // Ť
{6, 13, 7, 1, 13, 10, 4074}, // ť
{10, 12, 10, 0, 12, 15, 4084}, // Ŧ
{6, 12, 7, 1, 12, 9, 4099}, // ŧ
{10, 16, 12, 1, 16, 20, 4108}, // Ũ
{8, 13, 10, 1, 13, 13, 4128}, // ũ
{10, 15, 12, 1, 15, 19, 4141}, // Ū
{8, 12, 10, 1, 12, 12, 4160}, // ū
{10, 15, 12, 1, 15, 19, 4172}, // Ŭ
{8, 12, 10, 1, 12, 12, 4191}, // ŭ
{10, 17, 12, 1, 17, 22, 4203}, // Ů
{8, 14, 10, 1, 14, 14, 4225}, // ů
{10, 16, 12, 1, 16, 20, 4239}, // Ű
{8, 13, 10, 1, 13, 13, 4259}, // ű
{10, 15, 12, 1, 12, 19, 4272}, // Ų
{8, 12, 10, 1, 9, 12, 4291}, // ų
{16, 16, 16, 0, 16, 32, 4303}, // Ŵ
{13, 13, 13, 0, 13, 22, 4335}, // ŵ
{11, 16, 10, 0, 16, 22, 4357}, // Ŷ
{9, 16, 8, 0, 13, 18, 4379}, // ŷ
{11, 15, 10, 0, 15, 21, 4397}, // Ÿ
{10, 16, 10, 0, 16, 20, 4418}, // Ź
{8, 13, 8, 0, 13, 13, 4438}, // ź
{10, 15, 10, 0, 15, 19, 4451}, // Ż
{8, 12, 8, 0, 12, 12, 4470}, // ż
{10, 16, 10, 0, 16, 20, 4482}, // Ž
{8, 13, 8, 0, 13, 13, 4502}, // ž
{6, 14, 5, 1, 14, 11, 4515}, // ſ
{6, 2, 6, 0, 12, 2, 4526}, // ̑
{9, 16, 10, 1, 16, 18, 4528}, // Ѐ
{9, 15, 10, 1, 15, 17, 4546}, // Ё
{13, 12, 13, 0, 12, 20, 4563}, // Ђ
{8, 16, 9, 1, 16, 16, 4583}, // Ѓ
{11, 12, 11, 0, 12, 17, 4599}, // Є
{9, 12, 9, 0, 12, 14, 4616}, // Ѕ
{3, 12, 5, 1, 12, 5, 4630}, // І
{6, 15, 5, -1, 15, 12, 4635}, // Ї
{8, 12, 9, 0, 12, 12, 4647}, // Ј
{18, 13, 18, 0, 12, 30, 4659}, // Љ
{16, 12, 17, 1, 12, 24, 4689}, // Њ
{12, 12, 13, 0, 12, 18, 4713}, // Ћ
{10, 16, 11, 1, 16, 20, 4731}, // Ќ
{10, 16, 12, 1, 16, 20, 4751}, // Ѝ
{10, 15, 10, 0, 15, 19, 4771}, // Ў
{10, 15, 12, 1, 12, 19, 4790}, // Џ
{12, 12, 11, 0, 12, 18, 4809}, // А
{9, 12, 11, 1, 12, 14, 4827}, // Б
{10, 12, 11, 1, 12, 15, 4841}, // В
{8, 12, 9, 1, 12, 12, 4856}, // Г
{12, 15, 12, 0, 12, 23, 4868}, // Д
{9, 12, 10, 1, 12, 14, 4891}, // Е
{15, 12, 15, 0, 12, 23, 4905}, // Ж
{9, 12, 10, 0, 12, 14, 4928}, // З
{10, 12, 12, 1, 12, 15, 4942}, // И
{10, 15, 12, 1, 15, 19, 4957}, // Й
{10, 12, 11, 1, 12, 15, 4976}, // К
{11, 12, 12, 0, 12, 17, 4991}, // Л
{13, 12, 15, 1, 12, 20, 5008}, // М
{10, 12, 12, 1, 12, 15, 5028}, // Н
{13, 12, 13, 0, 12, 20, 5043}, // О
{10, 12, 12, 1, 12, 15, 5063}, // П
{9, 12, 10, 1, 12, 14, 5078}, // Р
{11, 13, 11, 0, 13, 18, 5092}, // С
{10, 12, 10, 0, 12, 15, 5110}, // Т
{10, 12, 10, 0, 12, 15, 5125}, // У
{14, 13, 15, 0, 13, 23, 5140}, // Ф
{11, 12, 11, 0, 12, 17, 5163}, // Х
{11, 15, 12, 1, 12, 21, 5180}, // Ц
{10, 12, 11, 0, 12, 15, 5201}, // Ч
{15, 12, 17, 1, 12, 23, 5216}, // Ш
{16, 15, 17, 1, 12, 30, 5239}, // Щ
{12, 12, 12, 0, 12, 18, 5269}, // Ъ
{13, 12, 15, 1, 12, 20, 5287}, // Ы
{9, 12, 10, 1, 12, 14, 5307}, // Ь
{10, 12, 11, 0, 12, 15, 5321}, // Э
{16, 12, 18, 1, 12, 24, 5336}, // Ю
{10, 12, 11, 0, 12, 15, 5360}, // Я
{8, 9, 9, 0, 9, 9, 5375}, // а
{9, 13, 10, 1, 13, 15, 5384}, // б
{8, 9, 9, 1, 9, 9, 5399}, // в
{6, 9, 7, 1, 9, 7, 5408}, // г
{10, 11, 10, 0, 9, 14, 5415}, // д
{9, 9, 10, 0, 9, 11, 5429}, // е
{13, 9, 13, 0, 9, 15, 5440}, // ж
{8, 9, 8, 0, 9, 9, 5455}, // з
{8, 9, 10, 1, 9, 9, 5464}, // и
{8, 12, 10, 1, 12, 12, 5473}, // й
{8, 9, 9, 1, 9, 9, 5485}, // к
{9, 9, 10, 0, 9, 11, 5494}, // л
{11, 9, 12, 1, 9, 13, 5505}, // м
{8, 9, 10, 1, 9, 9, 5518}, // н
{10, 9, 10, 0, 9, 12, 5527}, // о
{8, 9, 10, 1, 9, 9, 5539}, // п
{9, 12, 10, 1, 9, 14, 5548}, // р
{8, 9, 8, 0, 9, 9, 5562}, // с
{8, 9, 8, 0, 9, 9, 5571}, // т
{9, 12, 8, 0, 9, 14, 5580}, // у
{13, 16, 13, 0, 13, 26, 5594}, // ф
{9, 9, 9, 0, 9, 11, 5620}, // х
{9, 11, 10, 1, 9, 13, 5631}, // ц
{8, 9, 9, 0, 9, 9, 5644}, // ч
{12, 9, 14, 1, 9, 14, 5653}, // ш
{13, 11, 14, 1, 9, 18, 5667}, // щ
{10, 9, 10, 0, 9, 12, 5685}, // ъ
{11, 9, 13, 1, 9, 13, 5697}, // ы
{8, 9, 9, 1, 9, 9, 5710}, // ь
{8, 9, 8, 0, 9, 9, 5719}, // э
{12, 9, 14, 1, 9, 14, 5728}, // ю
{8, 9, 9, 0, 9, 9, 5742}, // я
{9, 13, 10, 0, 13, 15, 5751}, // ѐ
{9, 12, 10, 0, 12, 14, 5766}, // ё
{9, 16, 10, 0, 13, 18, 5780}, // ђ
{6, 13, 7, 1, 13, 10, 5798}, // ѓ
{8, 9, 8, 0, 9, 9, 5808}, // є
{7, 9, 8, 0, 9, 8, 5817}, // ѕ
{3, 13, 4, 1, 13, 5, 5825}, // і
{6, 12, 4, -1, 12, 9, 5830}, // ї
{6, 16, 4, -2, 13, 12, 5839}, // ј
{15, 9, 15, 0, 9, 17, 5851}, // љ
{13, 9, 14, 1, 9, 15, 5868}, // њ
{9, 13, 10, 0, 13, 15, 5883}, // ћ
{8, 13, 9, 1, 13, 13, 5898}, // ќ
{8, 13, 10, 1, 13, 13, 5911}, // ѝ
{9, 15, 8, 0, 12, 17, 5924}, // ў
{8, 11, 10, 1, 9, 11, 5941}, // џ
{12, 13, 12, 0, 13, 20, 5952}, // Ѣ
{10, 13, 10, 0, 13, 17, 5972}, // ѣ
{13, 12, 13, 0, 12, 20, 5989}, // Ѳ
{10, 9, 10, 0, 9, 12, 6009}, // ѳ
{14, 12, 13, 0, 12, 21, 6021}, // Ѵ
{10, 9, 10, 0, 9, 12, 6042}, // ѵ
{12, 18, 13, 1, 15, 27, 6054}, // Ҋ
{10, 15, 10, 1, 12, 19, 6081}, // ҋ
{11, 13, 11, 0, 13, 18, 6100}, // Ҍ
{9, 9, 9, 0, 9, 11, 6118}, // ҍ
{9, 12, 10, 1, 12, 14, 6129}, // Ҏ
{9, 12, 10, 1, 9, 14, 6143}, // ҏ
{8, 14, 9, 1, 14, 14, 6157}, // Ґ
{6, 11, 7, 1, 11, 9, 6171}, // ґ
{9, 12, 9, 0, 12, 14, 6180}, // Ғ
{7, 9, 7, 0, 9, 8, 6194}, // ғ
{9, 15, 11, 1, 12, 17, 6202}, // Ҕ
{8, 12, 9, 1, 9, 12, 6219}, // ҕ
{16, 15, 16, 0, 12, 30, 6231}, // Җ
{14, 11, 13, 0, 9, 20, 6261}, // җ
{9, 15, 10, 0, 12, 17, 6281}, // Ҙ
{8, 12, 8, 0, 9, 12, 6298}, // ҙ
{11, 15, 11, 1, 12, 21, 6310}, // Қ
{9, 12, 9, 1, 9, 14, 6331}, // қ
{11, 12, 12, 1, 12, 17, 6345}, // Ҝ
{10, 9, 11, 1, 9, 12, 6362}, // ҝ
{11, 12, 11, 0, 12, 17, 6374}, // Ҟ
{10, 9, 9, 0, 9, 12, 6391}, // ҟ
{13, 12, 13, 0, 12, 20, 6403}, // Ҡ
{11, 9, 10, 0, 9, 13, 6423}, // ҡ
{11, 15, 12, 1, 12, 21, 6436}, // Ң
{9, 11, 10, 1, 9, 13, 6457}, // ң
{13, 12, 14, 1, 12, 20, 6470}, // Ҥ
{10, 9, 11, 1, 9, 12, 6490}, // ҥ
{16, 15, 18, 1, 12, 30, 6502}, // Ҧ
{14, 12, 15, 1, 9, 21, 6532}, // ҧ
{13, 15, 13, 0, 12, 25, 6553}, // Ҩ
{10, 11, 10, 0, 9, 14, 6578}, // ҩ
{11, 16, 11, 0, 13, 22, 6592}, // Ҫ
{8, 12, 8, 0, 9, 12, 6614}, // ҫ
{10, 15, 10, 0, 12, 19, 6626}, // Ҭ
{8, 11, 8, 0, 9, 11, 6645}, // ҭ
{11, 12, 10, 0, 12, 17, 6656}, // Ү
{9, 12, 9, 0, 9, 14, 6673}, // ү
{11, 12, 10, 0, 12, 17, 6687}, // Ұ
{9, 12, 9, 0, 9, 14, 6704}, // ұ
{11, 15, 11, 0, 12, 21, 6718}, // Ҳ
{9, 11, 9, 0, 9, 13, 6739}, // ҳ
{15, 15, 14, 0, 12, 29, 6752}, // Ҵ
{11, 11, 11, 0, 9, 16, 6781}, // ҵ
{11, 16, 11, 0, 12, 22, 6797}, // Ҷ
{9, 11, 9, 0, 9, 13, 6819}, // ҷ
{10, 12, 11, 0, 12, 15, 6832}, // Ҹ
{8, 9, 9, 0, 9, 9, 6847}, // ҹ
{9, 12, 11, 1, 12, 14, 6856}, // Һ
{8, 13, 10, 1, 13, 13, 6870}, // һ
{14, 12, 14, 0, 12, 21, 6883}, // Ҽ
{11, 9, 11, 0, 9, 13, 6904}, // ҽ
{14, 15, 14, 0, 12, 27, 6917}, // Ҿ
{11, 11, 11, 0, 9, 16, 6944}, // ҿ
{3, 12, 5, 1, 12, 5, 6960}, // Ӏ
{15, 15, 15, 0, 15, 29, 6965}, // Ӂ
{13, 12, 13, 0, 12, 20, 6994}, // ӂ
{9, 15, 11, 1, 12, 17, 7014}, // Ӄ
{8, 12, 9, 1, 9, 12, 7031}, // ӄ
{13, 15, 12, 0, 12, 25, 7043}, // Ӆ
{11, 12, 10, 0, 9, 17, 7068}, // ӆ
{10, 15, 12, 1, 12, 19, 7085}, // Ӈ
{8, 12, 10, 1, 9, 12, 7104}, // ӈ
{12, 15, 12, 1, 12, 23, 7116}, // Ӊ
{10, 12, 10, 1, 9, 15, 7139}, // ӊ
{9, 15, 11, 1, 12, 17, 7154}, // Ӌ
{8, 11, 9, 0, 9, 11, 7171}, // ӌ
{15, 15, 15, 1, 12, 29, 7182}, // Ӎ
{12, 12, 13, 1, 9, 18, 7211}, // ӎ
{3, 12, 5, 1, 12, 5, 7229}, // ӏ
{12, 15, 11, 0, 15, 23, 7234}, // Ӑ
{8, 12, 9, 0, 12, 12, 7257}, // ӑ
{12, 15, 11, 0, 15, 23, 7269}, // Ӓ
{8, 12, 9, 0, 12, 12, 7292}, // ӓ
{16, 12, 16, 0, 12, 24, 7304}, // Ӕ
{14, 9, 15, 0, 9, 16, 7328}, // ӕ
{9, 15, 10, 1, 15, 17, 7344}, // Ӗ
{9, 12, 10, 0, 12, 14, 7361}, // ӗ
{11, 12, 12, 0, 12, 17, 7375}, // Ә
{9, 9, 10, 0, 9, 11, 7392}, // ә
{11, 15, 12, 0, 15, 21, 7403}, // Ӛ
{9, 12, 10, 0, 12, 14, 7424}, // ӛ
{15, 15, 15, 0, 15, 29, 7438}, // Ӝ
{13, 12, 13, 0, 12, 20, 7467}, // ӝ
{9, 15, 10, 0, 15, 17, 7487}, // Ӟ
{8, 12, 8, 0, 12, 12, 7504}, // ӟ
{9, 12, 10, 0, 12, 14, 7516}, // Ӡ
{9, 12, 8, -1, 9, 14, 7530}, // ӡ
{10, 15, 12, 1, 15, 19, 7544}, // Ӣ
{8, 12, 10, 1, 12, 12, 7563}, // ӣ
{10, 15, 12, 1, 15, 19, 7575}, // Ӥ
{8, 12, 10, 1, 12, 12, 7594}, // ӥ
{13, 15, 13, 0, 15, 25, 7606}, // Ӧ
{10, 12, 10, 0, 12, 15, 7631}, // ӧ
{13, 12, 13, 0, 12, 20, 7646}, // Ө
{10, 9, 10, 0, 9, 12, 7666}, // ө
{13, 15, 13, 0, 15, 25, 7678}, // Ӫ
{10, 12, 10, 0, 12, 15, 7703}, // ӫ
{10, 15, 11, 0, 15, 19, 7718}, // Ӭ
{8, 12, 8, 0, 12, 12, 7737}, // ӭ
{10, 15, 10, 0, 15, 19, 7749}, // Ӯ
{9, 15, 8, 0, 12, 17, 7768}, // ӯ
{10, 15, 10, 0, 15, 19, 7785}, // Ӱ
{9, 15, 8, 0, 12, 17, 7804}, // ӱ
{10, 16, 10, 0, 16, 20, 7821}, // Ӳ
{9, 16, 8, 0, 13, 18, 7841}, // ӳ
{10, 15, 11, 0, 15, 19, 7859}, // Ӵ
{8, 12, 9, 0, 12, 12, 7878}, // ӵ
{8, 15, 9, 1, 12, 15, 7890}, // Ӷ
{6, 11, 7, 1, 9, 9, 7905}, // ӷ
{13, 15, 15, 1, 15, 25, 7914}, // Ӹ
{11, 12, 13, 1, 12, 17, 7939}, // ӹ
{10, 1, 8, -1, 5, 2, 7956}, //
{18, 1, 17, -1, 5, 3, 7958}, // —
{18, 1, 17, -1, 5, 3, 7961}, // ―
{3, 6, 4, 0, 13, 3, 7964}, //
{3, 6, 4, 0, 13, 3, 7967}, //
{3, 4, 4, 0, 2, 2, 7970}, //
{6, 6, 6, 0, 13, 5, 7972}, // “
{6, 6, 6, 0, 13, 5, 7977}, // ”
{7, 4, 7, 0, 2, 4, 7982}, // „
{8, 14, 8, 0, 12, 14, 7986}, // †
{8, 14, 8, 0, 12, 14, 8000}, // ‡
{6, 4, 6, 0, 8, 3, 8014}, // •
{15, 2, 17, 1, 2, 4, 8017}, // …
{21, 12, 21, 0, 12, 32, 8021}, // ‰
{5, 7, 5, 0, 8, 5, 8053}, //
{5, 7, 5, 0, 8, 5, 8058}, //
{9, 12, 3, -3, 12, 14, 8063}, //
{10, 12, 10, 0, 12, 15, 8077}, // €
{9, 12, 10, 0, 12, 14, 8092}, // ₮
{9, 14, 10, 0, 13, 16, 8106}, // ₴
{9, 12, 10, 1, 12, 14, 8122}, // ₹
{10, 13, 10, 0, 13, 17, 8136}, // ∂
{11, 12, 11, 0, 12, 17, 8153}, // ∆
{10, 13, 12, 1, 11, 17, 8170}, // ∏
{9, 14, 9, 0, 12, 16, 8187}, // ∑
{9, 1, 10, 0, 5, 2, 8203}, //
{9, 12, 3, -3, 12, 14, 8205}, //
{4, 2, 4, 0, 6, 1, 8219}, // ∙
{10, 13, 10, 0, 13, 17, 8220}, // √
{10, 5, 10, 0, 7, 7, 8237}, // ∞
{7, 16, 6, 0, 13, 14, 8244}, // ∫
{9, 6, 10, 0, 8, 7, 8258}, // ≈
{9, 8, 10, 0, 9, 9, 8265}, // ≠
{9, 9, 10, 0, 9, 11, 8274}, // ≤
{9, 9, 10, 0, 9, 11, 8285}, // ≥
};
static const EpdUnicodeInterval pixelarial14Intervals[] = {
{0x20, 0x7E, 0x0},
{0x2018, 0x2019, 0x5F},
{0x201C, 0x201D, 0x61},
{0x0, 0x0, 0x0}, {0x8, 0x9, 0x1}, {0xD, 0xD, 0x3}, {0x1D, 0x1D, 0x4},
{0x20, 0x7E, 0x5}, {0xA0, 0xFF, 0x64}, {0x100, 0x17F, 0xC4}, {0x311, 0x311, 0x144},
{0x400, 0x45F, 0x145}, {0x462, 0x463, 0x1A5}, {0x472, 0x475, 0x1A7}, {0x48A, 0x4F9, 0x1AB},
{0x2013, 0x2015, 0x21B}, {0x2018, 0x201A, 0x21E}, {0x201C, 0x201E, 0x221}, {0x2020, 0x2022, 0x224},
{0x2026, 0x2026, 0x227}, {0x2030, 0x2030, 0x228}, {0x2039, 0x203A, 0x229}, {0x2044, 0x2044, 0x22B},
{0x20AC, 0x20AC, 0x22C}, {0x20AE, 0x20AE, 0x22D}, {0x20B4, 0x20B4, 0x22E}, {0x20B9, 0x20B9, 0x22F},
{0x2202, 0x2202, 0x230}, {0x2206, 0x2206, 0x231}, {0x220F, 0x220F, 0x232}, {0x2211, 0x2212, 0x233},
{0x2215, 0x2215, 0x235}, {0x2219, 0x221A, 0x236}, {0x221E, 0x221E, 0x238}, {0x222B, 0x222B, 0x239},
{0x2248, 0x2248, 0x23A}, {0x2260, 0x2260, 0x23B}, {0x2264, 0x2265, 0x23C},
};
static const EpdFontData pixelarial14 = {
pixelarial14Bitmaps, pixelarial14Glyphs, pixelarial14Intervals, 3, 17, 13, -4, false,
pixelarial14Bitmaps, pixelarial14Glyphs, pixelarial14Intervals, 35, 17, 13, -4, false,
};

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
#pragma once
#include "EpdFontData.h"
static const uint8_t ubuntu_bold_10Bitmaps[8017] = {
static const uint8_t ubuntu_bold_10Bitmaps[13720] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xEF, 0xEF, 0xE7, 0x1E, 0xF0, 0xF7, 0x87, 0x3C,
0x39, 0xCF, 0xFF, 0xFF, 0xFC, 0xF7, 0x87, 0xBC, 0x39, 0xE7, 0xFF, 0xFF, 0xFE, 0xF7, 0x87, 0xBC, 0x39, 0xE1, 0xCE,
0x00, 0x0F, 0x01, 0xE0, 0xFF, 0xBF, 0xF7, 0xFC, 0xFB, 0x9E, 0x03, 0xF8, 0x3F, 0xC3, 0xFC, 0x1F, 0x80, 0xF7, 0xBE,
@ -400,36 +400,337 @@ static const uint8_t ubuntu_bold_10Bitmaps[8017] = {
0x80, 0xF8, 0x07, 0x80, 0x7C, 0x07, 0xC0, 0x3C, 0x03, 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x33, 0x0F, 0xE3,
0xF0, 0x7C, 0x0E, 0x00, 0x07, 0xFD, 0xFF, 0x7F, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1F, 0x0F, 0xFF, 0xFF, 0xFF, 0xC0,
0x3F, 0x3F, 0xBF, 0xDF, 0x6F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0x7E,
0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFE, 0x3B, 0xDE, 0xEF, 0x78, 0x7B, 0xDF, 0xEF, 0x70, 0x7B, 0xDF, 0xEF, 0x70, 0x3B, 0xDE, 0xE7,
0xF9, 0xDE, 0xF7, 0xBD, 0xE0, 0x7F, 0xBF, 0xDD, 0xFE, 0xFF, 0x77, 0x38, 0x7F, 0xBF, 0xDD, 0xFE, 0xFF, 0x77, 0x38,
0x1E, 0x07, 0x81, 0xE0, 0x78, 0xFF, 0xFF, 0xFF, 0xFC, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x03, 0x80, 0xE0,
0x38, 0x0E, 0x03, 0x80, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0xFF, 0xFF, 0xFF, 0xFC, 0x78, 0x1E, 0x07, 0x8F, 0xFF, 0xFF,
0xFF, 0xC7, 0x80, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0x7C, 0xFF, 0xFF, 0xF7, 0xEF, 0x80, 0xF0, 0xE1, 0xFF, 0x3E, 0x7F,
0xE7, 0xCF, 0xF8, 0x70, 0xF0, 0x3E, 0x1E, 0x00, 0x0F, 0xE3, 0xC0, 0x01, 0xDC, 0xF0, 0x00, 0x7B, 0xDE, 0x00, 0x0F,
0x7F, 0x80, 0x00, 0xEE, 0xF0, 0x00, 0x1F, 0xFC, 0x00, 0x01, 0xF7, 0xFE, 0x7E, 0x01, 0xFF, 0xCF, 0xE0, 0x3B, 0xFF,
0xFC, 0x0F, 0x73, 0xF3, 0x83, 0xCE, 0x7E, 0x70, 0x79, 0xFF, 0xFE, 0x1E, 0x3F, 0x9F, 0xC3, 0xC3, 0xF3, 0xF0, 0x00,
0x38, 0xF3, 0xE7, 0x9F, 0x1E, 0x3E, 0x3C, 0x38, 0x00, 0x00, 0xE3, 0xE3, 0xE3, 0xC7, 0xCF, 0x3E, 0xF8, 0xE0, 0x00,
0x01, 0xE0, 0x3C, 0x0F, 0x01, 0xE0, 0x78, 0x0F, 0x03, 0xC0, 0x78, 0x1E, 0x03, 0xC0, 0xF0, 0x1E, 0x07, 0x80, 0xF0,
0x3C, 0x00, 0x07, 0xF0, 0xFF, 0x1F, 0xF1, 0xF6, 0x3C, 0x07, 0xFE, 0x7F, 0xC3, 0xC0, 0x7F, 0xC7, 0xFC, 0x3C, 0x03,
0xF7, 0x1F, 0xF0, 0xFF, 0x07, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0x0F, 0xC0, 0xFC, 0x1F, 0xC3, 0xF0, 0x3F,
0xC3, 0xFC, 0x1F, 0xC3, 0xF0, 0x3F, 0x03, 0xF0, 0x0F, 0x00, 0x3F, 0x87, 0xFC, 0x3F, 0xE3, 0xBE, 0xFF, 0xFF, 0xFF,
0x1F, 0x83, 0xF0, 0xFF, 0xFF, 0xFF, 0x78, 0x07, 0xDE, 0x7F, 0xE3, 0xFE, 0x1F, 0xE0, 0xFF, 0xFF, 0xFF, 0xC1, 0xF0,
0x07, 0xCF, 0xFF, 0x7F, 0xF8, 0x0F, 0x01, 0xF8, 0xFF, 0x87, 0xF8, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F,
0x00, 0x3F, 0x83, 0xFC, 0x3F, 0xE3, 0xBF, 0x00, 0xF1, 0xFF, 0x3F, 0xF7, 0xFF, 0x7D, 0xFF, 0x0F, 0xF0, 0xFF, 0xBE,
0x7F, 0xE7, 0xFC, 0x3F, 0x80, 0x07, 0x80, 0x0F, 0x80, 0x3F, 0x00, 0x7F, 0x01, 0xFE, 0x03, 0xDC, 0x07, 0xBC, 0x1E,
0x78, 0x3C, 0x78, 0x78, 0xF1, 0xE1, 0xE3, 0xC1, 0xE7, 0xFF, 0xDF, 0xFF, 0xBF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F,
0xC1, 0xFE, 0x0F, 0xF0, 0x78, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0x07, 0xC0, 0x7C, 0x07, 0x80, 0xF8, 0x0F, 0x83, 0xE0,
0x78, 0x1E, 0x07, 0xC0, 0xF0, 0x3F, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, 0xE0, 0x3C, 0x0F, 0x01,
0xE0, 0x78, 0x0F, 0x03, 0xC0, 0x78, 0x1E, 0x03, 0xC0, 0xF0, 0x1E, 0x07, 0x80, 0xF0, 0x3C, 0x00, 0x77, 0xFE, 0xE0,
0x00, 0x3C, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x70, 0x03, 0xC0, 0x0F, 0x0F, 0x38, 0xFD, 0xE3, 0xF7, 0x87, 0xFC,
0x07, 0xF0, 0x0F, 0xC0, 0x3E, 0x00, 0x78, 0x00, 0x7D, 0xF3, 0xFF, 0xFF, 0xFF, 0xEE, 0x7F, 0xFF, 0xBF, 0xFD, 0xF7,
0xC0, 0x00, 0x07, 0xC7, 0xE7, 0xF3, 0xE1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78,
0x7C, 0x7E, 0x3F, 0x1F, 0x00, 0x00, 0x3C, 0x77, 0xFF, 0x7F, 0xEF, 0xFE, 0xE3, 0xC0, 0x00, 0x3C, 0x77, 0xFF, 0x7F,
0xEF, 0xFE, 0xE3, 0xC0, 0x03, 0x80, 0xE0, 0x7B, 0xFF, 0xFF, 0xFF, 0xF0, 0xE0, 0x70, 0xFF, 0xFF, 0xFF, 0xFD, 0xC0,
0x70, 0x1C, 0x00, 0x07, 0xDF, 0xFF, 0xFF, 0xFE, 0xF8, 0x3F, 0xEF, 0xFD, 0xFF, 0x07, 0xC0, 0x0F, 0xFF, 0xFF, 0xFF,
0xC0, 0xF8, 0x3F, 0xCF, 0xFD, 0xFF, 0x0F, 0xDF, 0xFF, 0xFF, 0xFE, 0xF8, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xC0,
0x7F, 0xFF, 0x0C, 0x03, 0xC0, 0x78, 0x07, 0x80, 0x70, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F,
0xFD, 0xFF, 0xBF, 0xF7, 0x80, 0xF0, 0x1E, 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0x7B, 0xCF, 0x79, 0xEF, 0x00, 0x00, 0x01,
0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x1E, 0x03, 0xC0, 0x7F, 0xEF, 0xFD, 0xFF, 0xBC, 0x07, 0x80, 0xF0, 0x1F, 0xFF, 0xFF,
0xFF, 0xF0, 0xFF, 0xF8, 0x7F, 0xFC, 0x3F, 0xFE, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x7F, 0xE0, 0x3F, 0xF8, 0x1F, 0xFE,
0x0F, 0x9F, 0x07, 0x87, 0xC3, 0xC1, 0xE1, 0xE3, 0xE0, 0xF7, 0xF0, 0x7B, 0xF8, 0x3D, 0xF8, 0x03, 0x00, 0xF0, 0x3E,
0x0F, 0x01, 0xC0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0,
0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x00, 0x1F, 0xF1, 0xFF, 0xDF, 0xFD, 0xFD, 0xEF, 0x80, 0x78, 0x03, 0xFF, 0x1F, 0xF8,
0xFF, 0xC7, 0x80, 0x3E, 0x01, 0xFD, 0xE7, 0xFF, 0x1F, 0xFC, 0x7F, 0xC0, 0x1F, 0xE3, 0xFE, 0x7F, 0xE7, 0xDC, 0x78,
0x07, 0xE0, 0x7F, 0x83, 0xFE, 0x0F, 0xE0, 0x3F, 0x01, 0xF7, 0xBF, 0x7F, 0xFF, 0xFE, 0x7F, 0xC0, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF7, 0x7B, 0xFD, 0xC0, 0x03, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83,
0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x00, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03,
0xC0, 0xF0, 0x3D, 0x9F, 0xFF, 0xFF, 0xEF, 0xF0, 0x07, 0xFE, 0x00, 0x1F, 0xFC, 0x00, 0x3F, 0xF8, 0x00, 0x78, 0xF0,
0x00, 0xF1, 0xE0, 0x01, 0xE3, 0xFF, 0x03, 0xC7, 0xFF, 0x07, 0x8F, 0xFF, 0x0F, 0x1E, 0x7E, 0x3E, 0x3C, 0x3C, 0x78,
0x78, 0x7B, 0xF0, 0xF3, 0xFF, 0xE1, 0xFF, 0xFF, 0x83, 0xFF, 0xBC, 0x07, 0xFE, 0x00, 0xF0, 0x78, 0x07, 0x83, 0xC0,
0x3C, 0x1E, 0x01, 0xE0, 0xF0, 0x0F, 0x07, 0x80, 0x7F, 0xFF, 0xF3, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xF0, 0x79, 0xFF,
0x83, 0xC3, 0xFC, 0x1E, 0x1F, 0xE0, 0xF3, 0xFF, 0x07, 0xFF, 0xF8, 0x3F, 0xFB, 0xC1, 0xFF, 0x00, 0xFF, 0xF8, 0xFF,
0xF8, 0xFF, 0xF8, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0xFC, 0x0F, 0xFE, 0x0F, 0xFE, 0x0F, 0x3F, 0x0F, 0x0F,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x01, 0x80, 0x07, 0x00, 0x3C, 0x01, 0xE0, 0x07, 0x00, 0x00, 0x0F,
0x0F, 0xBC, 0x7C, 0xF3, 0xE3, 0xDF, 0x0F, 0xF8, 0x3F, 0xC0, 0xFE, 0x03, 0xFC, 0x0F, 0xF8, 0x3D, 0xF0, 0xF7, 0xC3,
0xCF, 0x8F, 0x1F, 0x3C, 0x3E, 0xF0, 0xF8, 0x06, 0x00, 0x3C, 0x00, 0xF8, 0x01, 0xE0, 0x01, 0x80, 0x00, 0x0F, 0x07,
0xFC, 0x1F, 0xF0, 0xFF, 0xC7, 0xFF, 0x3F, 0xFC, 0xFF, 0xF7, 0xBF, 0xFE, 0xFF, 0xF3, 0xFF, 0x8F, 0xFE, 0x3F, 0xF0,
0xFF, 0x83, 0xFE, 0x0F, 0xF0, 0x3C, 0x0C, 0xE0, 0x7B, 0x80, 0xFE, 0x01, 0xF0, 0x00, 0x03, 0xE1, 0xF7, 0x87, 0x9F,
0x1E, 0x3C, 0xF8, 0xFB, 0xC1, 0xEF, 0x07, 0xFC, 0x0F, 0xE0, 0x3F, 0x80, 0x7C, 0x01, 0xF0, 0x6F, 0x81, 0xFE, 0x07,
0xF0, 0x1F, 0x80, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83,
0xFC, 0x1F, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x07, 0xC0, 0x0F, 0x80,
0x3F, 0x80, 0x7F, 0x00, 0xFF, 0x03, 0xDE, 0x07, 0xBC, 0x1F, 0x3C, 0x3C, 0x78, 0x7F, 0xF1, 0xFF, 0xF3, 0xFF, 0xE7,
0x83, 0xFF, 0x07, 0xFC, 0x07, 0x80, 0xFF, 0xEF, 0xFE, 0xFF, 0xEF, 0x00, 0xF0, 0x0F, 0xFC, 0xFF, 0xEF, 0xFF, 0xF3,
0xFF, 0x0F, 0xF0, 0xFF, 0x3F, 0xFF, 0xFF, 0xFE, 0xFF, 0xC0, 0xFF, 0xC7, 0xFF, 0x3F, 0xFD, 0xE3, 0xEF, 0x1F, 0x7F,
0xF3, 0xFF, 0x9F, 0xFE, 0xF1, 0xF7, 0x87, 0xFC, 0x3F, 0xE7, 0xEF, 0xFF, 0x7F, 0xF3, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x00, 0x0F,
0xFE, 0x07, 0xFF, 0x03, 0xFF, 0x81, 0xE3, 0xC0, 0xF1, 0xE0, 0x78, 0xF0, 0x3C, 0x78, 0x1E, 0x3C, 0x1F, 0x1E, 0x0F,
0x0F, 0x07, 0x87, 0x87, 0xC3, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC,
0x01, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, 0x01, 0xE0, 0x3F, 0xF7, 0xFE, 0xFF, 0xDE, 0x03, 0xC0, 0x78, 0x0F,
0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0xF0, 0xFB, 0xE7, 0x8F, 0x9F, 0xBC, 0xF8, 0x7D, 0xEF, 0x81, 0xFF, 0x7C, 0x07, 0xFF,
0xC0, 0x1F, 0xFC, 0x00, 0xFF, 0xC0, 0x0F, 0xFF, 0x00, 0xFF, 0xFC, 0x07, 0xFD, 0xF0, 0x7D, 0xE7, 0xC7, 0xCF, 0x3E,
0x3C, 0x78, 0xFB, 0xE3, 0xC3, 0xE0, 0x7F, 0xC7, 0xFE, 0x7F, 0xE7, 0xBF, 0x01, 0xF0, 0x3E, 0x1F, 0xE1, 0xFE, 0x1F,
0xF0, 0x3F, 0x00, 0xF7, 0xBF, 0x7F, 0xFF, 0xFE, 0x7F, 0xC0, 0xF0, 0x7F, 0xC1, 0xFF, 0x0F, 0xFC, 0x7F, 0xF3, 0xFF,
0xCF, 0xFF, 0x7B, 0xFF, 0xEF, 0xFF, 0x3F, 0xF8, 0xFF, 0xE3, 0xFF, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x03, 0xC0, 0x0C,
0xE0, 0x7F, 0x80, 0xFE, 0x03, 0xF0, 0x00, 0x03, 0xC1, 0xFF, 0x07, 0xFC, 0x3F, 0xF1, 0xFF, 0xCF, 0xFF, 0x3F, 0xFD,
0xEF, 0xFF, 0xBF, 0xFC, 0xFF, 0xE3, 0xFF, 0x8F, 0xFC, 0x3F, 0xE0, 0xFF, 0x83, 0xFC, 0x0F, 0xF0, 0xFB, 0xC7, 0xCF,
0x3E, 0x3D, 0xF0, 0xFF, 0x83, 0xFC, 0x0F, 0xE0, 0x3F, 0xC0, 0xFF, 0x83, 0xDF, 0x0F, 0x7C, 0x3C, 0xF8, 0xF1, 0xF3,
0xC3, 0xEF, 0x0F, 0x80, 0x07, 0xFE, 0x1F, 0xFC, 0x3F, 0xF8, 0x78, 0xF0, 0xF1, 0xE1, 0xE3, 0xC3, 0xC7, 0x87, 0x8F,
0x0F, 0x1E, 0x3E, 0x3C, 0x78, 0x7B, 0xF0, 0xFF, 0xE1, 0xFF, 0x83, 0xFC, 0x07, 0x80, 0x78, 0x0F, 0x3E, 0x0F, 0x9F,
0x07, 0xCF, 0xC7, 0xEF, 0xE3, 0xF7, 0xFB, 0xFB, 0xFD, 0xFF, 0xEE, 0xEF, 0xF7, 0xF7, 0xFB, 0xF3, 0xFC, 0xF9, 0xFE,
0x7C, 0xFF, 0x1C, 0x7F, 0x80, 0x3F, 0xC0, 0x1E, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xE0, 0x1F, 0xE0, 0x7F, 0xF1, 0xFF,
0xF3, 0xF7, 0xEF, 0x83, 0xDE, 0x07, 0xFC, 0x07, 0xF8, 0x0F, 0xF0, 0x1F, 0xE0, 0x7F, 0xE0, 0xFF, 0xF7, 0xE7, 0xFF,
0xC7, 0xFF, 0x07, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0,
0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xE0, 0xFF, 0xCF, 0xFE, 0xFF, 0xFF, 0x3F, 0xF0, 0xFF,
0x0F, 0xF3, 0xFF, 0xFF, 0xFF, 0xEF, 0xFC, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x00, 0x1F, 0xF1, 0xFF, 0x9F,
0xFC, 0xFD, 0xEF, 0x80, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3E, 0x01, 0xFC, 0xE7, 0xFF, 0x1F, 0xF8,
0x7F, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x1F, 0x00, 0xF8, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03,
0xE0, 0x1F, 0x00, 0xF8, 0x07, 0xC0, 0x3E, 0x00, 0xF8, 0x7D, 0xE1, 0xE7, 0xC7, 0x8F, 0x3E, 0x3E, 0xF0, 0x7B, 0xC1,
0xFF, 0x03, 0xF8, 0x0F, 0xE0, 0x1F, 0x00, 0x7C, 0x1B, 0xE0, 0x7F, 0x81, 0xFC, 0x07, 0xE0, 0x00, 0x01, 0xE0, 0x00,
0x78, 0x00, 0xFF, 0xC0, 0x7F, 0xFC, 0x3F, 0xFF, 0x9F, 0xFF, 0xE7, 0x9E, 0x7D, 0xE7, 0x8F, 0x79, 0xE3, 0xDE, 0x79,
0xF7, 0xFF, 0xF8, 0xFF, 0xFE, 0x3F, 0xFF, 0x03, 0xFF, 0x00, 0x1E, 0x00, 0x07, 0x80, 0xF8, 0x7D, 0xF3, 0xE7, 0xEF,
0x8F, 0xFC, 0x1F, 0xE0, 0x7F, 0x80, 0xFC, 0x01, 0xF0, 0x0F, 0xC0, 0x7F, 0x83, 0xFF, 0x0F, 0xFC, 0x7C, 0xF9, 0xE1,
0xFF, 0x87, 0xC0, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78,
0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x00, 0x0F, 0x00,
0x0F, 0x00, 0x0F, 0xF8, 0x7F, 0xC3, 0xFE, 0x1F, 0xF0, 0xFF, 0x87, 0xFC, 0x3D, 0xF3, 0xEF, 0xFF, 0x7F, 0xF8, 0xFF,
0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0xF0, 0xF1, 0xFE, 0x1E, 0x3F, 0xC3, 0xC7, 0xF8, 0x78, 0xFF,
0x0F, 0x1F, 0xE1, 0xE3, 0xFC, 0x3C, 0x7F, 0x87, 0x8F, 0xF0, 0xF1, 0xFE, 0x1E, 0x3F, 0xC3, 0xC7, 0xF8, 0x78, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xF0, 0xF1, 0xE3, 0xC3, 0xC7, 0x8F, 0x0F, 0x1E, 0x3C, 0x3C, 0x78, 0xF0,
0xF1, 0xE3, 0xC3, 0xC7, 0x8F, 0x0F, 0x1E, 0x3C, 0x3C, 0x78, 0xF0, 0xF1, 0xE3, 0xC3, 0xC7, 0x8F, 0x0F, 0x1E, 0x3C,
0x3C, 0x78, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, 0x00, 0x00, 0xF0,
0x00, 0x03, 0xC0, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0xF8, 0x0F, 0xFE, 0x0F, 0xFE,
0x0F, 0x7F, 0x0F, 0x1F, 0x0F, 0x1F, 0x0F, 0x7F, 0x0F, 0xFE, 0x0F, 0xFC, 0x0F, 0xF8, 0xF0, 0x07, 0xF8, 0x03, 0xFC,
0x01, 0xFE, 0x00, 0xFF, 0x00, 0x7F, 0xFE, 0x3F, 0xFF, 0x9F, 0xFF, 0xEF, 0xF3, 0xF7, 0xF8, 0x7B, 0xFC, 0x3D, 0xFE,
0x7E, 0xFF, 0xFF, 0x7F, 0xFF, 0x3F, 0xFE, 0x1E, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0xFC, 0xFF, 0xEF,
0xFF, 0xF3, 0xFF, 0x0F, 0xF0, 0xFF, 0x3F, 0xFF, 0xFF, 0xFE, 0xFF, 0xC0, 0x7F, 0xC1, 0xFF, 0x87, 0xFF, 0x1E, 0xFE,
0x00, 0x78, 0x01, 0xE1, 0xFF, 0xC7, 0xFF, 0x1F, 0xFC, 0x01, 0xF0, 0x07, 0x9E, 0xFE, 0x7F, 0xF1, 0xFF, 0x87, 0xFC,
0x00, 0xF0, 0x3F, 0x87, 0x83, 0xFF, 0x3C, 0x3F, 0xFD, 0xE3, 0xF7, 0xEF, 0x1E, 0x0F, 0xF9, 0xF0, 0x7F, 0xFF, 0x01,
0xFF, 0xF8, 0x0F, 0xFF, 0xC0, 0x7F, 0x9F, 0x07, 0xFC, 0xF8, 0x3F, 0xE3, 0xF7, 0xEF, 0x1F, 0xFF, 0x78, 0x7F, 0xF3,
0xC0, 0xFE, 0x00, 0x0F, 0xF8, 0xFF, 0xCF, 0xFE, 0xFC, 0xF7, 0xC7, 0xBE, 0x3D, 0xF9, 0xE7, 0xFF, 0x3F, 0xF8, 0xFF,
0xC7, 0xDE, 0x7C, 0xF3, 0xC7, 0xBE, 0x3D, 0xE1, 0xE0, 0x7F, 0x8F, 0xF8, 0xFF, 0x19, 0xF3, 0xFE, 0xFF, 0xFE, 0x7F,
0xCF, 0xFF, 0xEF, 0xFC, 0xFF, 0x80, 0x03, 0xE0, 0xFE, 0x1F, 0xE3, 0xFE, 0x7C, 0x07, 0xFC, 0x7F, 0xE7, 0xFF, 0x7D,
0xF7, 0x8F, 0x78, 0xF7, 0x8F, 0x7D, 0xF7, 0xFE, 0x3F, 0xE1, 0xFC, 0xFF, 0x9F, 0xFB, 0xFF, 0xF9, 0xEF, 0xFD, 0xFF,
0xBC, 0xFF, 0x9F, 0xFF, 0xFF, 0xFB, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78,
0x3C, 0x00, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xBC, 0x1E, 0xF0, 0xF3, 0xC3, 0xCF, 0x0F, 0x3C, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x70, 0x1F, 0xC3, 0xFE, 0x7F, 0xE7, 0xDF, 0x7F, 0xF7, 0xFF, 0x78, 0x07,
0xEE, 0x7F, 0xE3, 0xFE, 0x1F, 0xE0, 0xF9, 0xE7, 0xDF, 0x7B, 0xE3, 0xFF, 0xF0, 0xFF, 0xF8, 0x1F, 0xFE, 0x03, 0xFF,
0x01, 0xFF, 0xE0, 0xFF, 0xFC, 0x7D, 0xEF, 0x1E, 0x7B, 0xEF, 0x9E, 0x7C, 0x7F, 0x1F, 0xE7, 0xFD, 0xDF, 0x3F, 0x8F,
0xE0, 0x7D, 0xDF, 0x7F, 0xFF, 0xFF, 0xF8, 0xF1, 0xFE, 0x7F, 0xDF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xF9,
0xFF, 0x3F, 0xC7, 0x80, 0x39, 0x87, 0x78, 0xFE, 0x0F, 0x80, 0x00, 0x00, 0x3C, 0x7F, 0x9F, 0xF7, 0xFE, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFB, 0xFE, 0x7F, 0xCF, 0xF1, 0xE0, 0xF3, 0xEF, 0x7C, 0xFF, 0x8F, 0xF0, 0xFE, 0x0F, 0xE0, 0xFF,
0x0F, 0xF8, 0xF7, 0xCF, 0x3E, 0xF1, 0xE0, 0x1F, 0xF1, 0xFF, 0x1F, 0xF1, 0xEF, 0x1E, 0xF1, 0xEF, 0x3E, 0xFF, 0xCF,
0xFC, 0xFF, 0x8F, 0xF0, 0xF0, 0x78, 0x79, 0xE1, 0xEF, 0xCF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF7, 0xBF, 0xDE, 0xFF, 0x03, 0xC0, 0xF3, 0xFC, 0xFF, 0x3F, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xF3, 0xFC, 0xFF,
0x3C, 0x1F, 0xC3, 0xFE, 0x7F, 0xF7, 0xDF, 0x78, 0xF7, 0x8F, 0x78, 0xF7, 0xDF, 0x7F, 0xF3, 0xFE, 0x1F, 0xC0, 0xFF,
0xFF, 0xFF, 0xFF, 0xCF, 0xF3, 0xFC, 0xFF, 0x3F, 0xCF, 0xF3, 0xFC, 0xFF, 0x3C, 0xFF, 0x9F, 0xFB, 0xFF, 0x7B, 0xFF,
0x1F, 0xE3, 0xFC, 0x7F, 0xDF, 0xFF, 0xFF, 0xFB, 0xFE, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x00, 0x1F, 0xCF, 0xF7, 0xFD,
0xF6, 0x78, 0x1E, 0x07, 0x81, 0xF3, 0x7F, 0xCF, 0xF1, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0x80, 0xF0, 0x1E, 0x03,
0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x00, 0xF1, 0xFF, 0x1E, 0x79, 0xE7, 0x9E, 0x7B, 0xC3, 0xFC, 0x3F, 0xC3, 0xF8,
0x1F, 0x81, 0xF0, 0x0F, 0x0D, 0xF0, 0xFE, 0x0F, 0xC0, 0xF8, 0x00, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
0x03, 0xC0, 0x1F, 0xF8, 0x3F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFF, 0x7B, 0xCF, 0x7B, 0xCF, 0x7B, 0xCF, 0x7F, 0xFF, 0x7F,
0xFE, 0x3F, 0xFE, 0x1F, 0xF8, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0xF9, 0xE7, 0xBE, 0x7F, 0xC3, 0xF8,
0x1F, 0x81, 0xF0, 0x1F, 0x83, 0xFC, 0x7F, 0xC7, 0x9E, 0xF1, 0xF0, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF,
0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x00, 0x70, 0x07, 0xF9, 0xFF, 0x3F, 0xE7, 0xBC, 0xF7,
0x9E, 0xFF, 0xDF, 0xF9, 0xFF, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF3, 0xCF, 0xF3, 0xCF, 0xF3, 0xCF, 0xF3, 0xCF, 0xF3,
0xCF, 0xF3, 0xCF, 0xF3, 0xCF, 0xF3, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C,
0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0xFE, 0x07, 0xF0, 0x3F, 0x80, 0x3C, 0x01, 0xFF, 0x0F, 0xFC, 0x7F, 0xE3,
0xDF, 0x1F, 0xF8, 0xFF, 0xC7, 0xFC, 0xF0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x80, 0xFF, 0xF9, 0xFF, 0xFB, 0xFF, 0xF7,
0xF9, 0xFF, 0xFF, 0xDF, 0xFF, 0xBF, 0xFE, 0x78, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0xF9, 0xFF, 0xBF, 0xF7, 0x9F,
0xFF, 0xDF, 0xFB, 0xFE, 0x00, 0x7F, 0x0F, 0xF1, 0xFF, 0x3B, 0xE3, 0xFE, 0x7F, 0xC0, 0xFB, 0xBE, 0x7F, 0xDF, 0xF3,
0xFC, 0x00, 0xF0, 0xFC, 0x78, 0xFF, 0x3C, 0xFF, 0xDE, 0x7F, 0xEF, 0xFC, 0x7F, 0xFC, 0x3F, 0xFF, 0x1F, 0xE7, 0xFE,
0xF3, 0xFF, 0x78, 0xFF, 0x3C, 0x3F, 0x00, 0x1F, 0xEF, 0xFD, 0xFF, 0xBE, 0xF7, 0xDE, 0xFF, 0xDF, 0xF9, 0xFF, 0x3D,
0xEF, 0x3F, 0xE7, 0x80, 0x0C, 0x01, 0xE0, 0x1F, 0x00, 0x78, 0x03, 0x80, 0x00, 0x1F, 0xC3, 0xFE, 0x7F, 0xE7, 0xDF,
0x7F, 0xF7, 0xFF, 0x78, 0x07, 0xEE, 0x7F, 0xE3, 0xFE, 0x1F, 0xE0, 0x3D, 0xC3, 0xDE, 0x3D, 0xC0, 0x00, 0x00, 0x01,
0xFC, 0x3F, 0xE7, 0xFE, 0x7D, 0xF7, 0xFF, 0x7F, 0xF7, 0x80, 0x7E, 0xE7, 0xFE, 0x3F, 0xE1, 0xFE, 0x78, 0x07, 0x80,
0xFF, 0x0F, 0xF0, 0x78, 0x07, 0xFC, 0x7F, 0xE7, 0xFE, 0x7D, 0xE7, 0x8F, 0x78, 0xF7, 0x8F, 0x78, 0xF7, 0x8F, 0x78,
0xF7, 0x8F, 0x01, 0xF0, 0x7E, 0x07, 0xE0, 0x7C, 0x0C, 0x0F, 0x07, 0x87, 0x83, 0x80, 0x03, 0xFF, 0xFF, 0xFF, 0xF8,
0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x00, 0x1F, 0xC7, 0xF9, 0xFF, 0x3E, 0xEF, 0xF9, 0xFF, 0x3E, 0x03,
0xEE, 0x7F, 0xC7, 0xFC, 0x7F, 0x80, 0x3F, 0x9F, 0xE7, 0xF9, 0xEE, 0x7F, 0x9F, 0xE3, 0xFD, 0xDF, 0x7F, 0xDF, 0xE7,
0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x73, 0xBF, 0xDC, 0xE0, 0x00, 0x00, 0xF0, 0x78, 0x3C, 0x1E,
0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x3C, 0x78, 0xF0, 0x03, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1,
0xE3, 0xC7, 0x8F, 0x3F, 0xFF, 0xF7, 0xE0, 0x1F, 0xF0, 0x03, 0xFE, 0x00, 0x7F, 0xC0, 0x0F, 0x78, 0x01, 0xEF, 0xF8,
0x3D, 0xFF, 0x8F, 0xBF, 0xFF, 0xE7, 0x9F, 0xFC, 0xFF, 0xDF, 0x1F, 0xFB, 0xC3, 0xFE, 0x00, 0xF3, 0xC0, 0x79, 0xE0,
0x3C, 0xF0, 0x1E, 0x78, 0x0F, 0xFF, 0xE7, 0xFF, 0xFB, 0xFF, 0xFF, 0xE7, 0x9F, 0xF3, 0xFF, 0xF9, 0xFF, 0xBC, 0x7F,
0x80, 0x78, 0x07, 0x80, 0xFF, 0x0F, 0xF0, 0x78, 0x07, 0xFC, 0x7F, 0xE7, 0xFE, 0x7D, 0xE7, 0x8F, 0x78, 0xF7, 0x8F,
0x78, 0xF7, 0x8F, 0x78, 0xF7, 0x8F, 0x03, 0x00, 0x78, 0x0F, 0x81, 0xE0, 0x1C, 0x00, 0x00, 0xF3, 0xEF, 0x7C, 0xFF,
0x8F, 0xF0, 0xFE, 0x0F, 0xE0, 0xFF, 0x0F, 0xF8, 0xF7, 0xCF, 0x3E, 0xF1, 0xE0, 0x18, 0x07, 0x80, 0xF0, 0x0F, 0x00,
0xE0, 0x00, 0x3C, 0x7F, 0x9F, 0xF7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFE, 0x7F, 0xCF, 0xF1, 0xE0, 0x39,
0x83, 0xFC, 0x3F, 0x81, 0xF0, 0x00, 0x00, 0x00, 0xF1, 0xFF, 0x1E, 0x79, 0xE7, 0x9E, 0x7B, 0xC3, 0xFC, 0x3F, 0xC3,
0xF8, 0x1F, 0x81, 0xF0, 0x0F, 0x0D, 0xF0, 0xFE, 0x0F, 0xC0, 0xF8, 0x00, 0xF3, 0xFC, 0xFF, 0x3F, 0xCF, 0xF3, 0xFC,
0xFF, 0x3F, 0xCF, 0xFF, 0xFF, 0xFF, 0xFC, 0x78, 0x1E, 0x07, 0x80, 0x1E, 0x00, 0x3C, 0x03, 0xFF, 0x87, 0xFF, 0x0F,
0xFE, 0x03, 0xC0, 0x07, 0xFE, 0x0F, 0xFE, 0x1F, 0xFE, 0x3C, 0xFC, 0x78, 0x78, 0xF0, 0xF1, 0xE7, 0xE3, 0xFF, 0xC7,
0xFF, 0x0F, 0xF8, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x7F, 0xE3, 0xFF, 0x1F, 0xF8, 0x3C, 0x01, 0xE0,
0x0F, 0xF8, 0x7F, 0xE3, 0xCF, 0x9F, 0xFC, 0xFF, 0xC7, 0xFE, 0x1F, 0xE0, 0x7F, 0xF1, 0xFF, 0xF3, 0xF7, 0xEF, 0x83,
0xDF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xE0, 0x7F, 0xE0, 0xFF, 0xF7, 0xE7, 0xFF, 0xC7, 0xFF, 0x07, 0xF8,
0x00, 0x1F, 0xC3, 0xFE, 0x7F, 0xF7, 0xDF, 0x7F, 0xF7, 0xFF, 0x7F, 0xF7, 0xDF, 0x7F, 0xF3, 0xFE, 0x1F, 0xC0, 0xF0,
0x1F, 0xBE, 0x07, 0xE7, 0x83, 0xF9, 0xE0, 0xF4, 0x7C, 0x7C, 0x0F, 0x1E, 0x03, 0xC7, 0x80, 0xFB, 0xC0, 0x1E, 0xF0,
0x07, 0xFC, 0x00, 0xFE, 0x00, 0x3F, 0x80, 0x0F, 0xE0, 0x01, 0xF0, 0x00, 0x7C, 0x00, 0xF0, 0xFF, 0x8F, 0xDE, 0x7E,
0xF3, 0x87, 0xBC, 0x1F, 0xE0, 0xFE, 0x07, 0xF0, 0x1F, 0x00, 0xF8, 0x03, 0xC0, 0x1F, 0xE0, 0x1F, 0xE0, 0x0F, 0xC0,
0x00, 0x00, 0xF0, 0x7C, 0xF0, 0x7C, 0xF0, 0xFC, 0xF1, 0xFC, 0xF3, 0xFC, 0xF3, 0xFC, 0xF7, 0xBC, 0xFF, 0xBC, 0xFF,
0x3C, 0xFE, 0x3C, 0xFE, 0x3C, 0xFC, 0x3C, 0xF8, 0x3F, 0xF8, 0x3F, 0xF0, 0x3F, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x3C,
0x00, 0x1C, 0x7F, 0x83, 0xFC, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x79, 0xF3, 0xCF, 0x9E, 0xFC, 0xFF, 0xE7, 0xFF, 0x3F,
0xF9, 0xFB, 0xCF, 0xDE, 0x7C, 0xFB, 0xC7, 0xDE, 0x3E, 0x00, 0xF0, 0x0F, 0x00, 0x30, 0x78, 0x03, 0xC0, 0x3F, 0xC1,
0xFE, 0x07, 0x80, 0x3F, 0xF1, 0xFF, 0xCF, 0xFF, 0x79, 0xFB, 0xC3, 0xDE, 0x1E, 0xF3, 0xF7, 0xFF, 0xBF, 0xF8, 0xFF,
0x80, 0x78, 0x0F, 0xF0, 0xFF, 0x07, 0x80, 0x7F, 0xC7, 0xFE, 0x79, 0xE7, 0x9F, 0x7F, 0xE7, 0xFE, 0x7F, 0xC0, 0xFF,
0xCF, 0xFE, 0xFF, 0xFF, 0x3F, 0xF2, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xEF, 0xFC, 0xF1, 0xEF, 0x1E, 0xF0, 0x8F,
0x00, 0xF0, 0x00, 0xFF, 0x9F, 0xFB, 0xFF, 0xF9, 0xFF, 0x1F, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0x79,
0xEF, 0x1D, 0xE1, 0x3C, 0x00, 0x01, 0xE0, 0x3C, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x07, 0x80, 0xF0, 0x1E, 0x03,
0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x00, 0x07, 0x83, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1,
0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x80, 0x3F, 0xF3, 0xFF, 0x3F, 0xF3, 0xC0, 0x3C, 0x03, 0xC0, 0xFF, 0x8F,
0xF8, 0xFF, 0x83, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x00, 0x7F, 0xDF, 0xF7, 0xFD, 0xE0, 0x78, 0x3F,
0xCF, 0xF1, 0xE0, 0x78, 0x1E, 0x07, 0x80, 0xFF, 0xE7, 0xFF, 0x3F, 0xF9, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xFF, 0x1F,
0xFC, 0xFF, 0xF7, 0x9F, 0xBC, 0x3D, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC3, 0xC0, 0x7E, 0x07, 0xF0, 0x7F, 0x03, 0xF0,
0xFF, 0x9F, 0xF3, 0xFE, 0x78, 0x0F, 0x01, 0xFF, 0x3F, 0xF7, 0xFE, 0xF7, 0xDE, 0x3F, 0xC7, 0x81, 0xF0, 0xFC, 0x1F,
0x83, 0xE0, 0xF8, 0xF0, 0xF9, 0xF3, 0xC7, 0xC7, 0xEF, 0x3E, 0x0F, 0xBD, 0xF0, 0x1F, 0xF7, 0xC0, 0x3F, 0xFE, 0x00,
0x7F, 0xF0, 0x01, 0xFF, 0x80, 0x0F, 0xFF, 0x00, 0x7F, 0xFE, 0x01, 0xFF, 0xFC, 0x0F, 0xBD, 0xF8, 0x7C, 0xF3, 0xF9,
0xE3, 0xC7, 0xEF, 0x8F, 0x0F, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x78, 0x00, 0x01, 0xE0, 0x00, 0x07, 0x80, 0xF9, 0xE7,
0xDF, 0x7B, 0xE3, 0xFF, 0xF0, 0xFF, 0xF8, 0x1F, 0xFE, 0x03, 0xFF, 0x01, 0xFF, 0xE0, 0xFF, 0xFC, 0x7D, 0xFF, 0xDE,
0x7B, 0xFF, 0x9E, 0x7C, 0x00, 0x07, 0x00, 0x01, 0xC0, 0x00, 0x70, 0x7F, 0xC7, 0xFE, 0x7F, 0xE7, 0xBF, 0x01, 0xF0,
0x3E, 0x1F, 0xE1, 0xFE, 0x1F, 0xF0, 0x3F, 0x00, 0xF7, 0xBF, 0x7F, 0xFF, 0xFE, 0x7F, 0xC0, 0xF0, 0x0F, 0x00, 0xF8,
0x1F, 0x01, 0xF0, 0x7F, 0x1F, 0xE7, 0xFD, 0xDF, 0x3F, 0x8F, 0xE0, 0x7D, 0xDF, 0x7F, 0xFF, 0xFF, 0xF8, 0x78, 0x1E,
0x07, 0xC3, 0xE0, 0xF8, 0xF0, 0xF9, 0xE3, 0xE3, 0xCF, 0x87, 0xBE, 0x0F, 0xF8, 0x1F, 0xE0, 0x3F, 0x80, 0x7F, 0x80,
0xFF, 0x81, 0xFF, 0x83, 0xDF, 0x87, 0x9F, 0x0F, 0x1F, 0xFE, 0x1F, 0xFC, 0x3F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C,
0x00, 0xF8, 0xF3, 0xEF, 0x7C, 0xF7, 0x8F, 0xF8, 0xFF, 0x0F, 0xE0, 0xFF, 0x0F, 0xF8, 0xF7, 0xFF, 0x3F, 0xF1, 0xF0,
0x0F, 0x00, 0xF0, 0x0F, 0xF0, 0x3E, 0xF0, 0x3E, 0xF6, 0x7C, 0xF6, 0xF8, 0xF7, 0xF0, 0xFF, 0xE0, 0xFF, 0xE0, 0xFF,
0xF0, 0xF7, 0xF0, 0xF6, 0xF8, 0xF6, 0xF8, 0xF0, 0x7C, 0xF0, 0x3E, 0xF0, 0x3E, 0xF0, 0x1F, 0xF0, 0xFB, 0xFF, 0xCF,
0xFE, 0x3F, 0xF0, 0xFF, 0x83, 0xFF, 0x0F, 0xFE, 0x3F, 0xF8, 0xF1, 0xF3, 0xC3, 0xEF, 0x07, 0x80, 0x7C, 0x00, 0xF8,
0x7F, 0xF9, 0xF7, 0xF7, 0xC7, 0xDF, 0x0F, 0xFE, 0x1F, 0xF8, 0x3F, 0xE0, 0x7F, 0x80, 0xFF, 0x81, 0xFF, 0x83, 0xFF,
0x87, 0xDF, 0x0F, 0x9F, 0x1F, 0x1F, 0x3E, 0x1F, 0x78, 0x07, 0xF7, 0xFF, 0xFD, 0xFF, 0xC7, 0xFC, 0x3F, 0xC1, 0xFC,
0x0F, 0xF0, 0x7F, 0xC3, 0xDF, 0x1E, 0x7C, 0xF1, 0xE0, 0xFF, 0x1F, 0x7F, 0x9F, 0x3F, 0xDF, 0x81, 0xFF, 0x80, 0xFF,
0x80, 0x7F, 0x80, 0x3F, 0x80, 0x1F, 0xE0, 0x0F, 0xF8, 0x07, 0xFC, 0x03, 0xDF, 0x01, 0xE7, 0xC0, 0xF1, 0xF0, 0x78,
0xF8, 0x3C, 0x3E, 0xFE, 0x7F, 0xFB, 0xEF, 0xFF, 0x07, 0xF8, 0x1F, 0xC0, 0x7F, 0x01, 0xFE, 0x07, 0xFC, 0x1E, 0xF8,
0x79, 0xE1, 0xE7, 0xC0, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xFF, 0xF8, 0xFF,
0xF8, 0xFF, 0xF8, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x7F, 0xF0, 0x7F, 0xF0, 0x7F, 0x00, 0x0F, 0x00, 0x0F,
0x00, 0x0F, 0x00, 0x0F, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0xCF, 0xFC, 0xFF, 0xCF, 0x3C, 0xF3, 0xFF, 0x3F,
0xF3, 0xF0, 0x07, 0x00, 0x70, 0x07, 0xF0, 0x7F, 0xF8, 0x3F, 0xFC, 0x1F, 0xFE, 0x0F, 0x0F, 0x07, 0x87, 0x83, 0xC3,
0xFF, 0xE1, 0xFF, 0xF0, 0xFF, 0xF8, 0x78, 0x3C, 0x3C, 0x1E, 0x1E, 0x0F, 0x0F, 0x07, 0x87, 0x83, 0xC3, 0xC1, 0xE0,
0xF3, 0xFF, 0x9F, 0xFC, 0xFF, 0xE7, 0x8F, 0xFC, 0x7F, 0xE3, 0xFF, 0x1E, 0x78, 0xF3, 0xC7, 0x9E, 0x3C, 0xF0, 0xFF,
0xF8, 0x03, 0xFF, 0xE0, 0x0F, 0xFF, 0x80, 0x3C, 0x1E, 0x00, 0xF0, 0x78, 0x03, 0xC1, 0xE0, 0x0F, 0x07, 0xFE, 0x3C,
0x1F, 0xFC, 0xF0, 0x7F, 0xFB, 0xC1, 0xE7, 0xEF, 0x07, 0x87, 0xFC, 0x1E, 0x0F, 0xF0, 0x78, 0x3F, 0xC1, 0xE0, 0xFF,
0x07, 0x87, 0xC0, 0x00, 0x3E, 0x00, 0x03, 0xF8, 0x00, 0x0F, 0xC0, 0x00, 0x3E, 0x00, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F,
0xF0, 0x1E, 0x78, 0x0F, 0x3F, 0xE7, 0x9F, 0xFB, 0xCF, 0xFD, 0xE7, 0x9F, 0xF3, 0xC7, 0xF9, 0xE3, 0xFC, 0xF1, 0xE0,
0x01, 0xF0, 0x03, 0xF8, 0x01, 0xF8, 0x00, 0xF8, 0x0F, 0xE0, 0x3F, 0xE0, 0x7F, 0xE0, 0x7E, 0x60, 0xF8, 0x00, 0xF1,
0xFC, 0xF3, 0xFE, 0xF3, 0xFE, 0xF7, 0xDE, 0xF7, 0x9E, 0xFF, 0x9E, 0xFF, 0xFE, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF0,
0x01, 0xFC, 0x01, 0xFE, 0x00, 0x7E, 0x00, 0x3E, 0x1F, 0xC1, 0xFE, 0x1F, 0xE0, 0xFF, 0xE7, 0x3F, 0xBB, 0xFD, 0xDC,
0xEF, 0xEF, 0x7F, 0xF9, 0xFF, 0x87, 0xF8, 0x07, 0xE0, 0x1F, 0x80, 0x7C, 0x1F, 0xF1, 0xFF, 0x9F, 0xFC, 0xFD, 0xEF,
0x80, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3E, 0x01, 0xFC, 0xE7, 0xFF, 0x1F, 0xF8, 0x7F, 0xC0, 0xF0,
0x07, 0x80, 0x5C, 0x03, 0xE0, 0x1F, 0x00, 0x1F, 0xCF, 0xF7, 0xFD, 0xF6, 0x78, 0x1E, 0x07, 0x81, 0xF3, 0x7F, 0xCF,
0xF0, 0xFC, 0x3C, 0x0F, 0x07, 0xC1, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x1F, 0x00, 0xF8, 0x07, 0xC0, 0x3E, 0x01,
0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0x00, 0xFE, 0x07, 0xF0, 0x3F, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78,
0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1F, 0x83, 0xF0, 0x7E, 0x01, 0xC0, 0x38, 0x07,
0x00, 0xF8, 0x7F, 0xE1, 0xE7, 0xCF, 0x9F, 0x3C, 0x3F, 0xF0, 0x7F, 0x81, 0xFE, 0x03, 0xF0, 0x0F, 0xC0, 0x1E, 0x00,
0x78, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x00, 0xF1, 0xFF, 0x1E, 0x79, 0xE7, 0xBE, 0x7B, 0xC3, 0xFC, 0x3F,
0x81, 0xF8, 0x1F, 0x81, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF8, 0x7F, 0xE1, 0xF7, 0xCF, 0x9F,
0x3C, 0x3F, 0xF0, 0xFF, 0x81, 0xFE, 0x03, 0xF0, 0x0F, 0xC0, 0xFF, 0xC3, 0xFF, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00,
0x78, 0x00, 0xF1, 0xFF, 0x1E, 0x79, 0xE7, 0xBE, 0x7B, 0xC3, 0xFC, 0x3F, 0x81, 0xF8, 0x1F, 0x87, 0xFC, 0x7F, 0xC0,
0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF8, 0x7C, 0xF9, 0xF1, 0xFB, 0xE1, 0xFF, 0x81, 0xFE, 0x03, 0xFC, 0x03, 0xF0,
0x03, 0xE0, 0x0F, 0xE0, 0x3F, 0xC0, 0xFF, 0xC1, 0xFF, 0xC7, 0xCF, 0xEF, 0x0F, 0xFE, 0x1F, 0x80, 0x0F, 0x00, 0x1E,
0x00, 0x3C, 0x00, 0x78, 0xF9, 0xE7, 0xBE, 0x7F, 0xC3, 0xF8, 0x1F, 0x81, 0xF0, 0x1F, 0x83, 0xFC, 0x7F, 0xF7, 0x9F,
0xF1, 0xF0, 0x07, 0x00, 0x70, 0x07, 0xFF, 0xF7, 0x8F, 0xFF, 0x78, 0xFF, 0xF7, 0x80, 0xF0, 0x78, 0x0F, 0x07, 0x80,
0xF0, 0x78, 0x0F, 0x07, 0x80, 0xF0, 0x78, 0x0F, 0x07, 0x80, 0xF0, 0x78, 0x0F, 0x07, 0x80, 0xF0, 0x78, 0x0F, 0xFF,
0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xF0, 0x00, 0x1F, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x01, 0xF0, 0xFF, 0x79, 0xFE,
0xF3, 0xFD, 0xE1, 0xE3, 0xC3, 0xC7, 0x87, 0x8F, 0x0F, 0x1E, 0x1E, 0x3C, 0x3F, 0xFE, 0x7F, 0xFC, 0xFF, 0xF8, 0x00,
0xF0, 0x01, 0xE0, 0x03, 0xC0, 0xF0, 0xF3, 0xC3, 0xCF, 0x0F, 0x3C, 0x3C, 0xF0, 0xF3, 0xC3, 0xCF, 0xCF, 0x3F, 0xFC,
0x7F, 0xF0, 0xFF, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03,
0xC0, 0xF1, 0xE7, 0x8F, 0x3C, 0x79, 0xE3, 0xCF, 0x9E, 0x7F, 0xF1, 0xFF, 0x87, 0xFC, 0x01, 0xF8, 0x0F, 0xC0, 0x7E,
0x00, 0xF0, 0x07, 0x80, 0x3C, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x6F, 0xFE, 0xFF, 0xFF, 0x7F, 0xF3,
0xFF, 0x06, 0xF0, 0x6F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0xF1, 0xFE, 0x3F, 0xC7, 0xFB, 0xFF, 0xFF, 0xFF, 0xDF, 0xF9,
0xFF, 0x07, 0xE0, 0xFC, 0x07, 0x80, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x7F, 0xF3, 0xFF, 0xDF, 0xFE,
0xF9, 0xFF, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3F,
0xEF, 0xFF, 0xFF, 0xF7, 0xFC, 0xFF, 0x3F, 0xCF, 0xF3, 0xFC, 0xFF, 0x3F, 0xCF, 0x01, 0xFE, 0x00, 0xFF, 0xCE, 0x7F,
0xFB, 0xBF, 0x3E, 0xFF, 0x07, 0xFF, 0xFF, 0xF7, 0xFF, 0xFC, 0xFF, 0xFF, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF8, 0x00,
0x1F, 0x9C, 0x07, 0xFF, 0x80, 0xFF, 0xE0, 0x0F, 0xF0, 0xC7, 0xF3, 0xBF, 0xEE, 0xFF, 0xFF, 0xDF, 0xFF, 0xFD, 0xFF,
0xF1, 0xE0, 0x07, 0xEE, 0x0F, 0xF8, 0x1F, 0xF0, 0x3F, 0xC0, 0x01, 0xFE, 0x00, 0xFF, 0xC0, 0x7F, 0xFB, 0x9F, 0xFE,
0xEF, 0x87, 0xBF, 0xC1, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0x3F, 0xFF, 0xC3, 0xC0, 0x00, 0xF8, 0x00, 0x3F, 0x9C, 0x07,
0xFF, 0x80, 0xFF, 0xE0, 0x1F, 0xF0, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x03, 0xF3, 0x1F, 0xEE,
0xFF, 0xFB, 0xFF, 0xFE, 0x3F, 0xFF, 0xF7, 0xFF, 0xC7, 0xEE, 0x0F, 0xF8, 0x3F, 0xF0, 0x7F, 0xC0, 0x78, 0x01, 0xE0,
0x07, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x01, 0x9C, 0x00, 0x1E, 0xE0, 0x00, 0x7F, 0x00, 0x01,
0xF0, 0x00, 0x00, 0x00, 0x7C, 0x78, 0x7D, 0xF3, 0xC7, 0xCF, 0xDE, 0x7C, 0x3E, 0xF7, 0xC0, 0xFF, 0xBE, 0x03, 0xFF,
0xE0, 0x0F, 0xFE, 0x00, 0x7F, 0xE0, 0x07, 0xFF, 0x80, 0x7F, 0xFE, 0x03, 0xFE, 0xF8, 0x3E, 0xF3, 0xE3, 0xE7, 0x9F,
0x1E, 0x3C, 0x7D, 0xF1, 0xE1, 0xF0, 0x07, 0x30, 0x01, 0xFE, 0x00, 0x7F, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x0F, 0x9E, 0x7D, 0xF7, 0xBE, 0x3F, 0xFF, 0x0F, 0xFF, 0x81, 0xFF, 0xE0, 0x3F, 0xF0, 0x1F, 0xFE, 0x0F, 0xFF, 0xC7,
0xDE, 0xF1, 0xE7, 0xBE, 0xF9, 0xE7, 0xC0, 0xF0, 0xFF, 0x8F, 0xBC, 0xF9, 0xEF, 0x8F, 0x78, 0x7F, 0xC3, 0xFF, 0x1F,
0xFC, 0xFF, 0xF7, 0x9F, 0xBC, 0x3F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC3, 0xE0, 0x3E, 0x07, 0xF0, 0x3F, 0x01, 0xF0,
0xF3, 0xFE, 0xFB, 0xDE, 0x7F, 0x8F, 0xF1, 0xFF, 0x3F, 0xF7, 0xBE, 0xF1, 0xFE, 0x3F, 0xC7, 0x80, 0xF0, 0x3C, 0x1F,
0x83, 0xE0, 0x0F, 0xFE, 0x03, 0xFF, 0x80, 0xFF, 0xE0, 0x3C, 0x78, 0x0F, 0x1E, 0x03, 0xC7, 0x80, 0xF1, 0xE0, 0x3C,
0x78, 0x0F, 0x1E, 0x07, 0xC7, 0x81, 0xE1, 0xE3, 0xF8, 0x78, 0xFC, 0x1F, 0xBF, 0x07, 0xEF, 0x01, 0xF8, 0x00, 0x1E,
0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0x60, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xBC, 0x1E, 0xF0, 0x7B, 0xC3, 0xEF,
0x3F, 0x3C, 0xFC, 0xFF, 0xE3, 0xFF, 0x0F, 0xC0, 0x0E, 0x00, 0x78, 0x01, 0xC0, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0,
0xFF, 0x07, 0xF8, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xE0,
0x0F, 0x01, 0xF8, 0x0F, 0xC0, 0xFC, 0xF1, 0xFE, 0x3F, 0xC7, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0xF1, 0xFE,
0x3F, 0xC7, 0x81, 0xF0, 0xFC, 0x1F, 0x83, 0xE0, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0,
0x78, 0xFF, 0xF8, 0xFF, 0xF8, 0xFF, 0xF8, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x7E, 0xF0, 0x7E, 0xF0, 0x7E,
0x00, 0x1E, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x18, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0xCF, 0xFC, 0xFF, 0xCF,
0x3C, 0xF3, 0xFF, 0x3F, 0xF3, 0xF0, 0x0E, 0x01, 0xE0, 0x1C, 0xF8, 0x7F, 0xC3, 0xFE, 0x1F, 0xF0, 0xFF, 0x87, 0xFC,
0x3D, 0xF3, 0xEF, 0xFF, 0x7F, 0xF8, 0xFF, 0xC0, 0x1E, 0x00, 0xF0, 0x3F, 0x81, 0xFC, 0x0F, 0xE0, 0x78, 0x03, 0xC0,
0x1E, 0x00, 0xF0, 0xF9, 0xFF, 0x3F, 0xE7, 0xBC, 0xF7, 0xFE, 0xFF, 0xCF, 0xF8, 0x0F, 0x01, 0xE0, 0xFC, 0x1F, 0x83,
0x80, 0x70, 0x0E, 0x00, 0x78, 0x0F, 0x0F, 0x83, 0xE1, 0xF0, 0x7C, 0x3F, 0x1F, 0x8F, 0xE3, 0xF1, 0xFE, 0xFE, 0x3F,
0xDF, 0xE7, 0xBB, 0xBC, 0xF7, 0xF7, 0x9E, 0xFC, 0xF3, 0xCF, 0x9E, 0x79, 0xF3, 0xCF, 0x1C, 0x7F, 0xE0, 0x0F, 0xFC,
0x01, 0xF8, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x0E, 0x00, 0xF0, 0x78, 0xF8, 0x78, 0xF8, 0xF8, 0xFC,
0xF8, 0xFD, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xBC, 0xF7, 0xBF, 0xF7, 0xBF, 0xF0, 0x3E, 0x00, 0x1E, 0x00, 0x1E,
0x00, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0C, 0xE0, 0x3D, 0xC0, 0x3F, 0x80, 0x3E, 0x00, 0x00,
0x00, 0xF8, 0x01, 0xF0, 0x07, 0xF0, 0x0F, 0xE0, 0x1F, 0xE0, 0x7B, 0xC0, 0xF7, 0x83, 0xE7, 0x87, 0x8F, 0x0F, 0xFE,
0x3F, 0xFE, 0x7F, 0xFC, 0xF0, 0x7F, 0xE0, 0xFF, 0x80, 0xF0, 0x39, 0x87, 0xF8, 0xFE, 0x0F, 0xC0, 0x00, 0x00, 0x1F,
0xE3, 0xFE, 0x3F, 0xC6, 0x7C, 0xFF, 0xBF, 0xFF, 0x9F, 0xF3, 0xFF, 0xFB, 0xFF, 0x3F, 0xE0, 0x1E, 0xF0, 0x3D, 0xE0,
0x7B, 0xC0, 0x00, 0x00, 0x7C, 0x00, 0xF8, 0x03, 0xF8, 0x07, 0xF0, 0x0F, 0xF0, 0x3D, 0xE0, 0x7B, 0xC1, 0xF3, 0xC3,
0xC7, 0x87, 0xFF, 0x1F, 0xFF, 0x3F, 0xFE, 0x78, 0x3F, 0xF0, 0x7F, 0xC0, 0x78, 0x7B, 0xCF, 0x79, 0xEF, 0x00, 0x00,
0x00, 0xFF, 0x1F, 0xF1, 0xFE, 0x33, 0xE7, 0xFD, 0xFF, 0xFC, 0xFF, 0x9F, 0xFF, 0xDF, 0xF9, 0xFF, 0x00, 0xFF, 0xF0,
0x07, 0xFF, 0x80, 0x7F, 0xFC, 0x07, 0xF8, 0x00, 0x3F, 0xC0, 0x03, 0xDE, 0x00, 0x1E, 0xFF, 0x81, 0xE7, 0xFC, 0x1F,
0x3F, 0xE0, 0xFF, 0xE0, 0x0F, 0xFF, 0x00, 0x7F, 0xF8, 0x07, 0xC3, 0xFF, 0xBC, 0x1F, 0xFF, 0xE0, 0xFF, 0xE0, 0x7F,
0xFF, 0x1F, 0xFF, 0xE3, 0xFF, 0xF8, 0xCF, 0xDF, 0x3F, 0xFF, 0xDF, 0xFF, 0xFF, 0x9E, 0x03, 0xE7, 0xEE, 0xFF, 0xFF,
0x9F, 0xFF, 0xE3, 0xFF, 0xF8, 0x39, 0x87, 0x78, 0xFE, 0x0F, 0x80, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x1E, 0x03,
0xC0, 0x7F, 0xEF, 0xFD, 0xFF, 0xBC, 0x07, 0x80, 0xF0, 0x1F, 0xFF, 0xFF, 0xFF, 0xF0, 0x19, 0xC3, 0xDC, 0x1F, 0xC0,
0xF8, 0x00, 0x00, 0x00, 0x1F, 0xC3, 0xFE, 0x7F, 0xE7, 0xDF, 0x7F, 0xF7, 0xFF, 0x78, 0x07, 0xEE, 0x7F, 0xE3, 0xFE,
0x1F, 0xE0, 0x7F, 0xC1, 0xFF, 0x87, 0xFF, 0x1E, 0x7E, 0x00, 0x78, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1,
0xFF, 0x07, 0xBF, 0x7E, 0x7F, 0xF0, 0xFF, 0xC1, 0xFC, 0x00, 0x7F, 0x87, 0xFC, 0x7F, 0xE3, 0x3E, 0x01, 0xF7, 0xFF,
0x7F, 0xF7, 0x9E, 0x7F, 0xE7, 0xFC, 0x1F, 0x80, 0x3D, 0xC0, 0xF7, 0x83, 0xDC, 0x00, 0x00, 0x7F, 0xC1, 0xFF, 0x87,
0xFF, 0x1E, 0x7E, 0x00, 0x78, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0x07, 0xBF, 0x7E, 0x7F, 0xF0,
0xFF, 0xC1, 0xFC, 0x00, 0x39, 0xC3, 0xFC, 0x39, 0xC0, 0x00, 0x00, 0x07, 0xF8, 0x7F, 0xC7, 0xFE, 0x33, 0xE0, 0x1F,
0x7F, 0xF7, 0xFF, 0x79, 0xE7, 0xFE, 0x7F, 0xC1, 0xF8, 0x03, 0xDC, 0x00, 0x1E, 0xF0, 0x00, 0xF7, 0x00, 0x00, 0x00,
0x0F, 0x8F, 0x0F, 0xBE, 0x78, 0xF9, 0xFB, 0xCF, 0x87, 0xDE, 0xF8, 0x1F, 0xF7, 0xC0, 0x7F, 0xFC, 0x01, 0xFF, 0xC0,
0x0F, 0xFC, 0x00, 0xFF, 0xF0, 0x0F, 0xFF, 0xC0, 0x7F, 0xDF, 0x07, 0xDE, 0x7C, 0x7C, 0xF3, 0xE3, 0xC7, 0x8F, 0xBE,
0x3C, 0x3E, 0x07, 0x78, 0x01, 0xFE, 0x00, 0x77, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x79, 0xF7, 0xDE, 0xF8, 0xFF,
0xFC, 0x3F, 0xFE, 0x07, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xF8, 0x3F, 0xFF, 0x1F, 0x7B, 0xC7, 0x9E, 0xFB, 0xE7, 0x9F,
0x3B, 0xC3, 0xFC, 0x3B, 0xC0, 0x00, 0x00, 0x07, 0xFC, 0x7F, 0xE7, 0xFE, 0x7B, 0xF0, 0x1F, 0x03, 0xE1, 0xFE, 0x1F,
0xE1, 0xFF, 0x03, 0xF0, 0x0F, 0x7B, 0xF7, 0xFF, 0xFF, 0xE7, 0xFC, 0x77, 0xBD, 0xE7, 0x78, 0x00, 0x00, 0x1F, 0xC7,
0xF9, 0xFF, 0x77, 0xCF, 0xE3, 0xF8, 0x1F, 0x77, 0xDF, 0xFF, 0xFF, 0xFE, 0x7F, 0xF7, 0xFF, 0x7F, 0xF0, 0x3E, 0x07,
0xC0, 0xF8, 0x1F, 0xC1, 0xFE, 0x03, 0xF0, 0x0F, 0x00, 0xF7, 0xBF, 0xFF, 0xFF, 0xFE, 0x7F, 0xC0, 0xFF, 0xFF, 0xFF,
0xFC, 0x1E, 0x0F, 0x07, 0x83, 0xF0, 0xFE, 0x0F, 0xC0, 0xF0, 0x3F, 0x9F, 0xFF, 0xFF, 0xEF, 0xF0, 0x1F, 0xE0, 0x7F,
0x80, 0x00, 0x3C, 0x1F, 0xF0, 0x7F, 0xC3, 0xFF, 0x1F, 0xFC, 0xFF, 0xF3, 0xFF, 0xDE, 0xFF, 0xFB, 0xFF, 0xCF, 0xFE,
0x3F, 0xF8, 0xFF, 0xC3, 0xFE, 0x0F, 0xF8, 0x3F, 0xC0, 0xF0, 0x3F, 0x87, 0xF0, 0x00, 0x00, 0x0F, 0x1F, 0xE7, 0xFD,
0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x9F, 0xF3, 0xFC, 0x78, 0x1E, 0xE0, 0x7B, 0xC1, 0xEE, 0x00, 0x00,
0xF0, 0x7F, 0xC1, 0xFF, 0x0F, 0xFC, 0x7F, 0xF3, 0xFF, 0xCF, 0xFF, 0x7B, 0xFF, 0xEF, 0xFF, 0x3F, 0xF8, 0xFF, 0xE3,
0xFF, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x03, 0xC0, 0x3B, 0xCF, 0x78, 0xEF, 0x00, 0x00, 0x01, 0xE3, 0xFC, 0xFF, 0xBF,
0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xF3, 0xFE, 0x7F, 0x8F, 0x1E, 0xE0, 0x3D, 0xE0, 0x7B, 0x80, 0x00, 0x01,
0xFE, 0x07, 0xFF, 0x1F, 0xFF, 0x3F, 0x7E, 0xF8, 0x3D, 0xE0, 0x7F, 0xC0, 0x7F, 0x80, 0xFF, 0x01, 0xFE, 0x07, 0xFE,
0x0F, 0xFF, 0x7E, 0x7F, 0xFC, 0x7F, 0xF0, 0x7F, 0x80, 0x3D, 0xE3, 0xDE, 0x3D, 0xE0, 0x00, 0x00, 0x01, 0xFC, 0x3F,
0xE7, 0xFF, 0x7D, 0xF7, 0x8F, 0x78, 0xF7, 0x8F, 0x7D, 0xF7, 0xFF, 0x3F, 0xE1, 0xFC, 0x1F, 0xE0, 0x7F, 0xF1, 0xFF,
0xF3, 0xF7, 0xEF, 0x83, 0xDE, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xE0, 0x7F, 0xE0, 0xFF, 0xF7, 0xE7, 0xFF,
0xC7, 0xFF, 0x07, 0xF8, 0x00, 0x1F, 0xC3, 0xFE, 0x7F, 0xF7, 0xDF, 0x7F, 0xF7, 0xFF, 0x78, 0xF7, 0xDF, 0x7F, 0xF3,
0xFE, 0x1F, 0xC0, 0x1E, 0xE0, 0x3D, 0xE0, 0x7B, 0x80, 0x00, 0x01, 0xFE, 0x07, 0xFF, 0x1F, 0xFF, 0x3F, 0x7E, 0xF8,
0x3D, 0xE0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFE, 0x07, 0xFE, 0x0F, 0xFF, 0x7E, 0x7F, 0xFC, 0x7F, 0xF0, 0x7F,
0x80, 0x3D, 0xC3, 0xDE, 0x3D, 0xC0, 0x00, 0x00, 0x01, 0xFC, 0x3F, 0xE7, 0xFF, 0x7D, 0xF7, 0xFF, 0x7F, 0xF7, 0x8F,
0x7D, 0xF7, 0xFF, 0x3F, 0xE1, 0xFC, 0x3D, 0xE0, 0xF7, 0x83, 0xDE, 0x00, 0x00, 0x7F, 0xC1, 0xFF, 0x87, 0xFF, 0x1E,
0xFE, 0x00, 0x78, 0x01, 0xE1, 0xFF, 0xC7, 0xFF, 0x1F, 0xFC, 0x01, 0xF0, 0x07, 0x9E, 0xFE, 0x7F, 0xF1, 0xFF, 0x87,
0xFC, 0x00, 0x7B, 0x8F, 0x79, 0xEE, 0x00, 0x00, 0x00, 0xFE, 0x1F, 0xE3, 0xFE, 0x77, 0xC7, 0xFC, 0xFF, 0x81, 0xF7,
0x7C, 0xFF, 0xBF, 0xE7, 0xF8, 0x1F, 0xE0, 0x7F, 0x80, 0x00, 0x3E, 0x1F, 0x78, 0x79, 0xF1, 0xE3, 0xCF, 0x8F, 0xBC,
0x1E, 0xF0, 0x7F, 0xC0, 0xFE, 0x03, 0xF8, 0x07, 0xC0, 0x1F, 0x06, 0xF8, 0x1F, 0xE0, 0x7F, 0x01, 0xF8, 0x00, 0x3F,
0xC3, 0xFC, 0x00, 0x00, 0x00, 0xF1, 0xFF, 0x1E, 0x79, 0xE7, 0x9E, 0x7B, 0xC3, 0xFC, 0x3F, 0xC3, 0xF8, 0x1F, 0x81,
0xF0, 0x0F, 0x0D, 0xF0, 0xFE, 0x0F, 0xC0, 0xF8, 0x00, 0x1E, 0xE0, 0x7B, 0xC1, 0xEE, 0x00, 0x00, 0xF8, 0x7D, 0xE1,
0xE7, 0xC7, 0x8F, 0x3E, 0x3E, 0xF0, 0x7B, 0xC1, 0xFF, 0x03, 0xF8, 0x0F, 0xE0, 0x1F, 0x00, 0x7C, 0x1B, 0xE0, 0x7F,
0x81, 0xFC, 0x07, 0xE0, 0x00, 0x3B, 0xC7, 0xBC, 0x3B, 0xC0, 0x00, 0x00, 0x0F, 0x1F, 0xF1, 0xE7, 0x9E, 0x79, 0xE7,
0xBC, 0x3F, 0xC3, 0xFC, 0x3F, 0x81, 0xF8, 0x1F, 0x00, 0xF0, 0xDF, 0x0F, 0xE0, 0xFC, 0x0F, 0x80, 0x07, 0x70, 0x3D,
0xC0, 0xEF, 0x07, 0xF8, 0x1C, 0xC0, 0x00, 0x0F, 0x87, 0xDE, 0x1E, 0x7C, 0x78, 0xF3, 0xE3, 0xEF, 0x07, 0xBC, 0x1F,
0xF0, 0x3F, 0x80, 0xFE, 0x01, 0xF0, 0x07, 0xC1, 0xBE, 0x07, 0xF8, 0x1F, 0xC0, 0x7E, 0x00, 0x0C, 0xE1, 0xFE, 0x3D,
0xC3, 0xB8, 0x33, 0x80, 0x00, 0xF1, 0xFF, 0x1E, 0x79, 0xE7, 0x9E, 0x7B, 0xC3, 0xFC, 0x3F, 0xC3, 0xF8, 0x1F, 0x81,
0xF0, 0x0F, 0x0D, 0xF0, 0xFE, 0x0F, 0xC0, 0xF8, 0x00, 0x1D, 0xE1, 0xEF, 0x07, 0x78, 0x00, 0x0F, 0x87, 0xFC, 0x3F,
0xE1, 0xFF, 0x0F, 0xF8, 0x7F, 0xC3, 0xDF, 0x3E, 0xFF, 0xF7, 0xFF, 0x8F, 0xFC, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03,
0xC0, 0x1E, 0x3B, 0xCF, 0x78, 0xEF, 0x00, 0x00, 0x01, 0xF3, 0xFE, 0x7F, 0xCF, 0x79, 0xEF, 0x3D, 0xFF, 0xBF, 0xF3,
0xFE, 0x03, 0xC0, 0x78, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03,
0xC0, 0x78, 0x0F, 0xE1, 0xFC, 0x3F, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x0F, 0x07,
0x83, 0xC1, 0xE0, 0xFC, 0x7E, 0x3F, 0x03, 0x81, 0xC0, 0xE0, 0x07, 0x78, 0x03, 0xFC, 0x01, 0xDE, 0x00, 0x00, 0x0F,
0x00, 0x7F, 0x80, 0x3F, 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xFF, 0xE3, 0xFF, 0xF9, 0xFF, 0xFE, 0xFF, 0x3F, 0x7F,
0x87, 0xBF, 0xC3, 0xDF, 0xE7, 0xEF, 0xFF, 0xF7, 0xFF, 0xF3, 0xFF, 0xE1, 0xE0, 0x0E, 0xF0, 0x3D, 0xE0, 0x3B, 0xC0,
0x00, 0x00, 0x00, 0x1E, 0x03, 0xFC, 0x07, 0xF8, 0x0F, 0xF0, 0x1F, 0xFF, 0x3F, 0xFF, 0x7F, 0xFE, 0xFF, 0x3F, 0xFF,
0xFB, 0xFF, 0xF7, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x3B, 0xDE, 0xEF, 0x78, 0x7B, 0xDF, 0xEF, 0x70, 0x7B, 0xDF, 0xEF, 0x70,
0x3B, 0xDE, 0xE7, 0xF9, 0xDE, 0xF7, 0xBD, 0xE0, 0x7F, 0xBF, 0xDD, 0xFE, 0xFF, 0x77, 0x38, 0x7F, 0xBF, 0xDD, 0xFE,
0xFF, 0x77, 0x38, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0xFF, 0xFF, 0xFF, 0xFC, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E,
0x03, 0x80, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0xFF, 0xFF, 0xFF, 0xFC, 0x78, 0x1E, 0x07,
0x8F, 0xFF, 0xFF, 0xFF, 0xC7, 0x80, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0x7C, 0xFF, 0xFF, 0xF7, 0xEF, 0x80, 0xF0, 0xE1,
0xFF, 0x3E, 0x7F, 0xE7, 0xCF, 0xF8, 0x70, 0xF0, 0x3E, 0x1E, 0x00, 0x0F, 0xE3, 0xC0, 0x01, 0xDC, 0xF0, 0x00, 0x7B,
0xDE, 0x00, 0x0F, 0x7F, 0x80, 0x00, 0xEE, 0xF0, 0x00, 0x1F, 0xFC, 0x00, 0x01, 0xF7, 0xFE, 0x7E, 0x01, 0xFF, 0xCF,
0xE0, 0x3B, 0xFF, 0xFC, 0x0F, 0x73, 0xF3, 0x83, 0xCE, 0x7E, 0x70, 0x79, 0xFF, 0xFE, 0x1E, 0x3F, 0x9F, 0xC3, 0xC3,
0xF3, 0xF0, 0x00, 0x38, 0xF3, 0xE7, 0x9F, 0x1E, 0x3E, 0x3C, 0x38, 0x00, 0x00, 0xE3, 0xE3, 0xE3, 0xC7, 0xCF, 0x3E,
0xF8, 0xE0, 0x00, 0x01, 0xE0, 0x3C, 0x0F, 0x01, 0xE0, 0x78, 0x0F, 0x03, 0xC0, 0x78, 0x1E, 0x03, 0xC0, 0xF0, 0x1E,
0x07, 0x80, 0xF0, 0x3C, 0x00, 0x07, 0xF0, 0xFF, 0x1F, 0xF1, 0xF6, 0x3C, 0x07, 0xFE, 0x7F, 0xC3, 0xC0, 0x7F, 0xC7,
0xFC, 0x3C, 0x03, 0xF7, 0x1F, 0xF0, 0xFF, 0x07, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0x0F, 0xC0, 0xFC, 0x1F,
0xC3, 0xF0, 0x3F, 0xC3, 0xFC, 0x1F, 0xC3, 0xF0, 0x3F, 0x03, 0xF0, 0x0F, 0x00, 0x3F, 0x87, 0xFC, 0x3F, 0xE3, 0xBE,
0xFF, 0xFF, 0xFF, 0x1F, 0x83, 0xF0, 0xFF, 0xFF, 0xFF, 0x78, 0x07, 0xDE, 0x7F, 0xE3, 0xFE, 0x1F, 0xE0, 0xFF, 0xFF,
0xFF, 0xC1, 0xF0, 0x07, 0xCF, 0xFF, 0x7F, 0xF8, 0x0F, 0x01, 0xF8, 0xFF, 0x87, 0xF8, 0x1F, 0x00, 0x7C, 0x01, 0xF0,
0x07, 0xC0, 0x1F, 0x00, 0x3F, 0x83, 0xFC, 0x3F, 0xE3, 0xBF, 0x00, 0xF1, 0xFF, 0x3F, 0xF7, 0xFF, 0x7D, 0xFF, 0x0F,
0xF0, 0xFF, 0xBE, 0x7F, 0xE7, 0xFC, 0x3F, 0x80, 0x07, 0x80, 0x0F, 0x80, 0x3F, 0x00, 0x7F, 0x01, 0xFE, 0x03, 0xDC,
0x07, 0xBC, 0x1E, 0x78, 0x3C, 0x78, 0x78, 0xF1, 0xE1, 0xE3, 0xC1, 0xE7, 0xFF, 0xDF, 0xFF, 0xBF, 0xFF, 0x80, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xFC, 0x1F, 0xE0, 0xFF,
0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x78, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0x07, 0xC0, 0x7C, 0x07, 0x80, 0xF8,
0x0F, 0x83, 0xE0, 0x78, 0x1E, 0x07, 0xC0, 0xF0, 0x3F, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, 0xE0,
0x3C, 0x0F, 0x01, 0xE0, 0x78, 0x0F, 0x03, 0xC0, 0x78, 0x1E, 0x03, 0xC0, 0xF0, 0x1E, 0x07, 0x80, 0xF0, 0x3C, 0x00,
0x77, 0xFE, 0xE0, 0x00, 0x3C, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x70, 0x03, 0xC0, 0x0F, 0x0F, 0x38, 0xFD, 0xE3,
0xF7, 0x87, 0xFC, 0x07, 0xF0, 0x0F, 0xC0, 0x3E, 0x00, 0x78, 0x00, 0x7D, 0xF3, 0xFF, 0xFF, 0xFF, 0xEE, 0x7F, 0xFF,
0xBF, 0xFD, 0xF7, 0xC0, 0x00, 0x07, 0xC7, 0xE7, 0xF3, 0xE1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1,
0xE0, 0xF0, 0x78, 0x7C, 0x7E, 0x3F, 0x1F, 0x00, 0x00, 0x3C, 0x77, 0xFF, 0x7F, 0xEF, 0xFE, 0xE3, 0xC0, 0x00, 0x3C,
0x77, 0xFF, 0x7F, 0xEF, 0xFE, 0xE3, 0xC0, 0x03, 0x80, 0xE0, 0x7B, 0xFF, 0xFF, 0xFF, 0xF0, 0xE0, 0x70, 0xFF, 0xFF,
0xFF, 0xFD, 0xC0, 0x70, 0x1C, 0x00, 0x07, 0xDF, 0xFF, 0xFF, 0xFE, 0xF8, 0x3F, 0xEF, 0xFD, 0xFF, 0x07, 0xC0, 0x0F,
0xFF, 0xFF, 0xFF, 0xC0, 0xF8, 0x3F, 0xCF, 0xFD, 0xFF, 0x0F, 0xDF, 0xFF, 0xFF, 0xFE, 0xF8, 0x00, 0x0F, 0xFF, 0xFF,
0xFF, 0xC0,
};
static const EpdGlyph ubuntu_bold_10Glyphs[] = {
@ -758,54 +1059,269 @@ static const EpdGlyph ubuntu_bold_10Glyphs[] = {
{10, 17, 11, 0, 17, 22, 7407}, // ž
{9, 16, 7, 1, 16, 18, 7429}, // ſ
{8, 3, 8, 0, 15, 3, 7447}, // ̑
{11, 3, 11, 0, 8, 5, 7450}, //
{21, 3, 21, 0, 8, 8, 7455}, // —
{21, 3, 21, 0, 8, 8, 7463}, // ―
{5, 6, 5, 0, 16, 4, 7471}, //
{5, 6, 5, 0, 16, 4, 7475}, //
{5, 6, 5, 0, 3, 4, 7479}, //
{10, 6, 10, 0, 16, 8, 7483}, // “
{9, 6, 10, 0, 16, 7, 7491}, // ”
{9, 6, 10, 0, 3, 7, 7498}, // „
{10, 18, 10, 0, 15, 23, 7505}, // †
{10, 18, 10, 0, 15, 23, 7528}, // ‡
{7, 6, 8, 0, 10, 6, 7551}, // •
{19, 4, 21, 1, 4, 10, 7557}, // …
{27, 15, 28, 0, 15, 51, 7567}, // ‰
{7, 11, 7, 0, 11, 10, 7618}, //
{7, 11, 7, 0, 11, 10, 7628}, //
{11, 15, 3, -4, 15, 21, 7638}, //
{12, 15, 12, 0, 15, 23, 7659}, // €
{12, 15, 12, 0, 15, 23, 7682}, // ₮
{12, 15, 12, 0, 15, 23, 7705}, // ₴
{13, 15, 12, 0, 15, 25, 7728}, // ₹
{12, 15, 13, 0, 15, 23, 7753}, // ∂
{15, 15, 15, 0, 15, 29, 7776}, // ∆
{13, 17, 15, 1, 15, 28, 7805}, // ∏
{11, 17, 11, 0, 15, 24, 7833}, // ∑
{10, 3, 12, 1, 8, 4, 7857}, //
{11, 15, 3, -4, 15, 21, 7861}, //
{5, 4, 5, 0, 9, 3, 7882}, // ∙
{14, 15, 13, 0, 15, 27, 7885}, // √
{13, 7, 13, 0, 10, 12, 7912}, // ∞
{9, 21, 8, 0, 16, 24, 7924}, // ∫
{12, 11, 12, 0, 12, 17, 7948}, // ≈
{10, 14, 12, 1, 14, 18, 7965}, // ≠
{10, 13, 12, 1, 13, 17, 7983}, // ≤
{10, 13, 12, 1, 13, 17, 8000}, // ≥
{11, 21, 13, 1, 21, 29, 7450}, // Ѐ
{11, 20, 13, 1, 20, 28, 7479}, // Ё
{17, 15, 17, 0, 15, 32, 7507}, // Ђ
{11, 21, 12, 1, 21, 29, 7539}, // Ѓ
{13, 15, 14, 1, 15, 25, 7568}, // Є
{12, 15, 12, 0, 15, 23, 7593}, // Ѕ
{4, 15, 7, 1, 15, 8, 7616}, // І
{9, 19, 7, -1, 19, 22, 7624}, // Ї
{10, 15, 11, 0, 15, 19, 7646}, // Ј
{23, 15, 24, 0, 15, 44, 7665}, // Љ
{21, 15, 23, 1, 15, 40, 7709}, // Њ
{16, 15, 16, 0, 15, 30, 7749}, // Ћ
{14, 21, 14, 1, 21, 37, 7779}, // Ќ
{14, 21, 16, 1, 21, 37, 7816}, // Ѝ
{14, 20, 14, 0, 20, 35, 7853}, // Ў
{13, 19, 15, 1, 15, 31, 7888}, // Џ
{15, 15, 15, 0, 15, 29, 7919}, // А
{12, 15, 14, 1, 15, 23, 7948}, // Б
{13, 15, 14, 1, 15, 25, 7971}, // В
{11, 15, 12, 1, 15, 21, 7996}, // Г
{17, 19, 17, 0, 15, 41, 8017}, // Д
{11, 15, 13, 1, 15, 21, 8058}, // Е
{21, 15, 21, 0, 15, 40, 8079}, // Ж
{12, 15, 13, 0, 15, 23, 8119}, // З
{14, 15, 16, 1, 15, 27, 8142}, // И
{14, 20, 16, 1, 20, 35, 8169}, // Й
{14, 15, 14, 1, 15, 27, 8204}, // К
{15, 15, 17, 0, 15, 29, 8231}, // Л
{17, 15, 19, 1, 15, 32, 8260}, // М
{13, 15, 15, 1, 15, 25, 8292}, // Н
{15, 15, 17, 1, 15, 29, 8317}, // О
{13, 15, 15, 1, 15, 25, 8346}, // П
{12, 15, 14, 1, 15, 23, 8371}, // Р
{13, 15, 14, 1, 15, 25, 8394}, // С
{13, 15, 13, 0, 15, 25, 8419}, // Т
{14, 15, 14, 0, 15, 27, 8444}, // У
{18, 16, 18, 0, 16, 36, 8471}, // Ф
{14, 15, 14, 0, 15, 27, 8507}, // Х
{16, 19, 17, 1, 15, 38, 8534}, // Ц
{13, 15, 14, 0, 15, 25, 8572}, // Ч
{19, 15, 21, 1, 15, 36, 8597}, // Ш
{22, 19, 23, 1, 15, 53, 8633}, // Щ
{16, 15, 16, 0, 15, 30, 8686}, // Ъ
{17, 15, 19, 1, 15, 32, 8716}, // Ы
{12, 15, 14, 1, 15, 23, 8748}, // Ь
{14, 15, 14, 0, 15, 27, 8771}, // Э
{21, 15, 23, 1, 15, 40, 8798}, // Ю
{13, 15, 14, 0, 15, 25, 8838}, // Я
{11, 11, 12, 0, 11, 16, 8863}, // а
{12, 16, 13, 0, 16, 24, 8879}, // б
{11, 11, 13, 1, 11, 16, 8903}, // в
{9, 11, 10, 1, 11, 13, 8919}, // г
{14, 14, 14, 0, 11, 25, 8932}, // д
{12, 11, 12, 0, 11, 17, 8957}, // е
{18, 11, 18, 0, 11, 25, 8974}, // ж
{10, 11, 10, 0, 11, 14, 8999}, // з
{11, 11, 13, 1, 11, 16, 9013}, // и
{11, 17, 13, 1, 17, 24, 9029}, // й
{12, 11, 12, 1, 11, 17, 9053}, // к
{12, 11, 13, 0, 11, 17, 9070}, // л
{14, 11, 16, 1, 11, 20, 9087}, // м
{10, 11, 12, 1, 11, 14, 9107}, // н
{12, 11, 13, 0, 11, 17, 9121}, // о
{10, 11, 12, 1, 11, 14, 9138}, // п
{11, 15, 13, 1, 11, 21, 9152}, // р
{10, 11, 11, 0, 11, 14, 9173}, // с
{11, 11, 11, 0, 11, 16, 9187}, // т
{12, 15, 11, 0, 11, 23, 9203}, // у
{16, 20, 17, 0, 16, 40, 9226}, // ф
{12, 11, 12, 0, 11, 17, 9266}, // х
{12, 14, 13, 1, 11, 21, 9283}, // ц
{11, 11, 12, 0, 11, 16, 9304}, // ч
{16, 11, 18, 1, 11, 22, 9320}, // ш
{18, 14, 19, 1, 11, 32, 9342}, // щ
{13, 11, 13, 0, 11, 18, 9374}, // ъ
{15, 11, 17, 1, 11, 21, 9392}, // ы
{11, 11, 12, 1, 11, 16, 9413}, // ь
{11, 11, 11, 0, 11, 16, 9429}, // э
{17, 11, 18, 1, 11, 24, 9445}, // ю
{11, 11, 12, 0, 11, 16, 9469}, // я
{12, 17, 12, 0, 17, 26, 9485}, // ѐ
{12, 16, 12, 0, 16, 24, 9511}, // ё
{12, 20, 13, 0, 16, 30, 9535}, // ђ
{9, 17, 10, 1, 17, 20, 9565}, // ѓ
{11, 11, 11, 0, 11, 16, 9585}, // є
{10, 11, 10, 0, 11, 14, 9601}, // ѕ
{4, 16, 6, 1, 16, 8, 9615}, // і
{9, 16, 6, -2, 16, 18, 9623}, // ї
{7, 20, 6, -2, 16, 18, 9641}, // ј
{19, 11, 19, 0, 11, 27, 9659}, // љ
{17, 11, 18, 1, 11, 24, 9686}, // њ
{12, 16, 13, 0, 16, 24, 9710}, // ћ
{12, 17, 12, 1, 17, 26, 9734}, // ќ
{11, 17, 13, 1, 17, 24, 9760}, // ѝ
{12, 21, 11, 0, 17, 32, 9784}, // ў
{10, 14, 12, 1, 11, 18, 9816}, // џ
{15, 16, 16, 0, 16, 30, 9834}, // Ѣ
{13, 16, 13, 0, 16, 26, 9864}, // ѣ
{15, 15, 17, 1, 15, 29, 9890}, // Ѳ
{12, 11, 13, 0, 11, 17, 9919}, // ѳ
{18, 15, 17, 0, 15, 34, 9936}, // Ѵ
{13, 11, 13, 0, 11, 18, 9970}, // ѵ
{16, 23, 17, 1, 19, 46, 9988}, // Ҋ
{13, 19, 13, 1, 16, 31, 10034}, // ҋ
{13, 15, 14, 0, 15, 25, 10065}, // Ҍ
{12, 11, 12, 0, 11, 17, 10090}, // ҍ
{12, 15, 14, 1, 15, 23, 10107}, // Ҏ
{11, 15, 13, 1, 11, 21, 10130}, // ҏ
{11, 18, 12, 1, 18, 25, 10151}, // Ґ
{9, 14, 10, 1, 14, 16, 10176}, // ґ
{12, 15, 13, 1, 15, 23, 10192}, // Ғ
{10, 11, 11, 1, 11, 14, 10215}, // ғ
{13, 19, 14, 1, 15, 31, 10229}, // Ҕ
{11, 15, 12, 1, 11, 21, 10260}, // ҕ
{22, 19, 21, 0, 15, 53, 10281}, // Җ
{18, 14, 18, 0, 11, 32, 10334}, // җ
{12, 20, 13, 0, 15, 30, 10366}, // Ҙ
{10, 16, 10, 0, 11, 20, 10396}, // ҙ
{15, 19, 15, 1, 15, 36, 10416}, // Қ
{12, 14, 13, 1, 11, 21, 10452}, // қ
{16, 15, 16, 1, 15, 30, 10473}, // Ҝ
{14, 11, 14, 1, 11, 20, 10503}, // ҝ
{15, 16, 15, 0, 16, 30, 10523}, // Ҟ
{13, 12, 13, 0, 12, 20, 10553}, // ҟ
{17, 15, 17, 0, 15, 32, 10573}, // Ҡ
{14, 11, 14, 0, 11, 20, 10605}, // ҡ
{16, 19, 17, 1, 15, 38, 10625}, // Ң
{12, 14, 13, 1, 11, 21, 10663}, // ң
{17, 15, 18, 1, 15, 32, 10684}, // Ҥ
{13, 11, 14, 1, 11, 18, 10716}, // ҥ
{22, 19, 23, 1, 15, 53, 10734}, // Ҧ
{17, 15, 18, 1, 11, 32, 10787}, // ҧ
{16, 19, 17, 1, 15, 38, 10819}, // Ҩ
{13, 14, 13, 0, 11, 23, 10857}, // ҩ
{13, 20, 14, 1, 15, 33, 10880}, // Ҫ
{10, 15, 11, 0, 11, 19, 10913}, // ҫ
{13, 19, 13, 0, 15, 31, 10932}, // Ҭ
{11, 14, 11, 0, 11, 20, 10963}, // ҭ
{14, 15, 14, 0, 15, 27, 10983}, // Ү
{12, 15, 12, 0, 11, 23, 11010}, // ү
{14, 15, 14, 0, 15, 27, 11033}, // Ұ
{12, 15, 12, 0, 11, 23, 11060}, // ұ
{15, 19, 15, 0, 15, 36, 11083}, // Ҳ
{12, 14, 12, 0, 11, 21, 11119}, // ҳ
{20, 19, 20, 0, 15, 48, 11140}, // Ҵ
{15, 14, 15, 0, 11, 27, 11188}, // ҵ
{14, 19, 15, 1, 15, 34, 11215}, // Ҷ
{13, 14, 12, 0, 11, 23, 11249}, // ҷ
{12, 15, 14, 1, 15, 23, 11272}, // Ҹ
{11, 11, 12, 0, 11, 16, 11295}, // ҹ
{13, 15, 15, 1, 15, 25, 11311}, // Һ
{10, 16, 12, 1, 16, 20, 11336}, // һ
{18, 15, 18, 0, 15, 34, 11356}, // Ҽ
{14, 11, 15, 0, 11, 20, 11390}, // ҽ
{18, 19, 18, 0, 15, 43, 11410}, // Ҿ
{14, 14, 15, 0, 11, 25, 11453}, // ҿ
{4, 15, 7, 1, 15, 8, 11478}, // Ӏ
{21, 20, 21, 0, 20, 53, 11486}, // Ӂ
{18, 17, 18, 0, 17, 39, 11539}, // ӂ
{13, 19, 15, 1, 15, 31, 11578}, // Ӄ
{11, 15, 12, 1, 11, 21, 11609}, // ӄ
{18, 19, 17, 0, 15, 43, 11630}, // Ӆ
{14, 14, 14, 0, 11, 25, 11673}, // ӆ
{13, 19, 15, 1, 15, 31, 11698}, // Ӈ
{11, 15, 13, 1, 11, 21, 11729}, // ӈ
{16, 19, 17, 1, 15, 38, 11750}, // Ӊ
{12, 14, 13, 1, 11, 21, 11788}, // ӊ
{13, 19, 14, 0, 15, 31, 11809}, // Ӌ
{11, 14, 12, 0, 11, 20, 11840}, // ӌ
{19, 19, 20, 1, 15, 46, 11860}, // Ӎ
{16, 14, 17, 1, 11, 28, 11906}, // ӎ
{4, 15, 6, 1, 15, 8, 11934}, // ӏ
{15, 20, 15, 0, 20, 38, 11942}, // Ӑ
{11, 17, 12, 0, 17, 24, 11980}, // ӑ
{15, 19, 15, 0, 19, 36, 12004}, // Ӓ
{11, 16, 12, 0, 16, 22, 12040}, // ӓ
{21, 15, 21, 0, 15, 40, 12062}, // Ӕ
{18, 11, 18, 0, 11, 25, 12102}, // ӕ
{11, 20, 13, 1, 20, 28, 12127}, // Ӗ
{12, 17, 12, 0, 17, 26, 12155}, // ӗ
{14, 15, 15, 1, 15, 27, 12181}, // Ә
{12, 11, 12, 0, 11, 17, 12208}, // ә
{14, 19, 15, 1, 19, 34, 12225}, // Ӛ
{12, 16, 12, 0, 16, 24, 12259}, // ӛ
{21, 19, 21, 0, 19, 50, 12283}, // Ӝ
{18, 16, 18, 0, 16, 36, 12333}, // ӝ
{12, 20, 13, 0, 20, 30, 12369}, // Ӟ
{10, 16, 10, 0, 16, 20, 12399}, // ӟ
{12, 15, 13, 0, 15, 23, 12419}, // Ӡ
{10, 15, 11, 0, 11, 19, 12442}, // ӡ
{14, 18, 16, 1, 18, 32, 12461}, // Ӣ
{11, 15, 13, 1, 15, 21, 12493}, // ӣ
{14, 19, 16, 1, 19, 34, 12514}, // Ӥ
{11, 16, 13, 1, 16, 22, 12548}, // ӥ
{15, 19, 17, 1, 19, 36, 12570}, // Ӧ
{12, 16, 13, 0, 16, 24, 12606}, // ӧ
{15, 15, 17, 1, 15, 29, 12630}, // Ө
{12, 11, 13, 0, 11, 17, 12659}, // ө
{15, 19, 17, 1, 19, 36, 12676}, // Ӫ
{12, 16, 13, 0, 16, 24, 12712}, // ӫ
{14, 19, 14, 0, 19, 34, 12736}, // Ӭ
{11, 16, 11, 0, 16, 22, 12770}, // ӭ
{14, 18, 14, 0, 18, 32, 12792}, // Ӯ
{12, 19, 11, 0, 15, 29, 12824}, // ӯ
{14, 19, 14, 0, 19, 34, 12853}, // Ӱ
{12, 20, 11, 0, 16, 30, 12887}, // ӱ
{14, 21, 14, 0, 21, 37, 12917}, // Ӳ
{12, 21, 11, 0, 17, 32, 12954}, // ӳ
{13, 19, 14, 0, 19, 31, 12986}, // Ӵ
{11, 16, 12, 0, 16, 22, 13017}, // ӵ
{11, 19, 12, 1, 15, 27, 13039}, // Ӷ
{9, 14, 10, 1, 11, 16, 13066}, // ӷ
{17, 19, 19, 1, 19, 41, 13082}, // Ӹ
{15, 16, 17, 1, 16, 30, 13123}, // ӹ
{11, 3, 11, 0, 8, 5, 13153}, //
{21, 3, 21, 0, 8, 8, 13158}, // —
{21, 3, 21, 0, 8, 8, 13166}, // ―
{5, 6, 5, 0, 16, 4, 13174}, //
{5, 6, 5, 0, 16, 4, 13178}, //
{5, 6, 5, 0, 3, 4, 13182}, //
{10, 6, 10, 0, 16, 8, 13186}, // “
{9, 6, 10, 0, 16, 7, 13194}, // ”
{9, 6, 10, 0, 3, 7, 13201}, // „
{10, 18, 10, 0, 15, 23, 13208}, // †
{10, 18, 10, 0, 15, 23, 13231}, // ‡
{7, 6, 8, 0, 10, 6, 13254}, // •
{19, 4, 21, 1, 4, 10, 13260}, // …
{27, 15, 28, 0, 15, 51, 13270}, // ‰
{7, 11, 7, 0, 11, 10, 13321}, //
{7, 11, 7, 0, 11, 10, 13331}, //
{11, 15, 3, -4, 15, 21, 13341}, //
{12, 15, 12, 0, 15, 23, 13362}, // €
{12, 15, 12, 0, 15, 23, 13385}, // ₮
{12, 15, 12, 0, 15, 23, 13408}, // ₴
{13, 15, 12, 0, 15, 25, 13431}, // ₹
{12, 15, 13, 0, 15, 23, 13456}, // ∂
{15, 15, 15, 0, 15, 29, 13479}, // ∆
{13, 17, 15, 1, 15, 28, 13508}, // ∏
{11, 17, 11, 0, 15, 24, 13536}, // ∑
{10, 3, 12, 1, 8, 4, 13560}, //
{11, 15, 3, -4, 15, 21, 13564}, //
{5, 4, 5, 0, 9, 3, 13585}, // ∙
{14, 15, 13, 0, 15, 27, 13588}, // √
{13, 7, 13, 0, 10, 12, 13615}, // ∞
{9, 21, 8, 0, 16, 24, 13627}, // ∫
{12, 11, 12, 0, 12, 17, 13651}, // ≈
{10, 14, 12, 1, 14, 18, 13668}, // ≠
{10, 13, 12, 1, 13, 17, 13686}, // ≤
{10, 13, 12, 1, 13, 17, 13703}, // ≥
};
static const EpdUnicodeInterval ubuntu_bold_10Intervals[] = {
{0x0, 0x0, 0x0}, {0x8, 0x9, 0x1}, {0xD, 0xD, 0x3}, {0x1D, 0x1D, 0x4},
{0x20, 0x7E, 0x5}, {0xA0, 0xFF, 0x64}, {0x100, 0x17F, 0xC4}, {0x311, 0x311, 0x144},
{0x2013, 0x2015, 0x145}, {0x2018, 0x201A, 0x148}, {0x201C, 0x201E, 0x14B}, {0x2020, 0x2022, 0x14E},
{0x2026, 0x2026, 0x151}, {0x2030, 0x2030, 0x152}, {0x2039, 0x203A, 0x153}, {0x2044, 0x2044, 0x155},
{0x20AC, 0x20AC, 0x156}, {0x20AE, 0x20AE, 0x157}, {0x20B4, 0x20B4, 0x158}, {0x20B9, 0x20B9, 0x159},
{0x2202, 0x2202, 0x15A}, {0x2206, 0x2206, 0x15B}, {0x220F, 0x220F, 0x15C}, {0x2211, 0x2212, 0x15D},
{0x2215, 0x2215, 0x15F}, {0x2219, 0x221A, 0x160}, {0x221E, 0x221E, 0x162}, {0x222B, 0x222B, 0x163},
{0x2248, 0x2248, 0x164}, {0x2260, 0x2260, 0x165}, {0x2264, 0x2265, 0x166},
{0x400, 0x45F, 0x145}, {0x462, 0x463, 0x1A5}, {0x472, 0x475, 0x1A7}, {0x48A, 0x4F9, 0x1AB},
{0x2013, 0x2015, 0x21B}, {0x2018, 0x201A, 0x21E}, {0x201C, 0x201E, 0x221}, {0x2020, 0x2022, 0x224},
{0x2026, 0x2026, 0x227}, {0x2030, 0x2030, 0x228}, {0x2039, 0x203A, 0x229}, {0x2044, 0x2044, 0x22B},
{0x20AC, 0x20AC, 0x22C}, {0x20AE, 0x20AE, 0x22D}, {0x20B4, 0x20B4, 0x22E}, {0x20B9, 0x20B9, 0x22F},
{0x2202, 0x2202, 0x230}, {0x2206, 0x2206, 0x231}, {0x220F, 0x220F, 0x232}, {0x2211, 0x2212, 0x233},
{0x2215, 0x2215, 0x235}, {0x2219, 0x221A, 0x236}, {0x221E, 0x221E, 0x238}, {0x222B, 0x222B, 0x239},
{0x2248, 0x2248, 0x23A}, {0x2260, 0x2260, 0x23B}, {0x2264, 0x2265, 0x23C},
};
static const EpdFontData ubuntu_bold_10 = {
ubuntu_bold_10Bitmaps, ubuntu_bold_10Glyphs, ubuntu_bold_10Intervals, 31, 24, 20, -4, false,
ubuntu_bold_10Bitmaps, ubuntu_bold_10Glyphs, ubuntu_bold_10Intervals, 35, 24, 20, -4, false,
};

View File

@ -54,7 +54,7 @@ intervals = [
# (0x0370, 0x03FF),
### Cyrillic ###
# Russian, Ukrainian, Bulgarian, etc.
# (0x0400, 0x04FF),
(0x0400, 0x04FF),
### Math Symbols (common subset) ###
# General math operators
(0x2200, 0x22FF),

View File

@ -69,11 +69,12 @@ bool Epub::parseContentOpf(const std::string& contentOpfFilePath) {
// Grab data from opfParser into epub
title = opfParser.title;
if (!opfParser.coverItemId.empty() && opfParser.items.count(opfParser.coverItemId) > 0) {
coverImageItem = opfParser.items.at(opfParser.coverItemId);
}
if (opfParser.items.count("ncx")) {
tocNcxItem = opfParser.items.at("ncx");
} else if (opfParser.items.count("ncxtoc")) {
tocNcxItem = opfParser.items.at("ncxtoc");
if (!opfParser.tocNcxPath.empty()) {
tocNcxItem = opfParser.tocNcxPath;
}
for (auto& spineRef : opfParser.spineRefs) {
@ -147,6 +148,18 @@ bool Epub::load() {
return false;
}
// determine size of spine items
size_t spineItemsCount = getSpineItemsCount();
size_t spineItemsSize = 0;
for (size_t i = 0; i < spineItemsCount; i++) {
std::string spineItem = getSpineItem(i);
size_t s = 0;
getItemSize(spineItem, &s);
spineItemsSize += s;
cumulativeSpineItemSize.emplace_back(spineItemsSize);
}
Serial.printf("[%lu] [EBP] Book size: %u\n", millis(), spineItemsSize);
Serial.printf("[%lu] [EBP] Loaded ePub: %s\n", millis(), filepath.c_str());
return true;
@ -254,6 +267,8 @@ bool Epub::getItemSize(const std::string& itemHref, size_t* size) const {
int Epub::getSpineItemsCount() const { return spine.size(); }
size_t Epub::getCumulativeSpineItemSize(const int spineIndex) const { return cumulativeSpineItemSize.at(spineIndex); }
std::string& Epub::getSpineItem(const int spineIndex) {
if (spineIndex < 0 || spineIndex >= spine.size()) {
Serial.printf("[%lu] [EBP] getSpineItem index:%d is out of range\n", millis(), spineIndex);
@ -301,3 +316,14 @@ int Epub::getTocIndexForSpineIndex(const int spineIndex) const {
Serial.printf("[%lu] [EBP] TOC item not found\n", millis());
return -1;
}
size_t Epub::getBookSize() const { return getCumulativeSpineItemSize(getSpineItemsCount() - 1); }
// Calculate progress in book
uint8_t Epub::calculateProgress(const int currentSpineIndex, const float currentSpineRead) {
size_t prevChapterSize = (currentSpineIndex >= 1) ? getCumulativeSpineItemSize(currentSpineIndex - 1) : 0;
size_t curChapterSize = getCumulativeSpineItemSize(currentSpineIndex) - prevChapterSize;
size_t bookSize = getBookSize();
size_t sectionProgSize = currentSpineRead * curChapterSize;
return round(static_cast<float>(prevChapterSize + sectionProgSize) / bookSize * 100.0);
}

View File

@ -20,6 +20,8 @@ class Epub {
std::string filepath;
// the spine of the EPUB file
std::vector<std::pair<std::string, std::string>> spine;
// the file size of the spine items (proxy to book progress)
std::vector<size_t> cumulativeSpineItemSize;
// the toc of the EPUB file
std::vector<EpubTocEntry> toc;
// the base path for items in the EPUB file
@ -51,8 +53,12 @@ class Epub {
bool getItemSize(const std::string& itemHref, size_t* size) const;
std::string& getSpineItem(int spineIndex);
int getSpineItemsCount() const;
EpubTocEntry& getTocItem(int tocTndex);
size_t getCumulativeSpineItemSize(const int spineIndex) const;
EpubTocEntry& getTocItem(int tocIndex);
int getTocItemsCount() const;
int getSpineIndexForTocIndex(int tocIndex) const;
int getTocIndexForSpineIndex(int spineIndex) const;
size_t getBookSize() const;
uint8_t calculateProgress(const int currentSpineIndex, const float currentSpineRead);
};

View File

@ -3,7 +3,9 @@
#include <HardwareSerial.h>
#include <Serialization.h>
namespace {
constexpr uint8_t PAGE_FILE_VERSION = 3;
}
void PageLine::render(GfxRenderer& renderer, const int fontId) { block->render(renderer, fontId, xPos, yPos); }

View File

@ -27,6 +27,8 @@ void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fo
const size_t totalWordCount = words.size();
const int pageWidth = renderer.getScreenWidth() - horizontalMargin;
const int spaceWidth = renderer.getSpaceWidth(fontId);
// width of 1em to indent first line of paragraph if Extra Spacing is enabled
const int indentWidth = (!extraParagraphSpacing) ? 1 * renderer.getTextWidth(fontId, "m", REGULAR) : 0;
std::vector<uint16_t> wordWidths;
wordWidths.reserve(totalWordCount);
@ -51,7 +53,7 @@ void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fo
ans[totalWordCount - 1] = totalWordCount - 1;
for (int i = totalWordCount - 2; i >= 0; --i) {
int currlen = -spaceWidth;
int currlen = -spaceWidth + indentWidth;
dp[i] = MAX_COST;
for (size_t j = i; j < totalWordCount; ++j) {
@ -122,7 +124,11 @@ void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fo
}
// Calculate spacing
const int spareSpace = pageWidth - lineWordWidthSum;
int spareSpace = pageWidth - lineWordWidthSum;
if (wordWidthIndex == 0) {
spareSpace -= indentWidth;
}
int spacing = spaceWidth;
const bool isLastLine = lineBreak == totalWordCount;
@ -131,7 +137,8 @@ void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fo
}
// Calculate initial x position
uint16_t xpos = 0;
uint16_t xpos = (wordWidthIndex == 0) ? indentWidth : 0;
if (style == TextBlock::RIGHT_ALIGN) {
xpos = spareSpace - (lineWordCount - 1) * spaceWidth;
} else if (style == TextBlock::CENTER_ALIGN) {

View File

@ -16,9 +16,11 @@ class ParsedText {
std::list<std::string> words;
std::list<EpdFontStyle> wordStyles;
TextBlock::BLOCK_STYLE style;
bool extraParagraphSpacing;
public:
explicit ParsedText(const TextBlock::BLOCK_STYLE style) : style(style) {}
explicit ParsedText(const TextBlock::BLOCK_STYLE style, const bool extraParagraphSpacing)
: style(style), extraParagraphSpacing(extraParagraphSpacing) {}
~ParsedText() = default;
void addWord(std::string word, EpdFontStyle fontStyle);

View File

@ -9,7 +9,9 @@
#include "Page.h"
#include "parsers/ChapterHtmlSlimParser.h"
constexpr uint8_t SECTION_FILE_VERSION = 4;
namespace {
constexpr uint8_t SECTION_FILE_VERSION = 5;
}
void Section::onPageComplete(std::unique_ptr<Page> page) {
const auto filePath = cachePath + "/page_" + std::to_string(pageCount) + ".bin";
@ -24,7 +26,8 @@ void Section::onPageComplete(std::unique_ptr<Page> page) {
}
void Section::writeCacheMetadata(const int fontId, const float lineCompression, const int marginTop,
const int marginRight, const int marginBottom, const int marginLeft) const {
const int marginRight, const int marginBottom, const int marginLeft,
const bool extraParagraphSpacing) const {
std::ofstream outputFile(("/sd" + cachePath + "/section.bin").c_str());
serialization::writePod(outputFile, SECTION_FILE_VERSION);
serialization::writePod(outputFile, fontId);
@ -33,12 +36,14 @@ void Section::writeCacheMetadata(const int fontId, const float lineCompression,
serialization::writePod(outputFile, marginRight);
serialization::writePod(outputFile, marginBottom);
serialization::writePod(outputFile, marginLeft);
serialization::writePod(outputFile, extraParagraphSpacing);
serialization::writePod(outputFile, pageCount);
outputFile.close();
}
bool Section::loadCacheMetadata(const int fontId, const float lineCompression, const int marginTop,
const int marginRight, const int marginBottom, const int marginLeft) {
const int marginRight, const int marginBottom, const int marginLeft,
const bool extraParagraphSpacing) {
if (!SD.exists(cachePath.c_str())) {
return false;
}
@ -63,15 +68,18 @@ bool Section::loadCacheMetadata(const int fontId, const float lineCompression, c
int fileFontId, fileMarginTop, fileMarginRight, fileMarginBottom, fileMarginLeft;
float fileLineCompression;
bool fileExtraParagraphSpacing;
serialization::readPod(inputFile, fileFontId);
serialization::readPod(inputFile, fileLineCompression);
serialization::readPod(inputFile, fileMarginTop);
serialization::readPod(inputFile, fileMarginRight);
serialization::readPod(inputFile, fileMarginBottom);
serialization::readPod(inputFile, fileMarginLeft);
serialization::readPod(inputFile, fileExtraParagraphSpacing);
if (fontId != fileFontId || lineCompression != fileLineCompression || marginTop != fileMarginTop ||
marginRight != fileMarginRight || marginBottom != fileMarginBottom || marginLeft != fileMarginLeft) {
marginRight != fileMarginRight || marginBottom != fileMarginBottom || marginLeft != fileMarginLeft ||
extraParagraphSpacing != fileExtraParagraphSpacing) {
inputFile.close();
Serial.printf("[%lu] [SCT] Deserialization failed: Parameters do not match\n", millis());
clearCache();
@ -107,7 +115,8 @@ bool Section::clearCache() const {
}
bool Section::persistPageDataToSD(const int fontId, const float lineCompression, const int marginTop,
const int marginRight, const int marginBottom, const int marginLeft) {
const int marginRight, const int marginBottom, const int marginLeft,
const bool extraParagraphSpacing) {
const auto localPath = epub->getSpineItem(spineIndex);
// TODO: Should we get rid of this file all together?
@ -128,7 +137,7 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression,
const auto sdTmpHtmlPath = "/sd" + tmpHtmlPath;
ChapterHtmlSlimParser visitor(sdTmpHtmlPath.c_str(), renderer, fontId, lineCompression, marginTop, marginRight,
marginBottom, marginLeft,
marginBottom, marginLeft, extraParagraphSpacing,
[this](std::unique_ptr<Page> page) { this->onPageComplete(std::move(page)); });
success = visitor.parseAndBuildPages();
@ -138,7 +147,7 @@ bool Section::persistPageDataToSD(const int fontId, const float lineCompression,
return false;
}
writeCacheMetadata(fontId, lineCompression, marginTop, marginRight, marginBottom, marginLeft);
writeCacheMetadata(fontId, lineCompression, marginTop, marginRight, marginBottom, marginLeft, extraParagraphSpacing);
return true;
}

View File

@ -13,7 +13,7 @@ class Section {
std::string cachePath;
void writeCacheMetadata(int fontId, float lineCompression, int marginTop, int marginRight, int marginBottom,
int marginLeft) const;
int marginLeft, bool extraParagraphSpacing) const;
void onPageComplete(std::unique_ptr<Page> page);
public:
@ -26,10 +26,10 @@ class Section {
}
~Section() = default;
bool loadCacheMetadata(int fontId, float lineCompression, int marginTop, int marginRight, int marginBottom,
int marginLeft);
int marginLeft, bool extraParagraphSpacing);
void setupCacheDir() const;
bool clearCache() const;
bool persistPageDataToSD(int fontId, float lineCompression, int marginTop, int marginRight, int marginBottom,
int marginLeft);
int marginLeft, bool extraParagraphSpacing);
std::unique_ptr<Page> loadPageFromSD() const;
};

View File

@ -25,7 +25,7 @@ constexpr int NUM_IMAGE_TAGS = sizeof(IMAGE_TAGS) / sizeof(IMAGE_TAGS[0]);
const char* SKIP_TAGS[] = {"head", "table"};
constexpr int NUM_SKIP_TAGS = sizeof(SKIP_TAGS) / sizeof(SKIP_TAGS[0]);
bool isWhitespace(const char c) { return c == ' ' || c == '\r' || c == '\n'; }
bool isWhitespace(const char c) { return c == ' ' || c == '\r' || c == '\n' || c == '\t'; }
// given the start and end of a tag, check to see if it matches a known tag
bool matches(const char* tag_name, const char* possible_tags[], const int possible_tag_count) {
@ -48,7 +48,7 @@ void ChapterHtmlSlimParser::startNewTextBlock(const TextBlock::BLOCK_STYLE style
makePages();
}
currentTextBlock.reset(new ParsedText(style));
currentTextBlock.reset(new ParsedText(style, extraParagraphSpacing));
}
void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* name, const XML_Char** atts) {
@ -274,6 +274,8 @@ void ChapterHtmlSlimParser::makePages() {
currentTextBlock->layoutAndExtractLines(
renderer, fontId, marginLeft + marginRight,
[this](const std::shared_ptr<TextBlock>& textBlock) { addLineToPage(textBlock); });
// Extra paragrpah spacing
currentPageNextY += lineHeight / 2;
// Extra paragraph spacing if enabled
if (extraParagraphSpacing) {
currentPageNextY += lineHeight / 2;
}
}

View File

@ -35,6 +35,7 @@ class ChapterHtmlSlimParser {
int marginRight;
int marginBottom;
int marginLeft;
bool extraParagraphSpacing;
void startNewTextBlock(TextBlock::BLOCK_STYLE style);
void makePages();
@ -46,7 +47,7 @@ class ChapterHtmlSlimParser {
public:
explicit ChapterHtmlSlimParser(const char* filepath, GfxRenderer& renderer, const int fontId,
const float lineCompression, const int marginTop, const int marginRight,
const int marginBottom, const int marginLeft,
const int marginBottom, const int marginLeft, const bool extraParagraphSpacing,
const std::function<void(std::unique_ptr<Page>)>& completePageFn)
: filepath(filepath),
renderer(renderer),
@ -56,6 +57,7 @@ class ChapterHtmlSlimParser {
marginRight(marginRight),
marginBottom(marginBottom),
marginLeft(marginLeft),
extraParagraphSpacing(extraParagraphSpacing),
completePageFn(completePageFn) {}
~ChapterHtmlSlimParser() = default;
bool parseAndBuildPages();

View File

@ -3,6 +3,10 @@
#include <HardwareSerial.h>
#include <ZipFile.h>
namespace {
constexpr const char MEDIA_TYPE_NCX[] = "application/x-dtbncx+xml";
}
bool ContentOpfParser::setup() {
parser = XML_ParserCreate(nullptr);
if (!parser) {
@ -90,23 +94,49 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
return;
}
// TODO: Support book cover
// if (self->state == IN_METADATA && (strcmp(name, "meta") == 0 || strcmp(name, "opf:meta") == 0)) {
// }
if (self->state == IN_METADATA && (strcmp(name, "meta") == 0 || strcmp(name, "opf:meta") == 0)) {
bool isCover = false;
std::string coverItemId;
for (int i = 0; atts[i]; i += 2) {
if (strcmp(atts[i], "name") == 0 && strcmp(atts[i + 1], "cover") == 0) {
isCover = true;
} else if (strcmp(atts[i], "content") == 0) {
coverItemId = atts[i + 1];
}
}
if (isCover) {
self->coverItemId = coverItemId;
}
return;
}
if (self->state == IN_MANIFEST && (strcmp(name, "item") == 0 || strcmp(name, "opf:item") == 0)) {
std::string itemId;
std::string href;
std::string mediaType;
for (int i = 0; atts[i]; i += 2) {
if (strcmp(atts[i], "id") == 0) {
itemId = atts[i + 1];
} else if (strcmp(atts[i], "href") == 0) {
href = self->baseContentPath + atts[i + 1];
} else if (strcmp(atts[i], "media-type") == 0) {
mediaType = atts[i + 1];
}
}
self->items[itemId] = href;
if (mediaType == MEDIA_TYPE_NCX) {
if (self->tocNcxPath.empty()) {
self->tocNcxPath = href;
} else {
Serial.printf("[%lu] [COF] Warning: Multiple NCX files found in manifest. Ignoring duplicate: %s\n", millis(),
href.c_str());
}
}
return;
}

View File

@ -28,6 +28,7 @@ class ContentOpfParser final : public Print {
public:
std::string title;
std::string tocNcxPath;
std::string coverItemId;
std::map<std::string, std::string> items;
std::vector<std::string> spineRefs;

View File

@ -132,13 +132,19 @@ void GfxRenderer::displayBuffer(const EInkDisplay::RefreshMode refreshMode) cons
einkDisplay.displayBuffer(refreshMode);
}
// TODO: Support partial window update
// void GfxRenderer::flushArea(const int x, const int y, const int width, const int height) const {
// const int rotatedX = y;
// const int rotatedY = EInkDisplay::DISPLAY_HEIGHT - 1 - x;
//
// einkDisplay.displayBuffer(EInkDisplay::FAST_REFRESH, rotatedX, rotatedY, height, width);
// }
void GfxRenderer::displayWindow(const int x, const int y, const int width, const int height) const {
// Rotate coordinates from portrait (480x800) to landscape (800x480)
// Rotation: 90 degrees clockwise
// Portrait coordinates: (x, y) with dimensions (width, height)
// Landscape coordinates: (rotatedX, rotatedY) with dimensions (rotatedWidth, rotatedHeight)
const int rotatedX = y;
const int rotatedY = EInkDisplay::DISPLAY_HEIGHT - 1 - x - width + 1;
const int rotatedWidth = height;
const int rotatedHeight = width;
einkDisplay.displayWindow(rotatedX, rotatedY, rotatedWidth, rotatedHeight);
}
// Note: Internal driver treats screen in command orientation, this library treats in portrait orientation
int GfxRenderer::getScreenWidth() { return EInkDisplay::DISPLAY_HEIGHT; }
@ -164,7 +170,7 @@ int GfxRenderer::getLineHeight(const int fontId) const {
uint8_t* GfxRenderer::getFrameBuffer() const { return einkDisplay.getFrameBuffer(); }
void GfxRenderer::swapBuffers() const { einkDisplay.swapBuffers(); }
size_t GfxRenderer::getBufferSize() { return EInkDisplay::BUFFER_SIZE; }
void GfxRenderer::grayscaleRevert() const { einkDisplay.grayscaleRevert(); }
@ -174,6 +180,90 @@ void GfxRenderer::copyGrayscaleMsbBuffers() const { einkDisplay.copyGrayscaleMsb
void GfxRenderer::displayGrayBuffer() const { einkDisplay.displayGrayBuffer(); }
void GfxRenderer::freeBwBufferChunks() {
for (auto& bwBufferChunk : bwBufferChunks) {
if (bwBufferChunk) {
free(bwBufferChunk);
bwBufferChunk = nullptr;
}
}
}
/**
* This should be called before grayscale buffers are populated.
* A `restoreBwBuffer` call should always follow the grayscale render if this method was called.
* Uses chunked allocation to avoid needing 48KB of contiguous memory.
*/
void GfxRenderer::storeBwBuffer() {
const uint8_t* frameBuffer = einkDisplay.getFrameBuffer();
// Allocate and copy each chunk
for (size_t i = 0; i < BW_BUFFER_NUM_CHUNKS; i++) {
// Check if any chunks are already allocated
if (bwBufferChunks[i]) {
Serial.printf("[%lu] [GFX] !! BW buffer chunk %zu already stored - this is likely a bug, freeing chunk\n",
millis(), i);
free(bwBufferChunks[i]);
bwBufferChunks[i] = nullptr;
}
const size_t offset = i * BW_BUFFER_CHUNK_SIZE;
bwBufferChunks[i] = static_cast<uint8_t*>(malloc(BW_BUFFER_CHUNK_SIZE));
if (!bwBufferChunks[i]) {
Serial.printf("[%lu] [GFX] !! Failed to allocate BW buffer chunk %zu (%zu bytes)\n", millis(), i,
BW_BUFFER_CHUNK_SIZE);
// Free previously allocated chunks
freeBwBufferChunks();
return;
}
memcpy(bwBufferChunks[i], frameBuffer + offset, BW_BUFFER_CHUNK_SIZE);
}
Serial.printf("[%lu] [GFX] Stored BW buffer in %zu chunks (%zu bytes each)\n", millis(), BW_BUFFER_NUM_CHUNKS,
BW_BUFFER_CHUNK_SIZE);
}
/**
* This can only be called if `storeBwBuffer` was called prior to the grayscale render.
* It should be called to restore the BW buffer state after grayscale rendering is complete.
* Uses chunked restoration to match chunked storage.
*/
void GfxRenderer::restoreBwBuffer() {
// Check if any all chunks are allocated
bool missingChunks = false;
for (const auto& bwBufferChunk : bwBufferChunks) {
if (!bwBufferChunk) {
missingChunks = true;
break;
}
}
if (missingChunks) {
freeBwBufferChunks();
return;
}
uint8_t* frameBuffer = einkDisplay.getFrameBuffer();
for (size_t i = 0; i < BW_BUFFER_NUM_CHUNKS; i++) {
// Check if chunk is missing
if (!bwBufferChunks[i]) {
Serial.printf("[%lu] [GFX] !! BW buffer chunks not stored - this is likely a bug\n", millis());
freeBwBufferChunks();
return;
}
const size_t offset = i * BW_BUFFER_CHUNK_SIZE;
memcpy(frameBuffer + offset, bwBufferChunks[i], BW_BUFFER_CHUNK_SIZE);
}
einkDisplay.cleanupGrayscaleBuffers(frameBuffer);
freeBwBufferChunks();
Serial.printf("[%lu] [GFX] Restored and freed BW buffer chunks\n", millis());
}
void GfxRenderer::renderChar(const EpdFontFamily& fontFamily, const uint32_t cp, int* x, const int* y,
const bool pixelState, const EpdFontStyle style) const {
const EpdGlyph* glyph = fontFamily.getGlyph(cp, style);
@ -207,14 +297,20 @@ void GfxRenderer::renderChar(const EpdFontFamily& fontFamily, const uint32_t cp,
if (is2Bit) {
const uint8_t byte = bitmap[pixelPosition / 4];
const uint8_t bit_index = (3 - pixelPosition % 4) * 2;
// the direct bit from the font is 0 -> white, 1 -> light gray, 2 -> dark gray, 3 -> black
// we swap this to better match the way images and screen think about colors:
// 0 -> black, 1 -> dark grey, 2 -> light grey, 3 -> white
const uint8_t bmpVal = 3 - (byte >> bit_index) & 0x3;
const uint8_t val = (byte >> bit_index) & 0x3;
if (fontRenderMode == BW && val > 0) {
if (renderMode == BW && bmpVal < 3) {
// Black (also paints over the grays in BW mode)
drawPixel(screenX, screenY, pixelState);
} else if (fontRenderMode == GRAYSCALE_MSB && val == 1) {
// TODO: Not sure how this anti-aliasing goes on black backgrounds
} else if (renderMode == GRAYSCALE_MSB && (bmpVal == 1 || bmpVal == 2)) {
// Light gray (also mark the MSB if it's going to be a dark gray too)
// We have to flag pixels in reverse for the gray buffers, as 0 leave alone, 1 update
drawPixel(screenX, screenY, false);
} else if (fontRenderMode == GRAYSCALE_LSB && val == 2) {
} else if (renderMode == GRAYSCALE_LSB && bmpVal == 1) {
// Dark gray
drawPixel(screenX, screenY, false);
}
} else {

View File

@ -7,17 +7,24 @@
class GfxRenderer {
public:
enum FontRenderMode { BW, GRAYSCALE_LSB, GRAYSCALE_MSB };
enum RenderMode { BW, GRAYSCALE_LSB, GRAYSCALE_MSB };
private:
static constexpr size_t BW_BUFFER_CHUNK_SIZE = 8000; // 8KB chunks to allow for non-contiguous memory
static constexpr size_t BW_BUFFER_NUM_CHUNKS = EInkDisplay::BUFFER_SIZE / BW_BUFFER_CHUNK_SIZE;
static_assert(BW_BUFFER_CHUNK_SIZE * BW_BUFFER_NUM_CHUNKS == EInkDisplay::BUFFER_SIZE,
"BW buffer chunking does not line up with display buffer size");
EInkDisplay& einkDisplay;
FontRenderMode fontRenderMode;
RenderMode renderMode;
uint8_t* bwBufferChunks[BW_BUFFER_NUM_CHUNKS] = {nullptr};
std::map<int, EpdFontFamily> fontMap;
void renderChar(const EpdFontFamily& fontFamily, uint32_t cp, int* x, const int* y, bool pixelState,
EpdFontStyle style) const;
void freeBwBufferChunks();
public:
explicit GfxRenderer(EInkDisplay& einkDisplay) : einkDisplay(einkDisplay), fontRenderMode(BW) {}
explicit GfxRenderer(EInkDisplay& einkDisplay) : einkDisplay(einkDisplay), renderMode(BW) {}
~GfxRenderer() = default;
// Setup
@ -27,6 +34,8 @@ class GfxRenderer {
static int getScreenWidth();
static int getScreenHeight();
void displayBuffer(EInkDisplay::RefreshMode refreshMode = EInkDisplay::FAST_REFRESH) const;
// EXPERIMENTAL: Windowed update - display only a rectangular region (portrait coordinates)
void displayWindow(int x, int y, int width, int height) const;
void invertScreen() const;
void clearScreen(uint8_t color = 0xFF) const;
@ -41,15 +50,19 @@ class GfxRenderer {
int getTextWidth(int fontId, const char* text, EpdFontStyle style = REGULAR) const;
void drawCenteredText(int fontId, int y, const char* text, bool black = true, EpdFontStyle style = REGULAR) const;
void drawText(int fontId, int x, int y, const char* text, bool black = true, EpdFontStyle style = REGULAR) const;
void setFontRenderMode(const FontRenderMode mode) { this->fontRenderMode = mode; }
int getSpaceWidth(int fontId) const;
int getLineHeight(int fontId) const;
// Low level functions
uint8_t* getFrameBuffer() const;
void swapBuffers() const;
void grayscaleRevert() const;
// Grayscale functions
void setRenderMode(const RenderMode mode) { this->renderMode = mode; }
void copyGrayscaleLsbBuffers() const;
void copyGrayscaleMsbBuffers() const;
void displayGrayBuffer() const;
void storeBwBuffer();
void restoreBwBuffer();
// Low level functions
uint8_t* getFrameBuffer() const;
static size_t getBufferSize();
void grayscaleRevert() const;
};

@ -1 +1 @@
Subproject commit 7e0dce916706da7d80ec225fade191aea6b87fb6
Subproject commit 98a5aa1f8969ccd317c9b45bf0fa84b6c82e167f

View File

@ -1,5 +1,5 @@
[platformio]
crosspoint_version = 0.5.1
crosspoint_version = 0.6.0
default_envs = default
[base]
@ -8,6 +8,9 @@ board = esp32-c3-devkitm-1
framework = arduino
monitor_speed = 115200
upload_speed = 921600
check_tool = cppcheck
check_skip_packages = yes
check_severity = medium, high
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
@ -17,6 +20,7 @@ build_flags =
-DARDUINO_USB_MODE=1
-DARDUINO_USB_CDC_ON_BOOT=1
-DMINIZ_NO_ZLIB_COMPATIBLE_NAMES=1
-DEINK_DISPLAY_SINGLE_BUFFER_MODE=1
# https://libexpat.github.io/doc/api/latest/#XML_GE
-DXML_GE=0
-DXML_CONTEXT_BYTES=1024

View File

@ -0,0 +1,67 @@
#include "CrossPointSettings.h"
#include <HardwareSerial.h>
#include <SD.h>
#include <Serialization.h>
#include <cstdint>
#include <fstream>
// Initialize the static instance
CrossPointSettings CrossPointSettings::instance;
namespace {
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
constexpr uint8_t SETTINGS_COUNT = 2;
constexpr char SETTINGS_FILE[] = "/sd/.crosspoint/settings.bin";
} // namespace
bool CrossPointSettings::saveToFile() const {
// Make sure the directory exists
SD.mkdir("/.crosspoint");
std::ofstream outputFile(SETTINGS_FILE);
serialization::writePod(outputFile, SETTINGS_FILE_VERSION);
serialization::writePod(outputFile, SETTINGS_COUNT);
serialization::writePod(outputFile, whiteSleepScreen);
serialization::writePod(outputFile, extraParagraphSpacing);
outputFile.close();
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
return true;
}
bool CrossPointSettings::loadFromFile() {
if (!SD.exists(SETTINGS_FILE + 3)) { // +3 to skip "/sd" prefix
Serial.printf("[%lu] [CPS] Settings file does not exist, using defaults\n", millis());
return false;
}
std::ifstream inputFile(SETTINGS_FILE);
uint8_t version;
serialization::readPod(inputFile, version);
if (version != SETTINGS_FILE_VERSION) {
Serial.printf("[%lu] [CPS] Deserialization failed: Unknown version %u\n", millis(), version);
inputFile.close();
return false;
}
uint8_t fileSettingsCount = 0;
serialization::readPod(inputFile, fileSettingsCount);
// load settings that exist
switch (fileSettingsCount) {
case 1:
serialization::readPod(inputFile, whiteSleepScreen);
break;
case 2:
serialization::readPod(inputFile, whiteSleepScreen);
serialization::readPod(inputFile, extraParagraphSpacing);
break;
}
inputFile.close();
Serial.printf("[%lu] [CPS] Settings loaded from file\n", millis());
return true;
}

34
src/CrossPointSettings.h Normal file
View File

@ -0,0 +1,34 @@
#pragma once
#include <cstdint>
#include <iosfwd>
class CrossPointSettings {
private:
// Private constructor for singleton
CrossPointSettings() = default;
// Static instance
static CrossPointSettings instance;
public:
// Delete copy constructor and assignment
CrossPointSettings(const CrossPointSettings&) = delete;
CrossPointSettings& operator=(const CrossPointSettings&) = delete;
// Sleep screen settings
uint8_t whiteSleepScreen = 0;
// Text rendering settings
uint8_t extraParagraphSpacing = 1;
~CrossPointSettings() = default;
// Get singleton instance
static CrossPointSettings& getInstance() { return instance; }
bool saveToFile() const;
bool loadFromFile();
};
// Helper macro to access settings
#define SETTINGS CrossPointSettings::getInstance()

View File

@ -6,8 +6,12 @@
#include <fstream>
namespace {
constexpr uint8_t STATE_FILE_VERSION = 1;
constexpr char STATE_FILE[] = "/sd/.crosspoint/state.bin";
} // namespace
CrossPointState CrossPointState::instance;
bool CrossPointState::saveToFile() const {
std::ofstream outputFile(STATE_FILE);

View File

@ -3,11 +3,20 @@
#include <string>
class CrossPointState {
// Static instance
static CrossPointState instance;
public:
std::string openEpubPath;
~CrossPointState() = default;
// Get singleton instance
static CrossPointState& getInstance() { return instance; }
bool saveToFile() const;
bool loadFromFile();
};
// Helper macro to access settings
#define APP_STATE CrossPointState::getInstance()

18
src/activities/Activity.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <InputManager.h>
class GfxRenderer;
class Activity {
protected:
GfxRenderer& renderer;
InputManager& inputManager;
public:
explicit Activity(GfxRenderer& renderer, InputManager& inputManager)
: renderer(renderer), inputManager(inputManager) {}
virtual ~Activity() = default;
virtual void onEnter() {}
virtual void onExit() {}
virtual void loop() {}
};

View File

@ -0,0 +1,21 @@
#include "ActivityWithSubactivity.h"
void ActivityWithSubactivity::exitActivity() {
if (subActivity) {
subActivity->onExit();
subActivity.reset();
}
}
void ActivityWithSubactivity::enterNewActivity(Activity* activity) {
subActivity.reset(activity);
subActivity->onEnter();
}
void ActivityWithSubactivity::loop() {
if (subActivity) {
subActivity->loop();
}
}
void ActivityWithSubactivity::onExit() { exitActivity(); }

View File

@ -0,0 +1,17 @@
#pragma once
#include <memory>
#include "Activity.h"
class ActivityWithSubactivity : public Activity {
protected:
std::unique_ptr<Activity> subActivity = nullptr;
void exitActivity();
void enterNewActivity(Activity* activity);
public:
explicit ActivityWithSubactivity(GfxRenderer& renderer, InputManager& inputManager)
: Activity(renderer, inputManager) {}
void loop() override;
void onExit() override;
};

View File

@ -1,11 +1,11 @@
#include "BootLogoScreen.h"
#include "BootActivity.h"
#include <GfxRenderer.h>
#include "config.h"
#include "images/CrossLarge.h"
void BootLogoScreen::onEnter() {
void BootActivity::onEnter() {
const auto pageWidth = GfxRenderer::getScreenWidth();
const auto pageHeight = GfxRenderer::getScreenHeight();

View File

@ -0,0 +1,8 @@
#pragma once
#include "../Activity.h"
class BootActivity final : public Activity {
public:
explicit BootActivity(GfxRenderer& renderer, InputManager& inputManager) : Activity(renderer, inputManager) {}
void onEnter() override;
};

View File

@ -1,11 +1,12 @@
#include "SleepScreen.h"
#include "SleepActivity.h"
#include <GfxRenderer.h>
#include "CrossPointSettings.h"
#include "config.h"
#include "images/CrossLarge.h"
void SleepScreen::onEnter() {
void SleepActivity::onEnter() {
const auto pageWidth = GfxRenderer::getScreenWidth();
const auto pageHeight = GfxRenderer::getScreenHeight();
@ -13,6 +14,11 @@ void SleepScreen::onEnter() {
renderer.drawImage(CrossLarge, (pageWidth - 128) / 2, (pageHeight - 128) / 2, 128, 128);
renderer.drawCenteredText(UI_FONT_ID, pageHeight / 2 + 70, "CrossPoint", true, BOLD);
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight / 2 + 95, "SLEEPING");
renderer.invertScreen();
// Apply white screen if enabled in settings
if (!SETTINGS.whiteSleepScreen) {
renderer.invertScreen();
}
renderer.displayBuffer(EInkDisplay::HALF_REFRESH);
}

View File

@ -0,0 +1,8 @@
#pragma once
#include "../Activity.h"
class SleepActivity final : public Activity {
public:
explicit SleepActivity(GfxRenderer& renderer, InputManager& inputManager) : Activity(renderer, inputManager) {}
void onEnter() override;
};

View File

@ -0,0 +1,103 @@
#include "HomeActivity.h"
#include <GfxRenderer.h>
#include <SD.h>
#include "config.h"
namespace {
constexpr int menuItemCount = 2;
}
void HomeActivity::taskTrampoline(void* param) {
auto* self = static_cast<HomeActivity*>(param);
self->displayTaskLoop();
}
void HomeActivity::onEnter() {
renderingMutex = xSemaphoreCreateMutex();
selectorIndex = 0;
// Trigger first update
updateRequired = true;
xTaskCreate(&HomeActivity::taskTrampoline, "HomeActivityTask",
2048, // Stack size
this, // Parameters
1, // Priority
&displayTaskHandle // Task handle
);
}
void HomeActivity::onExit() {
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
xSemaphoreTake(renderingMutex, portMAX_DELAY);
if (displayTaskHandle) {
vTaskDelete(displayTaskHandle);
displayTaskHandle = nullptr;
}
vSemaphoreDelete(renderingMutex);
renderingMutex = nullptr;
}
void HomeActivity::loop() {
const bool prevPressed =
inputManager.wasPressed(InputManager::BTN_UP) || inputManager.wasPressed(InputManager::BTN_LEFT);
const bool nextPressed =
inputManager.wasPressed(InputManager::BTN_DOWN) || inputManager.wasPressed(InputManager::BTN_RIGHT);
if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) {
if (selectorIndex == 0) {
onReaderOpen();
} else if (selectorIndex == 1) {
onSettingsOpen();
}
} else if (prevPressed) {
selectorIndex = (selectorIndex + menuItemCount - 1) % menuItemCount;
updateRequired = true;
} else if (nextPressed) {
selectorIndex = (selectorIndex + 1) % menuItemCount;
updateRequired = true;
}
}
void HomeActivity::displayTaskLoop() {
while (true) {
if (updateRequired) {
updateRequired = false;
xSemaphoreTake(renderingMutex, portMAX_DELAY);
render();
xSemaphoreGive(renderingMutex);
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
void HomeActivity::render() const {
renderer.clearScreen();
const auto pageWidth = GfxRenderer::getScreenWidth();
const auto pageHeight = GfxRenderer::getScreenHeight();
renderer.drawCenteredText(READER_FONT_ID, 10, "CrossPoint Reader", true, BOLD);
// Draw selection
renderer.fillRect(0, 60 + selectorIndex * 30 + 2, pageWidth - 1, 30);
renderer.drawText(UI_FONT_ID, 20, 60, "Read", selectorIndex != 0);
renderer.drawText(UI_FONT_ID, 20, 90, "Settings", selectorIndex != 1);
renderer.drawRect(25, pageHeight - 40, 106, 40);
renderer.drawText(UI_FONT_ID, 25 + (105 - renderer.getTextWidth(UI_FONT_ID, "Back")) / 2, pageHeight - 35, "Back");
renderer.drawRect(130, pageHeight - 40, 106, 40);
renderer.drawText(UI_FONT_ID, 130 + (105 - renderer.getTextWidth(UI_FONT_ID, "Confirm")) / 2, pageHeight - 35,
"Confirm");
renderer.drawRect(245, pageHeight - 40, 106, 40);
renderer.drawText(UI_FONT_ID, 245 + (105 - renderer.getTextWidth(UI_FONT_ID, "Left")) / 2, pageHeight - 35, "Left");
renderer.drawRect(350, pageHeight - 40, 106, 40);
renderer.drawText(UI_FONT_ID, 350 + (105 - renderer.getTextWidth(UI_FONT_ID, "Right")) / 2, pageHeight - 35, "Right");
renderer.displayBuffer();
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <freertos/task.h>
#include <functional>
#include "../Activity.h"
class HomeActivity final : public Activity {
TaskHandle_t displayTaskHandle = nullptr;
SemaphoreHandle_t renderingMutex = nullptr;
int selectorIndex = 0;
bool updateRequired = false;
const std::function<void()> onReaderOpen;
const std::function<void()> onSettingsOpen;
static void taskTrampoline(void* param);
[[noreturn]] void displayTaskLoop();
void render() const;
public:
explicit HomeActivity(GfxRenderer& renderer, InputManager& inputManager, const std::function<void()>& onReaderOpen,
const std::function<void()>& onSettingsOpen)
: Activity(renderer, inputManager), onReaderOpen(onReaderOpen), onSettingsOpen(onSettingsOpen) {}
void onEnter() override;
void onExit() override;
void loop() override;
};

View File

@ -1,27 +1,30 @@
#include "EpubReaderScreen.h"
#include "EpubReaderActivity.h"
#include <Epub/Page.h>
#include <GfxRenderer.h>
#include <SD.h>
#include "Battery.h"
#include "EpubReaderChapterSelectionScreen.h"
#include "CrossPointSettings.h"
#include "EpubReaderChapterSelectionActivity.h"
#include "config.h"
constexpr int PAGES_PER_REFRESH = 15;
constexpr unsigned long SKIP_CHAPTER_MS = 700;
namespace {
constexpr int pagesPerRefresh = 15;
constexpr unsigned long skipChapterMs = 700;
constexpr float lineCompression = 0.95f;
constexpr int marginTop = 8;
constexpr int marginRight = 10;
constexpr int marginBottom = 22;
constexpr int marginLeft = 10;
} // namespace
void EpubReaderScreen::taskTrampoline(void* param) {
auto* self = static_cast<EpubReaderScreen*>(param);
void EpubReaderActivity::taskTrampoline(void* param) {
auto* self = static_cast<EpubReaderActivity*>(param);
self->displayTaskLoop();
}
void EpubReaderScreen::onEnter() {
void EpubReaderActivity::onEnter() {
if (!epub) {
return;
}
@ -30,7 +33,6 @@ void EpubReaderScreen::onEnter() {
epub->setupCacheDir();
// TODO: Move this to a state object
if (SD.exists((epub->getCachePath() + "/progress.bin").c_str())) {
File f = SD.open((epub->getCachePath() + "/progress.bin").c_str());
uint8_t data[4];
@ -44,7 +46,7 @@ void EpubReaderScreen::onEnter() {
// Trigger first update
updateRequired = true;
xTaskCreate(&EpubReaderScreen::taskTrampoline, "EpubReaderScreenTask",
xTaskCreate(&EpubReaderActivity::taskTrampoline, "EpubReaderActivityTask",
8192, // Stack size
this, // Parameters
1, // Priority
@ -52,7 +54,7 @@ void EpubReaderScreen::onEnter() {
);
}
void EpubReaderScreen::onExit() {
void EpubReaderActivity::onExit() {
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
xSemaphoreTake(renderingMutex, portMAX_DELAY);
if (displayTaskHandle) {
@ -65,22 +67,22 @@ void EpubReaderScreen::onExit() {
epub.reset();
}
void EpubReaderScreen::handleInput() {
// Pass input responsibility to sub screen if exists
if (subScreen) {
subScreen->handleInput();
void EpubReaderActivity::loop() {
// Pass input responsibility to sub activity if exists
if (subAcitivity) {
subAcitivity->loop();
return;
}
// Enter chapter selection screen
// Enter chapter selection activity
if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) {
// Don't start screen transition while rendering
// Don't start activity transition while rendering
xSemaphoreTake(renderingMutex, portMAX_DELAY);
subScreen.reset(new EpubReaderChapterSelectionScreen(
subAcitivity.reset(new EpubReaderChapterSelectionActivity(
this->renderer, this->inputManager, epub, currentSpineIndex,
[this] {
subScreen->onExit();
subScreen.reset();
subAcitivity->onExit();
subAcitivity.reset();
updateRequired = true;
},
[this](const int newSpineIndex) {
@ -89,16 +91,16 @@ void EpubReaderScreen::handleInput() {
nextPageNumber = 0;
section.reset();
}
subScreen->onExit();
subScreen.reset();
subAcitivity->onExit();
subAcitivity.reset();
updateRequired = true;
}));
subScreen->onEnter();
subAcitivity->onEnter();
xSemaphoreGive(renderingMutex);
}
if (inputManager.wasPressed(InputManager::BTN_BACK)) {
onGoHome();
onGoBack();
return;
}
@ -119,7 +121,7 @@ void EpubReaderScreen::handleInput() {
return;
}
const bool skipChapter = inputManager.getHeldTime() > SKIP_CHAPTER_MS;
const bool skipChapter = inputManager.getHeldTime() > skipChapterMs;
if (skipChapter) {
// We don't want to delete the section mid-render, so grab the semaphore
@ -165,7 +167,7 @@ void EpubReaderScreen::handleInput() {
}
}
void EpubReaderScreen::displayTaskLoop() {
void EpubReaderActivity::displayTaskLoop() {
while (true) {
if (updateRequired) {
updateRequired = false;
@ -178,7 +180,7 @@ void EpubReaderScreen::displayTaskLoop() {
}
// TODO: Failure handling
void EpubReaderScreen::renderScreen() {
void EpubReaderActivity::renderScreen() {
if (!epub) {
return;
}
@ -204,31 +206,31 @@ void EpubReaderScreen::renderScreen() {
const auto filepath = epub->getSpineItem(currentSpineIndex);
Serial.printf("[%lu] [ERS] Loading file: %s, index: %d\n", millis(), filepath.c_str(), currentSpineIndex);
section = std::unique_ptr<Section>(new Section(epub, currentSpineIndex, renderer));
if (!section->loadCacheMetadata(READER_FONT_ID, lineCompression, marginTop, marginRight, marginBottom,
marginLeft)) {
if (!section->loadCacheMetadata(READER_FONT_ID, lineCompression, marginTop, marginRight, marginBottom, marginLeft,
SETTINGS.extraParagraphSpacing)) {
Serial.printf("[%lu] [ERS] Cache not found, building...\n", millis());
{
renderer.grayscaleRevert();
const int textWidth = renderer.getTextWidth(READER_FONT_ID, "Indexing...");
constexpr int margin = 20;
const int x = (GfxRenderer::getScreenWidth() - textWidth - margin * 2) / 2;
constexpr int y = 50;
const int w = textWidth + margin * 2;
const int h = renderer.getLineHeight(READER_FONT_ID) + margin * 2;
renderer.grayscaleRevert();
uint8_t* fb1 = renderer.getFrameBuffer();
renderer.swapBuffers();
memcpy(fb1, renderer.getFrameBuffer(), EInkDisplay::BUFFER_SIZE);
renderer.fillRect(x, y, w, h, 0);
// Round all coordinates to 8 pixel boundaries
const int x = ((GfxRenderer::getScreenWidth() - textWidth - margin * 2) / 2 + 7) / 8 * 8;
constexpr int y = 56;
const int w = (textWidth + margin * 2 + 7) / 8 * 8;
const int h = (renderer.getLineHeight(READER_FONT_ID) + margin * 2 + 7) / 8 * 8;
renderer.fillRect(x, y, w, h, false);
renderer.drawText(READER_FONT_ID, x + margin, y + margin, "Indexing...");
renderer.drawRect(x + 5, y + 5, w - 10, h - 10);
renderer.displayBuffer();
// EXPERIMENTAL: Still suffers from ghosting
renderer.displayWindow(x, y, w, h);
pagesUntilFullRefresh = 0;
}
section->setupCacheDir();
if (!section->persistPageDataToSD(READER_FONT_ID, lineCompression, marginTop, marginRight, marginBottom,
marginLeft)) {
marginLeft, SETTINGS.extraParagraphSpacing)) {
Serial.printf("[%lu] [ERS] Failed to persist page data to SD\n", millis());
section.reset();
return;
@ -285,41 +287,53 @@ void EpubReaderScreen::renderScreen() {
f.close();
}
void EpubReaderScreen::renderContents(std::unique_ptr<Page> page) {
void EpubReaderActivity::renderContents(std::unique_ptr<Page> page) {
page->render(renderer, READER_FONT_ID);
renderStatusBar();
if (pagesUntilFullRefresh <= 1) {
renderer.displayBuffer(EInkDisplay::HALF_REFRESH);
pagesUntilFullRefresh = PAGES_PER_REFRESH;
pagesUntilFullRefresh = pagesPerRefresh;
} else {
renderer.displayBuffer();
pagesUntilFullRefresh--;
}
// Save bw buffer to reset buffer state after grayscale data sync
renderer.storeBwBuffer();
// grayscale rendering
// TODO: Only do this if font supports it
{
renderer.clearScreen(0x00);
renderer.setFontRenderMode(GfxRenderer::GRAYSCALE_LSB);
renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB);
page->render(renderer, READER_FONT_ID);
renderer.copyGrayscaleLsbBuffers();
// Render and copy to MSB buffer
renderer.clearScreen(0x00);
renderer.setFontRenderMode(GfxRenderer::GRAYSCALE_MSB);
renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB);
page->render(renderer, READER_FONT_ID);
renderer.copyGrayscaleMsbBuffers();
// display grayscale part
renderer.displayGrayBuffer();
renderer.setFontRenderMode(GfxRenderer::BW);
renderer.setRenderMode(GfxRenderer::BW);
}
// restore the bw data
renderer.restoreBwBuffer();
}
void EpubReaderScreen::renderStatusBar() const {
void EpubReaderActivity::renderStatusBar() const {
constexpr auto textY = 776;
// Calculate progress in book
float sectionChapterProg = static_cast<float>(section->currentPage) / section->pageCount;
uint8_t bookProgress = epub->calculateProgress(currentSpineIndex, sectionChapterProg);
// Right aligned text for progress counter
const std::string progress = std::to_string(section->currentPage + 1) + " / " + std::to_string(section->pageCount);
const std::string progress = std::to_string(section->currentPage + 1) + "/" + std::to_string(section->pageCount) +
" " + std::to_string(bookProgress) + "%";
const auto progressTextWidth = renderer.getTextWidth(SMALL_FONT_ID, progress.c_str());
renderer.drawText(SMALL_FONT_ID, GfxRenderer::getScreenWidth() - marginRight - progressTextWidth, textY,
progress.c_str());

View File

@ -5,19 +5,19 @@
#include <freertos/semphr.h>
#include <freertos/task.h>
#include "Screen.h"
#include "../Activity.h"
class EpubReaderScreen final : public Screen {
class EpubReaderActivity final : public Activity {
std::shared_ptr<Epub> epub;
std::unique_ptr<Section> section = nullptr;
TaskHandle_t displayTaskHandle = nullptr;
SemaphoreHandle_t renderingMutex = nullptr;
std::unique_ptr<Screen> subScreen = nullptr;
std::unique_ptr<Activity> subAcitivity = nullptr;
int currentSpineIndex = 0;
int nextPageNumber = 0;
int pagesUntilFullRefresh = 0;
bool updateRequired = false;
const std::function<void()> onGoHome;
const std::function<void()> onGoBack;
static void taskTrampoline(void* param);
[[noreturn]] void displayTaskLoop();
@ -26,10 +26,10 @@ class EpubReaderScreen final : public Screen {
void renderStatusBar() const;
public:
explicit EpubReaderScreen(GfxRenderer& renderer, InputManager& inputManager, std::unique_ptr<Epub> epub,
const std::function<void()>& onGoHome)
: Screen(renderer, inputManager), epub(std::move(epub)), onGoHome(onGoHome) {}
explicit EpubReaderActivity(GfxRenderer& renderer, InputManager& inputManager, std::unique_ptr<Epub> epub,
const std::function<void()>& onGoBack)
: Activity(renderer, inputManager), epub(std::move(epub)), onGoBack(onGoBack) {}
void onEnter() override;
void onExit() override;
void handleInput() override;
void loop() override;
};

View File

@ -1,4 +1,4 @@
#include "EpubReaderChapterSelectionScreen.h"
#include "EpubReaderChapterSelectionActivity.h"
#include <GfxRenderer.h>
#include <SD.h>
@ -8,12 +8,12 @@
constexpr int PAGE_ITEMS = 24;
constexpr int SKIP_PAGE_MS = 700;
void EpubReaderChapterSelectionScreen::taskTrampoline(void* param) {
auto* self = static_cast<EpubReaderChapterSelectionScreen*>(param);
void EpubReaderChapterSelectionActivity::taskTrampoline(void* param) {
auto* self = static_cast<EpubReaderChapterSelectionActivity*>(param);
self->displayTaskLoop();
}
void EpubReaderChapterSelectionScreen::onEnter() {
void EpubReaderChapterSelectionActivity::onEnter() {
if (!epub) {
return;
}
@ -23,7 +23,7 @@ void EpubReaderChapterSelectionScreen::onEnter() {
// Trigger first update
updateRequired = true;
xTaskCreate(&EpubReaderChapterSelectionScreen::taskTrampoline, "EpubReaderChapterSelectionScreenTask",
xTaskCreate(&EpubReaderChapterSelectionActivity::taskTrampoline, "EpubReaderChapterSelectionActivityTask",
2048, // Stack size
this, // Parameters
1, // Priority
@ -31,7 +31,7 @@ void EpubReaderChapterSelectionScreen::onEnter() {
);
}
void EpubReaderChapterSelectionScreen::onExit() {
void EpubReaderChapterSelectionActivity::onExit() {
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
xSemaphoreTake(renderingMutex, portMAX_DELAY);
if (displayTaskHandle) {
@ -42,7 +42,7 @@ void EpubReaderChapterSelectionScreen::onExit() {
renderingMutex = nullptr;
}
void EpubReaderChapterSelectionScreen::handleInput() {
void EpubReaderChapterSelectionActivity::loop() {
const bool prevReleased =
inputManager.wasReleased(InputManager::BTN_UP) || inputManager.wasReleased(InputManager::BTN_LEFT);
const bool nextReleased =
@ -72,7 +72,7 @@ void EpubReaderChapterSelectionScreen::handleInput() {
}
}
void EpubReaderChapterSelectionScreen::displayTaskLoop() {
void EpubReaderChapterSelectionActivity::displayTaskLoop() {
while (true) {
if (updateRequired) {
updateRequired = false;
@ -84,7 +84,7 @@ void EpubReaderChapterSelectionScreen::displayTaskLoop() {
}
}
void EpubReaderChapterSelectionScreen::renderScreen() {
void EpubReaderChapterSelectionActivity::renderScreen() {
renderer.clearScreen();
const auto pageWidth = renderer.getScreenWidth();

View File

@ -6,9 +6,9 @@
#include <memory>
#include "Screen.h"
#include "../Activity.h"
class EpubReaderChapterSelectionScreen final : public Screen {
class EpubReaderChapterSelectionActivity final : public Activity {
std::shared_ptr<Epub> epub;
TaskHandle_t displayTaskHandle = nullptr;
SemaphoreHandle_t renderingMutex = nullptr;
@ -23,16 +23,16 @@ class EpubReaderChapterSelectionScreen final : public Screen {
void renderScreen();
public:
explicit EpubReaderChapterSelectionScreen(GfxRenderer& renderer, InputManager& inputManager,
const std::shared_ptr<Epub>& epub, const int currentSpineIndex,
const std::function<void()>& onGoBack,
const std::function<void(int newSpineIndex)>& onSelectSpineIndex)
: Screen(renderer, inputManager),
explicit EpubReaderChapterSelectionActivity(GfxRenderer& renderer, InputManager& inputManager,
const std::shared_ptr<Epub>& epub, const int currentSpineIndex,
const std::function<void()>& onGoBack,
const std::function<void(int newSpineIndex)>& onSelectSpineIndex)
: Activity(renderer, inputManager),
epub(epub),
currentSpineIndex(currentSpineIndex),
onGoBack(onGoBack),
onSelectSpineIndex(onSelectSpineIndex) {}
void onEnter() override;
void onExit() override;
void handleInput() override;
void loop() override;
};

View File

@ -1,4 +1,4 @@
#include "FileSelectionScreen.h"
#include "FileSelectionActivity.h"
#include <GfxRenderer.h>
#include <SD.h>
@ -15,12 +15,12 @@ void sortFileList(std::vector<std::string>& strs) {
});
}
void FileSelectionScreen::taskTrampoline(void* param) {
auto* self = static_cast<FileSelectionScreen*>(param);
void FileSelectionActivity::taskTrampoline(void* param) {
auto* self = static_cast<FileSelectionActivity*>(param);
self->displayTaskLoop();
}
void FileSelectionScreen::loadFiles() {
void FileSelectionActivity::loadFiles() {
files.clear();
selectorIndex = 0;
auto root = SD.open(basepath.c_str());
@ -42,7 +42,7 @@ void FileSelectionScreen::loadFiles() {
sortFileList(files);
}
void FileSelectionScreen::onEnter() {
void FileSelectionActivity::onEnter() {
renderingMutex = xSemaphoreCreateMutex();
basepath = "/";
@ -52,7 +52,7 @@ void FileSelectionScreen::onEnter() {
// Trigger first update
updateRequired = true;
xTaskCreate(&FileSelectionScreen::taskTrampoline, "FileSelectionScreenTask",
xTaskCreate(&FileSelectionActivity::taskTrampoline, "FileSelectionActivityTask",
2048, // Stack size
this, // Parameters
1, // Priority
@ -60,7 +60,7 @@ void FileSelectionScreen::onEnter() {
);
}
void FileSelectionScreen::onExit() {
void FileSelectionActivity::onExit() {
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
xSemaphoreTake(renderingMutex, portMAX_DELAY);
if (displayTaskHandle) {
@ -72,7 +72,7 @@ void FileSelectionScreen::onExit() {
files.clear();
}
void FileSelectionScreen::handleInput() {
void FileSelectionActivity::loop() {
const bool prevPressed =
inputManager.wasPressed(InputManager::BTN_UP) || inputManager.wasPressed(InputManager::BTN_LEFT);
const bool nextPressed =
@ -91,11 +91,16 @@ void FileSelectionScreen::handleInput() {
} else {
onSelect(basepath + files[selectorIndex]);
}
} else if (inputManager.wasPressed(InputManager::BTN_BACK) && basepath != "/") {
basepath = basepath.substr(0, basepath.rfind('/'));
if (basepath.empty()) basepath = "/";
loadFiles();
updateRequired = true;
} else if (inputManager.wasPressed(InputManager::BTN_BACK)) {
if (basepath != "/") {
basepath = basepath.substr(0, basepath.rfind('/'));
if (basepath.empty()) basepath = "/";
loadFiles();
updateRequired = true;
} else {
// At root level, go back home
onGoHome();
}
} else if (prevPressed) {
selectorIndex = (selectorIndex + files.size() - 1) % files.size();
updateRequired = true;
@ -105,7 +110,7 @@ void FileSelectionScreen::handleInput() {
}
}
void FileSelectionScreen::displayTaskLoop() {
void FileSelectionActivity::displayTaskLoop() {
while (true) {
if (updateRequired) {
updateRequired = false;
@ -117,12 +122,15 @@ void FileSelectionScreen::displayTaskLoop() {
}
}
void FileSelectionScreen::render() const {
void FileSelectionActivity::render() const {
renderer.clearScreen();
const auto pageWidth = GfxRenderer::getScreenWidth();
renderer.drawCenteredText(READER_FONT_ID, 10, "CrossPoint Reader", true, BOLD);
// Help text
renderer.drawText(SMALL_FONT_ID, 20, GfxRenderer::getScreenHeight() - 30, "Press BACK for Home");
if (files.empty()) {
renderer.drawText(UI_FONT_ID, 20, 60, "No EPUBs found");
} else {

View File

@ -7,9 +7,9 @@
#include <string>
#include <vector>
#include "Screen.h"
#include "../Activity.h"
class FileSelectionScreen final : public Screen {
class FileSelectionActivity final : public Activity {
TaskHandle_t displayTaskHandle = nullptr;
SemaphoreHandle_t renderingMutex = nullptr;
std::string basepath = "/";
@ -17,6 +17,7 @@ class FileSelectionScreen final : public Screen {
int selectorIndex = 0;
bool updateRequired = false;
const std::function<void(const std::string&)> onSelect;
const std::function<void()> onGoHome;
static void taskTrampoline(void* param);
[[noreturn]] void displayTaskLoop();
@ -24,10 +25,11 @@ class FileSelectionScreen final : public Screen {
void loadFiles();
public:
explicit FileSelectionScreen(GfxRenderer& renderer, InputManager& inputManager,
const std::function<void(const std::string&)>& onSelect)
: Screen(renderer, inputManager), onSelect(onSelect) {}
explicit FileSelectionActivity(GfxRenderer& renderer, InputManager& inputManager,
const std::function<void(const std::string&)>& onSelect,
const std::function<void()>& onGoHome)
: Activity(renderer, inputManager), onSelect(onSelect), onGoHome(onGoHome) {}
void onEnter() override;
void onExit() override;
void handleInput() override;
void loop() override;
};

View File

@ -0,0 +1,68 @@
#include "ReaderActivity.h"
#include <SD.h>
#include "CrossPointState.h"
#include "Epub.h"
#include "EpubReaderActivity.h"
#include "FileSelectionActivity.h"
#include "activities/util/FullScreenMessageActivity.h"
std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
if (!SD.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
return nullptr;
}
auto epub = std::unique_ptr<Epub>(new Epub(path, "/.crosspoint"));
if (epub->load()) {
return epub;
}
Serial.printf("[%lu] [ ] Failed to load epub\n", millis());
return nullptr;
}
void ReaderActivity::onSelectEpubFile(const std::string& path) {
exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, inputManager, "Loading..."));
auto epub = loadEpub(path);
if (epub) {
APP_STATE.openEpubPath = path;
APP_STATE.saveToFile();
onGoToEpubReader(std::move(epub));
} else {
exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, inputManager, "Failed to load epub", REGULAR,
EInkDisplay::HALF_REFRESH));
delay(2000);
onGoToFileSelection();
}
}
void ReaderActivity::onGoToFileSelection() {
exitActivity();
enterNewActivity(new FileSelectionActivity(
renderer, inputManager, [this](const std::string& path) { onSelectEpubFile(path); }, onGoBack));
}
void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) {
exitActivity();
enterNewActivity(new EpubReaderActivity(renderer, inputManager, std::move(epub), [this] { onGoToFileSelection(); }));
}
void ReaderActivity::onEnter() {
if (initialEpubPath.empty()) {
onGoToFileSelection();
return;
}
auto epub = loadEpub(initialEpubPath);
if (!epub) {
onGoBack();
return;
}
onGoToEpubReader(std::move(epub));
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <memory>
#include "../ActivityWithSubactivity.h"
class Epub;
class ReaderActivity final : public ActivityWithSubactivity {
std::string initialEpubPath;
const std::function<void()> onGoBack;
static std::unique_ptr<Epub> loadEpub(const std::string& path);
void onSelectEpubFile(const std::string& path);
void onGoToFileSelection();
void onGoToEpubReader(std::unique_ptr<Epub> epub);
public:
explicit ReaderActivity(GfxRenderer& renderer, InputManager& inputManager, std::string initialEpubPath,
const std::function<void()>& onGoBack)
: ActivityWithSubactivity(renderer, inputManager),
initialEpubPath(std::move(initialEpubPath)),
onGoBack(onGoBack) {}
void onEnter() override;
};

View File

@ -0,0 +1,130 @@
#include "SettingsActivity.h"
#include <GfxRenderer.h>
#include "CrossPointSettings.h"
#include "config.h"
// Define the static settings list
const SettingInfo SettingsActivity::settingsList[settingsCount] = {
{"White Sleep Screen", &CrossPointSettings::whiteSleepScreen},
{"Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing}};
void SettingsActivity::taskTrampoline(void* param) {
auto* self = static_cast<SettingsActivity*>(param);
self->displayTaskLoop();
}
void SettingsActivity::onEnter() {
renderingMutex = xSemaphoreCreateMutex();
// Reset selection to first item
selectedSettingIndex = 0;
// Trigger first update
updateRequired = true;
xTaskCreate(&SettingsActivity::taskTrampoline, "SettingsActivityTask",
2048, // Stack size
this, // Parameters
1, // Priority
&displayTaskHandle // Task handle
);
}
void SettingsActivity::onExit() {
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
xSemaphoreTake(renderingMutex, portMAX_DELAY);
if (displayTaskHandle) {
vTaskDelete(displayTaskHandle);
displayTaskHandle = nullptr;
}
vSemaphoreDelete(renderingMutex);
renderingMutex = nullptr;
}
void SettingsActivity::loop() {
// Handle actions with early return
if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) {
toggleCurrentSetting();
updateRequired = true;
return;
}
if (inputManager.wasPressed(InputManager::BTN_BACK)) {
SETTINGS.saveToFile();
onGoHome();
return;
}
// Handle navigation
if (inputManager.wasPressed(InputManager::BTN_UP) || inputManager.wasPressed(InputManager::BTN_LEFT)) {
// Move selection up (with wrap-around)
selectedSettingIndex = (selectedSettingIndex > 0) ? (selectedSettingIndex - 1) : (settingsCount - 1);
updateRequired = true;
} else if (inputManager.wasPressed(InputManager::BTN_DOWN) || inputManager.wasPressed(InputManager::BTN_RIGHT)) {
// Move selection down (with wrap-around)
selectedSettingIndex = (selectedSettingIndex < settingsCount - 1) ? (selectedSettingIndex + 1) : 0;
updateRequired = true;
}
}
void SettingsActivity::toggleCurrentSetting() {
// Validate index
if (selectedSettingIndex < 0 || selectedSettingIndex >= settingsCount) {
return;
}
// Toggle the boolean value using the member pointer
bool currentValue = SETTINGS.*(settingsList[selectedSettingIndex].valuePtr);
SETTINGS.*(settingsList[selectedSettingIndex].valuePtr) = !currentValue;
// Save settings when they change
SETTINGS.saveToFile();
}
void SettingsActivity::displayTaskLoop() {
while (true) {
if (updateRequired) {
updateRequired = false;
xSemaphoreTake(renderingMutex, portMAX_DELAY);
render();
xSemaphoreGive(renderingMutex);
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
void SettingsActivity::render() const {
renderer.clearScreen();
const auto pageWidth = GfxRenderer::getScreenWidth();
const auto pageHeight = GfxRenderer::getScreenHeight();
// Draw header
renderer.drawCenteredText(READER_FONT_ID, 10, "Settings", true, BOLD);
// We always have at least one setting
// Draw all settings
for (int i = 0; i < settingsCount; i++) {
const int settingY = 60 + i * 30; // 30 pixels between settings
// Draw selection indicator for the selected setting
if (i == selectedSettingIndex) {
renderer.drawText(UI_FONT_ID, 5, settingY, ">");
}
// Draw setting name and value
renderer.drawText(UI_FONT_ID, 20, settingY, settingsList[i].name);
bool value = SETTINGS.*(settingsList[i].valuePtr);
renderer.drawText(UI_FONT_ID, pageWidth - 80, settingY, value ? "ON" : "OFF");
}
// Draw help text
renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 30, "Press OK to toggle, BACK to save & exit");
// Always use standard refresh for settings screen
renderer.displayBuffer();
}

View File

@ -0,0 +1,42 @@
#pragma once
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <freertos/task.h>
#include <cstdint>
#include <string>
#include <vector>
#include "../Activity.h"
class CrossPointSettings;
// Structure to hold setting information
struct SettingInfo {
const char* name; // Display name of the setting
uint8_t CrossPointSettings::* valuePtr; // Pointer to member in CrossPointSettings
};
class SettingsActivity final : public Activity {
TaskHandle_t displayTaskHandle = nullptr;
SemaphoreHandle_t renderingMutex = nullptr;
bool updateRequired = false;
int selectedSettingIndex = 0; // Currently selected setting
const std::function<void()> onGoHome;
// Static settings list
static constexpr int settingsCount = 2; // Number of settings
static const SettingInfo settingsList[settingsCount];
static void taskTrampoline(void* param);
[[noreturn]] void displayTaskLoop();
void render() const;
void toggleCurrentSetting();
public:
explicit SettingsActivity(GfxRenderer& renderer, InputManager& inputManager, const std::function<void()>& onGoHome)
: Activity(renderer, inputManager), onGoHome(onGoHome) {}
void onEnter() override;
void onExit() override;
void loop() override;
};

View File

@ -1,10 +1,10 @@
#include "FullScreenMessageScreen.h"
#include "FullScreenMessageActivity.h"
#include <GfxRenderer.h>
#include "config.h"
void FullScreenMessageScreen::onEnter() {
void FullScreenMessageActivity::onEnter() {
const auto height = renderer.getLineHeight(UI_FONT_ID);
const auto top = (GfxRenderer::getScreenHeight() - height) / 2;

View File

@ -0,0 +1,21 @@
#pragma once
#include <EInkDisplay.h>
#include <EpdFontFamily.h>
#include <string>
#include <utility>
#include "../Activity.h"
class FullScreenMessageActivity final : public Activity {
std::string text;
EpdFontStyle style;
EInkDisplay::RefreshMode refreshMode;
public:
explicit FullScreenMessageActivity(GfxRenderer& renderer, InputManager& inputManager, std::string text,
const EpdFontStyle style = REGULAR,
const EInkDisplay::RefreshMode refreshMode = EInkDisplay::FAST_REFRESH)
: Activity(renderer, inputManager), text(std::move(text)), style(style), refreshMode(refreshMode) {}
void onEnter() override;
};

View File

@ -9,7 +9,7 @@
* "./lib/EpdFont/builtinFonts/bookerly_italic_2b.h",
* ].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
*/
#define READER_FONT_ID 1747632454
#define READER_FONT_ID 828106571
/**
* Generated with:
@ -18,7 +18,7 @@
* "./lib/EpdFont/builtinFonts/ubuntu_bold_10.h",
* ].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
*/
#define UI_FONT_ID 225955604
#define UI_FONT_ID -56235187
/**
* Generated with:
@ -26,4 +26,4 @@
* "./lib/EpdFont/builtinFonts/pixelarial14.h",
* ].map{|f| Digest::SHA256.hexdigest(File.read(f)).to_i(16) }.sum % (2 ** 32) - (2 ** 31)'
*/
#define SMALL_FONT_ID 2037928017
#define SMALL_FONT_ID -1952330053

View File

@ -14,13 +14,15 @@
#include <builtinFonts/ubuntu_bold_10.h>
#include "Battery.h"
#include "CrossPointSettings.h"
#include "CrossPointState.h"
#include "activities/boot_sleep/BootActivity.h"
#include "activities/boot_sleep/SleepActivity.h"
#include "activities/home/HomeActivity.h"
#include "activities/reader/ReaderActivity.h"
#include "activities/settings/SettingsActivity.h"
#include "activities/util/FullScreenMessageActivity.h"
#include "config.h"
#include "screens/BootLogoScreen.h"
#include "screens/EpubReaderScreen.h"
#include "screens/FileSelectionScreen.h"
#include "screens/FullScreenMessageScreen.h"
#include "screens/SleepScreen.h"
#define SPI_FQ 40000000
// Display SPI pins (custom pins for XteinkX4, not hardware SPI defaults)
@ -39,8 +41,7 @@
EInkDisplay einkDisplay(EPD_SCLK, EPD_MOSI, EPD_CS, EPD_DC, EPD_RST, EPD_BUSY);
InputManager inputManager;
GfxRenderer renderer(einkDisplay);
Screen* currentScreen;
CrossPointState appState;
Activity* currentActivity;
// Fonts
EpdFont bookerlyFont(&bookerly_2b);
@ -58,35 +59,22 @@ EpdFontFamily ubuntuFontFamily(&ubuntu10Font, &ubuntuBold10Font);
// Power button timing
// Time required to confirm boot from sleep
constexpr unsigned long POWER_BUTTON_WAKEUP_MS = 1000;
constexpr unsigned long POWER_BUTTON_WAKEUP_MS = 500;
// Time required to enter sleep mode
constexpr unsigned long POWER_BUTTON_SLEEP_MS = 1000;
constexpr unsigned long POWER_BUTTON_SLEEP_MS = 500;
// Auto-sleep timeout (10 minutes of inactivity)
constexpr unsigned long AUTO_SLEEP_TIMEOUT_MS = 10 * 60 * 1000;
std::unique_ptr<Epub> loadEpub(const std::string& path) {
if (!SD.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
return nullptr;
}
auto epub = std::unique_ptr<Epub>(new Epub(path, "/.crosspoint"));
if (epub->load()) {
return epub;
}
Serial.printf("[%lu] [ ] Failed to load epub\n", millis());
return nullptr;
}
void exitScreen() {
if (currentScreen) {
currentScreen->onExit();
delete currentScreen;
void exitActivity() {
if (currentActivity) {
currentActivity->onExit();
delete currentActivity;
}
}
void enterNewScreen(Screen* screen) {
currentScreen = screen;
currentScreen->onEnter();
void enterNewActivity(Activity* activity) {
currentActivity = activity;
currentActivity->onEnter();
}
// Verify long press on wake-up from deep sleep
@ -130,8 +118,8 @@ void waitForPowerRelease() {
// Enter deep sleep mode
void enterDeepSleep() {
exitScreen();
enterNewScreen(new SleepScreen(renderer, inputManager));
exitActivity();
enterNewActivity(new SleepActivity(renderer, inputManager));
Serial.printf("[%lu] [ ] Power button released after a long press. Entering deep sleep.\n", millis());
delay(1000); // Allow Serial buffer to empty and display to update
@ -146,28 +134,20 @@ void enterDeepSleep() {
}
void onGoHome();
void onSelectEpubFile(const std::string& path) {
exitScreen();
enterNewScreen(new FullScreenMessageScreen(renderer, inputManager, "Loading..."));
void onGoToReader(const std::string& initialEpubPath) {
exitActivity();
enterNewActivity(new ReaderActivity(renderer, inputManager, initialEpubPath, onGoHome));
}
void onGoToReaderHome() { onGoToReader(std::string()); }
auto epub = loadEpub(path);
if (epub) {
appState.openEpubPath = path;
appState.saveToFile();
exitScreen();
enterNewScreen(new EpubReaderScreen(renderer, inputManager, std::move(epub), onGoHome));
} else {
exitScreen();
enterNewScreen(
new FullScreenMessageScreen(renderer, inputManager, "Failed to load epub", REGULAR, EInkDisplay::HALF_REFRESH));
delay(2000);
onGoHome();
}
void onGoToSettings() {
exitActivity();
enterNewActivity(new SettingsActivity(renderer, inputManager, onGoHome));
}
void onGoHome() {
exitScreen();
enterNewScreen(new FileSelectionScreen(renderer, inputManager, onSelectEpubFile));
exitActivity();
enterNewActivity(new HomeActivity(renderer, inputManager, onGoToReaderHome, onGoToSettings));
}
void setup() {
@ -193,27 +173,20 @@ void setup() {
renderer.insertFont(SMALL_FONT_ID, smallFontFamily);
Serial.printf("[%lu] [ ] Fonts setup\n", millis());
exitScreen();
enterNewScreen(new BootLogoScreen(renderer, inputManager));
exitActivity();
enterNewActivity(new BootActivity(renderer, inputManager));
// SD Card Initialization
SD.begin(SD_SPI_CS, SPI, SPI_FQ);
appState.loadFromFile();
if (!appState.openEpubPath.empty()) {
auto epub = loadEpub(appState.openEpubPath);
if (epub) {
exitScreen();
enterNewScreen(new EpubReaderScreen(renderer, inputManager, std::move(epub), onGoHome));
// Ensure we're not still holding the power button before leaving setup
waitForPowerRelease();
return;
}
SETTINGS.loadFromFile();
APP_STATE.loadFromFile();
if (APP_STATE.openEpubPath.empty()) {
onGoHome();
} else {
onGoToReader(APP_STATE.openEpubPath);
}
exitScreen();
enterNewScreen(new FileSelectionScreen(renderer, inputManager, onSelectEpubFile));
// Ensure we're not still holding the power button before leaving setup
waitForPowerRelease();
}
@ -229,13 +202,27 @@ void loop() {
}
inputManager.update();
// Check for any user activity (button press or release)
static unsigned long lastActivityTime = millis();
if (inputManager.wasAnyPressed() || inputManager.wasAnyReleased()) {
lastActivityTime = millis(); // Reset inactivity timer
}
if (millis() - lastActivityTime >= AUTO_SLEEP_TIMEOUT_MS) {
Serial.printf("[%lu] [SLP] Auto-sleep triggered after %lu ms of inactivity\n", millis(), AUTO_SLEEP_TIMEOUT_MS);
enterDeepSleep();
// This should never be hit as `enterDeepSleep` calls esp_deep_sleep_start
return;
}
if (inputManager.wasReleased(InputManager::BTN_POWER) && inputManager.getHeldTime() > POWER_BUTTON_WAKEUP_MS) {
enterDeepSleep();
// This should never be hit as `enterDeepSleep` calls esp_deep_sleep_start
return;
}
if (currentScreen) {
currentScreen->handleInput();
if (currentActivity) {
currentActivity->loop();
}
}

View File

@ -1,8 +0,0 @@
#pragma once
#include "Screen.h"
class BootLogoScreen final : public Screen {
public:
explicit BootLogoScreen(GfxRenderer& renderer, InputManager& inputManager) : Screen(renderer, inputManager) {}
void onEnter() override;
};

View File

@ -1,21 +0,0 @@
#pragma once
#include <EInkDisplay.h>
#include <EpdFontFamily.h>
#include <string>
#include <utility>
#include "Screen.h"
class FullScreenMessageScreen final : public Screen {
std::string text;
EpdFontStyle style;
EInkDisplay::RefreshMode refreshMode;
public:
explicit FullScreenMessageScreen(GfxRenderer& renderer, InputManager& inputManager, std::string text,
const EpdFontStyle style = REGULAR,
const EInkDisplay::RefreshMode refreshMode = EInkDisplay::FAST_REFRESH)
: Screen(renderer, inputManager), text(std::move(text)), style(style), refreshMode(refreshMode) {}
void onEnter() override;
};

View File

@ -1,17 +0,0 @@
#pragma once
#include <InputManager.h>
class GfxRenderer;
class Screen {
protected:
GfxRenderer& renderer;
InputManager& inputManager;
public:
explicit Screen(GfxRenderer& renderer, InputManager& inputManager) : renderer(renderer), inputManager(inputManager) {}
virtual ~Screen() = default;
virtual void onEnter() {}
virtual void onExit() {}
virtual void handleInput() {}
};

View File

@ -1,8 +0,0 @@
#pragma once
#include "Screen.h"
class SleepScreen final : public Screen {
public:
explicit SleepScreen(GfxRenderer& renderer, InputManager& inputManager) : Screen(renderer, inputManager) {}
void onEnter() override;
};