Merge pull request #48 from Blueforcer/development

- Fixes some rendering issues in the GIF decoder.
- 32x8 gifs are possible
- New json key: "textCase"
- Slight color correction
- Http /api/loop shows the current apps in loop.
- Sends uptime to HA in seconds closes #45 
- /apps api improved, deleting and reordering apps should work a bit better. closes #41 
- Memory leak fixed, closes #38
This commit is contained in:
Stephan Mühl
2023-04-09 21:08:31 +02:00
committed by GitHub
33 changed files with 1800 additions and 2040 deletions

10
.vscode/settings.json vendored
View File

@@ -47,6 +47,14 @@
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
"typeinfo": "cpp",
"tjpgd.h": "c",
"chrono": "cpp",
"condition_variable": "cpp",
"list": "cpp",
"ratio": "cpp",
"mutex": "cpp",
"thread": "cpp",
"set": "cpp"
}
}

View File

@@ -17,5 +17,4 @@
- API
- [MQTT/HTTP](api.md)
- [Custom Pages & Notifications](custom.md)

View File

@@ -14,14 +14,61 @@ You can start the update with update button in HA or:
| --- | --- | --- | --- | --- |
| `[PREFIX]/doupdate` |`http://[IP]/api/doupdate` | JSON | empty payload/body | POST |
## Add custom app
create custom apps or notifications to display your own text and icons.
Have a look at [this section](custom?id=custom-apps-and-notifications)
## Custom Apps and Notifications
With AWTRIX Light, you can create custom apps or notifications to display your own text and icons.
With MQTT simply send a JSON object to the topic `[PREFIX]/custom/[page]` where [page] is a the name of your page (without spaces).
With the [HTTP API](api?id=add-custom-app) you have to set the appname in the request header (`name = Appname`)
| Topic | URL | Payload/Body | Query parameters | HTTP method |
| --- | --- | --- | --- | --- |
| `[PREFIX]/custom/[appname]` |`http://[IP]/api/custom` | JSON | name = [appname] | POST |
### JSON Properties
The JSON object has the following properties:
| Key | Type | Description | Default |
| --- | ---- | ----------- | ------- |
| `pos` | number | defines the position of your custompage in the loop, starting at 0 for the first position. This will only apply with your first push. You cant change the position afterwards with [this function](api?id=addremove-and-rearange-apps) |
| `text` | string | The text to display on the app. | |
| `icon` | string | The icon ID or filename (without extension) to display on the app. | |
| `repeat` | number | Sets how many times the text should be scrolled through the matrix before the app ends. | 1 |
| `rainbow` | boolean | Fades each letter in the text differently through the entire RGB spectrum. | false |
| `duration` | number | Sets how long the app or notification should be displayed. | 5 |
| `color` | string | A color hex string for the text color, or an array of R,G,B values | "#FFFFFF" or [255,255,0] |
| `hold` | boolean | Set it to true, to hold your **notification** on top until you press the middle button or dismiss it via HomeAssistant. This key only belongs to notification. | false |
| `sound` | string | The filename of your RTTTL ringtone file (without extension). | |
| `pushIcon` | number | 0 = Icon doesn't move. 1 = Icon moves with text and will not appear again. 2 = Icon moves with text but appears again when the text starts to scroll again. | 0 |
| `bar` | array of integers | draws a bargraph. Without icon maximum 16 values, with icon 11 values | |
| `textCase` | integer | Changes teh Uppercase setting. 0=global setting, 1=forces uppercase; 2=shows what is sent. | 0 |
All keys are optional, so you can send just the properties you want to use.
To update a custom page, simply send a modified JSON object to the same topic. The display will be updated immediately.
You can also send a one-time notification with the same JSON format. Simply send your JSON object to "awtrixlight/notify".
### Example
Here's an example JSON object to display the text "Hello, AWTRIX Light!" with the icon name "1", in rainbow colors, for 10 seconds:
```json
{
"text": "Hello, AWTRIX Light!",
"icon": "1",
"rainbow": true,
"duration": 10
}
```
## Delete a custom app
To delete a custom app simply send a empty payload/body to the same topic/url.
You can also use [this API](api?id=addremove-and-rearange-apps)
## Dismiss Notification
Dismiss a notification which was set to "hold"=true.

View File

@@ -22,6 +22,8 @@ The JSON object has the following properties:
| `sound` | string | The filename of your RTTTL ringtone file (without extension). | |
| `pushIcon` | number | 0 = Icon doesn't move. 1 = Icon moves with text and will not appear again. 2 = Icon moves with text but appears again when the text starts to scroll again. | 0 |
| `bar` | array of integers | draws a bargraph. Without icon maximum 16 values, with icon 11 values | |
| `textCase` | integer | Changes teh Uppercase setting. 0=global setting, 1=forces uppercase; 2=shows what is sent. | 0 |
All keys are optional, so you can send just the properties you want to use.

View File

@@ -11,5 +11,6 @@ The JSON object has the following properties:
| Key | Type | Description | Default |
| --- | ---- | ----------- | ------- |
| `bootsound` | string | Uses a custom melodie from the MELODIES folder | |
| `bootsound` | string | Uses a custom melodie while booting | |
| `uppercase` | boolean | Print every character in uppercase | true |
| `temp_dec_places` | int | Number of decimal places for temperature measurements | 0 |

View File

@@ -254,7 +254,7 @@ const uint8_t AwtrixBitmaps[] PROGMEM = {
0x00, /*[199] 0x13A0 uni13A0 */
0x80, /*[200] 0x2022 bullet */
0xA0, /*[201] 0x2026 ellipsis */
0x60, 0xE0, 0xE0, 0xC0, 0x60, /*[202] 0x20AC Euro */
0x60, 0xC0, 0xE0, 0xC0, 0x60, /*[202] 0x20AC Euro */
0xE0, 0xA0, 0xA0, 0xA0, 0xE0, /*[203] 0xFFFD uniFFFD */
};

View File

@@ -1,320 +0,0 @@
const uint8_t Fallout[] PROGMEM = {
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xF8,
0xF9, 0xCF, 0x9C, 0xF9, 0xCF, 0x9F, 0xF9, 0xF0, 0x3E, 0x3E, 0x1F, 0x1F,
0x0F, 0x8F, 0x87, 0xC7, 0xC3, 0xE3, 0xE7, 0xFF, 0xF3, 0xFF, 0xF8, 0x7C,
0x7C, 0x3E, 0x3E, 0x1F, 0x1F, 0x3F, 0xFF, 0xFF, 0xFF, 0xF3, 0xE3, 0xE1,
0xF1, 0xF0, 0xF8, 0xF8, 0x7C, 0x7C, 0x3E, 0x3E, 0x00, 0x07, 0xC0, 0x0F,
0x80, 0xFF, 0xF9, 0xFF, 0xF3, 0xFF, 0xFF, 0x00, 0x3E, 0x00, 0x1F, 0xF8,
0x3F, 0xF0, 0x7F, 0xE0, 0x00, 0xF8, 0x01, 0xFF, 0xFF, 0x1F, 0xFE, 0x3F,
0xFC, 0x03, 0xE0, 0x07, 0xC0, 0xF8, 0x01, 0x8F, 0x80, 0x18, 0xF8, 0x0F,
0x8F, 0x80, 0xF8, 0xF8, 0x0F, 0x80, 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x1F,
0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x3E,
0x01, 0xF3, 0xE0, 0x1F, 0x3E, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xF0,
0x07, 0xF0, 0x03, 0xF8, 0x0F, 0x8F, 0x87, 0xC7, 0xC3, 0xE3, 0xE0, 0x3F,
0x80, 0x1F, 0xC0, 0x7F, 0x9F, 0x3F, 0xCF, 0x9F, 0xE7, 0xFE, 0x7F, 0x9F,
0x3F, 0xCF, 0x83, 0xE7, 0xC1, 0xF3, 0xE0, 0xF8, 0x7F, 0x9F, 0x3F, 0xCF,
0x80, 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0xC1, 0xF3, 0xE0, 0xF8, 0x3E, 0x3E,
0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0x3E, 0x0F, 0x83, 0xE0,
0x1F, 0x07, 0xC0, 0xF8, 0x3E, 0x03, 0xE0, 0xF8, 0x3E, 0x01, 0xF0, 0x7C,
0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x3E, 0x0F, 0x83, 0xE3, 0xE0, 0xF8,
0x00, 0x3E, 0x3E, 0x1F, 0x1F, 0x0F, 0x8F, 0x80, 0xFE, 0x00, 0x7F, 0x07,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xF0, 0x03, 0xF8, 0x0F, 0x8F,
0x87, 0xC7, 0xC3, 0xE3, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E,
0x00, 0x7C, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x0F, 0x80,
0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0x3E, 0x7C, 0xF9, 0xF3, 0xFF, 0x3E,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x80, 0x00,
0x0E, 0x00, 0x1C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x3E, 0x00, 0x7C,
0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0xF8, 0x01, 0xF0, 0x0F, 0x80, 0x1F,
0x00, 0x3E, 0x00, 0x60, 0x00, 0xC0, 0x00, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0,
0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x3F, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xF8, 0xFF, 0xF1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0x9F,
0xF8, 0x3F, 0xF0, 0x07, 0xC1, 0xF3, 0xFC, 0xFF, 0x3F, 0xFF, 0xFF, 0xFC,
0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07,
0xC0, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xE0, 0x07,
0xC0, 0x0F, 0x83, 0xF8, 0x07, 0xF0, 0x0F, 0xE0, 0xF8, 0x01, 0xF0, 0x0F,
0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7F, 0xFF, 0xFF, 0xFE, 0x3F, 0xF0, 0x7F,
0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xE0, 0x07, 0xC0, 0x0F, 0x83, 0xF8,
0x07, 0xF0, 0x0F, 0xE0, 0x00, 0xF8, 0x01, 0xFF, 0x83, 0xFF, 0x07, 0xFE,
0x0F, 0x9F, 0xF8, 0x3F, 0xF0, 0x01, 0xFE, 0x03, 0xFC, 0x1F, 0xF8, 0x3F,
0xF0, 0x7F, 0xE7, 0xC7, 0xCF, 0x8F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7F,
0xFF, 0xFF, 0xFF, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00,
0x3E, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0xFE,
0x3F, 0xFC, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xFF,
0x83, 0xFF, 0x07, 0xFE, 0x0F, 0x9F, 0xF8, 0x3F, 0xF0, 0x07, 0xF0, 0x0F,
0xE0, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x1F, 0x00, 0x3E, 0x00, 0x7F, 0xF8,
0xFF, 0xF1, 0xFF, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE,
0x0F, 0x9F, 0xF8, 0x3F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xC1,
0xFF, 0x83, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0xF8, 0x01, 0xF0, 0x03, 0xE0,
0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07,
0xC0, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07,
0xFE, 0x0F, 0x9F, 0xF8, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF,
0x83, 0xFF, 0x07, 0xFE, 0x0F, 0x9F, 0xF8, 0x3F, 0xF0, 0x3F, 0xF0, 0x7F,
0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0x9F, 0xFF,
0x3F, 0xFE, 0x7F, 0xFC, 0x00, 0xF8, 0x01, 0xF0, 0x1F, 0x00, 0x3E, 0x00,
0x7C, 0x1F, 0xE0, 0x3F, 0xC0, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x3F,
0xFF, 0xFF, 0xE0, 0x3E, 0x7C, 0xF9, 0xF3, 0xE0, 0x00, 0x00, 0x00, 0x00,
0xF9, 0xF3, 0xE7, 0xCF, 0xFC, 0xF8, 0x01, 0xF0, 0x1F, 0x07, 0xC0, 0x7C,
0x07, 0xC3, 0xE0, 0x3E, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0x3E, 0x03, 0xE0,
0x07, 0xC0, 0x7C, 0x07, 0xC0, 0x1F, 0x01, 0xF0, 0xFF, 0xFF, 0xFF, 0xFC,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF,
0xFF, 0xFF, 0xFC, 0xF8, 0x0F, 0x80, 0x3E, 0x03, 0xE0, 0x3E, 0x00, 0x7C,
0x07, 0xC0, 0x1F, 0x01, 0xF0, 0x1F, 0x07, 0xC0, 0x7C, 0x3E, 0x03, 0xE0,
0x3E, 0x0F, 0x80, 0xF8, 0x00, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1,
0xFF, 0x83, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0xF8, 0x01, 0xF0, 0x03, 0xE0,
0x1F, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE0, 0x07,
0xC0, 0x3F, 0xFE, 0x1F, 0xFF, 0x3E, 0x03, 0x9F, 0x01, 0xCF, 0x80, 0xE7,
0xCF, 0xFF, 0xE7, 0xFF, 0xF3, 0xFF, 0xF9, 0xFF, 0xFC, 0xFF, 0xFE, 0x7F,
0xFF, 0x3F, 0xFF, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x00, 0x7F, 0xE0, 0x3F,
0xF0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x18, 0x00, 0x0F, 0xF0, 0x00, 0xFF,
0x00, 0x0F, 0xF0, 0x03, 0xFF, 0x00, 0x3F, 0xF0, 0x1F, 0x1F, 0x01, 0xF1,
0xF0, 0x1F, 0x1F, 0x07, 0xFF, 0xF0, 0x7F, 0xFF, 0x3E, 0x01, 0xF3, 0xE0,
0x1F, 0x3E, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xF0, 0xFF, 0xFE, 0x7F,
0xFF, 0x3E, 0x03, 0x9F, 0x01, 0xCF, 0x80, 0xE7, 0xC0, 0x7F, 0xE0, 0x3F,
0xFF, 0xFC, 0xFF, 0xFE, 0x7F, 0xFF, 0x3E, 0x03, 0xFF, 0x01, 0xFF, 0x80,
0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xFF, 0xFC, 0xFF, 0xFE, 0x00, 0x3F, 0xFE,
0x7F, 0xFF, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C,
0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00,
0x3E, 0x00, 0x1F, 0xFF, 0x3F, 0xFE, 0xFF, 0xFE, 0x7F, 0xFF, 0x3E, 0x03,
0x9F, 0x01, 0xCF, 0x80, 0xE7, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8,
0x0F, 0xFC, 0x07, 0xFE, 0x03, 0xFF, 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F,
0xE0, 0x3F, 0xFF, 0xFC, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0,
0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7F, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7F,
0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xC0, 0x0F, 0x80,
0x1F, 0x00, 0x3E, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07,
0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x00, 0x3F,
0xFE, 0x1F, 0xFF, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03,
0xE0, 0x01, 0xF0, 0x7F, 0xF8, 0x3F, 0xFC, 0x1F, 0xFE, 0x03, 0xFF, 0x01,
0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3E, 0x7F, 0xFC, 0x3F, 0xFE, 0x00,
0xF8, 0x0E, 0x7C, 0x07, 0x3E, 0x03, 0xFF, 0x01, 0xFF, 0x80, 0xFF, 0xC0,
0x7F, 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x03, 0xFF,
0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F,
0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8,
0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00,
0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xFE, 0x03, 0xFF,
0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3E, 0x7F, 0xFC, 0x3F, 0xFE,
0x00, 0xF8, 0x0E, 0x7C, 0x07, 0x3E, 0x0F, 0x9F, 0x07, 0xCF, 0x83, 0xE7,
0xCF, 0x83, 0xE7, 0xC1, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3E, 0x7C,
0x1F, 0x3E, 0x0F, 0x83, 0xE7, 0xC1, 0xF3, 0xE0, 0xF9, 0xF0, 0x1F, 0xF8,
0x0F, 0x80, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F,
0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0,
0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7F, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE,
0x7F, 0xFF, 0x3E, 0x73, 0x9F, 0x39, 0xCF, 0x9C, 0xE7, 0xCE, 0x7F, 0xE7,
0x3F, 0xF3, 0x9F, 0xF9, 0xCF, 0xFC, 0xE7, 0xFE, 0x73, 0xFF, 0x39, 0xFF,
0x9C, 0xFF, 0xCE, 0x7F, 0xE7, 0x3F, 0xF3, 0x9F, 0xF9, 0xCF, 0x80, 0xF8,
0x0E, 0x7C, 0x07, 0x3F, 0x83, 0xFF, 0xC1, 0xFF, 0xE0, 0xFF, 0xFE, 0x7F,
0xFF, 0x3F, 0xF3, 0xFF, 0xF9, 0xFF, 0xFC, 0xFF, 0xFE, 0x0F, 0xFF, 0x07,
0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0x80,
0x3F, 0xFE, 0x1F, 0xFF, 0x3E, 0x03, 0x9F, 0x01, 0xCF, 0x80, 0xE7, 0xC0,
0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFE, 0x03, 0xFF,
0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3E, 0x7F, 0xFC, 0x3F, 0xFE,
0x00, 0xFF, 0xFE, 0x7F, 0xFF, 0x3E, 0x03, 0x9F, 0x01, 0xCF, 0x80, 0xE7,
0xC0, 0x7F, 0xE0, 0x3F, 0xFF, 0xFC, 0xFF, 0xFE, 0x7F, 0xFF, 0x3E, 0x00,
0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8,
0x00, 0x00, 0x3F, 0xFE, 0x1F, 0xFF, 0x3E, 0x03, 0x9F, 0x01, 0xCF, 0x80,
0xE7, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFE,
0x03, 0xFF, 0x01, 0xFF, 0x9C, 0xFF, 0xCE, 0x7F, 0xE7, 0x3E, 0x7F, 0xFC,
0x3F, 0xFE, 0x00, 0x1F, 0xC0, 0x0F, 0xE0, 0xFF, 0xFE, 0x7F, 0xFF, 0x3E,
0x03, 0x9F, 0x01, 0xCF, 0x80, 0xE7, 0xC0, 0x7F, 0xE0, 0x3F, 0xFF, 0xFC,
0xFF, 0xFE, 0x7F, 0xFF, 0x3E, 0x03, 0xFF, 0x01, 0xFF, 0x80, 0xFF, 0xC0,
0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0x80, 0x3F, 0xFE, 0x1F, 0xFF,
0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x00, 0x7F,
0xFC, 0x3F, 0xFE, 0x1F, 0xFF, 0x00, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8,
0x00, 0x7C, 0x00, 0x3F, 0xFF, 0xFC, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFF,
0xFC, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0,
0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01,
0xF0, 0x03, 0xE0, 0x07, 0xC0, 0xF8, 0x0E, 0x7C, 0x07, 0x3E, 0x03, 0xFF,
0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F,
0xFC, 0x07, 0xFE, 0x03, 0xFF, 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0,
0x3E, 0x7F, 0xFF, 0x3F, 0xFF, 0x80, 0xF8, 0x01, 0x8F, 0x80, 0x18, 0xF8,
0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xF3, 0xE0, 0xF8, 0x3E, 0x0F, 0x83,
0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x07, 0xFE, 0x00, 0x7F, 0xE0,
0x07, 0xFE, 0x00, 0x7F, 0xE0, 0x07, 0xFE, 0x00, 0x1F, 0x00, 0x01, 0xF0,
0x00, 0xF9, 0xCE, 0x7C, 0xE7, 0x3E, 0x73, 0xFF, 0x39, 0xFF, 0x9C, 0xFF,
0xCE, 0x7F, 0xE7, 0x3F, 0xF3, 0x9F, 0xF9, 0xCF, 0xFC, 0xE7, 0xFE, 0x73,
0xFF, 0x39, 0xFF, 0x9C, 0xFF, 0xCE, 0x7F, 0xE7, 0x3F, 0xFF, 0xFC, 0xFF,
0xFE, 0x00, 0xF8, 0x01, 0x8F, 0x80, 0x18, 0xF8, 0x01, 0xFF, 0x80, 0x1F,
0xF8, 0x01, 0xF3, 0xE0, 0xF8, 0x3E, 0x0F, 0x80, 0x7F, 0xE0, 0x07, 0xFE,
0x00, 0x7F, 0xE0, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0xF8, 0x01, 0xFF, 0x80,
0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xF0, 0xF8, 0x01, 0xFC,
0x00, 0xCF, 0x83, 0xE7, 0xC1, 0xF3, 0xE0, 0xF8, 0x3F, 0xF0, 0x1F, 0xF8,
0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F,
0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xFF, 0xFE,
0x7F, 0xFF, 0x00, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x01, 0xF0, 0x00,
0xF8, 0x0F, 0xE0, 0x07, 0xF0, 0x03, 0xF8, 0x0F, 0x80, 0x07, 0xC0, 0x0F,
0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF,
0xFF, 0xFF, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F,
0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xFF, 0xFF, 0xC0, 0xC0, 0x00, 0x60,
0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0xF8, 0x00,
0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x03,
0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0xFF, 0xFF,
0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C,
0x1F, 0x07, 0xC1, 0xF0, 0x7F, 0xFF, 0xFF, 0xC0, 0x01, 0xC0, 0x00, 0xE0,
0x01, 0xFC, 0x00, 0xFE, 0x00, 0x7F, 0x01, 0xF1, 0xF0, 0xF8, 0xF9, 0xF0,
0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xC0, 0xFF, 0xFF, 0xFF, 0xFC, 0xF9, 0xF3,
0xE7, 0xCF, 0x87, 0xCF, 0x80, 0x3F, 0xFE, 0x7F, 0xFF, 0xE0, 0xFF, 0xC1,
0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7C,
0xFF, 0xF9, 0xFF, 0xF0, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F,
0x80, 0x1F, 0xFE, 0x3F, 0xFC, 0x7C, 0x1F, 0xF8, 0x3F, 0xF0, 0x7F, 0xE0,
0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0xFF, 0xF8, 0xFF, 0xF0,
0x3F, 0xF3, 0xFF, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80,
0xF8, 0x0F, 0x80, 0x3F, 0xF3, 0xFF, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8,
0x01, 0xF0, 0x03, 0xE7, 0xFF, 0xCF, 0xFF, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0,
0x7F, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0x9F, 0xFF,
0x3F, 0xFE, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF,
0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0xF8, 0x01, 0xF0, 0x00, 0xFF, 0xC1, 0xFF,
0x80, 0x07, 0xF0, 0x7F, 0x3E, 0x03, 0xE0, 0x3E, 0x0F, 0xFF, 0xFF, 0xF3,
0xE0, 0x3E, 0x03, 0xE0, 0x3E, 0x03, 0xE0, 0x3E, 0x03, 0xE0, 0x3E, 0x03,
0xE0, 0x3E, 0x00, 0x3F, 0xFE, 0x7F, 0xFF, 0xE0, 0xFF, 0xC1, 0xFF, 0x83,
0xFF, 0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7C, 0xFF, 0xF9,
0xFF, 0xF0, 0x03, 0xE0, 0x07, 0xCF, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0xF8,
0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0xFE, 0x3F, 0xFC,
0x7C, 0x1F, 0xF8, 0x3F, 0xF0, 0x7F, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF,
0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xF0, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F,
0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0xF9, 0xFF, 0x9F,
0x3F, 0xC3, 0xFC, 0x3F, 0xC0, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0,
0x0F, 0x80, 0x1F, 0x07, 0xFE, 0x0F, 0xFC, 0xF8, 0xF9, 0xF1, 0xF3, 0xE3,
0xFF, 0x07, 0xFE, 0x0F, 0x9F, 0x1F, 0x3E, 0x3E, 0x7C, 0x7C, 0x1F, 0xF8,
0x3E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8,
0xFF, 0xFE, 0x7F, 0xFF, 0x3E, 0x73, 0xFF, 0x39, 0xFF, 0x9C, 0xFF, 0xCE,
0x7F, 0xE7, 0x3F, 0xF3, 0x9F, 0xF9, 0xCF, 0xFC, 0xE7, 0xFE, 0x73, 0xFF,
0x39, 0xF0, 0xFF, 0xF1, 0xFF, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF,
0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7F, 0xE0, 0xFF, 0xC1,
0xF0, 0x3F, 0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07,
0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7C, 0xFF, 0xC1, 0xFF, 0x80,
0xFF, 0xF1, 0xFF, 0xE3, 0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE,
0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7F, 0xFF, 0xC7, 0xFF, 0x8F, 0x80,
0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x00, 0x3F, 0xFE, 0x7F, 0xFF,
0xE0, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8,
0x3F, 0xF0, 0x7C, 0xFF, 0xF9, 0xFF, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F,
0x80, 0x1F, 0x00, 0x3E, 0xF9, 0xFF, 0x9F, 0xFF, 0xCF, 0xFC, 0xFF, 0xCF,
0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0x3F, 0xF0,
0x7F, 0xE3, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x07, 0xFE, 0x0F, 0xFC, 0x00,
0x1F, 0x00, 0x3E, 0x00, 0x7C, 0xFF, 0xC1, 0xFF, 0x80, 0x07, 0xC0, 0x0F,
0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x1F, 0xFF, 0xFF, 0xFF, 0x83, 0xE0,
0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x01,
0xF0, 0x03, 0xE0, 0x07, 0xC0, 0xF8, 0x3F, 0xF0, 0x7F, 0xE0, 0xFF, 0xC1,
0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF0, 0x7C,
0xFF, 0xF9, 0xFF, 0xF0, 0xF8, 0x0E, 0x7C, 0x07, 0x3E, 0x03, 0xFF, 0x01,
0xFF, 0x80, 0xF9, 0xF1, 0xF0, 0xF8, 0xF8, 0x7C, 0x7C, 0x3E, 0x3E, 0x1F,
0x1F, 0x01, 0xFC, 0x00, 0xFE, 0x00, 0xF9, 0xCE, 0x7C, 0xE7, 0x3E, 0x73,
0xFF, 0x39, 0xFF, 0x9C, 0xFF, 0xCE, 0x7F, 0xE7, 0x3F, 0xF3, 0x9F, 0xF9,
0xCF, 0xFC, 0xE7, 0xFF, 0xFF, 0x9F, 0xFF, 0xC0, 0xF8, 0x3F, 0xF0, 0x7C,
0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x00, 0xF8, 0x01, 0xF0, 0x1F, 0xF8, 0x3F,
0xF0, 0x7F, 0xE3, 0xE0, 0xFF, 0xC1, 0xF0, 0xF8, 0x3F, 0xF0, 0x7F, 0xE0,
0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xFE, 0x0F, 0xFC, 0x1F, 0xF8, 0x3F,
0xF0, 0x7C, 0xFF, 0xF9, 0xFF, 0xF0, 0x03, 0xE0, 0x07, 0xCF, 0xFC, 0x1F,
0xF8, 0x3F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFC, 0x07, 0xC0, 0x0F, 0x80, 0x1F,
0x00, 0xF8, 0x01, 0xF0, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x03, 0xFF, 0xFF,
0xFF, 0xF0, 0x07, 0xF0, 0x7F, 0x3E, 0x03, 0xE0, 0x3E, 0x03, 0xE0, 0x3E,
0x0F, 0x80, 0xF8, 0x0F, 0x80, 0x3E, 0x03, 0xE0, 0x3E, 0x03, 0xE0, 0x3E,
0x00, 0x7F, 0x07, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFE, 0x0F, 0xE0, 0x07, 0xC0, 0x7C,
0x07, 0xC0, 0x7C, 0x07, 0xC0, 0x1F, 0x01, 0xF0, 0x1F, 0x07, 0xC0, 0x7C,
0x07, 0xC0, 0x7C, 0x07, 0xCF, 0xE0, 0xFE, 0x00, 0x3E, 0x0E, 0x7C, 0x1F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x3E, 0x30, 0x7C, 0x00 };
const GFXglyph FalloutGlyphs[] PROGMEM = {
{ 0, 1, 1, 12, 0, 0 }, // 0x20 ' '
{ 1, 5, 17, 7, 0, -16 }, // 0x21 '!'
{ 12, 12, 5, 15, 0, -19 }, // 0x22 '"'
{ 20, 17, 17, 20, 0, -16 }, // 0x23 '#'
{ 57, 15, 17, 17, 0, -16 }, // 0x24 '$'
{ 89, 20, 17, 22, 0, -16 }, // 0x25 '%'
{ 132, 17, 17, 20, 0, -16 }, // 0x26 '&'
{ 169, 5, 5, 7, 0, -19 }, // 0x27 '''
{ 173, 10, 17, 12, 0, -16 }, // 0x28 '('
{ 195, 10, 17, 12, 0, -16 }, // 0x29 ')'
{ 217, 17, 13, 20, 0, -14 }, // 0x2A '*'
{ 245, 15, 13, 17, 0, -14 }, // 0x2B '+'
{ 270, 7, 7, 10, 0, -4 }, // 0x2C ','
{ 277, 15, 3, 17, 0, -9 }, // 0x2D '-'
{ 283, 5, 5, 7, 0, -4 }, // 0x2E '.'
{ 287, 15, 17, 17, 0, -16 }, // 0x2F '/'
{ 319, 15, 17, 17, 0, -16 }, // 0x30 '0'
{ 351, 10, 17, 12, 0, -16 }, // 0x31 '1'
{ 373, 15, 17, 17, 0, -16 }, // 0x32 '2'
{ 405, 15, 17, 17, 0, -16 }, // 0x33 '3'
{ 437, 15, 17, 17, 0, -16 }, // 0x34 '4'
{ 469, 15, 17, 17, 0, -16 }, // 0x35 '5'
{ 501, 15, 17, 17, 0, -16 }, // 0x36 '6'
{ 533, 15, 17, 17, 0, -16 }, // 0x37 '7'
{ 565, 15, 17, 17, 0, -16 }, // 0x38 '8'
{ 597, 15, 17, 17, 0, -16 }, // 0x39 '9'
{ 629, 5, 15, 7, 0, -14 }, // 0x3A ':'
{ 639, 7, 17, 10, 0, -14 }, // 0x3B ';'
{ 654, 12, 17, 15, 0, -16 }, // 0x3C '<'
{ 680, 15, 10, 17, 0, -11 }, // 0x3D '='
{ 699, 12, 17, 15, 0, -16 }, // 0x3E '>'
{ 725, 15, 17, 17, 0, -16 }, // 0x3F '?'
{ 757, 17, 17, 20, 0, -16 }, // 0x40 '@'
{ 794, 20, 17, 22, 0, -16 }, // 0x41 'A'
{ 837, 17, 17, 20, 0, -16 }, // 0x42 'B'
{ 874, 15, 17, 17, 0, -16 }, // 0x43 'C'
{ 906, 17, 17, 20, 0, -16 }, // 0x44 'D'
{ 943, 15, 17, 17, 0, -16 }, // 0x45 'E'
{ 975, 15, 17, 17, 0, -16 }, // 0x46 'F'
{ 1007, 17, 17, 20, 0, -16 }, // 0x47 'G'
{ 1044, 17, 17, 20, 0, -16 }, // 0x48 'H'
{ 1081, 5, 17, 7, 0, -16 }, // 0x49 'I'
{ 1092, 17, 17, 20, 0, -16 }, // 0x4A 'J'
{ 1129, 17, 17, 20, 0, -16 }, // 0x4B 'K'
{ 1166, 15, 17, 17, 0, -16 }, // 0x4C 'L'
{ 1198, 17, 17, 20, 0, -16 }, // 0x4D 'M'
{ 1235, 17, 17, 20, 0, -16 }, // 0x4E 'N'
{ 1272, 17, 17, 20, 0, -16 }, // 0x4F 'O'
{ 1309, 17, 17, 20, 0, -16 }, // 0x50 'P'
{ 1346, 17, 19, 20, 0, -16 }, // 0x51 'Q'
{ 1387, 17, 17, 20, 0, -16 }, // 0x52 'R'
{ 1424, 17, 17, 20, 0, -16 }, // 0x53 'S'
{ 1461, 15, 17, 17, 0, -16 }, // 0x54 'T'
{ 1493, 17, 17, 20, 0, -16 }, // 0x55 'U'
{ 1530, 20, 17, 22, 0, -16 }, // 0x56 'V'
{ 1573, 17, 17, 20, 0, -16 }, // 0x57 'W'
{ 1610, 20, 17, 22, 0, -16 }, // 0x58 'X'
{ 1653, 17, 17, 20, 0, -16 }, // 0x59 'Y'
{ 1690, 17, 17, 20, 0, -16 }, // 0x5A 'Z'
{ 1727, 10, 17, 12, 0, -16 }, // 0x5B '['
{ 1749, 17, 17, 20, 0, -16 }, // 0x5C '\'
{ 1786, 10, 17, 12, 0, -16 }, // 0x5D ']'
{ 1808, 17, 10, 20, 0, -16 }, // 0x5E '^'
{ 1830, 15, 2, 17, 0, -1 }, // 0x5F '_'
{ 1834, 7, 7, 10, 0, -16 }, // 0x60 '`'
{ 1841, 15, 12, 17, 0, -11 }, // 0x61 'a'
{ 1864, 15, 17, 17, 0, -16 }, // 0x62 'b'
{ 1896, 12, 12, 15, 0, -11 }, // 0x63 'c'
{ 1914, 15, 17, 17, 0, -16 }, // 0x64 'd'
{ 1946, 15, 12, 17, 0, -11 }, // 0x65 'e'
{ 1969, 12, 17, 15, 0, -16 }, // 0x66 'f'
{ 1995, 15, 17, 17, 0, -11 }, // 0x67 'g'
{ 2027, 15, 17, 17, 0, -16 }, // 0x68 'h'
{ 2059, 5, 12, 7, 0, -11 }, // 0x69 'i'
{ 2067, 12, 17, 15, 0, -11 }, // 0x6A 'j'
{ 2093, 15, 17, 17, 0, -16 }, // 0x6B 'k'
{ 2125, 5, 17, 7, 0, -16 }, // 0x6C 'l'
{ 2136, 17, 12, 20, 0, -11 }, // 0x6D 'm'
{ 2162, 15, 12, 17, 0, -11 }, // 0x6E 'n'
{ 2185, 15, 12, 17, 0, -11 }, // 0x6F 'o'
{ 2208, 15, 17, 17, 0, -11 }, // 0x70 'p'
{ 2240, 15, 17, 17, 0, -11 }, // 0x71 'q'
{ 2272, 12, 12, 15, 0, -11 }, // 0x72 'r'
{ 2290, 15, 12, 17, 0, -11 }, // 0x73 's'
{ 2313, 15, 17, 17, 0, -16 }, // 0x74 't'
{ 2345, 15, 12, 17, 0, -11 }, // 0x75 'u'
{ 2368, 17, 12, 20, 0, -11 }, // 0x76 'v'
{ 2394, 17, 12, 20, 0, -11 }, // 0x77 'w'
{ 2420, 15, 12, 17, 0, -11 }, // 0x78 'x'
{ 2443, 15, 17, 17, 0, -11 }, // 0x79 'y'
{ 2475, 15, 12, 17, 0, -11 }, // 0x7A 'z'
{ 2498, 12, 17, 15, 0, -16 }, // 0x7B '{'
{ 2524, 5, 22, 7, 0, -19 }, // 0x7C '|'
{ 2538, 12, 17, 15, 0, -16 }, // 0x7D '}'
{ 2564, 15, 7, 17, 0, -11 } }; // 0x7E '~'
const GFXfont Fallout__1_20pt7b PROGMEM = {
(uint8_t *)Fallout__1_20pt7bBitmaps,
(GFXglyph *)Fallout__1_20pt7bGlyphs,
0x20, 0x7E, 38 };
// Approx. 3250 bytes

File diff suppressed because it is too large Load Diff

View File

@@ -30,6 +30,9 @@
#include "MatrixDisplayUi.h"
#include "Fonts/AwtrixFont.h"
GifPlayer gif1;
GifPlayer gif2;
MatrixDisplayUi::MatrixDisplayUi(FastLED_NeoMatrix *matrix)
{
this->matrix = matrix;
@@ -41,6 +44,8 @@ void MatrixDisplayUi::init()
this->matrix->setTextWrap(false);
this->matrix->setBrightness(70);
this->matrix->setFont(&AwtrixFont);
gif1.setMatrix(this->matrix);
gif2.setMatrix(this->matrix);
}
void MatrixDisplayUi::setTargetFPS(uint8_t fps)
@@ -170,13 +175,14 @@ int8_t MatrixDisplayUi::update()
int8_t timeBudget = this->updateInterval - (appStart - this->state.lastUpdate);
if (timeBudget <= 0)
{
// Implement app skipping to ensure time budget is keept
// Implement frame skipping to ensure time budget is keept
if (this->setAutoTransition && this->state.lastUpdate != 0)
this->state.ticksSinceLastStateSwitch += ceil(-timeBudget / this->updateInterval);
this->state.lastUpdate = appStart;
this->tick();
}
return this->updateInterval - (millis() - appStart);
}
@@ -255,12 +261,12 @@ void MatrixDisplayUi::drawApp()
bool FirstApp = progress < 0.2;
bool LastApp = progress > 0.8;
this->matrix->drawRect(x, y, x1, y1, matrix->Color(0, 0, 0));
(this->AppFunctions[this->state.currentApp])(this->matrix, &this->state, x, y, FirstApp, LastApp);
(this->AppFunctions[this->getnextAppNumber()])(this->matrix, &this->state, x1, y1, FirstApp, LastApp);
(this->AppFunctions[this->state.currentApp])(this->matrix, &this->state, x, y, FirstApp, LastApp, &gif1);
(this->AppFunctions[this->getnextAppNumber()])(this->matrix, &this->state, x1, y1, FirstApp, LastApp, &gif2);
break;
}
case FIXED:
(this->AppFunctions[this->state.currentApp])(this->matrix, &this->state, 0, 0, false, false);
(this->AppFunctions[this->state.currentApp])(this->matrix, &this->state, 0, 0, false, false, &gif2);
break;
}
}
@@ -277,7 +283,7 @@ void MatrixDisplayUi::drawOverlays()
{
for (uint8_t i = 0; i < this->overlayCount; i++)
{
(this->overlayFunctions[i])(this->matrix, &this->state);
(this->overlayFunctions[i])(this->matrix, &this->state, &gif2);
}
}

View File

@@ -31,7 +31,7 @@
#include <Arduino.h>
#include "FastLED_NeoMatrix.h"
#include <vector>
#include "GifPlayer.h"
// #define DEBUG_MatrixDisplayUi(...) Serial.printf( __VA_ARGS__ )
#ifndef DEBUG_MatrixDisplayUi
@@ -53,6 +53,7 @@ enum AppState
// Structure of the UiState
struct MatrixDisplayUiState
{
u_int64_t lastUpdate = 0;
uint16_t ticksSinceLastStateSwitch = 0;
@@ -61,32 +62,32 @@ struct MatrixDisplayUiState
// Normal = 1, Inverse = -1;
int8_t appTransitionDirection = 1;
bool lastFrameShown = false;
bool manuelControll = false;
// Custom data that can be used by the user
void *userData = NULL;
};
typedef void (*AppCallback)(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstApp, bool lastApp);
typedef void (*OverlayCallback)(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state);
typedef void (*AppCallback)(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer);
typedef void (*OverlayCallback)(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer *gifPlayer);
class MatrixDisplayUi
{
private:
FastLED_NeoMatrix *matrix;
// Values for the Apps
AnimationDirection appAnimationDirection = SLIDE_DOWN;
int8_t lastTransitionDirection = 1;
uint16_t ticksPerApp = 151; // ~ 5000ms at 30 FPS
uint16_t ticksPerTransition = 15; // ~ 500ms at 30 FPS
bool setAutoTransition = true;
AppCallback *AppFunctions;
bool lastFrameShown;
AppCallback *AppFunctions = nullptr;
// Internally used to transition to a specific app
int8_t nextAppNumber = -1;

View File

@@ -6,7 +6,7 @@
#define HADEVICE_INIT \
_ownsUniqueId(false), \
_serializer(new HASerializer(nullptr, 5)), \
_serializer(new HASerializer(nullptr, 6)), \
_availabilityTopic(nullptr), \
_sharedAvailability(false), \
_available(true) // device will be available by default
@@ -68,6 +68,11 @@ void HADevice::setModel(const char* model)
_serializer->set(AHATOFSTR(HADeviceModelProperty), model);
}
void HADevice::setURL(const char* url)
{
_serializer->set(AHATOFSTR(HAIPProperty), url);
}
void HADevice::setName(const char* name)
{
_serializer->set(AHATOFSTR(HANameProperty), name);

View File

@@ -25,7 +25,7 @@ public:
*
* @param uniqueId String with the null terminator.
*/
HADevice(const char* uniqueId);
HADevice(const char *uniqueId);
/**
* Constructs HADevice using the given byte array as the unique ID.
@@ -34,7 +34,7 @@ public:
* @param uniqueId Bytes array that's going to be converted into the string.
* @param length Number of bytes in the array.
*/
HADevice(const byte* uniqueId, const uint16_t length);
HADevice(const byte *uniqueId, const uint16_t length);
/**
* Deletes HASerializer and the availability topic if the shared availability was enabled.
@@ -44,34 +44,44 @@ public:
/**
* Returns pointer to the unique ID. It can be nullptr if the device has no ID assigned.
*/
inline const char* getUniqueId() const
{ return _uniqueId; }
inline const char *getUniqueId() const
{
return _uniqueId;
}
/**
* Returns the instance of the HASerializer used by the device.
* This method is used by all entities to serialize device's representation.
*/
inline const HASerializer* getSerializer() const
{ return _serializer; }
inline const HASerializer *getSerializer() const
{
return _serializer;
}
/**
* Returns true if the shared availability is enabled for the device.
*/
inline bool isSharedAvailabilityEnabled() const
{ return _sharedAvailability; }
{
return _sharedAvailability;
}
/**
* Returns availability topic generated by the HADevice::enableSharedAvailability method.
* It can be nullptr if the shared availability is not enabled.
*/
inline const char* getAvailabilityTopic() const
{ return _availabilityTopic; }
inline const char *getAvailabilityTopic() const
{
return _availabilityTopic;
}
/**
* Returns online/offline state of the device.
*/
inline bool isAvailable() const
{ return _available; }
{
return _available;
}
/**
* Sets unique ID of the device based on the given byte array.
@@ -81,35 +91,36 @@ public:
* @param length Number of bytes in the array.
* @note The unique ID can be set only once (via constructor or using this method).
*/
bool setUniqueId(const byte* uniqueId, const uint16_t length);
bool setUniqueId(const byte *uniqueId, const uint16_t length);
/**
* Sets the "manufacturer" property that's going to be displayed in the Home Assistant.
*
* @param manufacturer Any string. Keep it short to save the memory.
*/
void setManufacturer(const char* manufacturer);
void setManufacturer(const char *manufacturer);
/**
* Sets the "model" property that's going to be displayed in the Home Assistant.
*
* @param model Any string. Keep it short to save the memory.
*/
void setModel(const char* model);
void setModel(const char *model);
void setURL(const char *url);
/**
* Sets the "name" property that's going to be displayed in the Home Assistant.
*
* @param name Any string. Keep it short to save the memory.
*/
void setName(const char* name);
void setName(const char *name);
/**
* Sets the "software version" property that's going to be displayed in the Home Assistant.
*
* @param softwareVersion Any string. Keep it short to save the memory.
*/
void setSoftwareVersion(const char* softwareVersion);
void setSoftwareVersion(const char *softwareVersion);
/**
* Sets device's availability and publishes MQTT message on the availability topic.
@@ -139,16 +150,16 @@ public:
private:
/// The unique ID of the device. It can be a memory allocated by HADevice::setUniqueId method.
const char* _uniqueId;
const char *_uniqueId;
/// Specifies whether HADevice class owns the _uniqueId pointer.
bool _ownsUniqueId;
/// JSON serializer of the HADevice class. It's allocated in the constructor.
HASerializer* _serializer;
HASerializer *_serializer;
/// The availability topic allocated by HADevice::enableSharedAvailability method.
char* _availabilityTopic;
char *_availabilityTopic;
/// Specifies whether the shared availability is enabled.
bool _sharedAvailability;

View File

@@ -37,6 +37,7 @@ const char HADeviceManufacturerProperty[] PROGMEM = {"mf"};
const char HADeviceModelProperty[] PROGMEM = {"mdl"};
const char HADeviceSoftwareVersionProperty[] PROGMEM = {"sw"};
const char HANameProperty[] PROGMEM = {"name"};
const char HAIPProperty[] PROGMEM = {"cu"};
const char HAUniqueIdProperty[] PROGMEM = {"uniq_id"};
const char HADeviceProperty[] PROGMEM = {"dev"};
const char HADeviceClassProperty[] PROGMEM = {"dev_cla"};

View File

@@ -35,6 +35,7 @@ extern const char HASerializerUnderscore[];
extern const char HADeviceIdentifiersProperty[];
extern const char HADeviceManufacturerProperty[];
extern const char HADeviceModelProperty[];
extern const char HAIPProperty[];
extern const char HADeviceSoftwareVersionProperty[];
extern const char HANameProperty[];
extern const char HAUniqueIdProperty[];

View File

@@ -199,7 +199,6 @@
}
#preview img {
width: 200px;
height: 200px;
image-rendering: pixelated;
}

View File

@@ -3,526 +3,403 @@
// To update it, please rerun the `reduce_index.sh` script located in the `extras` subfolder
// then recompile the sketch after each change to the `index.html` file.
const char edit_htm_gz[] = {
0x1f, 0x8b, 0x08, 0x08, 0x0a, 0x67, 0x14, 0x64, 0x00, 0x03, 0x65, 0x64,
0x69, 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x00, 0xec, 0x3b, 0x09, 0x73, 0x9b,
0x48, 0x97, 0x7f, 0x05, 0x93, 0x1d, 0x1b, 0x56, 0x08, 0x49, 0xbe, 0x23,
0x19, 0x7b, 0x7c, 0xc8, 0xb7, 0x7c, 0x9f, 0xc9, 0x66, 0xab, 0x5a, 0xd0,
0x12, 0x6d, 0x23, 0x20, 0xd0, 0x58, 0x92, 0x1d, 0xef, 0x6f, 0xdf, 0xf7,
0x1a, 0x90, 0x40, 0x42, 0x4e, 0x66, 0x77, 0x66, 0x67, 0xea, 0xab, 0x4d,
0xaa, 0x22, 0x68, 0xba, 0xdf, 0xd5, 0xef, 0xee, 0xce, 0xc6, 0xdc, 0xde,
0xf9, 0xee, 0xcd, 0xe3, 0x45, 0x53, 0xb2, 0x79, 0xcf, 0x91, 0x2e, 0x6e,
0x77, 0x4e, 0x8f, 0x76, 0x25, 0xb9, 0x5c, 0xa9, 0xdc, 0x2f, 0xed, 0x56,
0x2a, 0x7b, 0x37, 0x7b, 0xd2, 0xc3, 0xe1, 0x4d, 0xeb, 0x54, 0xaa, 0xe9,
0x55, 0xe9, 0x26, 0x20, 0x6e, 0xc8, 0x38, 0xf3, 0x5c, 0xe2, 0x54, 0x2a,
0xcd, 0x33, 0x59, 0x92, 0x6d, 0xce, 0xfd, 0x7a, 0xa5, 0xd2, 0xef, 0xf7,
0xf5, 0xfe, 0x92, 0xee, 0x05, 0xdd, 0xca, 0xcd, 0x55, 0x65, 0x80, 0xb0,
0x6a, 0xb8, 0x38, 0x79, 0x2c, 0xf3, 0xcc, 0x4a, 0xdd, 0xe2, 0x96, 0xbc,
0xb9, 0x21, 0xf0, 0x39, 0xc4, 0xed, 0x1a, 0xd4, 0xdd, 0xdc, 0xe0, 0x8c,
0x3b, 0x74, 0x73, 0x9f, 0x39, 0x54, 0xea, 0x11, 0x97, 0x74, 0x69, 0xb0,
0x51, 0x89, 0xc7, 0x36, 0x42, 0x3e, 0xc4, 0x51, 0x6a, 0x31, 0x62, 0x84,
0x66, 0x40, 0x61, 0x7a, 0xdb, 0xb3, 0x86, 0x6f, 0x1d, 0xcf, 0xe5, 0xe5,
0x90, 0xbd, 0xd2, 0x7a, 0x6d, 0xd1, 0x1f, 0x34, 0xc4, 0x6b, 0x87, 0xf4,
0x98, 0x33, 0xac, 0xdf, 0xd1, 0xc0, 0x02, 0x28, 0xda, 0x76, 0xc0, 0x88,
0xa3, 0x5d, 0x03, 0xee, 0x72, 0x48, 0x03, 0xd6, 0x79, 0xd7, 0x4d, 0x98,
0x45, 0x07, 0xbc, 0x45, 0xdd, 0xe8, 0xed, 0xb5, 0xcc, 0x5c, 0x8b, 0x0e,
0xea, 0x4b, 0xd5, 0x6a, 0xc3, 0xf7, 0x62, 0xf2, 0xea, 0xa4, 0x1d, 0x7a,
0x4e, 0xc4, 0x69, 0xc3, 0xa1, 0x1d, 0x5e, 0x5f, 0x01, 0xc0, 0x6d, 0x2f,
0xb0, 0x68, 0x50, 0xaf, 0xf9, 0x03, 0x09, 0x3e, 0x31, 0x4b, 0xfa, 0xb4,
0xbc, 0xbc, 0xdc, 0x68, 0x13, 0xf3, 0xb9, 0x1b, 0x78, 0x91, 0x6b, 0x95,
0x4d, 0xcf, 0xf1, 0x82, 0xfa, 0xa7, 0xce, 0x0a, 0xfe, 0x6d, 0x58, 0x2c,
0xf4, 0x1d, 0x32, 0xac, 0xbb, 0x9e, 0x4b, 0x61, 0xed, 0xa0, 0x1c, 0xda,
0xc4, 0xf2, 0xfa, 0xf5, 0xaa, 0x54, 0x95, 0x6a, 0x55, 0x00, 0x12, 0x74,
0xdb, 0x44, 0xa9, 0x6a, 0xf8, 0x57, 0x5f, 0x56, 0x1b, 0x19, 0x36, 0x6a,
0x29, 0x1b, 0x7d, 0xca, 0xba, 0x36, 0xaf, 0xaf, 0x55, 0xab, 0x39, 0x8a,
0xa5, 0xc8, 0x79, 0x73, 0x58, 0x08, 0xd3, 0x51, 0x24, 0x31, 0x06, 0xee,
0xf9, 0xf5, 0x6a, 0x4c, 0x6c, 0xb5, 0xd1, 0x23, 0x41, 0x97, 0xb9, 0xf0,
0xe0, 0x13, 0xcb, 0x62, 0x6e, 0xb7, 0x3e, 0xb1, 0xde, 0x61, 0x6f, 0x23,
0x46, 0x03, 0xea, 0x10, 0xce, 0x5e, 0x68, 0xa3, 0xc7, 0xdc, 0x72, 0x9f,
0x59, 0xdc, 0xae, 0xaf, 0x02, 0x79, 0x0d, 0x33, 0x0a, 0x42, 0x60, 0xc7,
0xf7, 0x18, 0xac, 0x0b, 0xf2, 0xeb, 0x43, 0x9f, 0xb8, 0x6f, 0x09, 0xbb,
0x28, 0x84, 0x94, 0x57, 0xe6, 0x3a, 0xcc, 0xa5, 0xe5, 0xb6, 0xe3, 0x99,
0xcf, 0x23, 0xdc, 0xab, 0xfe, 0x60, 0x12, 0x7b, 0xdd, 0xf6, 0x5e, 0x68,
0xf0, 0x36, 0x96, 0x9d, 0x00, 0x53, 0x3c, 0x2b, 0x87, 0x8c, 0x52, 0x0a,
0xb3, 0xc2, 0x10, 0x14, 0x89, 0xd2, 0x17, 0x46, 0xfb, 0x30, 0x4d, 0xcb,
0x0f, 0x80, 0x6c, 0x46, 0x5c, 0x8f, 0x05, 0x31, 0x21, 0xae, 0x09, 0x20,
0xcc, 0xf5, 0x23, 0xfe, 0x36, 0xbd, 0xf7, 0x9e, 0x4f, 0x4c, 0xc6, 0x87,
0x42, 0x7c, 0x99, 0xf9, 0x6f, 0x13, 0x7b, 0x55, 0xee, 0x79, 0xaf, 0xe5,
0x08, 0x34, 0x0b, 0xb4, 0xcb, 0xa1, 0x26, 0x8f, 0x77, 0x04, 0x76, 0xaf,
0xfd, 0xcc, 0xf8, 0xf4, 0x87, 0xc9, 0x81, 0x09, 0x62, 0xb2, 0xfc, 0x56,
0xab, 0x9d, 0xe9, 0x8d, 0x98, 0x9c, 0x9c, 0x48, 0x13, 0x25, 0x57, 0xb6,
0xa8, 0xe9, 0x05, 0x44, 0x70, 0x01, 0x62, 0xa5, 0x01, 0xee, 0x47, 0x11,
0xb3, 0x25, 0x87, 0xb4, 0xa9, 0x53, 0x02, 0x61, 0xa5, 0x22, 0x92, 0xf0,
0xef, 0xe2, 0xa2, 0xd8, 0xac, 0xa9, 0xe9, 0xff, 0x05, 0x13, 0xb3, 0x0a,
0x3d, 0xb9, 0x09, 0x08, 0x4c, 0x2b, 0x18, 0xab, 0xd7, 0xdb, 0xb4, 0xe3,
0x05, 0xf4, 0xed, 0x43, 0x26, 0x04, 0x8a, 0x3a, 0xc0, 0x27, 0x6d, 0x87,
0x5a, 0x31, 0x69, 0xe9, 0x0a, 0x8b, 0x76, 0x48, 0xe4, 0xf0, 0xd1, 0x56,
0xe8, 0xab, 0x85, 0x8b, 0x4d, 0x9b, 0x9a, 0xcf, 0xd4, 0x02, 0xe2, 0xb8,
0x32, 0x82, 0xa4, 0x66, 0xc9, 0x16, 0x4a, 0xf9, 0x47, 0xe9, 0xd6, 0x0a,
0xb6, 0x26, 0xa3, 0xb5, 0x51, 0xe0, 0x28, 0x16, 0xe1, 0xa4, 0xce, 0x7a,
0xe0, 0xaa, 0x2a, 0xbe, 0xdb, 0x05, 0x7f, 0x10, 0xd2, 0xd5, 0x65, 0x8d,
0xdd, 0xed, 0x9c, 0x5f, 0xf5, 0xab, 0x27, 0x07, 0x5d, 0x6f, 0x1b, 0xfe,
0x9c, 0x5d, 0xdf, 0xda, 0xcd, 0xdb, 0x2e, 0x3c, 0xed, 0xe0, 0xeb, 0x6e,
0x77, 0x77, 0xbb, 0x85, 0x0f, 0xc3, 0x95, 0x41, 0xbf, 0x87, 0x0f, 0xed,
0xda, 0x4e, 0xeb, 0xae, 0x79, 0x77, 0x68, 0x36, 0x87, 0xf7, 0xbd, 0x95,
0x95, 0xfb, 0xfb, 0xc5, 0xe6, 0xea, 0xe5, 0xad, 0xb5, 0x7d, 0xd9, 0xdc,
0x61, 0xe4, 0xa0, 0xf6, 0x44, 0x0e, 0xd6, 0x2a, 0x95, 0xca, 0xfa, 0xcb,
0xd9, 0xd3, 0xd2, 0xc9, 0x6b, 0x6b, 0x6d, 0x77, 0xd0, 0x6a, 0xf7, 0x56,
0xa2, 0x4e, 0xeb, 0xd5, 0xac, 0x3c, 0x2e, 0x5a, 0xdf, 0x07, 0xfc, 0x94,
0x1c, 0x30, 0x6f, 0x65, 0xbd, 0xfb, 0x78, 0x7f, 0xfc, 0xf4, 0x65, 0xff,
0xea, 0x6e, 0xff, 0xcb, 0xf1, 0x4d, 0xb3, 0x72, 0xfa, 0x6a, 0x96, 0x5e,
0xc2, 0xf6, 0x99, 0xf5, 0x70, 0xb7, 0xb6, 0x5c, 0xba, 0xb0, 0x5f, 0xac,
0x43, 0x27, 0x6c, 0xdf, 0x2f, 0x3e, 0xfb, 0xab, 0xdf, 0xd7, 0x5e, 0x4e,
0x5f, 0x87, 0xeb, 0x2f, 0xad, 0xe8, 0xec, 0xe6, 0xb5, 0xb3, 0xf4, 0xb9,
0x64, 0x7b, 0xab, 0xb7, 0xc3, 0xf3, 0xdb, 0xdd, 0x7d, 0xfb, 0xf1, 0xfe,
0xd6, 0x59, 0x71, 0x5f, 0xd6, 0x4a, 0x15, 0x7f, 0x95, 0x3e, 0x5f, 0xb2,
0xca, 0xc1, 0x15, 0xd2, 0xb8, 0xfd, 0x70, 0x75, 0x7d, 0xe3, 0xb4, 0xb6,
0x2f, 0xcf, 0xdb, 0x8f, 0x5f, 0x90, 0x97, 0xeb, 0xab, 0xe3, 0xab, 0xe6,
0xfe, 0xed, 0x75, 0xab, 0xc3, 0x9f, 0x3f, 0xf3, 0x61, 0x9f, 0x6d, 0x5f,
0xda, 0xde, 0xed, 0xb6, 0x7d, 0xb7, 0xdd, 0x3f, 0xf6, 0xbf, 0xef, 0x5d,
0x7d, 0xef, 0x90, 0x97, 0x97, 0xf5, 0x57, 0x27, 0x3a, 0x3b, 0x79, 0x8e,
0x82, 0xe6, 0x53, 0xf0, 0xb8, 0x54, 0xa2, 0x6b, 0xcb, 0xc7, 0xec, 0xf5,
0xd4, 0x5d, 0xbc, 0xaf, 0xf5, 0xd8, 0xf6, 0xc9, 0xc0, 0xb7, 0xcf, 0x77,
0x5a, 0xf4, 0xf6, 0xf1, 0xfb, 0x6a, 0x74, 0x58, 0xd9, 0x5e, 0xda, 0x5e,
0x5d, 0x7d, 0xf4, 0xaf, 0x76, 0xae, 0xbe, 0x1f, 0x7f, 0x21, 0xad, 0xa3,
0x75, 0xd6, 0x0f, 0xef, 0x2a, 0xbb, 0x56, 0x6b, 0x75, 0x7b, 0x71, 0xf0,
0xb4, 0xe2, 0x1e, 0xdd, 0x86, 0x27, 0xd5, 0x0a, 0xbb, 0xb9, 0xbd, 0x08,
0x0e, 0xce, 0x7a, 0xd5, 0xd6, 0xed, 0xde, 0xd1, 0x33, 0x3d, 0xa8, 0x1c,
0xaf, 0x2c, 0x47, 0xe7, 0xec, 0x39, 0x6c, 0x7f, 0xb6, 0x1f, 0xec, 0x95,
0x95, 0x0b, 0xfb, 0xe8, 0xe8, 0xa9, 0x73, 0xd2, 0xb5, 0x8e, 0x6f, 0x0e,
0xaf, 0x9b, 0xc3, 0xc5, 0xca, 0xfe, 0x5e, 0x75, 0xf5, 0xa1, 0xe7, 0x59,
0xeb, 0x67, 0xe7, 0xfd, 0x20, 0xe8, 0xef, 0xdf, 0x86, 0x97, 0xbd, 0x87,
0x2f, 0x87, 0x5f, 0x6c, 0x9b, 0x3e, 0x1f, 0xee, 0xb0, 0x9d, 0xe1, 0xe3,
0x91, 0x47, 0x8e, 0x8e, 0xb7, 0x9f, 0x2e, 0xd6, 0x6f, 0xaf, 0xef, 0xd9,
0xee, 0xf6, 0xfa, 0x89, 0xdd, 0xbc, 0x5f, 0xbf, 0x3d, 0xb8, 0x59, 0x3b,
0xb9, 0x20, 0x5f, 0x9a, 0x83, 0xf0, 0xbc, 0x7d, 0x38, 0x0c, 0x6e, 0xbb,
0x37, 0xcf, 0x4f, 0x37, 0xaf, 0xeb, 0x0e, 0xbb, 0x78, 0xe8, 0xbf, 0xf6,
0x9b, 0x3b, 0xa5, 0xf3, 0x8b, 0xfd, 0xbb, 0xc1, 0x61, 0x73, 0xfd, 0x61,
0xd1, 0x7c, 0xbe, 0xda, 0x19, 0x9e, 0x92, 0xbb, 0xa1, 0x7d, 0x77, 0x32,
0xb8, 0x58, 0x5c, 0x3b, 0x39, 0x2b, 0xb9, 0xdb, 0xfc, 0x70, 0xed, 0xea,
0x25, 0x0a, 0x16, 0xf7, 0x82, 0xd5, 0xc5, 0x1a, 0xa7, 0xcf, 0x2d, 0x1a,
0x96, 0xee, 0xd9, 0xc1, 0xfa, 0xea, 0x61, 0xb0, 0xfa, 0x74, 0xf2, 0xf8,
0x54, 0x5a, 0xbb, 0xac, 0x9d, 0x58, 0xd5, 0x0b, 0x7f, 0x70, 0xb4, 0xb2,
0x7e, 0x16, 0x5e, 0x5a, 0x67, 0x95, 0xc5, 0x95, 0x57, 0xe7, 0x72, 0xef,
0xd2, 0x3a, 0x69, 0x7f, 0xde, 0x76, 0x5b, 0xab, 0x9d, 0xc3, 0xeb, 0x83,
0xe7, 0x8b, 0xf0, 0x92, 0x1c, 0x93, 0xde, 0x91, 0x7f, 0xf9, 0xba, 0x1b,
0x0c, 0xfb, 0xf6, 0x5e, 0x8d, 0xdd, 0x2c, 0x3e, 0x3c, 0x87, 0xa7, 0xbb,
0xfd, 0xb0, 0x72, 0xf4, 0xe5, 0x65, 0xfd, 0x8b, 0xd7, 0x59, 0xe3, 0x8b,
0x2b, 0x8f, 0xce, 0xb3, 0xd8, 0xa6, 0xeb, 0xdb, 0xbb, 0xf3, 0xab, 0x93,
0x95, 0xdd, 0xc7, 0xa3, 0x23, 0x43, 0x95, 0x5c, 0xaf, 0x1c, 0x50, 0x9f,
0x12, 0xfe, 0x27, 0xe8, 0x7e, 0xc1, 0xd0, 0xc8, 0xc2, 0x0b, 0x63, 0x80,
0x1d, 0x07, 0xb0, 0x1a, 0xc4, 0x80, 0x86, 0x18, 0xce, 0x0e, 0x80, 0xd3,
0xe2, 0xcc, 0x24, 0x4e, 0x99, 0x38, 0xac, 0xeb, 0xd6, 0x7b, 0xcc, 0xb2,
0x9c, 0x42, 0xcf, 0x92, 0x31, 0xb9, 0xf2, 0xc8, 0x49, 0xd7, 0xd6, 0x21,
0x86, 0x56, 0x8b, 0x7c, 0xe7, 0xcc, 0xd9, 0xe5, 0xe5, 0xf5, 0x29, 0xf7,
0x86, 0x2b, 0x74, 0x3e, 0xe0, 0x1f, 0xac, 0x5a, 0x5d, 0x2e, 0x5e, 0xc5,
0x7a, 0xdd, 0x0f, 0x56, 0xad, 0x57, 0xa7, 0x56, 0x4d, 0xb8, 0x44, 0x0c,
0x76, 0x2e, 0xaf, 0xcb, 0x72, 0x23, 0x0e, 0xbb, 0x42, 0x28, 0x23, 0x77,
0x8c, 0xae, 0x18, 0x7d, 0x72, 0xb1, 0x98, 0x1a, 0x45, 0x88, 0xab, 0x52,
0x79, 0x69, 0xda, 0x81, 0xe7, 0x76, 0xe9, 0x17, 0x91, 0x7e, 0xe4, 0x63,
0x4b, 0x79, 0x36, 0x66, 0x10, 0x82, 0x70, 0xdf, 0x7f, 0x17, 0xd9, 0x9a,
0x14, 0x67, 0x6b, 0x12, 0x71, 0x2d, 0x49, 0x49, 0xa3, 0x22, 0x66, 0x1b,
0x16, 0x40, 0x37, 0x69, 0xd9, 0x67, 0x03, 0xea, 0x94, 0x45, 0xd4, 0xaa,
0x57, 0xd5, 0xb7, 0x7c, 0xa8, 0x4d, 0xe7, 0x13, 0x17, 0x7c, 0xac, 0x00,
0x9e, 0x0e, 0x58, 0x4f, 0xc4, 0x04, 0x56, 0xca, 0x10, 0x48, 0x7b, 0xf8,
0x1b, 0x47, 0x54, 0x2f, 0x28, 0xb7, 0xa3, 0x6e, 0x87, 0x0d, 0x80, 0xe8,
0x0e, 0x73, 0x19, 0xa7, 0x52, 0x2d, 0x7c, 0xff, 0x3d, 0x05, 0xf3, 0x4c,
0x87, 0x9d, 0x80, 0xf4, 0x68, 0x28, 0xfd, 0x22, 0x98, 0xb7, 0x4e, 0xe0,
0xf5, 0xc6, 0x19, 0xc5, 0x3b, 0xf7, 0x32, 0x2f, 0xef, 0xef, 0x9f, 0x6c,
0x4a, 0x20, 0xcc, 0x16, 0xe4, 0x0e, 0x71, 0x42, 0x16, 0x08, 0x75, 0x1f,
0x25, 0x66, 0x89, 0xfa, 0x2f, 0x82, 0x46, 0x8d, 0xf2, 0x23, 0x4c, 0x28,
0x6b, 0x42, 0xec, 0x98, 0x16, 0x16, 0x24, 0x94, 0x98, 0x61, 0x65, 0xf2,
0x9f, 0x4f, 0x28, 0x9b, 0x19, 0x08, 0x17, 0xe3, 0x44, 0x95, 0x73, 0xaf,
0x37, 0x46, 0x1a, 0x6f, 0xf4, 0x62, 0xf5, 0xb7, 0x11, 0x4a, 0x34, 0x83,
0x4f, 0xb0, 0x35, 0xc0, 0xa6, 0xf6, 0xc9, 0x0f, 0x62, 0x49, 0x7f, 0x00,
0x31, 0xe5, 0x22, 0x0f, 0x19, 0x20, 0xbe, 0x8f, 0x56, 0x4f, 0x93, 0x0d,
0xb4, 0x8e, 0x10, 0xae, 0x20, 0xc2, 0x64, 0xaa, 0x84, 0x76, 0x93, 0xd2,
0x84, 0x1c, 0xa7, 0x42, 0x11, 0x2f, 0x22, 0x92, 0x82, 0xc7, 0xc2, 0xe4,
0x05, 0x57, 0x0a, 0xe5, 0x20, 0x9c, 0x5a, 0xef, 0x9f, 0x42, 0x4e, 0x78,
0x14, 0xce, 0xa0, 0x73, 0x69, 0x44, 0xa6, 0x90, 0x62, 0x26, 0x43, 0x13,
0xb8, 0x3b, 0x61, 0x8b, 0x42, 0xe2, 0x91, 0xe0, 0xad, 0x09, 0x54, 0x09,
0x71, 0xe5, 0x84, 0x2b, 0xb4, 0x9c, 0x4f, 0x7d, 0x12, 0xb8, 0x30, 0xf6,
0x96, 0xfa, 0xa9, 0x2a, 0x48, 0x6d, 0x8a, 0x35, 0xc8, 0xb0, 0xdc, 0x2e,
0x6d, 0x8c, 0x72, 0x34, 0x30, 0x17, 0xee, 0x79, 0x0e, 0x67, 0x7e, 0x01,
0x71, 0x69, 0x75, 0xb1, 0x38, 0x92, 0xa2, 0x10, 0x2b, 0x12, 0xf0, 0xc2,
0x42, 0xd6, 0x66, 0x0e, 0xa6, 0x35, 0x36, 0x58, 0x35, 0x75, 0x8b, 0xaa,
0x89, 0x4e, 0x27, 0x83, 0xa8, 0x21, 0x92, 0xbc, 0xd8, 0x11, 0xa0, 0xd6,
0xd2, 0xa0, 0xa0, 0x2c, 0xc1, 0x79, 0xa9, 0xe0, 0x97, 0xf2, 0xb2, 0xa8,
0x66, 0x78, 0x4c, 0xd2, 0xeb, 0x11, 0xe9, 0x19, 0x6a, 0xc4, 0x23, 0xf8,
0xe2, 0x4f, 0x8e, 0x47, 0x10, 0xcc, 0x0c, 0x99, 0x97, 0x41, 0x3c, 0x2f,
0x76, 0x5e, 0xcd, 0x70, 0xa8, 0xdf, 0x18, 0x8b, 0x0f, 0xbe, 0xa7, 0x12,
0x80, 0xb7, 0x69, 0x06, 0xb3, 0x55, 0xd0, 0x8a, 0x3a, 0xce, 0xb8, 0x1b,
0xe3, 0x52, 0xb1, 0x9e, 0x0c, 0x4a, 0xfa, 0x4a, 0x28, 0x51, 0xc8, 0xaf,
0x00, 0x5e, 0xd9, 0x8b, 0xf8, 0x88, 0x3c, 0x3d, 0xb4, 0xbd, 0xbe, 0xfb,
0x16, 0x5b, 0x5c, 0x0a, 0xa1, 0x36, 0xfa, 0x5c, 0xee, 0x85, 0xdd, 0xe2,
0xf0, 0x34, 0xcb, 0x6a, 0xe3, 0x9a, 0x0f, 0xb6, 0x5e, 0x10, 0x01, 0x6e,
0xae, 0x57, 0x17, 0x4f, 0xa8, 0x88, 0x0f, 0x4a, 0x19, 0xbe, 0xa8, 0x8d,
0xcc, 0xfe, 0x8c, 0x05, 0x2c, 0xdc, 0xef, 0xef, 0x63, 0x27, 0x13, 0xfa,
0xcc, 0x75, 0x21, 0xdb, 0x47, 0xef, 0xf5, 0x56, 0xfd, 0xed, 0x6d, 0x0c,
0x2f, 0xf0, 0x40, 0x9b, 0xa9, 0x52, 0x55, 0xdf, 0x51, 0xc7, 0xa6, 0x3f,
0x2c, 0xad, 0x56, 0x2d, 0xda, 0x55, 0xdf, 0xdf, 0xf5, 0x2c, 0x8c, 0x38,
0xbf, 0x0d, 0xe8, 0xf7, 0x88, 0x05, 0x90, 0xdf, 0xfe, 0x84, 0xab, 0x51,
0x69, 0x87, 0x5c, 0x21, 0x3b, 0x1f, 0xf1, 0x25, 0xd8, 0xd2, 0x62, 0xde,
0xc6, 0xce, 0x36, 0x8b, 0x1c, 0x1c, 0xe9, 0xd8, 0xa9, 0x22, 0x3e, 0x32,
0xd6, 0xbe, 0xd5, 0xb1, 0xfa, 0xa1, 0xdd, 0xc7, 0xc3, 0x65, 0xa1, 0xf1,
0xc9, 0x46, 0x0b, 0x44, 0x3e, 0x01, 0xcb, 0xe6, 0xa3, 0xcf, 0xb0, 0x3d,
0x51, 0x28, 0x84, 0x16, 0x57, 0xc8, 0xec, 0x15, 0xf5, 0x32, 0xf9, 0x0a,
0x23, 0x0d, 0xd4, 0xd0, 0x8e, 0x03, 0x55, 0x73, 0x62, 0x1f, 0x42, 0xfd,
0x51, 0x9b, 0x20, 0x84, 0x95, 0x3f, 0xc3, 0x1f, 0x58, 0x99, 0xd4, 0xac,
0xcb, 0x63, 0x4f, 0x22, 0x02, 0xf6, 0x46, 0x45, 0x94, 0x7b, 0x9b, 0x1b,
0x10, 0x7d, 0x98, 0xcf, 0x37, 0x5f, 0x48, 0x20, 0xa1, 0xe7, 0xd4, 0x3a,
0xe1, 0x91, 0xdb, 0xf1, 0x1a, 0x9d, 0xc8, 0x35, 0x91, 0x45, 0x29, 0xa4,
0xfc, 0x34, 0x56, 0x14, 0x85, 0x6a, 0x5c, 0x7d, 0xe3, 0xf3, 0xf3, 0x10,
0x25, 0x81, 0x19, 0xaa, 0x3b, 0x5e, 0x57, 0xe1, 0xaa, 0x66, 0x79, 0x66,
0x84, 0xb1, 0x41, 0xef, 0x52, 0xde, 0x8c, 0xc3, 0xc4, 0xce, 0xf0, 0xc8,
0x52, 0xe4, 0x8c, 0x82, 0xc9, 0xaa, 0x2e, 0x24, 0x85, 0x4d, 0x12, 0x83,
0xff, 0xf8, 0x21, 0xcb, 0x1a, 0xdd, 0xfa, 0xd9, 0x42, 0x58, 0x64, 0x3a,
0x24, 0x0c, 0x4f, 0xa1, 0x3a, 0xd5, 0xc1, 0x62, 0x15, 0x59, 0x68, 0xb2,
0xac, 0xd6, 0xff, 0xd0, 0xca, 0x80, 0xf6, 0x40, 0x50, 0xa3, 0xc5, 0x63,
0x7a, 0xb1, 0x3f, 0xa2, 0x0b, 0x31, 0xe8, 0x71, 0x39, 0x65, 0xd0, 0x2d,
0xb9, 0x4f, 0x18, 0x97, 0xeb, 0x72, 0x52, 0x58, 0xc9, 0xef, 0x23, 0x41,
0x04, 0x10, 0xca, 0xb0, 0x6e, 0xba, 0x06, 0x4d, 0x56, 0xa8, 0xfa, 0xc6,
0x3a, 0x0a, 0xdd, 0xa8, 0x55, 0x17, 0x97, 0xd5, 0x80, 0xf2, 0x28, 0x70,
0x25, 0x5a, 0x92, 0xa5, 0x1d, 0x19, 0xd4, 0x3d, 0x50, 0x84, 0x34, 0x8d,
0x72, 0xad, 0xc1, 0x4b, 0x25, 0x0d, 0xe7, 0x6c, 0x28, 0xb4, 0x62, 0x88,
0xc9, 0x0d, 0xb5, 0x91, 0xce, 0x07, 0xdf, 0xb2, 0x0f, 0xfe, 0xdb, 0x52,
0x16, 0xd5, 0xd2, 0x57, 0x59, 0x3a, 0x61, 0x3b, 0xb2, 0x26, 0x4b, 0xad,
0xf8, 0xe7, 0x20, 0xfe, 0xb9, 0x11, 0x3f, 0x17, 0xf0, 0xef, 0xb7, 0xaf,
0xfc, 0x5b, 0x96, 0x9a, 0x4e, 0x40, 0x43, 0xfb, 0x5a, 0x38, 0x7d, 0x05,
0x54, 0x7d, 0x96, 0x44, 0xe2, 0xb0, 0x90, 0x93, 0xbf, 0xac, 0x24, 0xab,
0xd1, 0x39, 0xe8, 0xba, 0x2a, 0x37, 0x90, 0x5e, 0xd7, 0x70, 0x21, 0xfa,
0x3c, 0xb4, 0x4e, 0x0f, 0x39, 0xf7, 0xaf, 0xc0, 0x86, 0x68, 0xc8, 0x1b,
0xae, 0xee, 0xb9, 0x28, 0x53, 0x23, 0x45, 0x0c, 0xa8, 0x70, 0x32, 0xa8,
0x42, 0x03, 0x22, 0xd2, 0x9c, 0xe1, 0xea, 0x31, 0x82, 0x2d, 0x94, 0x2e,
0xae, 0x6c, 0x06, 0x01, 0x08, 0xc0, 0x55, 0xeb, 0x0a, 0x35, 0x94, 0x58,
0x99, 0x8c, 0xe3, 0xeb, 0xf3, 0x33, 0x1d, 0x94, 0x3b, 0xa4, 0x8a, 0x0b,
0xdb, 0x11, 0xfa, 0xa0, 0x40, 0xf4, 0x06, 0x94, 0x55, 0x55, 0x75, 0x3e,
0xf4, 0x51, 0x70, 0x65, 0x49, 0x4e, 0x54, 0x4f, 0x67, 0xe1, 0xf9, 0xf3,
0x96, 0x42, 0x4b, 0x86, 0xbc, 0xd1, 0xc3, 0xa8, 0x24, 0x31, 0xcb, 0x58,
0x48, 0x22, 0xd4, 0x82, 0x04, 0x99, 0x91, 0xb1, 0x50, 0x5d, 0x90, 0x3c,
0x9f, 0xb3, 0x5e, 0xd4, 0xc3, 0x67, 0xb0, 0x00, 0x63, 0xe1, 0x33, 0x8c,
0xd9, 0xa0, 0xdf, 0xf0, 0xb4, 0x02, 0xb3, 0xc8, 0xc0, 0x58, 0x00, 0xd7,
0xb1, 0x20, 0xbd, 0x10, 0x27, 0xa2, 0xc6, 0x82, 0x5c, 0x52, 0x6a, 0xa5,
0x16, 0xe1, 0xb6, 0x2e, 0xdc, 0xab, 0xf2, 0xf9, 0xf3, 0xbf, 0x27, 0xe8,
0xa2, 0x90, 0x5a, 0x3b, 0x43, 0x4e, 0xc3, 0x4a, 0x32, 0xc0, 0xc1, 0xc5,
0x38, 0x62, 0x44, 0x55, 0x4b, 0xf2, 0x82, 0x24, 0x1a, 0x6c, 0x02, 0x02,
0x37, 0x72, 0x4a, 0x30, 0x35, 0xbf, 0x3c, 0x09, 0x12, 0xd6, 0x4b, 0x20,
0x69, 0x2a, 0x79, 0x1d, 0x49, 0x2e, 0x7d, 0xbc, 0x58, 0x20, 0xdb, 0x94,
0x4b, 0xbc, 0x24, 0x6f, 0x54, 0x04, 0xe3, 0x9b, 0x23, 0x91, 0x44, 0x6e,
0x18, 0xf9, 0xbe, 0x17, 0x40, 0xa0, 0xc7, 0xe6, 0x5f, 0x38, 0x3f, 0x2f,
0xe4, 0x23, 0x6d, 0x60, 0xf6, 0x2a, 0xe4, 0x93, 0x44, 0xad, 0x85, 0xcd,
0xfb, 0xed, 0xab, 0xb3, 0xa3, 0xb3, 0x83, 0xf8, 0x8b, 0x30, 0x02, 0x63,
0x21, 0x89, 0x61, 0x0b, 0xa2, 0x73, 0x18, 0x0e, 0x43, 0x4e, 0x7b, 0xf3,
0x6e, 0x3b, 0xf4, 0x1b, 0x98, 0xef, 0x12, 0xe6, 0x86, 0xf1, 0x5b, 0x06,
0x4b, 0x3c, 0xd0, 0x81, 0xe9, 0x2e, 0x7a, 0xea, 0xfa, 0x46, 0x3b, 0xa8,
0x00, 0x6d, 0x33, 0xc8, 0x41, 0x8a, 0x11, 0xdf, 0x66, 0xf2, 0x23, 0xab,
0x6a, 0x5d, 0xec, 0x9f, 0x20, 0x42, 0x58, 0x98, 0xb1, 0x30, 0x1d, 0xdb,
0xa8, 0x95, 0x84, 0x89, 0xbe, 0x0d, 0x3e, 0x33, 0xd7, 0xd3, 0x6b, 0x7b,
0x8e, 0xb5, 0xb0, 0x79, 0x74, 0x76, 0x74, 0x23, 0x35, 0xaf, 0xae, 0xce,
0xaf, 0xa4, 0xb9, 0x14, 0xf4, 0x6c, 0x77, 0x53, 0xa0, 0xe9, 0x54, 0x93,
0xaf, 0x2f, 0x8e, 0xf6, 0xf7, 0xaf, 0xe5, 0x39, 0x23, 0x15, 0x38, 0xe8,
0x1b, 0x88, 0x6f, 0x26, 0x94, 0xde, 0xb3, 0xc5, 0x02, 0x00, 0x12, 0xfb,
0x85, 0x24, 0x82, 0x18, 0x72, 0x1c, 0x42, 0x80, 0xb1, 0x77, 0x0d, 0x6c,
0xc2, 0xa7, 0xae, 0x22, 0x1f, 0x34, 0x6f, 0xc0, 0x34, 0x2b, 0x09, 0x5a,
0x6d, 0xae, 0xaa, 0xc2, 0xa7, 0x10, 0x52, 0x33, 0xc5, 0x8d, 0x1c, 0x47,
0x1d, 0xdb, 0x6a, 0xde, 0x34, 0xc0, 0x75, 0x10, 0x07, 0x8a, 0x16, 0x45,
0x16, 0x9c, 0xd5, 0xa5, 0xaf, 0x72, 0x89, 0x26, 0x56, 0x54, 0x92, 0xbf,
0x49, 0xf8, 0x96, 0xb3, 0x91, 0x31, 0x20, 0x93, 0xb8, 0xe8, 0x8b, 0xcf,
0x68, 0x7f, 0x37, 0x2e, 0x54, 0xd0, 0xf2, 0x63, 0x6f, 0x32, 0x37, 0x37,
0x5b, 0x2e, 0xe4, 0x85, 0xee, 0x70, 0xf0, 0x7c, 0x7a, 0xda, 0xf9, 0xf9,
0xf1, 0x63, 0x6e, 0x0e, 0xb6, 0xbe, 0xc3, 0x82, 0x9e, 0x22, 0xef, 0xda,
0x98, 0xae, 0x85, 0x12, 0xf7, 0xa4, 0xa1, 0x17, 0x05, 0x52, 0x0a, 0x47,
0xea, 0x33, 0xc7, 0x91, 0xda, 0x10, 0xcb, 0xbc, 0x90, 0x4b, 0xac, 0x83,
0x5f, 0x25, 0x54, 0x18, 0xe6, 0x46, 0x20, 0x08, 0x54, 0x41, 0x57, 0x68,
0x33, 0x80, 0xdf, 0x63, 0xa1, 0x49, 0x02, 0x0b, 0xb0, 0x84, 0xca, 0x5c,
0x4d, 0x45, 0x59, 0x8c, 0xa9, 0x2e, 0x9e, 0x46, 0x3f, 0xf2, 0x59, 0x53,
0x14, 0x1b, 0x73, 0x74, 0xf6, 0xc6, 0x5b, 0x23, 0xb0, 0xf9, 0x15, 0x63,
0x12, 0x60, 0xc5, 0x85, 0x88, 0xad, 0xfb, 0xa0, 0x57, 0x54, 0xec, 0x41,
0x2c, 0x36, 0x74, 0x52, 0xd4, 0x10, 0xe2, 0x0f, 0x78, 0x78, 0xcf, 0xb8,
0xad, 0xc8, 0x15, 0x59, 0xdd, 0xa2, 0x75, 0xf8, 0x29, 0x51, 0x55, 0x87,
0xed, 0xcc, 0x0e, 0xeb, 0xa1, 0x03, 0x35, 0x19, 0x64, 0x64, 0xe5, 0x1a,
0xa8, 0x38, 0x68, 0x49, 0xd4, 0x0e, 0x39, 0x66, 0xe2, 0x30, 0x04, 0x01,
0x91, 0x84, 0xfc, 0x08, 0x93, 0xb9, 0xf3, 0x8e, 0x98, 0x9f, 0xdd, 0x3a,
0x30, 0x7e, 0x4e, 0x0f, 0x45, 0x39, 0x04, 0x81, 0xd4, 0xc5, 0x50, 0x8a,
0x8e, 0xd4, 0x33, 0x66, 0xb1, 0x45, 0x55, 0x8d, 0x8c, 0x3f, 0xc6, 0xeb,
0x93, 0xef, 0x8a, 0x2c, 0x4a, 0x4e, 0x8c, 0x65, 0x86, 0x42, 0x84, 0x4a,
0x1b, 0x32, 0x1a, 0xab, 0xac, 0x11, 0xbd, 0x17, 0xa1, 0xad, 0x83, 0xc5,
0xcd, 0xd5, 0xe0, 0x0d, 0xcd, 0xd7, 0x90, 0xb1, 0x0b, 0x27, 0x6b, 0x9e,
0x4e, 0x7c, 0xd0, 0x5c, 0x6b, 0xd7, 0x66, 0x8e, 0xa5, 0x90, 0x4c, 0x24,
0x2c, 0x86, 0xae, 0x6a, 0x8e, 0xa1, 0x58, 0x3a, 0xb8, 0x17, 0xd9, 0x07,
0xcf, 0x79, 0x24, 0x46, 0x35, 0x2b, 0xc1, 0x87, 0xc9, 0x06, 0xbe, 0xc5,
0x18, 0x70, 0x02, 0xbe, 0x25, 0x71, 0xf3, 0x4e, 0x78, 0x5d, 0x90, 0xc1,
0x04, 0x52, 0x6b, 0x36, 0xd2, 0x76, 0x04, 0x75, 0x86, 0x8b, 0x58, 0x43,
0x43, 0x71, 0xb2, 0xe1, 0xea, 0xd6, 0xc7, 0x10, 0x34, 0x09, 0xca, 0xf9,
0x15, 0x50, 0xcc, 0x50, 0x42, 0xc1, 0x40, 0x6c, 0xd6, 0x5a, 0x38, 0x69,
0xd7, 0xd8, 0xae, 0xc5, 0xe1, 0x0c, 0xba, 0xd6, 0xf3, 0x1e, 0x4e, 0xcd,
0x63, 0x0b, 0x7f, 0x05, 0x9b, 0x69, 0x28, 0x2c, 0x0f, 0x69, 0x5f, 0x6c,
0x4a, 0x1e, 0x14, 0x9b, 0x0d, 0x0a, 0x5d, 0x1c, 0x02, 0x0a, 0x0c, 0xc5,
0x14, 0x64, 0xc7, 0x55, 0xe8, 0x8e, 0xc0, 0x00, 0x3e, 0xc6, 0x2c, 0x26,
0x3f, 0x0f, 0xdf, 0xfc, 0x15, 0x52, 0x7b, 0x86, 0x12, 0x08, 0x0c, 0xa9,
0xad, 0x69, 0x41, 0x96, 0x72, 0xb4, 0x56, 0x1c, 0x8a, 0xd1, 0xc5, 0x0d,
0x90, 0x53, 0x48, 0x8f, 0x0d, 0x79, 0x09, 0x8a, 0x24, 0xfc, 0x32, 0xb6,
0xb3, 0x2a, 0x90, 0x95, 0xc5, 0x1f, 0xfc, 0x02, 0xfe, 0x46, 0x4f, 0x20,
0xcf, 0x58, 0xae, 0xd6, 0xcb, 0xe2, 0x4f, 0x3c, 0x05, 0x8e, 0xce, 0x46,
0xd4, 0x53, 0x35, 0x30, 0xde, 0x9f, 0xe2, 0x12, 0x98, 0x6c, 0xea, 0xf8,
0x02, 0x0d, 0xcd, 0xa2, 0xd9, 0x92, 0x27, 0x40, 0x82, 0xd1, 0x29, 0xe6,
0x4c, 0x90, 0xc9, 0xf6, 0xc4, 0x72, 0x4b, 0xdc, 0xbe, 0x99, 0x4b, 0xac,
0x92, 0xfc, 0x53, 0x2d, 0xd8, 0x13, 0x02, 0xa9, 0x94, 0x29, 0x7c, 0xed,
0x38, 0x99, 0xa2, 0xb1, 0x13, 0xe0, 0x0d, 0xc8, 0xa4, 0x0c, 0xa2, 0xa3,
0x09, 0x87, 0x3a, 0xc4, 0xdc, 0x2e, 0xb7, 0xc1, 0xbf, 0xf2, 0x74, 0xe8,
0x6b, 0xf5, 0x9b, 0x30, 0x33, 0xb0, 0x2f, 0x91, 0xce, 0x4c, 0xba, 0xab,
0x1f, 0x3f, 0x94, 0xe4, 0x0b, 0x9a, 0x5c, 0x29, 0x79, 0x56, 0xd3, 0xe9,
0xc6, 0xa4, 0xfb, 0x4b, 0x27, 0x94, 0x70, 0x36, 0x04, 0x18, 0xcd, 0x41,
0xda, 0xc0, 0xb3, 0x3d, 0xe7, 0x48, 0x2b, 0x22, 0xca, 0xd5, 0xf1, 0x2c,
0x33, 0xb6, 0x48, 0x65, 0x4c, 0x5e, 0x8a, 0x0a, 0x60, 0xb1, 0x42, 0x58,
0x71, 0x46, 0x9c, 0xd2, 0x0f, 0x2e, 0xb3, 0xa7, 0xa8, 0x0d, 0x59, 0x36,
0x0c, 0x83, 0x6f, 0x25, 0xe1, 0x70, 0x5b, 0x4a, 0xf3, 0x0d, 0xa9, 0x17,
0x41, 0xc8, 0x81, 0xd0, 0xd3, 0x85, 0xf2, 0x0c, 0xf3, 0x7d, 0x3e, 0xe1,
0x87, 0x93, 0x15, 0xfb, 0x69, 0x7e, 0x12, 0x2f, 0x80, 0xea, 0x0f, 0x82,
0x8d, 0x05, 0x81, 0x8b, 0xdb, 0x12, 0x91, 0x16, 0x2a, 0x0b, 0x12, 0x08,
0x3c, 0x20, 0x26, 0xe4, 0x52, 0x00, 0x24, 0x26, 0x7d, 0x57, 0x6c, 0xa9,
0x82, 0x5c, 0x87, 0xff, 0x0b, 0x4a, 0x85, 0x20, 0xa5, 0x42, 0x62, 0x95,
0x09, 0x6a, 0x61, 0x77, 0x78, 0x09, 0x37, 0x06, 0xf3, 0x83, 0x1c, 0x09,
0x40, 0x43, 0x50, 0x48, 0x03, 0xd7, 0xd1, 0x2c, 0x15, 0xf8, 0xde, 0x9b,
0xf1, 0x3d, 0xb1, 0x1c, 0x9c, 0x42, 0x67, 0x81, 0x80, 0xb4, 0xe3, 0xda,
0x86, 0x2c, 0xcd, 0x8c, 0x30, 0x51, 0x78, 0x9f, 0x0c, 0x46, 0x37, 0x90,
0x98, 0x42, 0x28, 0x22, 0x31, 0xcb, 0xee, 0xcc, 0x40, 0x24, 0x27, 0x9d,
0x29, 0xa0, 0x9f, 0xcf, 0x34, 0x0d, 0x8b, 0xbd, 0xc8, 0xea, 0xb8, 0x6a,
0xb4, 0x3e, 0x8c, 0xef, 0xe3, 0x68, 0xa2, 0x26, 0x1a, 0xfa, 0x41, 0x74,
0x8f, 0x5d, 0xe0, 0x74, 0x46, 0x16, 0xbb, 0xbe, 0x9f, 0x2c, 0x4b, 0x3d,
0xe7, 0x8c, 0xd5, 0xee, 0xe4, 0xb0, 0x68, 0x11, 0xe0, 0x78, 0xc6, 0xa8,
0x37, 0x58, 0xaf, 0x2b, 0x85, 0x81, 0x89, 0x25, 0x00, 0xc5, 0x82, 0x20,
0x49, 0x68, 0xa1, 0xc6, 0x28, 0x8f, 0xba, 0x3a, 0xbf, 0x35, 0xb0, 0xe6,
0x28, 0x67, 0x1b, 0x63, 0x52, 0xd2, 0x37, 0x26, 0x11, 0xf7, 0x1a, 0x52,
0xee, 0xa0, 0xad, 0xb1, 0x20, 0x41, 0x3a, 0x3d, 0xde, 0x10, 0xe7, 0x5f,
0x49, 0x5c, 0xd9, 0xa4, 0x7f, 0x9c, 0xe9, 0x2f, 0x6c, 0x6e, 0x9b, 0x54,
0x8a, 0xd1, 0x40, 0x1a, 0x19, 0x39, 0x96, 0xb0, 0x57, 0x91, 0x5f, 0x42,
0x52, 0x64, 0x49, 0xd8, 0x49, 0x96, 0xb8, 0x4d, 0x25, 0x71, 0x06, 0xea,
0x52, 0xb4, 0xe7, 0x20, 0x1e, 0xad, 0xe0, 0xb2, 0x0a, 0x31, 0xa9, 0xfe,
0x14, 0x4a, 0xba, 0xb4, 0x17, 0xe7, 0x18, 0xe0, 0x67, 0x31, 0x69, 0xc5,
0x3c, 0x44, 0x42, 0xfd, 0xa4, 0x01, 0x14, 0xb3, 0x69, 0x21, 0x02, 0x3a,
0x2b, 0xea, 0x22, 0x3e, 0xe0, 0x69, 0xae, 0x3c, 0xda, 0xb8, 0x51, 0xdb,
0x44, 0x12, 0x5b, 0xb3, 0x00, 0x65, 0x0b, 0x4c, 0xdf, 0x8c, 0xcb, 0x60,
0x5e, 0x54, 0x06, 0xf3, 0x82, 0x32, 0x78, 0xa6, 0x28, 0x33, 0x28, 0x41,
0x90, 0x48, 0x5e, 0xf2, 0x6a, 0x70, 0x9b, 0x85, 0xb9, 0xdc, 0xfe, 0x5d,
0xe3, 0xd9, 0x62, 0x02, 0x5c, 0x36, 0x8f, 0x2b, 0x88, 0x4c, 0xe6, 0xd8,
0x4b, 0x9a, 0x0d, 0x2f, 0x1e, 0xb3, 0x24, 0x74, 0xc9, 0x10, 0xf3, 0x2a,
0xca, 0x56, 0xfd, 0x3f, 0x74, 0xe5, 0xeb, 0x7f, 0xea, 0xdf, 0x4a, 0xaa,
0xba, 0xf5, 0x6f, 0x15, 0x9d, 0x0e, 0xa8, 0x09, 0x13, 0xbf, 0xd6, 0xbe,
0xa9, 0x6a, 0x08, 0x0e, 0xd0, 0xb4, 0x15, 0xec, 0x2f, 0x9c, 0x7a, 0x20,
0x96, 0x5d, 0x02, 0x85, 0xb7, 0xaa, 0xbe, 0x99, 0xf0, 0x8b, 0xd4, 0xc9,
0x75, 0xf1, 0x64, 0xf3, 0xde, 0xf8, 0xc9, 0x49, 0x1e, 0x9f, 0xc2, 0xd1,
0x03, 0x04, 0xcf, 0xf8, 0xd1, 0x4c, 0xa7, 0xa5, 0xef, 0xbe, 0x9f, 0x3e,
0x85, 0xe9, 0xf4, 0x01, 0x42, 0x48, 0x1a, 0x1b, 0xb5, 0x8c, 0xab, 0x89,
0xfe, 0x5c, 0xea, 0x7d, 0xb7, 0x9b, 0xd2, 0xe7, 0x8f, 0x9f, 0x68, 0xfa,
0xd8, 0x65, 0x9d, 0xe4, 0x89, 0x99, 0x5e, 0x21, 0x3d, 0x81, 0xe2, 0x6a,
0x5e, 0xd2, 0xc3, 0x98, 0xe9, 0xcc, 0x22, 0x47, 0xf8, 0x3a, 0xc5, 0x9d,
0xcc, 0x0d, 0x66, 0x2d, 0x70, 0x18, 0xe6, 0x34, 0x34, 0x37, 0x9d, 0x43,
0x92, 0xa5, 0x78, 0xea, 0x96, 0x8c, 0x37, 0x0d, 0x3a, 0x50, 0x3c, 0x5a,
0x10, 0x43, 0x30, 0x75, 0xf6, 0x3a, 0x12, 0xa8, 0xf2, 0x16, 0x84, 0x89,
0x49, 0xab, 0xd9, 0xbc, 0x03, 0x35, 0x1e, 0x15, 0xba, 0xbc, 0x38, 0x28,
0x6f, 0xe4, 0xfb, 0x57, 0x63, 0xed, 0x0b, 0x77, 0x86, 0xbb, 0x58, 0xef,
0x9f, 0x41, 0x50, 0x52, 0xe4, 0xcc, 0x65, 0x11, 0xd0, 0xc2, 0x34, 0x7c,
0xe7, 0xd7, 0xc6, 0x9d, 0xb1, 0x98, 0x5c, 0x17, 0xd2, 0xd7, 0x82, 0xf2,
0x72, 0x7e, 0xde, 0x01, 0x26, 0xde, 0x45, 0x54, 0x9b, 0x22, 0xb7, 0x09,
0x66, 0xf9, 0x4f, 0x23, 0x97, 0xe8, 0x68, 0xa8, 0xb7, 0x41, 0x42, 0x76,
0x04, 0x3f, 0x98, 0x4a, 0x4d, 0x13, 0x7f, 0x11, 0x47, 0xb5, 0x7f, 0x1a,
0xfd, 0x96, 0xa0, 0xfb, 0x83, 0x48, 0x8b, 0xba, 0xa6, 0x4d, 0xa9, 0x5a,
0x01, 0x83, 0x7b, 0x5e, 0x5f, 0x38, 0xad, 0x9f, 0x70, 0x98, 0x24, 0xa0,
0x7f, 0x1d, 0x9f, 0xdc, 0xf0, 0x3e, 0xa8, 0xdd, 0x13, 0x22, 0xcb, 0xe2,
0x48, 0x00, 0x03, 0x0f, 0x04, 0x5a, 0x5e, 0x92, 0xb7, 0xd2, 0x0f, 0x06,
0x0f, 0x22, 0x2a, 0xbf, 0xff, 0x19, 0x02, 0xb9, 0x12, 0xc9, 0x62, 0xa5,
0x05, 0xc4, 0xfd, 0x6d, 0xbb, 0x9e, 0xc4, 0x18, 0x1f, 0xc2, 0x9a, 0x0f,
0xb4, 0xc7, 0x24, 0x49, 0x72, 0xc9, 0x2b, 0xc9, 0x10, 0xcc, 0xa0, 0x6c,
0x50, 0x1b, 0xd8, 0x3d, 0x9a, 0x33, 0xf8, 0xfc, 0x3c, 0x9f, 0x33, 0xbc,
0xf9, 0xf9, 0xa1, 0xe2, 0x69, 0x98, 0xad, 0xfe, 0x19, 0x1a, 0x41, 0x1d,
0xca, 0xff, 0x3e, 0xde, 0xb5, 0x2e, 0xea, 0xf6, 0xd8, 0x17, 0xfb, 0x78,
0xa2, 0xa0, 0xb9, 0x53, 0x8d, 0x90, 0xa2, 0xd4, 0x32, 0xdb, 0x0b, 0x89,
0xfb, 0xf6, 0x66, 0xe0, 0x39, 0xce, 0x8d, 0xe7, 0xff, 0xf8, 0x31, 0xfa,
0x90, 0x3e, 0x24, 0x4b, 0xc7, 0x73, 0x34, 0xab, 0x70, 0x35, 0x56, 0xb4,
0x3f, 0x5d, 0x8e, 0x93, 0x34, 0xc7, 0xa0, 0x3a, 0x88, 0x0a, 0x46, 0x1f,
0x4a, 0x96, 0x16, 0x8e, 0xde, 0x1e, 0x4b, 0x04, 0x7b, 0x0c, 0x5e, 0x7c,
0xdc, 0x70, 0x26, 0x5a, 0x21, 0x59, 0xc1, 0x40, 0x19, 0x58, 0x9c, 0x32,
0xa5, 0xe3, 0x78, 0xe6, 0x64, 0x38, 0x25, 0x19, 0x8b, 0xea, 0x74, 0x8c,
0x7b, 0xbe, 0x11, 0xc6, 0x43, 0x8a, 0xbb, 0x15, 0xd4, 0x47, 0xbb, 0xf3,
0x97, 0x85, 0x2e, 0x90, 0xae, 0x32, 0xa5, 0x40, 0xb3, 0x6c, 0xd6, 0x53,
0x75, 0x13, 0xe7, 0x9c, 0x79, 0x56, 0x5c, 0x9a, 0x26, 0x37, 0x1f, 0x7e,
0xe6, 0xb4, 0xa6, 0xe3, 0x23, 0x29, 0x0c, 0x82, 0xbb, 0x20, 0x74, 0xe2,
0x87, 0x7f, 0xa3, 0x9e, 0xfe, 0x51, 0xce, 0x8d, 0xb9, 0xda, 0xfb, 0x07,
0xcd, 0xba, 0x02, 0xfb, 0x24, 0xd8, 0x0f, 0x28, 0x70, 0x50, 0xe2, 0x58,
0x66, 0xc4, 0x38, 0xf9, 0xbf, 0x66, 0xdc, 0xfe, 0x20, 0xd6, 0x0f, 0xe0,
0xdf, 0x9f, 0xc5, 0x92, 0x7f, 0xd4, 0x9e, 0x54, 0x13, 0x76, 0xfe, 0x3f,
0x74, 0xfc, 0xcb, 0x84, 0x0e, 0x55, 0x30, 0x34, 0x71, 0x82, 0x9b, 0x25,
0xde, 0x53, 0xc1, 0x8b, 0x7a, 0x9d, 0x4e, 0x48, 0xf9, 0x3d, 0x96, 0xe6,
0xd8, 0x93, 0x4d, 0x07, 0x0e, 0x45, 0x6d, 0xde, 0x80, 0x57, 0xb7, 0xe7,
0x45, 0x21, 0xf5, 0x22, 0x9e, 0xa3, 0x5e, 0x19, 0xb9, 0xf8, 0x0d, 0xe7,
0xc7, 0x8f, 0xd1, 0xcb, 0xa6, 0x53, 0x62, 0xe3, 0xd7, 0xc7, 0x8d, 0x30,
0xf3, 0xb2, 0x19, 0x96, 0x4c, 0xc8, 0xd9, 0xfe, 0x2a, 0xbe, 0x73, 0xd1,
0xd2, 0x53, 0x44, 0xac, 0x4c, 0x6a, 0x9a, 0xc9, 0xf3, 0xd8, 0x46, 0xe6,
0x9c, 0x1e, 0x4f, 0x60, 0xc4, 0xe1, 0x2c, 0x2f, 0x3e, 0x9c, 0xe5, 0x6a,
0xdd, 0xdd, 0x52, 0xa6, 0xdb, 0x82, 0x98, 0xab, 0xe5, 0xca, 0x53, 0xd0,
0xa3, 0xdc, 0xfb, 0x9c, 0x41, 0xe7, 0xe7, 0x93, 0xb3, 0xe3, 0x0b, 0xc2,
0x6d, 0x25, 0xff, 0x59, 0xd5, 0xb2, 0xdf, 0xf0, 0xfc, 0x82, 0x73, 0x0a,
0xba, 0x8a, 0x74, 0x01, 0x70, 0xb5, 0xfe, 0x0b, 0x4b, 0xd3, 0x03, 0xed,
0x0c, 0xe3, 0x76, 0x7c, 0xf1, 0x00, 0xd9, 0x64, 0x9a, 0xa9, 0x05, 0x39,
0x56, 0xab, 0x9a, 0x8c, 0x87, 0xfc, 0xd8, 0x0b, 0x48, 0xda, 0x33, 0xba,
0xae, 0x83, 0x4e, 0x2b, 0x50, 0x90, 0x22, 0xc7, 0x05, 0xd5, 0xbc, 0x9a,
0x16, 0xf3, 0x0a, 0x33, 0x92, 0x59, 0xa0, 0x25, 0x54, 0x0b, 0x0c, 0xae,
0x15, 0x1c, 0x73, 0x43, 0xf1, 0x5a, 0x24, 0x5b, 0x96, 0xc8, 0x56, 0xcd,
0xcb, 0x96, 0x41, 0x98, 0x73, 0x42, 0xfa, 0x96, 0x6d, 0x4c, 0x4f, 0x78,
0x2c, 0x53, 0x15, 0x15, 0x89, 0x11, 0x9f, 0x17, 0x25, 0x5f, 0xc4, 0x86,
0xc3, 0xb8, 0x7c, 0x7b, 0x8a, 0x65, 0xa2, 0xce, 0x49, 0x17, 0x75, 0x66,
0x7e, 0x9e, 0xe6, 0x34, 0x82, 0xab, 0xc9, 0x59, 0xbd, 0xa9, 0xe5, 0x8e,
0xd5, 0xd9, 0x84, 0x34, 0x09, 0xe6, 0x24, 0xa1, 0x17, 0x70, 0x65, 0xac,
0xe1, 0x28, 0xc4, 0xf1, 0xd5, 0x03, 0x3c, 0xc3, 0x41, 0x3c, 0xf0, 0xbb,
0x45, 0x45, 0x77, 0x19, 0x0a, 0x27, 0x93, 0x38, 0x74, 0x17, 0xdc, 0x0b,
0x68, 0x05, 0x6c, 0x10, 0x0e, 0xaa, 0xf5, 0x78, 0xee, 0xd4, 0x47, 0x1c,
0x44, 0xe7, 0xfa, 0x51, 0x22, 0xa2, 0x36, 0x66, 0xc9, 0xc0, 0x55, 0x27,
0xc2, 0xe1, 0xe8, 0xda, 0x84, 0x05, 0xf6, 0x1a, 0x5b, 0x06, 0x24, 0x5d,
0xd5, 0x86, 0xb3, 0x61, 0x35, 0x9c, 0x52, 0x29, 0xde, 0x8e, 0x30, 0x39,
0xe5, 0x32, 0x0c, 0x43, 0x09, 0x0d, 0xef, 0xab, 0xf3, 0x2d, 0xbe, 0x3f,
0xb0, 0x95, 0x65, 0xf2, 0xe7, 0x09, 0xa5, 0x48, 0x46, 0x12, 0x49, 0x78,
0xd8, 0xcc, 0xc7, 0x36, 0xad, 0x81, 0x97, 0x3f, 0xe4, 0x7a, 0xda, 0x14,
0xd7, 0x66, 0xa7, 0x58, 0xf1, 0x29, 0x00, 0x14, 0xf7, 0x1c, 0x0f, 0x04,
0x27, 0x6e, 0xa8, 0x60, 0x7b, 0x05, 0xab, 0x4e, 0xae, 0xe2, 0xd6, 0x4d,
0x7c, 0x64, 0xbd, 0xae, 0x70, 0xb7, 0x99, 0xab, 0x30, 0xe0, 0xbb, 0x37,
0xd8, 0xa6, 0x32, 0x71, 0x39, 0xc0, 0x05, 0x2a, 0xd4, 0x8d, 0x0a, 0xdb,
0x9c, 0x3c, 0x47, 0xa0, 0xc2, 0xbf, 0x15, 0xb8, 0xde, 0xac, 0xa9, 0x21,
0x4f, 0xe0, 0xf5, 0xc5, 0xc4, 0xd8, 0xe3, 0x00, 0xe1, 0x51, 0x6e, 0x3a,
0xd5, 0xb1, 0xa9, 0x0b, 0xec, 0x24, 0xbd, 0x34, 0x05, 0xc9, 0x0a, 0x21,
0xf1, 0xbc, 0x08, 0x3c, 0x9f, 0x74, 0x49, 0x6c, 0x03, 0x1a, 0x66, 0xe8,
0x08, 0x4d, 0x1c, 0xe8, 0x6a, 0xde, 0x3b, 0x64, 0xa0, 0x61, 0x7c, 0x12,
0x11, 0xea, 0x78, 0xa3, 0x4b, 0xad, 0xff, 0x71, 0xc9, 0xc7, 0xba, 0x39,
0x43, 0xea, 0x3f, 0x3b, 0x91, 0x4c, 0xb7, 0x2d, 0x3d, 0xf4, 0x14, 0xc1,
0xbe, 0xed, 0x0d, 0x0a, 0x0e, 0x37, 0x15, 0x77, 0x36, 0x19, 0x78, 0x45,
0x17, 0x0f, 0x72, 0x72, 0xcd, 0xb9, 0x09, 0x10, 0xee, 0xcc, 0x23, 0x1b,
0x92, 0xe6, 0x18, 0xf3, 0xf3, 0x76, 0x2a, 0x6c, 0xb7, 0x78, 0x57, 0xd2,
0x99, 0x5b, 0x24, 0x93, 0x2b, 0xd6, 0x15, 0x32, 0x91, 0xa5, 0x20, 0x8c,
0x3f, 0x7b, 0xc7, 0x6a, 0xf9, 0x1d, 0x53, 0x1b, 0x64, 0xe2, 0x40, 0xf3,
0x7d, 0xd4, 0x93, 0x9b, 0xed, 0xa9, 0x8a, 0x73, 0xab, 0x0f, 0xee, 0x4f,
0xcc, 0x5a, 0x62, 0xe0, 0xf5, 0x88, 0x00, 0xa2, 0xc7, 0x28, 0xec, 0x75,
0x94, 0x00, 0x23, 0xba, 0x96, 0xb8, 0xe0, 0xfc, 0xa5, 0x0a, 0xfc, 0x0f,
0x49, 0x5b, 0x16, 0x0b, 0x0c, 0xf0, 0xe9, 0xe2, 0x66, 0x45, 0x3a, 0xab,
0xe8, 0x7e, 0x45, 0x67, 0x7c, 0x6c, 0x03, 0x52, 0xf2, 0x7c, 0x45, 0x6d,
0x70, 0xdc, 0x1a, 0x30, 0xe2, 0xcc, 0xac, 0x61, 0xec, 0x01, 0x27, 0x82,
0x87, 0xc8, 0xa2, 0x32, 0xd1, 0x03, 0x3b, 0xca, 0x0b, 0xe2, 0x12, 0x4e,
0x12, 0x48, 0x78, 0xc1, 0x61, 0x1b, 0x37, 0xe2, 0x83, 0xb3, 0x5f, 0x8a,
0x32, 0x5e, 0x3a, 0x49, 0x1b, 0x39, 0x6f, 0x9c, 0xbd, 0xef, 0x05, 0xbd,
0x3d, 0xc2, 0x49, 0x23, 0xad, 0xd4, 0x94, 0xe4, 0x0c, 0x9d, 0xe3, 0x31,
0x51, 0x3a, 0x14, 0x06, 0xa6, 0x68, 0x0b, 0xe7, 0x85, 0x74, 0x71, 0x2b,
0x84, 0x84, 0x5d, 0x71, 0x79, 0x52, 0x34, 0x19, 0x8e, 0xbb, 0x28, 0x97,
0x09, 0x7e, 0x45, 0x1e, 0xf7, 0x3f, 0x8a, 0x96, 0x23, 0x3e, 0xd4, 0x4c,
0x9f, 0x7c, 0xc4, 0x05, 0x9f, 0xe0, 0x62, 0x8a, 0xe6, 0xbd, 0xe6, 0x69,
0xf3, 0xa6, 0x39, 0x8b, 0x6c, 0xc8, 0x52, 0x13, 0xcb, 0xe6, 0xb9, 0x52,
0x3a, 0x73, 0xd7, 0x1d, 0x93, 0x4e, 0x3c, 0x78, 0xad, 0xcc, 0x3e, 0xc5,
0xa0, 0xea, 0x54, 0x26, 0x8b, 0x1d, 0x77, 0xd3, 0xa1, 0x24, 0x68, 0x11,
0xe6, 0x5e, 0x10, 0x97, 0x3a, 0xbf, 0xd4, 0xc3, 0xff, 0xfb, 0x4f, 0x51,
0x2c, 0xf6, 0x92, 0x9e, 0x57, 0x4c, 0xdd, 0x6a, 0x5e, 0xd8, 0x54, 0x30,
0x0e, 0x8a, 0x03, 0x94, 0x0e, 0xde, 0xa8, 0x92, 0xf0, 0xa4, 0x04, 0xb6,
0x82, 0xc4, 0x87, 0xa0, 0xa3, 0xdb, 0x59, 0x10, 0x43, 0x00, 0xce, 0x26,
0xb6, 0xcf, 0x50, 0x10, 0x99, 0x20, 0x91, 0xf3, 0x2d, 0xd9, 0x0b, 0x9d,
0xf2, 0x76, 0x3c, 0x09, 0x75, 0x04, 0xf7, 0x1d, 0xaf, 0xae, 0xe5, 0x74,
0xe5, 0x0f, 0x1d, 0x53, 0x15, 0xf7, 0x38, 0x15, 0x3c, 0xd3, 0x98, 0xd9,
0x18, 0xc7, 0xc3, 0xb0, 0xfa, 0xb8, 0x8d, 0x4b, 0x31, 0x9c, 0xc2, 0x74,
0xdc, 0xde, 0x7a, 0x7e, 0x2b, 0x15, 0x74, 0x9a, 0xc9, 0xa1, 0xca, 0x28,
0xb3, 0xcc, 0x71, 0x06, 0xc9, 0x5b, 0x7a, 0x03, 0xcc, 0xc8, 0xde, 0x00,
0x53, 0x73, 0x2c, 0x5f, 0x8d, 0xae, 0x43, 0xe2, 0xa1, 0x71, 0xcc, 0x66,
0x6c, 0xec, 0x22, 0x99, 0x93, 0x00, 0xca, 0xcc, 0xf9, 0x59, 0xd1, 0x94,
0x6b, 0x86, 0x51, 0x70, 0x0b, 0x28, 0x03, 0xea, 0x6d, 0x7c, 0x3b, 0xf4,
0xeb, 0x37, 0xcd, 0x35, 0x68, 0xa3, 0x5c, 0xc3, 0x4b, 0x94, 0x93, 0x6b,
0xe6, 0xe7, 0x67, 0xde, 0xe7, 0x82, 0x42, 0x50, 0xe5, 0xba, 0x1f, 0x85,
0x36, 0x86, 0x28, 0xf7, 0xbf, 0x8b, 0xb9, 0xb6, 0x9e, 0xb6, 0x61, 0x28,
0xfc, 0x57, 0x20, 0x9a, 0xaa, 0x64, 0x98, 0x06, 0xa6, 0x3d, 0x6c, 0x29,
0x2e, 0x62, 0x68, 0xd2, 0xa4, 0x81, 0x98, 0x54, 0xf6, 0x84, 0x10, 0x4a,
0xd3, 0x94, 0x06, 0x52, 0x1b, 0x35, 0x61, 0xac, 0xaa, 0xf8, 0xef, 0x3b,
0x17, 0x27, 0x71, 0xdc, 0xb4, 0x88, 0xbe, 0xec, 0xa5, 0x4d, 0x6d, 0xc7,
0x97, 0xe3, 0xe3, 0x73, 0xf1, 0xf9, 0x4e, 0x3b, 0xac, 0xf8, 0x81, 0xa9,
0xc6, 0xa0, 0xb5, 0x3a, 0x85, 0xee, 0x22, 0x68, 0x38, 0xc5, 0x33, 0x66,
0xa8, 0xd5, 0x84, 0xf0, 0x65, 0xdb, 0x3c, 0x74, 0x84, 0x05, 0xb7, 0x31,
0xcb, 0xfc, 0x2f, 0x22, 0x91, 0x81, 0x4b, 0x38, 0x37, 0x57, 0x04, 0x5e,
0x8d, 0xb6, 0xc9, 0xc0, 0x66, 0x9d, 0x1c, 0x6c, 0x6f, 0x31, 0x85, 0xb3,
0x4a, 0x6a, 0xb1, 0xb6, 0x97, 0x5d, 0x20, 0x0b, 0x86, 0x57, 0xa4, 0xef,
0x5d, 0x64, 0xba, 0x9b, 0xc4, 0xdc, 0x22, 0xe5, 0xd1, 0xa9, 0xe7, 0x59,
0xd1, 0x42, 0xdd, 0xc8, 0xfe, 0x77, 0x12, 0x43, 0x18, 0xdb, 0x47, 0xa3,
0x4c, 0x4c, 0x82, 0x95, 0xe5, 0x45, 0xd6, 0xba, 0xd2, 0x03, 0xe9, 0x93,
0x29, 0x90, 0x3b, 0x5b, 0x03, 0x72, 0x03, 0x3b, 0x78, 0xa7, 0xaa, 0xe8,
0x9c, 0xb2, 0xa3, 0x89, 0x75, 0x57, 0x83, 0x31, 0x0c, 0xff, 0x38, 0x68,
0xa2, 0x8b, 0x50, 0x43, 0xb1, 0x45, 0xbb, 0x02, 0x23, 0x8c, 0x50, 0xfe,
0x10, 0xff, 0x89, 0x19, 0x7b, 0xde, 0xaa, 0x4d, 0xec, 0x18, 0x23, 0x34,
0x4b, 0xee, 0xf0, 0xa9, 0xd5, 0xa2, 0x8e, 0x39, 0x16, 0xcd, 0xe3, 0xd3,
0xec, 0xa9, 0x2b, 0x96, 0x59, 0x87, 0x30, 0x29, 0x3c, 0x09, 0x1b, 0x50,
0x6b, 0x19, 0x63, 0xfc, 0x80, 0x27, 0x11, 0x83, 0x3c, 0x8a, 0x61, 0x63,
0x29, 0x0b, 0xa3, 0x8f, 0xd3, 0x0e, 0x44, 0x5d, 0x59, 0x92, 0xa7, 0xa6,
0xc1, 0x9e, 0xb4, 0x0a, 0x15, 0x14, 0x2a, 0x06, 0xc0, 0x81, 0xc4, 0x4d,
0xed, 0xf6, 0x64, 0x1a, 0x55, 0xb3, 0x26, 0xc8, 0x08, 0x35, 0x0b, 0x99,
0x3e, 0x11, 0xff, 0xc0, 0x73, 0x42, 0x1c, 0x91, 0x4b, 0xb4, 0x64, 0x44,
0x21, 0x31, 0xb4, 0x8d, 0xfb, 0x0c, 0x24, 0x6f, 0x30, 0x14, 0x99, 0xdf,
0x66, 0xd5, 0xca, 0xf3, 0xcc, 0x8d, 0xe7, 0xd9, 0xeb, 0xb5, 0x5d, 0xcf,
0x1c, 0x98, 0x01, 0x74, 0xa5, 0x2d, 0x0b, 0x7d, 0x57, 0x38, 0xe0, 0x3a,
0x5c, 0x4f, 0xbb, 0x61, 0x9e, 0xf5, 0x01, 0xdf, 0xc6, 0x84, 0xec, 0xa4,
0x21, 0xd7, 0x5f, 0x33, 0x3a, 0x70, 0x57, 0xcd, 0x6a, 0xe0, 0xb9, 0x48,
0x20, 0x59, 0x13, 0xe8, 0xd4, 0x07, 0x2f, 0x25, 0x65, 0x2c, 0xa2, 0x9f,
0x3b, 0x1e, 0xb2, 0x31, 0x0b, 0x46, 0x94, 0xcf, 0xc6, 0xb6, 0xf3, 0x46,
0x3c, 0x6b, 0x10, 0x11, 0x61, 0x5d, 0xe5, 0x63, 0x47, 0x95, 0xd7, 0xc5,
0xca, 0x45, 0x23, 0x3a, 0x2d, 0x43, 0x2b, 0xdf, 0x26, 0x32, 0x12, 0x04,
0x62, 0x59, 0x70, 0x00, 0xb2, 0x7c, 0x73, 0xdb, 0xe6, 0x65, 0xf6, 0x35,
0xc7, 0x6d, 0x9f, 0xf8, 0xb3, 0x40, 0x5a, 0x8d, 0xd2, 0xa2, 0xa0, 0x45,
0xe0, 0x82, 0x2f, 0xc1, 0xf6, 0xf6, 0x3d, 0xe0, 0xa9, 0x70, 0x0e, 0x4f,
0x2c, 0x96, 0x89, 0x12, 0xd7, 0xb3, 0x74, 0x6e, 0x6a, 0x4a, 0x7c, 0x84,
0x2a, 0x85, 0x55, 0x1f, 0x88, 0xfa, 0x23, 0x0a, 0x77, 0xc0, 0x94, 0xe5,
0x71, 0x78, 0x24, 0xd6, 0xbb, 0xfd, 0x5d, 0xa4, 0x23, 0x3d, 0x2d, 0xaf,
0xe3, 0x31, 0x10, 0xe5, 0x28, 0xe8, 0x68, 0x01, 0x55, 0xe4, 0xbe, 0x7e,
0x32, 0xe3, 0xfd, 0xc8, 0xee, 0x67, 0x39, 0x5e, 0xba, 0x9d, 0x25, 0x98,
0x68, 0x73, 0x01, 0x5b, 0x64, 0xde, 0x84, 0xca, 0x11, 0x30, 0xef, 0xaf,
0x45, 0xa6, 0xca, 0x4b, 0x82, 0xc9, 0x10, 0xbb, 0xc1, 0xa6, 0xe8, 0xf9,
0x3c, 0x56, 0x93, 0x02, 0x1d, 0xe6, 0x73, 0x7e, 0xf6, 0x57, 0xe8, 0xbf,
0x44, 0x84, 0x54, 0xf4, 0xc4, 0x18, 0xce, 0xe9, 0xcf, 0x74, 0x19, 0xad,
0x5e, 0x32, 0x15, 0x79, 0xe7, 0xe5, 0x22, 0x3f, 0x1c, 0x79, 0x62, 0x1e,
0x27, 0xf0, 0x83, 0xdb, 0xc3, 0xef, 0x57, 0x81, 0x02, 0x2c, 0x6a, 0xfb,
0x4f, 0x15, 0xa4, 0x0a, 0x3d, 0xed, 0x2b, 0x95, 0x2f, 0xa3, 0xfd, 0xe3,
0xd7, 0xb7, 0x86, 0x84, 0x39, 0xc2, 0x60, 0x63, 0x0d, 0xcc, 0x50, 0x43,
0xa9, 0x3a, 0xe7, 0x70, 0x96, 0x97, 0x87, 0x33, 0x67, 0x1e, 0x5c, 0xd6,
0x3d, 0x17, 0x17, 0x9b, 0xc5, 0x44, 0x21, 0x5a, 0x02, 0x37, 0xf8, 0x1e,
0xbb, 0x9d, 0x9e, 0x68, 0xbd, 0xd6, 0xcd, 0x9f, 0x47, 0x01, 0xbd, 0x6d,
0xec, 0xa5, 0x96, 0xa6, 0x7b, 0x97, 0xad, 0xb6, 0x19, 0xce, 0x4d, 0x12,
0x50, 0x62, 0x10, 0x49, 0xd6, 0x12, 0x4c, 0xec, 0xc0, 0x84, 0x28, 0x7f,
0x10, 0x76, 0x87, 0x3b, 0xd1, 0x91, 0x51, 0x02, 0xaa, 0x4a, 0x0f, 0x36,
0xcf, 0x22, 0x95, 0xa0, 0xce, 0x24, 0x8d, 0xc4, 0x47, 0x3a, 0x38, 0xf0,
0x50, 0x7b, 0x4d, 0x84, 0x73, 0xf2, 0xe0, 0xe5, 0x77, 0x1e, 0xbc, 0x4c,
0xf8, 0xba, 0xa5, 0x9d, 0x03, 0xc7, 0x02, 0xc1, 0xba, 0x6f, 0xb9, 0x1e,
0xfb, 0x37, 0xe5, 0xad, 0x58, 0xa1, 0x05, 0x19, 0x29, 0xa0, 0x7a, 0x1a,
0xd4, 0x27, 0xd6, 0x31, 0x48, 0xcc, 0xa9, 0xd5, 0xb4, 0x5e, 0x03, 0xd6,
0xb3, 0x97, 0x5c, 0xef, 0x17, 0x5e, 0x55, 0x6c, 0x5c, 0x33, 0x11, 0xcb,
0x66, 0x15, 0xbb, 0x0b, 0x54, 0x1a, 0x84, 0xe2, 0xbf, 0xa7, 0xbe, 0x80,
0xe0, 0xcf, 0xb9, 0x21, 0x39, 0xee, 0xd1, 0x23, 0xf0, 0x2d, 0xf0, 0x29,
0x50, 0xe2, 0x6e, 0x4e, 0xa1, 0xc8, 0x36, 0x07, 0x62, 0x9e, 0x1a, 0xa2,
0x9a, 0x79, 0x80, 0x35, 0x26, 0x07, 0x9e, 0xc4, 0xa3, 0x82, 0xb3, 0xb3,
0xcc, 0x0b, 0xad, 0xbe, 0xe9, 0xc9, 0x92, 0x2e, 0x99, 0xaa, 0x5d, 0xd3,
0x72, 0xf5, 0x3a, 0x80, 0x73, 0x30, 0xd1, 0x2f, 0x74, 0x47, 0x88, 0xed,
0xfa, 0x33, 0xd0, 0x31, 0x20, 0x6f, 0x81, 0x43, 0x92, 0xd4, 0x0f, 0x6f,
0x4e, 0x7b, 0xb7, 0x07, 0x60, 0x5d, 0x48, 0xf8, 0x0a, 0x24, 0x3c, 0xf4,
0x6e, 0x3f, 0x06, 0xe1, 0x7d, 0x26, 0xdc, 0xcb, 0x23, 0x0d, 0xd4, 0x95,
0x48, 0x57, 0xcb, 0x35, 0xd8, 0xb7, 0x5c, 0x03, 0xcc, 0x39, 0x90, 0x2d,
0x13, 0xa7, 0xd2, 0x27, 0x42, 0x13, 0x14, 0x15, 0xbe, 0xf0, 0xbf, 0x72,
0xe0, 0x8b, 0xe4, 0x1b, 0x42, 0xb2, 0x6d, 0xdc, 0xbd, 0xc7, 0xe9, 0xc8,
0x1e, 0xe9, 0x49, 0x69, 0xa1, 0x20, 0x3d, 0x2c, 0x20, 0x13, 0x2c, 0x5d,
0xd7, 0x8f, 0x27, 0xa1, 0xc9, 0x91, 0x33, 0xb9, 0x72, 0x84, 0x05, 0x44,
0xd3, 0xb2, 0x88, 0xc2, 0x30, 0x99, 0xa8, 0x07, 0x54, 0x25, 0xfa, 0x79,
0x32, 0xcd, 0x41, 0xd3, 0xa2, 0x34, 0x09, 0xe3, 0x87, 0xf8, 0x6f, 0x98,
0x67, 0xe3, 0x02, 0x31, 0x6b, 0xe1, 0x71, 0xff, 0x73, 0xff, 0x6b, 0x85,
0x5e, 0x43, 0x40, 0x2a, 0xb0, 0xab, 0x7c, 0x2e, 0xa7, 0x87, 0x5f, 0x86,
0x6e, 0xd7, 0x94, 0x86, 0xc7, 0x8f, 0x83, 0x0d, 0xee, 0x11, 0xd0, 0xa0,
0xe5, 0x8b, 0x9c, 0xc7, 0x0a, 0x5d, 0x3e, 0x72, 0xd5, 0xcc, 0x18, 0x35,
0x92, 0xee, 0x25, 0x1d, 0x8b, 0xbd, 0x72, 0xb1, 0x64, 0x5f, 0x2e, 0x89,
0xf3, 0xbd, 0x44, 0x3f, 0x2d, 0xf1, 0x34, 0xf0, 0x18, 0x9b, 0xaf, 0x38,
0xd9, 0x30, 0x0b, 0x18, 0x8e, 0xe1, 0xd9, 0xf8, 0x3b, 0x4f, 0x70, 0x65,
0x3f, 0x2e, 0x96, 0x2a, 0xc1, 0x24, 0x83, 0xba, 0x13, 0xa4, 0x6e, 0xfb,
0x8e, 0x89, 0x5a, 0x06, 0x41, 0xb3, 0x4c, 0x0c, 0x71, 0xec, 0x55, 0x06,
0xb2, 0xc5, 0x4c, 0x43, 0xf2, 0x77, 0xc1, 0xbd, 0xe7, 0x1d, 0x1a, 0xb2,
0xdf, 0x5a, 0x15, 0xe2, 0xee, 0x38, 0x45, 0xbc, 0xef, 0x4e, 0x61, 0x95,
0x42, 0xcd, 0x7e, 0xb3, 0xfd, 0x8f, 0x2c, 0x4e, 0x43, 0xe3, 0xd6, 0x0c,
0xeb, 0xfc, 0x29, 0x2b, 0x55, 0xb1, 0x4a, 0x62, 0x3a, 0x19, 0x2f, 0xb8,
0x3d, 0x27, 0x51, 0xd9, 0xa9, 0x9e, 0x43, 0x23, 0x6d, 0x08, 0x6f, 0x48,
0xfd, 0xf2, 0x67, 0x46, 0x20, 0x16, 0xec, 0xaf, 0x0d, 0x6b, 0xe9, 0x9e,
0x10, 0xb7, 0x1e, 0xfe, 0x03, 0x0b, 0x5a, 0x75, 0x81, 0x5c, 0x4a, 0x00,
0x00
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xed, 0x3c, 0x09, 0x5b, 0xdb, 0xc8,
0x92, 0x7f, 0x45, 0x28, 0x6f, 0x06, 0xe9, 0x81, 0x25, 0x9b, 0x04, 0x42, 0x00, 0x91, 0xe1, 0x0c,
0x84, 0x33, 0x9c, 0x21, 0xd9, 0xec, 0xfb, 0xda, 0x52, 0xdb, 0x16, 0xc8, 0x92, 0x22, 0xb5, 0x30,
0x86, 0xc7, 0xfe, 0xf6, 0xad, 0xaa, 0xd6, 0xed, 0x83, 0x64, 0xde, 0x9b, 0x9d, 0xf9, 0x76, 0x77,
0x32, 0x5f, 0x2c, 0xf5, 0x59, 0x5d, 0x55, 0x5d, 0xb7, 0xb2, 0x36, 0xb3, 0x7d, 0xb2, 0x75, 0x71,
0x73, 0xba, 0xa3, 0xf4, 0x44, 0xdf, 0x53, 0x4e, 0x2f, 0x37, 0x0f, 0xf7, 0xb7, 0x14, 0xb5, 0x61,
0x9a, 0xd7, 0xaf, 0xb7, 0x4c, 0x73, 0xfb, 0x62, 0x5b, 0xf9, 0xbc, 0x77, 0x71, 0x74, 0xa8, 0xb4,
0x8c, 0xa6, 0x72, 0x11, 0x31, 0x3f, 0x76, 0x85, 0x1b, 0xf8, 0xcc, 0x33, 0xcd, 0x9d, 0x63, 0x55,
0x51, 0x7b, 0x42, 0x84, 0x2b, 0xa6, 0x39, 0x18, 0x0c, 0x8c, 0xc1, 0x6b, 0x23, 0x88, 0xba, 0xe6,
0xc5, 0x99, 0xf9, 0x80, 0x6b, 0xb5, 0x70, 0x72, 0xfa, 0xd8, 0x10, 0xa5, 0x99, 0x86, 0x23, 0x1c,
0x75, 0x7d, 0x8d, 0xf6, 0xf3, 0x98, 0xdf, 0xb5, 0xb8, 0xbf, 0xbe, 0x26, 0x5c, 0xe1, 0xf1, 0xf5,
0x5d, 0xd7, 0xe3, 0x4a, 0x9f, 0xf9, 0xac, 0xcb, 0xa3, 0x35, 0x53, 0xb6, 0xad, 0xc5, 0x62, 0x88,
0xad, 0xdc, 0x71, 0x99, 0x15, 0xdb, 0x11, 0x87, 0xe1, 0x4a, 0x3b, 0x70, 0x86, 0x4f, 0x9d, 0xc0,
0x17, 0x8d, 0xd8, 0x7d, 0xe4, 0x2b, 0x4a, 0x6b, 0x21, 0x7c, 0x58, 0x55, 0xa8, 0xa1, 0xc3, 0xfa,
0xae, 0x37, 0x5c, 0x51, 0xae, 0x78, 0xe4, 0xc0, 0x4a, 0xf3, 0xca, 0x46, 0xe4, 0x32, 0x6f, 0x5e,
0x39, 0x07, 0x08, 0x1a, 0x31, 0x8f, 0xdc, 0xce, 0xb3, 0x61, 0xc3, 0x40, 0xfe, 0x20, 0x8e, 0xb8,
0x9f, 0x3c, 0x3d, 0x36, 0x5c, 0xdf, 0xe1, 0x0f, 0x2b, 0xca, 0xeb, 0x66, 0x73, 0x55, 0x09, 0x03,
0x09, 0xe6, 0x8a, 0xc2, 0xda, 0x71, 0xe0, 0x25, 0x82, 0xaf, 0x2a, 0x1e, 0xef, 0x88, 0x15, 0x65,
0x11, 0x77, 0x68, 0x07, 0x91, 0xc3, 0x23, 0xd8, 0x2f, 0x7c, 0x50, 0xa0, 0xdb, 0x75, 0x94, 0x57,
0x6f, 0xde, 0xbc, 0x81, 0x76, 0x66, 0xdf, 0x75, 0xa3, 0x20, 0xf1, 0x9d, 0x86, 0x1d, 0x78, 0x01,
0x8c, 0x78, 0xd5, 0x59, 0xc4, 0x3f, 0xab, 0x8a, 0xe3, 0xc6, 0xa1, 0xc7, 0x00, 0x20, 0x3f, 0xf0,
0x39, 0xae, 0xf0, 0xd0, 0x88, 0x7b, 0xcc, 0x09, 0x06, 0x2b, 0x4a, 0x13, 0xfe, 0xb4, 0x9a, 0xb0,
0x54, 0xd4, 0x6d, 0x33, 0xad, 0x39, 0xaf, 0xc8, 0xff, 0x8d, 0x37, 0x7a, 0x7a, 0x96, 0xf4, 0x70,
0xad, 0xfc, 0x70, 0x03, 0xee, 0x76, 0x7b, 0x00, 0xcc, 0xdb, 0x66, 0xb3, 0x72, 0x0a, 0x25, 0xf1,
0x9e, 0x3c, 0x37, 0x86, 0x19, 0x88, 0xac, 0x6c, 0x2f, 0x11, 0x84, 0xb0, 0x49, 0x76, 0x00, 0x78,
0xe8, 0xb3, 0xa8, 0xeb, 0xfa, 0xf4, 0x18, 0x32, 0xc7, 0x71, 0xfd, 0x2e, 0x3c, 0x57, 0x17, 0xf2,
0xdc, 0xa7, 0x02, 0x07, 0x11, 0xf7, 0x98, 0x70, 0xef, 0x61, 0xa9, 0xbe, 0xeb, 0x37, 0x06, 0xae,
0x23, 0x7a, 0x2b, 0xca, 0x52, 0x13, 0xc1, 0xb1, 0x93, 0x28, 0xc6, 0x73, 0x86, 0x81, 0x0b, 0x93,
0xa3, 0xea, 0x22, 0x71, 0xc8, 0xfc, 0xa7, 0x0c, 0x11, 0x84, 0xa0, 0x1c, 0x0b, 0xae, 0xef, 0xb9,
0x3e, 0x6f, 0xb4, 0xbd, 0xc0, 0xbe, 0x2b, 0x41, 0xb1, 0x14, 0x3e, 0xd4, 0xe1, 0x58, 0xe9, 0x05,
0xf7, 0x3c, 0x7a, 0x2a, 0x50, 0x2b, 0xd7, 0x1a, 0x3f, 0xac, 0xba, 0x25, 0xe7, 0x1c, 0x86, 0xc5,
0x31, 0xf0, 0x1d, 0xe7, 0xf7, 0x2e, 0x1f, 0xc0, 0x38, 0xc0, 0x6b, 0xa5, 0x05, 0x30, 0x56, 0xe0,
0xa0, 0x82, 0x9a, 0x3a, 0x22, 0x6b, 0x4b, 0xb9, 0x7e, 0x98, 0x88, 0xa7, 0x71, 0x8c, 0x12, 0x84,
0xcc, 0x76, 0xc5, 0x50, 0xe2, 0xb4, 0x34, 0xe5, 0x69, 0x84, 0x98, 0x8d, 0x7e, 0xf0, 0xd8, 0x48,
0x80, 0x1b, 0x81, 0x23, 0x3d, 0x6e, 0x8b, 0x8c, 0x62, 0x40, 0xe0, 0xf6, 0x9d, 0x2b, 0xc6, 0x75,
0x8d, 0x34, 0xd5, 0xc0, 0xaa, 0x20, 0xa0, 0xd9, 0xec, 0x8c, 0x23, 0x51, 0x7d, 0x7c, 0x8a, 0x62,
0xc4, 0x66, 0xc3, 0xe1, 0x76, 0x10, 0x31, 0x79, 0x24, 0x40, 0x36, 0x8f, 0x90, 0x4e, 0xe3, 0x8e,
0x3e, 0xe7, 0xb1, 0x36, 0xf7, 0xe6, 0x00, 0x7f, 0x39, 0xce, 0xe8, 0xcf, 0xc2, 0x02, 0xd1, 0x70,
0x64, 0xfc, 0x7f, 0xc1, 0xc8, 0xca, 0x25, 0xa8, 0x93, 0x06, 0x97, 0xab, 0x53, 0x87, 0x1a, 0x57,
0x56, 0xda, 0xbc, 0x13, 0x44, 0xfc, 0x69, 0xfa, 0x49, 0x68, 0x97, 0x15, 0xd8, 0x82, 0xb5, 0x3d,
0xee, 0x48, 0xf0, 0xf2, 0x29, 0x0e, 0xef, 0xb0, 0xc4, 0x13, 0x25, 0xe2, 0x18, 0x4b, 0x63, 0xe7,
0xdb, 0x3d, 0x6e, 0xdf, 0x71, 0x67, 0xc5, 0x0f, 0x84, 0x96, 0x2f, 0xa6, 0x57, 0x80, 0x27, 0xa6,
0xfd, 0x69, 0xe8, 0xeb, 0x9d, 0x44, 0xa8, 0x32, 0x57, 0x27, 0x91, 0xa7, 0x39, 0x4c, 0xb0, 0x15,
0xb7, 0x0f, 0x82, 0xcf, 0x0c, 0xfd, 0xee, 0x6a, 0x9b, 0xc5, 0x7c, 0xe9, 0xcd, 0xbc, 0x7b, 0xb5,
0x79, 0x72, 0x36, 0x68, 0x1e, 0x7c, 0xe8, 0x06, 0x1b, 0xf0, 0xdf, 0xf1, 0xf9, 0x65, 0x6f, 0xe7,
0xb2, 0x0b, 0x4f, 0x9b, 0xf8, 0xba, 0xd5, 0xdd, 0xda, 0x38, 0xc2, 0x87, 0xe1, 0xe2, 0xc3, 0xa0,
0x8f, 0x0f, 0xed, 0xd6, 0xe6, 0xd1, 0xd5, 0xce, 0xd5, 0x9e, 0xbd, 0x33, 0xbc, 0xee, 0x2f, 0x2e,
0x5e, 0x5f, 0x2f, 0xec, 0x2c, 0x7d, 0xba, 0x74, 0x36, 0x3e, 0xed, 0x6c, 0xba, 0xec, 0x43, 0xeb,
0x96, 0x7d, 0x78, 0x6b, 0x9a, 0xe6, 0xf2, 0xfd, 0xf1, 0xed, 0xeb, 0x83, 0xc7, 0xa3, 0xb7, 0x5b,
0x0f, 0x47, 0xed, 0xfe, 0x62, 0xd2, 0x39, 0x7a, 0xb4, 0xcd, 0x9b, 0x05, 0xe7, 0xfb, 0x83, 0x38,
0x64, 0x1f, 0xdc, 0x60, 0x71, 0xb9, 0x7b, 0x73, 0xfd, 0xf1, 0xf6, 0xcb, 0xee, 0xd9, 0xd5, 0xee,
0x97, 0x8f, 0x17, 0x3b, 0xe6, 0xe1, 0xa3, 0x3d, 0x77, 0x1f, 0xb7, 0x8f, 0x9d, 0xcf, 0x57, 0x6f,
0xdf, 0xcc, 0x9d, 0xf6, 0xee, 0x9d, 0x3d, 0x2f, 0x6e, 0x5f, 0x2f, 0xdc, 0x85, 0x4b, 0xdf, 0xdf,
0xde, 0x1f, 0x3e, 0x0e, 0x97, 0xef, 0x8f, 0x92, 0xe3, 0x8b, 0xc7, 0xce, 0xeb, 0x77, 0x73, 0xbd,
0x60, 0xe9, 0x72, 0x78, 0x72, 0xb9, 0xb5, 0xdb, 0xbb, 0xb9, 0xbe, 0xf4, 0x16, 0xfd, 0xfb, 0xb7,
0x73, 0x66, 0xb8, 0xc4, 0xef, 0x3e, 0xb9, 0xe6, 0x87, 0x33, 0x84, 0x71, 0xe3, 0xf3, 0xd9, 0xf9,
0x85, 0x77, 0xb4, 0xf1, 0xe9, 0xa4, 0x7d, 0xf3, 0x05, 0xcf, 0x72, 0x7e, 0xf6, 0xf1, 0x6c, 0x67,
0xf7, 0xf2, 0xfc, 0xa8, 0x23, 0xee, 0xde, 0x89, 0xe1, 0xc0, 0xdd, 0xf8, 0xd4, 0x0b, 0x2e, 0x37,
0x7a, 0x57, 0x1b, 0x83, 0x8f, 0xe1, 0xf7, 0xed, 0xb3, 0xef, 0x1d, 0x76, 0x7f, 0xbf, 0xfc, 0xe8,
0x25, 0xc7, 0x07, 0x77, 0x49, 0xb4, 0x73, 0x1b, 0xdd, 0xbc, 0x9e, 0xe3, 0x6f, 0xdf, 0x7c, 0x74,
0x1f, 0x0f, 0xfd, 0x85, 0xeb, 0x56, 0xdf, 0xdd, 0x38, 0x78, 0x08, 0x7b, 0x27, 0x9b, 0x47, 0xfc,
0xf2, 0xe6, 0xfb, 0x52, 0xb2, 0x67, 0x6e, 0xbc, 0xde, 0x58, 0x5a, 0xba, 0x09, 0xcf, 0x36, 0xcf,
0xbe, 0x7f, 0xfc, 0xc2, 0x8e, 0xf6, 0x97, 0xdd, 0x41, 0x7c, 0x65, 0x6e, 0x39, 0x47, 0x4b, 0x1b,
0x0b, 0x0f, 0xb7, 0x8b, 0xfe, 0xfe, 0x65, 0x7c, 0xd0, 0x34, 0xdd, 0x8b, 0xcb, 0xd3, 0xe8, 0xc3,
0x71, 0xbf, 0x79, 0x74, 0xb9, 0xbd, 0x7f, 0xc7, 0x3f, 0x98, 0x1f, 0x17, 0xdf, 0x24, 0x27, 0xee,
0x5d, 0xdc, 0x7e, 0xd7, 0xfb, 0xdc, 0x5b, 0x5c, 0x3c, 0xed, 0xed, 0xef, 0xdf, 0x76, 0x0e, 0xba,
0xce, 0xc7, 0x8b, 0xbd, 0xf3, 0x9d, 0xe1, 0x82, 0xb9, 0xbb, 0xdd, 0x5c, 0xfa, 0xdc, 0x0f, 0x9c,
0xe5, 0xe3, 0x93, 0x41, 0x14, 0x0d, 0x76, 0x2f, 0xe3, 0x4f, 0xfd, 0xcf, 0x5f, 0xf6, 0xbe, 0xf4,
0x7a, 0xfc, 0x6e, 0x6f, 0xd3, 0xdd, 0x1c, 0xde, 0xec, 0x07, 0x6c, 0xff, 0xe3, 0xc6, 0xed, 0xe9,
0xf2, 0xe5, 0xf9, 0xb5, 0xbb, 0xb5, 0xb1, 0x7c, 0xd0, 0xdb, 0xb9, 0x5e, 0xbe, 0xfc, 0x70, 0xf1,
0xf6, 0xe0, 0x94, 0x7d, 0xd9, 0x79, 0x88, 0x4f, 0xda, 0x7b, 0xc3, 0xe8, 0xb2, 0x7b, 0x71, 0x77,
0x7b, 0xf1, 0xb8, 0xec, 0xb9, 0xa7, 0x9f, 0x07, 0x8f, 0x83, 0x9d, 0xcd, 0xb9, 0x93, 0xd3, 0xdd,
0xab, 0x87, 0xbd, 0x9d, 0xe5, 0xcf, 0x0b, 0xf6, 0xdd, 0xd9, 0xe6, 0xf0, 0x90, 0x5d, 0x0d, 0x7b,
0x57, 0x07, 0x0f, 0xa7, 0x0b, 0x6f, 0x0f, 0x8e, 0xe7, 0xfc, 0x0d, 0xb1, 0xf7, 0xf6, 0xec, 0x3e,
0x89, 0x16, 0xb6, 0xa3, 0xa5, 0x85, 0x96, 0xe0, 0x77, 0x47, 0x3c, 0x9e, 0xbb, 0x76, 0x3f, 0x2c,
0x2f, 0xed, 0x45, 0x4b, 0xb7, 0x07, 0x37, 0xb7, 0x73, 0x6f, 0x3f, 0xb5, 0x0e, 0x9c, 0xe6, 0x69,
0xf8, 0xb0, 0xbf, 0xb8, 0x7c, 0x1c, 0x7f, 0x72, 0x8e, 0xcd, 0x85, 0xc5, 0x47, 0xef, 0xd3, 0xf6,
0x27, 0xe7, 0xa0, 0xfd, 0x6e, 0xc3, 0x3f, 0x5a, 0xea, 0xec, 0x9d, 0x7f, 0xb8, 0x3b, 0x8d, 0x3f,
0xb1, 0x8f, 0xac, 0xbf, 0x1f, 0x7e, 0x7a, 0xdc, 0x8a, 0x86, 0x83, 0xde, 0x76, 0xcb, 0xbd, 0x58,
0xf8, 0x7c, 0x17, 0x1f, 0x6e, 0x0d, 0x62, 0x73, 0xff, 0xcb, 0xfd, 0xf2, 0x97, 0xa0, 0xf3, 0x56,
0x2c, 0x2c, 0xde, 0x78, 0x77, 0x44, 0xa6, 0xf3, 0xcb, 0xab, 0x93, 0xb3, 0x83, 0xc5, 0xad, 0x9b,
0xfd, 0x7d, 0x4b, 0x87, 0x7b, 0xdb, 0x88, 0x78, 0xc8, 0x99, 0xf8, 0xb7, 0xb0, 0xff, 0xb8, 0xb6,
0xfc, 0xb2, 0x4f, 0x50, 0x15, 0xbd, 0x54, 0xf5, 0xb5, 0x96, 0x50, 0x80, 0x52, 0x4f, 0xb5, 0x09,
0x24, 0x99, 0x70, 0x6d, 0xe6, 0x35, 0x98, 0xe7, 0x76, 0x41, 0x2a, 0xf5, 0x5d, 0xc7, 0xf1, 0xc6,
0x0a, 0x9b, 0xd2, 0xed, 0x6b, 0x14, 0x72, 0xbc, 0xb5, 0x0c, 0x9a, 0xb8, 0x39, 0x4e, 0xaa, 0x4e,
0x1e, 0xde, 0x78, 0xb3, 0x3c, 0x22, 0xf4, 0x70, 0x8a, 0x21, 0x1e, 0xc4, 0xb4, 0x69, 0x4b, 0x6f,
0xc6, 0x4f, 0x73, 0xfb, 0xdd, 0x69, 0xd3, 0x96, 0x9b, 0x23, 0xd3, 0x6a, 0x82, 0x12, 0x55, 0xa3,
0x0f, 0x28, 0x51, 0xd5, 0x55, 0x25, 0xd5, 0xd7, 0x12, 0x3b, 0x85, 0xac, 0x46, 0x39, 0x8d, 0x02,
0x7b, 0x12, 0xc6, 0x2a, 0xd6, 0x4c, 0x01, 0x41, 0x53, 0x69, 0xbc, 0x1e, 0x95, 0xf0, 0x15, 0xca,
0xfd, 0xcc, 0xee, 0xd3, 0x64, 0xf0, 0x5c, 0xf5, 0x50, 0x93, 0xc0, 0xc1, 0xa5, 0x9f, 0x7f, 0x23,
0xc3, 0x50, 0x91, 0x86, 0xa1, 0xc2, 0x7c, 0x47, 0xd1, 0x32, 0x25, 0x8a, 0x36, 0x8b, 0x03, 0xcb,
0xdb, 0xbc, 0x11, 0xba, 0x0f, 0xdc, 0x6b, 0x90, 0x7a, 0x5b, 0x69, 0xea, 0x4f, 0x55, 0xed, 0x9c,
0x8d, 0x67, 0x3e, 0x08, 0x60, 0xb9, 0x7a, 0xd6, 0xe2, 0xdc, 0x32, 0x1b, 0x4e, 0xd4, 0x00, 0xb5,
0xdb, 0xc7, 0x5f, 0xa9, 0x7f, 0x83, 0xa8, 0xd1, 0x4e, 0xba, 0x1d, 0xf7, 0x01, 0xc0, 0xee, 0xb8,
0xbe, 0x2b, 0xb8, 0xd2, 0x8a, 0x9f, 0x7f, 0xcb, 0xd6, 0xb9, 0xe3, 0xc3, 0x4e, 0xc4, 0xfa, 0x3c,
0xfe, 0xd1, 0x65, 0x9e, 0x3a, 0x51, 0xd0, 0x2f, 0x59, 0x23, 0xcf, 0x22, 0x28, 0xbf, 0x3d, 0x3f,
0xbf, 0xea, 0x71, 0x06, 0x1a, 0x79, 0xac, 0xd1, 0x91, 0x19, 0x79, 0x91, 0xbc, 0x0b, 0x65, 0x73,
0x2f, 0xbb, 0x1f, 0x0b, 0x6f, 0x90, 0x06, 0xf9, 0x8a, 0x68, 0xbc, 0xb6, 0x88, 0x0a, 0x2d, 0x32,
0xe5, 0xc6, 0x18, 0xaf, 0x64, 0xb3, 0x95, 0xad, 0xa9, 0x57, 0x88, 0xad, 0xc9, 0xfb, 0x2f, 0xa4,
0xd6, 0xb1, 0x10, 0x41, 0xbf, 0x0a, 0x43, 0xca, 0x06, 0x0b, 0xcd, 0x5f, 0x4a, 0x10, 0xe0, 0xa5,
0x79, 0x05, 0x74, 0x03, 0x14, 0xcc, 0x2b, 0xaf, 0xc2, 0x48, 0xd2, 0xe1, 0x85, 0xd5, 0x8b, 0x03,
0x8e, 0xec, 0x03, 0xab, 0x3f, 0xe7, 0xcb, 0x8c, 0x39, 0x0e, 0x9c, 0xa0, 0xb4, 0xfb, 0x22, 0xee,
0x9e, 0x8e, 0x56, 0xf0, 0xc6, 0xe5, 0x78, 0x6a, 0x12, 0x3e, 0x48, 0x0d, 0x83, 0xb8, 0x43, 0x23,
0x88, 0x26, 0x10, 0xf7, 0x30, 0xc1, 0x9d, 0xd5, 0xe7, 0x57, 0xb1, 0x60, 0x22, 0x89, 0x27, 0xc3,
0xfa, 0xba, 0x04, 0xaa, 0x44, 0x6f, 0xd9, 0xf8, 0xa3, 0xad, 0x3b, 0xf1, 0x11, 0x07, 0x2b, 0xe6,
0x29, 0xbb, 0x21, 0x72, 0xd7, 0x14, 0xbc, 0x46, 0x76, 0x38, 0xbc, 0x6b, 0xaf, 0x06, 0x2c, 0xf2,
0xa1, 0x31, 0x87, 0x10, 0xc6, 0xfe, 0x32, 0x8e, 0x60, 0x60, 0xb9, 0xf9, 0x5d, 0x5e, 0x90, 0xac,
0x89, 0xfe, 0x81, 0x08, 0x02, 0x4f, 0xb8, 0xe1, 0x58, 0x58, 0x73, 0xaf, 0x67, 0xa1, 0x8c, 0x58,
0x89, 0x6d, 0x02, 0xe7, 0xde, 0x8d, 0xdd, 0xb6, 0xeb, 0x91, 0xc5, 0xd4, 0x03, 0xb9, 0xc0, 0xfd,
0xf1, 0x5e, 0x4e, 0xa7, 0x53, 0xd9, 0x15, 0xd6, 0x40, 0x63, 0x32, 0x15, 0x28, 0xc8, 0xf4, 0x3c,
0x1a, 0xeb, 0x36, 0xd1, 0xd8, 0x9c, 0x24, 0xaf, 0xeb, 0x88, 0x6a, 0x96, 0x4e, 0x9f, 0x5a, 0xf8,
0xf9, 0x79, 0xca, 0xa0, 0xd1, 0x33, 0x48, 0xf9, 0x57, 0x5e, 0xc0, 0x70, 0xa9, 0xc9, 0x84, 0x69,
0x00, 0xee, 0xee, 0x7b, 0xa3, 0x9c, 0x89, 0xcd, 0x83, 0x92, 0x7a, 0x91, 0xa3, 0x72, 0xfc, 0xb4,
0x10, 0xce, 0xd1, 0x83, 0xd7, 0x3c, 0xb6, 0x45, 0xbd, 0x6c, 0xfd, 0xc3, 0x8e, 0xb9, 0xbf, 0xbb,
0x92, 0xb5, 0xc3, 0xa0, 0x58, 0xe1, 0x60, 0xd7, 0xc1, 0xca, 0x8d, 0x20, 0x11, 0x39, 0xc8, 0x46,
0xdc, 0x0b, 0x06, 0xfe, 0x53, 0x76, 0x8f, 0xf3, 0x65, 0x5a, 0xf9, 0x88, 0x46, 0x3f, 0xee, 0x4e,
0x52, 0x8b, 0xd3, 0x44, 0x42, 0xea, 0xb8, 0x22, 0xcb, 0x10, 0x40, 0x20, 0x4d, 0x81, 0xb1, 0xe8,
0x11, 0xd9, 0xf9, 0xb3, 0xd6, 0x80, 0x3e, 0xbd, 0xa0, 0x1f, 0x11, 0xb3, 0x44, 0x05, 0x92, 0xf7,
0xbf, 0x15, 0xe2, 0x2c, 0x0e, 0x5d, 0xdf, 0x07, 0x2f, 0x04, 0x05, 0xe5, 0x53, 0xf3, 0x97, 0xa7,
0xd2, 0xa2, 0x51, 0x00, 0xf7, 0x82, 0x6b, 0x4d, 0xfd, 0x19, 0x59, 0x74, 0x4c, 0xcf, 0xeb, 0xa5,
0xa6, 0xc3, 0xbb, 0xfa, 0xf3, 0xb3, 0x51, 0x5e, 0x45, 0x5a, 0xdb, 0x11, 0xff, 0x9e, 0xb8, 0x11,
0x58, 0xdb, 0x2f, 0x1f, 0xb2, 0xf0, 0x48, 0xe9, 0x90, 0x74, 0xb6, 0x17, 0x8e, 0x49, 0xa7, 0x9c,
0x57, 0xd2, 0xb3, 0x96, 0x84, 0x7c, 0x19, 0x10, 0x10, 0xe0, 0x85, 0x30, 0xc7, 0xad, 0x59, 0x99,
0x6d, 0x97, 0x0a, 0xbe, 0x25, 0x51, 0x22, 0x3b, 0x1a, 0x74, 0x71, 0x32, 0x8e, 0xa0, 0xfd, 0x42,
0x06, 0x62, 0x43, 0x14, 0x03, 0x80, 0x7c, 0x49, 0x2c, 0x11, 0x99, 0xba, 0xfe, 0xee, 0x23, 0x31,
0x7c, 0x3a, 0x00, 0x9a, 0x80, 0xe2, 0xc0, 0xdd, 0x1d, 0x0f, 0x03, 0x02, 0xd9, 0x45, 0xa3, 0x3b,
0x84, 0x0c, 0x88, 0xca, 0xb4, 0xf1, 0x0e, 0xfe, 0xc3, 0xf9, 0x99, 0xff, 0x4d, 0xd2, 0x3c, 0xe3,
0x57, 0xb2, 0x24, 0xd6, 0x4c, 0x72, 0x57, 0xd7, 0xd7, 0x40, 0x0d, 0xba, 0xa1, 0x58, 0xbf, 0x67,
0x91, 0x82, 0x02, 0x7b, 0x5e, 0xe9, 0xc4, 0xfb, 0x7e, 0x27, 0x00, 0xaa, 0x26, 0xbe, 0x8d, 0xa7,
0x56, 0x62, 0x2e, 0x0e, 0x25, 0x57, 0x69, 0xd0, 0x2d, 0xf4, 0x27, 0xa1, 0xfc, 0xfa, 0x2b, 0x70,
0x80, 0x0f, 0xe7, 0xe3, 0x86, 0x17, 0x74, 0x35, 0xa1, 0xcf, 0x2b, 0x4e, 0x60, 0x27, 0xa8, 0xa9,
0x8c, 0x2e, 0x17, 0x3b, 0x52, 0x69, 0x6d, 0x0e, 0xf7, 0x1d, 0x4d, 0x2d, 0x71, 0xa4, 0xaa, 0x1b,
0x84, 0x3f, 0x0c, 0x0f, 0x59, 0x42, 0xf9, 0xe7, 0x3f, 0x41, 0xed, 0xcf, 0x2b, 0x5c, 0x79, 0xff,
0xe2, 0x6c, 0x98, 0x69, 0x7b, 0x2c, 0x8e, 0x0f, 0xc1, 0xd1, 0x36, 0x40, 0x04, 0x68, 0x2a, 0x5d,
0x01, 0x55, 0x57, 0x56, 0x7e, 0x6e, 0x6e, 0xc4, 0xfb, 0x80, 0xbc, 0x7c, 0x7a, 0x09, 0x6e, 0x0c,
0x10, 0x19, 0x84, 0x14, 0x43, 0x7a, 0x82, 0x16, 0x02, 0xa6, 0x0e, 0x98, 0x2b, 0x54, 0xd8, 0x45,
0x4d, 0xdd, 0x42, 0xf5, 0x39, 0x47, 0x4c, 0x04, 0x2a, 0x16, 0x7d, 0xbe, 0x73, 0x60, 0x7d, 0x8d,
0xeb, 0x4f, 0x6e, 0x47, 0xd1, 0xb8, 0xb2, 0x06, 0x02, 0x60, 0xe1, 0x8d, 0x0e, 0xbd, 0x22, 0x89,
0x7c, 0x38, 0xdd, 0x9c, 0xa2, 0x2a, 0x9b, 0x2a, 0x5e, 0x93, 0x48, 0xd1, 0x08, 0xcf, 0x56, 0xa3,
0x05, 0x14, 0x9b, 0x9b, 0x9b, 0xa7, 0xa1, 0x30, 0x03, 0xa6, 0x99, 0x16, 0x4d, 0x5b, 0x05, 0x86,
0xcb, 0x66, 0x82, 0xf8, 0xda, 0x05, 0x3d, 0xe2, 0x68, 0x0b, 0x3a, 0x2c, 0xf2, 0x55, 0x55, 0x0e,
0xdc, 0x4d, 0xc0, 0x97, 0xaa, 0x1c, 0xa5, 0xbf, 0x1f, 0xd2, 0xdf, 0x0b, 0xf9, 0x7b, 0x0a, 0x3f,
0xdf, 0xbe, 0x8a, 0x6f, 0x65, 0x08, 0x3b, 0x11, 0x8f, 0x7b, 0xe7, 0xa4, 0x81, 0x34, 0xb8, 0x2c,
0x93, 0x50, 0x25, 0x75, 0x54, 0x85, 0x3e, 0xaa, 0x96, 0xce, 0x46, 0x81, 0x63, 0x18, 0x3a, 0x9c,
0x00, 0x81, 0xf7, 0x2d, 0x1f, 0x74, 0xe0, 0xe7, 0xa3, 0xc3, 0x3d, 0x21, 0xc2, 0x33, 0xb8, 0x86,
0x3c, 0x06, 0xee, 0xf5, 0x8d, 0xc0, 0x47, 0x74, 0x5b, 0xf9, 0xd6, 0xb0, 0x1b, 0x0e, 0x47, 0x8e,
0x59, 0x45, 0x35, 0xa9, 0xcc, 0x58, 0xbe, 0x21, 0xb7, 0x01, 0xb4, 0x22, 0xfa, 0x71, 0x81, 0x9d,
0x28, 0x0a, 0x22, 0xcd, 0x47, 0x32, 0x6a, 0xdc, 0xd2, 0x24, 0xef, 0x59, 0x1f, 0xcf, 0x4f, 0x8e,
0x0d, 0xb8, 0x18, 0x31, 0xd7, 0x7c, 0xa0, 0x58, 0x1c, 0x02, 0xaf, 0xf1, 0x0b, 0xe0, 0x70, 0x5d,
0x37, 0xc4, 0x30, 0x94, 0x28, 0x6d, 0x28, 0x6a, 0xc6, 0xac, 0x86, 0x1b, 0x9f, 0xdc, 0xc1, 0xaa,
0x80, 0xc6, 0x39, 0x4b, 0x5d, 0xeb, 0xa3, 0xae, 0x54, 0x5c, 0xc7, 0x9a, 0x4d, 0xf5, 0xe6, 0x2c,
0x06, 0xa3, 0xac, 0xd9, 0xe6, 0x2c, 0x88, 0x4a, 0xe1, 0xf6, 0x93, 0x3e, 0x3e, 0xc3, 0xf5, 0xb1,
0x66, 0xdf, 0x41, 0x5b, 0x0f, 0xae, 0x05, 0x3c, 0x2d, 0xc2, 0x28, 0xf6, 0x60, 0xcd, 0x82, 0x34,
0x9a, 0x85, 0x93, 0x7a, 0x09, 0xb7, 0x66, 0x55, 0xd8, 0x49, 0x6b, 0xc1, 0x5f, 0x47, 0x4c, 0xf4,
0x0c, 0x12, 0xe7, 0xda, 0xbb, 0x77, 0xca, 0xdf, 0xb3, 0x7d, 0x93, 0x98, 0x3b, 0x9b, 0x43, 0x01,
0x82, 0xce, 0xcc, 0x9a, 0x04, 0x08, 0x2f, 0x8f, 0xda, 0x74, 0xa4, 0x9a, 0x3a, 0xab, 0x50, 0x50,
0x32, 0x5d, 0x4b, 0x58, 0x15, 0xa6, 0x19, 0x99, 0x03, 0xa7, 0xaa, 0x2f, 0x4d, 0xab, 0x28, 0x40,
0x09, 0xae, 0x04, 0x1d, 0x05, 0x57, 0x99, 0xbe, 0x44, 0xba, 0xed, 0x3a, 0x8e, 0x14, 0xf8, 0xb8,
0x66, 0x12, 0x42, 0xd6, 0x0b, 0x74, 0x25, 0x7e, 0x9c, 0x84, 0x61, 0x10, 0x81, 0x7d, 0x82, 0xf1,
0xd3, 0x18, 0xef, 0xb3, 0xc4, 0x9d, 0xb2, 0x86, 0xe6, 0x39, 0xe1, 0x2e, 0x55, 0xa5, 0xb3, 0xeb,
0xd7, 0x1b, 0x67, 0xc7, 0xfb, 0xc7, 0x1f, 0x64, 0x0f, 0xdd, 0x24, 0x6b, 0x36, 0x55, 0xac, 0xb3,
0x14, 0x7f, 0x8d, 0x87, 0xb1, 0xe0, 0xfd, 0x5f, 0xfd, 0x76, 0x1c, 0xae, 0xa2, 0x41, 0xcf, 0x5c,
0x3f, 0x96, 0x6f, 0xa5, 0x8d, 0x64, 0x43, 0x07, 0x86, 0xfb, 0xa8, 0x19, 0x56, 0xd6, 0xda, 0x91,
0x49, 0x30, 0x4e, 0x82, 0x89, 0x20, 0xc7, 0x3d, 0xd7, 0xd3, 0x1f, 0x55, 0x47, 0x36, 0x91, 0x24,
0x26, 0x58, 0xe8, 0xb2, 0x5a, 0xb3, 0x23, 0xaa, 0x16, 0xf4, 0xc2, 0xaa, 0x7c, 0x1a, 0xf4, 0x40,
0x38, 0xaf, 0x96, 0xe3, 0xa0, 0xed, 0xc0, 0x73, 0x66, 0xd7, 0xf7, 0x8f, 0xf7, 0x2f, 0x94, 0x9d,
0xb3, 0xb3, 0x93, 0x33, 0x65, 0x26, 0x5b, 0x7d, 0x8a, 0x08, 0x1b, 0x73, 0x3b, 0x80, 0xaf, 0xd5,
0xf3, 0xd3, 0xfd, 0xdd, 0xdd, 0x73, 0x15, 0x38, 0x3b, 0x23, 0x02, 0xf2, 0x26, 0xe2, 0x72, 0xe2,
0x4a, 0xfd, 0x3b, 0xc7, 0x8d, 0x60, 0x21, 0x29, 0x67, 0x52, 0xdd, 0x65, 0xa9, 0x52, 0x77, 0xc1,
0x01, 0x9f, 0xe7, 0xf1, 0x2a, 0x85, 0xdc, 0xd7, 0xd4, 0x0f, 0x3b, 0x17, 0x78, 0xa9, 0xcd, 0x74,
0xf3, 0x79, 0x65, 0xa6, 0xa9, 0x63, 0x6f, 0x0c, 0x56, 0xa6, 0xe6, 0x27, 0x9e, 0xa7, 0x17, 0xf7,
0xbc, 0x7a, 0x9d, 0x40, 0x14, 0x31, 0x0f, 0x1c, 0x35, 0x4d, 0xa5, 0x23, 0xae, 0xa0, 0xe8, 0x98,
0x03, 0x71, 0x92, 0xde, 0x3e, 0x40, 0xec, 0x37, 0x45, 0xb6, 0x54, 0xee, 0x56, 0xb1, 0x9c, 0xcd,
0x7c, 0x94, 0xf8, 0xc7, 0x7c, 0xb0, 0x25, 0xfd, 0x33, 0x94, 0x1d, 0xa9, 0x54, 0x9a, 0x99, 0x99,
0x8c, 0x26, 0x76, 0xcf, 0x37, 0x05, 0x48, 0x55, 0x23, 0x0b, 0x86, 0xa1, 0x88, 0x9f, 0x99, 0x01,
0x9e, 0xe8, 0xb8, 0x51, 0x5f, 0x53, 0xb7, 0x7a, 0x68, 0x73, 0xc6, 0xa0, 0x88, 0x95, 0x61, 0x90,
0x44, 0x39, 0xc2, 0x41, 0x4f, 0x79, 0x9e, 0xd2, 0x06, 0x35, 0x1a, 0xc4, 0x42, 0x01, 0x31, 0x0a,
0xbd, 0xa8, 0x60, 0x84, 0xeb, 0x27, 0x80, 0x15, 0xc9, 0x9e, 0x3e, 0xb1, 0x3c, 0x6c, 0xb1, 0xed,
0xc6, 0x36, 0x8b, 0x1c, 0xd8, 0x29, 0xd6, 0x66, 0x5a, 0x3a, 0x21, 0xa6, 0x80, 0x7d, 0xfc, 0x38,
0x3e, 0x4d, 0xf6, 0x8d, 0x80, 0x6d, 0xcd, 0xf0, 0x29, 0xdc, 0xe0, 0xe4, 0xeb, 0x56, 0xa7, 0x14,
0x30, 0xc0, 0x8c, 0x53, 0x52, 0xeb, 0xbb, 0xc0, 0x6d, 0x9c, 0x08, 0x92, 0x62, 0x0f, 0x85, 0x1c,
0xb7, 0x88, 0x14, 0x91, 0x88, 0xaf, 0x5d, 0xd1, 0xd3, 0x54, 0x13, 0x4e, 0xf8, 0x1e, 0xf8, 0x1a,
0x74, 0x8c, 0x49, 0x64, 0xd1, 0x0d, 0x20, 0x71, 0xb5, 0xd3, 0x88, 0x3d, 0x70, 0x4a, 0xd1, 0x7c,
0x6c, 0xb4, 0xe8, 0x16, 0x00, 0x0b, 0x25, 0xed, 0x58, 0xa0, 0xb7, 0x81, 0xad, 0xa0, 0x87, 0x59,
0x2c, 0xf6, 0xd1, 0x00, 0x3d, 0xe9, 0xd0, 0xac, 0x32, 0x39, 0x41, 0x60, 0x08, 0xbe, 0x47, 0x0e,
0x21, 0xaa, 0x70, 0x9f, 0xb4, 0x38, 0x4a, 0xe7, 0xc0, 0x9a, 0x74, 0x4a, 0x0e, 0x78, 0x65, 0x45,
0xaf, 0x5c, 0x22, 0x1d, 0xa0, 0xa9, 0xe4, 0x7b, 0xab, 0x68, 0x1b, 0x11, 0xcf, 0x5b, 0x2a, 0xde,
0x6b, 0x60, 0x51, 0x66, 0xf4, 0x13, 0x94, 0x0b, 0x70, 0x2d, 0x67, 0x5a, 0xf8, 0x8a, 0x77, 0xdd,
0x52, 0x31, 0x54, 0x09, 0xbd, 0x81, 0xc1, 0x42, 0x60, 0x6d, 0x67, 0xab, 0xe7, 0x7a, 0x8e, 0xc6,
0x74, 0xa9, 0x50, 0x9c, 0x97, 0x77, 0x71, 0x0c, 0x10, 0x48, 0x6a, 0x08, 0x32, 0x78, 0x9f, 0x9a,
0x80, 0x38, 0xe9, 0xbe, 0x68, 0xf6, 0xd0, 0xab, 0xdc, 0x08, 0x87, 0xd0, 0x6b, 0xaa, 0xac, 0xaf,
0x48, 0x8c, 0x03, 0x3a, 0xea, 0x9b, 0x3b, 0xe9, 0xe6, 0xde, 0xc4, 0xcd, 0xdb, 0x09, 0x38, 0x55,
0x3e, 0xee, 0xee, 0x95, 0x95, 0xe2, 0x65, 0x88, 0x6a, 0x6e, 0x64, 0x3d, 0x2f, 0x5d, 0x2f, 0xfe,
0x81, 0xf5, 0x62, 0x3a, 0x8d, 0x94, 0x04, 0xf3, 0xf0, 0x56, 0x93, 0x05, 0x18, 0xef, 0xa6, 0xf6,
0xd2, 0xae, 0x47, 0x77, 0xdb, 0x34, 0xb8, 0xba, 0x69, 0x9c, 0x6e, 0xea, 0xfe, 0xc0, 0xa6, 0x6e,
0x75, 0xb9, 0x5d, 0x49, 0xaf, 0xea, 0x7a, 0x6e, 0xba, 0x9e, 0x3d, 0x71, 0x3d, 0x94, 0x94, 0xb8,
0x9a, 0x4d, 0x47, 0x90, 0xee, 0xf8, 0x26, 0xed, 0x81, 0x02, 0xca, 0x9e, 0x70, 0x94, 0xea, 0x2e,
0x76, 0xba, 0x4b, 0xf4, 0x03, 0x50, 0x47, 0xb4, 0x4f, 0x76, 0x41, 0xe7, 0xf1, 0xbd, 0x38, 0x05,
0xde, 0x71, 0x6a, 0x93, 0xbb, 0xca, 0x80, 0xd1, 0x21, 0x58, 0xf6, 0x96, 0xfa, 0x1a, 0x9c, 0x41,
0xea, 0x2a, 0xae, 0x67, 0x13, 0xe1, 0x2b, 0xc3, 0x11, 0xa5, 0x70, 0xf4, 0x7f, 0x00, 0x8e, 0x3e,
0xc1, 0x51, 0xba, 0xf8, 0xf3, 0xd8, 0x54, 0x80, 0x92, 0x8a, 0x1a, 0x6a, 0x9e, 0xb2, 0x65, 0x1f,
0x2e, 0x15, 0x5c, 0xff, 0x97, 0xf6, 0xd3, 0x69, 0xb7, 0x1e, 0xf7, 0x42, 0xb9, 0x15, 0x2f, 0x6f,
0xf5, 0x5e, 0xad, 0xaf, 0x8a, 0x57, 0x55, 0x7b, 0x89, 0x66, 0x72, 0xcd, 0x5c, 0x97, 0xd8, 0x15,
0x43, 0x2f, 0x35, 0x94, 0xf5, 0x31, 0xb4, 0xc2, 0x4b, 0x1c, 0xf8, 0x36, 0x09, 0xee, 0x92, 0x71,
0xc7, 0xa5, 0xfc, 0x00, 0xd3, 0x0e, 0x0d, 0x3b, 0x8b, 0x19, 0x28, 0x00, 0x62, 0x03, 0x94, 0x7b,
0x57, 0xf4, 0x48, 0x5e, 0x8b, 0xac, 0xf1, 0x6b, 0xf3, 0x1b, 0xdd, 0x4e, 0xbc, 0x96, 0x64, 0x56,
0x8d, 0x08, 0x3f, 0x50, 0x12, 0x5a, 0xda, 0x67, 0x49, 0x11, 0x98, 0xbe, 0xe9, 0xf9, 0x1c, 0xab,
0x2e, 0x52, 0xb3, 0x11, 0xa8, 0xcd, 0x68, 0x8a, 0x40, 0xdd, 0xe9, 0x21, 0xac, 0x20, 0x29, 0xef,
0xaa, 0xa0, 0x4e, 0x80, 0xd1, 0x37, 0x30, 0x17, 0x2d, 0x6f, 0xb4, 0x56, 0x40, 0x9b, 0x6f, 0x8a,
0x2b, 0xba, 0xe3, 0x57, 0x94, 0x66, 0x7c, 0x76, 0x20, 0x10, 0xc3, 0x7d, 0x0d, 0xd8, 0x44, 0x55,
0x2d, 0x0b, 0xfc, 0x9a, 0xf7, 0x4a, 0xaa, 0x7e, 0x37, 0x94, 0xcc, 0xde, 0x51, 0xfa, 0x09, 0x68,
0x36, 0xd0, 0x70, 0x5d, 0xf0, 0x44, 0xa5, 0xdb, 0x22, 0x46, 0xa4, 0x7c, 0x3a, 0x6b, 0x37, 0xb3,
0x91, 0xe4, 0x24, 0xf0, 0x77, 0x41, 0xa9, 0x39, 0xa0, 0x23, 0x01, 0x6a, 0xa6, 0xcc, 0x9a, 0xb3,
0x0a, 0x90, 0x23, 0x62, 0x36, 0xd8, 0x74, 0xb4, 0x90, 0x3c, 0xc6, 0x16, 0x51, 0x5d, 0x23, 0x34,
0xc4, 0xff, 0x22, 0xd0, 0x84, 0x62, 0x65, 0x02, 0xdc, 0x5a, 0x1d, 0x70, 0x24, 0x9f, 0x40, 0xab,
0xcc, 0x54, 0xc9, 0x40, 0xa9, 0x40, 0x83, 0xe0, 0x44, 0xe3, 0xc1, 0x11, 0x06, 0x5e, 0x6c, 0x0d,
0x47, 0xf4, 0x27, 0x8d, 0x48, 0xaf, 0x1c, 0x0d, 0xe2, 0x13, 0x97, 0x01, 0xeb, 0xe7, 0xbc, 0x07,
0xa6, 0xa3, 0x9d, 0xa0, 0xa5, 0xf2, 0x5c, 0xd7, 0x7c, 0x17, 0x60, 0x3b, 0xa3, 0xde, 0x63, 0x12,
0x05, 0xfe, 0x44, 0xa5, 0xa7, 0xa6, 0x21, 0x3e, 0x3c, 0x87, 0x98, 0x78, 0xa1, 0x1c, 0xf7, 0x1e,
0x65, 0x42, 0xbe, 0x89, 0x33, 0xd5, 0xba, 0x28, 0xb4, 0x96, 0x9e, 0xb2, 0xf2, 0x34, 0xdb, 0x42,
0x8a, 0xd4, 0x51, 0x03, 0x31, 0x95, 0xa4, 0x2f, 0xcc, 0xcb, 0x44, 0xf1, 0xa4, 0xe9, 0x7e, 0xbd,
0x9d, 0x82, 0x25, 0xd4, 0x51, 0x12, 0x07, 0x6b, 0x6e, 0xbf, 0xab, 0xc4, 0x91, 0x2d, 0x5d, 0x16,
0x2e, 0x9d, 0x98, 0xd4, 0xd6, 0x06, 0x0f, 0x29, 0x4d, 0xea, 0xcb, 0xb8, 0x22, 0xbe, 0xa7, 0x71,
0x85, 0xac, 0x81, 0xc2, 0xf6, 0x2c, 0x11, 0x41, 0x91, 0xc2, 0x97, 0x31, 0x99, 0x59, 0xb0, 0xf7,
0x0b, 0xd2, 0x78, 0xff, 0xdb, 0xb0, 0x56, 0x76, 0x49, 0x0a, 0x3f, 0x64, 0x76, 0x7d, 0xc3, 0xe6,
0x8a, 0xdc, 0x08, 0x4c, 0xda, 0xc4, 0x73, 0xe8, 0x42, 0x93, 0xad, 0x0b, 0xf6, 0x98, 0xa3, 0x60,
0x20, 0x5f, 0x11, 0x3d, 0xae, 0x50, 0x9e, 0xda, 0xe7, 0x78, 0xe1, 0x23, 0xd9, 0x6a, 0xe2, 0x34,
0x93, 0xd9, 0xdc, 0xb8, 0x8d, 0x15, 0x43, 0xd9, 0x96, 0x36, 0x0d, 0x08, 0x6a, 0x34, 0xa0, 0xd1,
0xf2, 0x51, 0x90, 0x59, 0x79, 0x04, 0xde, 0x79, 0xe6, 0x29, 0x01, 0x03, 0x93, 0xf3, 0x26, 0x1e,
0x44, 0x66, 0xba, 0xe7, 0xb4, 0x2b, 0x82, 0x46, 0x44, 0x9d, 0x59, 0xf0, 0xab, 0x60, 0xf8, 0x7a,
0xea, 0xd7, 0x8b, 0xb1, 0x7e, 0xbd, 0x18, 0xe7, 0xd7, 0x4f, 0xc4, 0x67, 0x69, 0x57, 0xc0, 0x26,
0x42, 0x98, 0xbe, 0x5a, 0xa2, 0xe7, 0xc6, 0x15, 0x6f, 0x03, 0xee, 0xb3, 0xa8, 0x38, 0x3a, 0x28,
0xec, 0x85, 0x74, 0x6e, 0xca, 0x8e, 0x4d, 0x16, 0x57, 0xb9, 0x0f, 0x5c, 0x47, 0xea, 0x1a, 0x50,
0xa0, 0xa6, 0xf6, 0x7e, 0xe5, 0x3f, 0x0c, 0xed, 0xeb, 0x7f, 0x1a, 0xdf, 0xe6, 0x74, 0xfd, 0xfd,
0xdf, 0x4c, 0x83, 0x3f, 0x70, 0x1b, 0x86, 0x7e, 0x6d, 0x7d, 0x03, 0x27, 0x31, 0x06, 0x51, 0x69,
0xf7, 0x40, 0x38, 0x80, 0x57, 0x7c, 0x18, 0x00, 0x82, 0xb6, 0x58, 0x0c, 0x72, 0x46, 0x7f, 0xb2,
0xe1, 0x57, 0x41, 0x28, 0xd5, 0x15, 0x45, 0x3e, 0xf7, 0x44, 0xbf, 0xfc, 0xec, 0xe5, 0x2f, 0xb7,
0x71, 0xe9, 0x11, 0x94, 0x72, 0xf6, 0x62, 0x17, 0xc3, 0x8b, 0xb6, 0x30, 0x2c, 0x9e, 0xe3, 0x62,
0xe2, 0x03, 0xad, 0x97, 0x5a, 0xfe, 0xad, 0x92, 0x58, 0x72, 0xff, 0x80, 0x53, 0x85, 0x7e, 0xb7,
0x80, 0x38, 0x2c, 0x3f, 0xf3, 0xe2, 0xa5, 0xeb, 0x76, 0xf2, 0x67, 0xd7, 0x0e, 0xc6, 0x43, 0x17,
0x69, 0xe0, 0x20, 0x04, 0x69, 0xf8, 0x66, 0xa2, 0x14, 0x4c, 0x3c, 0x14, 0x82, 0x7e, 0xcd, 0x12,
0xc9, 0x78, 0x69, 0xd2, 0x2c, 0xcf, 0xc5, 0x59, 0xbc, 0x32, 0x0b, 0xa3, 0x87, 0xb1, 0x16, 0xa0,
0x06, 0x54, 0xb1, 0x8c, 0xa4, 0x03, 0xae, 0xb0, 0x03, 0x4a, 0x09, 0x2d, 0xfc, 0xa0, 0xa3, 0x00,
0xff, 0x63, 0x68, 0x47, 0x8c, 0x5c, 0xb6, 0xf5, 0x2b, 0xe0, 0xfe, 0xc2, 0x7b, 0x17, 0x93, 0x74,
0xff, 0x5a, 0x2d, 0xc6, 0x57, 0x70, 0x6d, 0xbc, 0x39, 0xdc, 0xc2, 0x78, 0xc6, 0x31, 0x68, 0x3a,
0x4d, 0x2d, 0x15, 0x09, 0x01, 0xf7, 0x16, 0x66, 0x42, 0x75, 0xb6, 0x0c, 0x20, 0x4a, 0xc8, 0x7d,
0x80, 0x7c, 0x9c, 0xaf, 0x8c, 0xb3, 0x3c, 0x38, 0xd1, 0x73, 0xaa, 0x2f, 0x47, 0x20, 0xdf, 0x81,
0x8b, 0xfd, 0x97, 0x85, 0x9c, 0x19, 0x78, 0xe3, 0x2f, 0xa3, 0xfc, 0x04, 0x2e, 0x12, 0x87, 0x6c,
0xba, 0xd1, 0x93, 0x9c, 0x4a, 0x8d, 0xf9, 0x97, 0x3d, 0x8c, 0x43, 0x87, 0x98, 0xa6, 0xce, 0x91,
0x25, 0xe7, 0xc7, 0xb0, 0xe4, 0x98, 0xc3, 0x6e, 0x07, 0x03, 0x92, 0x86, 0x2f, 0x9e, 0x36, 0xb7,
0x8d, 0xff, 0xd8, 0x43, 0x0b, 0x2b, 0x98, 0x16, 0xa7, 0x48, 0xa1, 0x6d, 0x50, 0x2e, 0x06, 0xd5,
0x1b, 0xe8, 0x74, 0x8a, 0x08, 0xbe, 0xcf, 0xba, 0x2c, 0x11, 0x25, 0x5c, 0x7d, 0xfe, 0x37, 0xa1,
0xe7, 0x8c, 0xcc, 0x56, 0xf3, 0x08, 0x60, 0xfc, 0x93, 0xf9, 0x21, 0x13, 0x43, 0x21, 0xa8, 0xd1,
0x10, 0x0e, 0x21, 0x21, 0xa3, 0xa0, 0x57, 0x40, 0xe1, 0x54, 0x11, 0xa0, 0xaf, 0x83, 0x02, 0x2c,
0xf1, 0x3c, 0x90, 0xbf, 0x94, 0xd2, 0x10, 0xf0, 0x10, 0xe0, 0x43, 0xa8, 0x05, 0xf3, 0xd2, 0xa1,
0xf8, 0xf7, 0xb0, 0x0d, 0xf7, 0xb8, 0xf8, 0xb3, 0x51, 0x32, 0xaf, 0xf4, 0xf0, 0x2a, 0x94, 0x6c,
0x63, 0xca, 0xe6, 0x80, 0x15, 0x33, 0x12, 0x0a, 0x1a, 0x67, 0xef, 0x56, 0xa2, 0x41, 0x32, 0x55,
0x62, 0x47, 0x81, 0xe7, 0x5d, 0x04, 0x21, 0x3a, 0x00, 0x79, 0x57, 0xf6, 0x90, 0xce, 0x2e, 0x46,
0xcd, 0x97, 0x03, 0x3d, 0xa5, 0x05, 0xd0, 0x61, 0xff, 0x81, 0x15, 0x70, 0x18, 0xf8, 0x77, 0x16,
0x37, 0x00, 0x73, 0xd0, 0xfc, 0x19, 0xbd, 0x44, 0xd0, 0x1b, 0x79, 0xc3, 0x0d, 0x34, 0xb0, 0x55,
0xf0, 0x5f, 0xed, 0x0c, 0x4f, 0x56, 0x05, 0x4f, 0xe8, 0xda, 0x4e, 0xb0, 0xe3, 0xb2, 0x0e, 0xcc,
0x0a, 0x5a, 0x1e, 0xf2, 0x07, 0x45, 0x0f, 0xb2, 0x66, 0x11, 0x84, 0x56, 0x9c, 0xb7, 0x6a, 0x3e,
0x68, 0xa3, 0x08, 0xa4, 0x62, 0x41, 0xbb, 0xff, 0x69, 0x75, 0x29, 0x67, 0xb1, 0x89, 0x6e, 0x4c,
0xa0, 0x1b, 0x36, 0x0e, 0x3d, 0x0e, 0x1c, 0xe9, 0x7e, 0xa7, 0x45, 0x32, 0x2f, 0xb1, 0xf3, 0x38,
0xc5, 0xcc, 0x26, 0xe8, 0xde, 0x2d, 0xa0, 0x09, 0x0b, 0xe3, 0x3f, 0x9f, 0xab, 0x7f, 0x16, 0x09,
0xd6, 0x4c, 0xeb, 0x79, 0x5a, 0x68, 0x73, 0xdc, 0xbd, 0x66, 0x14, 0x06, 0x19, 0x23, 0xef, 0x28,
0x3f, 0x56, 0xa0, 0x80, 0xfd, 0x39, 0x28, 0xe8, 0x4f, 0x35, 0x35, 0x1e, 0xe0, 0xef, 0x97, 0x35,
0xd6, 0x5f, 0x8f, 0x4c, 0xcd, 0xec, 0x60, 0xff, 0xaf, 0x9d, 0xfe, 0xef, 0x68, 0x27, 0x5d, 0x9e,
0xad, 0x9e, 0x96, 0x2f, 0x1f, 0x23, 0xc8, 0xa3, 0xde, 0x81, 0x11, 0x74, 0x3a, 0x31, 0x17, 0xd7,
0x18, 0x90, 0x00, 0x13, 0x30, 0x6f, 0xd8, 0xa3, 0x88, 0x04, 0x2a, 0x83, 0xc0, 0xef, 0x07, 0x49,
0xcc, 0x83, 0x44, 0x54, 0x4f, 0xa3, 0x15, 0x7a, 0x64, 0x4d, 0xf1, 0x50, 0xff, 0x14, 0x0d, 0xeb,
0x0a, 0xea, 0x00, 0xb7, 0xdc, 0x78, 0x03, 0xa3, 0xe2, 0x6a, 0xc3, 0xba, 0x82, 0x3a, 0xc1, 0x26,
0x23, 0xf3, 0x8f, 0xc4, 0x4d, 0x45, 0x67, 0x07, 0x9a, 0x54, 0xd8, 0xa9, 0xd7, 0x36, 0x92, 0x6c,
0x5f, 0x2d, 0x17, 0x6b, 0x50, 0x6e, 0x4c, 0x66, 0xde, 0xc5, 0xa4, 0xcc, 0xbb, 0xa0, 0x00, 0x22,
0xa5, 0xce, 0x47, 0x42, 0xac, 0x64, 0x61, 0x56, 0x9c, 0x76, 0x62, 0xc3, 0x6a, 0xcb, 0x8c, 0x45,
0x19, 0xcf, 0xb4, 0x54, 0xe0, 0x94, 0x89, 0x9e, 0x56, 0x1d, 0x01, 0x8b, 0x94, 0x3b, 0x29, 0xaf,
0x24, 0x04, 0x07, 0xc6, 0x47, 0x38, 0x61, 0x13, 0x84, 0xe0, 0x47, 0xa6, 0x67, 0x45, 0x0c, 0x25,
0x74, 0xf4, 0xd3, 0x82, 0x14, 0x8a, 0xea, 0xc1, 0x8d, 0x99, 0x47, 0x0b, 0xa0, 0x8c, 0x01, 0x90,
0x21, 0x2a, 0x96, 0x7d, 0x60, 0xcc, 0xa4, 0x14, 0xcd, 0x32, 0x0c, 0x03, 0xaf, 0x07, 0xf8, 0xe7,
0x88, 0x89, 0x31, 0x81, 0x8f, 0xbc, 0x2f, 0x0b, 0x7f, 0x68, 0xbe, 0x95, 0xb6, 0xc0, 0x36, 0x18,
0x8b, 0x62, 0x16, 0x0c, 0x1a, 0x5f, 0xec, 0x30, 0x9e, 0x04, 0x2f, 0x14, 0x3f, 0xcc, 0x94, 0xf3,
0x02, 0x23, 0x32, 0x32, 0x0d, 0xb2, 0x5a, 0x32, 0xcd, 0x97, 0xf6, 0x11, 0x7f, 0x10, 0xff, 0xa9,
0x97, 0x87, 0xe8, 0x2f, 0x1b, 0x82, 0x75, 0x91, 0xcd, 0xb0, 0x89, 0x57, 0x98, 0x08, 0xd1, 0x58,
0xe2, 0x7f, 0x59, 0xc5, 0x63, 0xc4, 0x41, 0x24, 0xb4, 0x7a, 0x73, 0x51, 0x7c, 0x82, 0x09, 0x36,
0x5c, 0x14, 0x93, 0xda, 0x98, 0x82, 0x44, 0x21, 0x05, 0xae, 0xa1, 0xcd, 0x3c, 0xbe, 0x05, 0x82,
0x0b, 0x58, 0x05, 0x68, 0x85, 0x8d, 0x94, 0x90, 0xa4, 0x71, 0x23, 0xdd, 0xd8, 0x08, 0x22, 0x3c,
0x2b, 0x1d, 0x99, 0x6e, 0x1d, 0x4d, 0xce, 0x45, 0x56, 0x04, 0x80, 0xaf, 0x97, 0x6a, 0x69, 0x02,
0x80, 0x50, 0x5e, 0x23, 0xa4, 0x49, 0x73, 0x15, 0x0c, 0x96, 0x35, 0x25, 0x80, 0x9f, 0xb9, 0x39,
0x49, 0x13, 0x27, 0x4d, 0x4e, 0x5a, 0x96, 0xa5, 0x81, 0xbf, 0xf3, 0x95, 0x7d, 0xd3, 0xb3, 0x23,
0x55, 0x8f, 0xfe, 0x03, 0x96, 0xb0, 0x34, 0x92, 0x52, 0x0c, 0x05, 0x98, 0x51, 0xc1, 0x08, 0xb8,
0x25, 0x0b, 0x85, 0x54, 0x4a, 0xcb, 0x16, 0xf9, 0x88, 0xf9, 0x29, 0xd6, 0xa0, 0xcc, 0xc9, 0x60,
0xd8, 0x43, 0xc8, 0xf4, 0x6e, 0xad, 0xb8, 0x09, 0x43, 0x54, 0xd2, 0xf3, 0x16, 0xba, 0xa4, 0x66,
0x6d, 0x80, 0xdb, 0xef, 0x4a, 0x01, 0x5f, 0xae, 0xa7, 0x42, 0xd5, 0xb1, 0xe6, 0xae, 0x6b, 0x23,
0x35, 0x22, 0x3e, 0x81, 0xa5, 0xaf, 0x99, 0xee, 0xfa, 0x48, 0x8a, 0x07, 0x2f, 0x64, 0x30, 0x5e,
0xe4, 0x97, 0xef, 0x29, 0x9e, 0x16, 0x55, 0x0e, 0x0d, 0x95, 0x42, 0x0c, 0x8e, 0x92, 0x54, 0x27,
0x70, 0x03, 0x03, 0xe8, 0x70, 0xc2, 0x34, 0x54, 0xa9, 0x11, 0x88, 0x31, 0x18, 0xd0, 0xa7, 0x51,
0x10, 0xb2, 0x2e, 0x55, 0xd1, 0x61, 0x23, 0xf9, 0x1e, 0xb8, 0xa4, 0x4c, 0xde, 0xc3, 0xf3, 0xb3,
0xc6, 0xb3, 0x34, 0x2e, 0xfe, 0x62, 0x35, 0xa1, 0x5e, 0x31, 0xb2, 0x7f, 0x8a, 0x44, 0x2f, 0xd1,
0x66, 0xc4, 0x82, 0x9e, 0x94, 0x79, 0x4e, 0x69, 0x9d, 0xa5, 0xb9, 0xc9, 0x38, 0x69, 0x07, 0xe8,
0x07, 0x14, 0xa1, 0x3b, 0x9f, 0x72, 0x49, 0x14, 0x20, 0x61, 0x45, 0xf6, 0x4f, 0xcd, 0x9e, 0x54,
0x7d, 0x34, 0xf3, 0x8d, 0x6e, 0xc4, 0xe4, 0x23, 0x60, 0x29, 0x3b, 0x66, 0xec, 0x2a, 0x01, 0xd4,
0xfa, 0x22, 0xfe, 0x94, 0xd4, 0x1c, 0xcb, 0xac, 0x28, 0x04, 0xaa, 0x9f, 0xd3, 0xce, 0x9f, 0x40,
0xe6, 0x7c, 0xf4, 0x7b, 0x85, 0x95, 0xcc, 0x64, 0x14, 0x4b, 0xac, 0x6e, 0x8f, 0xe1, 0x52, 0x7f,
0x0c, 0x1f, 0xb4, 0xea, 0x7c, 0x30, 0xe2, 0x2f, 0xc1, 0x21, 0x9e, 0xd1, 0x3e, 0x98, 0x52, 0x1e,
0x56, 0xa6, 0xcb, 0xcf, 0x9a, 0x9c, 0x53, 0x2b, 0x77, 0xa6, 0xd8, 0xa9, 0xe4, 0x25, 0xc9, 0xb8,
0x59, 0xae, 0xcf, 0x13, 0x20, 0x32, 0x99, 0xae, 0xb9, 0x1e, 0xa9, 0xd4, 0xf4, 0xe0, 0xf7, 0x82,
0xef, 0x1d, 0x37, 0xb2, 0x48, 0x27, 0xa5, 0xa5, 0x3d, 0xd9, 0xd0, 0x71, 0x05, 0x3e, 0x49, 0x91,
0xbf, 0x03, 0xe4, 0x06, 0x21, 0x26, 0xee, 0x84, 0xa4, 0x2e, 0x0a, 0x9a, 0xd2, 0xc8, 0x30, 0x95,
0xe3, 0x75, 0x35, 0x48, 0x46, 0x66, 0x4d, 0x0f, 0x62, 0x1e, 0x61, 0x36, 0xaf, 0x13, 0xcb, 0xd4,
0xa2, 0x18, 0x9b, 0xa0, 0x15, 0x56, 0x96, 0x67, 0xfd, 0x29, 0xc5, 0x19, 0x68, 0xb9, 0xde, 0x14,
0x7a, 0xb9, 0x82, 0x70, 0x37, 0x88, 0xfa, 0xdb, 0x4c, 0xb0, 0x82, 0xc8, 0x5a, 0x56, 0xbe, 0x21,
0x28, 0x8d, 0x98, 0x35, 0xc6, 0x91, 0x9d, 0xa6, 0x07, 0xaa, 0xb8, 0x3c, 0xbd, 0x94, 0xb8, 0xc4,
0x24, 0x89, 0x3a, 0x82, 0xbe, 0x12, 0x46, 0xd0, 0xe8, 0x18, 0x41, 0x07, 0x59, 0xbd, 0xff, 0xb2,
0x59, 0x90, 0x9f, 0x4e, 0x2f, 0x27, 0x51, 0x8a, 0xa3, 0x89, 0xfa, 0xd1, 0x46, 0x8f, 0xb1, 0xbd,
0x73, 0xb8, 0x73, 0xb1, 0x33, 0xf9, 0x24, 0x60, 0xe8, 0xa7, 0x42, 0x48, 0x54, 0x42, 0x1b, 0xa5,
0xcf, 0x51, 0xc8, 0x68, 0xc7, 0xf4, 0xbe, 0x39, 0x25, 0xd9, 0x55, 0x53, 0xa2, 0xe4, 0x0c, 0x60,
0x52, 0xc6, 0xf6, 0x38, 0x8b, 0x8e, 0x98, 0xeb, 0x9f, 0x32, 0x9f, 0x7b, 0x3f, 0x96, 0xe7, 0xf9,
0x4b, 0xe4, 0xdb, 0x1c, 0xf7, 0x3e, 0xcb, 0x6c, 0x95, 0x3e, 0x20, 0x90, 0xdf, 0x0f, 0xcc, 0xae,
0x6b, 0xa8, 0xf4, 0x29, 0xd5, 0xd6, 0xc1, 0xca, 0x40, 0x05, 0x73, 0x6a, 0x40, 0x16, 0x26, 0xf3,
0xe9, 0x79, 0xa9, 0x21, 0xe8, 0x44, 0x58, 0x67, 0x9d, 0x42, 0xa0, 0x88, 0x8d, 0x92, 0xca, 0xab,
0x8a, 0xb4, 0x72, 0xb9, 0xb3, 0xba, 0x21, 0x47, 0x21, 0xfb, 0x20, 0x1b, 0x60, 0x5d, 0xe6, 0x28,
0x1b, 0xfd, 0x5c, 0x6e, 0x73, 0x52, 0xfc, 0x5a, 0xc3, 0x0c, 0xd8, 0xd4, 0xcc, 0x08, 0x26, 0x52,
0x41, 0x54, 0x17, 0x51, 0x7b, 0x2e, 0x2d, 0x07, 0x9a, 0xe6, 0xc8, 0xb7, 0x2a, 0x91, 0x35, 0x92,
0xe0, 0x69, 0x4a, 0x2e, 0x37, 0xbc, 0xab, 0xe7, 0xc5, 0xec, 0x54, 0x56, 0xe0, 0x68, 0x95, 0xeb,
0x1b, 0xf5, 0x4a, 0xe5, 0xb7, 0x7a, 0x96, 0xd7, 0x08, 0x63, 0x65, 0x42, 0x7a, 0xf4, 0x3e, 0x89,
0x8d, 0x55, 0x85, 0x7b, 0x31, 0xc7, 0x72, 0x3e, 0x6d, 0xe2, 0x94, 0x11, 0xac, 0x35, 0x5a, 0x96,
0x35, 0xa6, 0x98, 0xad, 0xb2, 0xe4, 0x53, 0xa9, 0x92, 0xfa, 0xeb, 0x37, 0xe0, 0x0b, 0x0b, 0xbf,
0x83, 0x6e, 0x91, 0x91, 0x5d, 0x9f, 0x89, 0x38, 0x9c, 0x58, 0xb1, 0x08, 0x96, 0xa4, 0x2e, 0x8c,
0x30, 0x89, 0x7b, 0xa4, 0x4e, 0xfd, 0x31, 0x2e, 0x90, 0xac, 0x8f, 0x40, 0x0f, 0x29, 0x1d, 0x48,
0x8b, 0xae, 0x28, 0xa5, 0x69, 0x09, 0xde, 0xd1, 0x0c, 0xa1, 0x45, 0x45, 0x89, 0x55, 0xb7, 0xac,
0xeb, 0x22, 0x48, 0x0e, 0xcb, 0xd1, 0xf0, 0x17, 0x91, 0xc1, 0x69, 0xad, 0x1e, 0x9f, 0x2f, 0xef,
0x92, 0x89, 0xdc, 0x93, 0xf3, 0xe9, 0x32, 0xb7, 0x84, 0x04, 0x59, 0x01, 0x52, 0x65, 0xaa, 0x3a,
0x06, 0x68, 0xcc, 0x78, 0x3e, 0x18, 0x5f, 0x25, 0x94, 0xd5, 0x07, 0xf1, 0xdf, 0x8d, 0x00, 0xfe,
0xfb, 0x25, 0xf5, 0x54, 0x85, 0x43, 0xf1, 0x18, 0xc9, 0xa4, 0x12, 0x09, 0xf5, 0x22, 0x94, 0x1d,
0x92, 0x7d, 0x99, 0x19, 0x2b, 0x9d, 0x55, 0xfd, 0xa9, 0x5a, 0x44, 0x22, 0x01, 0x53, 0x41, 0xea,
0xb9, 0x58, 0xf7, 0xe5, 0x4f, 0x4d, 0x09, 0xaf, 0x2a, 0xd5, 0x0c, 0xb2, 0x5f, 0xa4, 0x88, 0xfd,
0x6a, 0xaa, 0x3b, 0x5f, 0x72, 0x55, 0x69, 0x03, 0x2c, 0x77, 0xab, 0x95, 0xe4, 0x37, 0xf4, 0x52,
0xe6, 0xbb, 0xd6, 0x49, 0x09, 0x70, 0xe8, 0xbb, 0x65, 0xf7, 0x4c, 0x7e, 0x23, 0x52, 0x1f, 0x61,
0xd7, 0x12, 0xe0, 0x30, 0xd8, 0xfe, 0x07, 0x3e, 0xd6, 0xc7, 0x95, 0x52, 0xe2, 0x71, 0xf9, 0x25,
0xec, 0x85, 0x93, 0x92, 0xef, 0xa5, 0x8c, 0xbb, 0xcc, 0xa2, 0x03, 0xbd, 0x72, 0x3d, 0xf8, 0x2c,
0x0f, 0x4d, 0x65, 0x4b, 0xb2, 0xd4, 0x4c, 0x35, 0xe9, 0xdb, 0x2b, 0x03, 0x4f, 0x94, 0xdb, 0x80,
0x56, 0x6a, 0x9a, 0xa3, 0xa9, 0xad, 0x95, 0x6c, 0x43, 0x68, 0xa7, 0x38, 0x9a, 0x16, 0xc8, 0xfa,
0x51, 0x50, 0x0a, 0xbc, 0x32, 0x8b, 0x49, 0x5b, 0x3e, 0x3b, 0x8e, 0x25, 0xef, 0x3f, 0x8d, 0x35,
0x25, 0x22, 0xb1, 0x56, 0x97, 0x5e, 0x91, 0x19, 0xb3, 0x80, 0x9e, 0x67, 0xa1, 0xd1, 0x86, 0x39,
0x09, 0x2c, 0xd9, 0x40, 0x2e, 0xa1, 0x08, 0x7f, 0x29, 0xeb, 0x5f, 0xbd, 0x01, 0x45, 0x6c, 0xc0,
0xcb, 0x62, 0x03, 0xb0, 0x6f, 0x35, 0x38, 0xe0, 0x21, 0x37, 0x81, 0x9a, 0x2f, 0x0b, 0x6a, 0xad,
0x2e, 0xa5, 0xe8, 0x6c, 0xf5, 0x28, 0x49, 0x29, 0xcf, 0x33, 0xba, 0xed, 0xcb, 0x05, 0x50, 0xbf,
0x4f, 0xb5, 0x8f, 0xce, 0xcb, 0x74, 0xf7, 0xef, 0xb5, 0x09, 0xd2, 0xca, 0x78, 0xc2, 0x94, 0x55,
0x20, 0xea, 0x3d, 0x28, 0x46, 0xb8, 0x78, 0xb2, 0xc0, 0x57, 0xf3, 0xea, 0x21, 0xa3, 0xd4, 0xac,
0x39, 0xa7, 0x8f, 0x66, 0x53, 0x5f, 0x63, 0x62, 0x01, 0x39, 0x89, 0x73, 0xc4, 0x71, 0x5d, 0x4b,
0x96, 0x4b, 0x22, 0xc6, 0x48, 0xaf, 0xc3, 0xb2, 0xf4, 0xae, 0x08, 0x2f, 0xcd, 0x1b, 0x23, 0x95,
0xf4, 0x4c, 0x1a, 0xd9, 0x54, 0xa7, 0x58, 0x2e, 0x7d, 0x49, 0x1d, 0x00, 0xaf, 0x6c, 0xfa, 0xa7,
0xcc, 0x9e, 0xde, 0xdc, 0xdc, 0xcf, 0x8c, 0x11, 0x81, 0xe7, 0x3c, 0x8e, 0xe9, 0x54, 0x88, 0x82,
0x23, 0xf0, 0x48, 0x34, 0x15, 0x58, 0xce, 0xec, 0xc3, 0x53, 0xca, 0x91, 0x54, 0x57, 0xcc, 0xc5,
0x45, 0x8f, 0xf7, 0xd3, 0x4e, 0x81, 0x8f, 0xd4, 0x1b, 0x50, 0xef, 0xdf, 0x88, 0x32, 0xe7, 0x94,
0x5c, 0x83, 0x53, 0x58, 0x2d, 0xc5, 0xc4, 0xef, 0x12, 0x47, 0xd7, 0xbf, 0x8c, 0xf9, 0x79, 0xd0,
0x11, 0x17, 0xac, 0x0d, 0xd8, 0x6a, 0xea, 0xe3, 0x86, 0x40, 0x1f, 0xc5, 0x19, 0x16, 0xb2, 0x7d,
0xf7, 0xdc, 0x6e, 0xcf, 0xc3, 0x18, 0xec, 0x86, 0x8d, 0x9f, 0xde, 0x1d, 0x02, 0x09, 0xb3, 0xb9,
0xd0, 0x7b, 0x0e, 0x2c, 0x7e, 0x1a, 0xb9, 0xbe, 0x38, 0xa2, 0x62, 0x31, 0xc9, 0x92, 0x40, 0xb2,
0xa0, 0xdf, 0x67, 0xbe, 0x13, 0x63, 0x84, 0x63, 0x4b, 0x3e, 0x6b, 0x4f, 0xe8, 0x08, 0xc2, 0x65,
0x8b, 0x65, 0xad, 0x6f, 0x1b, 0xae, 0xf9, 0x01, 0x1f, 0xae, 0x3c, 0x0d, 0xf0, 0xd3, 0x70, 0x75,
0x4b, 0x44, 0x5e, 0xe3, 0x1c, 0xab, 0x6e, 0x99, 0x8d, 0xaf, 0x72, 0x12, 0xb4, 0x60, 0xb5, 0x20,
0x08, 0xca, 0x4a, 0xfc, 0x00, 0xdd, 0xd2, 0xbc, 0xe0, 0x10, 0xc3, 0x23, 0x27, 0x3e, 0xfe, 0xa3,
0x3f, 0x33, 0xad, 0xe7, 0x97, 0x77, 0x07, 0x80, 0x61, 0xdb, 0x76, 0x00, 0x5c, 0x93, 0x17, 0x1a,
0x4e, 0x00, 0x67, 0xc3, 0x13, 0x8d, 0xde, 0x08, 0x48, 0xb2, 0x75, 0x22, 0x58, 0xf5, 0x02, 0xc6,
0x14, 0x53, 0x84, 0x62, 0x60, 0x1b, 0x4d, 0x95, 0x5e, 0xbe, 0x3a, 0x5f, 0x9b, 0x39, 0x9e, 0xa5,
0x9b, 0xba, 0x5c, 0x20, 0x35, 0x08, 0xab, 0x3a, 0xf8, 0xe7, 0xcc, 0xd2, 0x29, 0x5f, 0x5d, 0x90,
0x54, 0xb5, 0xe4, 0x77, 0x02, 0x25, 0x61, 0x38, 0xff, 0xfb, 0x59, 0x36, 0xca, 0xaa, 0x57, 0x91,
0x4c, 0x15, 0x4f, 0x64, 0x0a, 0x18, 0x63, 0x22, 0x44, 0xf5, 0x8b, 0x0a, 0xf3, 0x7e, 0xcf, 0x3d,
0x75, 0xa5, 0x58, 0x0f, 0x6a, 0x96, 0x42, 0x50, 0x37, 0x95, 0xb0, 0x7b, 0xd3, 0x0b, 0xda, 0xda,
0x57, 0xf1, 0x6d, 0xfe, 0x09, 0x6d, 0xe4, 0x15, 0xc5, 0x47, 0x0a, 0x70, 0xbd, 0xb8, 0xe9, 0x23,
0xa6, 0x53, 0x7a, 0xd9, 0x03, 0xfd, 0x19, 0x3d, 0x78, 0xc2, 0x91, 0x14, 0x66, 0x14, 0xa6, 0xc2,
0x64, 0xa2, 0xc4, 0x45, 0x5a, 0x01, 0x5b, 0x41, 0x47, 0x4e, 0x5a, 0x72, 0xe3, 0x26, 0x22, 0x47,
0xe2, 0xb2, 0xcc, 0x5b, 0x95, 0x55, 0x50, 0x4b, 0xd1, 0xa7, 0x39, 0x5d, 0x5a, 0x0e, 0x88, 0x92,
0x78, 0x29, 0x59, 0x90, 0x9a, 0x77, 0xc0, 0xf0, 0xc0, 0xdf, 0x80, 0xb9, 0x7f, 0xf4, 0x65, 0x02,
0xbd, 0xc6, 0xb5, 0xf8, 0xe5, 0xab, 0x16, 0xeb, 0xd9, 0x26, 0x23, 0x17, 0x04, 0x18, 0x99, 0xae,
0x9a, 0x2c, 0xf0, 0x2a, 0x25, 0x31, 0xfc, 0xcd, 0xc0, 0x19, 0x52, 0x54, 0x31, 0x0f, 0x9b, 0x07,
0xd6, 0xd3, 0x33, 0x7e, 0xae, 0xea, 0x3b, 0xc1, 0x80, 0x82, 0xc8, 0x38, 0xd2, 0xe8, 0x81, 0x52,
0x03, 0xd1, 0x0e, 0xfc, 0x64, 0x73, 0xcd, 0xfc, 0xfa, 0xfe, 0xd7, 0x6f, 0x73, 0x60, 0x0b, 0x59,
0xf0, 0xa3, 0x5b, 0xf0, 0xf0, 0xeb, 0xb7, 0xbf, 0xeb, 0x66, 0xd7, 0x1d, 0xcb, 0x03, 0x01, 0x10,
0xc3, 0x22, 0x2a, 0x94, 0x3c, 0x27, 0xcc, 0x84, 0x14, 0xae, 0x13, 0x7d, 0x55, 0x64, 0x55, 0xac,
0xb3, 0x4c, 0x8d, 0x61, 0x50, 0x0a, 0x1d, 0x48, 0xfc, 0xc5, 0x7f, 0x70, 0x0c, 0x7f, 0x49, 0x80,
0xa2, 0xa6, 0xad, 0x7c, 0x4e, 0xa3, 0xca, 0x7f, 0x67, 0x41, 0x95, 0x6a, 0xda, 0x2a, 0x15, 0x1c,
0xab, 0xd8, 0x90, 0x1a, 0x92, 0x7c, 0x8c, 0x82, 0x5e, 0x33, 0xd3, 0x4f, 0x6f, 0xd3, 0x4f, 0x70,
0xa9, 0xe4, 0x16, 0x2d, 0xe7, 0x78, 0xc5, 0x34, 0x6d, 0xc7, 0xbf, 0x45, 0x25, 0x16, 0x24, 0x4e,
0xc7, 0x03, 0x5d, 0x8f, 0xe2, 0xc9, 0x64, 0xb7, 0xec, 0xc1, 0xf4, 0xdc, 0x76, 0x8c, 0x35, 0xa1,
0x66, 0xcb, 0x78, 0x63, 0xbc, 0xcb, 0xaa, 0x43, 0xb1, 0x22, 0x1c, 0xd8, 0xde, 0x4a, 0x44, 0xa7,
0xb1, 0xbc, 0x5e, 0x5f, 0x9a, 0xbe, 0xee, 0x95, 0x8f, 0xab, 0x13, 0x3d, 0x49, 0x44, 0x47, 0xc5,
0x4f, 0xdb, 0x62, 0x3e, 0xfa, 0xca, 0xe4, 0xe1, 0xa6, 0xdb, 0xe4, 0xc5, 0xaa, 0x03, 0xde, 0xc6,
0x13, 0x0f, 0xa5, 0x0b, 0x6c, 0x33, 0x0f, 0xbc, 0xc2, 0x70, 0x48, 0x77, 0x4a, 0xee, 0x33, 0x39,
0xf4, 0x2d, 0x6d, 0x49, 0x5d, 0x96, 0x23, 0xa9, 0xe5, 0x1a, 0x57, 0xfc, 0xea, 0x85, 0x7a, 0x0d,
0x16, 0x0f, 0x7d, 0x9b, 0x3e, 0x21, 0xca, 0x97, 0x41, 0x3c, 0x57, 0xbf, 0x7e, 0xa1, 0xa1, 0xba,
0x5e, 0x1c, 0x16, 0x73, 0x67, 0x4a, 0x66, 0xf2, 0x97, 0x98, 0x6c, 0x5d, 0xa1, 0x60, 0x81, 0xeb,
0x58, 0x92, 0x58, 0xeb, 0xd2, 0xe9, 0xcf, 0x1a, 0x91, 0x4e, 0xb5, 0x26, 0xc9, 0x06, 0xb5, 0xc6,
0xec, 0xdf, 0x7f, 0x90, 0x41, 0x87, 0xac, 0xb6, 0x19, 0x0d, 0xa3, 0xda, 0xc0, 0xd4, 0xad, 0x5b,
0xcf, 0xbf, 0xa5, 0x2c, 0x7d, 0x02, 0x9d, 0x7d, 0xcc, 0xb8, 0xd6, 0x8e, 0xe4, 0x78, 0xf9, 0x41,
0x65, 0xf9, 0xc3, 0xf2, 0xf5, 0x54, 0x78, 0x51, 0x59, 0x2f, 0xad, 0x2b, 0xff, 0x76, 0xa9, 0x8e,
0x0b, 0xd7, 0xab, 0x56, 0x76, 0x8d, 0x07, 0x48, 0x8e, 0x5e, 0xff, 0x6f, 0x98, 0x1d, 0x58, 0x91,
0xae, 0x4f, 0x00, 0x00
};

View File

@@ -150,19 +150,12 @@ IPAddress FSWebServer::startWiFi(uint32_t timeout, const char *apSSID, const cha
const char *_ssid;
const char *_pass;
#if defined(ESP8266)
struct station_config conf;
wifi_station_get_config_default(&conf);
_ssid = reinterpret_cast<const char *>(conf.ssid);
_pass = reinterpret_cast<const char *>(conf.password);
#elif defined(ESP32)
wifi_config_t conf;
esp_wifi_get_config(WIFI_IF_STA, &conf);
_ssid = reinterpret_cast<const char *>(conf.sta.ssid);
_pass = reinterpret_cast<const char *>(conf.sta.password);
#endif
if (strlen(_ssid) && strlen(_pass))
{

View File

@@ -14,6 +14,8 @@ board = esp32dev
board_build.partitions = awtrix_partition.csv
upload_speed = 921600
framework = arduino
monitor_speed = 115200
board_build.f_cpu = 240000000L
build_flags = -DULANZI -D MQTT_MAX_PACKET_SIZE=1024
lib_deps =
adafruit/Adafruit SHT31 Library@^2.2.0
@@ -29,10 +31,12 @@ platform = https://github.com/platformio/platform-espressif32.git
board = wemos_d1_mini32
board_build.partitions = awtrix_partition.csv
upload_speed = 921600
monitor_speed = 115200
framework = arduino
build_flags = -DAWTRIX_UPGRADE -D MQTT_MAX_PACKET_SIZE=1024
lib_deps =
adafruit/Adafruit BME280 Library@^2.2.2
plerup/EspSoftwareSerial@^8.0.1
bblanchon/ArduinoJson@^6.20.0
evert-arias/EasyButton@^2.0.1
fastled/FastLED@^3.5.0

View File

@@ -38,6 +38,7 @@ struct CustomApp
bool soundPlayed;
uint16_t duration = 0;
String sound;
byte textCase = 0;
int16_t repeat = 0;
int16_t currentRepeat = 0;
String name;
@@ -65,6 +66,7 @@ struct Notification
uint16_t duration = 0;
int16_t repeat = -1;
bool hold = false;
byte textCase = 0;
byte pushIcon = 0;
int16_t iconPosition = 0;
bool iconWasPushed = false;
@@ -91,7 +93,7 @@ String getAppNameByFunction(AppCallback AppFunction)
}
}
return ""; // Gibt einen leeren String zurück, wenn die App-Funktion nicht gefunden wurde
return "";
}
int findAppIndexByName(const String &name)
@@ -105,7 +107,7 @@ int findAppIndexByName(const String &name)
return -1;
}
void TimeApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void TimeApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
if (notify.flag)
return;
@@ -153,7 +155,7 @@ void TimeApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x,
}
}
void DateApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void DateApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
if (notify.flag)
return;
@@ -181,55 +183,60 @@ void DateApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x,
}
}
void TempApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void TempApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
if (notify.flag)
return;
CURRENT_APP = "Temperature";
DisplayManager.getInstance().resetTextColor();
matrix->drawRGBBitmap(x, y, get_icon(234), 8, 8);
matrix->setCursor(12 + x, 6 + y);
matrix->drawRGBBitmap(x, y, icon_234, 8, 8);
if (TEMP_DECIMAL_PLACES > 0)
matrix->setCursor(8 + x, 6 + y);
else
matrix->setCursor(12 + x, 6 + y);
if (IS_CELSIUS)
{
matrix->print((int)CURRENT_TEMP);
matrix->print(CURRENT_TEMP, TEMP_DECIMAL_PLACES);
matrix->print(utf8ascii("°C"));
}
else
{
int tempF = (CURRENT_TEMP * 9 / 5) + 32;
matrix->print(tempF);
double tempF = (CURRENT_TEMP * 9 / 5) + 32;
matrix->print(tempF, TEMP_DECIMAL_PLACES);
matrix->print(utf8ascii("°F"));
}
}
void HumApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void HumApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
if (notify.flag)
return;
CURRENT_APP = "Humidity";
DisplayManager.getInstance().resetTextColor();
matrix->drawRGBBitmap(x, y + 1, get_icon(2075), 8, 8);
matrix->drawRGBBitmap(x, y + 1, icon_2075, 8, 8);
matrix->setCursor(14 + x, 6 + y);
int humidity = CURRENT_HUM; // Temperatur ohne Nachkommastellen
matrix->print(humidity); // Ausgabe der Temperatur
int humidity = CURRENT_HUM; // Humidity without decimal places
matrix->print(humidity); // Output humidity
matrix->print("%");
}
#ifdef ULANZI
void BatApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void BatApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
if (notify.flag)
return;
CURRENT_APP = "Battery";
DisplayManager.getInstance().resetTextColor();
matrix->drawRGBBitmap(x, y, get_icon(1486), 8, 8);
matrix->drawRGBBitmap(x, y, icon_1486, 8, 8);
matrix->setCursor(14 + x, 6 + y);
matrix->print(BATTERY_PERCENT); // Ausgabe des Ladezustands
matrix->print("%");
}
#endif
void MenuApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
void MenuApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer *gifPlayer)
{
if (!MenuManager.inMenu)
return;
@@ -237,13 +244,13 @@ void MenuApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
DisplayManager.printText(0, 6, utf8ascii(MenuManager.menutext()).c_str(), true, true);
}
void AlarmApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
void AlarmApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer *gifPlayer)
{
if (ALARM_ACTIVE)
{
matrix->fillScreen(matrix->Color(255, 0, 0));
CURRENT_APP = "Alarm";
uint16_t textWidth = getTextWidth("ALARM", false);
uint16_t textWidth = getTextWidth("ALARM", 0);
int16_t textX = ((32 - textWidth) / 2);
matrix->setTextColor(0);
matrix->setCursor(textX, 6);
@@ -251,19 +258,25 @@ void AlarmApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
if (ALARM_SOUND != "")
{
if (!PeripheryManager.isPlaying())
{
#ifdef ULANZI
PeripheryManager.playFromFile("/MELODIES/" + ALARM_SOUND + ".txt");
#else
PeripheryManager.playFromFile(DFMINI_MP3_ALARM);
#endif
}
}
}
}
void TimerApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
void TimerApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer *gifPlayer)
{
if (TIMER_ACTIVE)
{
matrix->fillScreen(matrix->Color(0, 255, 0));
CURRENT_APP = "Timer";
String menuText = "TIMER";
uint16_t textWidth = getTextWidth(menuText.c_str(), false);
uint16_t textWidth = getTextWidth(menuText.c_str(), 0);
int16_t textX = ((32 - textWidth) / 2);
matrix->setTextColor(0);
matrix->setCursor(textX, 6);
@@ -271,12 +284,18 @@ void TimerApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
if (TIMER_SOUND != "")
{
if (!PeripheryManager.isPlaying())
{
#ifdef ULANZI
PeripheryManager.playFromFile("/MELODIES/" + TIMER_SOUND + ".txt");
#else
PeripheryManager.playFromFile(DFMINI_MP3_TIMER);
#endif
}
}
}
}
void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
// Abort if notify.flag is set
if (notify.flag)
@@ -316,14 +335,14 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
bool hasIcon = ca->icon;
uint16_t availableWidth = (hasIcon) ? 24 : 32;
bool noScrolling = getTextWidth(ca->text.c_str(), false) <= availableWidth;
bool noScrolling = getTextWidth(ca->text.c_str(), ca->textCase) <= availableWidth;
if (ca->barSize > 0)
{
DisplayManager.drawBarChart(x, y, ca->barData, ca->barSize, hasIcon, ca->color);
}
else
{
if ((ca->repeat > 0) && (getTextWidth(ca->text.c_str(), false) > availableWidth) && (state->appState == FIXED))
if ((ca->repeat > 0) && (getTextWidth(ca->text.c_str(), ca->textCase) > availableWidth) && (state->appState == FIXED))
{
DisplayManager.setAutoTransition(false);
}
@@ -332,9 +351,9 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
DisplayManager.setAutoTransition(true);
}
if (getTextWidth(ca->text.c_str(), false) > availableWidth && !(state->appState == IN_TRANSITION))
if (getTextWidth(ca->text.c_str(), ca->textCase) > availableWidth && !(state->appState == IN_TRANSITION))
{
if (ca->scrollposition <= -getTextWidth(ca->text.c_str(), false))
if (ca->scrollposition <= -getTextWidth(ca->text.c_str(), ca->textCase))
{
ca->scrollDelay = 0;
ca->scrollposition = 9;
@@ -382,7 +401,7 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
}
}
}
int16_t textX = (hasIcon) ? ((24 - getTextWidth(ca->text.c_str(), false)) / 2) + 9 : ((32 - getTextWidth(ca->text.c_str(), false)) / 2);
int16_t textX = (hasIcon) ? ((24 - getTextWidth(ca->text.c_str(), ca->textCase)) / 2) + 9 : ((32 - getTextWidth(ca->text.c_str(), ca->textCase)) / 2);
matrix->setTextColor(ca->color);
if (noScrolling)
{
@@ -390,12 +409,12 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
// Display text with rainbow effect if enabled
if (ca->rainbow)
{
DisplayManager.HSVtext(x + textX, 6 + y, ca->text.c_str(), false);
DisplayManager.HSVtext(x + textX, 6 + y, ca->text.c_str(), false, ca->textCase);
}
else
{
// Display text
DisplayManager.printText(x + textX, y + 6, ca->text.c_str(), false, false);
DisplayManager.printText(x + textX, y + 6, ca->text.c_str(), false, ca->textCase);
}
}
else
@@ -403,11 +422,11 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
// Display scrolling text with rainbow effect if enabled
if (ca->rainbow)
{
DisplayManager.HSVtext(x + ca->scrollposition, 6 + y, ca->text.c_str(), false);
DisplayManager.HSVtext(x + ca->scrollposition, 6 + y, ca->text.c_str(), false, ca->textCase);
}
else
{
DisplayManager.printText(x + ca->scrollposition, 6 + y, ca->text.c_str(), false, false);
DisplayManager.printText(x + ca->scrollposition, 6 + y, ca->text.c_str(), false, ca->textCase);
}
}
}
@@ -436,10 +455,8 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
// Display animated GIF if enabled and App is fixed, since we have only one gifplayer instance, it looks weird when 2 apps want to draw a different gif
if (ca->isGif)
{
if (state->appState == FIXED)
{
DisplayManager.drawGIF(x + ca->iconPosition, y, ca->icon);
}
gifPlayer->playGif(x + ca->iconPosition, y, &ca->icon);
}
else
{
@@ -457,7 +474,7 @@ void ShowCustomApp(String name, FastLED_NeoMatrix *matrix, MatrixDisplayUiState
DisplayManager.getInstance().resetTextColor();
}
void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, GifPlayer *gifPlayer)
{
// Check if notification flag is set
if (!notify.flag)
@@ -481,6 +498,7 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
notify.iconWasPushed = false;
notify.iconPosition = 0;
notify.scrollDelay = 0;
DisplayManager.showGif = false;
return;
}
@@ -491,7 +509,7 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
matrix->fillRect(0, 0, 32, 8, 0);
// Calculate text and available width
uint16_t textWidth = getTextWidth(notify.text.c_str(), false);
uint16_t textWidth = getTextWidth(notify.text.c_str(), notify.textCase);
uint16_t availableWidth = hasIcon ? 24 : 32;
// Check if text is scrolling
@@ -563,12 +581,12 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
if (notify.rainbow)
{
// Display text in rainbow color if enabled
DisplayManager.HSVtext(textX, 6, notify.text.c_str(), false);
DisplayManager.HSVtext(textX, 6, notify.text.c_str(), false, notify.textCase);
}
else
{
// Display text in solid color
DisplayManager.printText(textX, 6, notify.text.c_str(), false, false);
DisplayManager.printText(textX, 6, notify.text.c_str(), false, notify.textCase);
}
}
else
@@ -576,12 +594,12 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
if (notify.rainbow)
{
// Display scrolling text in rainbow color if enabled
DisplayManager.HSVtext(notify.scrollposition, 6, notify.text.c_str(), false);
DisplayManager.HSVtext(notify.scrollposition, 6, notify.text.c_str(), false, notify.textCase);
}
else
{
// Display scrolling text in solid color
DisplayManager.printText(notify.scrollposition, 6, notify.text.c_str(), false, false);
DisplayManager.printText(notify.scrollposition, 6, notify.text.c_str(), false, notify.textCase);
}
}
}
@@ -612,7 +630,8 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
if (notify.isGif)
{
// Display GIF if present
DisplayManager.drawGIF(notify.iconPosition, 0, notify.icon);
gifPlayer->playGif(notify.iconPosition, 0, &notify.icon);
}
else
{
@@ -633,124 +652,124 @@ void NotifyApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state)
// Unattractive to have a function for every customapp wich does the same, but currently still no other option found TODO
void CApp1(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp1(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp1);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp2(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp2(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp2);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp3(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp3(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp3);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp4(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp4(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp4);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp5(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp5(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp5);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp6(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp6(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp6);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp7(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp7(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp7);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp8(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp8(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp8);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp9(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp9(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp9);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp10(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp10(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp10);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp11(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp11(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp11);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp12(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp12(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp12);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp13(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp13(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp13);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp14(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp14(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp14);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp15(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp15(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp15);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp16(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp16(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp16);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp17(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp17(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp17);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp18(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp18(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp18);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp19(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp19(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp19);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
void CApp20(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame)
void CApp20(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t x, int16_t y, bool firstFrame, bool lastFrame, GifPlayer *gifPlayer)
{
String name = getAppNameByFunction(CApp20);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame);
ShowCustomApp(name, matrix, state, x, y, firstFrame, lastFrame, gifPlayer);
}
const uint16_t *getWeatherIcon(int code)
@@ -775,7 +794,7 @@ void WeatherApp(FastLED_NeoMatrix *matrix, MatrixDisplayUiState *state, int16_t
DisplayManager.getInstance().resetTextColor();
matrix->drawRGBBitmap(x, y, getWeatherIcon(WEATHER_CODE), 8, 8);
String text = WEATHER_TEMP + "°" + WEATHER_HUM + "%";
uint16_t textWidth = getTextWidth(text.c_str(), false);
uint16_t textWidth = getTextWidth(text.c_str(), 0);
int16_t textX = ((23 - textWidth) / 2);
matrix->setCursor(textX + 11, 6 + y);
matrix->print(utf8ascii(text));

View File

@@ -106,8 +106,10 @@ const char HAramClass[] PROGMEM = {"data_size"};
const char HAramUnit[] PROGMEM = {"B"};
// JSON properites
#ifdef ULANZI
const char BatKey[] PROGMEM = {"bat"};
const char BatRawKey[] PROGMEM = {"bat_raw"};
#endif
const char LuxKey[] PROGMEM = {"lux"};
const char LDRRawKey[] PROGMEM = {"ldr_raw"};
const char BrightnessKey[] PROGMEM = {"bri"};

View File

@@ -106,8 +106,10 @@ extern const char HAramClass[];
extern const char HAramUnit[];
// JSON properites
#ifdef ULANZI
extern const char BatKey[];
extern const char BatRawKey[];
#endif
extern const char LuxKey[];
extern const char LDRRawKey[];
extern const char BrightnessKey[];

View File

@@ -14,6 +14,8 @@
#include "MenuManager.h"
#include "Apps.h"
#include "Dictionary.h"
#include <set>
#include "GifPlayer.h"
Ticker AlarmTicker;
Ticker TimerTicker;
@@ -26,13 +28,14 @@ Ticker TimerTicker;
#define MATRIX_WIDTH 32
#define MATRIX_HEIGHT 8
fs::File gifFile;
GifPlayer gif;
uint16_t gifX, gifY;
CRGB leds[MATRIX_WIDTH * MATRIX_HEIGHT];
FastLED_NeoMatrix matrix(leds, 32, 8, NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_ZIGZAG);
MatrixDisplayUi ui(&matrix);
FastLED_NeoMatrix *matrix = new FastLED_NeoMatrix(leds, 8, 8, 4, 1, NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE);
MatrixDisplayUi *ui = new MatrixDisplayUi(matrix);
DisplayManager_ &DisplayManager_::getInstance()
{
@@ -46,22 +49,22 @@ void DisplayManager_::setBrightness(uint8_t bri)
{
if (MATRIX_OFF && !ALARM_ACTIVE)
{
matrix.setBrightness(0);
matrix->setBrightness(0);
}
else
{
matrix.setBrightness(bri);
matrix->setBrightness(bri);
}
}
void DisplayManager_::setFPS(uint8_t fps)
{
ui.setTargetFPS(fps);
ui->setTargetFPS(fps);
}
void DisplayManager_::setTextColor(uint16_t color)
{
matrix.setTextColor(color);
matrix->setTextColor(color);
}
void DisplayManager_::MatrixState(bool on)
@@ -73,27 +76,22 @@ void DisplayManager_::MatrixState(bool on)
bool DisplayManager_::setAutoTransition(bool active)
{
if (ui.AppCount < 2)
if (ui->AppCount < 2)
{
ui.disablesetAutoTransition();
ui->disablesetAutoTransition();
return false;
}
if (active && AUTO_TRANSITION)
{
ui.enablesetAutoTransition();
ui->enablesetAutoTransition();
return true;
}
else
{
ui.disablesetAutoTransition();
ui->disablesetAutoTransition();
return false;
}
}
void DisplayManager_::drawGIF(uint16_t x, uint16_t y, fs::File gifFile)
{
gif.setFile(gifFile);
gif.drawFrame(x, y);
showGif = false;
}
void DisplayManager_::drawJPG(uint16_t x, uint16_t y, fs::File jpgFile)
@@ -103,14 +101,14 @@ void DisplayManager_::drawJPG(uint16_t x, uint16_t y, fs::File jpgFile)
void DisplayManager_::drawBMP(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h)
{
matrix.drawRGBBitmap(y, x, bitmap, w, h);
matrix->drawRGBBitmap(y, x, bitmap, w, h);
}
void DisplayManager_::applyAllSettings()
{
ui.setTargetFPS(MATRIX_FPS);
ui.setTimePerApp(TIME_PER_APP);
ui.setTimePerTransition(TIME_PER_TRANSITION);
ui->setTargetFPS(MATRIX_FPS);
ui->setTimePerApp(TIME_PER_APP);
ui->setTimePerTransition(TIME_PER_TRANSITION);
setBrightness(BRIGHTNESS);
setTextColor(TEXTCOLOR_565);
setAutoTransition(AUTO_TRANSITION);
@@ -118,47 +116,42 @@ void DisplayManager_::applyAllSettings()
void DisplayManager_::resetTextColor()
{
matrix.setTextColor(TEXTCOLOR_565);
matrix->setTextColor(TEXTCOLOR_565);
}
void DisplayManager_::clearMatrix()
{
matrix.clear();
matrix.show();
matrix->clear();
matrix->show();
}
bool jpg_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap)
{
uint16_t bitmapIndex = 0;
for (uint16_t row = 0; row < h; row++)
{
for (uint16_t col = 0; col < w; col++)
{
uint16_t color = bitmap[bitmapIndex++];
uint8_t r = ((color & 0xF800) >> 11) << 3;
uint8_t g = ((color & 0x07E0) >> 5) << 2;
uint8_t b = (color & 0x001F) << 3;
matrix.drawPixel(x + col, y + row, matrix.Color(r, g, b));
matrix->drawPixel(x + col, y + row, bitmap[bitmapIndex++]);
}
}
return 0;
}
void DisplayManager_::printText(int16_t x, int16_t y, const char *text, bool centered, bool ignoreUppercase)
void DisplayManager_::printText(int16_t x, int16_t y, const char *text, bool centered, byte textCase)
{
if (centered)
{
uint16_t textWidth = getTextWidth(text, ignoreUppercase);
uint16_t textWidth = getTextWidth(text, textCase);
int16_t textX = ((32 - textWidth) / 2);
matrix.setCursor(textX, y);
matrix->setCursor(textX, y);
}
else
{
matrix.setCursor(x, y);
matrix->setCursor(x, y);
}
if (UPPERCASE_LETTERS && !ignoreUppercase)
if ((UPPERCASE_LETTERS && textCase == 0) || textCase == 1)
{
size_t length = strlen(text);
char upperText[length + 1]; // +1 for the null terminator
@@ -169,43 +162,43 @@ void DisplayManager_::printText(int16_t x, int16_t y, const char *text, bool cen
}
upperText[length] = '\0'; // Null terminator
matrix.print(upperText);
matrix->print(upperText);
}
else
{
matrix.print(text);
matrix->print(text);
}
}
void DisplayManager_::HSVtext(int16_t x, int16_t y, const char *text, bool clear)
void DisplayManager_::HSVtext(int16_t x, int16_t y, const char *text, bool clear, byte textCase)
{
if (clear)
matrix.clear();
matrix->clear();
static uint8_t hueOffset = 0;
uint16_t xpos = 0;
for (uint16_t i = 0; i < strlen(text); i++)
{
uint8_t hue = map(i, 0, strlen(text), 0, 255) + hueOffset;
uint32_t textColor = hsvToRgb(hue, 255, 255);
matrix.setTextColor(textColor);
matrix->setTextColor(textColor);
const char *myChar = &text[i];
matrix.setCursor(xpos + x, y);
if (UPPERCASE_LETTERS)
matrix->setCursor(xpos + x, y);
if ((UPPERCASE_LETTERS && textCase == 0) || textCase == 1)
{
matrix.print((char)toupper(text[i]));
matrix->print((char)toupper(text[i]));
}
else
{
matrix.print(&text[i]);
matrix->print(&text[i]);
}
char temp_str[2] = {'\0', '\0'};
temp_str[0] = text[i];
xpos += getTextWidth(temp_str, false);
xpos += getTextWidth(temp_str, textCase);
}
hueOffset++;
if (clear)
matrix.show();
matrix->show();
}
void pushCustomApp(String name, int position)
@@ -213,7 +206,7 @@ void pushCustomApp(String name, int position)
if (customApps.count(name) == 0)
{
++customPagesCount;
void (*customApps[20])(FastLED_NeoMatrix *, MatrixDisplayUiState *, int16_t, int16_t, bool, bool) = {CApp1, CApp2, CApp3, CApp4, CApp5, CApp6, CApp7, CApp8, CApp9, CApp10, CApp11, CApp12, CApp13, CApp14, CApp15, CApp16, CApp17, CApp18, CApp19, CApp20};
void (*customApps[20])(FastLED_NeoMatrix *, MatrixDisplayUiState *, int16_t, int16_t, bool, bool, GifPlayer *) = {CApp1, CApp2, CApp3, CApp4, CApp5, CApp6, CApp7, CApp8, CApp9, CApp10, CApp11, CApp12, CApp13, CApp14, CApp15, CApp16, CApp17, CApp18, CApp19, CApp20};
if (position < 0) // Insert at the end of the vector
{
@@ -228,34 +221,40 @@ void pushCustomApp(String name, int position)
Apps.push_back(std::make_pair(name, customApps[customPagesCount]));
}
ui.setApps(Apps); // Add Apps
ui->setApps(Apps); // Add Apps
DisplayManager.getInstance().setAutoTransition(true);
}
}
void removeCustomApp(const String &name)
void removeCustomAppFromApps(const String &name)
{
auto it = std::find_if(Apps.begin(), Apps.end(), [&name](const std::pair<String, AppCallback> &appPair)
{ return appPair.first == name; });
Apps.erase(it);
ui.setApps(Apps);
ui->setApps(Apps);
}
void DisplayManager_::generateCustomPage(String name, const char *json)
void DisplayManager_::generateCustomPage(const String &name, const char *json)
{
if (strcmp(json, "") == 0 && customApps.count(name))
{
Serial.println("delete");
customApps.erase(customApps.find(name));
removeCustomApp(name);
removeCustomAppFromApps(name);
showGif = false;
return;
}
DynamicJsonDocument doc(1024);
DeserializationError error = deserializeJson(doc, json);
if (error)
{
showGif = false;
doc.clear();
return;
}
CustomApp customApp;
@@ -266,7 +265,11 @@ void DisplayManager_::generateCustomPage(String name, const char *json)
if (doc.containsKey("sound"))
{
#ifdef ULANZI
customApp.sound = ("/" + doc["sound"].as<String>() + ".txt");
#else
customApp.sound = doc["sound"].as<String>();
#endif
}
else
{
@@ -297,8 +300,9 @@ void DisplayManager_::generateCustomPage(String name, const char *json)
int pos = doc.containsKey("pos") ? doc["pos"].as<uint8_t>() : -1;
customApp.rainbow = doc.containsKey("rainbow") ? doc["rainbow"] : false;
customApp.pushIcon = doc.containsKey("pushIcon") ? doc["pushIcon"] : 0;
customApp.textCase = doc.containsKey("textCase") ? doc["textCase"] : 0;
customApp.name = name;
customApp.text = utf8ascii(doc["text"].as<String>());
customApp.text = doc.containsKey("text") ? utf8ascii(doc["text"].as<String>()) : "";
if (doc.containsKey("color"))
{
@@ -339,6 +343,10 @@ void DisplayManager_::generateCustomPage(String name, const char *json)
}
else
{
if (customApp.icon)
{
customApp.icon.close();
}
if (LittleFS.exists("/ICONS/" + iconFileName + ".jpg"))
{
customApp.isGif = false;
@@ -364,6 +372,7 @@ void DisplayManager_::generateCustomPage(String name, const char *json)
pushCustomApp(name, pos - 1);
customApps[name] = customApp;
doc.clear();
}
void DisplayManager_::generateNotification(const char *json)
@@ -372,12 +381,12 @@ void DisplayManager_::generateNotification(const char *json)
deserializeJson(doc, json);
notify.duration = doc.containsKey("duration") ? doc["duration"].as<int>() * 1000 : TIME_PER_APP;
notify.text = utf8ascii(doc["text"].as<String>());
notify.text = doc.containsKey("text") ? utf8ascii(doc["text"].as<String>()) : "";
notify.repeat = doc.containsKey("repeat") ? doc["repeat"].as<uint16_t>() : -1;
notify.rainbow = doc.containsKey("rainbow") ? doc["rainbow"].as<bool>() : false;
notify.hold = doc.containsKey("hold") ? doc["hold"].as<bool>() : false;
notify.pushIcon = doc.containsKey("pushIcon") ? doc["pushIcon"] : 0;
notify.flag = true;
notify.textCase = doc.containsKey("textCase") ? doc["textCase"] : 0;
notify.startime = millis();
notify.scrollposition = 9;
notify.iconWasPushed = false;
@@ -385,7 +394,11 @@ void DisplayManager_::generateNotification(const char *json)
if (doc.containsKey("sound"))
{
#ifdef ULANZI
PeripheryManager.playFromFile("/MELODIES/" + doc["sound"].as<String>() + ".txt");
#else
PeripheryManager.playFromFile(doc["sound"].as<String>());
#endif
}
if (doc.containsKey("bar"))
@@ -432,6 +445,9 @@ void DisplayManager_::generateNotification(const char *json)
notify.color = TEXTCOLOR_565;
}
notify.flag = true;
showGif = false;
if (doc.containsKey("icon"))
{
String iconFileName = doc["icon"].as<String>();
@@ -507,77 +523,86 @@ void DisplayManager_::loadNativeApps()
updateApp("bat", BatApp, SHOW_BAT, 4);
#endif
ui.setApps(Apps);
ui->setApps(Apps);
setAutoTransition(true);
}
void DisplayManager_::setup()
{
TJpgDec.setCallback(jpg_output);
FastLED.addLeds<NEOPIXEL, MATRIX_PIN>(leds, MATRIX_WIDTH * MATRIX_HEIGHT);
gif.setMatrix(&matrix);
ui.setAppAnimation(SLIDE_DOWN);
ui.setOverlays(overlays, 4);
TJpgDec.setJpgScale(1);
FastLED.addLeds<NEOPIXEL, MATRIX_PIN>(leds, MATRIX_WIDTH * MATRIX_HEIGHT).setTemperature(OvercastSky);
setMatrixLayout(MATRIX_LAYOUT);
gif.setMatrix(matrix);
ui->setAppAnimation(SLIDE_DOWN);
ui->setTimePerApp(TIME_PER_APP);
ui->setTimePerTransition(TIME_PER_TRANSITION);
ui->setTargetFPS(MATRIX_FPS);
ui->setOverlays(overlays, 4);
setAutoTransition(AUTO_TRANSITION);
ui.init();
ui->init();
}
void DisplayManager_::tick()
{
if (AP_MODE)
{
HSVtext(2, 6, "AP MODE", true);
HSVtext(2, 6, "AP MODE", true, 1);
}
else
{
if (ui.getUiState()->appState == IN_TRANSITION && !appIsSwitching)
ui->update();
if (ui->getUiState()->appState == IN_TRANSITION && !appIsSwitching)
{
appIsSwitching = true;
showGif = false;
}
else if (ui.getUiState()->appState == FIXED && appIsSwitching)
else if (ui->getUiState()->appState == FIXED && appIsSwitching)
{
appIsSwitching = false;
MQTTManager.setCurrentApp(CURRENT_APP);
setAppTime(TIME_PER_APP);
}
ui.update();
}
}
void DisplayManager_::clear()
{
matrix.clear();
matrix->clear();
}
void DisplayManager_::show()
{
matrix.show();
matrix->show();
}
void DisplayManager_::leftButton()
{
if (!MenuManager.inMenu)
ui.previousApp();
ui->previousApp();
}
void DisplayManager_::rightButton()
{
if (!MenuManager.inMenu)
ui.nextApp();
ui->nextApp();
}
void DisplayManager_::nextApp()
{
if (!MenuManager.inMenu)
ui.nextApp();
ui->nextApp();
}
void DisplayManager_::previousApp()
{
if (!MenuManager.inMenu)
ui.previousApp();
ui->previousApp();
}
void snozzeTimerCallback()
@@ -620,8 +645,10 @@ void DisplayManager_::selectButtonLong()
void DisplayManager_::dismissNotify()
{
notify.hold = false;
notify.flag = false;
showGif = false;
}
void timerCallback()
@@ -647,7 +674,7 @@ void DisplayManager_::gererateTimer(String Payload)
futureTimeinfo.tm_sec += seconds;
time_t futureTime = mktime(&futureTimeinfo);
int interval = difftime(futureTime, now) * 1000;
TimerTicker.attach_ms(interval, timerCallback);
TimerTicker.once_ms(interval, timerCallback);
}
void DisplayManager_::switchToApp(const char *json)
@@ -660,7 +687,7 @@ void DisplayManager_::switchToApp(const char *json)
bool fast = doc["fast"] | false;
int index = findAppIndexByName(name);
if (index > -1)
ui.transitionToApp(index);
ui->transitionToApp(index);
}
void DisplayManager_::setNewSettings(const char *json)
@@ -676,21 +703,22 @@ void DisplayManager_::setNewSettings(const char *json)
BRIGHTNESS = doc.containsKey("brightness") ? doc["brightness"] : BRIGHTNESS;
AUTO_BRIGHTNESS = doc.containsKey("autobrightness") ? doc["autobrightness"] : AUTO_BRIGHTNESS;
AUTO_TRANSITION = doc.containsKey("autotransition") ? doc["autotransition"] : AUTO_TRANSITION;
UPPERCASE_LETTERS = doc.containsKey("uppercase") ? doc["uppercase"] : UPPERCASE_LETTERS;
applyAllSettings();
saveSettings();
}
void DisplayManager_::drawProgressBar(int cur, int total)
{
matrix.clear();
matrix->clear();
int progress = (cur * 100) / total;
char progressStr[5];
snprintf(progressStr, 5, "%d%%", progress); // Formatieren des Prozentzeichens
snprintf(progressStr, 5, "%d%%", progress);
printText(0, 6, progressStr, true, false);
int leds_for_progress = (progress * MATRIX_WIDTH * MATRIX_HEIGHT) / 100;
matrix.drawFastHLine(0, 7, MATRIX_WIDTH, matrix.Color(100, 100, 100));
matrix.drawFastHLine(0, 7, leds_for_progress / MATRIX_HEIGHT, matrix.Color(0, 255, 0));
matrix.show();
matrix->drawFastHLine(0, 7, MATRIX_WIDTH, matrix->Color(100, 100, 100));
matrix->drawFastHLine(0, 7, leds_for_progress / MATRIX_HEIGHT, matrix->Color(0, 255, 0));
matrix->show();
}
void DisplayManager_::drawMenuIndicator(int cur, int total, uint16_t color)
@@ -704,11 +732,11 @@ void DisplayManager_::drawMenuIndicator(int cur, int total, uint16_t color)
int x = leftMargin + i * (menuItemWidth + pixelSpacing);
if (i == cur)
{
matrix.drawLine(x, 7, x + menuItemWidth - 1, 7, color);
matrix->drawLine(x, 7, x + menuItemWidth - 1, 7, color);
}
else
{
matrix.drawLine(x, 7, x + menuItemWidth - 1, 7, matrix.Color(100, 100, 100));
matrix->drawLine(x, 7, x + menuItemWidth - 1, 7, matrix->Color(100, 100, 100));
}
}
}
@@ -718,7 +746,6 @@ void DisplayManager_::drawBarChart(int16_t x, int16_t y, const int data[], byte
int maximum = 0;
int newData[dataSize];
// Finde das Maximum in der Datenliste
for (int i = 0; i < dataSize; i++)
{
int d = data[i];
@@ -728,14 +755,12 @@ void DisplayManager_::drawBarChart(int16_t x, int16_t y, const int data[], byte
}
}
// Berechne neue Datenwerte zwischen 0 und 8 basierend auf dem Maximum
for (int i = 0; i < dataSize; i++)
{
int d = data[i];
newData[i] = map(d, 0, maximum, 0, 8);
}
// Berechne die Breite der Balken basierend auf der Anzahl der Daten und der Breite der Matrix
int barWidth;
if (withIcon)
{
@@ -746,150 +771,110 @@ void DisplayManager_::drawBarChart(int16_t x, int16_t y, const int data[], byte
barWidth = (32 / (dataSize)-1);
}
// Berechne die Startposition des Graphen basierend auf dem Icon-Parameter
int startX = withIcon ? 9 : 0;
// Zeichne die Balken auf die Matrix
for (int i = 0; i < dataSize; i++)
{
int x1 = x + startX + (barWidth + 1) * i;
int barHeight = newData[i];
int y1 = min(8 - barHeight, 7);
matrix.fillRect(x1, y1 + y, barWidth, barHeight, color);
matrix->fillRect(x1, y1 + y, barWidth, barHeight, color);
}
}
std::pair<String, AppCallback> getNativeAppByName(const String &appName)
{
if (appName == "time")
{
return std::make_pair("time", TimeApp);
}
else if (appName == "date")
{
return std::make_pair("date", DateApp);
}
else if (appName == "temp")
{
return std::make_pair("temp", TempApp);
}
else if (appName == "hum")
{
return std::make_pair("hum", HumApp);
}
else if (appName == "bat")
{
return std::make_pair("bat", BatApp);
}
return std::make_pair("", nullptr);
}
void DisplayManager_::updateAppVector(const char *json)
{
// Parse the JSON input
DynamicJsonDocument doc(1024);
auto error = deserializeJson(doc, json);
if (error)
StaticJsonDocument<512> doc; // Erhöhen Sie die Größe des Dokuments bei Bedarf
deserializeJson(doc, json);
JsonArray appArray;
if (doc.is<JsonObject>())
{
// If parsing fails, print an error message and return
Serial.print("Failed to parse JSON: ");
Serial.println(error.c_str());
return;
JsonArray tempArray = doc.to<JsonArray>();
tempArray.add(doc.as<JsonObject>());
appArray = tempArray;
}
else if (doc.is<JsonArray>())
{
appArray = doc.as<JsonArray>();
}
// Create new vectors to store updated apps
std::vector<std::pair<String, AppCallback>> newApps;
std::vector<String> activeApps;
// Loop through all apps in the JSON input
for (const auto &app : doc.as<JsonArray>())
for (JsonObject appObj : appArray)
{
// Get the app name, active status, and position (if specified)
String name = app["name"].as<String>();
bool show = true;
int position = -1;
String appName = appObj["name"].as<String>();
bool show = appObj["show"].as<bool>();
int position = appObj.containsKey("pos") ? appObj["pos"].as<int>() : Apps.size();
if (app.containsKey("show"))
auto appIt = std::find_if(Apps.begin(), Apps.end(), [&appName](const std::pair<String, AppCallback> &app)
{ return app.first == appName; });
std::pair<String, AppCallback> nativeApp = getNativeAppByName(appName);
if (!show)
{
show = app["show"].as<bool>();
if (appIt != Apps.end())
{
Apps.erase(appIt);
}
}
if (app.containsKey("pos"))
{
position = app["pos"].as<int>();
}
// Find the corresponding AppCallback function based on the app name
AppCallback callback;
if (name == "time")
{
callback = TimeApp;
SHOW_TIME = show;
}
else if (name == "date")
{
callback = DateApp;
SHOW_DATE = show;
}
else if (name == "temp")
{
callback = TempApp;
SHOW_TEMP = show;
}
else if (name == "hum")
{
callback = HumApp;
SHOW_HUM = show;
}
#ifdef ULANZI
else if (name == "bat")
{
callback = BatApp;
SHOW_BAT = show;
}
#endif
else
{
// If the app is not one of the built-in apps, check if it's already in the vector
int appIndex = findAppIndexByName(name);
if (appIndex >= 0)
if (nativeApp.second != nullptr)
{
// The app is in the vector, so we can move it to a new position or remove it
auto it = Apps.begin() + appIndex;
if (show)
if (appIt != Apps.end())
{
if (position >= 0 && static_cast<size_t>(position) < newApps.size())
{
Apps.erase(it);
newApps.insert(newApps.begin() + position, std::make_pair(name, it->second));
}
Apps.erase(appIt);
}
else
{
// If the app is being removed, also remove it from the customApps map
if (customApps.count(name))
{
customApps.erase(customApps.find(name));
removeCustomApp(name);
}
}
}
continue;
}
if (show)
{
// Add the app to the new vector
if (position >= 0 && static_cast<size_t>(position) < newApps.size())
{
newApps.insert(newApps.begin() + position, std::make_pair(name, callback));
position = position < 0 ? 0 : position >= Apps.size() ? Apps.size()
: position;
Apps.insert(Apps.begin() + position, nativeApp);
}
else
{
newApps.emplace_back(name, callback);
if (appIt != Apps.end() && appObj.containsKey("pos"))
{
std::pair<String, AppCallback> app = *appIt;
Apps.erase(appIt);
position = position < 0 ? 0 : position >= Apps.size() ? Apps.size()
: position;
Apps.insert(Apps.begin() + position, app);
}
}
}
activeApps.push_back(name);
}
// Loop through all apps currently in the vector
for (const auto &app : Apps)
{
// If the app is not in the updated activeApps vector, add it to the newApps vector
if (std::find(activeApps.begin(), activeApps.end(), app.first) == activeApps.end())
{
newApps.push_back(app);
}
}
// Update the apps vector, set it in the UI, and save settings
Apps = std::move(newApps);
ui.setApps(Apps);
// Set the updated apps vector in the UI and save settings
ui->setApps(Apps);
saveSettings();
}
String DisplayManager_::getStat()
{
StaticJsonDocument<200> doc;
StaticJsonDocument<256> doc;
char buffer[5];
#ifdef ULANZI
doc[BatKey] = BATTERY_PERCENT;
@@ -898,6 +883,7 @@ String DisplayManager_::getStat()
snprintf(buffer, 5, "%.0f", CURRENT_LUX);
doc[LuxKey] = buffer;
doc[LDRRawKey] = LDR_RAW;
doc["ram"] = ESP.getFreeHeap();
doc[BrightnessKey] = BRIGHTNESS;
snprintf(buffer, 5, "%.0f", CURRENT_TEMP);
doc[TempKey] = buffer;
@@ -906,12 +892,52 @@ String DisplayManager_::getStat()
doc[UpTimeKey] = PeripheryManager.readUptime();
doc[SignalStrengthKey] = WiFi.RSSI();
doc[UpdateKey] = UPDATE_AVAILABLE;
doc["messages"] = RECEIVED_MESSAGES;
String jsonString;
serializeJson(doc, jsonString);
return jsonString;
return serializeJson(doc, jsonString), jsonString;
}
void DisplayManager_::setAppTime(uint16_t duration)
{
ui.setTimePerApp(duration);
}
ui->setTimePerApp(duration);
}
void DisplayManager_::setMatrixLayout(int layout)
{
delete matrix; // Free memory from the current matrix object
switch (layout)
{
case 0:
matrix = new FastLED_NeoMatrix(leds, 32, 8, NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_ZIGZAG);
break;
case 1:
matrix = new FastLED_NeoMatrix(leds, 8, 8, 4, 1, NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE);
break;
case 2:
matrix = new FastLED_NeoMatrix(leds, 32, 8, NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_COLUMNS + NEO_MATRIX_ZIGZAG);
break;
default:
break;
}
delete ui; // Free memory from the current ui object
ui = new MatrixDisplayUi(matrix); // Create a new ui object with the new matrix
}
String DisplayManager_::getAppsAsJson()
{
// Create a JSON object to hold the app positions and names
DynamicJsonDocument doc(1024);
JsonObject appsObject = doc.to<JsonObject>();
// Add each app position and name to the object
for (size_t i = 0; i < Apps.size(); i++)
{
appsObject[String(i)] = Apps[i].first;
}
// Serialize the JSON object to a string and return it
String json;
serializeJson(appsObject, json);
return json;
}

View File

@@ -27,6 +27,7 @@ private:
public:
static DisplayManager_ &getInstance();
bool appIsSwitching;
bool showGif;
void setup();
void tick();
void clear();
@@ -34,7 +35,7 @@ public:
void applyAllSettings();
void rightButton();
void dismissNotify();
void HSVtext(int16_t, int16_t, const char *, bool);
void HSVtext(int16_t, int16_t, const char *, bool, byte textCase);
void loadNativeApps();
void nextApp();
void previousApp();
@@ -49,8 +50,8 @@ public:
void setFPS(uint8_t);
void MatrixState(bool);
void generateNotification(const char *json);
void generateCustomPage(String name, const char *json);
void printText(int16_t x, int16_t y, const char *text, bool centered, bool ignoreUppercase);
void generateCustomPage(const String &name, const char *json);
void printText(int16_t x, int16_t y, const char *text, bool centered, byte textCase);
bool setAutoTransition(bool active);
void switchToApp(const char *json);
void setNewSettings(const char *json);
@@ -63,6 +64,7 @@ public:
void updateAppVector(const char *json);
void setMatrixLayout(int layout);
void setAppTime(uint16_t duration);
String getAppsAsJson();
String getStat();
};

View File

@@ -32,13 +32,13 @@ uint16_t hexToRgb565(String hexValue)
return color;
}
uint16_t getTextWidth(const char *text, bool ignoreUpperCase)
uint16_t getTextWidth(const char *text, byte textCase)
{
uint16_t width = 0;
for (const char *c = text; *c != '\0'; ++c)
{
char current_char = *c;
if (UPPERCASE_LETTERS && !ignoreUpperCase)
if ((UPPERCASE_LETTERS && textCase == 0) || textCase == 1)
{
current_char = toupper(current_char);
}
@@ -91,4 +91,4 @@ String utf8ascii(String s)
}
return r;
}
#endif
#endif

View File

@@ -19,7 +19,9 @@ void startLittleFS()
{
if (LittleFS.begin())
{
#ifdef ULANZI
LittleFS.mkdir("/MELODIES");
#endif
LittleFS.mkdir("/ICONS");
}
else
@@ -32,31 +34,40 @@ void startLittleFS()
void loadDevSettings()
{
Serial.println("laodSettings");
File file = LittleFS.open("/dev.json", "r");
if (!file)
Serial.println("loadSettings");
if (LittleFS.exists("/dev.json"))
{
return;
}
DynamicJsonDocument doc(128);
DeserializationError error = deserializeJson(doc, file);
if (error)
{
Serial.println(F("Failed to read dev settings"));
return;
}
File file = LittleFS.open("/dev.json", "r");
DynamicJsonDocument doc(128);
DeserializationError error = deserializeJson(doc, file);
if (error)
{
Serial.println(F("Failed to read dev settings"));
return;
}
if (doc.containsKey("bootsound"))
{
BOOT_SOUND = doc["bootsound"].as<String>();
}
if (doc.containsKey("bootsound"))
{
BOOT_SOUND = doc["bootsound"].as<String>();
}
if (doc.containsKey("bootsound"))
{
UPPERCASE_LETTERS = doc["uppercase"].as<bool>();
}
if (doc.containsKey("matrix"))
{
MATRIX_LAYOUT = doc["matrix"];
}
file.close();
if (doc.containsKey("bootsound"))
{
UPPERCASE_LETTERS = doc["uppercase"].as<bool>();
}
if (doc.containsKey("temp_dec_places"))
{
TEMP_DECIMAL_PLACES = doc["temp_dec_places"].as<int>();
}
file.close();
}
}
void loadSettings()
@@ -68,8 +79,8 @@ void loadSettings()
AUTO_BRIGHTNESS = Settings.getBool("ABRI", true);
TEXTCOLOR_565 = Settings.getUInt("COL", 0xFFFF);
AUTO_TRANSITION = Settings.getBool("TRANS", true);
TIME_PER_TRANSITION = Settings.getUInt("TSPEED", 500);
TIME_PER_APP = Settings.getUInt("ADUR", 5000);
TIME_PER_TRANSITION = Settings.getUInt("TSPEED", 400);
TIME_PER_APP = Settings.getUInt("ADUR", 7000);
TIME_FORMAT = Settings.getString("TFORMAT", "%H:%M:%S");
DATE_FORMAT = Settings.getString("DFORMAT", "%d.%m.%y");
START_ON_MONDAY = Settings.getBool("SOM", true);
@@ -83,6 +94,10 @@ void loadSettings()
SHOW_BAT = Settings.getBool("BAT", true);
#endif
SOUND_ACTIVE = Settings.getBool("SOUND", true);
#ifndef ULANZI
VOLUME_PERCENT = Settings.getUInt("VOL", 50);
VOLUME = map(VOLUME_PERCENT, 0, 100, 0, 30);
#endif
Settings.end();
uniqueID = getID();
MQTT_PREFIX = String(uniqueID);
@@ -112,6 +127,9 @@ void saveSettings()
Settings.putBool("BAT", SHOW_BAT);
#endif
Settings.putBool("SOUND", SOUND_ACTIVE);
#ifndef ULANZI
Settings.putUInt("VOL", VOLUME_PERCENT);
#endif
Settings.end();
}
@@ -121,7 +139,7 @@ IPAddress gateway;
IPAddress subnet;
IPAddress primaryDNS;
IPAddress secondaryDNS;
const char *VERSION = "0.47";
const char *VERSION = "0.48";
String MQTT_HOST = "";
uint16_t MQTT_PORT = 1883;
String MQTT_USER;
@@ -147,7 +165,7 @@ String NET_PDNS = "8.8.8.8";
String NET_SDNS = "1.1.1.1";
int TIME_PER_APP = 7000;
uint8_t MATRIX_FPS = 23;
int TIME_PER_TRANSITION = 500;
int TIME_PER_TRANSITION = 400;
String NTP_SERVER = "de.pool.ntp.org";
String NTP_TZ = "CET-1CEST,M3.5.0,M10.5.0/3";
bool HA_DISCOVERY = false;
@@ -185,7 +203,11 @@ bool ALARM_ACTIVE;
uint16_t TEXTCOLOR_565 = 0xFFFF;
bool SOUND_ACTIVE;
String BOOT_SOUND = "";
uint8_t VOLUME;
int TEMP_DECIMAL_PLACES = 0;
#ifndef ULANZI
uint8_t VOLUME_PERCENT;
uint8_t VOLUME;
#endif
int MATRIX_LAYOUT;
bool UPDATE_AVAILABLE = false;
bool UPDATE_AVAILABLE = false;
long RECEIVED_MESSAGES;

View File

@@ -68,10 +68,14 @@ extern bool START_ON_MONDAY;
extern bool IS_CELSIUS;
extern bool SOUND_ACTIVE;
extern String BOOT_SOUND;
extern uint8_t VOLUME;
extern int TEMP_DECIMAL_PLACES;
#ifndef ULANZI
extern uint8_t VOLUME_PERCENT;
extern uint8_t VOLUME;
#endif
extern int MATRIX_LAYOUT;
extern bool UPDATE_AVAILABLE;
extern long RECEIVED_MESSAGES;
void loadSettings();
void saveSettings();
#endif // Globals_H

View File

@@ -12,7 +12,7 @@
WiFiClient espClient;
uint8_t lastBrightness;
HADevice device;
HAMqtt mqtt(espClient, device, 19);
HAMqtt mqtt(espClient, device, 22);
unsigned long reconnectTimer = 0;
const unsigned long reconnectInterval = 30000; // 30 Sekunden
@@ -140,61 +140,72 @@ void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length)
char *payloadCopy = new char[length + 1];
memcpy(payloadCopy, payload, length);
payloadCopy[length] = '\0';
if (strTopic == MQTT_PREFIX + "/notify")
++RECEIVED_MESSAGES;
if (strTopic.equals(MQTT_PREFIX + "/notify"))
{
if (payload[0] != '{' || payload[length - 1] != '}')
{
delete[] payloadCopy;
return;
}
DisplayManager.generateNotification(payloadCopy);
delete[] payloadCopy;
return;
}
if (strTopic == MQTT_PREFIX + "/timer")
if (strTopic.equals(MQTT_PREFIX + "/timer"))
{
DisplayManager.gererateTimer(payloadCopy);
delete[] payloadCopy;
return;
}
if (strTopic == MQTT_PREFIX + "/notify/dismiss")
if (strTopic.equals(MQTT_PREFIX + "/notify/dismiss"))
{
DisplayManager.dismissNotify();
delete[] payloadCopy;
return;
}
if (strTopic == MQTT_PREFIX + "/apps")
if (strTopic.equals(MQTT_PREFIX + "/apps"))
{
DisplayManager.updateAppVector(payloadCopy);
delete[] payloadCopy;
return;
}
if (strTopic == MQTT_PREFIX + "/switch")
if (strTopic.equals(MQTT_PREFIX + "/switch"))
{
DisplayManager.switchToApp(payloadCopy);
delete[] payloadCopy;
return;
}
if (strTopic == MQTT_PREFIX + "/settings")
if (strTopic.equals(MQTT_PREFIX + "/settings"))
{
DisplayManager.setNewSettings(payloadCopy);
delete[] payloadCopy;
return;
}
if (strTopic == MQTT_PREFIX + "/nextapp")
if (strTopic.equals(MQTT_PREFIX + "/nextapp"))
{
DisplayManager.nextApp();
delete[] payloadCopy;
return;
}
if (strTopic == MQTT_PREFIX + "/previousapp")
if (strTopic.equals(MQTT_PREFIX + "/previousapp"))
{
DisplayManager.previousApp();
delete[] payloadCopy;
return;
}
if (strTopic == MQTT_PREFIX + "/doupdate")
if (strTopic.equals(MQTT_PREFIX + "/doupdate"))
{
if (UPDATE_AVAILABLE)
UpdateManager.updateFirmware();
delete[] payloadCopy;
return;
}
@@ -208,9 +219,9 @@ void onMqttMessage(const char *topic, const uint8_t *payload, uint16_t length)
}
DisplayManager.generateCustomPage(topic_str, payloadCopy);
delete[] payloadCopy;
return;
}
delete[] payloadCopy;
}
void onMqttConnected()
@@ -357,16 +368,16 @@ void MQTTManager_::setup()
humidity->setName(HAhumName);
humidity->setDeviceClass(HAhumClass);
humidity->setUnitOfMeasurement(HAhumUnit);
#ifdef ULANZI
sprintf(batID, HAbatID, macStr);
battery = new HASensor(batID);
battery->setIcon(HAbatIcon);
battery->setName(HAbatName);
battery->setDeviceClass(HAbatClass);
battery->setUnitOfMeasurement(HAbatUnit);
#endif
#endif
sprintf(luxID, HAluxID, macStr);
illuminance = new HASensor(luxID);
illuminance->setIcon(HAluxIcon);
@@ -388,6 +399,7 @@ void MQTTManager_::setup()
uptime = new HASensor(upID);
uptime->setName(HAupName);
uptime->setDeviceClass(HAupClass);
uptime->setUnitOfMeasurement("s");
sprintf(btnLID, HAbtnLID, macStr);
btnleft = new HABinarySensor(btnLID);
@@ -455,8 +467,8 @@ void MQTTManager_::sendStats()
#ifdef ULANZI
snprintf(buffer, 5, "%d", BATTERY_PERCENT);
battery->setValue(buffer);
#endif
#endif
snprintf(buffer, 5, "%.0f", CURRENT_TEMP);
temperature->setValue(buffer);

View File

@@ -28,8 +28,12 @@ enum MenuState
WeekdayMenu,
TempMenu,
Appmenu,
#ifdef ULANZI
SoundMenu
#else
SoundMenu,
VolumeMenu
#endif
};
const char *menuItems[] PROGMEM = {
@@ -45,10 +49,17 @@ const char *menuItems[] PROGMEM = {
"TEMP",
"APPS",
"SOUND",
#ifndef ULANZI
"VOLUME" ,
#endif
"UPDATE"};
int8_t menuIndex = 0;
#ifdef ULANZI
uint8_t menuItemCount = 13;
#else
uint8_t menuItemCount = 14;
#endif
const char *timeFormat[] PROGMEM = {
"%H:%M:%S",
@@ -193,6 +204,10 @@ String MenuManager_::menutext()
break;
}
break;
#ifndef ULANZI
case VolumeMenu:
return String(VOLUME_PERCENT) + "%";
#endif
default:
break;
}
@@ -250,10 +265,13 @@ void MenuManager_::rightButton()
case TempMenu:
IS_CELSIUS = !IS_CELSIUS;
break;
#ifndef ULANZI
case VolumeMenu:
VOLUME_PERCENT = (VOLUME_PERCENT % 100) + 1;
VOLUME = map(VOLUME_PERCENT, 0, 100, 0, 30);
PeripheryManager.setVolume(VOLUME);
if ((VOLUME_PERCENT + 1) > 100)
VOLUME_PERCENT = 0;
else
VOLUME_PERCENT++;
#endif
default:
break;
}
@@ -314,10 +332,13 @@ void MenuManager_::leftButton()
case SoundMenu:
SOUND_ACTIVE = !SOUND_ACTIVE;
break;
#ifndef ULANZI
case VolumeMenu:
VOLUME_PERCENT = (VOLUME_PERCENT % 100) + 1;
VOLUME = map(VOLUME_PERCENT, 0, 100, 0, 30);
PeripheryManager.setVolume(VOLUME);
if ((VOLUME_PERCENT - 1) < 0)
VOLUME_PERCENT = 100;
else
VOLUME_PERCENT--;
#endif
default:
break;
}
@@ -372,11 +393,10 @@ void MenuManager_::selectButton()
currentState = SoundMenu;
break;
case 12:
#ifdef AWTRIX_UPGRADE
#ifndef ULANZI
currentState = VolumeMenu;
break;
#endif
break;
#endif
case 13:
if (UpdateManager.checkUpdate(true))
{
@@ -454,12 +474,6 @@ void MenuManager_::selectButtonLong()
DisplayManager.applyAllSettings();
saveSettings();
break;
case VolumeMenu:
#ifdef AWTRIX_UPGRADE
VOLUME = map(VOLUME_PERCENT, 0, 100, 0, 30);
saveSettings();
#endif
break;
case TimeFormatMenu:
TIME_FORMAT = timeFormat[timeFormatIndex];
saveSettings();
@@ -476,6 +490,13 @@ void MenuManager_::selectButtonLong()
DisplayManager.loadNativeApps();
saveSettings();
break;
#ifndef ULANZI
case VolumeMenu:
VOLUME = map(VOLUME_PERCENT, 0, 100, 0, 30);
PeripheryManager.setVolume(VOLUME);
saveSettings();
break;
#endif
default:
break;
}

View File

@@ -1,6 +1,13 @@
#include <PeripheryManager.h>
#ifdef ULANZI
#include <melody_player.h>
#include <melody_factory.h>
#include "Adafruit_SHT31.h"
#else
#include "Adafruit_BME280.h"
#include "SoftwareSerial.h"
#include <DFMiniMp3.h>
#endif
#include "Globals.h"
#include "DisplayManager.h"
#include "MQTTManager.h"
@@ -17,32 +24,39 @@
#define BUTTON_UP_PIN 26
#define BUTTON_DOWN_PIN 14
#define BUTTON_SELECT_PIN 27
#define I2C_SCL_PIN 22
#define I2C_SDA_PIN 21
#else
// Pinouts für das WEMOS_D1_MINI32-Environment
#define BUZZER_PIN -1
#define LDR_PIN A0
#define BUTTON_UP_PIN D0
#define BUTTON_DOWN_PIN D4
#define BUTTON_SELECT_PIN D8
#define BUTTON_DOWN_PIN D8
#define BUTTON_SELECT_PIN D4
#define DFPLAYER_RX D7
#define DFPLAYER_TX D5
#define I2C_SCL_PIN D1
#define I2C_SDA_PIN D3
#endif
#ifdef ULANZI
Adafruit_SHT31 sht31;
#else
class Mp3Notify
{
};
Adafruit_BME280 bme280;
SoftwareSerial mySoftwareSerial(D7, D5); // RX, TX
typedef DFMiniMp3<SoftwareSerial, Mp3Notify> DfMp3;
DfMp3 dfmp3(mySoftwareSerial);
TwoWire I2Cbme280 = TwoWire(0);
#endif
EasyButton button_left(BUTTON_UP_PIN);
EasyButton button_right(BUTTON_DOWN_PIN);
EasyButton button_select(BUTTON_SELECT_PIN);
#ifdef ULANZI
MelodyPlayer player(BUZZER_PIN, LOW);
#else
class Mp3Notify
{
};
SoftwareSerial mySoftwareSerial(DFPLAYER_RX, DFPLAYER_TX); // RX, TX
DFMiniMp3<SoftwareSerial, Mp3Notify> dfmp3(mySoftwareSerial);
#endif
#define USED_PHOTOCELL LightDependentResistor::GL5516
@@ -67,11 +81,6 @@ float sampleSum = 0.0;
float sampleAverage = 0.0;
float brightnessPercent = 0.0;
#ifdef awrtrix_upgrade
class Mp3Notify;
SoftwareSerial mySoftwareSerial(D7, D5); // RX, TX
#endif
// The getter for the instantiated singleton instance
PeripheryManager_ &PeripheryManager_::getInstance()
{
@@ -84,51 +93,53 @@ PeripheryManager_ &PeripheryManager = PeripheryManager.getInstance();
void left_button_pressed()
{
if (AP_MODE)
{
--MATRIX_LAYOUT;
if (MATRIX_LAYOUT < 0)
MATRIX_LAYOUT = 2;
saveSettings();
ESP.restart();
}
else
{
DisplayManager.leftButton();
MenuManager.leftButton();
}
#ifndef ULANZI
PeripheryManager.playFromFile(DFMINI_MP3_CLICK);
#endif
DisplayManager.leftButton();
MenuManager.leftButton();
}
void right_button_pressed()
{
if (AP_MODE)
{
++MATRIX_LAYOUT;
if (MATRIX_LAYOUT > 2)
MATRIX_LAYOUT = 0;
saveSettings();
ESP.restart();
}
else
{
DisplayManager.rightButton();
MenuManager.rightButton();
}
#ifndef ULANZI
PeripheryManager.playFromFile(DFMINI_MP3_CLICK);
#endif
DisplayManager.rightButton();
MenuManager.rightButton();
}
void select_button_pressed()
{
#ifndef ULANZI
PeripheryManager.playFromFile(DFMINI_MP3_CLICK);
#endif
DisplayManager.selectButton();
MenuManager.selectButton();
}
void select_button_pressed_long()
{
DisplayManager.selectButtonLong();
MenuManager.selectButtonLong();
if (AP_MODE)
{
#ifndef ULANZI
++MATRIX_LAYOUT;
if (MATRIX_LAYOUT < 0)
MATRIX_LAYOUT = 2;
saveSettings();
ESP.restart();
#endif
}
else
{
DisplayManager.selectButtonLong();
MenuManager.selectButtonLong();
}
}
void select_button_tripple()
void select_button_double()
{
if (MATRIX_OFF)
{
@@ -147,13 +158,14 @@ void PeripheryManager_::playBootSound()
if (BOOT_SOUND == "")
{
#ifdef ULANZI
// no standard sound
const int nNotes = 6;
String notes[nNotes] = {"E5", "C5", "G4", "E4", "G4", "C5"};
const int timeUnit = 150;
Melody melody = MelodyFactory.load("Bootsound", timeUnit, notes, nNotes);
player.playAsync(melody);
#else
// no standardsound
playFromFile(DFMINI_MP3_BOOT);
#endif
}
else
@@ -161,7 +173,7 @@ void PeripheryManager_::playBootSound()
#ifdef ULANZI
playFromFile("/MELODIES/" + BOOT_SOUND + ".txt");
#else
dfmp3.playMp3FolderTrack(BOOT_SOUND.toInt());
playFromFile(BOOT_SOUND);
#endif
}
}
@@ -171,16 +183,20 @@ void PeripheryManager_::stopSound()
#ifdef ULANZI
player.stop();
#else
dfmp3.stopAdvertisement();
delay(50);
dfmp3.stop();
#endif
}
#ifndef ULANZI
void PeripheryManager_::setVolume(uint8_t vol)
{
#ifdef AWTRIX_UPGRADE
uint8_t curVolume = dfmp3.getVolume(); // need to read volume in order to work. Donno why! :(
dfmp3.setVolume(vol);
#endif
delay(50);
}
#endif
void PeripheryManager_::playFromFile(String file)
{
@@ -199,35 +215,22 @@ bool PeripheryManager_::isPlaying()
#ifdef ULANZI
return player.isPlaying();
#else
return false;
if ((dfmp3.getStatus() & 0xff) == 0x01) // 0x01 = DfMp3_StatusState_Playing
return true;
else
return false;
#endif
}
void fistStart()
{
#ifdef ULANZI
uint16_t ADCVALUE = analogRead(BATTERY_PIN);
BATTERY_PERCENT = min((int)map(ADCVALUE, 490, 690, 0, 100), 100);
BATTERY_RAW = ADCVALUE;
sht31.readBoth(&CURRENT_TEMP, &CURRENT_HUM);
CURRENT_TEMP -= 9.0;
#else
CURRENT_TEMP = bme280.readTemperature();
CURRENT_HUM = bme280.readHumidity();
#endif
uint16_t LDRVALUE = analogRead(LDR_PIN);
brightnessPercent = LDRVALUE / 4095.0 * 100.0;
int brightness = map(brightnessPercent, 0, 100, 10, 120);
DisplayManager.setBrightness(brightness);
}
void PeripheryManager_::setup()
{
startTime = millis();
pinMode(LDR_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
#ifdef AWTRIX_UPGRADE
dfmp3.begin();
delay(100);
setVolume(VOLUME);
#endif
button_left.begin();
button_right.begin();
button_select.begin();
@@ -235,21 +238,21 @@ void PeripheryManager_::setup()
button_right.onPressed(right_button_pressed);
button_select.onPressed(select_button_pressed);
button_select.onPressedFor(1000, select_button_pressed_long);
button_select.onSequence(2, 300, select_button_tripple);
Wire.begin(21, 22);
button_select.onSequence(2, 300, select_button_double);
#ifdef ULANZI
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);
sht31.begin(0x44);
#else
bme280.begin();
I2Cbme280.begin(I2C_SDA_PIN, I2C_SCL_PIN);
bme280.begin(0x76, &I2Cbme280);
dfmp3.begin();
#endif
photocell.setPhotocellPositionOnGround(false);
fistStart();
}
void PeripheryManager_::tick()
{
MQTTManager.sendButton(0, button_left.read());
MQTTManager.sendButton(1, button_select.read());
MQTTManager.sendButton(2, button_right.read());
@@ -268,7 +271,7 @@ void PeripheryManager_::tick()
CURRENT_TEMP = bme280.readTemperature();
CURRENT_HUM = bme280.readHumidity();
#endif
checkAlarms();
// checkAlarms();
MQTTManager.sendStats();
}
@@ -302,78 +305,70 @@ time_t lastAlarmTime = 0;
void PeripheryManager_::checkAlarms()
{
File file = LittleFS.open("/alarms.json", "r");
if (!file)
if (LittleFS.exists("/alarms.json"))
{
return;
}
DynamicJsonDocument doc(file.size() * 1.33);
DeserializationError error = deserializeJson(doc, file);
if (error)
{
Serial.println(F("Failed to read Alarm file"));
return;
}
JsonArray alarms = doc["alarms"];
file.close();
time_t now1 = time(nullptr);
struct tm *timeInfo;
timeInfo = localtime(&now1);
int currentHour = timeInfo->tm_hour;
int currentMinute = timeInfo->tm_min;
int currentDay = timeInfo->tm_wday - 1;
for (JsonObject alarm : alarms)
{
int alarmHour = alarm["hour"];
int alarmMinute = alarm["minute"];
String alarmDays = alarm["days"];
if (currentHour == alarmHour && currentMinute == alarmMinute && alarmDays.indexOf(String(currentDay)) != -1)
File file = LittleFS.open("/alarms.json", "r");
DynamicJsonDocument doc(file.size() * 1.33);
DeserializationError error = deserializeJson(doc, file);
if (error)
{
if (difftime(now1, lastAlarmTime) < MIN_ALARM_INTERVAL)
{
return;
}
Serial.println(F("Failed to read Alarm file"));
return;
}
JsonArray alarms = doc["alarms"];
file.close();
ALARM_ACTIVE = true;
lastAlarmTime = now1;
time_t now1 = time(nullptr);
struct tm *timeInfo;
timeInfo = localtime(&now1);
int currentHour = timeInfo->tm_hour;
int currentMinute = timeInfo->tm_min;
int currentDay = timeInfo->tm_wday - 1;
if (alarm.containsKey("sound"))
{
ALARM_SOUND = alarm["sound"].as<String>();
}
else
{
ALARM_SOUND = "";
}
for (JsonObject alarm : alarms)
{
int alarmHour = alarm["hour"];
int alarmMinute = alarm["minute"];
String alarmDays = alarm["days"];
if (alarm.containsKey("snooze"))
if (currentHour == alarmHour && currentMinute == alarmMinute && alarmDays.indexOf(String(currentDay)) != -1)
{
SNOOZE_TIME = alarm["snooze"].as<uint8_t>();
}
else
{
SNOOZE_TIME = 0;
if (difftime(now1, lastAlarmTime) < MIN_ALARM_INTERVAL)
{
return;
}
ALARM_ACTIVE = true;
lastAlarmTime = now1;
if (alarm.containsKey("sound"))
{
ALARM_SOUND = alarm["sound"].as<String>();
}
else
{
ALARM_SOUND = "";
}
if (alarm.containsKey("snooze"))
{
SNOOZE_TIME = alarm["snooze"].as<uint8_t>();
}
else
{
SNOOZE_TIME = 0;
}
}
}
}
}
const char *PeripheryManager_::readUptime()
const char* PeripheryManager_::readUptime()
{
static char uptime[25]; // Make the array static to keep it from being destroyed when the function returns
unsigned long currentTime = millis();
unsigned long elapsedTime = currentTime - startTime;
unsigned long uptimeSeconds = elapsedTime / 1000;
unsigned long uptimeMinutes = uptimeSeconds / 60;
unsigned long uptimeHours = uptimeMinutes / 60;
unsigned long uptimeDays = uptimeHours / 24;
unsigned long hours = uptimeHours % 24;
unsigned long minutes = uptimeMinutes % 60;
unsigned long seconds = uptimeSeconds % 60;
sprintf(uptime, "P%dDT%dH%dM%dS", uptimeDays, hours, minutes, seconds);
sprintf(uptime, "%lu", uptimeSeconds);
return uptime;
}

View File

@@ -3,12 +3,13 @@
#include <Arduino.h>
#include <EasyButton.h>
#ifdef ULANZI
#include "Adafruit_SHT31.h"
#else
#include "Adafruit_BME280.h"
#include "SoftwareSerial.h"
#include <DFMiniMp3.h>
#ifndef ULANZI
#define DFMINI_MP3_BOOT "1"
#define DFMINI_MP3_ALARM "2"
#define DFMINI_MP3_TIMER "2"
#define DFMINI_MP3_CLICK "5"
#define DFMINI_MP3_CLICK_ON "3"
#define DFMINI_MP3_ENTER "4"
#endif
class PeripheryManager_
@@ -37,7 +38,9 @@ public:
void playFromFile(String file);
bool isPlaying();
void stopSound();
#ifndef ULANZI
void setVolume(uint8_t);
#endif
const char *readUptime();
};

View File

@@ -50,7 +50,7 @@ void ServerManager_::setup()
isConnected = !(myIP == IPAddress(192, 168, 4, 1));
Serial.println(myIP.toString());
Serial.println(isConnected);
if (isConnected)
{
@@ -78,27 +78,29 @@ void ServerManager_::setup()
mws.addJavascript(custom_script);
mws.addHandler("/save", HTTP_POST, saveHandler);
mws.addHandler("/api/notify", HTTP_POST, []()
{DisplayManager.generateNotification(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); });
{ DisplayManager.generateNotification(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); });
mws.addHandler("/api/nextapp", HTTP_POST, []()
{DisplayManager.nextApp(); mws.webserver->send(200,"OK"); });
{ DisplayManager.nextApp(); mws.webserver->send(200,"OK"); });
mws.addHandler("/api/previousapp", HTTP_POST, []()
{DisplayManager.previousApp(); mws.webserver->send(200,"OK"); });
{ DisplayManager.previousApp(); mws.webserver->send(200,"OK"); });
mws.addHandler("/api/timer", HTTP_POST, []()
{ DisplayManager.gererateTimer(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); });
mws.addHandler("/api/notify/dismiss", HTTP_POST, []()
{ DisplayManager.dismissNotify(); mws.webserver->send(200,"OK"); });
mws.addHandler("/api/apps", HTTP_POST, []()
{ DisplayManager.updateAppVector(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); });
{ DisplayManager.updateAppVector(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); });
mws.addHandler("/api/switch", HTTP_POST, []()
{ DisplayManager.switchToApp(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); });
{ DisplayManager.switchToApp(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); });
mws.addHandler("/api/loop", HTTP_GET, []()
{ mws.webserver->sendContent(DisplayManager.getAppsAsJson()); });
mws.addHandler("/api/settings", HTTP_POST, []()
{ DisplayManager.setNewSettings(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); });
{ DisplayManager.setNewSettings(mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); });
mws.addHandler("/api/custom", HTTP_POST, []()
{ DisplayManager.generateCustomPage(mws.webserver->arg("name"),mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); });
{ DisplayManager.generateCustomPage(mws.webserver->arg("name"),mws.webserver->arg("plain").c_str()); mws.webserver->send(200,"OK"); });
mws.addHandler("/api/stats", HTTP_GET, []()
{ mws.webserver->sendContent(DisplayManager.getStat()); });
mws.addHandler("/api/doupdate", HTTP_POST, []()
{ if (UPDATE_AVAILABLE)
{ if (UPDATE_AVAILABLE)
UpdateManager.updateFirmware(); mws.webserver->send(200,"OK"); });
Serial.println("Webserver loaded");
}

View File

@@ -8,8 +8,13 @@
#include <Ticker.h>
#include "Globals.h"
#ifdef ULANZI
#define URL_fw_Version "https://raw.githubusercontent.com/Blueforcer/awtrix-light/main/version"
#define URL_fw_Bin "https://raw.githubusercontent.com/Blueforcer/awtrix-light/main/docs/flasher/firmware/firmware.bin"
#else
#define URL_fw_Version "todo"
#define URL_fw_Bin "todo"
#endif
Ticker UpdateTicker;

View File

@@ -50,7 +50,7 @@ void BootAnimation(void *parameter)
{
break;
}
DisplayManager.HSVtext(4, 6, "AWTRIX", true);
DisplayManager.HSVtext(4, 6, "AWTRIX", true, 0);
vTaskDelay(xDelay);
}
vTaskDelete(NULL);
@@ -58,18 +58,19 @@ void BootAnimation(void *parameter)
void setup()
{
PeripheryManager.setup();
delay(1000);
Serial.begin(9600);
pinMode(15, OUTPUT);
digitalWrite(15, LOW);
delay(2000);
loadSettings();
Serial.begin(115200);
PeripheryManager.setup();
ServerManager.loadSettings();
DisplayManager.setup();
DisplayManager.HSVtext(9, 6, VERSION, true);
delay(500);
PeripheryManager.playBootSound();
xTaskCreatePinnedToCore(BootAnimation, "Task", 10000, NULL, 1, &taskHandle, 1);
ServerManager.setup();
DisplayManager.HSVtext(9, 6, VERSION, true, 0);
PeripheryManager.playBootSound();
xTaskCreatePinnedToCore(BootAnimation, "Task", 10000, NULL, 1, &taskHandle, 0);
ServerManager.setup();
if (ServerManager.isConnected)
{
MQTTManager.setup();
@@ -80,10 +81,10 @@ void setup()
float x = 4;
while (x >= -85)
{
DisplayManager.HSVtext(x, 6, ("AWTRIX " + ServerManager.myIP.toString()).c_str(), true);
DisplayManager.HSVtext(x, 6, ("AWTRIX " + ServerManager.myIP.toString()).c_str(), true, 0);
x -= 0.18;
}
// BeaconScanner.setup();
}
else
{
@@ -92,6 +93,7 @@ void setup()
}
delay(200);
DisplayManager.setBrightness(BRIGHTNESS);
DisplayManager.clearMatrix();
}