From c0d815cdcfd79d9fc877736e0f2869ab87305941 Mon Sep 17 00:00:00 2001 From: engmung <122682380+engmung@users.noreply.github.com> Date: Sat, 3 Oct 2026 11:51:29 +0900 Subject: [PATCH 01/10] firmware: a pattern that has run stays loaded and comes back at once An installed module was unloaded whenever another pattern took the panel, so every return paid a whole load: FAT read, relocation, constructors and setup() - 25-100 ms for most of the catalogue, 3.3 s for Branched Flow, 4.1 s for Two Stream, 0.6 s for Burgers and Wave Cascade. A module that holds no internal RAM is now parked in PSRAM when it is left (src/core_module_resident.h: 16 slots, LRU) and resumed on the loop task when it is picked again - no read, no relocation, no setup(), carrying on from its own state the way compiled-in presets always have. SELECT switches to a preset or a parked module on the detent and shows it live. So that modules are parkable, data sections go to PSRAM first, as code already did (PF_MODULE_DATA_PSRAM_FIRST; follows PF_MODULE_RESIDENT_MAX). A-B-B-A on two boards, 16 module runs: 13 within noise (-1.1..+0.8 %), Burgers +2.6 %, Wave Cascade +2.2 %, Breakout +0.85 %; internal heap with a module running +4..10 KB. Parked modules give way: before a fresh load until PSRAM free >= the 4 MB per-module runtime limit + 512 KB, on every module allocation while anything is parked until 512 KB stays free, on a refused allocation, before the loader's retries, and on any install/replace/delete (a storage generation bumped by every module-file writer, including ones that do not capture). Hardware (Audio edition, .217 and .246): every revisit resumed in 85-210 us; internal heap flat with 12-13 modules parked; an upload emptied the table and PSRAM came back by exactly the parked 683 KB; five 1.5 MB probes held the floor (PSRAM never under ~3.1 MB, 0 refusals); random soaks of 300 and 200 switches, 0 resets. Checked by hand in SELECT. Static DRAM +112..120 B per edition (re-pinned), IRAM unchanged. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/firmware-checks.yml | 2 +- CHANGELOG.md | 8 + docs/EDITIONS.md | 9 +- docs/rest-api.md | 8 +- firmware/CUSTOM_PATTERNS.md | 6 + firmware/README.md | 50 +- firmware/patternflow/pattern_registry.h | 146 +++-- firmware/patternflow/patternflow.ino | 27 +- firmware/patternflow/src/core_module_loader.h | 367 ++++++++++++- firmware/patternflow/src/core_module_memory.h | 77 ++- .../patternflow/src/core_module_resident.h | 258 +++++++++ firmware/patternflow/src/core_patterns_http.h | 20 + firmware/patternflow/src/core_status_http.h | 18 +- firmware/toolchain/check_footprint.py | 16 +- firmware/toolchain/check_runtime.py | 60 +- firmware/toolchain/tests/resident_test.cpp | 512 ++++++++++++++++++ firmware/toolchain/tests/runtime_test.cpp | 234 +++++++- 17 files changed, 1712 insertions(+), 106 deletions(-) create mode 100644 firmware/patternflow/src/core_module_resident.h create mode 100644 firmware/toolchain/tests/resident_test.cpp diff --git a/.github/workflows/firmware-checks.yml b/.github/workflows/firmware-checks.yml index 6f1a8be8..9d92b4ec 100644 --- a/.github/workflows/firmware-checks.yml +++ b/.github/workflows/firmware-checks.yml @@ -97,7 +97,7 @@ jobs: run: python firmware/toolchain/check_thumbs.py --sanitize - name: Wi-Fi and name-service recovery run: python firmware/toolchain/check_network.py --sanitize - - name: Runtime admission and frame-boundary lifecycle + - name: Runtime admission, resident modules and frame-boundary lifecycle run: python firmware/toolchain/check_runtime.py --sanitize - name: Crash record tells this reset's dump from an older one run: python firmware/toolchain/check_crash.py --sanitize diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a051000..1730d480 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to Patternflow will be documented in this file, newest first ## [Unreleased] +### Firmware + +- **Going back to a pattern no longer loads it again.** An installed pattern (a `.pfm` module) was unloaded the moment another pattern took the panel, so every return paid for a whole load: reading the file, relocating it, its constructors and its own `setup()`. For most of the catalogue that is 25-100 ms; for the heavy ones it was the pause you could see - Branched Flow 3.3 s, Two Stream 4.1 s, Burgers and Wave Cascade 0.6 s each. A module that has run now stays loaded in PSRAM ("parked") when another pattern takes over, and picking it again resumes it: nothing is read or relocated, `setup()` does not run again, and the pattern carries on from where it was, as the built-in presets always have. Measured on two boards, a return takes 115-197 µs. Picked while another pattern is still loading, it comes back once that load is done; picked during an install, it is loaded afresh afterwards, because an install empties what is parked. Up to 16 modules stay parked (`PF_MODULE_RESIDENT_MAX`; `0` turns this off). +- **SELECT shows patterns that are already in memory live.** A preset or a parked module comes on as the knob reaches it and runs behind the overlay instead of showing its thumbnail, as long as the pattern being left can be kept too. A pattern that has to be loaded still waits for the knob to rest. +- **A module's data now goes to PSRAM first, as its code already did.** Only a module that holds no internal RAM at all is kept, so the console and Wi-Fi give up nothing for parked patterns. Measured A-B-B-A on two boards: 13 of 16 module runs within noise (-1.1..+0.8%), Burgers +2.6% (38.9 -> 39.9 ms a frame), Wave Cascade +2.2%, Breakout Arcade +0.85%; in exchange 4-6 KB more internal heap with a module running, up to 9.9 KB. +- **Parked patterns give their memory back.** Least recently used first, whenever a new load would otherwise start with less than 4.5 MB of PSRAM free (the most one pattern may allocate, plus 512 KB), and whenever a running pattern's own allocation would leave less than 512 KB. A pattern installed, replaced or deleted - from the console, or by a feature that installs patterns - is never resumed from the old file. Checked on two boards with 12-13 modules parked: internal heap stayed flat, an install emptied the table and PSRAM came back by exactly the parked bytes (683 KB), and with five 1.5 MB test modules PSRAM never fell under about 3.1 MB free, with no refused load. `/api/status` gains `load.resumed`, `load.resumeUs` and `moduleMemory.resident`. +- **What this takes away:** a pattern that wants a fresh start every time it is picked cannot have one. `setup()` runs once per load, as `firmware/CUSTOM_PATTERNS.md` now says. + ## [3.10.5] - 2026-10-02 ### Firmware diff --git a/docs/EDITIONS.md b/docs/EDITIONS.md index a4469d33..fab3a183 100644 --- a/docs/EDITIONS.md +++ b/docs/EDITIONS.md @@ -261,7 +261,14 @@ Four rules that are not negotiable: panel is not being drawn while it runs. - **Buffers of 1 KB or more go through `PFMem`** (PSRAM). Internal heap is the scarcest thing on the board and it is what caps how big a loadable pattern - can be. + can be. PSRAM is plentiful but shared: patterns that have run stay parked in + it (`src/core_module_resident.h`), and they give way to patterns, not to + you. While any is parked, the core keeps `PF_MODULE_RESIDENT_HEADROOM` + (512 KB) free whenever one is parked and after every allocation a pattern + makes, and evicts parked ones to do it, but your own allocation evicts nothing: it gets what is free, + which can then be as little as those 512 KB less whatever other features + and the console took from them. Your `setup()` runs at boot, before anything + is parked, so take big buffers there, not on first use hours later. - **Never edit a core file.** Your entire diff is additions. That is what makes taking a core update a file copy rather than a merge, and it is the whole reason the seam exists. diff --git a/docs/rest-api.md b/docs/rest-api.md index 965176fb..05a4ff88 100644 --- a/docs/rest-api.md +++ b/docs/rest-api.md @@ -94,7 +94,7 @@ The numbers that explain a device when something is off. Requires `PF_STATUS_HTT | `busy` | Since 1.5. What is keeping the one connection occupied, as a word to slow polling for: `"update"` while a firmware image is arriving or the reboot after it is due, `"storage"` while the pattern volume is being written (a format, a delete, or an install batch between files), `""` otherwise. The console polls no faster than every 5 s while it is non-empty. | | `frameUs` / `presentUs` | Smoothed rendered-frame time and the part spent pushing pixels. `1e6 / frameUs` estimates rendering fps; it excludes housekeeping and is not an input-latency or worst-loop-gap measurement. | | `runtime` | Since 1.5. Whole-loop `loops`, `lastUs`, `maxUs`, `over50ms`; `housekeepingMaxUs` includes work before the rendered-frame timer, and `syncMaxUs` measures execution of a frame-boundary request, excluding time its caller waits. Timing includes loading-state pacing, but excludes time between exiting one loop and entering the next. `GET /api/status?resetTiming=1` returns the current runtime snapshot and starts a new timing window; a loop spanning the reset is discarded. This resets only `runtime`, not lifetime network/load counters. | -| `moduleMemory` | Since 1.5. `reserve` is the module allocator's internal byte-addressable RAM floor, not a guarantee about allocations by other subsystems. `serviceFree` is current internal byte-addressable free RAM; `execLargest` is the largest contiguous executable block. `runtimeBytes` and lifetime `runtimePeakBytes` track retained module dynamic allocations; `runtimeLimit` defaults to 4 MiB. Sections and temporary ELF storage are admitted separately. `refusals` counts allocation refusals, including recovered attempts; `loaderRetries` counts the asynchronous loader's bounded retries after such failures. `loaderStackBytes` reports the reusable worker's reserved stack, and `loaderStackMin` is its minimum free space after jobs (0 until measured). | +| `moduleMemory` | Since 1.5. `reserve` is the module allocator's internal byte-addressable RAM floor, not a guarantee about allocations by other subsystems. `serviceFree` is current internal byte-addressable free RAM; `execLargest` is the largest contiguous executable block. `runtimeBytes` and lifetime `runtimePeakBytes` track retained module dynamic allocations; `runtimeLimit` defaults to 4 MiB. Sections and temporary ELF storage are admitted separately. `refusals` counts allocation refusals, including recovered attempts; `loaderRetries` counts the asynchronous loader's bounded retries after such failures. `loaderStackBytes` reports the reusable worker's reserved stack, and `loaderStackMin` is its minimum free space after jobs (0 until measured). `resident` (since 1.5) describes the modules kept loaded after another pattern took over, so picking one again resumes it instead of loading it: `count` parked now, `bytes` of PSRAM they hold (sections plus their own allocations), `slots` the most that may be parked (`PF_MODULE_RESIDENT_MAX`, 16; `0` when residency is compiled out), and boot counters `resumes` and `evictions`. A parked module holds no internal RAM - one that does is unloaded instead. Parked modules are evicted least recently used first whenever a fresh load would otherwise start with less than `runtimeLimit` plus 512 KiB of PSRAM free, and whenever a running module's own allocation would leave less than 512 KiB free or finds PSRAM full; they do not make way for allocations by features or the core. All of them go at once before a refused load is retried and when an upload, delete or format begins. A module loaded before any module file was last written - by those, or by a feature installing a pattern - is never resumed: parked, it is evicted at the next chance; running, it is unloaded when left, and at the list rebuild that follows the write. | | `netMaintenance` | Since 1.5. Lifetime `calls` and `maxGapMs` for the Wi-Fi/name maintenance hook on the network worker. It runs approximately every 25 ms when serviced, including page-body sends and parser/loop-request waits. Other blocking work, including filesystem calls, can still produce longer gaps. | | `loopCore` / `httpCore` | Which core renders (1) and which answered this request — `0` on 3.9.1 and later, `1` when the network task could not be created and `loop()` is serving. | | `loopStackMin` | Since 1.5: the same for the loop task, which runs every pattern's `draw()` and the panel blit inside it. | @@ -103,9 +103,9 @@ The numbers that explain a device when something is off. Requires `PF_STATUS_HTT | `loopAgeMs` / `loopStalled` / `loopSyncGaveUp` | Since 1.5. Milliseconds since `loop()` was last at its frame boundary, read without the loop's help — a frame or two on a running panel. `loopStalled` turns `true` at 20 s (`PF_LOOP_STALL_MS`): the render loop has not come round, which in practice is a pattern that never returns from `draw()` — `active` names it. It can also be a healthy loop held up: with the internet down one feature lookup holds the loop 14 s, two features' lookups in the same iteration (Performance: weather and an MQTT broker named by host) 28-30 s, and a TLS handshake longer still, so `true` there is not yet a hang. What tells a hang from a loop that is only held up is the next poll: a hung loop's age has grown by exactly the time between the two, a busy one's is back to a few milliseconds with `loopStalled` `false` (`runtime.maxUs` is the longest it has been held since boot). The panel holds its last frame; this endpoint and `POST /api/wifi/reboot` keep answering, as does `/update` while it is armed without the UPDATE screen (the default), and every route that waits for the loop answers `503` (see *Conventions*). Two limits: the console's routes are registered by the loop on the first network link, so a loop that hangs before the panel has ever joined a network or raised its hotspot has no console to outlive it; and routes that only queue work for the loop - `POST /api/params`, `/api/sleep`, a brightness change - still answer `ok` on such a panel and do nothing until it returns. `loopSyncGaveUp` counts the requests refused that way. Nothing reboots the panel on its own, and a reboot goes back to the remembered pattern unless that pattern hung within 15 s of the boot that restored it — pick another one before it hangs again. | | `colorBits` / `refreshHz` | What the HUB75 driver actually settled on — it trades colour depth against the requested refresh rate, so these are read back rather than configured. | | `loadError` | Why the last module load failed, empty when it did not. Without it a refusal is invisible from the network. | -| `loading` | `true` while a module is being loaded on the network core (since 1.4 a switch no longer holds the frame; a heavy pattern's `setup()` takes seconds). `active` reads `"-"` meanwhile. | +| `loading` | `true` while a module is being loaded on the network core (since 1.4 a switch no longer holds the frame; a heavy pattern's `setup()` takes seconds). `active` reads `"-"` meanwhile. Since 1.5 a module that is still parked (`moduleMemory.resident`) comes back without `loading`, in the frame it is picked - when no load is in flight and no upload, delete or format is holding pattern switches. Picked during either, it is applied once that is over: resumed if it is still parked then, loaded if not (an upload, delete or format evicts every parked module). | | `thumbs` | Since 1.5: boot counters `captures` (cache refreshed), `reads` (disk image adopted), `writes` (save completed). `captureMaxUs` is the maximum loop-side capture duration; `ioMaxUs` is the maximum background file-operation wall time, including scheduling/filesystem contention. Both are µs. The cache and its temporary I/O snapshot use PSRAM only. | -| `load` | The last module load, in µs: `total`, `read` (flash), `relocate`, `setup` (the pattern's own). Since 1.4 also where its sections landed, in bytes: `internal` and `psram`. A big `internal` is the number to look at when the console dies the moment a pattern is chosen — the loader now sends data sections over 16 KB, or any that would leave under 24 KB of internal heap, to PSRAM (`PF_MODULE_DATA_INTERNAL_MAX`, `PF_MODULE_INTERNAL_RESERVE`). Since 1.5 `code` says where the module's code runs from, `"psram"` or `"internal"`: in PSRAM it is counted in `psram` and takes nothing from the internal heap, and `"internal"` on a module means PSRAM could not hold it or `moduleMemory.codePolicy` is `0` - which it becomes, until reboot, if code placed in PSRAM ever fails to read back on this unit. | +| `load` | The last module load, in µs: `total`, `read` (flash), `relocate`, `setup` (the pattern's own). Since 1.4 also where its sections landed, in bytes: `internal` and `psram`. A big `internal` is the number to look at when the console dies the moment a pattern is chosen — the loader now sends data sections over 16 KB, or any that would leave under 24 KB of internal heap, to PSRAM (`PF_MODULE_DATA_INTERNAL_MAX`, `PF_MODULE_INTERNAL_RESERVE`). Since 1.5 `code` says where the module's code runs from, `"psram"` or `"internal"`: in PSRAM it is counted in `psram` and takes nothing from the internal heap, and `"internal"` on a module means PSRAM could not hold it or `moduleMemory.codePolicy` is `0` - which it becomes, until reboot, if code placed in PSRAM ever fails to read back on this unit. Since 1.5 data sections go to PSRAM first as well, whatever their size, so `internal` is `0` on a module that loaded normally. Since 1.5 `load` describes the module on the panel: `resumed` is `true` when it came back from residency rather than from a load - the timings are then its own, from when it first loaded, and nothing was read or set up this time - and `resumeUs` is what coming back took; `false` and `0` after a fresh load. With no module on the panel (a preset, or a load that failed) `internal` and `psram` are `0`, `code` reads `"internal"`, `resumed` is `false` and `resumeUs` `0`; the timings are left as the last module had them - except after a failed load, where `read`, and `relocate` if the load got that far, describe the attempt that failed. | | `variant` | Which firmware this is: `"core"`, or a variant's own name. What the site's variant list matches, and what stops the update banner offering a core build on top of someone's chosen firmware. | | `caps` | What this build can do. **Probe this rather than assuming a feature exists.** The default build reports `["patterns","params","sleep"]` and nothing else; each [edition](EDITIONS.md) adds its own — Audio adds `osc` and `audio`, Performance adds `weather`, `mqtt` and `shows`. `patterns` and `params` are on every build. | | `mqttRole` | `"off"`, `"publisher"` or `"subscriber"`. Decides whether the device obeys knob and pattern topics — see [Knobs](#knobs-and-parameters). | @@ -535,7 +535,7 @@ In short: HTTP is the management and state transport, OSC and MIDI are the low-l ## Version history -- **1.5** (unreleased) — the hotspot (`hotspot` in status, `GET`/`POST /api/hotspot`); status gains `network` and `thumbs` diagnostics, `fsError` (why storage is not mounted) and `flashId`; a failed `POST /api/patterns/format` returns the reason as its `error`; `POST /api/wifi/reconnect` reconnects without a reboot; core name registration retries partial failures and preserves feature-owned services; the MIDI edition adds a `midiUsb` block to status ([`midi-spec.md`](midi-spec.md)); `GET`/`POST /api/knobs` and the `/knobs` page (encoder direction and edges per click, per knob, persisted); `PUT /update` takes a raw image, and an upload survives a stall of up to two minutes; `GET /api/wifi` gains `join` (what became of the last network asked for) and `GET /api/hotspot` gains `seen` (the names in range); a network added on the hotspot with no station link is tried at once; console pages are cached by build (`?v=` immutable, bare URLs `no-cache` with an `ETag` and `304`, another build's `v` redirected with `302`), the chrome by its CRC (`?h=`), only for a `Host` that can only be the panel; `GET /favicon.ico` answers `204`; status gains `build`, `viaHotspot` and `busy`; `load` gains `code` (where the module's code runs from); pattern names in `GET /api/patterns` and `/api/patterns/select` are JSON-escaped, so a quote or backslash in a title no longer makes the reply unparseable; a multipart request that stops mid-form is dropped - the connection is closed with no reply - instead of spinning the server into its watchdog, and leaves none of its fields behind for later requests; `moduleMemory` gains `codePolicy`; status gains `loopStackMin`; the hotspot password is JSON-escaped in `/api/hotspot`; a `POST` that is not multipart to `/api/patterns` or `/update` is answered instead of crashing the panel, a multipart boundary longer than 70 characters is refused, and a raw `PUT` sees its own query string; status gains `crash` (the core dump's summary, and the pattern and phase the reset interrupted) and `DELETE /api/crash` clears it; status gains `loopAgeMs`, `loopStalled` and `loopSyncGaveUp`, and a route that needs the render loop answers `503` (`render loop is not answering`) when a pattern never returns from `draw()`, where it used to take the whole server down with it. +- **1.5** (unreleased) — the hotspot (`hotspot` in status, `GET`/`POST /api/hotspot`); status gains `network` and `thumbs` diagnostics, `fsError` (why storage is not mounted) and `flashId`; a failed `POST /api/patterns/format` returns the reason as its `error`; `POST /api/wifi/reconnect` reconnects without a reboot; core name registration retries partial failures and preserves feature-owned services; the MIDI edition adds a `midiUsb` block to status ([`midi-spec.md`](midi-spec.md)); `GET`/`POST /api/knobs` and the `/knobs` page (encoder direction and edges per click, per knob, persisted); `PUT /update` takes a raw image, and an upload survives a stall of up to two minutes; `GET /api/wifi` gains `join` (what became of the last network asked for) and `GET /api/hotspot` gains `seen` (the names in range); a network added on the hotspot with no station link is tried at once; console pages are cached by build (`?v=` immutable, bare URLs `no-cache` with an `ETag` and `304`, another build's `v` redirected with `302`), the chrome by its CRC (`?h=`), only for a `Host` that can only be the panel; `GET /favicon.ico` answers `204`; status gains `build`, `viaHotspot` and `busy`; `load` gains `code` (where the module's code runs from); pattern names in `GET /api/patterns` and `/api/patterns/select` are JSON-escaped, so a quote or backslash in a title no longer makes the reply unparseable; a multipart request that stops mid-form is dropped - the connection is closed with no reply - instead of spinning the server into its watchdog, and leaves none of its fields behind for later requests; `moduleMemory` gains `codePolicy`; status gains `loopStackMin`; the hotspot password is JSON-escaped in `/api/hotspot`; a `POST` that is not multipart to `/api/patterns` or `/update` is answered instead of crashing the panel, a multipart boundary longer than 70 characters is refused, and a raw `PUT` sees its own query string; status gains `crash` (the core dump's summary, and the pattern and phase the reset interrupted) and `DELETE /api/crash` clears it; status gains `loopAgeMs`, `loopStalled` and `loopSyncGaveUp`, and a route that needs the render loop answers `503` (`render loop is not answering`) when a pattern never returns from `draw()`, where it used to take the whole server down with it; a module that has run stays loaded when another pattern takes over and resumes when picked again - `load` gains `resumed` and `resumeUs`, `moduleMemory` gains `resident`, and a module's data sections go to PSRAM first. - **1.4** (2026-09-06) — `GET /api/patterns/file` gains `ext=thumb`; `GET /api/display` takes `brightness` and status reports it; status gains `resetReason` and `load.internal`/`load.psram`; console pages are served gzip-compressed (`Content-Encoding: gzip`); the page sender no longer truncates on a slow link; the server no longer trips the Core-0 watchdog on a request that stalls mid-header. - **1.3** (2026-09-04) — `GET`/`POST /api/clock` (Utility edition) and the `clock` block in status; `caps` gains `"clock"`. - **1.2** (2026-09-03) — the server is serviced on Core 0 (the one-connection rule stands; the render-pays rule is history); status gains `httpCore`, `netStackMin`, `loopSyncServed`/`loopSyncMaxUs`; `POST /api/params` documents `d1`..`d4` and how a held value reaches a legacy pattern; `GET /api/patterns/select` gains `step`; `GET`/`POST /api/audio` (Audio-React) are documented; `featureNav`'s microphone label is *Audio*. diff --git a/firmware/CUSTOM_PATTERNS.md b/firmware/CUSTOM_PATTERNS.md index 84a03744..02c0ae85 100644 --- a/firmware/CUSTOM_PATTERNS.md +++ b/firmware/CUSTOM_PATTERNS.md @@ -103,6 +103,12 @@ One class of pattern deserves a note because it used to look impossible: anythin Note that the score measures the *JavaScript* as written — the C++ conversion prompt ships a decision table of firmware fast paths (precomputed per-pixel radius/angle tables for fixed-center patterns, `PFMath::fastAtan2`, cell-hash and pow LUTs), so a HIGH-scoring radial pattern often converts to cheap C++ anyway. Treat the score as pressure, not a wall. +### When `setup()` runs + +Once per load, before the first frame — which is why it is the place for the tables above. It does not run when the pattern is picked again. An installed pattern that has run stays loaded when the panel switches to something else, and coming back to it resumes it where it was: its variables, its buffers and its animation carry on as they were left, the way the compiled-in presets have always behaved. The first `update()` after a return gets an ordinary frame's `dt`, not the time it was away. + +So write `setup()` to prepare, not to reset. A pattern that wants a fresh start every time it is picked cannot have one today: nothing tells it that it was just selected, and `setup()` runs again only when the pattern is loaded again — after a reboot, after patterns were installed or deleted, or when the board needed the memory back. If a reset matters, give it a knob press (`input.btnPressed[i]` in `update()`). And keep anything the pattern needs from one frame to the next in its own variables or buffers: the canvas holds whatever was drawn last, which after a return is another pattern's frame. + --- ## Installing your pattern diff --git a/firmware/README.md b/firmware/README.md index a2bdfa81..7652c57a 100644 --- a/firmware/README.md +++ b/firmware/README.md @@ -248,8 +248,13 @@ service reserve to module allocations, including PSRAM-to-internal fallbacks. Admission checks the relevant largest block and rechecks service RAM after an allocation. Executable IRAM is not presumed interchangeable with byte RAM. This protects against module allocations consuming the reserve; unrelated -system/feature allocations can still reduce free memory. Large data prefers -PSRAM; small data can remain internal. Module dynamic allocations keep their +system/feature allocations can still reduce free memory. Data goes to PSRAM +first since 2026-10, small sections included (they used to stay internal while +the budget allowed): that is what lets a module be parked holding no internal +RAM. Measured A-B-B-A on two boards, most modules' frame time did not move +(-1.1..+0.8 %); small per-pixel state arrays now read through the PSRAM cache +cost Burgers +2.6 % and Wave Cascade +2.2 %. `PF_MODULE_DATA_PSRAM_FIRST 0` +puts the old placement back. Module dynamic allocations keep their 16-slot, unload-as-a-group lifetime and add a configurable 4 MiB limit (`PF_MODULE_RUNTIME_MAX_BYTES`); `moduleMemory` reports usage and refusals. @@ -395,11 +400,25 @@ libm hooks). A module is compiled freestanding against `abi/pf_module.h` only — never against Arduino or the HUB75 driver — and partially linked with `toolchain/module.ld` so all code lands in one contiguous `.text` with literals inside it. At load time `core_module_loader.h` reads the ELF from -FATFS, allocates executable internal RAM, applies `R_XTENSA_32` relocations, +FATFS, places it (PSRAM first since 2026-10, its code run through the +instruction-bus alias), applies `R_XTENSA_32` relocations, resolves libm/libgcc against the host's own symbols, runs `.init_array` (so C++ global constructors work), syncs the instruction cache, and calls the -module's entry point. Switching away unloads it; one module is resident at a -time. +module's entry point. One module runs at a time. Switching away parks it: a +module that has run stays loaded in PSRAM, and picking it again resumes it in +the frame it is picked — no read, no relocation, no second `setup()` — the +way a compiled-in preset resumes (115–197 µs, measured on two boards). That +is when no other load is in flight and no upload, delete or format is holding +pattern switches; picked during either, it comes in once that is over — +resumed if it is still parked, loaded if an install has emptied the table. +Up to 16 are kept (`PF_MODULE_RESIDENT_MAX` in `src/core_module_memory.h`; +`src/core_module_resident.h` has the rules), only modules that hold no +internal RAM, and they are evicted least recently used first when a new load +or a running pattern needs the PSRAM — until a pattern's allocation leaves +at least 512 KB free, `PF_MODULE_RESIDENT_HEADROOM`; a feature's allocation +evicts nothing — and all at once when patterns are installed or deleted. A +module loaded before its file was replaced — by the console or by a feature — +is never resumed from the old file. **Converting an existing pattern header:** @@ -429,7 +448,7 @@ surface — the math headers are literally the same files, included with | Switch latency (7.5 KB module) | 6.0 ms = read 4.4 + relocate 0.6 + setup 1.0 | | Switch latency (22 KB module) | 10.9 ms — still under one 60 fps frame | | Runtime speed vs the same source compiled in | **~20 % slower** (Origin: 53.4 → 43.5 fps) — the cost of relocatable code (`-mlongcalls`); not fixable by `-O2` (~2 %) or memory placement | -| Comfortable module size | ~32 KB of statics on a core 2.x build — measured: 0–64 KB of static tables all render at the same 62 fps, they just spend heap. (The old "≲ 8 KB, then `.rodata` spills to PSRAM and ~14 fps" figure was the core 3.x build's 7.7 KB largest block talking; see [Required board package](#required-board-package).) | +| Comfortable module size | ~32 KB of statics on a core 2.x build — measured: 0–64 KB of static tables all render at the same 62 fps. They spend PSRAM since 2026-10, not internal heap: statics go to PSRAM first, which costs most modules nothing measurable and a few with small per-pixel state arrays 2–3 % (Burgers +2.6 %, Wave Cascade +2.2 %; `PF_MODULE_DATA_PSRAM_FIRST 0` puts small statics back in internal RAM). (The old "≲ 8 KB, then `.rodata` spills to PSRAM and ~14 fps" figure was the core 3.x build's 7.7 KB largest block talking; see [Required board package](#required-board-package).) | | Panel size | Baked in at build (`-DPF_PANEL_W/H`); the loader rejects a mismatch | | ABI | `PF_ABI_VERSION` must match; bump it on ANY layout change in `pf_abi.h` and rebuild every module | @@ -467,19 +486,22 @@ Installing costs nothing at runtime. The registry allocates its arrays at full capacity on boot, in PSRAM, whether or not the modules exist — so five installed modules and 128 installed modules use exactly the same RAM. Only the **resident** module costs internal RAM, and unloading returns all of it -(measured: 4,548 B free with a module resident → 11,692 B on a preset). +(measured: 4,548 B free with a module resident → 11,692 B on a preset). Since +2026-10 a module's code and data both go to PSRAM first, so a module that +loaded normally costs no internal RAM at all, and a module kept loaded after +being left (parked, see above) only ever holds PSRAM. | Limit | Value | Binding? | |---|---|---| | Installed modules | **128** (`MAX_MODULE_PATTERNS`) | The only real cap, and it is a UX choice — 136 B of PSRAM per slot, 17 KB total | | Storage | ~1,500 modules (10.2 MB partition, 5.9 KB median) | No — 12× the count cap | -| Per-module RAM | ~32 KB of statics comfortable on a core 2.x build (0–64 KB measured at identical fps; the old ≲ 8 KB figure was the core 3.x heap talking) | Heap only — frame rate does not move | -| Concurrent modules | 1 | By design — one pattern is selected at a time | +| Per-module RAM | ~32 KB of statics comfortable on a core 2.x build (0–64 KB measured at identical fps; the old ≲ 8 KB figure was the core 3.x heap talking) | PSRAM since 2026-10. Frame rate mostly does not move; a few modules whose small per-pixel arrays used to sit in internal RAM run 2–3 % slower (Burgers +2.6 %, Wave Cascade +2.2 %) — `PF_MODULE_DATA_PSRAM_FIRST 0` trades that back for internal heap | +| Concurrent modules | 1 running, up to 16 parked (`PF_MODULE_RESIDENT_MAX`) | By design — one pattern is selected at a time; parked ones hold PSRAM only and give it back to a new load or a running pattern that needs it | -A large module only costs while it is the selected pattern; it has no effect -on the presets or on any other module. On the core 3.x build a resident -module dropped `heapLargest` to ~3 KB — which is what made opening a console -page pause the pattern; on the core 2.x release build the same module leaves +A large module only costs internal RAM while it is the selected pattern, if +at all; it has no effect on the presets or on any other module. On the core +3.x build a resident module dropped `heapLargest` to ~3 KB — which is what +made opening a console page pause the pattern; on the core 2.x release build the same module leaves ~65 KB and the console stays comfortable (the pause-on-open mechanism remains, see the constraints section below). @@ -767,7 +789,7 @@ For the original defaults: Exits on a second K2 longpress, a **K2 click**, or after 8 seconds of idle. - **Encoder 3 longpress (≥1s)** — enter/exit the KNOB MAP screen: it shows which physical knob is which number (front view: K1 top-right, K2 top-left, K3 bottom-right, K4 bottom-left), and turning any knob lights its digit green so each one can be verified without leaving the screen. Knob input is swallowed while it's up, so the pattern underneath never sees it. Exits on a K3 click, a second K3 longpress, or after 8 seconds of idle. -- **Encoder 4 longpress (≥1s)** — enter/exit pattern SELECT mode. In SELECT mode, K4 rotation moves the highlight through the list — three detents per pattern, so a hand does not overshoot — and the panel shows each pattern's **thumbnail** (the frame it last drew, kept from the last time it ran); the highlighted pattern loads once the knob has rested for a third of a second — on the other core, so the knob keeps answering while a heavy pattern's setup runs — then runs live behind the overlay. A pattern that has never run shows nothing but its name until it has. Longpress again to confirm — a choice the knob was still resting on loads right then. +- **Encoder 4 longpress (≥1s)** — enter/exit pattern SELECT mode. In SELECT mode, K4 rotation moves the highlight through the list — three detents per pattern, so a hand does not overshoot — and the panel shows each pattern's **thumbnail** (the frame it last drew, kept from the last time it ran); the highlighted pattern loads once the knob has rested for a third of a second — on the other core, so the knob keeps answering while a heavy pattern's setup runs — then runs live behind the overlay. A pattern already in memory — a preset, or a module still parked from its last run — comes on as the knob reaches it and runs live straight away (unless the pattern being left cannot be kept, when it waits for the knob to rest like any other). A pattern that has never run shows nothing but its name until it has. Longpress again to confirm — a choice the knob was still resting on loads right then. Thumbnail ownership follows the frame boundary too: the loop owns the PSRAM cache, and the existing network task reads/writes one immutable job at a time. diff --git a/firmware/patternflow/pattern_registry.h b/firmware/patternflow/pattern_registry.h index 958ee528..524a8bfa 100644 --- a/firmware/patternflow/pattern_registry.h +++ b/firmware/patternflow/pattern_registry.h @@ -139,6 +139,10 @@ constexpr int MAX_MODULE_PATTERNS = 128; constexpr size_t MODULE_NAME_BYTES = 40; constexpr size_t MODULE_PATH_BYTES = 72; constexpr const char* MODULE_DIR = "/patterns"; +// A parked module is filed under its path (src/core_module_resident.h). A key +// shorter than the path would park two files under one name. +static_assert(PFModuleResident::PATH_BYTES == MODULE_PATH_BYTES, + "the resident table keys on whole module paths"); // These three live in PSRAM, deliberately. // @@ -173,6 +177,12 @@ bool moduleStorageDiagnosed = false; // it touched, so a rebuild reads only what changed. Boot still reads them // all, once. On a board with no PSRAM there is no cache and every rebuild // reads, as before. +// +// Which also makes the two forget calls below the place every writer already +// reports a write, core and feature alike, so they move the pattern storage's +// generation too: a module loaded or parked before it is not resumed from the +// old file afterwards (src/core_module_loader.h, storageGeneration). One +// atomic add, from whatever task wrote; nothing here frees a module. char (*sidecarPaths)[MODULE_PATH_BYTES] = nullptr; char (*sidecarNames)[MODULE_NAME_BYTES] = nullptr; bool* sidecarAbs = nullptr; @@ -186,6 +196,7 @@ inline int sidecarFind(const char* path) { } inline void sidecarForgetPath(const char* path) { + PFModuleLoader::noteStorageWrite(); // before the early return: uncached is still written int i = sidecarFind(path); if (i < 0) return; int last = sidecarCount - 1; @@ -204,7 +215,10 @@ inline void sidecarForgetSlug(const char* slug) { sidecarForgetPath(path); } -inline void sidecarForgetAll() { sidecarCount = 0; } +inline void sidecarForgetAll() { + PFModuleLoader::noteStorageWrite(); + sidecarCount = 0; +} inline void sidecarRemember(const char* path, const char* name, bool absReady) { if (!sidecarPaths) return; @@ -712,9 +726,6 @@ inline void buildPatternList() { } } -// Make `index` the running pattern. Presets were already set up at boot, so -// this only costs anything for a module: read the .pfm, relocate it, run its -// setup(). Returns false if a module failed to load, leaving nothing active. // When the running pattern started running. The sketch's thumbnail capture // wants a pattern to have been on the panel for a few seconds before its // frame is worth keeping - a module's first frames are often its setup. @@ -734,34 +745,71 @@ inline void rememberHeldSelection(int index) { else heldPresetIdx = index; } +// The loaded descriptor is authoritative; the sidecar name was only a guess +// for the selection list. +// Module slot, not pattern index: the list is presets, then any build-service +// custom slots, THEN modules. Subtracting only NUM_PRESETS wrote the loaded +// name into the wrong slot on an image that has custom slots filled — which +// is exactly how a pattern ends up displaying somebody else's name. +inline void adoptModuleName(int index) { + const int moduleSlot = index - (NUM_PRESETS + PF_CUSTOM_SLOT_COUNT); + if (moduleSlot >= 0 && moduleSlot < numModules && PFModuleLoader::active) { + snprintf(moduleNames[moduleSlot], MODULE_NAME_BYTES, "%s", PFModuleLoader::active->name); + } +} + +// A module that is parked (src/core_module_resident.h) comes back here, on +// the loop task, in this frame: the outgoing module is parked or unloaded, +// the parked one becomes the current module, and it carries on from where it +// was - no read, no relocation, no setup(). False when `index` is not parked; +// then the caller loads it. Loop task, no load in flight: the table's owner. +inline bool resumeParked(int index) { + const char* path = patterns[index].modulePath; + if (!path || !PFModuleLoader::isParked(path)) return false; + // Parking the outgoing module into a full table evicts the least recently + // used one, which must not be the one about to come back. + if (PFModuleLoader::active) PFModuleLoader::leave(path); + if (!PFModuleLoader::resume(path)) { + // Only when a write on another task moved the storage generation between + // the two calls (leave() never evicts `path`). The caller then loads the + // file, with nothing current - which is what that write calls for. + activePatternIdx = -1; + return false; + } + adoptModuleName(index); + activePatternIdx = index; + activatedAtMs = millis(); + return true; +} + +// Make `index` the running pattern, synchronously. Presets were set up at +// boot and a parked module resumes, so this only costs anything for a module +// that is not loaded: read the .pfm, relocate it, run its setup(). Returns +// false if a module failed to load, leaving nothing active. The boot restore +// uses this directly; every later switch comes through activatePatternAsync(). inline bool activatePattern(int index) { if (index < 0 || index >= NUM_PATTERNS) return false; if (index == activePatternIdx) return true; const PatternEntry& entry = patterns[index]; if (!entry.modulePath) { - // Hand the module's executable RAM back before running a preset. - if (PFModuleLoader::active) PFModuleLoader::unload(); + // The module this replaces stays loaded if it can (it costs only PSRAM), + // and hands its RAM back if it cannot. + if (PFModuleLoader::active) PFModuleLoader::leave(); activePatternIdx = index; activatedAtMs = millis(); return true; } + if (resumeParked(index)) return true; + if (PFModuleLoader::active) PFModuleLoader::leave(); + PFModuleLoader::makeRoom(); if (!PFModuleLoader::load(FFat, entry.modulePath)) { Serial.printf("[PATTERNS] %s failed: %s\n", entry.modulePath, PFModuleLoader::error()); activePatternIdx = -1; return false; } - // The loaded descriptor is authoritative; the sidecar name was only a guess - // for the selection list. - // Module slot, not pattern index: the list is presets, then any build-service - // custom slots, THEN modules. Subtracting only NUM_PRESETS wrote the loaded - // name into the wrong slot on an image that has custom slots filled — which - // is exactly how a pattern ends up displaying somebody else's name. - const int moduleSlot = index - (NUM_PRESETS + PF_CUSTOM_SLOT_COUNT); - if (moduleSlot >= 0 && moduleSlot < numModules) { - snprintf(moduleNames[moduleSlot], MODULE_NAME_BYTES, "%s", PFModuleLoader::active->name); - } + adoptModuleName(index); activePatternIdx = index; activatedAtMs = millis(); return true; @@ -778,12 +826,19 @@ inline bool activatePattern(int index) { // The read, relocate and setup() run on a task of their own on Core 0 // (the network core, which has the room: the render never leaves Core 1). // The loop task does the two things that touch what a frame is using - -// unloading the outgoing module before the task starts, and adopting the -// incoming one after it finishes - so nothing draws a module that is -// halfway in or out. Between the two the loop draws the incoming pattern's -// thumbnail. One load at a time; a request that arrives while one is in -// flight is remembered, and the LATEST such request is what loads next - -// a knob that moved on through five patterns loads the one it rests on. +// parking or unloading the outgoing module before the task starts, and +// adopting the incoming one after it finishes - so nothing draws a module +// that is halfway in or out. Between the two the loop draws the incoming +// pattern's thumbnail. One load at a time; a request that arrives while one +// is in flight is remembered, and the LATEST such request is what loads next +// - a knob that moved on through five patterns loads the one it rests on. +// +// A module that is parked (src/core_module_resident.h) never comes this way: +// it resumes on the loop task in the frame it is asked for. The table of +// parked modules changes hands with the load - the worker's from the +// release-store of loadInFlight to its release-store of loadFinished, the +// loop's otherwise - which is why nothing below reads it while a load is in +// flight. // // What the task may do concurrently with the frame: allocate (the heap is // locked), read the volume (so is the VFS), write the canvas (a torn @@ -833,6 +888,12 @@ inline void loadPatternJob() { for (uint32_t pause : pauses) { if (ok || PFModuleMemory::refusals == refusals) break; ++patternLoaderRetries; + // A refused load gets everything there is: every parked module goes + // before the retry. A refusal is rare, the floor makeRoom() kept was + // meant to prevent it, and which heap said no is not recorded - evicting + // only helps when it was PSRAM, and costs only re-loads when it was not. + // This worker owns the table until it publishes loadFinished. + PFModuleLoader::dropParked(); vTaskDelay(pdMS_TO_TICKS(pause)); refusals = PFModuleMemory::refusals; ok = PFModuleLoader::load(FFat, patterns[loadTargetIdx].modulePath); @@ -859,10 +920,7 @@ inline bool beginPatternLoader() { inline void finishAsyncLoad() { const int index = loadTargetIdx; if (loadResult) { - const int moduleSlot = index - (NUM_PRESETS + PF_CUSTOM_SLOT_COUNT); - if (moduleSlot >= 0 && moduleSlot < numModules && PFModuleLoader::active) { - snprintf(moduleNames[moduleSlot], MODULE_NAME_BYTES, "%s", PFModuleLoader::active->name); - } + adoptModuleName(index); activePatternIdx = index; activatedAtMs = millis(); } else { @@ -874,9 +932,9 @@ inline void finishAsyncLoad() { __atomic_store_n(&loadInFlight, false, __ATOMIC_RELEASE); } -// Make `index` the running pattern without holding the frame. Presets are -// resident and switch at once; a module switches when its task is done. -// Task creation failure preserves the old module and returns false. +// Make `index` the running pattern without holding the frame. Presets and +// parked modules switch at once; any other module switches when its task is +// done. Task creation failure preserves the old module and returns false. inline bool activatePatternAsync(int index) { if (index < 0 || index >= NUM_PATTERNS) return false; if (patternLoadsHeld) { @@ -890,13 +948,17 @@ inline bool activatePatternAsync(int index) { if (index == activePatternIdx) return true; const PatternEntry& entry = patterns[index]; if (!entry.modulePath) return activatePattern(index); + if (resumeParked(index)) return true; if (!beginPatternLoader()) { return PFModuleLoader::fail("not enough RAM for loader task"); } // The outgoing module leaves here, on the loop task, while nothing is - // drawing it. From this frame on the loop draws the thumbnail. - if (PFModuleLoader::active) PFModuleLoader::unload(); + // drawing it - parked if it can be kept. From this frame on the loop draws + // the thumbnail. Then the parked modules make room for the incoming one, + // the outgoing one last: it is the most recently used. + if (PFModuleLoader::active) PFModuleLoader::leave(); + PFModuleLoader::makeRoom(); activePatternIdx = -1; loadTargetIdx = index; loadResult = false; @@ -926,6 +988,28 @@ inline bool tryFinishAsyncLoad() { return true; } +// Whether `index` is already in memory: a preset, or a parked module. Loop +// task only, and a module is never answered for while a load is in flight - +// the worker owns the table then. +inline bool isResidentOrPreset(int index) { + if (index < 0 || index >= NUM_PATTERNS) return false; + if (!patterns[index].modulePath) return true; + return !loadInFlight && PFModuleLoader::isParked(patterns[index].modulePath); +} + +// What SELECT asks on every detent: does making `index` the running pattern +// cost nothing at all? The target must be in memory, and the pattern it +// replaces must be a preset or a module that will be parked - leaving one +// that cannot be kept would cost its whole load the moment the knob comes +// back to it, which is what waiting for the knob to rest avoids. Never while +// a load is in flight (the switch would only be queued), and never with +// residency compiled out, where SELECT browses exactly as it did before. +inline bool switchesInstantly(int index) { + if (PF_MODULE_RESIDENT_MAX <= 0 || loadInFlight) return false; + if (!isResidentOrPreset(index)) return false; + return !PFModuleLoader::active || PFModuleLoader::parkable(); +} + // ── Naming a pattern from outside the list ─────────────────────────── // Two callers need to talk about a pattern by something other than its index: // MQTT (which addresses patterns by name or slug on the wire) and the sketch's diff --git a/firmware/patternflow/patternflow.ino b/firmware/patternflow/patternflow.ino index 5ab561c8..cb409430 100644 --- a/firmware/patternflow/patternflow.ino +++ b/firmware/patternflow/patternflow.ino @@ -224,13 +224,17 @@ const uint32_t PATTERN_SAVE_DELAY_MS = 3000; bool patternLatchArmed = false; // ── SELECT-mode browsing ──────────────────────────────────────── -// The knob moves the highlight; the pattern loads only once the knob has -// rested for SELECT_SETTLE_MS. Until it does, the panel shows the -// highlighted pattern's thumbnail (src/core_thumbs.h says why: a module's -// setup() can take seconds, and loading on every detent froze the loop for -// that long while the encoder kept counting). A thumbnail is taken when a +// The knob moves the highlight; a pattern that has to be loaded loads only +// once the knob has rested for SELECT_SETTLE_MS. Until it does, the panel +// shows the highlighted pattern's thumbnail (src/core_thumbs.h says why: a +// module's setup() can take seconds, and loading on every detent froze the +// loop for that long while the encoder kept counting). A preset, or a module +// still parked from its last run, costs nothing to switch to, so it becomes +// the running pattern on the detent and runs live behind the overlay +// (switchesInstantly() in pattern_registry.h). A thumbnail is taken when a // pattern is LEFT, provided it has run for THUMB_MIN_RUN_MS and the canvas -// still holds its frame rather than another pattern's thumbnail. +// still holds its frame rather than another pattern's thumbnail - so a knob +// spun past live patterns writes no pictures. const uint32_t SELECT_SETTLE_MS = 350; // Detents per pattern while browsing. One per detent overshot: a hand that // meant one pattern landed two or three along, and once the load stopped @@ -1998,6 +2002,17 @@ void loop() { // left and the choice has stopped moving. notePatternChanged(); Serial.printf("SELECTING: %s\n", patterns[currentPatternIdx].name); + // ...unless switching costs nothing. A preset, or a module still parked + // from its last run (src/core_module_resident.h), is already in memory: + // no read, no setup(), nothing for the loop to wait on. So it becomes + // the running pattern on this detent, and the preview below is live + // instead of a thumbnail. Only when the pattern being left will be kept + // as well - leaving one that cannot be parked costs its whole load the + // moment the knob comes back to it, which is what resting avoids. + if (switchesInstantly(currentPatternIdx)) { + selectPending = false; + if (currentPatternIdx != activePatternIdx) activateWithSnapshot(currentPatternIdx); + } } if (selectPending && (uint32_t)(now - selectMovedAtMs) >= SELECT_SETTLE_MS) { // One attempt per rest: a module that fails to load is not retried diff --git a/firmware/patternflow/src/core_module_loader.h b/firmware/patternflow/src/core_module_loader.h index 81e0fe94..2768e6ea 100644 --- a/firmware/patternflow/src/core_module_loader.h +++ b/firmware/patternflow/src/core_module_loader.h @@ -22,6 +22,7 @@ #include "core_canvas.h" #include "core_crash.h" #include "core_module_memory.h" +#include "core_module_resident.h" #include "core_encoders.h" #include "core_mem.h" #include "core_module_elf.h" @@ -118,8 +119,10 @@ inline LoadedSection sections[MAX_SECTIONS]; inline int sectionCount = 0; // Module data, executable sections and temporary ELF images use the shared -// admission policy in core_module_memory.h. Large data prefers PSRAM; every -// permitted internal fallback preserves the configured service reserve. +// admission policy in core_module_memory.h. Code and data both go to PSRAM +// first (data since 2026-10: PFModuleMemory::dataPsramFirst has what it costs +// a frame, and PF_MODULE_DATA_PSRAM_FIRST 0 puts small data back in internal +// RAM); every permitted internal fallback preserves the service reserve. // Bytes of the resident module's sections in internal RAM and in PSRAM - // /api/status reports them next to the load timing, so "this pattern ate the // console" is a number rather than a hunch. @@ -142,6 +145,96 @@ inline float* tableTheta = nullptr; inline bool tablesReady = false; inline char lastError[128] = {}; +// Bytes of runtimeBytes that came from internal RAM: api->alloc() falls back +// there only when PSRAM refuses, and a module holding any is never parked. +inline uint32_t runtimeInternalBytes = 0; +// The file the current module was loaded from - the key it is parked under. +// A copy, not the registry's pointer: rebuilding the list rewrites the +// registry's path slots, and a parked module filed under whatever its old +// slot names now would be resumed as somebody else. +inline char currentPath[PFModuleResident::PATH_BYTES] = {}; +// Which version of the pattern storage a module was loaded from. +// +// Every writer of a module file moves storageGeneration: looksLikeModule() +// before a .pfm is put in place (an install runs it on the bytes it is about +// to install), and pattern_registry.h's sidecarForgetPath()/sidecarForgetAll() +// once a file has been written, replaced or deleted. The core's own writers +// also empty memory first (captureSelectionOnceNow(), core_patterns_http.h); +// a feature's need not, and does not have to remember to - it already calls +// one of those to keep the sidecar cache honest. A module loaded under an older generation may be the +// file as it was: parked, it is never resumed (isParked() says no, and the +// loop evicts it the next time it owns the table); current, it is unloaded +// when left instead of being parked, and at the list rebuild that follows a +// write (dropStale()). +// +// Moved from any task with one atomic add, and only moved: nothing that +// bumps it frees anything. The loop and the worker read it, and only they +// ever free a module (core_module_resident.h). +inline uint32_t storageGeneration = 0; +inline uint32_t currentGeneration = 0; // the current module's +inline uint32_t storageNow() { return __atomic_load_n(&storageGeneration, __ATOMIC_ACQUIRE); } +inline void noteStorageWrite() { __atomic_add_fetch(&storageGeneration, 1, __ATOMIC_ACQ_REL); } +// Whether the current module came back from residency rather than from a +// load, and what that took. /api/status's load.resumed and load.resumeUs. +inline bool resumed = false; +inline uint32_t lastResumeUs = 0; + +// Everything that makes a loaded module the current one, as plain data: what +// park() moves out of the globals above and resume() moves back. Field for +// field the "current module" state; runtimePeakBytes is not in it because it +// is a lifetime figure, which unload() never reset either. +struct ResidentModule { + LoadedSection sections[MAX_SECTIONS]; + int sectionCount; + void* moduleAllocs[MAX_MODULE_ALLOCS]; + int moduleAllocCount; + uint32_t runtimeBytes; + uint32_t runtimeInternalBytes; + const PFPatternModule* active; + uint32_t lastInternalBytes; + uint32_t lastPsramBytes; + uint32_t lastCodeBytes; + bool lastCodeExternal; + uint32_t lastReadUs; + uint32_t lastRelocateUs; + uint32_t lastSetupUs; + uint32_t lastTotalUs; + uint32_t generation; +}; + +// What a module owns, given back: its api->alloc() blocks and its sections. +// unload() and evicting a parked module both come through here, so the two +// cannot drift apart - a code block in PSRAM is freed through `block`, the +// heap's own pointer, because `memory` is the line-aligned address inside it. +inline void freeModuleMemory(LoadedSection* loaded, int count, void* const* allocs, + int allocCount) { + for (int i = 0; i < allocCount; ++i) free(allocs[i]); + for (int i = 0; i < count; ++i) free(loaded[i].block ? loaded[i].block : loaded[i].memory); +} + +inline void releaseResident(ResidentModule& module) { + freeModuleMemory(module.sections, module.sectionCount, module.moduleAllocs, + module.moduleAllocCount); +} + +// The slots, in PSRAM and only once something is parked. Not a static array: +// static DRAM is what check_footprint.py pins per edition, and internal RAM is +// what parking exists to leave alone. No PSRAM, no table, no parking. +inline void* allocateResidentTable(size_t bytes) { + return heap_caps_calloc(1, bytes, MALLOC_CAP_SPIRAM); +} + +inline PFModuleResident::Table + resident; + +// Loaded from the storage as it is now. A parked module that is not is never +// resumed, and goes whenever its owner next looks. +inline bool fresh(const ResidentModule& module) { return module.generation == storageNow(); } +inline int evictStale() { + return resident.evictIf([](const ResidentModule& module) { return !fresh(module); }); +} + inline bool fail(const char* message) { snprintf(lastError, sizeof(lastError), "%s", message); Serial.printf("[MODULE] %s\n", lastError); @@ -433,10 +526,43 @@ inline void* moduleAlloc(size_t bytes) { // honoured it through PFMem::alloc (core_mem.h memsets). The rework dropped // the zeroing, so a pattern that allocates a trail map or accumulator and // reads it before writing has been reading whatever the last module left. - void* memory = PFModuleMemory::data(bytes, true, true); + void* memory = nullptr; + // Parked modules hold PSRAM this module could have had before residency + // existed, and so could everything else that takes PSRAM late - the + // thumbnail buffers, a feature's PFMem, any malloc over 4 KB. So while any + // are parked, two rules, least recently used first: + // + // This allocation may not leave less than PF_MODULE_RESIDENT_HEADROOM of + // PSRAM free. A module that grows lazily, long after it loaded, would + // otherwise take PSRAM down to nothing with megabytes parked - megabytes + // that before residency would simply have been unloaded. + // + // A PSRAM refusal costs another parked module and PSRAM is asked again - + // before data() may fall back to the internal heap, which is the + // services' RAM and would also cost this module its own chance of being + // parked. Asked per allocation, so it also covers PSRAM with enough free + // in total but no block that large. + // + // Modules loaded before the storage last changed go first: nobody can + // resume them. This runs inside a call into the module - on the loader + // worker during its load, on the loop while it is the running pattern - + // which is the task that owns the table either way (core_module_resident.h). + if (resident.count) { + evictStale(); + resident.evictUntil([bytes] { + const size_t room = heap_caps_get_free_size(MALLOC_CAP_SPIRAM); + return room >= bytes && room - bytes >= (size_t)PF_MODULE_RESIDENT_HEADROOM; + }); + memory = PFModuleMemory::external(bytes, true); + while (!memory && resident.evictOldest()) memory = PFModuleMemory::external(bytes, true); + } + if (!memory) memory = PFModuleMemory::data(bytes, true, true); if (memory) { moduleAllocs[moduleAllocCount++] = memory; - runtimeBytes += bytes; + // fits() above bounds `bytes` by the 4 MB limit, so the narrowing is + // exact; spelled out for the 64-bit host the tests compile this on. + runtimeBytes += (uint32_t)bytes; + if (!esp_ptr_external_ram(memory)) runtimeInternalBytes += (uint32_t)bytes; if (runtimeBytes > runtimePeakBytes) runtimePeakBytes = runtimeBytes; } return memory; @@ -486,28 +612,41 @@ inline PFHostAPI hostAPI = { hostTableTheta, }; -inline void unload() { - active = nullptr; - // Every way a module leaves comes through here, so this is where the crash - // breadcrumb stops naming it. - PFCrash::forget(); - for (int i = 0; i < moduleAllocCount; ++i) free(moduleAllocs[i]); +// The current module's globals back to "nothing is here", freeing nothing. +// unload() calls it once the memory is given back; park() once the module has +// been moved into a slot, which is why it must not free: those blocks belong +// to the slot now. +inline void clearCurrent() { memset(moduleAllocs, 0, sizeof(moduleAllocs)); moduleAllocCount = 0; runtimeBytes = 0; - for (int i = 0; i < sectionCount; ++i) { - free(sections[i].block ? sections[i].block : sections[i].memory); - sections[i] = {}; - } + runtimeInternalBytes = 0; + for (int i = 0; i < sectionCount; ++i) sections[i] = {}; sectionCount = 0; - // Nothing is resident: /api/status must stop reporting the footprint of a + // Nothing is current: /api/status must stop reporting the footprint of a // module that left, or the partial footprint of one that never arrived. lastInternalBytes = 0; lastPsramBytes = 0; lastCodeExternal = false; + currentPath[0] = '\0'; + // load.resumed describes the module on the panel; with none there it is + // false, not whatever the last one was. + resumed = false; + lastResumeUs = 0; PFModuleMemory::endLoad(); } +// Free the current module. Never a parked one: those are not in the globals +// this reads, and only eviction (core_module_resident.h) frees them. +inline void unload() { + active = nullptr; + // Every way a module leaves comes through here or through park(), so these + // are where the crash breadcrumb stops naming it. + PFCrash::forget(); + freeModuleMemory(sections, sectionCount, moduleAllocs, moduleAllocCount); + clearCurrent(); +} + inline bool copyExecutable(uint8_t* destination, const uint8_t* source, size_t bytes) { size_t words = (bytes + 3) / 4; volatile uint32_t* output = reinterpret_cast(destination); @@ -602,7 +741,16 @@ inline uint32_t lastTotalUs = 0; // the knob reached it. Validating the header at upload time makes the reply // mean something: a file that passes this is at least the right kind of object // for this device. +// +// Every path that installs a .pfm runs this: an upload on the file it has +// just written (memory was emptied and loads held before its first byte, by +// captureSelectionOnceNow()), a library pull on its .tmp before the old file +// is removed (nothing emptied). For a writer of the second kind this is the one +// core call it makes BEFORE the file it replaces changes, so the storage +// generation moves here, whatever the verdict: a module parked from the old +// file is not resumed from here on. A refused file costs only that. inline bool looksLikeModule(fs::FS& filesystem, const char* path, char* why, size_t whySize) { + noteStorageWrite(); File file = filesystem.open(path, FILE_READ); if (!file) { snprintf(why, whySize, "cannot reopen after write"); @@ -649,6 +797,12 @@ struct LoadMark { inline bool load(fs::FS& filesystem, const char* path) { unload(); lastError[0] = '\0'; + // The key this module would be parked under. One the key cannot hold whole + // stays empty, and the module is then unloaded when left, as before. + if (path && strlen(path) < sizeof(currentPath)) memcpy(currentPath, path, strlen(path) + 1); + // Taken before the file is opened: a write that lands while it is being + // read moves the generation after this, and the module is never kept. + currentGeneration = storageNow(); Serial.printf("[MODULE] loading %s\n", path); const LoadMark mark(path); const uint32_t startedUs = micros(); @@ -762,10 +916,15 @@ inline bool load(fs::FS& filesystem, const char* path) { if (executable != (pass == 0)) continue; const size_t allocationSize = plannedSize[q]; void* block = nullptr; + // Data: PSRAM first whenever residency is on (PFModuleMemory:: + // dataPsramFirst says why and what it costs), otherwise only for a + // section over PF_MODULE_DATA_INTERNAL_MAX. uint8_t* memory = executable ? static_cast(PFModuleMemory::code(allocationSize, &block)) : static_cast(PFModuleMemory::data( - allocationSize, true, allocationSize > PF_MODULE_DATA_INTERNAL_MAX)); + allocationSize, true, + PFModuleMemory::dataPsramFirst || + allocationSize > PF_MODULE_DATA_INTERNAL_MAX)); if (!memory) { // Sample before free()/unload(), or the line reports the heap as it is // after the cleanup and contradicts the failure it is explaining. @@ -1026,6 +1185,182 @@ inline bool load(fs::FS& filesystem, const char* path) { return true; } +// ── Staying loaded ────────────────────────────────────────────────── +// A module that has run is parked when another pattern takes over, and comes +// back from its slot when picked again (core_module_resident.h has the why, +// and the rule for which task may do any of this). The globals above stay +// "the current module"; parking moves them into a slot and clears them +// without freeing, resuming moves a slot back. load() and unload() are the +// same functions they were. + +// Only a module that holds no internal RAM at all is kept. Internal RAM is +// what the console, Wi-Fi and lwIP live on, and a parked module is one nobody +// is looking at: every section in PSRAM, its code run through the +// instruction-bus alias, and every api->alloc() block in PSRAM too. A module +// that missed any of that - PSRAM full when it loaded, a unit whose code was +// demoted to internal RAM, a board without PSRAM - is unloaded exactly as +// before. So is one whose file may have changed since it loaded (an older +// storageGeneration). +inline bool parkable() { + return PF_MODULE_RESIDENT_MAX > 0 && active && sectionCount > 0 && currentPath[0] && + currentGeneration == storageNow() && lastCodeExternal && lastInternalBytes == 0 && + runtimeInternalBytes == 0; +} + +inline void captureCurrent(ResidentModule& module) { + for (int i = 0; i < MAX_SECTIONS; ++i) module.sections[i] = sections[i]; + module.sectionCount = sectionCount; + for (int i = 0; i < MAX_MODULE_ALLOCS; ++i) module.moduleAllocs[i] = moduleAllocs[i]; + module.moduleAllocCount = moduleAllocCount; + module.runtimeBytes = runtimeBytes; + module.runtimeInternalBytes = runtimeInternalBytes; + module.active = active; + module.lastInternalBytes = lastInternalBytes; + module.lastPsramBytes = lastPsramBytes; + module.lastCodeBytes = lastCodeBytes; + module.lastCodeExternal = lastCodeExternal; + module.lastReadUs = lastReadUs; + module.lastRelocateUs = lastRelocateUs; + module.lastSetupUs = lastSetupUs; + module.lastTotalUs = lastTotalUs; + module.generation = currentGeneration; +} + +// Its own load timings come back with it: /api/status's load.* keeps +// describing the module on the panel, and load.resumed says it did not just +// pay them again. +inline void restoreCurrent(const ResidentModule& module) { + for (int i = 0; i < MAX_SECTIONS; ++i) sections[i] = module.sections[i]; + sectionCount = module.sectionCount; + for (int i = 0; i < MAX_MODULE_ALLOCS; ++i) moduleAllocs[i] = module.moduleAllocs[i]; + moduleAllocCount = module.moduleAllocCount; + runtimeBytes = module.runtimeBytes; + runtimeInternalBytes = module.runtimeInternalBytes; + active = module.active; + lastInternalBytes = module.lastInternalBytes; + lastPsramBytes = module.lastPsramBytes; + lastCodeBytes = module.lastCodeBytes; + lastCodeExternal = module.lastCodeExternal; + lastReadUs = module.lastReadUs; + lastRelocateUs = module.lastRelocateUs; + lastSetupUs = module.lastSetupUs; + lastTotalUs = module.lastTotalUs; + currentGeneration = module.generation; +} + +// Move the current module into a slot. False - and the module still current, +// nothing moved - when it may not be kept or the table cannot take it; the +// caller then unloads it. `keep` is a parked module the caller is about to +// resume, which a full table must not evict to make room. +inline bool park(const char* keep = nullptr) { + if (!parkable()) return false; + // This task owns the table: clear out what can never be resumed before the + // least recently used of what can is evicted to make room. + evictStale(); + // Parking keeps this module's PSRAM, and while anything is parked the core + // keeps PF_MODULE_RESIDENT_HEADROOM free (core_module_memory.h) - from the + // moment this one is parked, not only from its next allocation. Older + // parked modules go first; if this one alone holds the last of it, it is + // unloaded as it always was. + while (heap_caps_get_free_size(MALLOC_CAP_SPIRAM) < (size_t)PF_MODULE_RESIDENT_HEADROOM && + resident.evictOldest(keep)) { + } + if (heap_caps_get_free_size(MALLOC_CAP_SPIRAM) < (size_t)PF_MODULE_RESIDENT_HEADROOM) return false; + const uint32_t held = lastPsramBytes + runtimeBytes; + if (!resident.park(currentPath, held, + [](ResidentModule& slot) { captureCurrent(slot); }, keep)) { + return false; + } + // Leaving, as far as anything but its memory is concerned: the same + // breadcrumb and the same globals unload() clears. + active = nullptr; + PFCrash::forget(); + clearCurrent(); + return true; +} + +// How every module leaves the panel now: parked when it can be kept, +// unloaded when it cannot. +inline void leave(const char* keep = nullptr) { + if (!park(keep)) unload(); +} + +// Parked, and loaded from the storage as it is now. One parked from an older +// file answers no, so the caller loads the file instead. +inline bool isParked(const char* path) { + const ResidentModule* parked = resident.peek(path); + return parked && fresh(*parked); +} + +// Make the module parked under `path` the current one: its own sections, +// allocations and descriptor, exactly as it left them. Nothing is read, +// relocated or constructed, and setup() does not run - the module carries on +// from its own state, as a compiled-in preset does. The caller has left the +// current module first. `path` is the registry's pointer, the same one load() +// would have been handed, so the crash breadcrumb's owner is the same either +// way. +// +// The code needs nothing done to it. It was written back and read through +// the instruction bus when it loaded, and nothing has written those bytes +// since: the block stayed allocated, so no other module could be placed on +// it. A later demotion of code placement (codeDemoted) concerns code yet to +// be placed; this was verified on this unit already. +inline bool resume(const char* path) { + if (active || sectionCount || !isParked(path)) return false; + const uint32_t startedUs = micros(); + if (!resident.take(path, [](ResidentModule& slot) { restoreCurrent(slot); })) return false; + memcpy(currentPath, path, strlen(path) + 1); // fits: it was found under it + lastError[0] = '\0'; + // From here a crash PC can be inside this module again: name it, and the + // range its code is fetched from, as load() does. + PFCrash::running(path, path); + for (int i = 0; i < sectionCount; ++i) { + if (!sections[i].executable) continue; + PFCrash::code(sections[i].exec, sections[i].size); + break; + } + PFCrash::enter(PFCrash::IDLE); + resumed = true; + lastResumeUs = micros() - startedUs; + Serial.printf("[MODULE] resumed %s in %lu us\n", path, (unsigned long)lastResumeUs); + return true; +} + +// Before a fresh load: least recently used parked modules go until PSRAM has +// at least the runtime limit plus PF_MODULE_RESIDENT_HEADROOM free, or until +// none is left. The bound is derived, not tuned: the module about to load can +// still get everything it could get before residency existed. The loader +// worker's retries and api->alloc() go further when they are refused. +inline void makeRoom() { + // Two statements: the stale go first, and the operands of a `+` would be + // unsequenced. + int evicted = evictStale(); + evicted += resident.evictUntil([] { + return heap_caps_get_free_size(MALLOC_CAP_SPIRAM) >= + (size_t)PF_MODULE_RUNTIME_MAX_BYTES + (size_t)PF_MODULE_RESIDENT_HEADROOM; + }); + if (evicted) Serial.printf("[MODULE] %d parked module(s) evicted for room\n", evicted); +} + +inline void dropParked() { + const int evicted = resident.evictAll(); + if (evicted) Serial.printf("[MODULE] %d parked module(s) dropped\n", evicted); +} + +// At the list rebuild that follows a write (the registry's restore): every +// parked module loaded before the storage last changed goes, and so does the +// current one, unloaded, if it is one of them - left running, it would go on +// as the old file under the new one's name for as long as nobody switched +// away. True when the current module was unloaded; the caller stops naming it. +// Nothing at all happens when nothing was written since. +inline bool dropStale() { + const int evicted = evictStale(); + if (evicted) Serial.printf("[MODULE] %d parked module(s) older than the storage dropped\n", evicted); + if (!active || currentGeneration == storageNow()) return false; + unload(); + return true; +} + // The two calls a frame makes into the module, each between two stores to // the crash breadcrumb (core_crash.h): after a reset, which of them never // came back is the difference between "a pattern crashed" and "this one, in diff --git a/firmware/patternflow/src/core_module_memory.h b/firmware/patternflow/src/core_module_memory.h index a17ca429..97ae12f9 100644 --- a/firmware/patternflow/src/core_module_memory.h +++ b/firmware/patternflow/src/core_module_memory.h @@ -41,6 +41,37 @@ #define PF_MODULE_RUNTIME_MAX_BYTES (4u * 1024u * 1024u) #endif +// How many modules may stay loaded ("parked") after another pattern takes +// over, so that picking one again resumes it instead of loading it +// (core_module_resident.h). 0 turns residency off: every module is unloaded +// when it is left, as before 2026-10, and data placement below goes back to +// what it was. The slots live in PSRAM, allocated on the first park. +#ifndef PF_MODULE_RESIDENT_MAX +#define PF_MODULE_RESIDENT_MAX 16 +#endif +// What parked modules must leave free in PSRAM - room for the features and +// the console, and for an incoming module's image and sections (tens of +// kilobytes). The loader holds it at two moments, evicting parked modules +// least recently used first until it holds or none is left: +// +// before a fresh load starts, PF_MODULE_RUNTIME_MAX_BYTES plus this is free, +// so the module about to load can still get everything it could get +// before residency existed; +// +// whenever a module is parked, and after every api->alloc() a module makes +// while anything is parked, at least this is free, however late the module +// allocates (a module that alone would hold the last of it is unloaded +// instead of parked). +// +// Parked modules give way to patterns only. An allocation by a feature or by +// the core (a thumbnail buffer, PFMem, a large malloc) evicts nothing: with +// modules parked it finds this much free at the least, less whatever other +// such allocations have taken from it since. Derived, not tuned to any +// pattern's size. +#ifndef PF_MODULE_RESIDENT_HEADROOM +#define PF_MODULE_RESIDENT_HEADROOM (512u * 1024u) +#endif + // Where a module's code may live. // // "The S3 cannot execute from PSRAM" was the axiom everything above was built @@ -103,6 +134,39 @@ inline uint8_t codeRule() { return codeDemoted ? (uint8_t)PF_MODULE_CODE_INTERNAL : codePolicy; } +// Where a module's data sections (.rodata/.data/.bss) go first. +// +// false internal RAM while the load's budget allows, for sections up to +// PF_MODULE_DATA_INTERNAL_MAX; PSRAM past that - the rule until 2026-10 +// true PSRAM, every section; internal RAM only if PSRAM refuses +// +// true is what residency needs, and it follows it: a parked module must hold +// no internal RAM at all (core_module_resident.h), and every module measured +// before this had 1-10 KB of small sections in internal RAM, so under the old +// rule none of them could have been parked. A section PSRAM refuses still +// lands internally - the load never fails for this - and that module is then +// simply not parked. +// +// What it costs, measured 2026-10-03, A-B-B-A on one boot per module, two +// boards, Audio edition, frame-time medians (A the old rule, B this one): 13 +// of 16 module runs within -1.1..+0.8%, which is noise (HUSH Grid -1.1%, 0601 +// +0.08%, Branched Flow +0.16%, Layer Stack +0.11%, Two Stream -0.3%, Firefly +// Hollow -0.1%, Ripple Grid +0.1%, 0510 -0.1%, 0531 +0.2/+0.8%, Bus Window +// Rain +0.4%, 0515-4 -0.5%). Three real costs, small per-pixel state arrays +// now read through the PSRAM cache: Burgers Original +2.6% (38.9 -> 39.9 ms), +// Wave Cascade +2.2% (20.7 -> 21.2 ms), Breakout Arcade +0.85% (21.40 -> +// 21.58 ms). In exchange the running module takes no internal RAM: internal +// heap with it running rose 0.2-9.9 KB, typically 4-6 KB (Layer Stack 23.2 -> +// 33.1 KB, Burgers 26.6 -> 33.2 KB). The same order of cost as putting code in +// PSRAM, above. +// +// A variable, like codePolicy, so the host test and a bench build can flip it +// on one boot; PF_MODULE_DATA_PSRAM_FIRST 0 reverts it in a build. +#ifndef PF_MODULE_DATA_PSRAM_FIRST +#define PF_MODULE_DATA_PSRAM_FIRST (PF_MODULE_RESIDENT_MAX > 0) +#endif +inline bool dataPsramFirst = PF_MODULE_DATA_PSRAM_FIRST; + // Code in PSRAM is given whole cache lines, start and length. The bytes are // written through the data cache and have to be written back to the chip // before they can be fetched, and the S3's write-back has an erratum: a line @@ -187,6 +251,14 @@ inline bool admitCode(size_t codeBytes) { } inline void endLoad() { dataBudget = 0; } +// PSRAM and nothing else: no internal fallback, no refusal counted. For a +// caller that has something to try before data() falls back (the loader +// evicts a parked module and asks again). +inline void* external(size_t bytes, bool zero) { + return zero ? heap_caps_calloc(1, bytes, externalData) + : heap_caps_malloc(bytes, externalData); +} + inline void* data(size_t bytes, bool zero, bool preferExternal) { if (!bytes) return nullptr; void* p = nullptr; @@ -197,10 +269,7 @@ inline void* data(size_t bytes, bool zero, bool preferExternal) { p = internal(bytes, internalData, zero); if (p) spend(bytes); } - if (!p) { - p = zero ? heap_caps_calloc(1, bytes, externalData) - : heap_caps_malloc(bytes, externalData); - } + if (!p) p = external(bytes, zero); if (!p) { p = internal(bytes, internalData, zero); if (p) spend(bytes); diff --git a/firmware/patternflow/src/core_module_resident.h b/firmware/patternflow/src/core_module_resident.h new file mode 100644 index 00000000..ec70ad19 --- /dev/null +++ b/firmware/patternflow/src/core_module_resident.h @@ -0,0 +1,258 @@ +// ═══════════════════════════════════════════════════════════ +// PatternFlow - modules that stay loaded when another pattern takes over +// +// A compiled-in preset is set up once at boot and resumes on every visit. A +// .pfm module used to be unloaded the moment anything else took the panel, so +// coming back to it cost a whole load: the FAT read (16-44 ms), relocation, +// constructors and the module's own setup(). For most of the catalogue that is +// 25-100 ms; for Branched Flow it is 3.3 s, Two Stream 4.1 s, Burgers and Wave +// Cascade 0.6 s each - all of it setup() (measured 2026-10-03, two boards). +// +// It had to be that way while a module needed internal RAM to exist: the +// console, Wi-Fi and lwIP live on the same few tens of kilobytes. Since 2026-10 +// a module's code runs from PSRAM (core_module_memory.h), and with its data +// placed there too the whole module lives in memory nothing else is short of. +// So a module that has run is PARKED when another pattern takes over: the +// loader moves its bookkeeping into a slot here and frees nothing, and picking +// it again moves the slot back - no read, no relocation, no constructors, no +// setup(). It carries on from its own state, which is what a preset does. +// +// This file is the bookkeeping only: the slots, finding one by path, which is +// least recently used, and parking, taking and evicting over a release +// function the caller supplies. It knows nothing about ELF sections or heaps, +// so it compiles on a PC and the host suite drives it +// (firmware/toolchain/tests/resident_test.cpp). What a parked module IS, and +// when one may be parked at all, is the loader's business +// (core_module_loader.h, "Staying loaded"). +// +// ── Who may touch the table ───────────────────────────────────────── +// +// Exactly one task at a time, and never by a lock: by the same hand-off the +// asynchronous loader already uses (pattern_registry.h, "Loading without +// stopping the frame"). +// +// the loop task (Core 1) while loadInFlight is false +// the pf-load worker (Core 0) from the loop's release-store of +// loadInFlight = true (and the notify) until the +// worker's own release-store of loadFinished = true +// +// The loop does not look at the table again until it has acquired +// loadFinished and adopted the result, so the worker's writes happen-before +// the loop's next read. HTTP handlers run on the network task and never touch +// the table: whatever they need done - evicting everything when the storage +// changes - is handed to the loop at the frame boundary through PFLoopSync, +// which only runs it once tryFinishAsyncLoad() says no load is in flight. A +// file written from the network task without that moves one counter, the +// loader's storageGeneration, with an atomic add; the owner reads it and does +// the evicting. +// +// That rests on one more invariant, because a module can reach the table on +// its own through api->alloc() (the loader evicts the oldest parked module +// when PSRAM says no): module code runs on the loop only while the registry +// names it active, and the registry names nothing active for the whole of a +// load - the loop draws the incoming pattern's thumbnail instead. So a module +// running on the loop means no load is in flight, and a module running on the +// worker means one is: whichever task calls into a module owns the table. +// +// /api/status reads `count`, `bytes`, `resumes` and `evictions` from the +// network task. Each is one aligned word written only by the owner, so a +// reader sees a whole value, at worst one change late. The slots themselves +// are never read from there. +// +// License: MIT +// ═══════════════════════════════════════════════════════════ +#pragma once + +#include +#include +#include +#include + +namespace PFModuleResident { + +// The registry's MODULE_PATH_BYTES; pattern_registry.h asserts they agree. A +// path that does not fit whole is never parked: a cut key could name another +// file. +constexpr size_t PATH_BYTES = 72; + +// Module: what the loader keeps per parked module, plain data. +// Capacity: slots. 0 compiles a table that never parks anything. +// Allocate: where the slots come from, once, on the first park. Called with +// the bytes for every slot; nullptr means there is no table this time, and +// the caller unloads as it would have without one. +// Release: frees exactly what unloading that module would have freed. The +// table calls it on eviction and never otherwise. +template +class Table { + public: + struct Slot { + bool used; + uint32_t stamp; // last use, from `clock`; the smallest is evicted first + uint32_t held; // bytes the owner said the module holds, for /api/status + char path[PATH_BYTES]; + Module module; + }; + + // Read from other tasks; see the header. + uint32_t count = 0; + uint32_t bytes = 0; + uint32_t resumes = 0; + uint32_t evictions = 0; + + static constexpr int capacity() { return Capacity > 0 ? Capacity : 0; } + bool allocated() const { return slots != nullptr; } + + int find(const char* path) const { + if (!slots || !path) return -1; + for (int i = 0; i < capacity(); ++i) { + if (slots[i].used && strcmp(slots[i].path, path) == 0) return i; + } + return -1; + } + bool has(const char* path) const { return find(path) >= 0; } + + // The module parked under `path`, to look at and not to keep: the pointer + // is good until the table next changes. nullptr when there is none. + const Module* peek(const char* path) const { + const int at = find(path); + return at < 0 ? nullptr : &slots[at].module; + } + + // The least recently used slot that is not `keep`, or -1. + int oldest(const char* keep = nullptr) const { + if (!slots) return -1; + int best = -1; + for (int i = 0; i < capacity(); ++i) { + if (!slots[i].used) continue; + if (keep && strcmp(slots[i].path, keep) == 0) continue; + if (best < 0 || slots[i].stamp < slots[best].stamp) best = i; + } + return best; + } + + // Park the module `fill` writes into the slot, under `path`. False when it + // cannot be kept - no capacity, no table, a path too long to key on, or a + // full table whose only resident is `keep` - and then nothing has been + // taken from the caller: it still owns its module and unloads it. + // + // `keep` is the module about to be resumed. Parking the outgoing one into a + // full table evicts the least recently used, and that must not be the one + // the caller is about to take back. + // + // A path that is already parked is a stale copy of the same file (the + // registry never parks a module it could have resumed, so this does not + // happen in ordinary use): it is evicted, and the module being parked now + // replaces it. One slot per path, always, or find() would be a guess. + template + bool park(const char* path, uint32_t held, Fill fill, const char* keep = nullptr) { + if (capacity() == 0 || !path || !path[0] || strlen(path) >= PATH_BYTES) return false; + if (!ensure()) return false; + const int stale = find(path); + if (stale >= 0) evict(stale); + int at = freeSlot(); + if (at < 0) { + at = oldest(keep); + if (at < 0) return false; + evict(at); + } + Slot& slot = slots[at]; + fill(slot.module); + memcpy(slot.path, path, strlen(path) + 1); + slot.held = held; + // A counter, not millis(): two parks in one millisecond (a knob spun + // through presets) must still be ordered, and it never wraps in practice - + // four billion switches. + slot.stamp = ++clock; + slot.used = true; + ++count; + bytes += held; + return true; + } + + // Hand the module parked under `path` to `drain` and forget it: from here + // the caller owns it again. False when nothing is parked under that path. + template + bool take(const char* path, Drain drain) { + const int at = find(path); + if (at < 0) return false; + drain(slots[at].module); + vacate(at); + ++resumes; + return true; + } + + bool evictOldest(const char* keep = nullptr) { + const int at = oldest(keep); + if (at < 0) return false; + evict(at); + return true; + } + + int evictAll() { + int evicted = 0; + for (int i = 0; i < capacity() && slots; ++i) { + if (!slots[i].used) continue; + evict(i); + ++evicted; + } + return evicted; + } + + // Least recently used first, until `enough()` or nothing is parked. + template + int evictUntil(Enough enough) { + int evicted = 0; + while (count && !enough() && evictOldest()) ++evicted; + return evicted; + } + + // Every parked module `doomed(module)` says must go. The loader's test is + // "loaded before the pattern storage last changed". + template + int evictIf(Doomed doomed) { + int evicted = 0; + for (int i = 0; i < capacity() && slots; ++i) { + if (!slots[i].used || !doomed(static_cast(slots[i].module))) continue; + evict(i); + ++evicted; + } + return evicted; + } + + private: + Slot* slots = nullptr; + uint32_t clock = 0; + + bool ensure() { + if (slots) return true; + void* raw = Allocate(sizeof(Slot) * (size_t)capacity()); + if (!raw) return false; + slots = static_cast(raw); + for (int i = 0; i < capacity(); ++i) new (&slots[i]) Slot(); + return true; + } + + int freeSlot() const { + for (int i = 0; i < capacity(); ++i) { + if (!slots[i].used) return i; + } + return -1; + } + + // The slot forgets the module; it frees nothing. A vacated slot holds no + // pointers, so nothing can ever be released through it twice. + void vacate(int at) { + Slot& slot = slots[at]; + if (count) --count; + bytes = slot.held >= bytes ? 0 : bytes - slot.held; + slot = Slot(); + } + + void evict(int at) { + Release(slots[at].module); + vacate(at); + ++evictions; + } +}; + +} // namespace PFModuleResident diff --git a/firmware/patternflow/src/core_patterns_http.h b/firmware/patternflow/src/core_patterns_http.h index 748e9509..c172edb9 100644 --- a/firmware/patternflow/src/core_patterns_http.h +++ b/firmware/patternflow/src/core_patterns_http.h @@ -91,6 +91,9 @@ inline char restorePath[MODULE_PATH_BYTES] = {}; inline int restorePresetIdx = -1; inline bool restorePending = false; +// The running module only. Parked ones (src/core_module_resident.h) are +// dropped by captureSelectionOnceNow() below, on every branch - including the +// one where a preset keeps running and this is never called. inline void evictResidentModule() { if (!PFModuleLoader::active) return; PFModuleLoader::unload(); @@ -109,6 +112,14 @@ inline bool captureSelectionOnceNow() { patternLoadsHeld = true; if (loadQueuedIdx >= 0) rememberHeldSelection(loadQueuedIdx); loadQueuedIdx = -1; + // Every parked module goes before the first byte is written, whichever + // branch below runs: from here a file may be replaced or deleted, and a + // parked copy of it would come back as the old version - or as a pattern + // that is no longer installed. A preset on the panel keeps running; nothing + // parked survives. Simplest rule that is always right, and the storage + // generation (PFModuleLoader::storageGeneration) backs it for writers that + // never come through here. + PFModuleLoader::dropParked(); if (restorePending) { // Show / night schedule / MQTT may reload a module while the console // still holds the pause. Evict again or the wake page loops forever. @@ -142,6 +153,15 @@ inline bool restoreSelectionNow() { if (!tryFinishAsyncLoad()) return false; loadQueuedIdx = -1; restorePending = false; + // The list is about to be read off the volume again because something + // wrote to it, and not every writer emptied memory first - a feature that + // installs a pattern can ask for this rebuild with a module still running. + // Whatever was loaded before the storage last changed + // (PFModuleLoader::storageGeneration) goes now: parked copies, and the + // running module too, or it would go on as the old file for as long as + // nobody switched away - the activation below loads the file as it is. + // After a rebuild with no write in between, nothing is touched. + if (PFModuleLoader::dropStale()) activePatternIdx = -1; buildPatternList(); const char* wantedPath = heldSelectionValid ? heldPatternPath : restorePath; int wanted = heldSelectionValid ? heldPresetIdx : restorePresetIdx; diff --git a/firmware/patternflow/src/core_status_http.h b/firmware/patternflow/src/core_status_http.h index 8fd9352f..7bfabef0 100644 --- a/firmware/patternflow/src/core_status_http.h +++ b/firmware/patternflow/src/core_status_http.h @@ -512,7 +512,14 @@ inline void handleStatus() { // `psram` above and costs the services nothing. json += ",\"code\":\""; json += PFModuleLoader::lastCodeExternal ? "psram" : "internal"; - json += "\"}"; + // Whether the module on the panel came back from residency rather than + // from a load - the timings above are then its own, from when it first + // loaded - and what coming back took, in µs. + json += "\",\"resumed\":"; + json += PFModuleLoader::resumed ? "true" : "false"; + json += ",\"resumeUs\":"; + json += PFModuleLoader::lastResumeUs; + json += "}"; json += ",\"moduleMemory\":{\"reserve\":"; json += PF_MODULE_INTERNAL_RESERVE; json += ",\"runtimeBytes\":"; json += PFModuleLoader::runtimeBytes; json += ",\"runtimePeakBytes\":"; json += PFModuleLoader::runtimePeakBytes; @@ -532,6 +539,15 @@ inline void handleStatus() { json += ",\"execLargest\":"; json += heap_caps_get_largest_free_block(PFModuleMemory::internalCode); json += ",\"refusals\":"; json += PFModuleMemory::refusals; + // Modules kept loaded after another pattern took over (core_module_resident.h). + // Counters only: the table belongs to the loop and the loader worker, and + // this runs on the network task, so the slots are never walked from here. + json += ",\"resident\":{\"count\":"; json += PFModuleLoader::resident.count; + json += ",\"bytes\":"; json += PFModuleLoader::resident.bytes; + json += ",\"slots\":"; json += PFModuleLoader::resident.capacity(); + json += ",\"resumes\":"; json += PFModuleLoader::resident.resumes; + json += ",\"evictions\":"; json += PFModuleLoader::resident.evictions; + json += "}"; json += "}"; json += ",\"nvs\":{\"usable\":"; json += nvsUsable ? "true" : "false"; json += ",\"failures\":"; json += nvsFailures; diff --git a/firmware/toolchain/check_footprint.py b/firmware/toolchain/check_footprint.py index 503d34ac..dfefb442 100644 --- a/firmware/toolchain/check_footprint.py +++ b/firmware/toolchain/check_footprint.py @@ -63,12 +63,18 @@ # Again the same day: static DRAM +304 in every edition - the crash record's 296 B # (224 of them the SDK's own strings behind esp_core_dump_get_summary, 64 the # breadcrumb in .noinit) and 8 B of loop-sync state. +# Re-pinned 2026-10-03: static DRAM +112..+120 in every edition, IRAM unchanged - +# resident modules' bookkeeping in core_module_loader.h: the current module's +# path (72 B, the key it is parked under), the table header (24 B: slot pointer, +# use counter, four status counters), the storage generation and the current +# module's (8 B) and four small flags and counters. The slots themselves are +# allocated in PSRAM on the first park. PINS = { - "default": (141576, 71471), - "audio": (161104, 71951), - "performance": (158080, 71471), - "clock": (141856, 71471), - "midi": (154168, 70671), + "default": (141688, 71471), + "audio": (161216, 71951), + "performance": (158200, 71471), + "clock": (141976, 71471), + "midi": (154288, 70671), } # Enough that an intentional, well-understood adjustment does not fire the check diff --git a/firmware/toolchain/check_runtime.py b/firmware/toolchain/check_runtime.py index 4de32649..f6d19c69 100644 --- a/firmware/toolchain/check_runtime.py +++ b/firmware/toolchain/check_runtime.py @@ -1,7 +1,12 @@ -"""Exercise module admission, loader lifecycle and conditional loop requests. +"""Exercise module admission, loader lifecycle, resident modules and conditional +loop requests. python firmware/toolchain/check_runtime.py [--sanitize] -Production code is compiled against deterministic hardware fixtures. +Production code is compiled against deterministic hardware fixtures. Two +programs: runtime_test.cpp (admission, the frame-boundary hand-off, the +registry's load/park/resume lifecycle against a fake loader) and +resident_test.cpp (the resident table, and the loader's own park, resume, +unload and eviction code lifted out of core_module_loader.h). """ import argparse from pathlib import Path @@ -18,7 +23,8 @@ def main(): compiler, env = compiler_environment() with tempfile.TemporaryDirectory(prefix='patternflow-runtime-') as directory: work = Path(directory) - for name in ('core_module_memory.h', 'core_loop_sync.h', 'core_net_maintenance.h'): + for name in ('core_module_memory.h', 'core_module_resident.h', 'core_loop_sync.h', + 'core_net_maintenance.h'): (work / name).write_bytes((ROOT / 'firmware/patternflow/src' / name).read_bytes()) for name in ('Arduino.h', 'esp_heap_caps.h', 'core_runtime.h'): (work / name).write_text('// Hardware supplied by runtime_test.cpp\n') @@ -29,24 +35,44 @@ def main(): start = registry.index('inline bool jsonStringValue(') end = registry.index('// Deliberately a substring scan', start) (work / 'sidecar_name.h').write_text(registry[start:end], encoding='utf-8') + # The sidecar cache's forget calls: every module-file writer reports + # its write through one, so they move the loader's storage generation. + start = registry.index('inline int sidecarFind(') + end = registry.index('inline void sidecarRemember(', start) + (work / 'sidecar_forget.h').write_text(registry[start:end], encoding='utf-8') manager = (ROOT / 'firmware/patternflow/src/core_patterns_http.h').read_text(encoding='utf-8') start = manager.index('inline char restorePath[') end = manager.index('// The rescan-and-reload', start) (work / 'patterns_lifecycle.h').write_text(manager[start:end], encoding='utf-8') - source = ROOT / 'firmware/toolchain/tests/runtime_test.cpp' - exe = work / ('runtime_test.exe' if Path(compiler).suffix.lower() == '.exe' else 'runtime_test') - if Path(compiler).stem.lower() == 'cl': - if args.sanitize: - raise SystemExit('--sanitize requires GCC or Clang') - command = [compiler, '/nologo', '/std:c++20', '/EHsc', '/O2', '/W4', '/WX', '/utf-8', - f'/I{work}', str(source), f'/Fe:{exe}'] - else: - command = [compiler, '-std=c++20', '-O2', '-Wall', '-Wextra', '-Werror', - f'-I{work}', str(source), '-o', str(exe)] - if args.sanitize: - command += ['-fsanitize=address,undefined', '-fno-omit-frame-pointer'] - subprocess.run(command, cwd=work, env=env, check=True) - subprocess.run([str(exe)], cwd=work, env=env, check=True) + # The loader's residency, in the pieces that need no ELF, no flash and + # no cache: its state, api->alloc(), unload(), the load timings, and + # the "Staying loaded" block. Each runs from one anchor to the next. + loader = (ROOT / 'firmware/patternflow/src/core_module_loader.h').read_text(encoding='utf-8') + for name, begin, finish in ( + ('loader_state.h', 'constexpr int MAX_SECTIONS = 8;', 'inline bool fail(const char* message) {'), + ('loader_alloc.h', 'inline void* moduleAlloc(size_t bytes) {', 'inline void hostLog('), + ('loader_unload.h', "// The current module's globals back to", 'inline bool copyExecutable('), + ('loader_timings.h', '// Phase timings from the last successful load()', '// Cheap structural check'), + ('loader_resident.h', '// \u2500\u2500 Staying loaded', '// The two calls a frame makes into the module'), + ): + start = loader.index(begin) + end = loader.index(finish, start) + (work / name).write_text(loader[start:end], encoding='utf-8') + for test in ('runtime_test', 'resident_test'): + source = ROOT / f'firmware/toolchain/tests/{test}.cpp' + exe = work / (f'{test}.exe' if Path(compiler).suffix.lower() == '.exe' else test) + if Path(compiler).stem.lower() == 'cl': + if args.sanitize: + raise SystemExit('--sanitize requires GCC or Clang') + command = [compiler, '/nologo', '/std:c++20', '/EHsc', '/O2', '/W4', '/WX', '/utf-8', + f'/I{work}', str(source), f'/Fe:{exe}'] + else: + command = [compiler, '-std=c++20', '-O2', '-Wall', '-Wextra', '-Werror', + f'-I{work}', str(source), '-o', str(exe)] + if args.sanitize: + command += ['-fsanitize=address,undefined', '-fno-omit-frame-pointer'] + subprocess.run(command, cwd=work, env=env, check=True) + subprocess.run([str(exe)], cwd=work, env=env, check=True) if __name__ == '__main__': diff --git a/firmware/toolchain/tests/resident_test.cpp b/firmware/toolchain/tests/resident_test.cpp new file mode 100644 index 00000000..ed124fec --- /dev/null +++ b/firmware/toolchain/tests/resident_test.cpp @@ -0,0 +1,512 @@ +// Modules that stay loaded: the bookkeeping (src/core_module_resident.h) on +// its own, then the loader's own park/resume/unload/evict code, lifted from +// src/core_module_loader.h by check_runtime.py, against a heap that knows +// which blocks are PSRAM and a crash breadcrumb that records what it is told. +#include +#include +#include +#include +#include +#include +#ifdef _MSC_VER +#include +#define __ATOMIC_ACQUIRE 0 +#define __ATOMIC_ACQ_REL 0 +template T __atomic_load_n(T* p, int) { return std::atomic_ref(*p).load(); } +template T __atomic_add_fetch(T* p, V v, int) { + return std::atomic_ref(*p).fetch_add(static_cast(v)) + static_cast(v); +} +#endif + +constexpr unsigned MALLOC_CAP_INTERNAL=1, MALLOC_CAP_8BIT=2, MALLOC_CAP_SPIRAM=4; +constexpr unsigned MALLOC_CAP_EXEC=8, MALLOC_CAP_32BIT=16; + +// PSRAM and the internal heap, block by block. A free() of anything neither +// handed out is an assert: that is what freeing a code block through its +// line-aligned `memory` instead of the heap's `block` would look like. +static size_t psramSize=64*1024, psramUsed=0, internalFree=100000; +static bool psramRefuses=false; +// PSRAM that says no to the next N asks with plenty free in total: no block +// that large, which eviction may or may not cure. +static int psramNoBlock=0; +static std::map psramOwned, internalOwned; +static unsigned frees=0; +static size_t heap_caps_get_free_size(unsigned caps) { + return (caps & MALLOC_CAP_SPIRAM) ? psramSize-psramUsed : internalFree; +} +static size_t heap_caps_get_largest_free_block(unsigned caps) { return heap_caps_get_free_size(caps); } +static void* heap_caps_malloc(size_t n, unsigned caps) { + if(caps & MALLOC_CAP_SPIRAM) { + if(psramNoBlock>0) { --psramNoBlock; return nullptr; } + if(psramRefuses || n>psramSize-psramUsed) return nullptr; + void* p=malloc(n); assert(p); psramOwned[p]=n; psramUsed+=n; return p; + } + if(n>internalFree) return nullptr; + void* p=malloc(n); assert(p); internalOwned[p]=n; internalFree-=n; return p; +} +static void* heap_caps_calloc(size_t n, size_t s, unsigned caps) { + void* p=heap_caps_malloc(n*s,caps); if(p) memset(p,0,n*s); return p; +} +static void testFree(void* p) { + if(!p) return; + ++frees; + auto e=psramOwned.find(p); + if(e!=psramOwned.end()) { psramUsed-=e->second; psramOwned.erase(e); free(p); return; } + auto i=internalOwned.find(p); + assert(i!=internalOwned.end()); + internalFree+=i->second; internalOwned.erase(i); free(p); +} +static bool esp_ptr_external_ram(const void* p) { + const char* at=static_cast(p); + for(const auto& block : psramOwned) { + const char* base=static_cast(block.first); + if(at>=base && at void printf(const char*,T...) {} } Serial; +namespace PFCrash { +enum Phase : uint32_t { IDLE=0, LOADING, CONSTRUCTORS, SETUP, UPDATE, DRAW }; +static const void* owner=nullptr; +static char slug[80]; +static uintptr_t codeBase=0; +static uint32_t codeSize=0, phase=IDLE; +inline void forget() { owner=nullptr; slug[0]=0; codeBase=0; codeSize=0; phase=IDLE; } +inline void running(const void* who, const char* path) { + owner=who; snprintf(slug,sizeof(slug),"%s",path); codeBase=0; codeSize=0; +} +inline void code(uintptr_t base, uint32_t bytes) { codeBase=base; codeSize=bytes; } +inline void enter(Phase p) { phase=p; } +} +struct PFPatternModule { const char* name; }; + +#define free(p) testFree(p) +namespace PFModuleLoader { +#include "loader_state.h" +#include "loader_alloc.h" +#include "loader_unload.h" +#include "loader_timings.h" +#include "loader_resident.h" +} +#undef free + +// ── The bookkeeping alone ───────────────────────────────────────────── +struct Toy { void* block; int id; }; +static unsigned toyReleases=0; +static void releaseToy(Toy& toy) { ++toyReleases; free(toy.block); toy.block=nullptr; } +static bool tableRefuses=false; +// A table keeps its slots for the boot. These do not outlive the case. +static void* toyTables[4]; static int toyTableCount=0; +static void* toyTable(size_t bytes) { + if(tableRefuses) return nullptr; + assert(toyTableCount<4); + return toyTables[toyTableCount++]=calloc(1,bytes); +} +using Toys=PFModuleResident::Table; +static Toy toy(int id) { return Toy{malloc(8),id}; } +template +static bool parkToy(Table& table, const char* path, int id, const char* keep=nullptr) { + Toy fresh=toy(id); + if(table.park(path,10,[&](Toy& slot){ slot=fresh; },keep)) return true; + free(fresh.block); // not taken: the caller still owns it and unloads it + return false; +} +template +static int takeToy(Table& table, const char* path) { + Toy back{nullptr,-1}; + if(!table.take(path,[&](Toy& slot){ back=slot; })) return -1; + free(back.block); + return back.id; +} + +static void bookkeeping() { + // No slots compiled in: nothing parks and nothing is allocated to find out. + { + PFModuleResident::Table none; + bool filled=false; + assert(!none.park("/a",1,[&](Toy&){ filled=true; }) && !filled && !none.allocated()); + assert(none.capacity()==0 && !none.has("/a") && none.evictAll()==0); + } + Toys table; + // No table to be had: the park is refused before anything is taken, and the + // next park tries again. + tableRefuses=true; + assert(!parkToy(table,"/a",1) && !table.allocated() && table.count==0); + tableRefuses=false; + // Park, find, take: the module comes back exactly once. + assert(parkToy(table,"/a",1) && table.allocated() && table.count==1 && table.bytes==10); + assert(table.has("/a") && !table.has("/b") && !table.has(nullptr)); + assert(takeToy(table,"/a")==1 && takeToy(table,"/a")==-1); + assert(table.count==0 && table.bytes==0 && table.resumes==1 && toyReleases==0); + // No key, an empty key, a key too long to hold whole: never parked. + char longPath[PFModuleResident::PATH_BYTES+1]; + memset(longPath,'x',sizeof(longPath)-1); longPath[sizeof(longPath)-1]=0; + assert(!parkToy(table,nullptr,9) && !parkToy(table,"",9) && !parkToy(table,longPath,9)); + longPath[PFModuleResident::PATH_BYTES-1]=0; // 71 characters: fits + assert(parkToy(table,longPath,9) && takeToy(table,longPath)==9); + // Full: the least recently PARKED goes first, by counter, not by clock. + assert(parkToy(table,"/a",1) && parkToy(table,"/b",2) && parkToy(table,"/c",3)); + assert(table.count==3 && table.oldest()==table.find("/a")); + assert(parkToy(table,"/d",4)); + assert(!table.has("/a") && table.count==3 && toyReleases==1 && table.evictions==1); + // Taking one back and parking it again makes it the newest. + assert(takeToy(table,"/b")==2 && parkToy(table,"/b",2)); + assert(table.oldest()==table.find("/c")); + // `keep` - the one about to be resumed - is never what a full table evicts. + assert(parkToy(table,"/e",5,"/c")); + assert(table.has("/c") && !table.has("/d") && table.count==3 && toyReleases==2); + // A path parked twice is one slot: the older copy is released. + assert(parkToy(table,"/c",33)); + assert(table.count==3 && toyReleases==3 && takeToy(table,"/c")==33); + // Until enough: least recently used first, and it stops there. + assert(parkToy(table,"/f",6)); // order now: b, e, f + int asked=0; + assert(table.evictUntil([&]{ return ++asked>1; })==1); + assert(!table.has("/b") && table.has("/e") && table.has("/f")); + // ...or until nothing is parked. + assert(table.evictUntil([]{ return false; })==2 && table.count==0 && table.bytes==0); + assert(!table.evictOldest() && table.evictUntil([]{ return false; })==0); + // A table whose only resident is `keep` cannot make room for another. + { + PFModuleResident::Table one; + assert(parkToy(one,"/a",1) && !parkToy(one,"/b",2,"/a") && one.has("/a")); + assert(parkToy(one,"/b",2) && !one.has("/a") && one.evictAll()==1); + } + assert(parkToy(table,"/a",1) && parkToy(table,"/b",2) && table.evictAll()==2); + assert(table.count==0 && table.bytes==0); + // Looking without taking; evicting by a test of the module itself - only + // the slots it names, released, the rest left exactly where they were. + assert(parkToy(table,"/a",1) && parkToy(table,"/b",2) && parkToy(table,"/c",3)); + assert(table.peek("/b") && table.peek("/b")->id==2 && !table.peek("/x") && table.count==3); + const unsigned released=toyReleases; + assert(table.evictIf([](const Toy& t){ return t.id!=2; })==2); + assert(table.count==1 && table.has("/b") && toyReleases==released+2 && table.bytes==10); + assert(table.evictIf([](const Toy&){ return false; })==0 && table.count==1); + assert(takeToy(table,"/b")==2 && table.count==0); + for(int i=0; i(heap_caps_malloc( + CODE+LINE, codeExternal ? MALLOC_CAP_SPIRAM : MALLOC_CAP_INTERNAL|MALLOC_CAP_EXEC)); + assert(block); + uint8_t* code=codeExternal ? block+16 : block; + LoadedSection& text=sections[sectionCount++]; + text.index=1; text.size=(uint32_t)CODE; text.memory=code; text.block=block; + text.exec=codeExternal ? (uintptr_t)code+0x06000000u : (uintptr_t)code; + text.executable=true; + uint8_t* bytes=static_cast(heap_caps_calloc( + 1,data,dataInternal ? MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT : MALLOC_CAP_SPIRAM)); + assert(bytes); + LoadedSection& rodata=sections[sectionCount++]; + rodata.index=2; rodata.size=(uint32_t)data; rodata.memory=bytes; + (codeExternal ? lastPsramBytes : lastInternalBytes)+=(uint32_t)(CODE+LINE); + (dataInternal ? lastInternalBytes : lastPsramBytes)+=(uint32_t)data; + lastCodeExternal=codeExternal; + lastCodeBytes=(uint32_t)CODE; + lastReadUs=1000u*which+1; lastRelocateUs=1000u*which+2; + lastSetupUs=1000u*which+3; lastTotalUs=1000u*which+6; + active=&descriptors[which]; + PFCrash::running(path,path); + PFCrash::code(text.exec,text.size); +} + +static bool same(const ResidentModule& a, const ResidentModule& b) { + if(a.sectionCount!=b.sectionCount || a.moduleAllocCount!=b.moduleAllocCount) return false; + for(int i=0; i0 && resident.count==0 && resident.bytes==0 && resident.resumes==1); + assert(PFCrash::owner==asked && !strcmp(PFCrash::slug,A) && PFCrash::phase==PFCrash::IDLE); + assert(PFCrash::codeBase==sections[0].exec && PFCrash::codeSize==sections[0].size); + assert(frees==freesParked && psramUsed==withA); + // ...and it goes on allocating as itself. + assert(moduleAlloc(50) && runtimeBytes==150 && moduleAllocCount==2); + + // Leaving it again: /api/status's load.resumed describes the module on the + // panel, and with a preset there it is false - the timings stay as A had + // them. + leave(); + assert(!resumed && lastResumeUs==0 && lastTotalUs==6 && isParked(A)); + + // Resuming over a current module would orphan it: refused. + fakeLoad(B,1,512); + assert(!resume(A) && active==&descriptors[1] && isParked(A)); + + // Not kept, so unloaded, and every byte comes back: any internal RAM at + // all, a file that may have changed, code that never left internal RAM. + const size_t internalBaseline=internalFree; + const unsigned beforeNotKept=resident.count; + fakeLoad(C,2,512,true); + assert(!parkable()); + leave(); + assert(nothingCurrent() && resident.count==beforeNotKept && internalFree==internalBaseline); + fakeLoad(C,2,512,false,false); + assert(!parkable()); + leave(); + assert(!isParked(C) && internalFree==internalBaseline); + fakeLoad(C,2,512); + psramRefuses=true; + assert(moduleAlloc(64) && runtimeInternalBytes==64); // the internal fallback + psramRefuses=false; + assert(!parkable()); + leave(); + assert(!isParked(C) && internalFree==internalBaseline); + + // A module file written, from any task: one atomic add, nothing freed. + // A is parked from before it, so A is never resumed again - isParked() and + // resume() say no while its slot is still held - and the running C, loaded + // before it too, is unloaded when left rather than parked. + fakeLoad(A,0,512); leave(); + assert(isParked(A) && resident.count==1); + fakeLoad(C,2,512); + const size_t beforeWrite=psramUsed; + const unsigned freesBeforeWrite=frees; + noteStorageWrite(); + assert(frees==freesBeforeWrite && psramUsed==beforeWrite && resident.count==1); + assert(!isParked(A) && !parkable()); + leave(); + assert(nothingCurrent() && !resume(A) && nothingCurrent() && resident.count==1); + // The loop evicts it the next time it owns the table: here, a park. A + // module loaded after the write is kept as usual. + const unsigned evictionsBefore=resident.evictions; + fakeLoad(B,1,512); + assert(parkable()); + leave(); + assert(isParked(B) && resident.count==1 && resident.evictions==evictionsBefore+1); + // ...or a fresh load making room, or a module's own allocation. + noteStorageWrite(); + makeRoom(); + assert(resident.count==0 && resident.evictions==evictionsBefore+2); + fakeLoad(B,1,512); leave(); + fakeLoad(C,2,512); + noteStorageWrite(); + assert(moduleAlloc(16) && resident.count==0 && resident.evictions==evictionsBefore+3); + leave(); + // A module parked and resumed keeps the generation it loaded under. + fakeLoad(A,0,512); leave(); + assert(resume(A) && parkable()); + noteStorageWrite(); + assert(!parkable()); + leave(); + // The rebuild after a write: stale parked copies go, and so does the + // running module, unloaded, when it is one of them. After a rebuild with + // nothing written since, nothing is touched. + fakeLoad(B,1,512); leave(); + fakeLoad(C,2,512); + assert(!dropStale() && active==&descriptors[2] && isParked(B)); + noteStorageWrite(); + assert(dropStale() && nothingCurrent() && resident.count==0); + assert(!dropStale()); + + // Evicting a parked module frees exactly what unloading it would have: + // the heap is back where it was before it loaded. + const size_t empty=psramUsed; + fakeLoad(A,0,512); + assert(moduleAlloc(200)); + leave(); + assert(psramUsed>empty && resident.count==1); + const unsigned evictedBefore=resident.evictions; + dropParked(); + assert(psramUsed==empty && resident.count==0 && resident.evictions==evictedBefore+1); + + // A full table (3 here) makes room by its least recently used - never the + // one the caller is about to resume. + fakeLoad(A,0,512); leave(); + fakeLoad(B,1,512); leave(); + fakeLoad(C,2,512); leave(); + assert(resident.count==3); + fakeLoad(D,3,512); + const unsigned evicted=resident.evictions; + leave(A); // A is the oldest: B goes instead + assert(resident.count==3 && isParked(A) && !isParked(B) && isParked(C) && isParked(D)); + assert(resident.evictions==evicted+1 && resume(A) && active==&descriptors[0]); + + // The same file parked twice is one slot: the older copy goes, whole. + leave(); // A parked again: table C, D, A + fakeLoad(A,4,512); // a second copy of the same file + const size_t twoCopies=psramUsed; + leave(); + assert(resident.count==3 && isParked(A) && psramUsed=floorBytes); + // A floor that cannot be met empties the table, and goes no further. + psramSize=psramUsed+100; + makeRoom(); + assert(resident.count==0 && heap_caps_get_free_size(MALLOC_CAP_SPIRAM)alloc() while modules are parked may not leave less than the + // headroom free: parked modules go, oldest first, only as many as that + // takes, and the allocation is in PSRAM. + const size_t headroom=PF_MODULE_RESIDENT_HEADROOM; + psramSize=psramUsed+3*footprint+2000; + fakeLoad(A,0,2000); leave(); + fakeLoad(B,1,2000); leave(); + fakeLoad(C,2,2000); // C runs with 2000 bytes free + const uint32_t refusals=PFModuleMemory::refusals; + assert(moduleAlloc(500) && isParked(A) && isParked(B)); // leaves 1500: nothing goes + assert(moduleAlloc(700) && !isParked(A) && isParked(B)); // would leave 800: A goes + assert(heap_caps_get_free_size(MALLOC_CAP_SPIRAM)>=headroom); + assert(runtimeInternalBytes==0 && runtimeBytes==1200 && PFModuleMemory::refusals==refusals); + leave(); + dropParked(); + // When evicting every parked module cannot give it the headroom, the + // allocation still gets what is free, as it would have before residency: + // the headroom is never a refusal. + const size_t small=CODE+LINE+100; + psramSize=psramUsed+3*small+100; + fakeLoad(A,0,100); leave(); + fakeLoad(B,1,100); leave(); + fakeLoad(C,2,100); // C runs with 100 bytes free + assert(moduleAlloc(500) && resident.count==0 && runtimeInternalBytes==0); + assert(heap_caps_get_free_size(MALLOC_CAP_SPIRAM)=headroom); + dropParked(); + psramSize=psramUsed+footprint+600; + fakeLoad(A,0,2000); // alone, 600 bytes free + leave(); + assert(resident.count==0 && nothingCurrent()); + psramSize=psramUsed+2*footprint+600; + fakeLoad(A,0,2000); leave(); + fakeLoad(B,1,2000); // B runs with 600 bytes free + leave(A); // `keep` survives the floor + assert(isParked(A) && !isParked(B) && nothingCurrent()); + dropParked(); + // PSRAM that refuses for want of a block, with plenty free: the refusal + // costs the oldest parked module and PSRAM is asked again, before the + // internal heap is - and no refusal is counted for a request that ended in + // PSRAM. + psramSize=psramUsed+3*footprint+20000; + fakeLoad(A,0,2000); leave(); + fakeLoad(B,1,2000); leave(); + fakeLoad(C,2,2000); + psramNoBlock=1; + assert(moduleAlloc(100) && !isParked(A) && isParked(B)); + assert(runtimeInternalBytes==0 && PFModuleMemory::refusals==refusals); + // Nothing left to give back: data()'s internal fallback, as before + // residency, and the module can no longer be kept. + psramNoBlock=3; + assert(moduleAlloc(16) && resident.count==0 && runtimeInternalBytes==16 && !parkable()); + psramNoBlock=0; + leave(); + + // Everything given back. + dropParked(); unload(); + psramSize=64*1024; + assert(internalOwned.empty() && internalFree==100000); + assert(psramOwned.size()==1); // the table itself, kept for the boot +} + +int main() { + bookkeeping(); + loader(); + puts("PASS: resident table (park/take/peek/LRU/keep/double park/evict-until/evict-if/no table) and the loader's park/resume/unload/evict, storage generation, floor, alloc headroom and backstop"); +} diff --git a/firmware/toolchain/tests/runtime_test.cpp b/firmware/toolchain/tests/runtime_test.cpp index 879dc718..decb73b5 100644 --- a/firmware/toolchain/tests/runtime_test.cpp +++ b/firmware/toolchain/tests/runtime_test.cpp @@ -50,6 +50,7 @@ static void heap_caps_free(void* p) { free(p); } #include "core_module_memory.h" +#include "core_module_resident.h" #include "sidecar_name.h" using TaskHandle_t = void*; @@ -127,7 +128,8 @@ static bool posted() { return __atomic_load_n(&PFLoopSync::pendingFn,__ATOMIC_AC constexpr int MODULE_PATH_BYTES=96, MODULE_NAME_BYTES=64, NUM_PRESETS=1, PF_CUSTOM_SLOT_COUNT=0; struct PatternEntry { const char* name; const char* modulePath; }; -static PatternEntry entries[]={{"Origin",nullptr},{"A","/a.pfm"},{"B","/b.pfm"}}; +// C is past NUM_PATTERNS until the resident cases, which need a third module. +static PatternEntry entries[]={{"Origin",nullptr},{"A","/a.pfm"},{"B","/b.pfm"},{"C","/c.pfm"}}; static PatternEntry* patterns=entries; static int NUM_PATTERNS=3, activePatternIdx=1, currentPatternIdx=1, numModules=2; static char moduleNames[2][MODULE_NAME_BYTES]{}; @@ -136,22 +138,100 @@ static bool createFails=false, notified=false, reorder=false, removeB=false; static unsigned created=0; static unsigned retryPauseMs=0; static void vTaskDelay(unsigned ms) { retryPauseMs+=ms; } +// The loader at the registry's boundary: real residency bookkeeping +// (core_module_resident.h), a malloc'd block standing in for a module's +// memory so the sanitizers see every free. What a module IS and when the real +// loader parks one is resident_test.cpp's business; here it is whether the +// registry parks, resumes and drops at the right moments. namespace PFModuleLoader { struct Descriptor { const char* name; } descriptor{"loaded"}; inline Descriptor* active=&descriptor; -inline unsigned unloads=0, loads=0; +inline unsigned unloads=0, loads=0, resumes=0, makeRooms=0, drops=0; inline unsigned allocationFailures=0; inline bool invalidFile=false; -inline void unload() { ++unloads; active=nullptr; } -inline bool load(int,const char*) { +// The module loaded next may be kept; the current one may be kept. The boot +// module of the cases below holds no block and is never kept, so the cases +// written before residency see what they always did. +inline bool parkableLoads=true, currentParkable=false; +inline char* memory=nullptr; +inline char currentPath[96]{}; +// The storage generation, as the real loader keeps it: moved by every write, +// stamped on every load, carried through a park and a resume. +inline unsigned storage=0, currentGeneration=0; +inline void noteStorageWrite() { ++storage; } +struct Parked { Descriptor* active; char* memory; unsigned generation; }; +inline void releaseParked(Parked& parked) { free(parked.memory); parked.memory=nullptr; } +inline void* allocateTable(size_t bytes) { return calloc(1,bytes); } +// Two slots, so a third module fills the table. +inline PFModuleResident::Table table; +inline void unload() { + ++unloads; active=nullptr; free(memory); memory=nullptr; + currentPath[0]=0; currentParkable=false; +} +inline bool load(int,const char* path) { ++loads; + unload(); + currentGeneration=storage; if(invalidFile) return false; if(allocationFailures) { --allocationFailures; ++PFModuleMemory::refusals; return false; } - active=&descriptor; return true; + active=&descriptor; memory=static_cast(malloc(16)); + snprintf(currentPath,sizeof(currentPath),"%s",path); + currentParkable=parkableLoads; return true; } inline bool fail(const char*) { return false; } inline const char* error() { return "test"; } +inline bool parkable() { return active && memory && currentParkable && currentGeneration==storage; } +inline bool fresh(const Parked& parked) { return parked.generation==storage; } +inline void evictStale() { table.evictIf([](const Parked& parked){ return !fresh(parked); }); } +inline bool park(const char* keep=nullptr) { + if(!parkable()) return false; + evictStale(); + Descriptor* leaving=active; char* held=memory; const unsigned generation=currentGeneration; + if(!table.park(currentPath,16,[&](Parked& slot){ + slot.active=leaving; slot.memory=held; slot.generation=generation; },keep)) + return false; + active=nullptr; memory=nullptr; currentPath[0]=0; currentParkable=false; + return true; +} +inline void leave(const char* keep=nullptr) { if(!park(keep)) unload(); } +inline bool isParked(const char* path) { + const Parked* parked=table.peek(path); + return parked && fresh(*parked); +} +inline bool resume(const char* path) { + if(active || !isParked(path)) return false; + Parked back{}; + if(!table.take(path,[&](Parked& slot){ back=slot; })) return false; + active=back.active; memory=back.memory; currentParkable=true; currentGeneration=back.generation; + snprintf(currentPath,sizeof(currentPath),"%s",path); + ++resumes; return true; +} +inline void makeRoom() { ++makeRooms; evictStale(); } +inline void dropParked() { ++drops; table.evictAll(); } +inline bool dropStale() { + evictStale(); + if(!active || currentGeneration==storage) return false; + unload(); return true; +} } +// The sidecar cache's forget calls, lifted from the registry: what every +// module-file writer already calls, core and feature alike. +static const char* const MODULE_DIR="/patterns"; +static char (*sidecarPaths)[MODULE_PATH_BYTES]=nullptr; +static char (*sidecarNames)[MODULE_NAME_BYTES]=nullptr; +static bool* sidecarAbs=nullptr; +static int sidecarCount=0; +// sidecarForgetPath() compacts by copying the last slot over slot i, under +// `if (i != last)`; g++'s -Wrestrict does not follow the guard and calls the +// two slots possibly the same object. They are not, on the device or here. +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wrestrict" +#endif +#include "sidecar_forget.h" +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif static int xTaskCreatePinnedToCore(void(*)(void*),const char*,uint32_t,void*,unsigned,void** out,int) { if(createFails) return 0; ++created; *out=reinterpret_cast(3); return pdPASS; @@ -487,6 +567,148 @@ int main() { retryPauseMs=0; beforeLoads=PFModuleLoader::loads; loadPatternJob(); assert(!loadResult && PFModuleLoader::loads-beforeLoads==1 && retryPauseMs==0); + + // ── Resident modules (src/core_module_resident.h) ── + // Every write reported to the sidecar cache moves the storage generation: + // a path the cache never held is still a file written, and a format is + // every file at once. + { + sidecarPaths=static_cast(calloc(2,MODULE_PATH_BYTES)); + sidecarNames=static_cast(calloc(2,MODULE_NAME_BYTES)); + sidecarAbs=static_cast(calloc(2,sizeof(bool))); + const unsigned before=PFModuleLoader::storage; + sidecarForgetSlug("never_cached"); + assert(PFModuleLoader::storage==before+1); + snprintf(sidecarPaths[0],MODULE_PATH_BYTES,"%s","/patterns/x.pfm"); sidecarCount=1; + sidecarForgetSlug("x"); + assert(PFModuleLoader::storage==before+2 && sidecarCount==0); + sidecarCount=1; sidecarForgetAll(); + assert(PFModuleLoader::storage==before+3 && sidecarCount==0); + free(sidecarPaths); free(sidecarNames); free(sidecarAbs); + sidecarPaths=nullptr; sidecarNames=nullptr; sidecarAbs=nullptr; + } + // Back to the list the cases above started from, Origin running. + PFModuleLoader::invalidFile=false; PFModuleLoader::allocationFailures=0; + entries[1]={"A","/a.pfm"}; entries[2]={"B","/b.pfm"}; NUM_PATTERNS=3; removeB=false; + PFModuleLoader::unload(); PFModuleLoader::dropParked(); + activePatternIdx=0; loadQueuedIdx=-1; loadTargetIdx=-1; loadFinished=false; + assert(!loadInFlight && !patternLoadsHeld); + // A loads on the worker, as it always did. + notified=false; + assert(activatePatternAsync(1) && loadInFlight && notified); + loadPatternJob(); serviceAsyncLoad(); + assert(activePatternIdx==1 && PFModuleLoader::active && !loadInFlight); + const unsigned loadsWithA=PFModuleLoader::loads; + // Leaving it for a preset parks it: nothing freed, nothing loaded. + assert(switchesInstantly(0)); + assert(activatePatternAsync(0) && activePatternIdx==0 && !PFModuleLoader::active); + assert(PFModuleLoader::isParked("/a.pfm") && PFModuleLoader::table.count==1); + // Coming back resumes it inside the call, on this task: no worker, no load, + // no thumbnail frame in between - and the name slot is refreshed as a load + // refreshes it. + notified=false; moduleNames[0][0]=0; + assert(isResidentOrPreset(1) && switchesInstantly(1)); + assert(activatePatternAsync(1)); + assert(activePatternIdx==1 && PFModuleLoader::active && !loadInFlight && !notified); + assert(PFModuleLoader::loads==loadsWithA && PFModuleLoader::resumes==1); + assert(PFModuleLoader::table.count==0 && !strcmp(moduleNames[0],"loaded")); + // A module that is not parked still loads on the worker; the outgoing one + // is parked before the worker starts, and room is made for the incoming. + const unsigned rooms=PFModuleLoader::makeRooms; + notified=false; + assert(!isResidentOrPreset(2) && !switchesInstantly(2)); + assert(activatePatternAsync(2) && loadInFlight && notified && activePatternIdx==-1); + assert(PFModuleLoader::isParked("/a.pfm") && PFModuleLoader::makeRooms==rooms+1); + // The worker owns the table now: the loop answers nothing from it, and no + // switch is instant, presets included - it would only be queued. + assert(!isResidentOrPreset(1) && isResidentOrPreset(0)); + assert(!switchesInstantly(0) && !switchesInstantly(1)); + // A request for A while B loads waits its turn, then resumes A rather + // than loading it, and parks B on the way. + assert(activatePatternAsync(1) && loadQueuedIdx==1); + loadPatternJob(); serviceAsyncLoad(); + assert(activePatternIdx==1 && !loadInFlight && PFModuleLoader::resumes==2); + assert(PFModuleLoader::loads==loadsWithA+1); + assert(PFModuleLoader::isParked("/b.pfm") && !PFModuleLoader::isParked("/a.pfm")); + // Leaving a module that cannot be kept would cost its whole load when the + // knob came back, so SELECT does not switch away from it on a detent. + PFModuleLoader::currentParkable=false; + assert(!switchesInstantly(0) && !switchesInstantly(2)); + PFModuleLoader::currentParkable=true; + // The boot path (synchronous) resumes too, and parks what it leaves. + assert(activatePattern(2) && activePatternIdx==2 && PFModuleLoader::resumes==3); + assert(PFModuleLoader::isParked("/a.pfm") && PFModuleLoader::loads==loadsWithA+1); + assert(activatePattern(1) && PFModuleLoader::resumes==4 && PFModuleLoader::isParked("/b.pfm")); + // A storage mutation starts with nothing in memory: the running module AND + // every parked one, since a file may be replaced or deleted from here on - + // the parked ones even when a preset is what keeps running through it. + assert(activatePatternAsync(0) && PFModuleLoader::isParked("/a.pfm")); + assert(Manager::captureSelectionOnce()); + assert(PFModuleLoader::table.count==0 && activePatternIdx==0); + assert(Manager::restoreSelection() && activePatternIdx==0 && !loadInFlight); + assert(activatePatternAsync(1)); loadPatternJob(); serviceAsyncLoad(); + assert(activePatternIdx==1); + assert(Manager::captureSelectionOnce()); + assert(PFModuleLoader::table.count==0 && !PFModuleLoader::active && activePatternIdx==-1); + assert(Manager::restoreSelection()); + assert(loadInFlight && loadTargetIdx==1); // a fresh load, not a resume + loadPatternJob(); serviceAsyncLoad(); + assert(activePatternIdx==1 && PFModuleLoader::loads==loadsWithA+3); + // A rebuild with nothing written since touches nothing: restorePath is + // A's (from the capture), A is parked and loaded from the storage as it is, + // so it is resumed, and B is parked on the way. + assert(activatePatternAsync(2)); loadPatternJob(); serviceAsyncLoad(); + assert(activePatternIdx==2 && PFModuleLoader::isParked("/a.pfm")); + unsigned resumesBefore=PFModuleLoader::resumes; + assert(Manager::restoreSelection()); + assert(!loadInFlight && activePatternIdx==1 && PFModuleLoader::resumes==resumesBefore+1); + assert(PFModuleLoader::isParked("/b.pfm")); + // A writer that does not empty memory first - a feature installing a + // pattern - reports the write through sidecarForgetSlug(), which moves the + // storage generation. From that moment nothing loaded before it comes back + // from memory: not the parked B, and not by an instant SELECT detent - not + // even onto a preset, because leaving A would now cost its reload. + PFModuleLoader::noteStorageWrite(); + assert(!PFModuleLoader::isParked("/b.pfm") && !isResidentOrPreset(2)); + assert(!switchesInstantly(2) && !switchesInstantly(0)); + notified=false; + assert(activatePatternAsync(2) && loadInFlight && notified && loadTargetIdx==2); + assert(PFModuleLoader::table.count==0); // A unloaded, stale B evicted + loadPatternJob(); serviceAsyncLoad(); + assert(activePatternIdx==2); + // And the rebuild the write asks for does not leave the old code running + // under the new file's name, even when the restore lands on the pattern + // that is already on the panel: it is unloaded, and loaded from the file. + assert(activatePatternAsync(1)); loadPatternJob(); serviceAsyncLoad(); + assert(activePatternIdx==1 && PFModuleLoader::isParked("/b.pfm")); + PFModuleLoader::noteStorageWrite(); + const unsigned unloadsBefore=PFModuleLoader::unloads, loadsBefore=PFModuleLoader::loads; + assert(Manager::restoreSelection()); // restorePath is still A's + assert(PFModuleLoader::table.count==0 && PFModuleLoader::unloads==unloadsBefore+1); + assert(loadInFlight && loadTargetIdx==1 && activePatternIdx==-1); + loadPatternJob(); serviceAsyncLoad(); + assert(activePatternIdx==1 && PFModuleLoader::loads==loadsBefore+1); + // A refused load gets every parked module back before it retries. + assert(activatePatternAsync(0) && PFModuleLoader::isParked("/a.pfm")); + const unsigned dropsBefore=PFModuleLoader::drops; + loadTargetIdx=2; PFModuleLoader::allocationFailures=1; retryPauseMs=0; + loadPatternJob(); + assert(loadResult && PFModuleLoader::table.count==0 && PFModuleLoader::drops==dropsBefore+1); + PFModuleLoader::dropParked(); PFModuleLoader::unload(); + // A full table makes room by its least recently used module - never the + // one the switch is about to resume, even when that one is the oldest. + NUM_PATTERNS=4; activePatternIdx=0; + assert(activatePatternAsync(1)); loadPatternJob(); serviceAsyncLoad(); + assert(activatePatternAsync(2)); loadPatternJob(); serviceAsyncLoad(); + assert(activatePatternAsync(3)); loadPatternJob(); serviceAsyncLoad(); + assert(activePatternIdx==3 && PFModuleLoader::table.count==2); + assert(PFModuleLoader::isParked("/a.pfm") && PFModuleLoader::isParked("/b.pfm")); + resumesBefore=PFModuleLoader::resumes; + notified=false; + assert(activatePatternAsync(1) && !loadInFlight && !notified); + assert(activePatternIdx==1 && PFModuleLoader::resumes==resumesBefore+1); + assert(PFModuleLoader::isParked("/c.pfm") && !PFModuleLoader::isParked("/b.pfm")); + PFModuleLoader::dropParked(); PFModuleLoader::unload(); delete PFLoopSync::doneSignal; delete PFLoopSync::callerLock; - puts("PASS: reserve/fallback/fragmentation/race, deferred loop requests, stalled-loop hand-off, task failure, mutation hold, rescan and deleted selection"); + puts("PASS: reserve/fallback/fragmentation/race, deferred loop requests, stalled-loop hand-off, task failure, mutation hold, rescan and deleted selection, park/resume/drop around loads, storage mutations and writes nobody captured for"); } From 52da8f2ff568fec562d59a0bda61ae2e7376ecff Mon Sep 17 00:00:00 2001 From: engmung <122682380+engmung@users.noreply.github.com> Date: Sat, 3 Oct 2026 11:53:52 +0900 Subject: [PATCH 02/10] firmware: the console is light, and its six core pages look like one thing Light by default with dark kept as the remembered toggle; one base block of shared parts across Console, Patterns, Status, Wi-Fi, Knobs and Update; home leads with the panel's controls; the header wraps instead of scrolling on a phone; the monospace stack gains Windows fonts. No page grew past its gzip size. Feature pages are untouched and take the light palette from the chrome. The guide's console demo is regenerated. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 4 + firmware/patternflow/console/README.md | 22 + firmware/patternflow/console/home.html | 728 ++--- firmware/patternflow/console/knobs.html | 129 +- firmware/patternflow/console/patterns.html | 504 ++-- firmware/patternflow/console/status.html | 287 +- firmware/patternflow/console/update.html | 157 +- firmware/patternflow/console/wifi.html | 341 +-- .../features/audio_in/audio_in_index.h | 2472 ++++++++--------- .../patternflow/features/clock/clock_index.h | 430 +-- .../patternflow/features/midi/midi_index.h | 882 +++--- .../patternflow/features/mqtt/mqtt_index.h | 752 ++--- .../patternflow/features/show/show_index.h | 1066 +++---- .../features/weather/weather_index.h | 534 ++-- firmware/patternflow/src/home_index.h | 2011 ++++++-------- firmware/patternflow/src/knobs_index.h | 576 ++-- firmware/patternflow/src/patterns_index.h | 2414 ++++++++-------- firmware/patternflow/src/status_index.h | 1053 ++++--- firmware/patternflow/src/theme_index.h | 1342 ++++----- firmware/patternflow/src/web_update_index.h | 959 ++++--- firmware/patternflow/src/wifi_index.h | 1477 +++++----- firmware/toolchain/console_demo.py | 13 +- web/public/guide/console-demo/index.html | 730 ++--- web/public/guide/console-demo/knobs.html | 131 +- web/public/guide/console-demo/patterns.html | 506 ++-- web/public/guide/console-demo/pf-console.js | 92 +- web/public/guide/console-demo/pf-demo.js | 15 +- web/public/guide/console-demo/status.html | 290 +- web/public/guide/console-demo/update.html | 159 +- web/public/guide/console-demo/wifi.html | 343 +-- .../components/guide/ConsoleWindow.module.css | 8 +- 31 files changed, 9508 insertions(+), 10919 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a051000..cca5d670 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to Patternflow will be documented in this file, newest first ## [Unreleased] +### Firmware + +- **The console is light, and its six core pages look like one thing.** It opens light; dark is still the toggle in the header, and a choice made there is remembered. Console, Patterns, Status, Wi-Fi, Knobs and Update now share one set of parts - buttons, chips, list rows, fields, notices, section titles - from a base block every page opens with (`console/README.md`, "The look"), with one accent, the LED orange, kept for what is live: the current tab, the playing pattern, the panel being on. The home page leads with the panel itself: what is playing with its arrows, on/sleep, brightness and the four knobs, then the device's facts in compact rows; the numbered index of every page with a paragraph each is now a list of one-line links. The header no longer scrolls sideways on a phone: Console and Patterns, the build's own feature pages, then Wi-Fi, Knobs, Update and Status, wrapped onto rows. Long explanations are a line, with the rest behind a disclosure where it is needed. Windows showed every small label in Courier New because no font in the monospace list was a Windows one; the list now includes Cascadia Mono and Consolas. The Status page shows the crash record (`crash` in `/api/status`) when there is one, with a button to clear it. Feature pages are not edited and take the light palette from the header. No page grew: home is 8.4 KB gzipped (was 10.9), the others are the same or slightly smaller, the header script is 9.6 KB, and the default image is 2.9 KB smaller. On a panel on the home network a page still opens in about 0.1 s the first time and in under 0.01 s after. Every request, control and message the pages had is still there; checked on a panel by stepping through patterns, sleeping and waking it, dimming it, dragging a knob and playing a pattern from the list. The guide's live console demo is regenerated to match. + ## [3.10.5] - 2026-10-02 ### Firmware diff --git a/firmware/patternflow/console/README.md b/firmware/patternflow/console/README.md index 4b9a2ea3..502a80e6 100644 --- a/firmware/patternflow/console/README.md +++ b/firmware/patternflow/console/README.md @@ -68,6 +68,28 @@ is editable the same way. The chrome draws itself inside a shadow root page, so do not style or query its insides. What a page may use is `window.PF`, below. +## The look + +The console is light unless someone picks dark. The choice is the toggle in +the header, kept in `localStorage` as `pf-theme`, and the chrome sets +`data-theme` on `` before the first paint. Every core page opens its +` - - -
-

Console

device
- - +
+
-
-
-
- Now playing +
+
+
+

Now playing

-
- - -
+ +
—
-
- - -
- Panel -
- - -
-
-
-
- Brightness - - — -
- -
-
- Live Knobs - -
-
- K1 - -
-
- K2 - -
-
- K3 - -
-
- K4 - +
+ +
+
+ Panel +
+ + +
+
+
—
+
-
-
Patterns
—
-
Storage
—
-
-
Wi-Fi
—
-
Address
—
- - -
Memory
—
-
Uptime
—
-
Firmware
—
- - - Edition -
—
-
-
+
+
Knobs
+
+
+
+
- - update - how to update → + release manifest and hands the new image to this board over Wi-Fi. --> +
- @@ -330,85 +159,68 @@ function $(i){return document.getElementById(i)} $('host').textContent=location.hostname; +// A range's filled part (--p) follows its value. +function fill(el){el.style.setProperty('--p',(el.value-el.min)/(el.max-el.min)*100+'%')} +document.addEventListener('input',function(e){if(e.target.type==='range')fill(e.target)}); + // ── What this build actually has ─────────────────────────────── -// Feature rows are not written into this page. Whatever features the firmware -// carries report their pages in /api/status featureNav — path, label, one -// line — and the Features group is built from that. A build with none gets -// no group, and a page the core has never heard of still gets a row. This -// used to work the other way round: rows for every feature in the markup, -// deleted when the capability was absent, which meant a core page naming -// features and a new feature's page getting no row at all. -// -// Rebuilt from scratch whenever featureNav changes (not on every status: the -// card polls, and a rebuild under the pointer drops hover and focus), then -// everything renumbers so the list still reads 01, 02, 03. +// Feature rows come from /api/status featureNav (path, label, one line), +// contributed by whatever features the firmware carries; a build with none +// gets none, and a page the core never heard of still gets a row. Rebuilt +// only when featureNav changes: the card polls, and a rebuild under the +// pointer drops hover and focus. var navKey; function gate(s){ - var i,nav=(s&&s.featureNav)||[],k=JSON.stringify(nav); + var i,nav=(s&&s.featureNav)||[],k=JSON.stringify(nav),f=$('featRows'); if(k===navKey)return; navKey=k; - var f=$('featRows'),fk=$('featKick'); - if(f){ - f.innerHTML=''; - for(i=0;i
'; - a.querySelector('.pf-row-t').textContent=e[1]; - a.querySelector('.pf-row-d').textContent=e[2]||''; - f.appendChild(a); - } - f.hidden=fk.hidden=!f.querySelector('.pf-row'); + f.innerHTML=''; + for(i=0;i'; + a.firstChild.textContent=e[1]; + a.lastChild.textContent=e[2]||''; + f.appendChild(a); } - var ghosts=document.querySelectorAll('.rows .pf-ghost'); - for(i=0;i 100) v = 100; - var sl = $('sl-' + i); - if (sl) { - sl.value = v; - lastReported[i] = v; - } +// ── Knob sliders (K1..K4 · 0..100) ──────────────────────────── +var activeSlider=-1,inFlight=false,queuedParams={}; +function updateSliders(params){ + if(!params||params.length<4)return; + for(var i=0;i<4;i++){ + if(activeSlider===i)continue; + var v=Math.round(params[i]/10); + if(v<0)v=0;if(v>100)v=100; + var sl=$('sl-'+i);sl.value=v;fill(sl); } } - -function pumpParams() { - if (inFlight) return; // Drop redundant updates while in-flight; keep newest in queue - var keys = Object.keys(queuedParams); - if (!keys.length) return; - - var bodyParts = []; - for (var i = 0; i < keys.length; i++) { - var k = keys[i]; - bodyParts.push(k + '=' + encodeURIComponent(queuedParams[k])); - } - queuedParams = {}; - inFlight = true; - - fetch('/api/params', { - method: 'POST', - cache: 'no-store', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - body: bodyParts.join('&') - }).then(function(r) { - if (!r.ok) throw Error('refused'); - $('ctrlmsg').textContent = ''; - }).catch(function(x) { - // Next to the sliders, not swallowed: a drag that never arrived looks - // exactly like a pattern ignoring its knobs. - PF.say('not sent — ' + (x && x.message === 'refused' ? 'refused' : 'no answer'), 'err', $('ctrlmsg')); - }).then(function() { - inFlight = false; - if (Object.keys(queuedParams).length) { - pumpParams(); // Flush pending latest updates - } - }); -} - -function onSliderInput(idx, val) { - var v = parseInt(val, 10); - if (isNaN(v)) return; - lastReported[idx] = v; - - // pX on the 0..1000 bus. The device derives the clicks a legacy pattern - // reads from the change in the held value, so no dX alongside — sending - // both counted every move twice. - queuedParams['p' + (idx + 1)] = v * 10; - - pumpParams(); -} - -function initSliders() { - for (var i = 0; i < 4; i++) { - (function(idx) { - var sl = $('sl-' + idx); - if (!sl) return; - held(sl, function() { activeSlider = idx; }, function() { - if (activeSlider === idx) activeSlider = -1; - pumpParams(); - }); - sl.addEventListener('input', function() { - var v = sl.value; - onSliderInput(idx, v); - }); - })(i); - } +function pumpParams(){ + if(inFlight)return; // one in flight; the newest values wait in the queue + var keys=Object.keys(queuedParams),body=[],i; + if(!keys.length)return; + for(i=0;i 0 ? 'Next…' : 'Prev…'; - PF.get('/api/patterns/select?step=' + dir).then(function(d) { - $('now').textContent = d.name || prev; - $('nowsub').textContent = 'switched'; - $('stepmsg').textContent = ''; - }, function(x) { - $('now').textContent = prev; - if (!x || !x.nav) - PF.say(x && x.status === 404 ? 'nothing to switch to' : 'not switched', 'err', $('stepmsg')); +function stepPattern(dir){ + var prev=$('now').textContent; + $('now').textContent=dir>0?'Next…':'Prev…'; + PF.get('/api/patterns/select?step='+dir).then(function(d){ + $('now').textContent=d.name||prev; + $('nowsub').textContent='switched'; + $('stepmsg').textContent=''; + },function(x){ + $('now').textContent=prev; + if(!x||!x.nav) + PF.say(x&&x.status===404?'nothing to switch to':'not switched','err',$('stepmsg')); }); } -$('pat-prev').addEventListener('click', function() { stepPattern(-1); }); -$('pat-next').addEventListener('click', function() { stepPattern(1); }); +$('pat-prev').addEventListener('click',function(){stepPattern(-1)}); +$('pat-next').addEventListener('click',function(){stepPattern(1)}); +[].forEach.call(document.querySelectorAll('input[type=range]'),fill); PF.watchStatus(3000); PF.status(paint); diff --git a/firmware/patternflow/console/knobs.html b/firmware/patternflow/console/knobs.html index 09f78bbe..112fd45d 100644 --- a/firmware/patternflow/console/knobs.html +++ b/firmware/patternflow/console/knobs.html @@ -5,93 +5,70 @@ Patternflow - Knobs
-

Knobs

-
-
-

Direction and click size

- - - -
PositionDirectionEdges per click
-
- - -
-
-

Turn a knob clockwise. Its position should go up by one per click. - Goes down: set that knob to Reversed. Moves two per click, or needs two clicks to - move one: change Edges per click until one click is one step (most encoders are 4; - the edge counter under the position shows how many one click really makes). - These are properties of the encoder soldered in, stored on the device — nothing to - rebuild, and a saved change does not move the knob.

-
- +.pf-offline .pos,.pf-offline #st{opacity:.5} + +
+

Knobs

-
+

Turn a knob one click clockwise: its position should go up by one.

+ + + +
PositionDirectionEdges per click
+
+ + +
+

Goes down: set it to Reversed. Moves two, or takes two clicks to move one: +change edges per click (most encoders are 4; the edge count under the position shows how many one click makes). +Saved on the panel: nothing to rebuild, and saving does not move a knob.

+ +
diff --git a/firmware/patternflow/console/patterns.html b/firmware/patternflow/console/patterns.html index f3f4fc16..73f90221 100644 --- a/firmware/patternflow/console/patterns.html +++ b/firmware/patternflow/console/patterns.html @@ -5,190 +5,145 @@ Patternflow - Patterns
-

Patterns

-
- - - -
-

Storage needs formatting

-

This board's pattern partition isn't readable — either it has never been - formatted, or its filesystem is damaged. Format it once, and patterns install - normally from then on.

-
- - -
+/* Touch: no drag and drop on a phone, so arrows instead, in the room the + module chip leaves (the checkbox says it is a module). Narrow buttons keep + the name wide; their 40px hit areas meet in the 6px gaps. */ +@media(pointer:coarse){.btn.mv{display:inline-flex;width:34px;padding:0;font-size:16px}.chip.mod,.fine{display:none} +.list>li{gap:6px;padding:4px 6px}.list .btn.sm::after{inset:-4px -3px}.list .dan{padding:0 8px}#bulk{row-gap:10px}} +@media(min-width:960px){.wrap{max-width:1080px;padding-top:32px} +.grid{display:grid;grid-template-columns:380px minmax(0,1fr);gap:48px;align-items:start} +.grid section{margin-top:0}.lc{position:sticky;top:8px}.q{max-height:55vh;overflow:auto}} + + +
+

Patterns

—
+ + + -
-
+
+

Upload

-
    +
    -
    -
    - -
    +
    -
    +
    -

    Installed

    -
    - - - - - +
    +

    Installed

    +
    -
    -
      +
        + +

        Tap or click a name to play it. Drag modules to reorder. Presets are built into the firmware and can’t be removed here.

        -
        Presets are built into the firmware and cannot be removed here. - Home
        -
        + +
        \ No newline at end of file + diff --git a/firmware/patternflow/console/status.html b/firmware/patternflow/console/status.html index 0d9e7325..cc126625 100644 --- a/firmware/patternflow/console/status.html +++ b/firmware/patternflow/console/status.html @@ -5,109 +5,105 @@ Patternflow - Status
        -

        Status

        -
        - - -
        - - -

        Device

        -
        Firmware
        -
        -
        Build
        -
        -
        Last restart
        -
        -
        Busy
        -
        -
        Panel size
        -
        +/* Console base: the same block opens every core page. Light in :root (the chrome's + injected light palette holds these same values: keep the two in step), + dark under html[data-theme=dark]. No web fonts: the hotspot has no internet. */ +:root{color-scheme:light;--cream:#F4EFE6;--panel:#FFFCFA;--ink:#1A1814;--muted:#625C51;--faint:#7D7668;--rule:#DDD5C6;--rule-soft:#E8E1D4;--ghost:#E3DCCE;--led:#FF5C2E;--bad:#B83C1C;--ok:#2B7A4B;--warn:#85600E; +--sans:system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;--mono:ui-monospace,'Cascadia Mono','SF Mono',Menlo,Consolas,'Roboto Mono',monospace} +html[data-theme=dark]{color-scheme:dark;--cream:#0C0B09;--panel:#131110;--ink:#EDE7DB;--muted:#A39B8A;--faint:#7A7364;--rule:#2B2721;--rule-soft:#1F1C18;--ghost:#2A2620;--bad:#FF7A55;--ok:#57B87F;--warn:#D9A03F} +*{box-sizing:border-box}[hidden]{display:none!important} +body{margin:0;background:var(--cream);color:var(--ink);font:15px/1.5 var(--sans);-webkit-font-smoothing:antialiased} +a{color:inherit}:focus-visible{outline:2px solid var(--led);outline-offset:2px} +.wrap{max-width:720px;margin:0 auto;padding:20px 16px 48px} +h2{margin:0 0 6px;font-size:13px;font-weight:600;color:var(--muted)} +.card{background:var(--panel);border:1px solid var(--rule);border-radius:10px;padding:16px} +.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:40px;padding:0 16px;border:1px solid var(--rule);border-radius:8px;background:var(--panel);color:var(--ink);font:500 14px var(--sans);text-decoration:none;cursor:pointer;transition:border-color .15s,background .15s,color .15s} +@media(hover:hover){.btn:hover{border-color:var(--ink)}footer a:hover{color:var(--ink)}} +.btn:disabled{opacity:.45;cursor:default;border-color:var(--rule)} +.msg{font:12px var(--mono);color:var(--faint)}.pf-ok{color:var(--ok)}.pf-err{color:var(--bad)} +footer{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:40px;border-top:1px solid var(--rule);font:12px var(--mono);color:var(--faint)} +footer a{display:inline-flex;align-items:center;min-height:40px;color:var(--muted);text-decoration:none} +header{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 12px;margin-bottom:20px} +h1{flex:1;margin:0;font-size:22px;font-weight:600;letter-spacing:-.01em} +.sub{font:12px var(--mono);color:var(--faint)} +section{margin-top:28px} +.note{margin:8px 0 0;font-size:13px;color:var(--muted)} +.btn.dan{color:var(--bad)}@media(hover:hover){.btn.dan:hover{border-color:var(--bad)}} +.acts{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:12px} +.kv{margin:0;border-top:1px solid var(--rule)} +.kv>div{display:flex;align-items:baseline;gap:12px;padding:8px 0;border-bottom:1px solid var(--rule-soft);font-size:13px} +.kv dt{flex:1 0 auto;color:var(--muted)}.kv dd{margin:0;min-width:0;font:12.5px var(--mono);text-align:right;overflow-wrap:anywhere} +/* ── Status ── */ +.kv .big{font-size:14px;font-weight:600} +.ok{color:var(--ok)}.warn{color:var(--warn)}.bad{color:var(--bad)} +.bar{display:block;height:3px;margin:5px 0 2px auto;max-width:160px;background:var(--ghost)}.bar i{display:block;height:100%;background:var(--led)} +#cptext{display:block;width:100%;height:180px;margin-top:12px;padding:8px 10px;resize:vertical;color:var(--ink);font:12px/1.45 var(--mono)} +.pf-offline .kv dd{opacity:.5} + +
        +

        Status

        -
        + +
        + + +

        Device

        +
        Firmware
        -
        +
        Build
        -
        +
        Last restart
        -
        +
        Busy
        -
        +
        Panel size
        -
        -

        Render

        -
        Panel
        -
        -
        Frame rate
        -
        -
        Frame time
        -
        -
        Active pattern
        -
        + + +

        Render

        +
        Panel
        -
        +
        Frame rate
        -
        +
        Frame time
        -
        +
        Active pattern
        -

        -

        Patterns

        -
        Total
        -
        -
        Built into firmware
        -
        -
        Loaded from storage
        -
        -
        Last load error
        -
        +

        Patterns

        +
        Total
        -
        +
        Built into firmware
        -
        +
        Loaded from storage
        -
        +
        Last load error
        -

        -

        Memory

        -
        Internal heap free
        -
        -
        Largest free block
        -
        -
        PSRAM free
        -
        +

        Memory

        +
        Internal heap free
        -
        +
        Largest free block
        -
        +
        PSRAM free
        -
        -

        Internal heap is the scarce one - the LED panel's DMA buffers -live there. A pattern module loads only if it leaves 24 KB -of it free; run lower and the network is the first thing to go, while the -panel keeps drawing.

        +

        Internal heap is the scarce one: the panel’s DMA buffers live there. A module loads only if it +leaves 24 KB free; below that the network goes first, while the panel keeps drawing.

        -

        Storage

        -
        Pattern storage
        -
        -
        Storage error
        -
        -
        +

        Storage

        +
        Pattern storage
        -
        +
        Storage error
        -
        +
        - -

        Network

        -
        Network
        -
        -
        Signal
        -
        -
        Address
        -
        -
        Names
        -
        -
        Hotspot
        -
        -
        Hotspot mode
        -
        -
        Hotspot clients
        -
        -
        Reached via
        -
        +

        Network

        +
        Network
        -
        +
        Signal
        -
        +
        Address
        -
        +
        Names
        -
        +
        Hotspot
        -
        +
        Hotspot mode
        -
        +
        Hotspot clients
        -
        +
        Reached via
        -
        - -
        + +
        + Patternflow - Mic mapping - -
        Memory
        —
        -
        Uptime
        —
        -
        Firmware
        —
        - - - Edition -
        —
        -
        -
        +
        +
        Knobs
        +
        +
        +
        +
        - - update - how to update → + release manifest and hands the new image to this board over Wi-Fi. --> + - @@ -361,85 +190,68 @@ const char HOME_INDEX_HTML[] PROGMEM = R"HTML( function $(i){return document.getElementById(i)} $('host').textContent=location.hostname; +// A range's filled part (--p) follows its value. +function fill(el){el.style.setProperty('--p',(el.value-el.min)/(el.max-el.min)*100+'%')} +document.addEventListener('input',function(e){if(e.target.type==='range')fill(e.target)}); + // ── What this build actually has ─────────────────────────────── -// Feature rows are not written into this page. Whatever features the firmware -// carries report their pages in /api/status featureNav — path, label, one -// line — and the Features group is built from that. A build with none gets -// no group, and a page the core has never heard of still gets a row. This -// used to work the other way round: rows for every feature in the markup, -// deleted when the capability was absent, which meant a core page naming -// features and a new feature's page getting no row at all. -// -// Rebuilt from scratch whenever featureNav changes (not on every status: the -// card polls, and a rebuild under the pointer drops hover and focus), then -// everything renumbers so the list still reads 01, 02, 03. +// Feature rows come from /api/status featureNav (path, label, one line), +// contributed by whatever features the firmware carries; a build with none +// gets none, and a page the core never heard of still gets a row. Rebuilt +// only when featureNav changes: the card polls, and a rebuild under the +// pointer drops hover and focus. var navKey; function gate(s){ - var i,nav=(s&&s.featureNav)||[],k=JSON.stringify(nav); + var i,nav=(s&&s.featureNav)||[],k=JSON.stringify(nav),f=$('featRows'); if(k===navKey)return; navKey=k; - var f=$('featRows'),fk=$('featKick'); - if(f){ - f.innerHTML=''; - for(i=0;i
        '; - a.querySelector('.pf-row-t').textContent=e[1]; - a.querySelector('.pf-row-d').textContent=e[2]||''; - f.appendChild(a); - } - f.hidden=fk.hidden=!f.querySelector('.pf-row'); + f.innerHTML=''; + for(i=0;i'; + a.firstChild.textContent=e[1]; + a.lastChild.textContent=e[2]||''; + f.appendChild(a); } - var ghosts=document.querySelectorAll('.rows .pf-ghost'); - for(i=0;i 100) v = 100; - var sl = $('sl-' + i); - if (sl) { - sl.value = v; - lastReported[i] = v; - } +// ── Knob sliders (K1..K4 · 0..100) ──────────────────────────── +var activeSlider=-1,inFlight=false,queuedParams={}; +function updateSliders(params){ + if(!params||params.length<4)return; + for(var i=0;i<4;i++){ + if(activeSlider===i)continue; + var v=Math.round(params[i]/10); + if(v<0)v=0;if(v>100)v=100; + var sl=$('sl-'+i);sl.value=v;fill(sl); } } - -function pumpParams() { - if (inFlight) return; // Drop redundant updates while in-flight; keep newest in queue - var keys = Object.keys(queuedParams); - if (!keys.length) return; - - var bodyParts = []; - for (var i = 0; i < keys.length; i++) { - var k = keys[i]; - bodyParts.push(k + '=' + encodeURIComponent(queuedParams[k])); - } - queuedParams = {}; - inFlight = true; - - fetch('/api/params', { - method: 'POST', - cache: 'no-store', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - body: bodyParts.join('&') - }).then(function(r) { - if (!r.ok) throw Error('refused'); - $('ctrlmsg').textContent = ''; - }).catch(function(x) { - // Next to the sliders, not swallowed: a drag that never arrived looks - // exactly like a pattern ignoring its knobs. - PF.say('not sent — ' + (x && x.message === 'refused' ? 'refused' : 'no answer'), 'err', $('ctrlmsg')); - }).then(function() { - inFlight = false; - if (Object.keys(queuedParams).length) { - pumpParams(); // Flush pending latest updates - } - }); -} - -function onSliderInput(idx, val) { - var v = parseInt(val, 10); - if (isNaN(v)) return; - lastReported[idx] = v; - - // pX on the 0..1000 bus. The device derives the clicks a legacy pattern - // reads from the change in the held value, so no dX alongside — sending - // both counted every move twice. - queuedParams['p' + (idx + 1)] = v * 10; - - pumpParams(); -} - -function initSliders() { - for (var i = 0; i < 4; i++) { - (function(idx) { - var sl = $('sl-' + idx); - if (!sl) return; - held(sl, function() { activeSlider = idx; }, function() { - if (activeSlider === idx) activeSlider = -1; - pumpParams(); - }); - sl.addEventListener('input', function() { - var v = sl.value; - onSliderInput(idx, v); - }); - })(i); - } +function pumpParams(){ + if(inFlight)return; // one in flight; the newest values wait in the queue + var keys=Object.keys(queuedParams),body=[],i; + if(!keys.length)return; + for(i=0;i 0 ? 'Next…' : 'Prev…'; - PF.get('/api/patterns/select?step=' + dir).then(function(d) { - $('now').textContent = d.name || prev; - $('nowsub').textContent = 'switched'; - $('stepmsg').textContent = ''; - }, function(x) { - $('now').textContent = prev; - if (!x || !x.nav) - PF.say(x && x.status === 404 ? 'nothing to switch to' : 'not switched', 'err', $('stepmsg')); +function stepPattern(dir){ + var prev=$('now').textContent; + $('now').textContent=dir>0?'Next…':'Prev…'; + PF.get('/api/patterns/select?step='+dir).then(function(d){ + $('now').textContent=d.name||prev; + $('nowsub').textContent='switched'; + $('stepmsg').textContent=''; + },function(x){ + $('now').textContent=prev; + if(!x||!x.nav) + PF.say(x&&x.status===404?'nothing to switch to':'not switched','err',$('stepmsg')); }); } -$('pat-prev').addEventListener('click', function() { stepPattern(-1); }); -$('pat-next').addEventListener('click', function() { stepPattern(1); }); +$('pat-prev').addEventListener('click',function(){stepPattern(-1)}); +$('pat-next').addEventListener('click',function(){stepPattern(1)}); +[].forEach.call(document.querySelectorAll('input[type=range]'),fill); PF.watchStatus(3000); PF.status(paint); )HTML"; // GENERATED by firmware/toolchain/console_pages.py build — do not edit. -// gzip -9 of HOME_INDEX_HTML (34460 bytes → 11493 bytes), served with Content-Encoding: gzip. +// gzip -9 of HOME_INDEX_HTML (25020 bytes → 8990 bytes), served with Content-Encoding: gzip. const uint8_t HOME_INDEX_HTML_GZ[] PROGMEM = { - 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xcd,0x7d,0xdb,0x76,0xdb,0x48, - 0x92,0xe0,0xbb,0xbe,0x22,0xcd,0x9a,0x12,0x88,0x12,0x08,0x92,0xba,0xb8,0x6c,0x52, - 0x94,0xc7,0x2e,0xdb,0x3d,0x1e,0x97,0x5d,0x6e,0xcb,0x35,0x35,0x53,0x3e,0xde,0x1e, - 0x90,0x48,0x92,0x68,0x81,0x00,0x1a,0x09,0x8a,0x62,0x4b,0x3c,0xa7,0x9f,0xe6,0x79, - 0xcf,0x9e,0xf9,0x86,0xfd,0x85,0x7d,0xdf,0x4f,0xa9,0x2f,0xd9,0xb8,0x64,0x02,0x09, - 0x5e,0x24,0xd9,0xee,0xde,0xee,0xea,0xb6,0x8d,0x4b,0x22,0x33,0x32,0x32,0xee,0x11, - 0x99,0x3c,0x7d,0x10,0xa6,0xa3,0x62,0x99,0x49,0x31,0x2d,0x66,0xf1,0xd9,0xde,0x29, - 0xfe,0x23,0xe2,0x20,0x99,0x0c,0x1a,0x32,0x69,0xe0,0x03,0x19,0x84,0xf0,0xcf,0x4c, - 0x16,0x81,0x18,0x4d,0x83,0x5c,0xc9,0x62,0xd0,0x98,0x17,0xe3,0xd6,0x23,0x7c,0xab, - 0x46,0x79,0x94,0x15,0x42,0xe5,0xa3,0x41,0xa3,0x9d,0x8d,0x5b,0xa3,0x34,0x51,0x69, - 0x2c,0xfd,0x3f,0xaa,0x27,0xd3,0x41,0xd8,0x39,0x1c,0x1e,0x1d,0x1d,0x1e,0x36,0xce, - 0x4e,0xdb,0xdc,0xf0,0x4c,0x7f,0x70,0x16,0x8d,0x9b,0x0f,0x16,0x51,0x12,0xa6,0x0b, - 0xff,0xdd,0x4b,0xb7,0x39,0x9e,0x27,0xa3,0x22,0x4a,0x93,0xa6,0x7b,0x7d,0x19,0xe4, - 0xe2,0x97,0x01,0xbf,0xf3,0x7e,0x1e,0x38,0xed,0x20,0x8b,0xda,0xaa,0x08,0x8a,0xb9, - 0x72,0xbc,0x1f,0x07,0x1f,0x3f,0x79,0x6f,0x06,0x87,0xf2,0xb1,0x77,0xee,0xfd,0xea, - 0xbd,0x1b,0xfc,0x02,0x9f,0x0f,0xae,0xf1,0xb5,0xec,0x39,0x71,0x74,0x29,0x1d,0x2f, - 0x8c,0xf2,0x62,0xd9,0x7b,0xd0,0xf5,0x2e,0x7b,0xc9,0x3c,0x8e,0xbd,0x89,0x2c,0x7a, - 0xbf,0xf3,0xa2,0x64,0x1c,0x47,0x93,0x69,0xd1,0x7b,0x3b,0x9f,0x0d,0x65,0xee,0x4d, - 0xd3,0x38,0xec,0xfd,0x34,0xfc,0xa3,0x1c,0x15,0x9e,0x0a,0x96,0xbd,0x12,0x82,0xc2, - 0xbb,0xf0,0xa4,0x7b,0x2d,0xf7,0xf7,0x9b,0xd2,0x2f,0xe4,0x55,0xf1,0x43,0x9a,0x14, - 0x32,0x29,0x06,0x85,0xbb,0xf2,0x86,0x73,0x65,0x35,0x1d,0x7a,0x99,0x7b,0x6d,0xee, - 0xc4,0x18,0x80,0x1f,0xfa,0x61,0xa4,0x82,0x61,0x2c,0xc3,0xc1,0x83,0xee,0xca,0xbe, - 0xeb,0xf4,0x33,0xbf,0x98,0xca,0xa4,0x39,0xf6,0xc6,0x6e,0x3f,0x97,0xc5,0x3c,0x4f, - 0x44,0xb6,0xf2,0xb2,0x34,0x8e,0xab,0x1e,0x95,0x37,0xf3,0x46,0x5e,0xca,0x58,0x28, - 0xbc,0xb1,0x37,0x19,0x74,0xfb,0xe5,0x08,0xef,0x61,0x84,0xc9,0xfe,0xfe,0x83,0x31, - 0xc0,0x36,0x1e,0x74,0xbd,0x51,0x2c,0x83,0xfc,0x43,0x34,0x93,0xe9,0xbc,0x68,0x16, - 0xae,0xd7,0x54,0xfe,0x28,0x88,0xe3,0x27,0xaa,0xe9,0xf6,0x7e,0xd7,0x54,0xae,0xab, - 0x47,0x34,0xbd,0x87,0xee,0xf5,0xa8,0x19,0x7a,0x88,0x15,0x98,0x4b,0xf9,0x58,0xe2, - 0x63,0x42,0x95,0x74,0x57,0xfa,0x9b,0xd7,0xde,0x6b,0xd7,0x5d,0x95,0x23,0xbf,0x86, - 0x91,0xc7,0x83,0x4e,0x7f,0x6d,0xc4,0x3e,0x40,0xd3,0x2c,0x06,0x40,0x12,0xe6,0xd9, - 0x7b,0x6f,0x06,0xdf,0xa5,0xfb,0xfb,0xa9,0x3f,0x8e,0x72,0x55,0x0c,0x06,0x80,0x88, - 0x27,0xf0,0x79,0x0f,0x80,0xd7,0xd3,0x86,0xe5,0x4a,0xb3,0x9e,0xb5,0xe4,0x93,0xcd, - 0x9e,0x57,0x1e,0x74,0x5a,0xb5,0x49,0xdc,0xeb,0xd9,0x20,0xe9,0x8f,0x6f,0x6e,0xa0, - 0xab,0x95,0x97,0xa4,0x8b,0xde,0xfb,0x15,0xb4,0x21,0xb2,0xa8,0x9a,0x8d,0x60,0x26, - 0xfb,0xfb,0x3f,0xfa,0xd9,0x5c,0x4d,0xe1,0xa6,0x7f,0xfe,0x04,0x6e,0x47,0xcd,0x73, - 0xb7,0xf7,0xeb,0x93,0x5f,0x7d,0xf8,0x0a,0xe0,0xf8,0x75,0xf0,0xce,0x47,0xa4,0x37, - 0x7f,0xf6,0xde,0x78,0xcf,0xa1,0xb3,0x45,0x50,0x8c,0xa6,0xe7,0x6b,0x3d,0xcd,0xdc, - 0xeb,0x77,0x3e,0x77,0x0f,0x70,0xff,0xea,0x03,0x34,0xcd,0x37,0x83,0x37,0x41,0x31, - 0xf5,0x67,0x11,0xbc,0xf6,0xde,0xb8,0xf4,0x69,0x54,0xbc,0x4c,0xf3,0xe7,0xf2,0x32, - 0x1a,0xc9,0xea,0x63,0x58,0xbf,0x74,0x90,0xde,0xdc,0x5c,0xaf,0xcc,0x42,0x27,0x72, - 0x21,0xde,0xe5,0xe9,0x2c,0x52,0xb2,0x5a,0x8e,0xa5,0x97,0xf0,0x42,0x4f,0x2b,0x90, - 0x0e,0xe5,0x51,0xb5,0x30,0xca,0xbd,0x56,0xb0,0xdc,0xcd,0xd4,0x1f,0xce,0xa3,0x38, - 0xdc,0xdf,0x57,0x7c,0x31,0x18,0xe8,0x27,0x2e,0xa0,0x7f,0xea,0x23,0x3a,0x9b,0xae, - 0xb7,0xc4,0x15,0x5f,0xb9,0x7d,0x6b,0x35,0x2c,0x1c,0x9b,0x66,0xfd,0xa4,0xf9,0x22, - 0xcf,0xd3,0xbc,0xe9,0x14,0xdc,0xc8,0xc1,0x89,0xa4,0xbe,0xbe,0xbb,0xb9,0x79,0x2c, - 0x8f,0xa1,0x97,0xd5,0xaa,0x22,0xbb,0xdf,0x35,0xe7,0x48,0x92,0x7a,0x2a,0x63,0x09, - 0xe8,0xa2,0x27,0x6b,0xd4,0x95,0xbb,0xd7,0xc8,0xd5,0xb9,0x9f,0x5e,0xb8,0xc5,0x34, - 0x4f,0x17,0x82,0x07,0xca,0x35,0x1e,0x4b,0xaa,0x27,0xea,0x40,0xce,0x7a,0x92,0xd3, - 0x3f,0xb0,0x28,0x39,0x08,0x0c,0x04,0x73,0x65,0xd1,0xdc,0x73,0x9c,0x3f,0xf4,0x08, - 0x7f,0x9f,0x03,0x9f,0x67,0x63,0x5e,0xa3,0x81,0xea,0xff,0xe8,0x8f,0xd3,0xfc,0x45, - 0x00,0x60,0x94,0x83,0x8f,0x81,0x3e,0xa1,0x25,0x02,0xbe,0x72,0x9b,0x6e,0x29,0x6f, - 0xb4,0xe0,0x4a,0x82,0x99,0x1c,0x34,0x2e,0x23,0xb9,0xc8,0xd2,0xbc,0x68,0x88,0x91, - 0xe6,0xe9,0xc6,0x22,0x0a,0x0b,0x10,0x54,0xb4,0x80,0x2d,0xba,0x01,0x49,0x11,0x15, - 0x51,0x10,0xb7,0x14,0xf0,0x92,0x1c,0x74,0x51,0xca,0x15,0x51,0x11,0xcb,0xb3,0x77, - 0x41,0x51,0xc8,0x1c,0xe4,0x48,0xba,0x38,0x6d,0xf3,0xa3,0xbd,0xd3,0x38,0x4a,0x2e, - 0x44,0x2e,0xe3,0x41,0x23,0x82,0x4e,0x1b,0x62,0x9a,0xcb,0xf1,0xa0,0x11,0x06,0x45, - 0xd0,0x8b,0x66,0xc1,0x44,0xb6,0xd5,0xe5,0xe4,0xe0,0x6a,0x16,0x7b,0xdf,0x1e,0xfd, - 0x00,0x97,0x02,0x2e,0x13,0x35,0x70,0xa6,0x45,0x91,0xf5,0xda,0xed,0xc5,0x62,0xe1, - 0x2f,0x8e,0xfc,0x34,0x9f,0xb4,0x0f,0x3b,0x9d,0x0e,0x36,0x76,0x04,0x82,0xf9,0x2c, - 0xbd,0x1a,0x38,0x1d,0xd1,0x11,0xdd,0x87,0xf0,0x7f,0xe7,0xdb,0xa3,0x17,0xf0,0x7d, - 0x0e,0xc2,0x4a,0x30,0xc4,0x0e,0x3c,0x14,0x53,0x89,0x12,0x8d,0xaf,0xc7,0x51,0x1c, - 0x0f,0x9c,0x6f,0x0f,0x8f,0x3a,0x3f,0x74,0x9e,0x75,0x1e,0x3b,0x6d,0xeb,0x13,0xe8, - 0xea,0xc4,0x11,0x4b,0xfa,0x5b,0x7f,0x6e,0x7d,0x6d,0x7f,0xfc,0xf2,0xe5,0xc9,0x0f, - 0x87,0x2f,0xcc,0xc7,0x08,0x0e,0x5c,0x91,0x9c,0x2f,0x96,0x38,0x5d,0x21,0xda,0xdf, - 0x89,0xb7,0xa9,0x58,0xc8,0xa1,0x18,0x03,0x0e,0x55,0x4f,0x00,0x11,0x08,0x58,0xe0, - 0xd1,0x85,0x12,0x63,0x10,0x3e,0x62,0x08,0x97,0xa2,0x80,0x26,0xd3,0xa0,0xa0,0x97, - 0x8c,0x5c,0x11,0x29,0xa1,0xa6,0x29,0xc8,0xf5,0x89,0x48,0x13,0x4f,0x04,0x49,0x08, - 0xbd,0xc1,0x7f,0xd8,0x24,0x0b,0x12,0x19,0x3b,0x4a,0xa4,0x8b,0x44,0x4c,0xd3,0x42, - 0x65,0x69,0x21,0xa6,0x81,0x12,0x49,0x2a,0xa2,0x04,0x71,0x2e,0x0b,0xec,0x92,0x48, - 0x0f,0x3f,0x98,0x89,0x31,0x30,0x13,0xf4,0xb1,0x5c,0x04,0x4b,0x5f,0x7c,0xd7,0x86, - 0xae,0x7a,0x79,0x9a,0x16,0xd7,0xad,0xd6,0x70,0xd2,0xfb,0x86,0x71,0xd0,0x6f,0xb5, - 0xa8,0xe3,0xde,0x37,0xdd,0xa3,0x6e,0xb7,0xdb,0x81,0x7b,0x58,0xac,0xde,0x37,0x2f, - 0x9e,0xbf,0xf8,0xfe,0xf9,0x33,0xb8,0x9b,0xcd,0x0b,0x19,0xf6,0xbe,0x79,0xf4,0xf4, - 0xd1,0xe1,0xf7,0x87,0x70,0x3f,0x0e,0x60,0xb4,0xde,0x37,0x27,0x4f,0x4f,0x4e,0x8e, - 0x1f,0xf6,0x19,0x3c,0xf8,0xaf,0xd5,0x9a,0x4c,0x53,0x05,0x2f,0x0e,0x0f,0xbb,0x2f, - 0xbb,0x8f,0xa0,0x61,0x3e,0x8f,0x25,0xdc,0x1e,0x1f,0x76,0xe9,0x36,0xc6,0x5e,0x18, - 0x75,0x70,0x97,0xc2,0x10,0x27,0xdf,0x3f,0x7b,0xf4,0xfd,0x4b,0xb8,0x59,0x04,0x79, - 0xd2,0xfb,0xe6,0xf9,0xe3,0xa7,0x9d,0xa3,0x97,0x76,0x8f,0x2a,0x48,0x54,0xcf,0x79, - 0x85,0x93,0x73,0xbc,0x79,0x44,0xf7,0x2d,0x25,0xf3,0x68,0xec,0xa9,0xa5,0x2a,0xe4, - 0xac,0x35,0x8f,0xbc,0xea,0xa1,0xfd,0xe9,0x2c,0x4d,0xd2,0x9e,0xf3,0xaf,0xb2,0x78, - 0x96,0x03,0xbc,0x4a,0xbc,0x81,0x7b,0xea,0x03,0x5f,0xa8,0x2c,0x18,0x49,0xef,0xfc, - 0x25,0x3e,0x6c,0xbd,0x97,0x93,0x79,0x1c,0xe4,0xde,0x1b,0x99,0xc4,0xa9,0x57,0xbe, - 0x5e,0x41,0x67,0xdf,0x5d,0x0f,0xd3,0xab,0x96,0x8a,0xfe,0x0c,0xeb,0xd1,0x1b,0xa6, - 0x79,0x28,0xf3,0x16,0x3c,0xe9,0xcf,0x82,0x7c,0x12,0x25,0x3d,0xd0,0x56,0x41,0x18, - 0xe2,0xbb,0x0e,0xb6,0x1e,0xa6,0xe1,0xf2,0x1a,0xe4,0x5e,0x8b,0x69,0xa6,0xd7,0xed, - 0x74,0x2e,0xa7,0x7d,0x5c,0xe9,0x49,0x9e,0xce,0x93,0xb0,0x07,0x52,0xac,0x89,0xa8, - 0x77,0xfb,0xa3,0x34,0x4e,0x73,0x7d,0x0f,0xd8,0x76,0x4b,0xc8,0x91,0x5c,0x7a,0xdd, - 0x93,0xec,0xaa,0xdd,0xf5,0x4f,0x4e,0x04,0xb7,0xc0,0x19,0xba,0xfd,0x16,0x90,0xd3, - 0x45,0x54,0xb4,0xb0,0x49,0x4b,0xcd,0x60,0x1d,0xa7,0x38,0x74,0x90,0x20,0x1f,0x46, - 0x81,0x92,0xe1,0x8a,0x29,0xef,0x03,0xd1,0x0a,0x01,0x86,0xf4,0x84,0xa4,0xb3,0xc8, - 0x83,0x2c,0x03,0x24,0x2a,0x0f,0xa8,0xa5,0x20,0x48,0xf1,0x5a,0xa5,0xf4,0x76,0x04, - 0x72,0x68,0x26,0x81,0xb2,0xd0,0x8a,0x91,0xb9,0x68,0xf2,0x7b,0x86,0x89,0x14,0x14, - 0x34,0x41,0x41,0x2a,0xf2,0x39,0xa0,0x52,0x86,0x13,0x89,0x84,0x46,0xff,0xc6,0xd1, - 0x85,0x04,0x52,0x15,0xf2,0x52,0xe6,0x4b,0x01,0x30,0xc1,0xf7,0x19,0x70,0xb4,0x2f, - 0x66,0xc1,0x15,0xcb,0x0a,0x01,0xd3,0x5f,0xe8,0xde,0x86,0x4b,0x66,0x85,0x28,0xac, - 0x60,0x84,0xae,0x2e,0xa4,0xcc,0xe8,0xc5,0xc9,0xc3,0x4e,0x76,0x05,0x82,0x27,0x9e, - 0xcf,0x12,0x4d,0xb2,0x3e,0x91,0xe7,0x35,0x75,0x85,0x38,0xfd,0xb6,0x5f,0xf6,0xdc, - 0x7b,0xd8,0x79,0x94,0x95,0xcb,0xd1,0x7d,0x08,0x9f,0x06,0x73,0xe8,0xae,0x5a,0x98, - 0xc3,0x63,0x78,0x46,0x7f,0x3d,0x84,0xbf,0x10,0x41,0x3c,0xc7,0x6b,0xb0,0x39,0xb2, - 0x18,0x2d,0x9a,0x58,0x5e,0xf5,0x01,0x7f,0x93,0xa4,0x15,0x01,0x41,0xa9,0xde,0x48, - 0x22,0xb9,0xf5,0x27,0x41,0xd6,0xc3,0xbe,0x75,0x47,0xb0,0xec,0x45,0x91,0xce,0x7a, - 0xdd,0x43,0x78,0x56,0x52,0x02,0x3f,0x82,0xce,0xc1,0x9a,0x8b,0x42,0xbd,0x5a,0x48, - 0xf6,0xae,0x86,0xc9,0xb4,0x39,0x7c,0xc4,0x83,0xfb,0x21,0x70,0x1f,0x83,0xfe,0x3d, - 0x74,0xa4,0x09,0x05,0x2f,0x37,0xc8,0x04,0xd8,0xc5,0x35,0x23,0xe5,0x41,0x18,0x81, - 0xde,0xed,0xea,0x19,0x74,0xaf,0x99,0x06,0xa2,0x3f,0x4b,0xa2,0x95,0x3e,0xdd,0x2e, - 0xb8,0xb3,0x87,0x9d,0x4e,0x3f,0x96,0x28,0x83,0x5b,0x48,0xc7,0x88,0x04,0xbf,0xd3, - 0x95,0xb3,0x8a,0x68,0x71,0xca,0xbd,0x2e,0x81,0xa3,0xe6,0x43,0xee,0x6b,0x1c,0xcc, - 0xa2,0x78,0xa9,0x87,0x46,0x1e,0x70,0xfb,0xd6,0x18,0x30,0x70,0x8d,0x64,0x49,0x04, - 0xb8,0xab,0x3d,0xa6,0xb7,0xdf,0xfe,0xfb,0x2f,0xf0,0x7f,0xc1,0xfa,0x5d,0x8c,0x82, - 0x3c,0x14,0xcd,0x34,0x81,0x45,0x9e,0xa1,0xa4,0x63,0xb5,0x26,0x50,0x73,0x8b,0xdf, - 0xfe,0xf2,0xdf,0xb6,0xb0,0x4b,0x90,0x68,0xa0,0x41,0x2e,0x83,0x19,0xb4,0x88,0xae, - 0x64,0xac,0x5c,0xd3,0x1d,0xaf,0x3d,0x28,0x28,0x29,0x93,0xeb,0x0d,0xec,0x10,0x4d, - 0x18,0xfc,0xec,0x58,0x82,0x92,0x06,0x90,0xa4,0xe8,0xaf,0x87,0x7a,0x15,0xc0,0xc6, - 0x69,0x4d,0xc3,0xfb,0x11,0x41,0xb7,0x63,0x7d,0x74,0x71,0x1f,0x6c,0xc1,0x07,0x1b, - 0x2b,0xd0,0x3d,0x86,0x15,0x40,0x35,0xde,0x2a,0x72,0xe0,0x66,0xd0,0xcc,0xb3,0xde, - 0x1c,0x59,0x72,0x04,0x8c,0xbb,0x05,0xb7,0x7a,0x91,0xfa,0x8b,0x29,0x00,0x44,0xdd, - 0xc8,0x1e,0x00,0x00,0x6c,0x5c,0xc2,0x92,0x04,0x97,0xf5,0x09,0x20,0xb4,0x27,0x16, - 0xb0,0xc3,0x22,0xb9,0x26,0xae,0xcb,0x52,0x15,0xa1,0xfe,0xef,0x81,0x06,0x0e,0x0a, - 0x30,0xff,0x6d,0x6a,0x23,0x78,0xb2,0x20,0x87,0x19,0xdf,0x8e,0x4e,0x1b,0x48,0xd2, - 0x09,0x5a,0x6a,0xdd,0x03,0x23,0xc8,0x34,0x60,0x02,0xc8,0x52,0x32,0xf6,0x99,0x07, - 0x90,0x2d,0x0c,0x13,0x20,0x93,0x72,0x87,0x75,0xa2,0xc7,0x6f,0x47,0xf3,0x5c,0xc1, - 0xd8,0x59,0x4a,0x7a,0xae,0x6f,0x66,0x1d,0x25,0xd4,0xe9,0xae,0xd5,0xa3,0xce,0xfe, - 0x38,0x57,0x45,0x34,0x5e,0xb6,0xb4,0x2d,0x63,0xde,0xd1,0xac,0x19,0x29,0x48,0xa4, - 0x7e,0xf7,0x04,0xe4,0x1a,0x2c,0x05,0x7c,0x63,0xe3,0xaf,0x37,0x4d,0x81,0x44,0xaf, - 0x37,0xc4,0xb5,0x06,0xd1,0x7e,0x8e,0xfc,0x5a,0xfb,0x34,0x18,0x21,0xaa,0x37,0x49, - 0x97,0xd4,0xa4,0xdb,0xaf,0xe8,0x80,0x4c,0xa8,0x66,0xc7,0x7f,0x7c,0xe8,0x6a,0x09, - 0xfe,0x5e,0xaa,0x79,0x5c,0x08,0x9c,0x1d,0x48,0x69,0xb4,0x3b,0x64,0x88,0xa2,0xf3, - 0xdd,0x4b,0x1f,0xbc,0x30,0xe0,0x9b,0x2b,0xd2,0xf4,0x24,0xbb,0x61,0x5e,0x79,0x1a, - 0xc3,0x35,0x18,0x12,0xa3,0x60,0x0e,0x6a,0x80,0x74,0xbf,0x11,0x9e,0x33,0x35,0xb9, - 0x17,0xcd,0xfa,0x27,0x3b,0x78,0x9c,0xfb,0x00,0xc3,0xb2,0x25,0xf3,0x3a,0x26,0x68, - 0xc6,0xe6,0x65,0x7a,0x51,0x7b,0x07,0xd6,0xad,0xcd,0x69,0x0c,0x07,0xea,0x46,0x5e, - 0xf8,0x4e,0x1f,0xf1,0x8a,0x36,0x62,0x6f,0x1a,0x85,0xa1,0x4c,0x98,0x37,0xca,0x87, - 0x32,0x8e,0xa3,0x4c,0x45,0x6a,0x17,0xfd,0xe3,0x80,0xe3,0x31,0xe2,0x87,0x86,0xf0, - 0x6a,0x0f,0x50,0xe2,0x08,0xff,0xf2,0x3a,0x45,0xe6,0x03,0x27,0xd7,0x3f,0x31,0xa0, - 0x58,0x72,0xf3,0xf0,0x1e,0x72,0xb3,0xe5,0x77,0x0e,0x81,0x6d,0x6b,0x94,0x0b,0x94, - 0x62,0x24,0x29,0x88,0x6d,0x30,0x3d,0x8f,0x50,0x01,0x55,0x4a,0xff,0xf0,0x31,0xdc, - 0x9b,0x79,0xb4,0x10,0xe0,0x1e,0x1a,0x60,0xa0,0x16,0x65,0x89,0x90,0x2f,0x94,0xba, - 0x9a,0xe9,0x6c,0x0b,0x43,0xb3,0x7b,0x25,0x84,0xdf,0xa1,0x5c,0x14,0x6a,0x11,0xa1, - 0x0d,0xc8,0xcf,0xfe,0xee,0xff,0x67,0xcd,0xff,0x54,0x28,0x39,0x99,0x21,0xf7,0x85, - 0xa0,0xf9,0xa3,0x9c,0x2d,0x91,0x40,0x28,0x90,0x33,0x6c,0x05,0x4c,0x26,0x60,0x2f, - 0x8a,0xf6,0xec,0x4f,0x05,0x3c,0x8f,0x41,0x29,0x84,0x4b,0x50,0x0a,0x68,0x32,0x0f, - 0x65,0xb1,0x00,0x35,0xc0,0x1d,0x51,0x18,0x03,0xcd,0x1a,0xb0,0x6d,0xc0,0xb0,0x15, - 0x4d,0x1f,0xa6,0xda,0x16,0x3e,0x70,0x01,0x18,0x3a,0x11,0xd8,0x1b,0x41,0x22,0x7c, - 0x30,0x49,0x46,0x71,0xa0,0x40,0x9f,0x80,0x0d,0xcd,0x8d,0xb5,0x2d,0xa4,0xc0,0xcb, - 0xe1,0x9e,0x26,0x52,0x81,0xab,0x25,0x2b,0x3b,0x88,0xc3,0x32,0x64,0x8d,0x80,0x99, - 0x0d,0xb4,0x74,0x99,0x8e,0x82,0x21,0x5a,0x87,0x60,0x3f,0xbf,0x42,0xa8,0xa0,0x25, - 0xda,0xe7,0x30,0xf2,0x34,0x82,0x61,0x09,0x16,0xee,0x6c,0x99,0xce,0x05,0x48,0x51, - 0x30,0xc5,0x45,0x1e,0x90,0x19,0x04,0x2c,0x99,0x88,0x40,0x5d,0xe0,0xec,0xf0,0x2d, - 0x70,0x2c,0x4e,0x0a,0xe6,0x1c,0x07,0x43,0x58,0x25,0x04,0x2c,0x4a,0xc6,0xd0,0x32, - 0x2a,0x4a,0x5b,0x67,0x71,0x4f,0xad,0x74,0x58,0xda,0x3d,0x2d,0x8c,0x13,0xa0,0xed, - 0x53,0x1a,0x91,0xc6,0x66,0xa1,0x17,0x47,0x95,0xc1,0x42,0xf7,0xdb,0x64,0xfb,0x4a, - 0x0f,0xfd,0x15,0xfa,0x0d,0xf8,0xc4,0x0c,0xff,0xf9,0x6a,0xae,0x1c,0x1f,0xe4,0xa6, - 0xda,0x54,0x6a,0x46,0x6d,0x53,0x8b,0xeb,0x4d,0x6d,0x76,0x4f,0x5e,0xda,0xb0,0x8a, - 0x1e,0xdd,0x07,0x68,0x63,0x45,0xa0,0x71,0xd9,0x3d,0xde,0x54,0x46,0xa6,0x83,0x1d, - 0x2a,0x75,0x0b,0x03,0xdf,0xaa,0x65,0x4b,0x78,0x2a,0x05,0x45,0x5d,0x54,0x2a,0xca, - 0xb3,0x95,0x4f,0xf5,0xb8,0xc2,0xd0,0x67,0x28,0x2d,0x86,0xa8,0xfa,0x14,0xd8,0xe6, - 0xde,0xca,0xae,0x4f,0xbe,0xd1,0x34,0x08,0x41,0x5e,0x83,0x87,0x05,0xce,0x67,0x87, - 0xfe,0x87,0xf3,0x5a,0x53,0x89,0xd8,0x37,0x70,0xbb,0xac,0x79,0x47,0xc7,0x75,0x0a, - 0xfe,0x7e,0x5d,0x94,0x3d,0xcb,0xb1,0x1d,0x68,0x40,0x65,0x9e,0x00,0x6e,0x89,0xad, - 0xa4,0x16,0x70,0xec,0x56,0xa7,0x9a,0xd9,0x90,0xcd,0x02,0x70,0x88,0x81,0xab,0xb4, - 0x4f,0x4d,0x46,0x22,0x23,0x34,0x4c,0x41,0x64,0x34,0x5f,0x77,0xc1,0xc9,0x89,0x53, - 0x60,0x8d,0x2c,0xc7,0x7e,0x15,0xfc,0x05,0x18,0x76,0x37,0x24,0x00,0xba,0xd5,0x11, - 0xea,0xd8,0xd4,0x30,0xe6,0x30,0x8f,0xbe,0x8c,0x31,0x8d,0xf9,0x08,0x1d,0x94,0x3c, - 0x86,0x44,0x9f,0x80,0x7c,0x31,0x2f,0x5a,0x97,0x5f,0xa1,0x0f,0x58,0xa3,0x1e,0x21, - 0x3a,0x89,0x88,0x09,0xb0,0x1e,0x21,0xaf,0x6f,0x8d,0x54,0xc3,0xed,0x8f,0xc0,0x36, - 0x80,0x9e,0x1c,0x44,0x61,0x81,0x26,0x38,0x50,0xa1,0xcc,0x09,0x41,0xbe,0xff,0xfa, - 0xd8,0xfd,0x2b,0x6b,0x0e,0x8d,0xc2,0x51,0x91,0xc7,0xea,0x7a,0x5d,0x68,0xd5,0x84, - 0xd5,0xf1,0x7d,0x85,0x15,0xf5,0xb5,0x69,0xc3,0xaf,0x5b,0x7b,0x64,0x38,0xb4,0xb4, - 0xfa,0xa8,0x2d,0xd9,0x10,0x58,0x06,0x15,0xfb,0x9a,0xa3,0x86,0xcb,0x67,0x0d,0xf0, - 0xe5,0xf2,0xf0,0xf0,0xf3,0xec,0x7d,0xf6,0xc6,0x68,0x19,0x5a,0xe0,0x2d,0x7f,0x36, - 0xa9,0xad,0x83,0x5f,0x75,0xd5,0x03,0x2d,0x58,0xb4,0xc8,0x7f,0xbf,0xae,0x37,0xee, - 0x70,0xcb,0x16,0x69,0xa3,0xfb,0x12,0xe0,0xba,0xc9,0xb4,0x93,0x20,0xd1,0xe1,0xea, - 0xd7,0x29,0xbd,0x02,0x0a,0xf4,0x5e,0x36,0x2f,0x3e,0x62,0x4a,0x65,0x00,0xf8,0x99, - 0xc8,0x4f,0x1e,0x31,0xc8,0xc6,0x63,0x76,0x60,0xb4,0x33,0xa4,0x25,0x07,0x52,0x0d, - 0x86,0x33,0x80,0x7c,0x13,0x32,0x0b,0x61,0x15,0x4d,0x70,0x64,0xfd,0xf9,0x2e,0xeb, - 0x7b,0x8b,0xa3,0x81,0x8a,0x32,0x9d,0x17,0x48,0x14,0xfc,0xed,0x9a,0xa0,0x0f,0x46, - 0x88,0xfb,0x4d,0x31,0x58,0xa4,0xf3,0xd1,0xb4,0x15,0x50,0x84,0xb5,0x07,0x22,0xa7, - 0xb5,0x34,0x4e,0xc4,0x6d,0xf3,0xed,0xf5,0x0c,0xc8,0xba,0x55,0x31,0x9d,0xcf,0x86, - 0x3b,0xb0,0xb0,0xbd,0x31,0xe3,0xe6,0xbe,0x98,0xd0,0xf1,0x13,0xcb,0xe3,0xa2,0xeb, - 0x3a,0x0e,0x4e,0x3a,0xdf,0x6a,0xd4,0xac,0xe3,0xcd,0xd2,0x04,0xe8,0x92,0xd5,0xd8, - 0x92,0xd0,0xb0,0x86,0x2d,0x4b,0x7f,0x95,0x1c,0x00,0xca,0xaa,0xee,0x65,0xdd,0x8a, - 0x20,0xf6,0x9f,0x3e,0x0f,0x4f,0xb7,0x7d,0xc3,0xe8,0x5a,0x77,0xbb,0xba,0xfe,0xa1, - 0xbb,0x3d,0xf8,0x72,0xcf,0x55,0x9c,0xa5,0x7f,0x6e,0xd1,0xcd,0x5d,0x2b,0xb8,0xd6, - 0x90,0xc1,0xb9,0xf7,0xaa,0x7c,0xed,0x82,0xe8,0xd9,0x80,0x0a,0x78,0x09,0x02,0x0a, - 0x84,0x7d,0x0f,0x94,0x25,0x98,0x09,0x45,0x04,0x68,0x40,0x7d,0x9a,0x49,0x11,0x8c, - 0xf2,0x14,0xb4,0x62,0xa0,0xf5,0x81,0x50,0x70,0x1f,0xc7,0x4a,0xeb,0xd2,0x89,0x14, - 0x4d,0x22,0x6f,0xd7,0x8a,0x4b,0x73,0xd8,0xcf,0x38,0xa1,0x13,0x59,0xe0,0xe7,0xc3, - 0x68,0x02,0x23,0x08,0x70,0xdd,0xd0,0x22,0x0e,0x44,0x98,0x07,0x8b,0x44,0xc8,0x2b, - 0x58,0x9d,0x78,0x09,0x16,0x31,0xd8,0xf3,0xb0,0x02,0xd2,0x47,0x9f,0x80,0x46,0x32, - 0xb1,0xc6,0x21,0x99,0xc4,0x4a,0x60,0x5c,0x80,0x4d,0x79,0x1c,0x1a,0x2d,0x2f,0x58, - 0xb6,0xd1,0x05,0x7e,0x1a,0x08,0xe4,0xc2,0x1c,0xfd,0xe1,0x12,0x23,0x1e,0xe8,0x6a, - 0x84,0x12,0xb0,0x4a,0x9f,0x72,0x67,0xe9,0x58,0x1b,0xe9,0x64,0x24,0xcc,0x51,0xcf, - 0x81,0xbb,0x44,0x5e,0x40,0x65,0x9f,0x69,0x19,0x20,0x9a,0xd8,0xe8,0xc7,0x17,0xcf, - 0x45,0x8e,0x66,0xc4,0x0c,0x0c,0x28,0x85,0xf6,0x7a,0xa0,0x7d,0x0e,0xb6,0x6f,0xd8, - 0xd8,0x71,0xfb,0xe0,0x80,0x4f,0xc8,0xf2,0x14,0x2c,0x50,0x55,0x15,0xbf,0xcc,0xd9, - 0x37,0x00,0x6f,0x0f,0x6f,0x97,0x62,0x21,0x71,0x9e,0x1f,0x28,0xfa,0x2f,0x33,0x3d, - 0xcb,0x39,0x88,0x5f,0xf8,0x08,0x50,0x03,0xd0,0x1d,0x63,0x70,0x12,0xc0,0x5b,0x04, - 0x39,0x4c,0x24,0x40,0x8f,0x86,0xc2,0xf6,0xf4,0x92,0x6c,0x1b,0x63,0x9d,0x2c,0x75, - 0xc0,0x0c,0xad,0xbb,0x38,0xc8,0xb4,0x65,0xf2,0xcf,0x33,0x19,0x46,0x41,0x53,0x2f, - 0x33,0x18,0x8b,0x98,0x7c,0x76,0x99,0xba,0xbe,0x48,0xe2,0x1a,0x47,0xd6,0x8a,0xac, - 0xb6,0x10,0x71,0x9d,0x35,0xaa,0xec,0x18,0x5b,0xd5,0x22,0x4d,0x14,0x9e,0x41,0xde, - 0x9a,0x60,0x13,0xc0,0x6e,0xd3,0x96,0xb9,0x9e,0x7d,0xe3,0x0a,0x56,0x64,0x6d,0x0c, - 0xe8,0xd2,0x0a,0x27,0x69,0x2b,0x97,0x20,0xb2,0x8a,0xd5,0xdd,0xa0,0xff,0xd5,0x84, - 0x27,0xea,0x80,0x6d,0x01,0xfe,0x2d,0xe1,0xa9,0x8a,0x2d,0x31,0xc8,0xa6,0xd9,0xcd, - 0xb6,0xf4,0x37,0xb0,0xd1,0x1a,0xc5,0x51,0xd6,0xab,0x02,0xc8,0x57,0xbb,0x2c,0xe6, - 0xc3,0x0d,0x8b,0xf9,0x6f,0x2d,0x76,0xfe,0x81,0xe7,0x6d,0xc2,0x67,0xbd,0x60,0x0c, - 0xf4,0xe1,0x69,0x97,0x86,0xef,0xae,0x8d,0x5d,0xd7,0x68,0xf4,0x4b,0x37,0x30,0x18, - 0x02,0x4c,0xc0,0xde,0x7d,0xb4,0x18,0x5b,0x3a,0x40,0x4f,0x06,0x0e,0xdf,0xc4,0x72, - 0x5c,0xf4,0x5a,0xa8,0xdd,0xc9,0x26,0xa6,0x4b,0x1e,0xeb,0x9b,0x2c,0x28,0xd0,0x13, - 0xb8,0x34,0xdd,0x73,0x53,0x8a,0xaa,0xd0,0x3b,0x0c,0xb4,0x99,0x77,0xfa,0x63,0x13, - 0x72,0x29,0x9d,0x2d,0xfd,0x9a,0x06,0x7f,0x64,0x8d,0xad,0x23,0xfe,0x64,0x78,0x53, - 0x48,0xaa,0x72,0x6c,0x27,0x79,0x14,0xf6,0xf1,0xaf,0x16,0x98,0x74,0xf0,0xa4,0x90, - 0x2d,0xce,0x78,0xa8,0x5e,0x77,0x9c,0x0b,0xf8,0x43,0xf6,0x5d,0x87,0x82,0xd6,0xeb, - 0x5e,0xfe,0xca,0xf4,0x77,0x6d,0x3c,0x53,0x34,0x40,0x01,0x9b,0x8f,0xef,0x6b,0x3b, - 0x73,0x7c,0xec,0xab,0x5c,0xfd,0xcf,0xb6,0x6c,0x75,0x48,0xee,0x3e,0xb1,0xe2,0x8d, - 0x48,0x24,0x69,0x3a,0x0b,0x0b,0xc7,0x56,0xa8,0x63,0x33,0x3e,0x78,0xcf,0xc8,0xa2, - 0x05,0xd6,0x30,0xc8,0x8d,0xd0,0x3b,0xda,0x96,0x89,0xd1,0x26,0xe3,0x56,0x5f,0x15, - 0x25,0x3b,0xc8,0x5f,0x4a,0xc5,0x0f,0xe3,0x14,0x74,0x54,0x84,0x3a,0x0a,0xf3,0xdd, - 0x24,0xb6,0x41,0x05,0xce,0xc0,0x27,0xa1,0x58,0x57,0x94,0x80,0x30,0x8f,0x28,0xac, - 0x7b,0x21,0x30,0x55,0x4c,0x1e,0xab,0xd1,0xa4,0x65,0xb3,0x38,0x4d,0x2f,0x04,0xb0, - 0xd0,0xe8,0x02,0x8b,0x62,0x30,0x9e,0x84,0x8a,0x65,0x06,0x93,0x81,0x3b,0x50,0x6a, - 0xd8,0x3b,0x34,0x85,0x2b,0x8c,0x26,0x81,0xe6,0x50,0xa4,0x60,0x74,0x70,0x6c,0x3e, - 0x6c,0x51,0x14,0x34,0xb2,0xd4,0x10,0x85,0xb2,0xd8,0x41,0x5e,0xa4,0x39,0x68,0x55, - 0x15,0x2c,0xf1,0x66,0x02,0x4e,0xb1,0xd6,0x22,0x01,0x93,0x94,0xa1,0x50,0x9a,0x0a, - 0x63,0x2e,0x94,0xa3,0x34,0x0f,0x88,0xd3,0xd8,0x2a,0xa6,0x95,0xd1,0x73,0x59,0x95, - 0x9f,0x72,0xd0,0x01,0xd7,0x78,0x5b,0x50,0xbc,0xde,0x06,0xe3,0x9f,0xeb,0x0b,0x6c, - 0xad,0x47,0x19,0x1e,0xb5,0x42,0x37,0xb5,0x10,0xec,0xf1,0xc9,0xb6,0x50,0x92,0xb5, - 0x3e,0x27,0x3b,0x29,0x24,0x9f,0x05,0x71,0x7d,0xe9,0x45,0xb4,0x36,0xeb,0x2a,0x7b, - 0xfb,0x6d,0xdf,0x44,0xab,0xb7,0x67,0xe7,0x2c,0x1b,0x97,0x13,0x9d,0xfe,0x91,0x5a, - 0x73,0xb4,0x7f,0xce,0x42,0x60,0x6f,0x34,0x6c,0x12,0xb4,0x32,0x98,0x24,0xc5,0x3c, - 0x29,0xa2,0x98,0x56,0x66,0x88,0x06,0x03,0xa6,0x4c,0x73,0x32,0x39,0xa2,0x62,0xc3, - 0xf7,0xe6,0xf5,0xf9,0x66,0x9e,0x85,0x25,0x9c,0xb4,0x0e,0xb6,0x58,0xa8,0xdc,0xe6, - 0x0d,0xb6,0x27,0x40,0x4b,0x49,0xd1,0x35,0x41,0x2c,0x3b,0xdf,0xac,0xf1,0x7c,0xb4, - 0x8d,0xed,0xb6,0x92,0x80,0xf9,0xb8,0x06,0xcf,0x56,0xe7,0xda,0x4e,0xa0,0xe1,0x14, - 0x84,0x5f,0x04,0x93,0x2f,0x15,0x3c,0x14,0xaf,0xdb,0x70,0xbf,0xee,0x0c,0xe0,0x6d, - 0x4f,0x21,0x20,0x34,0x3a,0x50,0x66,0x2d,0x6e,0x3e,0x19,0x06,0xcd,0xc3,0x93,0x13, - 0xef,0xf1,0xa1,0x77,0xfc,0xd0,0xf3,0x3b,0x0f,0xdd,0x0a,0xf4,0x49,0x6a,0x1c,0x68, - 0xd2,0x13,0x98,0x69,0xee,0x7f,0x45,0xd8,0x66,0x2b,0x58,0x40,0x39,0x3f,0x25,0xb5, - 0x6a,0x0f,0x53,0xe9,0x41,0xe6,0x70,0x92,0xc2,0xfd,0x0c,0x33,0xa7,0x05,0x70,0xf2, - 0x05,0x07,0xc0,0x28,0x1d,0x84,0xe6,0xa5,0x27,0xe6,0x60,0x85,0xa6,0xc6,0x32,0xa4, - 0x32,0x37,0x90,0x0f,0x6b,0xf4,0x6d,0x6c,0x3a,0xad,0x36,0x0e,0xff,0xff,0x12,0xcf, - 0xca,0x02,0xec,0xde,0xf8,0x27,0x6e,0xf5,0x81,0xc7,0xe4,0x35,0xa9,0x4d,0xd6,0x96, - 0xbd,0x6e,0xbb,0xd5,0x5d,0x55,0xef,0x50,0xf8,0x6c,0xe7,0x76,0xc0,0xea,0xd3,0x79, - 0x31,0x4d,0x73,0x43,0xb2,0x02,0xb5,0xa1,0x12,0x4d,0xcc,0x1b,0x5d,0x80,0xa4,0x45, - 0x23,0xdb,0x40,0xe5,0x82,0x90,0x9c,0xc7,0x21,0xdb,0xde,0x8b,0x48,0x01,0x93,0x4a, - 0x1d,0x50,0xfc,0xf9,0xa9,0x63,0x04,0xe6,0x47,0x66,0xe5,0x4f,0x35,0xa6,0x7c,0x10, - 0xcd,0xb0,0x72,0x2a,0x48,0x8a,0x35,0x31,0xf0,0x12,0x7a,0x98,0xe7,0xda,0x3d,0xf8, - 0xbb,0x27,0x64,0x34,0x79,0x20,0x30,0x76,0x38,0xee,0xa8,0x8c,0xb3,0x1b,0xa4,0xac, - 0x51,0xce,0x17,0xc6,0xd9,0x6f,0xcf,0x7d,0x1b,0x62,0xda,0x2d,0xd1,0xb5,0x45,0xb5, - 0x01,0x9d,0x38,0x10,0x98,0x03,0xdf,0x5e,0x69,0x81,0x6f,0xee,0x63,0x0d,0x41,0x3b, - 0x8e,0x90,0xa5,0xe3,0x16,0x1a,0xce,0x5b,0x63,0x64,0x30,0xa4,0x1d,0x94,0x63,0x6c, - 0x6c,0xe6,0x21,0x4a,0x4e,0x41,0x7f,0xe6,0x31,0x5a,0xb7,0x74,0xd5,0xb9,0x57,0xc1, - 0xc8,0x36,0x3c,0x68,0x51,0xb1,0x55,0x08,0x6f,0x98,0x39,0x3b,0x13,0x06,0xac,0x80, - 0x79,0x0e,0x3b,0x72,0x03,0x9b,0x4d,0x68,0xd2,0x64,0xf9,0x5c,0xef,0x4a,0x18,0x98, - 0xf7,0x9b,0x96,0xb8,0xb6,0x95,0xd1,0xfa,0x26,0x75,0x0c,0x9a,0xb4,0x5a,0x7a,0xba, - 0x42,0xa3,0xf7,0x3f,0x9a,0x2d,0x78,0x53,0x2f,0x2c,0xb0,0xc3,0x73,0x35,0x09,0x73, - 0x72,0xb8,0x16,0x7c,0x3c,0xda,0x9a,0xaf,0x3d,0x5e,0xcf,0xd7,0xf6,0xb5,0x63,0xdc, - 0x02,0xd7,0x19,0x2b,0xf1,0x08,0x77,0xb7,0xe3,0x4a,0xe3,0xa1,0x55,0xd8,0x56,0xc8, - 0xf7,0x6b,0xc3,0x9f,0x6c,0x1d,0xbe,0xbb,0x91,0x2e,0x3e,0xea,0x6f,0xb5,0x74,0x78, - 0x08,0x5f,0xa5,0x60,0x37,0x56,0xe3,0xed,0xc6,0x34,0xbe,0xc7,0xf8,0xad,0x29,0x7c, - 0x3a,0x7a,0x38,0x9a,0xda,0x26,0xc0,0xd1,0x76,0x25,0xb3,0x26,0xa1,0xd7,0xcd,0xa8, - 0x75,0x50,0xbc,0xad,0x70,0x85,0xd7,0x3b,0xac,0x7a,0xd4,0xe5,0x6b,0xb5,0x18,0xf7, - 0x16,0x14,0x3b,0x15,0xfc,0x9d,0x82,0x62,0x87,0xae,0xd2,0x32,0x63,0x0b,0x12,0x0c, - 0x5b,0x02,0x06,0x04,0x06,0x96,0xac,0xb0,0x39,0x29,0x72,0x82,0xc5,0x84,0xc2,0x74, - 0xfa,0x44,0xc7,0xd1,0xc7,0x69,0x8a,0xce,0x9d,0x8d,0x68,0x54,0x80,0x9f,0x91,0x73, - 0x20,0x0b,0xe8,0xe1,0xba,0xd2,0xfc,0xc2,0x64,0xe5,0x67,0xba,0x5d,0x0c,0xbd,0x08, - 0xae,0xef,0x29,0x53,0xec,0x6f,0x6e,0x11,0x14,0x3a,0xe2,0x54,0x11,0x23,0x15,0xed, - 0xb9,0xd7,0xba,0x50,0xaf,0x94,0x82,0x87,0xda,0x5e,0x10,0x27,0x87,0xc6,0x67,0x16, - 0xb6,0xdc,0xa8,0x66,0x7c,0x8c,0x0d,0x8c,0x94,0x35,0x81,0x03,0x16,0x22,0xdf,0x77, - 0xac,0x6f,0xb5,0x2e,0x7f,0x2e,0xd5,0x05,0xae,0x05,0x97,0x36,0x4e,0x31,0x61,0x67, - 0x12,0x77,0x40,0xb6,0x54,0x7a,0x46,0x65,0x63,0x54,0x6f,0x46,0x40,0x89,0x2c,0x02, - 0x03,0x3c,0x14,0xb8,0xde,0x9e,0xa8,0xca,0x11,0x69,0x0c,0x6a,0x16,0x25,0x60,0x41, - 0x05,0x21,0x3b,0x58,0xd9,0x14,0x3b,0x61,0x2b,0x43,0x80,0x90,0x05,0x14,0x61,0x2d, - 0x65,0x22,0xc0,0x5d,0x2f,0x96,0x82,0x56,0xb8,0x1e,0x7e,0xab,0x4a,0x5b,0x1e,0x33, - 0x32,0xaa,0xe9,0x12,0x52,0x2a,0x64,0x75,0xbb,0x0f,0x1f,0xd9,0xe8,0x40,0x83,0xe6, - 0x3e,0x91,0x01,0x10,0x38,0x80,0x4a,0x18,0x07,0xba,0x6a,0x76,0xbc,0xee,0x38,0x77, - 0x39,0x39,0x8e,0xd4,0x6b,0x1b,0xdf,0x60,0x0f,0xe5,0x45,0xd5,0x3f,0x4e,0xb9,0x12, - 0xd1,0x40,0xaa,0xa3,0x8b,0x25,0x49,0xe5,0xe3,0x63,0x1b,0x8c,0x75,0x63,0xa0,0xb3, - 0x5a,0xed,0x9d,0xb6,0xb9,0xa0,0xf9,0xb4,0x4d,0xdb,0x5b,0x4e,0xb1,0x2c,0xf4,0x6c, - 0x0f,0xfe,0x3b,0x9d,0x01,0x8d,0x71,0x7d,0xc5,0xa0,0x41,0x13,0x6c,0x60,0xd5,0xf3, - 0x29,0xd7,0x56,0x9e,0x9d,0x02,0x82,0xca,0xd7,0x61,0x5a,0xd0,0xce,0x16,0x78,0x74, - 0x76,0x3a,0xed,0x9e,0xfd,0xc0,0x2b,0x05,0x7d,0x76,0xeb,0x0d,0xc1,0xed,0x6b,0x9c, - 0x71,0x65,0xa0,0x69,0xde,0xd6,0x1d,0xa2,0x31,0x75,0x1a,0x98,0x86,0xda,0x4e,0x6b, - 0x88,0x28,0x1c,0x34,0xa6,0xea,0x07,0xb8,0x35,0x15,0xe5,0xed,0x45,0x34,0x8e,0xe0, - 0x86,0x54,0xe2,0xd9,0x7f,0xa4,0xf3,0xfd,0x5c,0xfd,0x69,0x9e,0xf6,0x73,0xa2,0x8c, - 0xd2,0xac,0xd6,0x4f,0xb9,0x94,0x5a,0xdb,0xd2,0x62,0x7f,0x16,0x06,0x6a,0xda,0x17, - 0x40,0x7e,0x58,0xae,0x91,0x8b,0x5f,0xa2,0xd6,0xcb,0x48,0xec,0xe7,0x41,0x9e,0xf7, - 0x4f,0xdb,0x01,0x43,0x11,0x46,0x97,0x06,0x0e,0x5c,0x27,0x9e,0xb7,0xf5,0x10,0xd1, - 0xbd,0xf1,0x90,0xc9,0x91,0x1e,0xd7,0x5f,0xe8,0xf2,0x28,0xfd,0x06,0xde,0xd9,0x08, - 0xa1,0x82,0xc3,0xc6,0xd9,0xdb,0x74,0x21,0x90,0x38,0x80,0x04,0x35,0x5e,0xb6,0x35, - 0x9e,0xa9,0x09,0x23,0x04,0x1d,0x01,0xbc,0x39,0x5b,0x6b,0xbc,0x36,0x2a,0xd8,0x3d, - 0xe5,0xa8,0xf0,0x96,0x63,0xd2,0x76,0x83,0x61,0x91,0x70,0x87,0x26,0x48,0xd6,0x10, - 0x54,0xcd,0x3f,0x68,0xbc,0x83,0x9b,0x28,0xc5,0x9a,0x4e,0x2e,0xf5,0x87,0x17,0x18, - 0x71,0x6c,0x70,0x1f,0x8d,0xb3,0xfd,0x98,0x31,0xc6,0xf7,0xf7,0x1f,0x04,0xfd,0x98, - 0x72,0x90,0xb7,0xe8,0xd4,0xec,0x1a,0x20,0xdf,0x36,0xc0,0x69,0x1b,0xa6,0xa8,0x51, - 0x6c,0x5d,0xd6,0xe7,0xcd,0xa3,0xe1,0xc5,0x99,0x5e,0xef,0xdd,0x6d,0xb1,0x4e,0xab, - 0x6c,0x4f,0xd4,0x79,0xcf,0xb6,0x20,0x95,0xc7,0x25,0x11,0xea,0x6f,0x36,0x3e,0xca, - 0x16,0x3b,0x96,0x9d,0x6a,0x04,0x1a,0x67,0x54,0xc9,0xb5,0x7b,0x0d,0x4d,0xb5,0xcc, - 0xee,0x45,0xa4,0x16,0x1a,0xbb,0xad,0x74,0x03,0x89,0x3f,0x25,0x77,0xae,0x50,0xad, - 0x07,0x15,0x4b,0x99,0xad,0x77,0x72,0x8e,0x0f,0x3f,0x7f,0x21,0x4c,0x3d,0x88,0x28, - 0xa9,0x16,0x9e,0xe0,0x83,0x9d,0x28,0x1e,0xe6,0xd1,0xad,0xd8,0xaa,0x8a,0x45,0xd6, - 0x50,0x46,0x21,0x71,0x0d,0x35,0x85,0xc1,0x1b,0xe5,0x97,0x63,0x9d,0x10,0x60,0x08, - 0x70,0x04,0x14,0xaf,0x83,0xc6,0x61,0x03,0x6b,0xd7,0x07,0x8d,0x6e,0xa7,0xd3,0x20, - 0xbf,0x1a,0x2e,0x1b,0x60,0x65,0xc4,0x73,0xe8,0xe3,0x11,0x3c,0x0b,0xf2,0x28,0xe0, - 0xac,0x39,0x30,0x03,0xa9,0x97,0x61,0x39,0xfc,0x76,0x28,0xa9,0xc6,0xa3,0x1c,0x07, - 0x2e,0x2b,0xea,0xab,0xa0,0xdd,0x45,0x29,0x54,0x8a,0xc0,0x1f,0xf3,0xe5,0x36,0x7a, - 0x28,0x0b,0x22,0x6c,0x82,0xb0,0x41,0xd0,0x05,0x0d,0x8d,0x33,0xaa,0xfd,0x78,0x9d, - 0xa4,0xc3,0x35,0x54,0xed,0x12,0x28,0xf8,0xe1,0x36,0x81,0x52,0x2d,0xd4,0x9a,0xb0, - 0x2b,0x13,0x17,0xbb,0x40,0xd1,0x25,0x07,0x8d,0xb3,0xd7,0xdd,0x0d,0x10,0xee,0xbd, - 0x5e,0x2a,0x6e,0x75,0xf4,0x82,0x75,0x6e,0x5b,0xb0,0x93,0x4e,0xe3,0xaf,0x0a,0xf2, - 0xe1,0x57,0x81,0xdc,0xfd,0x7b,0x80,0x7c,0xf4,0x55,0x20,0x1f,0xfe,0x3d,0x40,0x3e, - 0xfe,0x2a,0x90,0x8f,0xbe,0x1c,0xe4,0x5d,0x4c,0x48,0x19,0x9c,0xad,0x9c,0x87,0x6f, - 0x1a,0x75,0x53,0x86,0xc4,0x37,0xa9,0x2e,0xc3,0x63,0xf6,0x07,0x5a,0x10,0xa8,0x56, - 0x86,0x1f,0xd6,0xd4,0xd0,0x6e,0xdc,0x6d,0x1d,0xe4,0xbc,0x00,0xf3,0x7d,0x22,0x6f, - 0x1b,0x63,0xac,0xb6,0x69,0xba,0x0d,0xf1,0x1a,0x80,0xdc,0x38,0x8d,0xca,0x6f,0xf8, - 0xbe,0x1d,0x9d,0x7d,0x11,0x58,0x64,0x38,0xdd,0x06,0x14,0x59,0x69,0x5f,0x35,0xf3, - 0xa7,0x61,0x98,0x57,0xc2,0x7e,0xeb,0x20,0x51,0x76,0xeb,0x10,0x0f,0x5a,0x2d,0xbd, - 0x53,0xaa,0xda,0x55,0x87,0x25,0x3e,0x0a,0xf7,0xaa,0x80,0x07,0xe5,0x61,0xe6,0x00, - 0xf3,0x2f,0x05,0xe6,0x52,0xe6,0x19,0xd6,0x4b,0x28,0x89,0x35,0x73,0x45,0x19,0x7f, - 0x2d,0x71,0x89,0x7e,0x1d,0x26,0xed,0x4d,0xb2,0x25,0x18,0x82,0xf7,0x64,0x12,0x40, - 0x54,0x15,0x81,0x15,0x0a,0x38,0x04,0x25,0x67,0x6a,0x05,0xc2,0x62,0x26,0x73,0xdc, - 0x2f,0xd5,0x6a,0xed,0x9a,0x3e,0x56,0x89,0x48,0x33,0xad,0xa9,0x42,0x9d,0x6c,0x8c, - 0x8b,0x35,0xb4,0xfc,0x0b,0x07,0x8b,0x6f,0x43,0xcb,0x54,0x7d,0x1d,0xe6,0xdf,0xc8, - 0x59,0x9a,0x2f,0x6f,0x1d,0x41,0x06,0xd9,0xd7,0x8d,0xf1,0x73,0x86,0x1b,0x6d,0x6f, - 0x1b,0x63,0xfe,0x95,0x23,0xbc,0x8c,0xf2,0xd9,0x22,0xc8,0x6f,0x67,0x9d,0xc5,0x9d, - 0x04,0xf4,0x0b,0x15,0x98,0x98,0x04,0x20,0x55,0x99,0xb3,0xbf,0x09,0x17,0xf9,0x3c, - 0x49,0xc0,0x66,0xa7,0xc2,0xf1,0x45,0xa0,0xb3,0x82,0x94,0xc1,0xe3,0x8d,0x51,0x59, - 0x0e,0x54,0x06,0x4e,0xa5,0x4d,0x44,0x48,0x3f,0xec,0x81,0x7b,0xba,0x78,0xa5,0xcc, - 0xe3,0x61,0x05,0x39,0x4a,0x40,0x95,0xce,0x24,0xe7,0xf2,0x40,0x85,0x83,0x43,0x06, - 0xb4,0x28,0x43,0x45,0x3e,0xac,0xa9,0x74,0xb7,0x7b,0xd4,0x45,0xef,0xbc,0x8b,0x8f, - 0xbf,0xc3,0xfd,0x76,0x60,0xa5,0x62,0xbf,0x48,0x7e,0x63,0x1d,0x9b,0xc6,0x01,0xe4, - 0x55,0x26,0x47,0x58,0xa1,0x1f,0x29,0xca,0x45,0xe2,0xc8,0xbe,0xdd,0xdd,0x79,0x30, - 0x93,0x3a,0xd1,0x09,0x53,0xa2,0xea,0x1f,0xee,0x54,0xc6,0x4a,0x52,0x5d,0x90,0xce, - 0x7e,0x0a,0x19,0x11,0x8d,0x2f,0xc0,0xab,0x45,0xdf,0x0b,0xb0,0xaf,0xd1,0x54,0x83, - 0xae,0xa0,0x24,0x24,0x6f,0x66,0x01,0x42,0xd7,0x4d,0x80,0x1d,0x47,0x54,0x0e,0xa3, - 0x9d,0xb6,0x50,0x8e,0x03,0xdc,0x10,0x53,0x6b,0x0e,0x5e,0xfe,0x54,0xc6,0x63,0xcf, - 0xee,0x6f,0x28,0x69,0x0b,0x8c,0x68,0x30,0xce,0x02,0x93,0xff,0x24,0x50,0x80,0x31, - 0xd1,0x8c,0x62,0x84,0xfc,0x69,0x2e,0x95,0x5e,0xb4,0xb2,0x7f,0xbb,0xa7,0x3c,0x88, - 0x14,0x66,0x47,0x2d,0xae,0x0c,0x6a,0x24,0xa5,0x89,0x44,0x86,0x1c,0xf3,0x32,0x1e, - 0x28,0x6e,0x59,0x56,0xbd,0x76,0x3b,0xab,0xb6,0x41,0xfb,0x28,0x2a,0xda,0x7a,0x6a, - 0x6a,0x97,0xee,0x03,0xa2,0x7c,0xc1,0x4d,0x36,0x54,0xdf,0x36,0xe2,0x94,0xe1,0x7d, - 0xe4,0x7a,0xe9,0x95,0x10,0xa0,0xeb,0x3e,0x0c,0x6a,0xbb,0x60,0xcd,0x50,0xaf,0xf4, - 0x1f,0x11,0xf8,0x3b,0x14,0x85,0xca,0x14,0x54,0x9f,0xbf,0xfa,0xf0,0x82,0xf7,0x6d, - 0x10,0xa9,0xb3,0xb3,0xae,0x65,0x67,0x7b,0x4e,0xa9,0xce,0x1e,0x2f,0x24,0x95,0x8b, - 0x61,0x7e,0x9a,0xb0,0x6d,0x60,0xcb,0x65,0x8c,0x41,0x56,0x50,0xca,0x49,0x34,0x06, - 0xfc,0x13,0xbd,0x60,0xc5,0xb6,0xd2,0x89,0xac,0x85,0xa0,0xed,0xe0,0xbc,0xc0,0x30, - 0xc2,0x30,0xc5,0xdd,0x84,0x14,0x8f,0x26,0xa5,0x82,0x22,0x75,0xaf,0xe2,0x95,0x5c, - 0x32,0xa1,0x0a,0x7f,0x88,0x69,0xf2,0x14,0xc8,0x1c,0x09,0x10,0xfe,0x24,0x69,0x49, - 0xeb,0x21,0x40,0x17,0xa7,0x01,0x6d,0xa0,0xc2,0xb1,0xcc,0x9a,0xc2,0x7a,0x22,0x66, - 0x00,0xec,0x3b,0xd7,0x8e,0xa7,0x06,0xce,0x4f,0x00,0x92,0xba,0x18,0x34,0xfe,0x30, - 0x8c,0x83,0x04,0x96,0x9c,0x76,0xb4,0x27,0x69,0x9a,0xc9,0x44,0x1a,0xc3,0xbb,0xb6, - 0xa8,0x45,0x00,0x76,0x33,0x7f,0x5d,0xb3,0xf4,0xa9,0x8d,0x1e,0x1d,0x23,0x71,0x55, - 0x84,0xc4,0xfe,0x7a,0x92,0x36,0xce,0xa6,0xc0,0xa8,0x30,0x09,0xee,0xa3,0x0c,0x46, - 0xe8,0xf0,0x48,0xb0,0xb6,0x62,0xd6,0xca,0x63,0x3c,0x87,0xe3,0x10,0x35,0x6f,0xc9, - 0xe4,0x4e,0x36,0x0c,0x14,0x6c,0x99,0x04,0xc6,0x08,0x0a,0xac,0x0f,0xd0,0x5e,0x33, - 0xe1,0x15,0x8d,0x99,0x1d,0x5e,0x8e,0x89,0xec,0x35,0xce,0x3a,0xdd,0x5b,0x3c,0x57, - 0x1d,0xed,0x2e,0x41,0x00,0x79,0x31,0x84,0x79,0x2d,0x77,0x8a,0x70,0x13,0x87,0x6e, - 0x9c,0x3d,0xcf,0xd3,0x0c,0xe3,0x70,0x01,0xb8,0xaa,0x67,0x7e,0x36,0x9e,0x81,0xef, - 0x79,0x26,0x66,0x69,0x38,0xc7,0xd8,0x5f,0x0e,0xcf,0x39,0x1c,0x88,0x6f,0xff,0x1c, - 0x65,0xf4,0x36,0xc3,0xca,0x41,0x13,0xdc,0xc1,0x40,0x0a,0x88,0xa9,0x9c,0x2c,0x48, - 0x0f,0x28,0x38,0x96,0x85,0xf4,0x6b,0xf6,0x9f,0x46,0x2a,0x21,0x63,0xaf,0x94,0xf3, - 0x80,0x7d,0xa4,0x42,0x2d,0x2c,0xf5,0xf6,0xa3,0xb1,0xd6,0x22,0x28,0xad,0xf2,0x08, - 0xf7,0xea,0xa1,0xf2,0xc7,0x92,0x2d,0xac,0xde,0xe3,0xba,0x3f,0x4a,0xf9,0x41,0x1b, - 0x43,0xb6,0xc8,0x3d,0x8b,0x3c,0x82,0x99,0x27,0xb8,0x6d,0x3f,0x35,0x5a,0x63,0x42, - 0xac,0x23,0x97,0x08,0x1c,0x7a,0x68,0x64,0x4f,0x58,0xc7,0xba,0x98,0xa1,0xdf,0x06, - 0x97,0x5e,0x95,0x2b,0x4a,0x8a,0x3c,0x1a,0x62,0x44,0xd7,0xec,0xac,0x46,0x4a,0x87, - 0x3b,0x03,0x27,0xd9,0x20,0x01,0xb3,0x23,0x6f,0x70,0xc8,0x79,0x77,0x03,0x97,0x12, - 0x82,0xaa,0xce,0x43,0xd3,0x1b,0x6a,0xa6,0x22,0x8a,0xcb,0x32,0x4e,0x9c,0x07,0x0b, - 0x74,0x3a,0x46,0xc3,0x64,0xa0,0x61,0x86,0xd4,0x00,0xd8,0x0e,0xb3,0xb6,0x19,0x4e, - 0x53,0xcf,0xc0,0xf4,0xc4,0xbb,0x10,0x53,0x62,0xb7,0x16,0x4e,0x56,0xa3,0x61,0x0c, - 0x4b,0xd4,0xc6,0xfd,0x53,0x9e,0xd9,0xe6,0x05,0xdd,0xb7,0x17,0x92,0xcd,0xa1,0x16, - 0xa0,0x31,0x0b,0x86,0x51,0x1c,0x15,0xcb,0x96,0xe9,0x6a,0x02,0x88,0x0f,0xab,0x0a, - 0xc8,0x50,0x62,0x6d,0x21,0x3e,0x81,0x59,0xd3,0x81,0x15,0x21,0xd3,0x03,0x4d,0x8c, - 0xa6,0x89,0xba,0xd5,0xec,0xf3,0xb2,0x2a,0x55,0x85,0xa5,0x07,0x8d,0xca,0x2b,0xd1, - 0x42,0x15,0x35,0x61,0x44,0x72,0x83,0x95,0x23,0x58,0x70,0x30,0x00,0x95,0x65,0x84, - 0x1c,0x38,0x44,0x49,0x08,0x58,0x36,0xbd,0x4d,0x83,0x4b,0x56,0xc2,0x8c,0x27,0xdc, - 0x1c,0x16,0x97,0xa2,0x65,0x3b,0xcf,0x11,0xc7,0xe3,0xd8,0xaf,0x23,0x52,0x18,0x6c, - 0xc3,0xe9,0xdc,0xf0,0x1a,0x23,0x96,0x6d,0xdf,0x23,0x23,0x57,0xc1,0xa4,0x92,0x2c, - 0x77,0xb0,0xf5,0xb9,0x2c,0xe6,0xd9,0x67,0xf1,0x34,0x1b,0xe3,0x77,0xf0,0xf3,0xd1, - 0x7d,0xf8,0x59,0xdb,0xfd,0x77,0x72,0xf1,0x7b,0x39,0x93,0x78,0xbc,0x10,0xd8,0xd3, - 0x40,0x84,0x41,0x6c,0xcc,0x69,0x55,0xb2,0xa9,0xb5,0x49,0xfc,0x8f,0x29,0x16,0xd8, - 0x92,0x31,0xc4,0xd5,0xaf,0x09,0xd9,0xe4,0x28,0xe9,0xd5,0x16,0xc6,0xbd,0x65,0xa2, - 0x17,0x18,0xf3,0xb8,0x73,0xa6,0xc7,0xf7,0x99,0xa9,0x0e,0x9f,0xdc,0x39,0x53,0xb6, - 0x0f,0xb1,0xa6,0x97,0xca,0x79,0x65,0x32,0x4a,0xb1,0xda,0x78,0x94,0xce,0x41,0xab, - 0xb2,0xb9,0x84,0x02,0x1e,0xf4,0xe1,0x92,0x8e,0x53,0x50,0x70,0x79,0x21,0x91,0x9c, - 0xb1,0xfe,0xab,0x44,0x07,0xf2,0x0d,0x07,0xaf,0x73,0x2a,0x74,0x0e,0x90,0x58,0xc7, - 0x63,0x99,0xfb,0xe2,0x6d,0xa5,0xe8,0x72,0x49,0x7c,0x7a,0xbb,0x34,0xdb,0x41,0x36, - 0xcf,0xed,0xb8,0xfb,0xfd,0xe8,0x46,0x2b,0xc5,0xbb,0xf0,0x79,0x72,0x1f,0x7c,0x1a, - 0x73,0x5c,0x18,0x5d,0x79,0x3f,0x4d,0x10,0xb0,0xe2,0xdf,0x42,0x35,0x63,0x68,0x3f, - 0xa5,0x82,0x2a,0x05,0x36,0x22,0x5b,0x10,0x54,0xe2,0xfd,0xf4,0x2d,0x61,0x1d,0x70, - 0x05,0x66,0x36,0xd8,0x77,0x46,0x0d,0xd2,0x53,0x8e,0xf8,0x13,0x1c,0x09,0x6d,0xeb, - 0x90,0xe1,0xe7,0x91,0x18,0x8b,0xea,0x3b,0x71,0xf2,0xf0,0x3e,0x38,0xe1,0x83,0x7c, - 0xee,0x81,0x8a,0x97,0xb8,0x8d,0x0b,0x7d,0x4a,0x10,0x77,0x33,0xf2,0xce,0x40,0x5e, - 0x72,0x64,0x80,0x6d,0xa1,0xb5,0x04,0xc7,0x96,0x33,0x67,0x82,0x51,0x31,0x07,0xf9, - 0x05,0xf2,0x35,0x45,0x97,0xe5,0x56,0x0a,0xda,0x62,0x29,0xb2,0xcb,0x72,0x56,0x99, - 0x35,0x3c,0xcf,0x9a,0xc9,0x13,0xdc,0x61,0x64,0xdd,0x69,0x5d,0xad,0x7f,0x80,0x90, - 0x9d,0xb6,0xf5,0xd0,0x7b,0xa7,0x6d,0xcc,0x49,0x01,0x38,0xe6,0xec,0xb4,0xbd,0xf2, - 0x88,0xa4,0x7f,0x6a,0x46,0xe5,0xb9,0x4c,0x61,0x3a,0x9a,0xe3,0x26,0x64,0x1f,0x46, - 0x7a,0x11,0x4b,0xbc,0x7c,0xb6,0x7c,0x15,0x42,0x8b,0xd5,0xde,0x3f,0x35,0x1d,0x84, - 0xdb,0x71,0x6b,0x07,0x9a,0x81,0x71,0x4f,0x19,0x52,0x1f,0xdf,0xa1,0xc2,0xe9,0xef, - 0xed,0xb5,0xdb,0xa6,0xb0,0xe7,0x17,0xc6,0x25,0x9a,0xaa,0xa4,0x23,0x4b,0x44,0xa2, - 0x8e,0xfd,0xdb,0xee,0xaa,0x06,0x20,0x6a,0x65,0x45,0x48,0xb6,0xbb,0x8d,0x0b,0x7f, - 0xab,0x0d,0x23,0x4b,0x13,0x06,0xbb,0xd3,0x56,0x0c,0x20,0x1e,0xab,0x98,0xf0,0x75, - 0xc4,0x87,0xb9,0x28,0xd4,0xb1,0xdb,0x6d,0x11,0x9d,0x63,0x2d,0xa6,0x1e,0xef,0x6a, - 0x26,0x13,0x08,0x3b,0x23,0x67,0xb7,0xf2,0x4a,0xa5,0x01,0x56,0xb1,0xd5,0x20,0x34, - 0xca,0x0a,0x13,0x38,0x09,0x0a,0xdc,0x0f,0xb2,0xcd,0xd2,0xc0,0xde,0x8c,0xb1,0x61, - 0x5c,0xcc,0x5b,0x0d,0x9a,0x6d,0x96,0x0c,0x5b,0x29,0xd8,0x95,0x31,0x4e,0x88,0x27, - 0x2a,0xef,0x10,0x85,0x34,0x17,0xa1,0x55,0xb6,0x0a,0xef,0x6e,0x31,0xd6,0x82,0xa9, - 0xc4,0x0d,0xf2,0x0b,0x00,0x04,0xbb,0x62,0xf3,0x31,0x64,0x4f,0x9a,0xa0,0x29,0x0d, - 0x18,0x76,0xf9,0x87,0x4a,0xea,0x48,0x12,0x48,0xff,0x99,0x0c,0x92,0xa2,0x66,0xaa, - 0x00,0x39,0x01,0xbb,0x61,0x4f,0xe5,0x9a,0xf0,0xf4,0xd0,0x13,0xd2,0x8f,0x1c,0x5e, - 0x3f,0x9c,0x4a,0xb1,0x69,0x70,0xc0,0xb7,0xf8,0xf9,0x7b,0x69,0xe1,0x12,0x18,0x00, - 0x0f,0x6b,0x23,0xa8,0xec,0x05,0xc7,0xd5,0x1a,0x4d,0xd1,0xf0,0x55,0xa2,0x89,0x94, - 0x52,0x1e,0xdb,0xa3,0x4f,0x88,0x23,0x57,0x8d,0xe9,0x20,0xa4,0x03,0x5b,0x94,0x41, - 0xb7,0x56,0x2d,0xd6,0x0e,0x5c,0x5d,0x56,0x23,0x42,0x90,0xc3,0x58,0xa4,0x88,0xe3, - 0x60,0xdb,0x31,0x30,0x98,0x72,0x3d,0x6c,0x93,0x60,0x5f,0x56,0x88,0x20,0x97,0x09, - 0x9d,0x2a,0xa8,0xcc,0x6e,0x5b,0xb2,0xba,0x78,0xa1,0xd8,0x55,0xec,0x74,0x3d,0xd1, - 0x39,0x84,0x3f,0x47,0xfe,0x1e,0x1e,0xf9,0x06,0x32,0xe7,0xb5,0x5c,0xf6,0x2b,0x56, - 0x46,0x6b,0x10,0x8f,0x3a,0x03,0x91,0x82,0xef,0x23,0x0f,0x5a,0x0c,0x9a,0x0a,0xcf, - 0x7c,0xab,0x26,0xe9,0xde,0xdc,0x7c,0xfc,0xe4,0x5d,0x0c,0xfe,0xf5,0xfc,0xa7,0xb7, - 0xbe,0x2a,0x70,0x47,0x4f,0x34,0x5e,0x36,0xa1,0x29,0x15,0x16,0x45,0xe3,0xe6,0xc5, - 0x60,0x30,0xe0,0xbe,0x5d,0x96,0x0b,0x7d,0xae,0x04,0x83,0x07,0x83,0x8b,0xbe,0xee, - 0x7c,0x3c,0x00,0x81,0x60,0x2c,0x30,0xc7,0xf5,0xc6,0x17,0xe6,0x01,0x9a,0x6f,0x8e, - 0xe9,0x6b,0xac,0x73,0xfd,0x63,0x1f,0x4b,0x0c,0xf2,0x7f,0xf9,0xf0,0xe6,0xc7,0x81, - 0xe3,0x98,0xa3,0x51,0xf2,0x66,0x34,0xe8,0xf4,0x23,0x54,0xa7,0x7e,0x2c,0x93,0x49, - 0x31,0xed,0x47,0x07,0x07,0x65,0x79,0x00,0x8e,0x23,0x11,0x94,0x8f,0xd1,0xa7,0x3e, - 0x9e,0x0b,0x27,0x6f,0x6e,0xa4,0x6e,0x78,0x7a,0xe8,0xa2,0x7d,0x1f,0x25,0xf3,0xb2, - 0xf6,0x05,0x9b,0x07,0x83,0x52,0x86,0x8d,0x00,0x6b,0x85,0xd4,0x62,0xac,0xe9,0x04, - 0x4e,0x59,0x38,0x15,0xf8,0xa4,0x25,0xde,0xe2,0x81,0x6e,0x0e,0x6b,0x0a,0xa7,0x1f, - 0xf8,0x24,0x81,0xe5,0xc7,0xce,0xa7,0xaa,0x9d,0x05,0xf4,0x2e,0x6d,0xd5,0xd1,0x72, - 0xdc,0x39,0x28,0x63,0x0c,0xce,0x76,0x95,0xa5,0xc3,0x64,0x5b,0xb5,0x14,0xbf,0x73, - 0xaa,0x91,0xff,0x34,0x07,0xca,0x38,0x07,0x0e,0x1a,0x15,0x78,0xd0,0x5e,0x59,0x05, - 0xb5,0x26,0x7f,0xe5,0xc7,0xee,0xa7,0x3b,0x3f,0x0a,0x37,0x3e,0x3a,0xfc,0x74,0x73, - 0xe3,0x94,0xa3,0x8d,0x7d,0xdc,0x0e,0x99,0x84,0x3f,0xe0,0x36,0xd8,0x66,0xa0,0xf1, - 0xb4,0xd2,0x0b,0xc7,0xc6,0xf5,0x60,0x7c,0x61,0xae,0x1e,0x8c,0x77,0x0c,0xc4,0x18, - 0x5e,0x69,0x0a,0x21,0x04,0xa9,0x6a,0x3d,0x6a,0xdf,0x3c,0x8d,0x63,0xf8,0x8c,0x44, - 0x49,0x59,0xf2,0xc2,0x9f,0x57,0x54,0xc1,0x1d,0xd8,0x84,0x41,0x10,0xf1,0x63,0x20, - 0x89,0xda,0x9c,0x9a,0xd1,0x41,0xf7,0xb4,0xdb,0x79,0xe2,0x74,0x9c,0x9e,0xe3,0xb8, - 0x07,0x78,0x0f,0xfd,0xad,0x6c,0x75,0x64,0x9f,0xc1,0xf4,0x0f,0x72,0xfa,0x47,0xa5, - 0xad,0x5e,0x54,0xa2,0x20,0x35,0xe2,0x12,0xe0,0x1c,0xa5,0x33,0x10,0x48,0xe8,0x6d, - 0x81,0xd8,0xb6,0x94,0x4c,0xaf,0x7e,0x36,0xd9,0x28,0xcd,0x96,0xd8,0x4b,0x13,0x0f, - 0xc1,0xe1,0xa3,0x12,0x3d,0x71,0x21,0x33,0x14,0x7a,0x52,0x4d,0xb5,0x24,0x3b,0x12, - 0x8a,0x5a,0x58,0xc7,0x55,0xba,0x38,0x1a,0x85,0xdf,0x41,0x9f,0x80,0x65,0x01,0x56, - 0x52,0x46,0xe7,0xe4,0x60,0x6f,0x1c,0xe3,0xc7,0x81,0x8a,0x60,0x88,0x3a,0x89,0x29, - 0x80,0x5d,0x77,0x6d,0x1f,0x99,0x03,0xaa,0x40,0xf2,0xf2,0x19,0x55,0x98,0x0a,0x18, - 0xa3,0xd1,0x45,0x75,0x11,0x91,0x5c,0x90,0xa0,0x4b,0x42,0x76,0x11,0xe5,0x15,0x88, - 0x35,0x74,0xc1,0x53,0x76,0x56,0x42,0x50,0x2c,0x28,0x19,0x41,0x37,0xa0,0x80,0x62, - 0x65,0x08,0xb2,0x10,0x25,0x69,0x0c,0xd6,0x0d,0x29,0x49,0x25,0x19,0x0a,0x4c,0x82, - 0x63,0x6f,0x58,0x5e,0x03,0x6a,0xe2,0x0f,0x26,0xe0,0xf2,0x07,0x34,0x9b,0xfc,0xa9, - 0x5f,0x89,0xc2,0x70,0x9e,0x5b,0x92,0x30,0xe4,0x53,0x37,0xc1,0x38,0x02,0xe2,0x52, - 0xed,0x47,0x0f,0x8f,0x3b,0x1d,0xd7,0x9b,0xd6,0x9e,0x7e,0x4b,0x4f,0xdb,0x47,0x0f, - 0xf1,0xd5,0xac,0xfe,0x0a,0x1f,0xb6,0x1f,0x76,0x8c,0x50,0x0b,0x5d,0x63,0x2f,0x1d, - 0x38,0xa1,0x70,0x0e,0xa6,0x07,0xce,0xd4,0x41,0x01,0x35,0x35,0x2f,0xf0,0x09,0xbc, - 0x98,0x1d,0x38,0x33,0x47,0x7f,0x34,0x33,0xef,0xf8,0xa1,0xbe,0x51,0x07,0x8e,0x72, - 0x90,0x4c,0x61,0x56,0x3f,0x65,0x08,0x7a,0x50,0x1e,0x0a,0x36,0x9a,0x46,0xa0,0x3c, - 0x48,0x69,0x19,0x25,0xcb,0x7c,0x7a,0xae,0xcd,0x8c,0x48,0xc6,0xe0,0xe5,0x89,0x1f, - 0xd1,0xb2,0x50,0xf8,0xd5,0xd2,0x52,0x96,0xad,0x60,0x92,0xa4,0x58,0xd0,0xc4,0xfa, - 0x24,0x52,0xb6,0x66,0x25,0xc5,0x87,0xe6,0x9a,0xb2,0x42,0xdc,0xcd,0xf7,0x27,0xae, - 0x85,0xc2,0x0c,0x2b,0xe5,0xde,0xc9,0x7c,0x6c,0x21,0x12,0x6c,0x4e,0x90,0xf2,0xba, - 0x88,0x03,0xf8,0x95,0x84,0x72,0x6c,0xa9,0x09,0x3a,0x73,0x76,0xf0,0xf1,0x93,0x9e, - 0xb4,0xf2,0x31,0x90,0xf1,0x3e,0x8d,0x25,0xe8,0x14,0x27,0x9b,0x0f,0x41,0xa9,0x81, - 0x39,0xe1,0xb8,0x05,0x9f,0xaf,0xea,0xbc,0x9b,0x0f,0x99,0xed,0x31,0x42,0xbe,0xf9, - 0x85,0x9a,0x0f,0xd1,0x60,0x1d,0xda,0x9f,0x9c,0x9b,0x4f,0xa0,0x35,0x26,0x3c,0xd1, - 0x9c,0xf1,0x95,0x04,0xf1,0x92,0x8c,0xe4,0x1b,0xf0,0x20,0xf1,0x43,0xf0,0x5f,0x62, - 0x30,0x28,0x1c,0x16,0x19,0xfa,0xd3,0x7a,0xb3,0x27,0xce,0xbb,0x38,0x58,0xa2,0x96, - 0x05,0x89,0xf1,0x8c,0x76,0x9a,0x54,0xfd,0x6a,0xa9,0xe3,0x5e,0xcb,0xb8,0x14,0x80, - 0x01,0x80,0xd8,0x87,0xfb,0xda,0x81,0xbe,0x3e,0x7a,0xe0,0x4d,0x47,0xfc,0xdf,0xff, - 0x23,0x1c,0xaa,0xff,0xc3,0x89,0x58,0x5f,0x15,0xf9,0x7c,0xe3,0x23,0xc7,0x59,0xc1, - 0x8a,0x23,0xaa,0xb0,0xb6,0x7a,0x80,0xc7,0xe6,0xf6,0xd7,0xf0,0xae,0x71,0x4e,0xef, - 0x15,0x02,0xa5,0x75,0x3b,0x5e,0xc2,0x1a,0x7f,0x00,0x5d,0x25,0xf5,0x59,0x3f,0x9e, - 0x31,0xbd,0x78,0xaf,0xae,0xe5,0xba,0x00,0xe7,0xa7,0xf1,0x25,0x9b,0xb2,0x33,0xb0, - 0x1f,0xa9,0x48,0x05,0x65,0x49,0x0e,0x1e,0x84,0xe2,0x9e,0x98,0xd9,0x29,0x7d,0x87, - 0x6f,0x51,0xfc,0x58,0x8e,0x0f,0x7f,0xb1,0x30,0xb6,0x31,0x2f,0x12,0xd8,0xa8,0xa9, - 0x75,0x04,0xa7,0x0e,0x61,0x23,0xe5,0x95,0xae,0x96,0x00,0x8a,0xc4,0x1c,0x0a,0x6d, - 0x15,0x18,0xa2,0xcb,0xce,0xc6,0x0d,0x53,0x33,0x6f,0x70,0xc6,0x38,0xc5,0x02,0x37, - 0x19,0x87,0x60,0x32,0x5a,0x09,0x11,0xdf,0x90,0x0e,0x0d,0xae,0x8d,0x01,0xa6,0xba, - 0x35,0x3d,0xe6,0xf0,0x8c,0xb4,0x1e,0xe3,0x26,0x0a,0xa9,0xa3,0xd6,0x4a,0xf9,0xbc, - 0xef,0xfd,0x49,0xd3,0x5c,0x1d,0x38,0x88,0x9a,0x39,0x09,0xd6,0x04,0x86,0xbc,0x80, - 0x85,0xef,0x39,0x9c,0x9a,0x4a,0xc7,0x63,0xea,0x6f,0x55,0x11,0xa4,0xae,0x9e,0x7c, - 0x47,0x98,0xd2,0xf0,0x10,0xbb,0xca,0x84,0x62,0x0b,0xd6,0xc9,0x28,0x20,0x04,0xf1, - 0x00,0x15,0x3a,0xe5,0x11,0x5a,0xa3,0xc1,0xca,0x32,0xbd,0x5f,0x1e,0xb2,0x04,0x46, - 0xc4,0x3c,0xc3,0x38,0xa4,0xe9,0x67,0x48,0xe6,0x28,0x85,0x67,0xb1,0x6e,0x15,0x4c, - 0x57,0x3c,0x57,0xda,0xf4,0xac,0x45,0x1c,0x88,0x78,0x76,0x5e,0xab,0xbc,0x2b,0x45, - 0x0e,0xab,0x04,0x02,0xf4,0x74,0x89,0xc5,0x90,0xec,0x56,0xe0,0x41,0x68,0x98,0x5f, - 0xad,0xea,0x36,0xcd,0xc1,0xa9,0x81,0xbd,0x4c,0x65,0x5a,0x96,0xc9,0x80,0x24,0xae, - 0x7f,0x0b,0xc2,0x19,0x07,0x77,0x20,0xdc,0xc9,0xca,0xa8,0x41,0x8e,0x94,0x40,0x3b, - 0xeb,0xb4,0xdb,0x85,0xb0,0x19,0xdc,0x6b,0xbf,0x20,0xa0,0x14,0x72,0x08,0xca,0x60, - 0x1d,0xf1,0x88,0x25,0xf8,0x18,0xed,0x57,0x5e,0x38,0xe4,0xec,0x96,0x53,0x2d,0xc1, - 0x53,0x13,0xdc,0xc6,0x96,0xca,0xe8,0x4d,0xf6,0x58,0x48,0xda,0x8d,0x09,0xad,0x4a, - 0xc2,0xfa,0x84,0x88,0x62,0x0c,0xf7,0xc2,0xd5,0x7f,0x72,0x77,0xff,0x69,0xfa,0x61, - 0xfb,0xba,0xd1,0x6a,0x90,0x17,0x42,0x18,0xee,0x55,0xbb,0xd6,0x51,0x4e,0x62,0x2f, - 0x05,0xdc,0x63,0x39,0x33,0x73,0xa8,0x0c,0xfd,0xdb,0xb1,0xa0,0xa1,0xff,0xed,0x2f, - 0xff,0xbb,0x9a,0xd7,0x2d,0xc4,0x6c,0xe6,0x08,0x86,0x19,0x20,0xe9,0x0e,0x14,0x03, - 0x72,0x68,0x15,0x7f,0x56,0x4f,0x48,0x51,0x91,0x6b,0xd6,0xec,0xca,0x87,0xed,0xf2, - 0x85,0x0b,0x54,0x3e,0x06,0xfd,0x81,0x82,0x89,0x2c,0x22,0x6d,0xec,0x95,0x5c,0xf0, - 0x4a,0xbd,0x21,0xe4,0x3d,0x71,0x18,0x89,0xd0,0x8a,0xdd,0xa4,0x28,0xa9,0x0c,0x39, - 0x5b,0x09,0xf4,0xcb,0xfb,0x74,0x21,0xf3,0x92,0x41,0xcb,0xc7,0x55,0x95,0x19,0xbc, - 0xab,0x6a,0xbe,0xa8,0x01,0x4c,0x84,0x2a,0x3a,0x36,0x26,0x6d,0x68,0x05,0xa0,0x15, - 0x4d,0xe7,0x00,0x1e,0x00,0x79,0x80,0x5f,0x0a,0xf7,0x06,0x1a,0x71,0x20,0xf0,0x05, - 0x43,0x89,0x2f,0xf4,0x95,0xeb,0x94,0x5a,0x66,0x0c,0x73,0x99,0xe3,0x9a,0x54,0xe2, - 0x02,0x0b,0x35,0xd6,0x46,0xb3,0x50,0x45,0xdf,0x7c,0x48,0x0b,0x3c,0xa3,0x19,0xae, - 0x7e,0x46,0xce,0x6e,0x77,0x3b,0xc7,0x8f,0x4e,0xbe,0x7f,0xf8,0x5d,0xb7,0x83,0xd7, - 0x30,0xd0,0x9b,0x67,0x68,0x3e,0xc9,0x6a,0x31,0x74,0xf5,0x07,0xf4,0x4b,0xb5,0xbf, - 0x3e,0x9f,0x84,0x5c,0x75,0xf6,0xc4,0x74,0xd6,0x2e,0x1f,0x41,0x6f,0x9d,0x5e,0x07, - 0x56,0xe3,0x5b,0x8b,0x0c,0xb6,0xc3,0xe7,0xa0,0xdb,0x39,0xe3,0x89,0x38,0x2b,0x23, - 0xe9,0x59,0xce,0xa3,0x66,0x68,0x72,0x1a,0xb0,0x28,0x7d,0x73,0x16,0x59,0xa8,0x81, - 0x00,0xfc,0x32,0x94,0xb0,0xe5,0x24,0x64,0xee,0x8b,0x12,0xbe,0x8b,0x94,0x32,0xd0, - 0xca,0x9c,0x89,0x98,0xa0,0x7c,0xa6,0x9d,0x71,0xe0,0x43,0x03,0xe3,0xf4,0x39,0x18, - 0xbb,0x51,0x96,0xe1,0x6b,0xed,0x3e,0x55,0xb0,0x6a,0xba,0x5b,0x3c,0x9e,0xdc,0x4b, - 0x06,0x53,0x90,0x91,0x31,0x9e,0x68,0xa0,0x6e,0x3a,0xe5,0x62,0x63,0xe0,0x7c,0x63, - 0xb5,0xf1,0x21,0xca,0x61,0xa5,0x22,0xb0,0x9d,0x88,0x36,0x61,0x65,0x73,0xb8,0x85, - 0xbb,0xf0,0xd9,0x0c,0xe4,0x30,0x74,0x36,0xcf,0x9e,0x10,0x2a,0x80,0x6b,0x13,0x4a, - 0xb8,0x03,0x69,0xea,0xf3,0x0b,0x9d,0xb2,0xff,0x28,0xdb,0xde,0xbb,0xf2,0xa3,0xac, - 0x57,0xb2,0x10,0x35,0xc5,0xa2,0x10,0x68,0x6c,0xdc,0x17,0x1a,0x41,0x93,0x0e,0x5d, - 0xbb,0xba,0xd5,0x5a,0x87,0xd3,0x3a,0x9c,0xd8,0x36,0xca,0x80,0x3d,0xbb,0x8f,0x0f, - 0xfd,0xee,0xc3,0x47,0xfe,0xb1,0xdf,0x75,0x5c,0xf3,0x36,0x39,0x68,0x26,0x20,0x9e, - 0xba,0x4f,0x1c,0xc1,0xb8,0x00,0x98,0xf5,0x95,0x72,0x8c,0xda,0x7e,0x8f,0xa8,0x95, - 0xa1,0x09,0xb8,0x92,0xa8,0xdf,0xbd,0x7f,0x51,0x2f,0x6c,0xaf,0xac,0x9b,0x01,0xd9, - 0x3b,0x9e,0xc7,0xdc,0x55,0xb9,0xad,0x91,0xf4,0x71,0x74,0x59,0xe9,0x0b,0xd2,0x62, - 0xbc,0x5e,0x18,0xb3,0xa3,0x0a,0x70,0x6b,0xf6,0x80,0xfd,0xcb,0x28,0xd0,0xa5,0x30, - 0xfb,0xfb,0x0f,0x18,0x6d,0x15,0x93,0x62,0x7d,0xca,0x6e,0xbe,0x81,0xa5,0x87,0xf7, - 0x74,0xe6,0x34,0x58,0xaa,0xc0,0x25,0x87,0xc7,0x80,0x82,0xd7,0xc4,0xa2,0xc4,0x24, - 0x1b,0x6d,0xdf,0x29,0x90,0x47,0x86,0xb5,0xa0,0xed,0x1b,0x91,0xe1,0x93,0x6a,0x75, - 0xe6,0xeb,0xc3,0x91,0xed,0x0e,0xcb,0x82,0x55,0x2e,0x15,0x5c,0xe3,0x0d,0x65,0x74, - 0x89,0xb4,0x03,0x98,0xc4,0x43,0xca,0xfa,0x7b,0x8c,0x16,0x5d,0x24,0x60,0x3c,0x14, - 0x2e,0x8c,0xe0,0xe8,0x0c,0xa8,0x44,0xc5,0xd1,0x5d,0x2e,0x5a,0x42,0x76,0xb1,0x36, - 0x81,0x23,0xed,0x93,0xc6,0xf2,0xb8,0xa7,0xb2,0x58,0x82,0xe2,0x80,0xda,0x44,0x7e, - 0x05,0xd6,0x42,0xa2,0x2b,0x40,0x66,0x11,0x50,0x47,0x32,0xd9,0xac,0x99,0x88,0x38, - 0x33,0x96,0x5e,0x48,0xa5,0xd7,0xbd,0x2a,0xef,0x30,0x50,0x60,0xc4,0x8b,0x4a,0xa1, - 0x00,0x08,0xcd,0x8e,0x69,0xc9,0x6e,0xe8,0xf8,0x19,0x76,0x93,0x21,0x10,0xf6,0x25, - 0xd6,0xd4,0x26,0x05,0x2a,0x42,0x7d,0xf9,0x00,0x34,0x21,0x6a,0x38,0xe7,0x49,0xf9, - 0xa8,0xe7,0x18,0x79,0x58,0x17,0x83,0x72,0xc3,0xfd,0x0f,0x0f,0x9a,0xe5,0x57,0xff, - 0xc6,0xf8,0x03,0xb2,0x25,0x6c,0xd6,0x1e,0xa2,0xda,0xe8,0xdb,0x1d,0xb5,0xb6,0xa8, - 0xb9,0x0f,0x55,0x59,0x0f,0x9d,0x7f,0x8d,0xa8,0x70,0x0e,0x24,0xb2,0x8d,0x34,0x8b, - 0x51,0xc6,0x46,0x9c,0x0f,0x41,0x46,0x4a,0xd9,0xac,0x43,0x95,0x1a,0xce,0x11,0x03, - 0x93,0xb4,0x3c,0xfb,0x5d,0x9f,0x09,0x9f,0x84,0xe8,0x05,0x9b,0x38,0xac,0xef,0xd4, - 0xe1,0xa1,0xe2,0x12,0x24,0x6e,0x0c,0xdd,0x38,0x77,0x56,0x97,0x7c,0x03,0x80,0x51, - 0x92,0xe9,0xe7,0xf7,0xaf,0x7e,0x48,0x67,0x19,0xac,0x00,0x98,0xda,0x7a,0x9f,0x74, - 0x5d,0x41,0x6f,0xc1,0x9b,0x63,0x1d,0xde,0xef,0xdc,0x03,0x2f,0xdb,0xe0,0x17,0x3f, - 0x91,0x71,0x62,0x00,0xa2,0xf9,0x2f,0x2d,0xfc,0x2c,0xca,0x88,0x39,0x39,0xc7,0x58, - 0xce,0x83,0x92,0x90,0x8e,0x86,0x0e,0x50,0x48,0x1b,0x5f,0x18,0xec,0xf9,0x57,0x60, - 0xdc,0x01,0x6f,0xb3,0x29,0xce,0xf6,0xba,0xce,0x8c,0x55,0xfd,0x21,0x7d,0xf1,0x81, - 0x9d,0xb4,0x69,0x23,0xb3,0xf3,0x39,0x8a,0x63,0xa6,0xea,0x2b,0x91,0xea,0x18,0x5b, - 0x81,0x34,0x31,0x1d,0x9b,0xa7,0x5c,0xce,0x54,0x9d,0xf3,0xc9,0x79,0xd5,0x63,0x6c, - 0x0a,0x12,0x70,0x74,0xc1,0x3b,0xff,0x9b,0x25,0xff,0x7a,0x25,0xed,0xad,0x07,0x6d, - 0xfe,0x11,0xcf,0x6c,0xd5,0x21,0x9b,0x0f,0xe5,0x59,0x8b,0x8c,0xfc,0x7f,0x7b,0xf5, - 0xe2,0x17,0x34,0xb5,0x2b,0x17,0xcc,0x51,0xec,0xa4,0x71,0x59,0x90,0xe1,0x6f,0xf0, - 0x09,0x8b,0x69,0x4f,0xbc,0xee,0x6a,0x8b,0x95,0x83,0xe5,0xe4,0x74,0x51,0x40,0x39, - 0x11,0x6f,0x7e,0xff,0xe1,0x03,0xd8,0xa2,0x4a,0xa1,0xb7,0xce,0x51,0xe9,0x32,0x6b, - 0xcf,0x75,0x6a,0xa5,0xeb,0x45,0x41,0x1d,0x1d,0x31,0xe0,0x10,0x3e,0xd1,0x10,0x2f, - 0x3a,0x51,0x12,0x6e,0xd7,0x02,0xab,0xd5,0x84,0xe1,0x31,0x8d,0x65,0x22,0xe3,0x1f, - 0xb4,0x66,0x91,0x57,0x23,0x99,0xb1,0xf0,0x62,0x0e,0x9e,0xa5,0x18,0xb3,0x13,0x74, - 0x7a,0x8b,0x21,0x2b,0x5f,0xbc,0xfb,0xe9,0xfc,0x83,0x0e,0x42,0xb1,0x2b,0x99,0xc4, - 0x4b,0x94,0x7b,0x20,0xf9,0xb0,0x37,0x0a,0x14,0x95,0x9b,0x47,0x89,0x68,0xd1,0xa1, - 0x68,0xba,0x02,0xc3,0x05,0xe0,0xdb,0xd0,0xb1,0x91,0x3a,0xde,0x94,0xf0,0x16,0x16, - 0xc5,0xc5,0x79,0x54,0x87,0xa1,0x67,0x11,0xc3,0xcc,0x74,0xe0,0x3f,0x4a,0xcc,0xe9, - 0xb6,0x65,0x24,0x1c,0x93,0x2f,0x0c,0x23,0x78,0x49,0x5c,0xad,0xcc,0xa2,0x9c,0x7c, - 0x4d,0x95,0x04,0x99,0x75,0x06,0x26,0x4b,0x13,0x8a,0xcb,0x1b,0x00,0xf9,0xe0,0x2f, - 0x9f,0xa8,0x3f,0x96,0x3f,0xd3,0x59,0x13,0x6a,0x9e,0xd1,0x91,0x97,0x52,0x5b,0x45, - 0xec,0x36,0xd0,0xc6,0x76,0x80,0xb0,0xd0,0x31,0xa9,0x2c,0x5e,0x56,0x75,0x87,0x94, - 0xc4,0x49,0xb1,0xb4,0x2f,0x49,0xe7,0x93,0x69,0x99,0x84,0xd6,0xeb,0x48,0xe5,0x1d, - 0x97,0xb2,0xca,0x78,0xe1,0xa1,0x59,0x61,0xdf,0x3e,0x91,0x80,0xe6,0x4a,0x08,0xa6, - 0x99,0x92,0xb9,0x83,0x72,0x42,0x71,0x74,0xdf,0x82,0x6f,0xd0,0x59,0x0f,0x0f,0xb0, - 0x05,0xce,0xee,0xb9,0x07,0x43,0x8f,0xf8,0x4c,0x2b,0x0c,0xc7,0xd0,0xdd,0xfe,0xfe, - 0x73,0xa0,0x3a,0xfe,0xb5,0x9a,0x53,0xab,0x27,0x2b,0x52,0x03,0xdc,0x8e,0x1b,0x5f, - 0x80,0xcf,0xed,0x60,0x38,0xee,0x69,0x01,0x53,0x87,0x7b,0x7e,0xe2,0xa0,0x11,0x93, - 0x6a,0x77,0x80,0x3e,0x60,0x87,0xfb,0xd6,0x6f,0xf0,0x03,0xd6,0x1c,0xab,0x0a,0x6a, - 0x8c,0xdc,0xe1,0xcf,0x22,0xb9,0xd7,0x7c,0x4a,0x37,0x5e,0x83,0x29,0x15,0x25,0xe3, - 0xd4,0xf1,0xb0,0x67,0xde,0xe1,0x82,0x3f,0x24,0x53,0x7d,0x04,0x80,0xdb,0x13,0xa5, - 0x29,0xda,0x68,0xa9,0xe6,0x78,0xd0,0xc5,0x1d,0xc7,0x75,0xff,0x44,0x63,0x07,0x03, - 0x30,0x04,0x3f,0x81,0x60,0x80,0x34,0xc1,0x0e,0xf4,0xce,0x7a,0xce,0x22,0xb8,0xd0, - 0xd7,0x1c,0x82,0xa6,0x9f,0xa7,0x71,0x2a,0x42,0x77,0xbc,0x6b,0x2c,0x2b,0x4d,0xc3, - 0x9e,0x83,0x2c,0xe0,0x78,0x23,0xb4,0xe3,0x7a,0x60,0xa4,0xb6,0x30,0x95,0x2c,0x1d, - 0x53,0x73,0xc4,0x3b,0xf2,0x54,0xef,0xda,0xd1,0x7a,0xa0,0xf5,0x61,0x99,0xa1,0x67, - 0x15,0x64,0x19,0xb0,0x10,0x99,0xf1,0xed,0xab,0xd6,0x62,0xb1,0x68,0x21,0x3f,0xb4, - 0xe6,0x79,0xcc,0x0a,0x09,0xec,0x7d,0xaf,0x3c,0x7b,0x2a,0x5c,0x82,0xbd,0x9b,0x0c, - 0x2c,0x9c,0x76,0xa1,0x8b,0x8e,0xe3,0xae,0x38,0x9c,0x75,0xe7,0x8f,0xe6,0x74,0x4c, - 0x78,0xb1,0xfa,0x4d,0x9c,0x6d,0x1f,0x96,0x89,0x16,0x1b,0xa9,0xfc,0xfb,0x44,0xc1, - 0x55,0xd3,0x7a,0xe8,0x59,0x98,0x7e,0xd4,0xe9,0x94,0x89,0x94,0x1a,0x4a,0xcb,0xf8, - 0x89,0xce,0x6b,0x2e,0xb1,0x54,0x68,0x88,0x8a,0x5d,0xef,0x9b,0xc2,0x40,0x0b,0x4a, - 0x00,0xa7,0xb2,0x2b,0x0c,0x5c,0x23,0x8c,0x81,0x6c,0x01,0x0c,0x18,0xe3,0xd9,0xfa, - 0x6f,0xc1,0xf0,0x38,0x18,0x19,0x03,0x71,0x18,0x85,0x2c,0x5a,0xe9,0x2d,0x26,0x15, - 0x49,0x52,0x19,0xdf,0x5c,0xac,0x73,0x91,0xae,0xab,0x1d,0x37,0xf1,0x73,0xd7,0x22, - 0x16,0xbc,0xb7,0xfc,0xd9,0x72,0x72,0xe4,0x87,0xb0,0x2c,0x01,0xab,0xcf,0xfc,0x42, - 0x03,0x83,0x60,0x2a,0xa2,0x40,0xe0,0x2d,0xf0,0x27,0x58,0x1c,0x99,0xe7,0xd5,0xc4, - 0x90,0xfc,0x2b,0x1e,0x0b,0xc2,0xf0,0x05,0x6e,0xb1,0xff,0x11,0xa3,0xdf,0x09,0x0c, - 0xe8,0x10,0xa0,0x8e,0x67,0xcd,0xb9,0x24,0x77,0x8a,0x34,0xe2,0xcf,0x30,0xed,0xd5, - 0x78,0xee,0xb3,0xfa,0x20,0xb2,0xc7,0x2e,0x2c,0x55,0xba,0x71,0x66,0xf0,0x3f,0x96, - 0x3a,0x7d,0x4a,0xbf,0x5a,0xb4,0xa1,0x40,0x59,0xc4,0xd3,0x2f,0xa9,0x58,0x82,0x9d, - 0xf6,0x10,0xa0,0x0e,0xad,0x9d,0x59,0x8c,0xdd,0xe8,0x63,0x8b,0xcd,0x31,0x85,0x46, - 0x6b,0x72,0x00,0x72,0xab,0xda,0x34,0xba,0x52,0x9a,0xa3,0x1d,0x59,0x63,0x52,0x3a, - 0x3c,0x89,0x25,0x1d,0xfa,0x38,0xd5,0x87,0x2f,0x92,0xf6,0xf2,0xc5,0xef,0x5e,0x68, - 0x45,0xa8,0xf7,0x26,0x3f,0xa9,0xe2,0x1d,0x83,0xea,0x67,0x65,0xb0,0xb4,0xaf,0x65, - 0x52,0xfe,0xb9,0x24,0x0f,0x01,0x75,0x1a,0xff,0x8c,0x9c,0x67,0xca,0x7a,0xf1,0x29, - 0xcf,0x12,0x7f,0x0c,0x0c,0xed,0xb9,0xa1,0x9c,0x62,0xad,0x6e,0x54,0xe8,0x0a,0xc5, - 0x30,0x0f,0x26,0xe8,0xab,0x03,0xb9,0x61,0x57,0xa4,0x72,0xd1,0x69,0x37,0x11,0xaf, - 0x04,0x77,0x42,0x93,0xb3,0xcc,0x72,0x33,0x07,0xb3,0x8a,0xd5,0x08,0xc0,0xf5,0x94, - 0x63,0x67,0x44,0x55,0x1e,0xdc,0xbf,0x4a,0x5e,0xd2,0xf8,0xd5,0x93,0xdf,0x63,0x7f, - 0xe1,0xa0,0xd5,0xc5,0x9b,0xf3,0x1d,0x8a,0x07,0x5e,0xbd,0x1b,0x15,0xcd,0x61,0x59, - 0x2d,0x52,0x4a,0x8a,0x43,0xaf,0xfc,0x51,0xb3,0x6e,0xa7,0xe3,0x59,0x2e,0xe0,0x10, - 0xa3,0x1f,0xed,0xc3,0x93,0x13,0xb7,0x26,0xd8,0xd7,0xc3,0x45,0x43,0xa3,0xbd,0x4a, - 0x68,0x6f,0x6e,0x2c,0x05,0x56,0x07,0xea,0xe6,0x46,0x47,0xfd,0x87,0xe8,0x04,0xf1, - 0xb2,0x3a,0x6b,0x29,0x88,0x6c,0x50,0x42,0xdb,0x07,0x1e,0x82,0x1b,0xe0,0x1f,0xde, - 0xd9,0x94,0xe9,0x07,0xad,0xcb,0x35,0x8b,0x3d,0xe3,0x10,0x8d,0x0d,0xe6,0x7c,0x96, - 0x01,0x94,0x4d,0x0b,0x3a,0x83,0xbb,0x9b,0x9b,0x12,0x6d,0xa7,0x9d,0x6d,0x83,0xf3, - 0xbb,0xbe,0x8d,0xdc,0xbe,0x8d,0x7b,0xca,0x0b,0xe8,0x0f,0x2e,0x2b,0xa1,0x7b,0x52, - 0xa1,0x12,0x0f,0xfa,0xb1,0x50,0x99,0x7d,0x07,0x0f,0xf0,0x40,0x48,0x40,0x25,0x29, - 0xa9,0x32,0xd5,0x05,0xab,0x8f,0x3f,0x1b,0xb8,0xbe,0xb0,0x7d,0x86,0x98,0x87,0x3f, - 0x1b,0x74,0xdc,0x72,0x3a,0x68,0xac,0x83,0x1a,0x9e,0xc8,0x42,0x2b,0xb9,0x2d,0x44, - 0xec,0x1c,0x5c,0xea,0x1f,0x67,0xc3,0xfe,0x2b,0x11,0x63,0x36,0xef,0xa3,0xc6,0xb9, - 0xba,0xb9,0x79,0x70,0xe5,0x63,0xe5,0x00,0xcb,0xca,0xea,0x73,0x92,0x8b,0x78,0x94, - 0x21,0x4a,0x4c,0xd0,0x63,0x57,0xfb,0xfb,0x57,0x3a,0x2f,0xf9,0xc4,0x01,0xb7,0x82, - 0xa2,0xc8,0x3d,0x67,0xa7,0x2c,0x75,0x6b,0xc2,0x94,0x67,0x48,0x6e,0x86,0x11,0xab, - 0xbc,0xa2,0x9b,0x12,0x91,0xf6,0xc1,0xd5,0x24,0x62,0xb9,0x28,0x19,0x1e,0xfd,0xf9, - 0x0a,0xfc,0x3d,0x34,0x8a,0x99,0x18,0xbc,0x6e,0x87,0x72,0x58,0x11,0x98,0x32,0x6f, - 0x9b,0x99,0x5b,0x37,0x8f,0x76,0x13,0x49,0xb5,0xaa,0x59,0x7f,0x8d,0x63,0xd6,0x6d, - 0x92,0x12,0xe9,0x00,0x38,0xfc,0x01,0xe6,0x7d,0xa7,0x6b,0x43,0xf8,0xc8,0x15,0x16, - 0x48,0xba,0x5e,0x64,0x84,0x07,0x12,0xc7,0xe5,0xd9,0xae,0xb3,0x1e,0x5f,0xd2,0xb9, - 0xb2,0x1b,0x07,0xd2,0xb2,0x41,0x1b,0x90,0x29,0x99,0x53,0x02,0xb7,0x3a,0x9b,0x76, - 0x28,0x39,0x6f,0x1c,0xe8,0x53,0x6a,0x8d,0xdd,0x2a,0x71,0x33,0x01,0x08,0xa0,0xfa, - 0x78,0xcd,0x94,0xad,0x63,0xac,0xe9,0xe3,0x47,0xae,0xa7,0x73,0x84,0x94,0xad,0x68, - 0x4b,0x3c,0x45,0x16,0xe1,0x6c,0xac,0x09,0xc2,0x86,0x31,0xbb,0xf1,0xe0,0x04,0x2b, - 0x77,0x38,0x95,0x71,0xd8,0x54,0xb1,0x07,0x8e,0x1d,0x18,0x04,0x55,0x1e,0x16,0xbc, - 0x1f,0x4d,0x9c,0x36,0x05,0xcf,0xc1,0x45,0x40,0x13,0x06,0x5f,0xbb,0xd7,0x56,0x23, - 0xf8,0x16,0xa8,0x15,0xc9,0x55,0xc5,0x5b,0x16,0x5b,0xcf,0x02,0x3f,0xa8,0x2d,0x39, - 0xf5,0x40,0x0c,0xc6,0xb6,0x0f,0x0e,0xa6,0x7f,0x28,0x74,0x67,0x27,0x73,0x30,0xf2, - 0xe6,0xd9,0xbd,0x9a,0x32,0x8a,0x74,0xf3,0xd5,0x1e,0xcd,0xd5,0x90,0xa4,0x0d,0x46, - 0x25,0x7a,0x11,0x96,0xd5,0xf6,0x57,0x3c,0xd1,0xdb,0x89,0x68,0x4d,0x8d,0xeb,0x53, - 0xf3,0xc8,0x8f,0x16,0x4d,0x0a,0xba,0xe8,0x0c,0xa0,0x3e,0x2f,0xcf,0x2c,0x5e,0xb9, - 0x7f,0x07,0x35,0xa9,0x75,0x74,0x1e,0x29,0x06,0xf0,0xd0,0x7f,0xc0,0x1e,0x80,0x88, - 0xf5,0x8a,0x68,0x7f,0xb0,0xda,0x7e,0x52,0x1e,0x31,0x50,0x3a,0xfd,0xd0,0x17,0xe7, - 0x63,0x95,0xf8,0xe1,0xa7,0xf7,0x2f,0xcc,0x96,0x15,0xe5,0x8b,0x9f,0xb0,0xe0,0x56, - 0x87,0x22,0xb0,0x27,0xd2,0xe2,0xa9,0x22,0x4f,0x28,0xa8,0xe2,0x43,0x94,0x31,0xc3, - 0x4d,0x5a,0xb4,0x39,0x0b,0x23,0x2e,0x8e,0xb5,0x51,0x80,0x89,0xa9,0x08,0xe2,0x0b, - 0x11,0x60,0x27,0xe0,0x36,0xaa,0x54,0xd7,0xea,0x51,0xcd,0x2a,0x25,0xb0,0xb0,0x16, - 0x8d,0x5c,0xcd,0xa9,0x0e,0x7a,0x62,0xe1,0x7b,0x8c,0x49,0x62,0x40,0x0b,0xb8,0x5a, - 0x23,0x1c,0xd7,0xd3,0x3f,0x76,0x82,0xdd,0xe8,0x18,0x03,0xd6,0x52,0x80,0x10,0x88, - 0x54,0xaa,0xd3,0x4e,0x98,0xec,0x51,0xe5,0x66,0x18,0x7d,0xbe,0x33,0x06,0xc8,0xcd, - 0x4e,0x1c,0xfa,0x89,0x21,0x5f,0x9c,0xa7,0x30,0x2b,0xec,0x28,0x10,0x3a,0x48,0xc1, - 0x8e,0x35,0x66,0xdc,0x15,0x28,0xe3,0x48,0x16,0x7a,0x63,0x0f,0x56,0x59,0x16,0xf0, - 0x87,0x38,0x07,0x1c,0x43,0x20,0x14,0xa5,0x2b,0x05,0x81,0x26,0xc9,0xa0,0xa0,0xc5, - 0x53,0x95,0x1d,0x62,0x8e,0x94,0xd1,0x3f,0xe9,0x52,0x06,0x03,0x29,0xc6,0x53,0x71, - 0x94,0x1d,0x35,0xe1,0x05,0xd5,0x41,0x3a,0xcf,0xc4,0x4d,0xb4,0x92,0xaa,0xd6,0x15, - 0xa4,0x73,0xad,0xa5,0x25,0xdd,0xa0,0x5d,0x19,0x53,0x5c,0x8f,0x28,0x5a,0xcd,0x2c, - 0x1a,0x31,0xfa,0x4a,0xfb,0x46,0x3b,0xa3,0x42,0xb4,0x4c,0x6d,0x43,0x43,0xe4,0x7e, - 0x80,0xf7,0xb4,0xee,0x2f,0xfd,0x95,0x1d,0x99,0x59,0xad,0x64,0x0c,0x0f,0x86,0x51, - 0xc5,0xe0,0x9c,0x6a,0xdb,0x9a,0x33,0x13,0x62,0xc2,0x8a,0x27,0xd7,0x47,0x37,0x3e, - 0x18,0xc9,0x66,0xfb,0x7f,0x5c,0xb6,0x3d,0xa7,0xaa,0x09,0x23,0x9f,0x00,0xbf,0xdb, - 0xdf,0xe7,0x7f,0x01,0x1f,0x75,0xec,0x95,0x87,0xd6,0xa0,0x6e,0xd0,0x3b,0x93,0xb6, - 0x84,0xa4,0xf9,0xeb,0x03,0x87,0x64,0xe4,0x5c,0x87,0xee,0xaa,0xfd,0x60,0x1c,0x24, - 0x85,0x76,0xb5,0xce,0x0f,0x1c,0xdf,0xe9,0xaf,0xf5,0x5f,0x26,0x99,0xb4,0x76,0x1e, - 0x38,0x78,0xa0,0x52,0xd9,0x6c,0xa5,0xfd,0x8c,0x4d,0xdf,0xa9,0xfd,0x9d,0x30,0xbf, - 0xf6,0x84,0x05,0xdd,0xe0,0x80,0x25,0x29,0xb2,0xeb,0x79,0x99,0x19,0x36,0x24,0xff, - 0x5d,0x7b,0xb5,0x1e,0x6e,0xbb,0xfd,0xb7,0x2f,0x30,0xd7,0xd1,0xf1,0x7d,0xb4,0x42, - 0xbe,0xd0,0x85,0x20,0xd9,0xc3,0x09,0x48,0x8e,0x0e,0x8a,0x81,0x00,0xd3,0x88,0x1e, - 0x47,0xda,0x7e,0x81,0x47,0x5a,0x24,0xe1,0x53,0x32,0x76,0xc3,0x77,0x14,0x40,0x84, - 0x37,0xd7,0xab,0x7e,0x59,0x3a,0xf1,0x9e,0xa2,0x41,0xe0,0x98,0x0d,0xc4,0xc7,0x93, - 0x8e,0x27,0xaa,0x3f,0x9f,0x40,0x62,0x5a,0xfa,0xc5,0x0e,0x46,0xea,0x50,0xa4,0x60, - 0x7e,0x11,0xcd,0x07,0xfc,0x40,0xdc,0xdc,0xf0,0xbc,0x4d,0xc5,0x99,0x38,0x15,0xc7, - 0xae,0xa8,0x98,0x01,0x23,0x3c,0x4d,0x02,0x13,0x86,0xeb,0xf4,0xe1,0x1f,0x68,0x00, - 0xff,0x1c,0x1c,0x70,0x5f,0xdc,0x5b,0x7d,0x6a,0x03,0x70,0x06,0x5c,0x51,0x2f,0x54, - 0x24,0x8b,0x0f,0xba,0xb0,0x6d,0x3b,0x1a,0xf7,0x63,0xf4,0x49,0xb4,0x45,0xd7,0xb8, - 0xd7,0xd8,0xdb,0x25,0x8c,0x01,0xa8,0xbe,0xd4,0x23,0xd2,0x93,0x33,0x41,0xe8,0xc7, - 0x67,0xdd,0x4e,0xa7,0xea,0x53,0xc5,0xf0,0x04,0x63,0xb8,0x71,0xcb,0x11,0x07,0x22, - 0xb2,0xba,0x51,0xb1,0x01,0x91,0x34,0x29,0xfb,0x1a,0x03,0x71,0x69,0x68,0xc9,0xc6, - 0x25,0x42,0x51,0xbe,0xe2,0x33,0x9a,0x57,0x7b,0x75,0x9b,0x98,0xd7,0xa2,0x59,0xa1, - 0xd0,0x2c,0x5c,0x89,0x2e,0x74,0xdc,0x69,0x0f,0x42,0x2e,0x43,0x98,0x20,0x4a,0x4c, - 0x2d,0xf8,0x4c,0xfd,0x42,0xd2,0x62,0x27,0xa8,0xcf,0x79,0x76,0xed,0x05,0x81,0x1e, - 0xa3,0xe5,0xd6,0xf6,0xc2,0x85,0x5c,0xe2,0x92,0xf3,0x4f,0x6c,0xfb,0x78,0xd7,0xb4, - 0xa9,0x41,0x57,0xeb,0xc0,0x12,0xe2,0x2b,0x53,0xb2,0x53,0x2e,0x99,0xee,0x04,0x35, - 0xcd,0x3b,0xb2,0x90,0x80,0x4a,0x3e,0xed,0x5a,0x49,0xab,0x87,0xda,0x9a,0x12,0x18, - 0xd0,0x0c,0xdf,0x63,0x19,0xea,0x9e,0x09,0xd1,0x50,0x97,0x5c,0x57,0x74,0x81,0xe9, - 0xaf,0x01,0x22,0x7d,0x4b,0x76,0xc1,0x06,0xf8,0xe3,0xc5,0x27,0xb7,0x4c,0xad,0x6f, - 0xa1,0x6b,0x61,0xb3,0x00,0x4b,0xdc,0xb5,0x70,0x14,0x53,0x8a,0xe3,0x69,0xe8,0x74, - 0x54,0x4a,0xe8,0xb0,0x14,0x3d,0x63,0x59,0x2b,0xd6,0x83,0x53,0x26,0x34,0x25,0xae, - 0xc5,0x5a,0x70,0x4a,0xdc,0x23,0x3a,0x25,0x74,0x78,0x8a,0x82,0x53,0xd6,0xfc,0xb9, - 0xfa,0x69,0x9f,0xea,0xac,0x56,0x9b,0xbf,0xe6,0x6c,0x31,0x06,0x8b,0x75,0x61,0xff, - 0xaa,0x73,0xe9,0x09,0x54,0x59,0x26,0x7d,0x9c,0x4a,0x5d,0xae,0x02,0x32,0x38,0xb7, - 0xb5,0x29,0xed,0xae,0xcc,0x10,0x40,0x70,0x6f,0xad,0x1f,0xfe,0xd3,0x72,0x8b,0x83, - 0x43,0x6a,0x81,0x67,0x62,0x2d,0xb8,0xcc,0x89,0x5c,0x69,0x52,0xd6,0xda,0xc2,0xa5, - 0x0d,0x85,0x54,0xfa,0x72,0xa1,0x4c,0x57,0xe6,0xd7,0x18,0x28,0xea,0x10,0x18,0x33, - 0x48,0x44,0x93,0x24,0x25,0x23,0x07,0x03,0xd8,0xb4,0x61,0x8a,0xe3,0x4c,0x3a,0xa6, - 0xc9,0xc1,0x22,0x04,0x98,0xdc,0x1e,0xa0,0x87,0xe6,0x95,0xd8,0xdf,0x17,0x57,0xbe, - 0x09,0xe5,0xa3,0x40,0x28,0x67,0x2d,0x9e,0x58,0xd7,0xb4,0x60,0x95,0xfb,0x23,0xc8, - 0xff,0xf1,0x6a,0x28,0xd1,0x1e,0xd0,0x7a,0x10,0xcf,0xe0,0x78,0x43,0x78,0x1a,0xcc, - 0xef,0x64,0x9f,0x92,0x63,0x8c,0x6c,0xb0,0x99,0x9b,0x78,0xf8,0x65,0x0c,0xf4,0x2d, - 0xb0,0xe6,0x10,0x67,0xcd,0xaa,0xcd,0x70,0x72,0x25,0x20,0x58,0x87,0x94,0x22,0x22, - 0x4d,0x58,0xfc,0xbd,0x42,0x5f,0xac,0x19,0x85,0x57,0x1e,0x46,0x37,0x78,0x14,0x23, - 0xfc,0x4a,0x67,0x0c,0xde,0x78,0x46,0xe6,0x91,0x28,0x21,0x57,0xec,0xd2,0xb5,0x25, - 0x6f,0x5d,0x3c,0x85,0x57,0x5a,0x40,0xe9,0x02,0xb6,0x7f,0x37,0x76,0x2e,0x2b,0xa6, - 0x8e,0x18,0xce,0x55,0xad,0x42,0x15,0x40,0x89,0x4c,0x28,0x88,0x22,0x66,0x74,0xda, - 0x80,0x9c,0x04,0xa3,0xa5,0x59,0xd9,0x3d,0xab,0x0c,0xa8,0xac,0x89,0xd2,0x79,0x17, - 0x6d,0x5b,0xa3,0x99,0xcf,0x51,0x1a,0x8a,0xc9,0xc0,0x62,0x85,0xff,0x0e,0x56,0x5b, - 0x9a,0x4c,0xe8,0xe7,0x7a,0xb9,0x4c,0x95,0x13,0x17,0x9c,0x3f,0x06,0x1d,0xcb,0x5b, - 0xd9,0x80,0xb8,0xb8,0xfc,0x16,0x23,0x52,0x60,0x5f,0x02,0x4c,0xfe,0x1a,0xff,0x7f, - 0x74,0x32,0x22,0x17,0x98,0x1c,0xfc,0xd3,0x75,0x69,0x86,0xe2,0x3b,0x40,0x0c,0x4d, - 0xb3,0xb6,0x2e,0x35,0x5c,0xe3,0x0f,0x8d,0x1b,0xc5,0xc6,0x18,0xbe,0x5b,0x4d,0x55, - 0xb4,0x03,0xc3,0x55,0x8b,0xbf,0x4d,0x87,0xc0,0xfb,0xca,0x40,0x02,0x1e,0x46,0x45, - 0x52,0xad,0x0b,0x8b,0x15,0xf6,0xf4,0x84,0x4d,0x90,0xeb,0x0a,0x1e,0xfa,0xe9,0x83, - 0x04,0x11,0x1b,0x44,0xbb,0x5b,0x6b,0x22,0x64,0x5b,0xcc,0x04,0xf3,0x51,0x1d,0x23, - 0xda,0x22,0x2a,0xaf,0xb6,0x7a,0x8b,0x3a,0x34,0xb0,0x1d,0x08,0x43,0x97,0x46,0x3b, - 0x56,0x23,0x6d,0xa3,0xe6,0x8d,0x21,0x57,0x6e,0x33,0xd2,0x82,0x7d,0xb5,0x57,0x5b, - 0x93,0x9a,0xe7,0xf6,0xfb,0x39,0x66,0x67,0x8d,0x34,0xc1,0xea,0x0d,0x2a,0xb8,0x6c, - 0xfe,0xf6,0x5f,0xff,0x13,0x34,0xff,0x6f,0xff,0xf5,0xbf,0x5c,0xf1,0x37,0x4b,0x54, - 0x52,0xfe,0x4a,0xd7,0xfc,0x9a,0xe3,0x04,0x34,0x24,0x9b,0x69,0x29,0x93,0x8a,0xc2, - 0x58,0xa7,0x95,0x8f,0x01,0x80,0x75,0x0e,0xbc,0x19,0x46,0x79,0xc5,0xd1,0x58,0xe8, - 0xcd,0x84,0xb3,0x51,0xd7,0xa6,0x63,0x29,0x1b,0xcf,0xa1,0x39,0x74,0x01,0xc6,0x4c, - 0x07,0xc5,0x20,0x8a,0x6e,0x4c,0xbf,0xa0,0x18,0xc4,0x03,0xf4,0x4c,0xd1,0x5c,0x2d, - 0x4a,0x65,0x92,0xd7,0x6d,0x45,0x9b,0x08,0x9e,0xd0,0x91,0x45,0x48,0xa6,0x08,0xcb, - 0x9a,0x54,0x0c,0xcd,0xe2,0xee,0x1a,0xdb,0xa7,0xaa,0x3e,0xb4,0xf9,0x60,0xb8,0x5b, - 0x8b,0xed,0x50,0xfb,0x98,0x0c,0x80,0x95,0x29,0xe7,0x83,0x04,0x77,0x29,0x2a,0x8b, - 0xcc,0xae,0xee,0x00,0xa5,0x02,0x80,0x58,0xec,0x0a,0x81,0xd2,0x61,0x35,0x4d,0x65, - 0x5a,0xbd,0x68,0x5d,0xa2,0x97,0x08,0xb9,0xe4,0xb8,0x73,0x8c,0xd8,0xb3,0x8e,0x73, - 0xd0,0xd1,0xf1,0x22,0xd5,0x1a,0xa5,0x4a,0x5e,0x38,0xb6,0x4e,0x29,0xa1,0xaf,0x47, - 0xd5,0xcc,0x61,0x86,0xb7,0x25,0x1b,0xea,0x8c,0x6e,0x93,0x44,0xab,0x0b,0x4a,0xc3, - 0x64,0x2d,0xf4,0x89,0x85,0x5f,0xd6,0x93,0xe9,0x68,0xaf,0xbe,0x57,0xa1,0x79,0xd4, - 0xa1,0xe4,0x53,0xb9,0xc7,0xa1,0x99,0xf1,0xb1,0xb6,0x78,0x16,0xa7,0xde,0xd7,0x78, - 0xda,0xa6,0x73,0x38,0x4f,0xdb,0xd3,0x62,0x16,0x9f,0xed,0xfd,0x3f,0x52,0x93,0x44, - 0x7c,0x9c,0x86,0x00,0x00, + 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xcd,0x7d,0xeb,0x76,0xdb,0x48, + 0x92,0xe6,0x7f,0x3d,0x45,0x9a,0x9e,0x12,0x88,0x12,0x08,0x5e,0x74,0xb1,0x4c,0x8a, + 0xd2,0xda,0xb2,0xd4,0xed,0x75,0xb9,0x4a,0x6b,0x55,0x4d,0xcd,0x96,0xd7,0xd3,0x03, + 0x12,0x49,0x11,0x2d,0x10,0x40,0x23,0x41,0x52,0x6a,0x8a,0xe7,0xf4,0xaf,0xf9,0x3d, + 0x67,0xce,0x3c,0xc3,0xbe,0xc2,0xfe,0xdf,0x47,0xe9,0x27,0xd9,0x2f,0x22,0x13,0x17, + 0x5e,0x24,0xab,0xba,0xb7,0xe6,0x4c,0x1f,0x37,0x05,0x24,0xf2,0x12,0x19,0x19,0x97, + 0x2f,0x22,0x13,0xa8,0x93,0x17,0x7e,0x3c,0xcc,0xee,0x13,0x29,0xc6,0xd9,0x24,0x3c, + 0xdd,0x39,0xa1,0x3f,0x22,0xf4,0xa2,0x9b,0x7e,0x4d,0x46,0x35,0x2a,0x90,0x9e,0x8f, + 0x3f,0x13,0x99,0x79,0x62,0x38,0xf6,0x52,0x25,0xb3,0x7e,0x6d,0x9a,0x8d,0x1a,0xc7, + 0xf4,0x54,0x0d,0xd3,0x20,0xc9,0x84,0x4a,0x87,0xfd,0x5a,0x33,0x19,0x35,0x86,0x71, + 0xa4,0xe2,0x50,0xba,0x7f,0x54,0x67,0xe3,0xbe,0x1c,0x8d,0x46,0xfe,0x61,0xeb,0xb0, + 0x76,0x7a,0xd2,0xd4,0x15,0x4f,0x4d,0x83,0xd3,0x60,0x54,0x7f,0x31,0x0f,0x22,0x3f, + 0x9e,0xbb,0x57,0x97,0x76,0x7d,0x34,0x8d,0x86,0x59,0x10,0x47,0x75,0x7b,0x31,0xf3, + 0x52,0xf1,0x73,0x5f,0x3f,0x73,0x7e,0xea,0x5b,0x4d,0x2f,0x09,0x9a,0x2a,0xf3,0xb2, + 0xa9,0xb2,0x9c,0xef,0xfa,0x9f,0xbf,0x38,0x1f,0xfb,0x1d,0xf9,0xda,0xb9,0x76,0x7e, + 0x71,0xae,0xfa,0x3f,0xa3,0x79,0x7f,0x41,0x8f,0x65,0xd7,0x0a,0x83,0x99,0xb4,0x1c, + 0x3f,0x48,0xb3,0xfb,0xee,0x8b,0xb6,0x33,0xeb,0x46,0xd3,0x30,0x74,0x6e,0x64,0xd6, + 0xfd,0x9d,0x13,0x44,0xa3,0x30,0xb8,0x19,0x67,0xdd,0xef,0xa7,0x93,0x81,0x4c,0x9d, + 0x71,0x1c,0xfa,0xdd,0x1f,0x06,0x7f,0x94,0xc3,0xcc,0x51,0xde,0x7d,0xb7,0xa0,0x20, + 0x73,0x6e,0x1d,0x69,0x2f,0xe4,0xee,0x6e,0x5d,0xba,0x99,0xbc,0xcb,0xce,0xe3,0x28, + 0x93,0x51,0xd6,0xcf,0xec,0xa5,0x33,0x98,0xaa,0x4a,0xd5,0x81,0x93,0xd8,0x8b,0xfc, + 0x4e,0x8c,0x40,0xfc,0xc0,0xf5,0x03,0xe5,0x0d,0x42,0xe9,0xf7,0x5f,0xb4,0x97,0xd5, + 0xbb,0x56,0x2f,0x71,0xb3,0xb1,0x8c,0xea,0x23,0x67,0x64,0xf7,0x52,0x99,0x4d,0xd3, + 0x48,0x24,0x4b,0x27,0x89,0xc3,0xb0,0xec,0x51,0x39,0x13,0x67,0xe8,0xc4,0x9a,0x0b, + 0x99,0x33,0x72,0x6e,0xfa,0xed,0x5e,0x31,0xc2,0x27,0x8c,0x70,0xb3,0xbb,0xfb,0x62, + 0x04,0xda,0x46,0xfd,0xb6,0x33,0x0c,0xa5,0x97,0xfe,0x18,0x4c,0x64,0x3c,0xcd,0xea, + 0x99,0xed,0xd4,0x95,0x3b,0xf4,0xc2,0xf0,0x4c,0xd5,0xed,0xee,0xef,0xea,0xca,0xb6, + 0xcd,0x88,0x79,0xef,0xbe,0xbd,0x18,0xd6,0x7d,0x87,0xb8,0x82,0xb9,0x14,0xc5,0x92, + 0x8a,0x99,0x55,0xd2,0x5e,0x9a,0x36,0x1f,0x9c,0x0f,0xb6,0xbd,0x2c,0x46,0xfe,0x80, + 0x91,0x47,0xfd,0x56,0x6f,0x6d,0xc4,0x1e,0xa8,0xa9,0x67,0x7d,0x88,0x44,0x5e,0xf6, + 0xc9,0x99,0xa0,0x5d,0xbc,0xbb,0x1b,0xbb,0xa3,0x20,0x55,0x59,0xbf,0x0f,0x46,0x9c, + 0xa1,0x79,0x17,0xc4,0x9b,0x69,0x63,0xb9,0xe2,0xa4,0x5b,0x59,0xf2,0x9b,0xcd,0x9e, + 0x97,0x0e,0x3a,0x2d,0xeb,0x44,0xf6,0x62,0xd2,0x8f,0x7a,0xa3,0x87,0x07,0x74,0xb5, + 0x74,0xa2,0x78,0xde,0xfd,0xb4,0x44,0x1d,0x16,0x8b,0xb2,0xda,0x10,0x33,0xd9,0xdd, + 0xfd,0xce,0x4d,0xa6,0x6a,0x8c,0x9b,0xde,0xf5,0x19,0x6e,0x87,0xf5,0x6b,0xbb,0xfb, + 0xcb,0xd9,0x2f,0x2e,0x5a,0x81,0x8e,0x5f,0xfa,0x57,0x2e,0x31,0xbd,0xfe,0x93,0xf3, + 0xd1,0x79,0x87,0xce,0xe6,0x5e,0x36,0x1c,0x5f,0xaf,0xf5,0x34,0xb1,0x17,0x57,0xae, + 0xee,0x1e,0x74,0xff,0xe2,0x82,0x9a,0xfa,0xc7,0xfe,0x47,0x2f,0x1b,0xbb,0x93,0x00, + 0x8f,0x9d,0x8f,0x36,0x37,0x0d,0xb2,0xcb,0x38,0x7d,0x27,0x67,0xc1,0x50,0x96,0x8d, + 0xb1,0x7e,0x71,0x3f,0x7e,0x78,0x58,0x2c,0xf3,0x85,0x8e,0xe4,0x5c,0x5c,0xa5,0xf1, + 0x24,0x50,0xb2,0x5c,0x8e,0x7b,0x27,0xd2,0x0b,0x3d,0x2e,0x49,0xea,0xc8,0xfd,0x72, + 0x61,0x94,0xbd,0x50,0x58,0xee,0x7a,0xec,0x0e,0xa6,0x41,0xe8,0xef,0xee,0x2a,0x7d, + 0xd1,0xef,0x9b,0x12,0x1b,0xec,0x1f,0xbb,0xc4,0xce,0xba,0xed,0xdc,0xd3,0x8a,0x2f, + 0xed,0x5e,0x65,0x35,0x2a,0x3c,0xce,0xab,0xf5,0xa2,0xfa,0x45,0x9a,0xc6,0x69,0xdd, + 0xca,0x74,0x25,0x8b,0x26,0x12,0xbb,0xe6,0xee,0xe1,0xe1,0xb5,0x3c,0x40,0x2f,0xcb, + 0x65,0x29,0x76,0xbf,0xab,0x4f,0x49,0x24,0xcd,0x54,0x46,0x12,0xec,0xe2,0x92,0x35, + 0xe9,0x4a,0xed,0x05,0x69,0x75,0xea,0xc6,0xb7,0x76,0x36,0x4e,0xe3,0xb9,0xd0,0x03, + 0xa5,0x86,0x8f,0x85,0xd4,0xb3,0x74,0x90,0x66,0x9d,0xa5,0xfc,0x07,0x8b,0x92,0xc2, + 0x60,0x10,0x99,0xcb,0x8a,0xcc,0xbd,0xa3,0xf9,0xa3,0x47,0xfc,0x5e,0x43,0xcf,0x93, + 0x91,0x5e,0xa3,0xbe,0xea,0x7d,0xe7,0x8e,0xe2,0xf4,0xc2,0x03,0x19,0xc5,0xe0,0x23, + 0xc8,0x27,0x6a,0x12,0xe1,0x4b,0xbb,0x6e,0x17,0xf6,0xc6,0x18,0xae,0xc8,0x9b,0xc8, + 0x7e,0x6d,0x16,0xc8,0x79,0x12,0xa7,0x59,0x4d,0x0c,0x8d,0x4e,0xd7,0xe6,0x81,0x9f, + 0x8d,0xfb,0x3e,0x2f,0x60,0x83,0x6f,0x60,0x29,0x82,0x2c,0xf0,0xc2,0x86,0x82,0x2e, + 0xc9,0x7e,0x9b,0xac,0x5c,0x16,0x64,0xa1,0x3c,0xbd,0xf2,0xb2,0x4c,0xa6,0xb0,0x23, + 0xf1,0xfc,0xa4,0xa9,0x8b,0x76,0x4e,0xc2,0x20,0xba,0x15,0xa9,0x0c,0xfb,0xb5,0x00, + 0x9d,0xd6,0xc4,0x38,0x95,0xa3,0x7e,0xcd,0xf7,0x32,0xaf,0x1b,0x4c,0xbc,0x1b,0xd9, + 0x54,0xb3,0x9b,0xbd,0xbb,0x49,0xe8,0x7c,0xb3,0x7f,0x8e,0x4b,0x81,0xcb,0x48,0xf5, + 0xad,0x71,0x96,0x25,0xdd,0x66,0x73,0x3e,0x9f,0xbb,0xf3,0x7d,0x37,0x4e,0x6f,0x9a, + 0x9d,0x56,0xab,0x45,0x95,0x2d,0x41,0x64,0xbe,0x8d,0xef,0xfa,0x56,0x4b,0xb4,0x44, + 0xfb,0x08,0xff,0xac,0x6f,0xf6,0x2f,0xd0,0x3e,0x85,0xb1,0x12,0x9a,0x62,0x0b,0x85, + 0x62,0x2c,0xc9,0xa2,0xe9,0xeb,0x14,0xf5,0xf7,0x2d,0x31,0x0a,0xc2,0xb0,0x6f,0x7d, + 0xd3,0xd9,0x6f,0x1f,0xb5,0x0f,0xdb,0x1d,0xab,0x59,0x69,0x89,0x1a,0x87,0x96,0xb8, + 0xe7,0x5f,0xd3,0x4b,0xa5,0x93,0xa3,0x4a,0xe3,0xcb,0xcb,0xc3,0xf3,0xce,0x45,0xde, + 0x98,0xa8,0xc2,0x15,0x9b,0xfb,0xec,0x9e,0x66,0xdd,0xfc,0x56,0x9c,0x6b,0x43,0x2f, + 0x06,0x9e,0x92,0x5d,0x01,0x49,0x10,0x0a,0x3c,0x16,0x83,0x30,0x1e,0xde,0x8a,0x38, + 0x91,0x91,0x12,0x72,0x26,0xd3,0x7b,0xb0,0x3a,0x95,0x22,0x01,0x27,0x5c,0xf1,0x1d, + 0x8d,0x24,0x82,0x48,0x74,0xd3,0x38,0xce,0x44,0x9d,0x5a,0x0d,0x21,0x29,0x13,0x69, + 0xa9,0x1d,0x21,0xf0,0x84,0xcc,0xb1,0xf4,0x05,0x5b,0x6a,0x34,0x0a,0x25,0x38,0x2e, + 0xc8,0x54,0x2b,0x1a,0x42,0x99,0x41,0x66,0x5e,0x38,0x95,0xaa,0x2b,0x6e,0xa5,0x4c, + 0x78,0xe8,0x6c,0x1e,0x53,0xb7,0x2a,0x93,0x89,0xed,0x50,0x4f,0xbe,0x97,0xde,0x8a, + 0x69,0xe4,0xcb,0x94,0xfd,0xda,0x67,0x5a,0x8f,0x06,0x6a,0x42,0x0a,0xe8,0xd1,0x17, + 0x57,0x7c,0x1f,0x8b,0xb9,0x1c,0x88,0x11,0x04,0x41,0x69,0xfa,0xc7,0x71,0xa6,0x12, + 0x90,0x35,0xf6,0x94,0x88,0xa8,0x3f,0x5a,0x6c,0x99,0xb9,0xe2,0xdb,0xe6,0x0e,0x13, + 0xbc,0x18,0xc6,0x61,0x9c,0x42,0x2e,0xa8,0x9f,0x2e,0xd3,0xd8,0x6b,0x34,0x86,0xa9, + 0xf4,0x26,0xdd,0x97,0x97,0x07,0x17,0x97,0x17,0x47,0xb8,0x4f,0xbc,0x48,0x86,0xb8, + 0xbf,0xbc,0x3c,0xbf,0x7c,0x83,0x7b,0xc8,0x47,0xf7,0x65,0xfb,0x4d,0xfb,0xb8,0x7d, + 0x80,0xbb,0xc9,0x14,0xf3,0xeb,0xbe,0x3c,0xea,0x1c,0x9e,0x1f,0xb6,0x71,0x3f,0xf2, + 0x30,0x4e,0xf7,0xe5,0xab,0x77,0xaf,0x8e,0x8e,0x8e,0x71,0x9f,0x4e,0x43,0xd9,0x7d, + 0xf9,0xee,0xdd,0xbb,0xc3,0xf3,0x23,0x73,0xdb,0x50,0xf1,0x08,0x55,0x2e,0x8e,0x2f, + 0xda,0xef,0xa8,0x8b,0x9b,0x71,0xac,0xe8,0x7e,0xff,0xdd,0xf9,0xf9,0x05,0xee,0x43, + 0xea,0x50,0xaf,0x18,0xee,0x06,0x1e,0xee,0xde,0x1e,0xef,0x9f,0xb7,0xcf,0x71,0x17, + 0x63,0xec,0xce,0xdb,0x57,0x6f,0x0e,0xde,0xe2,0x66,0xee,0xa5,0x51,0xf7,0xe5,0xf1, + 0xe1,0x51,0xab,0x75,0xd1,0xdb,0x69,0x34,0x94,0x17,0xa9,0xae,0xba,0x07,0xd7,0x26, + 0x8d,0x69,0xe0,0x34,0xbc,0x24,0xa1,0xd1,0xb8,0xc0,0xb1,0xae,0xe5,0x4d,0x2c,0xc5, + 0x4f,0xef,0x2d,0xe7,0x53,0x3c,0x88,0xb3,0xd8,0xa1,0xea,0x0d,0x25,0xd3,0x60,0x44, + 0xf3,0x88,0xa3,0xb8,0x3b,0x0d,0xf8,0xaf,0x4a,0xbc,0xa1,0x74,0xac,0x73,0x0f,0x1a, + 0xe3,0x07,0x9e,0xf8,0x88,0x32,0x0b,0x1d,0x5c,0x9a,0xab,0x8f,0x32,0x0a,0x63,0x47, + 0x0b,0x8c,0xa7,0x1c,0x4b,0xf7,0x67,0x1e,0x16,0x1d,0x2c,0x77,0xb6,0xae,0xd4,0x2a, + 0xd3,0xa9,0xa8,0xe4,0x79,0xeb,0xbc,0xf5,0xb6,0xf5,0xba,0xe4,0x79,0x7b,0xbf,0xdd, + 0x6e,0xb7,0x72,0x9e,0x5f,0xbc,0xbb,0x78,0xf5,0xee,0x6d,0xc9,0xf3,0x37,0xfb,0xaf, + 0xdf,0x1e,0xbf,0xa9,0xf0,0xfc,0xcd,0xab,0xfd,0xa3,0x83,0x82,0xe7,0x9d,0xb7,0x9d, + 0x57,0x9d,0xf6,0x2a,0xcf,0xdb,0x97,0xed,0xf3,0xf6,0x71,0xc9,0xf3,0xce,0x9b,0xce, + 0x51,0xa7,0x95,0x73,0xf9,0xf2,0xf2,0xd5,0x9b,0xc3,0x43,0xc3,0xe5,0xc3,0x57,0x6f, + 0x8f,0x5f,0x5d,0x16,0x5c,0x7e,0xf7,0xfa,0x4d,0x6b,0xff,0x72,0xb9,0xf3,0xed,0x62, + 0x10,0xdf,0x35,0x54,0xf0,0xe7,0x20,0xba,0xe9,0x0e,0xe2,0x14,0x12,0xd9,0x40,0xc9, + 0xf2,0xf3,0x38,0xf0,0x7d,0x19,0x7d,0x59,0x00,0x21,0x24,0x21,0xf0,0x47,0x14,0x47, + 0xf2,0x45,0x30,0x21,0xf3,0xe4,0x45,0xd9,0x72,0x67,0x10,0xfb,0xf7,0x8b,0x89,0x97, + 0xde,0x04,0x51,0xb7,0xd5,0x1b,0x78,0xc3,0xdb,0x9b,0x34,0x86,0x44,0x77,0xe1,0x30, + 0xea,0x86,0x03,0x76,0x8f,0x99,0x63,0x8a,0x30,0x69,0xbb,0x47,0xf2,0xdc,0x6d,0x1f, + 0x26,0x77,0xcd,0xb6,0x7b,0x28,0xf4,0x03,0x5a,0x38,0xbb,0xd7,0x80,0xb8,0xdf,0x06, + 0x59,0x83,0x6a,0x34,0xd4,0x04,0xf2,0x3c,0x26,0x9a,0x30,0x18,0x8c,0x5d,0x00,0x2d, + 0xf6,0x97,0x3b,0x9e,0xe6,0x76,0x37,0x88,0xc6,0x58,0xe7,0x6c,0xd9,0x1d,0xc5,0xc3, + 0xa9,0x6a,0xcc,0x02,0x15,0x00,0xc5,0x2c,0xe0,0x1f,0x60,0xee,0x64,0xb7,0x93,0xdc, + 0x09,0xac,0x65,0xe0,0x9b,0x01,0x20,0x81,0x76,0xcf,0x3c,0x6c,0xc4,0xa3,0x11,0xb9, + 0x6e,0xd4,0x59,0xee,0xb8,0xf3,0xd4,0x4b,0x30,0x8b,0x3b,0x6d,0x5a,0xbb,0xaf,0x3a, + 0xad,0xe4,0xae,0x97,0xcf,0x4a,0x78,0xd3,0x2c,0xee,0x25,0x9e,0xef,0x13,0x21,0xf4, + 0x08,0xa6,0x0e,0x3f,0x07,0xc7,0xd4,0x76,0xdc,0x29,0xa6,0x0f,0x33,0x88,0xf2,0x9e, + 0xa6,0x3c,0xf8,0xb3,0xec,0xb6,0xf7,0xf3,0xdb,0x39,0x5b,0xaf,0x2e,0x44,0x7a,0x85, + 0x17,0xbc,0xe4,0x36,0x08,0x18,0x7a,0xa9,0xbf,0xd8,0xe0,0x1e,0xcb,0x8b,0xdd,0xd3, + 0xeb,0xd1,0x6d,0xaf,0x4d,0x87,0x04,0x20,0x7f,0xd8,0x48,0x21,0xd2,0x00,0x06,0x6d, + 0x22,0x3c,0x27,0x95,0xa8,0x44,0xdf,0x83,0x2c,0x2a,0x96,0x2f,0x88,0x78,0xf2,0xa3, + 0x50,0xde,0xf5,0xc0,0xce,0x9b,0xa8,0x11,0x40,0x8b,0x54,0x77,0x28,0xc9,0x8c,0xf4, + 0xfe,0x38,0x55,0x59,0x30,0xba,0x6f,0x18,0xbf,0x93,0x17,0xdf,0x78,0x49,0x97,0x66, + 0x06,0x48,0xd1,0xd0,0x76,0xb8,0x7b,0x50,0x1d,0xa8,0xc5,0x0c,0xf9,0x35,0x74,0x1e, + 0x53,0xf5,0x47,0xa6,0xbb,0x5d,0x58,0x0e,0x5b,0x18,0xe5,0x00,0x5d,0x57,0x85,0x85, + 0xdc,0x72,0xc3,0x97,0xb0,0xdd,0x1e,0xb9,0x57,0x96,0xce,0xde,0x70,0x9a,0x2a,0x74, + 0x90,0xc4,0x6c,0x1a,0x7b,0x59,0x8a,0xaa,0x01,0x3f,0x36,0x34,0xf0,0x00,0xc2,0x6d, + 0x1f,0x2a,0xa7,0xa4,0x41,0xdf,0x97,0x8f,0x96,0x3b,0xff,0x6d,0x22,0x61,0x26,0xea, + 0xe3,0x18,0xfe,0xa1,0xcb,0xbf,0xf6,0x82,0x98,0xa9,0xaf,0x17,0xd5,0xce,0x2a,0xd4, + 0x2e,0xa9,0x8a,0x9b,0xa4,0x41,0x5e,0x6d,0x7d,0x96,0x2c,0x85,0x5b,0x1a,0x73,0xb9, + 0x2e,0x78,0x89,0x80,0x64,0x39,0x82,0xe8,0xc3,0x2f,0x78,0xa6,0x9f,0x8d,0x71,0xf4, + 0xca,0x76,0x73,0xe8,0xbe,0x88,0x61,0x9d,0x02,0x44,0x14,0xee,0xc1,0x61,0xce,0x02, + 0x5f,0x8e,0xbc,0x69,0x98,0x6d,0x1b,0x8d,0x17,0x45,0x77,0x41,0xc4,0x6e,0x92,0xc9, + 0x9c,0x7f,0x64,0x8e,0x2b,0x4b,0xa4,0x55,0xdc,0x74,0x15,0x0c,0x17,0x5a,0x85,0x56, + 0xe5,0x03,0x4f,0x27,0xea,0x66,0xa1,0xb5,0xbe,0x53,0x2c,0x22,0x19,0xd5,0xd5,0xce, + 0xd8,0xe6,0x81,0x87,0x08,0xd1,0xe2,0xdb,0x95,0x39,0xc7,0xb7,0xba,0x58,0xa6,0xab, + 0xbc,0x80,0x89,0x63,0x05,0x1a,0x07,0xc9,0xba,0x94,0xb3,0x93,0xaf,0x08,0xe9,0xf1, + 0xaf,0x93,0xd1,0xd7,0xaf,0x8d,0xf6,0x76,0xdb,0xa8,0xde,0x64,0xc5,0x7f,0x8c,0x6e, + 0xad,0xc8,0xbd,0xf9,0x18,0xea,0xd4,0x60,0x3f,0x01,0x59,0x24,0xab,0x02,0xd2,0xa2, + 0x38,0x03,0x6a,0x2b,0x88,0x5b,0xa5,0x8a,0xb9,0x41,0x72,0xfd,0x2c,0xca,0x42,0x09, + 0x73,0xbf,0xbf,0xcd,0xac,0x3d,0x5f,0xbd,0x2a,0xe6,0x89,0x86,0xdd,0xa6,0x42,0x4b, + 0x43,0xb3,0x18,0x2c,0xaa,0xd6,0x0b,0x2a,0xb8,0x75,0x86,0x5a,0x52,0x8b,0x09,0x3e, + 0xd7,0xb8,0x70,0x27,0x8d,0x81,0xcc,0xe6,0x52,0x46,0x6c,0x63,0xd8,0x8a,0x68,0x6b, + 0xda,0xa0,0xd8,0x8b,0x85,0xc8,0xcc,0x8c,0xee,0xb7,0xf3,0xe6,0xd9,0x52,0xb5,0x93, + 0xab,0xd4,0x73,0xcd,0xe1,0xba,0xbd,0xdb,0xb2,0xe2,0x5b,0xd9,0x47,0xc0,0xf3,0x93, + 0x17,0xdd,0x00,0x71,0x82,0xed,0x22,0x60,0x54,0xc8,0xb0,0x15,0xa0,0x31,0xf1,0xd2, + 0xcc,0x11,0xf0,0x3d,0x62,0x70,0xcf,0x65,0x75,0x9b,0x40,0x21,0x43,0x53,0x0e,0x06, + 0x18,0xc9,0x05,0x51,0x32,0xcd,0x3e,0x53,0xc6,0xa3,0x9f,0x52,0x4f,0x5f,0x16,0xb9, + 0x63,0x04,0xfc,0x41,0x08,0xea,0x45,0xbc,0x00,0x30,0x77,0xeb,0xf7,0xab,0x72,0xa6, + 0xb5,0xb1,0xdd,0x6a,0x7d,0xd3,0x33,0x33,0xe9,0x1c,0x57,0x7c,0x5b,0x55,0x4a,0x88, + 0x15,0x5e,0xda,0xb8,0x21,0x19,0xc2,0xfc,0xeb,0xaf,0x5b,0xbe,0xbc,0x71,0x4a,0xad, + 0x37,0xec,0x4d,0x9c,0xc3,0xd6,0x37,0xb6,0x29,0x67,0xc0,0x61,0x8b,0x96,0x2d,0x34, + 0xcb,0x9a,0x34,0x92,0x20,0x33,0x1d,0xc5,0x8d,0x54,0x82,0xb2,0x6c,0xc3,0x1e,0xc7, + 0xd3,0xe1,0xb8,0xe1,0x71,0x3c,0xd4,0x85,0x4c,0x36,0xee,0x97,0x9b,0xb3,0xed,0x76, + 0xf3,0xe9,0x2a,0x2c,0x37,0x2d,0xff,0x78,0x3a,0x19,0x3c,0xca,0x03,0x3d,0x4b,0xf6, + 0xda,0xf9,0x2c,0x2b,0xa2,0x63,0x94,0x02,0x64,0xf7,0xbe,0xe2,0x62,0xd7,0x11,0x03, + 0x1b,0xbb,0xa7,0x1c,0xc8,0x76,0xd2,0x27,0xf1,0x9f,0x1b,0x7c,0x63,0xc8,0xde,0x8a, + 0xad,0x7e,0x53,0xa2,0xb7,0xd1,0x45,0x2c,0x9f,0xc9,0x47,0x38,0xfb,0x88,0x43,0x5a, + 0x3e,0xd1,0xcd,0xe6,0x2c,0xb7,0x77,0x91,0x3b,0x52,0x23,0x00,0xdd,0x61,0x4c,0xd9, + 0x39,0xc4,0xcc,0x1b,0x22,0x5e,0xd1,0xb5,0xe5,0x73,0x45,0xc2,0x70,0xf1,0xa8,0xc2, + 0xc5,0xa3,0x47,0x9a,0xaf,0x13,0xfc,0x48,0x53,0x56,0xdf,0xbf,0xfe,0xc7,0x5f,0xf0, + 0x4f,0xfc,0x1e,0x41,0x5f,0x7e,0x0d,0xad,0x74,0xc3,0x41,0xb8,0x78,0x02,0xdf,0x1d, + 0x6e,0xc5,0x77,0x85,0xb6,0xc1,0x19,0x8c,0xfd,0xaf,0xda,0x49,0xb2,0x84,0x04,0x2d, + 0x51,0x57,0xe8,0x01,0x51,0xb1,0xdb,0xe6,0xc6,0x82,0xfd,0x28,0xd9,0x25,0x4d,0x7c, + 0xab,0x47,0xe0,0x80,0x42,0xfd,0xae,0x46,0xea,0xda,0x20,0x15,0x85,0x32,0x0c,0x83, + 0x44,0x05,0xea,0x31,0xcf,0x34,0xaf,0xcc,0x86,0x0d,0xc3,0x3a,0x5a,0xe5,0xd0,0x36, + 0xe5,0x86,0x24,0xbe,0x0d,0xb7,0xd5,0x91,0x93,0x1e,0x5b,0x4d,0xc3,0xb3,0x36,0xf4, + 0x20,0x9f,0x21,0x89,0x62,0x8b,0xd4,0xbf,0x6a,0x3a,0xf7,0x51,0x5a,0x90,0xd9,0xa0, + 0xa1,0x81,0xe6,0xef,0xe7,0x80,0xee,0x92,0x68,0x50,0xd3,0xc1,0x2a,0x4b,0xe8,0x47, + 0x57,0xa3,0x9f,0xc7,0x38,0x44,0x08,0x9c,0xd1,0x6e,0x65,0x24,0xd6,0x9f,0xaf,0xbb, + 0x83,0x02,0x75,0x0f,0xc2,0xdb,0x45,0xc5,0xdd,0xb0,0xfb,0x31,0x8e,0xb9,0x2c,0xf8, + 0x8a,0xff,0xe1,0x10,0x8c,0x3a,0x4b,0xc1,0xcc,0xe7,0x2c,0x2d,0x91,0xb6,0xa4,0xda, + 0x6b,0x8b,0xab,0xe4,0xcd,0x56,0xbf,0x44,0x6d,0x3a,0x15,0x30,0xd5,0xf9,0x95,0x28, + 0x66,0x1b,0x14,0x28,0x30,0x1b,0x06,0x15,0x83,0x69,0x96,0xc5,0xd1,0x62,0xdd,0xd9, + 0x95,0x42,0xf6,0xea,0xe8,0x51,0xac,0xdf,0x5a,0x1b,0xed,0xd5,0xea,0x68,0x1a,0x8f, + 0x6f,0x2a,0xc4,0xe3,0x88,0xfe,0x09,0xf0,0xfe,0x04,0x54,0xaf,0xcc,0xe3,0x31,0xb8, + 0x5c,0xad,0xe3,0x62,0xba,0xcf,0x8e,0x3e,0xd8,0x78,0x8f,0x3d,0x1f,0xda,0x44,0x11, + 0x1e,0x68,0x2e,0x48,0x66,0x7e,0x3b,0x41,0x44,0xce,0xbc,0x25,0x1a,0xa5,0xcc,0x69, + 0xbb,0xf7,0x32,0x99,0xa7,0x00,0x52,0xb2,0xca,0xda,0x76,0xc5,0xfb,0x1e,0xe5,0xda, + 0x02,0xe2,0x66,0x5e,0xb8,0xf8,0x15,0x92,0x7b,0x5b,0x86,0x74,0x37,0x69,0xe0,0xf7, + 0xe8,0xa7,0x01,0x49,0x43,0x09,0xd4,0x1c,0x4d,0xa6,0x93,0x48,0xb1,0x46,0x8b,0xf6, + 0x28,0xdd,0x26,0x8a,0xba,0x4e,0x83,0x25,0xb2,0xb5,0x06,0xbb,0x98,0xa2,0xdb,0x48, + 0x84,0xde,0x40,0x1a,0xb2,0x8e,0x68,0xb1,0x9e,0x43,0xda,0xcb,0x69,0xe2,0xaf,0x28, + 0x15,0xc9,0xeb,0x53,0xfa,0x4d,0x14,0x90,0x14,0x70,0xc5,0x2a,0xa1,0x94,0xb2,0x23, + 0x35,0x58,0x52,0x97,0x02,0x16,0x28,0x2a,0x94,0x85,0x4a,0xf4,0x42,0x03,0xa2,0xae, + 0x43,0x30,0xce,0xa7,0x71,0xc3,0x1d,0x8e,0x23,0x46,0x23,0xba,0x11,0x64,0xed,0x9c, + 0x95,0x82,0x91,0x70,0x67,0x65,0xd8,0x74,0x48,0x22,0x02,0xc7,0x52,0x25,0xbe,0xc3, + 0x76,0x98,0x4a,0xc5,0xb8,0xb3,0xf7,0xed,0xe2,0x6b,0x58,0x14,0x5d,0x8c,0x1e,0x37, + 0x02,0xf9,0x84,0x0a,0x33,0x50,0x28,0x15,0xad,0x53,0xa1,0x4a,0x83,0x18,0x32,0x3a, + 0x79,0xc2,0xd8,0xac,0x67,0x18,0xb6,0x63,0x50,0x9a,0xde,0xad,0xe6,0x58,0x05,0x23, + 0x1d,0x1f,0x6c,0xc5,0xb1,0xba,0xfa,0xcc,0x30,0xb8,0x57,0x75,0x30,0x46,0x2a,0xdd, + 0xc3,0xb5,0xc5,0xe7,0x51,0x79,0x7a,0xdd,0x94,0x73,0x8c,0x8f,0x9a,0xf8,0x91,0x50, + 0x13,0x2f,0x0c,0xd7,0x22,0xa0,0x75,0x69,0x37,0xfa,0xbf,0x85,0x34,0xcf,0x1d,0x99, + 0xc5,0x06,0x85,0x4f,0xad,0xf6,0xc0,0x4b,0xd7,0x06,0xc9,0x5d,0x50,0xa9,0x74,0x87, + 0xac,0x74,0x34,0x2c,0xa7,0x75,0xca,0xa4,0x4f,0xfb,0xa8,0xb5,0xcd,0x54,0x6a,0x84, + 0xab,0x3b,0x17,0xc1,0xf6,0xee,0x19,0x5e,0xe7,0xfc,0xda,0x1e,0xf0,0x57,0x0c,0x19, + 0x57,0x14,0xee,0xbe,0x62,0xa0,0xf1,0x46,0xf8,0x52,0xe3,0x7e,0xda,0x4c,0xc8,0xc6, + 0x5e,0x26,0xfc,0x58,0x52,0x6a,0x37,0x43,0x74,0x80,0x20,0x41,0xb2,0xf8,0x05,0x19, + 0x82,0x08,0xca,0xe5,0x0b,0xe2,0xae,0x32,0x49,0xe3,0x00,0x91,0xc4,0x7c,0x4c,0x1b, + 0x99,0x1a,0x9d,0xc0,0x60,0x29,0x84,0x37,0x49,0x6c,0x86,0x4a,0x25,0xec,0x01,0xd0, + 0x5a,0xef,0xeb,0x32,0xb9,0x61,0x0f,0x2a,0xee,0xe0,0xa0,0x9a,0x54,0xa2,0x30,0xb8, + 0x73,0x60,0xbc,0xef,0xaf,0x91,0xda,0x47,0xc4,0x54,0x13,0xfd,0xac,0x48,0x33,0x9f, + 0xe0,0xb3,0x54,0x5f,0xd7,0xd5,0x92,0xb7,0x45,0xac,0xff,0x66,0xdc,0xb4,0xae,0x7d, + 0x5b,0x95,0x29,0x27,0xb4,0xeb,0x8d,0x32,0xf6,0x46,0x3a,0xe4,0xad,0xfd,0xaf,0x4e, + 0xfb,0x75,0xa7,0xd6,0x2b,0x16,0xc8,0x1b,0x80,0x59,0x68,0xd4,0x63,0x15,0x02,0x59, + 0x6c,0x5a,0xd6,0x63,0xcd,0x3c,0x7e,0x25,0xeb,0x15,0x44,0xa3,0x78,0xb1,0xd5,0xf0, + 0x8e,0x10,0x6c,0x7d,0x8a,0xe7,0xaa,0x90,0x51,0x33,0x6a,0x99,0xca,0x2a,0xe7,0xff, + 0x9a,0x84,0xdd,0x5e,0xac,0x27,0x3e,0xdb,0xad,0xe3,0xd6,0x1a,0x06,0xda,0xe7,0x0c, + 0xa9,0x70,0xc9,0xc3,0x3c,0xc7,0xe7,0x60,0x0c,0xf4,0x57,0x6f,0x39,0xf0,0x3b,0xb6, + 0xd8,0xe7,0xfe,0xd8,0xc4,0x1f,0xaf,0x99,0x77,0x95,0x21,0x10,0xa6,0x9e,0x87,0x59, + 0x58,0x4a,0xac,0xca,0x82,0xe1,0xed,0x3d,0xb3,0x81,0xd0,0xdc,0x72,0xc3,0x24,0xb7, + 0x96,0x3a,0x59,0x5a,0xc0,0x21,0xf2,0x56,0x6b,0x48,0x76,0xff,0x80,0x61,0xfc,0x49, + 0x53,0xef,0x03,0x9d,0x34,0xf9,0x70,0xc0,0x09,0xe5,0xaa,0x4f,0x77,0x76,0x4e,0x26, + 0x60,0xa7,0x18,0x86,0x9e,0x52,0xfd,0x1a,0x31,0xa0,0x76,0xba,0x23,0xc4,0x89,0x97, + 0x17,0xe9,0xdc,0x47,0x4d,0x04,0x7e,0xbf,0x36,0x56,0xe7,0x90,0x9f,0x7c,0xbb,0xac, + 0x39,0x0f,0x46,0x01,0x6e,0x58,0x62,0x04,0x77,0xde,0xaf,0x19,0xda,0x72,0xf9,0x87, + 0x53,0xaf,0x9d,0xfe,0xcf,0x78,0xba,0x9b,0xaa,0x3f,0x4d,0xe3,0x5e,0x2a,0x45,0xac, + 0x83,0x7b,0xc6,0x17,0xa6,0x54,0x89,0x78,0x4e,0xbb,0xad,0xd9,0x3c,0x4e,0x6f,0x5d, + 0x71,0x32,0x38,0x7d,0xe3,0xfb,0xe2,0x3e,0x9e,0xa6,0xe2,0xe7,0xa0,0x71,0x19,0x88, + 0xdd,0xd4,0x4b,0xd3,0xde,0x49,0x73,0x00,0xe2,0x3d,0xd0,0x0c,0xfa,0xfc,0x60,0x96, + 0x53,0x48,0x9c,0xd7,0x44,0x57,0x0a,0xc1,0xc6,0xcd,0x32,0x70,0x8a,0x0b,0x57,0x8b, + 0xc7,0x79,0x21,0x8a,0xc7,0xed,0xbc,0x14,0x68,0xb4,0x76,0xfa,0x3d,0x70,0x29,0x2d, + 0x31,0x58,0x0b,0xb6,0xb5,0x8b,0x6a,0xe4,0x7e,0xf3,0x8a,0x08,0x41,0x34,0x77,0x68, + 0x23,0x8b,0x6e,0xe8,0xdc,0x04,0x9e,0x17,0x95,0x35,0xca,0xca,0xab,0x0f,0xb2,0x48, + 0x04,0x43,0xdd,0x22,0xf1,0xb2,0x46,0x92,0xca,0x59,0x4d,0x1b,0xb3,0x7e,0xed,0x0a, + 0x37,0x41,0x3c,0x55,0x60,0x0f,0xef,0x5a,0xd6,0x84,0x97,0x06,0x5e,0x83,0x91,0xc7, + 0xb6,0xa7,0x1c,0xd1,0xd5,0xf4,0x00,0xb5,0xd3,0xdd,0xd0,0xb0,0x89,0xef,0x9f,0x39, + 0x7e,0x04,0x4d,0x2f,0xc6,0xff,0x1e,0x37,0xdb,0xc7,0x5e,0x7d,0xb2,0x36,0x6e,0xba, + 0x39,0xee,0x49,0x13,0x1c,0xde,0xe4,0x35,0x24,0x53,0x0f,0x4d,0x17,0xa7,0xbb,0x13, + 0xdf,0x53,0xe3,0xde,0x63,0x75,0x11,0x0b,0x81,0x99,0xcc,0x6b,0xd3,0x44,0x97,0x68, + 0xf6,0xae,0x2c,0x02,0x25,0x3c,0x8b,0x8e,0x13,0x98,0xad,0x5c,0x2e,0x8b,0xda,0x7a, + 0x8c,0x8d,0x41,0x10,0xf4,0x94,0xab,0x5f,0x29,0x4f,0x89,0x3e,0x53,0xbe,0xb6,0xe0, + 0x2c,0x19,0x57,0x24,0xbf,0xab,0x0b,0xbd,0xda,0x01,0xf0,0x75,0x4d,0xa4,0x31,0x71, + 0x95,0xfc,0x5f,0xb2,0xb6,0x94,0xd4,0xbc,0x32,0x40,0xb9,0x4c,0xbc,0x2e,0x8d,0x78, + 0x83,0xc9,0x3f,0x44,0xeb,0x0b,0xbb,0xd9,0x4a,0x85,0x52,0x26,0xeb,0x0d,0xaf,0xa9, + 0x70,0xb3,0x6d,0x85,0xe9,0xeb,0x37,0x95,0x59,0x14,0xc2,0x6d,0xc0,0x7b,0xed,0xf4, + 0xd1,0xaa,0xcc,0xb1,0x13,0x9e,0x5f,0x95,0x53,0x62,0x14,0xa7,0x20,0x26,0x0d,0x6a, + 0xa7,0x6f,0xd9,0xac,0x47,0x52,0xa9,0x93,0x26,0xd7,0x5b,0x5d,0x43,0x80,0x7e,0x3d, + 0x16,0x2a,0x37,0x66,0x15,0xe9,0xa8,0x2e,0xa0,0x19,0x97,0x13,0x1a,0x66,0xa2,0x9c, + 0xc4,0x28,0x5a,0xd6,0x04,0x6c,0x6e,0xbf,0xd6,0xc1,0x5f,0xef,0xae,0x5f,0x03,0x18, + 0xa9,0xf1,0x16,0x33,0x2e,0x6b,0x7a,0x0f,0xba,0x5f,0x3b,0x6e,0xd5,0x56,0xa4,0x74, + 0xab,0x54,0x70,0x87,0xc3,0x2c,0x0d,0xd5,0x56,0x01,0x21,0xab,0xb1,0x29,0x16,0x1f, + 0xa2,0x78,0xa0,0xb6,0x09,0x68,0xc1,0x48,0xea,0xb1,0x6a,0x25,0x1e,0xe5,0xe7,0x6d, + 0x54,0xb0,0x93,0x59,0xa8,0xc2,0x06,0xc8,0xfe,0xd0,0x2e,0x78,0xf7,0x08,0x0f,0xb8, + 0x9e,0x66,0x42,0xeb,0x29,0x26,0x1c,0xb6,0x6a,0xbf,0x6a,0xf0,0x36,0x06,0xef,0x3c, + 0x63,0xf0,0xf6,0x6f,0x31,0x78,0x07,0x83,0xef,0x3f,0x63,0xf0,0xce,0x6f,0x31,0xf8, + 0x3e,0x06,0x3f,0x78,0xc6,0xe0,0xfb,0x7f,0xc3,0xe0,0xc5,0x65,0x29,0x8a,0x27,0x2f, + 0x1a,0x0d,0x71,0x45,0x21,0x3f,0x30,0x53,0xc6,0xde,0xf2,0xfa,0xfd,0x8f,0x17,0x0e, + 0x83,0xe0,0x6c,0x1c,0x28,0xa1,0x4f,0xbe,0x58,0xda,0x6f,0x36,0x11,0xfd,0xd1,0x41, + 0x3a,0x8d,0x96,0xe9,0xcc,0x86,0x48,0xe1,0xe0,0x39,0xcb,0x9e,0x6b,0x3b,0x90,0xaf, + 0x04,0xb4,0x05,0x59,0x51,0x30,0x92,0x2a,0x13,0x5e,0xe4,0x8b,0x31,0x7e,0x74,0x2e, + 0x9e,0x0e,0x3a,0xf1,0xb9,0x17,0x91,0xc5,0x7a,0x84,0x41,0x0c,0x5f,0x29,0x18,0x57, + 0xb2,0x0b,0x76,0x45,0xa3,0xf1,0x38,0x2e,0x00,0x05,0x39,0x28,0xa0,0x23,0x32,0xaa, + 0xdb,0x6c,0x26,0xe5,0xb1,0x1b,0x97,0xdc,0xba,0xa1,0x12,0xc6,0x09,0x00,0x81,0x0e, + 0x23,0xfe,0x61,0x10,0x7a,0x11,0xb4,0x8c,0x4f,0xe1,0x44,0x31,0x1d,0x3e,0x91,0x69, + 0x61,0xb5,0x77,0x4a,0xab,0x6b,0x06,0x20,0x44,0x5a,0x2a,0xcd,0xe0,0xf4,0xf7,0x70, + 0xcd,0xa0,0x56,0x77,0xbb,0x8e,0x10,0x56,0xd8,0x59,0x35,0xca,0x80,0x4f,0xb9,0xea, + 0x8f,0x3b,0xa7,0xfa,0x08,0x18,0x3c,0x7b,0xa7,0xf4,0x3e,0xdb,0x64,0x62,0xb4,0xa6, + 0xea,0xb7,0xb5,0xfc,0x58,0xd1,0x56,0x5d,0x9f,0x19,0x89,0x68,0x80,0x09,0x4f,0x9b, + 0xb1,0xa7,0xc7,0xb8,0xce,0x80,0xe4,0x6f,0xe4,0xf6,0x21,0x2a,0x8e,0x51,0x35,0x46, + 0x6a,0x63,0x9c,0x6a,0x6d,0x04,0x6b,0xa8,0x1f,0x14,0x95,0xf5,0x7d,0x33,0x28,0x6d, + 0xd0,0xaf,0xa6,0x8d,0xa5,0xe2,0xc9,0xc9,0x33,0x3a,0xfc,0x3b,0x66,0x0f,0x0c,0x98, + 0xb2,0xab,0x78,0x62,0x0c,0x38,0xfd,0x27,0x47,0x20,0x4d,0xfa,0x31,0x47,0x9b,0x46, + 0x5f,0xbc,0xe1,0x10,0xdd,0x0a,0xce,0xa9,0x51,0xbc,0x18,0x84,0x14,0x4f,0xd2,0xb6, + 0xd4,0x34,0xe9,0x0a,0x4f,0x28,0x99,0x78,0x29,0xc9,0x94,0x01,0xa4,0x15,0x6f,0x2b, + 0x46,0x69,0x3c,0x61,0x8d,0x41,0xb0,0x26,0xbc,0x01,0xf4,0xc3,0x41,0x7c,0xc7,0xe1, + 0x28,0x75,0x4d,0xb1,0x56,0xae,0x29,0x9b,0x33,0x34,0x34,0x8f,0x55,0x63,0x50,0xa2, + 0x93,0xb5,0x49,0xff,0x5e,0x1f,0x67,0x7a,0x72,0xd2,0x63,0xf5,0xf7,0xb0,0xf5,0xa3, + 0x9c,0xc4,0xe9,0xfd,0xd3,0x03,0x48,0x2f,0xf9,0x7b,0x86,0xf8,0x29,0xa1,0x73,0x89, + 0x4f,0x0e,0x31,0xfd,0xbb,0x06,0xb8,0x0c,0xd2,0xc9,0xdc,0x4b,0x9f,0x1e,0x62,0x34, + 0xff,0xba,0x6c,0xfc,0x3c,0x0e,0x86,0x63,0x81,0x68,0xd0,0xa4,0x1b,0x02,0xa5,0x45, + 0x45,0xa4,0xd3,0xc8,0x1c,0x30,0xe3,0x03,0xb1,0x82,0x8f,0xdd,0x90,0xbd,0xb9,0x05, + 0xbe,0x84,0xd0,0x20,0xe0,0xf1,0x56,0x04,0x03,0xd1,0xe6,0x14,0xd1,0x0d,0x82,0x16, + 0x21,0xef,0x12,0x7d,0x20,0x2e,0xd0,0x79,0x0b,0xca,0xfb,0xb8,0xe2,0x8d,0xe0,0x43, + 0x87,0x32,0x40,0xa7,0xa9,0x98,0x23,0x6c,0x84,0x11,0xce,0x87,0xd6,0x27,0xe9,0xf2, + 0xff,0x91,0x28,0x51,0xac,0xe2,0x88,0x38,0xd5,0x3b,0xa1,0x63,0x19,0x8e,0x4a,0xe1, + 0x33,0x07,0x19,0x56,0x24,0xcd,0xdb,0x90,0x33,0xe9,0xeb,0x2d,0xff,0xaf,0x5a,0x66, + 0x43,0x83,0x7a,0x0c,0xef,0x82,0xe1,0x17,0xba,0xca,0x33,0x2c,0x91,0xf4,0x37,0x2d, + 0x11,0x25,0x1d,0x4a,0xa2,0x72,0x0c,0x4f,0xa5,0xa5,0xe5,0xf1,0xb6,0x00,0xb2,0x71, + 0x67,0x2d,0xaa,0xcc,0x93,0x90,0x64,0x7e,0x6f,0xa4,0xaa,0x18,0x6e,0x5a,0xcc,0x4b, + 0xb3,0x06,0x00,0xa2,0x70,0x9c,0xb8,0x20,0xe6,0xcf,0xd3,0x00,0xd3,0x8d,0x78,0x11, + 0x78,0x41,0xef,0xf1,0x28,0x0d,0x66,0x52,0xb3,0xb3,0x72,0x4e,0x7d,0x67,0x7d,0x31, + 0xbf,0xf7,0x66,0x0e,0x9f,0x39,0x4d,0x83,0x01,0x65,0x15,0x68,0x87,0x9a,0xd8,0x1f, + 0xc6,0x9e,0x8f,0x3b,0x53,0x4b,0x89,0xba,0x92,0x52,0xdc,0xc0,0x62,0xd4,0x6d,0xbb, + 0x5c,0x93,0x93,0xc8,0x2b,0x44,0x98,0xf3,0x1f,0xb5,0xca,0x5a,0x99,0x00,0xda,0x2c, + 0x05,0x1e,0xc1,0xa1,0x95,0x1e,0x65,0x60,0x78,0x06,0x45,0xa2,0xb1,0x84,0x9b,0x8c, + 0x26,0x24,0x0a,0xee,0x9f,0x83,0xc4,0xe1,0x78,0xd4,0xa1,0x49,0x10,0xf6,0x70,0x20, + 0x0c,0xa1,0xcc,0x64,0xc9,0x4f,0x6f,0x45,0x87,0x88,0xeb,0x79,0x26,0xa4,0x12,0x12, + 0x55,0xf5,0xc0,0x5b,0x09,0xe7,0x89,0x12,0x63,0xdb,0x0b,0x32,0xae,0xbd,0x19,0xe6, + 0x6b,0xcc,0x21,0xe6,0xfb,0x47,0x98,0x4e,0x70,0x38,0xba,0xa7,0x9d,0x7a,0x26,0xc3, + 0x76,0xf2,0x83,0x98,0xdb,0x08,0x29,0x46,0xb8,0x25,0x74,0xcc,0x43,0x18,0x9c,0x5c, + 0x0c,0xf1,0x2e,0xa0,0xc3,0xae,0xa4,0x84,0x84,0x4c,0x86,0x61,0x30,0xbc,0x15,0x94, + 0xbc,0x78,0xb2,0x3b,0x03,0x29,0xa8,0xbf,0x9f,0xf8,0xb2,0xd2,0xe1,0xfb,0x08,0xab, + 0x0a,0xb1,0x23,0x68,0x33,0x32,0xe6,0xa2,0x97,0x07,0xb0,0x8a,0x47,0xd1,0xb9,0x05, + 0x54,0xbb,0x7f,0x72,0x14,0x2d,0x1d,0x3c,0x8a,0x3e,0xcb,0x5c,0x19,0xe5,0x32,0xa5, + 0x93,0xad,0xe4,0x2d,0x1c,0x31,0x61,0xc3,0x0a,0x7f,0xa0,0xbd,0xb6,0x93,0x33,0x6c, + 0xa3,0xf3,0x93,0x26,0x44,0xa3,0x82,0x51,0x56,0xc0,0x8a,0x3e,0x94,0x51,0x51,0x29, + 0x4a,0xb8,0xae,0xa6,0x14,0x0a,0xd2,0x1e,0xd3,0xe8,0xaf,0x81,0xac,0xd3,0xf5,0x06, + 0x44,0xda,0x49,0xd3,0x0c,0xbd,0x73,0xd2,0xa4,0x94,0x10,0xa5,0x86,0xf2,0xe3,0xd8, + 0xc5,0xe9,0xee,0x7f,0xa8,0x07,0xc5,0x91,0x72,0x3f,0x1e,0x4e,0x27,0x32,0xca,0x5c, + 0x8c,0x74,0x11,0x4a,0xba,0x7c,0x7b,0xff,0xde,0x47,0x8d,0xe5,0xce,0x3f,0xd4,0x2d, + 0xa2,0xdb,0xb2,0x57,0xde,0xc5,0x80,0x35,0xe2,0xc4,0xa4,0x4b,0xcf,0xe8,0x70,0x77, + 0x6f,0x67,0xa7,0xd9,0x84,0x65,0x64,0x19,0x82,0x7b,0xae,0x9c,0x09,0x11,0xb4,0x07, + 0x65,0x03,0x82,0x87,0x21,0xa9,0x33,0x79,0x58,0x06,0xd0,0x6e,0x49,0x0c,0x9f,0x16, + 0x91,0xa1,0xbd,0x90,0xa1,0xcb,0x76,0x82,0xce,0xfb,0x5f,0xa5,0x98,0x64,0x9a,0xdd, + 0xd7,0x2d,0xb4,0xb7,0x1c,0x3c,0x77,0xb9,0x5d,0x03,0x17,0x00,0xe7,0x76,0x93,0x4a, + 0x28,0xc5,0x67,0xee,0xbf,0x05,0x48,0xdf,0xb3,0xbe,0xb1,0x40,0x74,0x31,0x21,0xcf, + 0xf7,0x2f,0x66,0xb8,0xf8,0x2e,0x00,0x78,0x07,0xc3,0xea,0x16,0x63,0x7e,0x6b,0xe5, + 0xe5,0x8b,0x60,0x44,0x6f,0x9a,0x30,0x9f,0x5d,0x0e,0x06,0xfa,0x7d,0x4b,0xcf,0xc3, + 0xd6,0x84,0x99,0x87,0x74,0xb8,0x9f,0xa7,0x69,0xf6,0xcd,0x7f,0x1e,0x7b,0x06,0xc5, + 0xf3,0xcb,0x00,0x80,0x23,0xd9,0x14,0xe2,0x71,0xcf,0x27,0x98,0x75,0x9d,0xdf,0xe8, + 0x1f,0x11,0xb1,0x62,0x23,0x87,0xb4,0x9d,0xbf,0x6e,0x06,0x2b,0xd6,0x4f,0xd4,0x21, + 0x28,0x63,0x47,0x6f,0x7c,0x39,0x8c,0x79,0x08,0xe1,0xd8,0x0e,0xf5,0xb4,0x66,0x18, + 0xe7,0x98,0x16,0x1d,0x1d,0x2f,0xcd,0xa2,0x71,0x9e,0xac,0x79,0xe4,0xce,0xd2,0x40, + 0xaa,0x1e,0xf0,0x95,0x9e,0xf6,0x1c,0x7e,0x50,0x50,0xce,0x9b,0xfa,0x02,0x9b,0x14, + 0xdf,0x38,0xac,0x98,0x9e,0x8e,0x62,0xf8,0xa0,0x39,0x9d,0x43,0x8f,0xb8,0x63,0xa0, + 0x12,0x0a,0x49,0x46,0x50,0x30,0xf0,0x57,0xb7,0xf1,0x68,0x22,0xae,0xf8,0x24,0xa9, + 0xd3,0x8c,0xba,0x8a,0xa3,0xf0,0x5e,0xfb,0xe7,0xca,0x3c,0x86,0x63,0x5a,0x18,0xe3, + 0xd0,0xc9,0xb3,0x0a,0x7a,0x71,0x43,0xe5,0xa3,0xa5,0x52,0xd3,0xa4,0x77,0x11,0x28, + 0x6c,0x42,0x47,0x66,0xcf,0x55,0xf8,0x10,0x28,0x25,0x74,0x8a,0x9d,0xaa,0xf3,0xe1, + 0x5a,0x77,0x87,0xde,0x00,0x81,0x1a,0x7f,0x90,0xf7,0xbd,0x52,0x22,0xd9,0x09,0x28, + 0x7b,0x01,0x35,0xa5,0xe7,0x81,0x83,0x1a,0xfd,0xba,0xa2,0x57,0x40,0x4a,0x6a,0xec, + 0x87,0x87,0xcf,0x5f,0x9c,0xdb,0xfe,0x7f,0xbf,0xfe,0xe1,0x7b,0xc8,0x6d,0x0a,0x60, + 0x11,0x8c,0xee,0xeb,0xa8,0x6a,0x3b,0xa3,0x3e,0x34,0x27,0xb7,0xd7,0x16,0x04,0x47, + 0x08,0xc8,0xd9,0x2d,0x64,0x4b,0x8f,0x65,0x6b,0xdd,0xa3,0x72,0x5d,0xd0,0xbf,0xa5, + 0xeb,0x91,0x1b,0x44,0x90,0xd3,0xdf,0xff,0xf8,0xf1,0xbb,0xbe,0x65,0x71,0x49,0x9c, + 0xd6,0x83,0x7e,0xab,0x17,0x90,0x1b,0x72,0x43,0x19,0xdd,0x64,0xe3,0x5e,0xb0,0xb7, + 0xc7,0xb4,0x69,0xea,0x24,0xf5,0xf9,0x39,0xf8,0xd2,0xa3,0xf7,0x3f,0xe4,0xc3,0x83, + 0x34,0xd5,0x4e,0x3a,0x36,0xad,0x6d,0x10,0x4d,0x65,0xaf,0xa8,0xec,0xf5,0x0b,0xed, + 0xa0,0xdd,0xf2,0x4c,0x1a,0x8d,0xaf,0x5b,0x9e,0x26,0x53,0x08,0xcf,0x65,0xab,0x24, + 0x3f,0xb7,0xbe,0xf4,0xbc,0x2a,0x41,0x27,0x14,0x94,0x15,0x26,0x33,0x37,0x87,0x56, + 0xde,0x8a,0x01,0xd6,0x39,0x60,0xb8,0xbf,0x62,0x2c,0xe4,0xe7,0xf6,0x97,0xbc,0x0a, + 0xbc,0xe8,0xd6,0x1a,0x9d,0x2f,0x0f,0x0f,0x96,0xe9,0x68,0xe4,0xd2,0x31,0xa8,0xc8, + 0xe7,0x7a,0x75,0x8f,0x89,0x5a,0x32,0x6f,0xb4,0xd7,0xeb,0xbf,0x18,0x55,0x86,0xea, + 0xed,0x2c,0xab,0x4a,0xa9,0x03,0x41,0x2d,0x1a,0xbf,0xa9,0x0e,0xfe,0x2d,0x3a,0x7b, + 0x41,0x6f,0x64,0x68,0x00,0x4a,0x28,0x86,0xd5,0x16,0xf1,0xc6,0x34,0x23,0x65,0xa8, + 0x68,0xae,0x11,0x6f,0xf3,0x6a,0x06,0xaa,0x25,0xf7,0xa2,0x7e,0x75,0x99,0xbf,0xc8, + 0xc3,0x5a,0x7b,0x2b,0x93,0x0c,0x2a,0x2f,0xd5,0xd8,0xbc,0xe8,0xb1,0x2f,0x14,0x57, + 0xaa,0xbc,0x4f,0x65,0x53,0x8e,0x9e,0x43,0x1a,0x52,0x78,0x8f,0x42,0x9a,0x1f,0x19, + 0x75,0x32,0x8f,0x20,0xb1,0xd2,0x9b,0x28,0xea,0x2c,0x8a,0x45,0x12,0xdc,0xc9,0xd0, + 0x40,0x20,0xce,0x24,0xc0,0x85,0x10,0x2a,0x20,0xbd,0xfd,0x43,0xee,0x6d,0xff,0x40, + 0x8e,0xca,0x1d,0xdb,0x15,0xdb,0xed,0x4f,0xd3,0x8a,0xa2,0xf8,0xfa,0x1d,0x2d,0xf8, + 0x23,0x88,0xad,0x6a,0x1e,0x1f,0x1d,0xb4,0x5a,0xb6,0x33,0x5e,0x29,0xfd,0x86,0x4b, + 0x9b,0xfb,0x47,0xf4,0x68,0xb2,0xfa,0x88,0x0a,0x9b,0x47,0xad,0x5c,0x5f,0x7c,0x3b, + 0x77,0x51,0x7b,0x96,0x2f,0xac,0xbd,0xf1,0x9e,0x35,0xb6,0x48,0xcc,0xc7,0xf9,0x03, + 0x2a,0xc1,0x83,0xc9,0x9e,0x35,0xb1,0x4c,0xa3,0x49,0xfe,0x4c,0x17,0x9a,0x1b,0xb5, + 0x67,0x29,0x8b,0x84,0x05,0xd3,0xfd,0x81,0x37,0x25,0xbd,0x50,0x18,0x43,0x49,0x39, + 0x67,0xa5,0xed,0x67,0x0e,0xff,0xb5,0x08,0x5e,0x1b,0x43,0x1a,0xc8,0xd0,0x57,0xae, + 0xf8,0x8e,0xcc,0xa7,0x62,0xa0,0x41,0xdd,0x98,0xba,0x0d,0xef,0x26,0x8a,0x69,0x7f, + 0x87,0x02,0x48,0xf6,0x07,0xc5,0x3b,0x37,0xc6,0xe0,0x91,0x87,0x24,0x13,0x67,0x1a, + 0x54,0xb8,0x97,0xd0,0x0e,0xd8,0x95,0x4c,0x47,0x15,0x1e,0xc2,0xc3,0xc3,0x76,0x98, + 0xec,0xb7,0x65,0x3b,0x59,0xff,0xf3,0x17,0x33,0x35,0xe5,0x4e,0xfe,0x94,0xc1,0xa4, + 0x84,0xec,0xa4,0x92,0xe9,0x20,0x0c,0x10,0x51,0xa4,0x96,0x9d,0xe9,0x77,0xee,0xac, + 0xab,0xe9,0x40,0x6b,0x31,0xe8,0x94,0x9b,0x2d,0x80,0xd8,0x09,0x09,0x0c,0xaa,0x4d, + 0xae,0xf3,0x26,0xa8,0x4d,0xee,0x8f,0xec,0x32,0xfc,0xef,0x9f,0xa6,0x32,0x1a,0xca, + 0x8f,0xb1,0xcf,0x0d,0x07,0x31,0x7a,0xf0,0x22,0xcb,0x66,0x0d,0x35,0x4d,0x57,0xab, + 0x9d,0x59,0x57,0xc0,0xb3,0x20,0x28,0xb3,0xba,0xd6,0x5b,0x72,0x4b,0x32,0x27,0xa5, + 0x50,0xdc,0x2c,0x37,0x60,0x28,0x5b,0x79,0xb7,0xd3,0x25,0x24,0x5a,0xb7,0xc4,0xff, + 0xfd,0x3f,0x82,0x1a,0x2d,0xd9,0x2a,0x93,0xb1,0xe8,0xd3,0x8b,0x91,0xbd,0x35,0x86, + 0x19,0x66,0xf1,0x73,0x45,0x43,0x18,0x73,0x4d,0x97,0x04,0x43,0x38,0x7b,0x4e,0x7a, + 0x05,0x37,0x7e,0x4b,0x81,0xe0,0x54,0x49,0x9f,0x33,0x02,0xf4,0x80,0xd4,0xcf,0xa8, + 0x00,0xd6,0xca,0xd3,0x95,0x0b,0xaf,0xa7,0x19,0xa7,0x74,0x4f,0x37,0x31,0x55,0x8e, + 0x23,0xed,0x5f,0x48,0x93,0x46,0x05,0x4e,0x14,0xf3,0x78,0x0a,0x57,0x33,0x30,0x8e, + 0x77,0x20,0x47,0xb4,0xea,0x01,0x02,0x15,0xcc,0x88,0xdf,0x80,0x72,0xf3,0x45,0xe3, + 0x21,0x8c,0xc1,0xd6,0x4b,0xbb,0x86,0xa7,0x2c,0x4d,0xb2,0x31,0x80,0xba,0x8a,0xa2, + 0x75,0x59,0xa9,0xa5,0x5c,0x7d,0x46,0xf1,0xac,0x9e,0x5f,0xed,0x59,0x70,0x79,0x6a, + 0xca,0x56,0x24,0x42,0x28,0x7a,0x0b,0x96,0x77,0x2d,0x1d,0xf8,0xc6,0xa3,0x11,0xf7, + 0xb7,0x2c,0x45,0xc1,0xbc,0x1d,0x7c,0xc5,0xfc,0x30,0xf4,0x10,0xbf,0x22,0x31,0xd5, + 0xf1,0xc9,0x80,0x6c,0x07,0x05,0x28,0x1e,0xf9,0x9d,0x09,0xf0,0x0d,0xbd,0xfc,0xc5, + 0x01,0x33,0xe7,0x5e,0xd8,0x0a,0xc0,0x22,0x69,0x84,0xec,0x3e,0x31,0x21,0x3d,0xc6, + 0x57,0x26,0x64,0x51,0x4c,0x47,0xbd,0x17,0x68,0xfe,0xaf,0x7f,0xf9,0x8f,0x62,0x46, + 0xec,0xfb,0x7d,0x98,0xae,0xf5,0x69,0x10,0xa9,0x68,0x45,0xce,0x58,0xb3,0x81,0x24, + 0xb4,0x61,0x55,0x26,0x24,0x26,0xb1,0x3f,0x0d,0x75,0x80,0xa7,0xf2,0x8d,0xca,0x98, + 0xe3,0x75,0xd6,0x4d,0x5a,0xcd,0x7f,0xd1,0x6d,0xff,0xc5,0xe4,0x58,0x6b,0x8d,0x1a, + 0xa6,0xe5,0x45,0x9c,0x46,0xea,0xe6,0x3d,0x15,0xaf,0xb8,0x91,0x0a,0x93,0x00,0x65, + 0xb8,0xa7,0x03,0xdf,0x5a,0x10,0xa5,0xef,0x3e,0x3d,0x41,0x43,0xea,0x5f,0xff,0xf2, + 0xbf,0xcb,0x49,0x3c,0x21,0x07,0xf9,0x84,0xe0,0x0c,0xc1,0x89,0xaf,0x70,0x0f,0x9c, + 0x60,0x69,0xfc,0x49,0x9d,0xb1,0x0d,0xe5,0xb3,0x19,0xf5,0xb6,0x3c,0x6a,0x16,0x0f, + 0x6c,0x08,0xc8,0x08,0xa6,0x8d,0xd4,0xaa,0x6b,0x59,0xf6,0x9e,0x89,0x89,0x0a,0x01, + 0x7a,0xaf,0x3e,0x32,0xa7,0xce,0x2c,0xcd,0x31,0xd4,0x62,0x00,0x06,0xcb,0x6f,0x15, + 0x8e,0xb7,0x6a,0xa4,0x7a,0xc5,0x7d,0x3c,0x07,0x9e,0xce,0x65,0xbb,0x28,0x2e,0x77, + 0x86,0xf0,0x6c,0x50,0xdc,0x70,0x05,0x4c,0x84,0x33,0xa9,0x1b,0x93,0xce,0x97,0x1f, + 0xd4,0xd6,0xad,0x3d,0xdc,0x43,0x04,0x00,0x0a,0x71,0x9b,0x13,0xe3,0x08,0x2a,0xd7, + 0x34,0x52,0xb9,0xb9,0xb2,0xad,0xc2,0x30,0x8e,0x30,0x93,0x29,0xad,0x48,0xa9,0x67, + 0x94,0x20,0x5d,0x1b,0xab,0xc2,0x28,0x6e,0xf3,0x63,0x9c,0xd1,0xab,0xa6,0xb8,0xfa, + 0x89,0x54,0xa2,0xd9,0x6e,0x1d,0x1c,0x1f,0xbe,0x3a,0x42,0x2c,0x41,0xd7,0x18,0xe8, + 0xe3,0x5b,0x72,0xb2,0xb2,0x5c,0x0a,0x93,0x75,0x45,0xbf,0x3a,0x52,0xd1,0x6f,0x72, + 0x96,0x9d,0x9d,0xe5,0x9d,0x35,0x8b,0x22,0x8a,0x4c,0xba,0x2d,0x9b,0x82,0x93,0x52, + 0x08,0xb6,0xd3,0x67,0x51,0xa6,0x63,0xa2,0x27,0x62,0x2d,0xb5,0x11,0x22,0x97,0x4d, + 0xe6,0xb1,0x8c,0xdc,0x59,0x7e,0xb3,0xb5,0x6c,0x68,0xfe,0xfe,0xe4,0x10,0xe1,0x26, + 0x8c,0xd2,0x14,0x72,0x1b,0x03,0x5a,0x43,0xe6,0x5d,0xe3,0x58,0xc6,0x0a,0xbc,0x36, + 0xd5,0xe8,0xed,0x68,0x27,0xea,0x8f,0x61,0x14,0x42,0x3a,0x15,0xaf,0x1e,0x5a,0xc5, + 0x12,0x51,0xfa,0x60,0x63,0x8d,0xa8,0x90,0x0c,0x8f,0x52,0x01,0x9c,0x31,0x4b,0x14, + 0x56,0x24,0xc5,0x2d,0xee,0xfc,0xb7,0x13,0x18,0x1e,0x74,0x36,0x4d,0xce,0x78,0x0a, + 0xb0,0x34,0x11,0xa7,0xce,0x20,0x50,0xe6,0x5c,0x9a,0x55,0xf4,0x1f,0x24,0xdb,0x7b, + 0x57,0x6e,0x90,0x74,0x0b,0xc1,0xe7,0xaa,0x94,0x62,0x45,0xe5,0xdc,0x7f,0xf0,0x08, + 0x66,0xc9,0xf9,0xda,0x36,0xb5,0xd6,0x3a,0x1c,0xaf,0xd2,0x49,0x75,0x83,0x04,0x4a, + 0xd5,0x7e,0xdd,0x71,0xdb,0x47,0xc7,0xee,0x81,0xdb,0xb6,0xec,0xfc,0x69,0xb4,0x57, + 0x8f,0x60,0x41,0xda,0x67,0x96,0xd0,0xbc,0x00,0xcd,0xe6,0xca,0x20,0x77,0x2c,0xc2, + 0x27,0xe9,0x0d,0xc7,0xd2,0x6c,0xa4,0xf0,0xfe,0x4c,0xce,0x6f,0x13,0xff,0xe0,0x7e, + 0x52,0x64,0x9a,0xcd,0x7a,0x75,0x8b,0x0c,0x33,0x8c,0xe1,0x68,0x1a,0xea,0xae,0x68, + 0x9f,0x5e,0x1b,0x12,0xb8,0x9f,0x9b,0x60,0x56,0x9a,0x57,0x36,0xdb,0x40,0x69,0x7a, + 0xf6,0xfa,0x8c,0x46,0x65,0xf6,0xe0,0xfe,0x2c,0xf0,0x4c,0x62,0x79,0x77,0xf7,0x85, + 0x66,0x5b,0xa9,0x5a,0x94,0xed,0x7d,0x5c,0xde,0xb1,0xf4,0x78,0xfe,0x9e,0x5f,0xab, + 0xf5,0x42,0x48,0x77,0xe7,0x00,0x2c,0xf8,0x20,0xf6,0xc0,0x02,0x16,0xee,0x8d,0xba, + 0x57,0x0a,0x56,0x24,0x57,0x09,0xd4,0xfd,0x28,0xae,0xae,0x3f,0xbd,0xf9,0x58,0xae, + 0xce,0x74,0x7d,0x38,0x06,0x83,0x58,0x16,0xca,0x1a,0x97,0x74,0x8d,0x36,0xbc,0xc3, + 0x8c,0x64,0x07,0x9c,0x54,0x70,0xe9,0xbd,0x1d,0xcd,0x16,0x93,0x99,0xec,0x52,0x22, + 0x9f,0x9c,0x50,0x24,0x4d,0x50,0xc7,0xd9,0xd6,0x4c,0xe7,0xe6,0x09,0xd7,0xf7,0xaa, + 0xa9,0x53,0x13,0x84,0x26,0xf9,0x26,0x9b,0xee,0xab,0x48,0xb5,0x3a,0x50,0x85,0x21, + 0xb9,0x22,0x51,0xe3,0x28,0xd6,0xa0,0xbb,0xf7,0xf0,0x95,0x91,0x49,0xec,0x4e,0x02, + 0x88,0x4a,0x44,0x7b,0xba,0x3a,0x39,0x01,0x44,0xa3,0x38,0xb7,0x91,0xc3,0x31,0x1f, + 0xf2,0x39,0xa3,0x2d,0xff,0x28,0x23,0x97,0x63,0x2e,0x5f,0xc0,0xe7,0x90,0x2f,0xb1, + 0xce,0x8a,0xa2,0xae,0x55,0xb2,0x06,0x92,0xbf,0x3a,0x67,0xe9,0x9f,0x49,0x7f,0xaf, + 0x5e,0x54,0xfe,0x47,0x3d,0x7b,0x08,0x1d,0xf3,0x62,0xa5,0x90,0x4c,0x75,0xd7,0xaa, + 0xbc,0xef,0x5e,0xed,0xb7,0xb1,0xe9,0x09,0xd0,0xb7,0xc5,0xd9,0x88,0x20,0xcb,0xe3, + 0x73,0xce,0x38,0xd3,0x91,0x3d,0xbd,0x11,0x48,0x68,0x1f,0xdc,0xa4,0xa8,0x28,0x8f, + 0xe4,0x21,0xe5,0xd7,0xeb,0x65,0xa4,0x10,0x81,0xce,0xb7,0x91,0x54,0x7a,0x91,0xf6, + 0x99,0x79,0x5a,0x9d,0xbc,0xa1,0xd2,0xc7,0x79,0x56,0xf2,0x6f,0x30,0xd6,0xe4,0xc6, + 0xd5,0x0a,0x99,0x9c,0xb2,0x26,0xe9,0xa5,0x58,0xd2,0xfa,0x6a,0xce,0x1a,0x5a,0x4a, + 0xd3,0x78,0x69,0xed,0x01,0x50,0x02,0x4e,0xfe,0xf4,0xe9,0xfd,0x79,0x3c,0x49,0x20, + 0x06,0xc0,0x7b,0x30,0xcd,0xc4,0x93,0xc2,0xd8,0xd3,0xbe,0xce,0x44,0xd9,0x3a,0x6d, + 0x78,0xcd,0xaf,0x4d,0xa8,0xb2,0x98,0xaa,0x41,0x59,0x87,0xb7,0x3a,0x97,0x58,0x2f, + 0x44,0xcd,0x29,0x18,0x6d,0xaf,0x85,0x8d,0x7c,0x8a,0x43,0x28,0xe8,0x32,0x44,0xef, + 0xbf,0x56,0xd0,0xf8,0x46,0xfc,0xe3,0xfb,0x8b,0x9f,0x29,0x42,0xcc,0x8a,0xd8,0xcd, + 0xe2,0x20,0x84,0xb6,0x8a,0x3f,0xb4,0x79,0x05,0xf4,0x3a,0x71,0x72,0x4b,0x99,0x24, + 0x49,0xf9,0x51,0x00,0x8e,0x38,0x39,0x68,0xcc,0xfd,0x06,0xc5,0x8a,0x26,0xf6,0xd1, + 0x6b,0x1a,0x90,0x3d,0x83,0xa3,0xce,0x5c,0x71,0xf5,0xc3,0xf5,0x8f,0x26,0x18,0xd5, + 0x30,0x9a,0xf2,0x30,0x50,0x8a,0xa9,0xce,0x04,0x71,0xc6,0x48,0x0f,0x50,0x47,0xd0, + 0x96,0xd4,0x6d,0x41,0x71,0x0a,0xd0,0x22,0xf7,0x12,0xe9,0xd3,0x45,0xf0,0xf8,0xbc, + 0x9f,0xe6,0xe5,0xc3,0x20,0xfa,0x64,0x1c,0x19,0x90,0x73,0xe2,0x37,0xe3,0xa8,0x23, + 0x9d,0x00,0x52,0xde,0xbd,0x4e,0x32,0x01,0x6b,0xea,0xdc,0x60,0x97,0x45,0x2a,0x94, + 0x3f,0x45,0xa8,0x50,0x7e,0x80,0x40,0xa7,0x93,0xf3,0xc9,0x53,0x06,0x4a,0xf2,0x46, + 0xb9,0xe2,0x84,0x11,0x55,0x48,0x65,0x12,0xde,0x3b,0xc5,0x3c,0x8d,0xa9,0x65,0x0a, + 0xf8,0xc4,0x22,0x6b,0x48,0x1c,0x91,0xbc,0x9b,0xd4,0x4f,0x65,0xa0,0x7e,0x6b,0x3d, + 0xd0,0xd0,0x20,0x47,0x87,0x08,0x0e,0xe6,0x38,0x94,0x8c,0x2e,0x28,0xcf,0xc2,0x77, + 0xbb,0xbb,0xef,0x40,0x88,0xfe,0xb2,0xc9,0x49,0xa5,0xa7,0x4a,0x76,0x07,0xea,0x40, + 0x87,0x80,0xa0,0x08,0xbc,0x85,0xf0,0x3d,0x7d,0x09,0x43,0x77,0x78,0x66,0x91,0x73, + 0x8c,0xac,0xa2,0x96,0x8e,0x01,0xb6,0x55,0x44,0xad,0xd2,0xb8,0x98,0xee,0x30,0xdc, + 0x9b,0xcc,0x24,0xee,0xea,0x16,0x1f,0x49,0x22,0xdc,0x44,0xa8,0xdb,0x79,0xe1,0x95, + 0xb0,0x6c,0xa5,0xeb,0x27,0x1b,0x95,0xad,0x96,0x25,0x1f,0x28,0x0f,0x40,0x1f,0xe5, + 0xb1,0x17,0x94,0x80,0xf0,0xee,0xe9,0x1a,0x9e,0x94,0x8e,0x6b,0x5a,0x0e,0xf5,0xad, + 0x8f,0x13,0xd1,0x67,0x4c,0xca,0x46,0x94,0xbe,0xad,0xb0,0x8e,0x99,0x56,0x65,0x74, + 0xc9,0xb5,0xbd,0x36,0x9d,0x89,0x5d,0x05,0x95,0x86,0xdf,0x59,0x3a,0xd5,0x4e,0x84, + 0x49,0xc8,0x59,0x91,0x87,0x70,0x04,0xa9,0xbb,0x16,0x42,0x1e,0x73,0xcd,0x35,0xf5, + 0xc7,0x51,0xac,0x52,0x7a,0x2d,0x67,0x31,0x01,0x06,0x8a,0x7d,0x98,0x53,0xc8,0xb5, + 0xe5,0x0c,0xc9,0x8d,0x77,0x81,0x51,0x1a,0x94,0xdd,0x97,0x96,0x63,0x10,0x31,0x9d, + 0xa4,0x84,0x91,0xe8,0x2e,0x2c,0x63,0x54,0x1b,0x3f,0x22,0x16,0xc6,0x08,0xf4,0x55, + 0x86,0x40,0x67,0xbb,0x9b,0x77,0x8d,0xf9,0x7c,0xde,0x20,0x59,0x6f,0x4c,0xd3,0x50, + 0xdb,0x29,0xc0,0xb4,0xbc,0x0f,0x3a,0x87,0x49,0x2b,0xda,0x87,0x2d,0xcb,0xc9,0x6d, + 0xa3,0x8b,0x96,0x65,0x2f,0x75,0xe0,0xfc,0xd5,0x4f,0xb6,0xb4,0xf2,0x74,0x45,0xf9, + 0x45,0x96,0x6d,0x0d,0x0d,0xc6,0x5d,0x65,0xaa,0xfe,0x3a,0x8e,0x77,0x57,0xaf,0x14, + 0x3a,0x15,0x4e,0x1f,0xb7,0x5a,0x26,0xc1,0xb7,0xc6,0xd2,0x22,0x5e,0xe4,0xf0,0x8b, + 0x76,0x83,0x68,0x7b,0x87,0x1d,0x88,0x3e,0x93,0x46,0x81,0x25,0x69,0xb7,0x95,0x1b, + 0x61,0x80,0x58,0x43,0xd7,0x90,0x22,0xc6,0x2d,0x84,0x41,0x1f,0xdf,0x1a,0xef,0x33, + 0x1f,0x9b,0xb3,0x2f,0x7a,0x1c,0x8a,0xda,0xa1,0xf2,0x81,0xaf,0x8f,0xc1,0xf0,0xd3, + 0xb9,0xa7,0xb4,0x6e,0xe7,0x01,0x95,0x58,0xd7,0x4b,0x5d,0x08,0x6e,0x51,0x73,0xbb, + 0x22,0x2c,0x74,0x5f,0x09,0x42,0x8a,0xc9,0x31,0x0c,0xd5,0x06,0x1d,0x7e,0x9e,0x26, + 0x56,0x92,0xe0,0x07,0x3e,0x8f,0xed,0x45,0x0a,0x5d,0x58,0x8e,0x25,0xd3,0xb4,0x9c, + 0x18,0x89,0x7f,0xa9,0x66,0x9b,0x5b,0x08,0xda,0x08,0x39,0x95,0x39,0x17,0xe2,0x3e, + 0xf2,0x00,0xed,0x79,0x9f,0x60,0x45,0xeb,0x7e,0x55,0x1f,0x2c,0xf6,0x6b,0x5b,0x0d, + 0x65,0x54,0xf5,0x5f,0x2b,0xa9,0x59,0xb8,0x28,0xfa,0x66,0x0e,0x80,0xda,0xad,0xf1, + 0x3a,0xcc,0x76,0x72,0x4e,0xb0,0xd5,0x61,0x1c,0xdd,0x68,0x23,0x83,0x35,0x55,0xe4, + 0x86,0x11,0xe0,0xcc,0xcc,0xb6,0x02,0xfb,0xa7,0x88,0x3f,0x09,0xe6,0x52,0x4f,0xbf, + 0xbb,0x30,0xbe,0xc7,0x9c,0xc8,0x3e,0x2b,0x43,0xc8,0x7e,0xfe,0xbe,0x31,0x25,0x0d, + 0xa4,0x68,0x30,0x42,0x84,0x3b,0xd1,0xdf,0x15,0x73,0xf2,0xe3,0x4f,0x52,0x3b,0x03, + 0x76,0x23,0x82,0x3e,0x10,0x45,0x5e,0x67,0x20,0xe1,0x02,0x7d,0x7e,0xad,0x80,0x9d, + 0x92,0x9f,0x7a,0x37,0x14,0x28,0x91,0x10,0xb0,0x6b,0xa3,0x70,0xc9,0xa4,0x09,0x94, + 0x4c,0x67,0x44,0x0d,0x39,0x07,0x8c,0xfe,0x46,0x67,0x18,0x78,0x65,0x1d,0xdc,0xbf, + 0x8f,0x2e,0x79,0xc0,0xb2,0xe4,0x7f,0x50,0x07,0x7e,0xbf,0xd1,0xa6,0x9b,0xeb,0x47, + 0xdc,0x09,0x1e,0x5d,0x0d,0xb3,0xfa,0xa0,0xd8,0x74,0x2b,0xb4,0xb5,0xe3,0x14,0x9f, + 0xb5,0x42,0x9c,0xe8,0x54,0x50,0xf8,0x80,0x02,0xc7,0x66,0xe7,0xf0,0xd0,0x5e,0x31, + 0xae,0xeb,0x71,0xf6,0x20,0xf7,0x49,0x05,0xb5,0x0f,0x0f,0x15,0xb7,0xb4,0x4a,0xd4, + 0xc3,0x83,0xc9,0xf1,0x0d,0x08,0xc0,0x6a,0xce,0x5b,0x15,0x77,0x45,0xb3,0x4e,0xfa, + 0x05,0xb5,0x3d,0xc8,0x31,0x6e,0x20,0xc3,0xfa,0xd0,0x5b,0xd2,0xe3,0x2d,0xb1,0xbc, + 0x34,0x7f,0xde,0x98,0xad,0x21,0xd2,0x44,0x07,0xbb,0x55,0xaa,0xa7,0x93,0x04,0x44, + 0xd7,0x2b,0xc4,0xe6,0xac,0x7c,0x78,0x28,0xb8,0x78,0xd2,0xda,0x46,0x8b,0x7e,0xd6, + 0xab,0xf2,0xba,0x57,0x5d,0x0a,0x52,0x99,0xbc,0xc1,0xac,0xb4,0x83,0x87,0x25,0x67, + 0xc1,0xc4,0x2a,0x67,0x93,0x6f,0x51,0x40,0xef,0x74,0x83,0xb3,0xec,0x37,0x8a,0x6c, + 0x36,0x84,0x8a,0xbe,0x23,0xb7,0xbe,0xce,0x3d,0x4d,0xb1,0x1e,0xfe,0xb4,0xdf,0xb2, + 0x8b,0xe9,0x50,0x90,0x0e,0xcf,0x88,0x48,0xdb,0xf8,0x9d,0x2d,0x92,0x6b,0xed,0xcd, + 0xcc,0xd7,0xba,0xa8,0xff,0x52,0xeb,0xef,0x8c,0xb9,0x24,0x27,0x70,0xf7,0xf0,0xf0, + 0xe2,0xce,0xa5,0xbd,0x23,0x6d,0xbe,0xca,0xe6,0x6c,0xaa,0xe8,0x55,0x3c,0x32,0x62, + 0x70,0x2d,0x77,0xbb,0xbb,0x77,0x66,0x2b,0xe0,0xcc,0x02,0xb8,0xe6,0x44,0x5b,0xd7, + 0x7a,0xd4,0xbc,0xd9,0x2b,0xf6,0x4d,0xcf,0x90,0xf3,0x10,0xb9,0xa5,0xd3,0x0b,0xfc, + 0xf5,0xbd,0xd2,0x22,0x43,0x9d,0xf4,0x13,0x7a,0xd5,0x19,0xb1,0x64,0x9d,0xf2,0xdd, + 0x5a,0x36,0x9c,0x36,0xdc,0x0b,0x66,0x12,0x00,0xba,0x7c,0x5f,0x4f,0xec,0x55,0x0c, + 0xf4,0xb8,0x90,0x94,0xab,0x9a,0xf4,0xd6,0x14,0x68,0x1d,0x26,0x14,0x4c,0x07,0xe1, + 0xf8,0x3f,0xd4,0xfc,0xca,0xec,0xed,0x49,0xa2,0xdc,0x6c,0x03,0x9a,0xfd,0xbe,0x21, + 0xbd,0x46,0x1f,0xea,0xf0,0x9c,0x3e,0x68,0xd4,0xd5,0x97,0xfc,0x66,0x3e,0x4c,0x00, + 0x74,0x3c,0x83,0x5f,0x67,0xd0,0x9f,0x48,0x8d,0x1f,0x3d,0x06,0x8b,0x29,0x6f,0x98, + 0x70,0xb6,0x98,0x02,0x0b,0x8a,0x20,0x63,0x9d,0xbf,0x57,0xc3,0x34,0x0e,0x43,0xc7, + 0x44,0xa8,0x92,0x0e,0x5d,0xc2,0x00,0xad,0x8c,0xc7,0x30,0x5b,0x67,0xfd,0x3d,0x4a, + 0xab,0x6a,0x92,0x6a,0x1e,0x9f,0xd1,0x24,0x0b,0xc6,0x3b,0x32,0x35,0x93,0x3c,0xe6, + 0xb7,0x42,0x2a,0xdb,0x01,0x08,0x59,0x11,0x7c,0x87,0x0e,0x42,0x15,0xb8,0xe3,0x72, + 0x57,0x25,0x9e,0x47,0x46,0x0e,0xab,0xc2,0x3a,0x05,0xf8,0x26,0x00,0x41,0x8f,0xed, + 0x45,0xa5,0x12,0xda,0xd6,0xe9,0x43,0x2a,0xf0,0xa2,0xe1,0x96,0x75,0x35,0x04,0x53, + 0x83,0x95,0xd5,0xe5,0x1e,0x58,0x97,0x34,0xf2,0xa0,0xc1,0xcc,0x47,0x22,0x1f,0xed, + 0x64,0x0a,0x88,0x35,0x4d,0x9e,0x55,0x55,0x33,0xc8,0x54,0x5f,0xee,0xf0,0x5c,0x73, + 0xe9,0xab,0x92,0x51,0x1a,0x5d,0xa2,0x65,0xb9,0xfd,0x91,0x9e,0xe8,0xd3,0xf2,0xb2, + 0xe6,0x44,0x75,0x34,0xa8,0x23,0x43,0x51,0xa7,0x73,0x61,0xf9,0xf7,0x29,0x06,0xbc, + 0x5b,0x91,0x3a,0x66,0xe1,0x8c,0x23,0xd0,0xa1,0x96,0x2d,0x56,0x5c,0x1d,0x25,0xe3, + 0x8a,0xb3,0xb7,0xfa,0x0d,0xb7,0x01,0x64,0xe3,0xfc,0x87,0x4f,0x17,0xf9,0xd9,0x5c, + 0xd5,0xd5,0xe2,0x63,0x42,0x4d,0xbd,0x25,0x44,0x7b,0x46,0x94,0x5b,0x08,0x64,0xc6, + 0x22,0xa2,0x02,0x30,0x83,0x30,0x97,0x4c,0xf5,0x16,0x43,0xbe,0x9f,0x80,0xd8,0xfb, + 0x16,0x4e,0x6a,0x22,0xb5,0x7b,0x03,0x7e,0x1a,0x01,0xe2,0xf0,0x9e,0xa1,0x37,0xf7, + 0xf4,0xb9,0x25,0x13,0x33,0x9b,0xa0,0xe7,0x1e,0x53,0x8a,0xe1,0x8a,0x68,0xf3,0x9e, + 0xe5,0x9a,0x7d,0x2c,0x64,0x16,0x4a,0x1a,0x28,0x22,0x05,0x62,0x0b,0x33,0x42,0x5f, + 0x69,0xcb,0x8f,0x0f,0x53,0x42,0xce,0x04,0x40,0x08,0xa2,0xcf,0x89,0x25,0x50,0x40, + 0x23,0x62,0x85,0x80,0x55,0x83,0x68,0xcd,0x0d,0x93,0xa0,0x70,0xf2,0x30,0xda,0x18, + 0xf3,0xb2,0x0f,0x58,0xb1,0x95,0x9a,0x15,0x2b,0x80,0x7a,0x45,0x1a,0x65,0x3d,0x89, + 0x52,0xa9,0x56,0xa1,0x27,0xb7,0xeb,0x06,0xd6,0x3f,0x9a,0x43,0x60,0x0e,0x35,0xf3, + 0x65,0x61,0xe4,0x0c,0xe0,0xbf,0x0e,0xf5,0xff,0x3f,0x63,0xf0,0x49,0x81,0x75,0xf5, + 0x5e,0x55,0x86,0xa1,0xfb,0xd7,0x7c,0x0a,0xa0,0x3e,0xc9,0x33,0x0e,0xb4,0xab,0x6d, + 0xbb,0x14,0x95,0x7a,0x43,0x59,0x6f,0xfe,0xf3,0xac,0xe9,0x14,0x10,0xda,0xc0,0x59, + 0x6a,0xb7,0xbb,0xab,0xff,0x82,0x1f,0xab,0xdc,0x5b,0x14,0x67,0xd9,0xa0,0x29,0xe6, + 0xec,0xf4,0x96,0x64,0x9a,0x6e,0xbd,0x67,0xb1,0x81,0x99,0x66,0x06,0xee,0xae,0x9c, + 0x81,0x14,0xa8,0xb6,0xd2,0xf7,0x9e,0xe5,0x5a,0xbd,0xb5,0xee,0xcb,0x64,0x63,0x61, + 0x6d,0x18,0x13,0x1b,0x64,0xbc,0x89,0xf6,0x9b,0xdf,0x8a,0xfc,0xb5,0xe3,0xef,0xde, + 0x7c,0x4f,0x21,0x43,0x14,0x93,0x32,0x5c,0x33,0x09,0x08,0x17,0xc9,0x11,0xb1,0xf0, + 0x7e,0xdb,0x5c,0xae,0x27,0x5d,0xe8,0xe8,0x98,0x31,0xb2,0x4a,0xd4,0x3f,0xb4,0x5d, + 0xf7,0xc3,0x01,0x65,0xa0,0x5a,0xae,0x4b,0xae,0xf9,0x37,0x81,0xba,0x2c,0xf2,0x7a, + 0xef,0x43,0xe7,0x8d,0x08,0xb7,0x05,0xab,0x98,0x8e,0x11,0xa1,0x7f,0xc5,0xc9,0xa4, + 0xfe,0x62,0x59,0x51,0x88,0xd5,0x84,0x93,0x49,0x37,0xe5,0x19,0x01,0x7d,0xfb,0xf0, + 0xa0,0xff,0xe6,0x67,0x30,0x0e,0x2a,0xa2,0x4d,0x67,0x39,0xf8,0x38,0x09,0x9f,0xe7, + 0x38,0xa8,0x1c,0xe3,0x40,0xfb,0x15,0xa2,0xfa,0xfd,0x60,0xcb,0xd9,0x8d,0x59,0x35, + 0x9f,0xab,0x87,0xf9,0x1c,0x7c,0x69,0xb6,0xf3,0xb8,0x8e,0x34,0x0c,0x08,0x6a,0x46, + 0xdd,0xe3,0xf2,0x94,0xb8,0x38,0xeb,0xb7,0x5b,0xad,0xb2,0x0b,0xc5,0x9b,0xcb,0x2a, + 0x6c,0x58,0x7b,0x81,0xdd,0x53,0xe6,0x4c,0x55,0x7f,0xa6,0x71,0x9d,0x0a,0xcd,0xa6, + 0xcf,0x1a,0x70,0xd3,0xbc,0x28,0xb0,0x5b,0xce,0xaf,0x7c,0x6a,0x82,0x8f,0xeb,0x54, + 0xd0,0x78,0xaf,0x82,0xc6,0xcd,0xe7,0x22,0x19,0x8b,0xe7,0x06,0x97,0x39,0x6c,0x9c, + 0xdb,0xad,0xbc,0x57,0x7d,0xfd,0x25,0x60,0x97,0xae,0xeb,0x55,0xf6,0xdb,0x0e,0x05, + 0xd5,0xf4,0xd5,0xe1,0xc0,0x98,0x90,0x17,0x54,0xc7,0x30,0x77,0x8d,0xb5,0x9a,0xad, + 0x95,0xe7,0xcc,0x60,0xea,0x40,0xef,0x57,0xd3,0x13,0xf0,0x6b,0xcf,0xea,0x6f,0x4d, + 0x32,0x56,0xc7,0xfd,0x6c,0xea,0x7e,0xd1,0xf8,0x70,0x43,0x22,0xe8,0x63,0x99,0x6b, + 0xe0,0xb3,0x9a,0x7b,0xd0,0x6b,0xf3,0x9f,0x93,0x7c,0xe0,0xac,0x03,0x4f,0x52,0xef, + 0xa1,0xef,0x3e,0x91,0x6d,0x28,0xed,0xce,0xe6,0x77,0x62,0x0b,0x28,0x59,0x98,0x27, + 0x08,0x8a,0x79,0xc7,0x69,0xdd,0xe4,0x58,0xbd,0x47,0x2c,0xc2,0x5d,0x35,0x01,0x70, + 0xed,0x11,0x10,0xa5,0x14,0x5c,0x9e,0x83,0xd6,0x8a,0xd3,0xcd,0x23,0x30,0x46,0x5c, + 0x06,0x2c,0xf1,0x51,0x5e,0x1f,0xd1,0x62,0x7c,0xab,0x84,0xbc,0x83,0x36,0x84,0xf7, + 0x65,0x57,0x1c,0x5a,0x7a,0x79,0xd6,0x59,0x04,0x37,0x51,0xcc,0x7e,0x93,0x12,0xf6, + 0x7c,0x16,0x35,0x4f,0x1b,0x98,0x24,0x95,0x8e,0xfe,0x69,0x23,0xbe,0x0a,0x9a,0x81, + 0xe2,0x94,0x77,0xa3,0x0f,0xf8,0x99,0xc9,0x56,0x11,0x34,0x4c,0xd7,0x2a,0x64,0x76, + 0xaa,0x1c,0x28,0xf2,0x03,0x8f,0xe5,0x62,0x56,0xad,0x48,0xc5,0xc6,0x3f,0x2a,0xdc, + 0xb9,0x18,0x57,0x55,0xac,0x9a,0x85,0xa0,0xc3,0x6b,0xff,0x94,0xc3,0x11,0x6d,0x15, + 0x5b,0x62,0x30,0x55,0x2b,0xc7,0x78,0xc0,0xd1,0x20,0x0f,0xa7,0x39,0xad,0x40,0x48, + 0x35,0x94,0x37,0xde,0xf0,0x3e,0xe7,0x17,0x75,0xa4,0x77,0xb9,0x8b,0x93,0xe7,0x26, + 0x85,0x6b,0xf4,0x91,0xb0,0x98,0xd6,0x53,0x0e,0x90,0xc1,0x08,0xff,0x9f,0x84,0x47, + 0x91,0x3b,0xbf,0xa4,0xdf,0x20,0x56,0x52,0xfa,0x96,0x3a,0x1a,0xc0,0xa0,0x03,0x5d, + 0xf0,0x16,0xa5,0x39,0x7a,0x44,0xf1,0x3c,0xe0,0x05,0xa8,0x71,0x77,0x3e,0xb7,0x9c, + 0xb6,0xd3,0x71,0xf6,0xbf,0x6c,0x7e,0x24,0x38,0xf0,0xef,0x0a,0x48,0x5b,0xb5,0x43, + 0x28,0xa6,0x59,0xe7,0xe0,0xb7,0xc2,0xd9,0x15,0x9b,0x88,0x7a,0x4b,0x67,0x9d,0xed, + 0x5b,0x0c,0x27,0xba,0x5b,0x33,0xf0,0x9a,0xa7,0xeb,0x5c,0xd6,0x00,0x77,0x2b,0x42, + 0xde,0x1a,0xf9,0xe4,0x36,0xb8,0x88,0x7d,0x72,0xeb,0xb9,0x1a,0xf9,0xcc,0xaa,0x91, + 0xcf,0xaa,0xe9,0xf8,0x6c,0x25,0x10,0x45,0x10,0xb8,0xd7,0xb6,0xbf,0xf4,0x67,0x08, + 0xef,0x1f,0xa7,0x6c,0x0d,0xbc,0x9a,0xcd,0x20,0xde,0x37,0xe4,0x13,0x2c,0xf5,0xbf, + 0xfe,0xeb,0xbf,0x09,0x3c,0xfe,0xd7,0x7f,0xb7,0xc5,0x7f,0x52,0x9a,0xe7,0xc7,0x3c, + 0xc1,0x6e,0x0e,0x34,0xe5,0x2f,0x9c,0x19,0x29,0xeb,0x6d,0xa4,0xdc,0xf3,0x4c,0x3b, + 0xd4,0xb4,0x12,0xe4,0xd0,0x14,0xcc,0x74,0xea,0x7e,0x90,0x96,0x51,0x65,0x2a,0x67, + 0xfd,0x6d,0xc7,0x22,0x4c,0x08,0xb9,0x79,0x5c,0x02,0xad,0x4f,0x5b,0x67,0x16,0xbd, + 0xd1,0xac,0xd3,0xc1,0xf4,0x5e,0x75,0x7e,0xd6,0x62,0x25,0x28,0xcf,0xb7,0xab,0x9a, + 0x0a,0x00,0x78,0x98,0x9d,0xf1,0xbb,0x7c,0x00,0x44,0x18,0x7e,0xf3,0x23,0xed,0x8f, + 0x9f,0xcf,0xf0,0x5d,0x9a,0x39,0x5c,0x3c,0xc6,0xf9,0xca,0xd1,0x96,0x3c,0xf5,0x58, + 0x39,0x39,0xa0,0xdf,0x2a,0xdf,0x6a,0x4b,0x97,0x9b,0x49,0x81,0xad,0x04,0x94,0x03, + 0xaf,0xe6,0x0c,0x56,0xad,0x5f,0x25,0x43,0x00,0x85,0x38,0x68,0x1d,0xf0,0xa6,0x7c, + 0xfe,0xe2,0x8b,0xd9,0xe5,0xca,0x62,0x36,0x79,0x65,0x92,0xd4,0x2a,0x8d,0x5e,0x41, + 0xea,0x6a,0xa2,0x20,0x7f,0xcb,0xfd,0xb9,0x29,0xcd,0xca,0x42,0x37,0xda,0x45,0x5a, + 0xd4,0xbc,0xaa,0xfe,0x37,0x74,0xa2,0xfb,0xd8,0xf9,0x5c,0xd8,0x16,0xfe,0xde,0x7e, + 0xbd,0x38,0xd0,0x0a,0x5d,0x4b,0xef,0xaf,0x79,0x85,0xe3,0xf4,0x0d,0x9e,0x58,0x1b, + 0x9f,0x4b,0xa3,0x50,0x13,0x48,0x07,0xdd,0xac,0x1e,0x95,0xac,0xef,0xb7,0x38,0x3d, + 0x5e,0x9c,0xb2,0xac,0x73,0x9a,0x0d,0x25,0x95,0x6f,0x99,0x37,0xf9,0x4b,0x0b,0x27, + 0x4d,0xfd,0xdf,0x6a,0xf8,0x7f,0x43,0xda,0xe8,0xcd,0xbc,0x61,0x00,0x00, }; constexpr size_t HOME_INDEX_HTML_GZ_LEN = sizeof(HOME_INDEX_HTML_GZ); // diff --git a/firmware/patternflow/src/knobs_index.h b/firmware/patternflow/src/knobs_index.h index a87cf8dc..eebcfb16 100644 --- a/firmware/patternflow/src/knobs_index.h +++ b/firmware/patternflow/src/knobs_index.h @@ -12,97 +12,74 @@ static const char KNOBS_INDEX_HTML[] PROGMEM = R"HTML( - + Patternflow - Knobs
        -

        Knobs

        -
        -
        -

        Direction and click size

        - - - -
        PositionDirectionEdges per click
        -
        - - -
        -
        -

        Turn a knob clockwise. Its position should go up by one per click. - Goes down: set that knob to Reversed. Moves two per click, or needs two clicks to - move one: change Edges per click until one click is one step (most encoders are 4; - the edge counter under the position shows how many one click really makes). - These are properties of the encoder soldered in, stored on the device — nothing to - rebuild, and a saved change does not move the knob.

        -
        - +.pf-offline .pos,.pf-offline #st{opacity:.5} + +
        +

        Knobs

        -
        +

        Turn a knob one click clockwise: its position should go up by one.

        + + + +
        PositionDirectionEdges per click
        +
        + + +
        +

        Goes down: set it to Reversed. Moves two, or takes two clicks to move one: +change edges per click (most encoders are 4; the edge count under the position shows how many one click makes). +Saved on the panel: nothing to rebuild, and saving does not move a knob.

        + +
        )HTML"; // GENERATED by firmware/toolchain/console_pages.py build — do not edit. -// gzip -9 of KNOBS_INDEX_HTML (8285 bytes → 3566 bytes), served with Content-Encoding: gzip. +// gzip -9 of KNOBS_INDEX_HTML (7946 bytes → 3517 bytes), served with Content-Encoding: gzip. static const uint8_t KNOBS_INDEX_HTML_GZ[] PROGMEM = { - 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xa5,0x5a,0x7d,0x73,0xdb,0xb8, - 0xf1,0xfe,0x5f,0x9f,0x02,0x51,0xfa,0x33,0xc5,0x33,0x45,0xbd,0xc4,0x49,0x1c,0x52, - 0x54,0xda,0xbc,0x5d,0xaf,0xb9,0x5c,0x33,0x71,0x3a,0x9d,0xc9,0xcd,0xcd,0x6f,0x20, - 0x11,0x94,0x78,0xa6,0x08,0x0e,0x01,0x5a,0x71,0x65,0xcd,0xf4,0x43,0xf4,0x13,0xf6, - 0x93,0xf4,0x59,0x80,0xa4,0x68,0xd9,0x79,0xe9,0x34,0x33,0xb6,0x49,0x60,0xb1,0x58, - 0x3c,0xfb,0xec,0x62,0x01,0x66,0xf6,0x20,0x96,0x4b,0x7d,0x5d,0x08,0xb6,0xd6,0x9b, - 0x6c,0xde,0x9b,0xd1,0x1f,0x96,0xf1,0x7c,0x15,0xf5,0x45,0xde,0xa7,0x06,0xc1,0xe3, - 0xf9,0x6c,0x23,0x34,0x67,0xcb,0x35,0x2f,0x95,0xd0,0x51,0xbf,0xd2,0xc9,0xf0,0x9c, - 0x3a,0xd5,0xb2,0x4c,0x0b,0xcd,0x54,0xb9,0x8c,0xfa,0xa3,0x22,0x19,0x2e,0x65,0xae, - 0x64,0x26,0xfc,0xdf,0xd5,0xf3,0x75,0x14,0x8f,0xa7,0x8b,0x47,0x8f,0xa6,0xd3,0xfe, - 0x7c,0x36,0xb2,0x82,0xf3,0x7a,0xc0,0x3c,0x4d,0x06,0x0f,0xb6,0x69,0x1e,0xcb,0xad, - 0xff,0xfe,0x8d,0x3b,0x48,0xaa,0x7c,0xa9,0x53,0x99,0x0f,0xdc,0xdd,0x15,0x2f,0xd9, - 0xdf,0x23,0xdb,0xe7,0xfd,0x2d,0x72,0x46,0xbc,0x48,0x47,0x4a,0x73,0x5d,0x29,0xc7, - 0xfb,0x39,0xfa,0xf5,0x37,0xef,0x5d,0x34,0x15,0xcf,0xbc,0x0b,0xef,0x93,0xf7,0x3e, - 0xfa,0x3b,0x86,0x47,0x3b,0xea,0x16,0x81,0x93,0xa5,0x57,0xc2,0xf1,0xe2,0xb4,0xd4, - 0xd7,0xc1,0x83,0x89,0x77,0x15,0xe4,0x55,0x96,0x79,0x2b,0xa1,0x83,0x1f,0xbd,0x34, - 0x4f,0xb2,0x74,0xb5,0xd6,0xc1,0x2f,0xd5,0x66,0x21,0x4a,0x6f,0x2d,0xb3,0x38,0xf8, - 0xeb,0xe2,0x77,0xb1,0xd4,0x9e,0xe2,0xd7,0x41,0x6b,0x81,0xf6,0x2e,0x3d,0xe1,0xee, - 0xc4,0xc9,0xc9,0x40,0xf8,0x5a,0x7c,0xd6,0x2f,0x65,0xae,0x45,0xae,0x23,0xed,0xee, - 0xbd,0x45,0xa5,0x3a,0xa2,0x0b,0xaf,0x70,0x77,0xcd,0x1b,0x4b,0x60,0xfc,0xc2,0x8f, - 0x53,0xc5,0x17,0x99,0x88,0xa3,0x07,0x93,0x7d,0xf7,0x6d,0x1c,0x16,0xbe,0x5e,0x8b, - 0x7c,0x90,0x78,0x89,0x1b,0x96,0x42,0x57,0x65,0xce,0x8a,0xbd,0x57,0xc8,0x2c,0x3b, - 0x68,0x54,0xde,0xc6,0x5b,0x7a,0xd2,0xa2,0xa0,0xbd,0xc4,0x5b,0x45,0x93,0xb0,0x9d, - 0xe1,0x03,0x66,0x58,0x9d,0x9c,0x3c,0x48,0x60,0x5b,0x12,0x4d,0xbc,0x65,0x26,0x78, - 0xf9,0x31,0xdd,0x08,0x59,0xe9,0x81,0x76,0xbd,0x81,0xf2,0x97,0x3c,0xcb,0x9e,0xab, - 0x81,0x1b,0xfc,0x38,0x50,0xae,0x5b,0xcf,0xd8,0x68,0x8f,0xdd,0xdd,0x72,0x10,0x7b, - 0x84,0x0a,0xd6,0xd2,0x36,0x0b,0x6a,0x36,0x50,0x09,0x77,0x5f,0x8f,0x79,0xeb,0xbd, - 0x75,0xdd,0x7d,0x3b,0xf3,0x5b,0xcc,0x9c,0x44,0xe3,0xf0,0x68,0xc6,0x10,0xd6,0x0c, - 0x74,0x04,0x4a,0x34,0x6d,0x1f,0xbc,0x0d,0xc6,0xc9,0x93,0x13,0xe9,0x27,0x69,0xa9, - 0x74,0x14,0x01,0x88,0xe7,0x18,0x1e,0xc0,0xf8,0x7a,0xd9,0x70,0x97,0x2c,0x82,0x8e, - 0xcb,0x57,0x77,0x35,0xef,0x3d,0x28,0x3d,0xc8,0xe4,0xee,0x6e,0x13,0xe5,0x61,0x72, - 0x73,0x03,0x55,0x7b,0x2f,0x97,0xdb,0xe0,0xc3,0x1e,0x32,0x86,0x16,0x07,0xb1,0x25, - 0x56,0x72,0x72,0xf2,0xb3,0x5f,0x54,0x6a,0x8d,0x97,0xf0,0xe2,0x39,0x5e,0x97,0x83, - 0x0b,0x37,0xf8,0xf4,0xfc,0x93,0x8f,0x51,0xb0,0xe3,0x53,0xf4,0xde,0x27,0xd0,0x07, - 0x7f,0xf3,0xde,0x79,0xaf,0xa0,0x6c,0xcb,0xf5,0x72,0x7d,0x71,0xa4,0x69,0xe3,0xee, - 0xde,0xfb,0x56,0x3d,0xec,0xfe,0xe4,0xc3,0x9a,0xc1,0xbb,0xe8,0x1d,0xd7,0x6b,0x7f, - 0x93,0xa2,0xdb,0x7b,0xe7,0x9a,0xa1,0xa9,0x7e,0x23,0xcb,0x57,0xe2,0x2a,0x5d,0x8a, - 0xc3,0x60,0xf8,0x4f,0x46,0xf2,0xe6,0x66,0xb7,0x6f,0x1c,0x9d,0x8b,0x2d,0x7b,0x5f, - 0xca,0x4d,0xaa,0xc4,0xc1,0x1d,0xd7,0x5e,0x6e,0x1d,0xbd,0x3e,0x98,0x34,0x15,0x8f, - 0x0e,0x8e,0x51,0xee,0x4e,0xc1,0xdd,0x03,0xe9,0x2f,0xaa,0x34,0x8b,0x4f,0x4e,0x94, - 0x7d,0x88,0xa2,0xba,0xc5,0x05,0xfc,0x6b,0x9f,0xe0,0x1c,0xb8,0xde,0x35,0x79,0x7c, - 0xef,0x86,0x1d,0x6f,0x74,0x30,0x6e,0xc4,0xc2,0x7c,0xf0,0xba,0x2c,0x65,0x39,0x70, - 0xb4,0x15,0x72,0x68,0x21,0xd2,0xaf,0xdf,0x6e,0x6e,0x9e,0x89,0x33,0x68,0xd9,0xef, - 0x0f,0xb4,0xfb,0x71,0x50,0x11,0x25,0xeb,0xa5,0x24,0x02,0x70,0x99,0x96,0x23,0x76, - 0x95,0xee,0x8e,0xa2,0xba,0xf4,0xe5,0xa5,0xab,0xd7,0xa5,0xdc,0x32,0x3b,0x51,0x59, - 0xe3,0xd8,0xb2,0xde,0xb0,0x83,0x22,0xeb,0x79,0x69,0xfe,0xc0,0x29,0x25,0x12,0x06, - 0x99,0xb9,0xef,0x70,0xee,0x15,0xad,0x1f,0x1a,0xf1,0xfb,0x02,0x71,0x5e,0x24,0xd6, - 0x47,0x91,0x0a,0x7f,0xf6,0x13,0x59,0xbe,0xe6,0x30,0xa3,0x9d,0x3c,0x01,0x3f,0x21, - 0x49,0x86,0xef,0xdd,0x81,0xdb,0xe6,0x9b,0x9e,0x4d,0x5c,0x39,0xdf,0x88,0xa8,0x7f, - 0x95,0x8a,0x6d,0x21,0x4b,0xdd,0x67,0xcb,0x3a,0xa6,0xfb,0xdb,0x34,0xd6,0x48,0x54, - 0xc6,0x81,0x43,0xf3,0x82,0x4c,0x91,0xea,0x94,0x67,0x43,0x85,0x58,0x12,0xd1,0x84, - 0xb2,0x9c,0x4e,0x75,0x26,0xe6,0xef,0xb9,0xd6,0xa2,0x44,0x1e,0xc1,0xd2,0x86,0xec, - 0x6d,0x2e,0x17,0x6a,0x36,0xb2,0x5d,0x48,0x84,0xfa,0x9a,0xfe,0x8e,0x7e,0x60,0xaf, - 0x78,0x79,0xc9,0xd2,0x5c,0xe9,0xb2,0xda,0x60,0x0e,0xa6,0xe5,0xa5,0xc8,0x15,0xfb, - 0xf7,0x3f,0xff,0xc5,0x94,0x10,0xac,0xb0,0x5a,0xd4,0xff,0x23,0xc3,0x89,0xcf,0xfe, - 0x9a,0x61,0x2d,0x0c,0x48,0xb2,0x5c,0x6a,0xe1,0xb3,0x1f,0x46,0xbd,0xa0,0x94,0x52, - 0xef,0x86,0xc3,0x65,0x29,0xf8,0x26,0x78,0x38,0x7e,0x39,0x7e,0x31,0x7e,0x16,0x0e, - 0x87,0x69,0x7e,0x19,0x3c,0x7c,0xfd,0xea,0xf5,0xd3,0x57,0x2f,0xf0,0xb6,0xa9,0xb4, - 0x88,0x83,0x87,0xe7,0x7f,0x3a,0x9f,0x3e,0x9d,0xe2,0x3d,0xe1,0x69,0xae,0x83,0x87, - 0x8f,0xff,0xf4,0xf8,0xf1,0xd9,0x93,0xb0,0x37,0x1c,0x96,0x55,0x26,0x82,0x87,0xd3, - 0xb3,0xe9,0x64,0x72,0x1e,0xda,0xd7,0xa1,0x92,0x09,0x64,0x26,0x2f,0x26,0xcf,0x26, - 0x67,0x68,0xcb,0x48,0xc3,0x9b,0x37,0x8f,0x5f,0x4e,0x5f,0xe3,0x4d,0x42,0xfd,0xe3, - 0xa7,0x2f,0xce,0x9f,0xbe,0xc1,0x4b,0xc1,0x73,0x91,0x41,0xf4,0xd1,0x64,0x32,0x19, - 0x93,0x3a,0xc5,0x73,0x15,0x38,0x3f,0x01,0xb7,0xd2,0xf1,0xaa,0xd4,0xbc,0x0f,0x95, - 0x28,0xd3,0xc4,0x53,0xd7,0x4a,0x8b,0xcd,0xb0,0x4a,0xbd,0x43,0x23,0x0d,0xd9,0xc8, - 0x5c,0x06,0xce,0x5f,0x84,0x7e,0x51,0xc2,0x38,0xc5,0xde,0xe1,0xdd,0x8c,0xa5,0x0e, - 0x55,0xf0,0xa5,0xf0,0x2e,0xde,0x50,0xe3,0xf0,0x83,0x58,0x55,0x19,0x2f,0xbd,0x77, - 0x22,0xcf,0xa4,0xd7,0x76,0xef,0x7b,0x3f,0xec,0x16,0xf2,0xf3,0x50,0xa5,0xff,0x48, - 0xf3,0x55,0xb0,0x90,0x65,0x2c,0xca,0x21,0x5a,0xf6,0xbd,0x85,0x8c,0xaf,0x77,0x1b, - 0x5e,0xae,0xd2,0x3c,0x18,0x87,0x0b,0xbe,0xbc,0x5c,0x95,0xb2,0xca,0xe3,0x00,0x01, - 0x35,0xa8,0xb1,0x73,0xc3,0xa5,0xcc,0x64,0x59,0x37,0x01,0x3e,0x37,0x4c,0xe0,0x78, - 0x40,0xb5,0x49,0xb3,0xeb,0xba,0x99,0x4c,0x76,0xc3,0x5e,0x96,0xe6,0x62,0xb8,0x16, - 0x66,0x8b,0x98,0xf8,0x8f,0xc3,0xe1,0x56,0x2c,0x2e,0x53,0xc8,0xd2,0x00,0xb5,0x81, - 0x47,0xd6,0x64,0x02,0xcf,0x89,0x1b,0x29,0x57,0x22,0xde,0xf7,0xfc,0x6d,0xc9,0x0b, - 0x18,0xf1,0xd9,0x32,0x27,0x78,0x72,0x3e,0x2e,0x3e,0x87,0x8d,0x51,0x8c,0x57,0x5a, - 0x86,0x05,0x8f,0x63,0x1a,0xf8,0x68,0x5a,0x7c,0x66,0x53,0xf4,0xb3,0x27,0x67,0x05, - 0xec,0xa7,0x5d,0x55,0x94,0x3b,0x6c,0x10,0x45,0x46,0xdb,0x4f,0x26,0x3e,0x87,0x50, - 0xbc,0xca,0x87,0x29,0xb0,0x54,0xc1,0x52,0x10,0xd2,0xe1,0x8a,0x17,0xc1,0x39,0x94, - 0xd6,0x6a,0xb0,0x76,0xad,0xe5,0x26,0x98,0x40,0x5b,0xd8,0x6b,0xf1,0xb0,0x6d,0xd0, - 0x8d,0xbd,0x37,0x8d,0x99,0x5d,0x18,0x39,0xdc,0x85,0x91,0x31,0xc8,0x64,0xed,0x7b, - 0x8a,0x41,0xf5,0x12,0xe9,0xf1,0x0e,0x68,0xa0,0x83,0x1b,0xd6,0x4a,0x4b,0x1e,0xa7, - 0x48,0x88,0x13,0x63,0xeb,0x64,0x67,0x61,0x48,0xff,0x21,0x82,0xc9,0x63,0x0c,0x35, - 0xaf,0x5b,0xab,0xea,0xc9,0x78,0xdc,0xae,0x39,0xa4,0x75,0x04,0x13,0xcc,0xaa,0xaa, - 0xc5,0xee,0x2e,0xd8,0xe4,0xd9,0xda,0x09,0x56,0x19,0xf4,0xdf,0x72,0x92,0x61,0x31, - 0xac,0x56,0xc2,0xc4,0x75,0xed,0xe1,0x21,0x6d,0x18,0xd3,0x27,0xc6,0x96,0xe9,0xee, - 0x68,0xf8,0xb1,0x2d,0x99,0xa0,0x00,0x1b,0x12,0x81,0x08,0x78,0x7f,0xfc,0x4c,0x6c, - 0x42,0xca,0x33,0x43,0x5d,0xc2,0xd7,0x08,0xb7,0x4d,0x50,0x15,0x85,0x28,0x97,0xf0, - 0x62,0xd8,0xeb,0xce,0x6e,0x62,0xca,0x3d,0x78,0x70,0xcc,0xce,0x69,0x4e,0x4d,0x7b, - 0x78,0x8d,0xe1,0x64,0x3c,0xfe,0xbf,0x06,0x23,0x0c,0xcd,0x78,0xa1,0x44,0xd0,0x3c, - 0x34,0x1d,0x64,0xee,0x7d,0xee,0x30,0xf1,0x87,0xd5,0xe9,0xf5,0x7f,0xbd,0x88,0x27, - 0xdf,0xbd,0x08,0x0b,0xa1,0x15,0x36,0x8c,0x0a,0x32,0x91,0xe8,0x96,0x88,0x4f,0x88, - 0x87,0x66,0x55,0xf1,0xae,0x69,0x7b,0x66,0xdb,0xc2,0x6f,0x13,0xca,0xae,0xa0,0xeb, - 0xc1,0x47,0x18,0x77,0x25,0x4a,0x9d,0x22,0x5d,0xd6,0xf3,0x6d,0xd2,0x38,0xce,0x04, - 0xcd,0xe0,0x5f,0x7e,0x0f,0x09,0xa6,0x47,0x24,0xa8,0xdd,0x60,0x01,0x7f,0x74,0x66, - 0x8d,0xc5,0x0e,0xa9,0xbe,0x47,0x19,0xd1,0xd3,0x8e,0x7c,0x36,0x3e,0x8c,0x64,0x6a, - 0x83,0xca,0xa8,0x0d,0xb7,0x45,0x26,0x97,0x97,0xdd,0x51,0xe3,0x2f,0xf2,0x30,0x03, - 0x13,0xcd,0xbc,0x41,0x9a,0xaf,0x91,0xd9,0x74,0xf8,0x9d,0x2b,0x6a,0xc0,0x85,0x41, - 0x44,0x23,0x84,0xeb,0x71,0xbc,0x99,0x1c,0x7b,0x4f,0x92,0xb2,0x6e,0xb8,0x3f,0xa0, - 0x8f,0xe2,0x73,0xda,0xae,0x96,0x88,0xd9,0xd8,0x1b,0x24,0x72,0x59,0xa9,0x1d,0xf6, - 0x73,0x4a,0x6b,0x41,0x2e,0x73,0xd1,0xe1,0x6c,0x3b,0x19,0xc5,0x7b,0x33,0xc4,0x37, - 0x65,0xf3,0xee,0x8b,0x52,0x3e,0x37,0x01,0xa9,0x6e,0x67,0xac,0x26,0x3d,0xdd,0x93, - 0xb9,0x3a,0x91,0x3b,0x31,0x2e,0x5c,0x54,0x60,0x55,0x7e,0x1b,0xca,0x65,0x55,0x2a, - 0x4c,0x54,0xc8,0x94,0xc6,0x34,0x32,0x7e,0x51,0xa6,0x18,0x0e,0x6b,0x8e,0x11,0x33, - 0xf0,0x74,0x8d,0xab,0xf3,0xfc,0x17,0x10,0x33,0xe2,0xbd,0xbb,0x88,0x35,0xae,0x41, - 0x16,0x64,0x93,0x27,0x4d,0xf8,0xb5,0x7c,0x3e,0xb6,0x23,0x58,0x4b,0x30,0x7c,0xf7, - 0xd5,0x7c,0x79,0x17,0xb1,0x23,0x1d,0xcd,0x51,0x60,0x27,0x29,0xa6,0x71,0x42,0xf1, - 0xcf,0x9a,0xe5,0xc7,0x22,0xe1,0x55,0xa6,0xdb,0x21,0x48,0x7e,0x32,0x8f,0x09,0x80, - 0xa3,0x38,0xbb,0xcb,0x94,0x83,0x49,0xc6,0xc9,0xbd,0xff,0x92,0x3a,0xc7,0x40,0xdc, - 0x35,0xa1,0x59,0xfb,0xfd,0xab,0x0c,0xef,0x2e,0xfb,0xe1,0x46,0xad,0xba,0x69,0xdb, - 0xc4,0xc2,0x77,0xee,0x04,0x28,0xad,0xdb,0x3d,0xd8,0x58,0x43,0xca,0x50,0xf9,0x0d, - 0x45,0x59,0xee,0xee,0x4c,0xd5,0x74,0xca,0xcb,0x5b,0x7d,0x28,0x3f,0xf7,0x54,0x87, - 0xc9,0x24,0x31,0xec,0x37,0xc5,0xd5,0x12,0x05,0xe9,0x46,0x38,0x0a,0x0f,0x69,0xc1, - 0x70,0xe0,0x43,0x46,0x90,0xa1,0xe9,0x02,0x83,0x62,0x44,0x0a,0x8b,0xd3,0x8d,0xa2, - 0xf2,0x8b,0x0e,0xc0,0x46,0xad,0x1d,0xcf,0x6c,0x02,0xf1,0x8e,0x9b,0x1f,0x2a,0xdd, - 0x71,0xe5,0xbe,0xf7,0xc7,0x8d,0x88,0x53,0x3e,0xa8,0xa9,0x8c,0x2d,0x81,0x8e,0xca, - 0xee,0xae,0x89,0x1b,0x56,0xd3,0x1f,0xaa,0x52,0x6a,0x08,0x4a,0x91,0x71,0x8d,0x03, - 0xeb,0x21,0xb4,0x6a,0x91,0x20,0xe0,0x09,0x34,0xec,0xea,0x1a,0x35,0xe8,0xf7,0xc3, - 0x76,0x10,0x5f,0xc0,0xab,0xc8,0x8e,0x21,0xca,0x29,0x9c,0x8f,0x86,0x94,0xcc,0xc7, - 0x7b,0xa8,0xa0,0xe2,0x71,0xf7,0x95,0x94,0x5a,0x6f,0x0a,0xf5,0xce,0x76,0x4e,0xc3, - 0x18,0x76,0x99,0x5b,0x45,0xcf,0xd9,0xe3,0x5a,0x11,0x5b,0xec,0xee,0x49,0xc7,0x47, - 0x5b,0xd4,0xbe,0x97,0xa0,0x28,0x82,0x9d,0x1d,0x5f,0x3f,0xea,0x70,0xea,0xe0,0xfc, - 0x6f,0x6c,0x8a,0x88,0xd0,0xff,0xa1,0x50,0xe0,0xf7,0x98,0xba,0xef,0xa1,0xfe,0x37, - 0xf5,0xf8,0x6c,0x64,0x6f,0x2f,0xa8,0x5a,0x9c,0xcf,0xe2,0xf4,0x8a,0x2d,0x33,0xae, - 0x14,0xea,0x7e,0x54,0x6e,0xcd,0xe5,0x86,0x28,0xe7,0x33,0x6c,0xb4,0x79,0xd3,0x87, - 0x82,0xc9,0xdc,0x58,0xa0,0x69,0x3e,0x5b,0x4f,0xe6,0x75,0xa5,0x8f,0xa7,0x5b,0x62, - 0xa8,0x70,0xfa,0x2c,0x8d,0xf1,0x00,0xf1,0x61,0x23,0x3f,0xaa,0x35,0xe2,0x44,0x60, - 0x4b,0x98,0x79,0x8f,0xb1,0xd9,0x7a,0x3a,0x7f,0x95,0x96,0xb6,0x81,0xf1,0x3c,0x86, - 0x8e,0x74,0x79,0xc9,0x68,0x69,0x18,0x31,0x35,0x32,0xa6,0xca,0xa0,0x27,0x7a,0xb6, - 0x66,0x6b,0x58,0xa6,0xd7,0x50,0x4a,0xbf,0xf0,0xf3,0xbe,0xe6,0x41,0xdb,0xd0,0x2a, - 0x6d,0x5b,0x5e,0xc7,0x2b,0xa1,0x18,0x0a,0x03,0x3b,0x85,0x6d,0x1f,0x91,0xa2,0x91, - 0x55,0x5a,0x4f,0x40,0x88,0x18,0xeb,0x71,0x50,0x53,0xb4,0x5c,0xd3,0x62,0x0c,0x19, - 0xb5,0x96,0x74,0x11,0xab,0x49,0xda,0xaf,0x15,0x58,0xae,0x36,0x9d,0x75,0x92,0xeb, - 0x33,0xba,0x49,0x8a,0xfa,0xb6,0xb3,0x46,0x87,0x5f,0x89,0x3e,0x6b,0xb2,0xdf,0xfc, - 0x02,0xaf,0xb3,0x91,0x15,0xb8,0x57,0x55,0x9b,0x79,0xee,0x53,0x56,0x0a,0x2a,0x35, - 0x3a,0xea,0x3e,0x98,0x86,0xae,0xc2,0xd9,0x08,0x46,0xb7,0xc6,0xd3,0x20,0xa4,0x09, - 0x5a,0x60,0xd3,0x5c,0x34,0x33,0x11,0xd5,0xd1,0xb1,0x98,0x7f,0xa4,0x53,0x29,0x67, - 0x97,0xf0,0x33,0xfa,0x50,0x19,0x6c,0x71,0x4e,0xf7,0xa1,0x74,0xce,0x7e,0xd2,0x00, - 0xb3,0x46,0x9d,0xa9,0xb5,0xac,0xb2,0x98,0xad,0x24,0xab,0x0a,0xb6,0xb8,0x66,0xc8, - 0xb8,0x07,0xa4,0x7d,0xe8,0xfe,0x51,0x02,0xfb,0x58,0x6e,0xf3,0x00,0x47,0x3d,0x9c, - 0xfc,0xd6,0x5c,0x5b,0xad,0x5a,0xb2,0x99,0xd8,0x58,0x6b,0x71,0x74,0x98,0x8d,0xf0, - 0xe2,0xe3,0x3c,0x74,0x05,0x79,0xbd,0x95,0x07,0x2d,0x1e,0xc3,0x69,0x30,0x17,0x22, - 0xb6,0xed,0xa6,0x0d,0x8f,0x12,0xca,0x37,0x90,0xa6,0x29,0x03,0xba,0x86,0xcb,0x57, - 0xc2,0x68,0xbc,0xe3,0x6e,0xb4,0xb1,0x0a,0x87,0x94,0xcc,0x58,0x67,0x69,0x96,0x2a, - 0xf3,0x82,0x43,0x5a,0xc1,0x06,0x1b,0xa9,0x34,0x13,0xf9,0x52,0x82,0xa5,0x8a,0xf1, - 0x52,0xb0,0xb3,0x10,0xda,0x29,0x13,0x0a,0x28,0xc3,0xd1,0xb8,0xa2,0x04,0x06,0x25, - 0x10,0x30,0xcd,0xdd,0xf5,0x6f,0x15,0xc3,0x2f,0xb6,0xe1,0xf9,0x75,0x67,0x02,0xa4, - 0xd0,0x2c,0xbb,0x46,0xeb,0xa5,0x50,0x2e,0x01,0xf1,0x71,0x2d,0x94,0x30,0xca,0x8b, - 0x52,0x16,0x54,0x1d,0xc2,0x4a,0x99,0xd8,0x59,0xec,0xdc,0x94,0x07,0xf0,0x47,0xc4, - 0x38,0x2b,0x7b,0xb0,0x4d,0xd2,0x23,0x26,0x21,0x11,0x7b,0x1e,0x67,0x27,0x9b,0x98, - 0xab,0x75,0x48,0x27,0x63,0x3a,0x7c,0x59,0x18,0x4a,0x61,0xae,0x3e,0x3c,0x13,0x46, - 0x9c,0x11,0xbd,0xe2,0x06,0x91,0x98,0xf0,0x87,0xb4,0xc5,0x8a,0x34,0x11,0xfa,0xf0, - 0x64,0x31,0xa7,0x94,0xd0,0x04,0xe4,0xcc,0x66,0xae,0xf9,0x8c,0xb3,0x75,0x29,0x92, - 0xa8,0x3f,0xea,0xcf,0xff,0x8c,0xed,0x61,0x36,0xe2,0x73,0x4c,0x8a,0xea,0x55,0xea, - 0x90,0x1d,0x7a,0xed,0xfd,0x45,0x7f,0x6e,0x2f,0x20,0x48,0x6a,0x36,0xaa,0x55,0xf4, - 0x6a,0x5e,0x35,0xf7,0x9a,0xbd,0xf6,0xfa,0xe2,0x0f,0x83,0xb4,0xbd,0x33,0x89,0x51, - 0x8e,0xd1,0x5d,0x80,0xbf,0x12,0xfa,0x75,0x26,0xe8,0xf1,0xc5,0xf5,0x4f,0x31,0x24, - 0xf6,0x87,0x01,0xd8,0x94,0xe8,0xf2,0xd1,0xdd,0xbd,0x7f,0xe3,0xd7,0xcf,0x37,0x37, - 0x4e,0x9a,0x27,0x38,0x33,0xff,0x61,0xe0,0x80,0xc5,0x74,0x55,0xd3,0xa3,0x0b,0x23, - 0xd4,0x0d,0x11,0x5d,0xd8,0x85,0xcc,0xfc,0x1b,0x8d,0xd8,0x96,0xa8,0xd6,0x81,0x6e, - 0xcd,0x95,0x91,0x34,0x55,0x5d,0x94,0xf0,0x0c,0xa7,0x04,0x2b,0x89,0x04,0x56,0xe5, - 0x0d,0x6a,0x92,0x64,0x6b,0xd0,0x0b,0xbe,0x12,0x66,0x0c,0x3a,0x81,0x76,0x3b,0x88, - 0xc6,0xb0,0xf7,0x7f,0xbd,0xf8,0x08,0x47,0xb1,0xfa,0x12,0x95,0x51,0x18,0xc3,0x69, - 0xb4,0x8f,0x62,0x43,0xec,0x2c,0x42,0x64,0xc8,0x49,0x9d,0xa5,0xc3,0xf2,0x34,0xbf, - 0x72,0x4e,0x6f,0x2f,0x55,0x64,0x17,0xd5,0xe2,0xb6,0x14,0xd2,0xe9,0x91,0x94,0xf1, - 0xf3,0xc0,0xdd,0xc1,0xe9,0xe6,0x3a,0x74,0x11,0x41,0x8c,0xd2,0x95,0x83,0xd3,0xcd, - 0xc2,0x4f,0xf3,0x5c,0x94,0x7f,0xfe,0xf8,0xee,0xe7,0xc8,0x71,0x88,0xc1,0x38,0x13, - 0x0d,0x48,0x2e,0x8d,0xc6,0x61,0x3a,0x3b,0x0b,0xd3,0xd3,0x53,0x33,0xb6,0x1e,0x5d, - 0x46,0xad,0x17,0xa8,0x68,0xd4,0xa2,0x76,0xc4,0xc0,0xd1,0x25,0x14,0xf6,0x6a,0x20, - 0xb1,0x9a,0x3a,0x7e,0x08,0x13,0x73,0x87,0x69,0x2a,0x04,0xe2,0xdf,0x2a,0xa5,0x78, - 0xe5,0x0d,0x6e,0x0a,0x94,0x69,0x88,0x09,0xa0,0x93,0x04,0xa4,0x4e,0x50,0x66,0x18, - 0x55,0xba,0xec,0x1a,0x38,0xd3,0x71,0x93,0x75,0x2e,0xfb,0xf3,0xb7,0xce,0xe9,0x20, - 0x3d,0x9d,0xb8,0xa7,0x0e,0x72,0x6d,0x3c,0x77,0x4e,0x7b,0xd6,0x8f,0x5d,0x31,0x04, - 0x5d,0xbf,0xde,0x6f,0x28,0x87,0xe1,0x15,0xe8,0x9c,0x3a,0x9d,0x9d,0xc6,0x9c,0x68, - 0x6c,0x56,0xe4,0xdb,0xba,0x13,0x7d,0xd4,0x3a,0xbf,0xab,0x17,0xf2,0xa6,0xce,0x37, - 0x03,0xac,0x47,0x30,0xe0,0x90,0x48,0x67,0xb2,0x30,0xa0,0x5f,0xf1,0xac,0x42,0xd2, - 0x1d,0xf7,0xe7,0xbf,0xe0,0x8c,0xc9,0xb3,0xd9,0xc8,0x76,0x1c,0x0b,0x4c,0xfa,0x9d, - 0x6c,0xd6,0x88,0x8c,0xec,0x1c,0xdf,0x9a,0xde,0xba,0xfa,0x6b,0xd3,0x9f,0xf5,0xe7, - 0x67,0x47,0xa9,0xca,0xfd,0x92,0x25,0xd3,0xfe,0x7c,0xfa,0x15,0x2b,0x27,0x5f,0x32, - 0xcf,0xba,0x1c,0x44,0xe2,0x38,0x47,0xe7,0xf1,0xcb,0x35,0xb1,0x4d,0x97,0x35,0x15, - 0x5a,0x22,0xfb,0x32,0xb7,0xd9,0x25,0x6a,0x59,0x7b,0x68,0xc2,0xa6,0x77,0xa9,0x68, - 0xc0,0xbe,0x87,0x9a,0x73,0xc4,0x10,0xba,0x26,0xe2,0xd8,0x20,0x97,0x8c,0xd0,0x21, - 0x5b,0x50,0xe9,0x49,0x1e,0xbb,0x88,0xd1,0x34,0x13,0x07,0xfa,0x58,0xc6,0x28,0x43, - 0x99,0x4e,0xe8,0x1e,0xf8,0x6f,0x94,0x1f,0xf8,0x8f,0x94,0x5b,0xc7,0xe4,0x37,0xc9, - 0xce,0xa3,0xc1,0xc1,0x7e,0x0b,0x45,0x14,0x39,0x13,0xc7,0x7d,0x10,0x45,0xc8,0x1d, - 0x60,0xe6,0xd5,0xaf,0xe9,0x6f,0xde,0x22,0x2a,0xa8,0x48,0xfd,0x09,0x41,0x70,0x58, - 0x9b,0x11,0xf7,0x26,0xe3,0x46,0x16,0xce,0x82,0xec,0x31,0x28,0x86,0xa5,0xbf,0xd0, - 0xad,0x2a,0x7f,0xee,0x98,0x25,0x3b,0x01,0xc2,0xf0,0xa0,0xe6,0x20,0xb0,0xe8,0x0a, - 0x18,0x35,0xb4,0x12,0xfc,0xdc,0xdc,0xf0,0x9b,0x9b,0x85,0x45,0x8f,0x74,0xeb,0x57, - 0x24,0x36,0x40,0x0f,0x7c,0x70,0x2b,0x5b,0xd4,0x3d,0x32,0x77,0x77,0x36,0xa1,0x35, - 0x38,0x47,0x32,0x0f,0x29,0x77,0x20,0x1b,0x39,0x6e,0xe7,0x6b,0x8b,0xcc,0x6f,0x6e, - 0x6c,0x1a,0xa3,0x6e,0x5b,0x35,0x1c,0x09,0x74,0x27,0xc0,0x96,0x46,0x1f,0x47,0x60, - 0x05,0x65,0xd6,0xf8,0xeb,0x00,0x43,0xa1,0x8d,0x46,0xf7,0xd6,0xe7,0xa1,0xd8,0xb7, - 0x9b,0x75,0x0b,0x16,0x4d,0x6c,0x02,0xf3,0x58,0x0e,0xad,0x10,0x3a,0x75,0xcc,0x7e, - 0xab,0x9c,0x63,0x68,0x5b,0x23,0x0f,0x60,0xb6,0x4d,0xad,0xff,0x19,0xa3,0xbb,0x76, - 0x83,0x41,0x6d,0x56,0x57,0x85,0x75,0x79,0x5c,0xfb,0xf9,0x39,0x3c,0x1f,0x38,0xe3, - 0x7a,0x22,0xc6,0x8e,0x7c,0x1d,0x5d,0xe8,0x12,0x40,0x0d,0xe2,0xda,0xd5,0x75,0x00, - 0xec,0x6b,0xbf,0x80,0xd5,0xa5,0x18,0xfe,0x5e,0xc1,0xd6,0x98,0x09,0xbe,0x5c,0x37, - 0xe9,0x30,0x80,0x1f,0xb1,0x31,0x53,0x91,0xc0,0x17,0x20,0xeb,0x35,0x36,0x1d,0xda, - 0x14,0x68,0x6b,0xe9,0x19,0xfb,0xac,0x79,0x35,0x8d,0x43,0x01,0xd3,0x0d,0xac,0x5d, - 0x48,0xef,0x63,0xd4,0x7d,0x24,0xb2,0xd4,0x21,0x57,0x93,0x1f,0xbb,0x78,0xda,0xaf, - 0x7e,0x44,0x98,0xae,0xa7,0x11,0xa1,0xe4,0x8d,0xa8,0xf3,0x05,0xa4,0xa5,0x91,0x01, - 0xd1,0x0d,0x61,0x20,0xbc,0xed,0x1a,0xe7,0xd3,0x43,0x48,0x9b,0xae,0xe3,0xb8,0xfb, - 0xb0,0x77,0xa0,0xd4,0x3d,0x7a,0xea,0x70,0xa4,0x72,0x39,0xfa,0xf5,0xb7,0xaf,0x73, - 0x85,0x84,0xec,0xd7,0x28,0xa7,0xc9,0xb9,0x91,0x73,0x7a,0xe4,0xa8,0x1a,0xf0,0x8e, - 0x6c,0x93,0x20,0xad,0x6c,0xd7,0x59,0x6e,0x1b,0x2e,0x76,0x93,0xbe,0x87,0xfc,0xba, - 0xac,0x6c,0x8a,0x30,0x1f,0x6a,0xec,0xf7,0x53,0x2a,0x83,0x94,0xe3,0xed,0x68,0xc3, - 0x92,0x71,0xe0,0xd0,0x76,0xee,0x78,0x66,0x5a,0x7b,0x5e,0x51,0xc1,0xce,0xa9,0x11, - 0x1d,0x7e,0x44,0xd9,0x0d,0xc2,0x20,0x2d,0x62,0xe9,0x9c,0x56,0x3d,0xfa,0x3c,0xdc, - 0x6e,0xb7,0x43,0xba,0x75,0x1c,0x56,0x65,0x66,0x53,0x72,0xec,0xec,0x3d,0xb2,0x39, - 0x30,0x86,0xff,0x8e,0x73,0xef,0xc0,0x39,0x01,0x7c,0xae,0x51,0x7b,0xf7,0xe3,0x50, - 0xbd,0xd5,0x1f,0x3e,0xf5,0xdc,0xfd,0x3a,0xd9,0x10,0xb4,0x5b,0x80,0xd4,0x6d,0x86, - 0xee,0xf4,0x69,0x69,0x47,0x6e,0x8a,0x7d,0x41,0xdf,0x96,0x50,0x1f,0xe1,0x1c,0x88, - 0x45,0x3b,0x9e,0x83,0x06,0x6c,0xe3,0xf7,0xe0,0x61,0xd5,0xd8,0xd9,0xf7,0x6d,0x08, - 0xdc,0xe6,0x42,0x9d,0x01,0x2c,0x05,0x0c,0x83,0xa1,0x51,0x5e,0x36,0x75,0x01,0x6c, - 0x5d,0xd2,0x57,0xc2,0xee,0x07,0xb5,0x5b,0x46,0x9a,0x71,0xd6,0x14,0x36,0xac,0xab, - 0xa9,0x5c,0x64,0xc8,0xf1,0xb1,0xa9,0x47,0x79,0xae,0xb6,0xf4,0xdd,0xe4,0x1b,0x56, - 0xee,0x29,0xf1,0x85,0xbd,0xba,0xf0,0x09,0x69,0x47,0x79,0xb9,0xc6,0x41,0xf7,0x50, - 0x19,0xb7,0xf7,0x18,0x19,0xa7,0x93,0x00,0xea,0x5f,0xfa,0x1a,0x85,0x73,0x3c,0x0e, - 0x93,0xba,0x24,0x8f,0xa3,0x42,0x49,0x35,0xaa,0x63,0xb6,0x46,0x1d,0x2b,0x72,0x0a, - 0x4e,0xd2,0x53,0xf0,0x4a,0x35,0x5d,0x28,0x9c,0xad,0xae,0xb4,0x40,0x30,0xd3,0x17, - 0x31,0xc5,0x0c,0x9e,0xca,0xef,0x21,0xb3,0x9a,0x4f,0x91,0xb7,0x78,0x73,0x36,0x1e, - 0x7b,0x5d,0x3f,0x51,0x6c,0xbb,0x35,0x66,0x64,0xf3,0xe1,0xf3,0xfe,0xc8,0x9e,0xb4, - 0x47,0xf6,0x3f,0x13,0xfc,0x07,0xc4,0xf4,0xe0,0x5a,0x5d,0x20,0x00,0x00, + 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xb5,0x59,0xeb,0x72,0xdb,0xb8, + 0x15,0xfe,0xaf,0xa7,0x40,0x94,0xd6,0x24,0xd7,0x24,0x25,0x3a,0xbe,0x85,0x14,0x95, + 0xfa,0xba,0xdd,0x49,0xb2,0xf5,0xc4,0xd9,0xe9,0x4c,0x32,0xf9,0x01,0x91,0xa0,0x84, + 0x98,0x22,0x38,0x04,0x64,0xc5,0x95,0x39,0xd3,0x87,0xe8,0x13,0xf6,0x49,0x7a,0x0e, + 0x40,0x89,0x94,0xa2,0xec,0xee,0x9f,0xce,0x24,0x32,0x01,0x1c,0x9c,0xcb,0x77,0x2e, + 0xb8,0x8d,0x5e,0xa4,0x22,0x51,0x4f,0x25,0x23,0x33,0x35,0xcf,0xc7,0xbd,0x11,0xfe, + 0x21,0x39,0x2d,0xa6,0x71,0x9f,0x15,0x7d,0xec,0x60,0x34,0x1d,0x8f,0xe6,0x4c,0x51, + 0x92,0xcc,0x68,0x25,0x99,0x8a,0xfb,0x0b,0x95,0x79,0xe7,0x38,0x28,0x93,0x8a,0x97, + 0x8a,0xc8,0x2a,0x89,0xfb,0x83,0x32,0xf3,0x12,0x51,0x48,0x91,0x33,0xff,0xab,0x7c, + 0x33,0x8b,0x59,0x96,0x65,0xe9,0xc9,0xf0,0xa4,0x3f,0x1e,0x0d,0x0c,0xe1,0xb8,0x99, + 0x30,0xe6,0x99,0xfd,0x62,0xc9,0x8b,0x54,0x2c,0xfd,0xbb,0x5b,0xc7,0xce,0x16,0x45, + 0xa2,0xb8,0x28,0x6c,0x67,0xf5,0x48,0x2b,0xf2,0xcf,0xd8,0x8c,0xb9,0xbf,0xc5,0xd6, + 0x80,0x96,0x7c,0x20,0x15,0x55,0x0b,0x69,0xb9,0xef,0xe2,0xcf,0x5f,0xdc,0xf7,0xf1, + 0x11,0x7b,0xed,0xde,0xbb,0x9f,0xdc,0xbb,0xf8,0x9f,0x30,0x3d,0x5e,0xe1,0x30,0x0b, + 0xad,0x9c,0x3f,0x32,0xcb,0x4d,0x79,0xa5,0x9e,0xc2,0x17,0x81,0xfb,0x18,0x16,0x8b, + 0x3c,0x77,0xa7,0x4c,0x85,0x3f,0xbb,0xbc,0xc8,0x72,0x3e,0x9d,0xa9,0xf0,0xd7,0xc5, + 0x7c,0xc2,0x2a,0x77,0x26,0xf2,0x34,0xfc,0xc7,0xe4,0x2b,0x4b,0x94,0x2b,0xe9,0x53, + 0xb8,0xd1,0x40,0xb9,0x0f,0x2e,0x73,0x56,0xec,0xe0,0xc0,0x66,0xbe,0x62,0xdf,0xd4, + 0x95,0x28,0x14,0x2b,0x54,0xac,0x9c,0xda,0x9d,0x2c,0x64,0x87,0x74,0xe2,0x96,0xce, + 0x6a,0xdd,0x22,0x19,0x28,0x3f,0xf1,0x53,0x2e,0xe9,0x24,0x67,0x69,0xfc,0x22,0xa8, + 0xbb,0xad,0x61,0x54,0xfa,0x6a,0xc6,0x0a,0x3b,0x73,0x33,0x27,0xaa,0x98,0x5a,0x54, + 0x05,0x29,0x6b,0xb7,0x14,0x79,0xde,0x72,0x94,0xee,0xdc,0x4d,0x5c,0x61,0x50,0x50, + 0x6e,0xe6,0x4e,0xe3,0x20,0xda,0x48,0xf8,0x00,0x12,0xa6,0x07,0x07,0x2f,0x32,0xd0, + 0x2d,0x8b,0x03,0x37,0xc9,0x19,0xad,0x3e,0xf2,0x39,0x13,0x0b,0x65,0x2b,0xc7,0xb5, + 0xa5,0x9f,0xd0,0x3c,0x7f,0x23,0x6d,0x27,0xfc,0xd9,0x96,0x8e,0xd3,0x48,0x5c,0x73, + 0x4f,0x9d,0x55,0x62,0xa7,0x2e,0xa2,0x02,0xb6,0x6c,0xba,0x19,0x76,0x6b,0xa8,0x98, + 0x53,0x37,0x73,0xde,0xba,0x6f,0x1d,0xa7,0xde,0x48,0x7e,0x0b,0x92,0xb3,0x78,0x18, + 0xed,0x48,0x8c,0x40,0x1b,0x5b,0xc5,0x10,0x12,0xeb,0xbe,0x0f,0xee,0x1c,0xe6,0x89, + 0x83,0x03,0xe1,0x67,0xbc,0x92,0x2a,0x8e,0x01,0x88,0x37,0x30,0x3d,0x04,0xe5,0x1b, + 0xb3,0xc1,0x5d,0xa2,0x0c,0x3b,0x2e,0x9f,0x7e,0xcf,0xb9,0x76,0x81,0x69,0x4b,0x53, + 0x38,0xab,0x79,0x5c,0x44,0xd9,0xf3,0x33,0xb0,0xaa,0xdd,0x42,0x2c,0xc3,0x0f,0x35, + 0xd0,0xe8,0xb0,0x68,0xc9,0x12,0xb0,0xe4,0xe0,0xe0,0x9d,0x5f,0x2e,0xe4,0x0c,0x1a, + 0xd1,0xfd,0x1b,0x68,0x26,0xf6,0xbd,0x13,0x7e,0x7a,0xf3,0xc9,0x87,0x59,0xa0,0xc7, + 0xa7,0xf8,0xce,0x47,0xd0,0xed,0xdf,0xdc,0xf7,0xee,0x35,0x30,0x5b,0x52,0x95,0xcc, + 0xee,0x77,0x38,0xcd,0x9d,0xd5,0x9d,0x6f,0xd8,0x83,0xde,0x9f,0x7c,0xd0,0xc6,0x7e, + 0x1f,0xbf,0xa7,0x6a,0xe6,0xcf,0x39,0x0c,0xbb,0xef,0x1d,0x3d,0x95,0xab,0x5b,0x51, + 0x5d,0xb3,0x47,0x9e,0xb0,0x76,0x32,0xf8,0x4f,0xc4,0xe2,0xf9,0x79,0x55,0xaf,0x1d, + 0x5d,0xb0,0x25,0xb9,0xab,0xc4,0x9c,0x4b,0xd6,0xba,0xe3,0xc9,0x2d,0x8c,0xa3,0x67, + 0xad,0x4a,0x47,0xec,0x55,0xeb,0x18,0xe9,0xac,0x24,0xb8,0xdb,0x16,0xfe,0x64,0xc1, + 0xf3,0xf4,0xe0,0x40,0x9a,0x8f,0x38,0x6e,0x7a,0x1c,0x80,0x7f,0xe6,0x23,0x9c,0xb6, + 0xe3,0x3e,0xa1,0xc7,0x6b,0x27,0xea,0x78,0xa3,0x83,0xf1,0x9a,0x2c,0x2a,0xec,0x9b, + 0xaa,0x12,0x95,0x6d,0x29,0x43,0x64,0xa1,0x21,0xc2,0x6f,0x5a,0xcf,0xcf,0xaf,0xd9, + 0x31,0x70,0xa9,0xeb,0x36,0xec,0x7e,0xb6,0x17,0x18,0x92,0x8d,0x29,0x19,0x03,0xb8, + 0x74,0xcf,0x4e,0x74,0x55,0xce,0x0a,0xb3,0xba,0xf2,0xc5,0x83,0xa3,0x66,0x95,0x58, + 0x12,0x23,0xa8,0x6a,0x70,0xdc,0x44,0xbd,0x8e,0x0e,0xcc,0xac,0x37,0x95,0xfe,0x03, + 0x4e,0xa9,0xa0,0x60,0xa0,0x9a,0x75,0x27,0xe6,0xae,0xd1,0x7e,0xe0,0x08,0xbf,0xf7, + 0x90,0xe7,0x65,0x66,0x7c,0x14,0xcb,0xe8,0x9d,0x9f,0x89,0xea,0x86,0x82,0x1a,0x1b, + 0xe1,0x19,0xc4,0x27,0x50,0xa2,0xe2,0xb5,0x63,0x3b,0x9b,0x7a,0xd3,0x33,0x85,0xab, + 0xa0,0x73,0x16,0xf7,0x1f,0x39,0x5b,0x96,0xa2,0x52,0x7d,0x92,0x34,0x39,0xdd,0x5f, + 0xf2,0x54,0xcd,0xe2,0x54,0x3b,0xd0,0xd3,0x0d,0xa8,0x14,0x5c,0x71,0x9a,0x7b,0x12, + 0x72,0x89,0xc5,0x01,0x56,0x39,0xc5,0x55,0xce,0xc6,0x77,0x54,0x29,0x56,0x41,0x1d, + 0x01,0xd3,0x3c,0xf2,0xb6,0x10,0x13,0x39,0x1a,0x98,0x21,0x28,0x84,0xea,0x09,0xff, + 0x0e,0x7e,0x22,0x57,0xa6,0x04,0x92,0x09,0x95,0x2c,0x24,0x80,0x11,0x91,0x20,0x9d, + 0x4c,0x72,0x91,0x3c,0x10,0x51,0xb2,0x42,0x12,0xf6,0xc8,0xaa,0x27,0x50,0xa2,0x62, + 0xa4,0xa4,0x53,0xe6,0x93,0x77,0x58,0x9a,0x08,0x2f,0x48,0x58,0x09,0xa1,0x88,0x8d, + 0xb3,0x12,0xc0,0x70,0xce,0x2c,0xd9,0x23,0x04,0x46,0xb0,0x50,0xb1,0x94,0xe8,0x1a, + 0x06,0x93,0x72,0x06,0xba,0x10,0x2c,0x62,0x12,0x45,0xc8,0x46,0xc8,0x23,0xcd,0x17, + 0x4c,0x86,0xe4,0x81,0xb1,0x52,0x8b,0x56,0x4b,0x81,0x6c,0xa5,0x62,0xa5,0xe3,0x22, + 0xa7,0x94,0x56,0x0f,0x64,0x51,0xa4,0xac,0xd2,0x05,0xff,0x73,0x4a,0x15,0xf5,0x80, + 0x12,0xf0,0xc1,0xa1,0x2f,0x3e,0xf9,0x55,0x90,0x25,0x9b,0x90,0x0c,0x20,0x92,0x46, + 0xff,0x99,0x50,0xb2,0x04,0xb5,0x66,0x54,0x92,0x02,0xf9,0x21,0x0c,0x4c,0xf9,0xe4, + 0xa7,0x41,0x4f,0x2b,0xbc,0x4a,0x44,0x2e,0x2a,0x40,0x0c,0xf9,0x84,0x5a,0xc7,0xc8, + 0xf3,0x92,0x8a,0xd1,0x79,0xf8,0xf2,0xf6,0xf8,0xe6,0xf6,0xe6,0x14,0xda,0x25,0x2d, + 0x58,0x0e,0xed,0xdb,0xdb,0xab,0xdb,0x0b,0x68,0xf3,0xe2,0x21,0x7c,0x19,0x5c,0x04, + 0xe7,0xc1,0x31,0xb4,0xe6,0x0b,0xb0,0x2f,0x7c,0x79,0x7a,0x74,0x72,0x75,0x12,0x40, + 0x3b,0xa3,0x20,0x27,0x7c,0x79,0x76,0x7d,0x76,0x7a,0x7a,0x0e,0xed,0x6a,0x91,0xb3, + 0xf0,0xe5,0xf5,0xf5,0xf5,0xc9,0xd5,0x69,0xd3,0xf4,0xa4,0xc8,0x80,0xe4,0xe6,0xfc, + 0x26,0xb8,0x46,0x16,0xd3,0x99,0x90,0xd8,0x7e,0x75,0x7d,0x75,0x75,0x03,0xed,0x1c, + 0x19,0xde,0xde,0x9e,0x5c,0x1d,0x61,0x6b,0x42,0xa1,0x75,0x79,0xfe,0xea,0x2a,0xb8, + 0x82,0x96,0x00,0xd9,0x47,0x97,0x67,0x17,0xc7,0x97,0xd0,0x58,0xd2,0xaa,0x08,0x5f, + 0x9e,0x9f,0x9c,0x0e,0x87,0x37,0x51,0xcf,0xf3,0x24,0x2d,0x64,0x28,0x9f,0x00,0xb5, + 0xb9,0xb7,0xe0,0xae,0x47,0xcb,0x12,0xa5,0xe9,0x0e,0xd7,0xba,0x67,0x53,0xc1,0xc8, + 0x6f,0xbf,0x58,0xee,0x07,0x31,0x11,0x4a,0xb8,0x48,0xee,0x49,0x56,0xf1,0x0c,0xed, + 0x10,0x85,0x08,0x17,0x5c,0xff,0x95,0x25,0x4d,0x98,0x6b,0x5d,0x51,0x88,0xa5,0x94, + 0x53,0xf2,0x1e,0xfa,0x2c,0x60,0x70,0xdb,0x7c,0xbd,0x67,0x45,0x2e,0x5c,0x13,0x30, + 0x54,0xba,0x96,0xe1,0xd7,0x0c,0x6e,0x18,0xd4,0xbd,0xbd,0x9e,0xda,0x06,0x1d,0xbb, + 0x5a,0xcc,0x87,0x57,0xc3,0xcb,0xe1,0xeb,0x16,0xf3,0xe0,0x55,0x10,0x04,0xc3,0x35, + 0xe6,0x37,0xd7,0x37,0x67,0xd7,0x97,0x2d,0xe6,0x17,0xaf,0x5e,0x5f,0x9e,0x5f,0x74, + 0x30,0xbf,0x38,0x7b,0x75,0x7a,0xbc,0xc1,0xfc,0xe8,0xf2,0xe8,0xec,0x28,0xd8,0xc6, + 0x3c,0xb8,0x0d,0xae,0x82,0xf3,0x16,0xf3,0xa3,0x8b,0xa3,0xd3,0xa3,0xe1,0x1a,0xe5, + 0xdb,0xdb,0xb3,0x8b,0x93,0x93,0x06,0xe5,0x93,0xb3,0xcb,0xf3,0xb3,0xdb,0x0d,0xca, + 0xd7,0xaf,0x2f,0x86,0xaf,0x6e,0xeb,0xde,0x4f,0xab,0x89,0xf8,0xe6,0x49,0xfe,0x2f, + 0x5e,0x4c,0xc3,0x89,0xa8,0x20,0x22,0x3d,0xe8,0xa9,0x3f,0xcf,0x78,0x9a,0xb2,0xe2, + 0xcb,0x0a,0xd6,0xce,0x32,0x87,0x95,0xb9,0x10,0x05,0x7b,0xc1,0xe7,0x98,0xb8,0xb4, + 0x50,0x75,0x6f,0x22,0xd2,0xa7,0xd5,0x9c,0x56,0x53,0x5e,0x84,0xc3,0x68,0x42,0x93, + 0x87,0x69,0x25,0x20,0xa2,0x43,0x28,0xa5,0x76,0x83,0x80,0x13,0x69,0x70,0x9a,0x2e, + 0x30,0xda,0x89,0x30,0x9e,0xc3,0xe0,0xa4,0xfc,0x36,0x08,0xfc,0x13,0x62,0x06,0xd0, + 0x71,0x4e,0xe4,0x41,0xb8,0x3f,0x70,0xe5,0x21,0x85,0x27,0xe7,0x10,0xcf,0x33,0xd4, + 0x09,0x84,0x41,0x19,0xe0,0x90,0xc5,0x69,0xdd,0xa3,0x06,0xed,0x90,0x17,0x33,0xf0, + 0xb3,0xaa,0xc3,0x4c,0x24,0x0b,0xe9,0x3d,0x72,0xc9,0x61,0x7d,0x5f,0x41,0xe5,0xcc, + 0x79,0xc1,0xc2,0xa3,0xf2,0x1b,0x01,0x5f,0xf2,0xb4,0x11,0x00,0x11,0xe8,0x44,0xcd, + 0xa0,0x27,0xb2,0x0c,0x17,0x35,0xa0,0xa9,0x7b,0xfe,0xb2,0xa2,0x25,0x58,0xf1,0xcd, + 0x14,0x9d,0xf0,0xec,0x68,0x58,0x7e,0x8b,0xd6,0x56,0x11,0xba,0x50,0x22,0x2a,0x69, + 0x9a,0xa2,0x22,0x38,0x44,0x82,0x53,0xf8,0x39,0x3e,0xd7,0x73,0x27,0xaa,0xd8,0xa0, + 0xc3,0x0b,0xcd,0x3b,0xcb,0xd9,0xb7,0x08,0xb4,0x9d,0x16,0x1e,0x87,0x20,0x95,0x61, + 0xc2,0x30,0x4b,0xa3,0xaf,0x0b,0xa9,0x78,0xf6,0xe4,0x35,0x05,0x6f,0xdd,0x3d,0xa5, + 0x65,0x78,0x8a,0x02,0x79,0xe1,0xcd,0x98,0xde,0x17,0x1d,0xa3,0x02,0x6b,0x91,0x43, + 0x2d,0x2f,0x32,0x6e,0x09,0x83,0x1d,0xab,0x30,0x0e,0x9c,0x66,0xd0,0xab,0x20,0xb2, + 0x61,0xe5,0x3c,0x47,0xf2,0x5d,0x5f,0xe8,0xe8,0xfb,0x91,0x2f,0x4e,0x86,0x20,0xe5, + 0x18,0x58,0x77,0x7d,0x81,0xeb,0x81,0x97,0x32,0x28,0x8d,0x14,0xeb,0xba,0x76,0x7e, + 0x94,0x2c,0x2a,0x09,0x0c,0x4a,0xa1,0x2b,0x4f,0xa4,0x2a,0x20,0xe5,0x7a,0xb8,0xd1, + 0x41,0x0b,0x20,0x7e,0x70,0x22,0xdd,0x56,0x07,0xd3,0x6e,0x87,0xea,0xde,0xdf,0xe6, + 0x0c,0xb2,0xd0,0x9e,0x09,0x28,0xbf,0xa1,0xfe,0x75,0x56,0x08,0xa6,0xf9,0x5e,0x75, + 0x99,0x75,0xb4,0xad,0x91,0xc4,0x2f,0x2b,0xbe,0x26,0xdb,0xb5,0x52,0x3b,0x79,0xcf, + 0x64,0xdd,0x6f,0x3a,0x5e,0xc2,0x4e,0xb8,0xce,0x20,0xb2,0xa0,0xec,0xd2,0x86,0xcf, + 0x77,0x72,0x8c,0x67,0xc3,0xf5,0x9e,0x71,0x25,0x20,0xf9,0x39,0x6c,0x65,0xfd,0xe3, + 0x93,0x35,0x04,0x29,0xcb,0xe8,0x22,0x57,0xfb,0xa4,0x69,0xa7,0x18,0x16,0xa8,0xec, + 0xf7,0x6a,0x6a,0xe4,0x7f,0x60,0xe3,0x96,0x8b,0x4c,0x06,0x01,0xab,0xb9,0x9c,0xae, + 0x4c,0xda,0x1c,0x6d,0xdc,0x84,0x55,0x69,0x9b,0x5c,0x17,0x0d,0x40,0x09,0x76,0xff, + 0xe2,0x61,0xcb,0x2a,0xf1,0x60,0xba,0x59,0xb5,0x6d,0x2d,0xd4,0x08,0x60,0x6f,0xe0, + 0xd8,0x04,0xf2,0x9f,0x8d,0x60,0x5d,0x12,0xbd,0x09,0x53,0x4b,0xc6,0x0a,0x1d,0xc8, + 0x3a,0x54,0x4d,0xea,0x78,0xb8,0xb3,0xd4,0x91,0xdc,0x18,0x8a,0xed,0xfd,0xe1,0xfb, + 0xa7,0x0d,0xeb,0xad,0xfd,0xf6,0x67,0x73,0x6e,0x37,0xa9,0xba,0x3c,0x75,0xc5,0xdd, + 0x1f,0xe6,0x50,0xe6,0xe1,0xa4,0xf5,0x7b,0x88,0xe0,0x8e,0x02,0x25,0x47,0x38,0xe2, + 0x61,0x05,0x09,0xf1,0x47,0x83,0x80,0x89,0x84,0xd6,0xac,0x81,0x80,0x85,0x44,0x89, + 0xb9,0xae,0x1d,0xc0,0x38,0x58,0xe1,0x94,0x30,0xd8,0x54,0x98,0xc8,0x14,0x3b,0xfe, + 0x2f,0xa8,0x59,0x38,0x4b,0x37,0x97,0x46,0x69,0x58,0x05,0x23,0xbd,0xbf,0x80,0xc5, + 0x05,0x43,0x10,0xea,0x81,0xe7,0x0f,0x03,0x36,0x87,0x90,0x90,0x8b,0xc9,0x9f,0x0f, + 0x89,0x1e,0x6c,0xb9,0x15,0x5b,0xd7,0x6a,0xa8,0x10,0x64,0x48,0xba,0x92,0x83,0x57, + 0x7b,0xd1,0x81,0x79,0x34,0x51,0x72,0x1b,0x87,0x1d,0x93,0xf7,0xc0,0x8e,0x28,0x9c, + 0x6f,0x47,0x42,0xa0,0x6b,0x2d,0x80,0x06,0x9b,0xa7,0x95,0x29,0xb4,0xc1,0x70,0xf8, + 0xd7,0x1f,0x96,0x3d,0x54,0x31,0x18,0xfe,0xbf,0x0b,0xdf,0x6e,0xd1,0xab,0x71,0xd7, + 0xf8,0xdf,0xff,0xfc,0x1b,0xfe,0x99,0x5d,0xe5,0xba,0x01,0xdb,0x2b,0x85,0xa5,0x60, + 0x4b,0xf5,0x8e,0x75,0x6d,0x89,0xc6,0x84,0xce,0x69,0x09,0x1b,0xce,0xf5,0x47,0xdd, + 0x83,0xad,0xac,0x4a,0x57,0x6b,0xd3,0x4e,0x35,0xfa,0xf8,0x7b,0xde,0xce,0x6a,0x82, + 0x64,0x9f,0x99,0x7a,0x9d,0x6f,0x02,0x55,0x83,0x1d,0xe6,0x2c,0x53,0xc8,0x75,0xf5, + 0xa3,0xe2,0xb3,0xeb,0xd9,0x6e,0x4c,0x41,0xb1,0xdf,0xef,0xe9,0x87,0xc6,0xb8,0xa3, + 0xf3,0xd6,0x0f,0x1e,0x8a,0x6a,0x62,0x14,0xa3,0x91,0xfc,0x6e,0xb0,0x6d,0x58,0x95, + 0x42,0x36,0xcc,0xce,0x4e,0x1b,0xf1,0x7a,0xc1,0xef,0xce,0x5c,0x47,0x83,0xaf,0x6f, + 0x09,0x56,0x3f,0xa8,0xda,0xc8,0x2c,0xc3,0xf5,0x1a,0xb3,0x8d,0x20,0x63,0xb7,0xdb, + 0xf1,0x52,0xaa,0xb6,0x38,0x9f,0xd4,0x3d,0x38,0x6d,0xe8,0xdd,0xff,0x68,0x60,0xee, + 0x4a,0x70,0x87,0x82,0x27,0x0f,0xc8,0x02,0x92,0xc0,0xc6,0x4e,0xc2,0x39,0x03,0x82, + 0x76,0x7d,0x99,0xc2,0xaa,0xf1,0x68,0x16,0x8c,0x9b,0x03,0x04,0x7c,0x8d,0x20,0xcd, + 0x36,0x94,0x90,0x61,0x7d,0xc2,0x53,0xf8,0x50,0xfd,0xb1,0x07,0xac,0x61,0xac,0xe1, + 0x0c,0x13,0x7b,0xa3,0x72,0x4d,0x88,0xb9,0xd5,0x1f,0x7f,0xc4,0x13,0x15,0x25,0x0f, + 0xc0,0x8c,0x40,0x11,0x81,0x41,0x0e,0xc7,0x8c,0x04,0x0f,0x1b,0x4b,0x8e,0x07,0x10, + 0xae,0x24,0x01,0x03,0xf4,0x7a,0x49,0xe4,0x4c,0x2c,0xf2,0x94,0x4c,0x05,0x59,0x94, + 0x64,0xf2,0x84,0x33,0xfc,0xd1,0xa0,0xc4,0x23,0x0e,0x06,0xda,0x18,0x4e,0x08,0x23, + 0x65,0x8c,0x50,0xa0,0xa5,0x9a,0xad,0x85,0x3d,0xe0,0x1d,0x8e,0x9a,0x61,0xd7,0xf8, + 0xae,0xe1,0xb6,0xe9,0xb8,0xe6,0x15,0x4b,0xb6,0x7a,0x6e,0xd2,0x29,0x03,0xb1,0x50, + 0x35,0xb5,0x3e,0xa6,0x7f,0x80,0x2c,0x07,0x86,0xbd,0x16,0x84,0x38,0x69,0x53,0xe1, + 0xb0,0x28,0xb5,0x80,0x06,0xb9,0x41,0xa3,0xcd,0x28,0xe5,0x8f,0x6b,0x0d,0xb0,0x24, + 0xf4,0xf5,0xbc,0xc9,0x02,0xa2,0x76,0x83,0x17,0xac,0x77,0x04,0xd6,0xbb,0x3e,0xc1, + 0x4b,0x2c,0x68,0xea,0xc1,0x06,0x41,0xfa,0xc8,0xfa,0x64,0xbd,0x9e,0x8e,0xef,0xa1, + 0x39,0x1a,0x18,0x82,0xfd,0x8c,0xf6,0x31,0xa9,0xf0,0xb0,0xa6,0x3a,0x6c,0x3e,0xe8, + 0x8e,0x2d,0x46,0x5d,0xff,0xc1,0xa2,0x69,0x26,0xe2,0xc7,0xb8,0xf1,0x1f,0x98,0x04, + 0xa6,0x7c,0xef,0xbd,0x9f,0x05,0xc0,0x94,0x8a,0x65,0x11,0x12,0xd8,0x1a,0x82,0xaf, + 0x08,0x6c,0xff,0xb5,0x00,0xd8,0x75,0xfa,0x70,0x10,0x78,0x84,0x71,0x38,0xc3,0xb9, + 0x04,0x36,0x31,0x8a,0x3e,0x98,0x96,0x01,0x55,0x22,0xed,0x1c,0x28,0xd0,0x8b,0x61, + 0x2f,0x99,0xd1,0x62,0xca,0x08,0xdb,0x46,0x9e,0xd8,0x73,0xd8,0x9f,0x13,0x56,0x24, + 0x02,0xc2,0x47,0x12,0x0a,0x47,0xce,0xe3,0x48,0x9f,0xea,0x90,0x12,0xce,0xa0,0x8b, + 0x42,0x35,0xe7,0x41,0xec,0xec,0x46,0xca,0x52,0xc2,0xc9,0x6f,0x49,0xe6,0xb4,0x78, + 0xea,0x84,0xd6,0x1c,0xb5,0x70,0xfc,0x1e,0xa2,0x99,0x42,0xbf,0x99,0xa6,0x8f,0x19, + 0x70,0x38,0xd4,0x5b,0x67,0x54,0xac,0x62,0xfa,0x86,0xc2,0x25,0x14,0x76,0x62,0xe0, + 0x08,0xec,0x4e,0xd1,0x5a,0xa0,0x31,0x5a,0x9b,0xa0,0x6d,0xc2,0xcf,0xac,0xb1,0xe3, + 0x11,0x25,0xb3,0x8a,0x65,0x71,0x7f,0xd0,0x1f,0x37,0xe7,0xe8,0xd1,0x80,0x76,0xba, + 0xcd,0x55,0x42,0x7f,0x6c,0xee,0x02,0xf4,0xd8,0xa0,0x99,0x0b,0x18,0x63,0xc6,0x6d, + 0x2e,0x25,0xc7,0xbd,0xcd,0x55,0xc2,0x5f,0x6c,0xbe,0xb9,0xbf,0x48,0x61,0xe3,0x3e, + 0x87,0x15,0xc3,0x9f,0x32,0x75,0x93,0x33,0xfc,0xbc,0x7c,0xfa,0x25,0x05,0x8a,0xba, + 0x9d,0x20,0xe9,0x13,0x5e,0x04,0x3a,0xab,0xbb,0x5b,0xbf,0xf9,0x7e,0x7e,0xb6,0x78, + 0x91,0xc1,0xb9,0xec,0x2f,0xb6,0x05,0xae,0xc5,0x6b,0x93,0x1e,0x5e,0xde,0xc0,0xce, + 0x2c,0xd6,0x97,0x67,0xba,0xa2,0xc4,0x19,0xcd,0x25,0x73,0x8d,0xc1,0xa6,0x11,0x91, + 0xc1,0x40,0x83,0x64,0x6e,0x19,0x2c,0x19,0x01,0x26,0x00,0xb9,0xd4,0x00,0x26,0x33, + 0x01,0x9d,0xd0,0x45,0xee,0xfe,0x71,0xff,0x11,0xcf,0xea,0xe6,0x9e,0xb2,0xa3,0x0b, + 0xcb,0x21,0xc1,0x3a,0x16,0x80,0x02,0xbc,0x78,0xb4,0x0e,0xb7,0x35,0x66,0xf9,0xfd, + 0x62,0xb2,0x4d,0x05,0xa5,0x64,0x87,0x4a,0xfb,0xc4,0x76,0x56,0x10,0xb4,0xfa,0x86, + 0x71,0x12,0x03,0x19,0x66,0x9f,0xe5,0x44,0xd0,0x97,0x89,0xca,0xc6,0x7e,0x1e,0x0f, + 0x23,0x3e,0x3a,0x8e,0xf8,0xe1,0xa1,0xa6,0x6d,0xa8,0xab,0x78,0x03,0x1e,0xee,0x11, + 0x15,0x6b,0xf0,0xb3,0x2d,0x55,0x19,0x06,0x04,0x6d,0x5d,0x67,0x0a,0xd8,0xa8,0x78, + 0x0e,0x96,0xe9,0x9b,0x40,0x88,0x08,0x8a,0xc5,0x9d,0x4c,0x39,0x06,0x35,0x6d,0x2c, + 0x87,0x85,0x67,0xce,0x36,0x51,0x93,0xf2,0x2c,0x83,0x48,0xcc,0x2a,0x31,0xd7,0xdc, + 0x54,0xe5,0xf3,0xa2,0x60,0xd5,0xdf,0x3f,0xbe,0x7f,0x17,0x5b,0x23,0x95,0x76,0xea, + 0xd1,0x5b,0xeb,0xd0,0xe6,0x87,0x81,0x73,0x68,0x41,0xbd,0x48,0xc7,0xd6,0xa1,0x9e, + 0x41,0x48,0x97,0x0c,0xc2,0xb9,0xdf,0x94,0x57,0x4c,0x49,0x68,0x02,0x20,0x87,0x56, + 0xa7,0xb0,0x76,0x2a,0xcc,0x26,0x73,0x2b,0xba,0x6c,0xc8,0x4c,0xda,0x7e,0xcf,0x1f, + 0x78,0xea,0x65,0x44,0x93,0x1b,0x67,0x00,0x79,0x5b,0x23,0x46,0xa2,0xd4,0x78,0xeb, + 0xfb,0x98,0xb8,0x3f,0xec,0x8f,0x7f,0x15,0xd5,0x9c,0xe6,0xa3,0x81,0x19,0xd8,0x25, + 0x08,0xfa,0xe3,0x75,0xd6,0xb7,0x24,0x03,0x23,0xe3,0x8f,0xc4,0x1b,0x2f,0xef,0x13, + 0x3f,0x3e,0xde,0x95,0x37,0x3e,0xfa,0xae,0x27,0xf8,0x91,0x40,0xe3,0x4f,0x35,0xf1, + 0x69,0x59,0xb2,0x22,0xbd,0x9a,0x61,0xe8,0xa8,0xaa,0xf1,0xf3,0x26,0x2a,0x7d,0x51, + 0x98,0xd2,0x13,0x6f,0x42,0xb0,0xed,0x82,0xdd,0xca,0x83,0xc4,0x09,0x75,0x0f,0x76, + 0x39,0x03,0x02,0xe9,0xa4,0xd3,0x84,0xd8,0x85,0x20,0x68,0x2f,0x62,0x50,0xb1,0x5c, + 0xc0,0x89,0x80,0x2c,0x41,0x02,0x6b,0x03,0xc3,0xc4,0x82,0xd4,0xc1,0xd0,0xc9,0x9f, + 0x36,0x98,0x35,0xf3,0x36,0x98,0xa1,0x4c,0x35,0x09,0xf7,0x87,0x91,0x4c,0x63,0xbb, + 0xd5,0xdf,0xb8,0x20,0x8e,0xad,0xc0,0x72,0x5e,0xc4,0x31,0xe4,0x33,0xc4,0xdc,0xe3, + 0x67,0xfe,0xc5,0x9d,0xc4,0x25,0xbe,0x77,0xfc,0x02,0x11,0xde,0xda,0xa6,0xc9,0xdd, + 0x60,0xb8,0xa6,0x05,0xf8,0x81,0x76,0x17,0x14,0x1d,0x52,0xbf,0xe2,0xad,0x23,0x7d, + 0x63,0x69,0x93,0xad,0xd0,0xb2,0xa2,0x96,0x4d,0x4b,0x30,0xe9,0x12,0x68,0x36,0x68, + 0x09,0xfc,0x7f,0x7e,0xa6,0xcf,0xcf,0x13,0x83,0x1e,0xf2,0x56,0xd7,0x48,0x66,0xc3, + 0x08,0xf8,0x60,0x2b,0xf5,0x9b,0x11,0x51,0x38,0x2b,0x53,0x85,0xd6,0x38,0xc7,0xa2, + 0x88,0xb0,0x10,0x40,0xa9,0xb1,0x9c,0xce,0x6b,0x84,0x28,0x9e,0x9f,0x4d,0x8d,0xc2, + 0x61,0xb3,0xc4,0xed,0x10,0x74,0x05,0xc0,0x32,0x80,0x8f,0x07,0xa0,0x05,0x56,0xbb, + 0xf4,0xf7,0x01,0x06,0x86,0x26,0xcf,0x9c,0xad,0xe7,0x93,0xd4,0x37,0xab,0xd6,0x06, + 0x2c,0x14,0xac,0x13,0x6d,0x97,0x0e,0x7a,0x81,0xe8,0xd0,0x32,0x6b,0x99,0xb5,0x0b, + 0xed,0x46,0xc9,0x16,0xcc,0x4d,0xd7,0xc6,0xff,0x84,0xe0,0x5d,0xb4,0xc6,0xa0,0x51, + 0xab,0xcb,0xc2,0xb8,0x3c,0x6d,0xfc,0xfc,0x06,0x3c,0x1f,0x5a,0xc3,0x46,0x10,0x21, + 0x3b,0xbe,0x8e,0xef,0x55,0x05,0x40,0xd9,0x69,0xe3,0xea,0x26,0x01,0xea,0xc6,0x2f, + 0x10,0xd5,0x15,0xf3,0xbe,0x2e,0x40,0xd7,0x94,0x30,0x9a,0xcc,0xd6,0x85,0x2e,0x04, + 0x3f,0xc2,0x7a,0x88,0x0b,0x2b,0x9d,0x40,0xb0,0x3e,0x91,0x19,0xb8,0x81,0xe8,0xb2, + 0xdf,0xd3,0xfa,0x19,0xf5,0x9a,0x30,0x8e,0x18,0xa8,0xae,0x61,0xed,0x42,0xba,0x2f, + 0xa2,0xf6,0x05,0x91,0x09,0x1d,0x74,0x35,0xfa,0xb1,0x8b,0xa7,0x79,0x15,0xc3,0x80, + 0xe9,0x7a,0x1a,0x32,0x14,0xbd,0x11,0x77,0x5e,0x08,0x36,0x61,0xa4,0x41,0x74,0x22, + 0x50,0x10,0xbc,0xed,0x68,0xe7,0xe3,0x47,0x84,0x0b,0xa1,0x65,0x39,0x75,0xd4,0x6b, + 0x43,0x6a,0x0f,0x9f,0x26,0x1d,0x71,0x2b,0x17,0x7f,0xfe,0xf2,0xfb,0xb1,0x82,0x44, + 0xe6,0xb5,0xc6,0x5a,0x57,0xd1,0xd8,0x3a,0xdc,0x71,0x54,0x03,0x78,0x87,0x76,0x5d, + 0xf2,0x0c,0x6d,0xd7,0x59,0xce,0x26,0x5d,0xcc,0x0a,0xbc,0x27,0xf8,0x55,0xb5,0x30, + 0x25,0x42,0x3f,0x64,0x98,0xf7,0x45,0xdc,0x89,0x48,0xcb,0x5d,0xe1,0x52,0x24,0xd2, + 0xd0,0xc2,0xb5,0xd8,0xd2,0xf7,0xe5,0xc4,0x6c,0xbc,0x65,0xb8,0xb2,0x1a,0x44,0xbd, + 0x8f,0xb0,0x47,0x84,0x80,0xc1,0x4b,0x61,0x9e,0xe8,0xf3,0xfb,0x00,0x8e,0xa6,0xcb, + 0xa5,0x07,0x76,0xce,0xbd,0x45,0x95,0x9b,0xdd,0x56,0x6a,0xd5,0x2e,0xea,0x1c,0x6a, + 0xc5,0xbf,0x0a,0x5e,0xd8,0xd6,0x01,0xc0,0xe7,0x68,0xb6,0xdf,0x3f,0x9e,0x34,0xeb, + 0x76,0xfb,0x14,0xf2,0xfd,0xeb,0xdd,0x3a,0x40,0xbb,0xbb,0x8b,0xa6,0x4f,0x87,0x3b, + 0x3e,0xbd,0xac,0xd0,0x4d,0xa9,0xcf,0xf0,0xed,0x05,0xf6,0x2c,0x70,0x14,0x07,0xa3, + 0x2d,0xd7,0x82,0x0e,0x58,0xa3,0xf7,0xe0,0x61,0xd8,0x18,0xe9,0xf5,0x26,0x05,0xb6, + 0x63,0xa1,0xa9,0x00,0x26,0x04,0x74,0x04,0x03,0x47,0xf1,0xb0,0x5e,0xf4,0x41,0xd7, + 0x04,0x5f,0xd1,0xba,0x0f,0x4e,0x5b,0x4a,0xea,0x79,0x46,0x15,0xe2,0xb5,0x3b,0x46, + 0xa8,0xf1,0xa9,0xde,0x10,0xc2,0x31,0x78,0xc9,0xaa,0x3f,0xd4,0xb2,0xc6,0xc2,0x17, + 0xf5,0x9a,0x5d,0x4c,0xd4,0x83,0x32,0xa7,0xdf,0xcd,0xb6,0x9c,0x78,0x3c,0x1c,0xba, + 0x5d,0xd0,0x30,0xd1,0x9c,0xc6,0x00,0x64,0xd0,0xbe,0x45,0x0f,0xf4,0x71,0x03,0xce, + 0x56,0xfa,0xe5,0xfb,0x7f,0x96,0x17,0xfd,0x83,0x0a,0x1f,0x00,0x00, }; constexpr size_t KNOBS_INDEX_HTML_GZ_LEN = sizeof(KNOBS_INDEX_HTML_GZ); // diff --git a/firmware/patternflow/src/patterns_index.h b/firmware/patternflow/src/patterns_index.h index a48a988a..2dfe0ac7 100644 --- a/firmware/patternflow/src/patterns_index.h +++ b/firmware/patternflow/src/patterns_index.h @@ -28,194 +28,149 @@ static const char PATTERNS_INDEX_HTML[] PROGMEM = R"HTML( - + Patternflow - Patterns
        -

        Patterns

        -
        +/* Touch: no drag and drop on a phone, so arrows instead, in the room the + module chip leaves (the checkbox says it is a module). Narrow buttons keep + the name wide; their 40px hit areas meet in the 6px gaps. */ +@media(pointer:coarse){.btn.mv{display:inline-flex;width:34px;padding:0;font-size:16px}.chip.mod,.fine{display:none} +.list>li{gap:6px;padding:4px 6px}.list .btn.sm::after{inset:-4px -3px}.list .dan{padding:0 8px}#bulk{row-gap:10px}} +@media(min-width:960px){.wrap{max-width:1080px;padding-top:32px} +.grid{display:grid;grid-template-columns:380px minmax(0,1fr);gap:48px;align-items:start} +.grid section{margin-top:0}.lc{position:sticky;top:8px}.q{max-height:55vh;overflow:auto}} + +
        +

        Patterns

        —
        - -
        -

        Storage needs formatting

        -

        This board's pattern partition isn't readable — either it has never been - formatted, or its filesystem is damaged. Format it once, and patterns install - normally from then on.

        -
        - - -
        + + -
        -
        +
        +

        Upload

        -
          +
          -
          -
          - -
          +
          -
          +
          -

          Installed

          -
          - - - - - +
          +

          Installed

          +
          -
          -
            +
              + +

              Tap or click a name to play it. Drag modules to reorder. Presets are built into the firmware and can’t be removed here.

              -
              Presets are built into the firmware and cannot be removed here. - Home
              -
              + +
              )HTML"; + +)HTML"; // GENERATED by firmware/toolchain/console_pages.py build — do not edit. -// gzip -9 of PATTERNS_INDEX_HTML (43203 bytes → 15416 bytes), served with Content-Encoding: gzip. +// gzip -9 of PATTERNS_INDEX_HTML (42129 bytes → 15116 bytes), served with Content-Encoding: gzip. static const uint8_t PATTERNS_INDEX_HTML_GZ[] PROGMEM = { - 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xcd,0x7d,0xdd,0x76,0x1b,0x47, - 0x92,0xe6,0x3d,0x9f,0xa2,0x04,0x4f,0xb3,0x50,0x66,0xa1,0x08,0x50,0x3f,0xb6,0x01, - 0x81,0x1c,0xc9,0x92,0xc6,0x9e,0x96,0x6c,0x8d,0x28,0x6f,0xf7,0x58,0xd6,0xf4,0x29, - 0x00,0x09,0xa2,0xcc,0x42,0x15,0x5c,0x55,0x20,0xc5,0x26,0x31,0x67,0xae,0xf6,0x01, - 0x76,0xe7,0xcc,0xde,0xec,0xf5,0x3e,0xc0,0x5e,0xef,0xd3,0xf8,0x49,0x36,0xbe,0x88, - 0xcc,0xac,0x2c,0xa0,0x28,0xd1,0xdd,0xbd,0x67,0xb6,0x8f,0x9b,0x42,0xfd,0x65,0x46, - 0x66,0x46,0xc6,0x7f,0x44,0x3e,0xbe,0x37,0xcb,0xa7,0xd5,0xd5,0x4a,0x79,0x8b,0x6a, - 0x99,0x1e,0xef,0x3d,0xc6,0x3f,0x5e,0x1a,0x67,0x67,0xe3,0x8e,0xca,0x3a,0xb8,0xa1, - 0xe2,0xd9,0xf1,0xe3,0xa5,0xaa,0x62,0x6f,0xba,0x88,0x8b,0x52,0x55,0xe3,0xce,0xba, - 0x9a,0xf7,0xbe,0xc4,0xc3,0x72,0x5a,0x24,0xab,0xca,0x2b,0x8b,0xe9,0xb8,0x73,0xb8, - 0x9a,0xf7,0xa6,0x79,0x56,0xe6,0xa9,0x8a,0x7e,0x2e,0x4f,0x16,0xe3,0x59,0xff,0x68, - 0x72,0xff,0xfe,0xd1,0x51,0xe7,0xf8,0xf1,0xa1,0xbc,0x78,0xac,0x3f,0x38,0x4e,0xe6, - 0xdd,0x7b,0x97,0x49,0x36,0xcb,0x2f,0xa3,0xd7,0x2f,0x82,0xee,0x7c,0x9d,0x4d,0xab, - 0x24,0xcf,0xba,0xc1,0xf5,0x45,0x5c,0x78,0x7f,0x18,0xcb,0xb3,0xf0,0x87,0xb1,0x7f, - 0x18,0xaf,0x92,0xc3,0xb2,0x8a,0xab,0x75,0xe9,0x87,0x2f,0xc7,0xef,0xde,0x87,0xaf, - 0xc6,0x47,0xea,0xab,0xf0,0x34,0xfc,0x31,0x7c,0x3d,0xfe,0x03,0x7d,0x3e,0xbe,0xc6, - 0x63,0x35,0xf4,0xd3,0xe4,0x42,0xf9,0xe1,0x2c,0x29,0xaa,0xab,0xe1,0xbd,0x41,0x78, - 0x31,0xcc,0xd6,0x69,0x1a,0x9e,0xa9,0x6a,0xf8,0x0f,0x61,0x92,0xcd,0xd3,0xe4,0x6c, - 0x51,0x0d,0xbf,0x5b,0x2f,0x27,0xaa,0x08,0x17,0x79,0x3a,0x1b,0x7e,0x3f,0xf9,0x59, - 0x4d,0xab,0xb0,0x8c,0xaf,0x86,0x16,0x82,0x2a,0x3c,0x0f,0x55,0x70,0xad,0xf6,0xf7, - 0xbb,0x2a,0xaa,0xd4,0x87,0xea,0xeb,0x3c,0xab,0x54,0x56,0x8d,0xab,0x60,0x13,0x4e, - 0xd6,0xa5,0xf3,0xea,0x24,0x5c,0x05,0xd7,0xe6,0xca,0x9b,0x13,0xf0,0x93,0x68,0x96, - 0x94,0xf1,0x24,0x55,0xb3,0xf1,0xbd,0xc1,0xc6,0xbd,0xea,0x8f,0x56,0x51,0xb5,0x50, - 0x59,0x77,0x1e,0xce,0x83,0x51,0xa1,0xaa,0x75,0x91,0x79,0xab,0x4d,0xb8,0xca,0xd3, - 0xb4,0x6e,0xb1,0x0c,0x97,0xe1,0x34,0xcc,0x65,0x16,0xaa,0x70,0x1e,0x9e,0x8d,0x07, - 0x23,0xdb,0xc3,0x1b,0xea,0xe1,0x6c,0x7f,0xff,0xde,0x9c,0x60,0x9b,0x8f,0x07,0xe1, - 0x34,0x55,0x71,0xf1,0x36,0x59,0xaa,0x7c,0x5d,0x75,0xab,0x20,0xec,0x96,0xd1,0x34, - 0x4e,0xd3,0x93,0xb2,0x1b,0x0c,0xff,0xa1,0x5b,0x06,0x81,0xee,0xd1,0xb4,0x3e,0x0b, - 0xae,0xa7,0xdd,0x59,0x88,0x59,0xa1,0xb1,0xd8,0xdb,0x0a,0xb7,0x79,0xaa,0x54,0xb0, - 0xd1,0xdf,0xfc,0x3e,0xfc,0x7d,0x10,0x6c,0x6c,0xcf,0xbf,0xa7,0x9e,0xe7,0xe3,0xfe, - 0x68,0xab,0xc7,0x11,0x41,0xd3,0xad,0xc6,0x84,0x12,0xe6,0xde,0x9b,0x70,0x49,0xdf, - 0xe5,0xfb,0xfb,0x79,0x34,0x4f,0x8a,0xb2,0x1a,0x8f,0x69,0x22,0x4e,0xe8,0xf3,0x21, - 0x01,0xaf,0x87,0x4d,0xcb,0x95,0xaf,0x86,0xce,0x92,0x9f,0xed,0xb6,0xbc,0x09,0xa9, - 0xd1,0xfa,0x9d,0x2c,0xb8,0x5e,0x8e,0xb3,0xd1,0xfc,0xe6,0x86,0x9a,0xda,0x84,0x59, - 0x7e,0x39,0x7c,0xb3,0xa1,0x77,0x18,0x2d,0xea,0xd7,0xa6,0x34,0x92,0xfd,0xfd,0x97, - 0xd1,0x6a,0x5d,0x2e,0xe8,0x62,0x74,0x7a,0x42,0x97,0xd3,0xee,0x69,0x30,0xfc,0xf1, - 0xe4,0xc7,0x88,0xbe,0x22,0x38,0x7e,0x1c,0xbf,0x8e,0x30,0xe9,0xdd,0x1f,0xc2,0x57, - 0xe1,0x33,0x6a,0xec,0x32,0xae,0xa6,0x8b,0xd3,0xad,0x96,0x96,0xc1,0xf5,0xeb,0x48, - 0x9a,0x27,0xb8,0x7f,0x8c,0x08,0x9a,0xee,0xab,0xf1,0xab,0xb8,0x5a,0x44,0xcb,0x84, - 0x1e,0x87,0xaf,0x02,0xfe,0x34,0xa9,0x5e,0xe4,0xc5,0x33,0x75,0x91,0x4c,0x55,0xfd, - 0x31,0xad,0x5f,0x3e,0xce,0x6f,0x6e,0xae,0x37,0x66,0xa1,0x33,0x75,0xe9,0xbd,0x2e, - 0xf2,0x65,0x52,0xaa,0x7a,0x39,0xae,0xc2,0x4c,0x16,0x7a,0x51,0x83,0x74,0xa4,0xee, - 0xd7,0x0b,0x53,0x06,0xd7,0x25,0x2d,0x77,0x37,0x8f,0x26,0xeb,0x24,0x9d,0xed,0xef, - 0x97,0xf2,0x63,0x3c,0xd6,0x77,0x02,0x9a,0xfe,0x45,0x84,0xe9,0xec,0x06,0xe1,0x15, - 0x56,0x7c,0x13,0x8c,0x9c,0xd5,0x70,0xe6,0xd8,0xbc,0x36,0xca,0xba,0xcf,0x8b,0x22, - 0x2f,0xba,0x7e,0x25,0x2f,0xf9,0x18,0x48,0x1e,0xe9,0xab,0x9b,0x9b,0xaf,0xd4,0x03, - 0x6a,0x65,0xb3,0xa9,0xd1,0xee,0x1f,0xba,0x6b,0xa0,0xa4,0x1e,0xca,0x5c,0xd1,0x74, - 0xf1,0x9d,0x2d,0xec,0x2a,0x82,0x6b,0xec,0xea,0x22,0xca,0xcf,0x83,0x6a,0x51,0xe4, - 0x97,0x9e,0x74,0x54,0xe8,0x79,0xb4,0x58,0xcf,0xd8,0x81,0x9d,0x75,0x52,0xf0,0x3f, - 0xb4,0x28,0x05,0x11,0x0c,0x80,0xb9,0x71,0x70,0xee,0x19,0xc6,0x4f,0x2d,0xd2,0xdf, - 0x53,0xda,0xe7,0xab,0xb9,0xac,0xd1,0xb8,0x1c,0xbd,0x8c,0xe6,0x79,0xf1,0x3c,0x26, - 0x30,0x6c,0xe7,0x73,0xc2,0x4f,0x7a,0x13,0x80,0x6f,0x82,0x6e,0x60,0xe9,0xcd,0x9e, - 0x10,0xae,0x2c,0x5e,0xaa,0x71,0xe7,0x22,0x51,0x97,0xab,0xbc,0xa8,0x3a,0xde,0x54, - 0xef,0xe9,0xce,0x65,0x32,0xab,0x88,0x50,0xf1,0x02,0xf6,0xf8,0x82,0x28,0x45,0x52, - 0x25,0x71,0xda,0x2b,0x69,0x2f,0xa9,0xf1,0x00,0x54,0xae,0x4a,0xaa,0x54,0x1d,0xbf, - 0x8e,0xab,0x4a,0x15,0x44,0x47,0x68,0x68,0x3d,0x4f,0x5f,0x95,0x8f,0x0f,0xe5,0x29, - 0xd1,0xc2,0xea,0x0a,0xff,0x1e,0x7e,0xee,0x3d,0x8b,0x8b,0x73,0x2f,0xc9,0xca,0xaa, - 0x58,0x2f,0xa9,0x1b,0xaf,0xca,0xcf,0x55,0x56,0x7a,0xbf,0xfe,0xdb,0xbf,0x7b,0x25, - 0x41,0xc2,0xe0,0x94,0x9e,0xba,0x50,0xc5,0x95,0xa7,0x29,0xa6,0xb7,0x8a,0xcf,0x94, - 0xb7,0x2e,0xe9,0x7e,0xb7,0xd7,0x9b,0x16,0x2a,0x5e,0x7a,0x49,0xb9,0xe7,0x79,0x5e, - 0x87,0xa6,0x59,0x9e,0x4e,0xe2,0xe9,0xf9,0x59,0x91,0xaf,0xb3,0x59,0xc7,0x9b,0x5c, - 0x79,0x8b,0x84,0x96,0xb4,0xb8,0x0a,0x42,0x2f,0x03,0x65,0xf3,0x2e,0xe2,0x74,0xad, - 0xca,0xc8,0x7b,0x4b,0xef,0x2f,0x09,0x02,0x55,0x25,0xd9,0x99,0x57,0x26,0x95,0xf2, - 0x68,0x05,0xae,0xb8,0xb1,0x55,0xbc,0x52,0xc5,0xc8,0x43,0x93,0x32,0x68,0xea,0x84, - 0xaf,0xaa,0x05,0x5e,0x3e,0xa3,0xb1,0xe1,0xdf,0x24,0xf3,0x62,0x6f,0x86,0x51,0x14, - 0x79,0xbe,0x8c,0xbc,0xcf,0x0f,0xf7,0x86,0xf4,0xab,0xba,0xd6,0xa0,0x0d,0x3f,0xeb, - 0x7f,0xdd,0x7f,0xda,0xff,0x6a,0xd4,0xeb,0x25,0xd9,0xf9,0xf0,0xb3,0xe7,0xcf,0x9e, - 0x7f,0xf1,0xec,0x29,0x5d,0x2d,0xd7,0x95,0x9a,0x0d,0x3f,0xfb,0xf2,0xc9,0x97,0x47, - 0x5f,0x1c,0xd1,0xf5,0x3c,0x4e,0xb2,0x6a,0xf8,0xd9,0xc3,0x27,0x0f,0x1f,0x3e,0x78, - 0x34,0xda,0xeb,0xf5,0x8a,0x75,0xaa,0x86,0x9f,0x1d,0x3d,0x38,0x1a,0x0c,0xbe,0x1c, - 0xc9,0x65,0xaf,0xcc,0xe7,0xf4,0xce,0xe0,0xe9,0xe0,0xab,0xc1,0x03,0xba,0x97,0xa2, - 0x85,0x17,0x2f,0x1e,0x7e,0x7d,0xf4,0x9c,0xae,0x72,0x6a,0xfe,0xe1,0x17,0x4f,0xbf, - 0xfc,0xe2,0x05,0x5d,0x5c,0xc6,0x45,0x36,0xfc,0xec,0xd9,0x57,0x4f,0xfa,0xf7,0x5f, - 0xa0,0xb5,0x55,0x9c,0xa9,0x94,0x3e,0xbd,0x3f,0x18,0x0c,0xfa,0xb8,0x51,0xc6,0x59, - 0x39,0xf4,0xbf,0xa5,0xd5,0x2d,0xfc,0x70,0x9d,0xf0,0x75,0xaf,0x54,0x45,0x32,0x0f, - 0xcb,0xab,0xb2,0x52,0xcb,0xde,0x3a,0x09,0xeb,0x9b,0xf8,0x64,0x99,0x67,0xf9,0xd0, - 0xff,0x47,0x55,0x3d,0x2d,0x08,0xd8,0xd2,0x7b,0x45,0xd7,0xfc,0x2d,0x1e,0x94,0xab, - 0x78,0xaa,0xc2,0xd3,0x17,0xb8,0xd9,0x7b,0xa3,0xce,0xd6,0x69,0x5c,0x84,0xaf,0x54, - 0x96,0xe6,0xa1,0x7d,0xbc,0xd9,0xfb,0xfc,0x7a,0x92,0x7f,0xe8,0x95,0xc9,0x9f,0x69, - 0xee,0x86,0x93,0xbc,0x98,0xa9,0xa2,0x47,0x77,0x36,0x7b,0x93,0x7c,0x76,0x75,0x4d, - 0x6b,0x71,0x96,0x64,0xc3,0xfe,0xa8,0x5e,0xbf,0x21,0x6d,0x7b,0xb3,0xcc,0xc1,0x68, - 0x9a,0xa7,0x79,0xa1,0x6f,0xd1,0x74,0x06,0xa3,0x39,0xa1,0x27,0x4d,0xdd,0x32,0x49, - 0xaf,0xf4,0x6d,0x80,0x1c,0x8c,0xf6,0xd2,0x24,0x53,0xbd,0x85,0x62,0x46,0x36,0x88, - 0x1e,0x8e,0x7a,0x97,0x6a,0x72,0x9e,0xd0,0xbb,0xf8,0xa0,0x5c,0xd2,0x0a,0x61,0x19, - 0x87,0x71,0x06,0x0c,0x4e,0xe2,0x52,0xcd,0x36,0x7b,0xd1,0x65,0x11,0xaf,0x08,0x88, - 0x0f,0x82,0xdf,0xc3,0x47,0x5f,0xf6,0x57,0x1f,0x46,0x06,0x28,0x2f,0x5e,0x57,0xf9, - 0x68,0x15,0xcf,0x66,0xf8,0xf0,0xfe,0xd1,0xea,0x83,0x77,0x44,0xcf,0xbd,0x47,0x0f, - 0x56,0x04,0x3f,0x78,0xbf,0x2a,0xae,0x89,0x8d,0xad,0x52,0x30,0xc9,0x54,0x7d,0x18, - 0x51,0xc3,0x67,0x59,0x8f,0xb0,0x6a,0x59,0x0e,0xa7,0x0a,0x33,0x3d,0x3a,0x8b,0x57, - 0xc3,0x2f,0xa9,0x51,0xdd,0x0c,0x8d,0xbd,0xaa,0xf2,0xe5,0x70,0x40,0xad,0x8d,0xf6, - 0xec,0x7c,0xc8,0x3d,0x6a,0x9b,0xf0,0x3d,0x99,0x79,0x32,0x30,0x20,0x40,0x40,0x40, - 0xce,0x08,0xb9,0x04,0xbe,0x2f,0xe8,0x23,0x3d,0x44,0xfc,0xdc,0x99,0x34,0x42,0x8f, - 0x60,0xa4,0x1b,0x2d,0xe2,0x59,0x42,0x64,0x7b,0xc0,0xb0,0x0e,0xae,0x65,0x1a,0x92, - 0x3f,0xab,0xe1,0xe0,0x21,0x7d,0xca,0x97,0x97,0xd2,0xd4,0xa3,0x7e,0x7f,0x94,0x2a, - 0x6c,0xd9,0x1e,0x16,0x0d,0x83,0x8d,0xfa,0x03,0xb5,0xb4,0x13,0x31,0xc2,0xe0,0x86, - 0x03,0x02,0xa5,0x5c,0x4f,0xae,0x77,0x57,0x00,0xcb,0xad,0x57,0x46,0x7a,0xa0,0x4e, - 0x1b,0x2b,0xc7,0xa8,0x4e,0x43,0x29,0x15,0x93,0x24,0xbd,0xec,0x3d,0xf0,0xba,0xa3, - 0x2f,0x19,0xc0,0xa3,0xeb,0xad,0xcf,0x3f,0x09,0xe0,0x57,0x04,0x20,0x48,0x64,0xaf, - 0x2a,0x08,0x01,0x88,0xea,0x2d,0x87,0xeb,0x15,0xed,0xe0,0x29,0x2d,0xed,0x68,0xcf, - 0xed,0x9d,0x37,0x5e,0x50,0x2f,0x6b,0xdf,0x1b,0xf4,0xd1,0x69,0x34,0x2b,0xf2,0x95, - 0x5d,0xc0,0x49,0x9a,0x4f,0xcf,0xf5,0xe4,0xf1,0x52,0xcc,0xe2,0x72,0xa1,0x1a,0x6b, - 0xb1,0x35,0xb5,0xf7,0xeb,0x65,0x1d,0x1e,0x3d,0xa2,0x2f,0x06,0x58,0x68,0x86,0x89, - 0x11,0xc1,0xa0,0xc0,0x9e,0xb3,0x4e,0xc5,0xd9,0x24,0xee,0x1e,0x3d,0x7c,0x18,0x9a, - 0xff,0x47,0xfd,0xa3,0x60,0xc4,0x43,0x48,0x30,0x35,0x66,0x8b,0x30,0xfc,0x5e,0x34, - 0x78,0x58,0x86,0xf5,0xd7,0x7c,0x3d,0x9a,0xae,0x8b,0x92,0xc6,0xb6,0xca,0x13,0xb4, - 0xae,0x87,0x11,0xe5,0x44,0x31,0xaf,0xdd,0x8f,0x1b,0x28,0xd1,0x02,0xc0,0x57,0x47, - 0xe1,0x83,0x47,0xd4,0xfd,0xa3,0x40,0x37,0xe1,0xad,0xea,0xed,0xe8,0x2c,0xc6,0xfd, - 0xad,0xb5,0x94,0xd9,0x34,0xdf,0x4c,0xae,0xdb,0x77,0x68,0xbd,0x72,0xf4,0x26,0x6d, - 0xbc,0xea,0x2f,0x47,0x9b,0x91,0x83,0x2d,0x8f,0xb0,0x6e,0x49,0xb6,0x5a,0x57,0xef, - 0x20,0x98,0x8f,0xe7,0x49,0xaa,0xde,0xdb,0x25,0xcc,0xf2,0x8c,0x28,0xce,0x3a,0xbd, - 0x4e,0x89,0xfc,0xf7,0x98,0xe7,0xf0,0xbd,0x1a,0x91,0xcd,0x72,0xf5,0xcd,0x52,0xa2, - 0xd1,0xb6,0x7d,0xc7,0x84,0x97,0x46,0x99,0x26,0x77,0xda,0xe1,0x40,0x28,0xdb,0xf8, - 0x57,0x20,0x14,0x77,0xdb,0xde,0xd2,0xcd,0xd6,0x74,0xa3,0x57,0x2f,0xca,0xfe,0x9a, - 0x19,0xa3,0xe9,0x12,0x8a,0x71,0xf4,0xc0,0xb6,0xb7,0xbc,0x96,0x6d,0x3c,0x02,0xaa, - 0x80,0x53,0x0f,0x17,0xc9,0x6c,0xa6,0x32,0xc1,0x58,0x7b,0x53,0xa5,0x69,0xb2,0x2a, - 0x93,0x72,0x74,0xb9,0xa0,0x61,0xf2,0x86,0xc3,0x2c,0x82,0x52,0xd2,0x52,0x56,0xf1, - 0xd9,0x5d,0xe0,0xc2,0x74,0xec,0xec,0xd8,0x47,0x1f,0xdd,0xb1,0x66,0xf6,0x30,0x4d, - 0x8f,0x40,0xdc,0xea,0x9d,0xb8,0x43,0x14,0xb7,0x36,0xe2,0xd1,0x6d,0x28,0x4a,0xd0, - 0x46,0xcb,0x7c,0x76,0xeb,0xbe,0xd8,0xbe,0x81,0x99,0x8a,0x88,0x3e,0x7d,0x6c,0xbf, - 0x7c,0x45,0x6f,0x91,0x1c,0x03,0x49,0x02,0xb2,0x8a,0x11,0x12,0x80,0x22,0x2c,0x3b, - 0x15,0x79,0xea,0xd1,0x74,0x8d,0x48,0xce,0x38,0x87,0xec,0x10,0x57,0x1e,0x61,0xd0, - 0x14,0xf3,0x0b,0x7d,0x87,0x05,0x06,0xbd,0x1e,0xdb,0x3b,0x59,0x6e,0x0f,0x17,0xbc, - 0x97,0x5b,0x61,0x9b,0x15,0x34,0xff,0x39,0x66,0x94,0xf4,0xb8,0xe8,0xfe,0x43,0x01, - 0xf8,0x02,0x53,0x91,0x5f,0x5e,0x3b,0x38,0x7d,0xb4,0x35,0x6d,0xd2,0xc2,0x64,0x4d, - 0x98,0x98,0x45,0x33,0x95,0xf2,0x22,0x0e,0x93,0x6c,0x41,0xac,0xbe,0xfa,0x18,0x46, - 0x69,0xe2,0xe9,0xcc,0x08,0xef,0xa8,0xbd,0xdf,0xb8,0x3c,0x96,0x4e,0xd2,0xfb,0xa0, - 0x92,0xcd,0xa1,0xb7,0xe2,0x5a,0x0d,0xac,0x9e,0x91,0xbb,0xaf,0xa2,0xf3,0xa9,0x51, - 0x33,0xeb,0x59,0x7b,0x60,0x3a,0x9f,0xa9,0x79,0xbc,0x4e,0xab,0x51,0x4b,0xbb,0x32, - 0x8c,0x36,0x9c,0xc2,0xda,0x7f,0x4b,0xe2,0x2b,0x29,0x93,0xde,0x2f,0x6b,0xb5,0x56, - 0x43,0x8f,0xe6,0xc3,0x83,0x4c,0x4f,0xa8,0xec,0x81,0x20,0x85,0x1e,0x2b,0xdd,0xa5, - 0x87,0xef,0xd7,0x68,0x78,0xa6,0x66,0x22,0x7b,0x4e,0x48,0xa5,0xa1,0x39,0xa4,0x17, - 0xe3,0x0c,0x32,0xe7,0x7a,0x95,0xe6,0x31,0x26,0x86,0x1b,0x20,0x54,0x4a,0xaa,0xd2, - 0xcb,0x2f,0x49,0xfd,0x2d,0xf2,0xb3,0x42,0x95,0x25,0x09,0xb0,0x79,0x45,0x02,0x27, - 0x49,0x9f,0x93,0x38,0x45,0x57,0x8c,0x40,0x11,0x77,0xed,0x2e,0xb8,0x43,0xe7,0x84, - 0xa8,0x61,0xd6,0x9b,0x84,0x51,0x3e,0xf2,0x1c,0x92,0x26,0x3c,0xcf,0xac,0xcd,0x23, - 0x4d,0xb7,0x76,0xc9,0xd6,0x0e,0x2b,0xd4,0x74,0x6b,0xef,0x2e,0x24,0x2a,0x7a,0xc8, - 0xcc,0xf6,0x17,0x60,0xe8,0x5d,0x69,0x29,0xde,0xcf,0xfe,0x6a,0x7a,0xd5,0x4e,0x14, - 0x7e,0x29,0xaf,0x5b,0x49,0xdb,0x2f,0x65,0x74,0xa6,0xaa,0x10,0xff,0x42,0x79,0xbd, - 0x6e,0x13,0x60,0xf0,0x70,0xbd,0xda,0xe1,0x79,0xf2,0x80,0x74,0xb8,0xe2,0xaa,0xf1, - 0x0c,0x32,0xb9,0x7e,0x98,0x9f,0x37,0x9e,0xe4,0xe6,0x23,0x6a,0x39,0x6d,0xd9,0xeb, - 0xd1,0x2f,0x84,0x2a,0xd7,0x5a,0xd6,0x3b,0x6a,0x93,0xf5,0x9c,0x65,0x70,0x96,0x5d, - 0xcf,0x35,0xf0,0x6c,0x7b,0x99,0x8d,0x6c,0xdc,0xef,0xff,0x6e,0x24,0xcc,0xa1,0xdf, - 0x2e,0x41,0xa2,0x01,0x55,0x14,0xae,0x94,0xb6,0x2d,0x04,0xf0,0xbe,0x73,0xe9,0x3d, - 0x16,0x79,0x6b,0x05,0x8a,0x65,0x9c,0xd2,0x7e,0x89,0x96,0xe5,0xd9,0x5d,0x59,0x19, - 0xf8,0x96,0x01,0x93,0x59,0x3d,0x3e,0x26,0xf5,0xb6,0x07,0x70,0x5a,0x26,0x49,0x3f, - 0x6d,0x9b,0xdb,0xcf,0xd0,0xed,0xd6,0x7e,0xa0,0xbb,0xa9,0x73,0x5b,0x23,0x38,0x0b, - 0xa0,0xb4,0xab,0xbf,0x86,0x99,0x05,0x5b,0x31,0xf6,0x26,0xc9,0x19,0x6d,0x93,0x49, - 0x11,0x93,0x12,0x4a,0x9b,0xf2,0xfb,0xef,0x9e,0x7b,0x85,0xa2,0xdd,0x53,0x56,0xae, - 0x7a,0x48,0x4c,0xec,0x52,0x15,0xb4,0x5f,0xb3,0xf4,0x8a,0xfe,0x40,0x61,0xac,0xbc, - 0x45,0xcc,0xca,0xe4,0x9c,0x54,0x65,0xec,0x19,0xa2,0x05,0x39,0xbe,0x29,0x98,0x51, - 0x64,0xb9,0xdd,0xd8,0xa4,0xf8,0x52,0x9b,0x50,0xb9,0xbd,0x79,0x91,0x2f,0xa1,0x12, - 0x27,0x33,0x6e,0x01,0xaa,0x70,0x0c,0x62,0x82,0x3d,0x41,0xba,0x2d,0x9a,0xe3,0x06, - 0x2e,0xf3,0x75,0x3a,0xf3,0x26,0xf4,0x52,0x76,0x81,0xed,0xc2,0x34,0x05,0x34,0xa3, - 0x24,0x88,0x08,0x5c,0x62,0x30,0x95,0x22,0x50,0x12,0x22,0x30,0xb4,0x99,0x68,0x32, - 0x61,0xfa,0x43,0x93,0x25,0xa9,0xb8,0x5e,0xa7,0xac,0x92,0x34,0x45,0x6b,0x97,0x79, - 0x71,0x4e,0x03,0xed,0x84,0x1e,0xad,0xd8,0x74,0x61,0x58,0x18,0x8f,0x83,0xf4,0x72, - 0xa3,0xf1,0xc6,0x17,0x84,0x9b,0x20,0x9e,0x21,0x0d,0x75,0x86,0x76,0x96,0xb4,0xeb, - 0xca,0xfa,0x2b,0x6e,0x0b,0x0c,0x0e,0xf6,0x93,0xd2,0x2b,0xa1,0xb5,0x13,0x91,0x5a, - 0xe6,0x90,0x64,0x53,0x0c,0x92,0x04,0xfe,0x3c,0x9b,0x95,0x32,0x44,0xd2,0xe8,0x98, - 0xd4,0xc5,0x25,0x8d,0x6f,0x11,0x67,0x67,0x42,0xca,0x68,0x12,0xd5,0xea,0x2f,0x40, - 0x75,0xb0,0x91,0x6d,0xd2,0xb0,0x45,0xf0,0xb8,0x69,0x30,0xf4,0xc6,0x4e,0x30,0x0f, - 0xee,0xb0,0x43,0xee,0x3f,0xf8,0xdd,0x2d,0x5a,0xd6,0x5e,0x9c,0x25,0xcb,0x98,0x45, - 0x76,0x69,0x6c,0x10,0x0d,0x4a,0x4f,0x91,0x28,0x43,0x14,0xa1,0x97,0xaf,0x2b,0x5a, - 0x06,0x20,0x41,0x45,0x70,0xfc,0xfd,0xb9,0xba,0x9a,0x17,0x6c,0xd8,0x90,0xc1,0x62, - 0x3a,0xae,0x6b,0x29,0x88,0x7f,0xa5,0xb4,0x58,0x7f,0xec,0xf6,0x48,0x59,0xff,0x5d, - 0xb0,0xa9,0xf2,0xf6,0xc7,0x0f,0xfa,0x78,0xca,0xe8,0xfa,0x26,0xbf,0x04,0xea,0x61, - 0xe5,0x92,0xc2,0xbb,0x24,0xe9,0x83,0x3a,0x0d,0x49,0xd6,0x58,0x2e,0x89,0x54,0x63, - 0x3d,0x61,0x65,0x21,0x75,0xd7,0xbb,0xca,0xd7,0x90,0x4c,0xe6,0x49,0x41,0x6b,0x10, - 0x03,0x19,0x21,0x96,0x64,0xb4,0x74,0x8a,0x3f,0xc7,0x32,0x12,0x2a,0xd2,0xe2,0xa7, - 0x31,0x16,0x0b,0x08,0x88,0xef,0xa7,0x69,0x32,0x3d,0xf7,0x32,0xa5,0xe8,0x1e,0xbd, - 0x2e,0xe8,0x0e,0xd9,0x46,0x98,0x52,0x92,0x11,0x96,0x5f,0x28,0xb3,0xc6,0x5a,0xb0, - 0x89,0xce,0x88,0xa5,0xbb,0x32,0xca,0xc6,0xde,0xf4,0x1c,0xf1,0xe3,0x22,0x29,0x93, - 0x49,0x92,0xe2,0x15,0x59,0x3a,0x5a,0x94,0x98,0x95,0xc3,0xb2,0xc9,0x24,0xf0,0xa7, - 0x07,0x0a,0x3d,0x64,0x8a,0x6e,0xd4,0xe9,0x2d,0x3c,0xd8,0x65,0x25,0x5a,0x4d,0x88, - 0x4a,0xea,0x4c,0xd6,0x72,0xf0,0xa0,0xd6,0x9e,0xf9,0x77,0x3c,0xc5,0xab,0xbb,0xf2, - 0x84,0xd1,0x16,0x18,0x4f,0x1a,0xd0,0x80,0xe4,0x5c,0x6c,0xa9,0x1b,0x9f,0x4d,0xd6, - 0xe9,0xf9,0xd6,0xbd,0x08,0xf7,0xde,0xe6,0xb5,0x42,0x55,0xeb,0x9c,0x78,0xf2,0x5d, - 0x5e,0xa9,0xbf,0x46,0x8d,0xa6,0xd5,0x7f,0x01,0x0b,0xb2,0x57,0xac,0xb3,0xc8,0x7b, - 0xe2,0xad,0xe2,0xa2,0x62,0xed,0x51,0xc4,0x4d,0x22,0x41,0xb4,0x6a,0xb4,0x33,0x88, - 0x56,0xd0,0x0a,0x03,0x87,0x60,0x90,0x9b,0x79,0xd3,0x38,0xc3,0xc2,0xc1,0xbe,0x4f, - 0xab,0x79,0xc5,0xbb,0x3c,0xc4,0xea,0x63,0x7b,0x5b,0x0a,0x40,0xd2,0x11,0x13,0xab, - 0xd8,0xa1,0x2a,0x84,0x57,0x0a,0x26,0x3b,0x5a,0x21,0x5a,0x71,0x59,0x47,0xb1,0xd9, - 0xe5,0xd2,0xa7,0xbe,0xb5,0x2e,0xd5,0x0c,0x0d,0x12,0x71,0x23,0x7d,0xd6,0x8b,0x85, - 0x5e,0xce,0x73,0xea,0x35,0x9f,0xf3,0x6f,0x91,0x78,0x20,0x1a,0xad,0x97,0x59,0x08, - 0x24,0xc2,0x5d,0x36,0xfd,0x11,0x5d,0xbc,0x02,0x71,0xe8,0xbc,0x01,0x23,0xf5,0xc0, - 0x19,0xd5,0xac,0xc3,0x00,0x0a,0x9e,0xb3,0xa4,0x05,0xcc,0xa9,0x80,0xbb,0x05,0x53, - 0x4b,0x97,0x76,0x19,0xf1,0x9b,0x21,0xe2,0x31,0x17,0x84,0x96,0xdf,0xeb,0x69,0x61, - 0xa1,0x8c,0x3e,0x41,0x7b,0xd3,0x1c,0x9b,0xb1,0xca,0xc5,0xbe,0x47,0x7a,0x2c,0x66, - 0x80,0xa9,0x24,0xd3,0x33,0x6e,0x57,0x9b,0x02,0xa1,0xe5,0xfe,0x19,0x1d,0x9f,0xe5, - 0x22,0xd2,0x81,0x04,0xd3,0xcc,0x81,0x20,0x32,0x6c,0x13,0x35,0x8d,0x69,0xdc,0x98, - 0x2f,0xbc,0x2b,0xc4,0x9e,0xa6,0x5a,0x60,0x22,0x7a,0x3f,0x5b,0x83,0x59,0x88,0xb4, - 0x88,0x69,0x98,0xaa,0xa2,0x8a,0xb1,0x7b,0x68,0x80,0x34,0xd7,0xb2,0x73,0xc4,0x27, - 0x40,0x0b,0xda,0x40,0x25,0x17,0xcf,0x8f,0x5c,0x1d,0x13,0x08,0xec,0x81,0x47,0xde, - 0x2a,0x89,0xb3,0xec,0xd1,0x62,0xb1,0xd8,0xd1,0x6d,0x06,0x5f,0x84,0x83,0x47,0xfd, - 0xf0,0xd1,0x7d,0x63,0x0c,0x30,0x90,0xb4,0x11,0x4e,0xf3,0xcc,0x5b,0x1c,0xed,0x4a, - 0x3a,0xae,0x89,0x45,0xd8,0xb7,0x7d,0xfd,0x37,0xda,0x16,0xec,0x77,0x96,0x28,0xb8, - 0xac,0x9c,0x6d,0x5a,0x35,0x31,0x89,0x56,0x45,0xb2,0x6c,0xd3,0x0e,0x04,0xa8,0x16, - 0x81,0x6c,0xeb,0x5b,0xa3,0x5f,0x7c,0x64,0x66,0x06,0x47,0x81,0xd5,0xe7,0xef,0xd4, - 0x85,0xb6,0xca,0xcc,0xe7,0x2d,0x8a,0x07,0x6d,0xc2,0x1e,0xe9,0x0f,0xf9,0xa5,0x9a, - 0x99,0x05,0x12,0x63,0x05,0xaf,0xdf,0x66,0x0f,0xfb,0x45,0x35,0xe5,0xaf,0x47,0x8e, - 0x09,0xd1,0x8a,0xf7,0x9f,0xb0,0x61,0xdc,0x51,0x3e,0xbf,0x85,0xc8,0xc4,0xd7,0x6d, - 0x2b,0x03,0x17,0x28,0x8b,0x5c,0xf3,0x39,0x0c,0xae,0xde,0x67,0x30,0xb5,0x84,0x3b, - 0x77,0xe7,0x65,0x3d,0xec,0x87,0xa2,0x2f,0xe7,0xeb,0xe9,0x62,0xe8,0x3d,0x00,0xde, - 0x56,0x31,0x6d,0x38,0x92,0x06,0xb4,0x76,0x43,0xd2,0xd6,0x19,0x11,0x2b,0xbd,0x7b, - 0x69,0x3b,0x7c,0x97,0x7b,0x50,0x74,0x79,0x53,0xf2,0x9e,0xca,0x61,0x73,0x5f,0x2d, - 0x68,0x43,0xf0,0x8e,0x23,0xa2,0xf3,0xeb,0x7f,0xfc,0xef,0x5f,0xff,0xe3,0xff,0x30, - 0x8b,0x23,0xa9,0xc2,0xd2,0x11,0x98,0xe4,0xf9,0x07,0x69,0xfd,0x34,0x03,0xd4,0x13, - 0x09,0x72,0x2a,0xbe,0x80,0xeb,0x00,0x3e,0x5a,0x35,0x3d,0x9f,0xe4,0x1f,0x64,0xa7, - 0x27,0x55,0xc0,0x3b,0xef,0xef,0x89,0x5f,0x26,0x71,0x57,0xab,0xa2,0xc3,0x69,0x0e, - 0x47,0x6e,0x70,0x0d,0xd3,0x8f,0xdd,0x6d,0x47,0xa2,0x1a,0x59,0x4b,0x4a,0xe3,0x41, - 0xdf,0xe0,0x7d,0x4f,0x5f,0xba,0xa6,0xe8,0x23,0x21,0xfb,0xc4,0x48,0xec,0x37,0x0f, - 0x6b,0x1b,0x73,0x6f,0xf0,0xb0,0x89,0xcb,0xd7,0xab,0x5c,0x1b,0x02,0x0b,0x45,0x2c, - 0x9f,0xa8,0x6d,0x43,0x9b,0x1d,0xc6,0xf3,0x8a,0x6d,0x03,0xec,0xa3,0x19,0x76,0x3a, - 0x23,0xfb,0x7e,0x3c,0xa1,0xf5,0xa7,0x55,0x1a,0x01,0x1d,0x7a,0xbc,0xac,0x5a,0xc0, - 0x95,0x8b,0x54,0xcd,0x2b,0xda,0x7d,0x05,0x43,0xd5,0x6f,0x72,0x32,0x11,0x7f,0xb4, - 0xc5,0xe8,0xcb,0x2d,0x75,0xbd,0x6f,0x21,0x58,0x5e,0x18,0x00,0xb8,0xb1,0x1e,0xde, - 0x94,0xf6,0x7a,0x5f,0x8a,0xb4,0x7e,0x71,0x80,0x66,0x35,0xe2,0xf2,0x4b,0x42,0x07, - 0x8c,0x21,0xa6,0x8d,0x75,0x92,0x5e,0xd8,0x63,0xbd,0x0f,0xa6,0x2a,0xc6,0x95,0x67, - 0xaa,0x3c,0xc7,0x28,0x0c,0xb3,0x58,0x25,0x59,0x46,0xec,0x0b,0xed,0x85,0xbc,0xba, - 0x46,0x36,0xe7,0xce,0xad,0xbc,0x72,0xb9,0xb0,0xce,0xa2,0xcb,0xa4,0x5a,0x90,0x38, - 0xc4,0xc8,0x32,0x25,0xa4,0x4a,0xc1,0xe9,0x0c,0xb6,0x80,0x06,0x6b,0x74,0xd2,0x7c, - 0x88,0xdf,0xf7,0xe2,0x29,0x11,0x63,0x22,0xe7,0x5a,0x10,0x77,0x91,0xa3,0x36,0xa8, - 0x7d,0xf5,0x88,0x16,0x94,0xb0,0x63,0xdb,0x75,0x30,0x18,0x3c,0x90,0x95,0xa6,0x16, - 0x6b,0x11,0xe6,0xac,0x48,0x66,0x23,0xfc,0xe9,0x91,0x68,0xb2,0x82,0x0c,0xd7,0x93, - 0x1e,0xcb,0xe1,0x83,0xfb,0xf0,0x25,0x50,0xc3,0xd4,0x46,0xb7,0x1f,0x0e,0xe6,0x45, - 0xc0,0xd2,0xcd,0x83,0x6d,0x79,0x86,0xf8,0x56,0x51,0x49,0xc3,0x2f,0x6b,0xf4,0x20, - 0x61,0x7e,0x7a,0x7e,0xc5,0x8b,0x3d,0xf8,0xd2,0x74,0xfc,0xc6,0x6b,0xb1,0xb0,0xb3, - 0x26,0xb5,0xd9,0x7b,0x7c,0x28,0x4e,0xb8,0xc7,0x87,0x12,0xb5,0x00,0xff,0xcb,0xf1, - 0xe3,0x59,0x72,0x41,0x72,0x5e,0x5c,0x96,0xe3,0x0e,0x06,0x64,0x82,0x1a,0x54,0x71, - 0xfc,0x98,0xf4,0xb8,0xcc,0x3c,0x9b,0xe5,0x15,0x47,0x2a,0xd0,0xad,0xe3,0xc7,0x8b, - 0xc1,0x71,0xed,0xe1,0xa3,0x8b,0xc6,0x9b,0xe5,0x7a,0xd2,0xf1,0x92,0xd9,0xb8,0x33, - 0x2f,0x3b,0xc7,0x3d,0xf3,0xc9,0xa1,0x6e,0x74,0x8f,0xfe,0xe7,0xf6,0x69,0xe8,0xbc, - 0xfe,0x04,0x57,0x6f,0xd6,0x08,0xad,0xf0,0xbc,0xc7,0x8b,0xa3,0xe3,0xd3,0x2a,0x2f, - 0xb0,0x9c,0x22,0x83,0x6a,0x41,0x86,0x96,0x92,0xda,0x3b,0xe2,0x77,0x56,0xc7,0xac, - 0x01,0x4d,0x68,0xcf,0xce,0xfc,0x92,0xd6,0x9e,0xc1,0x72,0x04,0xa2,0xa4,0xcc,0xfc, - 0x8a,0x35,0x0f,0x28,0x32,0x8c,0x2a,0x2a,0x61,0x11,0x38,0xd9,0x16,0x94,0xa8,0x3d, - 0x2b,0x2a,0x85,0x5e,0x5e,0xb0,0x2d,0x06,0xf6,0x1c,0xf1,0x8e,0xb1,0x9a,0x15,0x2f, - 0x09,0x1c,0xd2,0xbb,0x5e,0xf0,0x8b,0x68,0x03,0x7a,0x9f,0xe8,0x47,0xba,0xf3,0x52, - 0xe4,0x6e,0xd6,0xb4,0x44,0x09,0x26,0x29,0x80,0xf5,0x1f,0xf8,0x84,0xe9,0xfd,0xe8, - 0xf1,0xe1,0x8a,0x81,0x77,0xe6,0x41,0x73,0x39,0x1e,0x38,0x3d,0xd1,0xd2,0x94,0x99, - 0x7c,0x95,0x7a,0x60,0x53,0x7a,0x92,0x96,0xb4,0x14,0xba,0xff,0x52,0xe6,0xe7,0xf1, - 0xa1,0x7c,0xa0,0xbf,0x76,0x97,0xc3,0x88,0x9b,0xf6,0x5b,0xbe,0x30,0x4b,0x09,0x28, - 0x0e,0x09,0x0c,0x5a,0x75,0xf9,0xa7,0xb1,0x38,0xc0,0x64,0x20,0x44,0xf3,0xd6,0x4b, - 0x8e,0x6d,0x11,0x34,0x33,0xeb,0xf4,0x03,0xef,0x53,0xbb,0x2a,0xa4,0x34,0x12,0xc8, - 0x06,0x7a,0x22,0xe0,0xd2,0x3b,0xff,0xd2,0x30,0xb2,0x70,0xee,0xb1,0x0d,0xbf,0x83, - 0x39,0x36,0x08,0x80,0x5f,0x90,0xcb,0x57,0xd5,0xb8,0xf3,0xf9,0xe1,0xe7,0x1d,0x6f, - 0xb9,0x4e,0xab,0x64,0x05,0xe7,0x31,0x7f,0xb7,0x3a,0x7e,0x06,0x86,0xf0,0x78,0x72, - 0x4c,0xfc,0x66,0x49,0x03,0x3f,0x96,0x25,0xc2,0x7a,0xc5,0x7c,0xfb,0xcf,0xc9,0x8a, - 0x6f,0x13,0xfb,0x39,0x67,0xbd,0x99,0xd7,0x52,0x74,0x19,0x12,0xf8,0xa6,0x8b,0x3c, - 0x2f,0x95,0x5e,0x02,0x34,0x68,0xe0,0x84,0x93,0xa2,0x73,0x2c,0x7c,0xa3,0xf4,0x0e, - 0xb4,0x5e,0xc5,0xce,0x77,0x0f,0x14,0x61,0x4a,0x6c,0x81,0x16,0x3a,0x4d,0x21,0xd5, - 0xb2,0xb6,0xbf,0xbf,0x24,0xcd,0x25,0xaf,0x46,0x1e,0x75,0xe9,0xad,0x33,0x74,0x58, - 0x1a,0x46,0x34,0x21,0xaa,0x56,0xaa,0xc2,0x2c,0xf5,0x21,0x4f,0x09,0xff,0x5c,0xdb, - 0x99,0x61,0x81,0x50,0x06,0xfe,0x0b,0x96,0x64,0x9d,0x6e,0xa3,0xc5,0xb2,0x3c,0x93, - 0xe7,0xf8,0x71,0xac,0xd7,0xa8,0xf9,0x0a,0x2b,0x94,0xf2,0x92,0xfc,0x3c,0x7e,0x9c, - 0xd0,0x9b,0x49,0xfb,0xdb,0x9f,0xc2,0x33,0x69,0x88,0x0d,0x59,0x1d,0x8f,0xe9,0x05, - 0xdd,0x76,0x68,0x76,0xe7,0xd8,0x95,0xcd,0x5d,0xbc,0xb3,0x78,0x64,0x51,0xe3,0x16, - 0x94,0x7a,0xd3,0x82,0x3f,0xda,0xa0,0xaa,0x6a,0x14,0xda,0x85,0xd9,0xd3,0x3a,0x95, - 0x80,0x88,0x8b,0x4f,0x8c,0x82,0x34,0xbf,0x27,0x69,0xda,0x39,0x3e,0x55,0x29,0xf5, - 0x86,0x95,0xdb,0xda,0x27,0xb7,0x7c,0x87,0xa6,0x7f,0x4c,0x68,0x22,0x9f,0xe5,0x97, - 0x19,0xf3,0x9f,0x1f,0xbf,0x7d,0x7d,0xf7,0x4f,0x9f,0xd1,0xc5,0x31,0xfd,0x51,0x88, - 0x2d,0xe0,0xae,0x9b,0x13,0xf5,0x11,0x80,0x49,0x4e,0xf9,0xbe,0x98,0xdd,0x32,0xf1, - 0xa7,0xf4,0xd4,0x63,0x81,0xef,0xce,0xdb,0x9d,0xaf,0x5a,0x36,0xfb,0x2d,0x48,0x96, - 0x6e,0x61,0x19,0x61,0x2a,0xdf,0x26,0x09,0xcf,0xa0,0xe7,0xee,0xf2,0xda,0x55,0x16, - 0xa1,0xf5,0xf8,0x35,0xf1,0x50,0x45,0x84,0x93,0xe4,0x3b,0x0f,0x81,0x38,0xb0,0x13, - 0x68,0x3d,0x0b,0x06,0x88,0x4b,0xdc,0x07,0xb5,0xd4,0xba,0xe8,0x84,0x64,0x36,0x05, - 0xb3,0xd2,0x8c,0xf7,0x6a,0xb4,0xb7,0x9f,0x4d,0xca,0xd5,0xe8,0x71,0xec,0x2d,0x0a, - 0x35,0x1f,0x77,0x0e,0x3b,0xc7,0xdf,0x90,0xae,0xf6,0xf8,0x30,0x26,0x08,0x74,0x17, - 0xb6,0x6b,0x13,0xc8,0x62,0xe3,0x62,0xfe,0xae,0x9b,0xd8,0x60,0x9c,0x59,0x3e,0xe5, - 0x08,0x13,0x18,0x75,0x9f,0xa7,0x0a,0x3f,0x9f,0x5e,0x7d,0x3b,0xa3,0x37,0x36,0x7b, - 0x88,0x2c,0xa2,0xc1,0x8e,0xff,0xae,0xeb,0xd3,0x3f,0x7e,0x10,0xa6,0xfa,0x2a,0xd5, - 0x97,0x34,0xe4,0xe7,0x29,0xdf,0xa0,0x5f,0x74,0x03,0xa4,0x0b,0x97,0xf8,0x97,0x2e, - 0x41,0x72,0x70,0x89,0x7f,0x71,0x59,0xf2,0x45,0x49,0x3f,0x79,0x49,0x7e,0x91,0x6f, - 0x7f,0xa1,0x6b,0xde,0x4a,0x4f,0xab,0x0c,0xd7,0xfc,0x9b,0xee,0x61,0x59,0x70,0x8d, - 0x7f,0xf5,0x25,0xe1,0x8b,0xb9,0x43,0x3f,0xf5,0xcd,0xef,0xcc,0xad,0xef,0x4c,0xc3, - 0x82,0xd2,0xb8,0x2d,0xbf,0xf4,0x8b,0x84,0xad,0xe6,0x55,0xfa,0xc9,0xf0,0x09,0x23, - 0x15,0x18,0xe5,0x37,0x6e,0x0b,0xf9,0xe7,0xbb,0xf2,0xd3,0x36,0x2c,0xa8,0xc7,0x2d, - 0xcb,0x4f,0x9f,0xb4,0x87,0xbd,0xc3,0x43,0x0f,0xc1,0x6f,0x44,0xdc,0xaa,0x24,0x35, - 0x6b,0x58,0x56,0x1e,0x07,0x1e,0x5a,0x7e,0xe7,0xd8,0x8e,0x20,0xbb,0x8b,0xf1,0x70, - 0x19,0x5f,0x79,0x44,0x34,0x21,0x4a,0x91,0xae,0x0e,0x8e,0x8b,0xd6,0x08,0x53,0x35, - 0x77,0x64,0x0d,0x99,0x94,0xe3,0x29,0xb1,0x76,0xc2,0x02,0xe2,0xbc,0x4a,0x18,0x24, - 0x58,0x34,0x89,0xec,0x25,0x5b,0x0c,0xf0,0x22,0x9b,0xa2,0xf2,0xe5,0x72,0x9d,0x91, - 0x3a,0x41,0x6d,0xaa,0x55,0x8f,0xc4,0xb9,0x73,0x34,0x47,0x34,0x15,0xd6,0x28,0xb1, - 0x47,0x12,0x68,0x8a,0x2d,0x62,0x2c,0x01,0xf2,0xc6,0x65,0xb3,0x65,0xe9,0xa9,0x0f, - 0x44,0x43,0x08,0x44,0xd6,0xed,0x63,0x19,0x43,0xcf,0xc0,0xc1,0xf6,0x84,0x5c,0xa0, - 0x2b,0x8a,0xe4,0x82,0xdb,0x88,0x04,0x45,0x48,0x17,0xa4,0xdd,0x3b,0xe6,0x00,0xc0, - 0x95,0xca,0x20,0x12,0x9f,0x16,0x53,0xbe,0x96,0xd9,0xf9,0x1e,0x2a,0xbe,0xe1,0x19, - 0x84,0x68,0x9e,0xa3,0x64,0x60,0x20,0x2b,0xbd,0x1b,0x10,0x7e,0x29,0x06,0x33,0xd9, - 0x02,0xd1,0x04,0x61,0x44,0x04,0x1d,0xb6,0x03,0xed,0x03,0xb4,0x35,0x03,0xcd,0xb0, - 0x52,0x8a,0x98,0x8d,0x61,0x56,0xc0,0x86,0x49,0xe5,0x92,0xe6,0x81,0x20,0xc2,0xc4, - 0x5c,0x8a,0xd1,0x25,0x3d,0xf7,0x0c,0x79,0xc4,0x7c,0x56,0x50,0xb2,0xa2,0x7a,0x3f, - 0x10,0x96,0x3c,0xcd,0x3f,0xa8,0xb2,0x6b,0x77,0x85,0x60,0x36,0x3c,0x41,0xc5,0x95, - 0x10,0xc6,0xbc,0x20,0x44,0xea,0xfa,0xd6,0x5a,0xe6,0xc3,0xc9,0xe5,0xb6,0xc0,0x14, - 0xec,0x34,0x5d,0x9f,0xa1,0x19,0xc2,0x16,0xcc,0x0c,0xc9,0xd6,0xe3,0x77,0xef,0x47, - 0x74,0xf5,0xe9,0x06,0x87,0x3c,0x23,0x8a,0x30,0x6a,0x37,0x36,0x6d,0x1a,0x5c,0x53, - 0x53,0x3a,0x28,0x31,0x9a,0xc5,0x55,0x4c,0xd3,0x15,0x95,0xd4,0x19,0xc2,0xf5,0xf6, - 0x60,0x97,0x94,0xb8,0xb8,0x75,0x35,0xda,0xdb,0xf0,0x94,0x1b,0x37,0x1a,0xad,0x2b, - 0x1b,0x11,0x53,0x46,0x30,0x11,0xe3,0xac,0xa1,0xdd,0x58,0xb7,0x34,0xfc,0x62,0xc4, - 0x06,0xbd,0xf9,0x79,0x5d,0x0a,0xf7,0x46,0x53,0x25,0x51,0x16,0x79,0x2d,0x29,0xed, - 0x48,0x87,0x5e,0xa7,0xe6,0x18,0x1d,0x96,0x11,0x89,0x7e,0x31,0x9d,0x22,0xd0,0x79, - 0x7d,0x58,0x9a,0xfb,0xb3,0x2a,0x72,0x8d,0x7a,0x68,0xcb,0x41,0x33,0x36,0x68,0xb1, - 0xb1,0x09,0x96,0x57,0xac,0x5f,0xa2,0x8d,0xad,0x31,0xa1,0x65,0x76,0xc6,0x73,0xa6, - 0x65,0xda,0xa9,0x71,0x3a,0x60,0x1a,0xea,0x69,0x5f,0xaf,0x68,0x2e,0xd4,0x53,0x5a, - 0xdf,0x7a,0xce,0xab,0x9c,0xf0,0x75,0x5c,0x2f,0x69,0x94,0xaa,0xec,0xac,0x5a,0x8c, - 0xf4,0xe3,0x6c,0xbc,0xb5,0x56,0xce,0x73,0x20,0x4a,0xc4,0x5c,0x25,0xd2,0x4c,0x65, - 0xcc,0xad,0x9d,0xf8,0xb0,0x6a,0xfa,0x43,0x1f,0x2c,0xc6,0x37,0x6f,0x12,0x05,0x6a, - 0x44,0xf7,0xfa,0x5b,0xdc,0xcc,0xeb,0xfa,0x07,0xd9,0x81,0x1f,0x34,0x3e,0xb0,0xe1, - 0xbc,0xd9,0x78,0x3c,0xee,0x9b,0x27,0x44,0x8e,0xb6,0x9a,0x72,0x78,0xea,0x4e,0x3b, - 0x78,0x7b,0xb7,0x1d,0x21,0x75,0x8d,0x66,0xba,0x78,0xc8,0x23,0xd8,0xdf,0xe7,0x7f, - 0x8e,0xfb,0xc1,0x89,0xcf,0x0e,0x1c,0x0d,0x25,0x4d,0x22,0x0d,0xab,0x5e,0x48,0xdb, - 0xc7,0x77,0xcd,0xc0,0x65,0x9e,0x85,0x6e,0x76,0xe2,0x9b,0x9d,0x5a,0xf3,0x25,0xde, - 0x8f,0x84,0xb6,0x43,0x7e,0xe9,0xc0,0xd7,0xfb,0xdc,0x3f,0xe8,0xca,0x4a,0x8c,0xc7, - 0x83,0x13,0x9f,0x3a,0x21,0xb2,0x1f,0x0c,0x7d,0x9f,0xf1,0x53,0xc3,0x4a,0x08,0x06, - 0x79,0x73,0xec,0x04,0x99,0xea,0x55,0x9a,0x60,0xed,0x9c,0x45,0x34,0xab,0x77,0x19, - 0x67,0xd5,0x2d,0x0b,0x78,0x6f,0x3c,0xe6,0xaf,0xdc,0xf5,0xe4,0xeb,0xb6,0xdd,0x34, - 0x8d,0xf4,0x6e,0x1b,0xa3,0x45,0xd9,0x43,0x2e,0x32,0x11,0x94,0x42,0xb9,0x9e,0x11, - 0xb5,0xc4,0x5e,0xf5,0x5e,0xfd,0xd3,0xdb,0xb7,0x7a,0xd2,0x38,0x34,0xb2,0xb4,0xf4, - 0x8c,0x19,0xb2,0xf7,0x46,0x5d,0x20,0xb8,0x3d,0x3b,0x53,0xa5,0x41,0x62,0x84,0xec, - 0x32,0x0e,0x6b,0x82,0x29,0xd4,0x52,0x13,0x48,0x7a,0x7f,0xdc,0x1b,0x8c,0x6a,0x5c, - 0x8e,0x57,0xc4,0x1e,0x5e,0x6b,0xea,0xc9,0x23,0xc3,0xfe,0x2e,0x89,0x35,0x5e,0x84, - 0x98,0xec,0x35,0x34,0x28,0x1a,0xcb,0x54,0xf1,0x2c,0x21,0x50,0x96,0xaf,0xbc,0xfd, - 0x7d,0xda,0x73,0x17,0x34,0xcf,0x75,0xcb,0x81,0xd0,0x03,0x33,0x6b,0xf4,0xf8,0x6b, - 0x06,0x6d,0x36,0xa6,0x9f,0xf7,0xdc,0x37,0xf1,0x8a,0x03,0x51,0x21,0x77,0x2e,0x18, - 0x41,0xaa,0xf1,0xf5,0x06,0x57,0x02,0xc8,0xcd,0xcd,0xbb,0xf7,0x2d,0xa4,0x09,0x11, - 0xc6,0xaa,0x7a,0x77,0x5a,0x61,0x7b,0xd2,0x55,0x54,0xe5,0x2f,0xf3,0x4b,0x55,0x7c, - 0x4d,0x24,0xaa,0x1b,0xbc,0x1f,0x0f,0x36,0x41,0xbd,0xf5,0x0c,0xa2,0x9a,0xad,0xd9, - 0xb6,0x34,0xcc,0x68,0x99,0x78,0x66,0xe3,0x7b,0xf7,0x9c,0xb6,0x9b,0x84,0xef,0xe6, - 0xc6,0xf7,0xb7,0x3b,0x1b,0xf1,0xb7,0xf5,0xda,0xe6,0x99,0xdc,0xa1,0xb9,0xca,0xb3, - 0x20,0x3b,0x38,0xc0,0x65,0xdb,0x62,0xf3,0x2b,0x66,0x92,0x69,0x7e,0xe6,0xc4,0x49, - 0xcc,0xc4,0xea,0x99,0xc3,0x95,0x3b,0x11,0x82,0x65,0x0e,0xb8,0xcb,0xa4,0x2c,0xa9, - 0xcf,0xdd,0x77,0x7a,0x1a,0x0a,0x26,0x4e,0x63,0xff,0x2d,0x1b,0x66,0xb2,0x73,0x09, - 0xb0,0x9d,0x79,0xbc,0xb9,0xeb,0x4d,0x93,0xb9,0x1b,0x86,0x1e,0xd0,0x14,0x91,0x8c, - 0x26,0xd4,0xc0,0xb7,0xc3,0x91,0xce,0x68,0x3b,0x57,0x07,0x63,0x3f,0xa4,0x36,0xe4, - 0x06,0xbd,0x8f,0x5d,0xc9,0x6e,0x80,0xa4,0x64,0xe4,0xd3,0xdf,0x94,0xf1,0x55,0xb7, - 0x0a,0x69,0x03,0xe7,0xe7,0xd4,0xb4,0x2a,0x0a,0x9f,0x85,0x39,0x1e,0xfb,0x46,0xb3, - 0x8c,0x37,0xaa,0x24,0x2d,0xb2,0x64,0x97,0xc4,0xe4,0x4a,0x6b,0x76,0x6c,0xb4,0x1f, - 0x7a,0xf0,0x13,0x33,0x2c,0x5a,0x1e,0x20,0x1d,0x8f,0x9d,0xc4,0x7c,0x4f,0x6c,0x4d, - 0xa5,0x4b,0x99,0xa5,0xbf,0xf3,0x50,0xa5,0xc1,0xf5,0xeb,0x17,0x91,0xbe,0xa4,0x45, - 0x4b,0xb2,0x79,0xee,0xd3,0xed,0x9b,0x1b,0x74,0x2f,0x1d,0x3f,0xf1,0x10,0x49,0xa0, - 0xad,0x4b,0xf0,0x9e,0xb2,0x17,0x2c,0x2e,0x84,0xf5,0x5b,0xef,0x28,0x73,0xf5,0xc8, - 0xfb,0x81,0x06,0x6a,0xbb,0xd5,0xfe,0x66,0xf6,0x6e,0x88,0x74,0xb0,0xeb,0x73,0xe6, - 0xed,0x28,0x3e,0x90,0x19,0x8c,0x59,0xc6,0x10,0xc6,0x02,0x90,0x26,0x64,0xe5,0x22, - 0xbf,0x04,0xeb,0x4a,0xad,0xe7,0x19,0xad,0x49,0x2f,0xa4,0x08,0x87,0xf0,0xdc,0xa0, - 0x0d,0x88,0x0f,0xfc,0x2e,0xfb,0x4a,0x10,0xf2,0x8e,0x66,0x27,0x0a,0x10,0x4f,0x45, - 0x0e,0x6a,0x38,0x0f,0xd3,0x1c,0xd3,0xa2,0xf9,0xb1,0x88,0x25,0x6c,0xa8,0x2a,0xa1, - 0x1e,0x1f,0x95,0x90,0x5f,0x48,0xd2,0x82,0x18,0x27,0xe2,0xa1,0x30,0xe8,0x79,0x8a, - 0x48,0x12,0xf8,0x96,0x32,0xce,0x35,0x11,0xca,0xc1,0x8a,0xab,0xc8,0xcc,0xfc,0x93, - 0xc5,0xda,0xf2,0x0a,0xa1,0xfa,0x85,0x16,0xb6,0xec,0xfc,0xe3,0x41,0x17,0x24,0x9c, - 0x57,0xc0,0xb0,0xc6,0xfe,0xf8,0x19,0x61,0xbd,0xa4,0x31,0x60,0xe5,0x49,0x9c,0xd6, - 0x2b,0x21,0x57,0xd1,0x8a,0xd8,0x70,0x46,0x22,0xef,0x4c,0x45,0xb4,0xd0,0xaa,0xa8, - 0x9e,0xb2,0xc8,0xd9,0xd5,0x5d,0x53,0x63,0x51,0x46,0x8d,0x9e,0x92,0x3c,0x41,0x23, - 0xe6,0x36,0xf4,0xa3,0x88,0xd5,0xa4,0x97,0xc0,0x82,0x78,0x36,0xeb,0xfa,0xc4,0x58, - 0xec,0xc6,0xaf,0x76,0x89,0xbc,0xa6,0x31,0x92,0x0f,0xc1,0xce,0x84,0x6e,0xb7,0x86, - 0xad,0x57,0xf5,0x83,0xc3,0x41,0xbf,0xdf,0x0f,0x6a,0xec,0x2d,0x8f,0xc7,0x47,0x27, - 0x18,0x11,0x21,0x39,0x56,0xd0,0x3f,0x28,0x0f,0x68,0x8f,0x0c,0xe5,0xd6,0xaf,0xff, - 0xf6,0xbf,0xfc,0xd0,0x22,0x97,0xa0,0x35,0xfe,0xa0,0x6b,0xbb,0xc3,0xed,0x6c,0x05, - 0x2c,0x4f,0x70,0x8c,0xf7,0x45,0x9c,0x3a,0xf7,0x85,0xfd,0x99,0x39,0x25,0x5a,0x63, - 0xdf,0x41,0x43,0xe1,0x43,0x86,0x68,0xd3,0x9c,0xe6,0x67,0x84,0x53,0x5d,0x43,0x93, - 0xeb,0xa6,0xae,0x6f,0xed,0xa3,0xb9,0x68,0x9b,0xd6,0x39,0x14,0x6d,0xcf,0x4c,0xe3, - 0x46,0x4b,0xd1,0x1c,0x3f,0x37,0x55,0x5a,0x63,0xd0,0x5e,0x38,0xc2,0xb2,0x75,0xb6, - 0x66,0x71,0xc0,0xbb,0x80,0xd5,0x14,0x52,0x7d,0x7e,0x8e,0xed,0x7f,0x4e,0x3b,0x97, - 0xcd,0x2c,0x84,0xe4,0x08,0xa6,0xaa,0x8c,0x23,0x2f,0x64,0x39,0x9e,0xda,0x89,0x67, - 0xb5,0xeb,0x2e,0xd4,0xfb,0xad,0xd6,0x22,0x98,0x4e,0x2d,0x54,0xda,0xc4,0xe9,0x72, - 0x85,0x8c,0x04,0x16,0xbf,0x40,0x95,0x78,0xa7,0xf0,0x76,0xd0,0x7b,0x09,0x2a,0x8e, - 0xb1,0xfd,0x49,0x02,0x01,0x72,0x07,0x1c,0x37,0xa9,0x78,0x2c,0x1c,0x4f,0xa9,0xd9, - 0x91,0x46,0xee,0x67,0x8d,0x8a,0x77,0xc2,0x0c,0xde,0x44,0xd0,0x23,0xf1,0x25,0x92, - 0xa4,0x58,0x70,0x12,0x83,0xd7,0xd5,0x7a,0xd5,0x9f,0x0a,0x75,0x46,0x13,0x56,0x5c, - 0x45,0x0b,0xe3,0x99,0xbc,0x0a,0x6a,0xd5,0x20,0x11,0x1a,0x80,0x06,0xb9,0x3d,0xda, - 0xdd,0xcb,0x55,0x55,0x36,0x84,0xff,0xea,0x95,0x6c,0x5c,0xa4,0xec,0xd0,0x62,0x18, - 0x75,0xe6,0xde,0xbd,0x25,0xd0,0xc1,0x28,0x86,0xb2,0x38,0xdf,0x21,0x0d,0x44,0xbf, - 0x71,0xe2,0x1b,0xbb,0x2c,0x91,0x54,0xeb,0x8a,0xa3,0x15,0xc3,0x67,0xec,0xd7,0x6a, - 0xf9,0x84,0x55,0xe3,0xa1,0x2f,0xfe,0x9a,0xf9,0xdc,0x97,0x2e,0x44,0xe2,0xd4,0x89, - 0x5e,0xfa,0x5d,0x7e,0x22,0xfa,0x67,0x53,0xaa,0x33,0x2f,0xec,0xef,0xd7,0xca,0x56, - 0x70,0xc2,0x1b,0xc5,0x8f,0xc5,0xa0,0x47,0xc3,0x06,0x49,0xc5,0xe4,0x63,0x2a,0x40, - 0xfc,0x34,0xdd,0x86,0xe7,0xb8,0xcc,0x21,0x6f,0x94,0x32,0x3d,0x9a,0x2a,0xfa,0x2c, - 0x9b,0x09,0x73,0x69,0x69,0xfe,0x5a,0xb6,0x6b,0x7d,0x67,0xb4,0xad,0xe8,0x71,0xd2, - 0x1c,0x32,0xb4,0xd6,0x19,0xdd,0x43,0x26,0xcd,0x9e,0xa1,0xee,0x32,0x58,0x58,0x1e, - 0x19,0xa1,0x48,0x19,0x48,0x59,0x8b,0x35,0xe8,0x4a,0x20,0x58,0x0c,0x96,0xe8,0x1d, - 0x95,0x89,0x1b,0x38,0xa6,0xc5,0xae,0x48,0x69,0x05,0x7a,0x31,0x41,0x8e,0x93,0xb4, - 0x64,0xff,0x36,0xe6,0xcc,0x63,0x3d,0x95,0x89,0x30,0x30,0x0a,0xe6,0x6b,0x1e,0x5f, - 0xa7,0x8e,0x17,0x04,0x71,0x2e,0x90,0x3b,0xd3,0x81,0x88,0x36,0x87,0x03,0xda,0x58, - 0xa3,0xd1,0xde,0x7a,0x05,0x2d,0x25,0xab,0xb4,0x69,0x1a,0xbe,0x2d,0xb3,0x4b,0xc4, - 0xed,0xe1,0x78,0xca,0xe7,0xc9,0x07,0xc6,0x45,0x17,0x77,0xc4,0xb0,0xfc,0x86,0x3a, - 0xbe,0xb2,0x24,0x40,0x4f,0x9f,0x96,0xc1,0x38,0x52,0xa8,0x39,0xb1,0xc4,0xe1,0x39, - 0x81,0xee,0x1a,0x64,0xcd,0xe7,0x70,0x23,0x51,0x87,0x01,0xb0,0x13,0x38,0xc5,0xbb, - 0xa2,0xb8,0x92,0xde,0xe3,0x33,0xf8,0xc2,0x39,0xab,0x66,0x99,0xc3,0x4a,0x43,0xe4, - 0x0e,0x6c,0xdc,0xe6,0x44,0xb1,0xcc,0xc2,0xc4,0x04,0xad,0xce,0x1b,0x96,0x6f,0x6d, - 0x8f,0x30,0xdb,0x4c,0x1b,0xd6,0x92,0xd2,0xa1,0x08,0x12,0x78,0x90,0x94,0xcc,0x15, - 0x6d,0xdb,0x2e,0xfe,0x8b,0x87,0x88,0x08,0x5a,0xfe,0x5f,0x12,0x75,0xd9,0xbd,0x66, - 0x6f,0x18,0xe9,0x44,0x44,0xe5,0x68,0x2b,0xfb,0x0d,0x45,0x94,0x81,0x19,0x59,0xb9, - 0x02,0x36,0x06,0x38,0xc4,0x3c,0xe8,0x86,0x5a,0x4c,0x0e,0xf5,0x0e,0x47,0xda,0x1a, - 0x21,0x3b,0xb3,0x41,0x58,0x4b,0x79,0x19,0xd1,0x4e,0x91,0x28,0x13,0xb9,0xe3,0x81, - 0xe9,0x78,0x92,0x04,0x26,0xbc,0x10,0xe2,0xc6,0x0b,0x7e,0x5f,0x84,0x35,0xb6,0x45, - 0xbd,0x51,0xbf,0x6c,0xf3,0x41,0xe0,0x81,0xac,0x8c,0x79,0x81,0xa4,0x91,0x33,0x55, - 0x75,0xfd,0x86,0x71,0xc6,0x0f,0xaf,0x75,0xfa,0xda,0x70,0x40,0x44,0xbe,0xbf,0x69, - 0x49,0x7c,0x34,0xb2,0x57,0xdd,0x75,0xc0,0x53,0x6d,0xf9,0x8e,0x15,0xa8,0xbc,0x1d, - 0xf0,0xe4,0xee,0xbc,0x6c,0x6c,0xe4,0x59,0x64,0xa8,0x42,0xd7,0x61,0x83,0xb3,0x68, - 0x5e,0x28,0x45,0xdc,0xef,0xe8,0x01,0xe4,0xbf,0xdf,0x3f,0xf5,0x70,0xed,0x93,0xee, - 0x64,0x16,0x13,0x34,0x56,0x7f,0x69,0xa4,0xbb,0x9a,0x86,0xd9,0x46,0x1d,0x48,0x88, - 0xb3,0xc0,0x35,0x58,0x7c,0xf3,0xf6,0xd5,0xcb,0xb1,0x5f,0x7f,0xf3,0x3d,0xcc,0xa4, - 0xcf,0x78,0xdf,0x32,0x94,0xc1,0xc8,0xf3,0x98,0xf2,0x5e,0x22,0xce,0xb6,0x1c,0xc2, - 0x3e,0x40,0x3b,0x13,0xa6,0x2e,0x98,0x60,0x0a,0x2c,0x1b,0x67,0xa3,0x11,0x9a,0x9c, - 0xd1,0xfe,0xe0,0x76,0x66,0x91,0x99,0x44,0x92,0xcb,0x09,0x6d,0x49,0xac,0x2f,0xb0, - 0xb0,0x90,0xc8,0x77,0x05,0xfc,0x95,0x9e,0x47,0xe1,0xff,0x69,0x32,0xb6,0xf6,0x47, - 0x64,0x32,0x55,0x4a,0x9b,0x20,0x61,0x51,0xf4,0xf5,0x08,0x78,0xd2,0x57,0x11,0xc2, - 0xf5,0x3e,0xd0,0xd6,0x99,0x71,0xac,0xc3,0x85,0x0a,0xd2,0xc4,0xa1,0xaf,0xbe,0x26, - 0xbb,0xa6,0xe5,0xec,0xd6,0x86,0x61,0xe4,0xa5,0xa6,0x5d,0x7a,0xee,0xd3,0xb7,0x59, - 0x63,0x69,0x74,0x77,0x07,0x83,0x46,0x9b,0xcb,0x4f,0x36,0xba,0x6c,0xb4,0xba,0xf4, - 0x71,0xa7,0xd9,0x2e,0x82,0xe1,0x4d,0xa3,0x78,0x88,0xcc,0xbf,0xb1,0x0f,0x5b,0x83, - 0xef,0xdc,0x6e,0xd1,0x8c,0xf1,0x8a,0x99,0x86,0x50,0xda,0x09,0x36,0x2e,0x78,0xd5, - 0xd9,0xa7,0xc0,0xd3,0x2f,0x57,0x67,0x2e,0x94,0x55,0x7c,0x46,0x6a,0xc7,0x2a,0x12, - 0x0d,0xe4,0x84,0x55,0x11,0x30,0x03,0xf7,0xf5,0xe6,0x10,0xcc,0x9b,0x5a,0x67,0x19, - 0x6a,0xa3,0x80,0xdf,0x58,0x2e,0x79,0x68,0x57,0x5b,0xcb,0x7b,0x97,0xb7,0xaf,0x37, - 0x3c,0x3f,0xd4,0x69,0x79,0xe9,0x02,0x57,0x5e,0xda,0x56,0xa5,0x85,0xe9,0xad,0x0d, - 0xb0,0x21,0x8d,0x1a,0x98,0x46,0xec,0x2e,0xf3,0x8d,0x81,0xd1,0xa7,0x3b,0x6e,0x8b, - 0x2a,0x75,0x9a,0x6c,0xea,0x94,0x76,0x6c,0xf4,0x09,0xad,0x00,0x93,0xa9,0x71,0xad, - 0x29,0xd6,0x9f,0x11,0x90,0xa4,0xae,0x13,0x03,0xfc,0x9a,0x58,0xd9,0x0c,0x79,0xc2, - 0x84,0x8c,0xee,0x9d,0xf2,0x32,0xa8,0xdf,0xd6,0x09,0x09,0x67,0xe0,0x6f,0x63,0xc3, - 0x0e,0xea,0x47,0xad,0x00,0xd8,0x37,0x2e,0x93,0x42,0x3d,0xa3,0xaf,0x89,0xec,0xd8, - 0x26,0x37,0x8a,0x36,0xeb,0xd6,0xcc,0xae,0x3e,0xb5,0xf8,0xe5,0x4a,0x9b,0xb6,0x24, - 0x61,0xd5,0x47,0x1c,0x81,0xbf,0x03,0xf7,0xaa,0xee,0x64,0xcf,0x82,0xe8,0xbe,0x91, - 0xed,0x8c,0x35,0x5b,0xee,0xdc,0xaa,0xce,0x82,0x8f,0x23,0xc3,0xd6,0xfb,0x90,0x75, - 0x0b,0x1a,0x61,0x88,0xd9,0x09,0x76,0x9a,0xb3,0x8f,0x85,0x4a,0x05,0x4d,0x94,0x98, - 0xdc,0x3a,0x72,0xe1,0x73,0x34,0xf6,0x89,0x8b,0x01,0x33,0x60,0xc0,0xa4,0x69,0x6f, - 0x13,0x23,0x96,0x83,0x18,0x93,0xb6,0x2d,0x48,0x6f,0xd9,0xc1,0xe8,0x2d,0x18,0x4e, - 0xea,0x4d,0xb8,0x33,0xac,0x49,0xcb,0x64,0x32,0x35,0x76,0x5f,0xb2,0xeb,0xba,0xd1, - 0xff,0xd2,0x13,0x6d,0xf1,0xf2,0x5a,0x8c,0x42,0x44,0x6e,0xe5,0x12,0x26,0x86,0xd0, - 0xb3,0x97,0x6f,0xd4,0xc5,0xcd,0x4d,0x3f,0x14,0xce,0x1b,0xb2,0xd4,0xa1,0xdb,0xd8, - 0x36,0x75,0x10,0x6f,0x9b,0x42,0xa8,0xea,0x6e,0x6b,0x64,0x0e,0xd3,0xaa,0xb1,0x94, - 0x59,0xdc,0x94,0x85,0x32,0xf0,0x1d,0x66,0xce,0x46,0xdf,0x67,0x81,0x82,0xdd,0x35, - 0x04,0x80,0x96,0x19,0x1c,0xb3,0xc2,0x36,0x0f,0x0d,0xae,0x1b,0x4c,0x9a,0xf5,0xe0, - 0x6e,0xd3,0x80,0xad,0x5f,0x30,0x92,0xc3,0xeb,0x1c,0x12,0x2b,0xbf,0xa8,0x05,0x88, - 0xda,0xb9,0xc2,0x00,0x00,0x9c,0x61,0x0d,0x4f,0x52,0x3a,0x32,0x4c,0xa9,0x5f,0x8c, - 0xcb,0x73,0xad,0x3f,0xa3,0x9d,0x9a,0x23,0x3b,0x52,0x1c,0x03,0xa2,0xc5,0x37,0xfd, - 0x96,0x63,0x42,0x33,0xdf,0x99,0x49,0x81,0x3d,0x43,0xf2,0xfa,0xf3,0xec,0x54,0x27, - 0xa6,0xcb,0x6d,0xa7,0x10,0x40,0xf7,0xbe,0x51,0x5f,0xe9,0x3e,0xa7,0xe6,0x37,0x25, - 0x8e,0x43,0xbd,0x6e,0x7e,0x78,0x44,0x02,0x47,0xd8,0x26,0x68,0xcc,0x82,0xb6,0xe5, - 0xb7,0xf6,0x25,0x2c,0x7e,0xa1,0x57,0xdd,0x2e,0xf7,0x26,0xbc,0xe6,0x51,0x0f,0x45, - 0x1c,0x0c,0x5c,0x77,0x00,0xa9,0xd6,0x3d,0x70,0x11,0xf1,0x3b,0x15,0xe7,0x30,0x34, - 0xe4,0x88,0xaf,0xd3,0xa9,0x59,0xc8,0x84,0x46,0xfc,0xd7,0x79,0x96,0x4f,0x3c,0x0c, - 0x1e,0x52,0x71,0x2e,0x7a,0x5f,0x3c,0x09,0xd8,0x9e,0x2f,0xba,0x9e,0xf2,0xca,0x05, - 0x49,0x7d,0x33,0x2d,0x92,0x85,0x26,0x90,0x88,0xd6,0xa3,0x67,0xc2,0xd7,0x6b,0xa3, - 0x10,0x5b,0x3d,0x13,0xb6,0xc8,0x89,0x8b,0x88,0x7f,0x3f,0xa9,0x60,0x0e,0xb4,0x8b, - 0x60,0xa6,0x12,0x06,0x45,0x1a,0xc7,0x22,0x2e,0x4f,0x17,0x04,0xd9,0x98,0x2b,0x52, - 0xac,0xb4,0x41,0x8d,0x99,0xdf,0xf7,0x73,0xa2,0x69,0x78,0xe6,0x07,0xc7,0x62,0x51, - 0x6c,0x08,0x65,0xfb,0xfb,0xf7,0x34,0x16,0x05,0x22,0xfc,0x19,0x2b,0x44,0x3c,0x2e, - 0xb5,0xe8,0xa0,0xbf,0x29,0x23,0xad,0x25,0xdc,0xdc,0xdc,0x8b,0x6f,0x6e,0x62,0x12, - 0x2e,0xfc,0x9e,0xef,0x2c,0x3c,0x2b,0x2f,0x3a,0x24,0x62,0xc1,0x5a,0xf5,0x4a,0x82, - 0x61,0x90,0x6b,0xc4,0x26,0x7e,0x02,0xfc,0x4a,0x55,0x43,0x68,0x50,0xbe,0xc4,0xfd, - 0x4b,0x58,0x9d,0xcc,0x2e,0x14,0xd5,0x48,0xfa,0x92,0x31,0xef,0xef,0xc7,0xb0,0xbe, - 0xea,0xdf,0x8e,0xbd,0xc3,0x4c,0xc9,0x63,0x08,0x9f,0x0e,0x04,0xce,0xb4,0x99,0x61, - 0x2c,0x92,0xaa,0x96,0x29,0x6f,0x75,0x2b,0x41,0x7c,0xda,0x95,0xbe,0x88,0xd6,0xd4, - 0xc6,0x17,0x12,0x67,0x88,0x5e,0x35,0x3e,0xed,0xfa,0x11,0x09,0x2d,0xc1,0xa8,0x61, - 0x83,0xa5,0x0e,0x69,0x4e,0xef,0x65,0xcb,0xfd,0xfd,0x2d,0x69,0x66,0x3c,0x8e,0x79, - 0xb6,0x9b,0x3c,0x6c,0x3c,0xbe,0x67,0x26,0xfa,0xdb,0xf2,0x95,0xc3,0xce,0xc4,0x0c, - 0x0b,0xf8,0x6b,0xf2,0x62,0x84,0x38,0x36,0x7a,0x54,0xf9,0xd9,0x59,0x2a,0x46,0x8f, - 0x90,0xde,0x34,0xd6,0x5a,0xc1,0xe0,0x5f,0xff,0xfd,0xdf,0xe8,0x3f,0xef,0x35,0x12, - 0x08,0xbb,0xb2,0x28,0x52,0x95,0x21,0xd0,0x8f,0xfe,0xb3,0xfe,0x03,0x70,0xa7,0x08, - 0xcc,0xa6,0x7d,0x2a,0x1a,0x64,0xc3,0x15,0xeb,0xb3,0xbe,0xda,0x13,0x88,0x8d,0x37, - 0x15,0x55,0x1a,0x24,0xd5,0x4d,0xeb,0x7a,0xac,0xee,0x96,0x76,0x77,0xd1,0x7e,0x22, - 0x45,0xc9,0xc4,0x9b,0x33,0xe2,0xad,0x54,0x01,0xa5,0x0e,0x1a,0x68,0x68,0x6d,0x1b, - 0x82,0x29,0xa5,0xe3,0x19,0xd6,0x96,0x64,0xb4,0x04,0x54,0x25,0x49,0x3c,0x93,0xf8, - 0x76,0xa6,0xdc,0x46,0x03,0x5c,0x24,0x67,0x0b,0x2e,0x66,0x23,0xb9,0x2a,0x5e,0xbe, - 0x22,0xf5,0x27,0x41,0xb0,0x1c,0xc7,0x61,0xa1,0x63,0xd9,0x3c,0x68,0xe7,0x02,0x75, - 0x0e,0xa0,0x8c,0xd1,0xae,0x2b,0xe0,0xb9,0x63,0x52,0xec,0xa8,0xc1,0x2c,0x9a,0x8a, - 0x60,0xca,0x0b,0x72,0x6d,0xb4,0x50,0x19,0x07,0x53,0x83,0x1c,0x86,0x6e,0x7a,0xd8, - 0x34,0xd5,0x59,0x66,0x21,0x35,0x41,0xb6,0x48,0xa4,0xb8,0x5b,0x4e,0x44,0xf2,0xf7, - 0x0f,0xa4,0x87,0xeb,0x29,0xa1,0xb4,0x82,0x2f,0xae,0x07,0x85,0x48,0x91,0xe2,0xc9, - 0x98,0xb4,0x5b,0x4b,0x44,0xf3,0x94,0xba,0x32,0x48,0xdb,0x7b,0x33,0x2b,0x95,0xc0, - 0xa3,0x32,0x43,0xe9,0x11,0xd6,0xcb,0x67,0x91,0x42,0xed,0x91,0x9b,0x1b,0x3d,0x08, - 0xad,0x9d,0x36,0xb9,0x9c,0xf4,0x60,0x98,0xbb,0xde,0xac,0x33,0x16,0x0c,0x6e,0x6e, - 0x58,0xd2,0xb7,0xb4,0xae,0x69,0x78,0xb5,0x9c,0x35,0x43,0x42,0xa4,0xd0,0xe4,0x21, - 0xcd,0x90,0xbc,0x1e,0xc2,0x4a,0xef,0xaa,0x93,0xbf,0x79,0xa3,0xc3,0xe8,0xab,0x6e, - 0xb3,0x27,0x6e,0x02,0x57,0x6d,0x80,0xa6,0x37,0xfe,0x48,0xf3,0x5e,0xe4,0xa8,0x0e, - 0x78,0xb9,0xbd,0x37,0x2b,0x03,0x81,0xd8,0x21,0x34,0xf8,0x5b,0x92,0xc0,0x9a,0x1e, - 0xd2,0x70,0xd0,0x0f,0x88,0x3a,0x68,0xcd,0x2a,0xb0,0xe6,0x66,0x2d,0xaf,0xdd,0x66, - 0x41,0x76,0x65,0xa3,0x36,0xd9,0x45,0xcf,0xa3,0x36,0xa0,0xb3,0xd3,0x59,0x36,0x55, - 0x63,0xad,0x76,0x08,0xc9,0x13,0xd1,0x67,0xbd,0x2e,0xc7,0x50,0x63,0x60,0xa1,0x44, - 0x56,0xd4,0x11,0x44,0x7f,0x53,0xca,0xc2,0xde,0x44,0xa8,0x01,0xda,0x2c,0xf5,0xec, - 0xdb,0xd3,0xd7,0x2f,0x9f,0xfc,0xb3,0xf4,0xe4,0xd6,0x53,0x01,0xc1,0xc0,0x3d,0x93, - 0xb3,0xa1,0xb5,0x69,0xaf,0x6b,0x38,0x2a,0xfb,0xe4,0x17,0x86,0x6d,0xa7,0x70,0x1e, - 0x98,0x88,0x4e,0xe6,0xfd,0xa1,0xcd,0xb5,0xe8,0xc0,0x88,0x05,0x2e,0xd4,0x13,0xab, - 0x0c,0xe6,0xe6,0xfb,0x22,0x21,0x10,0x3a,0xba,0x75,0xb4,0x35,0x4d,0xf3,0x12,0x39, - 0x7b,0x65,0x9a,0xa3,0xd0,0x0c,0x72,0xce,0x66,0x41,0x64,0x82,0x5d,0x48,0xf2,0x0e, - 0xbc,0x75,0xd6,0xd3,0x60,0x58,0x5a,0x73,0x59,0xb0,0x7d,0x11,0xb4,0x88,0x1b,0x21, - 0x16,0x90,0xe6,0xa4,0x2a,0x7e,0xa8,0xb4,0x21,0xce,0x1a,0x95,0xb4,0xb1,0x6e,0x6c, - 0xa1,0x3c,0x0a,0x1b,0xb1,0x26,0xf8,0xbc,0xc5,0x9a,0xab,0x3e,0xac,0x08,0x0f,0x35, - 0x99,0xe4,0x16,0xaa,0x82,0x40,0x4a,0x01,0x77,0x91,0xaf,0xcf,0x16,0x62,0xa6,0x2b, - 0x88,0x83,0x23,0xc8,0x59,0x6c,0x7e,0xba,0xad,0x85,0x38,0x93,0xfe,0xd8,0x7b,0xfd, - 0xa2,0x07,0xa9,0x7f,0xd8,0x80,0x0f,0x54,0x90,0x10,0x66,0xa6,0x66,0x44,0xef,0xc0, - 0xc6,0x0d,0xe5,0x16,0x59,0x65,0xa6,0x57,0x49,0xa4,0x95,0xdc,0x1a,0x49,0x0c,0xdb, - 0x45,0x1f,0x3f,0x68,0xab,0x88,0xac,0x14,0xdb,0x36,0x8d,0xc1,0x15,0x36,0x4e,0x91, - 0x49,0xa7,0x04,0x27,0xf1,0x85,0x25,0x82,0x29,0x44,0x78,0x66,0x9f,0xbe,0xf1,0x3d, - 0x39,0x14,0x54,0x1b,0x4f,0xe1,0x2a,0xe3,0x9f,0xe3,0xba,0x57,0x12,0x4e,0xee,0xd5, - 0xb6,0xd6,0x4d,0xc3,0x70,0xed,0x18,0x70,0x88,0x5f,0x62,0x0f,0x3a,0xd0,0xe6,0x99, - 0xb5,0xc9,0xee,0xd9,0xd0,0xa5,0xad,0xf0,0x86,0x3c,0x63,0x57,0xa3,0x8e,0x6b,0x70, - 0x1a,0xe7,0x76,0xb4,0xeb,0x53,0x44,0xe3,0x66,0x77,0x22,0x70,0xd6,0xaa,0x0a,0x6f, - 0x42,0x99,0x8c,0xa9,0x76,0x98,0xca,0x2c,0x57,0x9e,0x4c,0x14,0x89,0x49,0xdb,0x54, - 0x5f,0x6f,0x47,0x49,0x51,0xe8,0x72,0x50,0x0e,0x1b,0xeb,0x43,0x78,0x1f,0xbf,0x3e, - 0x3d,0x0d,0x86,0x9c,0x2c,0x14,0x13,0x8e,0x99,0xdc,0x71,0x6b,0xf0,0x8d,0xbc,0x57, - 0xda,0xfd,0x8e,0xc0,0x11,0xd8,0x69,0x93,0xb3,0x75,0xbe,0x76,0x0d,0xfb,0x56,0x6b, - 0x5c,0xaf,0xea,0xb8,0x82,0x4f,0xeb,0x8a,0xf0,0x00,0x6d,0xa9,0x8b,0xde,0xf2,0x62, - 0x5b,0x63,0x5c,0xaf,0x4e,0x7c,0x82,0x9c,0xe6,0x8e,0x80,0x97,0xa8,0x09,0x54,0xf8, - 0x7a,0x52,0x55,0x45,0x42,0x4d,0x11,0xa5,0x8d,0x8b,0x24,0xee,0x89,0x55,0x23,0xc4, - 0xdb,0x2c,0x1c,0xae,0x61,0xfb,0xe7,0x5f,0xf0,0xe9,0x9a,0xde,0xda,0xe3,0x20,0xb4, - 0x62,0x9f,0x4c,0xd0,0x19,0xc9,0x49,0x2b,0xda,0x81,0x09,0x0d,0x51,0x83,0xac,0x7d, - 0x70,0x43,0x7a,0x02,0xeb,0x68,0xf3,0xae,0x15,0xb8,0xee,0xd1,0xf7,0x84,0x41,0xf4, - 0xb7,0x19,0x36,0x54,0x8b,0x98,0x8e,0x89,0xd0,0x71,0xf8,0xf1,0xb4,0x9d,0xd0,0x67, - 0x43,0x7c,0xba,0xed,0xf3,0x03,0xd0,0x73,0x9a,0x48,0xab,0xa7,0x36,0xd1,0xc5,0x7a, - 0xdf,0x34,0x07,0x9e,0x34,0x50,0x4b,0x90,0xc6,0xac,0x48,0xf1,0x31,0xde,0xf3,0x0e, - 0x30,0xf7,0x00,0xf0,0x7b,0x6d,0x8c,0x26,0x19,0x15,0x5f,0x25,0x24,0xf8,0x27,0x8f, - 0x0b,0x13,0xeb,0x91,0x1c,0x1c,0xe8,0x29,0x2b,0xde,0x25,0xef,0x77,0x64,0x5a,0x5a, - 0xbe,0xa0,0xf6,0xaf,0x24,0x26,0x62,0xa6,0xed,0x6d,0xee,0x98,0x3f,0x78,0x37,0x78, - 0xdf,0xfc,0xc6,0xf4,0xd6,0x1b,0x58,0xa7,0xb9,0x1d,0x93,0x6b,0xa5,0x11,0x63,0x33, - 0x78,0xd8,0x73,0xe4,0x1f,0x83,0xa1,0xa9,0x8c,0x30,0xd1,0x07,0x2a,0xb3,0x2e,0xe9, - 0x87,0xae,0x51,0xc1,0x50,0x9b,0x34,0x19,0x35,0xa4,0x61,0x66,0x82,0x78,0x6a,0x38, - 0xf6,0xad,0x8d,0xd2,0x8c,0x36,0x9a,0xdc,0x95,0xac,0x0d,0xfb,0x97,0xe6,0x1a,0xcb, - 0xfe,0xd7,0x8b,0x14,0xba,0xae,0x86,0x01,0xf3,0x13,0xc0,0xe2,0x75,0x07,0x5a,0x75, - 0x51,0x2b,0xbc,0xf7,0xcc,0x5c,0xdc,0xdc,0xd8,0x59,0x19,0xd3,0xbc,0x34,0xb0,0x55, - 0x5d,0xf0,0x4e,0xa0,0x76,0x9f,0x49,0x61,0x8a,0x6e,0xd0,0xa2,0x4a,0x88,0x04,0x61, - 0x21,0xbb,0x03,0x5c,0x9c,0xff,0xd4,0x98,0xc6,0xd6,0x19,0xdc,0x1e,0xed,0x2d,0xed, - 0xe5,0xab,0xb6,0x31,0xde,0x0d,0xf6,0xdd,0xae,0x46,0xbf,0x69,0x86,0xda,0xf6,0xb3, - 0x79,0x3b,0xb4,0xe6,0xa6,0x96,0x2d,0x6b,0x69,0xb2,0x49,0x28,0x01,0x8f,0x47,0x4e, - 0x18,0x74,0x8d,0x50,0x47,0x7a,0xd1,0x0f,0x71,0x2e,0x85,0xc6,0xff,0x1b,0x30,0x0d, - 0x26,0xd6,0x85,0x8c,0xd9,0x6e,0x50,0x0e,0xd9,0xa7,0x23,0x1e,0x48,0x09,0x3f,0x65, - 0xdf,0x2d,0xb1,0xbd,0xa5,0xf8,0xd9,0x30,0xd5,0x6c,0x84,0x48,0x66,0x3d,0xee,0x02, - 0x36,0x1a,0x6d,0xae,0x89,0xf6,0x0c,0xa7,0xba,0x3d,0x3a,0x8c,0x4d,0x20,0x9f,0x0a, - 0xac,0xdc,0xa2,0x1e,0xed,0x08,0xcd,0x2d,0x49,0x5c,0x25,0x82,0xf3,0x76,0x03,0x2b, - 0xe5,0x05,0xeb,0xd0,0x10,0x07,0x89,0xe6,0x9e,0x9a,0xf9,0xff,0xfa,0x5f,0xff,0x9b, - 0xd1,0xe2,0xe4,0x46,0xb7,0x54,0xec,0xa4,0xa1,0x61,0x4d,0x68,0x0d,0x03,0x13,0x05, - 0x41,0x44,0x74,0xec,0x7f,0xe6,0xb9,0x45,0x00,0x8b,0x75,0x96,0x71,0x58,0xa3,0xb4, - 0x44,0x1c,0xd3,0x18,0xb7,0x32,0x76,0x8b,0x5a,0x89,0xe9,0xa7,0xcc,0x3f,0x10,0x58, - 0x7e,0x26,0x41,0xa5,0xeb,0xd3,0x75,0x70,0x80,0xbf,0x96,0xf9,0x96,0x32,0xa7,0xdc, - 0x52,0xab,0x8a,0x45,0x0b,0xc4,0x51,0x21,0x7a,0x7e,0x43,0xb3,0x60,0xad,0x95,0x25, - 0xe1,0x12,0x76,0xb8,0xd0,0x87,0x45,0x31,0xc6,0x7b,0x7f,0x7c,0xf5,0xf2,0x9b,0xaa, - 0x5a,0xbd,0x91,0xa8,0x1b,0x83,0xbd,0xf4,0x34,0xca,0x49,0x46,0xe9,0xfa,0xaf,0x7f, - 0x78,0x4b,0x1d,0x37,0x5d,0x6b,0xce,0x4b,0x34,0xb9,0xfa,0xd3,0x6f,0x38,0xd1,0xa9, - 0xeb,0x5b,0x09,0x8d,0x3e,0x73,0x44,0xb4,0x3b,0x7c,0xf4,0x92,0xe4,0x5e,0xfa,0x68, - 0xe0,0xbe,0x9a,0x73,0x98,0xd4,0x0e,0x1f,0x95,0x31,0x68,0x33,0x0a,0x8a,0x8f,0xcc, - 0xc6,0xff,0x78,0xfa,0xfd,0x77,0x11,0xeb,0x29,0x5d,0x7c,0x58,0xa8,0x72,0x95,0xd3, - 0x7e,0x79,0x4b,0x6b,0x14,0x6c,0x44,0xc5,0xa0,0xf1,0x6f,0x6a,0xd5,0x70,0xb6,0xbf, - 0xaf,0x95,0xc3,0x36,0xbf,0x59,0xed,0x19,0xa8,0xe5,0x20,0x96,0x7b,0x7c,0x57,0x97, - 0x73,0xea,0x6a,0x02,0xce,0xf0,0xab,0x7e,0x3f,0x30,0x5d,0xc0,0xa4,0xcf,0x5f,0x4b, - 0x4f,0xac,0x7c,0x06,0xd0,0x3e,0xa1,0x8d,0xb4,0xe9,0x9e,0xfa,0xbb,0x19,0x47,0x9f, - 0x68,0xed,0xc8,0x9d,0x09,0x6e,0x61,0xfc,0x9b,0xf5,0xa4,0x91,0x34,0xb8,0x71,0xe7, - 0x3f,0x13,0x24,0x79,0x9a,0xe6,0x93,0xee,0x3b,0xa0,0xf1,0xfb,0x40,0x13,0x8c,0xf0, - 0xfa,0x6c,0x1d,0x17,0xb3,0x21,0xc4,0xc1,0x4d,0x50,0x87,0x4d,0x6a,0x1d,0x0b,0x46, - 0x67,0x4d,0x36,0xfe,0x93,0x8d,0x34,0x1f,0xd3,0xca,0xdc,0xba,0x25,0x26,0xae,0x4c, - 0x92,0x24,0x6d,0x90,0xac,0x2e,0x21,0x82,0xbc,0x7d,0x68,0x48,0x97,0x71,0x2a,0x26, - 0xc1,0x15,0x72,0x92,0x69,0x5b,0xb2,0x72,0xf7,0xfc,0xe5,0xf3,0xb7,0xcf,0x4d,0x14, - 0xdb,0x04,0xe2,0xe5,0x82,0x73,0xe6,0xaa,0x4b,0xd8,0x5f,0xe0,0xfa,0x16,0xf2,0x27, - 0x55,0x3b,0x21,0xd2,0xb2,0x7a,0x44,0xca,0x97,0x37,0xe5,0xd0,0x8c,0x25,0xa1,0xb7, - 0x31,0x01,0x69,0x8a,0x42,0x88,0x89,0x90,0xb3,0x17,0x4f,0xde,0xbe,0x38,0xd5,0x41, - 0x0e,0x56,0x87,0x30,0xc4,0x43,0x27,0xf1,0xea,0x98,0x17,0x1b,0x2a,0x1d,0xa3,0x29, - 0x93,0x02,0x4a,0x3d,0xcd,0x93,0x79,0x45,0x0a,0x17,0x97,0x15,0x59,0x26,0x19,0x09, - 0xa9,0x1c,0x21,0x1f,0x1b,0x0b,0x8d,0x31,0xa2,0x17,0x8a,0x98,0xc5,0xa5,0x6b,0x9d, - 0xe2,0x70,0x1c,0xc4,0xbc,0xc5,0xe7,0xaa,0xb4,0x2f,0x86,0x3a,0x25,0xa5,0xb4,0x2a, - 0x1e,0xa7,0x75,0x61,0x5c,0xab,0x18,0x25,0x99,0x04,0x5c,0xc0,0x5f,0x72,0xc4,0x05, - 0xe2,0xe0,0x98,0xbb,0x88,0x36,0xe3,0x75,0x3e,0xef,0xb8,0xb9,0xa6,0x4d,0x2b,0xbe, - 0x59,0x02,0x3d,0x80,0xa1,0x3b,0x29,0x3c,0x44,0x36,0x96,0x41,0x7d,0xe4,0x28,0x02, - 0xa4,0xb9,0x69,0x18,0x38,0x13,0x60,0x5a,0xad,0xd9,0x92,0xc5,0xba,0x55,0x79,0x6e, - 0x92,0x1f,0x38,0x43,0x80,0xb7,0xb7,0xaa,0x03,0x78,0xb5,0x1a,0x8c,0x79,0x55,0x08, - 0x96,0xfd,0x59,0xc2,0xb7,0x91,0x39,0x80,0x8a,0x0c,0x62,0x85,0x93,0x48,0x89,0x42, - 0x74,0x5f,0x89,0x5c,0x80,0x17,0x07,0xb2,0xa8,0x13,0x6d,0xe9,0xaa,0x74,0x8c,0xf6, - 0x6e,0x24,0xaf,0xc7,0xda,0x00,0xd3,0x24,0x6d,0x91,0x87,0xd5,0xc1,0x3b,0xcb,0x51, - 0x8d,0xc4,0x44,0x3a,0x30,0xcf,0x0b,0xeb,0x30,0x4e,0x25,0xfb,0x15,0xd1,0x2b,0x3a, - 0x30,0x52,0xd6,0x51,0x03,0x2f,0x6d,0xd5,0x0b,0x63,0xe2,0x1f,0xbd,0x39,0x6d,0x58, - 0x13,0x38,0xa9,0xcb,0xd2,0x98,0x50,0x47,0xe2,0x5c,0x88,0x60,0x9c,0xc3,0x26,0xce, - 0x81,0xf6,0x1c,0x1b,0xc9,0x8a,0xbc,0xb4,0x66,0x62,0x23,0x4d,0x14,0xa5,0xdc,0x28, - 0x38,0x00,0x92,0x03,0xb2,0xce,0x81,0x0d,0x5c,0x41,0x25,0xe1,0x5a,0x3a,0x43,0x27, - 0x09,0x43,0xc7,0xce,0x68,0xc8,0xa4,0xa2,0x49,0x7c,0x19,0x5f,0x45,0xc6,0x0c,0x9f, - 0xa6,0x63,0xe1,0x64,0x22,0x4e,0x23,0xde,0x75,0x7f,0x9f,0xef,0xbc,0xeb,0xbf,0x87, - 0x0d,0xfe,0x73,0xff,0x6e,0x19,0x13,0xfe,0x47,0x02,0x88,0x11,0xcf,0x9b,0xa6,0x37, - 0x37,0xd2,0x93,0xf1,0x1b,0x6c,0xe5,0x4e,0x1c,0x8f,0xfb,0x0d,0x0e,0x41,0xcb,0x31, - 0x86,0xb3,0x98,0xcd,0x21,0x3b,0x21,0x08,0xf4,0x34,0xa0,0xff,0x6f,0x0b,0x99,0x3c, - 0x42,0xf3,0xe2,0x46,0x8b,0x51,0x3a,0x8c,0xb0,0x2b,0x8e,0x45,0x4c,0x81,0xef,0x1d, - 0xc8,0xfa,0x13,0x1a,0x18,0xfa,0xbd,0x9d,0x14,0xe0,0x8d,0x3d,0xc7,0xc7,0xc4,0xcc, - 0xb9,0xd5,0x2e,0xaa,0xbd,0x95,0xe1,0x35,0xf2,0x32,0xf2,0xd9,0xd0,0x7f,0xfd,0xfd, - 0x29,0xf1,0x5d,0xa4,0x2a,0x0f,0xb7,0x85,0x84,0xbf,0x95,0x75,0xb4,0x8e,0x74,0x1c, - 0xd9,0x3b,0x5b,0x29,0x0d,0x4e,0xa4,0x8b,0x6b,0x4d,0xb5,0xbc,0x91,0xd0,0xe1,0x5b, - 0x8e,0xe2,0xb9,0x42,0xfa,0xc8,0x9a,0x88,0xc0,0x92,0x93,0x4e,0xed,0xc6,0x97,0xb0, - 0x45,0xb5,0x5c,0x55,0x89,0x89,0x35,0x6c,0x94,0x19,0x8e,0x1c,0x47,0xeb,0xad,0x52, - 0x5f,0xa4,0x17,0x64,0x17,0x37,0x30,0xe8,0x16,0x31,0x5b,0xbf,0xbf,0xd9,0xe2,0xe2, - 0xb5,0x01,0x58,0x33,0xb0,0xdb,0x0d,0xc0,0xdb,0x5e,0x5e,0x89,0xf4,0x9e,0xe9,0x1e, - 0x66,0x6e,0x78,0xb7,0xbd,0xb9,0x15,0xe6,0xad,0xef,0xba,0x31,0x14,0xb3,0x08,0x41, - 0xdd,0x50,0xb9,0x4d,0x90,0xb7,0xbd,0xa3,0xe3,0xbc,0xe7,0x08,0x18,0xf2,0x5d,0x7b, - 0x72,0x15,0xda,0x77,0x4e,0x18,0xce,0xe1,0xae,0x29,0xd9,0xd0,0x1e,0xe1,0x2c,0x5c, - 0x15,0x6b,0x4e,0xaf,0x8a,0x37,0xcb,0x99,0x6f,0x16,0x63,0x35,0x5f,0x7c,0xc3,0x5c, - 0x27,0x30,0x65,0xba,0xea,0x96,0x0c,0xc1,0xe6,0x40,0x6b,0xa9,0x33,0x60,0x02,0xd4, - 0x1c,0x8f,0xad,0x90,0x30,0x03,0x67,0x8b,0x14,0x64,0xac,0xbb,0x82,0x83,0xed,0xee, - 0xe9,0x36,0x1c,0xfc,0x7f,0x8a,0x07,0xb7,0x20,0xf8,0x1d,0xe5,0x28,0x3d,0xa2,0xa6, - 0x84,0xc4,0x0a,0x96,0x69,0xf7,0x53,0x0a,0xce,0x56,0x9e,0x8b,0xf6,0x5a,0xde,0x73, - 0x89,0xe7,0x56,0xa2,0xc7,0x47,0x72,0x9f,0x68,0xad,0x6c,0xe5,0x36,0x16,0x40,0x6c, - 0x46,0x97,0xf1,0x56,0x21,0xd5,0x96,0x68,0xa3,0x51,0xd7,0xa4,0xbc,0x9b,0x95,0x80, - 0x42,0xe3,0x8d,0x92,0xb6,0x0c,0x27,0x8e,0x91,0x41,0xea,0xe9,0xe0,0x7d,0x78,0x80, - 0x25,0x14,0xbe,0x42,0xfd,0x1f,0x61,0x54,0x5c,0xa9,0x5c,0x7b,0x41,0xb7,0xe8,0x7e, - 0x23,0x35,0xe9,0xc8,0xb1,0x03,0xe8,0x32,0x5c,0x5d,0x93,0x52,0x05,0x97,0x99,0x7f, - 0xd0,0x4c,0x30,0x2a,0x4f,0xb4,0x29,0x5b,0xc2,0x8b,0x23,0x3f,0x68,0x28,0xc1,0x2e, - 0xfb,0x7d,0x47,0x2c,0xe5,0x3d,0x2d,0x0e,0xcb,0x5d,0x7a,0x2b,0xea,0x05,0xaa,0x3f, - 0xd9,0xec,0xb5,0xf7,0x6d,0xf4,0x2e,0x81,0xda,0xdd,0xcb,0xdb,0x5c,0xcc,0x6e,0x67, - 0x4b,0x47,0xe4,0x7f,0xbe,0xd7,0xeb,0x79,0x4d,0xf5,0x8d,0x76,0x33,0xed,0xfa,0x93, - 0x06,0xcc,0xbb,0x02,0xc3,0x6f,0xed,0x58,0xcb,0xdf,0xf5,0x79,0x12,0x60,0x1e,0x5a, - 0xdd,0x7c,0x41,0xc4,0x8b,0x3f,0x0c,0xa1,0xe2,0x5c,0x3b,0xa1,0x9a,0x6d,0x1c,0x06, - 0x92,0xd4,0x09,0x7b,0x73,0xfd,0x03,0x95,0xa1,0x32,0xe7,0x0f,0x6f,0xbe,0xfd,0x3a, - 0x5f,0x92,0x92,0x04,0x6b,0x29,0x73,0xcf,0x03,0x7f,0x9f,0x35,0xda,0x03,0x64,0x19, - 0xdc,0xdd,0x2b,0xe7,0x30,0x54,0x1d,0x46,0x41,0x43,0x78,0xd0,0x7f,0x60,0xe2,0x65, - 0x8d,0xaf,0xdb,0xe0,0x82,0x73,0x1a,0x00,0x94,0x10,0x7d,0xf4,0xc0,0x56,0x44,0x8a, - 0xcc,0xee,0x81,0x1f,0x31,0x34,0xb5,0xbb,0xca,0xf0,0x38,0x04,0x2f,0x5e,0x3d,0x5d, - 0xcf,0xe7,0xf0,0x66,0x6c,0xc1,0x34,0xb1,0xbc,0x10,0xed,0xff,0x90,0x64,0xd5,0x97, - 0xf0,0x0d,0x5d,0xd1,0x83,0x8d,0x13,0x9a,0xa3,0x2d,0x23,0xa0,0x87,0x5c,0x1b,0x9d, - 0x53,0x68,0xd7,0xc5,0x2a,0x2f,0x39,0xc8,0x9e,0x36,0xd2,0x37,0x6f,0xdf,0xbe,0xa6, - 0x0d,0x53,0x5c,0x88,0xef,0x86,0xbd,0xbe,0x79,0x96,0x19,0x0d,0xe2,0x75,0x5c,0x20, - 0x79,0x3f,0xe5,0x38,0x66,0x25,0x22,0xe8,0x0a,0x6e,0x8d,0xf5,0xaa,0x2e,0xee,0x85, - 0x02,0x75,0xb1,0xe4,0xc1,0xb2,0xbd,0x97,0x20,0xe2,0x22,0x0a,0x88,0xb5,0x55,0xb3, - 0x3a,0x4e,0x23,0xf2,0xbe,0x51,0x29,0x7b,0x3b,0xba,0xeb,0x8c,0x29,0x0c,0x78,0xaa, - 0x31,0xac,0xb0,0x04,0xa3,0x0b,0x15,0x2e,0x94,0xcd,0x1f,0x0a,0x40,0xbe,0x6b,0xdb, - 0x0c,0xed,0xd2,0x3c,0xda,0x33,0x19,0x85,0x7f,0x5b,0x6a,0x24,0xd2,0x0f,0x62,0xd1, - 0x01,0xcf,0x9f,0x93,0x95,0x43,0x16,0x77,0x72,0x18,0xb7,0x85,0x1e,0xc0,0xfa,0x62, - 0x8e,0x32,0x30,0xdd,0xdd,0x18,0x22,0x6b,0x93,0x60,0x69,0x5f,0xa7,0xa8,0xe9,0xe0, - 0xc0,0x45,0x9c,0x64,0x63,0x6d,0xcb,0x80,0x4e,0x9f,0xa7,0x17,0x96,0x59,0x08,0xa0, - 0xbb,0xf9,0x6b,0xd8,0x12,0x89,0x45,0x4b,0x69,0x82,0xff,0xb6,0xf7,0x6c,0x95,0x7c, - 0x67,0x6c,0x3a,0x1f,0xa5,0x9b,0x1c,0x0c,0x68,0x57,0x1c,0x36,0x29,0x46,0x4b,0x74, - 0xb0,0x83,0x9a,0xed,0x5b,0xd4,0x27,0x6d,0xc6,0xdf,0x1e,0x3a,0xdd,0x73,0x60,0x90, - 0xd9,0xc7,0xbd,0xed,0xbd,0xa1,0x77,0x02,0x14,0x22,0xad,0x45,0x68,0xf6,0xe4,0xf4, - 0x2e,0x39,0x07,0xe5,0xbb,0xfa,0x5d,0xff,0xfd,0x98,0xfe,0xba,0x6f,0x7c,0x1c,0x42, - 0x48,0x8d,0x6e,0x8b,0x3b,0xd1,0x5e,0x3f,0x97,0xdb,0xd0,0xd2,0x9d,0x46,0xaf,0xdc, - 0xc4,0xfb,0xf1,0xcf,0xa5,0xdb,0xca,0xae,0xc7,0xd7,0x25,0xd4,0xde,0x47,0x57,0xc6, - 0x39,0x12,0x68,0xce,0xe8,0x73,0x73,0x83,0x58,0x50,0xe8,0xbe,0x7c,0x89,0xa2,0x27, - 0xa7,0x57,0xd9,0xf4,0x1e,0x29,0x19,0xe6,0x6b,0x3f,0xb0,0x9d,0xef,0x10,0x19,0x2c, - 0xad,0x51,0xa0,0xb5,0x54,0xe5,0xe9,0x26,0xfc,0x86,0x0f,0x9d,0x6e,0xae,0x20,0x1f, - 0x34,0x7a,0xe9,0xf2,0x60,0xc3,0xeb,0x94,0xf8,0x4e,0x3a,0x7c,0xd4,0xf4,0xba,0x4f, - 0xd2,0x7c,0x32,0xae,0x8d,0x2a,0xd2,0xc0,0xfb,0xf0,0x1a,0xf0,0x0e,0x7d,0xc4,0x7d, - 0xc1,0x35,0x49,0xf0,0x1d,0x62,0xef,0x34,0xbf,0x8d,0x6f,0x75,0x62,0xc5,0x35,0x58, - 0x71,0xc4,0x95,0x21,0x7e,0x78,0xf3,0x52,0xbf,0x24,0x27,0x15,0xd1,0x75,0x17,0x7d, - 0x3b,0xef,0x19,0xea,0x30,0xf6,0x57,0xb5,0x65,0xb2,0x07,0xf4,0xc6,0x48,0xfc,0xda, - 0xd0,0xa4,0xfb,0x84,0x9a,0xd1,0x88,0x60,0x8c,0x9d,0xc6,0x98,0x86,0x74,0x9d,0x1b, - 0x5a,0xba,0xaa,0xa3,0x1e,0x5a,0xcf,0x96,0x01,0x98,0x44,0xee,0xf2,0x73,0x07,0x4c, - 0x19,0x41,0xb0,0x09,0x8f,0xea,0x44,0xb0,0xdb,0xf4,0x90,0x06,0x39,0x69,0xe8,0x21, - 0xdb,0xd1,0x8f,0x76,0xff,0x9a,0x61,0xab,0xd9,0x5f,0xc0,0xe2,0x77,0x22,0x34,0x36, - 0xb7,0x84,0x56,0x1a,0x23,0xea,0x36,0xd8,0x1f,0x03,0x7a,0x17,0x64,0xb6,0x0b,0xaa, - 0xfd,0x7d,0x15,0x91,0x2c,0x55,0x92,0x6a,0x0e,0xcb,0x20,0xb0,0xf3,0x16,0xc3,0xe0, - 0x66,0x47,0x14,0x40,0xe8,0x2a,0x6f,0x5c,0x09,0x5a,0xad,0x32,0x9b,0x44,0xbc,0x2d, - 0xef,0x74,0x4c,0x9c,0x4e,0xa7,0x29,0x9e,0x18,0xf3,0x31,0x7d,0x1b,0x7e,0x4c,0x3b, - 0xfd,0x94,0xd8,0x50,0x6b,0xad,0x62,0x30,0xfb,0x0d,0xf1,0x3b,0xb7,0x2a,0xa7,0xa2, - 0xaf,0xe5,0xe7,0x27,0x5a,0xe1,0xb6,0x6b,0x1a,0x0c,0x6f,0xd5,0xe3,0x82,0x90,0xbf, - 0x68,0x4b,0x88,0x75,0xb4,0x24,0x6b,0x86,0xe3,0xd3,0x92,0xa4,0xf0,0x38,0xeb,0x3c, - 0xf9,0x5c,0x2c,0x56,0xcc,0xf4,0x39,0xe2,0xe0,0x5f,0x07,0x0f,0xfb,0x4b,0x7a,0x1a, - 0x73,0x70,0x54,0xbb,0xae,0xf3,0x85,0xa3,0xeb,0xdc,0x12,0xc9,0x72,0xbb,0xb6,0xd9, - 0x66,0x6e,0x75,0xad,0xad,0x8d,0x7a,0xeb,0xde,0xff,0x8f,0x96,0x56,0xa9,0xd4,0xe6, - 0x5d,0xcf,0x87,0xe0,0x24,0x37,0x1c,0x5f,0xc1,0x0a,0x02,0x6a,0xc1,0x0f,0xfd,0x33, - 0x55,0xf9,0x37,0x3e,0x44,0x13,0xfa,0x67,0xbd,0xa2,0x3f,0x52,0x0b,0xe6,0x06,0x8b, - 0x74,0xe3,0x63,0x4a,0x48,0x72,0x5e,0x4d,0xab,0xd0,0xa3,0x59,0x91,0xfa,0x34,0xdc, - 0x24,0xfb,0x82,0xd0,0xc1,0x1f,0xa4,0x86,0x8a,0xc8,0x63,0xb6,0x90,0x0e,0x17,0xa7, - 0xa0,0xb5,0x12,0xe1,0x6d,0x8a,0x48,0x36,0xc8,0xa8,0xa1,0x64,0xdf,0x12,0xf7,0x2b, - 0x25,0xb1,0x8a,0x53,0xe7,0xa0,0xd2,0x4c,0xd8,0x20,0x58,0x70,0xbe,0xd8,0xcc,0x58, - 0x74,0x51,0x89,0x31,0xcf,0x9a,0xd5,0xf1,0xd2,0x44,0x45,0xde,0x1f,0xb4,0xea,0x23, - 0x71,0xb1,0xb0,0xac,0x11,0xbd,0x5d,0x8b,0x29,0x8c,0xeb,0x6c,0x88,0xfd,0x54,0xca, - 0xc1,0x70,0xe0,0x8e,0x58,0x33,0x5f,0xff,0xf0,0x16,0xc5,0x50,0x04,0x36,0x92,0x80, - 0xd9,0xe8,0x16,0x7a,0xb5,0x6b,0x42,0xd2,0xdd,0xac,0xe6,0x25,0x0b,0x2b,0x90,0xa1, - 0x22,0x76,0xe9,0x75,0xda,0xd4,0xd0,0x8e,0x51,0xbc,0x2f,0x73,0xc9,0x68,0xe3,0x12, - 0xd3,0x3a,0xa1,0x2a,0xf2,0x9e,0x94,0x25,0x72,0xee,0xae,0x24,0xda,0x50,0x4a,0xd6, - 0xc4,0x3a,0x90,0xd7,0xab,0x23,0x9a,0x25,0x99,0x92,0xa3,0x7f,0x2f,0x21,0x4d,0xf1, - 0x64,0xdb,0xa8,0x5c,0x91,0xd8,0x4c,0x52,0x2a,0x57,0xca,0x45,0x9a,0x41,0x69,0x12, - 0xf6,0x42,0xed,0xc7,0x92,0xb0,0x9d,0x9c,0x83,0x94,0x22,0x7e,0x57,0xf2,0xf9,0x6c, - 0x1c,0xc7,0xd0,0xe6,0x77,0xb3,0x39,0x97,0xa5,0x7a,0x2e,0x30,0xc9,0xee,0x58,0x99, - 0x7a,0x1b,0xf3,0x2d,0x40,0x10,0xdf,0x79,0x8a,0x46,0xb6,0x53,0xbd,0x00,0x05,0x3f, - 0x30,0xb1,0x30,0x1c,0x6f,0xba,0xbf,0x7f,0xcf,0x7c,0x10,0xdc,0xc1,0xe3,0x65,0x1b, - 0xc7,0xe5,0xae,0xf6,0xae,0xfd,0x34,0xa0,0x9b,0x68,0xda,0xb6,0x6c,0xbf,0xeb,0x72, - 0x50,0x4c,0x0d,0x9f,0x49,0x82,0x94,0xd2,0x6f,0xe6,0xc4,0x03,0x96,0xcc,0x21,0x34, - 0x5a,0xf3,0xa0,0xe8,0x0b,0xd6,0x0d,0x01,0xfb,0xaa,0x98,0xcf,0x65,0xa1,0xd9,0x68, - 0x0f,0xf9,0x43,0x22,0x3b,0xe1,0x1e,0x64,0xec,0x4d,0xf0,0x2a,0x57,0x4b,0x81,0xa7, - 0x21,0x2f,0x0a,0x89,0x0a,0xa3,0xd6,0x18,0x57,0x64,0xc2,0x4e,0xdf,0x3e,0x79,0xfb, - 0xfc,0x4f,0x2f,0x9f,0x3c,0x7d,0xfe,0x72,0x7c,0x8d,0xb3,0x0c,0x7d,0xa6,0xdb,0xd4, - 0x1a,0xfb,0x09,0xb1,0xdf,0x86,0xbe,0x8e,0x5e,0x42,0xac,0xca,0xd0,0xb7,0xf9,0x93, - 0x7e,0xb8,0xa5,0xcb,0x42,0x04,0x51,0xc5,0xd0,0xe7,0x98,0xd0,0x2b,0xd3,0x04,0x6f, - 0xd3,0xa1,0x6f,0x52,0x01,0xf8,0x5e,0x7e,0x3e,0xf4,0x7f,0xfd,0x9f,0xff,0x5d,0x92, - 0x4b,0x43,0x60,0x32,0xae,0xff,0x87,0x21,0x6c,0x0d,0xee,0x54,0x28,0x1c,0xf6,0xf0, - 0x4f,0x22,0xc9,0xfd,0xf2,0x3c,0xdd,0x8a,0x52,0xe2,0x3d,0xae,0xb9,0xf0,0x89,0xcf, - 0x79,0x87,0x6e,0x31,0x96,0x5f,0x5a,0xf2,0xdb,0xe4,0x93,0x1d,0x69,0x3f,0xa9,0x1c, - 0x05,0xe2,0x4e,0xd9,0x67,0xc6,0x2e,0x7c,0xdb,0x9b,0xb3,0xe4,0x02,0x39,0x98,0x79, - 0x23,0x6d,0x09,0x87,0x38,0xf8,0xa3,0xbd,0xbf,0x34,0x71,0xec,0x97,0x6c,0x27,0x71, - 0x2c,0xa9,0x9c,0xcc,0x31,0x49,0x66,0xb8,0x53,0xb6,0x57,0x59,0x35,0x1a,0x2e,0x59, - 0x4d,0xa9,0x22,0x3e,0x56,0x11,0x8b,0xe8,0x9f,0x80,0xd0,0x0e,0xf9,0x56,0xfd,0xc9, - 0x56,0xcf,0xf2,0x36,0xbd,0x47,0xfc,0xb5,0x4e,0xad,0x95,0x96,0x88,0x1a,0xdf,0xdc, - 0xf4,0x49,0xed,0xf9,0x9d,0x1f,0x0c,0x1d,0x4c,0x7b,0xc7,0xdf,0xe9,0x92,0x1c,0x98, - 0x9e,0xed,0x94,0xa1,0xed,0x7b,0xe8,0x7f,0x2b,0x7f,0x06,0x16,0x77,0x1b,0xfa,0xe0, - 0xc2,0xd1,0xb0,0xda,0x4f,0x3e,0xb1,0x36,0x8d,0x68,0x2e,0x1c,0xf9,0xd0,0x48,0x14, - 0x9c,0xdf,0x9e,0x50,0x46,0xdf,0xce,0x1b,0x39,0x53,0x5b,0xe3,0xb5,0x02,0x68,0x03, - 0xe8,0xf9,0xce,0x30,0x26,0x8e,0x73,0xa0,0x39,0x14,0xe6,0x68,0xfb,0xfb,0x74,0x4d, - 0xfc,0xac,0x31,0x28,0xf5,0x89,0x41,0xa9,0xc6,0xa0,0x20,0x23,0x8c,0xd4,0xf6,0xb2, - 0xd1,0xdd,0x51,0x7b,0x12,0x97,0x6a,0x40,0xf4,0x4b,0x7b,0x46,0x92,0x36,0x7a,0xd4, - 0xd6,0x24,0x3e,0xab,0x41,0x53,0x39,0xce,0xd1,0xb0,0x04,0xb7,0xf6,0x82,0x73,0xd2, - 0xc0,0xf9,0xb8,0xcf,0x1b,0x5e,0x67,0x67,0xdc,0xbe,0x15,0xdd,0xb9,0x20,0x16,0x1f, - 0xe4,0xe7,0x07,0x07,0x23,0x43,0x61,0x9b,0xb3,0x14,0xe0,0xef,0xc1,0xc1,0xc6,0x18, - 0x1e,0xb8,0xfd,0x31,0x1c,0x38,0x90,0x9a,0xe8,0x43,0x9f,0x99,0x0d,0x21,0x25,0x75, - 0xdf,0xb4,0xad,0x27,0xa6,0x6c,0xa2,0x38,0xe3,0xd9,0xe5,0xce,0x19,0x74,0xf6,0x4b, - 0xfb,0x06,0xac,0xec,0xdc,0x91,0xdf,0x14,0xc0,0xf8,0x1b,0x53,0xa4,0xae,0x95,0x3a, - 0xa1,0x48,0x56,0x73,0x70,0x5a,0x7c,0x6d,0x59,0xec,0xf9,0x26,0x70,0xc3,0x2e,0x6f, - 0x13,0x13,0x77,0x2c,0x4e,0xb7,0xb9,0x96,0xc5,0xef,0x29,0xb1,0xfd,0x44,0xfa,0xff, - 0xa0,0x26,0xa7,0x62,0x85,0x22,0x7d,0x14,0x8e,0x41,0x3e,0x4a,0x87,0xe5,0x06,0x92, - 0x40,0x66,0x3a,0x20,0x38,0xef,0x71,0x1d,0x05,0x29,0x1c,0x0a,0xe7,0x1e,0x9c,0x48, - 0x24,0x01,0xfc,0xeb,0x00,0xc2,0xd0,0xe0,0xc8,0x9b,0x25,0x4a,0xe7,0x0f,0x70,0x01, - 0x95,0x85,0x8a,0xd3,0x6a,0x71,0x15,0x70,0x35,0x93,0x17,0xba,0x26,0xbb,0x4e,0x7c, - 0xc1,0xc1,0x16,0xba,0xd0,0x44,0x85,0xf2,0xd5,0x52,0x63,0xfa,0x52,0x6a,0xc1,0x17, - 0x46,0x84,0x12,0x4f,0x00,0x0b,0x51,0xc6,0x96,0xcc,0xb2,0x4c,0x09,0xd7,0x64,0xc1, - 0x2e,0x71,0x94,0xe9,0x9f,0x49,0xfe,0x37,0xa4,0x9a,0xae,0x16,0xbf,0xd7,0xa5,0x78, - 0x73,0x59,0x6c,0x9b,0xd5,0x21,0xc5,0x71,0x76,0x75,0x19,0x5f,0x05,0x2c,0x45,0xb1, - 0xe3,0xfc,0x32,0x37,0x82,0xce,0x48,0x24,0xb6,0x94,0xc5,0x29,0xed,0xd4,0x05,0x16, - 0x8b,0xeb,0xd6,0x48,0x43,0x0e,0x0b,0x5a,0x67,0xff,0xd4,0x15,0x3b,0x10,0xd7,0x27, - 0xe8,0x26,0x8f,0x5d,0xb6,0x83,0x75,0xa3,0x2b,0xc4,0x0b,0x96,0x15,0xec,0x07,0x2c, - 0xa5,0xee,0xdc,0xd5,0xb5,0x0b,0x13,0x29,0x35,0x04,0x24,0x3e,0x6e,0x70,0xaf,0xe0, - 0xba,0xb1,0x8b,0x9c,0x04,0x02,0x91,0x65,0xc7,0xa6,0x3d,0xb3,0x97,0x92,0x12,0x71, - 0x2e,0xd6,0x42,0x66,0xe2,0x1f,0x7f,0x1e,0x27,0x07,0x83,0xd1,0xcf,0x0d,0x10,0x47, - 0x3f,0x1f,0x1c,0x04,0x86,0xc4,0x74,0xa5,0xa1,0x9f,0xdf,0x6b,0xe4,0x13,0xa1,0xfa, - 0x66,0xeb,0xae,0x06,0x97,0x64,0xa4,0xc3,0x9f,0x20,0x06,0xff,0xdd,0x61,0x42,0x44, - 0xa4,0xac,0xea,0xaf,0x39,0x9f,0x23,0xd0,0x50,0x58,0x1d,0x55,0x70,0x1a,0x94,0x78, - 0x24,0x24,0x91,0x76,0xba,0xe5,0xe1,0xec,0xfd,0xfc,0x54,0xd0,0x10,0xca,0x02,0xc4, - 0x97,0x10,0x81,0xc5,0xd7,0x6d,0xd1,0xb0,0xe1,0xe8,0xb7,0x98,0xec,0x97,0x0e,0xa2, - 0xb2,0x6c,0x5c,0xe8,0x63,0xa0,0xa4,0x2d,0x20,0x7a,0xa2,0x24,0x10,0x7e,0xe1,0x75, - 0xf9,0xdd,0xde,0x74,0xb1,0xce,0xce,0x49,0x2a,0x62,0x44,0xa6,0x3f,0x1a,0x0d,0xad, - 0xcc,0x9c,0x93,0x98,0x8c,0x70,0x54,0x89,0x25,0xcf,0xf9,0x24,0x32,0x69,0xce,0x16, - 0xcb,0x98,0x2b,0x95,0xea,0x02,0x12,0x01,0x70,0xb3,0x20,0x98,0x61,0xff,0xe0,0x52, - 0xb7,0xa4,0x07,0xac,0x50,0x54,0x99,0xb6,0x17,0x2c,0x44,0x00,0x8b,0xbd,0x2b,0xb4, - 0x59,0x0b,0x25,0xfe,0x2e,0x6c,0x15,0x42,0x26,0x3e,0x01,0xcd,0x48,0xf1,0x22,0x01, - 0x13,0xc4,0x67,0x3a,0xa0,0x1d,0xd2,0x9d,0x14,0x7e,0x26,0xac,0x85,0xa4,0x3c,0x1e, - 0xd0,0x13,0xae,0xf6,0x5e,0x6e,0x7b,0x5c,0xfc,0x52,0x8b,0x81,0x10,0x83,0x7b,0xf9, - 0xbc,0x27,0xad,0x89,0x33,0x4f,0x7a,0x34,0x89,0x6b,0xac,0xcd,0xa0,0xbe,0xa4,0x6c, - 0x2e,0x56,0x73,0xa4,0x74,0x11,0x2c,0x0e,0x4e,0x05,0xef,0x3a,0x12,0x42,0x48,0x08, - 0x02,0x52,0xce,0x72,0x7d,0xec,0x83,0xb4,0xb6,0xa5,0x39,0xd5,0x05,0xe5,0xcd,0xa0, - 0xb4,0x37,0x91,0x47,0xa5,0x0f,0x99,0x20,0xd5,0x42,0x54,0x1b,0x46,0x26,0x99,0x27, - 0xbd,0x5a,0x79,0xb1,0x55,0x1b,0xb3,0xab,0xd5,0x30,0x1b,0x2a,0x5f,0x5e,0x72,0xe5, - 0xff,0x7a,0xc2,0x7c,0x23,0x20,0xa3,0x9f,0x20,0xb2,0xdb,0xe3,0xf5,0xbc,0x1c,0xef, - 0x20,0xaf,0xa0,0xad,0xd9,0x82,0x78,0x87,0x50,0xdc,0x28,0x2f,0xc6,0xcf,0x24,0x38, - 0xcc,0x54,0xb9,0xc6,0x62,0xf3,0x88,0x88,0xfe,0xd8,0x6f,0x6a,0x91,0x3a,0x7c,0x82, - 0x23,0xff,0x18,0xd8,0x9a,0xec,0xd2,0xc8,0xd5,0x2c,0xd1,0x79,0x8c,0x5a,0x0f,0x54, - 0xe9,0x1c,0x9f,0xf8,0xc6,0x7c,0x69,0x76,0x47,0xbb,0x01,0x4c,0xc8,0xcf,0xc1,0x20, - 0xd8,0x84,0xf7,0x1f,0xf6,0x5d,0xc7,0x32,0x88,0xc3,0x56,0x80,0x1d,0x8f,0xe8,0xc4, - 0xaf,0xf5,0x49,0xe2,0x25,0x2d,0x31,0x77,0x9f,0x8c,0xb8,0xdb,0x9a,0xa8,0x7b,0xdc, - 0x6e,0xf0,0xc9,0x98,0x3b,0xa1,0x06,0x27,0xfe,0x80,0xba,0xed,0xfb,0x66,0x3b,0xbf, - 0xe5,0x83,0x78,0x10,0xf7,0xc6,0xa9,0x29,0xfd,0xde,0x57,0xfd,0xdf,0x45,0x5e,0x07, - 0xa7,0x04,0x71,0x46,0x89,0x44,0x4e,0x49,0x31,0x8f,0x0a,0x47,0x2b,0x75,0xe4,0xa8, - 0xa7,0xca,0xeb,0x58,0xf6,0xdb,0xc1,0x6c,0x4a,0x73,0x31,0x17,0x00,0x5b,0x49,0x8d, - 0x34,0x9a,0x54,0x6a,0xc7,0x29,0x1c,0xa3,0xe9,0x03,0x82,0x99,0xa4,0x7e,0x8a,0xce, - 0x46,0x21,0x05,0xb6,0x60,0xce,0x0d,0xb7,0x39,0xbb,0x86,0x74,0x6b,0xf4,0xde,0x7a, - 0x4a,0xf8,0xab,0xd3,0x49,0x38,0x69,0x66,0x40,0x90,0x25,0xe5,0x56,0xe6,0xcd,0x65, - 0x66,0x0e,0x01,0x62,0xf3,0x6b,0xa4,0xe7,0x51,0xc4,0xde,0x28,0xcf,0x4c,0x79,0xb0, - 0xf1,0x8e,0x89,0x0f,0x33,0xa8,0x34,0x2d,0x86,0xcd,0x6b,0xcd,0xfb,0xac,0xe1,0x94, - 0xd4,0x68,0xe6,0x54,0xfb,0x50,0x91,0xd8,0x20,0x0f,0x49,0x7a,0x83,0x7b,0xf3,0xf3, - 0xaf,0xfa,0xb5,0xc8,0x6b,0x1e,0x12,0xa9,0xd6,0x8f,0x03,0x8d,0xb5,0x20,0x89,0xdb, - 0x88,0x65,0x82,0xee,0x59,0xe3,0x80,0x67,0xce,0xb5,0x2c,0xdd,0x05,0xe9,0xec,0xd7, - 0xe0,0xc0,0x6f,0x40,0x22,0x77,0x22,0x29,0xa9,0x7b,0x66,0x9c,0x2c,0x0a,0xf3,0x2f, - 0x16,0x86,0x07,0x8d,0xe1,0xf5,0x5d,0x99,0x9d,0x5f,0x7a,0x3c,0x3e,0x22,0x61,0x4f, - 0x40,0x17,0x9e,0x33,0x6a,0xc0,0x7d,0xbb,0x61,0x58,0xb3,0xe5,0x8d,0x88,0x44,0x6e, - 0xbe,0xdd,0xf6,0xfe,0xe5,0x1d,0xdb,0xea,0x96,0x77,0xfa,0xca,0xf8,0xb0,0x70,0x3b, - 0x55,0x1f,0x89,0x19,0xfd,0xab,0x22,0x46,0xdd,0x78,0x51,0x0d,0x27,0x09,0x9e,0x86, - 0xca,0x10,0x2a,0xef,0x80,0x24,0xdf,0x19,0xd1,0xd7,0x09,0x01,0xbd,0x6e,0x1b,0xa7, - 0x7e,0xf8,0xb1,0x56,0xec,0x1a,0xee,0x0c,0x57,0x02,0x43,0xed,0xf3,0x9a,0x52,0x10, - 0x3a,0x42,0x38,0xdd,0xc9,0xb8,0xb5,0xa7,0x05,0xa0,0x70,0x7b,0x17,0x4e,0x81,0xff, - 0xd4,0x94,0xdb,0xbd,0x9a,0xbb,0x71,0x09,0xdb,0x3a,0x05,0x0c,0x16,0xf1,0x7c,0x2e, - 0xb1,0x80,0x07,0xba,0x26,0x3d,0xc8,0xf3,0xa5,0x8e,0xde,0x73,0x2a,0x9b,0x3d,0x53, - 0x53,0x2e,0x8d,0xac,0x3e,0xf0,0xd9,0x72,0x0b,0x3e,0xd1,0xeb,0x2a,0x5f,0x37,0x92, - 0x72,0x45,0x56,0x2c,0x95,0x8e,0xad,0x8b,0x8b,0xe9,0x22,0xb9,0x90,0xa3,0xe2,0xb8, - 0x8e,0xed,0x8a,0xc9,0x1a,0xa7,0xda,0xaa,0xa2,0x66,0xf0,0x4b,0x85,0x9a,0x7d,0xa5, - 0x07,0x57,0x7f,0xed,0xd9,0x35,0x05,0xad,0x88,0x7f,0xd0,0x6d,0x91,0x50,0x74,0x3d, - 0x51,0x64,0x03,0x87,0x52,0x69,0xd7,0x3d,0xfc,0x89,0x65,0x19,0xae,0xdd,0xac,0x2b, - 0xa8,0x11,0x47,0x45,0x92,0x14,0x4e,0x56,0x10,0x57,0x93,0x3e,0xa0,0xc9,0x1c,0x9b, - 0xe0,0x14,0x40,0xec,0xca,0x79,0x98,0x5f,0x3f,0xfb,0x2e,0xb0,0xc9,0xc2,0x20,0xba, - 0xa5,0x1c,0x12,0xf3,0xf2,0xc9,0x77,0x56,0x18,0x62,0x73,0x1b,0xd1,0x64,0x7b,0x7c, - 0x9d,0x18,0x2c,0x99,0x8b,0x8b,0x9f,0x7a,0x66,0x2a,0x9a,0x62,0x82,0x6d,0x68,0xa5, - 0xd0,0xf9,0xf5,0x4a,0x8c,0x4c,0x3f,0x7e,0xfb,0xfa,0x4f,0xaf,0x9e,0xfc,0xf1,0x4f, - 0x4f,0xff,0xf9,0xed,0xf3,0xd3,0xf1,0x97,0x9f,0xa3,0x7e,0x11,0xff,0x71,0xed,0x3c, - 0xae,0x63,0x57,0x5b,0xe8,0x1a,0xfe,0x3a,0x13,0x03,0xd0,0xea,0xc2,0x75,0x9c,0xf4, - 0x3b,0xc6,0x3b,0x7a,0x31,0x24,0x19,0xbf,0x51,0x5a,0xf0,0x56,0xf3,0x08,0x97,0x43, - 0xb7,0x06,0x92,0xa8,0x2c,0xa6,0x63,0xdf,0x09,0x7d,0x10,0x27,0xde,0xcf,0xa5,0xa9, - 0x93,0xd4,0x42,0x21,0x0a,0x04,0xd7,0x6c,0xea,0xe7,0x3b,0xb1,0xd6,0x04,0x4b,0xb7, - 0x35,0x5a,0xc1,0x06,0xef,0xae,0x33,0xc7,0xbb,0xe8,0x07,0xa6,0x35,0x0b,0x34,0x04, - 0xc2,0xa6,0x7d,0x64,0x2b,0x47,0x43,0xcf,0x01,0x0b,0x53,0x31,0x04,0xaf,0x8a,0x45, - 0xcd,0x77,0xef,0x87,0xbc,0x4c,0x06,0x09,0x0d,0x96,0x86,0x88,0xae,0x2b,0x4d,0x9c, - 0x2e,0x02,0x74,0x05,0x73,0x75,0x2e,0x25,0xea,0xf5,0xa5,0x90,0x40,0x71,0xd4,0x4b, - 0x1a,0xaf,0x4a,0x36,0xdb,0x4e,0xe2,0x92,0x65,0x57,0x09,0x21,0x9d,0xe5,0x95,0x7c, - 0x4d,0xc2,0x21,0x22,0x3a,0x9d,0x13,0x0e,0x75,0x28,0x2e,0x57,0x7a,0x93,0xcd,0xf2, - 0x27,0xc2,0x86,0xaf,0xbf,0x3f,0xfd,0xe3,0x61,0xf4,0xa7,0xcf,0xbd,0x9f,0x21,0x88, - 0xc7,0xde,0xab,0x78,0xda,0x43,0x8c,0x33,0x03,0x08,0xa9,0x94,0x55,0x30,0x1d,0x14, - 0xbc,0x4a,0xb9,0x30,0x9b,0xf7,0xf4,0xfb,0xb7,0xdf,0xd0,0x9e,0x23,0x4a,0x1b,0x93, - 0xa8,0xa9,0xf9,0x35,0x3e,0x28,0x57,0x6a,0x2a,0x56,0x69,0x9a,0x9f,0x42,0x07,0x16, - 0x79,0x9c,0xe6,0x7a,0xd8,0xe1,0x02,0x9d,0x68,0x27,0xfa,0xee,0xf9,0x5b,0xe2,0xe3, - 0x5f,0xf3,0x9a,0xbf,0xa0,0x39,0x32,0x15,0x7c,0xaf,0x6a,0x52,0xf0,0x1a,0x35,0x63, - 0x4f,0x49,0x42,0x4b,0xf1,0x26,0xb1,0x6a,0x30,0xf4,0xde,0x13,0xd9,0xde,0x5c,0x32, - 0x0e,0x15,0xf9,0x65,0x13,0xc8,0x57,0x92,0x07,0xd3,0xf9,0xa9,0x83,0x3b,0x7f,0x60, - 0x94,0x2d,0x4d,0xb9,0x44,0x2d,0x67,0xcf,0xf4,0x29,0xc6,0x1c,0xc1,0xa1,0x2b,0xa4, - 0xf3,0x16,0x4b,0x2a,0x3d,0x3f,0x72,0xec,0x0e,0xdd,0x29,0xab,0xb5,0x9c,0xb2,0x61, - 0x14,0xd9,0x8c,0x53,0x54,0x71,0xc5,0x33,0x45,0xb7,0x60,0xc0,0x97,0xe3,0x22,0x97, - 0x3a,0x40,0x3b,0xb4,0x3b,0x7c,0x2d,0xce,0x61,0x25,0x45,0xe3,0x76,0x5e,0x6b,0x78, - 0x0b,0xf4,0x2e,0xed,0xc4,0x3f,0x4d,0x7e,0xba,0x24,0x65,0x03,0xb4,0xb1,0x13,0x89, - 0xab,0x84,0x80,0x65,0x05,0x3d,0x37,0x27,0x0f,0x08,0xed,0xe0,0xf4,0x4b,0x56,0xaf, - 0x59,0x6d,0xc1,0xf8,0x59,0xf2,0x46,0x8c,0x39,0x90,0x4d,0xc2,0xa8,0x30,0xcc,0x24, - 0x1b,0x4a,0x94,0x39,0x96,0x3d,0x14,0xfa,0x10,0xea,0x2a,0x7f,0xd1,0x4e,0x52,0x30, - 0x57,0xac,0xe4,0x80,0xe3,0xa1,0x73,0x22,0x1d,0x66,0x8f,0x56,0xa1,0x99,0x08,0x43, - 0x7a,0x3f,0x0d,0x4c,0x72,0xb0,0xb9,0x21,0xf1,0xd1,0xc0,0x08,0x6e,0x0b,0x32,0xd7, - 0xaa,0x8c,0x94,0x38,0x34,0x32,0x24,0xe6,0x95,0xa5,0x62,0xe9,0x8b,0x75,0x1c,0xd3, - 0x11,0xb7,0xa5,0x0b,0x29,0xc4,0x88,0x48,0x67,0x16,0xc1,0x90,0xc4,0x52,0x03,0x96, - 0x40,0x81,0x24,0xcf,0xcd,0x96,0xf9,0x1a,0xf5,0x95,0xbb,0xb6,0xcb,0x43,0x94,0xc6, - 0x55,0x41,0x68,0x4a,0xd1,0xc7,0x26,0xf4,0x5e,0x1f,0x7c,0xd2,0xd0,0x5d,0xa5,0x50, - 0x08,0xe3,0x27,0xd7,0xcd,0xad,0x8c,0xc1,0x5e,0x68,0xb9,0x44,0xd9,0x39,0x06,0x08, - 0x3d,0x00,0xf4,0xdc,0xb5,0xfe,0x8b,0xc3,0x7f,0x71,0xa0,0xfd,0x89,0xc1,0xb5,0x6a, - 0x4e,0x16,0xdc,0xdc,0x40,0xf3,0xa1,0x17,0x76,0x9e,0x04,0xcd,0x3a,0x7c,0x96,0x78, - 0xd2,0xfb,0x88,0x23,0xb9,0xc1,0xeb,0x37,0x34,0xa7,0x41,0xb3,0xb5,0x7f,0xd1,0x0b, - 0xf6,0x13,0x56,0xcc,0x79,0xd4,0xb0,0x03,0x0a,0x45,0x01,0xad,0x29,0x39,0xc4,0x01, - 0x41,0x94,0x36,0x56,0x08,0xbe,0xd1,0x31,0x87,0x4f,0x45,0x24,0x29,0x93,0xcc,0x7a, - 0xb5,0x52,0x52,0x17,0x2e,0x42,0x8e,0x83,0xfd,0x80,0xeb,0xb9,0x18,0xbd,0x83,0x23, - 0xe7,0x9b,0x06,0xb4,0xb9,0xb5,0x9f,0x11,0xc8,0x84,0x56,0x16,0x98,0xb9,0xae,0x7c, - 0x16,0x04,0x6e,0x58,0xc8,0x36,0xc3,0xe0,0x16,0x65,0x1b,0xb5,0xb5,0xe9,0xce,0x75, - 0xdd,0x20,0x1b,0x2e,0xd8,0x07,0x2b,0xa7,0xd4,0xe8,0x70,0x0f,0x78,0x33,0x1a,0x35, - 0x8a,0xee,0x14,0x9d,0x24,0xa5,0xff,0x43,0x12,0x1e,0xb2,0xf1,0xf5,0x26,0x94,0xc8, - 0xcc,0x7e,0x6d,0xbf,0x47,0xce,0xd9,0xd8,0x05,0x8d,0x83,0xa9,0xe8,0xed,0x77,0x02, - 0xd0,0x7b,0x08,0xed,0xf5,0xd5,0x78,0x30,0xb2,0x27,0x00,0xcc,0x83,0xcd,0x5d,0x83, - 0x9e,0x64,0x1e,0xb6,0x4d,0xaf,0xf3,0x46,0xc4,0x4c,0xfb,0x04,0x8b,0x71,0x76,0x77, - 0x9e,0x02,0x0d,0xc2,0x56,0xed,0x8b,0x8f,0xc5,0x4d,0x19,0x5c,0x6c,0x46,0xe1,0xed, - 0xb8,0xf3,0x27,0xeb,0xf9,0x56,0xb9,0x38,0xe6,0x91,0x4e,0x60,0x0d,0x5f,0x73,0x68, - 0xcd,0x76,0xa4,0x1e,0x7d,0xea,0xc4,0x22,0x49,0x0c,0x49,0x74,0xae,0xae,0xca,0xae, - 0x69,0xa3,0x25,0x0e,0xd8,0xd6,0x2a,0x69,0x54,0x13,0x23,0x96,0x37,0xc6,0x93,0xa8, - 0x04,0x47,0xea,0x1e,0xbe,0xfb,0xe9,0xa7,0xc3,0xf7,0x87,0x41,0xb4,0xca,0x57,0xdd, - 0x46,0x04,0x15,0xe6,0x0e,0x6f,0xdf,0xdc,0xe0,0x6f,0x44,0x63,0x2f,0x9e,0x54,0x5d, - 0x2e,0x71,0xe1,0x47,0xfe,0xcd,0xcd,0x3d,0x77,0xf6,0xf0,0x4a,0x33,0x40,0x55,0xc7, - 0x1c,0x71,0x4c,0xeb,0xd8,0x40,0xf9,0x8e,0x17,0xdb,0x09,0xdb,0x75,0x3a,0x93,0x30, - 0xd9,0x86,0x9c,0x15,0x34,0xbc,0x73,0xad,0xf1,0x4b,0x30,0xd2,0xc3,0xc0,0xc3,0xee, - 0x68,0x12,0x96,0xfd,0x83,0x6e,0xa3,0x89,0xe3,0xe3,0x23,0x78,0x33,0xbc,0x57,0x4f, - 0x21,0x3a,0x6f,0x27,0xed,0xe9,0xc2,0x26,0x58,0x72,0xb4,0xcb,0xf1,0x5f,0xef,0x9a, - 0xc0,0xbe,0x0f,0x65,0x6c,0x7f,0x75,0x10,0x57,0x7d,0x86,0xc5,0x66,0x4b,0xd4,0x79, - 0xce,0x1c,0x47,0xb8,0xbe,0xae,0xb0,0x93,0x3b,0x2c,0x8e,0x99,0x98,0xa9,0x09,0xc1, - 0x92,0x38,0xfb,0xf5,0x31,0x7a,0xae,0x2c,0x8b,0xbd,0x2c,0xc2,0x8e,0xa9,0x3a,0x21, - 0xa7,0x91,0xf1,0xe1,0xa8,0x17,0x72,0xc6,0xd9,0x14,0xac,0x0e,0x72,0xb4,0x5b,0xd6, - 0x26,0x99,0x9e,0xb7,0x90,0x39,0xde,0xa8,0x8d,0xc2,0xaf,0xce,0xba,0x42,0x6b,0xb7, - 0x4e,0x61,0xa6,0x25,0xce,0x59,0x2e,0x49,0xcd,0xe7,0xd8,0x6a,0x34,0x9b,0xe9,0xbc, - 0x19,0x53,0xa1,0x1c,0x3c,0xc3,0x1c,0x89,0xbd,0x55,0xdf,0x95,0x9d,0x16,0x6d,0x94, - 0x77,0x6b,0x1e,0x59,0x42,0x73,0x2c,0x12,0x7c,0x6d,0xad,0xcf,0x3a,0x76,0xbd,0x32, - 0x35,0x79,0x0c,0x64,0xba,0x22,0x06,0xa4,0x83,0x50,0x2b,0x4e,0x79,0x61,0x23,0x23, - 0x2a,0x23,0xda,0xb5,0xc0,0xa4,0xcb,0xa3,0x69,0x3f,0x10,0x77,0x7e,0x6b,0x24,0x54, - 0x6b,0x18,0xd3,0x4e,0x6d,0x39,0xea,0x8b,0xe3,0x45,0xb5,0xe3,0x65,0xcb,0x0b,0xb5, - 0xd5,0x9b,0x5d,0x95,0xda,0x19,0x65,0x6b,0xa1,0xd5,0xa1,0x21,0xdb,0x85,0x03,0xcc, - 0x97,0x6e,0xfd,0x00,0x6d,0x54,0x80,0x3d,0x9d,0xf1,0xfd,0x7a,0x3e,0x34,0xaf,0xbd, - 0x4b,0xde,0x73,0xdc,0x94,0x7b,0x43,0xaa,0xff,0x95,0xda,0x73,0xee,0x87,0xa4,0xd8, - 0x0f,0xfb,0x21,0x5b,0x3b,0x86,0x7d,0x5b,0xd3,0xae,0xcd,0x5f,0xe4,0xb8,0x7d,0xb8, - 0x7c,0x6c,0xe0,0xa8,0xf1,0x6c,0xee,0xe8,0x3b,0x55,0xdb,0x58,0x18,0xe5,0x6a,0xbd, - 0xac,0x8f,0x39,0x79,0x67,0xa2,0xc9,0xed,0xd4,0xfe,0x36,0x29,0x1a,0x1e,0x0e,0x58, - 0x95,0xc8,0x02,0x96,0x3e,0x49,0x82,0xad,0xe4,0x94,0x63,0x9e,0xe2,0x66,0x3e,0x9d, - 0xae,0xdb,0x8d,0xb8,0x26,0x39,0xd8,0xd7,0x14,0xde,0x2d,0x58,0x0d,0xa8,0x48,0x52, - 0xe6,0x43,0x5a,0x4c,0xb5,0x16,0x73,0x60,0x4b,0x3c,0xe1,0xb8,0x97,0x9c,0x03,0x8e, - 0x45,0xf2,0x64,0xf5,0x72,0x4e,0x6c,0x68,0x21,0xc7,0x0d,0x4a,0xb9,0x29,0x24,0x84, - 0x55,0xe6,0x68,0xec,0x84,0x03,0x57,0x18,0x07,0x49,0x14,0x95,0x53,0x96,0xfc,0xe0, - 0x96,0x00,0xe4,0x46,0x88,0x9a,0x3e,0xcf,0xcf,0x64,0x45,0xeb,0x5d,0x78,0xf2,0x53, - 0xf6,0x53,0xc6,0x53,0xa5,0xe5,0x74,0x03,0x80,0x73,0x2a,0xa1,0x26,0x18,0x3e,0xaf, - 0xf2,0x81,0xbf,0x73,0x02,0x62,0xe4,0x3d,0xb1,0x67,0xe1,0xb0,0x41,0x31,0xcf,0xcc, - 0x21,0xf3,0x09,0xc1,0xb5,0x9e,0xd5,0x89,0x96,0x8d,0x44,0x3b,0xd3,0xa0,0x9e,0xc2, - 0xe9,0xba,0x40,0x45,0x23,0xe4,0xc2,0x98,0x72,0x5b,0x9c,0x60,0x53,0x56,0x45,0x7e, - 0x05,0xbd,0xfd,0x7b,0x73,0x30,0x88,0x9d,0x1c,0x73,0xe4,0xbd,0x74,0x6e,0xda,0xb3, - 0x73,0x8f,0x99,0x6d,0xe6,0x36,0x98,0x72,0x63,0xe5,0x22,0x5e,0x29,0x4f,0x87,0x36, - 0x4d,0xea,0x4c,0xdb,0xa1,0x94,0xae,0x8e,0x39,0xb6,0x2a,0xb7,0xe7,0x19,0x88,0x95, - 0x80,0x36,0xbc,0x18,0xfd,0x79,0xb5,0xa4,0x35,0xce,0x01,0x34,0x6e,0x10,0x39,0xfb, - 0x49,0xe6,0x40,0x9f,0x10,0x85,0xa4,0x2c,0xf1,0x81,0x44,0x36,0xb2,0xbb,0x3e,0x64, - 0xd2,0x6f,0x24,0x97,0x73,0xa5,0x80,0x8f,0x26,0xaf,0xc9,0x97,0xdb,0xc9,0x6b,0x7f, - 0x83,0x20,0xc0,0xdd,0xc8,0x50,0x1b,0x16,0x68,0x4b,0x27,0x63,0x55,0xae,0xbc,0x9e, - 0x63,0x61,0x11,0xff,0x43,0x46,0x92,0xbf,0x1b,0x2a,0xa8,0xcb,0x67,0xdb,0x50,0x41, - 0x87,0x19,0x6e,0x45,0x0d,0xb6,0xd9,0x2f,0x77,0xd2,0x9a,0x76,0x43,0xfd,0x1c,0x60, - 0xdd,0x7a,0xdd,0x5b,0x4e,0xe7,0xf6,0xfc,0x6a,0x4b,0x57,0x6e,0x0f,0xd9,0x2f,0xd4, - 0x2c,0xd7,0x94,0xef,0x8e,0xee,0x77,0xc7,0x3b,0x1d,0xe0,0x6b,0x21,0x82,0x7c,0x69, - 0x7d,0xee,0x7c,0x5f,0xb3,0x12,0x87,0x0e,0xe3,0x76,0x9d,0xfa,0xed,0x1e,0x4b,0x39, - 0x64,0xcf,0xc8,0x07,0x22,0x3c,0x25,0x9b,0x7f,0x40,0x60,0x96,0xec,0x92,0x7e,0x92, - 0x11,0x3f,0x49,0xf8,0x30,0x52,0x94,0x3c,0x2b,0x3c,0xce,0x25,0xed,0x81,0xc8,0x11, - 0x07,0x46,0x3d,0x7c,0x5b,0x80,0xd7,0x19,0x1d,0xfc,0xfe,0x78,0xd6,0x60,0x6a,0x4d, - 0x36,0x2d,0xcf,0x60,0x4e,0xd1,0x11,0x9c,0xac,0xc9,0xca,0x39,0x9a,0xd8,0x8a,0x26, - 0xd5,0x52,0x7c,0x09,0xeb,0x4c,0x57,0xcb,0x0e,0x25,0x75,0x3a,0xa9,0x8b,0xb0,0xcb, - 0xe9,0x9c,0xf0,0xba,0xe8,0xf8,0x3d,0xd9,0xa0,0x62,0x44,0x48,0xb8,0x54,0x11,0xfb, - 0xce,0xe0,0x31,0x80,0x2b,0x32,0x9b,0xa1,0x7e,0x5e,0x76,0xb6,0x26,0xee,0x5d,0x1f, - 0x7f,0x15,0xeb,0x9d,0x23,0x05,0x9f,0x68,0xe3,0xa2,0xe4,0x15,0x0d,0x91,0x8f,0x07, - 0xd8,0x2d,0x1c,0xc2,0x10,0x34,0x8a,0x90,0x80,0xfe,0x99,0x8a,0xde,0x4d,0xa9,0x03, - 0xcb,0xf2,0x4e,0xd7,0x7f,0xa9,0x50,0x53,0xa5,0x2e,0xaf,0xf2,0xbe,0xa5,0xda,0x05, - 0xe3,0x46,0x7b,0xb7,0xaa,0x59,0xaa,0xe4,0xd6,0x2a,0x25,0x4e,0x71,0xfb,0xfa,0x78, - 0x83,0x66,0xb9,0x15,0x20,0x6d,0x0d,0x98,0xae,0xa9,0x22,0xf5,0x50,0xfe,0xf6,0x40, - 0x6d,0x01,0xe1,0xd6,0x4d,0x31,0x70,0xdc,0x32,0xcf,0xed,0x05,0x5a,0x20,0xbc,0x5d, - 0x70,0x8a,0xb0,0x71,0x66,0xdd,0x86,0x69,0xad,0xaf,0x71,0x87,0x3a,0x26,0x72,0xab, - 0xde,0xa3,0xb1,0xd0,0x3a,0x16,0x68,0x98,0x12,0x86,0x9e,0x13,0x36,0x5d,0x4c,0xc7, - 0x8f,0x35,0x87,0xe9,0xad,0x8b,0xf4,0x38,0xb2,0x12,0x00,0xd3,0x61,0x12,0x0d,0xec, - 0xb1,0xa9,0xfa,0x30,0x3e,0xbf,0x34,0x07,0xa8,0x1a,0x53,0x1c,0x7c,0xb0,0x7c,0x00, - 0x1b,0xf1,0x17,0x1d,0x71,0xd1,0x5d,0x54,0xd5,0xaa,0xe4,0x42,0x8e,0x75,0xe7,0x62, - 0x23,0xa2,0xa6,0xf9,0x69,0xe0,0x9e,0x38,0x40,0xfb,0xe0,0xdb,0xb7,0x92,0xe6,0xcd, - 0xe6,0x29,0xa2,0x44,0x52,0x9d,0x90,0xa9,0xb9,0x35,0x59,0xed,0xe9,0xe4,0x4f,0x5d, - 0x34,0x8f,0xfb,0xc4,0x7d,0x7d,0x6d,0xcd,0xde,0x9a,0xd2,0x8a,0xa4,0xce,0x8c,0xd3, - 0x1c,0x37,0x52,0x17,0xc1,0x74,0xec,0xd6,0xfa,0x80,0xba,0x38,0x3d,0x2f,0x0d,0xcf, - 0x36,0xf6,0x69,0x6b,0xd8,0xd2,0xa3,0xb7,0x69,0x4d,0x96,0x7b,0xee,0x5a,0x53,0x60, - 0x00,0xfc,0xa1,0x48,0xbb,0x65,0x31,0xfd,0xb4,0xec,0x2e,0x84,0x58,0x87,0x46,0x1a, - 0xd3,0x0e,0xd3,0xac,0xdd,0xe5,0xb3,0x46,0x01,0x39,0x2a,0x6b,0x35,0xa6,0x1e,0xea, - 0xf2,0xb4,0x27,0x5c,0x9a,0xf6,0xc4,0xdf,0x27,0x26,0x71,0xe2,0xd7,0xf5,0x2d,0xe9, - 0xa5,0x03,0x7a,0xf9,0x80,0xcf,0xcb,0x1c,0x0f,0x76,0x52,0x7c,0x0a,0x47,0x70,0x77, - 0xf2,0xde,0xfa,0xa3,0x2d,0x2e,0xd8,0x5a,0x5e,0xd9,0x70,0x42,0x4d,0xf7,0x78,0xf6, - 0xd9,0x68,0xc7,0xc1,0xa3,0x98,0x76,0xd2,0xd9,0x20,0x5a,0x47,0x48,0xc3,0x36,0xa5, - 0x2c,0x26,0x8a,0xa5,0xfe,0x43,0x2d,0xf4,0x73,0xf9,0x35,0x39,0xad,0xcf,0x64,0xf8, - 0xaa,0x79,0xc5,0x47,0xc5,0xb0,0x9d,0xce,0xb5,0xe8,0x89,0x09,0x6b,0xa8,0x1f,0xd2, - 0x2c,0x64,0x6d,0x33,0xe5,0x97,0xa6,0xa5,0x59,0x8e,0x9a,0xad,0x6c,0x1a,0x9d,0x71, - 0xc0,0x75,0xba,0x22,0x4a,0xa9,0xb8,0xe8,0xa8,0x29,0x79,0xd8,0x2c,0x07,0xa1,0x6f, - 0x56,0xec,0xe8,0x35,0xc7,0xa4,0x46,0x75,0x5c,0x25,0x2c,0xc0,0x63,0x9c,0x98,0x80, - 0xed,0xa7,0x0f,0x28,0x13,0xa3,0x8f,0xa3,0x7b,0x3b,0xd5,0x93,0x24,0x17,0xb5,0x69, - 0x69,0xca,0x5c,0x4b,0x13,0xcd,0x84,0x63,0xf6,0x22,0x8e,0x6b,0x16,0x80,0x9b,0x68, - 0xd1,0x31,0x8c,0x96,0x21,0x2d,0x2f,0xe3,0x55,0x5b,0xc3,0xa4,0x4a,0x70,0xa8,0x3b, - 0xeb,0x10,0x59,0x68,0x42,0xdd,0xb7,0x74,0x06,0x47,0x49,0xfe,0xb8,0xda,0xd0,0xa6, - 0x38,0xdc,0xcd,0x1c,0xf4,0xa9,0xa8,0xd8,0x3b,0xe6,0xbf,0x35,0x32,0x47,0x2d,0x4e, - 0xf3,0x69,0xaf,0xad,0x79,0x1f,0x26,0xce,0xc0,0x35,0x57,0xec,0x62,0xfe,0xed,0x48, - 0x8f,0x84,0x25,0x5b,0xa1,0xa0,0xf5,0xf3,0x09,0xfb,0x49,0xe7,0xe3,0xda,0x48,0x31, - 0x79,0x5f,0x87,0x37,0x68,0x17,0x2a,0x2b,0x6a,0xf5,0x9c,0x35,0xdb,0xdb,0x91,0xd0, - 0x5a,0xfd,0xcb,0xb5,0xb2,0x2a,0xd4,0x90,0xd1,0xbd,0x46,0x75,0xb7,0xf1,0xbf,0xcc, - 0x06,0x22,0xfa,0xdf,0xe6,0xe3,0x85,0xda,0xdb,0x02,0x2f,0x77,0x2a,0xb5,0x0b,0x80, - 0x46,0x65,0xb1,0xfb,0x92,0x4f,0xe0,0xd1,0x7a,0x89,0x28,0x0e,0x09,0x82,0xf7,0x59, - 0xde,0x8f,0x2f,0x68,0xb0,0xd8,0x32,0x27,0xee,0x01,0x30,0xa2,0x81,0xb7,0xb2,0x35, - 0xce,0x81,0x78,0xfd,0xe4,0xeb,0xdf,0xef,0x30,0x32,0x62,0x60,0xf2,0x14,0xb6,0xc5, - 0x63,0xe3,0xe4,0xb1,0x74,0xc9,0x70,0x15,0xa6,0x4d,0x28,0x92,0x15,0xd6,0x87,0xfa, - 0x6c,0x25,0x58,0x94,0xf6,0x14,0x23,0x43,0x84,0x98,0x5d,0x98,0x03,0x32,0x89,0xb7, - 0xb3,0x76,0x63,0x98,0x03,0xd8,0xaa,0x8e,0xe3,0x58,0x35,0x1c,0xd7,0x7c,0xd2,0x32, - 0x98,0xa2,0x38,0x60,0x09,0xac,0xd2,0xd4,0x2e,0x45,0x31,0x73,0x06,0x06,0x42,0x3c, - 0x8a,0xa7,0xb2,0x57,0x55,0x9f,0x56,0xe4,0x9e,0x7c,0xd5,0xb1,0xdd,0x4a,0x45,0x34, - 0x66,0x75,0x5c,0x3f,0x56,0x2a,0x9d,0x41,0x69,0xeb,0x88,0xc7,0x4a,0x3b,0x8b,0x9b, - 0xc6,0x29,0x2b,0x40,0x18,0x5f,0x80,0x63,0x9f,0x82,0xd7,0x45,0xdb,0xa7,0x4c,0x0d, - 0x20,0x6c,0xa4,0x26,0xe9,0x66,0x9e,0x39,0xb2,0xc2,0x28,0x2b,0x89,0x28,0xc6,0x62, - 0x8e,0x02,0x13,0xdf,0x77,0x62,0xbd,0x6a,0x4f,0x84,0x34,0x67,0x39,0x07,0xad,0xc1, - 0xbc,0xe4,0xa4,0xbd,0x5d,0xa9,0xca,0x39,0xb7,0x95,0x06,0xbd,0xe2,0xf3,0x77,0x74, - 0x0d,0x59,0x5b,0xf6,0x86,0x40,0xaf,0xe4,0x1c,0x58,0xf8,0x2d,0x08,0x6e,0xf6,0x6a, - 0x1d,0xf5,0x8f,0x1a,0x53,0xc3,0x51,0xf9,0xe0,0xc1,0x5c,0xb4,0x5f,0xa7,0x34,0x4c, - 0x61,0xaa,0x20,0x0e,0x91,0x60,0x29,0x05,0xd3,0xb4,0x39,0x42,0xcd,0xce,0x58,0xe8, - 0x96,0x6a,0xf4,0x25,0x20,0x88,0x2b,0x4e,0x72,0x58,0x71,0x28,0xbf,0x74,0x6d,0x82, - 0x35,0x99,0x88,0x95,0xbb,0xec,0xfd,0xc7,0x64,0xe5,0x70,0x78,0xa1,0xa4,0xbc,0x47, - 0x24,0x48,0xc5,0x04,0xa8,0x18,0xe6,0xce,0xd7,0x27,0x3e,0x03,0x62,0xc4,0x7c,0x4c, - 0x3e,0x98,0x79,0x9d,0x14,0xd1,0xb8,0x1d,0x34,0x98,0x77,0x5b,0x9a,0xfb,0xed,0x2c, - 0xdc,0xc9,0x6f,0xa7,0xd9,0x72,0x6d,0xee,0x0c,0xc8,0xf1,0xf8,0x41,0x7f,0x37,0xb1, - 0xdd,0x74,0xce,0x67,0xed,0xf2,0xae,0xb4,0xe0,0x9a,0xf3,0xa0,0xdc,0xa3,0xa0,0xb8, - 0x8e,0x93,0xbf,0x9d,0xf0,0x7e,0x9b,0x8f,0xbc,0x11,0x08,0x04,0x9f,0x39,0xa7,0x56, - 0x3a,0x84,0xf0,0x36,0xa3,0xec,0x47,0xe6,0x1b,0xe1,0x43,0xdb,0x01,0xee,0x9f,0x4c, - 0xda,0x37,0xb2,0x24,0x1b,0x73,0x70,0x9a,0x9b,0x7f,0x60,0x66,0x0b,0x27,0xdd,0x36, - 0x49,0xa5,0x61,0x00,0xbb,0x34,0xdf,0xcd,0xe7,0xac,0x27,0xa1,0x16,0xd3,0xdf,0x35, - 0xf8,0x81,0x6f,0x73,0x5a,0x83,0xf7,0x77,0x4c,0xdb,0xfc,0x84,0xc5,0x72,0x6b,0x18, - 0xbb,0x54,0xb3,0x11,0x5f,0xcc,0xc7,0xa2,0x69,0x41,0x94,0xf6,0xc0,0x2b,0x8e,0xdc, - 0xd4,0xf1,0x82,0xec,0x17,0x86,0xf4,0x35,0x74,0x88,0xde,0x0f,0x6f,0x5e,0x4a,0xf0, - 0x26,0x57,0xcb,0x3a,0x21,0x7c,0x1c,0x7f,0x00,0xfc,0x9d,0x3a,0x4e,0x72,0xa2,0x03, - 0x34,0x51,0xbc,0x3d,0x3e,0xd7,0x06,0x3e,0xf1,0x49,0x47,0xde,0x53,0x90,0x3b,0x36, - 0x13,0xe9,0xc3,0x33,0x35,0x19,0xb5,0xce,0xdd,0x99,0xd7,0x99,0xc4,0x65,0x32,0x2d, - 0xa5,0x55,0x6b,0x11,0xb2,0xe2,0x1e,0xef,0x7d,0xa3,0x5c,0xa0,0x70,0x2b,0xd0,0xae, - 0x73,0xc8,0x6f,0x9b,0xf8,0x91,0x5a,0xbf,0x8f,0xf9,0x0c,0x61,0x13,0x9b,0x49,0x43, - 0x7d,0x4d,0xa3,0x62,0xc9,0x58,0x7c,0x29,0x90,0x8b,0xdf,0xf5,0xdf,0x9b,0xab,0xcf, - 0xf8,0x4a,0xdb,0x16,0x0e,0xdf,0x45,0x87,0xef,0x5d,0x3f,0x94,0xfe,0x3c,0x08,0x5a, - 0x71,0xcf,0xc9,0xc5,0xda,0x95,0xf4,0x79,0xe6,0x2d,0x08,0x45,0xbc,0x64,0xb9,0x80, - 0x66,0xf3,0x54,0x81,0x2c,0xf3,0xad,0xb2,0x4b,0x04,0x4b,0x42,0xfc,0x4a,0xbe,0x1b, - 0xc8,0xb1,0x60,0xf4,0x09,0x16,0x10,0xc5,0x4a,0xf4,0xc7,0xfb,0xfb,0x87,0xff,0xc2, - 0x3a,0xd4,0xc9,0xf0,0xa7,0xc3,0x9f,0x0e,0x0f,0x1d,0xf0,0xe8,0x69,0x60,0x96,0xf3, - 0x19,0xf4,0x1a,0xba,0x2b,0xce,0x07,0x5d,0xa6,0x0d,0x6a,0x14,0x02,0xe4,0x0b,0xa5, - 0xc1,0x1c,0x79,0xe7,0x4a,0xad,0xbc,0x0b,0xa9,0xe6,0xad,0x0b,0x44,0x4b,0xbd,0x6c, - 0x92,0xc2,0xcc,0xd4,0x81,0xae,0x1b,0x98,0x6b,0x38,0x39,0x1d,0x1a,0xe3,0xe6,0x13, - 0x87,0x4b,0x67,0x2c,0x91,0x58,0xfe,0x2c,0xf4,0xf4,0x4a,0x02,0xfa,0x74,0x15,0x21, - 0x1a,0x2e,0x9e,0x2a,0x24,0xf5,0xa9,0xae,0xb9,0xc9,0x59,0x68,0xa1,0xef,0x87,0xdc, - 0x10,0x50,0x8f,0x33,0x7e,0x9d,0x66,0xe5,0x37,0x31,0x87,0x85,0x09,0xef,0x44,0xb9, - 0x09,0x09,0xd5,0x26,0x4c,0x1e,0xba,0x27,0x8e,0x05,0x7c,0x20,0x24,0x0f,0x40,0x6a, - 0x55,0xd4,0x67,0xb4,0x48,0x2c,0x1e,0xf3,0x8d,0xfa,0xb8,0x3f,0x69,0x8f,0xcf,0x61, - 0x27,0x8c,0x75,0xa2,0x68,0x09,0x73,0x75,0x05,0xa1,0xfa,0xa8,0x17,0x6d,0x16,0x13, - 0x9f,0x08,0xb1,0x4d,0xe2,0x24,0x75,0x25,0x33,0x62,0x60,0x51,0x7d,0x7e,0x31,0x4e, - 0x22,0x34,0xab,0xc2,0xf5,0x54,0x4c,0xf1,0x6b,0x42,0x06,0x73,0x12,0xc8,0xe3,0x43, - 0x89,0xfe,0x39,0x7e,0x7c,0x08,0x8e,0x48,0xff,0x2c,0xaa,0x65,0x7a,0xfc,0x7f,0x01, - 0xe1,0xd7,0x15,0x74,0xc3,0xa8,0x00,0x00, + 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xcd,0x7d,0xdd,0x77,0xdb,0xc6, + 0x92,0xe7,0xbb,0xfe,0x0a,0x58,0x9e,0x11,0x88,0x08,0x84,0x48,0xd9,0x4e,0x1c,0xd2, + 0x90,0xd6,0x9f,0x93,0xec,0xb5,0x1d,0x8f,0xe5,0x6c,0xee,0xc4,0xd1,0xe4,0x80,0x04, + 0x28,0x22,0x02,0x01,0x1a,0x00,0x25,0x2b,0x12,0xe7,0xcc,0xd3,0xbc,0xef,0xce,0x9c, + 0xb3,0x2f,0xfb,0xbc,0x7f,0xd8,0xfd,0x4b,0xb6,0x7e,0x55,0xdd,0x8d,0x06,0x09,0xd9, + 0xce,0xde,0xbb,0x67,0xf6,0x9e,0x5c,0x99,0x00,0x1a,0xfd,0x51,0x5d,0xdf,0x55,0x5d, + 0x78,0x74,0x27,0x2e,0xa6,0xf5,0xd5,0x32,0x71,0xe6,0xf5,0x22,0x3b,0xda,0x79,0x84, + 0x7f,0x9c,0x2c,0xca,0xcf,0xc2,0xdd,0x24,0xdf,0xc5,0x8d,0x24,0x8a,0x8f,0x1e,0x2d, + 0x92,0x3a,0x72,0xa6,0xf3,0xa8,0xac,0x92,0x3a,0xdc,0x5d,0xd5,0xb3,0xfe,0x43,0x3c, + 0xac,0xa6,0x65,0xba,0xac,0x9d,0xaa,0x9c,0x86,0xbb,0x07,0xcb,0x59,0x7f,0x5a,0xe4, + 0x55,0x91,0x25,0xc1,0x6f,0xd5,0xf1,0x3c,0x4c,0x66,0xb3,0x59,0xfc,0x60,0xf0,0x60, + 0xf7,0xe8,0xd1,0x81,0x34,0x3c,0x52,0x2f,0x1c,0xa5,0xb3,0xde,0x9d,0xcb,0x34,0x8f, + 0x8b,0xcb,0xe0,0xcd,0x0b,0xaf,0x37,0x5b,0xe5,0xd3,0x3a,0x2d,0xf2,0x9e,0x77,0x7d, + 0x11,0x95,0xce,0x4f,0xa1,0x3c,0xf3,0x7f,0x0c,0xdd,0x83,0x68,0x99,0x1e,0x54,0x75, + 0x54,0xaf,0x2a,0xd7,0x7f,0x19,0xbe,0x3f,0xf5,0x5f,0x85,0x87,0xc9,0xb7,0xfe,0x89, + 0xff,0xb3,0xff,0x26,0xfc,0x89,0x5e,0x0f,0xaf,0xf1,0x38,0x19,0xb9,0x59,0x7a,0x91, + 0xb8,0x7e,0x9c,0x96,0xf5,0xd5,0xe8,0xce,0xd0,0xbf,0x18,0xe5,0xab,0x2c,0xf3,0xcf, + 0x92,0x7a,0xf4,0x0f,0x7e,0x9a,0xcf,0xb2,0xf4,0x6c,0x5e,0x8f,0x5e,0xaf,0x16,0x93, + 0xa4,0xf4,0xe7,0x45,0x16,0x8f,0x7e,0x98,0xfc,0x96,0x4c,0x6b,0xbf,0x8a,0xae,0x46, + 0x66,0x06,0xb5,0x7f,0xee,0x27,0xde,0x75,0xb2,0xb7,0xd7,0x4b,0x82,0x3a,0xf9,0x58, + 0x3f,0x2d,0xf2,0x3a,0xc9,0xeb,0xb0,0xf6,0xd6,0xfe,0x64,0x55,0x59,0x4d,0x27,0xfe, + 0xd2,0xbb,0xd6,0x57,0xce,0x8c,0x26,0x3f,0x09,0xe2,0xb4,0x8a,0x26,0x59,0x12,0x87, + 0x77,0x86,0x6b,0xfb,0x6a,0x30,0x5e,0x06,0xf5,0x3c,0xc9,0x7b,0x33,0x7f,0xe6,0x8d, + 0xcb,0xa4,0x5e,0x95,0xb9,0xb3,0x5c,0xfb,0xcb,0x22,0xcb,0x9a,0x1e,0x2b,0x7f,0xe1, + 0x4f,0xfd,0x42,0xa0,0x50,0xfb,0x33,0xff,0x2c,0x1c,0x8e,0xcd,0x08,0x6f,0x69,0x84, + 0xb3,0xbd,0xbd,0x3b,0x33,0x9a,0xdb,0x2c,0x1c,0xfa,0xd3,0x2c,0x89,0xca,0x77,0xe9, + 0x22,0x29,0x56,0x75,0xaf,0xf6,0xfc,0x5e,0x15,0x4c,0xa3,0x2c,0x3b,0xae,0x7a,0xde, + 0xe8,0x1f,0x7a,0x95,0xe7,0xa9,0x11,0x75,0xef,0xb1,0x77,0x3d,0xed,0xc5,0x3e,0xa0, + 0x42,0x6b,0x31,0xb7,0x13,0xdc,0x66,0x50,0x25,0xde,0x5a,0xbd,0xf3,0x27,0xff,0x4f, + 0x9e,0xb7,0x36,0x23,0xff,0x89,0x46,0x9e,0x85,0x83,0xf1,0xc6,0x88,0x63,0x9a,0x4d, + 0xaf,0x0e,0x09,0x25,0xf4,0xbd,0xb7,0xfe,0x82,0xde,0x2b,0xf6,0xf6,0x8a,0x60,0x96, + 0x96,0x55,0x1d,0x86,0x04,0x88,0x63,0x7a,0x7d,0x44,0x93,0x57,0xcb,0xa6,0xed,0x2a, + 0x96,0x23,0x6b,0xcb,0xcf,0xb6,0x7b,0x5e,0xfb,0xd4,0x69,0xd3,0x26,0xf7,0xae,0x17, + 0x61,0x3e,0x9e,0xdd,0xdc,0x50,0x57,0x6b,0x3f,0x2f,0x2e,0x47,0x6f,0xd7,0xd4,0x86, + 0xd1,0xa2,0x69,0x36,0xa5,0x95,0xec,0xed,0xbd,0x0c,0x96,0xab,0x6a,0x4e,0x17,0xe3, + 0x93,0x63,0xba,0x9c,0xf6,0x4e,0xbc,0xd1,0xcf,0xc7,0x3f,0x07,0xf4,0x16,0xcd,0xe3, + 0xe7,0xf0,0x4d,0x00,0xa0,0xf7,0x7e,0xf4,0x5f,0xf9,0xcf,0xa8,0xb3,0xcb,0xa8,0x9e, + 0xce,0x4f,0x36,0x7a,0x5a,0x78,0xd7,0x6f,0x02,0xe9,0x9e,0xe6,0xfd,0x73,0x40,0xb3, + 0xe9,0xbd,0x0a,0x5f,0x45,0xf5,0x3c,0x58,0xa4,0xf4,0xd8,0x7f,0xe5,0xf1,0xab,0x69, + 0xfd,0xa2,0x28,0x9f,0x25,0x17,0xe9,0x34,0x69,0x5e,0xa6,0xfd,0x2b,0xc2,0xe2,0xe6, + 0xe6,0x7a,0xad,0x37,0x3a,0x4f,0x2e,0x9d,0x37,0x65,0xb1,0x48,0xab,0xa4,0xd9,0x8e, + 0x2b,0x3f,0x97,0x8d,0x9e,0x37,0x53,0x3a,0x4c,0xee,0x35,0x1b,0x53,0x79,0xd7,0x15, + 0x6d,0x77,0xaf,0x08,0x26,0xab,0x34,0x8b,0xf7,0xf6,0x2a,0xf9,0x11,0x86,0xea,0x8e, + 0x47,0xe0,0x9f,0x07,0x00,0x67,0xcf,0xf3,0xaf,0xb0,0xe3,0x6b,0x6f,0x6c,0xed,0x86, + 0x05,0x63,0xdd,0x6c,0x9c,0xf7,0x9e,0x97,0x65,0x51,0xf6,0xdc,0x5a,0x1a,0xb9,0x58, + 0x48,0x11,0xa8,0xab,0x9b,0x9b,0x6f,0x93,0xfb,0xd4,0xcb,0x7a,0xdd,0xa0,0xdd,0x3f, + 0xf4,0x56,0x40,0x49,0xb5,0x94,0x59,0x42,0xe0,0xe2,0x3b,0x1b,0xd8,0x55,0x7a,0xd7, + 0xa0,0xea,0x32,0x28,0xce,0xbd,0x7a,0x5e,0x16,0x97,0x8e,0x0c,0x54,0x2a,0x38,0x1a, + 0xac,0x67,0xec,0x00,0x65,0x1d,0x97,0xfc,0x0f,0x6d,0x4a,0x49,0x0c,0x03,0xd3,0x5c, + 0x5b,0x38,0xf7,0x0c,0xeb,0xa7,0x1e,0xe9,0xef,0x09,0xd1,0xf9,0x72,0x26,0x7b,0x14, + 0x56,0xe3,0x97,0xc1,0xac,0x28,0x9f,0x47,0x34,0x0d,0x33,0xf8,0x8c,0xf0,0x93,0x5a, + 0x62,0xe2,0x6b,0xaf,0xe7,0x19,0x7e,0xb3,0x23,0x8c,0x2b,0x8f,0x16,0x49,0xb8,0x7b, + 0x91,0x26,0x97,0xcb,0xa2,0xac,0x77,0x9d,0xa9,0xa2,0xe9,0xdd,0xcb,0x34,0xae,0xe7, + 0x61,0xcc,0x1b,0xd8,0xe7,0x0b,0xe2,0x14,0x69,0x9d,0x46,0x59,0xbf,0x22,0x5a,0x4a, + 0xc2,0x21,0xb8,0x5c,0x9d,0xd6,0x59,0x72,0xf4,0x26,0xaa,0xeb,0xa4,0x24,0x3e,0x42, + 0x4b,0xeb,0x3b,0xea,0xaa,0x7a,0x74,0x20,0x4f,0x89,0x17,0xd6,0x57,0xf8,0xf7,0xe0, + 0x2b,0xe7,0xa9,0x70,0x41,0x67,0x12,0x55,0xc9,0xc8,0x21,0x30,0x39,0x15,0x4d,0xc0, + 0x99,0x64,0xc5,0xf4,0xdc,0x29,0x96,0x49,0x5e,0x39,0xc9,0x45,0x52,0x5e,0xd1,0x3c, + 0xca,0xc4,0x59,0x46,0x67,0x49,0xe0,0xbc,0x04,0x77,0x72,0xd2,0xdc,0x19,0x95,0x45, + 0x51,0x3b,0x3d,0xbc,0x35,0x25,0x30,0x2e,0x12,0xb7,0xda,0x71,0x1c,0x7a,0x02,0x5e, + 0x95,0xc4,0x0e,0xb3,0x31,0x7a,0x29,0x4b,0x68,0x02,0x0e,0xf8,0x58,0x85,0x21,0x2a, + 0x35,0xc8,0x45,0x94,0xad,0x92,0x6a,0xe4,0x9c,0x27,0xc9,0x92,0x87,0xae,0x2f,0x0b, + 0x74,0x5b,0xd5,0xc9,0xd2,0xf3,0xd1,0x53,0x1c,0x95,0xe7,0xce,0x2a,0x8f,0x93,0x92, + 0x79,0xfe,0xfb,0x38,0xaa,0xa3,0x3e,0xb5,0x24,0x10,0xe1,0xd1,0x69,0xe0,0xbc,0x2e, + 0x9c,0xcb,0x64,0xe2,0xcc,0x08,0x4a,0x95,0xcc,0x7f,0x5e,0xd4,0xd5,0x92,0xa6,0x35, + 0x8f,0x2a,0x27,0x47,0x7f,0x58,0x7b,0x52,0x07,0xce,0x57,0x07,0x3b,0x3c,0xe1,0xeb, + 0x69,0x91,0x15,0x25,0x01,0x0d,0xfd,0x8c,0x78,0x8e,0xe3,0x7e,0x7f,0x5a,0x26,0xd1, + 0x62,0x74,0xf7,0xc5,0xfd,0xe7,0x2f,0x9e,0x7f,0x4d,0xd7,0xcb,0x28,0x4f,0x32,0xba, + 0x7e,0xf1,0xe2,0xe9,0x8b,0xc7,0x74,0x9d,0xe6,0xe7,0xa3,0xbb,0xc3,0xc7,0xc3,0x87, + 0xc3,0xfb,0x74,0xb5,0x58,0xd1,0xfa,0x46,0x77,0xbf,0x3e,0x7c,0xf0,0xf4,0xc1,0x90, + 0xae,0x67,0x11,0x8d,0x33,0xba,0xfb,0xcd,0xb3,0x6f,0xbe,0xfe,0xfa,0x21,0x5d,0x97, + 0xab,0x2c,0x19,0xdd,0x7d,0xf6,0xec,0xd9,0x83,0xa7,0x5f,0xab,0xcb,0x7e,0x55,0xcc, + 0xa8,0xc9,0xf3,0x87,0xcf,0x87,0xcf,0xd0,0xc5,0xd9,0xbc,0xa8,0x70,0x7d,0xef,0xd9, + 0xd3,0xa7,0xcf,0xe9,0x3a,0x43,0x87,0x2f,0x5e,0x3c,0x78,0x7a,0x88,0xab,0x49,0x44, + 0x57,0x4f,0x1e,0xde,0x7b,0x3a,0x7c,0x4a,0x57,0x05,0x8d,0x7d,0xf8,0xe4,0x9b,0xc7, + 0xf7,0x9f,0xd0,0xc5,0x65,0x54,0xe6,0xa3,0xbb,0x0f,0x1f,0x7c,0x3d,0x18,0x3c,0x1f, + 0xef,0xf4,0xfb,0x55,0x94,0x57,0xa3,0xea,0x8a,0xa0,0xb6,0xe8,0xaf,0x52,0xbf,0x1f, + 0x2d,0x97,0x18,0x8d,0x6f,0xf8,0xee,0x49,0x72,0x56,0x24,0xce,0x8f,0xdf,0xbb,0xfe, + 0xdb,0x62,0x52,0xd4,0x85,0x8f,0xe6,0xfd,0x2a,0x29,0xd3,0x19,0xd6,0x51,0xe4,0xc5, + 0x68,0x95,0xf2,0xbf,0xd5,0x32,0x9a,0x26,0xbe,0xfb,0x34,0x22,0x74,0x8a,0xd3,0xc8, + 0x79,0x45,0xf7,0x5c,0xea,0xe0,0x85,0xfa,0xf5,0x2a,0xc9,0xb3,0xc2,0x17,0x84,0x89, + 0x2a,0xdf,0x95,0xfe,0xd4,0x43,0xd3,0xc1,0x7a,0xa7,0x73,0xa7,0xda,0x40,0xc7,0xad, + 0x06,0xe6,0x83,0xa7,0x83,0x27,0x83,0x6f,0x1b,0x98,0x0f,0xef,0x0d,0x87,0xc3,0x81, + 0x86,0xf9,0xf3,0x67,0xcf,0xbf,0x79,0xf6,0xa4,0x81,0xf9,0xe3,0x7b,0xdf,0x3e,0x79, + 0xf8,0xd8,0x82,0xf9,0xe3,0x6f,0xee,0x7d,0x7d,0xdf,0xc0,0xfc,0xf0,0xc9,0xe1,0x37, + 0x87,0xc3,0x36,0xcc,0x87,0x2f,0x86,0x4f,0x87,0x0f,0x1b,0x98,0x1f,0x3e,0x3e,0xfc, + 0xfa,0x70,0xa0,0xa1,0xfc,0xe2,0xc5,0x37,0x8f,0x1f,0x3c,0x50,0x50,0x7e,0xf0,0xcd, + 0x93,0x87,0xdf,0xbc,0x30,0x50,0x7e,0xf6,0xed,0xe3,0xc1,0xbd,0x17,0xeb,0x9d,0xaf, + 0xae,0x27,0xc5,0xc7,0x7e,0x95,0xfe,0x9e,0xe6,0x67,0xa3,0x49,0x51,0x12,0x46,0xf6, + 0xe9,0xce,0xfa,0xfd,0x3c,0x8d,0xe3,0x24,0x3f,0xbd,0x26,0xf1,0xb9,0xcc,0x48,0x38, + 0xe7,0x45,0x9e,0xdc,0x49,0x17,0xa0,0xdd,0x28,0xaf,0xd7,0x3b,0x93,0x22,0xbe,0xba, + 0x5e,0x44,0xe5,0x59,0x9a,0x8f,0x06,0xe3,0x49,0x34,0x3d,0x3f,0x2b,0x0b,0xc2,0xe8, + 0x11,0x71,0xd3,0x9e,0x82,0x80,0x37,0x66,0xe0,0xa8,0x5b,0xb4,0x68,0x6f,0x0c,0x7c, + 0x1e,0x0d,0x1f,0x2c,0x3f,0x1e,0x0c,0x83,0x07,0x8e,0x3c,0xc0,0xc6,0x79,0xe3,0x3e, + 0xa1,0xfb,0x79,0x5a,0xf7,0xd1,0xa2,0x5f,0x2d,0x08,0x9f,0xe7,0x98,0x13,0x0d,0x46, + 0x9c,0x20,0x25,0x2a,0x8e,0xd7,0x3b,0x91,0x40,0x7b,0x94,0xe6,0x73,0xda,0xe7,0x7a, + 0x3d,0x9a,0x15,0xd3,0x55,0xd5,0xbf,0x48,0xab,0x94,0x44,0xfc,0x35,0x31,0xcf,0x2c, + 0xcd,0x93,0xd1,0xe1,0xf2,0xa3,0x43,0x7b,0x99,0xc6,0x6a,0x00,0xc2,0x40,0x6f,0xac, + 0x1e,0xf6,0x8b,0xd9,0x0c,0x72,0x8d,0xda,0xac,0x77,0x82,0xcb,0x32,0x5a,0xd2,0x2a, + 0x3e,0x0a,0xdf,0x19,0x7d,0x73,0x38,0x58,0x7e,0x1c,0xeb,0x55,0x39,0xd1,0xaa,0x2e, + 0xc6,0xcb,0x28,0x8e,0x31,0x11,0x3c,0x72,0x86,0x5f,0xd3,0x9f,0xfb,0x0f,0xf1,0xee, + 0xfc,0xd0,0x2c,0xdf,0x19,0x38,0x74,0x7f,0x2c,0x33,0x4f,0x7f,0x4f,0x46,0xc3,0x7b, + 0xfa,0xf2,0x32,0x61,0x8d,0x87,0x50,0xba,0x05,0x0b,0xde,0x72,0x8f,0x26,0x30,0x8d, + 0xca,0xf8,0x7a,0x0b,0x7a,0x8c,0x2f,0xde,0x58,0xf6,0x63,0x34,0xdc,0x58,0x0e,0x10, + 0x40,0x3f,0xec,0x97,0x84,0xd2,0x24,0x35,0x87,0x98,0xb8,0x9e,0x2a,0x66,0x49,0x7d, + 0x4f,0xea,0xdc,0x6c,0x5f,0x9a,0xf3,0xe2,0x67,0x59,0xf2,0x71,0x4c,0xe0,0x3c,0xcb, + 0xfb,0x29,0x51,0x51,0x35,0x9a,0x26,0x60,0x23,0xe3,0xdf,0x56,0x55,0x9d,0xce,0xae, + 0xfa,0x8a,0x29,0xeb,0xdb,0x67,0xd1,0x72,0x84,0x95,0x91,0xbc,0xed,0xcf,0x65,0x25, + 0xf7,0xed,0x81,0x06,0x0c,0x90,0x3f,0x32,0xcf,0x87,0x68,0x7e,0xcb,0x72,0xbb,0x91, + 0xe5,0xc1,0x80,0x46,0xb9,0x4f,0x5d,0xdb,0xc8,0x02,0x99,0xd5,0x8f,0x13,0xe2,0xdd, + 0x11,0x64,0x0f,0x63,0xe7,0x78,0xba,0x2a,0x2b,0xea,0x60,0x59,0x30,0x6b,0x1c,0xd7, + 0x25,0x35,0x4d,0xf9,0xb1,0x9a,0x03,0x0f,0xe0,0x04,0xc3,0x07,0x95,0xdf,0xcc,0x41, + 0xae,0x9b,0x47,0xeb,0x9d,0xff,0xb2,0x48,0x88,0x4d,0xf4,0xe6,0x05,0xc9,0x87,0x11, + 0xff,0xf5,0xae,0x01,0x4c,0xf9,0x7d,0x6d,0x77,0x66,0xcd,0x76,0x8d,0x26,0xc1,0xb2, + 0x4c,0x75,0xb3,0xcd,0x55,0x32,0x16,0x76,0xbc,0xcc,0xf7,0xe5,0xc6,0x5d,0xd2,0xd6, + 0xd7,0x33,0x42,0x7d,0x92,0x0b,0x91,0xea,0x67,0x6b,0x1c,0xd9,0xd9,0x91,0xd6,0x6b, + 0xaf,0x0b,0xe2,0x4e,0x29,0xa9,0xdb,0xc1,0xfd,0x07,0x1a,0x04,0x71,0x32,0x8b,0x56, + 0x59,0xdd,0x35,0x1a,0x6f,0x8a,0x74,0x81,0xc9,0x6e,0x4f,0x93,0x21,0x7f,0xcb,0x1a, + 0x5b,0x5b,0x24,0x24,0xae,0xba,0x4a,0xa7,0xd7,0x42,0x42,0x6d,0xfc,0xa0,0xa7,0x8b, + 0xea,0xec,0x5a,0xa8,0xfe,0xd0,0x6c,0x22,0x98,0x6a,0xbb,0x33,0xe6,0x79,0x04,0x43, + 0xb2,0x5f,0x8a,0xf3,0xd6,0x9a,0x8b,0x73,0xb9,0x9d,0x94,0x6d,0x58,0x10,0x8b,0x63, + 0x02,0x9a,0xa7,0xcb,0x4d,0x2c,0x67,0x21,0x6f,0x21,0xe9,0xc3,0x3f,0x86,0xa3,0xdf, + 0x7e,0xab,0xa8,0x77,0x34,0xa4,0xe6,0x07,0x4c,0xf8,0xb7,0xcd,0x5b,0x08,0x79,0x7c, + 0x39,0x27,0x72,0xea,0xb3,0x9c,0x20,0x5c,0x04,0x57,0xa1,0xa9,0xe5,0x45,0x4d,0x2a, + 0x8d,0x99,0x5c,0x7b,0x56,0x0c,0x0d,0xe0,0xf5,0x17,0xcd,0x2c,0x4b,0x88,0xdd,0xdf, + 0xeb,0x62,0x6b,0x5f,0x4e,0x5e,0x16,0x7b,0xc2,0xb0,0x5d,0x24,0xb4,0x56,0x73,0x76, + 0x26,0xd7,0x36,0xf7,0x22,0x12,0xec,0x5c,0xa1,0x60,0xaa,0x59,0xe0,0x97,0x32,0x17, + 0xee,0xa4,0x3f,0x49,0xea,0xcb,0x24,0xc9,0x99,0xc7,0x30,0x17,0x11,0x6e,0xda,0x87, + 0x61,0xc2,0x48,0xa4,0x56,0x86,0xeb,0x6e,0xd8,0x7c,0x31,0x56,0xed,0x68,0x92,0xfa, + 0x52,0x76,0xb8,0xc9,0xef,0x3a,0x76,0xbc,0x13,0x7c,0x3b,0x30,0xd4,0x3f,0x05,0x11, + 0x68,0xa3,0x18,0x79,0x8c,0x27,0x7d,0x40,0x71,0x84,0x3f,0x0c,0x04,0xf0,0x38,0xac, + 0x46,0x03,0x82,0x94,0x90,0xba,0x58,0xb0,0xdc,0xa1,0x8e,0x87,0xd7,0x78,0x65,0x34, + 0x34,0xd2,0xc9,0xda,0xcf,0xc3,0xc3,0x0e,0x71,0xc3,0xba,0x69,0xc9,0x3b,0x06,0x7c, + 0xeb,0x07,0x83,0x61,0xb2,0x20,0xac,0xac,0x56,0x93,0x2f,0xa7,0xc7,0x9d,0x2a,0x61, + 0xe5,0xfe,0xda,0xda,0x9c,0x43,0x16,0x7f,0xc0,0x94,0x44,0x4b,0x40,0xba,0x43,0x32, + 0x70,0xb0,0x29,0x01,0x3b,0x25,0x1e,0xb8,0x45,0xb5,0xb8,0xb6,0x40,0x7c,0xef,0xb0, + 0x2d,0x52,0x0e,0xb7,0x64,0xa9,0x7a,0x2d,0x8e,0xf2,0x6d,0x16,0x70,0x1b,0xb7,0x46, + 0xeb,0xdb,0x39,0x36,0xbf,0x4a,0xdd,0x46,0xd3,0xba,0x6a,0x6f,0xd7,0xc6,0xce,0x74, + 0x60,0x07,0x36,0xeb,0x61,0x1b,0x61,0x87,0xac,0x4e,0xa8,0xa9,0x28,0x01,0x34,0x9a, + 0x16,0x70,0xd5,0xa8,0xd9,0xd0,0x92,0x97,0x85,0x12,0x47,0x65,0x92,0x11,0xd2,0x5c, + 0x24,0x6b,0xf5,0x64,0x34,0x8a,0x66,0x35,0xb3,0x7a,0x21,0x90,0xdd,0xdd,0xb1,0x69, + 0x1b,0x4d,0x08,0xf1,0x09,0x76,0xe3,0x34,0x87,0xda,0xd2,0x07,0x96,0x0c,0x30,0xf3, + 0x2c,0xad,0xea,0x46,0x01,0x33,0xe0,0x1b,0xe3,0x7e,0x9f,0xed,0x20,0x91,0x8a,0x9f, + 0x23,0x23,0xd5,0xd5,0x51,0x96,0x7e,0x96,0x90,0x99,0x54,0x07,0x1b,0xfa,0xc0,0x43, + 0x6b,0xf3,0xa0,0x1d,0x0d,0xc6,0x46,0x8d,0x64,0xfc,0xed,0x1a,0x94,0xd5,0x57,0x3d, + 0xb2,0x13,0xe4,0x0b,0x83,0xdc,0xd4,0xb1,0xc8,0x91,0xc1,0x18,0x5b,0x07,0x43,0x6f, + 0x24,0xaa,0xa8,0x50,0x9c,0xb9,0x99,0x64,0x59,0xba,0xac,0xd2,0xaa,0x9b,0xf5,0xaa, + 0x7e,0xaf,0x9b,0xfe,0x58,0xb3,0xfb,0x72,0xbc,0x0f,0xe2,0xb2,0x58,0x76,0x20,0x46, + 0x9c,0x96,0x42,0x11,0xb4,0xbb,0xd9,0x6a,0x91,0xff,0x41,0x65,0xea,0x7e,0x1b,0x78, + 0xc3,0x96,0xb4,0x3c,0x1c,0xb4,0xa5,0x41,0x1c,0x55,0xf3,0xe4,0xb3,0x4a,0xdf,0x6d, + 0xec,0x9e,0xc1,0xc5,0xb3,0xd3,0x13,0xd8,0xd0,0x8f,0x3a,0x98,0x5a,0x5b,0x44,0x28, + 0x28,0x04,0x9f,0x54,0x7b,0x6e,0x53,0xfd,0xd7,0x30,0xc2,0xff,0xf2,0x1f,0xff,0x4a, + 0xff,0x19,0x3b,0x5d,0x5f,0x93,0xc1,0xca,0x3d,0x77,0x88,0x99,0x2d,0x6d,0x47,0xcd, + 0x81,0xb4,0xf6,0x2e,0x45,0x87,0x98,0x10,0xad,0x91,0xf0,0x21,0x89,0x35,0x6c,0x04, + 0xf5,0x19,0xe3,0xd6,0x3b,0x77,0x67,0x69,0x96,0xb4,0x6c,0x18,0xa5,0x91,0xd8,0x9b, + 0x00,0x7e,0x76,0x97,0x6f,0x36,0x04,0xad,0xef,0x8d,0x92,0xc5,0xb2,0xbe,0xda,0xe8, + 0x81,0x56,0xf6,0x8e,0x0c,0x72,0xdc,0xa1,0x7d,0x73,0x4a,0x42,0x47,0xb6,0xd0,0xa3, + 0x29,0x20,0xed,0x24,0xf1,0x59,0xe2,0xf3,0x0d,0xf8,0x3c,0x60,0xf8,0x4f,0x8a,0x2c, + 0x66,0x3b,0xdd,0x90,0x9a,0xe6,0x21,0x7a,0xef,0x41,0xd6,0xcc,0x57,0xb3,0x34,0x20, + 0x76,0x7b,0xbb,0x45,0x40,0xc6,0xda,0x3c,0x8a,0x69,0x44,0xe6,0x07,0xce,0x3d,0xe6, + 0xbc,0x8d,0x3e,0xa0,0x3a,0x10,0x9a,0x6a,0x4b,0x84,0x6e,0xb2,0x30,0xaa,0x80,0xa0, + 0x4a,0x89,0xd6,0x66,0x85,0x32,0x7f,0xf6,0x6d,0xf0,0x6a,0xd9,0x69,0x53,0x16,0x99, + 0x2c,0xf7,0x72,0x0e,0x07,0x0b,0xbc,0x4c,0x02,0x49,0xb4,0x4c,0x6b,0x6a,0x4d,0x60, + 0x54,0x7e,0x89,0xc9,0x8a,0x78,0x40,0x8e,0xc9,0x08,0x9d,0x90,0xf4,0x9b,0x8d,0xaa, + 0xba,0x84,0x03,0x4b,0x4b,0x32,0x61,0x69,0x2d,0x48,0x68,0x1e,0xd2,0xb6,0x2c,0x45, + 0xc9,0xb7,0x0d,0x40,0x21,0x68,0x7d,0x61,0x2d,0x03,0xfa,0xd2,0x06,0xbe,0xaf,0x9b, + 0xc9,0x28,0xb1,0xb0,0x29,0xc2,0xd9,0x1f,0x03,0xe9,0x0c,0x29,0x79,0xd9,0x26,0x7e, + 0xa3,0xb6,0x0d,0x1b,0x03,0xb1,0x8f,0x0b,0xb4,0x4d,0x32,0xa5,0xfc,0x02,0x95,0xc6, + 0x16,0x5a,0x35,0xc2,0x5a,0x50,0xa3,0xdf,0x81,0xde,0xd5,0x52,0x98,0x1f,0xaf,0xae, + 0xe9,0x06,0x1b,0xf9,0x3e,0x2e,0xa3,0xb3,0x33,0x68,0xf9,0x61,0x5d,0xae,0x92,0xd3, + 0x6b,0xb5,0xa2,0xb3,0x32,0x9a,0xf0,0x46,0xe3,0x79,0x43,0x16,0xf7,0x1e,0xc8,0xee, + 0x0b,0xb5,0x6e,0x20,0xca,0xc0,0x69,0xd8,0x9e,0x20,0x0a,0xed,0xf1,0xdb,0xe2,0xb2, + 0x72,0x08,0x5b,0x68,0x37,0xd3,0xd2,0xb9,0xa4,0x0d,0x26,0x2b,0xd9,0x89,0xd3,0x05, + 0xef,0x2f,0xbd,0x08,0x5b,0xdf,0xb9,0x2a,0x56,0xd8,0xf8,0x59,0x5a,0x2e,0x7c,0x87, + 0x28,0x8e,0x36,0x3e,0xe1,0x77,0x9c,0x32,0x59,0x66,0x57,0x88,0x54,0xc4,0x15,0x6f, + 0x37,0x8d,0x7e,0x46,0xd0,0xb6,0xe7,0xb4,0xd6,0xf7,0x1c,0x16,0xdf,0x6c,0xaa,0xa7, + 0x19,0x9e,0x09,0x5b,0xe7,0x79,0xbc,0x28,0xca,0xfa,0xca,0x79,0x96,0x90,0xce,0x42, + 0xba,0x27,0x6f,0x53,0xe5,0x54,0xf3,0x62,0x95,0xc5,0x3c,0x20,0x7e,0xd6,0x23,0xe7, + 0xc3,0x2a,0xa5,0x95,0xac,0xf2,0x3a,0xcd,0x64,0x78,0x42,0x3d,0xc2,0x39,0xd9,0xe0, + 0xd8,0x89,0xea,0x86,0xc6,0x64,0xb4,0x4d,0xe4,0x69,0xf1,0x30,0xb6,0x0f,0x97,0x51, + 0x49,0xfb,0xd2,0xa5,0xa9,0x48,0x37,0x99,0x32,0xe7,0x9c,0x6e,0xe5,0x83,0x98,0xc9, + 0x45,0x37,0x73,0xc0,0xdb,0x2e,0xd1,0x02,0x1c,0x93,0x3e,0x93,0x45,0x99,0x54,0x64, + 0x93,0x39,0x40,0x30,0x87,0x20,0x26,0x3e,0x49,0x5a,0xb2,0xb8,0x5a,0x09,0xd4,0x57, + 0x60,0x15,0xc4,0x3c,0xa7,0x73,0x87,0xf6,0x2d,0x77,0x22,0x78,0x0a,0xb3,0x82,0x40, + 0x87,0xce,0x02,0xe7,0xb1,0xee,0x02,0x60,0x27,0x71,0x27,0x74,0xb9,0x28,0x62,0x12, + 0x0d,0xb4,0x41,0x04,0x17,0xda,0x19,0xe2,0x77,0x34,0x1a,0x20,0x76,0x29,0x7b,0x12, + 0xd4,0x45,0x91,0x55,0x8d,0xf2,0x41,0xb2,0x69,0x7a,0x7e,0x35,0x06,0x93,0x1b,0x8c, + 0x7f,0x27,0x2c,0x8c,0x2d,0xb5,0x92,0x79,0x5f,0xdf,0x66,0x4c,0x0f,0x85,0x1c,0x3f, + 0xc1,0xe4,0x1f,0xcb,0x1c,0xd5,0xdc,0xc0,0xad,0x69,0x62,0x05,0x2f,0x19,0xab,0xc0, + 0x7a,0x65,0x22,0xf3,0xf8,0x8b,0x35,0x2d,0xa3,0x27,0x83,0x4f,0x1e,0x2a,0xc5,0x78, + 0x4d,0x3d,0x38,0xf3,0xc3,0x4d,0x45,0x78,0x8d,0x9e,0x9d,0xc0,0x30,0x6b,0xff,0x6e, + 0x86,0xdf,0x84,0x37,0x3d,0xb9,0xe1,0xed,0xdf,0x9d,0xac,0xb2,0xf3,0xd7,0xed,0x8d, + 0xe2,0x56,0x16,0x27,0xa4,0x7e,0xb8,0xd9,0xb5,0x71,0x7a,0x6c,0x48,0x03,0x3c,0x74, + 0xd8,0xa9,0x62,0xe9,0xaa,0x03,0xfd,0x84,0x90,0xb7,0x31,0xc9,0x6f,0xb7,0xbb,0x09, + 0x5e,0xdf,0x83,0xac,0xb2,0x8c,0xb0,0x39,0x59,0x25,0x23,0x22,0x3f,0x41,0xe4,0x25, + 0x21,0x19,0xa4,0x55,0xc0,0xe8,0x33,0x89,0x4a,0x61,0xbc,0x51,0x8d,0xa7,0xae,0xc0, + 0x72,0x59,0x16,0x67,0x04,0x67,0xb5,0xb1,0x1f,0xb4,0xfa,0xc7,0x1a,0xcd,0xc0,0xf9, + 0x94,0x16,0xd8,0xad,0xf9,0x7c,0x81,0x6e,0xf8,0x81,0x36,0xf0,0x7a,0x03,0x19,0xbe, + 0x5c,0xbf,0xfb,0x40,0x73,0x6f,0x6f,0xba,0xd6,0x21,0xf1,0x30,0xff,0x9b,0xaa,0x7d, + 0xdd,0xe6,0xc6,0x87,0xea,0xfa,0x33,0x4d,0x8d,0xca,0xf7,0xa1,0x0a,0x56,0xcb,0x6d, + 0x7f,0x0b,0xee,0x93,0xc0,0x2a,0xaf,0x5a,0x8f,0xe0,0x46,0x95,0x67,0x5d,0xfe,0x0a, + 0xba,0x4d,0xdd,0x66,0x7e,0xf0,0xe1,0x16,0xb7,0xc5,0x07,0xda,0xe0,0x6b,0x25,0x29, + 0x0e,0xdb,0xc8,0xf6,0x75,0x97,0x52,0xc7,0x0e,0x5e,0xfd,0xa2,0x93,0x6e,0x38,0x15, + 0xb4,0xc8,0x19,0x0c,0xfe,0x7e,0xdc,0xe9,0x77,0xc2,0x8b,0x98,0x89,0x6d,0xc6,0xd1, + 0x30,0x1a,0xac,0x42,0x85,0x51,0x7e,0x45,0x9c,0xbd,0x54,0x9e,0x6e,0x76,0xc5,0xcc, + 0x66,0xcc,0xae,0xee,0x02,0x9d,0xfc,0xad,0xbb,0xb3,0xaa,0x61,0xf4,0x0f,0x84,0xf3, + 0x15,0xab,0xe9,0x7c,0x84,0xf0,0x04,0x44,0x13,0xb3,0x39,0x56,0xf4,0x88,0xc1,0x45, + 0xce,0x72,0x4e,0x98,0xe8,0x13,0xb2,0x38,0x51,0x59,0x42,0xf2,0x40,0xc0,0x90,0xc1, + 0xec,0x83,0xef,0x09,0x3f,0x2f,0x58,0xf2,0x80,0xef,0x69,0xb6,0x36,0x4f,0x97,0x4e, + 0x96,0x44,0x17,0xc4,0xed,0x54,0x3c,0x26,0x99,0x9e,0x93,0x74,0x73,0xaa,0xe8,0x0a, + 0xea,0x06,0xa8,0x24,0x52,0xad,0xbd,0xc0,0x79,0xcd,0x5d,0x1b,0x19,0x82,0x08,0x0c, + 0x7a,0x33,0xca,0x18,0x61,0x59,0x32,0x56,0xf2,0x0e,0xca,0xb7,0x43,0xb8,0x41,0xd3, + 0x49,0xa2,0xca,0x59,0x24,0x49,0xad,0x67,0x02,0x43,0x86,0x30,0x55,0x08,0xed,0x53, + 0x66,0x9d,0xc5,0xfe,0x6d,0x9f,0x82,0x20,0xf3,0xbd,0xfb,0xb6,0x61,0x6b,0x6b,0xd7, + 0x70,0xd0,0xb2,0xeb,0x2a,0xa0,0x99,0xfb,0xc1,0x8c,0x5e,0xdc,0xd4,0x52,0x6d,0x4d, + 0xf1,0xeb,0x0d,0x4d,0x91,0x5f,0x17,0x31,0xd7,0xb6,0x20,0x2d,0x23,0xb1,0x7f,0xaf, + 0x69,0x04,0xd9,0xd5,0x72,0x87,0x09,0xcf,0xba,0x26,0x50,0xf5,0x0d,0x41,0x1a,0xfb, + 0xb5,0xa1,0xc6,0x6f,0xbf,0xa6,0x07,0xb4,0xd2,0x0d,0x37,0xf9,0x70,0xf0,0xd0,0xb2, + 0x5b,0x18,0x9b,0xee,0x89,0x3f,0xfd,0xac,0x4c,0x1b,0x26,0x8f,0x8b,0x31,0xfe,0xf4, + 0x89,0xa7,0xd3,0x1d,0x22,0x42,0x31,0x9a,0xaa,0xd1,0x3d,0x74,0xe0,0xd0,0x40,0xd4, + 0x69,0x6f,0xe0,0x0f,0x67,0xa5,0x27,0xf6,0x11,0x44,0x8f,0x2d,0x08,0x88,0x55,0x96, + 0xb5,0xea,0xd8,0xe9,0x70,0x46,0x0c,0x68,0x89,0xd3,0x4e,0xe1,0x86,0x55,0x32,0x8b, + 0xfc,0xa8,0x15,0xfd,0x07,0x0f,0x2e,0xe6,0x0d,0x7b,0x81,0x73,0x9f,0xd6,0xfc,0xe8, + 0x40,0x62,0x86,0x8f,0x0e,0x24,0xc9,0x02,0x71,0x8d,0xa3,0x9d,0x9d,0x47,0x0b,0xe2, + 0x0a,0xce,0x34,0x8b,0xaa,0x2a,0xdc,0xc5,0xf2,0x75,0x1a,0x46,0x52,0x1e,0x3d,0x9a, + 0x0f,0x8f,0x9a,0xd0,0x23,0x5d,0x3c,0x22,0xde,0x62,0x1a,0x57,0xab,0xc9,0xae,0x93, + 0xc6,0xe1,0xee,0xac,0xda,0x3d,0xda,0x5b,0xc0,0x88,0x1b,0xd3,0x20,0xd4,0x42,0x8d, + 0x41,0x3d,0x50,0xff,0x77,0xfa,0x7d,0xe7,0x05,0xc2,0xf3,0x4e,0xb9,0xca,0x49,0xb6, + 0xe7,0xa4,0xd7,0xcc,0x8a,0x72,0x81,0x7e,0x63,0xa7,0x28,0xc9,0xfa,0x5b,0x44,0x67, + 0x30,0xff,0x00,0x32,0xc2,0xfb,0x28,0x87,0x26,0x84,0x58,0x23,0x91,0xd5,0x15,0x07, + 0x47,0x7c,0xad,0x47,0x00,0xc5,0x1d,0x22,0x32,0x52,0xc6,0x48,0x45,0x4c,0x84,0x26, + 0x62,0x92,0xa0,0x93,0x84,0x74,0x5b,0xa2,0xb9,0x38,0x21,0xa5,0x7b,0x35,0x85,0xd3, + 0x41,0xd1,0xc6,0x48,0xf4,0x3e,0x12,0x2f,0x9c,0xb9,0x01,0x4a,0x9a,0x16,0x0b,0xe8, + 0x14,0x85,0xf4,0xc6,0x71,0x4b,0x22,0x5d,0xad,0xaa,0x30,0x1d,0xff,0x0e,0x69,0x75, + 0x56,0x50,0xb3,0x29,0x26,0x32,0x49,0x68,0x1a,0x31,0xbd,0x1b,0x38,0xfd,0x3e,0x01, + 0x28,0x4e,0x2f,0x34,0x18,0xc4,0x91,0xa8,0x20,0x81,0x75,0xbe,0x5d,0xe5,0xbb,0x8e, + 0xf0,0x74,0x87,0x41,0x1e,0xee,0x6e,0x3b,0xba,0x08,0xca,0x8e,0xf3,0x68,0x72,0x74, + 0x52,0x93,0x52,0x7e,0x46,0x34,0x9b,0x24,0x71,0xe5,0x28,0xb8,0xd0,0x8a,0x1f,0x1d, + 0x4c,0xb8,0xc5,0xd2,0x1a,0x26,0xd9,0x3d,0x62,0x6b,0x4c,0x76,0x84,0xfe,0x2d,0x6b, + 0x46,0x06,0x80,0x6c,0xaf,0xac,0x3e,0xac,0x8a,0x71,0x4d,0x33,0x85,0x66,0x15,0x13, + 0x6b,0x42,0xd4,0xd7,0x31,0x90,0xf6,0x2d,0x50,0x07,0xd0,0x43,0xe9,0x36,0x60,0x51, + 0xe4,0x53,0xd1,0xd2,0x96,0xda,0x76,0x4d,0x95,0xd8,0xce,0xd1,0x26,0xcb,0xae,0x82, + 0x47,0x07,0x4b,0x9e,0x8b,0xb5,0x68,0x78,0x93,0x76,0x09,0x87,0x18,0xc2,0xfa,0x26, + 0x51,0x28,0x8d,0x90,0x2b,0x50,0x2c,0xea,0x5d,0x07,0xb9,0x3e,0x74,0x9f,0x5b,0xed, + 0x1e,0xa9,0x41,0x2b,0x59,0x32,0xad,0x90,0xef,0xb7,0x91,0x8a,0x54,0x15,0xf3,0xfe, + 0x6b,0x5e,0xb2,0x41,0x29,0x1a,0x9e,0x20,0x2f,0xff,0xb4,0x76,0x00,0x24,0xb3,0xdb, + 0xde,0x94,0x6c,0xca,0x09,0x43,0x42,0x46,0x3c,0xf9,0xf9,0xe1,0xd1,0x8f,0xcb,0xac, + 0x88,0x62,0xc2,0xcd,0x43,0xbe,0x93,0x45,0x93,0x24,0xd3,0x2f,0x60,0xd3,0x65,0x60, + 0xfe,0x75,0xc4,0xa8,0xf1,0x28,0xcd,0x97,0x64,0x26,0xc8,0x2a,0xa0,0xb2,0xe8,0x5d, + 0xc6,0x2f,0x18,0x3a,0xcb,0x3a,0xdc,0xfd,0xea,0xe0,0xab,0x5d,0x67,0x41,0x1a,0x61, + 0xba,0x44,0x44,0x9e,0xdf,0x9b,0x1c,0x3d,0x9d,0x17,0x45,0x95,0x38,0x24,0x45,0x16, + 0xac,0xec,0x54,0x00,0x7f,0xe4,0x04,0xbf,0x13,0x97,0x27,0x49,0x72,0xae,0xf6,0x97, + 0xda,0xf2,0xea,0xb0,0x37,0x40,0x3b,0xc4,0x5b,0x1d,0x88,0x26,0x9f,0x18,0x78,0x3d, + 0x77,0x58,0x47,0x16,0x9e,0xaf,0x76,0xb8,0x72,0x38,0x7d,0x41,0x41,0x05,0xeb,0x38, + 0xe0,0x85,0xf0,0xcf,0x95,0x59,0xcf,0x07,0x99,0xea,0x07,0x8d,0x89,0x04,0xbf,0x55, + 0xb6,0xb9,0x8b,0x06,0xd8,0xf8,0xa1,0x21,0x8c,0xe9,0x6f,0x6e,0xab,0xb4,0x62,0xdd, + 0x60,0x63,0x53,0x75,0xf7,0x6f,0xf1,0xcc,0x81,0x2a,0x90,0xc4,0x66,0x67,0xc1,0x73, + 0xf4,0x16,0xd8,0x1b,0xb7,0xb1,0x35,0xd6,0x8c,0x58,0x85,0xd7,0xd0,0xb7,0xee,0xcf, + 0x69,0x83,0xb1,0x85,0x4a,0xa5,0x4c,0x64,0x17,0xbb,0x31,0x27,0x53,0xab,0x11,0xb4, + 0xe9,0x6c,0xc2,0x5a,0xf2,0x26,0x6a,0x6d,0x8e,0xc9,0x38,0x6e,0x9a,0x9b,0x95,0x0a, + 0xd3,0xe8,0x00,0x92,0x53,0x2d,0xa4,0x39,0x69,0xf4,0x8f,0xb3,0x6c,0x13,0xfb,0x4f, + 0xd8,0x02,0x72,0x68,0xf6,0x0d,0x7c,0x3e,0xdb,0x15,0x46,0xfe,0x39,0x5d,0x6e,0xf6, + 0xf5,0x8c,0x74,0x64,0xe0,0xb2,0xf3,0xf3,0xf7,0x6f,0xbe,0xa8,0xb7,0x86,0x2e,0x95, + 0x0a,0xbf,0xd5,0xa3,0x98,0xa4,0x62,0xa6,0xd9,0x5b,0xf8,0xa9,0x4e,0x97,0x65,0xaa, + 0x56,0x4c,0x6a,0xcb,0x0f,0x65,0x7c,0x0b,0x6e,0x9c,0xd0,0x53,0x87,0x55,0xe9,0x76, + 0xb7,0x0d,0xc2,0x99,0x1f,0x0d,0x02,0x43,0x9e,0xab,0xfd,0xc4,0xaf,0x06,0x7f,0xdb, + 0x1c,0x91,0x5b,0x40,0x91,0x30,0xa3,0xbd,0x2e,0x14,0xc1,0x54,0xce,0x15,0xa9,0x08, + 0xce,0x8a,0xa9,0x9e,0x94,0xb1,0x45,0xc2,0x3c,0xb0,0x4a,0x88,0xd9,0x45,0x4c,0x84, + 0xce,0xac,0x14,0x3d,0x0c,0x12,0x61,0xb1,0xca,0x49,0xbf,0x33,0xcc,0x6e,0x93,0xf1, + 0x46,0x4b,0xbc,0x3c,0xcd,0x48,0xec,0x3a,0x92,0xe3,0x03,0xdb,0x8f,0x7d,0x45,0x24, + 0x15,0x5a,0x68,0x06,0x25,0x67,0xf7,0xc8,0x79,0x06,0xc5,0x50,0x4f,0x85,0xda,0x96, + 0x09,0xc3,0x20,0x50,0x58,0xe7,0xbc,0x21,0x03,0x27,0x21,0xdb,0x91,0x94,0x32,0x07, + 0x19,0x56,0xd0,0xc9,0xa8,0x19,0xa6,0x03,0x0f,0xc4,0x25,0xee,0x83,0x31,0x6f,0x71, + 0xf7,0x05,0x89,0xf6,0x98,0xb9,0x84,0xcc,0x76,0x9b,0xca,0x0c,0xb1,0x49,0x3c,0xe8, + 0xe8,0x51,0xe4,0xcc,0xcb,0x64,0x16,0xee,0x1e,0xec,0x1e,0xa9,0x7c,0xa1,0x47,0x07, + 0x51,0x73,0x7b,0x5e,0xd7,0xcb,0x6a,0x74,0x70,0xb0,0x6c,0xb2,0x8e,0x82,0xcb,0xa2, + 0x24,0xa4,0x17,0x17,0x57,0xb8,0xfb,0xeb,0x24,0x8b,0x72,0xba,0x2e,0x93,0x0c,0x20, + 0x41,0x5e,0x51,0x52,0xee,0x1e,0x6d,0xbe,0xc0,0xbd,0x1e,0xa8,0x51,0x69,0x1a,0x50, + 0x2e,0x4c,0xe6,0xe6,0xd1,0x8e,0xc9,0xb7,0xfa,0xbb,0x5e,0x6a,0x92,0xbc,0xe2,0x62, + 0x4a,0x72,0x3f,0xaf,0x03,0x1a,0xe8,0x79,0x96,0xe0,0xe7,0x93,0xab,0xef,0x63,0x6a, + 0xb1,0x6e,0x5e,0x58,0x9c,0xf7,0x6a,0x7f,0xea,0x7f,0x94,0x24,0xb6,0x24,0x34,0x2f, + 0xc1,0x3e,0xaf,0x13,0xf5,0x1e,0xd2,0x04,0x93,0x80,0xb7,0xe1,0x35,0xb2,0xb0,0xa6, + 0xe3,0x74,0xd6,0xfb,0x78,0x27,0xe4,0x2c,0xc4,0x76,0x86,0xe5,0x47,0x9d,0x21,0x46, + 0x2a,0x28,0xba,0x24,0xde,0x10,0xfe,0x5d,0xcf,0xa5,0x7f,0x5c,0xcf,0xcf,0xd4,0x55, + 0xa6,0x2e,0x09,0x03,0x9f,0x67,0x7c,0x03,0xce,0x0e,0xcf,0x07,0xaf,0xc6,0x25,0xfe, + 0xa5,0x4b,0x30,0x78,0x5c,0xe2,0x5f,0x5c,0x56,0x7c,0x51,0xb9,0x92,0x02,0xe5,0x7c, + 0x90,0x77,0x3f,0xd0,0x35,0xb3,0xd0,0x27,0x75,0x8e,0x6b,0xfe,0x4d,0xf7,0x40,0x91, + 0xb8,0xc6,0xbf,0xea,0x92,0xa8,0x51,0xdf,0xa1,0x9f,0xea,0xe6,0x6b,0x7d,0xeb,0xb5, + 0xee,0x58,0x18,0x0d,0x6e,0xcb,0x2f,0xd5,0x90,0x18,0x86,0x6e,0x4a,0x3f,0x79,0x7e, + 0xa2,0x96,0xc8,0x1c,0xe5,0x37,0x6e,0x8b,0x88,0xe5,0xbb,0xf2,0xd3,0x74,0x2c,0xf4, + 0xcc,0x3d,0xcb,0x4f,0xd7,0x1b,0xef,0xec,0x1c,0x1c,0x38,0x80,0xa4,0xe5,0x98,0xe2, + 0xde,0x1c,0x4e,0x9b,0x35,0xfa,0x43,0xcb,0x57,0xf6,0x5a,0xb2,0x5b,0x9c,0x05,0xd1, + 0x49,0x9c,0x4c,0xc9,0x28,0x81,0x53,0x8d,0x5e,0x2d,0xd1,0x1b,0xd1,0x8c,0xd6,0x36, + 0x08,0xcb,0x61,0xf5,0x4f,0x49,0x0f,0x22,0x2c,0x9f,0x21,0x57,0x0d,0x29,0x7f,0xce, + 0x5f,0xfe,0xf5,0x3f,0x60,0x16,0xd1,0x28,0xc5,0x0c,0xcc,0xb3,0x4d,0xae,0xd4,0x67, + 0xb2,0xec,0x93,0x39,0x72,0x8e,0xee,0x48,0x0c,0x16,0x97,0x3e,0x7c,0x43,0x24,0x35, + 0x69,0x6a,0x09,0xfb,0xfc,0x90,0xf2,0xe6,0x30,0x0f,0x00,0x35,0x91,0xc6,0x98,0x7c, + 0x24,0xd6,0x4e,0x53,0xbc,0x84,0x52,0x18,0xc9,0x1a,0xfa,0x7a,0x1e,0xf0,0xdb,0x91, + 0x82,0xc2,0xb3,0x2b,0xcb,0xf4,0x82,0xfb,0x08,0x04,0x45,0xe0,0x79,0x4a,0x62,0xc6, + 0x26,0x9f,0x08,0x00,0x36,0xc1,0x49,0x39,0xe5,0x6b,0x81,0xce,0x0f,0x50,0x4c,0x35, + 0xc9,0x13,0x3a,0x3b,0x51,0x63,0xc6,0x61,0x21,0x4b,0x45,0xf2,0x48,0x1e,0x86,0x05, + 0xa6,0xe9,0x3c,0x98,0xd0,0x05,0x66,0x07,0x9a,0x27,0x86,0x83,0xbe,0x62,0x70,0x64, + 0x78,0x59,0xf8,0xcd,0xaa,0x50,0x79,0x77,0xcc,0x15,0x32,0xb9,0x54,0xbe,0x30,0x02, + 0x0c,0x2f,0x85,0xfd,0x36,0x11,0xd3,0x4b,0xc5,0xf0,0xac,0x61,0xa4,0x06,0x0d,0x11, + 0x11,0x96,0x3c,0x29,0x3e,0x26,0x55,0xcf,0xd0,0x9e,0x60,0x76,0xf0,0x61,0x95,0x94, + 0x57,0x22,0xa0,0x8a,0x92,0x10,0xa9,0xe7,0xb2,0xe6,0x03,0x87,0xaf,0x4b,0x54,0xd8, + 0xea,0x81,0xe5,0xc3,0x49,0xb6,0x3a,0x43,0x37,0x84,0x2d,0x80,0x4c,0xb1,0xaa,0xc3, + 0xf7,0xa7,0x63,0xba,0xfa,0x7c,0x87,0x23,0x86,0x48,0x42,0x18,0xb5,0x9d,0x59,0x39, + 0xf5,0x90,0xda,0xa4,0x52,0x6a,0x03,0x64,0xa0,0x11,0xb8,0x82,0x8a,0x06,0x43,0xb2, + 0x29,0x75,0xaf,0xb3,0x3a,0x57,0xf5,0x78,0x67,0xcd,0x20,0x6f,0xf9,0x90,0x88,0x25, + 0xb2,0xcf,0x96,0x55,0x5f,0x6d,0x3c,0xe0,0x91,0xcc,0x1b,0xd0,0x14,0xc7,0x2e,0x22, + 0x57,0xa2,0xfa,0x42,0x2e,0x70,0x33,0x74,0x66,0x5a,0x26,0xa4,0x40,0xef,0x36,0x12, + 0x7b,0x97,0x73,0x11,0x89,0x39,0x8b,0x76,0x3d,0x9d,0xf3,0xbe,0xb0,0xf4,0xf8,0x3d, + 0x29,0x0b,0x0b,0xc4,0xab,0x25,0xcd,0x3a,0x79,0x42,0x3b,0xd1,0x40,0xa7,0x2e,0x08, + 0xb3,0xc2,0x06,0xf8,0x41,0x96,0xe4,0x67,0xf5,0x7c,0xac,0x1e,0xe7,0xe1,0x06,0x54, + 0xad,0xe7,0xd8,0xd2,0x40,0x04,0x5b,0x78,0x87,0xfb,0xc1,0x5d,0x22,0x4b,0x88,0x3c, + 0x82,0xa0,0x7e,0x24,0xcf,0x6e,0x6e,0xee,0x28,0x1c,0xd5,0xef,0x12,0xf7,0x68,0x71, + 0x3d,0x77,0x43,0xce,0x3b,0x3d,0x77,0x3f,0xdf,0x77,0x3d,0xd7,0x7e,0xc1,0x24,0x92, + 0xe7,0x61,0x18,0x0e,0xf4,0x13,0x62,0x25,0x1b,0x5d,0x59,0x4a,0xc8,0x56,0x3f,0x68, + 0xbd,0xdd,0x8f,0xb0,0xa9,0x56,0x37,0x3d,0x3c,0xe4,0xd9,0xef,0xed,0xf1,0x3f,0x47, + 0x03,0xef,0xd8,0x7d,0x8a,0x0c,0xed,0xc6,0x69,0xec,0x8e,0xdc,0x66,0x33,0xcc,0x18, + 0xaf,0xdb,0x29,0xf3,0x78,0xf9,0xb8,0x97,0x1f,0xbb,0x9a,0xca,0x94,0x25,0x49,0x7b, + 0xc6,0xb4,0x44,0x28,0x37,0xe2,0x46,0xfb,0xae,0xa2,0x51,0x77,0xbf,0x27,0x7b,0x13, + 0x86,0xc3,0x63,0x97,0x06,0x21,0x96,0xed,0x8d,0x5c,0x97,0x71,0x4b,0xcd,0x95,0x90, + 0x04,0x32,0x3f,0xb4,0xd2,0x9b,0xd5,0xbe,0x4d,0xb0,0x9b,0xd6,0xb6,0xea,0xfd,0xbc, + 0x8c,0xf2,0xfa,0x96,0x2d,0xbd,0x13,0x86,0xfc,0x96,0xbd,0xc3,0x7c,0xdd,0x45,0x09, + 0xd3,0x40,0x51,0x4a,0x88,0x1e,0x05,0xff,0x6d,0xf4,0xa2,0x59,0x0a,0xd7,0x79,0xc6, + 0xa1,0x5a,0xd2,0x4e,0x5e,0xfd,0xe3,0xbb,0x77,0x0a,0x68,0xc4,0x70,0xcb,0xf3,0xca, + 0xf0,0x22,0x56,0x16,0x9c,0xb7,0xc9,0x05,0x8e,0x55,0xe4,0x67,0x74,0x87,0x43,0x1b, + 0x11,0x27,0x8b,0xb3,0xeb,0x44,0x31,0x3b,0xe1,0x74,0x8a,0xb9,0x51,0xfb,0xb0,0x3f, + 0x1c,0x37,0xd8,0x8d,0xc4,0xd4,0xab,0x37,0x8a,0xf3,0xf1,0xca,0x40,0x9b,0x15,0x89, + 0xb5,0x0b,0x1f,0xc0,0xa6,0x76,0x89,0x4f,0x6b,0x99,0x26,0x0c,0x25,0xa4,0x68,0xf3, + 0x95,0xb3,0xb7,0x47,0x74,0x73,0x41,0x70,0x6e,0x7a,0xf6,0x84,0x96,0x35,0xd4,0xe8, + 0xf1,0x53,0x9e,0x5a,0x1c,0xd2,0xcf,0x3b,0x76,0x4b,0x34,0xb1,0x66,0x54,0xca,0x9d, + 0x0b,0x46,0x90,0x3a,0xbc,0x5e,0xe3,0x4a,0x26,0x72,0x73,0xf3,0xfe,0xb4,0x83,0xad, + 0x20,0xb7,0x3d,0xa9,0xdf,0x9f,0xd4,0x25,0x75,0x41,0x57,0x41,0x5d,0xbc,0x2c,0x2e, + 0x93,0xf2,0x29,0xb1,0x97,0x9e,0x77,0x1a,0x0e,0xd7,0x5e,0x43,0x8c,0x1a,0x51,0x35, + 0xb1,0x76,0x6d,0x0d,0x0b,0x49,0x66,0x7c,0xa0,0x3d,0xab,0xef,0x36,0xd3,0xba,0xb9, + 0x71,0xdd,0xcd,0xc1,0xc6,0xfc,0x6e,0xb3,0xb7,0x45,0x2e,0x77,0x08,0x56,0x45,0xee, + 0xe5,0xfb,0xfb,0xb8,0xec,0xda,0x6c,0x6e,0xa2,0x81,0x4c,0xf0,0x99,0x91,0x14,0xd0, + 0x80,0x55,0x90,0xc3,0x95,0x0d,0x08,0xc1,0x32,0x6b,0xba,0x8b,0xb4,0xaa,0x68,0xcc, + 0xed,0x36,0x7d,0x35,0x0b,0x66,0x57,0xa1,0x2b,0x71,0x9d,0xfc,0x9c,0xb1,0x88,0xfa, + 0x65,0xe2,0x6e,0x88,0x26,0xb7,0x09,0x86,0x1e,0xcc,0x60,0xbe,0x2a,0x6e,0xe0,0x9a, + 0xe5,0xc8,0x60,0x44,0xce,0xf5,0x7e,0xe8,0xfa,0xd4,0x87,0xdc,0xa0,0xf6,0xa0,0x4a, + 0x76,0xca,0xa4,0x95,0x84,0x8f,0xc6,0x4a,0xeb,0xb8,0x22,0x25,0x8f,0x08,0xb8,0x38, + 0xa7,0xae,0x93,0xb2,0x74,0x59,0x11,0xe3,0xb5,0xaf,0x15,0xbb,0x7f,0xcb,0xc1,0x17, + 0x62,0xd3,0x29,0x11,0xf6,0x95,0xf2,0x6f,0x4e,0xa3,0x15,0x72,0xdf,0x11,0xc6,0xe6, + 0xb9,0x28,0x59,0x5e,0xf9,0x0e,0xc7,0x3e,0xf8,0x5e,0xad,0x42,0x55,0xb6,0x38,0xe4, + 0xf1,0xce,0xfd,0x24,0xf3,0xae,0xdf,0xbc,0x08,0xd4,0x25,0x6d,0x5a,0x9a,0xcf,0x0a, + 0x97,0x6e,0xdf,0xdc,0x60,0x78,0x19,0xf8,0x85,0xea,0xa3,0x4c,0x48,0xb6,0x55,0xb5, + 0x84,0xa4,0x24,0x97,0x9f,0x24,0x4d,0x45,0x1b,0x5c,0x89,0x5f,0x8a,0x09,0x4b,0xdc, + 0xb5,0x31,0x9c,0x48,0xbd,0x48,0x04,0xb3,0xf0,0x20,0x9f,0x15,0x0b,0xe5,0x96,0xf1, + 0xd8,0x81,0xac,0x63,0x1d,0xa4,0x97,0xa4,0xdc,0x71,0xc1,0x41,0x2d,0x5f,0xc9,0x7c, + 0x89,0xa3,0xb1,0xa4,0x87,0x74,0x9a,0x16,0xa4,0x57,0x19,0x87,0x32,0x7a,0x13,0x75, + 0x87,0xbd,0xc4,0xbb,0x15,0x29,0x66,0x99,0x03,0x4d,0x9c,0xb0,0x71,0x97,0x35,0x07, + 0x74,0xc1,0x13,0x43,0x64,0xd5,0x11,0x89,0x18,0x5d,0x90,0xa1,0x0e,0xde,0x1c,0x38, + 0x27,0xf0,0x3b,0x92,0x11,0x52,0x3b,0xc3,0x0a,0xbd,0xc1,0x69,0x4d,0x76,0x7c,0x85, + 0x34,0x32,0xd1,0xe4,0x94,0x23,0x29,0x43,0x92,0x06,0xdc,0x6d,0x39,0x1f,0x6a,0x42, + 0x94,0xee,0xc7,0xef,0x1d,0x1c,0xe5,0x28,0x45,0xa6,0x46,0x1a,0x1c,0x0a,0x44,0xc2, + 0x4a,0x70,0x8a,0x09,0x47,0x44,0x4a,0xa5,0x26,0x19,0xe8,0xe3,0x41,0x0f,0x0c,0x9c, + 0xe1,0xaf,0x45,0xe5,0x20,0x7c,0x46,0x38,0x2f,0xc7,0x67,0xb0,0xef,0xa4,0x08,0xab, + 0x7d,0xd0,0x14,0x5a,0x6f,0x73,0x63,0xc5,0x0c,0xe4,0xc8,0x0c,0xd9,0x22,0x45,0xd9, + 0xeb,0x35,0xdd,0xf4,0xeb,0x81,0x77,0x30,0x1c,0x0c,0x06,0x5e,0x83,0x66,0xd5,0x31, + 0x46,0x26,0x54,0x04,0x84,0xdc,0xfd,0x6a,0x9f,0x30,0x79,0x24,0xb7,0xfe,0xf2,0xaf, + 0xff,0xdb,0xf5,0x0d,0x0a,0x08,0xf2,0xe1,0x0f,0xc6,0x95,0x39,0xf1,0xf1,0xa1,0xef, + 0xe1,0x22,0xbf,0x88,0xb2,0x9e,0x59,0xa0,0x27,0x72,0x49,0x2f,0x97,0x98,0x80,0x69, + 0x83,0x77,0xfd,0xc3,0x07,0x98,0xc1,0xba,0x0d,0x81,0x67,0x84,0x22,0xb4,0x88,0x5b, + 0xbb,0x6c,0x83,0x6f,0xad,0xb4,0x4c,0x4e,0x52,0x98,0x26,0x4a,0xa3,0xae,0x94,0x26, + 0x0b,0xcf,0xea,0x8a,0x45,0xae,0xf6,0xa5,0x12,0x28,0xce,0x41,0x62,0xe7,0xea,0x64, + 0x88,0x4a,0x7a,0xa4,0xc6,0xca,0xe9,0xa9,0xd0,0x31,0x26,0x5c,0x6a,0xfc,0x9e,0xe2, + 0x6d,0x8d,0x2c,0x2d,0x9b,0x79,0xc1,0x3c,0xc9,0x62,0xa7,0x8c,0xa0,0x65,0xc1,0x9f, + 0x4a,0xf4,0xb3,0x44,0x12,0x08,0x2b,0x3d,0xa0,0x7c,0x46,0x1f,0x76,0xb4,0x2a,0xc1, + 0x0b,0x13,0x40,0xbb,0x1a,0xe1,0xd3,0xe4,0xd0,0x6f,0x65,0xb9,0x6b,0x25,0x6c,0x62, + 0x79,0x6c,0x35,0xbe,0x6a,0xbd,0x98,0x2d,0x0e,0x46,0xbf,0x18,0xae,0x58,0xd0,0xbc, + 0x38,0x62,0xaf,0x8a,0x15,0xa1,0x16,0x4c,0xf8,0x9e,0xb2,0x3b,0x7e,0x2d,0x93,0x33, + 0x22,0x9f,0xf2,0x2a,0x50,0xb4,0x70,0x39,0xbf,0xf2,0x1a,0xd5,0x39,0x15,0xea,0x44, + 0x87,0xdc,0x1f,0x11,0xdd,0x62,0x59,0x57,0x2d,0xe5,0xb8,0x7e,0x25,0xca,0x13,0x0e, + 0x64,0xed,0x38,0x46,0xdd,0xbf,0x73,0x67,0x81,0x9d,0xd5,0x86,0x93,0xd6,0xb9,0x2c, + 0x4d,0x8b,0x13,0x77,0xd8,0xea,0x7c,0x09,0x0e,0x53,0x17,0x67,0x67,0x59,0xd2,0x73, + 0x8b,0xd9,0xcc,0xf5,0xb5,0x46,0xe6,0x49,0x1f,0x44,0x72,0xcd,0x39,0x3d,0xab,0x0b, + 0x65,0x80,0xb5,0x55,0x23,0xdd,0x60,0x6f,0xaf,0xb1,0x36,0xbc,0x63,0x46,0x62,0x57, + 0x79,0x30,0x68,0x5d,0x38,0x18,0x06,0xe8,0x62,0xad,0xe0,0x3b,0x8a,0xf9,0x39,0xa4, + 0xb1,0x56,0x05,0x84,0x76,0x25,0xeb,0x57,0x0c,0xc9,0x65,0x05,0x47,0x38,0x74,0x47, + 0xf7,0xd7,0x42,0x4a,0xcd,0x9d,0xf1,0xa6,0xa5,0xc3,0x67,0x1e,0x71,0xc0,0x6e,0x95, + 0xd3,0x3d,0x1c,0x84,0x52,0xbc,0xf9,0xb1,0x0a,0x81,0xc1,0xd1,0xc9,0x18,0x23,0x41, + 0x7a,0x6c,0xa8,0xc2,0x47,0x9a,0x82,0x41,0xd1,0x4b,0x4e,0x7a,0x48,0x72,0x8e,0x0e, + 0xd3,0x1b,0x13,0x1c,0x8d,0x63,0xfc,0x41,0x5f,0xf0,0x24,0x56,0x1c,0x32,0x06,0xcc, + 0x1c,0x36,0xd4,0xc0,0x6b,0x18,0x65,0xe0,0xe0,0xe6,0xf5,0xed,0x0a,0xe6,0x29,0x25, + 0x7f,0x52,0x16,0xe7,0x49,0xbe,0x0b,0x3d,0x67,0x46,0x02,0x41,0x7b,0xb7,0x19,0xc7, + 0x57,0x4b,0xa8,0xeb,0x79,0x2d,0xb8,0xcd,0x11,0x2e,0x4d,0x06,0x05,0xb3,0x57,0x4e, + 0xf7,0x11,0xf4,0x9d,0xa5,0x1f,0x19,0xd9,0x6c,0xe4,0x10,0x9f,0xf5,0x5b,0x1a,0xf8, + 0xaa,0xa7,0x75,0x1b,0xbd,0xb3,0xca,0x28,0x01,0x7f,0x6d,0x03,0x96,0xc4,0x24,0x7b, + 0x1e,0xae,0xc1,0x72,0x5c,0xe1,0xcd,0x2c,0xf7,0x31,0x61,0x4b,0x7e,0x30,0xda,0x97, + 0x57,0x32,0x7a,0x74,0x86,0x80,0x0c,0xec,0x41,0xc2,0x40,0x38,0x35,0x88,0x1b,0x41, + 0x16,0x9a,0x23,0x6d,0x2c,0xf8,0xd7,0x3b,0xc2,0xc8,0xdc,0x59,0xcb,0xa9,0xae,0x0c, + 0x72,0x4d,0x47,0xca,0x6b,0x97,0x56,0x16,0xc9,0xc3,0x5c,0x64,0x7c,0x80,0x5d,0x6c, + 0xfa,0xb6,0x11,0xbc,0x9a,0x12,0x28,0x32,0xe2,0x46,0xc5,0x7f,0x4b,0x93,0xcb,0xde, + 0x35,0x87,0x5e,0x47,0x6e,0x4e,0x2c,0x8a,0x68,0xd5,0x6d,0x59,0x62,0x3c,0x99,0xb1, + 0x11,0xce,0x30,0xb2,0x11,0x9f,0x13,0xc7,0xb5,0xe8,0x9a,0xbe,0x22,0x61,0x9c,0x3a, + 0x24,0x64,0x67,0xf1,0x02,0x37,0x31,0x6f,0x23,0xfa,0x29,0xd3,0x44,0x27,0xe7,0x50, + 0xd3,0x8f,0x12,0xa8,0x59,0x29,0x55,0x14,0x32,0xfb,0x05,0xb7,0x17,0x8d,0x87,0x9d, + 0x31,0x6f,0x93,0x0f,0x9b,0xe2,0x04,0x78,0x20,0x3b,0xa3,0x1b,0x90,0x48,0x27,0x13, + 0xbc,0xe7,0xb6,0xbc,0x13,0xae,0x7f,0xad,0x4e,0x1f,0x8e,0x86,0x0f,0x48,0x26,0xac, + 0x3b,0xce,0xad,0x6a,0x05,0xa6,0x19,0xda,0x63,0x50,0x1b,0xb1,0x60,0xb4,0x12,0x67, + 0x6b,0x7a,0x72,0x97,0x60,0xf1,0xa7,0x27,0xea,0xd8,0xdb,0xd0,0x79,0xf5,0x64,0x64, + 0x22,0xb7,0x12,0xb1,0x9a,0x91,0xd6,0xfd,0xa7,0x27,0x81,0x11,0x5d,0xe7,0x61,0x1c, + 0xcc,0xca,0x24,0x21,0x31,0x75,0x78,0x5f,0xba,0x98,0x55,0x2d,0x5e,0x10,0x07,0x0a, + 0xa7,0x8e,0x7b,0xe7,0x8f,0xa8,0xd5,0xbd,0xe0,0xc1,0x31,0x8b,0x3b,0x0e,0x80,0xf7, + 0xce,0xa1,0x86,0xd1,0x90,0xe8,0xc4,0x1d,0xd9,0x0f,0xd0,0x65,0x70,0x1f,0x02,0x90, + 0x5a,0xbc,0x52,0x2d,0xc8,0xc8,0xd1,0x08,0x03,0x46,0xad,0xba,0xd6,0x6a,0x58,0xc3, + 0x08,0xcd,0xa8,0xd6,0x6a,0xc9,0xba,0x4f,0xf3,0x3c,0x29,0xbf,0x7b,0xf7,0xea,0x65, + 0xe8,0x36,0xef,0xfc,0x00,0xe7,0xe6,0x33,0xe6,0x0d,0x0c,0x09,0x6f,0xcc,0x70,0x80, + 0x81,0x81,0x18,0xf8,0x08,0xf6,0x38,0x81,0x04,0xfe,0x24,0xf8,0x39,0x4a,0xa0,0x06, + 0xd0,0x1b,0x10,0x39,0x23,0x1a,0xe4,0x7e,0xe2,0x40,0x6f,0x14,0x29,0xd0,0x44,0x1a, + 0xa4,0x7f,0x97,0x40,0x1e,0xa8,0xce,0xdb,0x9a,0xf8,0x52,0xed,0x95,0x00,0x31,0x4b, + 0xc3,0xc5,0x39,0x5c,0x74,0xae,0xbf,0x0c,0x38,0xdb,0x87,0xe8,0x2f,0x46,0xe2,0x33, + 0x89,0x16,0x52,0x2a,0x61,0x45,0xba,0x9e,0xbf,0x08,0x39,0x16,0x4d,0x7b,0x31,0x56, + 0x2f,0x83,0x60,0x4d,0x4f,0x4a,0x97,0xb8,0x94,0xbe,0x10,0x59,0xa1,0x6d,0xaf,0x2e, + 0xe9,0xc5,0x29,0xdf,0x62,0x3f,0x06,0x6e,0xc1,0x35,0x32,0x36,0x2f,0x4d,0x03,0x76, + 0x7d,0xbb,0xda,0xdd,0xe3,0x8e,0xdb,0xa6,0x40,0xb8,0xa0,0x1b,0xc4,0x8d,0x98,0x22, + 0xc2,0x46,0xb3,0xb7,0x7b,0xa0,0xb6,0x8f,0x6b,0xa2,0x06,0xa2,0x5a,0x92,0x1e,0x51, + 0x99,0x46,0x7d,0x33,0x01,0x31,0xea,0xdc,0xfd,0x65,0x00,0xd7,0xb3,0x35,0x70,0x75, + 0x19,0x90,0x55,0x46,0x2c,0xfa,0x29,0x31,0xdb,0x18,0x07,0x91,0xb3,0xb4,0x75,0xa7, + 0xba,0xb4,0x5a,0xab,0x54,0xba,0x26,0xd5,0xae,0xfd,0xa8,0x3d,0x61,0xf3,0xe8,0x92, + 0x0c,0x4c,0x78,0xb3,0x89,0x22,0x4c,0x5f,0xeb,0x04,0xe6,0xc7,0xc6,0x58,0x00,0x10, + 0x9c,0xdb,0x98,0xf1,0x92,0x6c,0x69,0xdd,0xf8,0xf6,0x66,0xb9,0xd9,0xac,0xfd,0x61, + 0xd3,0x9e,0x2d,0xb1,0x05,0xc3,0x5b,0x58,0x18,0x5a,0x2e,0xd0,0xb4,0xb5,0xfa,0x7c, + 0xa1,0xa0,0xae,0x1a,0x8d,0x71,0x03,0x79,0x68,0xa1,0x0b,0xc7,0xbc,0x6b,0xb5,0xeb, + 0x30,0xe3,0xd1,0xa4,0xa7,0x06,0xd7,0x3d,0xaf,0x6f,0x99,0x71,0xbe,0xf8,0xfc,0x5a, + 0x16,0xc7,0x2e,0x27,0x71,0x10,0x72,0x11,0xa6,0xe1,0x27,0xdf,0x53,0x56,0xd3,0x48, + 0xb9,0x25,0x2c,0xa8,0x6c,0xe0,0xdd,0x66,0xc7,0x08,0xe0,0x13,0xc4,0x7d,0x6c,0x93, + 0xb7,0xb5,0xad,0xe6,0xb1,0x10,0x9b,0xb5,0xc7,0xac,0x75,0xb7,0x61,0xd7,0x04,0x81, + 0xe8,0x42,0x5c,0x40,0x84,0xbc,0x93,0x0d,0xe8,0x99,0x1e,0x26,0x5d,0xe0,0x22,0xb5, + 0xad,0xb7,0x50,0x70,0xf2,0x27,0x0d,0xa4,0xb6,0x26,0x3e,0x69,0x70,0xc4,0x80,0x8c, + 0xd9,0x86,0xdd,0xc8,0x60,0xd2,0x5a,0xfd,0x4b,0x4f,0x94,0x0f,0xc5,0xe9,0x70,0x33, + 0x10,0x5f,0x90,0x4b,0x18,0xad,0xbe,0x63,0x2e,0xdf,0x26,0x17,0x37,0x37,0x03,0x5f, + 0xc4,0x90,0xcf,0x22,0x58,0xf5,0xb1,0x69,0x3c,0x13,0xa3,0x9f,0x42,0xc3,0xe8,0x6d, + 0x9a,0x0e,0x16,0x07,0x6f,0x08,0x82,0xf9,0xfd,0xd4,0xa4,0x65,0xb2,0xa4,0xd2,0x16, + 0x24,0x4b,0x57,0x76,0xde,0xd3,0x04,0x94,0x00,0xb5,0x0c,0xd5,0x4d,0x81,0xe2,0x5d, + 0xb7,0x24,0x16,0xe7,0x79,0xf4,0xda,0xee,0x4c,0xd5,0x40,0x8b,0xd1,0x37,0x05,0xd4, + 0x37,0x6e,0xa8,0xa4,0x69,0xe3,0x6a,0xe7,0x09,0x48,0x80,0xdf,0xcc,0x27,0xad,0x2c, + 0x81,0x5e,0xa9,0x86,0x51,0x75,0x2e,0x02,0x94,0xfb,0x69,0xc4,0x93,0xa5,0xd2,0xf0, + 0x44,0x94,0x2e,0xa3,0x5a,0x59,0x4e,0x19,0xfd,0x9e,0x06,0x0a,0x2c,0x64,0xa9,0x51, + 0x50,0xe4,0x27,0xea,0x90,0xbd,0xdc,0xb6,0x8a,0x1a,0xf4,0xee,0x69,0x3b,0x8b,0xee, + 0x73,0x99,0x81,0xb6,0xf8,0x3d,0x50,0xfb,0xe6,0xc2,0x1a,0x1a,0xf8,0x5d,0x52,0x37, + 0xf6,0xba,0xb6,0xdf,0x78,0x2c,0xb0,0xf9,0xa5,0xda,0x75,0xb3,0xdd,0x6b,0xff,0x9a, + 0x57,0x3d,0x12,0xdd,0xc8,0xb3,0x9d,0xc3,0x64,0x03,0xf6,0x75,0x02,0x3b,0xbb,0x33, + 0x90,0x14,0x81,0x4c,0x7a,0x95,0xed,0x8d,0x7c,0x73,0x18,0xe9,0xe7,0x79,0x31,0x71, + 0xb0,0x78,0xa8,0x88,0x85,0x58,0x39,0xd1,0xc4,0x63,0x2f,0xaf,0x58,0x36,0x09,0xd9, + 0xe5,0xa4,0x02,0xc5,0x4a,0x3f,0x91,0x10,0x3d,0xf2,0x88,0xcb,0xa4,0x8f,0x2d,0xd1, + 0x5a,0x9d,0xb8,0x19,0xd8,0x8f,0x96,0xb2,0x8f,0x47,0x02,0x06,0xfc,0xfb,0x71,0x0d, + 0x07,0x93,0xd9,0x04,0x0d,0x4a,0xb8,0xa8,0x68,0x1d,0xf3,0xa8,0x3a,0x41,0x3e,0x6b, + 0xc8,0xd5,0x35,0x96,0xca,0x45,0xc3,0x1c,0xea,0x87,0x19,0xf1,0x19,0x3c,0x73,0xbd, + 0x23,0xf1,0x51,0xb5,0x34,0x94,0xbd,0xbd,0x3b,0x0a,0x8b,0x3c,0xd1,0x84,0xb4,0xb9, + 0x1c,0x85,0x95,0x12,0x81,0xea,0x9d,0x2a,0x50,0x2a,0xf3,0xcd,0xcd,0x9d,0xe8,0xe6, + 0x26,0x22,0x21,0xe9,0xf6,0x5d,0x6b,0xe3,0x59,0x93,0x97,0x40,0x27,0xaf,0xa6,0x20, + 0x9d,0x51,0x8e,0xe2,0xd7,0x88,0x2e,0x20,0x69,0x27,0x97,0xd0,0x2a,0x99,0x13,0x2e, + 0xb4,0x87,0x0b,0x51,0xf2,0x15,0x74,0x61,0x96,0x05,0x32,0x96,0xac,0x79,0x6f,0x2f, + 0x82,0x3f,0x4f,0xfd,0xb6,0x0c,0x73,0x0d,0x92,0x47,0xd0,0xc4,0xac,0x19,0x58,0x60, + 0xd3,0xcb,0x98,0xa7,0x75,0xa3,0x60,0xdd,0x1a,0x64,0x20,0xd9,0xdf,0xa1,0x26,0x10, + 0xaf,0x69,0xbc,0x04,0x24,0x56,0x88,0x5f,0xb5,0x5e,0xed,0xb9,0x01,0x09,0x17,0x6f, + 0xdc,0xf2,0xea,0xd1,0x80,0x04,0xd3,0x3b,0xf9,0x62,0x6f,0x0f,0x52,0xc5,0x52,0xc5, + 0xc2,0x30,0x62,0x68,0xb7,0xc5,0x65,0x18,0xde,0xd1,0x80,0xfe,0xbe,0x7a,0x65,0xe9, + 0x17,0xe2,0xd8,0xc3,0xfc,0x1b,0xf6,0x42,0x2f,0x77,0x98,0x8b,0xc4,0x9c,0xa9,0xa5, + 0xf6,0xff,0x09,0x06,0xeb,0x83,0x25,0x88,0x33,0xf7,0xec,0xe8,0xb3,0xa7,0x1e,0xfd, + 0x67,0xfd,0x87,0xc9,0x9d,0x20,0x0a,0x4e,0x74,0x2a,0xe6,0x54,0x2b,0x30,0xe7,0xb2, + 0xf1,0xd6,0x97,0x19,0xeb,0xd8,0x1a,0x19,0x65,0x95,0x64,0xfd,0x2a,0xc3,0x87,0x6d, + 0xbf,0xca,0x50,0x17,0xd1,0x13,0x59,0x0d,0x3a,0x0f,0x8b,0x11,0x6f,0x99,0x94,0xb0, + 0x70,0x60,0x8e,0xf9,0xc6,0x92,0x17,0x4c,0xa9,0xac,0x38,0xa1,0xd2,0xae,0xd1,0x13, + 0x50,0x95,0x54,0xc6,0x9c,0x9e,0x26,0xb9,0x70,0x6e,0x6d,0x0e,0xcd,0xd3,0xb3,0xb9, + 0x54,0xb4,0x00,0xce,0xd2,0x0c,0x97,0x64,0x0b,0xa4,0x48,0xa5,0x43,0x9e,0x13,0x0f, + 0x2c,0xc4,0x83,0x7e,0x2e,0x50,0x60,0x01,0x96,0x09,0x51,0x5d,0x89,0x70,0x21,0xb3, + 0x62,0xcb,0x26,0x64,0xfd,0x41,0xb4,0x07,0xde,0x90,0x6b,0x6d,0x92,0xc9,0x3a,0x98, + 0x1b,0x14,0x70,0x9d,0xd2,0xc3,0xb6,0x5b,0xc9,0x08,0x0b,0xa9,0x6f,0xb2,0xc1,0x22, + 0x45,0xd7,0x3b,0x16,0x0d,0xd6,0xdd,0x97,0x11,0xae,0xa7,0x84,0xd2,0x09,0x19,0x61, + 0x45,0x1f,0x9a,0x7b,0x42,0x56,0x18,0x63,0xd2,0x76,0x5d,0x14,0x25,0x53,0x9a,0x2a, + 0x27,0x5d,0xed,0x62,0xa3,0x77,0xc0,0x47,0x1f,0xa3,0x8c,0x0a,0x1b,0xa9,0x71,0x90, + 0xa0,0x8e,0xca,0xcd,0x8d,0x5a,0x84,0x32,0xd5,0xda,0x52,0x4e,0x46,0xd0,0xc2,0x5d, + 0x11,0x6b,0xcc,0x8a,0xc1,0xcd,0x0d,0xfe,0x8e,0x0d,0xaf,0x6b,0x3b,0xf3,0x8c,0x64, + 0xcd,0x91,0x06,0x2e,0x3c,0x79,0x04,0xa5,0x96,0x9b,0xfb,0xf0,0xfb,0xda,0xb6,0xd5, + 0x1f,0x26,0x74,0x38,0x12,0x93,0xcc,0x22,0x2d,0xc9,0x95,0x60,0xd2,0xf2,0xd6,0x2d, + 0xed,0x12,0x26,0x49,0xf8,0x89,0xee,0x9d,0x20,0x6f,0xd4,0x7b,0x34,0xee,0x1e,0xcd, + 0xe8,0x40,0x60,0x76,0xc8,0x96,0x25,0xab,0xb9,0xd7,0x8e,0xb9,0xf9,0xc3,0x81,0x47, + 0xdc,0x41,0xeb,0xb8,0xf4,0x50,0x8e,0x62,0xa8,0x94,0x05,0x6b,0xb6,0x51,0x1c,0xcb, + 0x54,0x8d,0xfe,0x64,0x74,0xa4,0x6d,0xdd,0x45,0xc1,0x51,0xf9,0x68,0x39,0x14,0x29, + 0x44,0xd5,0xda,0xab,0x2d,0x46,0xf2,0x58,0x0c,0x2f,0xa7,0xc7,0x69,0xcb,0x58,0x98, + 0x2f,0x71,0xf6,0x26,0x49,0xe7,0x6f,0xca,0x59,0x38,0x3e,0x05,0x8b,0x43,0xf9,0x68, + 0x9e,0x7d,0x7f,0xf2,0xe6,0xe5,0xe3,0x7f,0x92,0x91,0xc6,0x96,0x13,0x04,0x0c,0x03, + 0xf7,0xf4,0x29,0x2c,0x65,0xf6,0x49,0x2e,0x34,0x36,0x8a,0x9d,0xd3,0x73,0x2d,0xb6, + 0x33,0x64,0x04,0xe8,0x4c,0x48,0x96,0xfd,0x3e,0x11,0x3c,0x07,0x02,0x9c,0x5d,0x78, + 0x74,0x20,0x85,0xfa,0xe2,0xa2,0x00,0x6c,0x7e,0x28,0x53,0x9a,0xc2,0xae,0xea,0x1d, + 0x7d,0x4d,0xb3,0x82,0xd8,0x51,0xed,0x54,0x19,0xc9,0x35,0x22,0x54,0xb2,0xcc,0x62, + 0x2f,0xd0,0xa9,0x0f,0xa4,0x5b,0x7b,0x64,0xad,0xf6,0xd5,0x34,0x0c,0xaf,0xb9,0x2c, + 0xd9,0xd9,0x06,0x5e,0xc4,0x9d,0x90,0x08,0xc8,0x8a,0xb3,0xa0,0xfe,0x58,0x2b,0xaf, + 0x94,0xf1,0xb0,0x28,0xcf,0x55,0x68,0x66,0x79,0xe8,0xb7,0x32,0x0f,0xf0,0x7a,0x87, + 0xef,0x32,0xf9,0xb8,0x24,0x3c,0x54,0x6c,0x92,0x7b,0xa8,0x4b,0x9a,0x52,0x86,0x79, + 0x93,0x49,0x7f,0x36,0x17,0x9f,0x55,0x49,0x12,0x3c,0x2a,0xaf,0x94,0xeb,0x55,0xf5, + 0x35,0x97,0xa4,0xc1,0x3f,0xf7,0xdf,0xbc,0xe8,0x23,0xff,0x65,0xd4,0x9a,0x1f,0xb8, + 0x20,0xf2,0xd5,0x93,0x98,0xf8,0x1d,0xc4,0xb8,0xe6,0xdc,0xa2,0xab,0xc4,0x6a,0x97, + 0x44,0x5b,0x29,0x8c,0x35,0xaf,0xc5,0x2e,0xc6,0xf8,0x51,0x99,0xef,0xb2,0x53,0xec, + 0xe8,0xd3,0xde,0x47,0x38,0xfc,0x44,0x27,0x95,0x42,0x42,0xce,0x02,0x21,0x76,0x51, + 0x9e,0x39,0x4a,0x2c,0xca,0xd6,0x59,0x62,0x71,0x50,0xe5,0x49,0x44,0xf0,0x85,0x7f, + 0x86,0xcd,0xa8,0xa4,0x9c,0xdc,0x69,0x1c,0x8f,0xeb,0x96,0x9b,0xd6,0xf2,0x34,0x90, + 0xbc,0x04,0x0d,0x5a,0xb3,0x2d,0x72,0xe3,0xa0,0xdc,0x31,0x89,0x2c,0x26,0x4e,0x8e, + 0x68,0x9b,0xd5,0x19,0xbf,0xa7,0x82,0x67,0xa2,0x0a,0xb7,0xbb,0x17,0x05,0xb3,0x31, + 0x4d,0x98,0xe8,0x64,0xf1,0x53,0x15,0x72,0x13,0xa8,0xd6,0x8e,0x00,0x86,0xd4,0xa2, + 0x4d,0x2e,0xaf,0xc8,0xef,0xdf,0xfe,0xfb,0x5f,0xfe,0xed,0xdf,0x09,0x9b,0x91,0x92, + 0xc1,0xae,0x68,0x1f,0xf1,0xab,0xa7,0x27,0x27,0x1e,0x9c,0x43,0x00,0xbe,0x6f,0x4e, + 0xc8,0x18,0x6f,0x67,0xe0,0xbc,0x52,0x01,0x5c,0xa4,0x7d,0xc0,0x49,0x99,0x9e,0xad, + 0x8a,0x95,0xed,0xb6,0x36,0x76,0xe0,0x6a,0xd9,0x44,0xa6,0x3b,0xad,0xbf,0xc5,0x85, + 0x4b,0x8d,0x8e,0x5d,0x9a,0x0a,0x59,0xa3,0x34,0x1b,0x61,0x34,0x1d,0x56,0xe0,0xe4, + 0x13,0xae,0x08,0xf4,0xc0,0x1a,0xdf,0x6a,0x49,0xbd,0xf0,0x2f,0x84,0xfe,0x74,0x5f, + 0xdd,0xe1,0x72,0xe5,0x54,0x49,0x27,0x21,0xbd,0x4e,0xca,0x0f,0x99,0xc2,0x17,0x29, + 0xad,0x43,0xf1,0xc0,0x93,0x74,0x92,0x41,0x14,0xd0,0x13,0xf8,0xff,0xda,0x77,0x8d, + 0x16,0x75,0x87,0xde,0x27,0xb4,0xa0,0xbf,0xed,0xcc,0x90,0x46,0x6f,0xb4,0x1c,0x54, + 0x55,0x52,0xd6,0x4f,0x98,0x64,0x05,0x36,0xc7,0xf4,0xda,0x08,0xaf,0x62,0x00,0xd5, + 0xb3,0xe2,0xae,0x93,0x80,0x8b,0xeb,0x68,0x11,0xd5,0xc6,0x09,0x13,0xfe,0x51,0x62, + 0x75,0xd2,0xc2,0x1f,0xc1,0x0c,0x0d,0xf6,0xf2,0x53,0x02,0x45,0xea,0x29,0x61,0xc2, + 0xa7,0xca,0xdd,0x4a,0x8a,0x27,0xde,0x4a,0x49,0x9b,0x4f,0x1f,0x95,0x3a,0x25,0x20, + 0xdd,0xdf,0x57,0x20,0x2b,0xdf,0xa7,0xa7,0x5b,0x8a,0x2a,0x6d,0xa2,0xd7,0x44,0x10, + 0x52,0x9d,0x58,0xd1,0xd5,0x9a,0x07,0xe6,0x17,0xde,0x0f,0x4f,0xdb,0xef,0xe8,0xd1, + 0x10,0xdc,0x6f,0x62,0xab,0x2f,0x38,0x4f,0x99,0xf9,0x00,0xa1,0x32,0x3c,0xd0,0x92, + 0x8d,0x44,0xc8,0x08,0xac,0xc4,0x03,0xa6,0xf0,0x2b,0xe7,0xac,0x70,0x54,0xa6,0x62, + 0x6a,0x9f,0xf1,0xb2,0xd0,0x92,0x5e,0x60,0x8f,0x51,0x72,0xd1,0xe4,0xf9,0x29,0x06, + 0xb3,0xb7,0xf7,0xfe,0x54,0xdb,0x34,0x5c,0x43,0x90,0x1a,0xf1,0x8e,0xbe,0xc3,0x39, + 0xc5,0x19,0xe9,0x58,0x40,0xc8,0xca,0x77,0x79,0x3e,0xae,0xf7,0x68,0x60,0x41,0xdc, + 0x76,0x45,0x89,0xb3,0x17,0x62,0xf3,0x39,0xe9,0x7b,0x35,0x64,0x28,0xb2,0x12,0x91, + 0x96,0x17,0x9d,0xb1,0xf9,0xea,0xfa,0xb6,0x03,0x43,0x33,0xb8,0x2c,0x1d,0xb7,0x14, + 0x70,0x96,0xbb,0x78,0xaa,0x95,0x84,0x5b,0x3b,0xa5,0xfd,0x6e,0x75,0x29,0x3e,0x4b, + 0x9b,0x71,0x76,0xe8,0xf7,0x5a,0x09,0x91,0x11,0x5a,0x78,0xfa,0xd7,0x2b,0x36,0x44, + 0xfc,0x7a,0xd6,0x9f,0x99,0x3b,0x37,0xb5,0x0a,0x31,0x5e,0x34,0x26,0xf7,0x1d,0x6b, + 0xb7,0x6e,0x6e,0xcc,0x7a,0x42,0x82,0x54,0x8b,0xba,0x68,0x9f,0x40,0xb9,0xd4,0xf5, + 0x33,0xa9,0xbb,0xd3,0xf3,0x3a,0xd6,0x2b,0x6a,0x0c,0x4f,0xec,0x0b,0xa6,0xc5,0x47, + 0x9e,0x5a,0x40,0xed,0x04,0x9e,0xbd,0xd0,0x5b,0xfa,0x2a,0x96,0x5d,0xcb,0xfb,0xb2, + 0x39,0xb7,0x87,0x19,0xff,0x51,0xc0,0x74,0xb1,0x1d,0xdd,0xda,0x37,0xae,0xae,0x0e, + 0xce,0xc2,0xf2,0x41,0xbb,0xc7,0xbe,0x74,0xdb,0x36,0x26,0xe6,0x75,0x2c,0x11,0x1d, + 0x7f,0xa2,0xdb,0x2e,0x50,0x51,0xaf,0x76,0xa7,0xcd,0xf2,0xba,0x20,0xb8,0x85,0xf3, + 0xf4,0xf6,0x26,0x15,0xf3,0xb1,0x07,0x9d,0x83,0x02,0x15,0x9f,0xe9,0xb9,0xbb,0x19, + 0xe0,0xa0,0x32,0x4c,0xf5,0x89,0x18,0x68,0x5a,0x72,0x16,0x2e,0xad,0x7c,0x95,0x3d, + 0x41,0x3f,0x24,0xde,0xe5,0xeb,0x98,0xb3,0xc7,0x4c,0x8a,0x14,0x08,0x9c,0x17,0xea, + 0x79,0xd5,0x88,0xc3,0x4c,0x12,0x14,0x95,0x94,0x50,0x8e,0x17,0xe3,0x5c,0x85,0x84, + 0xfe,0x80,0x6f,0xec,0x0a,0x4a,0xe3,0x3e,0x0f,0x01,0x4f,0x99,0x72,0x9a,0x05,0x3b, + 0x5a,0x5f,0xb8,0x3d,0xeb,0x8b,0x1d,0x51,0x9f,0x4b,0x76,0xdc,0x60,0xf7,0xdd,0x04, + 0xcd,0x3d,0x49,0xae,0x23,0x92,0xee,0xb6,0x93,0x1d,0xa5,0x81,0x89,0x7f,0x48,0x3c, + 0x45,0x9d,0x39,0x53,0x2a,0xd8,0x5f,0xfe,0xed,0x7f,0x68,0x5b,0x5a,0x6e,0xf4,0xaa, + 0x84,0x79,0x36,0x2d,0x6b,0x42,0xa8,0xe3,0xe9,0xa4,0x09,0x92,0x7a,0xa1,0x7b,0xd7, + 0xb1,0xcb,0x4a,0x96,0xab,0x3c,0x07,0x24,0x54,0x4f,0xa4,0xc7,0x68,0x17,0x63,0xce, + 0x61,0x2a,0xa3,0xb7,0xfe,0x92,0xbb,0xfb,0x32,0x97,0xdf,0x48,0x5d,0xec,0xb9,0x74, + 0xed,0xed,0xe3,0xaf,0x51,0x89,0x2a,0x81,0x29,0xf7,0xd4,0x69,0xe8,0xd2,0x06,0x71, + 0xbe,0x87,0x82,0xaf,0xaf,0x37,0xac,0xb3,0x56,0x29,0xa2,0xd4,0x96,0xda,0xf0,0x71, + 0x5e,0x86,0x68,0xf7,0xe7,0x57,0x2f,0xbf,0xab,0xeb,0xe5,0x5b,0xc9,0x2e,0xd1,0x64, + 0x4c,0x4f,0x03,0x64,0xa3,0xf7,0xdc,0x37,0x3f,0xbe,0xa3,0x81,0xdb,0xd1,0x3e,0xab, + 0x11,0x01,0x57,0xbd,0xfa,0x1d,0x9f,0x4d,0xeb,0xb9,0x46,0x4f,0xa6,0xd7,0x2c,0x45, + 0xf9,0x0b,0x5e,0x7a,0x49,0xd6,0x07,0xbd,0x34,0xb4,0x9b,0x16,0x9c,0xfe,0xb4,0xa5, + 0xf8,0xc8,0x1a,0x94,0x33,0x0b,0x67,0x6b,0xe3,0xf0,0xbf,0x9e,0xfc,0xf0,0x3a,0x60, + 0x6b,0xb1,0x87,0x17,0xcb,0xa4,0x5a,0x16,0xc4,0x39,0xde,0xd1,0x1e,0x79,0x6b,0x31, + 0xf4,0x68,0xfd,0xeb,0xc6,0x40,0x8f,0xf7,0xf6,0x94,0x89,0xde,0x15,0x66,0x6b,0x42, + 0x41,0x8d,0x76,0xca,0xda,0xa8,0x6b,0x5b,0xd4,0x56,0xa5,0x56,0xcc,0xd3,0xff,0x76, + 0x30,0xf0,0xf4,0x10,0x1c,0xca,0xc1,0xdb,0x32,0x12,0xbb,0x00,0x3c,0xf8,0x00,0x60, + 0x13,0x76,0x79,0x00,0xd4,0x7b,0x31,0x27,0xaf,0x28,0x1b,0xd5,0x86,0x04,0xf7,0x10, + 0xfe,0x61,0x6b,0x75,0x2c,0x1d,0xae,0x6d,0xf8,0xe7,0x82,0x24,0x4f,0xb2,0x62,0xd2, + 0x7b,0x0f,0x34,0x3e,0xf5,0x14,0xeb,0xf4,0xaf,0xcf,0x56,0x51,0x19,0x8f,0xa0,0xa4, + 0xaf,0xbd,0x26,0x1d,0x52,0x59,0xba,0x4f,0x9a,0xa4,0xab,0xff,0x64,0x57,0xd9,0xa7, + 0x6c,0xe3,0x1f,0x5e,0x3f,0xd7,0xf9,0x52,0x26,0x4d,0x4d,0xca,0x8d,0x98,0xe4,0xd7, + 0x91,0x9d,0x2a,0x20,0x82,0xaa,0x32,0xf6,0x25,0x52,0xc1,0x60,0x37,0x88,0x05,0x58, + 0x55,0x2a,0x3f,0xa2,0x9a,0x12,0x77,0x95,0x04,0xe7,0x5e,0xe4,0x3c,0x7b,0xfe,0xf2, + 0xf9,0xbb,0xe7,0x7c,0xf0,0x1e,0x74,0xec,0x2c,0x08,0x95,0x91,0x1d,0x21,0xed,0x9c, + 0x17,0x8f,0xdf,0xbd,0x38,0x51,0x2f,0x6a,0x6b,0x92,0x4d,0x70,0xc5,0x20,0x54,0xe4, + 0x5a,0xaa,0xc8,0x72,0x12,0x06,0x98,0x45,0x84,0x53,0xad,0x64,0x1e,0x40,0x13,0xe4, + 0xf4,0x25,0x9a,0xcf,0xac,0xbe,0xf2,0x02,0x7a,0x9d,0xf9,0xb8,0x58,0x6f,0xce,0xee, + 0x57,0xbb,0x3a,0x5d,0x4d,0x1b,0xc6,0x4d,0xd4,0x42,0x2f,0x36,0x4b,0x27,0x25,0x99, + 0xb3,0xad,0xa5,0x72,0xa7,0x95,0x64,0xb8,0x91,0xbd,0xca,0xb5,0x29,0x9a,0xe3,0x74, + 0x9c,0x07,0x3f,0xad,0x57,0xec,0xb9,0x63,0x5b,0xb2,0x3a,0xd7,0xa9,0xff,0x9c,0x1f, + 0xcf,0x84,0x94,0x34,0x29,0xb0,0xca,0xec,0xc7,0x02,0x39,0xb5,0x4d,0x55,0xb8,0x45, + 0xde,0x3c,0x6a,0xe0,0x8a,0xd7,0x51,0xd2,0x24,0x4a,0xb1,0xf5,0x55,0x1a,0xf9,0x72, + 0x89,0xc5,0xa5,0x56,0xbe,0xa2,0x6d,0xc2,0x32,0x82,0xd9,0xb9,0xb0,0x0e,0x1b,0x4a, + 0x46,0x5e,0xd0,0xfc,0x42,0x61,0x9e,0x22,0x09,0x91,0x3a,0xb9,0xb7,0xc7,0x77,0xde, + 0x0f,0x4e,0xe1,0x7c,0xff,0xca,0xfd,0xb2,0xc4,0x79,0xf7,0x13,0xb9,0xa8,0x48,0x0d, + 0xcd,0xb2,0x9b,0x1b,0x19,0x49,0x07,0x0c,0x36,0x52,0xe8,0x8f,0xc2,0x41,0x8b,0x29, + 0x91,0xb8,0x0f,0xa7,0x81,0xf2,0x83,0x88,0xea,0x69,0x85,0x26,0xe9,0xa9,0x47,0xff, + 0xdf,0x54,0xec,0xb8,0xc4,0x89,0x6e,0xb8,0x56,0x3a,0x8c,0x4a,0x7c,0x23,0xd5,0x02, + 0xe0,0xc0,0xae,0xbb,0xce,0xbe,0x00,0x82,0xe0,0xa1,0x59,0xc6,0x66,0x7e,0xb9,0x13, + 0x3a,0x56,0x70,0x89,0xe5,0x41,0xa7,0x43,0x54,0x60,0xec,0xfa,0xd7,0xc8,0xd4,0x2f, + 0xe2,0x91,0xfb,0xe6,0x87,0x13,0x62,0xf5,0x38,0xc0,0x3c,0xda,0x94,0x4b,0x7f,0x2b, + 0xb7,0x68,0x93,0x9b,0x37,0x36,0x77,0x36,0xb2,0xe3,0xad,0x7c,0x0f,0xdb,0x8d,0x6a, + 0xd8,0x31,0x21,0xdb,0xf7,0x9c,0xcb,0x72,0x85,0xd3,0x04,0x2b,0xa2,0x86,0x05,0x1f, + 0x40,0x33,0x14,0x20,0xd9,0x79,0xa8,0xdc,0x91,0xea,0x94,0x3a,0x0b,0xfd,0xd3,0x2a, + 0xb0,0x22,0xac,0xb7,0x2a,0x1a,0x81,0xda,0x90,0x6d,0xdc,0xc0,0xa2,0x3b,0x54,0x5c, + 0xd5,0x7e,0xbd,0x21,0x38,0x1a,0xcf,0xaf,0xe2,0x99,0xb7,0x7b,0x7e,0x37,0xc3,0xbb, + 0x92,0x34,0x1c,0xab,0x11,0x62,0x3b,0x53,0xd8,0xdc,0xdc,0xc8,0x18,0x56,0x77,0x5d, + 0x0b,0x7c,0x71,0x80,0xfc,0x60,0x98,0xe5,0x3a,0x5f,0xd8,0xdc,0x51,0x29,0xc3,0x33, + 0x64,0xb4,0xb8,0xb6,0x23,0xb9,0xf6,0x4d,0x9b,0x63,0x9e,0xe7,0x68,0xdb,0x87,0xac, + 0xc2,0x80,0x8a,0xd7,0x21,0x09,0x2e,0x21,0xb5,0xb3,0x94,0x30,0x96,0x05,0x6f,0xd6, + 0x9c,0x14,0x2b,0x7e,0xcb,0x7c,0xd0,0xd3,0x29,0xb8,0x4d,0x4f,0x9a,0x73,0x71,0x42, + 0x2d,0x97,0x90,0x32,0x69,0x5a,0x56,0xa8,0x96,0xa5,0x9c,0xde,0xbd,0x2e,0xc1,0xab, + 0xdd,0xba,0x82,0x83,0xdd,0x71,0xe9,0x2e,0x1c,0xfc,0x7f,0x8a,0x07,0xb7,0x20,0xf8, + 0x17,0x8a,0x6e,0xb5,0xa2,0xb6,0x50,0x66,0xef,0x97,0xee,0xf7,0x73,0x3a,0xf5,0xc6, + 0x91,0x09,0x65,0x55,0xdc,0xb1,0x99,0xe7,0xc6,0x99,0x81,0x4f,0x1c,0xac,0xa1,0xbd, + 0xe2,0x33,0x24,0xe0,0x45,0x2c,0xb8,0xcc,0x51,0x20,0x1d,0xa6,0xe2,0x73,0xf3,0xa4, + 0xf7,0x28,0x0b,0x21,0x72,0x26,0xe9,0x59,0x23,0x74,0xed,0x8a,0x03,0x7c,0x18,0x4b, + 0x44,0x52,0x84,0xe3,0x8a,0x10,0x9d,0x3a,0xf4,0x3b,0x49,0x24,0xce,0x93,0xc5,0x22, + 0xfe,0x38,0x36,0x57,0xa9,0xf0,0xe7,0x06,0xdf,0x6f,0x9d,0x72,0x39,0xb4,0xcc,0x6f, + 0x55,0x73,0xaa,0xa7,0x4f,0xe7,0xc0,0xa1,0xe2,0xee,0xb7,0xcf,0xaa,0x54,0xc7,0xca, + 0x87,0x2d,0x59,0xb4,0x81,0xeb,0xb5,0x2c,0x50,0x5b,0x0e,0xbd,0x27,0x91,0x72,0x4a, + 0x9b,0xc3,0xf2,0x5a,0x91,0xa2,0xda,0xa0,0xe6,0x95,0xf5,0x4e,0xf7,0xd8,0x5a,0xd5, + 0x97,0x59,0xdb,0xb4,0xbc,0x29,0xc5,0x0c,0x39,0x1b,0x3e,0x22,0xff,0x73,0x9d,0x7e, + 0xdf,0x69,0x5b,0x0c,0x44,0xcd,0x44,0xf5,0xc7,0xad,0x39,0x6f,0x4b,0xce,0x3f,0x3a, + 0xb0,0x52,0xf9,0x9a,0x8f,0x62,0x40,0x78,0x28,0x0b,0x07,0xb6,0x26,0xbf,0xe8,0x43, + 0xab,0xbe,0xb6,0x12,0x16,0xbb,0x24,0x0c,0x54,0x8a,0x63,0x0e,0xe3,0xba,0xfb,0x49, + 0x3e,0x2d,0xe2,0xe4,0xc7,0xb7,0xdf,0x3f,0x2d,0x16,0xa4,0x97,0xe3,0x54,0x29,0x4b, + 0xcf,0x7d,0x77,0x8f,0x8d,0xa8,0x7d,0xa4,0xac,0x7f,0x79,0x38,0xce,0x12,0xa8,0x2a, + 0x7f,0x82,0x96,0x70,0x7f,0x70,0x5f,0x67,0x8d,0x36,0x4e,0x23,0xe5,0x71,0x68,0x3e, + 0x69,0x00,0xbd,0x57,0x7d,0x3f,0x61,0x23,0x15,0x45,0xa0,0xbb,0xef,0x06,0x3c,0x9b, + 0x26,0x4e,0xa5,0x65,0x1c,0xd2,0xeb,0xae,0x9e,0xac,0x66,0x33,0x84,0x31,0x36,0xe6, + 0x34,0x31,0xb2,0x10,0xfd,0xff,0x98,0xe6,0xf5,0x43,0x04,0x85,0xae,0xe8,0xc1,0xda, + 0xca,0xc9,0x11,0x97,0xe0,0x09,0xf8,0x21,0x17,0x26,0xe7,0x93,0x94,0xab,0x72,0x59, + 0xc8,0x57,0x06,0x88,0x90,0xbe,0x7b,0xf7,0xee,0x0d,0x11,0x4c,0x79,0x21,0x41,0x1b, + 0x0e,0xf7,0x16,0x79,0x2e,0xf4,0x13,0x90,0xa9,0x59,0xe2,0xa4,0x7e,0xc6,0xd9,0xbc, + 0x89,0xe8,0x62,0x4b,0xc4,0x33,0x56,0xcb,0xe6,0x2b,0x05,0xa8,0xc4,0x16,0xc9,0x71, + 0x48,0xf6,0x09,0xd3,0x8c,0x58,0x69,0x45,0xc6,0x69,0x12,0x37,0x09,0x1a,0x81,0xf3, + 0x5d,0x92,0xb1,0x62,0xda,0x5b,0xe5,0xcc,0x61,0x20,0x53,0xb5,0x2d,0xcf,0x1a,0x8c, + 0x3a,0xe4,0x30,0x4f,0xcc,0x51,0x14,0x0f,0xec,0xbb,0x71,0x07,0x10,0x95,0x16,0xc1, + 0x8e,0x3e,0x9c,0xf6,0xb7,0xe5,0x46,0xa2,0xfd,0x20,0x23,0x1b,0xf3,0xf9,0x1d,0xa9, + 0x5f,0x2d,0xb5,0xa7,0x75,0x1c,0x6e,0x53,0xe9,0xc1,0x5c,0x5f,0xcc,0x50,0x36,0xa6, + 0xb7,0x9d,0x3c,0x64,0xcc,0x60,0x56,0x7b,0xd5,0x69,0x27,0xb9,0x33,0x9d,0x47,0x69, + 0x1e,0x2a,0xf3,0x19,0x66,0x64,0x91,0x5d,0x18,0x61,0x21,0x13,0xdd,0x3e,0x0a,0x05, + 0x92,0x48,0x0d,0x5a,0x4a,0x17,0xfc,0xb7,0x7b,0x64,0x63,0x57,0x5a,0x6b,0x53,0x87, + 0x26,0x7a,0xe9,0xfe,0x90,0xa8,0xe2,0xa0,0xcd,0x31,0x3a,0x72,0x64,0x2d,0xd4,0xec, + 0x26,0x51,0x97,0xd4,0x7a,0x77,0x73,0xe9,0x74,0xcf,0x9a,0x83,0x40,0x1f,0xf7,0x36, + 0x69,0x43,0x51,0x02,0x2c,0x03,0x75,0xae,0x48,0x89,0x27,0x6b,0x74,0xc9,0xbc,0xaf, + 0xde,0x37,0x6d,0xdd,0xd3,0x90,0xfe,0xda,0x2d,0x3e,0x3d,0x43,0x68,0x8d,0x76,0x8f, + 0x5b,0x69,0x5e,0xbf,0x55,0x9b,0xb3,0xa5,0x3b,0xad,0x51,0xb9,0x8b,0xd3,0xf0,0xb7, + 0xca,0xee,0x65,0x3b,0xd4,0x6b,0x33,0x6a,0xe7,0x93,0x3b,0x63,0x7d,0xd7,0x68,0xc6, + 0xe8,0x73,0x73,0x03,0xcf,0x39,0x19,0x59,0x72,0x89,0x62,0x23,0x27,0x57,0xf9,0xf4, + 0x0e,0x19,0x19,0xfa,0x6d,0xd7,0x33,0x83,0x6f,0x31,0x19,0x6c,0xad,0x32,0xc4,0x1c, + 0xa5,0x55,0x39,0xaa,0x0b,0xb7,0x15,0x3c,0xa7,0x9b,0x4b,0xe8,0x07,0xad,0x51,0x7a, + 0xbc,0x58,0xff,0x3a,0x23,0xb9,0x93,0x8d,0xbe,0x6e,0x87,0xdb,0x27,0x64,0xbe,0x87, + 0x8d,0x1d,0x2f,0x1d,0x9c,0xfa,0xd7,0x98,0xef,0xc8,0x45,0xc2,0x17,0x62,0x92,0x34, + 0xbf,0x03,0xd0,0x4e,0xfb,0xdd,0xe8,0xb6,0xc3,0xfe,0x6e,0xd4,0x4c,0x2b,0x0a,0xb8, + 0x92,0xc1,0x8f,0x6f,0x5f,0xaa,0x46,0xf2,0xb9,0x25,0xba,0xee,0x61,0x6c,0xab,0x9d, + 0xe6,0x0e,0xa1,0x6b,0x15,0x2f,0xe8,0x03,0xbd,0xb1,0x12,0xb7,0xf1,0x6d,0xa8,0x31, + 0x61,0x66,0xb4,0x52,0x17,0x23,0xab,0x33,0xe6,0x21,0x3d,0xeb,0x86,0xd2,0xae,0x9a, + 0x74,0x87,0xce,0x0f,0xe4,0x60,0x9a,0xc4,0xee,0x8a,0x73,0x6b,0x9a,0xb2,0x02,0x6f, + 0xed,0x1f,0x36,0x47,0x95,0x6e,0xb3,0x43,0x5a,0xec,0xa4,0x65,0x87,0x6c,0xa6,0x3d, + 0x1a,0xfa,0xd5,0xcb,0x4e,0xe2,0xff,0x0b,0x11,0xbf,0x95,0x9a,0xb1,0xbe,0x25,0xa7, + 0x52,0xfb,0xed,0x36,0xa7,0xfd,0xa9,0x49,0x6f,0x4f,0x99,0x5d,0x51,0xc9,0xde,0x5e, + 0x12,0x90,0x2e,0x55,0x45,0x67,0x09,0x9c,0x51,0xc0,0xce,0x5b,0x7c,0x51,0xeb,0x2d, + 0x55,0x00,0xc9,0xaa,0x4c,0xb8,0x92,0xad,0x5a,0xe7,0xe6,0x3c,0xea,0xa6,0xbe,0xb3, + 0xab,0x13,0x74,0x76,0xdb,0xea,0x89,0xf6,0x58,0xd2,0xbb,0xfe,0xa7,0xac,0xd3,0xcf, + 0xa9,0x0d,0x8d,0xd5,0x2a,0x5e,0x98,0x3f,0x90,0xb8,0x73,0xab,0x71,0x2a,0xf6,0x5a, + 0x71,0x7e,0xac,0x0c,0x6e,0xb3,0xa7,0xde,0xe8,0x56,0x3b,0xce,0xf3,0xf9,0x8d,0xae, + 0xb3,0x95,0x96,0x95,0x64,0xbc,0x4c,0xfc,0xc9,0x27,0xa9,0x72,0xcb,0x36,0x4f,0x31, + 0x13,0xd7,0x0d,0x0b,0x7d,0x4e,0x35,0xf8,0x97,0xe1,0x83,0xc1,0x82,0x9e,0x46,0x9c, + 0x15,0xd5,0x6d,0xeb,0x7c,0x63,0xd9,0x3a,0xb7,0xa4,0xb0,0xdc,0x6e,0x6d,0x76,0x79, + 0xf8,0x6c,0x07,0x5f,0xab,0xbc,0xa4,0xf3,0xff,0xa3,0x73,0x4f,0x2a,0xbb,0x39,0xd7, + 0xb3,0x11,0x24,0xc9,0x0d,0x27,0x56,0xb0,0x81,0x40,0x86,0x65,0x3d,0x72,0xcf,0x92, + 0xda,0xbd,0x71,0xa1,0x9a,0xd0,0x3f,0xab,0x25,0xfd,0x91,0x92,0x20,0x37,0xd8,0xa4, + 0x1b,0x17,0x20,0x21,0xcd,0x79,0x39,0xad,0x7d,0x87,0xa0,0x22,0x65,0x4a,0xb8,0x4b, + 0x0e,0x3f,0x60,0x80,0x9f,0xa4,0x94,0x86,0xe8,0x63,0xa6,0x68,0x0c,0xd7,0x2a,0xa0, + 0xbd,0x12,0xe5,0x0d,0xe5,0x53,0x59,0x47,0x95,0x82,0x84,0xf0,0xa1,0x55,0x72,0xbc, + 0x88,0x0f,0x90,0xc1,0xa4,0x99,0xb0,0x67,0xac,0xe4,0x53,0x53,0xb1,0xe4,0x90,0x44, + 0x50,0x34,0xab,0x22,0xb7,0x5d,0x77,0x50,0xd4,0x92,0xc0,0xf9,0x49,0x99,0x3e,0x92, + 0x10,0x4b,0x22,0x64,0x46,0xfc,0x76,0x25,0x79,0x78,0x5c,0x92,0x8d,0x4f,0xed,0x15, + 0x52,0x15,0x84,0x33,0x76,0xc4,0xad,0xf7,0xe6,0xc7,0x77,0xa8,0x89,0x21,0x73,0x23, + 0x0d,0x98,0xb3,0x41,0x7c,0xa7,0xf1,0x86,0xcb,0xa1,0x2f,0x63,0x79,0xc9,0xc6,0xca, + 0xcc,0xf0,0x35,0x9e,0xca,0xd9,0xed,0x32,0x43,0x77,0xb5,0xe1,0x7d,0x59,0xc8,0xb9, + 0xae,0x0c,0x67,0x69,0xd5,0xb1,0xa2,0xc0,0x79,0x5c,0x55,0x38,0x79,0x76,0x25,0x69, + 0x86,0x52,0xb9,0x24,0x52,0x19,0xbc,0x4e,0x93,0xca,0x2c,0x67,0x06,0x39,0xed,0xf7, + 0x12,0xda,0x14,0x03,0xdb,0xa4,0xe3,0x8a,0xc6,0xa6,0xcf,0x5e,0x72,0x69,0x3a,0xe4, + 0xfc,0x57,0xfa,0xd8,0x9a,0xaf,0x42,0x27,0x92,0xaf,0x53,0x70,0x76,0x52,0xc0,0x6d, + 0xe5,0x54,0x9b,0x49,0xe8,0x40,0xae,0x87,0x9c,0xe1,0x65,0xbf,0x26,0x6b,0xf5,0x5c, + 0x6c,0x91,0xc3,0xa0,0x02,0x7a,0x93,0xec,0x2d,0x93,0x20,0xb9,0xf3,0x04,0x9d,0x6c, + 0x1e,0x78,0xc2,0x2c,0xf8,0x81,0x4e,0x82,0xe1,0x44,0xd3,0xbd,0xbd,0x3b,0xfa,0x05, + 0xef,0x0b,0x82,0x2c,0xa6,0x73,0x5c,0x6e,0x5b,0xef,0x2a,0x34,0x00,0xbe,0x89,0xae, + 0x4d,0xcf,0xe6,0xbd,0x1e,0x67,0xc7,0x34,0xf3,0xe3,0x54,0x02,0xcc,0xfa,0xe4,0xdd, + 0xe3,0x77,0xcf,0x7f,0x7d,0xf9,0xf8,0xc9,0xf3,0x97,0xe1,0x35,0xbe,0x8a,0xe8,0x32, + 0xf3,0x24,0x95,0x82,0xe3,0x43,0x40,0xfa,0x91,0xab,0x72,0x87,0x90,0x54,0x32,0x72, + 0xcd,0x51,0x3e,0xd7,0xdf,0x30,0x28,0xa1,0x07,0x24,0xe5,0xc8,0xe5,0x8c,0xcc,0x2b, + 0xdd,0x05,0xd3,0xca,0xc8,0xd5,0x89,0xf8,0x7c,0xaf,0x38,0x1f,0xb9,0x7f,0xf9,0x5f, + 0xff,0x2e,0xe7,0x1c,0x7d,0xa0,0x13,0xae,0xff,0xa7,0xe6,0x2e,0x2d,0x11,0x51,0x26, + 0x38,0x9e,0xf5,0x8f,0xa2,0x4e,0x7d,0x78,0x9e,0x99,0x1c,0x21,0x26,0x31,0xcb,0x95, + 0xf0,0xa1,0xe3,0xc4,0x93,0xb4,0xd9,0xd2,0xae,0xd3,0xda,0x52,0xd8,0xad,0xf3,0x48, + 0x38,0x77,0x04,0x6f,0x2b,0xae,0xe3,0xf4,0x82,0x6e,0xa0,0x5e,0xac,0x31,0xca,0x8b, + 0xcb,0xdb,0x8e,0xc7,0x7c,0xa0,0x3f,0x69,0x2d,0x67,0x53,0xbe,0xa0,0x75,0xc5,0x6a, + 0x79,0x1d,0xf0,0xb7,0x10,0x01,0x2f,0xb2,0xb9,0x91,0xa7,0xc3,0xb7,0x3c,0x0d,0x57, + 0xd3,0x80,0x1e,0x91,0x08,0x69,0xce,0x50,0xca,0xcb,0xc4,0x70,0x6e,0x6e,0x06,0xa4, + 0xd9,0xff,0xbd,0xeb,0x8d,0xac,0x7d,0x7c,0xcf,0xef,0x9d,0x7a,0x4d,0xfc,0xdc,0x9e, + 0x06,0xdc,0xc5,0x26,0x6e,0x6e,0x8f,0xd0,0x72,0x39,0x4f,0x6c,0x10,0x4c,0xa2,0x12, + 0x55,0x88,0xe4,0x58,0x15,0x03,0x69,0x3c,0x0b,0xb8,0x62,0x62,0x20,0x9f,0xca,0xdb, + 0x98,0x8d,0xd1,0x80,0x5a,0x03,0xcf,0xb6,0x8e,0xc6,0x4c,0x2c,0xef,0x74,0x7b,0x3a, + 0xcc,0x52,0xf7,0xf6,0xe8,0x9a,0x18,0xaa,0xd7,0x71,0x92,0x47,0xcd,0x8c,0x85,0x90, + 0x6a,0xa5,0x3a,0xfb,0xd0,0x7d,0x80,0x45,0xa8,0x84,0x53,0xe6,0xe5,0xd8,0x24,0xe0, + 0x88,0x72,0x3f,0xbd,0x38,0xa9,0xce,0xeb,0x62,0xe9,0x71,0x69,0xd6,0x26,0x60,0xc3, + 0x65,0x7f,0x32,0xfd,0xfd,0x3d,0x58,0xbc,0x81,0xc9,0xd4,0xff,0xb0,0xe9,0xdb,0xeb, + 0xb9,0x52,0xab,0xd7,0x35,0xf5,0x1f,0xe4,0x7c,0x6e,0x19,0x46,0x2a,0x8b,0xf4,0x35, + 0x29,0x1d,0xd6,0x4f,0xbf,0x08,0xcb,0x40,0x3e,0xfc,0xf5,0xae,0x58,0xf6,0xd1,0xa1, + 0xb9,0x6a,0xd2,0xd1,0x1f,0xe1,0xbe,0x4c,0x97,0xee,0xdf,0xdc,0x14,0xfb,0xfa,0xa5, + 0xef,0xb8,0x80,0xe8,0x51,0xeb,0xf9,0x3e,0xae,0x48,0xd1,0xa5,0x21,0xe4,0xb1,0x36, + 0x21,0x5a,0xad,0xc2,0xa2,0xbf,0xd9,0xee,0xe0,0x90,0xd9,0x41,0xe3,0x9f,0x49,0xf3, + 0xb4,0x9a,0x2b,0xbe,0xc1,0xc7,0x1d,0x0c,0x0b,0x6b,0x42,0x99,0x9c,0x7f,0x7f,0x1e, + 0x0e,0x98,0x7a,0xd5,0x41,0x87,0xdb,0x89,0xcd,0xde,0x5c,0x12,0x9a,0x5e,0x71,0xbe, + 0xbf,0x3f,0xd6,0x3c,0xab,0xbd,0xed,0x1e,0xfe,0xee,0xef,0xaf,0x35,0x28,0xb9,0xff, + 0x10,0x21,0x11,0xe8,0x21,0xf4,0xa2,0xcb,0xfb,0x43,0x34,0x40,0xc3,0xb7,0xbd,0xd5, + 0xa9,0xae,0x3a,0x28,0x11,0x55,0x8e,0x9b,0x62,0x90,0xe6,0x4d,0xd3,0x02,0x7e,0x6b, + 0x1e,0xc8,0x6d,0xab,0x34,0xfc,0x8e,0xae,0xfe,0xb5,0xc1,0x6a,0x50,0x82,0xa8,0xbd, + 0x2c,0xa5,0x0a,0x76,0xe0,0xed,0x4c,0xa5,0x06,0x74,0x2a,0x5a,0x5b,0x3e,0x1b,0x25, + 0xca,0x27,0xb0,0x88,0xa0,0x27,0xa8,0x4f,0x11,0xa9,0x10,0x9a,0xa4,0xc5,0x93,0xe6, + 0xf0,0x53,0x32,0x39,0x11,0x3f,0x0e,0x59,0x74,0xe7,0x49,0x25,0x27,0x57,0x59,0xf2, + 0x92,0x0c,0x8f,0x55,0x2e,0x6d,0xd1,0xe7,0x03,0xf7,0xa6,0x00,0x46,0xef,0x5f,0x86, + 0x40,0xe1,0xe1,0xa1,0x13,0x23,0x4d,0x9e,0x73,0xee,0xb9,0xf8,0xc5,0x3c,0x89,0xb2, + 0x7a,0x7e,0xe5,0x05,0x0e,0xce,0xa6,0x90,0x66,0xc0,0xa2,0x57,0x0e,0x8b,0xe0,0xc3, + 0xa0,0x72,0x34,0x19,0xfb,0x3e,0x32,0xd5,0xed,0xb9,0xd4,0x6a,0xa9,0xb5,0x0f,0x71, + 0xa2,0xb3,0xfe,0xa1,0x95,0x01,0x1c,0x3d,0x26,0x65,0xa5,0x2c,0xf9,0x0c,0x3f,0x1c, + 0x4c,0x8f,0xa5,0x6c,0x81,0x28,0x04,0x3d,0xa5,0xb9,0xae,0x2a,0x89,0x08,0xb2,0xc6, + 0x13,0x37,0x54,0x87,0x92,0xcf,0xd1,0x95,0xa7,0x14,0x90,0xcb,0x42,0xd4,0x0a,0xd6, + 0x11,0xc6,0xa2,0xec,0x64,0xac,0x89,0xa8,0xc0,0x20,0xd0,0x55,0xc2,0x7f,0x5a,0x91, + 0xb0,0x04,0xc7,0x2a,0xff,0xc7,0x9e,0xb8,0x50,0xf8,0x80,0x7b,0x2f,0x7d,0x64,0x8b, + 0x0c,0x6c,0x13,0x5d,0x21,0x1d,0xaf,0xaa,0x61,0x7a,0xb3,0x82,0xb7,0x75,0x57,0x55, + 0x7f,0x4b,0xa5,0xe0,0x0b,0xb0,0xf5,0x28,0xb4,0xbb,0xf1,0xae,0x5b,0xe4,0x62,0x25, + 0xdd,0x8b,0x1a,0x18,0xea,0xfe,0x34,0xd1,0xa4,0x15,0xb2,0x12,0x8c,0x73,0x49,0xa7, + 0x17,0xfe,0x16,0xa6,0xfb,0xc3,0xf1,0x6f,0xad,0x29,0x8e,0x7f,0xdb,0xdf,0xf7,0x34, + 0x37,0xe8,0x49,0x47,0xbf,0x9d,0x2a,0x5c,0x13,0x7d,0xf4,0x66,0xe3,0xae,0x9a,0x2e, + 0xa9,0x17,0x07,0xbf,0x40,0x83,0xfc,0xbb,0x83,0x34,0xa8,0x11,0x36,0x34,0xed,0x44, + 0x46,0xa9,0x59,0x18,0xf3,0x4e,0x50,0x18,0x72,0x60,0x2c,0xcc,0x9c,0x48,0xda,0x48, + 0x5e,0x0e,0x1c,0x7e,0x2e,0xc5,0x03,0xe7,0xca,0xa3,0x4b,0x68,0x8f,0x52,0x66,0x44, + 0x4a,0xad,0x46,0x65,0x3d,0x6a,0x67,0x8f,0x9b,0xfb,0x0e,0x2b,0x93,0xa5,0xfe,0x48, + 0x07,0x50,0x9a,0x36,0xb0,0x96,0xae,0x60,0xba,0x04,0x9c,0xe9,0xc8,0x25,0x1c,0x35, + 0x76,0x89,0x9a,0x46,0x4d,0xcf,0x54,0xba,0x35,0xaa,0x0b,0x48,0x0d,0x63,0xc2,0x0f, + 0xa8,0x73,0xe1,0x90,0x9e,0xa4,0x67,0x67,0xa8,0xf3,0xb2,0x11,0x16,0x70,0x51,0x8e, + 0x26,0x3f,0xcb,0xf8,0x2c,0x4c,0xbf,0x98,0xf5,0xa5,0x37,0x89,0x38,0x05,0xdc,0x52, + 0xcb,0x08,0x56,0xb9,0x51,0x0b,0x8f,0x31,0x59,0x74,0x71,0xd6,0xa1,0xb9,0x36,0x19, + 0xb2,0xcc,0xab,0x94,0x63,0xf3,0x4d,0xdc,0x5a,0xa8,0x14,0xc5,0x64,0x4d,0xd6,0xa5, + 0xf4,0xb6,0xa1,0xde,0x37,0x45,0xc6,0x2d,0x92,0x81,0x76,0xcf,0xab,0x92,0x92,0xc9, + 0x52,0x44,0x86,0xf3,0x36,0xb1,0x6d,0x24,0xa8,0x88,0xd2,0xa5,0x37,0x24,0x1f,0xb4, + 0xeb,0xf8,0xf5,0x94,0xad,0x60,0x12,0xb9,0xab,0x4b,0xfe,0x02,0x4d,0x03,0x30,0x39, + 0xe4,0xa3,0xc6,0xf1,0x02,0x83,0x88,0x6f,0x66,0x55,0xb8,0x85,0x26,0xcd,0xd1,0x5d, + 0x20,0x3b,0xda,0x10,0x32,0x69,0x0d,0x5b,0x07,0x43,0x04,0x5b,0x98,0xdd,0x35,0xf8, + 0xa2,0x1f,0x11,0x1f,0x0d,0xdd,0xb6,0xa9,0xa3,0x2a,0x8d,0x70,0x46,0x14,0x4f,0xb6, + 0xe1,0x6c,0xb4,0xf2,0x24,0x4e,0xd5,0x29,0x3b,0x65,0xac,0x24,0xd9,0x0c,0xaf,0xb8, + 0xda,0xc7,0xa6,0xf1,0xb0,0xdb,0x4b,0x23,0x84,0xbe,0x3f,0xf4,0xd6,0xfe,0x3d,0xd4, + 0x6e,0x69,0x07,0x4f,0x36,0x12,0x8f,0x78,0x45,0xc7,0x6e,0x63,0xf4,0x90,0xf4,0xe8, + 0xc8,0x45,0xfa,0x6c,0x26,0xd2,0x06,0xa0,0xee,0x70,0xbf,0xde,0x67,0x73,0x91,0x84, + 0xee,0x8e,0xdd,0x21,0x0d,0x3b,0x70,0x35,0xe1,0xe8,0x24,0x3b,0x75,0x70,0x62,0xd0, + 0xff,0x76,0xf0,0xf7,0x81,0xb3,0x8b,0xf2,0xf9,0x7c,0xde,0x01,0x1c,0xb2,0x50,0x75, + 0x17,0x6a,0x29,0xf8,0x99,0xca,0x41,0xbf,0x5d,0x23,0xd1,0x76,0x47,0xd2,0x97,0x39, + 0x75,0x31,0xa4,0x97,0xd3,0x6a,0xe3,0xe8,0xc6,0x65,0xae,0xbf,0x9c,0xc2,0x6e,0xbc, + 0x40,0x2d,0x55,0x74,0xcb,0xa0,0xc8,0x75,0x91,0xa3,0x70,0xcb,0x55,0x84,0x45,0x26, + 0x8a,0x31,0xc1,0x77,0xb2,0x62,0x52,0x68,0x05,0xb7,0x14,0x26,0x58,0x65,0x0d,0x92, + 0x40,0x7c,0x59,0x07,0x49,0xc0,0x61,0xb2,0xaf,0xbe,0x1d,0x34,0xda,0xa7,0x7e,0x48, + 0x7c,0x4b,0x3d,0xf6,0x14,0x62,0x41,0x23,0xde,0xdc,0x7b,0x9d,0xe0,0xcd,0x87,0x03, + 0x11,0xe1,0xb1,0x3d,0x14,0x5f,0x82,0x17,0xe6,0x6d,0x88,0xa3,0xb7,0x90,0x46,0x5b, + 0x49,0x60,0x34,0x3c,0x4b,0x11,0xd6,0x68,0xf9,0x17,0xeb,0xb4,0xc3,0xd6,0xf2,0x06, + 0xb6,0xfa,0xcc,0x8d,0x1e,0x85,0x87,0xa4,0xe2,0xc8,0xd4,0x85,0x01,0x8f,0x5b,0xf3, + 0xbe,0xdd,0xc1,0xa8,0x64,0xd4,0x5a,0x14,0x03,0xfb,0xc0,0xd6,0x26,0x89,0x31,0x51, + 0x75,0x86,0x77,0xad,0xb1,0x72,0xfe,0x72,0xb6,0x01,0xd5,0x27,0xd2,0xdd,0xfe,0xaa, + 0x64,0x37,0x3b,0xd5,0x4d,0xcd,0x93,0xd4,0x2d,0xcd,0x08,0x08,0x6b,0xb7,0xa6,0x24, + 0xef,0x69,0x85,0xcf,0xca,0x5e,0xbb,0xee,0x5a,0xa7,0x7a,0xf8,0xa9,0x5e,0xcc,0x1e, + 0x6e,0x2d,0x57,0x72,0xda,0xcc,0xf3,0x86,0x98,0x09,0x1d,0xa1,0x98,0x6d,0x1d,0xd9, + 0x34,0x65,0xda,0xa7,0xe7,0xc4,0x4c,0xe1,0x5c,0xfe,0x4f,0x3d,0xb3,0xb9,0xd3,0x08, + 0x20,0xd4,0x20,0xc9,0x9b,0x33,0x44,0xf0,0xac,0x16,0x33,0x49,0xae,0xda,0x97,0xf2, + 0xe2,0xcc,0x41,0x2f,0x55,0x3a,0x94,0x55,0x08,0xea,0x59,0x32,0xe5,0x4a,0xab,0xc9, + 0x47,0x78,0x64,0x98,0x87,0x54,0x28,0xc6,0xd4,0x3a,0xd5,0x29,0x8a,0x53,0x95,0xa8, + 0x34,0xb5,0xa8,0x24,0xbb,0xff,0x22,0x19,0xa9,0xa2,0x68,0xf4,0x2a,0x73,0x1e,0x3e, + 0xab,0x99,0x94,0x8d,0x0c,0x5e,0x24,0xa8,0x2b,0x56,0x39,0x08,0x19,0x37,0x11,0x42, + 0x5d,0x1e,0x88,0x58,0x3c,0xdd,0x66,0x21,0xdf,0x57,0xd5,0x30,0xf8,0x38,0x29,0x87, + 0x17,0x39,0x10,0xa1,0xca,0xfa,0x9b,0x9a,0xce,0x3a,0xaf,0x43,0x4e,0x30,0x3c,0x7d, + 0xf6,0xda,0x33,0x07,0x48,0xc1,0xea,0x2a,0xf9,0x56,0xc7,0xcb,0xc7,0xaf,0x45,0xe7, + 0xcc,0x59,0x27,0xd4,0x1f,0x1b,0x17,0x29,0x9a,0x36,0xc9,0x1e,0x12,0xc2,0x8c,0x75, + 0xdd,0x44,0xc0,0xcc,0xa4,0x9f,0x09,0x77,0x5d,0x2d,0xc5,0x61,0xf3,0xf3,0xf7,0x6f, + 0x7e,0x7d,0xf5,0xf8,0xcf,0xbf,0x3e,0xf9,0xa7,0x77,0xcf,0x4f,0xc2,0x87,0x5f,0xa1, + 0xa6,0xcb,0x57,0x52,0xd8,0xa5,0x5d,0xae,0x46,0xc7,0xfc,0x94,0xf3,0xa6,0x15,0xca, + 0xd1,0xe1,0xe1,0xce,0xe8,0x9e,0x15,0xbf,0xdd,0xf2,0xeb,0x50,0x43,0x9f,0x74,0xd8, + 0x56,0x5d,0xb4,0xdb,0xe2,0x27,0x52,0x96,0x59,0xbb,0x21,0xc8,0x10,0x29,0xa7,0xa1, + 0x6b,0x45,0xc5,0x25,0xbe,0xf3,0x5b,0xa5,0x8b,0xbc,0x74,0x10,0x7d,0x89,0xbc,0x8b, + 0x75,0xf3,0x7c,0x2b,0xf3,0x93,0xe6,0xd2,0xeb,0x0c,0x64,0x9b,0x43,0x61,0xab,0xdc, + 0x0a,0x3c,0xb9,0x9e,0xee,0xcd,0x4c,0x1a,0x6a,0x58,0xbb,0xa2,0xc9,0xc6,0x19,0xe9, + 0x9f,0x80,0xa7,0x6c,0x40,0x14,0xba,0x80,0xb6,0xec,0x3d,0x1f,0xb1,0x62,0xf5,0x9f, + 0x95,0x3d,0xe0,0x34,0xeb,0x2b,0xc8,0x66,0x84,0xbe,0x23,0x19,0x12,0x97,0xfc,0x3d, + 0xaa,0x91,0x13,0xb1,0x95,0x52,0x16,0x4b,0x5f,0xf6,0xd7,0x57,0x65,0xac,0x82,0xd6, + 0x29,0x3a,0xfd,0x91,0x38,0xa2,0x23,0x92,0x7b,0xed,0x1c,0x6a,0x32,0x42,0x88,0xba, + 0xe4,0x10,0x25,0x23,0xa6,0xf8,0x5a,0xe1,0x26,0x34,0x35,0x3a,0x1b,0x6d,0x2f,0xd0, + 0x87,0x9b,0x23,0x52,0xe2,0x84,0xea,0xf4,0x87,0x90,0xd0,0x88,0x7a,0x87,0xfe,0x82, + 0x96,0x52,0x97,0x6f,0x55,0x4e,0x13,0x5d,0x69,0x4f,0xa5,0x64,0x42,0x59,0x24,0x4d, + 0xb2,0x95,0x36,0x29,0x47,0xf5,0x41,0x1c,0x52,0x0b,0xd1,0xce,0x56,0x54,0x42,0x1d, + 0x7d,0xf6,0x8c,0xd3,0xf0,0xe0,0x9f,0xad,0x79,0xfc,0xc2,0x13,0x31,0x6a,0x5b,0xee, + 0xdd,0xdc,0x40,0x93,0xa3,0x06,0x5b,0x4f,0xbc,0x76,0x09,0x28,0x83,0x96,0xd4,0x1e, + 0xc1,0xdb,0x1b,0x34,0xbf,0x21,0x00,0x78,0xed,0xde,0xfe,0x59,0x41,0xf3,0x17,0x80, + 0xd3,0x7a,0xa4,0x8b,0x5f,0x08,0x42,0xf3,0xdc,0x23,0xe8,0xae,0x35,0x6b,0xeb,0xef, + 0x4f,0x47,0x4c,0x73,0x9a,0x49,0x68,0x2e,0xe2,0x23,0x8b,0xae,0xd2,0xb9,0xb0,0xc8, + 0x80,0x4d,0x54,0xfe,0x2a,0x1f,0x96,0x44,0xf9,0xb9,0x0c,0x4a,0x3c,0x3e,0xe3,0x91, + 0x45,0xcb,0x8a,0xdd,0xb3,0xf8,0xe8,0x16,0xe7,0xe9,0x48,0x01,0xba,0xa2,0x96,0xb7, + 0x49,0xbf,0x8e,0x80,0x0c,0x3d,0x95,0x2a,0xfa,0x2b,0x91,0xf1,0xd3,0x1f,0x4e,0xfe, + 0x7c,0x10,0xfc,0xfa,0x95,0xf3,0xdb,0x2a,0xc7,0xd1,0xfb,0x57,0xd1,0xb4,0xcf,0xe9, + 0xb3,0x98,0x0c,0x94,0x78,0x12,0xd3,0x64,0xe8,0x9e,0x2c,0x33,0xae,0x36,0xe6,0x3c, + 0xf9,0xe1,0xdd,0x77,0xc4,0xfa,0x48,0xe0,0x45,0xb4,0xdb,0xd5,0x48,0xea,0x79,0x5c, + 0x26,0xe5,0x09,0x29,0x9f,0x19,0xed,0x29,0x54,0x1c,0x28,0x42,0xfd,0xc7,0xc2,0x16, + 0xf5,0x39,0x87,0xdd,0x5f,0x90,0x26,0x4b,0x16,0x04,0x0a,0x81,0xc9,0xe4,0xa8,0xbb, + 0x9f,0x98,0x27,0xd8,0xd6,0xa7,0x2c,0x5c,0x8e,0x52,0x60,0xda,0xc8,0xe9,0x32,0xa9, + 0x0b,0x08,0xd5,0x84,0x9c,0xcd,0x11,0x90,0xc2,0x45,0xaa,0xcf,0xd5,0x32,0x91,0x42, + 0x4a,0x72,0xd0,0x4a,0xbf,0xc0,0x75,0x25,0xb4,0x86,0xc9,0x19,0xad,0x6d,0x1f,0xc4, + 0xcc,0xb8,0x20,0x68,0x33,0x69,0xa5,0x66,0x9b,0x66,0xaa,0x4c,0x8e,0xe7,0xd9,0x51, + 0xea,0x4d,0x26,0xc5,0x3d,0xd2,0x58,0xc4,0x46,0xba,0xfa,0xb4,0xb1,0xb0,0xe9,0x90, + 0x8d,0x41,0x0e,0x09,0xad,0x72,0x2b,0xd9,0x00,0x7e,0xdd,0x56,0xad,0x94,0x2f,0x4a, + 0x96,0x90,0x82,0xd4,0x3e,0xc9,0xa0,0x3c,0xbc,0x5e,0xfb,0x92,0x28,0x36,0x68,0x52, + 0x27,0x70,0xea,0x22,0xb4,0xa7,0xc6,0xb9,0x1d,0xd4,0xfa,0xbd,0x4c,0xe8,0x14,0xba, + 0x5f,0x73,0x15,0x0e,0xc7,0xa6,0x2e,0xf5,0xcc,0x5b,0x7f,0x69,0x0e,0x86,0xc0,0x61, + 0xd3,0x6f,0x35,0x6b,0x05,0xf0,0xbb,0x01,0x2c,0x9e,0xad,0x6d,0x38,0x79,0x6a,0x0a, + 0x1b,0x67,0xf0,0x3f,0x95,0xc6,0xa1,0xa9,0xb4,0x9d,0x14,0xb4,0x15,0x5d,0x9c,0xac, + 0x66,0x1b,0x35,0xb0,0x98,0x2f,0x5b,0x71,0x7e,0xbe,0xe6,0x48,0xff,0x66,0xe2,0x10, + 0xbd,0x6a,0xa5,0x46,0x48,0x48,0x3b,0x38,0x4f,0xae,0xaa,0x9e,0xee,0xa3,0x23,0x2d, + 0xd1,0xd4,0x4c,0x68,0xd5,0x2d,0x22,0xca,0x0c,0xf1,0x24,0xa8,0x40,0x51,0xbd,0x83, + 0xf7,0xbf,0xfc,0x72,0x70,0x7a,0xe0,0x05,0xcb,0x62,0xd9,0x6b,0x25,0x74,0x00,0x76, + 0x68,0x7d,0x73,0x83,0xbf,0x01,0xad,0xbd,0x7c,0x5c,0xf7,0xf8,0xa8,0xbd,0x1b,0xb8, + 0x37,0x37,0x77,0x6c,0xe8,0xa1,0x49,0x3b,0x5f,0x4e,0xa5,0x40,0x70,0x8a,0x5d,0xa8, + 0x67,0xf9,0x9e,0x37,0xdb,0x72,0xfd,0x5b,0x83,0x49,0xd6,0x5e,0x4b,0xb6,0x7b,0xad, + 0x38,0x45,0x67,0x3a,0x05,0x3c,0x9c,0x30,0xe5,0x39,0x3a,0x46,0x3a,0x97,0xbb,0xdf, + 0x6b,0x75,0x71,0x74,0x74,0x08,0xdf,0x36,0x0a,0xb3,0x91,0x06,0xb6,0x79,0x6c,0x45, + 0x15,0x58,0xc0,0x96,0xa3,0x5f,0x4e,0x47,0x79,0xdf,0x9e,0xec,0xa9,0x2f,0x6b,0xfb, + 0xab,0x73,0x4a,0x9a,0xca,0xea,0xeb,0x0d,0xf1,0xfa,0x9c,0xa5,0xa4,0x30,0x26,0x55, + 0xe9,0xa3,0x68,0xe2,0x73,0x22,0x78,0xf5,0xd9,0x74,0x56,0xe8,0x38,0xcc,0x88,0xd5, + 0x73,0xb9,0x47,0xd0,0xb2,0xf0,0x64,0x7d,0xfa,0x9d,0x8b,0x32,0x3a,0xfc,0x05,0x36, + 0xce,0x1d,0x83,0x5f,0x6f,0x21,0xe5,0xd4,0xed,0xf2,0x1a,0xe6,0xc4,0x58,0x8b,0xcd, + 0x31,0xa1,0xb6,0xaa,0x31,0x5a,0xfb,0x0a,0xe3,0xcf,0xc4,0xa8,0x98,0x97,0x58,0x5f, + 0x18,0x48,0x1b,0x71,0xcd,0xfe,0x81,0x38,0x56,0x25,0xf5,0x75,0xc5,0x5e,0x48,0x4e, + 0x71,0xba,0x35,0x6e,0x5b,0x8b,0xd0,0x3a,0x39,0xef,0x06,0x1c,0xe5,0x30,0x5b,0x63, + 0xd8,0xb6,0xce,0xc0,0xe9,0x53,0x30,0xb5,0xae,0x0d,0xa2,0x67,0xa6,0x4e,0xe6,0x43, + 0x01,0xf7,0x95,0xfe,0x5d,0x94,0x26,0x50,0xcb,0x1a,0x81,0x9c,0xd9,0xdb,0x9a,0x93, + 0x2a,0xd3,0xa4,0x9c,0xe8,0xea,0x24,0xdd,0x2d,0x89,0x19,0x9d,0x59,0x15,0x5b,0x35, + 0xae,0x68,0x2c,0x4e,0x5f,0x53,0x5e,0x6b,0xc1,0x82,0x76,0xd1,0xa8,0x66,0x34,0xb3, + 0x2b,0x8d,0x27,0xdf,0xd4,0x64,0x6a,0x22,0xd5,0x9b,0x67,0x9d,0xf5,0x9b,0xf6,0x91, + 0x67,0x65,0x9b,0xc2,0x47,0xc9,0xf8,0x7e,0x3d,0x1b,0xe9,0x66,0xef,0xd3,0x53,0x4e, + 0xe3,0xb0,0x6f,0x48,0x15,0xb2,0x4a,0xc5,0x10,0x5d,0x9f,0xec,0xc3,0xd1,0xc0,0x67, + 0xa3,0x79,0x34,0x30,0xb5,0xb5,0x5a,0xce,0x76,0xed,0x18,0x95,0x52,0x8e,0x9e,0x65, + 0x04,0xb2,0xb1,0x3c,0xb0,0x8a,0x46,0xa1,0x96,0xa8,0x54,0xce,0x64,0xd5,0xdf,0x3a, + 0x06,0x22,0x46,0xc3,0x56,0xa1,0x5d,0x53,0xab,0x19,0x1f,0x4b,0x94,0x3c,0x63,0x8e, + 0xef,0x92,0x68,0xaf,0xe1,0x6e,0xe7,0xac,0xff,0xa8,0x6e,0x1f,0x6f,0x51,0x45,0x72, + 0x91,0x5d,0xc1,0x96,0x56,0xaa,0x8b,0x60,0x96,0xac,0xa4,0xd4,0xa4,0x2f,0xf0,0x17, + 0x69,0x75,0xb1,0x08,0xfc,0xe6,0x53,0x2f,0x13,0x8e,0xbe,0x17,0x9c,0xf6,0x28,0x76, + 0x0a,0x5b,0x32,0x33,0x92,0x3e,0x73,0x67,0x52,0x44,0xa5,0xe8,0xd5,0xf8,0x08,0x21, + 0x0a,0x81,0x71,0x71,0x6a,0xf4,0xbe,0xab,0x50,0x6f,0x37,0xd8,0x91,0x4f,0x7e,0xb8, + 0xde,0x2d,0x69,0x90,0xad,0x44,0x19,0xf5,0xd9,0x2e,0x7d,0x1c,0x50,0x11,0xdf,0xf1, + 0x2f,0xf9,0x2f,0x39,0x83,0x4a,0x29,0x30,0x7a,0x02,0x8c,0x85,0x57,0x15,0x6d,0xa5, + 0xe6,0x13,0x2e,0x6f,0xee,0xbe,0xbb,0xf5,0xe1,0x32,0x7c,0x0d,0x4e,0x25,0x66,0x4b, + 0x71,0xd4,0x82,0xe9,0x90,0x0b,0xd9,0xd2,0xbc,0x56,0x71,0x73,0xfa,0xa8,0x55,0x6f, + 0x5b,0x77,0xa8,0x40,0x38,0x5d,0x95,0x88,0x7f,0x21,0x23,0x5f,0x57,0xfb,0xe1,0x34, + 0xff,0xaa,0x2e,0x8b,0x2b,0x7c,0xed,0xec,0x07,0x5d,0xe9,0xde,0x00,0x47,0x3e,0x1d, + 0xa7,0x49,0x51,0xf7,0x67,0x60,0x0f,0xc8,0xb6,0x33,0xac,0x75,0xb5,0xa3,0x6a,0x1e, + 0x2d,0x13,0x47,0x25,0x58,0x58,0x75,0xbd,0xe5,0xf3,0xa6,0x50,0xb2,0xfc,0x56,0x4d, + 0x6f,0xb6,0x46,0x89,0xce,0xc5,0xab,0x1b,0x98,0x54,0xd1,0xe6,0x4b,0x6f,0x6e,0xeb, + 0x80,0x24,0x9f,0x76,0xfd,0xe4,0x69,0x18,0x79,0x73,0xf3,0x34,0xcc,0xdf,0x20,0xab, + 0x68,0x3b,0xd5,0xcc,0xe4,0x19,0x99,0x6a,0xa1,0x00,0xf0,0x95,0xd3,0xd7,0x1f,0x55, + 0x32,0xbe,0xe2,0x9c,0xec,0x15,0x3b,0xf7,0x48,0x55,0xa5,0x35,0xb9,0x47,0x96,0x38, + 0xdb,0x48,0x43,0xea,0x72,0x64,0x6d,0x9d,0x93,0xd8,0xce,0x1d,0xb2,0x26,0x6b,0x97, + 0xc1,0xdd,0x88,0xb9,0x75,0x9f,0x11,0x34,0x9c,0xe1,0xf6,0x1c,0xe0,0x32,0x89,0x0b, + 0xc5,0xbb,0xbe,0x30,0xfa,0x68,0x85,0xe8,0x3c,0xbc,0x2d,0x6c,0x8c,0x2f,0x4d,0xc8, + 0x91,0xef,0x2b,0x61,0x60,0x71,0x52,0xdc,0x6e,0x8e,0x2f,0xda,0xdf,0x95,0x1b,0xb1, + 0x17,0xfb,0x23,0xf1,0x90,0x8a,0x9d,0x06,0xe0,0x15,0x0b,0x8e,0xd0,0x3d,0xce,0x49, + 0x22,0xa4,0xb1,0x5b,0x49,0xfd,0xa5,0xd2,0xe1,0x2f,0x5a,0xf6,0xc1,0xaf,0x48,0x86, + 0xa2,0xcc,0xb4,0x29,0x36,0x6a,0xad,0x0e,0x61,0x4f,0x3c,0xbb,0xe5,0x68,0x76,0xf3, + 0x0c,0x46,0xb8,0x4a,0x09,0x53,0x41,0x6b,0x7c,0x08,0x0f,0x54,0xa5,0xcf,0x6e,0x49, + 0x6d,0xe7,0x55,0xae,0x0a,0xc4,0x32,0x07,0x64,0x68,0x9a,0x2a,0x78,0xfc,0x79,0x3d, + 0x78,0xc8,0x55,0x42,0x90,0xd0,0x9a,0x38,0x96,0x52,0x2e,0x82,0x62,0x3e,0x9d,0x8c, + 0x50,0x4d,0x1e,0xa3,0x12,0x57,0x7e,0xb6,0x22,0xf9,0xdb,0x7c,0x5e,0x25,0x52,0x55, + 0x9d,0xa5,0x74,0x0c,0xd1,0x20,0x8a,0xe7,0xd0,0x12,0xb9,0xe4,0xf6,0xf6,0xd1,0x76, + 0x9e,0x41,0xab,0x9a,0x00,0x58,0x99,0x2e,0x62,0xdb,0xd6,0x1b,0xb0,0x2d,0xef,0x55, + 0x59,0x87,0x1a,0x87,0xec,0x9b,0xf3,0xf6,0xa7,0x1d,0x27,0xb6,0x19,0x37,0xba,0x87, + 0x4d,0xda,0x87,0xe9,0x6f,0x2d,0x39,0x60,0xd5,0x8c,0xde,0x28,0x19,0xce,0x47,0xeb, + 0xe6,0xba,0xc8,0x41,0x33,0x33,0x55,0x1d,0x41,0x8e,0xec,0xff,0xed,0x67,0xb5,0x31, + 0x0b,0x7d,0x34,0xa8,0x35,0x91,0x5b,0x20,0x7d,0x6b,0x11,0x81,0xbf,0xaa,0x0c,0x80, + 0x2e,0x02,0xf0,0xc3,0x56,0xed,0xb8,0xed,0x4f,0xb5,0xe1,0x1b,0x10,0xc4,0x77,0xad, + 0x4c,0xcc,0x72,0x1a,0x3e,0x52,0xe2,0xa2,0xbf,0x2a,0xb3,0xa3,0xc0,0x88,0x73,0xfe, + 0x06,0x14,0xc9,0xf9,0x4a,0x7f,0xf7,0x56,0x7d,0xe6,0xc9,0xe5,0xaa,0xe1,0x97,0x15, + 0xbe,0x61,0x20,0x58,0x89,0x88,0x99,0x7c,0x9a,0x7c,0x52,0xa8,0x48,0x74,0x8f,0x3f, + 0x8f,0xc6,0x45,0xe1,0x9a,0xc1,0xc5,0x6b,0x49,0x5d,0xf3,0x53,0xcf,0x2e,0xe5,0x4d, + 0x94,0xf0,0xfd,0x3b,0xa9,0x58,0xcf,0xf1,0x67,0xe2,0x45,0x52,0xe9,0x8c,0xf9,0xb9, + 0x89,0x49,0xef,0xa8,0xf3,0x64,0xaa,0x00,0x17,0x8f,0x89,0xfb,0xea,0xda,0x78,0x40, + 0x15,0xaf,0x15,0x6d,0xbb,0xfd,0x81,0x52,0x53,0x50,0x6f,0xa7,0x39,0xa3,0x24,0xde, + 0x57,0x82,0xd9,0x79,0xd5,0x14,0x69,0x11,0xa7,0xa6,0x71,0xb5,0xaa,0xd5,0x9b,0x93, + 0x12,0x46,0x14,0x6e,0xfb,0x8a,0x5e,0x10,0xdc,0x7f,0x2c,0xb3,0x5e,0x55,0x4e,0x3f, + 0xaf,0x7f,0x0b,0x2b,0x56,0x89,0x5e,0xda,0x49,0xc5,0x5c,0x6b,0x7b,0xfb,0x8c,0x61, + 0x2f,0x1f,0x72,0x59,0x86,0x34,0x42,0x53,0xea,0xf2,0x98,0xcb,0x5c,0x1e,0xbb,0x7b, + 0x24,0x26,0x8e,0xdd,0xa6,0x56,0x1e,0x35,0xda,0xa7,0xc6,0xfb,0xfc,0x25,0xb6,0x70, + 0xb8,0x75,0x6a,0xa0,0xb4,0xab,0x9a,0x34,0x47,0x69,0x06,0xe3,0x0d,0x39,0xd8,0x59, + 0xaa,0x55,0xcb,0x42,0xc5,0xf9,0x18,0xfa,0xec,0x2c,0x8c,0xf8,0x33,0xb3,0x04,0x76, + 0xb2,0xbb,0xc4,0x35,0xc8,0x36,0x0e,0xdc,0x7d,0x6e,0xd5,0x72,0x0f,0x8a,0x0f,0x3a, + 0xc2,0x87,0xe2,0x75,0x57,0xca,0x91,0xac,0xbf,0x26,0xa6,0x10,0x50,0x15,0x3b,0x23, + 0xdd,0x2f,0xaa,0xcc,0xe7,0xff,0x9a,0x8a,0xe0,0xec,0x01,0x0a,0x49,0xa2,0x32,0x5d, + 0xa8,0xef,0xda,0x88,0x47,0xc5,0x32,0x6c,0xad,0x4a,0x25,0x72,0xee,0xac,0xed,0xc6, + 0xc9,0x6d,0x37,0x0e,0x19,0x17,0x96,0xb7,0x8d,0x84,0xa1,0x86,0x0c,0x77,0xd1,0xa1, + 0xc0,0x6b,0x15,0x5e,0x7a,0x5e,0x44,0xcb,0xae,0x8e,0x49,0x4f,0xe7,0xb4,0x56,0x56, + 0xd0,0x73,0x5f,0xa7,0xb5,0x6e,0x28,0xe4,0x96,0x05,0xda,0xa9,0x93,0x77,0x69,0xe5, + 0x5f,0xe6,0x62,0xf9,0x5c,0x22,0xde,0x17,0x1e,0x71,0x69,0x1d,0x0e,0x33,0x38,0xc6, + 0xdf,0xf5,0xeb,0x4c,0xed,0x36,0x39,0x79,0x96,0x62,0xb3,0x8d,0x89,0xb7,0x23,0x21, + 0xce,0x24,0x98,0x43,0xc8,0x9d,0xaf,0x4f,0x38,0x84,0x35,0x0b,0x1b,0xc3,0x7f,0x72, + 0xda,0x04,0x87,0x55,0x74,0x8b,0x8d,0x9f,0x06,0x66,0xed,0xfe,0xb6,0x74,0xa6,0xce, + 0xd0,0x5f,0x63,0x00,0x0a,0x77,0x62,0x42,0x6d,0xca,0x78,0xda,0x9d,0xff,0xdf,0xf9, + 0x15,0xc4,0xb8,0x5a,0x7f,0xba,0x08,0x73,0x57,0x26,0xd8,0x56,0x15,0x66,0x99,0xa0, + 0xb6,0x07,0x0c,0x47,0xe1,0x4f,0x4d,0x28,0xa5,0x5f,0xb4,0xf2,0x14,0xf9,0xb9,0x6c, + 0x50,0x98,0x0f,0xdd,0x1c,0xdb,0x5f,0x3a,0x10,0xab,0xb6,0x53,0xcc,0x70,0x9a,0xf3, + 0x9b,0xc7,0x4f,0xff,0xb4,0x25,0x58,0x48,0xa0,0xc8,0x53,0xf8,0xeb,0x8e,0x02,0xc3, + 0x21,0xe4,0x7c,0x9b,0xb0,0x78,0xbf,0xf9,0x62,0xc5,0x46,0xde,0x34,0xab,0x36,0x63, + 0x3b,0x1e,0xd6,0x72,0x9c,0x70,0xf9,0x06,0x2d,0x1b,0x99,0xbb,0x48,0xe8,0x49,0xbb, + 0x4f,0x10,0xc8,0xd0,0xee,0x13,0xe1,0xa2,0x71,0xd2,0x66,0x49,0x26,0x1a,0xa6,0xbe, + 0xc4,0x81,0x48,0x44,0x5e,0xe0,0xf0,0x0a,0xfb,0x35,0xac,0xe3,0x1f,0x57,0x49,0x6d, + 0x7d,0xce,0x8e,0xb6,0x7a,0xc9,0x5f,0x63,0x50,0x45,0x14,0x4d,0x1d,0x04,0x9a,0x57, + 0x2d,0x91,0x07,0x64,0x46,0xd3,0x8c,0x38,0x4a,0x76,0x38,0x38,0x6c,0x7d,0x03,0x86, + 0xbf,0x0d,0x01,0xc1,0xc1,0x55,0xab,0xd5,0x11,0xdb,0x29,0x8c,0xe5,0x78,0x44,0x7c, + 0x09,0xfa,0x1b,0x6f,0x87,0x32,0x88,0x93,0xf8,0x8c,0x75,0x45,0x29,0xc7,0x5c,0x61, + 0x06,0x11,0xbe,0x3e,0xe4,0x54,0x4b,0x4e,0xb1,0x95,0xa1,0x75,0xe6,0x15,0x53,0x7a, + 0xb5,0x2d,0x93,0x7e,0x4e,0x97,0x96,0x58,0x12,0x2e,0xc3,0x88,0x24,0x41,0x76,0x1d, + 0x60,0xd7,0x12,0x89,0xaf,0x8f,0x5d,0x9e,0x88,0xd6,0x4e,0x01,0x56,0x48,0xa0,0x26, + 0x2f,0xb9,0x75,0xdb,0x6b,0x49,0x9c,0xae,0xe3,0x9e,0xb7,0xcb,0x1d,0xeb,0x9c,0x27, + 0x41,0xcb,0x76,0xf6,0xf2,0x44,0x8e,0xc2,0xfb,0x83,0xed,0x03,0x9e,0x7a,0x70,0xfe, + 0x04,0x21,0xa3,0xae,0x99,0xae,0xfe,0x3a,0x88,0xfd,0x61,0x10,0xae,0xbc,0xe1,0x6e, + 0x1e,0xfc,0xbc,0x2d,0x20,0xd8,0x4a,0x64,0x40,0x80,0x90,0x8f,0x18,0x59,0xdc,0xe2, + 0x36,0x6f,0xe0,0x27,0xe0,0x8d,0xf4,0x87,0xcd,0x3c,0xdb,0xcf,0x1e,0x5e,0xd5,0x0a, + 0x10,0xbb,0x13,0xf0,0xf1,0x1e,0x77,0x5f,0x43,0x0b,0x1f,0x0f,0x6c,0xf3,0x13,0xcd, + 0x25,0xb7,0x19,0xa3,0x7d,0xae,0xa9,0x01,0x42,0xa3,0x5b,0xbe,0x6f,0x31,0x4d,0xd7, + 0x9c,0xed,0xf2,0x4e,0xbf,0xf0,0xf8,0xd2,0x67,0x5c,0x65,0x1b,0xcb,0xd8,0x66,0x2d, + 0xad,0x64,0x41,0xfe,0x48,0x8e,0xd2,0x9e,0x88,0x06,0x5e,0x71,0x72,0x98,0x4a,0x49, + 0xe2,0x93,0x34,0x30,0xda,0x46,0x0d,0x97,0x70,0x7e,0x7c,0xfb,0x52,0xf2,0xc3,0xb8, + 0x7c,0xca,0x31,0xe1,0x63,0xf8,0x11,0xf3,0xdf,0x6d,0x52,0xb1,0x26,0x2a,0x07,0x0c, + 0xd5,0x8b,0xa3,0x73,0xe5,0x62,0x92,0x13,0x1d,0x81,0xf3,0x04,0x8a,0x2b,0x3b,0x2a, + 0x2a,0xf5,0x85,0x50,0xa9,0xd7,0x62,0x22,0xa1,0xb1,0xb3,0x3b,0x89,0xaa,0x74,0x5a, + 0x49,0xaf,0x91,0xce,0x01,0x33,0x1a,0x0d,0xd3,0xbe,0xd6,0x88,0x13,0xf9,0xe0,0x98, + 0xb3,0x7b,0xc0,0xad,0x55,0xb0,0xdc,0x32,0x4b,0x23,0xfe,0x2c,0xa3,0x4e,0xff,0xa2, + 0xa5,0xbe,0xa1,0x55,0xb1,0x3a,0x27,0x4e,0x7c,0x28,0x73,0xef,0x07,0xa7,0xfa,0xea, + 0x2e,0x5f,0x29,0x93,0xf8,0xe0,0x7d,0x70,0x70,0x6a,0x07,0x40,0xd4,0xeb,0x9e,0xd7, + 0x89,0x7b,0xd6,0x99,0x84,0x6d,0xf5,0x74,0xac,0x0f,0x1f,0x70,0x1f,0x65,0xb4,0x60, + 0xe1,0x49,0xd0,0x3c,0x49,0xc0,0x73,0xf9,0x56,0xd5,0x23,0x86,0x25,0x29,0x4a,0x15, + 0xdf,0xf5,0xe4,0x23,0x31,0xf4,0x0a,0x36,0x10,0x87,0xf6,0xd5,0xcb,0x7b,0x7b,0x07, + 0xff,0xcc,0x8a,0xff,0xf1,0xe8,0x97,0x83,0x5f,0x0e,0x0e,0xac,0xe9,0xd1,0x53,0x4f, + 0x6f,0xe7,0x33,0x28,0xe3,0x74,0x57,0x34,0x42,0x55,0xeb,0x14,0xba,0x3f,0xb2,0x5d, + 0xcb,0x44,0x4d,0x73,0xcc,0x59,0xe0,0xce,0x85,0x94,0xb3,0x55,0x15,0x52,0xa5,0x60, + 0x2c,0xa9,0x2a,0x1a,0x74,0x70,0x3f,0xe9,0x39,0x37,0xf3,0xe4,0x63,0x81,0x58,0x37, + 0x7f,0xc4,0xb1,0xb2,0xd6,0x12,0x88,0xef,0xc9,0xcc,0x9e,0x9a,0xa4,0xe0,0x4f,0x57, + 0x01,0xb2,0x79,0xa2,0x69,0x82,0xc3,0x2d,0x49,0x4f,0xdf,0x04,0xa1,0x25,0xbe,0xeb, + 0xfa,0xdc,0x11,0x50,0x8f,0x4f,0xbe,0x59,0xdd,0xca,0x6f,0x12,0x0e,0x73,0x9d,0x41, + 0x86,0x63,0xd7,0x12,0x74,0x26,0x4c,0x1e,0xd9,0xdf,0x86,0xf1,0xf8,0xfb,0x5f,0xbc, + 0x00,0x39,0xb3,0xdd,0x7c,0xa4,0x40,0x72,0x89,0x58,0x6e,0x34,0x1f,0x7f,0x92,0xfe, + 0xf8,0xb3,0xb4,0x84,0xb1,0x56,0xa2,0x1e,0x61,0xae,0xaa,0xa4,0xd1,0x7c,0xeb,0x40, + 0x79,0x73,0xc4,0x19,0x4f,0x02,0x91,0x24,0x49,0x6a,0xbe,0x2b,0x46,0x02,0x2c,0x68, + 0x3e,0x09,0x89,0xef,0x52,0xe9,0x5d,0xe1,0xba,0x02,0xba,0xfa,0x2b,0x21,0x83,0x2e, + 0x85,0xff,0xe8,0x40,0x7d,0x81,0xfa,0xd1,0x01,0x24,0x22,0xfd,0x33,0xaf,0x17,0xd9, + 0xd1,0xce,0xff,0x01,0xc3,0x72,0x03,0x9b,0x91,0xa4,0x00,0x00, }; constexpr size_t PATTERNS_INDEX_HTML_GZ_LEN = sizeof(PATTERNS_INDEX_HTML_GZ); // diff --git a/firmware/patternflow/src/status_index.h b/firmware/patternflow/src/status_index.h index 4ac1891c..17a89af3 100644 --- a/firmware/patternflow/src/status_index.h +++ b/firmware/patternflow/src/status_index.h @@ -12,113 +12,109 @@ static const char STATUS_INDEX_HTML[] PROGMEM = R"HTML( - + Patternflow - Status
              -

              Status

              -
              +/* Console base: the same block opens every core page. Light in :root (the chrome's + injected light palette holds these same values: keep the two in step), + dark under html[data-theme=dark]. No web fonts: the hotspot has no internet. */ +:root{color-scheme:light;--cream:#F4EFE6;--panel:#FFFCFA;--ink:#1A1814;--muted:#625C51;--faint:#7D7668;--rule:#DDD5C6;--rule-soft:#E8E1D4;--ghost:#E3DCCE;--led:#FF5C2E;--bad:#B83C1C;--ok:#2B7A4B;--warn:#85600E; +--sans:system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;--mono:ui-monospace,'Cascadia Mono','SF Mono',Menlo,Consolas,'Roboto Mono',monospace} +html[data-theme=dark]{color-scheme:dark;--cream:#0C0B09;--panel:#131110;--ink:#EDE7DB;--muted:#A39B8A;--faint:#7A7364;--rule:#2B2721;--rule-soft:#1F1C18;--ghost:#2A2620;--bad:#FF7A55;--ok:#57B87F;--warn:#D9A03F} +*{box-sizing:border-box}[hidden]{display:none!important} +body{margin:0;background:var(--cream);color:var(--ink);font:15px/1.5 var(--sans);-webkit-font-smoothing:antialiased} +a{color:inherit}:focus-visible{outline:2px solid var(--led);outline-offset:2px} +.wrap{max-width:720px;margin:0 auto;padding:20px 16px 48px} +h2{margin:0 0 6px;font-size:13px;font-weight:600;color:var(--muted)} +.card{background:var(--panel);border:1px solid var(--rule);border-radius:10px;padding:16px} +.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:40px;padding:0 16px;border:1px solid var(--rule);border-radius:8px;background:var(--panel);color:var(--ink);font:500 14px var(--sans);text-decoration:none;cursor:pointer;transition:border-color .15s,background .15s,color .15s} +@media(hover:hover){.btn:hover{border-color:var(--ink)}footer a:hover{color:var(--ink)}} +.btn:disabled{opacity:.45;cursor:default;border-color:var(--rule)} +.msg{font:12px var(--mono);color:var(--faint)}.pf-ok{color:var(--ok)}.pf-err{color:var(--bad)} +footer{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:40px;border-top:1px solid var(--rule);font:12px var(--mono);color:var(--faint)} +footer a{display:inline-flex;align-items:center;min-height:40px;color:var(--muted);text-decoration:none} +header{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 12px;margin-bottom:20px} +h1{flex:1;margin:0;font-size:22px;font-weight:600;letter-spacing:-.01em} +.sub{font:12px var(--mono);color:var(--faint)} +section{margin-top:28px} +.note{margin:8px 0 0;font-size:13px;color:var(--muted)} +.btn.dan{color:var(--bad)}@media(hover:hover){.btn.dan:hover{border-color:var(--bad)}} +.acts{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:12px} +.kv{margin:0;border-top:1px solid var(--rule)} +.kv>div{display:flex;align-items:baseline;gap:12px;padding:8px 0;border-bottom:1px solid var(--rule-soft);font-size:13px} +.kv dt{flex:1 0 auto;color:var(--muted)}.kv dd{margin:0;min-width:0;font:12.5px var(--mono);text-align:right;overflow-wrap:anywhere} +/* ── Status ── */ +.kv .big{font-size:14px;font-weight:600} +.ok{color:var(--ok)}.warn{color:var(--warn)}.bad{color:var(--bad)} +.bar{display:block;height:3px;margin:5px 0 2px auto;max-width:160px;background:var(--ghost)}.bar i{display:block;height:100%;background:var(--led)} +#cptext{display:block;width:100%;height:180px;margin-top:12px;padding:8px 10px;resize:vertical;color:var(--ink);font:12px/1.45 var(--mono)} +.pf-offline .kv dd{opacity:.5} + +
              +

              Status

              -
              - -
              - +
              + -

              Device

              -
              Firmware
              -
              -
              Build
              -
              -
              Last restart
              -
              -
              Busy
              -
              -
              Panel size
              -
              +

              Device

              +
              Firmware
              -
              +
              Build
              -
              +
              Last restart
              -
              +
              Busy
              -
              +
              Panel size
              -
              -

              Render

              -
              Panel
              -
              -
              Frame rate
              -
              -
              Frame time
              -
              -
              Active pattern
              -
              + + +

              Render

              +
              Panel
              -
              +
              Frame rate
              -
              +
              Frame time
              -
              +
              Active pattern
              -

              -

              Patterns

              -
              Total
              -
              -
              Built into firmware
              -
              -
              Loaded from storage
              -
              -
              Last load error
              -
              +

              Patterns

              +
              Total
              -
              +
              Built into firmware
              -
              +
              Loaded from storage
              -
              +
              Last load error
              -

              -

              Memory

              -
              Internal heap free
              -
              -
              Largest free block
              -
              -
              PSRAM free
              -
              +

              Memory

              +
              Internal heap free
              -
              +
              Largest free block
              -
              +
              PSRAM free
              -
              -

              Internal heap is the scarce one - the LED panel's DMA buffers -live there. A pattern module loads only if it leaves 24 KB -of it free; run lower and the network is the first thing to go, while the -panel keeps drawing.

              +

              Internal heap is the scarce one: the panel’s DMA buffers live there. A module loads only if it +leaves 24 KB free; below that the network goes first, while the panel keeps drawing.

              -

              Storage

              -
              Pattern storage
              -
              -
              Storage error
              -
              -
              +

              Storage

              +
              Pattern storage
              -
              +
              Storage error
              -
              +
              - -

              Network

              -
              Network
              -
              -
              Signal
              -
              -
              Address
              -
              -
              Names
              -
              -
              Hotspot
              -
              -
              Hotspot mode
              -
              -
              Hotspot clients
              -
              -
              Reached via
              -
              +

              Network

              +
              Network
              -
              +
              Signal
              -
              +
              Address
              -
              +
              Names
              -
              +
              Hotspot
              -
              +
              Hotspot mode
              -
              +
              Hotspot clients
              -
              +
              Reached via
              -
              - -
              + +
              )HTML"; // GENERATED by firmware/toolchain/console_pages.py build — do not edit. -// gzip -9 of STATUS_INDEX_HTML (15075 bytes → 6144 bytes), served with Content-Encoding: gzip. +// gzip -9 of STATUS_INDEX_HTML (14577 bytes → 6101 bytes), served with Content-Encoding: gzip. static const uint8_t STATUS_INDEX_HTML_GZ[] PROGMEM = { - 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xc5,0x5b,0x6b,0x72,0xdb,0x48, - 0x92,0xfe,0xaf,0x53,0x94,0xe5,0x6e,0x01,0x18,0x81,0x10,0x25,0xbf,0x41,0x53,0x1a, - 0xc9,0x8f,0x99,0x9e,0xb6,0x7a,0xbc,0x96,0x7b,0x27,0xb6,0xbd,0x1d,0x13,0x45,0xa0, - 0x40,0xa2,0x05,0x02,0x08,0x14,0x28,0x8a,0x43,0x31,0xa2,0x0f,0x31,0x7f,0xf6,0x02, - 0x7b,0x85,0xfd,0xbf,0x47,0xe9,0x93,0xec,0x97,0x59,0x05,0x10,0xa4,0x64,0x5b,0x1d, - 0xf3,0x63,0x27,0x7a,0x2c,0xd6,0x2b,0x2b,0x2b,0xdf,0x99,0x55,0x78,0xf9,0x20,0x2e, - 0xa2,0x7a,0x51,0x2a,0x31,0xa9,0xa7,0xd9,0xf1,0xce,0x4b,0xfa,0x23,0x32,0x99,0x8f, - 0x87,0xbb,0x2a,0xdf,0xa5,0x0e,0x25,0xe3,0xe3,0x97,0x53,0x55,0x4b,0x11,0x4d,0x64, - 0xa5,0x55,0x3d,0xdc,0x9d,0xd5,0x49,0xef,0x39,0x0d,0xea,0xa8,0x4a,0xcb,0x5a,0xe8, - 0x2a,0x1a,0xee,0x1e,0x94,0x49,0x2f,0x2a,0x72,0x5d,0x64,0x2a,0xf8,0x45,0x9f,0x4c, - 0x86,0x71,0xff,0x68,0xf4,0xe8,0xd1,0xd1,0xd1,0xee,0xf1,0xcb,0x03,0x33,0xf1,0xd8, - 0x2e,0x38,0x4e,0x13,0xf7,0xc1,0x3c,0xcd,0xe3,0x62,0x1e,0xbc,0x7f,0xeb,0xb9,0xc9, - 0x2c,0x8f,0xea,0xb4,0xc8,0x5d,0x6f,0x79,0x25,0x2b,0xf1,0xb7,0xa1,0x19,0xf3,0x7f, - 0x1c,0x3a,0x07,0xb2,0x4c,0x0f,0x74,0x2d,0xeb,0x99,0x76,0xfc,0x77,0xc3,0x4f,0x3f, - 0xfb,0xe7,0xc3,0x23,0xf5,0xc2,0xbf,0xf0,0x7f,0xf2,0xdf,0x0f,0xff,0x86,0xe5,0xc3, - 0x25,0x0d,0xab,0xd0,0xc9,0xd2,0x2b,0xe5,0xf8,0x71,0x5a,0xd5,0x8b,0xf0,0xc1,0xa1, - 0x7f,0x15,0xe6,0xb3,0x2c,0xf3,0xc7,0xaa,0x0e,0xff,0xe4,0xa7,0x79,0x92,0xa5,0xe3, - 0x49,0x1d,0xfe,0x30,0x9b,0x8e,0x54,0xe5,0x4f,0x8a,0x2c,0x0e,0xff,0x3a,0xfa,0x45, - 0x45,0xb5,0xaf,0xe5,0x22,0x6c,0x31,0xa8,0xfd,0x4b,0x5f,0x79,0x4b,0xb5,0xb7,0xe7, - 0xaa,0xa0,0x56,0xd7,0xf5,0xab,0x22,0xaf,0x55,0x5e,0x0f,0x6b,0x6f,0xe5,0x8f,0x66, - 0xba,0x33,0x75,0xe4,0x97,0xde,0xb2,0x69,0x89,0x04,0xc8,0x8f,0x82,0x38,0xd5,0x72, - 0x94,0xa9,0x78,0xf8,0xe0,0x70,0xd5,0x6d,0xf5,0x07,0x65,0x50,0x4f,0x54,0xee,0x26, - 0x7e,0xe2,0x0d,0x2a,0x55,0xcf,0xaa,0x5c,0x94,0x2b,0xbf,0x2c,0xb2,0x6c,0x0d,0x51, - 0xfb,0x53,0x3f,0xf2,0x0b,0x43,0x85,0xda,0x4f,0xfc,0xf1,0xf0,0x70,0xd0,0xee,0xf0, - 0x01,0x3b,0x8c,0xf7,0xf6,0x1e,0x24,0xc0,0x2d,0x19,0x1e,0xfa,0x51,0xa6,0x64,0xf5, - 0x31,0x9d,0xaa,0x62,0x56,0xbb,0xb5,0xe7,0xbb,0x3a,0x88,0x64,0x96,0x9d,0x68,0xd7, - 0x0b,0xff,0xe4,0x6a,0xcf,0xb3,0x3b,0x36,0xd0,0x63,0x6f,0x19,0xb9,0xb1,0x4f,0x54, - 0xc1,0x59,0xda,0x6e,0x45,0xdd,0x4c,0x2a,0xe5,0xad,0xec,0x9a,0xef,0xfd,0xef,0x3d, - 0x6f,0xd5,0xee,0xfc,0x3d,0x76,0x4e,0x86,0xfd,0xc1,0xd6,0x8e,0x03,0x60,0xe3,0xd6, - 0x43,0x88,0x44,0xd3,0xf7,0xc1,0x9f,0x62,0x5d,0xb1,0xb7,0x57,0x04,0x49,0x5a,0xe9, - 0x7a,0x38,0x04,0x21,0x4e,0xb0,0x3c,0x04,0xf2,0xf6,0xd8,0x60,0x57,0x51,0x86,0x1d, - 0x96,0x8f,0x6f,0x43,0x5e,0xf9,0x00,0xba,0x9e,0x93,0x7b,0xcb,0xe9,0x30,0x1f,0x24, - 0x37,0x37,0x00,0xb5,0xf2,0xf3,0x62,0x1e,0x7e,0x58,0x61,0x0e,0x8b,0xc5,0x7a,0x5a, - 0x84,0x93,0xec,0xed,0xbd,0x0b,0xca,0x99,0x9e,0xa0,0x31,0xb8,0x38,0x41,0x33,0x72, - 0x2f,0xbc,0xf0,0xa7,0x93,0x9f,0x02,0xac,0x02,0x1e,0x3f,0x0d,0xdf,0x07,0x44,0x74, - 0xf7,0x47,0xff,0xdc,0x7f,0x0d,0x60,0x73,0x59,0x47,0x93,0x8b,0x2d,0x48,0x53,0x6f, - 0xf9,0x3e,0x30,0xe0,0x81,0xf7,0x4f,0x01,0xb0,0x71,0xcf,0x87,0xe7,0xb2,0x9e,0x04, - 0xd3,0x14,0xc3,0xfe,0xb9,0xc7,0x4b,0xd3,0xfa,0x6d,0x51,0xbd,0x56,0x57,0x69,0xa4, - 0xd6,0x8b,0xc1,0xbf,0x62,0x58,0xdc,0xdc,0x2c,0x57,0x0d,0xa3,0x73,0x35,0x17,0xef, - 0xab,0x62,0x9a,0x6a,0xb5,0x66,0xc7,0xc2,0xcf,0x0d,0xa3,0x27,0x6b,0x94,0x8e,0xd4, - 0xa3,0x35,0x63,0xb4,0xb7,0xd4,0x60,0xb7,0x5b,0x04,0xa3,0x59,0x9a,0xc5,0x7b,0x7b, - 0xda,0xfc,0x18,0x0e,0x6d,0x8f,0x07,0xf2,0x4f,0x02,0x22,0xa7,0xeb,0xf9,0x0b,0xe2, - 0xf8,0xca,0x1b,0x74,0xb8,0xd1,0xa1,0x71,0x33,0x6d,0x90,0xbb,0x6f,0xaa,0xaa,0xa8, - 0x5c,0xa7,0x36,0x93,0x1c,0x3a,0x48,0x11,0xd8,0xd6,0xcd,0xcd,0x0b,0xf5,0x18,0x50, - 0x56,0xab,0xb5,0xd8,0xfd,0xc9,0x9d,0x91,0x48,0xda,0xa3,0x24,0x0a,0xe4,0xe2,0x9e, - 0x2d,0xe9,0xaa,0xbc,0x25,0x69,0x75,0x15,0x14,0x97,0x5e,0x3d,0xa9,0x8a,0xb9,0x30, - 0x1b,0x55,0x96,0x8e,0xad,0xd4,0xb3,0x74,0x90,0x66,0x9d,0x54,0xfc,0x07,0x4c,0xa9, - 0x60,0x30,0x08,0xcd,0x55,0x47,0xe6,0x5e,0xd3,0xf9,0x01,0x11,0xff,0x5e,0x40,0xcf, - 0xcb,0xc4,0xf0,0x68,0xa8,0x07,0xef,0x82,0xa4,0xa8,0xde,0x48,0xa0,0xd1,0x6e,0x9e, - 0x40,0x3e,0x31,0x93,0x10,0x5f,0x79,0xae,0xd7,0xda,0x9b,0x1d,0x63,0xb8,0x72,0x39, - 0x55,0xc3,0xdd,0xab,0x54,0xcd,0xcb,0xa2,0xaa,0x77,0x45,0x64,0x75,0x7a,0x77,0x9e, - 0xc6,0x35,0x0c,0x15,0x33,0xb0,0xc7,0x0d,0x58,0x8a,0xb4,0x4e,0x65,0xd6,0xd3,0xd0, - 0x25,0x35,0x3c,0x24,0x2b,0x57,0xa7,0x75,0xa6,0x8e,0xdf,0xcb,0xba,0x56,0x15,0xec, - 0x08,0x8e,0xd6,0x13,0x06,0x9b,0x97,0x07,0x66,0x0c,0x96,0xb0,0x5e,0xd0,0xdf,0xb0, - 0x2a,0x8a,0x7a,0xd9,0xeb,0x45,0x95,0x92,0xd3,0xf0,0x61,0xff,0x55,0xff,0xac,0xff, - 0x62,0xd0,0xeb,0xa5,0xf9,0x65,0xf8,0xf0,0xcd,0xeb,0x37,0xcf,0x5e,0x9f,0xa1,0x35, - 0x9d,0xd5,0x2a,0x0e,0x1f,0x3e,0x3f,0x7d,0x7e,0xf4,0xec,0x08,0xed,0x44,0xa6,0x79, - 0x1d,0x3e,0x7c,0x72,0xfa,0xe4,0xc9,0xe3,0xa7,0x83,0x9d,0x5e,0xaf,0x9a,0x65,0x2a, - 0x7c,0x78,0xf4,0xf8,0xe8,0xf0,0xf0,0xf9,0xc0,0x34,0x7b,0xba,0x48,0x30,0xe7,0xf0, - 0xec,0xf0,0xc5,0xe1,0x63,0xf4,0x65,0x04,0xe1,0xed,0xdb,0x27,0xaf,0x8e,0xde,0xa0, - 0x55,0x00,0xfc,0x93,0x67,0x67,0xcf,0x9f,0xbd,0x45,0x63,0x2e,0xab,0x3c,0x7c,0xf8, - 0xfa,0xc5,0x69,0xff,0xd1,0x5b,0x82,0x56,0xca,0x5c,0x65,0x58,0xfa,0xe8,0xf0,0xf0, - 0xb0,0x4f,0x1d,0x5a,0xe6,0x3a,0x74,0xbe,0x03,0x11,0x2a,0xc7,0x9f,0xa5,0xdc,0xee, - 0x69,0x55,0xa5,0x89,0xaf,0x17,0xba,0x56,0xd3,0xde,0x2c,0xf5,0xd7,0x9d,0xb4,0x64, - 0x5a,0xe4,0x45,0xe8,0xfc,0x45,0xd5,0x67,0x15,0x90,0xd5,0xe2,0x1c,0x6d,0x5e,0x4b, - 0x03,0xba,0x94,0x91,0xf2,0x2f,0xde,0x52,0x67,0xef,0x83,0x1a,0xcf,0x32,0x59,0xf9, - 0xe7,0x2a,0xcf,0x0a,0xbf,0x1d,0x5e,0xed,0xfc,0x61,0x39,0x2a,0xae,0x7b,0x3a,0xfd, - 0x47,0x9a,0x8f,0xc3,0x51,0x51,0xc5,0xaa,0xea,0xa1,0x67,0xb5,0x33,0x2a,0xe2,0xc5, - 0x72,0x2a,0xab,0x71,0x9a,0x87,0xfd,0xc1,0x48,0x46,0x97,0xe3,0xaa,0x98,0xe5,0x71, - 0x08,0xed,0x70,0x2d,0x2d,0xbd,0x41,0x54,0x64,0x45,0x65,0xbb,0x40,0x4e,0x6f,0x90, - 0x80,0x8b,0x20,0xdd,0x34,0xcd,0x16,0xb6,0x9b,0x50,0xf6,0x06,0x3b,0x59,0x9a,0xab, - 0xde,0x44,0xb1,0xbd,0x3f,0x0c,0x9e,0x0c,0x7a,0x73,0x35,0xba,0x4c,0x31,0x97,0x16, - 0xe8,0x29,0x38,0x34,0x21,0x14,0x64,0x4e,0x8c,0x4e,0xa5,0x56,0xf1,0x6a,0x27,0x98, - 0x57,0xb2,0x04,0x12,0xd7,0x46,0x0c,0xc2,0xa7,0xcf,0xfb,0xe5,0xf5,0xa0,0x41,0x4a, - 0xc8,0x59,0x5d,0x0c,0x4a,0x19,0xc7,0xb4,0xf0,0xd1,0x51,0x79,0x2d,0x8e,0x30,0x2e, - 0x9e,0x3e,0x2e,0x81,0x3f,0xb9,0x48,0x55,0x2d,0x61,0xed,0xcb,0x8c,0x7c,0x49,0xa6, - 0xae,0x07,0x00,0x3c,0xce,0x7b,0x29,0x68,0xa9,0xc3,0x48,0x11,0xa5,0x07,0x63,0x59, - 0x86,0xcf,0x01,0xd4,0x82,0xc1,0xd9,0xeb,0xba,0x98,0x86,0x87,0x80,0x36,0xd8,0x69, - 0xe9,0x61,0xfa,0x00,0x1b,0x8e,0x34,0x8d,0x85,0x39,0x18,0x09,0x80,0x07,0x24,0x63, - 0x08,0x97,0xc1,0xef,0x19,0x16,0xd9,0x23,0xd2,0xcf,0x5b,0x44,0x83,0x78,0x78,0x03, - 0x0b,0xb4,0x92,0x71,0x0a,0xeb,0x76,0xc8,0xb8,0x1e,0x2e,0x0d,0x19,0xd2,0x7f,0xa8, - 0xf0,0xf0,0x09,0x96,0x72,0x73,0x6e,0x40,0x3d,0xed,0xf7,0xdb,0x33,0x0f,0xe8,0x1c, - 0xe1,0x21,0x76,0xd5,0xb3,0xd1,0xf2,0x36,0xb1,0x89,0xb3,0x96,0x09,0x06,0x18,0xe0, - 0x6f,0x30,0x89,0xa5,0x1a,0x58,0x6b,0xc5,0x4a,0x6a,0x39,0xdc,0x23,0xeb,0x7f,0xf4, - 0x94,0x71,0x39,0x5a,0x6e,0x2d,0xdf,0xc6,0x25,0x53,0xa4,0x73,0x3d,0x12,0x20,0x22, - 0x7c,0xd0,0x7f,0xa1,0xa6,0x03,0x32,0x1a,0xbd,0xba,0x02,0xaf,0x61,0x07,0xa6,0xe1, - 0xac,0x2c,0x55,0x15,0x81,0x8b,0x83,0x9d,0xee,0xee,0xac,0x63,0xde,0x9a,0x83,0x7d, - 0xf1,0x9c,0xf6,0x8c,0xb3,0x8e,0xa4,0x19,0xf2,0x10,0x42,0x77,0x11,0x9c,0x35,0x8e, - 0xa8,0x0e,0x63,0xf6,0x79,0xe6,0x8e,0xb0,0x33,0x09,0x1c,0xb3,0x97,0x79,0xd9,0x88, - 0xc9,0x33,0x92,0x92,0xfb,0xf1,0xb6,0xd9,0x2a,0xae,0x97,0x86,0xea,0xc2,0x8a,0x5c, - 0x87,0x3e,0x8f,0xb6,0xc8,0xbb,0x75,0x40,0x2c,0x8e,0xd7,0x47,0x83,0x97,0xb2,0x82, - 0xdc,0x1f,0xdc,0x83,0x75,0x84,0x26,0x93,0x95,0x4f,0x16,0x56,0xc4,0x80,0x41,0x71, - 0xa5,0x2a,0xb2,0x76,0x3d,0x52,0x0d,0x68,0xcb,0x62,0x3e,0x51,0x95,0xa2,0x7d,0x82, - 0x51,0x3a,0x5e,0x6e,0xa1,0xb6,0xc5,0x3a,0x90,0xad,0xb8,0x5c,0x76,0xf1,0x85,0x5f, - 0x58,0x05,0x64,0x9a,0x36,0x7a,0xa9,0x03,0xfd,0x23,0x19,0x6f,0x74,0x93,0xf8,0x02, - 0xc4,0x48,0x56,0x4b,0x2b,0xe5,0x8f,0xee,0x92,0xf2,0x35,0xed,0x06,0x1d,0xe9,0x22, - 0xa9,0x36,0x87,0x3f,0xec,0xf7,0xbf,0x35,0x60,0x44,0xda,0xb2,0x70,0x94,0x15,0xd1, - 0x65,0xa3,0x3c,0x34,0xe3,0x6e,0xed,0xc1,0xba,0xbc,0xa8,0xd5,0x72,0x8b,0x4c,0xb7, - 0x25,0xbc,0x61,0x01,0xe4,0x0b,0x6c,0x83,0xd0,0x6e,0x98,0x9f,0xc7,0x4f,0x00,0xa8, - 0x2e,0x8a,0x4c,0xdf,0xcb,0x40,0xf0,0x1e,0x9d,0xb3,0x1c,0xb2,0x85,0x19,0xcd,0x20, - 0x3a,0xf9,0xb2,0x2c,0x74,0x4a,0xaa,0x14,0x56,0x2a,0x93,0x35,0xc2,0xdd,0xc1,0x3d, - 0xd5,0xf2,0x96,0x1e,0x3d,0xff,0xa2,0x1e,0x35,0x12,0x0c,0x2d,0x15,0x8c,0x50,0x87, - 0x40,0xbc,0xa0,0x94,0x15,0x50,0xbe,0x4b,0x1c,0x8d,0xac,0xdf,0x6d,0xc0,0xb6,0xec, - 0x11,0x53,0x73,0x56,0x69,0x80,0x28,0x8b,0x94,0x28,0xd0,0x1c,0x34,0x9c,0x90,0xec, - 0x2d,0x6f,0x59,0x7c,0xbb,0xfe,0xb6,0xa0,0xfc,0x71,0xaa,0xe2,0x54,0xba,0x16,0x4c, - 0x18,0x15,0x94,0xa8,0x20,0x1e,0x37,0xd0,0x42,0x99,0xd4,0x0c,0x8e,0xbd,0x7e,0xb8, - 0xbb,0x3b,0x68,0x09,0x29,0x47,0xc0,0x12,0x98,0x0f,0x88,0xd6,0x3d,0xb2,0xce,0x56, - 0x4b,0xf9,0x77,0xa6,0xe0,0x72,0x7b,0xe0,0xc0,0x80,0x35,0x82,0x7f,0xae,0xc0,0xce, - 0xa9,0x1e,0xff,0x2b,0x06,0x91,0xd6,0x23,0xa0,0xe9,0xdd,0xa5,0x20,0x76,0x48,0x55, - 0xd5,0x1d,0xfa,0xf0,0x30,0x2a,0x89,0x69,0x5b,0x92,0xbc,0x16,0xf5,0x56,0xa8,0x3b, - 0xce,0xcb,0x48,0x51,0xbf,0x63,0x97,0xe8,0x64,0x95,0x62,0x14,0x41,0xe5,0x3a,0x45, - 0xa0,0x03,0x1b,0xb5,0xad,0x02,0x1c,0x34,0xdc,0xe1,0x75,0x7f,0x27,0x83,0x89,0x1c, - 0x4c,0x89,0x03,0x52,0x05,0xd1,0xa1,0xd4,0x6a,0xe7,0xd3,0x24,0x8d,0x63,0x95,0xff, - 0xdc,0x9e,0x27,0x2f,0x72,0xf5,0x20,0x9d,0x52,0x90,0x06,0xe7,0x0c,0x42,0x11,0x91, - 0x92,0x84,0x14,0x4a,0xc0,0xba,0x15,0x24,0xbe,0x48,0xee,0x02,0xa8,0x54,0x02,0x2f, - 0x0e,0x9e,0x76,0xce,0xf8,0xa8,0x63,0x7b,0xcd,0xa1,0x59,0x72,0xbf,0x6c,0xe3,0x11, - 0x2d,0xfc,0x0b,0x8c,0x94,0xcb,0xdb,0x1a,0xb0,0xda,0x41,0xf4,0xc9,0xc1,0xe0,0xcb, - 0x03,0x93,0x3b,0x53,0x78,0x73,0xfc,0x32,0x4e,0xaf,0x44,0x94,0x49,0xad,0x11,0x75, - 0xc2,0x9e,0x36,0xa9,0xb5,0xaa,0x90,0x14,0x83,0xd6,0xcd,0x18,0x3c,0x3c,0xe7,0xcb, - 0xe8,0x3a,0x7e,0x39,0x39,0x3c,0x6e,0xe2,0x4c,0xfc,0xdc,0x98,0x07,0x9f,0xbc,0x2b, - 0xd2,0x18,0xb9,0x38,0x40,0xf5,0x9a,0x05,0x07,0x16,0xe4,0xce,0xce,0xcb,0x07,0xbd, - 0x9e,0xf8,0x38,0x49,0xb5,0x28,0xe5,0x58,0x09,0xfc,0x9d,0x4f,0x64,0x2d,0x90,0x0d, - 0x6b,0x81,0xe0,0x58,0xa9,0x5c,0x4f,0x20,0xe9,0x2a,0xf6,0x45,0x51,0x61,0x8e,0xe6, - 0x9f,0xb0,0xf0,0x39,0x68,0x34,0x55,0x84,0xb3,0x90,0xfa,0x52,0x0b,0xd8,0x86,0x1d, - 0x41,0xff,0x9b,0xa8,0xac,0x0c,0x05,0x82,0x7e,0x61,0xd4,0x0a,0x51,0x74,0x99,0x2a, - 0x2d,0x14,0x84,0x68,0x21,0x92,0x54,0x65,0xb1,0xe8,0x64,0xeb,0x62,0x22,0xb5,0x2f, - 0x60,0x41,0xc5,0x2f,0x33,0x5d,0xf3,0x3a,0xf8,0x51,0x1d,0x88,0x5e,0x0f,0x47,0xef, - 0x50,0x83,0x6d,0x23,0xce,0x6c,0xa1,0x52,0x31,0x62,0xb8,0x6b,0x1a,0xe6,0x84,0xd8, - 0x67,0xb1,0x7b,0xfc,0x0a,0xff,0x0a,0x28,0xf9,0x18,0xf1,0x24,0x64,0x16,0x24,0x31, - 0x73,0x36,0xc9,0x02,0xf5,0xb1,0x8b,0x4a,0xfa,0xd9,0x52,0xf2,0x00,0x1b,0x52,0x24, - 0x0f,0xed,0x81,0xe9,0x92,0x76,0x0a,0x35,0x77,0x05,0xda,0x71,0x91,0x67,0x0b,0x61, - 0xc4,0x51,0xc8,0x2a,0x95,0xbd,0x4c,0x8e,0x54,0x36,0xdc,0x7d,0xbd,0xde,0x90,0x80, - 0x35,0xeb,0x89,0xc0,0x36,0xac,0x01,0x97,0x8e,0x8e,0x4d,0x0a,0x08,0xf2,0x1f,0x81, - 0xd1,0xd9,0x31,0x08,0xd6,0x3d,0x21,0xce,0x8d,0xc5,0x71,0x7d,0xfc,0x36,0xad,0xa6, - 0x70,0x78,0x98,0x88,0xc6,0xcb,0x38,0x66,0x34,0x92,0x39,0x33,0x30,0x8e,0x1b,0x2c, - 0x3f,0xb3,0xf8,0x8c,0x52,0xbe,0x8d,0x95,0xa3,0x2c,0xbe,0xdf,0xd2,0x77,0x60,0x2f, - 0x8e,0x09,0xc6,0x54,0xf5,0x06,0x84,0xaa,0xba,0xef,0xde,0x7a,0xb1,0xb9,0x35,0x3a, - 0xee,0xb7,0xf4,0x3d,0xd9,0x11,0x41,0x7a,0xb4,0x01,0xa0,0xcc,0xb7,0x96,0xe3,0x4f, - 0x46,0xec,0xb2,0x54,0xdd,0x22,0xf0,0x07,0x95,0x43,0xae,0xbf,0x4a,0x60,0xde,0x6c, - 0x73,0x9f,0xf9,0x3d,0x8f,0xf8,0xb6,0x42,0x92,0x28,0x2a,0x59,0xaf,0xf1,0xb4,0x53, - 0x10,0xec,0x18,0x99,0x4a,0x4a,0xfd,0x7b,0x60,0x51,0x4e,0xbd,0xc9,0xe9,0xfa,0x7e, - 0xcb,0x4f,0x23,0xf2,0xed,0x50,0x4a,0x4e,0x38,0x37,0x40,0xc8,0xa8,0xbe,0x8b,0x6e, - 0x3b,0x2f,0xcb,0x06,0x0a,0xc5,0x2c,0xbb,0xcd,0xd1,0xb9,0x81,0x99,0xe5,0xe7,0x29, - 0x6b,0xd3,0x5a,0xfd,0x55,0xda,0x7e,0x2c,0x6a,0xb9,0x45,0xdb,0xfa,0xfe,0x92,0x5b, - 0x0b,0x98,0xcc,0x02,0x66,0xe2,0x0e,0x0d,0x28,0xcb,0x7b,0x8a,0x71,0x01,0xe3,0x16, - 0x8b,0xa4,0x2a,0xa6,0x42,0xd7,0x45,0x05,0xc3,0xb6,0x09,0x67,0xfa,0x3b,0xd4,0x21, - 0x03,0x30,0xa1,0xa8,0x44,0xb1,0x01,0x23,0x53,0xf7,0xa6,0x2f,0x41,0xb8,0x07,0x81, - 0xcf,0xd5,0xb4,0xa8,0x16,0x5f,0x25,0x2f,0x67,0xe3,0xb9,0xcc,0x60,0x67,0x65,0x89, - 0x33,0xaa,0xcd,0xb3,0x4d,0xd2,0xfb,0x9e,0xad,0x1a,0x43,0xd1,0x19,0x80,0xe0,0xf8, - 0x60,0x13,0x4c,0x76,0x4f,0xad,0xbd,0xf8,0x70,0x7a,0x7e,0x07,0x16,0xe5,0x7d,0xa8, - 0xb3,0x75,0x16,0xf8,0x1e,0xb2,0xfe,0x3a,0x92,0x55,0xa4,0x04,0x5c,0xbc,0xe8,0x71, - 0xc7,0xbb,0x37,0xaf,0x05,0x47,0x19,0x8e,0x16,0xaf,0xcf,0x4f,0xe1,0x56,0x92,0x44, - 0x55,0x7a,0x87,0xea,0xb8,0x34,0xa1,0x52,0x81,0x38,0x6d,0xb4,0x40,0x4c,0x8b,0x18, - 0xfe,0x9a,0xd9,0xa6,0x05,0x9b,0xeb,0x34,0x11,0x29,0xf8,0xa8,0xe4,0x15,0xbc,0x90, - 0xf1,0x02,0x6c,0xd3,0xf4,0xd5,0xee,0xf1,0xd1,0x63,0xf1,0xfd,0x99,0x35,0xfe,0x3b, - 0x05,0x4f,0xa4,0xc3,0x0c,0x44,0x35,0xcb,0x01,0x63,0xae,0x2a,0x21,0xf3,0x98,0xd1, - 0xc8,0x55,0x3d,0x2f,0xaa,0xcb,0x06,0x4d,0xae,0x5b,0x0a,0xae,0x10,0x08,0x08,0xec, - 0xb8,0x20,0xaf,0x98,0x66,0x8c,0xd1,0x0e,0xa3,0x2b,0x2e,0x95,0x2a,0xb5,0x88,0x2b, - 0x39,0xc7,0xa4,0xe0,0x8b,0xcc,0xbf,0x68,0xc4,0xf4,0xab,0x86,0xcb,0x9c,0xf2,0x2e, - 0xb1,0x4e,0xee,0x69,0x75,0xec,0x5e,0x77,0x08,0x75,0xa2,0xef,0x94,0xea,0x2e,0x14, - 0xa4,0x48,0x80,0x92,0xda,0xe9,0xd4,0x12,0x1c,0xc5,0xd8,0x1a,0x59,0xd8,0x27,0x29, - 0x4f,0xed,0xf2,0x8d,0xe3,0x72,0xa0,0x31,0x2f,0x04,0xa2,0xb4,0x4b,0x22,0x21,0xa2, - 0x8c,0x08,0xac,0x18,0x29,0x31,0x2b,0x05,0x1a,0x45,0x1e,0xa9,0x70,0x83,0xd2,0xf4, - 0xdb,0x50,0xf2,0x17,0x04,0xec,0xd0,0x68,0x97,0x68,0xcb,0x41,0x06,0xc5,0x0e,0x80, - 0xeb,0xb5,0xdc,0x69,0x04,0xa4,0x98,0xe7,0x02,0x01,0x8b,0x2e,0x8b,0x3a,0x10,0x54, - 0xfc,0x33,0xa1,0x4c,0x5a,0x9b,0xa1,0x4e,0x68,0xd1,0x25,0xff,0x0f,0x66,0xc7,0xaf, - 0x92,0xbf,0x9d,0xd7,0x21,0x9a,0xbe,0x2f,0xd9,0x91,0xc7,0x6d,0x19,0xc6,0xea,0x9e, - 0x4b,0x4f,0xe3,0x18,0x5e,0x59,0x6f,0xac,0x4d,0xef,0x69,0x0c,0x7f,0x80,0x8b,0xd9, - 0x5c,0x99,0xdf,0xd3,0xfc,0xfd,0xd9,0x90,0x71,0x53,0xb1,0xf5,0xef,0x5a,0x4b,0xda, - 0xb8,0x65,0x19,0xf4,0xef,0xdb,0x1d,0xfd,0x29,0x92,0x31,0xbd,0x05,0x24,0xba,0x1f, - 0x90,0x0f,0x0a,0x12,0x00,0xc1,0xb9,0x4a,0xe5,0x06,0x00,0xb4,0xbf,0x1a,0x56,0x98, - 0xcc,0xe1,0xf8,0xa5,0x14,0x93,0x4a,0x25,0xc3,0xdd,0x83,0x5d,0xe0,0x44,0x9e,0x5a, - 0x1e,0x8b,0xbd,0x29,0x42,0xc0,0xa2,0x1e,0x88,0xf5,0xa8,0xb5,0x3f,0xa0,0xcf,0xda, - 0x53,0x4a,0x40,0xb4,0x60,0x76,0x9a,0x7d,0x9a,0x8a,0x73,0x5b,0xc0,0xfe,0xc6,0x4d, - 0xdb,0xaa,0x79,0x5c,0x44,0xb3,0x29,0x8e,0x1b,0x40,0x68,0xdf,0x64,0x8a,0x7e,0x9e, - 0x2d,0xbe,0x8b,0x31,0x63,0xb5,0x5e,0x70,0x39,0x72,0x47,0xed,0x8a,0xd1,0xf1,0xf0, - 0xb0,0xff,0xf8,0xf9,0x93,0x67,0x4f,0x4f,0xdc,0xd1,0x81,0xfd,0xe9,0x05,0x75,0xf1, - 0x36,0xbd,0x56,0xb1,0x7b,0xe4,0xed,0x3b,0xe2,0xfc,0xcc,0x09,0xf9,0x4e,0x82,0xf3, - 0x36,0x9e,0x76,0xf4,0x98,0x06,0xbe,0x3f,0x73,0x3a,0x70,0xe3,0x59,0x45,0x55,0x74, - 0xd0,0x92,0x6e,0x1b,0x62,0x73,0x8d,0x91,0x64,0x45,0x81,0xee,0x83,0xe7,0x4f,0x1f, - 0xf7,0xfb,0x9e,0x3f,0xd9,0xe8,0xfd,0x96,0x7b,0x0f,0x1e,0x3d,0xa5,0x21,0xa3,0x98, - 0x62,0xba,0x39,0x83,0xc6,0x0e,0x9e,0x62,0xf8,0x7a,0xa8,0xbf,0x7d,0xda,0x1f,0x60, - 0x56,0x9a,0xb8,0xb1,0xd7,0x1c,0x78,0xdf,0x89,0x85,0xb3,0x3f,0xd9,0x77,0x26,0xce, - 0x00,0x03,0x93,0x66,0x80,0x7a,0x30,0x30,0xdd,0x77,0xa6,0x8e,0x5d,0x34,0x6d,0xc6, - 0xa8,0x13,0x63,0xd7,0xfb,0x8e,0x76,0x9a,0xdb,0x02,0xd3,0xd8,0xe9,0x1c,0x27,0xca, - 0xb4,0xab,0x32,0x3f,0xf2,0x96,0x2a,0x0b,0x58,0x30,0x48,0x15,0x86,0x0e,0xc2,0x34, - 0x2c,0x8e,0x3a,0x33,0xcb,0x59,0xed,0xa6,0xb1,0x5f,0xd3,0x5c,0x3a,0xba,0x1a,0x82, - 0x27,0xb1,0x37,0xd8,0xba,0xd8,0x43,0x7b,0x0d,0x26,0xba,0xb9,0x71,0x40,0xbc,0x83, - 0x03,0xa1,0x74,0xf9,0x77,0x68,0xa7,0xaa,0xf1,0xaf,0xe4,0xeb,0x09,0x24,0x44,0x8d, - 0x8b,0xe0,0x20,0x86,0xef,0x15,0xc8,0x06,0xf9,0x08,0x6e,0x04,0x0c,0x48,0x0c,0x1b, - 0xf4,0x71,0xc2,0x3e,0x4e,0x0b,0x09,0x87,0x36,0x26,0x40,0x91,0x9c,0x69,0x6a,0x63, - 0x41,0xa5,0x62,0x98,0x42,0x18,0xcb,0x0a,0x19,0x56,0x41,0xb6,0x0b,0xc6,0x51,0xcc, - 0x81,0x86,0x98,0xe5,0xf0,0x9d,0x48,0x22,0x62,0x58,0x4e,0x5e,0x61,0xe2,0x9c,0x8e, - 0xdd,0x24,0x58,0x52,0x44,0x95,0xd4,0x13,0xb8,0xb0,0x02,0xc6,0x56,0x5d,0x23,0x1e, - 0x84,0x27,0xcc,0xd2,0x4b,0x85,0xa1,0x09,0x19,0x4d,0x4a,0xa1,0xc8,0x6e,0x66,0xb3, - 0x71,0xb0,0x43,0xa7,0xfe,0xf0,0x61,0xb8,0x2c,0xc9,0xe3,0x15,0x79,0xe8,0xf0,0x0f, - 0xcc,0x71,0x7c,0x50,0x20,0x74,0xf8,0x7c,0xa2,0x4c,0xd1,0xd6,0xf3,0xd0,0xa1,0x4a, - 0xda,0xdc,0xe0,0xc9,0xb9,0x82,0xe3,0xc3,0xfc,0xa6,0x51,0xe8,0x98,0x4d,0x5d,0x6e, - 0x79,0x0e,0x89,0x04,0xa2,0xb9,0xbf,0xcf,0x63,0x80,0xe0,0xfb,0xb3,0xb8,0x18,0x0b, - 0x97,0x6b,0x2f,0xd5,0xac,0xac,0x31,0xa3,0x46,0xee,0xb8,0x3d,0x4e,0x7d,0x18,0xda, - 0xe8,0x65,0x58,0x31,0xf9,0xd3,0x0c,0xff,0x50,0xff,0xa5,0x3d,0x38,0x75,0x0a,0xee, - 0x75,0xfc,0x11,0x14,0x3f,0x2f,0x66,0x58,0xd7,0xfc,0x02,0x2e,0x7c,0x92,0x38,0x2d, - 0x3d,0x67,0x35,0xe0,0x83,0x9e,0xfd,0x78,0xf1,0x1f,0x74,0x19,0xcc,0x5e,0x10,0xa0, - 0xaa,0xb4,0x26,0x27,0xde,0x28,0xb0,0xe3,0xcf,0xca,0x98,0x2f,0x8a,0x2b,0x15,0xa9, - 0xf4,0x8a,0xc6,0x1a,0x4e,0x12,0x08,0x86,0x01,0x39,0xa8,0x87,0x74,0x19,0x3a,0xe8, - 0x88,0x11,0x65,0xfb,0x74,0x7b,0x0a,0x54,0x79,0x3c,0x26,0xc1,0xfd,0xc6,0x75,0x66, - 0xa5,0xe3,0x6d,0x88,0x12,0x7a,0x20,0x82,0xa4,0x6f,0x71,0x00,0x3a,0x20,0xfe,0xf7, - 0x68,0x2a,0xf8,0x76,0x9f,0x4c,0xfc,0x33,0xd9,0x37,0x27,0xde,0x3e,0xfa,0x0d,0x24, - 0x44,0x32,0x13,0x92,0xc3,0x42,0x68,0xb9,0xa0,0xd0,0x04,0xae,0xb0,0x15,0x48,0xf6, - 0xbe,0x6b,0xa0,0xb4,0x59,0x91,0x04,0xe2,0x55,0x81,0x31,0x4c,0xd7,0x94,0x8f,0x53, - 0x64,0x63,0x40,0x01,0xf3,0x4a,0x8a,0xdf,0x7e,0xfd,0x27,0x01,0xb5,0xe1,0x4f,0xac, - 0x12,0x39,0x43,0xb4,0xde,0x46,0x47,0x45,0xaa,0x19,0x69,0xca,0xe4,0x21,0x85,0xf5, - 0x04,0x93,0x03,0xac,0x27,0xe5,0x72,0x92,0xb9,0xe3,0xc7,0xc1,0x15,0xa2,0x36,0x10, - 0x6a,0xdf,0xc5,0xb1,0xaf,0x28,0x7b,0xce,0xeb,0xbd,0xbd,0xf6,0xe7,0x83,0xe1,0xd0, - 0x89,0x80,0x80,0xe3,0x9d,0x38,0xe2,0x7f,0xff,0x87,0x08,0xd4,0x0c,0xed,0xaf,0x17, - 0xfc,0xbb,0x81,0x81,0x29,0x9d,0x71,0xdb,0x19,0x3a,0x8e,0x47,0xff,0x67,0x62,0xf2, - 0xbe,0xc8,0x7c,0x69,0x63,0xbe,0x05,0x85,0xc2,0xf6,0x9c,0xf5,0x50,0x55,0x39,0xfe, - 0x87,0x0f,0x9f,0xe2,0x80,0x65,0xfb,0x03,0xab,0xee,0xcf,0x37,0x37,0x1b,0x6d,0x5e, - 0xe2,0x1f,0xb0,0x38,0xdf,0x40,0x1e,0x6f,0x1a,0xb1,0x3a,0x00,0x3b,0x35,0x78,0xdd, - 0x9d,0x0c,0xb4,0x47,0x32,0x76,0x08,0x81,0xf5,0xfe,0x48,0x7f,0x0d,0x02,0x7a,0x71, - 0xe2,0x92,0xe0,0x7d,0x32,0x0d,0xde,0x89,0x7e,0x00,0x61,0xba,0x20,0xb3,0x53,0x1c, - 0x2a,0x73,0x6f,0x82,0x28,0x73,0x1a,0xe5,0xf0,0xa6,0x39,0x81,0xe1,0x0a,0x76,0x8d, - 0x7b,0xa6,0x1e,0x81,0x10,0x78,0x60,0x62,0xe7,0x79,0x0a,0x7d,0x11,0x14,0x19,0xeb, - 0x46,0xc3,0xed,0x5b,0x0b,0x44,0x45,0x53,0xc5,0xa2,0x15,0x88,0x33,0x70,0x57,0xc4, - 0x12,0xa6,0x82,0x21,0xf1,0xbb,0x08,0x63,0x78,0x0c,0xe7,0x60,0xaf,0xc0,0x7c,0xbf, - 0xb5,0x30,0xcc,0x60,0x7e,0x10,0xa1,0xd1,0x47,0x17,0x9b,0xe8,0x99,0xb2,0x71,0x81, - 0x3b,0x85,0x44,0x53,0x6d,0xd0,0xca,0x4a,0x4a,0x11,0xb9,0x98,0x43,0xe6,0x48,0x60, - 0x48,0x3c,0x24,0x6b,0xa7,0x29,0x1f,0x01,0x5a,0xec,0x1b,0xe3,0xd8,0xe6,0xd1,0x24, - 0x35,0xac,0xca,0x23,0x95,0x14,0x95,0x09,0xa0,0x19,0x96,0x89,0xfd,0xd8,0xea,0x11, - 0xb2,0x01,0xf7,0x9a,0xa1,0x53,0x82,0x4b,0xd1,0x77,0x15,0x1b,0xf4,0x8d,0x48,0x5b, - 0xf9,0xa3,0xd9,0x14,0x52,0xca,0x2c,0x33,0x11,0x65,0xc5,0x65,0x01,0x42,0xb8,0x64, - 0xad,0xa0,0x4b,0xee,0x52,0xc5,0x06,0x56,0x54,0xd0,0x69,0x05,0x3b,0x47,0xe1,0xd2, - 0x9c,0x0b,0x64,0xb0,0x54,0x49,0x25,0x6d,0xea,0x44,0xa1,0x50,0x95,0xb9,0x09,0x25, - 0x49,0xbd,0xed,0x09,0xe8,0x84,0x5c,0xda,0x32,0xc0,0x0c,0x99,0x2c,0x95,0xb6,0x0e, - 0x06,0xed,0xb1,0x1b,0x07,0xe2,0x9d,0x4a,0x08,0x3f,0xca,0x72,0xea,0x56,0xe7,0xb5, - 0x4c,0x2d,0x4e,0xbb,0x92,0x2c,0x9c,0x2f,0x9e,0xf6,0x05,0x55,0x13,0x84,0x1c,0x91, - 0x31,0x93,0x04,0xee,0x1f,0x2a,0x37,0xf8,0xf8,0x0d,0x87,0x3b,0x8a,0x5c,0xaa,0xa2, - 0x04,0xaf,0x35,0xce,0xcb,0x66,0xc2,0x40,0xc3,0x24,0xb6,0x13,0xad,0x99,0x08,0xc4, - 0x77,0xb0,0x2c,0x05,0x98,0xce,0x69,0x4c,0xb8,0x05,0xb9,0xa1,0xa3,0xe1,0x9c,0xcf, - 0x86,0x88,0xce,0xd8,0x42,0x13,0x49,0x26,0xc7,0x74,0x1e,0x8a,0xe0,0x73,0xc4,0xf4, - 0x45,0x3e,0xc6,0xa9,0xf9,0x75,0x06,0x1b,0x90,0xc0,0x46,0x11,0x06,0xea,0xf0,0xc1, - 0x83,0x38,0xe8,0x10,0x76,0xd0,0xc4,0x18,0xe0,0xd3,0x30,0x0e,0x78,0x17,0x52,0x08, - 0x2b,0xaa,0xef,0x59,0x4c,0x6e,0x6e,0xcc,0xe2,0xb5,0x26,0xcc,0xa1,0xb2,0xa6,0xef, - 0xc4,0x61,0xf4,0x72,0x0d,0xdb,0xce,0xf6,0x19,0xe7,0x32,0x06,0xb5,0x13,0xe7,0x98, - 0x2d,0x4f,0xc7,0xea,0x5c,0x23,0xe2,0x41,0x88,0xe2,0x85,0x1c,0xa3,0xd8,0x0d,0x4f, - 0x1c,0x73,0x3c,0x27,0xdc,0xda,0xf8,0xc4,0x31,0x72,0xca,0x50,0xad,0x9b,0x80,0x4e, - 0x32,0x47,0xd6,0x08,0xb0,0xae,0xd3,0x01,0xb6,0x94,0x96,0x8d,0xf8,0x5a,0xeb,0xd6, - 0xc4,0x29,0x8d,0x7b,0x37,0xe2,0x64,0xb2,0x38,0xda,0x60,0xa4,0xe8,0x00,0x45,0xa9, - 0xf2,0xd0,0x8e,0xcd,0xd8,0x90,0x1a,0x50,0x20,0xef,0xac,0xe4,0x12,0xc4,0x88,0x3c, - 0x21,0x29,0x91,0xa4,0x65,0x53,0x48,0x37,0xbd,0x4d,0xe2,0xec,0x73,0x0d,0x11,0x09, - 0xd0,0x94,0xcb,0x08,0x36,0x17,0x05,0x87,0xc8,0xbd,0x29,0xe6,0xc7,0x37,0x4c,0x42, - 0xca,0xbc,0xb7,0xdc,0x91,0x39,0x12,0xd3,0xe6,0xc4,0xf9,0x78,0x87,0xba,0x10,0xb1, - 0x23,0x32,0x1f,0x46,0x47,0x7a,0x08,0xeb,0xa9,0x32,0x82,0x68,0x02,0xd6,0x87,0xb6, - 0x97,0x1b,0x95,0xa8,0x46,0x7c,0x4c,0x68,0xc6,0xfc,0x21,0x2d,0x90,0x46,0x63,0x06, - 0x02,0x46,0x6a,0xc2,0xcb,0x38,0x12,0x40,0xd4,0x82,0xb8,0x17,0xb9,0x99,0x15,0x27, - 0x99,0x41,0xe9,0x46,0x14,0xa7,0x24,0x4a,0x02,0x00,0x8c,0x92,0x34,0x1e,0x1a,0xe2, - 0x2e,0xd9,0xe8,0xcc,0x58,0x26,0xc9,0xa3,0xb1,0xc4,0xc1,0x28,0x2d,0x48,0x2d,0x55, - 0x96,0x30,0xec,0x94,0xe6,0x41,0xa7,0x67,0x30,0x0b,0x20,0x18,0x82,0x22,0xc8,0x7b, - 0xc2,0x3b,0x92,0xaf,0x25,0x65,0x02,0xb2,0x26,0x3b,0x1f,0xc3,0xa2,0xb3,0xad,0xbb, - 0xcc,0x8b,0x91,0x66,0x6d,0x6e,0x4e,0x61,0x8c,0x29,0x6d,0x4c,0x96,0x31,0x86,0xb9, - 0x45,0xf0,0x55,0xa7,0x59,0xc7,0x22,0xd8,0xf8,0x47,0x0f,0x60,0x8d,0x29,0x50,0x6b, - 0x34,0xf2,0x6f,0x69,0xef,0x6d,0x6a,0x75,0x1a,0x2b,0x32,0xb2,0xab,0x97,0x9a,0xb5, - 0x8e,0xe8,0x08,0x84,0x65,0x74,0xd9,0xaa,0xaf,0x9c,0xb6,0xa4,0x63,0x8b,0x53,0xa6, - 0x18,0x94,0xe4,0x82,0xd9,0x92,0x74,0x6d,0x07,0x30,0x1c,0x23,0xcc,0x08,0x1c,0xe6, - 0x56,0x68,0x45,0xd9,0xb2,0xce,0x94,0x50,0x8b,0x24,0xf1,0xed,0xae,0x76,0x03,0x1b, - 0x17,0x06,0xb0,0x9a,0x0b,0x3e,0x27,0x51,0xc5,0x96,0xd1,0x49,0xa8,0x4d,0x68,0x0a, - 0x3e,0xc7,0x85,0x15,0x50,0xeb,0x47,0x3e,0xeb,0x41,0xda,0xed,0xb7,0x14,0xa7,0x49, - 0x7d,0x98,0x62,0x46,0xb2,0x49,0xfe,0x20,0x65,0x1c,0x88,0x18,0x5d,0x1a,0x6c,0xe8, - 0x00,0x48,0x38,0x23,0x8a,0x70,0x50,0xd3,0x18,0xf1,0x18,0x76,0x31,0x20,0x95,0x62, - 0x67,0xc7,0x86,0xa4,0xd4,0xb0,0x14,0x2c,0x40,0x3f,0xea,0x93,0x43,0xf5,0xf4,0xa0, - 0x6d,0x85,0x7d,0x1b,0x67,0x61,0xce,0x96,0x64,0xaf,0x57,0xb8,0x46,0x55,0xe1,0x93, - 0x9c,0x10,0xf3,0xda,0x04,0xe9,0x90,0xf2,0x20,0x5e,0x18,0xc2,0xb9,0x12,0x20,0xca, - 0x1b,0x1a,0x60,0xbe,0x59,0xc5,0x4b,0x8e,0x87,0x8f,0x9f,0x9c,0x38,0xc5,0xa5,0x6d, - 0x1c,0x3d,0x69,0x15,0x9f,0x4c,0x81,0xd7,0xe0,0x50,0x7f,0x0e,0x85,0xbd,0xbd,0x07, - 0x0c,0xcd,0x6d,0x7b,0x8c,0x55,0xda,0xcc,0xd5,0xa6,0xda,0x69,0x10,0x01,0x34,0xe8, - 0xd5,0x2d,0x70,0x64,0x0d,0x40,0x58,0x8a,0x9c,0x8c,0xda,0x0d,0x11,0x38,0xf5,0x9c, - 0x13,0xc7,0x0e,0xfc,0xf6,0xeb,0x7f,0x3b,0x8d,0xa1,0x33,0x13,0x28,0x7c,0x32,0xbf, - 0xbe,0xd3,0xe7,0x5c,0x1e,0x43,0xf8,0x24,0x5c,0x53,0x29,0xf3,0xb0,0x1f,0x1a,0x23, - 0x5b,0x7b,0xf5,0x6c,0x80,0x41,0xc6,0xe2,0xf6,0xde,0x4d,0x8c,0x3c,0xa0,0xe1,0xf2, - 0xf6,0x30,0x87,0x43,0xda,0x22,0x5f,0x4e,0x6f,0x4d,0x30,0x5b,0xea,0xd6,0xa4,0x67, - 0xf4,0x10,0x93,0x4f,0xc4,0x8f,0xc0,0x10,0xe0,0xd0,0xd5,0xde,0x46,0x5f,0x37,0xaa, - 0xb2,0xb2,0x90,0xc5,0x96,0x0c,0xfc,0x76,0xce,0x24,0x87,0x59,0x0c,0x3a,0xc2,0xbb, - 0x70,0xf4,0xcd,0xdb,0x37,0x65,0xd7,0xed,0xd8,0x9b,0xab,0xba,0x9d,0x2a,0x61,0x08, - 0xcf,0xd1,0x2e,0xdf,0x62,0x09,0xa4,0xc3,0xa6,0xb5,0xc4,0x19,0x21,0x86,0x82,0x6f, - 0x81,0xec,0x0a,0xfa,0xf9,0x85,0x05,0xfb,0x98,0x9b,0x15,0x11,0x05,0x27,0xcd,0x7c, - 0xd3,0xfc,0xe2,0x1a,0x10,0x90,0xb3,0x03,0x5a,0xc0,0xbf,0x6f,0xcf,0x66,0x29,0xa1, - 0x73,0xaf,0x84,0xca,0xe0,0x2c,0xbe,0x7a,0xe4,0x1f,0x8a,0xee,0x81,0xe1,0xd9,0x74, - 0x4a,0xf9,0x24,0x59,0xac,0xc0,0x00,0xda,0x59,0x7b,0x2e,0x9e,0x52,0xd9,0x52,0x1a, - 0xa7,0xf1,0x8d,0xa8,0x98,0x0a,0x35,0xc7,0xbc,0xd5,0x95,0xf2,0x9a,0x54,0x80,0xaf, - 0x5d,0x59,0x73,0xa7,0x2c,0x1e,0xda,0xb7,0x61,0x65,0x61,0xad,0x47,0x56,0xcc,0x2a, - 0x4a,0x51,0x32,0x8e,0x89,0x6a,0x0a,0xfa,0xc8,0xb2,0x61,0x09,0x19,0xea,0x84,0x8e, - 0x65,0xe3,0xa6,0x90,0x32,0x5f,0x2e,0x06,0x56,0xb0,0xb5,0x71,0x13,0x71,0xb0,0x79, - 0xe2,0xb8,0xca,0x9a,0xf7,0xe7,0xe2,0xfb,0x33,0xc1,0xe5,0xda,0x26,0xd0,0xa8,0xf4, - 0xd5,0xd0,0x6d,0x04,0xcc,0x20,0x4a,0x1a,0x72,0x27,0xe2,0x37,0x37,0x47,0x8f,0x9f, - 0x3c,0x7b,0x6a,0xc5,0x14,0x2b,0xb7,0xe8,0x75,0x39,0x72,0xd1,0xb9,0x0e,0xc1,0x27, - 0xa9,0xe3,0xa3,0x2f,0x0e,0xa8,0x4c,0xdd,0xd4,0xac,0x61,0x1b,0x36,0xda,0xc7,0x58, - 0xb2,0xff,0xfc,0xf0,0xc5,0x91,0xb1,0x11,0xb7,0x07,0xef,0x34,0x17,0x93,0xec,0xf6, - 0xde,0x66,0xa9,0x2d,0xd0,0xb7,0x13,0xcb,0xcf,0x4d,0x7c,0xaf,0x2b,0x7a,0xf6,0xb6, - 0x63,0x2b,0x2b,0x41,0x02,0x1d,0x87,0x9f,0x52,0xb1,0x55,0x05,0xa2,0x0e,0x59,0x67, - 0xb2,0x44,0xfa,0x47,0x8a,0xbf,0x21,0xe9,0xdc,0xe0,0x9b,0x9a,0x01,0x4f,0x32,0x59, - 0x9a,0xe6,0x73,0x62,0xb8,0x47,0x0b,0xd8,0x32,0xd2,0xf5,0x00,0x08,0xed,0xec,0x9b, - 0x01,0x93,0x5b,0x19,0x4b,0x47,0xd5,0x5f,0x20,0xc5,0xe5,0xdf,0xc0,0xbc,0x90,0xa4, - 0x29,0x27,0xb4,0xf6,0x00,0x3f,0xfe,0x00,0xc1,0x0d,0xfb,0x80,0xf2,0xed,0x86,0xb0, - 0xae,0xf7,0xe2,0x20,0x6e,0x6a,0x90,0x45,0xcb,0xd0,0xe5,0x73,0xa0,0x9d,0xbe,0x33, - 0x80,0x9c,0xb6,0xa8,0xb2,0x95,0x48,0xf4,0xb6,0xdd,0xb0,0x3d,0x5b,0x56,0x03,0x32, - 0x74,0x61,0x2a,0xc6,0x26,0xe0,0x0d,0xe0,0xa1,0x29,0xcf,0x29,0xda,0x5a,0xb3,0xad, - 0x30,0xc3,0x2b,0xb2,0xd0,0xda,0x12,0x32,0x95,0xa6,0x5d,0x13,0x69,0x40,0xd8,0x11, - 0xfe,0x37,0x11,0x70,0x27,0x4b,0xaf,0x6c,0x8d,0x91,0x9e,0xb9,0x7a,0x7e,0xeb,0xc2, - 0xa4,0xd5,0x64,0xce,0x4e,0xcc,0x05,0x37,0x64,0x9d,0x72,0xe6,0x46,0x64,0x27,0xe4, - 0xd1,0xec,0x46,0x8d,0x25,0xe3,0xc3,0x69,0x4d,0x27,0x99,0xa7,0x49,0x7a,0x02,0x1b, - 0xa0,0xd3,0x18,0xd2,0x74,0x95,0xca,0x3f,0x37,0x53,0x27,0x3a,0x98,0x21,0x7c,0x6d, - 0x70,0xa4,0x1c,0x10,0x47,0xb5,0x0f,0x20,0x1c,0xdf,0xda,0x7e,0x5e,0x6f,0x65,0xf1, - 0x8e,0xd5,0x77,0x08,0x63,0x75,0xdb,0x7d,0x5a,0x24,0x2a,0x60,0x01,0x69,0x88,0xcf, - 0xa6,0x5d,0xef,0x94,0x96,0x9f,0x9b,0x9f,0x96,0xcd,0x34,0x6b,0x54,0x46,0x85,0xac, - 0x62,0x6b,0x53,0xf8,0x2d,0x65,0x93,0x78,0xac,0x2b,0x0a,0x94,0x0a,0x81,0x21,0x26, - 0xea,0x31,0xe1,0x95,0x09,0xf0,0xa9,0x88,0xd1,0xd0,0x2c,0x9f,0x0e,0x3f,0xfd,0xdc, - 0x14,0x11,0x41,0x3c,0x5d,0x9f,0x12,0x34,0x2f,0x9f,0x9a,0xd7,0xdc,0x9d,0xbe,0x7d, - 0x27,0x20,0x73,0x9b,0x99,0xe3,0xb5,0xf3,0xc9,0x2a,0xd0,0xdf,0x07,0xc3,0xe1,0xe7, - 0x01,0x6c,0xae,0xc5,0x51,0xf3,0x6d,0x5f,0x86,0xf9,0x24,0x32,0xae,0x29,0x55,0x78, - 0x9c,0x9a,0xaf,0x0d,0x06,0x18,0x68,0xc9,0x0c,0x89,0xe3,0x5a,0x06,0x9a,0xc4,0xc9, - 0x7d,0x17,0x3f,0xd2,0xb2,0xa9,0x70,0x70,0xc3,0x94,0x2d,0xc0,0xbe,0xf5,0xa2,0xcb, - 0x36,0x9d,0x20,0xd5,0xd7,0xdb,0x9b,0x63,0x1a,0x15,0xd6,0xdb,0x4d,0x79,0x52,0x74, - 0x7b,0x12,0x60,0xe1,0x5f,0x5b,0x41,0xef,0x30,0x0e,0xe2,0x70,0x8b,0x73,0x6b,0x11, - 0x39,0x71,0xda,0x00,0xf7,0xb7,0x5f,0xff,0x4b,0x37,0xba,0x00,0x94,0x3a,0xc1,0xa4, - 0xd3,0xe8,0x15,0x7c,0x4b,0x13,0xa7,0xd3,0xe5,0x8a,0x30,0xf7,0x71,0xeb,0x3a,0xd6, - 0x04,0xee,0x12,0x76,0xfe,0xfc,0xdf,0x3e,0x7e,0x64,0x4f,0xe1,0x23,0xc8,0x2f,0xe5, - 0x28,0xcd,0xd2,0x7a,0xd1,0x1b,0x4b,0xaa,0x67,0xf5,0x6c,0xae,0x23,0xa8,0xfc,0x63, - 0x56,0x55,0x8a,0x1e,0xf7,0x98,0xa0,0x5f,0x35,0x1b,0x38,0xda,0xe6,0xfa,0x08,0xf7, - 0xa9,0xa4,0x4a,0xd7,0x7e,0x5b,0x43,0x06,0x52,0xa7,0xfe,0x01,0x65,0x5c,0x4f,0x21, - 0xe9,0x23,0xf0,0x3e,0x43,0x05,0x5d,0x10,0x67,0xb7,0xd5,0x53,0xf3,0x24,0x26,0x10, - 0x2e,0xbd,0x20,0x31,0x70,0x3a,0xcf,0x48,0x6c,0x44,0x1d,0xc9,0xaa,0x4a,0x95,0x6e, - 0x33,0x62,0xf3,0x9e,0xc5,0x96,0x7b,0xcd,0x3e,0x50,0x7d,0xa4,0xf8,0x79,0x1c,0x78, - 0x3b,0x70,0xab,0x80,0xf2,0xdb,0x3f,0x7f,0xc5,0x7f,0x62,0xfb,0x61,0x8a,0xed,0xff, - 0xff,0xfa,0x8f,0x30,0x7b,0xd3,0x79,0x92,0x53,0x98,0x04,0x29,0xa3,0x52,0x50,0x2d, - 0xec,0xdb,0x1c,0xe8,0xe9,0xee,0xa5,0x5a,0x84,0xd0,0xbd,0x6c,0xa6,0x76,0x99,0x81, - 0xf4,0x5a,0x47,0xd1,0x33,0x20,0x51,0xf0,0x77,0x31,0x9a,0x20,0xc5,0xf6,0x8d,0x10, - 0x7c,0xbe,0x34,0xaf,0x84,0xcc,0x3d,0x3e,0xdd,0xb5,0x6a,0x3d,0x53,0x26,0x71,0x8d, - 0xb8,0xec,0x48,0xf5,0x45,0xae,0x98,0x98,0xcb,0x53,0xd9,0xa9,0x5f,0x98,0x32,0x38, - 0x55,0xb8,0x83,0x75,0x5d,0x35,0x01,0x4e,0x6e,0xe1,0x97,0x7e,0x31,0xab,0xd9,0xa7, - 0x21,0x21,0x72,0xc9,0x18,0x5c,0x52,0x39,0xbd,0xe8,0xb8,0xb9,0xab,0x61,0xf1,0xe9, - 0xf2,0x67,0x3f,0x1f,0x96,0x27,0x25,0x54,0x18,0x4e,0x2b,0xbc,0x34,0xfe,0x0a,0xea, - 0x7f,0xb5,0xb7,0x47,0x6f,0x86,0x70,0xce,0x2b,0x8a,0x98,0x0d,0xf2,0x0e,0xa2,0xf2, - 0xd3,0xaa,0x92,0x8b,0x20,0xd5,0xfc,0xd7,0xbd,0xf2,0x3c,0xde,0xf0,0xca,0xcf,0x79, - 0x43,0xb3,0x9e,0x5d,0x17,0x9a,0xc6,0x48,0xe4,0xfb,0x0e,0x47,0x8d,0xdb,0x2b,0x4f, - 0xae,0x82,0xa9,0x2c,0xd7,0x9f,0x1b,0x5c,0xb7,0xd7,0x34,0xd7,0xed,0xe6,0xd7,0x9d, - 0xcd,0x4f,0xfe,0x72,0xf1,0xd7,0x1f,0xe0,0xe5,0xa8,0x86,0x91,0x26,0x0b,0xcc,0x0f, - 0xaf,0x57,0x9e,0x35,0x2c,0x3e,0xcc,0x4a,0x78,0x65,0x1c,0x2e,0xf9,0xbd,0xe6,0xb3, - 0x88,0x59,0x4d,0xd7,0x1c,0x20,0xd4,0xa4,0xae,0xcb,0x90,0xa2,0x23,0x5b,0xac,0x81, - 0xc3,0x89,0x48,0x0d,0xf9,0xfd,0xe2,0x75,0xcd,0xcc,0xc8,0xe5,0x55,0x0a,0x25,0x2b, - 0x2a,0xb2,0x02,0x25,0x5b,0x61,0x9a,0x3f,0xd3,0x33,0x99,0x21,0x77,0x9f,0x82,0x39, - 0x54,0xe6,0x05,0x14,0x4e,0xae,0x9b,0x5b,0x54,0x69,0x2e,0x1c,0x07,0x42,0x5d,0xab, - 0xe8,0x55,0x31,0x9d,0x22,0x2f,0x76,0x1d,0x7a,0x60,0xe5,0x78,0x6b,0x8d,0x31,0x0a, - 0xd4,0x49,0x70,0xc1,0x0f,0xbe,0x11,0x61,0xb1,0xa2,0x5a,0xa9,0x36,0x61,0x5e,0x1b, - 0x19,0x72,0x1e,0x3e,0xa2,0xea,0x63,0x22,0x6d,0x22,0x4d,0xa8,0x12,0x4a,0x54,0x5c, - 0xe3,0x2c,0x91,0x76,0x21,0x0d,0xa7,0x5b,0x8a,0x8e,0x14,0x64,0x6a,0x2c,0xa3,0x05, - 0x29,0x91,0x5b,0xb7,0x97,0x54,0x72,0xd8,0xde,0x98,0xd1,0xeb,0xff,0x5a,0xd9,0x4b, - 0x33,0xd7,0x69,0x5e,0x60,0x21,0x87,0x2b,0x2e,0x87,0x89,0xcc,0xe8,0xbd,0xaa,0x10, - 0x32,0x60,0x49,0x1e,0xd6,0x03,0x49,0xd1,0xf5,0x69,0x0d,0xda,0xc3,0xe7,0x2b,0x38, - 0x3f,0xfb,0xba,0x0b,0x81,0x88,0xb1,0xbc,0xd2,0x86,0x1f,0x91,0xd6,0x1f,0x01,0x6c, - 0xe8,0xb4,0x8f,0x41,0x39,0x62,0xe5,0x97,0xa0,0x7d,0xf3,0xf4,0xb3,0x3f,0x68,0x9e, - 0x1c,0xf6,0xd9,0xc4,0xb6,0x48,0x51,0x81,0x3e,0x30,0xe6,0xe0,0xd5,0x24,0xcd,0x62, - 0x57,0x36,0xa0,0x55,0x06,0x01,0x70,0x3d,0x83,0xc6,0x05,0xb7,0x00,0xfa,0x83,0xcc, - 0xc7,0xca,0xed,0xfb,0x75,0x90,0xa9,0x7c,0x5c,0x4f,0x78,0x76,0x5d,0x2d,0x96,0x38, - 0x43,0x0b,0xf4,0x0e,0x9e,0xac,0x22,0xaa,0x0e,0xd1,0x27,0x5a,0xab,0x5b,0xdb,0x57, - 0x08,0x7e,0xaf,0x54,0x77,0x7b,0xfa,0xfe,0x66,0xeb,0xeb,0x1b,0x86,0x03,0x11,0x4b, - 0x28,0x78,0xa3,0xf3,0x77,0x2f,0xd2,0x30,0x44,0x14,0xb0,0x74,0xc7,0x6a,0xfb,0x49, - 0x5e,0xaa,0x2f,0x58,0xe2,0x5e,0x19,0x81,0xdb,0xdb,0xbb,0x43,0xda,0xee,0xec,0x0c, - 0xb8,0x28,0x45,0x30,0x3d,0xd6,0xae,0xe6,0xf3,0xa7,0x2f,0xcd,0xc4,0xee,0xe6,0x4b, - 0x22,0xfe,0x04,0xad,0xf3,0xc9,0xd2,0x86,0x60,0xac,0xf8,0x80,0x5f,0xfc,0x9c,0x6a, - 0x6b,0xc5,0x60,0xe1,0xf2,0xaa,0xd5,0xce,0x37,0x0d,0x35,0x03,0x88,0x3f,0x4c,0x63, - 0x5e,0xbf,0x4b,0x61,0xc8,0x72,0x45,0xe4,0x21,0x51,0x77,0xba,0xdb,0x5a,0x09,0x9c, - 0x0e,0x69,0x19,0x3d,0x22,0x84,0xa4,0x49,0xd3,0x20,0x62,0xb4,0x51,0xc7,0x03,0xaa, - 0x15,0x7b,0xcb,0xf7,0x6f,0x03,0x18,0x3e,0x04,0x12,0x45,0x63,0x5b,0x17,0xaa,0x86, - 0xac,0x29,0xba,0x87,0x98,0x36,0x1f,0x3d,0xad,0x2c,0x54,0x48,0x5b,0xf7,0x33,0x22, - 0xbb,0x82,0x43,0x06,0x3a,0xd4,0x6b,0x48,0xba,0x4b,0x29,0xe1,0x77,0x17,0x7f,0xbd, - 0x60,0xeb,0xe1,0x52,0xb0,0xce,0xe3,0x9c,0x62,0x02,0x45,0x1b,0xc7,0xfc,0x67,0xee, - 0xec,0xb3,0x3d,0x23,0x34,0x20,0xda,0xfe,0xa7,0x9f,0x1b,0x03,0x83,0x21,0x46,0xb2, - 0xc3,0xdf,0xad,0x6f,0xb5,0xbc,0xa5,0x0c,0xcc,0x63,0xc7,0x61,0x5d,0xcd,0xd4,0xa0, - 0x39,0x04,0xbf,0xe8,0xa4,0x90,0x1d,0x81,0x0a,0x90,0x5f,0x6d,0xd1,0x65,0x53,0xcd, - 0x2c,0x00,0xa3,0x82,0x32,0x48,0x20,0x9c,0xda,0x0a,0xbe,0xd5,0x01,0x5e,0xd2,0xc0, - 0x36,0xbd,0x6b,0xd3,0x60,0x2a,0xe9,0x54,0x97,0x63,0x11,0x4d,0x89,0x68,0x69,0x9e, - 0x14,0x4c,0x35,0x32,0x8d,0xc4,0x3b,0x8a,0xf2,0x01,0xa0,0xf3,0x8d,0x9e,0x7b,0x44, - 0x59,0xf3,0x80,0x7a,0xed,0xf7,0x79,0xa5,0x79,0x84,0xbf,0xb3,0xfe,0xc8,0xf4,0xc0, - 0xbc,0xb8,0x3d,0x30,0x9f,0xb4,0xfe,0x1f,0xad,0x8a,0x95,0x31,0xe3,0x3a,0x00,0x00, + 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0x95,0x5b,0xdd,0x72,0xdb,0x38, + 0x96,0xbe,0xf7,0x53,0x20,0x4e,0xb7,0x49,0xb6,0x29,0x5a,0x52,0x6c,0xc7,0xa1,0x42, + 0x6b,0xfd,0xdb,0x93,0xed,0xa4,0x27,0x65,0xa7,0x77,0x6a,0x3b,0xdb,0x35,0x05,0x91, + 0xa0,0xc4,0x36,0x45,0x72,0x09,0x4a,0xb2,0x46,0x56,0x55,0x3f,0xc4,0xdc,0xec,0x0b, + 0xec,0x2b,0xec,0xfd,0x3e,0x4a,0x3f,0xc9,0x7e,0x07,0x00,0x25,0x4a,0x76,0x9c,0x6c, + 0xca,0x91,0x08,0xe0,0xe0,0xe0,0xe0,0xfc,0x1f,0x10,0x7a,0xfb,0x22,0xca,0xc3,0x6a, + 0x5e,0x08,0x36,0xaa,0xc6,0xe9,0xe9,0xce,0x5b,0xfa,0x62,0x29,0xcf,0x86,0xc1,0xae, + 0xc8,0x76,0xa9,0x43,0xf0,0xe8,0xf4,0xed,0x58,0x54,0x9c,0x85,0x23,0x5e,0x4a,0x51, + 0x05,0xbb,0x93,0x2a,0x6e,0x9d,0xd0,0xa0,0x0c,0xcb,0xa4,0xa8,0x98,0x2c,0xc3,0x60, + 0xf7,0xa0,0x88,0x5b,0x61,0x9e,0xc9,0x3c,0x15,0xde,0xef,0xb2,0x3f,0x0a,0x44,0x1c, + 0xc7,0xd1,0x51,0xfb,0x68,0xf7,0xf4,0xed,0x81,0x06,0x3c,0x35,0x13,0x4e,0x93,0xd8, + 0x7e,0x31,0x4b,0xb2,0x28,0x9f,0x79,0x1f,0xaf,0x1d,0x3b,0x9e,0x64,0x61,0x95,0xe4, + 0x99,0xed,0x2c,0xa6,0xbc,0x64,0x7f,0x0b,0xf4,0x98,0xfb,0x4b,0x60,0x1d,0xf0,0x22, + 0x39,0x90,0x15,0xaf,0x26,0xd2,0x72,0xdf,0x07,0x9f,0x7f,0x73,0x3f,0x04,0x5d,0xf1, + 0xc6,0xbd,0x75,0x7f,0x75,0x3f,0x06,0x7f,0xc3,0xf4,0x60,0x41,0xc3,0xc2,0xb7,0xd2, + 0x64,0x2a,0x2c,0x37,0x4a,0xca,0x6a,0xee,0xbf,0xe8,0xb8,0x53,0x3f,0x9b,0xa4,0xa9, + 0x3b,0x14,0x95,0xff,0xa3,0x9b,0x64,0x71,0x9a,0x0c,0x47,0x95,0xff,0xf3,0x64,0x3c, + 0x10,0xa5,0x3b,0xca,0xd3,0xc8,0xff,0xeb,0xe0,0x77,0x11,0x56,0xae,0xe4,0x73,0x7f, + 0x45,0x41,0xe5,0xde,0xb9,0xc2,0x59,0x88,0xbd,0x3d,0x5b,0x78,0x95,0xb8,0xaf,0x2e, + 0xf2,0xac,0x12,0x59,0x15,0x54,0xce,0xd2,0x1d,0x4c,0x64,0x03,0x74,0xe0,0x16,0xce, + 0xa2,0x6e,0xb1,0x18,0xc4,0x0f,0xbc,0x28,0x91,0x7c,0x90,0x8a,0x28,0x78,0xd1,0x59, + 0x36,0x5b,0xed,0x5e,0xe1,0x55,0x23,0x91,0xd9,0xb1,0x1b,0x3b,0xbd,0x52,0x54,0x93, + 0x32,0x63,0xc5,0xd2,0x2d,0xf2,0x34,0x5d,0x63,0x94,0xee,0xd8,0x0d,0xdd,0x5c,0x73, + 0xa1,0x72,0x63,0x77,0x18,0x74,0x7a,0xab,0x15,0x6e,0xb0,0xc2,0x70,0x6f,0xef,0x45, + 0x0c,0xda,0xe2,0xa0,0xe3,0x86,0xa9,0xe0,0xe5,0xa7,0x64,0x2c,0xf2,0x49,0x65,0x57, + 0x8e,0x6b,0x4b,0x2f,0xe4,0x69,0xda,0x97,0xb6,0xe3,0xff,0x68,0x4b,0xc7,0x31,0x2b, + 0xd6,0xd8,0x23,0x67,0x11,0xda,0x91,0x4b,0x5c,0xc1,0x5e,0x56,0xdd,0x82,0xba,0x15, + 0xab,0x84,0xb3,0x34,0x73,0x7e,0x72,0x7f,0x72,0x9c,0xe5,0x6a,0xe5,0x9f,0xb0,0x72, + 0x1c,0xb4,0x7b,0x5b,0x2b,0xf6,0x40,0x8d,0x5d,0x05,0x50,0x89,0xba,0xef,0xc6,0x1d, + 0x63,0x5e,0xbe,0xb7,0x97,0x7b,0x71,0x52,0xca,0x2a,0x08,0xc0,0x88,0x3e,0xa6,0xfb, + 0x20,0xde,0x6c,0x1b,0xe2,0xca,0x0b,0xbf,0x21,0xf2,0xe1,0x63,0xcc,0x4b,0x17,0x48, + 0xd7,0x30,0x99,0xb3,0x18,0x07,0x59,0x2f,0x7e,0x78,0x00,0xaa,0xa5,0x9b,0xe5,0x33, + 0xff,0x66,0x09,0x18,0xa5,0x16,0x6b,0xb0,0x10,0x3b,0xd9,0xdb,0x7b,0xef,0x15,0x13, + 0x39,0x42,0xa3,0x77,0xdb,0x47,0x33,0xb4,0x6f,0x1d,0xff,0xd7,0xfe,0xaf,0x1e,0x66, + 0x81,0x8e,0x5f,0x83,0x8f,0x1e,0x31,0xdd,0xfe,0xc5,0xfd,0xe0,0x5e,0x02,0xd9,0x8c, + 0x57,0xe1,0xe8,0x76,0x0b,0xd3,0xd8,0x59,0x7c,0xf4,0x34,0x7a,0xd0,0xfd,0xab,0x07, + 0x6a,0xec,0x0f,0xc1,0x07,0x5e,0x8d,0xbc,0x71,0x82,0x61,0xf7,0x83,0xa3,0xa6,0x26, + 0xd5,0x75,0x5e,0x5e,0x8a,0x69,0x12,0x8a,0xf5,0x64,0xc8,0x2f,0x0f,0xf2,0x87,0x87, + 0xc5,0xb2,0x16,0x74,0x26,0x66,0xec,0x63,0x99,0x8f,0x13,0x29,0xd6,0xe2,0x98,0xbb, + 0x99,0x16,0xf4,0x68,0x4d,0x52,0x57,0xbc,0x5a,0x0b,0x46,0x3a,0x0b,0x09,0x71,0xdb, + 0xb9,0x37,0x98,0x24,0x69,0xb4,0xb7,0x27,0xf5,0x43,0x10,0x98,0x1e,0x07,0xec,0x1f, + 0x79,0xc4,0x4e,0xdb,0x71,0xe7,0x24,0xf1,0xa5,0xd3,0x6b,0x48,0xa3,0xc1,0xe3,0x1a, + 0xac,0x97,0xd9,0x57,0x65,0x99,0x97,0xb6,0x55,0x69,0x20,0x8b,0x36,0x92,0x7b,0xa6, + 0xf5,0xf0,0xf0,0x46,0x1c,0x02,0xcb,0x72,0xb9,0x56,0xbb,0x1f,0xed,0x09,0xa9,0xa4, + 0xd9,0x4a,0x2c,0xc0,0x2e,0xd5,0xb3,0xa5,0x5d,0xa5,0xb3,0x20,0xab,0x2e,0xbd,0xfc, + 0xce,0xa9,0x46,0x65,0x3e,0x63,0x7a,0xa1,0xd2,0xf0,0x71,0xa5,0xf5,0x4a,0x3b,0xc8, + 0xb2,0xfa,0xa5,0xfa,0x82,0x50,0x4a,0x38,0x0c,0x22,0x73,0xd9,0xd0,0xb9,0x4b,0xda, + 0x3f,0x30,0xe2,0xf3,0x16,0x76,0x5e,0xc4,0x5a,0x46,0x81,0xec,0xbd,0xf7,0xe2,0xbc, + 0xbc,0xe2,0x20,0x63,0xb5,0x78,0x0c,0xfd,0x04,0x24,0x11,0xbe,0x74,0x6c,0x67,0xe5, + 0x6f,0x76,0xb4,0xe3,0xca,0xf8,0x58,0x04,0xbb,0xd3,0x44,0xcc,0x8a,0xbc,0xac,0x76, + 0x59,0x68,0x6c,0x7a,0x77,0x96,0x44,0xd5,0x28,0x88,0x94,0x00,0x5b,0xaa,0x01,0x4f, + 0x91,0x54,0x09,0x4f,0x5b,0x12,0xb6,0x24,0x82,0x0e,0x79,0xb9,0x2a,0xa9,0x52,0x71, + 0xfa,0x91,0x57,0x95,0x28,0xe1,0x47,0xb0,0xb5,0x16,0xd3,0xd4,0xbc,0x3d,0xd0,0x63, + 0xf0,0x84,0xd5,0x9c,0xbe,0x0f,0x7e,0x60,0x17,0xda,0x07,0xb2,0x01,0x97,0xc2,0x67, + 0x60,0x12,0x93,0x58,0x9e,0x0d,0xd2,0x3c,0xbc,0x63,0x79,0x21,0x32,0xc9,0xc4,0x54, + 0x94,0x73,0x50,0x51,0x0a,0x56,0xf0,0xa1,0xf0,0xd8,0x7b,0xf2,0x4d,0x2c,0xc9,0x98, + 0x5f,0xe6,0x79,0xc5,0x6c,0x9a,0x15,0x82,0x89,0x63,0x61,0xc9,0x1d,0xc6,0x30,0x42, + 0x9e,0x4a,0x44,0x4c,0x39,0x31,0x4c,0x4a,0x05,0x88,0x61,0xe4,0xc5,0x24,0x2d,0x21, + 0xcd,0x22,0x53,0x9e,0x4e,0x84,0xf4,0xd9,0x9d,0x10,0x85,0x5a,0xba,0x9a,0xe5,0x84, + 0x56,0x56,0xa2,0x70,0x5c,0xc2,0x14,0xf1,0xf2,0x8e,0x4d,0xb2,0x48,0x94,0xca,0xe3, + 0x7f,0x8e,0x78,0xc5,0x5b,0x80,0x04,0x83,0x68,0xe8,0x37,0x8f,0xfd,0x9c,0xb3,0x99, + 0x18,0xb0,0x18,0x3c,0x92,0x9a,0xfe,0x51,0x5e,0xc9,0x02,0x64,0x8d,0xb8,0x64,0x19, + 0xe1,0x23,0x3e,0x88,0xca,0x63,0x3f,0x1c,0xec,0x28,0x82,0x17,0x61,0x9e,0xe6,0x25, + 0x58,0x46,0x78,0x7c,0x45,0x63,0xaf,0xd5,0x0a,0x4b,0xc1,0xc7,0xfe,0xcb,0xeb,0xc3, + 0xab,0xeb,0xab,0x63,0xb4,0x0b,0x9e,0x89,0x14,0xed,0xeb,0xeb,0x8b,0xeb,0x33,0xb4, + 0x93,0xec,0xce,0x7f,0xd9,0x39,0xeb,0x9c,0x74,0x0e,0xd1,0x1a,0x4f,0xb0,0x3f,0xff, + 0xe5,0x71,0xf7,0xe8,0xe2,0xa8,0x83,0x76,0xcc,0xb1,0x8e,0xff,0xf2,0xf5,0xe5,0xeb, + 0xe3,0xe3,0x13,0xb4,0xcb,0x49,0x2a,0xfc,0x97,0x97,0x97,0x97,0x47,0x17,0xc7,0xa6, + 0xd9,0x92,0x79,0x0c,0x90,0xab,0x93,0xab,0xce,0x25,0xa1,0x18,0x8e,0x72,0x49,0xed, + 0x57,0x97,0x17,0x17,0x57,0x68,0xa7,0x84,0xf0,0xfa,0xfa,0xe8,0xa2,0x4b,0xad,0x01, + 0x47,0xeb,0xfc,0xe4,0xd5,0x45,0xe7,0x02,0xad,0x1c,0x6b,0x77,0xcf,0x5f,0x9f,0x1d, + 0x9e,0xa3,0x31,0xe3,0x65,0xe6,0xbf,0x3c,0x39,0x3a,0x6e,0xb7,0xaf,0x7a,0x3b,0xad, + 0x96,0xe4,0x99,0xf4,0xe5,0x1c,0x5c,0x1b,0xb7,0x26,0x89,0xdb,0xe2,0x45,0x41,0xab, + 0xa9,0x0e,0xd7,0xba,0x15,0xc3,0x5c,0xb0,0x5f,0xde,0x59,0xee,0x4d,0x3e,0xc8,0xab, + 0xdc,0x25,0xf0,0x96,0x14,0x65,0x12,0xd3,0x3e,0xf2,0x2c,0xf7,0x27,0x89,0xfa,0x96, + 0x05,0x0f,0x85,0x6b,0x5d,0x70,0x28,0x53,0x94,0x70,0xf6,0x01,0x7d,0x16,0x10,0x5c, + 0x9b,0xa7,0x0f,0x22,0x4b,0x73,0x57,0x2b,0x0c,0x97,0xae,0xa5,0xf1,0x99,0xc1,0x15, + 0x82,0xe5,0xce,0x93,0x92,0xda,0x64,0x3a,0x75,0xad,0x79,0xde,0xbe,0x68,0x9f,0xb7, + 0xdf,0xac,0x79,0xde,0x79,0xd5,0xe9,0x74,0xda,0x35,0xcf,0xaf,0x2e,0xaf,0x5e,0x5f, + 0x9e,0xaf,0x79,0x7e,0xf6,0xea,0xcd,0xf9,0xc9,0x59,0x83,0xe7,0x67,0xaf,0x5f,0x1d, + 0x1f,0xae,0x78,0xde,0x3d,0xef,0xbe,0xee,0x76,0x36,0x79,0xde,0xb9,0xee,0x5c,0x74, + 0x4e,0xd6,0x3c,0xef,0x9e,0x75,0x8f,0xbb,0xed,0x9a,0xcb,0xd7,0xd7,0xaf,0xcf,0x8e, + 0x8e,0x0c,0x97,0x8f,0x5e,0x9f,0x9f,0xbc,0xbe,0x5e,0x71,0xf9,0xf2,0xcd,0x59,0xfb, + 0xd5,0xf5,0x72,0xe7,0x87,0xc5,0x20,0xbf,0x6f,0xc9,0xe4,0x1f,0x49,0x36,0xf4,0x07, + 0x79,0x09,0x8d,0x6c,0xa1,0x67,0xf9,0x79,0x94,0x44,0x91,0xc8,0x7e,0x5b,0x20,0x78, + 0x16,0x29,0x42,0x73,0x96,0x67,0xe2,0x45,0x32,0x26,0xcb,0xe5,0x59,0xb5,0xdc,0x19, + 0xe4,0xd1,0x7c,0x31,0xe6,0xe5,0x30,0xc9,0xfc,0x76,0x6f,0xc0,0xc3,0xbb,0x61,0x99, + 0x43,0xa3,0x7d,0xf8,0x52,0xdb,0x70,0xc0,0xe9,0x29,0xe6,0x98,0x2e,0x6c,0xda,0xe9, + 0x91,0x3e,0xfb,0x9d,0xa3,0xe2,0xfe,0xa0,0xe3,0x1d,0x31,0x3d,0x40,0x82,0x73,0x7a, + 0x2d,0xa8,0xfb,0x5d,0x52,0xb5,0x08,0xa2,0x25,0xc7,0xd0,0xe7,0x11,0xd1,0x84,0xc5, + 0xe0,0x07,0x12,0x58,0x71,0xb4,0xdc,0xe1,0x9a,0xdb,0x7e,0x92,0x8d,0x20,0xe7,0x6a, + 0xe9,0xc7,0x79,0x38,0x91,0xad,0x69,0x22,0x13,0x04,0xf8,0x05,0x5c,0x67,0x9a,0x64, + 0xc2,0xef,0x16,0xf7,0x0c,0xb2,0x4c,0x22,0xb3,0x00,0x34,0xd0,0xe9,0x99,0xc1,0x56, + 0x1e,0xc7,0x14,0xd5,0x00,0xb3,0xdc,0xf1,0x66,0x25,0x2f,0xb0,0x8b,0x7b,0xed,0x75, + 0xfc,0xd7,0xdd,0x76,0x71,0xdf,0xab,0x77,0xc5,0xf8,0xa4,0xca,0x7b,0x05,0x8f,0x22, + 0x22,0x84,0x86,0x58,0xe7,0x18,0x1f,0x87,0x27,0x34,0x77,0xd4,0x5d,0x6d,0x9f,0xb5, + 0x19,0xfa,0x7b,0x9a,0xf2,0xe4,0x1f,0xc2,0xef,0xbc,0xaa,0x9b,0x33,0xa1,0xf2,0x1d, + 0xa8,0xf4,0x06,0x2f,0x94,0xc8,0x1d,0x10,0x10,0xf2,0x32,0x5a,0x3c,0xe2,0x9e,0xd2, + 0x17,0xa7,0xa7,0xe5,0xe1,0x77,0xb6,0xb6,0x43,0x0a,0x50,0x0f,0xb6,0x4a,0xa8,0x34, + 0x62,0x66,0x87,0x08,0xaf,0x49,0x25,0x2a,0x81,0x7b,0x50,0x65,0x2b,0xf1,0x25,0x99, + 0xda,0x7c,0x9c,0x8a,0xfb,0x1e,0xd8,0x39,0xcc,0x5a,0x09,0xac,0x48,0xfa,0xa1,0x20, + 0x37,0xd2,0xfb,0x7d,0x22,0xab,0x24,0x9e,0xb7,0x8c,0x4b,0xae,0xbb,0x87,0xbc,0xf0, + 0x69,0x67,0x88,0xb6,0xad,0x91,0xde,0xc9,0x61,0x73,0xa1,0xb6,0x62,0xc8,0xff,0x87, + 0xce,0x13,0x02,0xff,0xc2,0x76,0x9f,0x56,0x96,0xa3,0x36,0x56,0x39,0x04,0xea,0xa6, + 0xb2,0x50,0xc4,0x6a,0x45,0x02,0xbe,0x9b,0x53,0xe4,0x51,0xda,0xd9,0x0b,0x27,0xa5, + 0x04,0x82,0x22,0x57,0xae,0xb1,0x57,0x95,0x00,0x4d,0xd4,0xb0,0xa1,0x41,0x2d,0xc0, + 0xbc,0xce,0x91,0x74,0xd7,0x34,0xe8,0xf6,0x7a,0x68,0xb9,0xf3,0x2f,0x63,0x01,0x37, + 0x61,0x8f,0x72,0xc4,0x07,0x5f,0x7d,0x3a,0x0b,0x62,0xa6,0x7e,0x5e,0x34,0x91,0x35, + 0xa8,0x5d,0xc6,0x50,0x59,0xf8,0x73,0x6e,0xc0,0x1e,0x8d,0x6b,0x89,0xf8,0x75,0x36, + 0xba,0xc8,0xe1,0x55,0x12,0x24,0xc9,0xde,0xe1,0x51,0x4d,0x7a,0x24,0x62,0x3e,0x49, + 0xab,0xde,0x13,0x4b,0x28,0x66,0x02,0xc5,0x58,0x0e,0x17,0xda,0x88,0xba,0x2b,0x9e, + 0x90,0x8f,0xda,0x64,0x9f,0x72,0x21,0xce,0x12,0xf1,0x1a,0xc6,0xbf,0x41,0x0a,0xf2, + 0x02,0xd5,0x2d,0xca,0x4d,0x12,0xe1,0x31,0x80,0x5e,0xef,0x61,0xa5,0x35,0xdf,0xaa, + 0x2e,0xca,0x41,0xb6,0x06,0xa2,0x9a,0x09,0x91,0x29,0xad,0x51,0x7a,0xa1,0xed,0xa3, + 0x45,0x89,0xa6,0x52,0x1b,0xb3,0x2d,0x6a,0x3f,0xad,0x2b,0xdf,0xbc,0xb1,0x9d,0x9a, + 0xd9,0xdf,0xaa,0xe0,0xdb,0x1a,0xfc,0xd8,0x18,0x9f,0xd4,0x29,0x98,0x39,0x0a,0xaf, + 0xe7,0x38,0x42,0xf9,0x05,0xad,0xdc,0xa3,0x91,0x16,0xf9,0x13,0x9f,0x3e,0x14,0x13, + 0x48,0x6b,0x69,0x37,0x35,0x23,0x10,0x56,0xaa,0x7c,0xac,0x3c,0x09,0x10,0x77,0x16, + 0x34,0xc5,0xef,0xac,0xfc,0x4d,0xc3,0x81,0x74,0xbb,0x4f,0x38,0x10,0x95,0x6d,0x20, + 0xd4,0x90,0xde,0xc0,0xf8,0x5a,0x5e,0xbb,0x23,0xc6,0x50,0x09,0x39,0x19,0x7c,0xbb, + 0x4a,0xec,0x48,0xa1,0x92,0xb5,0x45,0x43,0x38,0x5d,0xe5,0xd0,0x90,0x9a,0x57,0xa2, + 0xf6,0x69,0xe8,0x81,0x57,0x6b,0x6f,0xfb,0xb4,0x27,0x7d,0x18,0xb4,0xda,0x8b,0x78, + 0xf6,0x58,0x9d,0xbe,0x64,0x48,0x04,0xfd,0x65,0x63,0x52,0x53,0x81,0x96,0x87,0x95, + 0xdc,0xe4,0xfb,0x16,0x8b,0x9f,0x10,0x33,0x71,0xfd,0x64,0x53,0xf3,0x3a,0xda,0xd3, + 0xdf,0x4d,0x1b,0xd1,0xea,0x2b,0x7a,0xa8,0xc0,0x4f,0xa3,0x64,0xfa,0x0d,0x62,0x57, + 0xca,0xde,0x6d,0xf8,0x44,0xc5,0xb9,0xde,0x2a,0x94,0x2a,0x89,0x3f,0xb5,0x8a,0x0a, + 0xe1,0xce,0x16,0x83,0xd5,0xca,0x2c,0xaa,0x8c,0x6a,0x30,0x13,0x83,0x9e,0x60,0xbb, + 0x82,0x8b,0xd6,0x7b,0x22,0x05,0xd7,0x41,0xac,0x5d,0x9b,0x91,0x77,0xb4,0xa5,0x0e, + 0x4a,0xc3,0xd5,0x2e,0xfc,0x52,0x65,0x87,0x24,0x02,0xca,0xa4,0x35,0x53,0x79,0x36, + 0x9f,0x21,0xae,0x42,0xe9,0x91,0x3f,0xff,0xf9,0xcf,0x3f,0xf0,0x67,0x12,0xec,0xba, + 0x85,0x4c,0x93,0xd6,0xf5,0x06,0x89,0x76,0x42,0x86,0xf0,0xc3,0xc7,0xca,0x8a,0x8d, + 0x3c,0xe5,0x78,0x28,0xf9,0xd8,0xe8,0xa5,0x0e,0xf4,0x43,0xe6,0x4f,0x78,0x23,0x74, + 0xaf,0x2d,0x4f,0x65,0xee,0x3d,0x63,0xc3,0xaf,0xd6,0x61,0xfa,0x48,0x69,0x2a,0x69, + 0xbe,0x62,0xd5,0x3a,0x98,0x77,0x8e,0xdb,0x4f,0x05,0x1b,0x95,0x2a,0xa9,0x25,0x4b, + 0x96,0x3c,0x8d,0xbd,0xd3,0x6e,0x7f,0xff,0x78,0x62,0xaa,0xb4,0xfd,0x65,0x58,0x10, + 0x1b,0xb7,0x26,0x9a,0x15,0x69,0x5e,0x8d,0xe3,0xa4,0xfd,0x58,0x0f,0x37,0x94,0x44, + 0x85,0xec,0x52,0x28,0x16,0x42,0x0e,0x55,0x82,0x52,0xe7,0x4b,0x09,0x53,0x57,0x25, + 0x4c,0x87,0x47,0x4d,0x71,0x82,0x3f,0xe4,0xde,0xe3,0x98,0xf4,0x90,0x19,0x7d,0x58, + 0x05,0x95,0xa3,0xe5,0x0e,0xea,0x2f,0x55,0x0e,0xbd,0x3d,0xd0,0xa7,0x47,0x94,0xb2, + 0x51,0x2d,0x06,0x47,0xc0,0x42,0x64,0xba,0x12,0x95,0x17,0xe4,0x5e,0x1f,0x2f,0x89, + 0xf2,0xf4,0xed,0xa8,0x73,0x5a,0x97,0x54,0x78,0x7c,0x0b,0x57,0xb3,0x02,0x85,0x97, + 0xd9,0x65,0x49,0x14,0xec,0x4e,0x30,0xa3,0x05,0xdc,0x18,0x33,0xa8,0x31,0x73,0x67, + 0xe7,0x2d,0xec,0xa5,0x86,0x25,0xd3,0xdd,0xc5,0x82,0x13,0x68,0xff,0x0a,0x01,0x0c, + 0x7f,0x97,0xd1,0x21,0x17,0x1e,0xd5,0x80,0x46,0x17,0xe6,0xc5,0x7c,0xf7,0xf4,0x02, + 0x9f,0x0c,0xce,0x62,0x88,0x6c,0x1b,0x9c,0xc0,0xfa,0x1a,0x66,0x93,0x06,0x04,0x3f, + 0x33,0xa9,0xa0,0xc7,0xd3,0x15,0x15,0x58,0x9b,0x2a,0x44,0x08,0x86,0x23,0xf1,0xac, + 0xc1,0x29,0xb9,0xaa,0xe1,0x69,0x6c,0x97,0x61,0x30,0xca,0xb3,0x74,0xce,0x74,0x7a, + 0xcb,0x78,0x99,0xf0,0x56,0xca,0x07,0x22,0x0d,0x76,0x2f,0xd7,0xab,0x13,0xe6,0x1a, + 0x19,0x6d,0xcd,0xf8,0x4c,0xf0,0xa7,0x7b,0xaa,0xcf,0x19,0xb0,0xf1,0xee,0xe9,0xdb, + 0x28,0xad,0x97,0xba,0x9b,0x82,0x8d,0x8c,0x11,0x13,0xd0,0x5d,0x9d,0x5e,0x27,0xe5, + 0x18,0xba,0x0d,0x38,0x34,0xde,0x46,0x91,0xa2,0x22,0x9e,0x29,0xce,0x45,0x51,0x4d, + 0x71,0x63,0xc2,0x39,0x1d,0x25,0x6c,0x40,0x0f,0xd2,0xe8,0xcb,0xe0,0xef,0xb9,0xac, + 0xb0,0x1b,0x14,0xf5,0x65,0xb5,0x31,0xab,0x2c,0x9f,0x5b,0x43,0xce,0x37,0x97,0x40, + 0xc7,0x97,0xc1,0x3f,0x52,0x5a,0xc6,0x48,0x3f,0x37,0x26,0x15,0xd9,0xd6,0x14,0x7c, + 0xa5,0x24,0x0a,0xc3,0xa4,0x35,0xbf,0x34,0xeb,0x4b,0xb9,0x6b,0xd8,0xad,0xf8,0xa7, + 0x28,0x0f,0x4b,0x2e,0x47,0x5f,0xe3,0xa1,0x29,0xf5,0x37,0x16,0x0f,0xcb,0xe2,0xcb, + 0x04,0x7f,0xe2,0xf2,0x6e,0x0b,0xba,0x7a,0x86,0x1b,0x30,0x70,0xe4,0x88,0xa1,0xd8, + 0x9a,0xf2,0x8c,0x90,0x2e,0xe8,0xac,0x20,0x9a,0x8c,0x8b,0xad,0x29,0xd1,0x53,0x1c, + 0xf9,0x26,0x8b,0x60,0x08,0x85,0x4f,0x5a,0x45,0x19,0xa6,0x90,0xe4,0x05,0x1d,0xc8, + 0x41,0xce,0x48,0x4a,0xa2,0xaf,0x99,0x44,0xf9,0xd8,0x24,0x9e,0x12,0x8a,0x12,0xc2, + 0x8d,0xa0,0xb3,0x87,0xaf,0x0b,0x00,0x0a,0xb0,0x29,0xfb,0xd9,0x33,0xea,0x75,0x5d, + 0xd2,0xe1,0x07,0xb2,0xa7,0x35,0x47,0xeb,0x8d,0x26,0x86,0xc8,0xb8,0x90,0x5f,0x9b, + 0x4f,0x67,0x60,0x9b,0x56,0xf3,0x8c,0x0c,0xcf,0xb0,0xa5,0x29,0x1d,0xdf,0x3c,0xd6, + 0x14,0x70,0xfc,0x69,0xa9,0x14,0x35,0x55,0x94,0xef,0xec,0xd6,0xdb,0x52,0x0d,0x40, + 0x16,0x5f,0x66,0x9a,0xd1,0x47,0xf9,0x35,0xb6,0x7d,0xca,0x2b,0xbe,0xc5,0xb6,0xea, + 0x79,0xc3,0xa7,0x43,0xa7,0x2a,0x67,0xf1,0x53,0x4e,0xa3,0x78,0x46,0xe1,0xdf,0xe7, + 0x70,0xbe,0x11,0x8b,0xcb,0x7c,0xcc,0x64,0x85,0xc4,0x75,0xb8,0x35,0x77,0xfc,0x15, + 0x0f,0x92,0x02,0x01,0x13,0x74,0x42,0xb8,0x31,0x2f,0x15,0xdf,0xcc,0x3a,0xc2,0xf0, + 0x0d,0xbc,0xfb,0x20,0xc6,0x79,0x39,0xff,0x1a,0xe7,0xde,0xa9,0x33,0x2d,0x9e,0x32, + 0x44,0x95,0x02,0xdb,0x12,0x9b,0xdb,0x19,0x25,0xcf,0x6d,0xa7,0x1c,0xc2,0x1d,0xaa, + 0x49,0xfa,0x94,0x6f,0x73,0x6a,0xfa,0x8c,0x9f,0xbb,0xbd,0x39,0xfb,0xf0,0xc4,0x6a, + 0xc5,0xb7,0x30,0x61,0x8b,0xe6,0x44,0xea,0xb3,0x46,0x84,0x9e,0x50,0x30,0x54,0x10, + 0xfa,0xec,0x4e,0x55,0xb8,0x7b,0xa5,0xfc,0xcf,0x49,0xde,0x93,0xec,0xf2,0xc3,0x19, + 0x1b,0x4c,0xe2,0x58,0x94,0x92,0xd1,0xeb,0x12,0x02,0x29,0x85,0xc7,0xce,0xd8,0x38, + 0x8f,0x90,0x1a,0x2a,0xb1,0x48,0xa6,0x02,0x55,0x12,0xb3,0xa4,0xda,0x81,0x1b,0x98, + 0x0a,0xc9,0xb4,0xe5,0x2b,0x37,0x2f,0xc1,0xba,0xee,0x21,0xfb,0xe9,0xdc,0x18,0xbc, + 0xa2,0xbf,0xc7,0x10,0xc9,0xf2,0x19,0xf0,0xf1,0x4a,0xad,0x9b,0xa1,0x24,0xcb,0xcb, + 0x3b,0x36,0xcc,0x31,0x5b,0xbd,0x0b,0x70,0xd9,0x6c,0x94,0xa4,0x62,0x4d,0x95,0x3a, + 0xa5,0x94,0x2c,0x2a,0xf9,0x0c,0x99,0x89,0xf7,0xac,0x14,0x6f,0x6b,0x1d,0xfb,0x26, + 0xc7,0xbd,0xad,0x92,0xa7,0x6b,0xf2,0x63,0xd9,0xc8,0x21,0x9a,0xee,0x0c,0x59,0x19, + 0x34,0x29,0x31,0x40,0xd4,0x62,0x2a,0x89,0x31,0x87,0xc4,0x7e,0x9b,0xf4,0x2c,0x69, + 0x78,0xb9,0xa7,0x04,0x6a,0xc8,0x7c,0x42,0xb1,0x63,0x29,0xbe,0x35,0x78,0xa9,0x0d, + 0xff,0xac,0xf9,0xf7,0xb5,0x0d,0xaf,0xc0,0x1a,0x4b,0xc9,0x67,0x3c,0xdd,0x2d,0x52, + 0xf0,0x2d,0x17,0x51,0x3e,0x03,0x7e,0x16,0x45,0x08,0xf5,0x72,0x03,0x3e,0x79,0xc6, + 0x2d,0xfc,0x0c,0x3f,0xba,0x09,0x9d,0x3d,0xe3,0x08,0xfe,0xa2,0xcf,0x95,0x37,0x75, + 0x5f,0x7e,0x15,0x9e,0x74,0x75,0xcb,0x60,0xe4,0xd7,0x57,0x01,0x07,0x13,0x94,0x6a, + 0x72,0x6b,0x62,0xf8,0xe5,0x89,0x37,0x82,0x87,0x23,0x38,0xb9,0x69,0xc2,0x37,0x26, + 0xa1,0xfd,0x55,0x51,0xea,0x53,0x82,0xd3,0xb7,0x9c,0x8d,0x4a,0x11,0x07,0xbb,0x07, + 0x94,0x68,0xaa,0xf7,0x02,0x6f,0x0f,0x78,0xa3,0xdb,0xc4,0x0f,0x6c,0x7a,0xed,0xe3, + 0x31,0x7e,0x60,0xe6,0x03,0x33,0x25,0xcd,0xab,0x37,0xad,0xa7,0x3b,0xab,0xf7,0x23, + 0xdf,0xd9,0xc9,0xea,0xa5,0x4c,0x94,0x87,0x93,0x31,0x36,0xe7,0x0d,0x45,0x75,0x95, + 0x0a,0x7a,0x3c,0x9f,0xbf,0x8b,0x00,0xb1,0x5c,0x4f,0xb8,0x1b,0xd8,0x83,0xd5,0x8c, + 0xc1,0x69,0xd0,0x69,0x1f,0x9e,0x1c,0xbd,0x3e,0xee,0xdb,0x83,0x03,0xf3,0xe8,0x78, + 0x55,0x7e,0x9d,0xdc,0x8b,0xc8,0xee,0x3a,0xfb,0x16,0xfb,0x70,0x6e,0xf9,0xea,0x95, + 0x97,0xaa,0x45,0x14,0x58,0xf7,0x90,0x06,0x7e,0x3a,0xb7,0x1a,0x78,0xa3,0x49,0x49, + 0x2f,0x69,0xc0,0x39,0x7a,0x99,0x15,0xe9,0xb7,0x64,0xa8,0xed,0x72,0x74,0x1f,0x9c, + 0x1c,0x1f,0xb6,0xdb,0x8e,0x3b,0xda,0xe8,0xfd,0x5e,0xf5,0x1e,0xbc,0x3a,0xa6,0x21, + 0x7a,0x29,0x81,0x7f,0xe3,0x4d,0x08,0x1a,0x3b,0x38,0xc6,0xf0,0x7d,0x20,0xbf,0x3f, + 0x6e,0xf7,0x00,0x95,0xc4,0x76,0xe4,0xd4,0x1b,0xde,0xb7,0x22,0x66,0xed,0x8f,0xf6, + 0xad,0x91,0xd5,0xc3,0xc0,0xa8,0x1e,0xa0,0x1e,0x0c,0x8c,0xf7,0xad,0xb1,0x65,0x26, + 0x8d,0xeb,0x31,0xea,0xc4,0xd8,0xfd,0xbe,0x25,0xad,0xfa,0x65,0x94,0x6e,0xec,0x34, + 0xb6,0x53,0x4c,0x2a,0x3b,0x89,0xdc,0xca,0x0d,0xf5,0xdb,0x39,0x11,0x80,0xd3,0x91, + 0xd3,0xdb,0x7a,0x1b,0x8c,0xb6,0x32,0x49,0xd2,0xf8,0x20,0x7c,0x78,0xb0,0xc0,0x92, + 0x83,0x03,0x26,0x64,0xf1,0x77,0x58,0x8c,0xa8,0xf0,0xc9,0xd5,0x3b,0x2d,0x7a,0xfd, + 0x02,0x13,0x8d,0xa4,0xc7,0x3e,0x8d,0x94,0x63,0x96,0x8c,0xc3,0x09,0x0f,0x59,0xc8, + 0x27,0x92,0x1a,0xc8,0xec,0x4a,0x11,0xf9,0x3a,0x98,0xc2,0x3b,0x12,0x9e,0xda,0x7d, + 0x72,0x9d,0xb0,0xc2,0x2f,0xe7,0x77,0x92,0x89,0x7b,0xe4,0x16,0x70,0xcd,0x69,0x72, + 0x27,0x30,0x34,0xe2,0x59,0x04,0x84,0xda,0xa3,0xa6,0x93,0xa1,0xb7,0x43,0x04,0xdf, + 0xdc,0x04,0x8b,0x22,0x9f,0x89,0x32,0xcf,0x7c,0x4b,0x3d,0x00,0xc6,0x72,0x41,0xbc, + 0x6f,0x29,0xd2,0x58,0x91,0xa0,0x2d,0x67,0xbe,0x45,0x07,0x01,0x33,0xbd,0xbe,0xca, + 0xe7,0x2d,0x17,0xbe,0x2d,0x09,0x7d,0x4b,0x2f,0x6a,0xab,0x96,0x63,0x91,0x8c,0x90, + 0x26,0xfc,0x7d,0x16,0x01,0x85,0x7a,0x5f,0x1a,0xe5,0x43,0x66,0xab,0xc3,0xce,0x72, + 0x52,0x54,0x80,0xa8,0x90,0x00,0x6f,0x8f,0x53,0x1f,0x86,0x36,0x7a,0x15,0xae,0x88, + 0xfc,0x7e,0x8a,0x0f,0xea,0xc7,0x4e,0xd4,0xc6,0xa9,0x93,0xa9,0x5e,0xcb,0x1d,0x94, + 0xf9,0x2c,0xcb,0x27,0x98,0x57,0x3f,0x81,0x16,0xb5,0x93,0x28,0x29,0x1c,0x6b,0xd9, + 0x53,0x1b,0x3d,0xff,0xe5,0xf6,0xdf,0xe9,0xe5,0xbf,0x72,0xb9,0x40,0x55,0x26,0x15, + 0xe2,0x48,0x9d,0x92,0x49,0xcb,0x9d,0x14,0x91,0xba,0x18,0x80,0x2c,0x56,0x24,0x53, + 0x1a,0xab,0xf3,0x1c,0x42,0xa1,0x70,0x40,0x84,0x55,0x40,0x2f,0xbf,0x7b,0x0d,0x0d, + 0xa0,0xf3,0x2a,0x7a,0x5b,0x0e,0x52,0xd5,0x78,0x44,0x9a,0x44,0x7a,0x61,0x4d,0x40, + 0x1c,0x3e,0xa0,0x45,0xa4,0xf5,0x91,0x87,0xcd,0x23,0x69,0x74,0x5c,0x0b,0x35,0xaa, + 0xe5,0xac,0xc0,0xe2,0x99,0xe5,0x46,0x1e,0x4a,0x6b,0x09,0x7c,0xfb,0x36,0x00,0xa7, + 0x54,0xef,0x65,0xd5,0xde,0xde,0xea,0xf1,0x45,0x10,0x58,0xf4,0x06,0xd0,0x72,0xfa, + 0x16,0xfb,0xdf,0xff,0x21,0x94,0xf5,0xd0,0xfe,0x7a,0xc2,0xbf,0x69,0x1c,0x00,0x69, + 0x8c,0x9b,0x4e,0xdf,0xb2,0x1c,0xfa,0xbf,0x5e,0x17,0x85,0x1b,0x2d,0xac,0x5e,0x0e, + 0x43,0x25,0x5b,0x0d,0x92,0xca,0xd2,0x72,0x6f,0x6e,0x3e,0x47,0x9e,0x52,0x81,0x1b, + 0xa5,0x9c,0xbf,0x3d,0x3c,0x6c,0xb4,0xd5,0x14,0xf7,0x40,0x49,0xfd,0x01,0x62,0x7b, + 0xa8,0xb9,0x7f,0x00,0xdd,0x97,0x60,0x49,0x13,0x18,0x64,0x0f,0x78,0x64,0x11,0x01, + 0xeb,0xf5,0x51,0xd5,0x69,0x02,0xe4,0xbc,0x6f,0x93,0x7c,0x3e,0xeb,0x86,0x5a,0x89, + 0x1e,0x40,0x30,0xbd,0xdb,0x32,0x20,0x16,0x1d,0xc2,0x6c,0xa2,0x28,0x32,0x1a,0x55, + 0xf9,0x41,0xbd,0x03,0x0c,0xc1,0x22,0x2e,0x94,0x4a,0xea,0x82,0x84,0xd9,0xf0,0x78, + 0xf2,0x80,0xb4,0xb6,0xc5,0x8b,0xc4,0x1b,0x47,0x8e,0xcf,0x8a,0x11,0x97,0x42,0xa7, + 0x2e,0x3c,0x56,0x47,0xb4,0x4c,0xed,0x84,0xe5,0x25,0xab,0xd5,0xcf,0x33,0x5e,0x2a, + 0x0c,0x22,0x4f,0xe9,0xb8,0x3b,0x09,0xe8,0x8e,0x80,0x47,0xa5,0x15,0xd1,0xf0,0x9d, + 0x0d,0xdd,0x97,0x96,0xe3,0xe9,0xba,0x31,0x78,0x11,0x1a,0x2f,0x12,0x2a,0x75,0x30, + 0x44,0xa2,0x16,0xb4,0xdc,0xd0,0x53,0x2b,0xf6,0x6d,0x3c,0x68,0x95,0x03,0xc1,0x74, + 0x74,0x6b,0x91,0x8f,0x54,0x12,0x35,0x20,0x7e,0x2d,0x89,0xd5,0x74,0x58,0xda,0xa4, + 0x3f,0xf1,0xc8,0x42,0x34,0xac,0xf2,0x05,0x98,0x31,0xf1,0xd4,0xd3,0xbe,0x6d,0x1e, + 0x82,0xa0,0x7b,0xf2,0xf0,0xb0,0x6e,0xbc,0x81,0x26,0x20,0xc3,0x22,0xc0,0x29,0x47, + 0x70,0xd6,0x3a,0xb0,0x8d,0x7e,0x46,0xe8,0x81,0x62,0x50,0x17,0x9a,0x0f,0x0f,0x9f, + 0x7f,0x73,0xbc,0xdf,0xf3,0x24,0xb3,0xa1,0x49,0x0e,0x61,0x2c,0xc2,0xc7,0xf3,0x22, + 0x33,0x8f,0x0c,0xf2,0xd3,0x28,0x91,0x37,0x24,0xee,0xbe,0x55,0xe1,0x91,0x29,0xd1, + 0x43,0x56,0xc8,0x98,0x50,0x19,0x22,0x96,0x96,0xa6,0xcb,0xec,0x56,0x29,0x1d,0x08, + 0xbb,0xad,0x4a,0x58,0x1a,0x2d,0xae,0xae,0x28,0x78,0x32,0x4d,0x42,0x61,0xb7,0xdd, + 0x13,0x47,0x6d,0x2a,0x57,0x1e,0x43,0x44,0x5a,0xe9,0x0b,0x38,0x9d,0x84,0xa7,0x96, + 0xde,0x86,0x62,0x9e,0x3b,0xd9,0xdb,0x7b,0x44,0x41,0x53,0xd3,0x96,0x46,0x21,0x2e, + 0x79,0x79,0xe7,0xea,0x5c,0x53,0xdd,0xe9,0xd1,0x9e,0x54,0xf9,0x92,0x81,0x88,0xa9, + 0x5e,0x4e,0x2a,0x36,0x83,0xb3,0x56,0xef,0xbc,0x29,0xc7,0x85,0x8f,0x4b,0x53,0x7a, + 0x89,0x9e,0xe7,0x05,0x83,0x5a,0x97,0x3c,0xbb,0x93,0x1a,0x99,0x76,0x47,0x8d,0xdc, + 0x54,0x8e,0xf2,0x99,0x04,0x06,0xa9,0x5c,0x00,0xd0,0x52,0x85,0x48,0xfe,0x36,0xe4, + 0x59,0xa6,0xb2,0x09,0xaa,0x8f,0x69,0x1c,0x26,0xc2,0xe2,0x94,0x0f,0x65,0xad,0x5c, + 0x20,0xe1,0x1f,0xa4,0x3a,0x2f,0x22,0x8f,0x56,0xba,0xd5,0xab,0xf6,0xea,0x00,0x09, + 0x62,0xa0,0x7d,0x6a,0x41,0xb2,0x0a,0x73,0x65,0xea,0x23,0x09,0x18,0x46,0xab,0x27, + 0xaf,0xcd,0x61,0x06,0xbb,0xd5,0x7d,0x7d,0x8b,0xd6,0xe5,0x99,0x84,0x1f,0x54,0xbe, + 0x0c,0x7a,0xad,0xfd,0x50,0x23,0x48,0xeb,0x25,0xcf,0x86,0xe2,0x83,0x44,0xb8,0x46, + 0x7c,0x75,0x7c,0x25,0x60,0xb3,0x60,0xdf,0xe2,0xda,0xc5,0xfa,0x5b,0x0b,0xf7,0xad, + 0x42,0x7d,0x2b,0xac,0xc6,0xa5,0x92,0xb0,0xc9,0x3f,0xaf,0x09,0x50,0x62,0xa0,0x0d, + 0x6c,0x59,0xee,0x77,0x8a,0x50,0xaa,0x4a,0x60,0x39,0xcd,0x30,0xa9,0x27,0x2a,0x0a, + 0xfa,0x16,0x85,0xbf,0x52,0x95,0xff,0x5a,0x02,0x74,0x9d,0x80,0x6e,0xa5,0x14,0x14, + 0xfc,0xc6,0x39,0x15,0x85,0x88,0x6b,0x30,0x5f,0x2d,0x05,0x9d,0xc9,0x67,0x74,0x57, + 0x82,0xe9,0x68,0x2d,0xb5,0x74,0xb9,0x91,0x86,0x3d,0x4b,0xaa,0x51,0xf3,0x42,0x82, + 0x4b,0x43,0x82,0x03,0x54,0x30,0xba,0x9b,0x43,0x5c,0x82,0x3f,0xe7,0x2a,0x7a,0x4e, + 0x0a,0x2d,0x33,0x49,0x01,0x99,0xb3,0x71,0x92,0x4d,0x2a,0x41,0xbe,0x01,0x81,0xd6, + 0xf1,0xd8,0xbb,0x58,0xdf,0x97,0x48,0x48,0xcc,0x83,0x1c,0xa5,0x91,0xae,0x4e,0x86, + 0x70,0x81,0xc0,0xe3,0xb2,0xbb,0x2c,0x1f,0x48,0xa5,0x01,0x35,0x69,0x12,0xeb,0x87, + 0xf4,0xaa,0x58,0x29,0x5e,0x24,0x50,0xd0,0x4e,0xb2,0x2a,0x49,0x1b,0x5a,0x64,0xe2, + 0xaa,0xec,0xb1,0x1b,0x31,0xa0,0x9b,0x1d,0x26,0x5a,0xff,0x2d,0x69,0x5d,0x27,0xea, + 0xee,0x07,0x38,0x90,0xa4,0x29,0x65,0x08,0x77,0xc8,0x10,0xde,0xad,0x8e,0xd6,0xa4, + 0x06,0x85,0xe1,0x99,0xe5,0xe0,0xe0,0x92,0x10,0x09,0x01,0xb8,0x8c,0x9a,0xad,0xa1, + 0xe2,0xc4,0x42,0x10,0x36,0x44,0xd4,0xf2,0x2c,0xc5,0x6a,0xdf,0x48,0xdb,0xf0,0x5d, + 0x9f,0xa6,0xe5,0x71,0xec,0x9a,0xc5,0x0c,0x11,0x26,0xc7,0x80,0x65,0x64,0x73,0xb5, + 0x3d,0xe2,0x86,0x39,0x27,0x22,0xb9,0x93,0xfa,0xbb,0x8a,0x43,0x54,0x57,0xaa,0xcd, + 0xd6,0x53,0x8d,0xee,0xb0,0x51,0x3e,0x36,0x57,0x58,0x56,0x2b,0x6f,0xa9,0x55,0x9d, + 0xd6,0x2a,0x1e,0x0d,0x04,0x71,0x8b,0x02,0x35,0xb4,0x83,0x55,0x79,0xad,0x69,0xbd, + 0x0d,0x91,0x83,0x03,0xc8,0x66,0x25,0xca,0x45,0x02,0xa2,0x82,0x12,0x5c,0x88,0xe0, + 0x1b,0x3c,0x52,0x38,0x15,0x0f,0x94,0x99,0x15,0x12,0x76,0xa4,0x54,0xe1,0x17,0xd9, + 0xef,0x88,0xe3,0x83,0x55,0xcb,0x6f,0xaf,0x43,0x71,0x21,0x29,0xa0,0xd4,0x60,0xb6, + 0xd6,0xde,0x3f,0xff,0xf8,0xa7,0xe5,0x63,0x68,0x95,0xf0,0x76,0xc8,0x8b,0x11,0xac, + 0xf2,0xa6,0xae,0x35,0x48,0x86,0x30,0x2e,0x03,0xad,0x40,0x4f,0x83,0xc3,0xa3,0xbe, + 0x95,0xdf,0x99,0x46,0xf7,0x68,0x65,0x03,0x64,0x15,0x8d,0x20,0x1c,0x57,0x8d,0x05, + 0xf7,0xf6,0x5e,0x28,0x1c,0xf6,0xaa,0x47,0x9b,0xe5,0x66,0xa6,0x3d,0x96,0x96,0xbf, + 0x11,0xad,0x91,0xe6,0x11,0x12,0xaa,0xc6,0xc1,0x31,0xca,0x1a,0xb8,0x3a,0x6f,0x0a, + 0x90,0x34,0xb4,0xac,0xbe,0x65,0x06,0xfe,0xfc,0xe3,0xbf,0xad,0xda,0xbe,0x35,0x00, + 0xa5,0x0e,0xfa,0xe9,0x9d,0xfc,0xa0,0x4a,0x7a,0x38,0x5a,0x66,0xeb,0xea,0xde,0xc1, + 0x2a,0x68,0x0c,0xcc,0xb9,0x8f,0xa3,0xa8,0x5e,0x79,0x9a,0x4a,0x07,0x5e,0x2d,0x2e, + 0xa7,0xa7,0x3b,0x0b,0xd5,0xa9,0x1c,0xfd,0xaa,0x6f,0x4c,0x7d,0x1a,0xa3,0x5c,0x93, + 0x9c,0x8a,0x9a,0x62,0x75,0xef,0xab,0x8e,0x85,0xcd,0xbe,0xa6,0x1f,0x37,0x42,0x4c, + 0xa3,0x40,0x03,0xa8,0xeb,0x72,0xda,0x95,0xd4,0x07,0x3b,0x5b,0xbe,0x24,0x8d,0xc0, + 0x34,0xf8,0xd2,0xbe,0xa5,0x0e,0x90,0x1a,0x07,0x16,0x3e,0x89,0xaa,0x1e,0xde,0xe2, + 0x2f,0x04,0x6b,0x2a,0x0c,0x62,0x33,0x63,0x01,0x53,0x47,0xf1,0x66,0x06,0x3d,0x3e, + 0x33,0x61,0x1f,0xb0,0x69,0x1e,0x22,0x89,0x5c,0xc1,0xeb,0xe6,0xb3,0x73,0xc0,0x2b, + 0x95,0x22,0xd2,0x04,0xf5,0xfc,0x18,0xda,0x88,0xfc,0xe7,0xbc,0xb9,0x0d,0x78,0x5f, + 0x99,0x64,0x21,0xcc,0x04,0x9e,0xc2,0xb3,0x56,0x89,0x4f,0x9e,0xe6,0x13,0xb8,0xad, + 0x38,0x4f,0xf5,0x09,0x8b,0x81,0x2e,0x2d,0xf4,0x51,0xb9,0xe4,0x53,0xf9,0x40,0x59, + 0x01,0x4c,0x55,0xdf,0xec,0x22,0xbb,0xe5,0x14,0x13,0x19,0xb9,0x48,0xf8,0xbb,0x13, + 0xd4,0x6c,0x75,0x78,0x2a,0xe5,0x34,0xb0,0x6b,0x01,0xea,0xd3,0x31,0x52,0xb0,0x66, + 0x5b,0xe5,0x79,0xe5,0x54,0x20,0x51,0xe8,0x1e,0xa2,0x30,0x5c,0x67,0x91,0x72,0x6a, + 0xb9,0x28,0x24,0xf1,0xdd,0xd0,0xf8,0x51,0xa2,0x3a,0x23,0x8f,0x0e,0xa2,0xea,0x53, + 0x29,0xc7,0xdd,0x6c,0x9f,0x62,0xce,0xfe,0x49,0xe7,0x4d,0x57,0x1b,0xd1,0xe3,0xc1, + 0x4d,0x7b,0x5a,0x23,0x4f,0x1b,0xc8,0xcd,0x59,0x5b,0x73,0xed,0xa2,0x31,0xfc,0x51, + 0xc2,0xc6,0x8c,0x52,0x53,0xb9,0xe8,0xc5,0x30,0x02,0xf8,0x64,0x11,0x99,0xec,0x8d, + 0xf6,0x4f,0x7e,0x89,0x1c,0x87,0xfc,0x05,0x0f,0x2e,0x74,0x46,0x35,0xd4,0xd1,0x69, + 0x23,0x19,0x8a,0xa5,0xc2,0x8b,0xe1,0x16,0x4d,0x50,0xee,0x81,0x0e,0xf8,0xf2,0x18, + 0x92,0xd5,0x03,0x8e,0x49,0x9e,0xbe,0x23,0xe8,0x01,0x2f,0xa1,0xaf,0xea,0xc4,0xc8, + 0xd3,0xb7,0x0a,0x09,0xa4,0x4f,0x73,0x0f,0xf0,0xf0,0x03,0x54,0xc0,0x6f,0x03,0xcb, + 0xf7,0xaa,0x2c,0x5d,0x32,0x91,0x22,0xdf,0x5b,0xac,0xd7,0x52,0xc1,0x7d,0xac,0x89, + 0x25,0xff,0xa3,0x78,0xf0,0x25,0xd4,0x56,0xdb,0xea,0x21,0x0f,0x5a,0x91,0xaa,0xcc, + 0x2c,0x96,0xdb,0x86,0x67,0x7a,0xb6,0xcc,0x0e,0x2a,0x55,0x1f,0x89,0x4c,0x0a,0x97, + 0xe2,0x67,0x5d,0x6c,0x52,0x7e,0x48,0xb1,0x98,0x1b,0x15,0x56,0xf7,0xaa,0x09,0xa2, + 0xa2,0xc0,0x4a,0xf7,0x43,0x6a,0x1d,0x1a,0x91,0xeb,0x35,0xd7,0x02,0x6b,0xcb,0x55, + 0xb4,0x48,0xe5,0x6d,0x67,0x49,0x9c,0xf4,0xa1,0xfc,0x32,0x89,0x20,0xe8,0x69,0xc2, + 0xff,0x52,0x83,0x8e,0x24,0x6a,0xa6,0xbe,0x55,0xdf,0x28,0xa4,0x6c,0x1d,0x94,0x99, + 0x57,0x89,0x96,0x6b,0x7c,0x99,0x9a,0x6f,0xd4,0xe4,0x89,0xd9,0x4f,0xea,0x49,0xd9, + 0x5c,0xb9,0xc4,0xd2,0x90,0x58,0x74,0x3e,0xde,0x72,0xac,0x49,0xd1,0x80,0x4a,0x8a, + 0xd5,0x20,0x6d,0x2a,0x1b,0x07,0x9f,0x7f,0xab,0x4f,0x1a,0x3c,0x7a,0x59,0x7b,0x46, + 0xd7,0xbf,0x9c,0x6c,0xac,0x6f,0x14,0x37,0xfa,0xf6,0x2d,0x8f,0x1c,0x41,0xaa,0x27, + 0xaf,0xe0,0xc9,0x8e,0xe8,0x1b,0xb5,0xdd,0x97,0x11,0x6c,0xce,0x55,0x54,0x65,0x70, + 0xa9,0x00,0x32,0xf9,0x39,0x95,0x0e,0xce,0x56,0xf9,0x36,0xc2,0xee,0xcc,0xee,0x11, + 0x82,0x55,0x71,0x81,0x26,0x31,0x78,0xdf,0xc6,0x43,0x52,0xd4,0x45,0xa4,0x6a,0xe8, + 0x74,0x1a,0x5c,0x5d,0x4f,0xba,0xdb,0x2c,0xb3,0x46,0x72,0xac,0xc6,0xe8,0x28,0xed, + 0xd1,0x52,0x61,0x3d,0x0d,0x9f,0xe6,0xd4,0x6c,0x93,0x8b,0x90,0x89,0x2a,0x70,0x57, + 0xa2,0xa1,0x1a,0xc1,0xe4,0x3c,0x7f,0xfe,0xf1,0x5f,0xb2,0xbe,0x31,0x8a,0x35,0x1b, + 0x89,0x06,0x21,0x40,0xf2,0xae,0x4a,0xac,0x30,0x25,0x9d,0xce,0x33,0xa0,0x0f,0xef, + 0x82,0xc6,0x45,0x65,0x23,0x8b,0x71,0xa0,0xc0,0xc6,0x72,0xb8,0x62,0xf1,0x0b,0x64, + 0x16,0x54,0xbf,0xdb,0xd6,0x55,0x49,0x95,0x9e,0xca,0x43,0x9a,0x45,0x21,0xe5,0x66, + 0x3a,0x39,0x31,0xef,0xca,0xfa,0x08,0x70,0x3a,0x73,0xec,0x69,0xbd,0xff,0x78,0x4d, + 0x27,0x64,0x94,0x4e,0xfc,0x78,0xf5,0x49,0x29,0x9f,0xc7,0x0e,0xdb,0x87,0xd0,0xf8, + 0x94,0x22,0xc1,0x9c,0x0d,0xe9,0x36,0x17,0x10,0xcd,0x99,0xce,0xb2,0x4a,0x11,0x4f, + 0x24,0x47,0x35,0xc0,0xe7,0x94,0x8f,0xcc,0x49,0xff,0x81,0x84,0x8a,0x57,0x9b,0x92, + 0x33,0x57,0x5f,0x87,0xd6,0xbf,0x52,0x50,0xc4,0x58,0xee,0x62,0x2c,0xaa,0x51,0x1e, + 0xf9,0xd6,0xe5,0xd5,0xfb,0xab,0x4f,0x57,0x28,0x14,0xe9,0x18,0x91,0xaa,0x9b,0x16, + 0xa5,0x3b,0xc2,0x5a,0x3e,0x71,0x75,0x5a,0x29,0x3e,0x36,0x49,0xd7,0xa7,0x1f,0x1e, + 0xea,0x3b,0xd3,0x41,0x00,0xea,0xea,0xe3,0x2b,0xac,0x0b,0x32,0xc0,0x15,0xca,0x62, + 0x95,0x93,0x80,0x50,0xdd,0xb1,0x71,0x42,0x06,0xa8,0xbe,0x49,0xbd,0xb5,0xc2,0xef, + 0xce,0x42,0xdf,0xc9,0xfe,0xdd,0x13,0xc6,0x49,0xfc,0xe5,0xd3,0xa7,0x8f,0xd0,0x97, + 0x7a,0xa9,0xc6,0x0f,0x02,0x6a,0xd8,0x47,0x20,0xba,0xfc,0x72,0x50,0x8c,0x56,0xcd, + 0xcb,0xd7,0xc2,0x59,0xd4,0xb4,0xad,0x2a,0x23,0x04,0x24,0xe4,0x58,0x14,0x04,0xe9, + 0x0d,0x23,0x9c,0x26,0x52,0x17,0x4b,0xaa,0xd2,0xd0,0xea,0x0b,0x7f,0xad,0x2e,0x2c, + 0x4a,0x22,0xb6,0x2e,0x6c,0x2c,0xc7,0xb5,0x04,0x9d,0x55,0x8c,0x9d,0x25,0xf9,0x57, + 0x3a,0xa7,0x81,0xe0,0xae,0xd4,0x85,0x69,0x4d,0x06,0x8b,0x13,0x81,0x4a,0x13,0xc5, + 0xc3,0xee,0x9d,0x98,0xfb,0xfa,0xce,0xf3,0x2e,0xdc,0x14,0x02,0x83,0x88,0xf4,0x01, + 0x5b,0x94,0x23,0x8d,0x89,0xbc,0xf5,0x99,0x0e,0x0a,0xb4,0xca,0xce,0xdd,0xc2,0x45, + 0xd9,0xa7,0xb8,0x8d,0xec,0xd9,0x26,0x45,0xbb,0xa3,0x72,0x20,0x6f,0x84,0x87,0x69, + 0x90,0x7f,0xbe,0xfb,0xcd,0xcd,0x82,0xa2,0x5f,0xc0,0x54,0xe1,0xec,0xfd,0xbb,0x5e, + 0x2d,0x9e,0xe9,0xde,0x9e,0xd9,0xcf,0x94,0x52,0xb1,0x5c,0xfd,0x80,0xc4,0x42,0x92, + 0x77,0x56,0x96,0x7c,0xee,0x25,0x52,0x7d,0xdb,0x08,0x8e,0x6a,0xc1,0xa9,0x9b,0xa9, + 0x05,0xf5,0x7c,0xe5,0xf2,0xd1,0xd4,0xce,0x20,0xdb,0xb7,0x54,0xde,0xb2,0x3d,0xb3, + 0x3f,0xf5,0xc6,0xbc,0x58,0x73,0xf7,0x7e,0x75,0x66,0x7b,0xbf,0x5a,0xfc,0xbe,0xb1, + 0x78,0xff,0x5f,0x6f,0xff,0xfa,0xb3,0xa7,0x59,0x9b,0xc4,0x73,0xc0,0xfb,0xf7,0xcb, + 0xba,0xd6,0x77,0xe1,0x49,0x7c,0x13,0xaa,0x29,0x5e,0xd4,0x57,0xf0,0x27,0x15,0x99, + 0x22,0x18,0x3b,0xaa,0xaa,0xc2,0xa7,0x6f,0x7d,0xb5,0x3b,0xe3,0xd3,0x64,0xc8,0xa1, + 0xa5,0x64,0xf7,0xc5,0x20,0xe7,0x65,0xd4,0x63,0xe2,0x5e,0x84,0x17,0xf9,0x78,0x0c, + 0xfb,0x82,0xf6,0xe5,0xc5,0xdc,0x72,0x56,0x67,0x95,0x4c,0x19,0x30,0x61,0xda,0xac, + 0x63,0x62,0x24,0x31,0x28,0xce,0x62,0x6e,0xca,0x21,0x4a,0xe4,0xc8,0xee,0xa8,0xac, + 0x56,0x99,0x3f,0xe1,0x61,0x83,0xb9,0x3a,0xc3,0x6c,0xc8,0x29,0x15,0x43,0x1e,0xce, + 0xe9,0x4e,0x86,0x5d,0xad,0x9c,0x01,0x0f,0x56,0x07,0xdc,0x74,0xbb,0xb7,0x12,0xe6, + 0x8c,0xdb,0xb6,0xea,0xab,0x12,0x50,0x9b,0x1c,0x6e,0x84,0x83,0xc3,0xb4,0x55,0xee, + 0x29,0xa5,0x08,0xaa,0x1e,0xa7,0x0c,0xec,0xac,0x02,0x77,0x50,0xd8,0x08,0x44,0x09, + 0x73,0x0d,0x03,0xd6,0xa3,0x1d,0x0b,0x37,0x81,0x35,0x94,0xf2,0x13,0x90,0x05,0x56, + 0x91,0x9b,0xab,0x9b,0x31,0x25,0x6b,0x3d,0xba,0x40,0x43,0x17,0xe0,0xe2,0x0a,0x5f, + 0xf5,0x1d,0x97,0xb6,0x0a,0xe2,0x2b,0xa2,0xe8,0x7a,0x8b,0xc7,0x51,0xc7,0x66,0xd1, + 0xc5,0x28,0x49,0x23,0x9b,0xd7,0xa8,0x45,0x0a,0x11,0xd9,0x8e,0x26,0xe3,0x56,0xb5, + 0x80,0xfa,0x86,0x67,0x43,0x3a,0x12,0xa9,0xbc,0x54,0x64,0xc3,0x6a,0xa4,0xa0,0xab, + 0x72,0xbe,0xc0,0x1e,0x56,0x48,0x9f,0xe0,0xfa,0x52,0x1b,0x1e,0xec,0x6d,0xf9,0x68, + 0xf9,0x12,0x89,0xdb,0x54,0x34,0x97,0x27,0x97,0xb9,0xf5,0x5b,0x0c,0x85,0x47,0x3b, + 0x35,0x11,0x69,0x77,0xbc,0xe2,0x3c,0x0d,0x11,0x07,0x0c,0xdf,0x31,0xdb,0xfc,0x40, + 0x2b,0x91,0xb7,0x22,0x44,0x49,0xad,0xf2,0xf0,0x7b,0xc4,0xb8,0x27,0x94,0xe4,0xc9, + 0x4e,0x8f,0x0a,0x3d,0x41,0x38,0x9d,0xa6,0x8b,0x7a,0x16,0x12,0xab,0x6b,0xd7,0xa5, + 0x7e,0x90,0xd4,0x70,0x49,0x1b,0x8a,0xa1,0x3d,0xd1,0xb3,0x3f,0xae,0xd9,0x9a,0xd1, + 0x9b,0xdb,0x6a,0xd6,0x52,0x85,0x1f,0xc5,0x4d,0x8f,0x47,0x11,0xfc,0x4a,0x56,0xbd, + 0x4f,0xe0,0x38,0x32,0x41,0xec,0x21,0x65,0xb6,0xdc,0x2f,0x85,0xa3,0x42,0x85,0x23, + 0x97,0xeb,0x06,0x31,0x63,0x1d,0x9c,0xe8,0x94,0xa8,0xe9,0x07,0x6b,0x67,0x35,0x17, + 0xa8,0xab,0x6a,0x97,0x66,0xde,0x3a,0x2c,0x0d,0x56,0x68,0x5b,0xf3,0x47,0x25,0x66, + 0x86,0x0a,0xe3,0xb4,0xa9,0x4b,0x68,0x3a,0x79,0xf2,0xfc,0xdd,0xed,0x5f,0xcd,0xa9, + 0xda,0xea,0x64,0x51,0x95,0x21,0x20,0xd1,0x64,0x14,0xff,0x91,0x59,0xfb,0xca,0xe3, + 0x10,0x19,0x50,0x6d,0x77,0x7d,0xdc,0x87,0x21,0x45,0x64,0x43,0xbe,0x5b,0xc1,0xc1, + 0x59,0xf0,0xfa,0xb8,0xb3,0x2a,0x27,0xa2,0xb7,0x0a,0x34,0x79,0x91,0x34,0xe2,0xcc, + 0x72,0x8b,0x2f,0x9b,0x66,0x66,0x10,0x68,0x13,0xe4,0x9e,0xba,0x1e,0x6f,0x14,0xdf, + 0xd8,0x80,0x9a,0x52,0xe3,0xd6,0xbd,0x6b,0xd7,0xa0,0xdf,0x1e,0xab,0xf3,0x35,0x52, + 0xd1,0x84,0x98,0x96,0x64,0x71,0x5e,0x07,0x38,0x25,0x3b,0xca,0x5f,0x81,0xa0,0xf1, + 0x8b,0x2d,0xbb,0x4b,0x95,0x55,0x8f,0x7a,0xcd,0xaf,0xb5,0xd4,0xe1,0x3d,0x7a,0xd6, + 0x3f,0x39,0x3c,0x50,0xb7,0xcf,0xde,0x1e,0xe8,0x1f,0x38,0xfe,0x1f,0x4b,0xc5,0xe8, + 0x57,0xf1,0x38,0x00,0x00, }; constexpr size_t STATUS_INDEX_HTML_GZ_LEN = sizeof(STATUS_INDEX_HTML_GZ); // diff --git a/firmware/patternflow/src/theme_index.h b/firmware/patternflow/src/theme_index.h index 05df763c..7078d794 100644 --- a/firmware/patternflow/src/theme_index.h +++ b/firmware/patternflow/src/theme_index.h @@ -11,24 +11,45 @@ // node --check on it, and it names no feature (check_boundaries.py R5): // the only paths it knows are the core's NAV below. // -// At parse time (no network): the theme stamp from localStorage 'pf-theme' -// before first paint; head CSS (light palette = the union of every page's -// variable families, color-scheme, a placeholder band of exactly -// --pf-chrome-h so nothing moves when the header mounts, 16px inputs on -// touch screens because iOS zooms into smaller ones, .pf-busy); the fetch +// At parse time (no network): the theme stamp before first paint, always +// set: data-theme=dark only when localStorage 'pf-theme' says 'dark', else +// light (the default). Head CSS: the font stacks for every page; the light +// palette, under every token name any page uses, as html:root[data-theme= +// light] so it outranks both a page's :root and a feature page's own +// html[data-theme=light] block (core pages carry the same values in :root so +// they are light without this file; feature pages keep dark in :root); +// color-scheme; a placeholder band of --pf-chrome-h where the header will +// mount; 16px inputs on touch screens because iOS zooms into smaller ones; +// .pf-busy. --pf-chrome-h is a guess (85px, 125px below 370px where even the +// core's six links wrap, 49px from 1024px) overridden by the height this +// browser measured at this viewport width before: 'pf-nav'.h, {width: px}, +// at most eight, written as media queries because the viewport meta below +// this script is not parsed yet, so innerWidth would be wrong on a phone. +// The mounted header is held at that height (min-height) until the first +// status says which nav to draw; then it takes its own height, which is +// measured and kept. So only a first visit at a new width can move the page +// (a firmware update keeps the heights, though it drops the cached nav). +// Then the fetch // wrapper, which gives every same-origin GET/HEAD without its own signal an // AbortController so a tab switch can free the panel's single connection // instead of queueing behind it; and window.PF. // // At DOMContentLoaded it mounts as body's first // child, everything inside an open shadow root so no page CSS reaches it and -// its CSS reaches no page (pages must not reach into it either). Heights are -// fixed: phone = 40px brand row + 40px nav row + 1px rule = 81px, >=720px = -// one 40px row + rule = 41px, the values of --pf-chrome-h. +// its CSS reaches no page (pages must not reach into it either). Phone: a +// 44px brand row (chip, theme toggle) over the nav, which wraps in 40px rows +// rather than scrolling sideways; >=1024px: one 48px row. A desktop row the +// nav cannot fit (many features, or the chip showing) wraps under it with +// brand, chip and toggle staying on the first line. The chip and the toggle +// are 40px tap targets (the chip draws its 30px pill inside a transparent +// border). // // The nav is the core's pages only; features contribute theirs through -// /api/status featureNav, spliced in after Patterns. (This file once named -// three optional features by path, so a build without them drew dead links.) +// /api/status featureNav, spliced in after Patterns. Order: Console, +// Patterns, the features, then the setup group (Wi-Fi, Knobs, Update, +// Status) in its own , so it wraps as one and sits right on +// a desktop. (This file once named three optional features by path, so a +// build without them drew dead links.) // Every href carries ?v=, which the device serves immutable, so a tab // switch after the first visit costs no request. The last nav drawn is kept // in localStorage 'pf-nav' and reused when its build matches the page's. @@ -74,32 +95,34 @@ const char PF_CONSOLE_JS[] PROGMEM = R"JS((function(){ if(window.PF)return; -var W=window,D=document,H=D.documentElement,L=location,light=false; +var W=window,D=document,H=D.documentElement,L=location,dark=false,cn=null,hm={},k, +st=D.createElement('style'),c; // Theme before first paint: this script is parser-blocking in . -try{light=localStorage.getItem('pf-theme')==='light'}catch(e){} -if(light)H.setAttribute('data-theme','light'); -var st=D.createElement('style'); -// --pf-chrome-h is the header's exact height (see the shadow CSS below). -st.textContent='html[data-theme=light]{color-scheme:light;--cream:#F4EFE6;--cream2:#FFFCFA;--ink:#1A1814;--muted:#6B6558;--faint:#9A9486;--rule:#D9D1C2;--rule-soft:#E8E2D6;--led:#FF5C2E;--ok:#2F8A55;--warn:#B88120;--panel:#FFFCFA;--bg:#F4EFE6;--ghost:#E0D9CC;--card:#FFFCFA;--card2:#E8E2D6;--fg:#1A1814;--mut:#6B6558;--ln:#D9D1C2;--bad:#B8402E;--bar:#E0D9CC;--bar-on:#FF5C2E;--accent:#FF5C2E}' -+':root{color-scheme:dark;--pf-chrome-h:81px}@media(min-width:720px){:root{--pf-chrome-h:41px}}' -+'html:not(.pf-mounted) body::before{content:"";display:block;box-sizing:border-box;height:var(--pf-chrome-h);border-bottom:1px solid var(--rule,#242118);background:var(--cream,var(--bg,#0C0B09))}' +try{dark=localStorage.getItem('pf-theme')==='dark';cn=JSON.parse(localStorage.getItem('pf-nav'));hm=cn&&cn.h||{}}catch(e){} +H.setAttribute('data-theme',dark?'dark':'light'); +// Light palette = the core pages' :root values; outranks any page's own. +c='html[data-theme]{--sans:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mono:ui-monospace,"Cascadia Mono","SF Mono",Menlo,Consolas,"Roboto Mono",monospace}' ++'html:root[data-theme=light]{color-scheme:light;--cream:#F4EFE6;--panel:#FFFCFA;--ink:#1A1814;--muted:#625C51;--faint:#7D7668;--rule:#DDD5C6;--rule-soft:#E8E1D4;--ghost:#E3DCCE;--led:#FF5C2E;--bad:#B83C1C;--ok:#2B7A4B;--warn:#85600E;--cream2:#FFFCFA}' ++'html[data-theme=dark]{color-scheme:dark}:root{--pf-chrome-h:85px}@media(max-width:369px){:root{--pf-chrome-h:125px}}@media(min-width:1024px){:root{--pf-chrome-h:49px}}' ++'html:not(.pf-mounted) body::before{content:"";display:block;box-sizing:border-box;height:var(--pf-chrome-h);border-bottom:1px solid var(--rule,#DDD5C6);background:var(--cream,#F4EFE6)}' +'@media(pointer:coarse){input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]),select,textarea{font-size:16px!important}}' +'.pf-busy{opacity:.55;cursor:progress}'; +for(k in hm)c+='@media(min-width:'+(k-1)+'px) and (max-width:'+k+'.9px){:root{--pf-chrome-h:'+(hm[k]|0)+'px}}'; +st.textContent=c; (D.head||H).appendChild(st); var PF=W.PF={v:null,state:'connecting',dirty:false}, nf=W.fetch,T=[],cur=null,Q=[],lb=0,run=1,P=[],S=null,subs=[],sq=null,sb=0,wms=1/0,sp=null, rtt=null,fails=0,off=0,alien=0,rs=0,holds=0,guards=0,leaveOk=0,RH={},bc=null, me=Math.random().toString(36).slice(2),touched=0,pd=0,nv=0,nvT,pgT, -adopted=0,healed=0,stale=null,pft=0,ct=0,cn=null,fnav=[],drawn='', +adopted=0,healed=0,stale=null,pft=0,ct=0,fnav=[],drawn='', sr,hl,ver,vb,nav,ch,tg,pg,tw,tq,tt,SKIP={}, // The core's pages and nothing else; features add theirs via featureNav at // NAV_AT. Third field: prefetch order, smallest page first. -NAV=[['/','Console',5],['/patterns','Patterns',6],['/status','Status',2],['/wifi','Wi-Fi',4],['/knobs','Knobs',1],['/update','Update',3]],NAV_AT=2; +NAV=[['/','Console',5],['/patterns','Patterns',6],['/wifi','Wi-Fi',4],['/knobs','Knobs',1],['/update','Update',3],['/status','Status',2]],NAV_AT=2; try{PF.v=new URLSearchParams(L.search).get('v')}catch(e){} var docB=PF.v; H.classList.add('pf-connecting'); -try{cn=JSON.parse(localStorage.getItem('pf-nav'))}catch(e){} if(cn&&Array.isArray(cn.nav)&&(!PF.v||cn.build===PF.v))fnav=cn.nav; function now(){return Date.now()} @@ -221,10 +244,12 @@ else if(sp)sp.set(ms); else sp=PF.poll(stGet,ms,function(){},{first:false}); } function deliver(s){ +var fn=Array.isArray(s.featureNav)?s.featureNav:[],r=!S; S=W.pfStatus=s;sb=0; -var fn=Array.isArray(s.featureNav)?s.featureNav:[]; -if(s.build+JSON.stringify(fn)!==drawn){fnav=fn;try{localStorage.setItem('pf-nav',JSON.stringify({build:s.build,nav:fn}))}catch(x){}drawNav()} +if(s.build+JSON.stringify(fn)!==drawn){fnav=fn;drawNav();r=1} badge(); +if(r&&sr){sr.host.style.minHeight='';if(Object.keys(hm).length>7)hm={};hm[W.innerWidth]=sr.host.offsetHeight} +if(r)try{localStorage.setItem('pf-nav',JSON.stringify({build:s.build,nav:fn,h:hm}))}catch(x){} for(var i=0;i1);nav.classList.toggle('fr',s
              '; ++'
              '; function q(c){return sr.querySelector('.'+c)} hl=q('h');ver=q('ver');vb=q('vb');nav=q('n');ch=q('c');tg=q('tg');pg=q('pg');tw=q('tw'); +if(!S)host.style.minHeight='var(--pf-chrome-h)'; D.body.insertBefore(host,D.body.firstChild); H.classList.add('pf-mounted'); -nav.addEventListener('scroll',fades,{passive:true}); -W.addEventListener('resize',fades); -tg.onclick=function(){var l=H.getAttribute('data-theme')!=='light';H.setAttribute('data-theme',l?'light':'dark');try{localStorage.setItem('pf-theme',l?'light':'dark')}catch(x){}tgl()}; +tg.onclick=function(){var t=dk()?'light':'dark';H.setAttribute('data-theme',t);try{localStorage.setItem('pf-theme',t)}catch(x){}tgl()}; ch.onclick=function(){if(stale)L.replace(vurl(stale));else if(PF.state==='offline')fetchStatus()}; tgl();drawNav();badge();chip(); setTimeout(function(){ct=1;chip()},800); @@ -468,7 +489,7 @@ if(u.pathname+u.search===L.pathname+L.search)return; if(guards){if(!confirm('An upload is running \u2014 leave anyway?')){e.preventDefault();return}leaveOk=1} nv=1;run=0; for(i=T.length;i--;)if(!(T[i].k==='prefetch'&&T[i].u===u.href)){T[i].why='nav';T[i].c.abort()} -if(nav)for(i=0;i GENERATED by firmware/toolchain/console_pages.py build — do not edit. -// gzip -9 of PF_CONSOLE_JS (22934 bytes → 9654 bytes), served with Content-Encoding: gzip. +// gzip -9 of PF_CONSOLE_JS (22826 bytes → 9639 bytes), served with Content-Encoding: gzip. const uint8_t PF_CONSOLE_JS_GZ[] PROGMEM = { - 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0x95,0x7c,0xff,0x77,0x9b,0xc6, - 0xb6,0xef,0xef,0xfe,0x2b,0xb0,0x73,0x2a,0x44,0x8d,0xb0,0xe4,0x38,0x69,0x82,0x42, - 0x7c,0x13,0x3b,0xb9,0xe9,0x3d,0x69,0x9b,0x53,0xbb,0xed,0x5b,0xcb,0xf5,0x3d,0x0b, - 0xc1,0x48,0x22,0x42,0x80,0x01,0x49,0xf6,0x91,0xf4,0xfe,0xf6,0xf7,0xd9,0x7b,0x06, - 0x18,0x64,0x39,0xed,0x5b,0x2b,0x91,0x61,0x18,0xf6,0xec,0xd9,0xb3,0xbf,0xcf,0x1e, - 0xba,0xe3,0x45,0x12,0x94,0x51,0x9a,0x74,0xad,0xf5,0x41,0x34,0xee,0xae,0xa2,0x24, - 0x4c,0x57,0xce,0x97,0x8f,0x56,0x2e,0xca,0x45,0x9e,0x0c,0x0f,0x96,0x7e,0x6e,0xfc, - 0xe1,0xc9,0x76,0xfb,0xd2,0x0b,0xd3,0x60,0x31,0x17,0x49,0x69,0x7f,0xf2,0x2e,0x9d, - 0xea,0xe6,0x43,0x2c,0xb8,0xed,0xb3,0x17,0xa7,0x81,0x4f,0xe0,0xec,0x38,0x9a,0x4c, - 0x4b,0x6f,0xec,0xc7,0x85,0x18,0x1e,0x9c,0x9c,0x18,0xd7,0x53,0x74,0x31,0x46,0x62, - 0x9c,0xe6,0xc2,0x18,0x47,0x79,0x51,0x1a,0x99,0x1f,0x25,0xa5,0x6b,0x94,0xd3,0xa8, - 0x30,0x8a,0x20,0x8f,0xb2,0xd2,0xc0,0x55,0xe6,0xe7,0x85,0xc8,0x7b,0x23,0x40,0x9a, - 0x45,0xc9,0xc4,0x88,0x12,0xe3,0xcd,0x54,0xf8,0xe1,0x5b,0xe7,0xa0,0xcc,0x1f,0xd6, - 0x12,0x2e,0x0d,0x13,0x5f,0x95,0x69,0xee,0x4f,0x84,0x33,0x11,0xe5,0x8f,0xa5,0x98, - 0x77,0xcd,0x6c,0xdc,0x2b,0x69,0x18,0xd3,0xf2,0x3c,0xcf,0xe4,0x9e,0xe6,0x16,0xf8, - 0x04,0xd3,0xae,0xb0,0xd6,0x5b,0x9a,0x1f,0x37,0x5a,0x9f,0x9c,0x42,0x94,0xef,0xca, - 0x32,0x8f,0x46,0x8b,0x52,0x74,0xcd,0xd0,0x2f,0x7d,0xf5,0xaa,0xad,0xde,0xb3,0xe4, - 0xcc,0x8b,0x12,0xd3,0x0c,0x72,0xe1,0x97,0x42,0x4d,0xb2,0x6b,0x16,0xe5,0x43,0x2c, - 0xa8,0x03,0xa6,0xd5,0xeb,0x61,0xd0,0x60,0x9a,0xa7,0x73,0xd1,0x9b,0x12,0xfa,0x80, - 0x62,0x10,0xba,0x22,0x37,0x0b,0x43,0xdc,0xfb,0x41,0x89,0x5b,0x82,0x68,0x74,0x0b, - 0x21,0xf8,0x71,0x31,0xf5,0x41,0x4b,0xe3,0xe2,0xea,0x0a,0xf4,0x88,0xd3,0x95,0xe5, - 0x1c,0x14,0xa5,0x53,0x8a,0xfb,0xf2,0x22,0x4d,0x4a,0x0c,0xe1,0x99,0xd3,0x72,0x1e, - 0xdf,0x34,0x58,0x79,0x8c,0xd3,0xed,0x3a,0x48,0xe3,0x34,0xef,0x15,0x01,0xb5,0xb9, - 0xdc,0x36,0xec,0xf5,0x08,0xbb,0xb9,0xfb,0xec,0xe3,0xd9,0x87,0x8f,0x1f,0x5e,0x56, - 0xf7,0xa7,0x68,0xf8,0xf8,0xf1,0xe2,0xe3,0x3b,0x34,0x44,0xc9,0xcc,0x7d,0x36,0x78, - 0x37,0x78,0x35,0x38,0xc3,0xdd,0x1c,0x33,0x0e,0xdd,0x67,0x2f,0xdf,0xbf,0x7c,0xf1, - 0xe2,0x15,0xee,0xc7,0xbc,0x0a,0xcf,0x5e,0xbf,0x7b,0x7d,0xf6,0x8a,0x5e,0xcf,0x17, - 0xb1,0x70,0x9f,0x5d,0xbe,0xbe,0x1c,0x5c,0x9c,0xaa,0xdb,0x5e,0x91,0x8e,0xd1,0xe5, - 0xc3,0xab,0x0f,0xa7,0x97,0xd4,0x25,0x26,0x00,0x1f,0x3f,0xbe,0xb8,0x38,0xfd,0x80, - 0xbb,0x14,0xd0,0x4f,0x3f,0xbe,0x7a,0xf7,0xe2,0x05,0x6e,0x56,0x7e,0x9e,0xb8,0xcf, - 0xde,0xbf,0x7a,0x35,0x38,0xed,0xe3,0x36,0xf3,0x13,0x11,0x6b,0xa8,0x8c,0x26,0x1a, - 0xa2,0x93,0x69,0x5a,0x10,0xd8,0xfe,0xe5,0xeb,0x8b,0x0b,0x42,0xdc,0xcf,0x43,0xad, - 0x2f,0xdd,0x9e,0x6a,0xa3,0x8e,0x27,0xed,0x59,0x68,0x73,0x88,0x13,0x0d,0xe3,0x91, - 0x1f,0x12,0x06,0x67,0x7d,0xc6,0x6e,0xe4,0xe7,0xda,0x10,0xb8,0xeb,0xa5,0x89,0x86, - 0xbc,0x1f,0x04,0x82,0xa6,0x2f,0x1b,0xb6,0xe6,0xc1,0xb1,0xe9,0xe6,0x69,0x5a,0xb6, - 0x49,0x1d,0xfa,0xf9,0x6c,0xd8,0x5a,0x6a,0xf7,0xd5,0x20,0xbb,0xdf,0xfe,0xd7,0x5c, - 0x84,0x91,0xdf,0x9d,0x47,0x49,0x6f,0x15,0x85,0xe5,0xd4,0xfd,0xe1,0xb4,0x9f,0xdd, - 0x5b,0x6b,0x09,0xa2,0xfd,0xc2,0x19,0xbd,0xc0,0x03,0xd0,0xe2,0xba,0x49,0x5a,0x76, - 0x1d,0x3c,0x9f,0xa7,0x0b,0xac,0x79,0x68,0x19,0xa3,0x34,0x7c,0x70,0x5d,0x29,0x20, - 0x18,0x9d,0x19,0xc1,0x3d,0x3a,0x1a,0x86,0x51,0x91,0xc5,0xfe,0x83,0xcb,0x02,0x31, - 0x1c,0xa5,0xf7,0xbd,0x22,0xfa,0x0f,0x04,0xc3,0x1d,0xa5,0x79,0x48,0x82,0x92,0xde, - 0x0f,0x25,0x87,0xb9,0x60,0xd8,0x6e,0x6b,0x50,0x6b,0x58,0x77,0x2a,0xcb,0x74,0xee, - 0x02,0x05,0xa3,0x48,0xe3,0x28,0x34,0x64,0x57,0x5a,0x5c,0xfb,0xd9,0xe9,0xd9,0xe9, - 0x60,0xf0,0x0a,0x7d,0xfd,0x60,0x36,0xc9,0x81,0x4f,0xa8,0x20,0x31,0x27,0xd9,0xf2, - 0x7a,0x34,0xb1,0x9f,0xf5,0x2f,0xfa,0xef,0xfb,0xaf,0x2d,0x8b,0x67,0xa1,0xe6,0x9e, - 0xa5,0x60,0x1f,0x91,0xbb,0x41,0x4a,0x72,0x6b,0xad,0xa3,0x24,0xc3,0xd2,0xd0,0xec, - 0x6e,0xca,0x87,0x4c,0x78,0x20,0x60,0x30,0x03,0x8e,0xb7,0x96,0xd6,0x98,0xfb,0x61, - 0x94,0xee,0xb4,0x24,0x13,0xd1,0x6a,0x19,0x47,0x31,0x1a,0xec,0x42,0xc4,0x22,0x28, - 0x6d,0x92,0x0e,0x1f,0xe8,0xac,0xc7,0xa0,0x0c,0x51,0x40,0xb8,0x83,0x97,0xd9,0xfd, - 0x61,0x34,0xcf,0xd2,0xbc,0xf4,0x93,0x52,0x92,0x96,0x28,0x3a,0x5a,0x14,0x0f,0xeb, - 0x34,0xf3,0x83,0xa8,0x7c,0x70,0x1d,0x70,0x65,0xb0,0xc8,0x8b,0x34,0x77,0xb3,0x3c, - 0x9d,0xe4,0xa2,0x28,0xb6,0xe6,0xf0,0xa0,0x7b,0xe9,0x90,0x90,0x6e,0x36,0x9f,0x2c, - 0xc7,0xcf,0x32,0x91,0x84,0x17,0xd3,0x28,0x0e,0xbb,0x45,0x09,0xb1,0x66,0xc1,0xff, - 0xf2,0xd1,0xfb,0x03,0x6a,0xd0,0x5b,0x2f,0xdd,0x64,0x11,0xc7,0x76,0x51,0x42,0x05, - 0xb8,0x26,0x16,0x26,0x01,0x3e,0xa0,0xbf,0x69,0x87,0x51,0x8e,0x11,0x58,0xc5,0x6d, - 0xed,0x83,0x64,0x8c,0x17,0xc6,0x02,0xca,0xc6,0xbe,0xf6,0x6e,0x6e,0x6d,0x8c,0xea, - 0xf1,0x9b,0xff,0xa2,0xbb,0x78,0xe4,0xf5,0xed,0x7c,0x91,0x78,0x03,0xfb,0x0b,0xdd, - 0x5f,0xc9,0x67,0xc5,0x62,0x54,0xd0,0x6d,0x71,0xa7,0xee,0xa9,0xdb,0x6a,0x5e,0x78, - 0x83,0x93,0xbe,0x5d,0x64,0xb2,0xf1,0x20,0x2f,0x4b,0x79,0x05,0x59,0x8d,0x0b,0xf4, - 0x48,0xc7,0x63,0xfc,0xfa,0x71,0x24,0x12,0x02,0x4b,0x4d,0xd3,0x34,0x0e,0xe9,0xef, - 0x64,0x01,0xb1,0xa1,0x8b,0x58,0xf8,0x4b,0xf1,0xcb,0x0c,0x57,0xbf,0x7e,0xf2,0xd6, - 0x5b,0x7b,0x14,0x28,0x68,0x50,0x27,0x3f,0xf9,0xe5,0xd4,0x01,0xc9,0xc3,0x74,0xde, - 0xb5,0x9c,0x32,0xbd,0x82,0x26,0x4c,0x26,0xdd,0xe7,0x2f,0x2d,0xa7,0x88,0xa3,0x40, - 0x74,0x4f,0x2d,0xbb,0x4c,0x17,0x58,0xbb,0x10,0xef,0x67,0xf4,0x93,0x2c,0xf9,0xe7, - 0xda,0xce,0x26,0xd7,0xf6,0x01,0x14,0x58,0x56,0xf2,0x43,0x90,0x31,0xe6,0x0b,0x10, - 0x28,0x16,0x72,0x88,0x6c,0x5c,0xa2,0x21,0xe0,0x9f,0x44,0x61,0x9e,0xf8,0x4b,0x9a, - 0x68,0x98,0xfb,0xab,0xc4,0x33,0x4d,0xfb,0xa0,0xc8,0xed,0x69,0x6c,0x2f,0x45,0x6e, - 0x2f,0x47,0x36,0x9e,0xda,0x20,0x5c,0x39,0x01,0x78,0xbb,0x5c,0xd9,0xe5,0x9d,0x5d, - 0x96,0xf6,0xd5,0x3f,0x7f,0xfc,0x42,0xa8,0x2b,0xfb,0x61,0x04,0x10,0x0d,0x93,0x2c, - 0xc4,0x44,0x14,0x06,0xb0,0x37,0xc0,0x2d,0x53,0xb2,0x11,0x82,0xac,0x8c,0x31,0x86, - 0x96,0x5e,0xe4,0xf4,0x28,0x0c,0x49,0xd1,0xc2,0xc8,0x18,0xcb,0xc8,0xaf,0xda,0x7f, - 0xf6,0x97,0x86,0x5f,0x12,0xac,0x9f,0xdf,0xfd,0xfe,0xef,0x77,0xd7,0x0e,0x60,0x46, - 0x79,0x08,0x63,0x24,0xe2,0xd0,0x35,0xb2,0x5c,0xf0,0xea,0x19,0x2c,0x31,0xb6,0x51, - 0xcc,0xfd,0x38,0x16,0x6c,0xa6,0x26,0xca,0x62,0x39,0x07,0x78,0xd3,0xbb,0xb9,0x31, - 0x4f,0x60,0x26,0xa0,0xab,0x21,0x4a,0x30,0x18,0x2f,0x6e,0x6d,0xb4,0x64,0x7e,0x09, - 0x31,0x48,0x0a,0x3c,0xf9,0x52,0x5f,0xbe,0xe4,0x47,0xc4,0x3a,0x0b,0x7a,0x70,0xa5, - 0x2e,0x4e,0xb9,0x79,0x15,0x8d,0x23,0x34,0xfe,0x11,0xf5,0x3e,0xe2,0xef,0x19,0xb7, - 0xcd,0x92,0x74,0x44,0x3d,0xff,0x29,0xff,0x0e,0xb8,0x71,0x91,0xc1,0x12,0x90,0x65, - 0xfa,0x4d,0x5d,0x3c,0xbf,0xbd,0xb5,0xe5,0x1c,0xbc,0xd3,0x21,0x5b,0xc5,0x2f,0x1f, - 0x9d,0xa5,0x97,0x88,0x95,0xf1,0xdb,0xaf,0x9f,0xaf,0x84,0x9f,0x07,0xd3,0x2f,0x7e, - 0xee,0xcf,0x8b,0xee,0x67,0x58,0x3a,0xba,0xb5,0xc8,0x4a,0x76,0xcd,0xa5,0x69,0xe9, - 0x06,0x91,0x18,0x1d,0x36,0xfc,0xbd,0x47,0xef,0x0f,0x0f,0x3e,0x39,0x41,0xec,0x17, - 0xc5,0xe7,0x08,0x53,0x05,0x0d,0xd9,0xa0,0x6a,0x0c,0x6f,0xc9,0xb1,0xb0,0xa4,0xff, - 0x73,0xf5,0xcb,0xcf,0x0e,0x1b,0xea,0xee,0x93,0x96,0x18,0x4b,0x6a,0x5a,0xd6,0x8e, - 0xf9,0x0d,0x92,0x4e,0xe7,0x5d,0x9e,0xfb,0x0f,0x4e,0x54,0xf0,0x5f,0xb4,0x38,0xe8, - 0x69,0x75,0x3a,0xdd,0x43,0x42,0x62,0xb3,0x41,0xc3,0x68,0x01,0x59,0x84,0x09,0xa7, - 0x06,0xcb,0x62,0xd6,0x91,0xdd,0x20,0x9b,0x95,0xbf,0x82,0xb5,0x5f,0xc1,0x67,0x91, - 0x5e,0x8a,0x71,0x09,0xba,0x38,0xdc,0xb2,0x6d,0x7a,0x00,0xb1,0xb8,0x3b,0xb6,0x7d, - 0x7b,0x64,0xad,0x09,0xf1,0x71,0x97,0x2e,0x15,0x46,0xd0,0xd2,0xf0,0x01,0xae,0xa3, - 0xb9,0x48,0x17,0x65,0x57,0xf3,0x82,0x4a,0xe8,0xce,0x95,0x71,0xbf,0xb5,0xb6,0x1a, - 0x28,0xb1,0xec,0x26,0x76,0x68,0xad,0xe1,0xf2,0x40,0x1d,0x13,0x80,0x0f,0x4b,0xf2, - 0x05,0x88,0xe4,0x17,0x8b,0x02,0xba,0x55,0xdd,0xdb,0xeb,0x50,0x94,0x90,0x52,0x37, - 0xdc,0x5a,0x3a,0x2e,0x61,0x9e,0x66,0x44,0x05,0xa2,0x78,0xe4,0x5d,0x3b,0x70,0xa7, - 0xc4,0xfd,0x2f,0x63,0x34,0x0d,0x41,0x96,0xe8,0x6d,0x6f,0x60,0x5d,0x3b,0x50,0xf4, - 0x24,0x7c,0x91,0x3d,0xc0,0xab,0xc4,0xa8,0x92,0x21,0x57,0x39,0xa9,0xa8,0xdc,0x35, - 0x0a,0x1f,0x4a,0x3d,0xcd,0xa3,0x09,0x7c,0xa2,0xff,0xfe,0x70,0x5d,0x18,0xa0,0xb7, - 0xe1,0x1b,0x64,0x2c,0xf2,0x14,0xcc,0x9a,0xe3,0xa6,0xf4,0x47,0x46,0xb1,0x8a,0xe8, - 0xbd,0xc0,0x4f,0x0c,0x1f,0x06,0x00,0x7c,0x5b,0xe3,0x51,0x8e,0xbb,0x0b,0x3b,0xb5, - 0x67,0xf0,0xf6,0x08,0x95,0x80,0x99,0xe6,0x1d,0x75,0xba,0xa8,0xa1,0x74,0x2d,0x5b, - 0x78,0xeb,0xc0,0x0d,0xec,0x85,0xab,0x78,0x0a,0x2f,0x7d,0x76,0xa6,0x90,0x10,0x8b, - 0x7f,0x6d,0xd2,0xf0,0x20,0xb6,0x3d,0x73,0x67,0x5b,0x3b,0x22,0x19,0x85,0xa7,0x08, - 0xcb,0xd5,0x4d,0xc8,0x5f,0x4b,0xad,0xe8,0x26,0xb9,0xf5,0x52,0xfc,0x0c,0x0f,0x22, - 0xa7,0x88,0x26,0x89,0x1f,0x7b,0x81,0xba,0x50,0x1d,0x41,0x84,0x58,0x24,0x93,0x72, - 0x3a,0x4c,0x7a,0xbd,0xa1,0x05,0x2a,0x08,0xa7,0xec,0x5d,0xe3,0x1d,0xa7,0x7c,0xfb, - 0x52,0x9c,0x35,0xf4,0x48,0x40,0x8f,0xe1,0xc1,0xb5,0x93,0x2d,0x8a,0xa9,0x22,0x18, - 0x94,0xab,0x85,0xff,0x75,0xd3,0x81,0x70,0xa0,0x2c,0xc7,0x0e,0x2f,0xf9,0x1f,0xf6, - 0xc2,0x8e,0xd0,0xa6,0x78,0x03,0xfe,0xe7,0xf6,0x40,0xa9,0x66,0xaf,0x5e,0x68,0x50, - 0x41,0xd1,0x60,0xee,0x29,0xf5,0x97,0x76,0x3a,0xa9,0x33,0x17,0xe5,0x34,0x85,0x61, - 0x30,0x41,0x60,0x93,0x74,0xe3,0x6f,0x44,0xfb,0x0b,0x1f,0xac,0x6e,0xd9,0xe9,0x4c, - 0x7a,0xb4,0xb6,0x90,0xa2,0x80,0xfb,0x2e,0x19,0xab,0x74,0x6c,0x2c,0xc8,0xe5,0x2c, - 0x18,0x90,0xb9,0xd9,0x2c,0x40,0x06,0x88,0x7d,0x12,0xd0,0x23,0xd0,0x8f,0xf8,0x7b, - 0x4e,0x3d,0x08,0xea,0x66,0xc3,0x97,0x9f,0x3e,0xbc,0xbb,0x34,0xf1,0xe0,0x90,0x06, - 0xee,0xa6,0x8a,0x3a,0x9b,0x4d,0xea,0xcc,0x84,0xc8,0xa0,0xdc,0x97,0xc2,0xc2,0xe3, - 0xc7,0x2b,0x20,0x39,0x00,0x20,0x3e,0xab,0xcb,0x86,0xa5,0x59,0xc8,0x0e,0xd3,0x99, - 0xf2,0xde,0x0d,0x90,0x04,0xbc,0x13,0x3f,0x80,0x26,0x7e,0x3e,0x61,0x5f,0xbd,0x20, - 0x6a,0x79,0x92,0x0f,0x36,0x1b,0xac,0x1c,0xe8,0x78,0x6e,0x8e,0x26,0xa6,0x6b,0x8e, - 0x59,0xc6,0x41,0x4a,0x07,0xda,0x33,0xd1,0x85,0x42,0xb1,0xef,0xd6,0xde,0xd3,0xa6, - 0x51,0xda,0xc9,0x40,0x6b,0xf6,0x8b,0x07,0xa7,0x06,0xf4,0x70,0x69,0xc0,0x0a,0xc1, - 0xc7,0x33,0x88,0xf3,0xc8,0x31,0x4e,0xcb,0x22,0x4b,0x4b,0x03,0xfc,0x39,0x95,0xae, - 0x70,0xc9,0xd1,0x82,0x01,0xa2,0xa6,0xc6,0x22,0xb3,0xc1,0xc0,0xac,0x77,0x8d,0x5c, - 0x00,0x6b,0x02,0x74,0xb7,0x10,0x0b,0x11,0xc2,0x51,0x86,0xa2,0x0f,0xf1,0x98,0xb5, - 0xb1,0x02,0x97,0x26,0xa2,0xd6,0x4f,0x68,0x42,0xd8,0x00,0x73,0x62,0x94,0x69,0x3a, - 0x33,0xce,0x7a,0x2f,0x80,0x40,0x77,0x24,0x92,0x60,0x4a,0x60,0x4e,0xfb,0xa7,0x2f, - 0x7b,0xfd,0xd7,0xbd,0xd3,0x33,0xcb,0x66,0xd3,0xe1,0x1b,0xd4,0x61,0x1c,0xa7,0x69, - 0xce,0x8a,0x42,0x90,0xc9,0x20,0x84,0xe1,0x2d,0x1b,0x21,0x7c,0x03,0x5d,0x68,0xe6, - 0x69,0xa3,0x6a,0xd8,0x76,0xc2,0xe3,0xeb,0x3e,0x17,0x67,0xb6,0xbc,0xf1,0xef,0xbb, - 0x83,0x53,0xf1,0xdc,0x3e,0xfb,0x1e,0x96,0x9a,0xc4,0x1e,0x03,0xbe,0x83,0x07,0x81, - 0x59,0x00,0x7d,0x98,0x90,0xee,0x3c,0x0d,0x85,0xf1,0xb5,0x48,0x93,0x0d,0x39,0x32, - 0x9b,0xa2,0xdc,0xc0,0xdc,0x58,0x88,0x7d,0x72,0xf8,0x5c,0x18,0x1a,0x3e,0x60,0x14, - 0x1b,0x51,0x59,0xb0,0x1b,0x48,0x71,0x04,0x7c,0x9d,0x70,0x48,0xb3,0x24,0x60,0xa5, - 0x54,0x53,0x78,0x08,0xe7,0x4c,0xc6,0x18,0x4c,0x20,0x9e,0x09,0xad,0x15,0x37,0xd1, - 0xab,0xb0,0x5b,0x29,0xe6,0x36,0x8a,0x26,0x12,0x12,0xd1,0xd6,0x28,0x10,0x64,0xf0, - 0xc4,0x08,0x16,0x60,0xc3,0x6c,0x1a,0x47,0xf0,0x21,0xd0,0x24,0x8e,0x1c,0xe3,0x97, - 0x04,0x90,0x08,0x5e,0x04,0xdb,0x39,0x86,0xe7,0x28,0x43,0x32,0xa5,0x68,0xba,0x04, - 0x9a,0xfd,0x78,0x0b,0xfa,0x88,0xc9,0x24,0x8c,0x5f,0xaf,0xaf,0x09,0x96,0x1a,0xde, - 0xd0,0x17,0x81,0xfc,0xa4,0x21,0x9e,0xc0,0x34,0x63,0x31,0x8a,0xa8,0x84,0xf1,0x84, - 0x42,0x24,0x33,0x5d,0xf8,0x0f,0x45,0x6d,0xb3,0xa1,0x99,0x30,0xa3,0x48,0x57,0x4e, - 0xf9,0x1d,0x98,0x72,0x66,0x13,0xb1,0xec,0x79,0xa1,0xc4,0x13,0x84,0xf2,0xa8,0x85, - 0x44,0x06,0xd7,0xa6,0xad,0x98,0x17,0xd7,0xe7,0xeb,0xad,0xbb,0x0e,0x7c,0xb8,0x29, - 0xae,0x99,0xa4,0x3d,0xa8,0x61,0x3c,0xdf,0x42,0xb9,0xd9,0x65,0xdf,0x93,0x0a,0xaa, - 0x4c,0x6d,0xd2,0x9a,0x95,0x6d,0x84,0x8e,0x59,0xec,0x11,0xa0,0x61,0x83,0x83,0x9f, - 0xc3,0x25,0x5a,0x07,0xe0,0xdb,0xbc,0x32,0x0e,0x65,0x6a,0x0d,0xcb,0xd4,0xdb,0x6f, - 0x2e,0x84,0xb3,0x9a,0x3e,0x78,0x66,0x69,0x0e,0x85,0x13,0x38,0xac,0x6e,0x61,0x84, - 0x80,0xfe,0x66,0xc3,0x6c,0xa3,0x1b,0x81,0x71,0x94,0xec,0x83,0x5d,0x09,0xd2,0x01, - 0x8f,0xad,0x4b,0xd3,0x8e,0x1c,0xe6,0x20,0x89,0xea,0x03,0x31,0x27,0x0e,0x52,0x5d, - 0x73,0xc7,0x27,0x63,0xfa,0x7e,0x31,0x1e,0x93,0xfa,0xe6,0xc7,0x34,0x6d,0x69,0x6f, - 0x42,0x49,0x8b,0x5e,0xd9,0x1f,0x92,0x27,0x49,0xff,0x3d,0xf6,0xca,0xce,0x43,0x17, - 0x37,0xdf,0x3b,0x3f,0x1c,0x87,0xdf,0x3b,0xcf,0x59,0x77,0x54,0x94,0x2e,0x10,0x01, - 0xd7,0xc0,0x89,0x67,0xc9,0x4f,0x6c,0x21,0x53,0x4a,0xe0,0x05,0x43,0x1a,0x92,0x36, - 0x2c,0x74,0xbf,0xa0,0xb4,0x74,0xad,0x04,0x5e,0x79,0x9f,0xa7,0x33,0x30,0x2a,0x75, - 0xa9,0xe2,0x64,0xe6,0x2a,0x38,0x74,0xe9,0x2a,0x51,0xfc,0x3c,0x81,0x48,0xc3,0xde, - 0xa5,0xc9,0xc4,0x66,0x2e,0xad,0xd8,0x28,0x14,0x4b,0x58,0x02,0x87,0xb5,0x5b,0xd1, - 0xe9,0x9c,0xfc,0xef,0x9f,0xc5,0xf7,0x7f,0xae,0x4f,0x80,0x59,0x01,0x1a,0x5a,0x64, - 0xcb,0x81,0x1b,0x96,0x89,0x8d,0xf7,0x87,0x3c,0x87,0x85,0x31,0x17,0x09,0x09,0x91, - 0x3f,0x8a,0xa5,0x9e,0x81,0xe7,0x65,0x49,0xfd,0x88,0xb5,0x39,0x2c,0x1c,0xe8,0x8a, - 0x02,0x13,0xb1,0xd6,0x14,0x71,0x41,0xf7,0xee,0xbe,0xce,0xe3,0x1b,0xca,0x99,0x1b, - 0x93,0x08,0x49,0x7c,0xad,0xad,0x72,0xbc,0x87,0x6a,0x50,0x45,0xa7,0x62,0xab,0x11, - 0x5e,0x3d,0xe2,0xe1,0x72,0xa7,0x51,0xc8,0xdf,0x26,0xe6,0xbd,0x27,0xc7,0x2e,0x61, - 0x7f,0x3e,0x5d,0x5f,0x7f,0x31,0xcc,0xe3,0xdc,0x91,0xb8,0x5b,0xc3,0x7b,0x75,0xe5, - 0x55,0x4d,0xc3,0xda,0x55,0xa9,0x79,0xa6,0x5a,0x3e,0x1a,0xc4,0x3c,0xaf,0x06,0x73, - 0x73,0x87,0x74,0x0f,0xe1,0xb3,0xdd,0x1d,0x19,0x4e,0x0d,0xb3,0x65,0x35,0x8b,0x50, - 0xd3,0xf1,0xf7,0xd5,0xb3,0x03,0xb6,0xce,0xc4,0xe8,0x04,0xdb,0xb4,0xd6,0x15,0xa2, - 0xa6,0xd2,0x4c,0x26,0xa1,0xa7,0xae,0xbd,0xc1,0xb6,0xd5,0x9f,0x1d,0xc1,0x7b,0x72, - 0xdf,0xbc,0x01,0xac,0x0b,0xcc,0xa7,0xa1,0xa8,0x04,0xdb,0x07,0x26,0x86,0xf1,0xab, - 0xdf,0xdd,0x6c,0xa8,0xe3,0x9c,0xe7,0x70,0x0d,0xc3,0xca,0xa3,0xc0,0x8d,0x24,0x0d, - 0xd2,0xf4,0x22,0x47,0xb4,0x99,0xba,0x74,0x95,0xde,0xd7,0xc1,0xab,0x11,0x63,0x99, - 0xc8,0xe4,0x88,0x5a,0xff,0x42,0x8d,0x8d,0x39,0x5d,0x62,0x1b,0x1f,0x7f,0xfc,0xf8, - 0x8b,0xc3,0xd1,0x04,0xaf,0xa6,0x34,0x1a,0x05,0xf5,0x26,0x28,0x9a,0x22,0xf3,0x69, - 0xf5,0x69,0xc0,0x21,0xa5,0xa4,0xc8,0x42,0xc4,0x46,0x06,0xff,0xa8,0x30,0x56,0xe9, - 0x22,0x0e,0xf1,0x06,0xf8,0x95,0xad,0x13,0xf1,0x72,0x2e,0x34,0x3d,0x26,0x92,0x3b, - 0xf8,0x9d,0x64,0x44,0x6a,0xab,0x41,0xfa,0xe7,0x0b,0x54,0x6b,0x04,0xd1,0xa8,0xe9, - 0xfb,0x60,0x83,0xfb,0xfe,0x25,0x9d,0x98,0xf5,0xd8,0x1d,0xdb,0x0f,0x2e,0x9a,0x5c, - 0x78,0x9a,0x2e,0xbd,0x8c,0xc9,0x65,0x8b,0x79,0x06,0x75,0xa2,0x2b,0x11,0xd9,0xc4, - 0xec,0xf2,0x75,0xb8,0x42,0xd4,0x2a,0xba,0x87,0xf1,0xa8,0xd3,0x41,0x70,0x09,0x7a, - 0x72,0x18,0xd8,0xe9,0xfc,0x4b,0xf9,0x56,0xd6,0xfa,0xab,0xf7,0x2f,0xa7,0x98,0x46, - 0x63,0xb0,0x01,0x39,0x4e,0x5f,0x9d,0xb0,0xd3,0xc1,0x0f,0x14,0xd3,0x57,0x27,0xe9, - 0x52,0x84,0x65,0x0d,0x79,0x4d,0x26,0x69,0xf7,0x6b,0xcb,0xe7,0xe5,0x06,0x1e,0x27, - 0x1b,0x22,0x7c,0x1d,0xb0,0x8c,0x67,0x9e,0x9a,0x85,0x83,0x40,0x2b,0x8d,0x97,0x02, - 0x10,0xc7,0x5d,0x4b,0x13,0x76,0xbd,0xc7,0x57,0xd0,0x12,0x6d,0xdb,0x83,0xec,0x31, - 0xd7,0x51,0x44,0x3c,0xfc,0xea,0x3c,0xe0,0xba,0x9a,0x66,0x8b,0xf3,0xd4,0x73,0xba, - 0xd6,0xc8,0xc0,0x96,0xb5,0x46,0xb1,0x48,0x17,0x79,0x20,0x5c,0x56,0x26,0xec,0xdf, - 0x61,0x25,0xa3,0x92,0xa4,0x3d,0x87,0x29,0x2d,0x1e,0x12,0x4a,0x84,0x24,0xe9,0xa2, - 0x20,0x53,0x99,0x8b,0xda,0xdc,0xfa,0x05,0x01,0x6a,0xf2,0x1d,0x6c,0xc8,0x8a,0x29, - 0x77,0x01,0x28,0x62,0x20,0xa8,0x25,0xc5,0x6d,0xda,0xc2,0x8e,0x8b,0x3c,0xe8,0x8e, - 0x6b,0xdf,0x99,0x42,0x7c,0xc4,0xb4,0x99,0x74,0x06,0x1f,0x93,0xe6,0x6f,0x10,0xa6, - 0xca,0x12,0xd4,0x12,0xfc,0x34,0xa3,0xf0,0xa0,0x4f,0xda,0x21,0x5d,0x7d,0xec,0x97, - 0xca,0x61,0xe0,0x40,0xd3,0x7d,0x80,0xb9,0x6c,0xde,0x13,0x4f,0x19,0x30,0x6b,0xc8, - 0x22,0x07,0xc7,0x9b,0x16,0x60,0x6b,0x4b,0x5b,0x36,0xdc,0xb7,0x90,0x8f,0xec,0x99, - 0xd2,0x7d,0xb4,0xb2,0xed,0x25,0x7d,0xd4,0x93,0x43,0x42,0xa7,0x48,0xe7,0xa2,0x85, - 0x52,0x6d,0x00,0x35,0x0d,0x82,0x70,0xaa,0xd1,0x3a,0x8c,0xa5,0x08,0x79,0x7e,0xac, - 0x57,0xb6,0xb5,0x5e,0xb9,0xef,0x74,0xf6,0xaa,0x10,0x9e,0x0e,0x46,0xe4,0xe9,0xb0, - 0x22,0x24,0xcd,0xd1,0xb8,0x1e,0x24,0x38,0x5d,0xb6,0x05,0x5d,0x22,0xe5,0x8c,0x74, - 0xc6,0xaf,0x9f,0x28,0x2c,0x91,0xc6,0xf3,0xd7,0x4f,0x37,0xb3,0xdb,0x37,0x2f,0xc5, - 0x8b,0x4a,0x93,0x97,0xf9,0x42,0x54,0x4a,0x53,0xe6,0x80,0x0e,0x10,0xaf,0x92,0x86, - 0x68,0x82,0x0c,0xb0,0x0b,0x3c,0x01,0x3b,0x18,0xd5,0xc1,0xc6,0xd4,0x5b,0xcf,0x0b, - 0x17,0x6d,0x62,0xe5,0xf6,0x11,0x46,0xf5,0xed,0x34,0x71,0x07,0xf6,0x1d,0x2e,0xd0, - 0xb0,0xd5,0x1c,0x91,0x84,0x55,0x77,0xdb,0xeb,0x84,0xa3,0x89,0xdf,0xc2,0x3e,0xfd, - 0x7e,0xea,0x88,0x95,0x7d,0xd5,0xe9,0x5c,0x39,0x94,0xee,0xda,0x6c,0x14,0xfe,0xe7, - 0x2f,0xc4,0x73,0xb7,0xaf,0xab,0x0b,0xca,0x60,0x86,0x8f,0x96,0x69,0xea,0x40,0x89, - 0xe2,0x47,0x67,0xa6,0xa9,0x33,0x49,0x11,0xe3,0x6e,0x0f,0xe8,0xc2,0xd3,0xf7,0x05, - 0xf6,0xbf,0xda,0x97,0xd6,0x6d,0xea,0xc0,0xab,0xdd,0x4c,0x9d,0xbb,0x7a,0xc7,0x00, - 0xad,0x97,0xce,0x34,0x0a,0x43,0x81,0x07,0x87,0xd0,0x4b,0xd6,0x7a,0xea,0xac,0xc0, - 0x80,0xb2,0x83,0x4c,0x3b,0xc0,0x19,0xc1,0x3b,0x6c,0x11,0x48,0x5b,0x6a,0xf1,0xb7, - 0x72,0xdd,0x2a,0xda,0xaa,0xf8,0x0a,0xa4,0xa4,0x15,0xad,0x3a,0x9a,0xe7,0x44,0x5c, - 0x27,0x1b,0x9f,0x93,0x48,0x5a,0x2e,0x4b,0x26,0xfe,0x5b,0x30,0x76,0x77,0x4c,0x77, - 0x0a,0x69,0x6c,0x93,0xec,0x9e,0xd9,0x8e,0x5b,0x14,0x5c,0x46,0x7c,0x6b,0x1d,0x3c, - 0x66,0xe8,0x10,0xc6,0xa0,0x3b,0xb0,0x77,0xb9,0x97,0x9b,0xfb,0xb6,0x64,0x9f,0x26, - 0xb0,0xa7,0xd6,0x74,0x66,0x2f,0x41,0x27,0x9a,0x90,0xa4,0xca,0x12,0xb8,0x92,0x6e, - 0xc5,0xfc,0x69,0x18,0x9d,0x34,0x88,0xce,0x3a,0x9d,0x25,0xfe,0x71,0xde,0x63,0x87, - 0x32,0x78,0x0e,0x5f,0x61,0xd7,0x6b,0xa3,0xc5,0xf6,0xe8,0xe7,0x9c,0x7e,0x2a,0x7f, - 0xcd,0x0d,0xb7,0x07,0x72,0x75,0x25,0xab,0x00,0xab,0x74,0x76,0xce,0x11,0x30,0x18, - 0x6e,0x69,0x93,0x5a,0xb1,0xdc,0xea,0x9e,0xb3,0x70,0x4b,0x66,0x7a,0x70,0xd9,0x17, - 0x69,0x74,0xa6,0x52,0x04,0x39,0xf0,0xe5,0x0c,0x17,0xd0,0x66,0x5e,0xb6,0x24,0x60, - 0x38,0xe1,0xd2,0x38,0x10,0x4b,0x34,0xae,0xe9,0x1a,0x9e,0x76,0xe6,0x6a,0x24,0xa5, - 0x39,0x62,0xe6,0x8f,0xf9,0x44,0xa6,0x3b,0xbe,0xd4,0xe9,0x8e,0x69,0x93,0xee,0xf8, - 0xd2,0x4a,0x77,0xd8,0x07,0x98,0xad,0xcb,0x2c,0x08,0x96,0x6c,0x60,0x33,0xef,0xcc, - 0xe1,0x64,0xd2,0x7b,0x04,0xb2,0x35,0xe3,0xed,0x96,0xe3,0xcd,0x46,0x8a,0x45,0x81, - 0x18,0x57,0x13,0xe3,0x08,0x58,0x45,0x6f,0xbe,0x54,0x99,0x86,0xe8,0xf8,0x98,0x24, - 0xfa,0xcb,0x4d,0x74,0xeb,0xac,0xac,0xb5,0xfc,0x8b,0x2e,0x7c,0x41,0x33,0xdc,0x4a, - 0x67,0x42,0x26,0xea,0xa4,0x0f,0x21,0x6d,0x8c,0x01,0x88,0x86,0x80,0xcb,0xf8,0xc0, - 0x11,0xa8,0x66,0x13,0x8a,0xf2,0xbf,0x85,0x26,0xa8,0xe0,0x3e,0xf3,0xc4,0xcf,0xa2, - 0x26,0xeb,0xc7,0x7c,0x48,0xfe,0xb4,0xe4,0xb4,0x50,0x50,0x64,0x9f,0x43,0xce,0xf8, - 0x4d,0xb0,0x30,0x09,0x01,0x06,0xfd,0x8d,0x63,0x40,0x5f,0xf9,0xaa,0xb0,0x57,0x79, - 0x44,0x9e,0x89,0x9e,0xe3,0x84,0xe1,0x9a,0x15,0x8c,0x0a,0x30,0x53,0xa1,0x1e,0x29, - 0x36,0x98,0x34,0x99,0x2a,0x8a,0xd8,0xb0,0x01,0x95,0x3c,0x42,0x5b,0x17,0x41,0xb8, - 0x0d,0x0e,0x5d,0x8c,0x38,0xfc,0x2a,0x53,0xe3,0x79,0xdf,0x28,0x2c,0x44,0x9b,0xb1, - 0x28,0xe0,0xf3,0xc8,0x08,0x90,0x32,0xaa,0x79,0x3a,0xc2,0x22,0xfb,0xb0,0x79,0x3e, - 0x39,0xe9,0x29,0x10,0xd4,0xcd,0x1e,0xc1,0x96,0x34,0xc1,0x44,0xd9,0x83,0xbe,0xb3, - 0x8a,0x3b,0x8f,0x24,0x97,0x27,0xa1,0xa6,0x16,0xc4,0xb9,0x2e,0x68,0xb8,0xad,0x5c, - 0x60,0x68,0xaa,0xc3,0x1c,0x7e,0x09,0x34,0x24,0x07,0x88,0x87,0x10,0xe5,0x6a,0x78, - 0x4b,0xd3,0x41,0x09,0x02,0x4c,0x4a,0x82,0xd7,0x41,0xf6,0xe9,0xf7,0xc5,0x68,0xb3, - 0xa1,0xe0,0x1a,0xe1,0xb6,0xc5,0x76,0xa9,0x4e,0xef,0x11,0xf8,0xb5,0xca,0x9c,0xeb, - 0x8e,0x0b,0x01,0x51,0x78,0x5e,0x59,0x2d,0xdc,0xb7,0xcd,0xe2,0x52,0x0c,0xc2,0x59, - 0x87,0x99,0xc8,0x4a,0x44,0xbd,0xa2,0x98,0x1a,0xec,0x4d,0xb1,0x03,0x41,0x81,0x2a, - 0x29,0x56,0x9b,0xda,0x40,0x57,0xce,0x13,0x14,0x15,0x03,0x40,0xc7,0x13,0xa0,0x2e, - 0x45,0x08,0xf2,0x1d,0xbc,0x4e,0x3e,0x07,0x6d,0xcb,0x18,0x2b,0x3f,0x2a,0x3f,0xa6, - 0xf9,0x25,0x87,0x2c,0x72,0x18,0x8a,0x43,0xe4,0x7b,0xbc,0xa3,0x09,0x7a,0x69,0xfc, - 0x43,0x69,0x4c,0x99,0x88,0x2a,0x9a,0x79,0xaf,0xa0,0xe5,0x2b,0x62,0x79,0x1a,0xb1, - 0x36,0x9b,0x5a,0xe9,0x33,0x49,0x59,0xe1,0x0f,0x4e,0xfa,0x92,0xce,0x80,0xe0,0xd1, - 0xd6,0x01,0x4f,0xbe,0xc8,0x40,0x9d,0xcc,0x21,0x59,0xc5,0x32,0xa8,0xcd,0x84,0x6d, - 0x63,0x29,0xf1,0x9c,0x1e,0x83,0x79,0xe7,0x9c,0x13,0xa2,0x66,0xf4,0x52,0x46,0x4c, - 0x2e,0x2c,0x59,0x2f,0x6d,0x45,0xb7,0xf6,0x9a,0xd5,0x84,0xda,0xf4,0x68,0x9b,0x50, - 0xc5,0xd8,0x5d,0x0a,0xdc,0xaf,0xbc,0x3f,0xc0,0xd8,0x92,0xd2,0x5e,0x31,0xa4,0x6d, - 0x0d,0xb9,0x9f,0x3a,0x4e,0xbc,0x76,0xfe,0xb7,0x70,0x9a,0xf4,0xbc,0x75,0xae,0xdf, - 0xb9,0x37,0xb7,0x32,0x9e,0x92,0xf9,0xe0,0x63,0x0e,0x2e,0x65,0x86,0x2d,0x1a,0x3f, - 0x74,0xc7,0x89,0x05,0x2e,0xe2,0xfd,0x04,0xc8,0x3b,0x79,0x01,0xe3,0x84,0x5d,0xd4, - 0x56,0x46,0xba,0xd8,0xc9,0x48,0xdb,0x3b,0x50,0xd6,0x0c,0xdb,0x55,0x63,0xd0,0x3e, - 0x84,0x3b,0x4e,0xb6,0xba,0xdb,0xb6,0xa5,0x21,0x80,0x0e,0x71,0xcf,0xc8,0x0f,0x27, - 0x82,0x78,0xba,0xad,0x5f,0x68,0x17,0x47,0x57,0x31,0xac,0x73,0xa9,0x11,0x6a,0xc5, - 0x66,0xda,0x2e,0x19,0x81,0x4a,0x25,0x14,0x4a,0x2a,0xb2,0x71,0x69,0xd1,0x5e,0x89, - 0x26,0x00,0xd5,0x2e,0x84,0x8d,0x75,0x3d,0x6e,0x6d,0xd3,0x7c,0x3f,0x80,0x00,0x0c, - 0x0f,0x88,0x5d,0x74,0xb2,0x58,0x4b,0xde,0x61,0xab,0x6f,0x6b,0x47,0xb2,0xa0,0xc5, - 0x51,0x2c,0x84,0x45,0xa8,0x57,0x31,0x18,0x31,0x77,0xd0,0x1f,0xc6,0x9b,0x0d,0x01, - 0xee,0x48,0xc1,0x5e,0x59,0x95,0xb9,0xb8,0xb2,0xb6,0x52,0x8c,0xc8,0x58,0x7c,0x74, - 0x56,0x7e,0x2d,0x45,0x0d,0x24,0x4a,0xd1,0x30,0xd3,0xbd,0x01,0xb7,0x5a,0xb4,0x6b, - 0x35,0x2f,0x86,0xf2,0xad,0x21,0xa1,0x29,0x5f,0x9d,0x88,0x72,0x27,0xeb,0x9a,0x7a, - 0x9c,0x78,0x1c,0x36,0x1a,0x73,0x61,0x53,0xee,0xd1,0x4e,0x39,0x5e,0x3d,0x97,0xd1, - 0xab,0x2b,0x6d,0x37,0x35,0xaa,0xa8,0x4f,0xc2,0x8b,0x92,0xb1,0xaa,0x2d,0x68,0xf8, - 0xb2,0x5a,0x0e,0xda,0x0d,0x93,0x4b,0x72,0xbd,0xa3,0xf2,0xaf,0x49,0xc3,0xcf,0xd8, - 0x83,0x98,0x98,0x9d,0x8e,0x34,0xad,0xdc,0x58,0xbe,0xa1,0x64,0x73,0x72,0x7c,0x5c, - 0xe1,0x93,0x60,0x1c,0x12,0xef,0x8b,0x9d,0xa4,0x96,0x2e,0xb3,0xa2,0x24,0x62,0x08, - 0xe6,0x75,0x32,0x28,0x8d,0xa4,0x16,0xba,0xad,0x2f,0x74,0xd1,0xb5,0x68,0xd7,0x4e, - 0xba,0x36,0x07,0xf5,0x0b,0x45,0x7b,0xd7,0x25,0x17,0x73,0xe8,0xde,0xdd,0x8d,0x17, - 0x9b,0xee,0x2b,0x30,0x7c,0xd3,0xe8,0x1b,0x53,0x71,0xc3,0x21,0x57,0x3c,0x2c,0x31, - 0xcc,0xbe,0x5d,0x1c,0xf3,0x98,0x78,0x2e,0x98,0x46,0x99,0x5a,0x9b,0xa1,0xc6,0x92, - 0x42,0x72,0xa4,0xee,0x34,0xb2,0x07,0xbf,0x56,0xdb,0x8d,0xc4,0x19,0x9c,0xf2,0x80, - 0x9b,0x59,0x4f,0xaf,0x3d,0xeb,0x7a,0x92,0x15,0x69,0x71,0xff,0x16,0x2c,0x6c,0x95, - 0xa9,0x5f,0x94,0x5d,0x93,0x42,0x2d,0x8a,0x98,0xe5,0x04,0xd2,0x99,0x49,0x51,0x82, - 0xa2,0xa1,0x42,0x9b,0x75,0xf3,0xf5,0x2a,0x25,0xc7,0xdb,0x37,0x10,0xdd,0xdb,0x55, - 0x00,0x06,0x5d,0x9d,0x04,0xf1,0x22,0x14,0xa1,0xb2,0xc8,0x94,0x8b,0x91,0xf9,0x22, - 0xd2,0xae,0x4d,0x7a,0x53,0xe5,0x8c,0x08,0x10,0xc5,0xcf,0xd2,0x48,0x52,0x68,0x47, - 0x5c,0x2d,0x35,0x6f,0x65,0xf4,0x8c,0xb9,0x1f,0xc2,0x9c,0x22,0x96,0xcf,0xb9,0xca, - 0x24,0x90,0xbb,0x79,0x46,0x4c,0xc9,0xe3,0x11,0xa7,0xaa,0x74,0x03,0xc8,0xc1,0x03, - 0x31,0xfb,0xf1,0x31,0x13,0xe5,0xed,0x80,0xb5,0xaf,0xd5,0x4c,0xa2,0x5e,0x65,0x3d, - 0xdf,0x57,0x25,0x96,0xd6,0x32,0x63,0x34,0x18,0x72,0x3a,0x68,0xef,0x6b,0x43,0xb9, - 0x38,0x5b,0x29,0x6d,0x9a,0x05,0x69,0xf8,0x9c,0x62,0x88,0x4a,0x76,0x58,0x99,0x8a, - 0x44,0x39,0x89,0xc7,0xdd,0xb4,0xc9,0xa0,0xbc,0x06,0x3b,0xdb,0xf0,0x1a,0x0f,0xf2, - 0x02,0x4c,0xdd,0x0c,0xd5,0xe6,0x99,0xbf,0x0e,0x37,0x9b,0x94,0xe8,0xc4,0xe7,0xc4, - 0xa5,0xa6,0xa6,0xe0,0xa6,0xd5,0x11,0x09,0xc2,0x98,0xfe,0x31,0x2c,0x74,0x8f,0x51, - 0x69,0x25,0x3c,0xc9,0xa5,0x62,0x01,0xe1,0x47,0x6f,0xe1,0x30,0x84,0xd2,0x2e,0xf7, - 0x7a,0xa0,0x42,0xcd,0x5f,0xfb,0xa8,0xa8,0x78,0x35,0xe9,0xee,0x86,0xb4,0x96,0xee, - 0x2c,0x27,0xcb,0x5d,0xb4,0x5e,0xf4,0xfb,0x4d,0x8f,0x3a,0x96,0x38,0x78,0xda,0x2d, - 0x83,0x63,0xf1,0x7c,0x37,0x29,0x56,0xe5,0x9e,0xd3,0x99,0x77,0x08,0xd2,0xb2,0x66, - 0xed,0x74,0x8a,0x7a,0x63,0x32,0xad,0x95,0xad,0x72,0xd8,0xf3,0xa2,0xd7,0x53,0x71, - 0xef,0xf6,0xa0,0x31,0x84,0xec,0x91,0xc3,0xc6,0x59,0xae,0xa2,0x21,0xa4,0xcc,0xe6, - 0x4b,0x96,0x37,0xe9,0x53,0xb3,0x19,0x95,0x2a,0xe7,0x13,0x65,0x6f,0x5c,0xb0,0xac, - 0xb1,0xc8,0xe2,0x94,0x38,0x78,0x95,0xc8,0x54,0x29,0xb1,0x37,0x6f,0x58,0x93,0x8b, - 0x36,0x82,0xcb,0x46,0x39,0x0a,0x76,0x35,0x8a,0xa1,0x21,0x73,0xa4,0x68,0x2f,0x64, - 0x96,0x03,0x50,0xf4,0xdd,0x0b,0x04,0x8d,0xf6,0x9d,0x0c,0x2a,0xe6,0xde,0x3a,0x0a, - 0xdd,0xb9,0xb0,0xa7,0xee,0xf4,0x7c,0x80,0xa0,0xf3,0xce,0xbd,0xe3,0xbf,0x6a,0x43, - 0x6f,0xcb,0x16,0x74,0x14,0x9c,0x8f,0x10,0x5b,0xa5,0x45,0xf9,0x13,0xfc,0x44,0x98, - 0xd1,0xee,0xdc,0x72,0x9f,0x34,0xab,0x14,0x79,0x3e,0xb2,0xab,0xf3,0x96,0x09,0xd5, - 0x03,0xed,0x7b,0x3c,0x63,0x1e,0x98,0x6f,0x36,0x73,0x27,0x22,0x72,0xce,0x85,0xa6, - 0x55,0xe6,0xce,0xd4,0x42,0xb0,0x4d,0x8f,0x6e,0xd5,0xea,0xb1,0x6b,0x02,0xaa,0x8a, - 0x52,0x18,0xd5,0x23,0xd9,0xf5,0xae,0xd3,0xe1,0x8c,0x97,0x85,0x49,0xd2,0xa6,0xa9, - 0xc4,0x9e,0xb3,0xfd,0xef,0x73,0x10,0x30,0x80,0xf6,0xb9,0x98,0xfa,0xd0,0xa4,0x31, - 0xe1,0x0a,0xc6,0xc7,0xc4,0xd2,0x64,0x2e,0xa7,0xe5,0xb5,0x92,0x0e,0xf7,0x5d,0xe1, - 0x50,0xc9,0x15,0x82,0x80,0x1a,0x73,0x55,0x34,0x41,0xfb,0x87,0x50,0xa5,0xbc,0xc7, - 0x4b,0x7a,0x55,0x24,0x58,0x5e,0xb3,0x90,0xc4,0x30,0x6d,0x1d,0x0c,0x67,0x3e,0x67, - 0x82,0xf3,0x16,0x15,0x71,0x3a,0x1d,0xe1,0x00,0xa5,0xdf,0xfd,0x78,0x21,0x2c,0x42, - 0x11,0x63,0x69,0xa9,0x72,0xed,0x61,0x8b,0x68,0x94,0xe6,0x24,0xf1,0x1a,0xe8,0xf1, - 0xe6,0x68,0xa1,0x46,0x91,0x85,0x1e,0x50,0x43,0xaa,0xd0,0x83,0x32,0x39,0xf0,0x1e, - 0x08,0xc5,0x4b,0x31,0xf6,0x17,0x31,0x65,0xfc,0x28,0xd7,0x44,0x84,0x65,0xe8,0x9e, - 0x69,0x56,0x36,0xce,0x34,0xb7,0xac,0x69,0x08,0xbd,0x86,0x0a,0x59,0x9d,0xa6,0x98, - 0x78,0x1c,0x13,0xf2,0x18,0x36,0x55,0x77,0x94,0xc3,0x03,0x26,0x34,0x34,0x0a,0xf1, - 0xfc,0x04,0xe3,0x4a,0x04,0x60,0x5e,0xf7,0xd1,0x46,0xd6,0x31,0x21,0xd0,0xc0,0x22, - 0x98,0xf6,0x68,0x21,0xe7,0xd2,0x9a,0x89,0xdc,0x0d,0x01,0xb0,0xb0,0x5a,0xfd,0x90, - 0x92,0x54,0xad,0x1c,0x91,0x35,0xe4,0x51,0x21,0x5c,0x6a,0xd0,0x5e,0x4f,0x0e,0x8b, - 0x41,0xa5,0xad,0xfc,0xcb,0x71,0x89,0xfd,0x09,0xc6,0xdb,0x7e,0x9d,0x47,0x3c,0x68, - 0xb9,0x5c,0xc0,0xc3,0xa6,0xbc,0x0e,0xac,0xf2,0x4e,0xfe,0x2e,0xab,0xf4,0x02,0x7a, - 0x8c,0x59,0x66,0x15,0xf9,0xb2,0x5a,0x62,0x7f,0x97,0x9b,0x08,0x06,0x3b,0x61,0x6e, - 0xbd,0x3f,0x19,0x87,0x24,0x90,0x60,0x3c,0x99,0x9a,0x8c,0xf2,0xf9,0x8a,0x24,0x93, - 0x8c,0x96,0x1f,0x70,0x92,0xb2,0x10,0xf1,0xd8,0x86,0x85,0x0a,0x74,0xbf,0x62,0xb9, - 0xc8,0xe3,0xee,0x48,0x8a,0xea,0xa2,0xde,0xb3,0x52,0xfb,0xbe,0xc3,0x85,0xaa,0xe5, - 0x90,0xa5,0x1d,0xec,0xb9,0x9b,0xf0,0x68,0x47,0x75,0xaa,0x64,0xc1,0x1d,0xf5,0x48, - 0xc8,0x5f,0x52,0x0a,0x8c,0x94,0x30,0xb1,0x9d,0x74,0x91,0x32,0x91,0x83,0x46,0x73, - 0xda,0x9c,0x26,0xe7,0xec,0x43,0x42,0xc1,0x62,0xf1,0xfe,0x81,0x7b,0x52,0xae,0x2d, - 0x9a,0xf0,0xa6,0xac,0x69,0xdd,0xf4,0x59,0xcc,0x12,0x18,0x75,0x87,0xd2,0x30,0xf5, - 0xae,0x32,0xdf,0xe9,0xfb,0x3b,0xcc,0xd4,0xf2,0xe1,0x4d,0x05,0x82,0x2c,0x7d,0x2e, - 0xe4,0x42,0xb0,0x03,0xf0,0x6f,0x0c,0x0b,0x32,0x84,0xe6,0xed,0x8d,0x8e,0x43,0x33, - 0x22,0x83,0xbd,0xdd,0x6c,0x1a,0x08,0xfa,0x18,0x15,0xeb,0xd6,0x0f,0x5b,0x2e,0x8b, - 0x72,0x83,0x47,0xd2,0xde,0x1c,0x52,0x55,0x0b,0xd8,0x45,0xd5,0x29,0xc1,0x00,0xab, - 0x82,0xa5,0x01,0xa7,0x24,0x4a,0xaf,0xa6,0x0c,0x4d,0xb0,0x54,0x49,0x46,0x09,0x76, - 0xb3,0xe1,0x7b,0x85,0x3a,0xe5,0x7d,0x54,0x81,0x8c,0x37,0x62,0xed,0x08,0x1d,0x0c, - 0xc1,0x7f,0x70,0xd4,0x62,0x4a,0xcb,0x55,0x35,0xb2,0x43,0x64,0x9b,0xa6,0xad,0x96, - 0xb2,0x25,0xd0,0x6c,0xb2,0x18,0x9c,0xe7,0x49,0x2f,0x9c,0x8b,0xa6,0x60,0xc2,0xea, - 0xda,0xa9,0xca,0x0d,0xa8,0x2c,0x98,0x7c,0x32,0x92,0xf6,0xde,0xf7,0x2e,0x1d,0x1f, - 0xd3,0x5d,0x56,0xb5,0xa8,0xf6,0x4c,0x2a,0x19,0xe1,0xc7,0xae,0x79,0xfc,0x19,0xfa, - 0xa4,0x9c,0x52,0xee,0xf3,0x18,0xde,0xf3,0xf1,0x88,0xca,0x15,0xaa,0x24,0x1d,0x57, - 0x69,0x35,0xfb,0x03,0x54,0x6b,0xc3,0xe5,0x6b,0xb8,0x54,0x85,0x5e,0x54,0x88,0xe0, - 0xd3,0xd6,0x5a,0xf7,0xc7,0x9f,0xbf,0xfc,0x76,0xbd,0xb9,0xfe,0xf0,0x7f,0xae,0xdf, - 0xfd,0xfa,0xe1,0xdd,0xe6,0xea,0xc3,0xe7,0x0f,0x17,0xd7,0xd6,0x3f,0xd4,0x6e,0x9b, - 0xef,0x94,0xfe,0xe4,0x67,0xda,0xe3,0xb2,0x14,0x5b,0x71,0x42,0x00,0x1a,0x15,0xcb, - 0xb0,0x5b,0x08,0x34,0xe3,0xad,0xb9,0xd6,0xa3,0xca,0x74,0xcc,0x6c,0x73,0x00,0x7d, - 0x0c,0x1c,0x07,0xdb,0x9d,0x02,0x06,0xb2,0xa8,0xaa,0xae,0x6c,0x30,0xfc,0x5c,0x11, - 0xba,0x5b,0x91,0xb4,0x36,0xef,0xdb,0xca,0xa3,0x55,0x7b,0x40,0x5f,0x54,0xf0,0xe4, - 0x1a,0x6a,0x6f,0x4f,0x84,0x55,0xb1,0x18,0x84,0x2f,0x9a,0xcf,0x17,0x25,0xed,0x06, - 0x72,0xe2,0x84,0x1c,0x49,0xb9,0x65,0x40,0x65,0x64,0x2b,0xe9,0x49,0xe2,0x31,0xc1, - 0x51,0xf5,0x33,0x5c,0x0f,0x10,0xc0,0x0a,0x52,0x12,0xa6,0xde,0x4b,0x8a,0xb1,0xc0, - 0xb9,0xda,0x34,0xe7,0xdd,0xf5,0xbb,0x45,0x84,0x40,0x19,0x3e,0x22,0x1e,0x4e,0xd3, - 0xb9,0xb2,0xd5,0xda,0x86,0xcd,0xf8,0x17,0xc9,0x97,0x72,0xbb,0xf4,0xca,0x0e,0x3c, - 0xc5,0x6b,0x69,0xee,0x34,0x1b,0x4e,0x76,0x64,0xc7,0xc3,0x6a,0x7b,0x52,0xb9,0x1a, - 0x70,0xea,0x47,0x74,0xb3,0x8c,0xfc,0x4f,0xb2,0x74,0x42,0x3e,0xa2,0x8c,0x2f,0xaf, - 0x64,0x9d,0xf8,0xdd,0x6c,0xda,0x29,0xd7,0xcd,0x46,0x4f,0xb5,0xb0,0x87,0xbd,0xd9, - 0x04,0x9d,0x4e,0xe0,0x14,0xb0,0x16,0x97,0x30,0x73,0xe8,0x87,0xa0,0x71,0x91,0x91, - 0x63,0xf5,0xf6,0x79,0x1f,0x10,0x9a,0x8d,0x61,0xbe,0x7e,0xeb,0x0d,0x5e,0xf4,0x37, - 0x1b,0xe9,0xcf,0x67,0xe1,0x1b,0xb8,0x78,0x96,0x9e,0xef,0x96,0x51,0xf0,0x37,0x32, - 0x6c,0x08,0x0c,0x07,0x8f,0xde,0xe1,0x08,0xfd,0x6f,0x15,0x90,0x55,0xa1,0x30,0xb9, - 0x7c,0x54,0xb9,0xdd,0xe9,0xc4,0x30,0xfc,0x87,0xe4,0x2e,0x54,0x51,0x46,0x2c,0xa3, - 0x37,0x10,0x65,0x3f,0xfb,0x31,0x98,0x31,0xc9,0x82,0xb5,0x83,0xc6,0x93,0xde,0x4c, - 0x3d,0xea,0xa3,0x4c,0x81,0x74,0x9c,0x2a,0x47,0x49,0x97,0xec,0xf6,0x2e,0x80,0xbe, - 0x3f,0xa0,0x6b,0xa8,0x0a,0x72,0x95,0xee,0x19,0x79,0x2a,0x95,0x43,0x89,0x87,0xcc, - 0xa3,0x3d,0xc4,0xae,0x65,0xc7,0xb4,0xa3,0x44,0x71,0xac,0xef,0xfd,0xfc,0xee,0x77, - 0x55,0x8e,0x69,0x39,0x05,0x6d,0xcb,0x34,0xd9,0x68,0xfb,0xa1,0x1e,0xf5,0xfe,0xe6, - 0xf4,0xb6,0xf7,0x80,0x9f,0xad,0x45,0xdc,0x04,0xa4,0xba,0x94,0x0d,0xb1,0xec,0x48, - 0x5f,0x20,0x7f,0x67,0x81,0x7c,0x2c,0x50,0xa7,0x43,0xbf,0x50,0xf2,0xa0,0x69,0xc6, - 0x9b,0xea,0x27,0xdd,0xf3,0xc3,0x3f,0x4f,0xac,0x4a,0xd2,0xe5,0x53,0xcb,0x8a,0x65, - 0x92,0xa0,0xba,0x1f,0x1e,0x74,0xb5,0xec,0xa7,0xc8,0x94,0x8f,0x7f,0x08,0x56,0x3d, - 0x54,0xcc,0xae,0x07,0xc1,0x31,0xda,0xab,0xfd,0x48,0x66,0xcb,0x2a,0x82,0xef,0x5a, - 0x2d,0xe7,0x9d,0x40,0xd9,0xc4,0x30,0x2d,0x07,0xff,0xad,0x17,0xd7,0x7b,0x99,0x5c, - 0x64,0xb0,0x5f,0x9b,0x34,0x2b,0xcd,0x6a,0x45,0x53,0x28,0x15,0xb0,0x9d,0x6d,0x86, - 0x26,0xf9,0x10,0xdf,0x20,0xf8,0xbf,0x3d,0x36,0xcf,0x97,0x1e,0xbf,0xde,0x70,0x00, - 0xd7,0x9b,0x58,0x8f,0xb6,0xcc,0xf7,0x63,0xdd,0xda,0x63,0x90,0x3b,0x4c,0x8d,0x66, - 0xba,0xa2,0xbd,0xc5,0xd0,0xf8,0xed,0x47,0xdd,0x2f,0xe7,0xd0,0xb8,0xe4,0x5a,0x3c, - 0x22,0x5f,0xb9,0xc2,0x0c,0xef,0xbc,0x1b,0xb4,0xdc,0xd6,0x24,0x68,0xbb,0x43,0xf0, - 0x87,0xca,0x55,0xfb,0xa4,0x80,0x29,0x4d,0x43,0xf8,0xf8,0x98,0x42,0x18,0x2d,0xa1, - 0x5f,0x43,0x99,0x0d,0x20,0x85,0x4d,0x9b,0x7c,0xc7,0x5d,0x4e,0x82,0x88,0x3c,0x37, - 0xcf,0x4d,0x43,0xc0,0x4e,0x70,0x1f,0x1d,0x64,0x49,0x63,0xe8,0x45,0xd1,0x14,0xe7, - 0x94,0xe5,0x13,0xfb,0x8e,0x8f,0xf0,0xd9,0xda,0xcd,0x08,0x2f,0xc5,0x73,0xf7,0x39, - 0x47,0x64,0x2a,0x17,0xe5,0x3f,0x34,0xde,0x26,0xe6,0x69,0x8b,0x18,0x93,0x9f,0x79, - 0x33,0xd8,0x7c,0x70,0x45,0x6a,0x4a,0x05,0x48,0xad,0x0d,0x75,0xf6,0xd3,0x42,0xc4, - 0xce,0xbf,0xb3,0xf1,0x35,0x27,0x2e,0x77,0xd0,0xa7,0x96,0xbd,0x29,0x95,0x74,0x26, - 0xb3,0x27,0x84,0x1b,0x5f,0xf0,0x98,0xd6,0xce,0x0b,0x4d,0xce,0x64,0x26,0x03,0x3c, - 0x9e,0x0f,0xe5,0x2c,0xd4,0x98,0x4f,0x50,0x82,0x3c,0xff,0x36,0x2a,0x9e,0x57,0xc2, - 0x2b,0x8f,0x77,0x17,0xec,0x1b,0xe8,0x21,0xf6,0xb0,0xcf,0x48,0x04,0x0e,0x64,0xb2, - 0x8b,0x54,0x7d,0x43,0xb1,0x91,0x9d,0xe9,0x71,0x39,0x0c,0x65,0x22,0x43,0xa9,0x51, - 0x25,0x6f,0x23,0xaa,0x4f,0x25,0x1b,0x17,0x7a,0x29,0xdd,0x35,0xe3,0x94,0xe9,0x64, - 0x12,0xcb,0x71,0x08,0xa8,0x69,0xe3,0x5d,0x52,0xab,0xf8,0x33,0xda,0x39,0x0d,0xe3, - 0xe7,0x91,0xaf,0x3a,0x99,0xa4,0xc5,0x4c,0x15,0x81,0x8d,0x14,0xb2,0x7b,0xbb,0x52, - 0xd8,0xdf,0xa5,0xde,0xdf,0xf2,0xa3,0xb5,0x8c,0x5d,0x57,0xee,0x33,0xb5,0xa4,0xa6, - 0x6e,0xdc,0xe7,0x69,0x5f,0xd7,0x07,0x6b,0x6c,0x99,0x22,0x52,0xc7,0x68,0xe8,0xa8, - 0x85,0x63,0x7c,0x8c,0xee,0x21,0x5f,0xf2,0x1c,0x44,0x61,0x1b,0x73,0x12,0x7f,0xca, - 0xeb,0xb4,0xcf,0x60,0x10,0x9c,0x6c,0x4a,0xa6,0xff,0xac,0x9f,0xdd,0x1b,0x23,0xca, - 0xad,0x52,0xaa,0xc9,0x38,0x96,0x0d,0xd0,0x9b,0xea,0x96,0x4e,0x4a,0xd0,0xe9,0x08, - 0xc3,0x33,0x5e,0x0d,0x86,0x08,0x3e,0x8b,0x59,0x99,0x66,0xe8,0x45,0xcf,0xd0,0x78, - 0x36,0x70,0x58,0xee,0x2e,0xae,0xae,0x3c,0xd3,0xa5,0x83,0x2c,0x6b,0x3f,0x8e,0xdd, - 0x28,0x89,0xca,0xc8,0x8f,0xdb,0x87,0x36,0x9a,0x43,0x0a,0x43,0xc4,0xd4,0x11,0x4d, - 0xd6,0x85,0x77,0xe9,0x93,0x23,0xb7,0xff,0x40,0x87,0xf6,0xc6,0x93,0x47,0x3b,0xb4, - 0x3e,0x74,0xf2,0xa1,0xd7,0xf3,0x55,0x27,0x2c,0xbe,0xad,0xce,0xb3,0x58,0x74,0xfa, - 0x47,0x35,0x53,0x7e,0x4c,0x5e,0x8d,0x27,0xf6,0xb3,0x0f,0x97,0x1f,0x7e,0xb8,0x7c, - 0x6f,0x51,0x87,0x85,0xbb,0xef,0x30,0x48,0xaf,0x37,0xfb,0x8b,0x53,0x20,0x3c,0xec, - 0xb7,0xcf,0x97,0x2c,0xf6,0x1c,0x2a,0x81,0x50,0xf1,0xd9,0x1a,0x75,0xcb,0xc7,0x91, - 0xec,0x67,0xaf,0xde,0xbd,0x3a,0xfd,0xe1,0xd4,0x1a,0xd2,0xf1,0x0e,0x77,0x80,0xb5, - 0x38,0x19,0x28,0x18,0xf3,0x34,0x49,0xed,0x45,0xc4,0x7f,0x8b,0x0c,0x7e,0xa0,0x7d, - 0xf5,0xf1,0x27,0x5c,0xf7,0x7e,0x15,0x93,0x45,0xec,0xe7,0xf6,0x4f,0x02,0xd1,0x9e, - 0x5d,0x3f,0x96,0xa7,0x53,0x6e,0xa4,0x33,0x74,0xbb,0xae,0x56,0x22,0xc1,0xaa,0x6b, - 0xa7,0x45,0x7c,0x79,0xc0,0x07,0x0b,0x06,0xbb,0x1b,0x41,0xe5,0x41,0x44,0x7b,0xa1, - 0x08,0x60,0x55,0x78,0x7d,0xa8,0xfb,0xd6,0x77,0xc7,0x69,0xb0,0x28,0x7a,0xcb,0xa8, - 0x88,0xc8,0x6f,0x04,0xcf,0x97,0x78,0xd6,0x6a,0x5c,0x43,0x0b,0x50,0xca,0xca,0x3d, - 0xdd,0x99,0xbb,0x0f,0xdf,0x56,0x3e,0xa2,0x64,0x28,0x6d,0x6a,0xf6,0xd0,0x45,0x9e, - 0x52,0x89,0x92,0xf5,0xdc,0xbf,0x57,0x67,0x86,0x06,0x03,0xe2,0xbd,0x6a,0xa1,0x5f, - 0xd1,0xf5,0xdc,0xcf,0x27,0x51,0xe2,0xf6,0x0d,0x7f,0x51,0xa6,0xc3,0x0c,0x1a,0x89, - 0xf8,0xa3,0x6f,0xd0,0x91,0x97,0x9a,0xb7,0x26,0x79,0x14,0x0e,0xe9,0xa7,0x07,0x03, - 0x98,0x91,0x5b,0xea,0x1e,0x8d,0x8c,0xc0,0x28,0x8f,0x24,0x33,0x1f,0x21,0x50,0x33, - 0x12,0x79,0x73,0x32,0x8f,0x12,0x99,0xab,0x1b,0x8c,0x73,0x8b,0xc1,0x4a,0xd8,0xa0, - 0xc2,0x62,0x9e,0xf4,0x26,0x7e,0xe6,0x0e,0x80,0xde,0xd0,0x87,0x65,0x4e,0x7a,0x11, - 0x20,0x16,0x2e,0x9d,0x8c,0x12,0xb9,0xc4,0x78,0xb4,0xe6,0x91,0xe8,0x08,0x8e,0x3b, - 0xaa,0x51,0x18,0xc7,0x62,0xdf,0x2b,0x43,0x02,0xf7,0x8a,0xe6,0x51,0x1f,0x8c,0xea, - 0x0f,0x69,0x4f,0x91,0xaa,0xe8,0x5c,0xb9,0x32,0x54,0xba,0x54,0x8a,0x1e,0x2f,0x19, - 0xb9,0x54,0xb9,0x9f,0xc9,0x91,0xa6,0xeb,0xbf,0x0b,0x3d,0x16,0x54,0x9a,0xc7,0x20, - 0x88,0x3c,0xce,0xe0,0x4c,0xcc,0xe5,0x42,0x96,0x10,0xec,0x82,0x02,0x4c,0x77,0x41, - 0xd5,0xdb,0x81,0x0f,0xbf,0x8c,0x81,0x87,0x6b,0x02,0xca,0xab,0x3b,0x94,0x88,0xbd, - 0x68,0x48,0x4f,0x97,0x8a,0x9f,0xe9,0x80,0xd2,0xa2,0x70,0x5f,0xf4,0xbf,0x7b,0xcc, - 0xc0,0xbe,0x25,0x85,0x96,0xd5,0x0f,0x16,0xa5,0x6f,0x60,0x55,0xea,0x45,0xdf,0x52, - 0x5d,0xe1,0x5a,0xe7,0x70,0x3e,0x60,0x67,0x3f,0x7b,0xf1,0xee,0xc5,0x8b,0xb3,0x97, - 0xd6,0x23,0xac,0xfb,0xaf,0xc4,0x5c,0x22,0xb7,0x1c,0xad,0xab,0xa5,0x26,0x41,0x7a, - 0x59,0xa3,0xf3,0x48,0xae,0x7c,0x6b,0x07,0x51,0x5a,0x3a,0x7d,0x4c,0xff,0xf1,0x38, - 0x83,0x6f,0x11,0x07,0x63,0x43,0x89,0x11,0xe6,0xfb,0xa6,0xab,0x43,0x9e,0x49,0xf9, - 0x72,0x12,0x8d,0x21,0x92,0xd6,0x42,0x2b,0x6a,0x32,0x53,0xb7,0x96,0xb2,0xe2,0x80, - 0xde,0xbd,0xcb,0xbc,0x57,0x04,0x74,0xde,0x80,0x8e,0xe4,0xc9,0x57,0x79,0x55,0x64, - 0x63,0xaf,0x48,0xfc,0xac,0x47,0xe9,0x00,0xf7,0x9e,0x76,0xa7,0xef,0xa3,0x79,0x54, - 0x3e,0x34,0x72,0xd1,0x63,0x49,0x68,0x04,0x83,0xee,0xb4,0x93,0x61,0x83,0x3d,0xdc, - 0xd1,0x27,0xee,0x90,0x9a,0x32,0x73,0x9f,0xf5,0xfb,0x74,0x3c,0xf1,0xae,0xba,0x98, - 0xbb,0x24,0xa8,0xc0,0x64,0x42,0x04,0x25,0xf7,0xe9,0x75,0x3f,0x14,0x13,0xa5,0xf5, - 0x32,0xcb,0xa6,0x7e,0xc6,0xe9,0x59,0x76,0x2f,0xaf,0x10,0x3c,0x04,0xdd,0x41,0xbf, - 0xff,0x9d,0xd1,0xe3,0x56,0x4b,0xf5,0xbc,0x23,0x8d,0xba,0x12,0xa3,0x59,0x54,0xf6, - 0xe6,0x7e,0x31,0xeb,0x45,0x73,0x78,0xa9,0x95,0xaa,0xb3,0x86,0x7b,0xda,0x14,0x39, - 0x5d,0xb7,0x7a,0xaf,0x26,0x4b,0x4b,0x77,0x6d,0x9d,0x71,0x4c,0x27,0x0a,0x5d,0x5e, - 0x3e,0x84,0x4e,0x40,0x12,0x6d,0xf9,0x9a,0x66,0xa1,0xb7,0x49,0x70,0x86,0xaf,0x71, - 0xfa,0x5f,0x09,0x94,0xa6,0x60,0x68,0xd1,0x1e,0x4b,0x66,0x6b,0x55,0x18,0x40,0xa5, - 0x1c,0x68,0x24,0xc5,0x39,0x6d,0xfe,0xe3,0x27,0x4e,0x9a,0xb4,0x9a,0xa3,0x96,0xe8, - 0x44,0x09,0xb4,0x22,0xc4,0x87,0xf4,0x62,0x23,0x3f,0x6c,0x55,0x58,0xd1,0xb2,0x45, - 0x5d,0x50,0xa7,0x6f,0x1f,0x7b,0xa4,0x05,0xd0,0xe6,0xf0,0xc3,0x3e,0xb9,0xd1,0x28, - 0xb4,0x4f,0x74,0xd4,0x09,0x41,0x79,0x96,0x71,0x1f,0x01,0xfe,0xbf,0xa4,0x89,0x97, - 0x20,0xd0,0x04,0x24,0x18,0x36,0xea,0xfe,0xec,0xe5,0x72,0xf5,0x48,0x19,0x32,0xa8, - 0xba,0x51,0xc4,0x71,0x94,0x15,0x51,0x51,0x61,0xaa,0x93,0x70,0x61,0xed,0xe7,0xec, - 0x1d,0x64,0x24,0xcb,0x04,0xce,0x6a,0xbd,0x07,0xc6,0x8e,0x48,0xd3,0x62,0x95,0x13, - 0x0d,0xdd,0x92,0xee,0xf7,0xac,0x6a,0xa4,0x98,0x35,0x9b,0xac,0x6b,0x47,0xc6,0x1f, - 0x81,0xc0,0xb0,0xe1,0xc0,0x6a,0x5c,0x42,0xfa,0xa9,0x32,0xa8,0x3f,0xdc,0xd1,0x05, - 0x44,0xe3,0x3d,0x8a,0x65,0x0b,0x48,0xc4,0x22,0x7e,0x02,0x91,0x60,0x68,0xd9,0xc4, - 0x38,0x2b,0x8c,0x60,0x31,0x8a,0x82,0xde,0x48,0xfc,0x27,0x12,0x79,0xd7,0x19,0xd8, - 0xce,0x2b,0xdb,0x39,0xb5,0x07,0x96,0xa1,0x12,0x88,0xc5,0xf6,0xbf,0x66,0xe2,0x61, - 0x9c,0x23,0xa6,0x29,0x0c,0x20,0x53,0xa6,0x6b,0x39,0xe0,0xeb,0xd3,0xef,0xd4,0x39, - 0xd0,0x72,0xd5,0xa0,0x38,0x26,0xdf,0xb0,0xc2,0x2f,0x67,0x84,0xfa,0x43,0xe5,0xb1, - 0x30,0xef,0xb4,0xe4,0xe3,0xeb,0xa2,0x28,0x11,0xef,0xf7,0xaa,0x23,0xb8,0x95,0x8c, - 0x48,0xde,0xe8,0x71,0x82,0xbd,0x90,0x72,0xf5,0x9f,0x1e,0xd7,0x35,0xb9,0xa7,0x83, - 0xb3,0x1f,0xce,0x5e,0x3d,0x7f,0x79,0xf6,0x83,0x1a,0x5c,0xb3,0xee,0x95,0xa6,0x58, - 0xae,0xa0,0x2a,0x9e,0x83,0x10,0xd6,0x13,0xcc,0x5c,0x31,0x30,0x2c,0x9b,0xc1,0xa6, - 0x78,0x57,0x9f,0x91,0x27,0xa1,0xe8,0x39,0x70,0xce,0x9e,0x32,0x0d,0x8b,0x7d,0xa6, - 0xe1,0x11,0xed,0xb9,0xf6,0xd9,0xd6,0xfc,0xbb,0x53,0xfb,0xd9,0xe0,0xf9,0x60,0x30, - 0xe8,0x5b,0x6d,0xde,0x88,0x88,0x37,0x1c,0xb1,0x9f,0x8b,0xf4,0x73,0xc0,0x1a,0x83, - 0xff,0xf0,0x9a,0xce,0x40,0xb3,0x1d,0x6c,0x69,0xb0,0x56,0xf7,0xdd,0x23,0xd3,0xe4, - 0x13,0xe9,0x96,0xa3,0x91,0x67,0x7a,0xfe,0xd8,0xcf,0x49,0x1a,0x4f,0xe7,0x84,0xdd, - 0x99,0xbf,0xe3,0xe1,0x80,0xb6,0xd0,0x4b,0xeb,0xca,0x8c,0x34,0x83,0x6c,0xe9,0x50, - 0x70,0x1d,0x58,0xc9,0x54,0x4c,0x95,0x22,0x68,0xd2,0xaa,0x75,0x26,0xf2,0xe4,0xcf, - 0x93,0xe3,0x7f,0x9c,0xd8,0x88,0x9d,0x11,0xb8,0x9e,0x98,0x5a,0x92,0x67,0xc4,0x55, - 0xa4,0xea,0xcd,0x26,0xbf,0xc3,0x79,0x0f,0x3e,0xdc,0xd8,0xe9,0x54,0x07,0x1c,0xf1, - 0xaa,0xfe,0x26,0xa5,0xee,0x11,0x29,0xad,0x65,0x6a,0x88,0xe1,0x54,0x79,0xfd,0xec, - 0xb8,0x3b,0x3a,0x57,0xf9,0x09,0x0a,0xd8,0x5b,0xe7,0x0a,0x55,0x71,0x8a,0xcc,0x21, - 0x50,0xe2,0x47,0xff,0x70,0x43,0xac,0x27,0x91,0x9a,0x24,0x53,0x64,0x7f,0xa5,0x0c, - 0x93,0x2d,0xec,0x5c,0x4f,0x12,0x51,0xde,0x48,0xcf,0x13,0xad,0x85,0x47,0x4d,0x37, - 0x11,0x6f,0x03,0x88,0x4e,0x47,0xd5,0x62,0x8a,0x9b,0xfe,0xad,0x76,0xdc,0x6d,0x4f, - 0xea,0x88,0x7a,0x58,0x9d,0x8e,0xb8,0x19,0xdc,0x5a,0x71,0x55,0xe8,0x27,0x8f,0xac, - 0x1e,0x7f,0x3d,0x3e,0xb6,0xfb,0x36,0x9d,0x77,0x91,0x87,0x81,0x79,0xaa,0x8f,0xab, - 0x7b,0x7c,0x2a,0x56,0x24,0x84,0x76,0xd3,0x1d,0x0d,0xbe,0x71,0x0b,0x59,0xff,0x71, - 0x0a,0xc4,0x47,0xe8,0xea,0xf3,0xa6,0x88,0xc7,0xe4,0x8d,0xab,0x0c,0x96,0xdf,0x82, - 0xca,0xcd,0x03,0x9e,0xa4,0xea,0x81,0xd9,0x61,0x29,0x7c,0x3d,0x77,0x92,0x26,0x26, - 0x5e,0xdb,0x13,0x29,0xc3,0x78,0x90,0x59,0xa1,0x8c,0x02,0xed,0x06,0x5a,0x5b,0x42, - 0x5a,0xcf,0x9f,0xf8,0x54,0x53,0x1b,0x6b,0x68,0x80,0x65,0xe4,0xd7,0x23,0xa4,0x59, - 0xfd,0x0c,0xcd,0x24,0x4b,0x17,0xe4,0xfd,0x8f,0x49,0x99,0xfe,0x1e,0x89,0x55,0x55, - 0x7c,0x26,0xcf,0x1b,0xc8,0x67,0xea,0xdc,0xcc,0x84,0x76,0x79,0x53,0xe7,0xc0,0xa7, - 0x54,0xb2,0x73,0xb7,0x10,0xf9,0xc3,0x15,0x1f,0x94,0xa7,0xad,0x72,0x87,0xf6,0x6e, - 0x38,0x73,0xe1,0xd3,0x12,0x52,0x8f,0x89,0x28,0xdf,0x93,0xf8,0x83,0xba,0x17,0x54, - 0x8a,0x50,0xfe,0x4a,0x05,0xe8,0x60,0x30,0xcf,0x7f,0xf2,0x19,0xbd,0xd7,0x20,0x78, - 0xec,0xe5,0x0e,0xa9,0xd0,0xe3,0xdc,0x61,0xb9,0x3d,0x39,0xed,0x09,0x6e,0xc0,0x1f, - 0xd5,0x00,0xb6,0x44,0x78,0x5e,0x74,0xdb,0xb5,0x24,0xaa,0x6d,0xbd,0xc3,0x9e,0xea, - 0xec,0x50,0x6b,0x0c,0x1e,0xf2,0x71,0xca,0x62,0x1c,0x9b,0x76,0xf1,0x76,0x60,0x3d, - 0xf5,0x38,0xc7,0xe3,0x37,0x0d,0xa4,0x3f,0x08,0x9b,0x9e,0xec,0x4b,0xd3,0x91,0xf7, - 0x03,0x5d,0x6a,0x54,0x1d,0x97,0x94,0x99,0x22,0xdf,0x6c,0x0e,0xaf,0x5a,0x62,0x43, - 0x59,0xfa,0xa5,0x57,0x38,0x4b,0x5a,0xe0,0xa4,0xa4,0xad,0x7f,0x75,0x49,0xd9,0x74, - 0x3e,0x86,0x8e,0x8e,0x22,0x6f,0x71,0x51,0x7d,0xa2,0xe8,0xbc,0xbb,0x3c,0xe7,0x4e, - 0xc6,0xd2,0x74,0xe9,0xc8,0xf5,0x71,0xfd,0xc8,0xe5,0x7c,0xdd,0x48,0xa5,0xea,0xbd, - 0xc3,0xa5,0xac,0x16,0x86,0xd4,0x8f,0x76,0x61,0xc9,0xf1,0x8e,0xbb,0xf5,0xa5,0xda, - 0x6a,0x3c,0x37,0x0d,0xf3,0x78,0xb7,0x91,0xd3,0x78,0x04,0x97,0x78,0xcc,0x9c,0x96, - 0x65,0x56,0xb8,0x27,0xd5,0x99,0x74,0xf2,0x29,0x1c,0x2a,0x74,0x39,0x81,0xea,0xa5, - 0xf9,0x17,0xcf,0xcc,0x63,0x91,0x04,0x69,0x28,0x7e,0xfb,0xf5,0xc7,0x8b,0x14,0x41, - 0x71,0x42,0xe2,0x52,0x03,0xb5,0xb6,0xfa,0x02,0xca,0x3d,0x16,0x49,0xab,0x60,0xba, - 0x43,0xa7,0x6a,0x97,0xc1,0x06,0xce,0x72,0xd7,0xac,0x2e,0x32,0x39,0xd7,0x6e,0xfe, - 0x5c,0xd0,0x01,0x4c,0xd3,0xe5,0x3a,0x98,0xf3,0x27,0x8f,0x56,0xb9,0xad,0x82,0xa9, - 0xf3,0xea,0xca,0xa0,0xd7,0x07,0x67,0x5c,0xd7,0xfa,0x40,0xa0,0x5d,0xde,0x16,0x3b, - 0xaf,0xce,0xe0,0x1b,0xf2,0x84,0x7c,0x58,0xf5,0x2b,0xfd,0x8c,0x8a,0x5d,0xd5,0x0e, - 0x9e,0x04,0xaa,0x95,0x53,0x41,0x05,0x97,0xe7,0x5a,0x43,0x85,0x1c,0xad,0x4d,0x30, - 0xdd,0x49,0x26,0xa2,0xa1,0x5a,0x2c,0xbe,0x69,0x34,0x02,0xb1,0xc5,0x61,0x1b,0x32, - 0xa0,0x1a,0x2b,0x00,0x0a,0xda,0x7b,0x93,0xe5,0x24,0x56,0x27,0x34,0x62,0xef,0x13, - 0xc9,0xdb,0xfe,0x4f,0xcf,0x68,0x5f,0xad,0x19,0x96,0x93,0xb6,0x86,0x3a,0x37,0x2f, - 0xfd,0x7c,0x06,0xd0,0x9f,0x9b,0xe7,0x51,0x19,0x43,0x2f,0x5d,0xa9,0xcd,0xaa,0x14, - 0x6c,0xd1,0x45,0xbf,0x50,0xf6,0x53,0x5f,0xb1,0x39,0x36,0x0d,0x09,0x5c,0x43,0x87, - 0x3f,0x39,0xa2,0x56,0x94,0x99,0xff,0xd2,0xa1,0xb3,0xa2,0xad,0x22,0xf5,0xcb,0x5d, - 0xa5,0x42,0x9b,0x5a,0x37,0xa0,0xe8,0xff,0xf5,0x8e,0x22,0xcc,0xf8,0xe8,0xd6,0xb4, - 0xd4,0x69,0xf6,0xe0,0xb1,0xde,0xa5,0xce,0x60,0xc8,0x28,0x80,0xc5,0x8c,0x3d,0x93, - 0x5e,0x30,0xe9,0x4e,0xb2,0x27,0x4d,0xd9,0xe5,0x20,0xe8,0xa4,0x58,0x4e,0x8e,0xef, - 0xe7,0xb1,0xfd,0xdd,0xf3,0x0b,0x5c,0x1a,0xb8,0x4c,0x0a,0xef,0x88,0xf8,0x17,0xec, - 0xbb,0x5a,0x81,0x6d,0x9f,0x3b,0x69,0x3e,0x39,0x39,0x45,0xd0,0x45,0x9d,0x8f,0x8c, - 0x25,0x14,0xe3,0xfb,0xf4,0xde,0x3b,0xa2,0xc0,0x7b,0xf0,0x12,0xff,0x8e,0xbe,0x7b, - 0xfe,0x01,0xef,0x07,0x51,0x1e,0x80,0x15,0x02,0x3c,0x7a,0x75,0x64,0x04,0x0f,0xfc, - 0x27,0xf7,0x8e,0x5e,0x1c,0x19,0xe3,0x28,0x8e,0xbd,0xa3,0xef,0x4e,0x9f,0xcb,0xac, - 0xd8,0xd1,0x89,0x7c,0x83,0x00,0xe2,0xca,0x1c,0x3e,0xf5,0x35,0x90,0x28,0xb0,0xe4, - 0x61,0x05,0xca,0xef,0x3d,0x9e,0x65,0x9d,0x8d,0x33,0xa9,0x4c,0x01,0x1a,0x29,0x0a, - 0x69,0x3b,0xf6,0x42,0xb6,0x0d,0x0f,0x8a,0xdc,0xe3,0x66,0xb0,0xb9,0x1f,0x4c,0xaf, - 0x38,0xe8,0xe9,0xae,0xe9,0x88,0x9e,0x6b,0xa6,0x18,0xc5,0xa4,0x3c,0x67,0x91,0xc3, - 0xf3,0x49,0x44,0xfe,0xe9,0xfa,0xa7,0xcf,0x9e,0xf9,0x86,0xbf,0x2d,0xf4,0xd6,0x3c, - 0xbe,0xb8,0xba,0x3a,0x36,0xdf,0x9c,0xc8,0xdb,0x37,0x61,0xb4,0x34,0x98,0xf1,0x40, - 0xfc,0xe4,0xa8,0x75,0x3f,0xc2,0xad,0x5f,0xdd,0x4c,0x8f,0xd8,0x8d,0xf0,0x8e,0x4e, - 0xd0,0x1a,0x55,0xad,0x21,0x6e,0x4e,0xa2,0xb7,0xba,0xb8,0xbd,0x41,0xf0,0x90,0x54, - 0xcf,0xa1,0x9b,0xa8,0x07,0x35,0xe1,0x8f,0xaf,0xc1,0x5b,0x8e,0x8e,0x20,0x4c,0x39, - 0x95,0x70,0x1e,0xfd,0x7b,0x14,0xfb,0xc9,0xec,0x88,0xa4,0xca,0x3b,0x4a,0x52,0x9a, - 0x00,0xde,0x33,0xa4,0x70,0xc8,0xf7,0x4e,0x80,0xd7,0x5b,0x72,0xf2,0x48,0x1b,0x57, - 0x30,0x92,0x23,0x83,0xcd,0x64,0xec,0x8f,0xe8,0x4d,0x25,0xb2,0x34,0x20,0x3a,0xbd, - 0x7d,0x23,0x43,0xbd,0xaa,0x73,0x70,0xc4,0xe7,0x3d,0x30,0x2d,0x6e,0xd6,0xc0,0xcb, - 0x86,0xdd,0xfe,0xe5,0x64,0xe7,0x05,0xad,0x27,0x63,0xa3,0x93,0x2a,0x9b,0x1c,0xed, - 0x69,0x2d,0x57,0x15,0x82,0xd1,0x12,0x70,0x32,0xf8,0xd2,0xa5,0xa8,0x3a,0xea,0x5e, - 0xe1,0x5d,0x37,0xa8,0x3d,0x3b,0xac,0xda,0xae,0xd1,0x35,0x8f,0x03,0xb6,0xf3,0xde, - 0x5d,0xd7,0x9c,0x92,0x36,0x16,0x39,0x5d,0xe2,0x0f,0xab,0x66,0xbe,0x1e,0x99,0x6c, - 0xc4,0xe8,0x3a,0xe1,0x92,0x3f,0xba,0x0a,0x70,0x55,0x4e,0xe8,0xaa,0xa4,0xca,0xbc, - 0x8c,0x2f,0x33,0xba,0x2c,0x57,0xdc,0xba,0x22,0x6b,0x2e,0x65,0xd4,0xa1,0x98,0x39, - 0x2f,0xdf,0x73,0x95,0x4b,0x97,0xb8,0xcb,0x56,0x0f,0xb8,0x2e,0x9b,0xd9,0xd6,0xda, - 0xff,0x21,0x0f,0xf5,0xa1,0x21,0x53,0x79,0x55,0x7b,0xca,0x99,0xd8,0x7a,0x9a,0x36, - 0x1b,0x6c,0x7b,0x9d,0x01,0x00,0x28,0xe2,0x52,0x4e,0x9f,0x18,0x75,0x5f,0x95,0x0f, - 0x14,0x3c,0xe2,0x13,0xf5,0x0a,0xed,0x12,0x51,0x38,0x07,0xab,0x1b,0xcc,0xbc,0x9d, - 0xa3,0x69,0xdf,0x56,0x7c,0x87,0x8d,0xe2,0xfb,0xd6,0xa7,0xb9,0xa0,0xdd,0x64,0x2f, - 0x57,0x6a,0x39,0xeb,0xdb,0xf5,0xde,0x4f,0xbd,0xa5,0x6d,0x0e,0xb2,0x66,0xde,0xb2, - 0xda,0xdf,0x83,0x78,0x5d,0xa0,0xb1,0x53,0x83,0x20,0x1b,0xd5,0xae,0xc8,0x13,0x85, - 0xb0,0x3b,0x07,0x0f,0x88,0x36,0x74,0xfe,0xac,0xf6,0xd7,0x87,0x55,0x2d,0x79,0x55, - 0xc2,0xb0,0x7f,0x53,0x29,0xe0,0x83,0x7b,0xb2,0x26,0xc4,0x7e,0xd5,0x57,0x75,0xfe, - 0xe5,0x5d,0xbd,0x41,0x76,0x07,0x6f,0xd5,0xc6,0x2f,0x1c,0xed,0x61,0xa9,0xce,0x42, - 0x54,0xdb,0x25,0xec,0x8f,0xca,0xe3,0xd5,0xf2,0x8b,0x6b,0xaa,0x86,0xa1,0x30,0x26, - 0x69,0xf5,0x29,0x36,0x75,0xda,0xa4,0xbb,0x60,0x93,0x39,0x70,0x4e,0x8d,0xc2,0x72, - 0xd4,0x09,0xad,0xaa,0x78,0xb2,0xd9,0xee,0x5d,0x49,0xaa,0x5c,0x6d,0x36,0xc5,0x5d, - 0xbb,0x12,0xb8,0xd9,0xd4,0xad,0x36,0xe7,0xcb,0xfe,0x9b,0x01,0xf4,0xb6,0x7e,0xbc, - 0x63,0x65,0xbf,0xe8,0x2b,0xb2,0xb5,0xc9,0xa3,0x6d,0x95,0xfe,0xdc,0x94,0x03,0x69, - 0x25,0xa8,0x49,0x30,0x85,0x94,0x89,0xea,0x9b,0x00,0x9e,0x70,0x02,0xf2,0x5b,0x0a, - 0x11,0x42,0xad,0x4d,0xcf,0xdb,0xb7,0x5d,0xcb,0xbd,0xb9,0x45,0x90,0x53,0xa2,0x9b, - 0x54,0x5f,0x7a,0xd4,0x90,0xed,0x6c,0x85,0x67,0x5c,0x05,0x2e,0x6b,0x5a,0x68,0x05, - 0xdf,0xc1,0x41,0xe0,0x36,0xae,0xba,0xaa,0x42,0x30,0x0a,0x82,0xea,0xad,0x7d,0x44, - 0x42,0x90,0x30,0x0c,0x57,0x94,0xe7,0xf5,0x15,0xc2,0x81,0x1b,0x7a,0x05,0x96,0xd1, - 0x95,0x47,0x3a,0xe5,0x71,0x13,0xfa,0x02,0x02,0x19,0xc4,0xc2,0x08,0xfc,0x3c,0x7f, - 0x90,0x1f,0x57,0xa8,0x8e,0xbe,0x43,0xa6,0xe8,0x9b,0x54,0x46,0xf7,0x5c,0x1e,0x71, - 0xf7,0x2c,0xae,0x4e,0xe1,0x6f,0x63,0xd0,0x8b,0x54,0x4e,0x4f,0xa1,0x81,0x3c,0xd6, - 0xc3,0xdb,0x69,0x86,0xee,0xd6,0x31,0xf3,0x4b,0x67,0xc7,0xa7,0xf3,0x3f,0xa5,0x03, - 0x4d,0xf1,0x58,0x50,0x99,0xb5,0xdb,0x85,0x8a,0xaa,0xa2,0xa8,0xa6,0xac,0x1d,0x65, - 0xd2,0xf4,0x53,0x65,0xc8,0xc9,0xff,0x4a,0x1f,0xf2,0x4f,0x44,0xba,0xdd,0x1b,0xbf, - 0xf7,0x9f,0x7e,0xef,0x75,0xef,0xf6,0xf8,0x4f,0xc7,0xfa,0x5e,0x1b,0xfd,0x4f,0xf6, - 0x2a,0xbb,0x37,0x7f,0x9e,0x9c,0x3f,0xbb,0xdd,0xfc,0xa3,0xae,0x1b,0x90,0x94,0x6b, - 0xfc,0x89,0xcc,0x43,0x80,0x18,0xe2,0xed,0xd6,0x4f,0x55,0x50,0xf4,0xd9,0x21,0x3d, - 0x46,0xf1,0xb5,0x75,0xde,0x5c,0xbb,0x1c,0x3c,0x57,0x38,0x45,0x59,0x0d,0xad,0x2a, - 0x64,0x6b,0xea,0xe3,0xd4,0x78,0x5c,0x5c,0xbd,0x53,0x23,0x37,0xf5,0x0b,0xa8,0x10, - 0xa6,0x2c,0xf9,0x2b,0xfb,0x2a,0xe8,0xd4,0x53,0x4c,0xbf,0x8e,0x15,0x55,0x1d,0x9d, - 0x5e,0x95,0xb4,0xb5,0xd5,0xde,0x66,0xcd,0x92,0x51,0xf1,0x85,0x2a,0x63,0x33,0x45, - 0xc9,0x68,0xd8,0x70,0x18,0xc5,0xdc,0x6d,0x1e,0x43,0x8b,0x16,0x58,0x2a,0x36,0x1a, - 0x7c,0x2b,0xf6,0xc6,0x4b,0x2a,0xf6,0xee,0x74,0xd4,0xc5,0xe3,0xd7,0xd5,0x55,0xbf, - 0x7d,0x94,0x55,0xf0,0x87,0x30,0xc8,0xc1,0xa3,0x8f,0x76,0x0d,0xeb,0x0f,0x81,0x0d, - 0xf9,0xfb,0x63,0xed,0x0a,0xcb,0x6c,0x72,0x6d,0xb5,0x5b,0x92,0xe5,0xb5,0xfa,0xbe, - 0xc4,0xc4,0xca,0x26,0x7a,0x04,0x0c,0x9b,0x34,0x3c,0x68,0x14,0x98,0x3a,0xe9,0x51, - 0x9d,0xb9,0x53,0xc5,0x95,0x8a,0xeb,0xdf,0xe9,0x1f,0x22,0x1a,0xe7,0x42,0xc8,0x32, - 0x66,0x45,0x6c,0x3e,0x6f,0xaf,0x1f,0xb6,0xa7,0x23,0x6d,0xf4,0x9c,0xce,0xf5,0xc9, - 0xf0,0xd6,0x2f,0x55,0x71,0xe4,0xdf,0x65,0x67,0x2e,0xbc,0x0d,0x65,0xe5,0xeb,0x17, - 0x59,0x07,0x2b,0xe0,0xd2,0x09,0x47,0xfa,0x03,0x30,0x31,0x7d,0xba,0x9b,0x8b,0xd2, - 0xff,0xa7,0x78,0xa0,0xcb,0xa0,0xcc,0x63,0x75,0xc9,0x27,0xe4,0xd5,0xb5,0x1f,0xd3, - 0x55,0x2b,0xce,0xd1,0xc5,0x64,0x42,0x5f,0x17,0xaa,0x25,0xc5,0x27,0x16,0xd3,0xcd, - 0x15,0x94,0xad,0xac,0x1b,0xac,0x01,0x4c,0x64,0x8c,0xad,0x75,0x92,0x3a,0xc9,0xb4, - 0x54,0x51,0xeb,0x84,0xcc,0xdf,0xbf,0xa9,0x20,0xd4,0x6c,0x71,0xf9,0x2e,0x87,0x57, - 0x1f,0x00,0xda,0x2d,0x3c,0xe2,0x42,0x99,0x85,0xfa,0x94,0xc9,0x61,0xf3,0x55,0x93, - 0x1a,0x18,0xaf,0x87,0x66,0x0c,0xa4,0x36,0x82,0xd2,0xa8,0x4e,0x3d,0xc8,0x22,0x39, - 0xfa,0x9a,0x14,0x2d,0x82,0x8a,0x55,0x29,0xc3,0x50,0x29,0xa3,0x07,0x74,0x9d,0xf3, - 0x17,0x12,0xe8,0xa3,0x2d,0xe9,0x58,0x7e,0xf5,0x85,0xbe,0xbc,0x02,0x60,0x33,0x79, - 0x6a,0x9e,0xeb,0xcf,0xc3,0x54,0x7e,0xa4,0x63,0x9f,0x1c,0x2e,0xe9,0x6b,0x47,0x9c, - 0xed,0xe9,0x74,0x94,0xf4,0x2c,0xea,0xdc,0xda,0x13,0xd2,0x49,0xf5,0xad,0xf4,0xc6, - 0xae,0x6c,0xca,0x29,0xd7,0xf5,0x8e,0xd5,0xab,0xfc,0x4d,0x97,0xba,0xb5,0xfe,0xf8, - 0x99,0x16,0xd9,0xa8,0xf2,0x61,0x4e,0x47,0x60,0xfa,0x54,0x9a,0xdb,0x35,0xdf,0xd5, - 0x05,0xf7,0xf4,0xe5,0x9d,0x45,0x92,0x50,0xe9,0x80,0x0a,0x26,0x59,0x7c,0x60,0x80, - 0x1e,0x56,0xfe,0xc3,0x39,0x29,0x91,0x3d,0x65,0xd6,0x6a,0x1d,0x2a,0x49,0x1b,0x6c, - 0x49,0xf2,0x06,0x2c,0x6f,0xfd,0x4a,0xc8,0x9b,0x13,0x49,0xea,0x73,0x57,0x87,0xda, - 0xa1,0xa4,0xba,0xe6,0xa8,0xd3,0xe1,0x46,0xfa,0x9a,0xd4,0x42,0xa9,0xd1,0x35,0xb7, - 0xf0,0x21,0x7d,0x3a,0xc1,0x36,0xe4,0xdb,0xe6,0xa4,0x3e,0x57,0x49,0xf9,0x4b,0xab, - 0x51,0x25,0x9c,0xfa,0x20,0x4f,0x30,0x17,0x89,0xae,0x52,0xf4,0x76,0x86,0x51,0x8b, - 0xf6,0xee,0x93,0x8a,0x82,0x8c,0x45,0x75,0x73,0x4e,0x29,0x30,0x19,0x24,0xff,0x1d, - 0x0d,0x82,0xf6,0xa7,0x0b,0x65,0xf6,0xe8,0x16,0x88,0xbb,0xb9,0xb5,0x07,0xe4,0x20, - 0xc8,0x53,0x9a,0x08,0xda,0x0c,0xb5,0xc9,0x6e,0x3c,0x37,0x48,0x65,0xc8,0x0f,0x3d, - 0x34,0xf5,0xc2,0xc6,0xca,0x27,0xa3,0x0a,0x35,0x41,0xdf,0x6f,0x72,0x40,0xf4,0xbd, - 0x43,0x1a,0xc1,0x74,0x26,0x87,0xad,0x6a,0x24,0xad,0x9d,0x9e,0xe8,0xc0,0xc7,0x40, - 0xa4,0x6b,0x52,0x2b,0xd0,0xad,0x6c,0x3c,0x78,0xca,0xfd,0x25,0xb1,0x01,0x40,0xfd, - 0x04,0x00,0x14,0x91,0xb6,0xea,0xd5,0xd7,0xde,0xf4,0x95,0xff,0xab,0xe5,0x7c,0xa2, - 0xa8,0xb2,0x7d,0x7e,0x9f,0xeb,0x2b,0x4b,0x4b,0x1e,0x5c,0x2e,0xab,0x13,0xcc,0x2b, - 0xf5,0xe9,0x95,0xfa,0x48,0x44,0xff,0x2f,0x90,0x2f,0xa6,0xe9,0xea,0xb1,0x1a,0x3d, - 0x04,0x87,0x93,0x0a,0x28,0xa8,0x72,0xba,0x12,0x9d,0x2b,0xf5,0x99,0x0a,0x1d,0xfc, - 0x80,0xeb,0x74,0x14,0xb1,0xea,0x53,0x8e,0xaa,0xc5,0x54,0x63,0xef,0xd3,0xdf,0xbc, - 0xac,0x11,0x02,0xad,0x87,0x60,0x4a,0x1f,0xfe,0x6c,0x11,0x50,0xa6,0x1f,0xe4,0x42, - 0xf1,0x67,0x4d,0xac,0xca,0xc4,0x10,0xb8,0x1b,0x53,0xed,0xc4,0x90,0xa6,0x35,0x6d, - 0x73,0x26,0x1e,0xd4,0x15,0x7f,0x79,0xd4,0xbc,0x7d,0xfc,0x91,0x8b,0x92,0xbe,0xdb, - 0xf7,0x08,0x89,0x52,0x1f,0xb3,0xfa,0xd8,0xe5,0xa0,0x2e,0x07,0xd7,0x47,0xb1,0x32, - 0x75,0xce,0x4a,0x79,0x01,0xea,0x43,0x3f,0x97,0x0e,0x9f,0xeb,0xbd,0xaa,0x5c,0x7f, - 0x52,0x20,0x7c,0xba,0x6a,0xdf,0x94,0x2f,0x7f,0xf9,0x49,0x25,0x73,0x3e,0xa3,0x1b, - 0xe2,0x30,0x9b,0x03,0x32,0xc5,0x72,0x2a,0x25,0x53,0x15,0x0d,0xfe,0x3f,0x22,0x33, - 0x2b,0xd0,0x96,0x59,0x00,0x00, + 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0x8d,0x7c,0x7d,0x77,0xdb,0x36, + 0xb2,0xf7,0xff,0xfe,0x14,0xb4,0xb3,0x15,0xc9,0x9a,0xa2,0x25,0xdb,0x49,0x53,0x32, + 0x8c,0x6f,0x62,0x27,0x37,0x7d,0x36,0x6d,0xb3,0xb5,0xbb,0xbd,0xe7,0xb8,0xbe,0x3d, + 0x14,0x09,0x49,0x8c,0x28,0x92,0x26,0x29,0xc9,0x5e,0x49,0xcf,0x67,0xbf,0xbf,0x19, + 0x80,0x6f,0xb2,0xdc,0x76,0xb7,0x91,0x49,0x10,0x18,0x00,0x83,0x79,0xc7,0x00,0xc6, + 0x78,0x91,0x04,0x65,0x94,0x26,0x86,0xb9,0x3e,0x88,0xc6,0xc6,0x2a,0x4a,0xc2,0x74, + 0x65,0x7f,0xf9,0x68,0xe6,0xa2,0x5c,0xe4,0x89,0x7b,0xb0,0xf4,0x73,0xed,0x37,0x4f, + 0x96,0x5b,0x57,0x5e,0x98,0x06,0x8b,0xb9,0x48,0x4a,0xeb,0x93,0x77,0x65,0x57,0x2f, + 0x1f,0x62,0xc1,0x65,0x9f,0xbd,0x38,0x0d,0x7c,0x02,0x67,0x85,0x7e,0x3e,0xf3,0xc6, + 0x7e,0x5c,0x08,0x2b,0x48,0xbc,0x64,0x11,0xc7,0xd6,0x74,0xee,0xad,0xb7,0xd6,0xcc, + 0x3a,0x28,0x4a,0xb4,0x0d,0x72,0xe1,0x97,0x42,0xb5,0x34,0xf4,0xa2,0x7c,0x8c,0x85, + 0x6e,0x5a,0x81,0x7b,0x70,0x72,0xa2,0xdd,0x4c,0x51,0xac,0x8d,0xc4,0x38,0xcd,0x85, + 0x36,0x8e,0xf2,0xa2,0xd4,0x32,0x3f,0x4a,0x4a,0x47,0x2b,0xa7,0x51,0xa1,0x15,0x41, + 0x1e,0x65,0xa5,0x86,0xa7,0xcc,0xcf,0x0b,0x91,0xf7,0x47,0xe8,0x77,0x16,0x25,0x13, + 0x2d,0x4a,0xb4,0x37,0x53,0xe1,0x87,0x6f,0xed,0x83,0x32,0x7f,0x5c,0xf3,0x28,0x68, + 0x4c,0xf1,0x75,0x99,0xe6,0xfe,0x44,0xd8,0x13,0x51,0xfe,0x50,0x8a,0xb9,0xa1,0x67, + 0xe3,0x7e,0x49,0xbd,0xe8,0xa6,0xe7,0x79,0x3a,0x55,0xd4,0x5d,0x8c,0xf4,0xff,0x5d, + 0xff,0xfc,0x93,0xcd,0x50,0x8d,0x67,0xdb,0x25,0xfe,0x52,0x37,0x4d,0x17,0xf3,0x09, + 0x92,0x5e,0x2f,0x48,0xec,0xe9,0x66,0xb3,0xde,0x6e,0x31,0xf3,0x60,0x6a,0x08,0x73, + 0xbd,0x3d,0xf8,0x64,0x17,0xa2,0x7c,0x57,0x96,0x79,0x34,0x5a,0x94,0xc2,0x00,0xf8, + 0xd2,0x57,0xdd,0x31,0x66,0x2e,0x64,0x87,0x8e,0x1e,0x47,0x93,0x69,0xa9,0x9b,0x3c, + 0xe9,0xcf,0xf4,0x8c,0x19,0xc5,0xa2,0x2c,0x85,0xe6,0x61,0xaa,0x42,0x0b,0x08,0x01, + 0x19,0x06,0x50,0xe8,0x9a,0x93,0xa7,0x69,0xa9,0x2d,0xfd,0x78,0x21,0x0a,0x57,0x4b, + 0x17,0x65,0xee,0x27,0xb3,0x42,0xf3,0x93,0x47,0xae,0xa1,0x17,0x5a,0xba,0x4a,0xec, + 0x83,0xc0,0xd3,0xa7,0xe5,0x3c,0xbe,0x6d,0xfa,0xbc,0x5b,0xf7,0xfb,0x85,0x9f,0x14, + 0x4e,0xf1,0x58,0x60,0x0e,0xfd,0x45,0x64,0xf5,0xfd,0x2c,0x8b,0x45,0x5f,0x16,0x58, + 0x47,0xd7,0x62,0x92,0x0a,0xed,0xd7,0x1f,0x8e,0xac,0x5f,0xd2,0x51,0x5a,0xa6,0x16, + 0x55,0xef,0x03,0xb3,0xd1,0xd8,0xed,0xf7,0xe7,0x69,0x92,0x3a,0x8b,0x88,0xff,0x16, + 0x99,0x1f,0x08,0xeb,0xe8,0xd2,0x2f,0x02,0x3f,0x8c,0x7c,0xed,0x47,0x94,0x1d,0x01, + 0xc0,0x47,0xf5,0xf4,0xa3,0x48,0xe2,0xd4,0xba,0x4c,0x93,0x22,0x8d,0xfd,0xc2,0x3a, + 0x92,0xf0,0xd4,0xc7,0x1a,0xc0,0x56,0x3f,0x38,0xe6,0x51,0xf2,0x9c,0x5a,0x43,0xf5, + 0x18,0x21,0x77,0xeb,0x20,0x8d,0xd3,0xbc,0x5f,0x04,0x54,0xe6,0x70,0x19,0xc6,0x41, + 0x24,0x33,0x77,0x5e,0x7c,0x3c,0xff,0xf0,0xf1,0xc3,0x2b,0xbc,0x67,0x7e,0x22,0x62, + 0xbc,0x7f,0xfc,0x78,0xf9,0xf1,0x1d,0xde,0xa3,0x64,0xe6,0xbc,0x18,0xbe,0x1b,0xbe, + 0x1e,0x9e,0xd3,0xa8,0x81,0xf9,0xd0,0x79,0xf1,0xea,0xf4,0xe5,0xe5,0xcb,0x21,0xde, + 0xc7,0x4c,0x40,0x2f,0xbe,0xbb,0xfa,0xee,0xd5,0xab,0xd7,0x78,0xcf,0x17,0xb1,0x70, + 0x5e,0x5c,0x5d,0x5d,0xbd,0xbc,0x7c,0xa5,0x5e,0xfb,0x45,0x3a,0x46,0x95,0x0f,0xaf, + 0x3f,0x0c,0xaf,0x08,0xc4,0x64,0x9a,0x16,0xf4,0x7e,0x76,0x75,0x79,0xf9,0x01,0xef, + 0x31,0x01,0xfc,0xf8,0xf1,0xe5,0xe5,0x29,0xbd,0x8d,0x7c,0xbc,0xbd,0x7f,0x7d,0x76, + 0x39,0xbc,0xc4,0x5b,0x8a,0xbe,0x4f,0xdf,0x7f,0xf7,0xee,0xfc,0x3d,0x5e,0x56,0x7e, + 0x9e,0x38,0x2f,0x5e,0xbf,0x7c,0x35,0x18,0x7c,0xa8,0x06,0x7e,0x5a,0x8d,0xb4,0x9e, + 0x7c,0x7b,0xde,0x44,0x0f,0x3b,0xd3,0xa6,0xa2,0x2d,0x23,0x08,0xeb,0x07,0xb2,0x0b, + 0xa6,0x79,0x3a,0x17,0xfd,0xa9,0xf3,0xfa,0x65,0xf6,0xb0,0xfd,0xaf,0xb9,0x00,0xfe, + 0x8d,0xb9,0xff,0xd0,0x5f,0x45,0x61,0x39,0x75,0xce,0x5e,0x7d,0x9f,0x3d,0x98,0xeb, + 0x7d,0x0d,0x86,0xa7,0xd4,0xa2,0x6e,0x12,0x25,0xaa,0xc9,0x70,0x70,0x7a,0xfe,0x5c, + 0x9b,0xf3,0xef,0xa9,0x49,0xbd,0x4e,0x49,0x5a,0x1a,0x36,0xbe,0xcf,0xd3,0x45,0x02, + 0xbc,0x9a,0xda,0x28,0x0d,0x1f,0x1d,0x47,0xb2,0x28,0xc6,0x8d,0x42,0x60,0xf7,0xe8, + 0xc8,0x0d,0xa3,0x22,0x8b,0xfd,0x47,0x87,0x59,0xd2,0x1d,0xa5,0x0f,0xfd,0x22,0xfa, + 0x0f,0x58,0xd3,0x19,0xa5,0x79,0x48,0xac,0x9a,0x3e,0xb8,0x53,0x41,0x2b,0xea,0x40, + 0xb4,0x18,0x9d,0x4e,0x4d,0xb7,0xae,0x54,0x96,0xe9,0xdc,0x19,0x66,0x0f,0x1a,0xe8, + 0x28,0x0a,0x35,0x59,0x95,0xd6,0xc8,0x52,0x4b,0x86,0xba,0x7e,0x30,0x9b,0xe4,0x18, + 0x4f,0xa8,0x20,0x31,0x9a,0x2d,0x45,0x1f,0x26,0x8f,0x5d,0x4d,0x39,0x4b,0xb1,0xf6, + 0x22,0x77,0x82,0x94,0x38,0xdb,0x5c,0x47,0x49,0xb6,0x28,0x79,0x4e,0xb7,0xe5,0x63, + 0x26,0x3c,0x20,0x3c,0x98,0x61,0x64,0x77,0x66,0xab,0x30,0x07,0x81,0xa7,0x3b,0x25, + 0xc9,0x44,0x74,0x4a,0xc6,0x51,0x8c,0x02,0xab,0x10,0xb1,0x08,0x4a,0xab,0x14,0x0f, + 0xa5,0x8f,0x41,0xac,0xc7,0xc0,0x07,0xcd,0x5b,0x38,0xc3,0x57,0xd9,0xc3,0x61,0x34, + 0xcf,0xd2,0xbc,0xf4,0x93,0x52,0x22,0x94,0xf0,0x38,0x5a,0x14,0x8f,0xeb,0x14,0xbc, + 0x10,0x95,0x8f,0x8e,0xfd,0xf2,0xa5,0x1b,0x2c,0xf2,0x22,0xcd,0x9d,0x2c,0x4f,0x27, + 0xb9,0x28,0x8a,0xad,0xee,0x1e,0x00,0xb5,0xc6,0x8c,0x44,0xda,0x74,0x6e,0x06,0xc7, + 0x9e,0xfe,0x64,0xfd,0xf4,0x63,0x63,0xd6,0x1f,0x9a,0xc7,0x3a,0x16,0x11,0x72,0x20, + 0xd4,0x5a,0xe4,0xa0,0x1f,0xcf,0xd0,0xd3,0xb3,0x24,0x81,0xa6,0xd3,0xf9,0xed,0xec, + 0x6e,0x33,0xe0,0xe6,0x5b,0xea,0xaf,0x28,0x6d,0x9a,0xc1,0xa5,0x5c,0x4c,0x0f,0xa2, + 0xd8,0xb8,0xb2,0x49,0x9a,0x6e,0x36,0x9f,0x4c,0x1b,0x12,0x43,0x24,0xe1,0xe5,0x34, + 0x8a,0x43,0xa3,0x28,0x21,0xb2,0x58,0x35,0x7c,0xf9,0xe8,0xfd,0x06,0x75,0xe1,0xad, + 0x97,0x0e,0x0b,0xf9,0xa2,0x84,0x54,0x77,0x74,0x10,0x44,0x02,0x8c,0x60,0xdd,0x21, + 0xf0,0xa2,0x1c,0x73,0x64,0x5d,0xb0,0xb5,0x0e,0x92,0x31,0x1a,0x8c,0x05,0x44,0xa5, + 0x75,0xe3,0xdd,0xde,0x59,0x98,0xb7,0x54,0x0f,0xff,0xa2,0xb7,0x78,0xe4,0x0d,0xac, + 0x7c,0x91,0x78,0x43,0xeb,0x0b,0xbd,0x5f,0xcb,0x6f,0xc5,0x62,0x54,0xd0,0x6b,0x71, + 0xaf,0xde,0xa9,0xda,0x6a,0x5e,0x78,0xc3,0x93,0x81,0x55,0x64,0xb2,0xf0,0x20,0x2f, + 0x4b,0xf9,0x04,0x56,0x8f,0x0b,0xd4,0x48,0xc7,0x63,0xfc,0xfa,0x71,0x24,0x12,0x02, + 0x4b,0x45,0xd3,0x34,0x0e,0xe9,0xef,0x64,0xe1,0xe7,0xfc,0x10,0x0b,0x7f,0x29,0x7e, + 0x9e,0xe1,0xe9,0x97,0x4f,0xa4,0x9f,0x46,0x81,0x82,0x06,0xa6,0xfc,0xd1,0x2f,0xa7, + 0x36,0x16,0x3d,0x4c,0xe7,0x86,0x69,0x97,0xe9,0x35,0x04,0x7a,0x32,0x31,0xce,0x5e, + 0x99,0x76,0x11,0x47,0x81,0x30,0x4e,0x4d,0xab,0x4c,0x17,0xa0,0x9e,0x10,0xed,0x33, + 0xfa,0x49,0x96,0xfc,0x73,0x63,0x65,0x93,0x1b,0xeb,0xc0,0x0f,0xd3,0xac,0xe4,0x8f, + 0x40,0x63,0xcc,0x0f,0x40,0x50,0x2c,0x64,0x17,0xd9,0xb8,0x44,0x41,0x40,0x3f,0x63, + 0xe8,0x14,0x9a,0x60,0x98,0xfb,0xab,0xc4,0xd3,0x75,0x28,0xc9,0xdc,0x9a,0xc6,0xd6, + 0x52,0xe4,0xd6,0x72,0x64,0xe1,0xab,0x05,0x84,0x95,0x13,0x80,0xb5,0xca,0x95,0x55, + 0xde,0x5b,0x65,0x69,0x5d,0xff,0xf3,0x87,0x2f,0x34,0x64,0xa5,0x31,0x59,0x59,0xe8, + 0x85,0x54,0x17,0x4c,0x0e,0xa0,0xd3,0x29,0x69,0x45,0x01,0xd4,0xbb,0xda,0x18,0x0a, + 0x77,0x91,0xd3,0xa7,0x30,0x24,0xe5,0x02,0xb5,0xaa,0x2d,0x21,0xc2,0x55,0xf9,0x4f, + 0xfe,0x52,0xf3,0x4b,0x82,0xf5,0xd3,0xbb,0x7f,0xff,0xf1,0xee,0xc6,0x06,0xcc,0x28, + 0x0f,0xa1,0x7e,0x45,0x1c,0x3a,0x5a,0x96,0x0b,0x5e,0x35,0x8d,0x39,0xd4,0xd2,0x8a, + 0xb9,0x1f,0xc7,0x82,0x15,0xf3,0x44,0xe9,0x68,0xfb,0x00,0x2d,0xbd,0xdb,0x5b,0xfd, + 0x44,0xb7,0x74,0xa9,0x02,0xa0,0xef,0x5e,0xde,0x59,0x28,0xc9,0x7c,0x28,0xb5,0x3c, + 0x29,0xf0,0xe5,0x4b,0xfd,0xf8,0x8a,0x3f,0xad,0xa2,0x71,0x84,0xe2,0xdf,0xa2,0xfe, + 0x47,0xfc,0x3d,0xe7,0xb2,0x59,0x92,0x8e,0xa8,0xee,0x3f,0xe5,0xdf,0x21,0x17,0x2e, + 0x32,0x08,0x4c,0x40,0xd4,0x7f,0x55,0x0f,0x67,0x5c,0x4c,0x24,0xb7,0xa0,0xca,0xd7, + 0xea,0xe1,0xf4,0xee,0xce,0x92,0x73,0xf0,0x4e,0x5d,0xb6,0x03,0xbe,0x7c,0xb4,0x97, + 0x5e,0x22,0x56,0xda,0xaf,0xbf,0x7c,0xbe,0x16,0x7e,0x1e,0x4c,0xbf,0xf8,0xb9,0x3f, + 0x2f,0x8c,0xcf,0x50,0xd4,0xf4,0x6a,0x92,0x82,0x37,0x74,0xe8,0xf5,0xb6,0x1a,0x27, + 0x02,0x87,0x8d,0xf3,0xde,0xa3,0xf6,0x2e,0xb4,0x7a,0x00,0x9d,0x56,0x7c,0x8e,0x30, + 0x55,0xe0,0x90,0x6d,0x81,0x16,0xa1,0x83,0x25,0x60,0x41,0x91,0x49,0xf0,0x2e,0xcf, + 0xfd,0x47,0x3b,0x2a,0xf8,0x2f,0x4a,0x6c,0xac,0x9f,0xd9,0xeb,0x19,0x87,0x04,0x67, + 0xb3,0x41,0xc1,0x68,0x01,0x36,0x82,0xe1,0x41,0x05,0xa6,0xc9,0xab,0x2f,0xab,0x81, + 0xad,0x2a,0x93,0x0c,0xcb,0xb7,0x82,0x59,0x26,0x0d,0x31,0xed,0x0a,0x33,0xb6,0xb9, + 0x64,0xdb,0xd4,0x80,0x81,0x12,0x1b,0x63,0xcb,0xb7,0x46,0xe6,0x9a,0xe6,0x39,0x36, + 0xe8,0x51,0x4d,0x01,0x9c,0x0f,0x2b,0xe4,0x26,0x9a,0x0b,0xd8,0x0a,0x46,0xcb,0xd0, + 0x2b,0x21,0x04,0x56,0xda,0xc3,0xd6,0xdc,0xb6,0x40,0x89,0xa5,0x01,0xab,0xcd,0x5c, + 0xc3,0xaa,0x83,0x04,0x27,0x00,0x1f,0x96,0x64,0x99,0x11,0xd6,0x2e,0x17,0x05,0xc4, + 0xb1,0x7a,0xb7,0xd6,0xa1,0x28,0xc1,0x60,0x4e,0xb8,0x35,0xdb,0x63,0x09,0xf3,0x34, + 0x23,0xb4,0x11,0xd2,0x22,0xef,0xc6,0x86,0xc5,0x28,0x1e,0x7e,0x1e,0xa3,0xc8,0x05, + 0x5a,0xa2,0xb7,0x10,0x54,0x37,0x36,0x74,0x03,0xf1,0x4d,0x64,0x0d,0xd1,0x94,0x68, + 0x4d,0xd2,0xd4,0x2a,0x27,0xe9,0x92,0x3b,0x5a,0xe1,0x43,0x3a,0xa5,0x79,0x34,0x81, + 0xd4,0xfb,0xef,0x0f,0x37,0x85,0x86,0x65,0xd1,0x7c,0x8d,0xf4,0x4b,0x9e,0x82,0xde, + 0x72,0xbc,0x94,0xfe,0x48,0x2b,0x56,0x11,0xb5,0x0b,0xfc,0x44,0xf3,0xa1,0x33,0x40, + 0x7a,0xf5,0x38,0xca,0xb1,0xb1,0xb0,0x52,0x6b,0x06,0x83,0x96,0x86,0x12,0xf0,0xba, + 0xbf,0xa3,0x4a,0x97,0x35,0x14,0xc3,0xb4,0x84,0xb7,0x0e,0x9c,0xc0,0x5a,0x38,0x8a, + 0x2c,0xd0,0xe8,0xb3,0x3d,0x05,0x91,0x9b,0xfc,0x6b,0x91,0x7a,0x00,0xb2,0xad,0x99, + 0x33,0xdb,0x5a,0x11,0xb1,0x59,0x22,0x25,0x72,0x42,0x12,0x39,0x35,0xa3,0xdb,0xe4, + 0xce,0x4b,0xf1,0x83,0x55,0xb7,0x8b,0x68,0x92,0xf8,0xb1,0x17,0xa8,0x07,0x55,0x11, + 0x48,0x88,0x45,0x32,0x29,0xa7,0x6e,0xd2,0xef,0xbb,0x26,0xb0,0x20,0xec,0xb2,0x7f, + 0x83,0x36,0x76,0xf9,0xf6,0x95,0x38,0x6f,0xf0,0x91,0x00,0x1f,0xee,0xc1,0x8d,0x9d, + 0x2d,0x8a,0xa9,0x42,0x18,0xe4,0xa2,0x89,0x7f,0x75,0xd1,0x81,0xb0,0x21,0xe7,0xc6, + 0x36,0x2f,0xf9,0x6f,0xd6,0xc2,0x8a,0x50,0xa6,0x68,0x43,0xb8,0x07,0xdb,0x03,0x25, + 0x55,0xbd,0x7a,0xa1,0x81,0x05,0x85,0x83,0xb9,0xa7,0x24,0x57,0xda,0xeb,0xa5,0xf6, + 0x5c,0x94,0xd3,0x14,0x32,0x5d,0x07,0x82,0x75,0x12,0x6b,0xbf,0x12,0xee,0x61,0xd1, + 0x09,0x4c,0x37,0xad,0xac,0x76,0x21,0x39,0x07,0xef,0x06,0x69,0xba,0x74,0xac,0x2d, + 0xc8,0x50,0x2e,0x18,0x90,0xbe,0xd9,0x2c,0x80,0x06,0x70,0x5e,0x12,0xd0,0x27,0xe0, + 0x8f,0xe8,0x7b,0x4e,0x35,0x08,0xea,0x66,0xc3,0x8f,0x9f,0x3e,0xbc,0xbb,0xd2,0xf1, + 0xe1,0x90,0x3a,0x36,0x52,0x85,0x9d,0xcd,0x26,0xb5,0x67,0x42,0xc0,0xd0,0x8d,0x96, + 0xc2,0xc4,0xe7,0xa7,0x2b,0x20,0x29,0x00,0x20,0x3e,0xab,0xc7,0x86,0xa4,0xb7,0xc4, + 0x64,0x87,0xe9,0x4c,0x39,0x28,0x1a,0x50,0x42,0xb6,0xec,0x23,0x70,0xe2,0xe7,0x13, + 0x76,0x47,0x0a,0xc2,0x96,0x27,0xe9,0x80,0x2c,0x73,0xd2,0x31,0x17,0xfa,0x68,0x02, + 0x7b,0x7b,0xcc,0x6c,0x0a,0x54,0xda,0x10,0x80,0x49,0x9b,0x29,0x14,0xf9,0x6e,0xad, + 0x3d,0x65,0x2d,0x4c,0xdb,0x19,0x70,0xcd,0xe6,0xfa,0xf0,0x54,0x83,0x28,0x2d,0x35, + 0x28,0x10,0x18,0x89,0x1a,0x51,0x1e,0x64,0xf0,0x34,0x2d,0x8b,0x0c,0x66,0x3a,0xe8, + 0x73,0xca,0x05,0x24,0x9d,0x88,0x2c,0x81,0xd4,0x54,0x5b,0x64,0x16,0x08,0x98,0x45, + 0xa7,0x96,0x0b,0x8c,0x9a,0x00,0xdd,0x2f,0xc4,0x42,0x84,0xf0,0x76,0x20,0xab,0x43, + 0x7c,0x66,0x81,0xaa,0xc0,0xa5,0x89,0xa8,0x45,0x0c,0x8a,0x60,0x91,0x43,0x23,0x68, + 0x65,0x9a,0xce,0xb4,0xf3,0xfe,0x4b,0x0c,0xc0,0x18,0x89,0x24,0x98,0x12,0x98,0xd3, + 0xc1,0xe9,0xab,0xfe,0xe0,0xfb,0xfe,0xe9,0xb9,0x69,0xb1,0xf4,0xf7,0x35,0xaa,0x30, + 0x8e,0xd3,0x34,0x67,0x41,0x21,0x48,0xea,0xd3,0x80,0x61,0x27,0x6b,0x21,0xd4,0x7a, + 0x9b,0x69,0xe6,0x69,0x23,0x6a,0x58,0xed,0xc1,0xca,0x30,0xce,0xc4,0xb9,0x25,0x5f, + 0xfc,0x07,0x63,0x78,0x2a,0xce,0xac,0xf3,0x6f,0xa1,0x64,0x89,0xed,0xd1,0xe1,0x3b, + 0x28,0x7f,0xcc,0x02,0xc3,0x87,0x16,0x30,0xe6,0x69,0x28,0xb4,0xaf,0x45,0x9a,0x6c, + 0xc8,0x86,0xd8,0x14,0xe5,0x06,0x1a,0xc3,0x84,0xc3,0x96,0xc3,0x4c,0x43,0xd7,0x30, + 0x1b,0xa3,0x58,0x8b,0xca,0x82,0x2d,0x47,0xf2,0xdd,0x60,0x28,0x85,0x2e,0xcd,0x92, + 0x80,0x95,0x52,0x4c,0xe1,0x23,0xec,0xb9,0x82,0xe7,0xce,0x08,0xe2,0x99,0xd0,0x5a, + 0x71,0x11,0x35,0x85,0xea,0x49,0x31,0xb7,0x51,0x34,0x91,0x90,0x08,0xb7,0x5a,0x11, + 0x43,0xa2,0xd1,0xc4,0x08,0x16,0x60,0x43,0xf3,0x69,0x47,0x50,0xff,0x28,0x12,0x47, + 0xb6,0xf6,0x73,0x02,0x48,0x04,0x2f,0x82,0xfa,0x1b,0xc3,0x04,0x92,0x7e,0xa4,0x12, + 0x34,0x06,0x81,0x66,0x67,0xc2,0x84,0x3c,0x62,0x34,0x09,0xed,0x97,0x9b,0x1b,0x82, + 0xa5,0xba,0xd7,0xda,0x8b,0x40,0x26,0x8e,0x8b,0x2f,0xd0,0xae,0x58,0x8c,0x22,0x82, + 0xb7,0x46,0x16,0x07,0x69,0xda,0xc2,0x7f,0x2c,0x6a,0xb5,0x0b,0xc9,0x84,0x19,0x45, + 0x6d,0xe1,0x94,0xdf,0x83,0x28,0x67,0x16,0x21,0xcb,0x9a,0x17,0x8a,0x3d,0x81,0x28, + 0x8f,0x4a,0x88,0x65,0xf0,0xac,0x5b,0x8a,0x78,0xf1,0x7c,0xb1,0xde,0x3a,0xeb,0xc0, + 0x87,0x85,0xe1,0xe8,0x49,0xda,0x87,0x18,0xc6,0x77,0x38,0xd1,0xb0,0x3b,0x06,0x9e, + 0x14,0x50,0xec,0xad,0xc1,0x58,0xa9,0xb8,0x48,0xd8,0x8b,0x3d,0x0c,0xe4,0x36,0x63, + 0xf0,0x73,0x58,0x33,0xeb,0x00,0x74,0x9b,0x57,0xca,0xa1,0x4c,0x4d,0xb7,0x4c,0xbd, + 0xfd,0xea,0x42,0xd8,0xab,0xe9,0xa3,0xa7,0x97,0xba,0x2b,0xec,0xc0,0x66,0x71,0x0b, + 0x25,0x84,0xe1,0x6f,0x36,0x4c,0x36,0x6d,0x25,0x30,0x8e,0x92,0x7d,0xb0,0x2b,0x46, + 0x3a,0xe0,0xbe,0xdb,0xdc,0xb4,0xc3,0x87,0x39,0x50,0xa2,0xea,0x80,0xcd,0x89,0x82, + 0x54,0xd5,0xdc,0xf6,0x49,0x99,0xbe,0x5f,0x8c,0xc7,0x24,0xbe,0xf9,0x33,0x4d,0x5b, + 0xea,0x9b,0x50,0xe2,0xa2,0x5f,0x0e,0x5c,0x32,0x02,0xe9,0x9f,0xc7,0x36,0xd6,0x45, + 0xe8,0xe0,0xe5,0x5b,0xfb,0xbb,0xe3,0xf0,0x5b,0xfb,0x8c,0x65,0x47,0x85,0xe9,0x02, + 0x7e,0x77,0x0d,0x9c,0x68,0x96,0x4c,0xbc,0xce,0x60,0x4a,0x09,0xbc,0x60,0x48,0x2e, + 0x49,0xc3,0xa2,0x1d,0x1f,0x28,0xcd,0xb6,0x54,0x02,0xad,0xbc,0xcf,0xd3,0x19,0x08, + 0x95,0xaa,0x10,0x0d,0xd6,0x54,0x25,0x3d,0x73,0x45,0xcf,0x13,0xb0,0x34,0xf4,0x5d, + 0x9a,0x4c,0x2c,0xa6,0xd2,0x8a,0x8c,0x42,0xb1,0x84,0x26,0xb0,0x59,0xba,0x15,0xbd, + 0xde,0xc9,0xff,0xfe,0x5e,0x7c,0xfb,0xfb,0xfa,0x04,0x23,0x2b,0x80,0x43,0x93,0x74, + 0x39,0xc6,0x86,0x65,0x62,0xe5,0xfd,0x21,0xcf,0xa1,0x61,0xf4,0x45,0x42,0x4c,0xe4, + 0x8f,0x62,0x29,0x67,0x60,0xfc,0x98,0x52,0x3e,0x62,0x6d,0x0e,0x0b,0x1b,0xb2,0xa2, + 0xc0,0x44,0xcc,0x35,0x39,0x69,0x90,0xbd,0xbb,0xcd,0xb9,0x7f,0x4d,0xd9,0x63,0x63, + 0x62,0x21,0x39,0x5e,0x73,0xab,0x6c,0x66,0x57,0x75,0xaa,0xf0,0x54,0x6c,0x5b,0x88, + 0x57,0x9f,0xb8,0xbb,0xdc,0x6e,0x04,0xf2,0x9f,0x23,0xf3,0xc1,0x93,0x7d,0x97,0xd0, + 0x3f,0x9f,0x6e,0x6e,0xbe,0x68,0xfa,0x71,0x6e,0xcb,0xb1,0x9b,0xee,0x83,0x7a,0xf2, + 0xaa,0x22,0xb7,0x36,0x55,0x6a,0x9a,0xa9,0x96,0x8f,0x3a,0xd1,0x2f,0xaa,0xce,0x9c, + 0xdc,0x26,0xd9,0x43,0xe3,0xd9,0xee,0xf6,0x0c,0xa3,0x86,0xc9,0xb2,0x9a,0x45,0xd8, + 0x92,0xf1,0x0f,0xd5,0xb7,0x03,0xd6,0xce,0x44,0xe8,0x04,0x5b,0x37,0xd7,0xd5,0x40, + 0x75,0x25,0x99,0x74,0x1a,0x9e,0x7a,0xf6,0x86,0xdb,0x4e,0x7d,0x0e,0x08,0x3d,0x90, + 0xf9,0xe6,0x0d,0xa1,0x5d,0xa0,0x3e,0x35,0x85,0x25,0xe8,0x3e,0x10,0x31,0x94,0x5f, + 0xdd,0x76,0xb3,0xa1,0x8a,0x73,0x9e,0xc3,0x0d,0x14,0x2b,0xf7,0xa2,0xc3,0x06,0x84, + 0x04,0x69,0x6a,0x61,0x40,0xad,0xa9,0x4b,0x53,0xe9,0x7d,0xed,0xef,0x6a,0x31,0x96, + 0x89,0x54,0x8e,0xa8,0xe5,0x2f,0xc4,0xd8,0x98,0xe3,0x24,0x96,0xf6,0xf1,0x87,0x8f, + 0x3f,0xdb,0xec,0x10,0xf0,0x6a,0x4a,0xa5,0x51,0x50,0x6d,0x82,0xd2,0x12,0x64,0x3e, + 0xad,0x3e,0x75,0xe8,0x52,0x1c,0x8d,0x34,0x44,0xac,0x65,0xb0,0x8f,0x0a,0x6d,0x95, + 0x2e,0xe2,0x10,0x2d,0x40,0xaf,0xac,0x9d,0x88,0x96,0x73,0xd1,0x92,0x63,0x22,0xb9, + 0x87,0xdd,0x49,0x4a,0xa4,0xd6,0x1a,0x24,0x7f,0xbe,0x40,0xb4,0x46,0x60,0x8d,0x1a, + 0xbf,0x8f,0x16,0xa8,0xef,0x5f,0xd2,0x88,0x59,0x8f,0x9d,0xb1,0xf5,0xe8,0xa0,0xc8, + 0x81,0xa5,0xe9,0x50,0x63,0x4c,0x2e,0x5b,0xcc,0x33,0x88,0x93,0xb6,0x10,0x91,0x45, + 0x4c,0x2e,0x5f,0xdd,0x15,0x1c,0x4e,0x61,0x1c,0xc6,0xa3,0x5e,0x0f,0x7e,0x21,0xf0, + 0xc9,0x1e,0x5c,0xaf,0xf7,0x2f,0x65,0x5b,0x99,0xeb,0xaf,0xde,0xbf,0xec,0x62,0x1a, + 0x8d,0x41,0x06,0x64,0x38,0x7d,0xb5,0xc3,0x5e,0x0f,0x3f,0x10,0x4c,0x5f,0xed,0xc4, + 0x20,0x27,0xc9,0x74,0x79,0x4d,0x26,0xa9,0xf1,0xb5,0x63,0xf3,0x72,0x01,0xf7,0x93, + 0xb9,0xf0,0x3c,0x87,0xcc,0xe3,0x99,0xa7,0x66,0x61,0xc3,0x57,0x4a,0xe3,0xa5,0x00, + 0xc4,0x31,0x49,0xb9,0x9a,0xd9,0xdb,0x35,0xbe,0x02,0x97,0x28,0xdb,0x1e,0x64,0x4f, + 0xa9,0x8e,0x9c,0x59,0xf7,0xab,0xfd,0x88,0xe7,0x6a,0x9a,0x1d,0xca,0x53,0xdf,0xe9, + 0xb9,0x85,0x06,0xd6,0xac,0xf5,0x10,0x8b,0x74,0x91,0x07,0xc2,0x61,0x61,0xc2,0xf6, + 0x1d,0x56,0x32,0x2a,0x89,0xdb,0x73,0xa8,0xd2,0xe2,0x31,0x21,0x8f,0x3e,0x49,0x17, + 0x05,0xa9,0xca,0x5c,0xd4,0xea,0xd6,0x2f,0x08,0x50,0x13,0x22,0x61,0x45,0x56,0x4c, + 0xb9,0x0a,0x40,0x11,0x01,0x41,0x2c,0x29,0x6a,0x6b,0x2d,0xec,0xb8,0xc8,0x03,0x63, + 0x5c,0xdb,0xce,0xe4,0x9d,0xc3,0x2d,0xcd,0xa4,0x31,0xf8,0x14,0x35,0x7f,0x03,0x31, + 0x95,0x83,0x5f,0x73,0xf0,0xf3,0x84,0xc2,0x9d,0x3e,0xab,0x87,0xda,0xe2,0x63,0x3f, + 0x57,0xba,0x81,0x0d,0x49,0xf7,0x01,0xea,0xb2,0x69,0x27,0x9e,0x53,0x60,0xa6,0xcb, + 0x2c,0x07,0xc3,0x9b,0x16,0x60,0x6b,0x49,0x5d,0xe6,0xee,0x5b,0xc8,0x27,0xfa,0x4c, + 0xc9,0x3e,0x5a,0xd9,0xee,0x92,0x3e,0xa9,0xc9,0x2e,0xa1,0x5d,0xa4,0x73,0xd1,0x19, + 0x52,0xad,0x00,0x5b,0x12,0x04,0xee,0x54,0x23,0x75,0x78,0x94,0x22,0xe4,0xf9,0xb1, + 0x5c,0xd9,0xd6,0x72,0xe5,0xa1,0xd7,0xdb,0x2b,0x42,0x78,0x3a,0xe8,0x91,0xa7,0xc3, + 0x82,0x90,0x24,0x47,0x63,0x7a,0x10,0xe3,0x18,0xac,0x0b,0x0c,0x42,0x25,0x47,0x96, + 0x7e,0xf9,0x44,0x6e,0x89,0x54,0x9e,0xbf,0x7c,0xba,0x9d,0xdd,0xbd,0x79,0x25,0x5e, + 0x56,0x92,0xbc,0xcc,0x17,0xa2,0x12,0x9a,0x32,0x7c,0x73,0x00,0x7f,0x95,0x24,0x44, + 0xe3,0x64,0x80,0x5c,0x60,0x09,0x58,0xc1,0xa8,0x76,0x36,0xa6,0xde,0x7a,0x5e,0x38, + 0x28,0x13,0x2b,0x67,0x00,0x37,0x6a,0x60,0xa5,0x89,0x33,0xb4,0xee,0xf1,0x80,0x82, + 0x6d,0xcb,0x10,0x49,0x58,0x74,0x77,0xad,0x4e,0x18,0x9a,0xf8,0x2d,0xac,0xd3,0x6f, + 0xa7,0xb6,0x58,0x59,0xd7,0xbd,0xde,0xb5,0x4d,0xb1,0xb2,0xcd,0x46,0x8d,0xff,0xe2, + 0xa5,0x38,0x73,0x06,0x6d,0x71,0x41,0xe1,0xd2,0xf0,0xc9,0x32,0x4d,0x6d,0x08,0x51, + 0xfc,0xb4,0x89,0x69,0x6a,0x4f,0x52,0xf8,0xb8,0xdb,0x03,0x7a,0xf0,0xda,0x5b,0x1f, + 0xfb,0x9b,0x0e,0xa4,0x76,0x9b,0xda,0xb0,0x6a,0x37,0x53,0xfb,0xbe,0xde,0x14,0x41, + 0xe9,0x95,0x3d,0x8d,0xc2,0x50,0xe0,0xc3,0x21,0xe4,0x92,0xb9,0x9e,0xda,0x2b,0x10, + 0xa0,0xac,0x20,0x23,0x07,0x30,0x46,0xd0,0x86,0x35,0x02,0x49,0xcb,0x96,0xff,0xad, + 0x4c,0xb7,0x0a,0xb7,0xca,0xbf,0x02,0x2a,0x69,0x45,0xab,0x8a,0xfa,0x05,0x21,0xd7, + 0xce,0xc6,0x17,0xc4,0x92,0xa6,0xc3,0x9c,0x89,0x7f,0x26,0x94,0xdd,0x3d,0xe3,0x9d, + 0x5c,0x1a,0x4b,0x27,0xbd,0xa7,0x77,0xfd,0x16,0x05,0x97,0x07,0xbe,0x35,0x0f,0x9e, + 0x12,0x74,0x08,0x65,0x60,0x0c,0xad,0x5d,0xea,0xe5,0xe2,0x81,0x25,0xc9,0xa7,0x71, + 0xec,0xa9,0x34,0x9d,0x59,0x4b,0xe0,0x89,0x26,0x24,0xb1,0xb2,0xc4,0x58,0x49,0xb6, + 0x62,0xfe,0xd4,0x4d,0x1b,0x35,0xf0,0xce,0x7a,0xbd,0x25,0xfe,0xe3,0xb8,0xc7,0x0e, + 0x66,0xf0,0x1d,0xb6,0xc2,0xae,0xd5,0x46,0x8b,0xed,0xd1,0xcf,0x05,0xfd,0x54,0xf6, + 0x9a,0x13,0x6e,0x0f,0xe4,0xea,0x4a,0x52,0xc1,0xa8,0xd2,0xd9,0x05,0x7b,0xc0,0x20, + 0xb8,0xa5,0x45,0x62,0xc5,0x74,0xaa,0x77,0x8e,0xa9,0x2d,0x99,0xe8,0x41,0x65,0x5f, + 0xa4,0xd2,0x99,0x4a,0x16,0x64,0xc7,0x97,0x83,0x54,0x18,0x36,0xd3,0xb2,0x29,0x01, + 0xc3,0x08,0x97,0xca,0x81,0x48,0xa2,0x31,0x4d,0xd7,0xb0,0xb4,0x33,0xa7,0x85,0x52, + 0x9a,0x23,0x66,0xfe,0x94,0x4e,0x64,0xb8,0xe3,0x4b,0x1d,0xee,0x98,0x36,0xe1,0x8e, + 0x2f,0x9d,0x70,0x87,0x75,0x80,0xd9,0x3a,0x4c,0x82,0x20,0xc9,0x06,0x36,0xd3,0xce, + 0x1c,0x46,0x26,0xb5,0x23,0x90,0x9d,0x19,0x6f,0xb7,0xec,0x6f,0x36,0x5c,0x2c,0x0a, + 0xf8,0xb8,0x2d,0x36,0x8e,0x30,0xaa,0xe8,0xcd,0x97,0x2a,0xd2,0x10,0x1d,0x1f,0x13, + 0x47,0x7f,0xb9,0x8d,0xee,0xec,0x95,0xb9,0x96,0x7f,0x51,0x85,0x1f,0x68,0x86,0x5b, + 0x69,0x4c,0xc8,0x58,0x99,0xb4,0x21,0xa4,0x8e,0xd1,0x00,0x51,0x13,0x30,0x19,0xe5, + 0x76,0x52,0x4b,0x27,0x14,0xe5,0x7f,0x8b,0x16,0xa3,0x82,0xfa,0xf4,0x13,0x3f,0x8b, + 0x9a,0xc0,0x1b,0xd3,0x21,0xd9,0xd3,0x92,0xd2,0x42,0x41,0x9e,0x7d,0x0e,0x3e,0xe3, + 0x96,0x20,0x61,0x62,0x02,0x74,0xfa,0x2b,0xfb,0x80,0xbe,0xb2,0x55,0xa1,0xaf,0xf2, + 0x88,0x2c,0x93,0x76,0x98,0x12,0x8a,0x6b,0x56,0xf0,0x50,0x30,0x32,0xe5,0xea,0x91, + 0x60,0x83,0x4a,0x93,0xa1,0xa2,0x88,0x15,0x1b,0x86,0x92,0x47,0x28,0x33,0xe0,0x84, + 0x5b,0xa0,0xd0,0xc5,0x88,0xdd,0xaf,0x32,0xd5,0xce,0x06,0x5a,0x61,0xc2,0xdb,0x8c, + 0x45,0x01,0x9b,0x47,0x7a,0x80,0x14,0x14,0xcd,0xd3,0x11,0x16,0xd9,0x87,0xce,0xf3, + 0xc9,0x48,0x4f,0x31,0xc0,0xb6,0xda,0x23,0xd8,0x12,0x27,0x98,0x28,0x5b,0xd0,0xf7, + 0x66,0x71,0xef,0x11,0xe7,0xf2,0x24,0xd4,0xd4,0x82,0x38,0x6f,0x33,0x1a,0x5e,0x2b, + 0x13,0x18,0x92,0xea,0x30,0x87,0x5d,0x02,0x09,0xc9,0x0e,0xe2,0x21,0x58,0xb9,0xea, + 0xde,0x6c,0xc9,0xa0,0x04,0x0e,0x26,0xc5,0xaf,0x6b,0x27,0xfb,0xf4,0xdb,0x62,0xb4, + 0xd9,0x90,0x73,0x0d,0x77,0xdb,0x64,0xbd,0x54,0x87,0xf7,0x08,0xfc,0x5a,0x05,0xbd, + 0xdb,0x86,0x0b,0x01,0x51,0xe3,0xbc,0x36,0x3b,0x63,0xdf,0x36,0x8b,0x4b,0x3e,0x08, + 0x47,0x1d,0x66,0x22,0x2b,0xe1,0xf5,0x8a,0x62,0xaa,0xb1,0x35,0xc5,0x06,0x04,0x39, + 0xaa,0x24,0x58,0x2d,0x2a,0x03,0x5e,0x39,0x4e,0x50,0x54,0x04,0x00,0x19,0x4f,0x80, + 0x0c,0xf2,0x10,0x64,0x1b,0x34,0x27,0x9b,0x83,0x76,0x72,0xb4,0x95,0x1f,0x95,0x1f, + 0xd3,0xfc,0x8a,0x5d,0x16,0xd9,0x0d,0xf9,0x21,0xb2,0x1d,0x6f,0xc3,0x02,0x5f,0x2d, + 0xfa,0xa1,0x30,0xa6,0x0c,0x44,0x15,0xcd,0xbc,0x57,0x90,0xf2,0x15,0xb2,0xbc,0x16, + 0xb2,0x36,0x9b,0x5a,0xe8,0x33,0x4a,0x59,0xe0,0x0f,0x4f,0x06,0x12,0xcf,0x80,0xe0, + 0x51,0xd4,0x9f,0x27,0x5f,0x64,0xc0,0x4e,0x66,0x13,0xaf,0x62,0x19,0xd4,0x3e,0xc0, + 0xb6,0xd1,0x94,0xf8,0x4e,0x9f,0x41,0xbc,0x73,0x8e,0x09,0x51,0x31,0x6a,0x29,0x25, + 0x26,0x17,0x96,0xb4,0x57,0x6b,0x45,0xb7,0xd6,0x9a,0xc5,0x84,0xda,0xaf,0xe8,0xaa, + 0x50,0x45,0xd8,0x46,0xe5,0xb8,0x8f,0x13,0xaf,0x1b,0xea,0x2d,0xec,0x26,0x98,0x6e, + 0x5e,0xb4,0xdf,0x1c,0x58,0x51,0xb9,0x77,0x78,0xed,0x1e,0x5c,0x7b,0xbf,0x81,0x23, + 0xe4,0x12,0x79,0x85,0x4b,0x5b,0x19,0xd2,0xa9,0x92,0x41,0xe1,0x63,0xf6,0x30,0x65, + 0x98,0x2d,0x1a,0x3f,0x1a,0xe3,0xc4,0x04,0x29,0xf1,0xbe,0x00,0x98,0x9e,0x4c,0x81, + 0x71,0xe2,0xd2,0x2b,0x80,0x92,0x0a,0x21,0xcb,0x60,0xe4,0x87,0x13,0xa1,0x08,0x31, + 0xef,0xf5,0x0a,0x78,0xd1,0x45,0x6e,0xd3,0xe6,0xa5,0xcd,0xfb,0xea,0x84,0xef,0x4f, + 0xbc,0xe7,0xe6,0xe9,0x3a,0x89,0x99,0x9f,0x47,0x64,0x9e,0xd9,0x33,0xf1,0x58,0x18, + 0xd3,0xb9,0xa9,0x84,0xc7,0xdb,0xef,0x4c,0xde,0xa3,0x77,0xa7,0xf3,0xdb,0xdf,0x20, + 0xd0,0x12,0x91,0xff,0x46,0x7b,0x49,0x77,0x5e,0x05,0x0d,0x6b,0x04,0x6c,0x4a,0x50, + 0x2c,0xca,0x73,0x93,0xec,0xc2,0xce,0x4e,0x79,0xb1,0xb3,0x53,0x6e,0xed,0x4c,0x68, + 0xcd,0xd3,0x74,0xd4,0x74,0x69,0x6b,0xc3,0x19,0x27,0xd6,0xd4,0x99,0xce,0xb7,0x66, + 0xc7,0xa3,0xee,0x4a,0x38,0xda,0x02,0x6a,0x0b,0x39,0x96,0xfa,0x54,0x08,0xc1,0x66, + 0xf1,0xea,0x2e,0xb9,0xcb,0x4a,0x28,0x15,0x8a,0x2f,0xb3,0x71,0x69,0xd2,0x46,0x4b, + 0x8b,0x05,0xab,0xad,0x0c,0x0b,0x94,0x75,0xdc,0xd9,0xe3,0xf9,0x76,0x08,0x16,0x74, + 0x0f,0x88,0x60,0xdb,0x6b,0x62,0x2e,0x79,0x83,0xb0,0x7e,0xad,0x4d,0xd9,0x82,0xc8, + 0x43,0x11,0x31,0x56,0xb3,0xa6,0xa3,0x60,0xc4,0xf4,0x49,0x7f,0x78,0xdc,0xac,0x8a, + 0xf0,0x46,0xb8,0xbf,0x36,0x2b,0x85,0x75,0x6d,0x6e,0x25,0x23,0x93,0xba,0xfa,0x68, + 0xaf,0xfc,0x9a,0x8f,0x1b,0x48,0x14,0x24,0x62,0xb2,0x7f,0x03,0x7e,0x31,0x69,0xcb, + 0x6b,0x5e,0xb8,0xb2,0x95,0x4b,0xc3,0x94,0x4d,0x27,0xa2,0xdc,0x89,0xfb,0xa6,0x1e, + 0x87,0x3e,0xdd,0x46,0x66,0x2f,0x2c,0x8a,0x7e,0x5a,0x29,0x7b,0xcc,0x17,0xd2,0x7f, + 0x76,0xa4,0xf5,0x40,0x85,0xca,0xef,0x94,0xf0,0xa2,0x44,0x3a,0x93,0x6d,0x1b,0xa9, + 0x5a,0x0e,0xda,0x4a,0x93,0x4b,0x72,0xb3,0xa3,0x74,0x6e,0x48,0xc7,0xcc,0xd8,0x86, + 0x99,0xe8,0xbd,0x9e,0x54,0xee,0x5c,0x58,0xbe,0xa1,0x70,0x77,0x72,0x7c,0x5c,0x8d, + 0x27,0x41,0x3f,0x24,0x60,0x2e,0x77,0xc2,0x6a,0x6d,0xa9,0x21,0x4a,0x42,0x86,0x60, + 0x6e,0x23,0x95,0xd6,0xc8,0x8a,0xa2,0x6d,0x6d,0x14,0x6d,0xe1,0x61,0xd2,0x96,0x9f, + 0x34,0xae,0x0e,0xea,0x06,0x45,0x77,0xeb,0x26,0x17,0x73,0x48,0xff,0xdd,0xdd,0x1b, + 0x8b,0xde,0x2b,0x30,0xfc,0xd2,0x48,0x3c,0xb5,0xb5,0x53,0x90,0x4c,0x27,0x09,0xa0, + 0x9b,0xfb,0xb6,0x82,0xf4,0x63,0xa2,0xb9,0x60,0x1a,0x65,0x6a,0x6d,0xdc,0x16,0x49, + 0x0a,0x49,0x91,0x6d,0xb3,0x95,0x7d,0x88,0xb5,0xda,0xab,0x24,0xca,0xe0,0xa0,0x0b, + 0x0c,0xdd,0x7a,0x7a,0xdd,0x59,0xd7,0x93,0xac,0x50,0x8b,0xf7,0xb7,0x20,0x61,0xb3, + 0x4c,0xfd,0xa2,0x34,0x74,0x72,0xf6,0xc8,0x67,0x97,0x13,0x48,0x67,0x3a,0xf9,0x29, + 0x0a,0x87,0x6a,0xd8,0xac,0x1d,0x6e,0x56,0x29,0x99,0xfe,0xbe,0x96,0xa7,0x2b,0xab, + 0x72,0x01,0xa1,0x2d,0x92,0x20,0x5e,0x84,0x22,0x54,0x36,0x01,0x45,0x83,0x64,0xc4, + 0x8a,0xe4,0x7b,0x13,0x60,0x55,0x51,0x2b,0x02,0x44,0x1e,0xbc,0x54,0xd3,0xe4,0x5c, + 0x12,0x55,0x4b,0xd9,0x5f,0xa9,0x5d,0x6d,0xee,0x87,0x50,0xe8,0xda,0x2a,0xcd,0x39, + 0x39,0x27,0x90,0x5b,0x82,0x5a,0x4c,0xe1,0xeb,0x11,0x07,0xcb,0xda,0x2a,0x98,0xdd, + 0x17,0x22,0xf6,0xe3,0x63,0x46,0xca,0xdb,0x21,0xcb,0x7f,0xb3,0x99,0x44,0xbd,0xca, + 0xed,0x88,0x63,0x15,0xda,0x5a,0xcb,0x98,0xd5,0xd0,0xe5,0x80,0xd4,0xde,0x66,0xae, + 0x5c,0x9c,0xad,0xe4,0xb6,0x96,0x0e,0x6b,0xe8,0x9c,0xbc,0x98,0x8a,0x77,0x58,0xc6, + 0x8b,0x44,0x99,0xa9,0xc7,0x46,0xda,0xc4,0x70,0xbe,0x07,0x39,0x5b,0xb0,0x5b,0x0f, + 0xf2,0x02,0x44,0xdd,0x74,0xd5,0xa5,0x99,0xbf,0x76,0x78,0x9b,0xa0,0xec,0xc4,0xe7, + 0xd0,0x69,0x4b,0x4c,0xc1,0x50,0xac,0x7d,0x22,0x38,0x52,0x83,0x63,0xd8,0x08,0x7d, + 0x1e,0x4a,0x27,0xe4,0x4a,0x46,0x1d,0x33,0x08,0x7f,0x7a,0x0b,0x93,0x25,0x94,0x96, + 0x41,0xbf,0x0f,0x2c,0xd4,0xf4,0xb5,0x0f,0x8b,0x8a,0x56,0x13,0x63,0xd7,0xa9,0x36, + 0xdb,0xe6,0x7a,0xb2,0xdc,0x1d,0xd6,0xcb,0xc1,0xa0,0xa9,0x51,0x7b,0x33,0x07,0xcf, + 0x1b,0x86,0x30,0x6d,0xce,0x76,0xc3,0x72,0x95,0x12,0x4d,0x67,0xde,0x21,0x50,0xcb, + 0x92,0x15,0xba,0xab,0xde,0x1a,0x4d,0x6b,0x61,0xab,0x5c,0x86,0xbc,0xe8,0xf7,0x95, + 0xe7,0xbd,0x3d,0x68,0x54,0x31,0xfb,0x04,0x50,0xbd,0xa6,0xa3,0x70,0x08,0x2e,0xb3, + 0xf8,0x91,0xf9,0x4d,0x5a,0xf5,0xac,0xc8,0xa5,0xc8,0xf9,0x44,0xf1,0x23,0x07,0x24, + 0xab,0x2d,0xb2,0x38,0x25,0x0a,0x5e,0x25,0x32,0x58,0x4b,0xe4,0xcd,0xbb,0xde,0x64, + 0x24,0x8e,0x60,0x34,0x52,0x94,0x84,0x8d,0x1d,0xca,0xb7,0xe2,0x28,0x2d,0xca,0x0b, + 0x19,0x67,0x01,0x94,0xf6,0xfe,0x09,0xdc,0x56,0xeb,0x5e,0xba,0x35,0x50,0xa1,0x51, + 0xe8,0xcc,0x05,0xe9,0xb4,0x8b,0x21,0xdc,0xde,0x7b,0xe7,0x9e,0xff,0xaa,0x2d,0xc5, + 0x2d,0x87,0x99,0x46,0xc1,0xc5,0x08,0xde,0x1d,0xb4,0xea,0x8f,0xb0,0x54,0xa1,0x38, + 0x8d,0xb9,0xe9,0x3c,0xab,0x48,0xc9,0xf7,0x7d,0xa2,0x49,0xe7,0x1d,0x7d,0xd9,0x76, + 0xf5,0x1f,0xf0,0x8d,0x69,0x60,0xbe,0xd9,0xcc,0xed,0x88,0xd0,0x39,0x17,0x2d,0xa9, + 0x32,0xb7,0xa7,0x26,0xdc,0x7d,0xfa,0x74,0xa7,0x56,0x8f,0x8d,0x23,0x60,0x55,0x94, + 0x42,0xab,0x3e,0xc9,0xaa,0xf7,0xbd,0x1e,0xc7,0xdc,0x4c,0x4c,0x92,0xb6,0x6d,0xe5, + 0xe8,0x79,0xbf,0xe1,0x7d,0x0e,0x04,0x06,0x90,0x3e,0x97,0x53,0x1f,0x92,0x34,0xa6, + 0xb1,0x82,0xf0,0x31,0xb1,0x34,0x99,0xcb,0x69,0x79,0x9d,0xb0,0xc7,0x83,0x21,0x6c, + 0xca,0x7a,0x32,0xb7,0xcd,0xc8,0x55,0xc6,0x05,0xed,0x60,0x42,0x94,0xf2,0x2e,0x33, + 0xc9,0x55,0x01,0xf3,0x83,0xf2,0x02,0x19,0x19,0xba,0xd5,0x06,0xc3,0xb1,0x57,0x18, + 0x2f,0xbc,0x61,0xa2,0x90,0xd3,0xeb,0x09,0x1b,0x43,0xfa,0x37,0xa5,0xc7,0xb1,0x51, + 0x82,0xbe,0x5a,0xc1,0xfa,0xd6,0xc7,0x0e,0xd2,0x28,0xd0,0x4a,0xec,0x35,0x6c,0x7b, + 0xbc,0xa3,0x85,0xea,0x45,0x66,0x89,0x40,0x0c,0xa9,0x2c,0x11,0x8a,0x25,0xc1,0x7a, + 0xa0,0x21,0x5e,0x89,0xb1,0xbf,0x88,0x29,0xe6,0x48,0xd1,0x2e,0x42,0x2c,0x43,0x27, + 0x03,0x4b,0xb1,0xbd,0xae,0x6f,0x59,0xd2,0xd0,0xf0,0x1a,0x2c,0x64,0x75,0xa0,0x64, + 0xe2,0xb1,0x57,0xca,0x7d,0x58,0x94,0x1a,0x52,0xba,0x07,0x8c,0x68,0x48,0x14,0xa2, + 0xf9,0x09,0xfa,0x95,0x03,0x80,0x7a,0xdd,0x87,0x1b,0x99,0x7c,0x05,0x57,0x07,0x8b, + 0xa0,0x5b,0xa3,0x85,0x9c,0x4b,0x67,0x26,0x72,0x3f,0x06,0xc0,0xc2,0x6a,0xf5,0x43, + 0x0a,0x93,0x75,0xa2,0x54,0xa6,0xcb,0xbd,0x82,0xb9,0x54,0xa7,0xfd,0xbe,0xec,0x16, + 0x9d,0x4a,0x5d,0xf9,0x97,0xfd,0x12,0xf9,0x13,0x8c,0xb7,0x83,0x3a,0x92,0x79,0xd0, + 0x31,0xb9,0x30,0x0e,0x8b,0x22,0x4b,0xd0,0xca,0x3b,0x11,0xc4,0xac,0x92,0x0b,0xa8, + 0x31,0x66,0x9e,0x55,0xe8,0xcb,0x6a,0x8e,0xfd,0xb7,0xdc,0xc6,0xd0,0xd8,0x08,0x73, + 0xea,0x1d,0xd2,0x38,0x24,0x86,0x04,0xe1,0xc9,0xe0,0x68,0x94,0xcf,0x57,0xc4,0x99, + 0xa4,0xb4,0xfc,0x80,0xc3,0xa4,0x85,0x88,0xc7,0x16,0x34,0x54,0xd0,0xb6,0x2b,0x96, + 0x8b,0x3c,0x36,0x46,0x92,0x55,0x17,0xf5,0xae,0x99,0xda,0x79,0x76,0x17,0x2a,0x21, + 0x44,0xe6,0x87,0xb0,0xef,0xa0,0xc3,0x86,0x1d,0xd5,0xc1,0x9a,0x05,0x57,0x6c,0xfb, + 0x62,0xfe,0x92,0x82,0x70,0x24,0x84,0x89,0xec,0xa4,0x89,0x94,0x89,0x1c,0x38,0x9a, + 0xd3,0xf6,0x38,0x19,0x67,0x1f,0x12,0x72,0x57,0x8b,0xf7,0x8f,0x5c,0x93,0xa2,0x7d, + 0xd1,0x84,0xb7,0x85,0x75,0xf3,0x76,0xc0,0x6c,0x96,0x40,0xa9,0xdb,0x14,0x08,0xaa, + 0xf7,0xb5,0xf9,0xad,0x6d,0x0f,0x33,0x51,0xcb,0x8f,0xb7,0x15,0x08,0xd2,0xf4,0xb9, + 0x90,0x0b,0xc1,0x06,0xc0,0x1f,0xe8,0x16,0x68,0x08,0xf5,0xbb,0xdb,0xf6,0x18,0x9a, + 0x1e,0x19,0xec,0xdd,0x66,0xd3,0x40,0x68,0xf7,0x51,0x91,0x6e,0xfd,0xb1,0x63,0xb2, + 0x28,0x33,0x78,0x24,0xf5,0xcd,0x21,0xa5,0xc6,0x80,0x5c,0x54,0x92,0x13,0x14,0xb0, + 0xca,0x76,0x1a,0x72,0x50,0xa4,0xf4,0x6a,0xcc,0xd0,0x04,0x4b,0x15,0xe6,0x94,0x60, + 0x37,0x1b,0x7e,0x57,0x43,0xa7,0xc8,0x93,0xca,0xb2,0xf1,0x46,0x2c,0x1d,0x21,0x83, + 0xc1,0xf8,0x8f,0xb6,0x5a,0x4c,0xa9,0xb9,0xaa,0x42,0x36,0x88,0x2c,0x5d,0xb7,0xd4, + 0x52,0x76,0x18,0x9a,0x55,0x16,0x83,0xf3,0x3c,0x69,0x85,0x73,0xc6,0x15,0x54,0x58, + 0x9d,0x78,0x55,0x99,0x01,0x95,0x06,0x93,0x5f,0x46,0x52,0xdf,0xfb,0xde,0x95,0xed, + 0x63,0xba,0xcb,0x2a,0x37,0xd9,0x9a,0x49,0x21,0x23,0xfc,0xd8,0xd1,0x8f,0x3f,0x43, + 0x9e,0x94,0x53,0x8a,0xbe,0x1e,0xc3,0x7a,0x3e,0x1e,0x51,0xc2,0x44,0x15,0x26,0xe4, + 0x14,0xaf,0x66,0x87,0x82,0xb2,0x7d,0x38,0xf7,0x0d,0x8f,0x2a,0x4b,0x8c,0x52,0x21, + 0x7c,0xda,0xdc,0x33,0x7e,0xf8,0xe9,0xcb,0xaf,0x37,0x9b,0x9b,0x0f,0xff,0x73,0xf3, + 0xee,0x97,0x0f,0xef,0x36,0xd7,0x1f,0x3e,0x7f,0xb8,0xbc,0x31,0xff,0xa1,0xf6,0xfb, + 0x7c,0xbb,0xf4,0x27,0x3f,0xd1,0x2e,0x9b,0xa9,0xc8,0x8a,0x43,0x12,0x90,0xa8,0x58, + 0x86,0xdd,0x94,0xe4,0x19,0x6f,0x0e,0x76,0x3e,0x55,0xaa,0x63,0x66,0xe9,0x43,0xc8, + 0x63,0x8c,0x71,0xb8,0xdd,0x49,0xa1,0x20,0x8d,0xaa,0x92,0xd2,0x86,0xee,0xe7,0x0a, + 0xd1,0x46,0x85,0xd2,0x5a,0xbd,0x6f,0x2b,0x8b,0x56,0xed,0x42,0x7d,0x51,0xce,0x93, + 0xa3,0xa9,0xdd,0x45,0x11,0x56,0x19,0x67,0x60,0xbe,0x68,0x3e,0x5f,0x94,0xb4,0x1f, + 0xc9,0xa1,0x1b,0x32,0x24,0xe5,0xa6,0x05,0xe5,0xa2,0xad,0xa4,0x25,0x89,0xcf,0x04, + 0x47,0x65,0xf0,0x70,0x46,0x42,0x00,0x2d,0x48,0x61,0xa0,0x7a,0x37,0x2b,0xc6,0x02, + 0xe7,0x6a,0xdb,0x9e,0xf7,0xf7,0xef,0x17,0x11,0x5c,0x75,0xd8,0x88,0xf8,0x38,0x4d, + 0xe7,0x4a,0x57,0xb7,0xb6,0x8c,0xc6,0x3f,0x4b,0xba,0x94,0x1b,0xb6,0xd7,0x56,0xe0, + 0x29,0x5a,0x4b,0x73,0xbb,0xd9,0xf2,0xb2,0x22,0x2b,0x76,0xab,0x0d,0x52,0x65,0x6a, + 0xc0,0xa8,0x1f,0xd1,0xcb,0x32,0xf2,0x3f,0xc9,0xe4,0x0d,0xf9,0x89,0x62,0xce,0xbc, + 0x92,0x75,0xe8,0x79,0xb3,0xe9,0x06,0x7d,0x37,0x9b,0x76,0xb0,0x87,0x2d,0xec,0xcd, + 0x26,0xe8,0xf5,0x02,0xbb,0x80,0xb6,0xb8,0x82,0x9a,0x43,0x3d,0x38,0x8d,0x8b,0x8c, + 0x0c,0xab,0xb7,0x67,0x03,0x40,0x68,0xb6,0xa6,0xf9,0xf9,0xad,0x37,0x7c,0x39,0xd8, + 0x6c,0xa4,0x3d,0x9f,0x85,0x6f,0x60,0xe2,0x99,0xed,0x88,0xbb,0xcc,0x24,0xfa,0x93, + 0x18,0x1f,0x1c,0xc3,0xe1,0x93,0x36,0xec,0x93,0xff,0xad,0x54,0xf6,0xca,0x15,0x26, + 0x93,0x0f,0x20,0xe3,0x5e,0x2f,0x86,0xe2,0x3f,0x24,0x73,0xa1,0xf2,0x32,0x62,0xe9, + 0xbd,0x01,0x29,0xfb,0xc9,0x8f,0xc1,0x8c,0x89,0x17,0xcc,0x9d,0x61,0x3c,0x6b,0xcd, + 0xd4,0xbd,0x3e,0x89,0x0d,0x48,0xc3,0xa9,0x32,0x94,0xda,0x9c,0xdd,0xdd,0x87,0x68, + 0xef,0x50,0xb4,0x25,0x54,0x05,0xb9,0x0a,0x38,0x8d,0x3c,0x15,0x4c,0xa2,0x50,0x43, + 0xe6,0xd1,0x2e,0xa6,0x61,0x5a,0x31,0xed,0x69,0x91,0x1f,0xeb,0x7b,0x3f,0xbd,0xfb, + 0xb7,0xca,0xe5,0x34,0xed,0x82,0x36,0x86,0x9a,0x78,0xb8,0xf5,0x58,0xf7,0xfa,0x70, + 0x7b,0x7a,0xd7,0x7f,0xc4,0xcf,0xd6,0x24,0x6a,0xc2,0xa0,0x0c,0x0a,0xc5,0x98,0x56, + 0xd4,0x5e,0x20,0x7f,0x67,0x81,0x7c,0x2c,0x50,0xaf,0x47,0xbf,0x10,0xf2,0xc0,0x69, + 0xc6,0xdb,0xfa,0x27,0xc6,0xc5,0xe1,0xef,0x27,0x66,0xc5,0xe9,0xf2,0xab,0x69,0xc6, + 0x32,0x48,0x50,0xbd,0xbb,0x07,0x46,0x2b,0xfe,0x2a,0x32,0x65,0xe3,0x1f,0x82,0x54, + 0x0f,0x15,0xb1,0xb7,0x9d,0xe0,0x18,0xe5,0xd5,0x8e,0x28,0x93,0x65,0xe5,0xc1,0x1b, + 0x66,0xc7,0x78,0x27,0x50,0x16,0x11,0x4c,0xc7,0xc0,0x7f,0xeb,0xc5,0xf5,0x6e,0x2a, + 0xa7,0x39,0xec,0x97,0x26,0xcd,0x4a,0xb3,0x58,0x69,0x09,0x94,0x0a,0xd8,0xce,0x46, + 0x47,0x13,0x7c,0x88,0x6f,0xe1,0xfc,0xdf,0x1d,0xeb,0x17,0x4b,0x8f,0x9b,0x37,0x14, + 0xc0,0x19,0x2f,0xe6,0x93,0x4d,0xfb,0xfd,0xa3,0xee,0xec,0x72,0xc8,0x3d,0xae,0x46, + 0x32,0x5d,0xd3,0xee,0x66,0xa8,0xfd,0xfa,0x43,0xdb,0x2e,0x67,0xd7,0xb8,0xe4,0x6c, + 0x40,0x42,0x5f,0xb9,0xc2,0x0c,0xef,0xbd,0x5b,0x94,0xdc,0xd5,0x28,0xe8,0x9a,0x43, + 0xb0,0x87,0xca,0x55,0x27,0x11,0x1a,0x26,0x9d,0x4c,0x05,0x7d,0x7a,0x6c,0x25,0x8c, + 0x96,0x90,0xaf,0xa1,0x8c,0x06,0x90,0xc0,0xa6,0x6d,0xc6,0x63,0x83,0x83,0x20,0x22, + 0xcf,0xf5,0x0b,0x5d,0x13,0xd0,0x13,0x5c,0xa7,0x0d,0xb2,0xa4,0x3e,0xda,0x19,0xd5, + 0xe4,0xe7,0x94,0xe5,0x33,0x3b,0x9f,0x4f,0xc6,0xb3,0xb5,0x9a,0x1e,0x5e,0x89,0x33, + 0xe7,0x8c,0x3d,0x32,0x15,0x8b,0xf2,0x1f,0x1b,0x6b,0x13,0xf3,0xb4,0x44,0x8c,0xc9, + 0xcf,0xbc,0x19,0x74,0x3e,0xa8,0x22,0xd5,0xa5,0x00,0xa4,0xd2,0x06,0x3b,0xfb,0x71, + 0x21,0x62,0xfb,0x8f,0x6c,0x7c,0xc3,0xa1,0xd3,0x9d,0xe1,0x53,0xc9,0xde,0x90,0x4a, + 0x3a,0x93,0xd1,0x13,0x1a,0x1b,0x3f,0x70,0x9f,0xe6,0x4e,0x83,0x26,0x66,0x32,0x93, + 0x0e,0x1e,0xcf,0x87,0x62,0x16,0xaa,0xcf,0x67,0x30,0x41,0x96,0x7f,0x77,0x28,0x9e, + 0x57,0xc2,0x2a,0x8f,0x77,0x17,0xec,0x4f,0x86,0x07,0xdf,0xc3,0x3a,0x27,0x16,0x38, + 0x90,0xc1,0x2e,0x12,0xf5,0x0d,0xc6,0x46,0x56,0xd6,0xf6,0xcb,0xa1,0x28,0x13,0xe9, + 0x4a,0x8d,0x2a,0x7e,0x1b,0x51,0x86,0x2c,0xe9,0xb8,0xd0,0x4b,0xe9,0xad,0xe9,0xa7, + 0x4c,0x27,0x93,0x58,0xf6,0x43,0x40,0x75,0x0b,0x6d,0x49,0xac,0xe2,0xcf,0x68,0xe7, + 0x44,0x90,0x9f,0x47,0xbe,0xaa,0xa4,0x93,0x14,0xd3,0x95,0x07,0x36,0x52,0x83,0xdd, + 0x5b,0x95,0xdc,0x7e,0x83,0x6a,0xff,0x99,0x1d,0xdd,0x8a,0xd8,0x19,0x72,0xa7,0xab, + 0xc3,0x35,0x75,0xe1,0x3e,0x4b,0x9b,0x92,0x46,0x28,0xe1,0x9f,0x12,0xbc,0x39,0x44, + 0x54,0x4c,0x61,0xd4,0xad,0x34,0x3a,0x40,0x60,0x33,0x0f,0x5c,0x5e,0x5f,0x7b,0xba, + 0x43,0xc1,0xe0,0xb5,0x1f,0xc7,0x4e,0x94,0x44,0x65,0xe4,0xc7,0xdd,0x53,0x1f,0xcd, + 0x79,0x07,0x17,0xfe,0x6d,0x44,0x1d,0x3b,0xb0,0xf4,0x7c,0x32,0xaa,0xf6,0x9f,0x08, + 0x69,0xb5,0xa0,0x03,0x12,0xfd,0xbe,0xaf,0x8e,0x74,0x00,0xc9,0x96,0x3a,0x71,0x63, + 0xd2,0x09,0x1f,0x55,0x4c,0x71,0x28,0x75,0xd2,0x87,0x8a,0x17,0xce,0xbe,0xf3,0x21, + 0xfd,0xfe,0x6c,0xef,0xc1,0x10,0xee,0xe2,0xcf,0x0f,0x9a,0x2c,0xf6,0x9c,0x2e,0x01, + 0xa1,0xf2,0xf1,0x1c,0xf5,0xca,0xc7,0x8b,0x2c,0x75,0xbc,0xc8,0x74,0xe9,0xc4,0x87, + 0x33,0x3c,0xcf,0x1e,0x4e,0x86,0xf6,0xa9,0x82,0x42,0x87,0xa8,0xac,0xe6,0xcc,0x55, + 0x73,0xa6,0x4a,0x9e,0x4d,0xb9,0x95,0xb6,0xc4,0xdd,0xba,0x42,0x5e,0x02,0x7b,0xa9, + 0x75,0x56,0xc4,0x97,0xc7,0x81,0x80,0x63,0xa8,0xad,0x08,0x12,0x03,0x14,0xde,0x0f, + 0x45,0x00,0xa1,0xcc,0x28,0xa5,0xea,0x5b,0xdf,0x19,0xa7,0xc1,0xa2,0xe8,0x2f,0xa3, + 0x22,0x22,0xb3,0x0b,0x24,0x53,0xe2,0x5b,0xa7,0x70,0x0d,0x26,0xa2,0x88,0x8f,0x73, + 0xba,0x33,0x4d,0x1f,0xa6,0xa1,0xfc,0xd4,0x97,0x91,0x7d,0xa7,0x8f,0x2a,0xf2,0x8c, + 0x4a,0x94,0xac,0x9b,0xc3,0x24,0xc3,0xe1,0xf9,0x20,0x7b,0x70,0xe7,0x7e,0x3e,0x89, + 0x12,0x67,0xa0,0xf9,0x8b,0x32,0x75,0x33,0x30,0x31,0x2d,0xe3,0x40,0x7b,0x05,0xb8, + 0x03,0x8d,0x8e,0xba,0xd4,0x84,0x30,0xc9,0xa3,0xd0,0xa5,0x9f,0x3e,0x66,0x9f,0x91, + 0x3d,0xe7,0x1c,0x8d,0xb4,0x40,0x2b,0x8f,0xb4,0x73,0x60,0x49,0x3b,0x82,0x87,0xa3, + 0x25,0x47,0x27,0xf3,0x28,0x91,0xf1,0xad,0xe1,0x38,0x37,0x19,0xae,0x04,0x8e,0xa9, + 0x2f,0xe6,0x49,0x7f,0xe2,0x67,0x0e,0xaa,0xbb,0x3e,0x94,0x59,0xd2,0x8f,0x00,0xab, + 0x70,0x02,0x41,0x67,0x79,0xe4,0x28,0x47,0x6b,0xee,0x83,0x0e,0xdd,0x38,0xa3,0xba, + 0xf3,0x71,0x2c,0xf6,0x35,0x71,0x09,0xda,0x90,0x27,0x52,0x1f,0xa1,0x19,0xb8,0xb4, + 0x13,0x48,0xb9,0x6f,0x8e,0x5c,0x0e,0x4a,0x38,0x2a,0x45,0x9f,0x8f,0xa9,0x91,0x19, + 0x92,0xfb,0x99,0xec,0x6a,0xba,0xfe,0x3b,0xe0,0x5f,0x03,0x7a,0x9b,0x4c,0x22,0x49, + 0x1a,0xfd,0x95,0x3c,0xf2,0xf4,0x6a,0x30,0x90,0xd0,0xc2,0x35,0x41,0xe1,0x35,0x74, + 0xe5,0x48,0xa8,0xa5,0x3a,0x18,0x45,0x8f,0x8a,0x40,0xe9,0x10,0xd2,0xa2,0xa0,0x95, + 0x7b,0x4a,0x91,0xbe,0xa4,0x23,0x4a,0xf3,0xb3,0xec,0xe5,0x68,0x2d,0x69,0x70,0x48, + 0x34,0xa8,0x16,0x98,0x0e,0xdc,0x35,0xa7,0xee,0xcc,0x2d,0x55,0x5d,0xff,0x05,0x15, + 0x57,0x43,0x3d,0xaf,0x86,0x0a,0xc8,0xbb,0x38,0x62,0x52,0xac,0x0b,0x45,0x1c,0x47, + 0x59,0x11,0x15,0x35,0x45,0xd0,0x02,0x37,0x73,0x78,0xc2,0x5d,0xbe,0xb9,0x33,0xbb, + 0xef,0xbf,0x7f,0x82,0x35,0x0c,0x75,0x04,0x31,0x43,0xe3,0xdd,0x33,0x6f,0x55,0xf9, + 0xc5,0x78,0x3c,0x96,0x63,0x4c,0x2c,0x7b,0xd2,0x5d,0x1f,0xfa,0xe9,0xd3,0xea,0x39, + 0xbc,0x84,0x76,0xd2,0xa2,0x94,0x44,0x51,0x32,0xc4,0xcb,0x18,0x34,0xff,0xba,0xa2, + 0x79,0x48,0xbc,0xbf,0x5c,0xe4,0x69,0x85,0x1d,0x0c,0xb9,0xe1,0x00,0x9a,0xed,0x53, + 0xc2,0x79,0x32,0xa7,0x89,0xb6,0xc3,0xd4,0x75,0xbf,0x6a,0xae,0x3b,0xa4,0xb3,0xcb, + 0xf2,0xc0,0x81,0xc8,0x89,0x5f,0xe5,0x97,0xfa,0xb5,0x62,0x5f,0x20,0x7e,0x4b,0xd0, + 0xec,0x34,0xf9,0x2b,0x50,0x4c,0x79,0x2c,0x8c,0x59,0xc4,0x63,0x40,0x00,0x00,0x2e, + 0x26,0x09,0xa0,0x75,0xe8,0x4b,0x8a,0x14,0x16,0xf7,0x0b,0xaa,0xf4,0xcc,0xa1,0xbe, + 0x0a,0x71,0x11,0xef,0x40,0xf4,0xff,0x8c,0x49,0x5e,0x35,0xa4,0xbe,0x83,0x47,0xe6, + 0xce,0x2e,0x71,0x50,0xe5,0xea,0x70,0x9c,0x3c,0xc6,0xb7,0x8f,0x45,0x95,0xdc,0xdb, + 0x87,0x45,0x89,0xe3,0xa0,0xb5,0xfe,0xc1,0xce,0x29,0xc5,0x46,0xd0,0xc1,0x61,0x09, + 0x8c,0xe1,0x60,0xb0,0x5c,0x69,0x7d,0x6d,0xf8,0x1d,0x46,0x63,0xba,0x3c,0x1d,0x35, + 0xdc,0x33,0x1a,0x5f,0xeb,0x74,0x1f,0xf1,0xe5,0xdf,0x64,0x0e,0xc5,0x0c,0x2f,0x6b, + 0x66,0xa0,0xf3,0xbb,0x98,0x43,0x0e,0xbc,0xec,0xe3,0x87,0x3d,0x6b,0x43,0xff,0x1f, + 0xd6,0xcb,0xb3,0x00,0x41,0x05,0xf6,0x6a,0xfd,0x97,0x15,0x7d,0xd3,0xdd,0x87,0x91, + 0x72,0xd2,0x42,0x49,0xd9,0x5e,0x84,0x33,0x22,0xa3,0x72,0xa2,0x45,0xeb,0xfd,0x4b, + 0xad,0x94,0xc2,0x79,0xb3,0x8c,0xfc,0x5c,0xb1,0xbb,0x5d,0xcf,0x71,0x67,0x5e,0x2f, + 0x07,0xdf,0xb4,0xa5,0x18,0x21,0xd6,0xcf,0xfb,0x13,0xfa,0x4a,0xd6,0xf4,0xf7,0x83, + 0x50,0x4c,0xe8,0xb0,0x06,0xa1,0xe4,0x92,0x46,0xac,0xa1,0x85,0xf5,0x62,0x80,0xff, + 0x69,0x03,0x35,0xea,0x6c,0xb2,0xae,0x8d,0x0a,0x7f,0x84,0x5e,0x20,0xc1,0x5c,0xe6, + 0xe3,0x81,0x4b,0x39,0x3b,0x03,0xb7,0x12,0xec,0x6a,0x68,0xcf,0x89,0x4e,0x40,0x22, + 0x36,0xf1,0x93,0x68,0x2e,0x39,0x22,0x9b,0x68,0xe7,0x85,0x16,0x2c,0x46,0x51,0xd0, + 0x1f,0x89,0xff,0x44,0x22,0x37,0xec,0xa1,0x65,0xbf,0xb6,0xec,0x53,0x6b,0x68,0x6a, + 0x2a,0xb0,0x56,0x6c,0xff,0x6b,0x26,0x1e,0xc7,0x39,0x6c,0xfd,0x42,0xc3,0x60,0xca, + 0x74,0x2d,0x3b,0xfc,0xfe,0xf4,0x1b,0x75,0xbc,0xb3,0x5c,0x35,0x43,0x1c,0x47,0x0f, + 0x22,0xac,0xc6,0x97,0xf3,0x80,0x06,0xae,0xb2,0x3a,0xe8,0xf0,0x6d,0x57,0x67,0x7d, + 0x5d,0x14,0x25,0xfc,0xe0,0x7e,0x75,0x9e,0x56,0xf1,0x8c,0xa2,0xfb,0x3e,0x07,0x9e, + 0x0b,0xc9,0xba,0xff,0xe9,0x73,0xc6,0x91,0x73,0x3a,0x3c,0xff,0xee,0xfc,0xf5,0xd9, + 0xab,0xf3,0xef,0x54,0xe7,0xeb,0x67,0xa8,0xf9,0xec,0x94,0x88,0x79,0xff,0x82,0x56, + 0x6b,0x4f,0xec,0xa7,0xf1,0x5a,0xb6,0x68,0x1c,0xd4,0xd0,0xe1,0x81,0xa1,0x7d,0xbe, + 0xb3,0xae,0xaf,0xf7,0xa1,0x38,0xea,0x52,0xdd,0x0c,0x18,0x2f,0x6d,0xf1,0x94,0x5a, + 0xcf,0xd9,0x78,0xe8,0x48,0x9c,0x27,0x67,0x9b,0xcf,0xbf,0xe3,0x83,0xac,0x52,0xd3, + 0x81,0x30,0xc1,0x36,0x49,0xc7,0x6c,0xda,0x76,0xda,0x3d,0x39,0xe0,0x4c,0xd6,0x4c, + 0x8b,0xbe,0x4f,0xb9,0xcb,0x53,0xe2,0xe5,0x27,0x26,0x4a,0x22,0x8d,0x14,0x65,0x97, + 0x9c,0x63,0x6a,0x16,0x19,0x24,0xe6,0x09,0xdb,0x26,0x7f,0xc3,0x5c,0x61,0x33,0xa8, + 0x2d,0xf8,0x78,0x47,0x70,0x0b,0x53,0xa5,0x12,0x79,0xa4,0x6f,0xec,0x80,0x26,0xb2, + 0x56,0x7a,0x88,0x08,0x57,0xca,0xee,0x75,0x65,0x63,0xb1,0x1c,0xef,0x36,0xa9,0xab, + 0x33,0x39,0x51,0xbf,0x7c,0x6c,0xb7,0xf6,0x55,0x64,0x74,0xa3,0xf2,0xba,0x9b,0x48, + 0x65,0x1d,0xdc,0x3b,0xf9,0xfd,0xe4,0xf8,0x1f,0x27,0x16,0xdc,0x51,0xf8,0x82,0x27, + 0x7a,0x2b,0x6e,0x32,0xe2,0xd4,0x50,0xd5,0xb2,0x09,0x99,0x70,0x28,0x81,0x4f,0x2c, + 0xf2,0x3d,0x07,0xaa,0x4c,0x6f,0xb7,0xa4,0x68,0x38,0x9c,0x8f,0xb5,0x8c,0xb6,0x30, + 0x9c,0x2a,0x54,0x9e,0x1d,0x1b,0xa3,0x0b,0xe5,0xf2,0x93,0x0f,0xdc,0x39,0x2c,0xa8, + 0x12,0x58,0xa4,0x5b,0x4e,0xb1,0x94,0xf6,0x85,0x13,0x71,0x3b,0x2e,0xd3,0xc4,0x6d, + 0x22,0xeb,0x2b,0x05,0x6d,0x2c,0x61,0x4d,0xf6,0xdc,0x20,0x01,0x9a,0x20,0x3f,0xb3, + 0x89,0xc7,0x50,0x88,0xa6,0x1d,0x92,0x59,0x0b,0x8f,0x8a,0x6e,0x23,0x8e,0xb8,0x8b, + 0x5e,0x4f,0x25,0x5e,0x8a,0xdb,0xc1,0x5d,0xeb,0x6c,0xdb,0x9e,0x28,0x0d,0xd5,0x30, + 0x7b,0x3d,0x71,0x3b,0xbc,0x33,0xe3,0x2a,0xab,0x4f,0x1e,0x31,0x3d,0xfe,0x7a,0x7c, + 0x6c,0x0d,0x2c,0x3a,0xdc,0x22,0x0f,0xef,0x32,0x0a,0x9e,0x66,0xf1,0xf8,0x94,0x99, + 0x48,0x03,0xda,0x71,0x54,0x27,0xed,0xd8,0xc1,0x44,0x6f,0x8f,0x3f,0xee,0x0c,0xde, + 0x7f,0x3a,0x65,0x1f,0xf3,0xf5,0x79,0x3f,0xc2,0xe3,0x65,0x88,0xab,0xe0,0x91,0xdf, + 0xe9,0x85,0x8b,0x87,0x3c,0x69,0x55,0x03,0xb3,0xc5,0x92,0xf9,0xed,0xae,0xd3,0x44, + 0x47,0xb3,0x3d,0x4e,0xaa,0x92,0xc7,0xe4,0xcc,0xd3,0x46,0x9c,0xb9,0x35,0xa2,0x37, + 0xd5,0xd4,0x2f,0x28,0x7b,0x67,0xd2,0x3d,0x1b,0x0e,0x1e,0xe6,0x79,0xb6,0xcb,0x26, + 0x98,0xfb,0x34,0x6e,0x8d,0x14,0xd4,0xd7,0xcd,0x86,0x50,0x29,0x4c,0x92,0x1c,0x8a, + 0x7c,0xb3,0x39,0xbc,0xee,0x50,0x04,0xc5,0x74,0x97,0x5e,0x61,0x2f,0x69,0x4c,0x49, + 0x49,0x1b,0xc5,0xea,0x91,0x62,0xaf,0x7c,0xf2,0x19,0x15,0x45,0xde,0x99,0x78,0x7d, + 0x02,0xe6,0xc2,0x58,0x5e,0x70,0x25,0x6d,0xa9,0x3b,0x74,0xca,0xf7,0xb8,0xfe,0xe4, + 0x70,0x74,0x67,0xa4,0x02,0xbb,0xde,0xe1,0x52,0x66,0xb7,0x82,0xa0,0x47,0xbb,0xb0, + 0x64,0x7f,0xc7,0x46,0xfd,0xa8,0x36,0xa6,0x2e,0x74,0x4d,0x3f,0xde,0x2d,0xe4,0xa0, + 0x0f,0xc1,0xa5,0x39,0xeb,0xd3,0xb2,0xcc,0x0a,0xe7,0xa4,0x3a,0x06,0x4d,0x96,0x81, + 0x4d,0x69,0x11,0x27,0x10,0x58,0x34,0xff,0xe2,0x85,0x7e,0x2c,0x92,0x20,0x0d,0xc5, + 0xaf,0xbf,0xfc,0x70,0x99,0xc2,0x07,0x4c,0x68,0x85,0x6b,0xa0,0xe6,0xb6,0x8d,0x2c, + 0x19,0x91,0x97,0xb8,0x0a,0xa6,0x3b,0x78,0xaa,0x62,0xd2,0x16,0xc6,0x2c,0xf7,0x58, + 0xea,0x94,0x84,0x8b,0xd6,0xcb,0xef,0x0b,0x3a,0x30,0xa8,0x3b,0x9c,0x35,0x71,0xf1, + 0xec,0x51,0x20,0xa7,0x93,0x5e,0x73,0x51,0x3d,0x69,0xd4,0x7c,0x78,0xce,0x79,0x98, + 0x8f,0x04,0xda,0xe1,0x4d,0x94,0x8b,0xea,0xd8,0xb7,0x26,0xcf,0x6a,0x87,0x55,0xbd, + 0xd2,0xcf,0x28,0x39,0x53,0xed,0xf7,0x48,0xa0,0xad,0xe4,0x1b,0x48,0x97,0xf2,0xa2, + 0x55,0x50,0x0d,0x8e,0xd6,0x26,0x98,0xee,0x84,0x9e,0x50,0x50,0x2d,0x16,0xbf,0x34, + 0x44,0x4c,0x64,0x71,0xd8,0x85,0x0c,0xa8,0xda,0x0a,0x80,0x82,0xee,0x4e,0x56,0x38, + 0x6b,0xc4,0xdd,0x27,0x0a,0x65,0xef,0xbf,0xac,0xa5,0xb9,0x1b,0xa6,0xd5,0xb6,0x9c, + 0xc4,0x46,0x95,0xc0,0x4c,0x70,0xdc,0x72,0x62,0xc7,0xbc,0x07,0x0e,0x52,0xef,0x8c, + 0x35,0xbc,0xd0,0xf9,0x52,0x17,0xf4,0x7f,0xc5,0x17,0xcc,0xa0,0x66,0x19,0x95,0x31, + 0xd8,0xed,0x5a,0x6d,0x7f,0xa4,0x20,0x1d,0x03,0xf5,0x62,0x55,0x8f,0x3b,0x33,0x8f, + 0x75,0x4d,0x0e,0x80,0x5a,0xec,0xe1,0xc9,0xd8,0x1f,0x61,0x6d,0xac,0x0a,0x5c,0x5b, + 0xb2,0xf2,0x05,0x1d,0x8a,0x38,0x98,0x8f,0xae,0x6c,0x3a,0x26,0xd9,0xc9,0xcf,0xbe, + 0xb2,0xef,0x17,0x22,0x7f,0xbc,0xe6,0x5b,0x2b,0x28,0xf1,0x83,0x76,0x53,0x6e,0xb1, + 0x38,0xff,0xdf,0x3b,0x8a,0x80,0xbc,0xa3,0x3b,0xdd,0x54,0x07,0xb9,0x83,0xa7,0x52, + 0x87,0x2a,0x83,0xb6,0xa3,0x00,0x7a,0x25,0xf6,0x74,0x6a,0xa0,0xd3,0x9b,0xa4,0x74, + 0xc2,0x9e,0x03,0x93,0x6a,0x22,0x4e,0x8a,0xe5,0xe4,0xf8,0x61,0x1e,0x5b,0xdf,0x9c, + 0x5d,0xe2,0x51,0xc3,0x63,0x52,0x78,0x47,0xc4,0x0a,0xe0,0x84,0xd5,0x0a,0x1c,0x70, + 0x66,0xa7,0xf9,0xe4,0xe4,0x14,0xf6,0x1d,0x55,0x3e,0xd2,0x96,0x91,0x58,0xbd,0x4f, + 0x1f,0xbc,0x23,0x36,0x60,0x5f,0xe1,0xbf,0xa3,0x6f,0xce,0x3e,0xa0,0x7d,0x10,0xe5, + 0x01,0xa8,0x2a,0xc0,0xa7,0xd7,0x47,0x5a,0xf0,0xc8,0x7f,0x72,0xef,0xe8,0xe5,0x91, + 0x36,0x8e,0xe2,0xd8,0x3b,0xfa,0xe6,0xf4,0x4c,0x86,0x89,0x8e,0x4e,0x64,0x0b,0x02, + 0x88,0x27,0xdd,0x7d,0xee,0x0e,0x8b,0x28,0x30,0x65,0x9e,0x3e,0x05,0xb3,0x9e,0xce, + 0xb2,0xbe,0x2c,0x43,0xa7,0xfd,0xf1,0xa2,0xa4,0x2c,0x0a,0x14,0x5e,0xca,0x32,0xf7, + 0xa0,0xc8,0x3d,0x2e,0x06,0xc7,0xf8,0xc1,0xf4,0x9a,0x2d,0x1a,0x63,0x4d,0xa7,0xd3, + 0x1c,0x3d,0x45,0x2f,0x3a,0x05,0xd8,0x8a,0x5c,0xa6,0x51,0x7e,0xba,0xf9,0xf1,0xb3, + 0xa7,0xbf,0xe1,0x64,0xcc,0xb7,0xfa,0xf1,0xe5,0xf5,0xf5,0xb1,0xfe,0xe6,0x44,0xbe, + 0xbe,0x09,0xa3,0xa5,0xc6,0x34,0x0c,0xe4,0x27,0x47,0x9d,0xf7,0x11,0x5e,0xfd,0xea, + 0x65,0x7a,0xc4,0xca,0xd6,0x3b,0x3a,0x41,0x69,0x54,0x95,0x86,0x78,0x39,0x89,0xde, + 0xb6,0x39,0xf7,0x0d,0xa9,0xc2,0xea,0x3b,0xc4,0x1c,0xd5,0xa0,0x22,0xfc,0xf1,0x5b, + 0xf0,0x96,0xa3,0x23,0xf0,0x65,0x4e,0xb9,0x83,0x47,0x7f,0x8c,0x62,0x3f,0x99,0x1d, + 0x11,0x83,0x7a,0x47,0x49,0x4a,0x13,0x40,0x3b,0x4d,0xf2,0x99,0x6c,0x77,0x82,0x71, + 0xbd,0x25,0x2b,0xeb,0x0d,0xa4,0x7b,0x05,0x23,0x39,0xd2,0x1a,0x82,0xf4,0x8e,0x14, + 0xf7,0x53,0x87,0xa8,0xf4,0xf6,0x8d,0xf4,0xca,0xaa,0xca,0xc1,0x11,0x1f,0x75,0xc0, + 0xb4,0xb8,0xb8,0x05,0x5e,0x16,0xec,0xd6,0x2f,0x27,0x3b,0x0d,0x30,0x6d,0x9e,0xec, + 0x1b,0x35,0x1b,0xf5,0xa7,0x6a,0xcd,0x23,0x6c,0xa3,0x2f,0x9b,0x1c,0xed,0x29,0x2d, + 0x57,0xd5,0xa0,0xa3,0x25,0x60,0x67,0x70,0x54,0x4a,0x51,0x55,0x6c,0xdb,0x53,0xf7, + 0x46,0x50,0x0b,0x09,0xac,0xe4,0x0e,0xcf,0xd8,0xfa,0x31,0x51,0xd0,0x34,0xf6,0xee, + 0x0d,0x7d,0x4a,0xc2,0x5e,0xe4,0xf4,0x88,0x3f,0x2c,0xf9,0xf9,0x79,0x84,0x47,0xca, + 0xd9,0xc5,0x73,0xc2,0xf9,0x67,0xf4,0x14,0xe8,0x24,0x33,0xe8,0xa9,0xa4,0x34,0xb1, + 0x8c,0x1f,0x33,0x7a,0x2c,0x57,0x5c,0xba,0xd2,0xab,0xa4,0x72,0x73,0x7f,0x12,0xef, + 0xd3,0x9b,0x73,0x30,0x6e,0xc9,0xe8,0x36,0x59,0xd5,0x79,0xf9,0x9e,0x73,0x34,0x0c, + 0x6a,0x6e,0xa9,0x0f,0x9c,0xd7,0xcc,0xb4,0x6f,0xee,0xbf,0xcb,0x42,0xdd,0xed,0x43, + 0x9d,0x97,0xe4,0x1b,0x05,0x30,0x73,0x66,0xde,0xce,0x09,0xac,0x92,0x65,0xde,0x8e, + 0xc0,0x72,0xff,0xec,0xc2,0x2b,0xda,0x50,0xf9,0xb3,0x24,0xe1,0xba,0x5a,0x6b,0x43, + 0x89,0x65,0xec,0x96,0x85,0xff,0x9e,0x71,0xd4,0x9b,0xfa,0x3b,0xfb,0xd6,0xb2,0x50, + 0x45,0xd2,0x9f,0x49,0x9e,0xdc,0x49,0x97,0xa7,0xa9,0xd2,0xa9,0xa9,0x26,0xa3,0xba, + 0x4a,0xa6,0xae,0xb6,0xbd,0xf7,0x6f,0x44,0x04,0x7c,0xdc,0x4c,0xe6,0x11,0x58,0xaf, + 0x07,0x2a,0x3b,0xbd,0xbc,0xaf,0x37,0x55,0xee,0x61,0x66,0x59,0xf8,0x85,0xc5,0xe8, + 0x96,0x2a,0x83,0xbf,0x0a,0xb1,0x37,0xd7,0x75,0xa9,0xcb,0xcd,0xd4,0xbe,0x77,0xa1, + 0x4d,0xd2,0xea,0xd6,0x33,0x75,0x46,0xc2,0x58,0xb0,0xe2,0xa4,0xa0,0x72,0x61,0xda, + 0xea,0x5c,0x51,0x95,0x70,0xd7,0x6c,0x11,0xae,0x24,0x56,0xae,0x37,0x9b,0xe2,0xbe, + 0x9b,0x3d,0xda,0x6c,0x04,0x56,0x1b,0xba,0xe5,0xe0,0xcd,0x10,0x22,0xb7,0x7d,0x28, + 0x61,0x65,0xbd,0x1c,0x28,0xb4,0x75,0xd1,0xd3,0xda,0x5e,0xfb,0xa9,0x49,0x21,0x69, + 0xa5,0x2d,0x26,0xc1,0x14,0xcc,0x20,0xaa,0x93,0xec,0x9e,0xb0,0x03,0xb2,0x5e,0x0a, + 0x11,0x42,0x22,0x4d,0x2f,0xba,0xaf,0x86,0x49,0x69,0xf0,0x11,0x2c,0x13,0x61,0x4b, + 0xc9,0xd3,0x36,0x77,0xb3,0x9d,0xed,0xd3,0x8c,0x33,0x87,0x65,0x1e,0x04,0xad,0xe0, + 0x3b,0x98,0x09,0x5c,0xc6,0x99,0x3a,0x95,0x8f,0x41,0xd6,0x7c,0xbd,0x1d,0x0c,0x93, + 0x1e,0x74,0x8d,0xee,0x8a,0xf2,0xa2,0x7e,0x82,0xce,0xbc,0xa5,0x26,0x50,0x6a,0x8e, + 0x3c,0x88,0x28,0x0f,0x49,0xd0,0xb9,0x7d,0xd2,0x65,0xf0,0xf9,0xfd,0x3c,0x7f,0x94, + 0x57,0x02,0x54,0x07,0xb6,0xc1,0x13,0x74,0x0d,0x93,0x66,0x5c,0xc8,0x83,0xd9,0x9e, + 0xc9,0x19,0x0d,0x7c,0xa3,0x03,0x35,0xa4,0x14,0x6c,0xca,0x84,0x95,0x87,0x51,0x78, + 0x0b,0x46,0x6b,0x1b,0x77,0x4c,0xed,0xd2,0xe4,0xf1,0xe9,0xd4,0x4a,0x69,0x83,0x3f, + 0x9f,0xa6,0x70,0x31,0x69,0x77,0x93,0xdb,0x54,0x16,0x4a,0x8d,0x59,0x2b,0xca,0xa4, + 0x30,0xa0,0x6c,0x82,0x93,0xff,0x95,0x96,0xe4,0xef,0x70,0xe5,0x8c,0x5b,0xbf,0xff, + 0x9f,0x41,0xff,0xfb,0xfe,0xdd,0xf1,0xef,0xb6,0xf9,0x6d,0xab,0xf7,0xdf,0xd9,0xb6, + 0x34,0x6e,0x7f,0x3f,0xb9,0x78,0x71,0xb7,0xf9,0x47,0xbd,0xd7,0x2c,0x31,0xd7,0x98, + 0x02,0x99,0x07,0x4f,0x27,0x44,0xeb,0xce,0x4f,0x95,0x84,0xf2,0x99,0x73,0xfe,0xc9, + 0x81,0x34,0x2f,0x9a,0x67,0x87,0xbd,0xc3,0x6a,0x4c,0x51,0x56,0x43,0xab,0x92,0x9f, + 0x9a,0x9c,0x2a,0xd5,0x1f,0x27,0xe4,0xee,0xe4,0x55,0x4d,0xfd,0x02,0x42,0x82,0x31, + 0x4b,0xa6,0xc6,0xbe,0xac,0x2b,0xf5,0x15,0xd3,0xaf,0x9d,0x1c,0x95,0x7b,0xd5,0xce, + 0x64,0xd9,0x5a,0x6a,0x3f,0xac,0x26,0xc9,0xa8,0xf8,0x42,0xd9,0x94,0x99,0xc2,0x64, + 0xe4,0x36,0x14,0x46,0x4e,0x65,0x97,0xc6,0x50,0xd2,0xf2,0x88,0x14,0x19,0x0d,0xff, + 0xcc,0x89,0x44,0x23,0xe5,0x44,0xf6,0x7a,0xea,0xe1,0x69,0x73,0xf5,0x34,0xe8,0x1e, + 0xc0,0x14,0x7c,0x7d,0x03,0xd9,0x66,0x74,0x4b,0x94,0x5b,0xdf,0x3c,0xe5,0xf2,0x85, + 0x57,0xdd,0xac,0xbc,0x6c,0x72,0x63,0x76,0x4b,0x92,0xe5,0x8d,0xba,0x15,0x61,0x62, + 0x66,0x1d,0xaf,0x31,0x23,0xb7,0xb1,0x11,0x60,0xea,0x74,0x40,0x75,0x52,0x4c,0x25, + 0xe4,0x29,0xaa,0x7f,0xd7,0xbe,0x3e,0x67,0x9c,0x0b,0x21,0x53,0x5f,0x15,0xb2,0xf9, + 0x94,0x78,0xfb,0x88,0x38,0x1d,0xc4,0xa2,0xef,0x74,0x1a,0x4d,0xa6,0xdd,0xf9,0xa5, + 0x4a,0xa8,0xfb,0xbb,0xe4,0xcc,0xc9,0x9a,0xa1,0xcc,0x96,0xfc,0x22,0x73,0x27,0x05, + 0xac,0x31,0x61,0x4b,0xb5,0x0d,0x7b,0x7d,0x40,0x6f,0x73,0x51,0xfa,0xff,0x14,0x8f, + 0xf4,0x18,0x94,0x79,0xac,0x1e,0xf9,0x5c,0xb7,0x7a,0xf6,0x63,0x7a,0xea,0x78,0x3b, + 0x6d,0x36,0x99,0xd0,0x9d,0x38,0x35,0xa7,0xf8,0x44,0x62,0x6d,0x85,0x04,0x61,0x2b, + 0x73,0xcd,0x6a,0x00,0x13,0xcf,0xdf,0xb1,0xfc,0xa5,0x4c,0xd2,0x4d,0x95,0x08,0x39, + 0x21,0x5f,0xe2,0x0f,0x4a,0x22,0xd4,0x3b,0x54,0xbe,0x4b,0xe1,0xd5,0xb5,0x35,0xbb, + 0xc9,0x2a,0x9c,0x5c,0xb1,0x50,0x17,0x70,0x1c,0x36,0x77,0x71,0xd4,0xc0,0x78,0x3d, + 0x5a,0xca,0x40,0x4a,0x23,0x08,0x8d,0x2a,0x53,0x5e,0x26,0x56,0xd1,0x1d,0x48,0xb4, + 0x08,0xca,0x63,0xa5,0xeb,0x5f,0x2a,0x61,0xf4,0x88,0xaa,0x73,0x3e,0xd7,0x4f,0x57, + 0x8d,0xa4,0x63,0x79,0x57,0x09,0xdd,0x17,0x02,0x60,0x33,0x79,0xd6,0x9b,0x73,0x96, + 0xc3,0x54,0x5e,0x2d,0xb1,0x8f,0x0f,0x97,0x74,0x47,0x0f,0x87,0x2d,0x7a,0x3d,0xc5, + 0x3d,0x8b,0x3a,0x78,0xf4,0x0c,0x77,0x52,0x4e,0x24,0xb5,0xd8,0xe5,0x4d,0x39,0xe5, + 0x3a,0x47,0xae,0x6a,0xca,0x37,0x91,0xd4,0xa5,0xf5,0xad,0x5b,0x2d,0xa7,0x44,0xa5, + 0x9c,0xf2,0x56,0x3b,0xa6,0x4f,0xe9,0x9c,0x86,0xfe,0xae,0x4e,0xd2,0xa6,0xfb,0x62, + 0x16,0x49,0x42,0xc7,0x08,0x94,0x4b,0xc9,0xec,0x43,0xb7,0x5f,0xae,0xfc,0xc7,0x0b, + 0x12,0x22,0x7b,0x52,0x73,0xd5,0x3a,0x54,0x9c,0x36,0xdc,0x12,0xe7,0x0d,0x99,0xdf, + 0x06,0x15,0x93,0x37,0xa7,0x58,0xd4,0x25,0x4d,0x87,0xad,0x83,0x2c,0x75,0x9e,0x4a, + 0xaf,0xc7,0x85,0x74,0x07,0xd2,0x42,0x89,0xd1,0x35,0x97,0xf0,0xd1,0x72,0x3a,0xe7, + 0xe4,0xf2,0x6b,0x73,0xbe,0x9c,0x33,0x6b,0xfc,0xa5,0x49,0xbd,0x4c,0x28,0x1b,0xad, + 0x6b,0x40,0xbe,0x8b,0x63,0x0e,0xe0,0xa8,0xb3,0x34,0x93,0xb6,0x8c,0x99,0x30,0xa4, + 0x9a,0xc1,0xf9,0xb5,0x42,0x1e,0x0f,0xa0,0x7a,0xb9,0xa0,0xb0,0x8d,0xf4,0x92,0xff, + 0x8e,0xf0,0x40,0xf9,0xf3,0x79,0x15,0x7b,0xc4,0x0a,0x38,0x5d,0xdf,0x5a,0x43,0xb2, + 0x0d,0xe4,0xb1,0x42,0xb8,0x5a,0x9a,0xda,0x54,0xd6,0xce,0x34,0x92,0x16,0xf2,0x66, + 0x82,0x26,0xbd,0x54,0x5b,0xf9,0xa4,0x4f,0x21,0x21,0xe8,0xc2,0x21,0x1b,0xf8,0xde, + 0xdb,0xa5,0x16,0x4c,0x67,0xb2,0xdb,0x2a,0xa5,0xce,0xdc,0xa9,0x89,0x0a,0x7c,0x6a, + 0x40,0x5a,0x25,0xb5,0xec,0xdc,0xca,0x42,0x4e,0xe8,0xdf,0x97,0x13,0x4d,0x1c,0x03, + 0x80,0xed,0x84,0x71,0xc8,0xa0,0xd6,0x82,0x57,0xd7,0x93,0xb5,0x17,0xfd,0xaf,0x56, + 0xf2,0x99,0x1c,0xbc,0xee,0x81,0x73,0x4e,0xc7,0x83,0xad,0x2b,0xff,0x56,0x47,0x6e, + 0x57,0xea,0xae,0x90,0x3a,0x83,0x7e,0xf0,0x17,0x83,0x2f,0xa6,0xe9,0xea,0xa9,0x04, + 0x3d,0x04,0x71,0x13,0xf7,0x17,0x94,0x68,0x5b,0x71,0xcd,0xb5,0xba,0x57,0xa1,0x0d, + 0x7e,0xc8,0x69,0x1d,0x0a,0x59,0xf5,0xa1,0x38,0x55,0xa2,0xab,0xbe,0xf7,0x89,0x6e, + 0x5e,0xd6,0x08,0xae,0xd0,0x63,0x30,0xa5,0x6b,0x2e,0x3b,0x08,0x94,0x41,0x03,0xb9, + 0x50,0x7c,0x0f,0x87,0x59,0x69,0x17,0x02,0x77,0xab,0xab,0x0d,0x0a,0x12,0xb2,0xba, + 0xa5,0xcf,0xc4,0xa3,0x7a,0xe2,0x7b,0x36,0xf5,0xbb,0xa7,0xb7,0x32,0x94,0x74,0xd1, + 0xdc,0x93,0x41,0x94,0xed,0x3e,0xab,0x8b,0x15,0x87,0x75,0xf6,0x70,0xbb,0x17,0x33, + 0x53,0xc7,0x72,0x94,0x01,0xa0,0x6e,0xa6,0xb9,0xb2,0xf9,0x20,0xea,0x75,0x65,0xf5, + 0x93,0xec,0xe0,0xc3,0x38,0xfb,0xa6,0x7c,0xf5,0xf3,0x8f,0x2a,0x52,0xf3,0x19,0xd5, + 0xe0,0xf8,0x58,0xec,0x01,0x29,0x92,0x53,0x81,0x94,0x2a,0xc7,0xec,0xff,0x00,0x05, + 0xd5,0xff,0xef,0x2a,0x59,0x00,0x00, }; constexpr size_t PF_CONSOLE_JS_GZ_LEN = sizeof(PF_CONSOLE_JS_GZ); // diff --git a/firmware/patternflow/src/web_update_index.h b/firmware/patternflow/src/web_update_index.h index 0b8b4ad6..f61bb907 100644 --- a/firmware/patternflow/src/web_update_index.h +++ b/firmware/patternflow/src/web_update_index.h @@ -27,103 +27,82 @@ const char WEB_UPDATE_HTML[] PROGMEM = R"HTML( - + Patternflow — Firmware update -
              -
              -

              Update

              …
              +
              +

              Update

              …
              +

              Drop a firmware .bin: the panel flashes itself over the network and restarts on the new build.

              -

              Drop a firmware .bin — the device flashes itself over the LAN and reboots on the new build.

              - - -
              - Linked build -
              - + + - Two steps -
              01

              Get a .bin: patternflow.work/update sends the latest release straight back to this page. Or bring your own — an arduino-cli export.

              -
              02

              Drop it below. Keep the device powered; it verifies, flashes, and reboots itself.

              - -
              This build requires arming first. On the device: hold K2 → NETWORK, then turn K4 → UPDATE.
              + -
              - Drop .bin here - Checking the panel… +
              + Drop a .bin here + Checking the panel…
              - + does the same; an explicit any-type accept is what reliably brings + up the file manager. The JS checks extension and size instead. --> +
              - + + +

              No file? patternflow.work/update sends the + latest release straight back to this page. Your own arduino-cli export works too. Keep the panel + powered: it checks, flashes and restarts by itself.

              + +
              -
              + Patternflow - Wi-Fi
              -

              Wi-Fi

              -
              +.s1 i+i,.s2 i+i+i,.s3 i+i+i+i{background:var(--ghost)} +.dym,.dym span+span{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.dym{margin-top:8px;padding:6px 6px 6px 12px} +#join{margin-top:12px}#join.ok{border-left-color:var(--ok)}#join.err{border-left-color:var(--bad)} +#join .big{display:inline-block;margin:6px 10px 6px 0;font:18px var(--mono);overflow-wrap:anywhere} +.seg{display:flex;gap:2px;max-width:360px;padding:2px;border:1px solid var(--rule);border-radius:9px;background:var(--cream)} +.seg label{flex:1;position:relative} +.seg input{position:absolute;opacity:0;margin:0} +.seg span{display:flex;align-items:center;justify-content:center;min-height:40px;border-radius:7px;color:var(--muted);font-weight:500;font-size:14px;cursor:pointer;transition:background .15s,color .15s} +.seg :checked+span{background:var(--panel);color:var(--ink);box-shadow:0 0 0 1px var(--rule),inset 0 -2px var(--led)} +.seg :focus-visible+span{outline:2px solid var(--led)} +.pf-offline #st,.pf-offline #list,.pf-offline #hsstate{opacity:.5} +@media(hover:hover){.btn.dan:hover{border-color:var(--bad)}summary:hover,.seg span:hover{color:var(--ink)}.scan button:hover .nm{text-decoration:underline}} + + +
              +

              Wi-Fi

              -
              - -

              Add a network

              -
              - - Network name + + + + +
              + - - +
              -
              - -
              - - -
              -
              -
              - - - - +
              + + +
              -
              - -

              Saved networks are tried in order starting from the boot slot, - wrapping around — so the device joins whichever one it can find, useful if it - moves between home, a studio and a venue. A new network is only stored; leave - switch now unticked and this page keeps working. Ticking it drops the - current connection immediately. On the panel's hotspot a network is tried at once, - and the panel shows the outcome on its screen as well as here: the address to open, - or why it could not join.

              + +

              Save stores it and this page keeps working; Switch now drops this connection to join it.

              +
              How saved networks are tried +

              In order from the boot slot, wrapping around, so the panel joins whichever it finds: home, studio, venue.

              Hotspot

              -

              -

              +

              -

              +

              The panel’s own network, patternflow-????: join it and open + http://192.168.4.1/, the same console anywhere. Phones stay on it though it has no internet. + Auto raises it about 15 s after the panel finds no Wi-Fi and drops it once it joins one.

              -
              - - -
              -
              - - +

              Mode

              +
              + + +
              -
              - + + +
              + +
              -
              -

              The panel as a network of its own: patternflow-????. - Join it from a phone or a laptop and open http://192.168.4.1/ — the - same console, anywhere. auto raises it about fifteen seconds after the panel - finds no network and drops it once one is joined; a network added above from the - hotspot is tried at once. The phone is told the network works, so it stays on it; - it has no internet through the panel.

              - -
              + + )HTML"; // GENERATED by firmware/toolchain/console_pages.py build — do not edit. -// gzip -9 of WIFI_INDEX_HTML (24284 bytes → 9034 bytes), served with Content-Encoding: gzip. +// gzip -9 of WIFI_INDEX_HTML (24463 bytes → 9067 bytes), served with Content-Encoding: gzip. static const uint8_t WIFI_INDEX_HTML_GZ[] PROGMEM = { - 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xb5,0x3c,0xdb,0x72,0xdb,0x48, - 0x76,0xef,0xfa,0x0a,0x88,0x93,0x08,0xc0,0x0a,0x84,0x44,0xc9,0x96,0x6d,0x40,0x90, - 0xe2,0xeb,0x8e,0x77,0xed,0xb1,0xcb,0xf2,0xd4,0x54,0x8d,0xe3,0xda,0x02,0x89,0x26, - 0xd1,0x16,0x08,0x60,0xd0,0xa0,0x68,0x2e,0xc5,0xaa,0x7c,0x44,0xbe,0x21,0xbf,0x90, - 0xf7,0x7c,0x4a,0xbe,0x24,0xe7,0x9c,0xee,0x06,0x1a,0x20,0xe9,0xf1,0x24,0x9b,0x99, - 0x2a,0x8b,0x6c,0xf4,0xe5,0xf4,0xb9,0xdf,0xc0,0xcb,0xc3,0xa4,0x98,0xd4,0xab,0x92, - 0x59,0x69,0x3d,0xcf,0xae,0x0e,0x2e,0xf1,0x8f,0x95,0xc5,0xf9,0x2c,0x1a,0xb0,0x7c, - 0x80,0x03,0x2c,0x4e,0xae,0x2e,0xe7,0xac,0x8e,0xad,0x49,0x1a,0x57,0x82,0xd5,0xd1, - 0x60,0x51,0x4f,0x87,0x8f,0xf1,0xa1,0x98,0x54,0xbc,0xac,0x2d,0x51,0x4d,0xa2,0xc1, - 0x49,0x39,0x1d,0x4e,0x8a,0x5c,0x14,0x19,0xf3,0xbf,0x88,0xeb,0x34,0x4a,0x4e,0xcf, - 0xc6,0xe7,0xe7,0x67,0x67,0x83,0xab,0xcb,0x13,0x39,0xf1,0x4a,0x2d,0xb8,0xe2,0x53, - 0xe7,0x70,0xc9,0xf3,0xa4,0x58,0xfa,0xef,0x5f,0xb9,0xce,0x74,0x91,0x4f,0x6a,0x5e, - 0xe4,0x8e,0xbb,0xbe,0x8b,0x2b,0xeb,0x97,0x48,0x3e,0xf3,0x7e,0x8e,0xec,0x93,0xb8, - 0xe4,0x27,0xa2,0x8e,0xeb,0x85,0xb0,0xbd,0x37,0xd1,0xa7,0xcf,0xde,0xdb,0xe8,0x8c, - 0x3d,0xf1,0x6e,0xbc,0x5f,0xbd,0xf7,0xd1,0x2f,0xb0,0x3c,0x5a,0xe3,0x63,0x16,0xd8, - 0x19,0xbf,0x63,0xb6,0x97,0xf0,0xaa,0x5e,0x05,0x87,0x23,0xef,0x2e,0xc8,0x17,0x59, - 0xe6,0xcd,0x58,0x1d,0xfc,0xd9,0xe3,0xf9,0x34,0xe3,0xb3,0xb4,0x0e,0x7e,0x5a,0xcc, - 0xc7,0xac,0xf2,0xd2,0x22,0x4b,0x82,0x77,0xe3,0x2f,0x6c,0x52,0x7b,0x22,0x5e,0x05, - 0x0d,0x04,0xb5,0x77,0xeb,0x31,0x77,0xcd,0x8e,0x8e,0x1c,0xe6,0xd7,0xec,0x6b,0xfd, - 0xbc,0xc8,0x6b,0x96,0xd7,0x51,0xed,0x6e,0xbc,0xf1,0x42,0x18,0x53,0xc7,0x5e,0xe9, - 0xae,0xf5,0x37,0x6b,0x0a,0xc0,0x8f,0xfd,0x84,0x8b,0x78,0x9c,0xb1,0x24,0x3a,0x1c, - 0x6d,0xcc,0x6f,0xa7,0x61,0xe9,0xd7,0x29,0xcb,0x9d,0xa9,0x37,0x75,0xc3,0x8a,0xd5, - 0x8b,0x2a,0xb7,0xca,0x8d,0x57,0x16,0x59,0xd6,0xee,0x28,0xbc,0xb9,0x37,0xf1,0x0a, - 0x89,0x85,0xda,0x9b,0x7a,0xb3,0x68,0x14,0x36,0x27,0x7c,0x80,0x13,0x66,0x47,0x47, - 0x87,0x53,0x80,0x6d,0x1a,0x8d,0xbc,0x49,0xc6,0xe2,0xea,0x23,0x9f,0xb3,0x62,0x51, - 0x3b,0xb5,0xeb,0x39,0xc2,0x9f,0xc4,0x59,0x76,0x2d,0x1c,0x37,0xf8,0xb3,0x23,0x5c, - 0x57,0x9d,0xa8,0x77,0x4f,0xdc,0xf5,0xc4,0x49,0x3c,0xc4,0x0a,0xdc,0xa5,0x19,0x66, - 0x38,0x4c,0xa8,0x62,0xee,0x46,0xad,0xf9,0xab,0xf7,0x57,0xd7,0xdd,0x34,0x27,0xff, - 0x15,0x4e,0x9e,0x46,0xa7,0x61,0xef,0xc4,0x10,0xa0,0x71,0xea,0x08,0x58,0x42,0x8f, - 0x7d,0xf0,0xe6,0xb0,0xae,0x38,0x3a,0x2a,0xfc,0x29,0xaf,0x44,0x1d,0x45,0x80,0x88, - 0x6b,0x58,0x1e,0x00,0xf0,0xea,0xda,0x40,0xae,0xa2,0x0c,0x0c,0x92,0xcf,0xb6,0x77, - 0xde,0x78,0xb0,0x69,0x3b,0x27,0x77,0xd7,0xf3,0x28,0x0f,0xa7,0xf7,0xf7,0xb0,0xd5, - 0xc6,0xcb,0x8b,0x65,0xf0,0x61,0x03,0x73,0x88,0x2d,0xda,0x69,0x13,0xb8,0xc9,0xd1, - 0xd1,0x1b,0xbf,0x5c,0x88,0x14,0xbe,0x84,0x37,0xd7,0xf0,0x75,0xe2,0xdc,0xb8,0xc1, - 0xaf,0xd7,0xbf,0xfa,0xb0,0x0a,0xe0,0xf8,0x35,0x7a,0xef,0x23,0xd2,0x9d,0x9f,0xbd, - 0xb7,0xde,0x0b,0xd8,0x6c,0x19,0xd7,0x93,0xf4,0xa6,0xb7,0xd3,0xdc,0x5d,0xbf,0xf7, - 0xe5,0xf6,0x00,0xf7,0xaf,0x3e,0x40,0xe3,0xbc,0x8d,0xde,0xc6,0x75,0xea,0xcf,0x39, - 0x3c,0xf6,0xde,0xba,0xb4,0x94,0xd7,0xaf,0x8a,0xea,0x05,0xbb,0xe3,0x13,0xd6,0x2e, - 0x06,0xfa,0x15,0x51,0x71,0x7f,0xbf,0xde,0x68,0x42,0xe7,0x6c,0x69,0xbd,0xaf,0x8a, - 0x39,0x17,0xac,0x25,0xc7,0xca,0xcb,0x25,0xa1,0xd3,0x16,0xa4,0x33,0x76,0xde,0x12, - 0x46,0xb8,0x6b,0x01,0xe4,0x76,0x0a,0x7f,0xbc,0xe0,0x59,0x72,0x74,0x24,0xe4,0x87, - 0x28,0x52,0x23,0x2e,0xa0,0x3f,0xf5,0x11,0x9d,0x8e,0xeb,0xad,0x90,0xe2,0x1b,0x37, - 0x34,0xa8,0x61,0xe0,0x58,0x4f,0x0b,0x73,0xe7,0x65,0x55,0x15,0x95,0x63,0xd7,0x72, - 0x92,0x8d,0x17,0x29,0x7c,0xf5,0xed,0xfe,0xfe,0x09,0x7b,0x00,0xbb,0x6c,0x36,0x2d, - 0xdb,0xfd,0xd9,0x59,0x20,0x4b,0xaa,0xab,0x4c,0x19,0xa0,0x8b,0x46,0x7a,0xdc,0x55, - 0xb9,0x6b,0x94,0xea,0xca,0x2f,0x6e,0xdd,0x3a,0xad,0x8a,0xa5,0x25,0x0f,0xaa,0x14, - 0x1e,0x1b,0xae,0x27,0xee,0x40,0xc9,0xba,0xae,0xe8,0x0f,0x10,0xa5,0x02,0x85,0x81, - 0x60,0x6e,0x0c,0x9e,0x7b,0x81,0xf7,0x87,0x1d,0xe1,0xdf,0x1b,0x90,0xf3,0x72,0x2a, - 0x69,0x14,0x89,0xf0,0x8d,0x3f,0x2d,0xaa,0x97,0x31,0x80,0xd1,0x1c,0x3e,0x05,0xfe, - 0x84,0x99,0x08,0xf8,0xc6,0x75,0xdc,0x46,0xdf,0x1c,0x48,0xc5,0x95,0xc7,0x73,0x16, - 0x0d,0xee,0x38,0x5b,0x96,0x45,0x55,0x0f,0xac,0x89,0x92,0xe9,0xc1,0x92,0x27,0x35, - 0x28,0x2a,0x22,0xe0,0x90,0xbe,0x80,0xa6,0xe0,0x35,0x8f,0xb3,0xa1,0x00,0x59,0x62, - 0xd1,0x08,0xb5,0x5c,0xcd,0xeb,0x8c,0x5d,0xbd,0x8f,0xeb,0x9a,0x55,0xa0,0x47,0xe0, - 0x6a,0x43,0xeb,0x17,0x3e,0x7c,0xc5,0x2f,0x4f,0xe4,0x23,0x50,0x84,0xf5,0x0a,0xff, - 0x9e,0xfc,0xc9,0x7a,0x11,0x57,0xb7,0x16,0xcf,0x45,0x5d,0x2d,0xe6,0x70,0x86,0x55, - 0x17,0xb7,0x2c,0x17,0xd6,0x7f,0xff,0xdb,0xbf,0x5b,0x82,0x31,0xab,0x94,0xbb,0x88, - 0xbf,0x81,0x86,0x63,0x5f,0xfd,0xd4,0x82,0xbb,0x58,0x80,0x49,0x2b,0x2f,0x6a,0xe6, - 0x5b,0x7f,0x3a,0x39,0x08,0xaa,0xa2,0xa8,0xd7,0xc3,0xe1,0xa4,0x62,0xf1,0x3c,0xf8, - 0xe1,0xf4,0xf9,0xe9,0xb3,0xd3,0x27,0xe1,0x70,0xc8,0xf3,0xdb,0xe0,0x87,0x97,0x2f, - 0x5e,0x3e,0x7a,0xf1,0x0c,0xbe,0xcd,0x17,0x35,0x4b,0x82,0x1f,0x1e,0x3f,0x7d,0x7c, - 0xf6,0xe8,0x0c,0xbe,0x4f,0x63,0x9e,0xd7,0xc1,0x0f,0x0f,0x9f,0x3e,0x7c,0xf8,0xe0, - 0x22,0x3c,0x18,0x0e,0xab,0x45,0xc6,0x82,0x1f,0xce,0x1e,0x9c,0x8d,0x46,0x8f,0x43, - 0xf9,0x75,0x28,0x8a,0x29,0xcc,0x19,0x3d,0x1b,0x3d,0x19,0x3d,0x80,0xb1,0x0c,0x77, - 0x78,0xf5,0xea,0xe1,0xf3,0xb3,0x97,0xf0,0xad,0x80,0xed,0x1f,0x3e,0x7a,0xf6,0xf8, - 0xd1,0x2b,0xf8,0x52,0xc6,0x39,0xcb,0x60,0xea,0xf9,0x68,0x34,0x3a,0xc5,0xed,0x44, - 0x9c,0x8b,0xc0,0x7e,0x0d,0x78,0xab,0x6c,0x6f,0xc1,0xe9,0xfb,0x50,0xb0,0x8a,0x4f, - 0x3d,0xb1,0x12,0x35,0x9b,0x0f,0x17,0xdc,0x6b,0x07,0x71,0xc9,0xbc,0xc8,0x8b,0xc0, - 0xfe,0x0b,0xab,0x9f,0x55,0x00,0x9c,0xb0,0xde,0xc2,0x77,0x5a,0x8b,0x0f,0x44,0x19, - 0x4f,0x98,0x77,0xf3,0x0a,0x07,0x87,0x1f,0xd8,0x6c,0x91,0xc5,0x95,0xf7,0x96,0xe5, - 0x59,0xe1,0x35,0x8f,0x37,0x07,0x7f,0x5a,0x8f,0x8b,0xaf,0x43,0xc1,0xff,0xce,0xf3, - 0x59,0x30,0x2e,0xaa,0x84,0x55,0x43,0x18,0xd9,0x1c,0x7c,0x4a,0x79,0x92,0xb0,0xfc, - 0xf3,0x1a,0x54,0x6c,0x99,0x81,0x02,0xcf,0x8b,0x9c,0x1d,0xf2,0x39,0xd2,0x37,0xce, - 0xeb,0xcd,0xc1,0xb8,0x48,0x56,0xeb,0x79,0x5c,0xcd,0x78,0x1e,0x9c,0x86,0xe3,0x78, - 0x72,0x3b,0xab,0x8a,0x45,0x9e,0x04,0x20,0x71,0x8e,0x42,0xae,0x1b,0x4e,0x8a,0xac, - 0xa8,0xd4,0x10,0xe0,0xd7,0x0d,0xa7,0xc0,0x19,0x80,0xcb,0x39,0xcf,0x56,0x6a,0x18, - 0xef,0xe4,0x86,0x07,0x19,0xcf,0xd9,0x30,0x65,0x64,0x43,0x46,0xfe,0xc3,0x70,0xb8, - 0x64,0xe3,0x5b,0x0e,0x73,0x71,0x81,0x98,0x03,0xc9,0x52,0x84,0x11,0xce,0x06,0xe6, - 0xe1,0xb1,0x60,0xc9,0xe6,0xc0,0x5f,0x56,0x71,0x09,0x40,0x7c,0x95,0xac,0x15,0x5c, - 0x3c,0x3e,0x2d,0xbf,0x86,0x1a,0x28,0x2b,0x5e,0xd4,0x45,0x58,0xc6,0x49,0x82,0x0b, - 0xcf,0xcf,0xca,0xaf,0xd6,0x19,0x3c,0xb7,0x2e,0x1e,0x94,0x70,0x41,0x34,0xbb,0xac, - 0x6a,0xae,0x37,0xcd,0xd8,0xd7,0x10,0x36,0x9e,0xe5,0x43,0x0e,0xc8,0x16,0xc1,0x84, - 0x21,0x29,0xc2,0x59,0x5c,0x06,0x8f,0x61,0x53,0xb5,0x0d,0x20,0xa7,0xae,0x8b,0x79, - 0x30,0x82,0xdd,0xc2,0x83,0x06,0x61,0x72,0x0c,0xf6,0x06,0xe3,0xcc,0x13,0x4b,0x5e, - 0x0c,0x39,0xc2,0x05,0x20,0x13,0xe0,0x36,0x09,0xdf,0x23,0x58,0xa4,0xae,0x88,0x1f, - 0xb7,0x90,0x06,0xfc,0xe2,0x86,0x6a,0xd3,0x2a,0x4e,0x38,0x68,0xcc,0x11,0xc1,0x3a, - 0x5a,0x4b,0x34,0xf0,0xbf,0xb3,0x60,0xf4,0x10,0x96,0xd2,0xd7,0xa5,0xdc,0xea,0xe2, - 0xf4,0xb4,0xb9,0x73,0x88,0xf7,0x08,0x46,0x70,0xaa,0x58,0x8c,0xd7,0xdb,0xc8,0x46, - 0xd2,0x2b,0x22,0xc8,0xcd,0x60,0xff,0x0e,0x91,0x88,0xcd,0xdd,0x10,0xf5,0xc6,0x90, - 0xd0,0x11,0x54,0x78,0xc8,0xe6,0x40,0x30,0xd2,0x04,0x8a,0xe4,0x43,0x34,0x31,0x67, - 0x17,0x04,0xdc,0xd9,0xba,0xb7,0x5f,0x1f,0xb8,0x8c,0xa1,0x48,0x0e,0x91,0xe5,0x90, - 0x12,0xfe,0xe9,0x13,0x36,0x97,0x27,0xd4,0x15,0x10,0x1f,0x04,0x74,0x1e,0x2c,0xca, - 0x92,0x55,0x13,0x20,0x6b,0x78,0x60,0x82,0x43,0x52,0xe8,0xb6,0x24,0x3d,0xb5,0x1e, - 0xe3,0x99,0x8b,0x6c,0x9d,0x71,0x01,0x67,0xa2,0x56,0x20,0xd6,0x6c,0x31,0xa0,0x09, - 0x7e,0xaa,0x31,0x89,0xa0,0xee,0xa2,0x0d,0x49,0x2b,0x10,0x28,0xe3,0xdf,0xc5,0x05, - 0xa3,0xd3,0x96,0x0d,0x82,0x27,0xc8,0x4c,0xdf,0xc7,0x02,0xf2,0x18,0x13,0xe7,0xe7, - 0x78,0x85,0x8c,0x5b,0x7e,0xfe,0x7f,0xa0,0x10,0x98,0x49,0xc5,0xf5,0xc8,0xd4,0x40, - 0xf0,0x7c,0xbe,0x96,0xc4,0x37,0x1e,0x9d,0x86,0xc5,0x1d,0xab,0x50,0xa3,0x06,0x52, - 0x9e,0x25,0xda,0x9b,0x41,0x96,0x65,0xbc,0x14,0x5c,0x84,0xcb,0x14,0xee,0x4b,0x14, - 0x42,0x74,0xa2,0x58,0x85,0x07,0xdf,0x01,0xdb,0x19,0x9d,0x5c,0xc7,0xb3,0xef,0xb9, - 0x08,0xe2,0x6f,0x8b,0x15,0x2e,0x80,0x15,0x0e,0xf6,0xf2,0x82,0x46,0x37,0xe2,0xf5, - 0x02,0x25,0x86,0xb0,0xbd,0x85,0x66,0xb0,0x88,0x0d,0x25,0x94,0xdc,0x9c,0xf5,0xb0, - 0x06,0x53,0x40,0x67,0x2d,0x80,0x4a,0x12,0xe9,0x01,0xcf,0x53,0xd0,0xa3,0x75,0x38, - 0x59,0x54,0x02,0x66,0x95,0x05,0x27,0x4a,0x97,0x85,0xe0,0xc8,0xe7,0x41,0xc5,0xb2, - 0xb8,0x06,0x87,0x57,0xaf,0xf2,0x13,0x96,0xad,0xbf,0x41,0x16,0xc5,0xa9,0x86,0x4c, - 0x13,0x5b,0x1e,0xec,0x01,0x99,0x94,0x43,0xb8,0x0d,0xb3,0xbe,0x31,0x6a,0x2b,0x62, - 0xf5,0xf6,0xf4,0x20,0x45,0xba,0xad,0xd5,0x1a,0xf3,0x6c,0xd2,0x1b,0xfd,0x81,0xcd, - 0x01,0x22,0xb3,0x55,0xd1,0x9a,0xc7,0x67,0x15,0x4f,0x5a,0x86,0x6e,0x95,0xe7,0xf9, - 0x63,0xe2,0xa3,0x2c,0x1e,0xb3,0xcc,0xf3,0xb3,0x71,0xd6,0x48,0xc5,0x38,0x2b,0x26, - 0xb7,0x3d,0xb2,0x87,0xdf,0x96,0x52,0x62,0x71,0x9e,0x97,0x0b,0xad,0xfa,0x46,0xa7, - 0xa7,0xff,0x1c,0x76,0x10,0xff,0x1d,0x1c,0x73,0x6e,0x20,0x04,0x14,0xa6,0xf5,0x84, - 0x24,0xae,0xaf,0x35,0xc9,0x94,0xee,0x30,0x35,0x7f,0x0c,0xf3,0x0a,0xdc,0x60,0x5a, - 0x4c,0x16,0x62,0x0d,0xae,0x1a,0x1a,0x24,0x49,0xc3,0x3d,0x18,0x07,0xce,0x8f,0x49, - 0x27,0x8a,0xae,0xfe,0xd0,0x26,0x63,0x87,0x1e,0x31,0x95,0xa7,0x41,0xdc,0xb2,0xe2, - 0xf0,0x64,0xb5,0xde,0xba,0x1a,0xdd,0xc3,0x3c,0x57,0x99,0xd5,0x3d,0x57,0xa3,0xe9, - 0x07,0xfb,0x99,0x0a,0x71,0x38,0xba,0xd0,0x1a,0xda,0x50,0x46,0x5d,0x38,0x34,0xa3, - 0x7d,0xcb,0x3c,0xed,0x40,0xc6,0x24,0x65,0x93,0xdb,0x6d,0x54,0x5c,0xec,0x46,0xc5, - 0xef,0xb2,0x93,0xde,0xd1,0x32,0xd9,0x08,0x4d,0xfa,0x06,0xbd,0xc0,0x0f,0x4c,0x2c, - 0xb2,0xda,0x42,0x22,0x09,0xcf,0x9a,0xf2,0x0c,0x80,0xb0,0xc6,0x2b,0xeb,0xfd,0x2b, - 0x1f,0xc2,0x4d,0x08,0x08,0xbe,0xa2,0x67,0x48,0x8e,0x1f,0x3a,0xa3,0x55,0x91,0xc1, - 0xe7,0xb8,0xb6,0x26,0xf1,0x02,0x5c,0x07,0x1c,0x9f,0x93,0x33,0xe8,0xcf,0xc5,0xcc, - 0xb4,0x69,0x24,0x14,0xdf,0xa9,0x95,0x51,0xcf,0x6a,0x8f,0xe5,0x62,0xdf,0x1d,0x60, - 0x7f,0xf0,0xad,0x41,0xff,0xac,0xfb,0xea,0x48,0x3f,0x62,0x55,0xb5,0xde,0x46,0xe7, - 0x0f,0x5f,0x40,0x23,0x75,0x20,0x33,0x29,0x89,0x60,0x5a,0x34,0xf2,0x07,0xf5,0xcb, - 0x41,0x4f,0xbc,0xfa,0x6e,0x57,0xab,0x0f,0x1e,0x4a,0xbb,0x42,0x70,0x40,0xcc,0xb1, - 0x4b,0xef,0x90,0x52,0x95,0x13,0xf0,0x12,0x7b,0x59,0x83,0xa6,0x58,0xbf,0xe3,0x8f, - 0xb4,0x0e,0x83,0x5e,0x10,0xaf,0xfb,0x32,0xad,0x9f,0xf8,0x63,0x3e,0x6b,0x38,0x8d, - 0xe7,0x74,0x09,0xa9,0xa5,0x94,0x0e,0xba,0x40,0xf4,0x9c,0x4a,0xab,0x61,0x9d,0xee, - 0x25,0xa8,0x81,0x0d,0xbc,0x6d,0xb8,0x84,0x1b,0x0c,0xc7,0x20,0x63,0xb7,0x01,0xfd, - 0x0b,0x2e,0x50,0x86,0xa6,0x15,0x42,0x87,0xf5,0x37,0x18,0x56,0x9b,0x64,0x79,0xf6, - 0x63,0x3c,0x12,0x0e,0xed,0xa2,0xf6,0xc1,0x43,0x54,0xc8,0xb0,0x51,0x65,0x12,0xf5, - 0xdc,0x20,0x6a,0x4b,0xe5,0xdf,0x71,0x5c,0xdc,0xef,0xb2,0xcd,0xbb,0xfd,0x86,0xcd, - 0x41,0x17,0xab,0x0d,0x9f,0x82,0x11,0xf7,0xc7,0x18,0x18,0xed,0xa0,0xa2,0xd2,0xef, - 0xbb,0xd6,0x09,0x96,0x81,0x63,0x68,0x2a,0xf9,0x9e,0x45,0xf9,0x5f,0x29,0xfd,0x83, - 0xbe,0xd6,0xff,0xc7,0x28,0xfd,0x83,0x1d,0x5a,0x5f,0xa9,0x3e,0x70,0x6f,0x8b,0x3c, - 0x41,0x25,0xdc,0x03,0x65,0xfb,0x84,0x7f,0x90,0x85,0xd7,0xca,0x78,0x1b,0x84,0x3f, - 0x6c,0xe8,0xfd,0x59,0x5a,0x88,0xfa,0x7f,0xe3,0x4c,0xfe,0x83,0xbd,0x96,0x73,0x25, - 0x76,0x1a,0xa4,0x3f,0x7e,0x93,0xaa,0x58,0xee,0x34,0x21,0xf2,0x91,0xb2,0x05,0xdb, - 0x7e,0x2e,0xd9,0x84,0x5f,0x50,0xc1,0xa3,0xc6,0x4f,0x8b,0x5a,0x94,0x45,0x6d,0x0b, - 0xcc,0xa8,0xe6,0xc0,0x28,0x96,0x98,0xc4,0xb9,0x35,0xc5,0x0b,0x7a,0x96,0x00,0x6b, - 0x90,0xcf,0x98,0xa8,0x2d,0x4a,0xa1,0x05,0x56,0x6c,0xe1,0xd6,0x68,0x2d,0xe2,0x52, - 0x1a,0x05,0x9a,0x0e,0x71,0x41,0x13,0x4b,0x6c,0xd4,0x98,0xf6,0x20,0x25,0x00,0xdf, - 0x1d,0x36,0x98,0x1e,0xb9,0xde,0xf3,0x71,0x13,0x42,0xf4,0x90,0xaf,0x70,0x7f,0xba, - 0xcd,0x7a,0x46,0x54,0x96,0xb1,0x69,0xdd,0x05,0x4a,0xe2,0xda,0xc2,0x38,0x60,0x07, - 0x5e,0x71,0x22,0x6c,0x5f,0x3b,0x3e,0xa8,0x34,0x17,0xee,0x16,0xe4,0x75,0x3a,0x9c, - 0xa4,0x3c,0x4b,0x9c,0xfc,0xf8,0x91,0xdb,0x89,0xf3,0x61,0xfe,0x38,0xae,0xc4,0xfe, - 0xb0,0x08,0x07,0x86,0x2c,0x97,0x7e,0xe4,0x59,0x1b,0xd5,0x2a,0xda,0xe3,0x62,0x8b, - 0x2b,0xa5,0x70,0xde,0x3e,0x7e,0x00,0xea,0x61,0x4b,0x92,0x75,0x98,0x2c,0x17,0x1d, - 0xf3,0x75,0xaa,0x0d,0xc1,0x3f,0x6f,0x9a,0xc1,0x76,0xf8,0x71,0x77,0xb8,0x7d,0x80, - 0xca,0x07,0x2f,0x3a,0xb2,0x78,0x40,0x84,0x95,0xb7,0xf3,0x7c,0x71,0x66,0x99,0xb7, - 0x1d,0xe6,0xc7,0x67,0x2e,0x8c,0x9e,0xf7,0x47,0xcf,0x71,0xf4,0x01,0xc0,0xbd,0x05, - 0x62,0x6b,0xcc,0x8b,0x8a,0x79,0xe0,0x96,0xf0,0x52,0x73,0xc2,0x5e,0xe2,0xb5,0x61, - 0xe8,0x77,0x18,0x1f,0x92,0x4b,0xa2,0x6e,0x02,0x4a,0xa0,0x8a,0x29,0x02,0x81,0x3d, - 0x59,0x85,0x46,0x44,0x1d,0x6c,0xda,0x8d,0x8b,0xfd,0x2e,0x13,0x2f,0xbb,0x74,0x23, - 0x5a,0x61,0x44,0x17,0x50,0x58,0xb7,0x87,0x4d,0x1f,0x68,0x7f,0xa2,0x77,0x48,0xa3, - 0x89,0x1f,0xca,0x80,0x64,0x9f,0x82,0xdd,0x91,0xba,0x38,0xfb,0x6e,0x4f,0x4a,0xc1, - 0xad,0x71,0xba,0xcd,0xbe,0x20,0xdc,0x37,0x73,0x60,0x5c,0xed,0xcb,0x09,0xeb,0x96, - 0xb1,0x12,0x65,0x9d,0x57,0x56,0x56,0x14,0xb7,0xa1,0x55,0x80,0xbf,0x00,0x32,0xbc, - 0x98,0xa4,0x20,0xec,0x15,0x63,0xb9,0xd4,0x04,0xbc,0xb6,0x62,0xb0,0xe4,0x16,0xd0, - 0x68,0x29,0x48,0xb8,0xff,0x65,0xce,0x12,0x1e,0x3b,0x2a,0xe0,0x0b,0x26,0x05,0xd6, - 0x5c,0xdc,0x75,0x47,0xbe,0x1b,0x37,0xeb,0x4c,0x0a,0x29,0x66,0x71,0x20,0x00,0x0b, - 0xe2,0x29,0x2c,0xf1,0x88,0x1a,0xcd,0x17,0x03,0x72,0x3d,0xa6,0x9c,0x14,0xa9,0x02, - 0xe5,0xd8,0x5a,0xa5,0x44,0x83,0xc1,0x00,0x70,0xaa,0x83,0xcc,0x78,0x0c,0x38,0x04, - 0xd2,0x85,0x3c,0xc7,0x7c,0xfc,0x10,0x91,0x61,0x0d,0x51,0xdd,0x6d,0x0e,0xb0,0x50, - 0x44,0x9e,0xe3,0x74,0x8a,0x4c,0x60,0xfd,0x20,0x6a,0x6f,0x6b,0x0c,0xb3,0x20,0xdb, - 0xa3,0xa9,0xa0,0x8a,0xcd,0xba,0xc0,0x30,0xbb,0x5e,0x05,0xe4,0x7c,0x5c,0x9e,0xc8, - 0x1c,0xea,0xe5,0x89,0xac,0x38,0x61,0x02,0xef,0xea,0x32,0xe1,0x77,0xd6,0x24,0x8b, - 0x85,0x88,0x06,0xc8,0x1e,0xba,0x20,0xc5,0xaa,0xab,0x4b,0x08,0xd2,0x73,0xfd,0x2c, - 0x29,0x6a,0xaa,0x32,0xc1,0xd0,0xd5,0x65,0x3a,0xba,0x52,0xd9,0x59,0xf8,0xd4,0x99, - 0x26,0x16,0xe3,0x81,0xc5,0x13,0xf8,0x00,0xd3,0x87,0x7a,0xfe,0x89,0xda,0xf1,0xe0, - 0xe0,0x52,0x65,0x91,0xe4,0x9c,0xf8,0x8e,0x25,0x03,0x4b,0x26,0x26,0xae,0x0e,0x2c, - 0xeb,0x32,0x3d,0xbb,0xba,0xc1,0x41,0x70,0xdf,0x6b,0x70,0xc5,0x6e,0x05,0x2c,0x3d, - 0xa3,0x27,0x8b,0x8c,0x96,0xe0,0x75,0x11,0x8e,0x45,0x46,0xa3,0xa5,0x3e,0x17,0x1d, - 0x34,0x79,0xf0,0x04,0xef,0x70,0x79,0x52,0xd2,0x73,0xe3,0x72,0xe0,0x6b,0x0f,0x9a, - 0x2d,0xf0,0x0b,0x4c,0x82,0xc7,0x57,0x88,0x16,0x09,0x53,0x1f,0x3c,0x74,0x86,0xe0, - 0x7b,0x1f,0xc0,0x67,0x30,0xac,0xe1,0x6b,0xc0,0xa3,0xa0,0x19,0x33,0xcd,0x72,0xd9, - 0xe0,0xea,0x63,0xb5,0x92,0xd6,0x05,0xf9,0xb2,0x2c,0x96,0x20,0x15,0x8b,0xf2,0xf2, - 0x84,0xe6,0xd1,0x0a,0xe9,0x37,0x35,0x07,0x11,0x72,0x69,0xa8,0x0f,0xb8,0x0a,0x31, - 0x07,0x16,0x51,0x0f,0x2e,0xd2,0x8d,0x55,0x06,0x38,0x1f,0x56,0x48,0x06,0x6c,0xe8, - 0xa0,0x5d,0x89,0x81,0x85,0xb5,0x47,0x38,0x83,0x1e,0x0f,0xda,0x8b,0x01,0x9a,0x07, - 0x84,0x6c,0x0b,0xbf,0x5a,0x65,0xc5,0xa6,0xac,0x62,0xf9,0x84,0x5d,0x9e,0xc8,0xb9, - 0x7f,0x7c,0xdf,0x8a,0xc9,0x9b,0x7c,0xa0,0xbf,0xe6,0x3e,0x0a,0xd5,0x7b,0x28,0x82, - 0xb3,0x4d,0x8a,0x6c,0x11,0xf6,0xea,0xa6,0x06,0x81,0x4b,0x10,0x95,0x28,0xd3,0xb2, - 0x9a,0xe0,0x5b,0xf2,0x1c,0xb4,0xdb,0x24,0x6e,0x14,0xea,0x81,0xc4,0xb1,0x5c,0x93, - 0x47,0x51,0xe0,0x68,0x9e,0xc4,0x22,0x0d,0x61,0x5f,0x9a,0xb2,0xa8,0x2a,0x2c,0x1b, - 0x08,0x26,0x04,0x91,0x5a,0x60,0x65,0xc0,0x12,0x4b,0x5e,0x43,0xb8,0x99,0x58,0x58, - 0xe4,0xf4,0x89,0x81,0xf6,0x72,0x06,0x28,0x87,0x81,0x66,0x87,0xa7,0x49,0x02,0x7a, - 0xa7,0xcf,0x0f,0x98,0x79,0xa1,0xa9,0x53,0x4d,0x1f,0xbc,0x38,0x31,0x3d,0x68,0x99, - 0x71,0xf1,0xd5,0xe4,0x2a,0x7a,0xde,0xdc,0x38,0x1b,0x67,0x83,0xab,0x9f,0x14,0xff, - 0x13,0xc4,0xe4,0xea,0x4a,0xe7,0x45,0xdf,0x05,0x3d,0x15,0x40,0x07,0x53,0x8c,0x4e, - 0x3b,0x80,0x88,0x68,0x2a,0xc1,0x19,0x83,0xe6,0xb4,0x56,0x5e,0x76,0x10,0x14,0x35, - 0xd9,0x2e,0x5a,0xca,0x71,0x05,0x63,0x8f,0x25,0x34,0x95,0xe4,0xad,0x9a,0x8d,0x0d, - 0x19,0x00,0xcc,0x26,0xcd,0x25,0xa8,0x38,0x64,0xb0,0x3e,0x4d,0x26,0x3f,0x4e,0x82, - 0x88,0x73,0x55,0x01,0x49,0x7e,0x86,0x00,0x22,0x63,0xf9,0xac,0x4e,0xa3,0xc1,0xf9, - 0xd9,0xc0,0xaa,0xd8,0x6f,0x0b,0x5e,0x11,0x65,0x44,0x8d,0x2c,0xc8,0xf2,0x81,0xda, - 0xc6,0xa2,0x14,0xff,0xa4,0x98,0x97,0x19,0xab,0x61,0x3d,0x28,0xc0,0x81,0x1c,0x8a, - 0x4b,0x5e,0x83,0xa5,0xfb,0x3b,0x43,0x16,0xca,0x99,0x1a,0x2d,0x80,0xf4,0x93,0x5a, - 0xcd,0x13,0x25,0xcb,0x32,0xca,0x30,0x00,0x99,0xe2,0x4c,0xb0,0x41,0x03,0x5d,0x12, - 0xe3,0x62,0xa1,0x00,0xc4,0x03,0x91,0x37,0xd5,0x60,0x3b,0xab,0xe5,0x65,0xb4,0x01, - 0x12,0x71,0xc9,0x6a,0xde,0xe0,0xed,0x05,0x58,0xc7,0x55,0xb1,0xb0,0xe6,0x0c,0x34, - 0xe4,0x51,0x16,0xff,0xb6,0x28,0xc2,0xcb,0xb1,0x9e,0x46,0x9b,0x8e,0xaf,0x8e,0x2a, - 0x1a,0xbf,0x6e,0xae,0xa4,0x29,0xb4,0x4d,0x14,0x58,0xb4,0x40,0x30,0xe1,0x1f,0x8b, - 0xb7,0x02,0xf6,0xcd,0x05,0x68,0x27,0x07,0x57,0x64,0x2d,0xc1,0x09,0x6d,0xa5,0xdb, - 0xa4,0xe2,0xef,0x13,0xb4,0x84,0x5b,0x0e,0xae,0xde,0xc3,0xbf,0x18,0x21,0xf7,0x89, - 0x69,0x20,0x02,0xac,0x6c,0x83,0xc6,0x0e,0x99,0x69,0x07,0x45,0x66,0xf9,0x59,0x82, - 0x5b,0xaa,0x3d,0x3b,0x64,0xbf,0x38,0x6f,0x29,0xfc,0xff,0x44,0xe3,0x2d,0x49,0x20, - 0x63,0xbd,0x4b,0x14,0xca,0x25,0x0c,0xc7,0x15,0x8f,0x87,0xda,0xf9,0xd0,0x37,0xa0, - 0x41,0xd0,0x9c,0x42,0xb0,0xa4,0xd9,0x5f,0xa4,0xc5,0xb2,0x2b,0x30,0x5d,0x0c,0x77, - 0x91,0xdd,0xd7,0xf2,0x7b,0xc4,0x54,0x25,0xe6,0x34,0x78,0x60,0x66,0xe7,0xbc,0x1e, - 0x68,0x65,0x34,0xae,0x73,0xa9,0xcb,0xb7,0xce,0x35,0x6d,0x33,0xa1,0x41,0xae,0xc9, - 0x8b,0x25,0xea,0xa0,0x2d,0x42,0xc9,0xdd,0x69,0x22,0xe9,0x28,0x35,0x17,0x18,0xd5, - 0xe0,0x05,0x1c,0xe8,0x1a,0xa3,0xe0,0x14,0xae,0x4d,0xfa,0x13,0x54,0xe9,0xb2,0xcf, - 0x1d,0xd2,0x09,0xe8,0x5e,0xfe,0xf2,0x04,0x35,0xe4,0x5e,0x8b,0xd0,0xb3,0x06,0x5a, - 0x77,0xa2,0x9a,0x37,0x94,0xd2,0x3e,0x63,0xd1,0xf1,0x20,0xd0,0xfb,0xb3,0xea,0x8a, - 0xc3,0x10,0xd8,0x08,0xf2,0x4f,0x01,0xf8,0xb8,0xaa,0xc1,0xbd,0xb3,0xa6,0x55,0x31, - 0x27,0x15,0x4b,0x86,0x44,0x64,0x45,0xed,0xc1,0x86,0xe8,0x07,0x95,0xf8,0x38,0xae, - 0x3a,0x3a,0x57,0x14,0x86,0xf9,0x21,0x9b,0x23,0xac,0x65,0xca,0x01,0x5d,0x18,0x77, - 0x01,0x07,0x82,0x50,0x5a,0x14,0x67,0x72,0x0c,0x33,0x41,0x4a,0xa7,0xe8,0xb6,0x4c, - 0x61,0x18,0x76,0x9d,0x43,0x74,0x26,0xac,0x31,0x80,0x85,0xbe,0x69,0x5a,0xcc,0x99, - 0x07,0x86,0x43,0xd4,0x8b,0x84,0x17,0x56,0x9c,0xa3,0x15,0xb9,0x63,0xf9,0x02,0xec, - 0xda,0x53,0x6a,0x67,0xd0,0x36,0x0c,0xec,0x53,0x91,0x67,0x2b,0x98,0x89,0x36,0x30, - 0xb4,0x32,0x06,0xf7,0xc3,0x6b,0xb3,0x79,0x07,0xe9,0xf0,0xd5,0x5a,0xe4,0x35,0x9f, - 0xdc,0xc2,0x55,0x71,0xbf,0x3a,0x85,0xa5,0x65,0x3c,0x63,0xe4,0x2b,0x03,0xa8,0xb0, - 0x1b,0xdc,0xca,0xb7,0x3e,0xc2,0x1c,0xbc,0x1e,0x40,0x9b,0x54,0x45,0x49,0x46,0x06, - 0x36,0xd4,0x86,0x11,0xb8,0x3c,0xd7,0xc6,0x6e,0x4e,0xbe,0x72,0xcd,0xb2,0x95,0x6f, - 0xbd,0xcb,0x5b,0x6b,0x04,0x91,0xb5,0x8a,0xb1,0x5b,0xe3,0x87,0x90,0x4a,0x44,0xc7, - 0xe8,0xf5,0x4c,0x18,0xe2,0x52,0x02,0xa2,0x6d,0x18,0xca,0x86,0xb4,0x69,0xc5,0xa2, - 0x06,0x91,0x66,0x68,0xd2,0x79,0x2d,0xb4,0xc7,0x1e,0x03,0x94,0x20,0xb0,0xf8,0x37, - 0x05,0x6f,0x24,0xa0,0xa9,0xc0,0xe0,0x28,0x62,0x68,0xe7,0x8b,0x92,0xe5,0xb8,0x6b, - 0x51,0x01,0xe2,0x57,0x84,0xee,0x62,0x91,0x25,0x64,0xc0,0x29,0x0b,0xb9,0xd7,0x6e, - 0x6b,0x73,0xfd,0xa3,0x84,0xba,0x31,0xd4,0x3b,0x3c,0x48,0xe5,0x3c,0x93,0xff,0x5a, - 0x76,0xad,0x79,0x2a,0x4c,0x7b,0xbe,0x4b,0x51,0xa6,0x62,0x5e,0x24,0xb0,0xf6,0x2d, - 0xfc,0xdb,0x17,0x04,0xc3,0xe5,0xd3,0xd3,0x5a,0x01,0x2c,0x4a,0xc2,0xf8,0x5d,0x9c, - 0x2d,0x40,0xae,0x50,0x93,0x0d,0xae,0xf0,0xdf,0x86,0xfb,0x16,0x25,0xdc,0x99,0xe5, - 0xc4,0x6b,0x2d,0x46,0xd3,0x18,0xdd,0x17,0xdd,0x2c,0x21,0x37,0xd9,0xbf,0x6b,0xb6, - 0x8c,0x57,0xa0,0x63,0xe4,0xdf,0xdf,0x9d,0x8e,0x1a,0xf4,0x0a,0xfe,0xe9,0x4f,0x34, - 0x3d,0xd5,0xef,0xb2,0x1e,0xa9,0xf8,0xb6,0xfd,0x68,0xad,0x84,0x9a,0xa9,0x14,0x11, - 0x06,0xc4,0x7b,0xed,0xc2,0xff,0x83,0x55,0xf8,0x87,0xeb,0x66,0x60,0xa5,0xc6,0xcf, - 0xde,0xe3,0x44,0xfd,0x8e,0x26,0x04,0x46,0xf9,0xa6,0x67,0xfc,0xb1,0xe1,0x04,0x60, - 0x84,0x56,0x14,0x8b,0x29,0x89,0x55,0xb1,0xcc,0x03,0x4b,0x79,0x1c,0x00,0x0b,0x79, - 0x65,0x65,0xdb,0x65,0x33,0xbc,0x86,0xff,0xd0,0x07,0xf1,0x61,0xe7,0xbf,0xa0,0x0f, - 0x0d,0x12,0x45,0x3a,0x31,0xb6,0xca,0x14,0x15,0x1a,0x08,0x5a,0x6c,0x65,0x71,0x09, - 0xd1,0x06,0x89,0x32,0x0a,0xa0,0x75,0x39,0x01,0xde,0xbd,0x4a,0xeb,0xba,0x0c,0x4e, - 0x4e,0x46,0x4f,0xce,0xfc,0xd1,0xc5,0x63,0xff,0x81,0x3f,0x3a,0xb9,0x3c,0xa1,0x27, - 0xad,0x93,0x4a,0x7a,0x45,0x80,0xcd,0xb7,0x54,0xdf,0x22,0xa8,0xbc,0x7c,0xb5,0x44, - 0xd9,0xf6,0x49,0x81,0x21,0x6d,0xa4,0xea,0xaa,0x62,0x0e,0x1e,0x39,0x02,0x10,0x8f, - 0x41,0x39,0x80,0x0e,0x85,0xa8,0x19,0x0e,0x93,0x11,0x07,0xdc,0x0d,0x83,0xe8,0x96, - 0xf1,0x61,0x5f,0xd4,0xb2,0xc4,0xfc,0xfa,0xd2,0x08,0xa0,0x54,0x68,0x5c,0x2a,0x20, - 0xa9,0x93,0x05,0xa9,0x06,0x54,0x9d,0x2d,0x7e,0x40,0xa7,0xa0,0x9e,0x1a,0x83,0x4e, - 0x6e,0x8c,0x00,0x6c,0xa9,0x75,0x5a,0x5f,0x93,0x81,0xce,0xc4,0x83,0x53,0xb5,0x5f, - 0x5d,0x64,0x52,0xab,0xe9,0xed,0xc8,0xd2,0x78,0x68,0x20,0xe0,0x64,0xd0,0x1e,0x2b, - 0x21,0x15,0x1b,0xc6,0x1c,0x30,0xa2,0x84,0x94,0xf2,0x0d,0xb0,0xc4,0xc2,0xee,0xad, - 0xc5,0x2c,0x6d,0x6f,0xb3,0x43,0x6f,0xc9,0x52,0xc1,0xd5,0x65,0x6c,0xa5,0x10,0x9a, - 0x45,0x83,0x93,0x01,0xe8,0x2e,0xf4,0xa3,0x63,0xc4,0x2f,0x98,0xc0,0xa2,0x0e,0xad, - 0xf6,0xa9,0x6c,0x01,0xc3,0x48,0x09,0xff,0xe2,0x2c,0x64,0x2c,0xda,0xe2,0x40,0x07, - 0xba,0xba,0x65,0xab,0xe9,0x00,0xfb,0x27,0x87,0x37,0x6d,0x67,0x49,0x31,0xa1,0x76, - 0x2a,0x7f,0xc6,0xea,0x97,0x19,0xc3,0x8f,0xcf,0x56,0xaf,0x13,0x98,0xb1,0x69,0x17, - 0x30,0x31,0x71,0xea,0x66,0xc9,0x0d,0xe0,0x28,0x9f,0xc1,0x80,0x5f,0xb1,0x32,0x8b, - 0x27,0xcc,0x39,0xf9,0x74,0x74,0x79,0x35,0xf8,0x7c,0x32,0xf3,0xcc,0x96,0x41,0x40, - 0x82,0x5a,0xb1,0xb6,0x8f,0xec,0xc0,0x3e,0x8a,0xe7,0x65,0x68,0x7b,0xf6,0x25,0x7e, - 0xce,0x6a,0xfc,0x78,0x85,0x1f,0x67,0xf4,0x71,0x80,0x1f,0xc1,0x23,0x86,0x2f,0x9b, - 0x4f,0x93,0xcf,0x9b,0xce,0xf9,0xb9,0x79,0x3e,0x7c,0x03,0x76,0xfb,0xf9,0xc3,0xeb, - 0xe7,0xa0,0x06,0x80,0x34,0x39,0x35,0x36,0xb6,0xb3,0xbf,0x60,0xcb,0x9c,0x9a,0xdb, - 0x34,0xc0,0xb5,0x8f,0x4b,0xf0,0xf7,0x9c,0x85,0x87,0x69,0x90,0xad,0xe6,0xbb,0xf5, - 0x9c,0xd5,0x69,0x91,0x04,0xf6,0xfb,0x77,0x37,0x1f,0x6d,0x34,0x39,0x32,0x85,0x21, - 0x82,0xb5,0xad,0xfa,0x55,0x87,0x1f,0x41,0xdc,0x01,0x56,0xf0,0x15,0x32,0x3e,0xa1, - 0x8c,0xdd,0xc9,0xd7,0xe1,0x72,0xb9,0x1c,0xa2,0x40,0x0f,0x17,0x55,0x26,0xe1,0x4b, - 0xec,0x0d,0x9d,0x11,0xe0,0x3f,0xba,0xfd,0xf3,0x8b,0x09,0x88,0x88,0x57,0xd8,0x15, - 0xeb,0xae,0x65,0xed,0x12,0x3f,0xdf,0xdf,0xdb,0xc5,0xad,0xed,0xfd,0x93,0x63,0x83, - 0xf8,0x63,0x07,0x61,0x67,0xf6,0x8f,0x62,0xff,0x7c,0x52,0x18,0xdd,0x15,0xe3,0x6f, - 0x1e,0xa0,0xa2,0x6f,0x5a,0x72,0x72,0x02,0x56,0x1e,0x7c,0x8d,0x62,0x51,0xa1,0xee, - 0x90,0x0d,0x86,0x02,0x7c,0x9a,0xaa,0x5a,0x19,0xbe,0x8f,0x4d,0xce,0x44,0x22,0xfc, - 0xf6,0x0c,0x30,0xc7,0xd8,0xe7,0xaa,0x29,0x73,0x74,0xc4,0x7c,0xf2,0xf5,0xa3,0xc8, - 0xa6,0x4d,0x6c,0x1c,0x99,0x83,0x19,0x07,0x7f,0x04,0xce,0x9e,0xc6,0x3c,0x43,0xcc, - 0x1c,0xc8,0x23,0x77,0x3a,0x16,0x68,0xe9,0x56,0x14,0x31,0x00,0xfb,0x80,0xf2,0x40, - 0xf7,0x49,0x55,0x74,0x69,0xaa,0xa7,0x1d,0x32,0xe5,0x20,0xe0,0x56,0xe0,0x7d,0x51, - 0x30,0x1f,0xaf,0x2c,0xd2,0x32,0xca,0x09,0x52,0x82,0x1b,0x5a,0x46,0xb3,0x33,0xce, - 0xf5,0x0f,0xb0,0x3d,0xf4,0x8e,0xc7,0x3f,0x8a,0x88,0x0c,0x81,0xa7,0x9c,0x1f,0xf0, - 0xe7,0xeb,0x6a,0xc1,0x3c,0xb0,0x3d,0xd1,0xc3,0x90,0x66,0x61,0x18,0xf8,0x13,0x00, - 0x23,0xb0,0x45,0x1a,0xbf,0xfc,0x95,0xad,0x22,0xdb,0xf6,0x52,0x81,0xa3,0xf2,0xd3, - 0x9b,0x02,0x98,0x24,0x89,0xb0,0xd7,0x37,0x44,0x70,0x7e,0xce,0x29,0xc7,0x65,0x95, - 0xe0,0x71,0x49,0xbf,0x07,0xa4,0x15,0x60,0x4d,0x2d,0x08,0xe4,0x6a,0x72,0x5b,0x30, - 0x67,0xbf,0xac,0x78,0xcd,0x24,0x2c,0x48,0x8d,0x17,0xd8,0x60,0xad,0xe0,0x49,0x85, - 0xf1,0x4d,0x02,0x72,0xcb,0xca,0x1a,0x8f,0x83,0xe0,0xee,0x97,0x98,0xd7,0xd1,0xa9, - 0x87,0xfa,0x4d,0x41,0x83,0x01,0xaa,0xfa,0x38,0x8d,0x21,0x5c,0x96,0xbb,0x00,0xfd, - 0xe2,0x7c,0x06,0x90,0x9d,0x86,0x2d,0xc9,0xa8,0x8f,0xdb,0x21,0xa6,0xa0,0x8f,0x51, - 0x73,0xf6,0xfd,0xbd,0x3a,0xf6,0xfe,0xfe,0xf0,0xd0,0x01,0x1e,0x41,0xcb,0x61,0xbb, - 0x3e,0xf9,0x05,0xf7,0xf7,0x30,0x80,0x56,0x5a,0x0f,0xb8,0x92,0x8a,0x4f,0x05,0x3a, - 0x9e,0xaa,0xa2,0x82,0x57,0xcd,0x80,0x48,0xa0,0x93,0xc5,0x92,0x55,0xa4,0x91,0xc7, - 0x0c,0x04,0x83,0xc9,0x47,0x00,0xa5,0x68,0xe8,0x27,0xb3,0x34,0xa8,0x43,0x56,0xb8, - 0x51,0x9c,0x55,0x20,0x6b,0x2b,0xeb,0x36,0x47,0x67,0x91,0x88,0xe3,0x1f,0x20,0xe7, - 0xca,0x6e,0x61,0xb3,0x7b,0x57,0x52,0xee,0xf0,0x50,0xf8,0xf8,0x49,0xf2,0x4d,0x88, - 0x4d,0xb2,0x92,0x28,0xd8,0xd0,0xab,0xb8,0xc9,0x55,0x64,0x6a,0x06,0x7c,0xbc,0x53, - 0x08,0x47,0x3c,0x2b,0xbe,0x62,0x5f,0x6c,0x28,0x39,0x11,0x53,0x48,0x31,0x5a,0x0b, - 0x4d,0x29,0x8f,0x80,0x45,0x38,0xf3,0x86,0x33,0x9d,0xd6,0xff,0xd2,0xf7,0x43,0x06, - 0x6b,0x1d,0x67,0xba,0x06,0xba,0xc6,0xd8,0xf5,0xeb,0x86,0x8a,0x95,0xcf,0x2c,0x8a, - 0x17,0x32,0xc0,0x8a,0xcc,0x58,0x71,0x8c,0x07,0xd0,0x13,0x27,0x63,0x23,0x19,0x00, - 0xfb,0x94,0x23,0xb8,0x2d,0xf5,0x2b,0x1b,0xfd,0xc5,0xa0,0x82,0xf0,0xf1,0x32,0x6c, - 0xb5,0xa9,0x54,0x56,0xb2,0x81,0x7f,0xc9,0xa7,0xdc,0x6e,0x94,0xcb,0x76,0x5f,0xfa, - 0x32,0x4a,0xc2,0x1d,0xcb,0x74,0xa1,0xac,0x55,0x4b,0x2e,0xb9,0x27,0xbd,0x0d,0xd2, - 0x46,0xb2,0xd7,0xcb,0x60,0xe9,0xa5,0x41,0xba,0xe9,0xf6,0xb7,0x03,0xce,0x97,0xae, - 0x31,0x65,0x13,0xca,0x0e,0x65,0x86,0x88,0xdd,0x78,0x0f,0x4f,0x4f,0x4f,0x3d,0x13, - 0x1c,0x98,0x0f,0xff,0x62,0x38,0xf0,0x0b,0x00,0xee,0x24,0xfe,0xd2,0x45,0xba,0x25, - 0x7e,0xea,0xe2,0x20,0x28,0x38,0xfc,0xb8,0xc1,0xd5,0x88,0x4b,0xb4,0xbe,0x4a,0x6a, - 0x51,0xf1,0x58,0xce,0x4f,0xef,0xac,0x9b,0x9b,0xd7,0x2f,0x3c,0xeb,0xe9,0xcf,0x1f, - 0x7f,0xb4,0x5e,0x3d,0x7d,0xfd,0xc6,0xf7,0x7d,0x17,0x11,0x8a,0x35,0x85,0xa4,0xe9, - 0xf9,0x7d,0xf3,0xf2,0x85,0xa9,0xa5,0x44,0xfd,0x11,0xfb,0xa1,0x13,0x42,0x27,0x9d, - 0xd7,0xc8,0xbb,0x86,0xde,0x86,0x69,0xf6,0x31,0x3c,0x90,0xd1,0xd0,0xb1,0x6d,0xfd, - 0xd7,0x7f,0xd2,0x00,0x2f,0x0d,0xd4,0xdb,0x24,0xba,0xb9,0xf4,0xbb,0xa9,0xf5,0xd8, - 0x3e,0x76,0x0e,0x13,0x5f,0x47,0x9d,0xbe,0xf4,0x58,0xaf,0x71,0x1e,0xb6,0xad,0x5a, - 0x52,0x0f,0xac,0x58,0x6d,0x07,0x84,0xe0,0x44,0xb1,0x33,0x2a,0x48,0x75,0x19,0x1b, - 0x67,0xab,0x89,0x4d,0x48,0x05,0x96,0x0b,0x25,0x77,0xc7,0xaa,0xe6,0xe6,0xb0,0x2e, - 0xee,0x2d,0x03,0xde,0xd5,0x5d,0x2e,0x96,0x4e,0xb0,0x80,0xa9,0xaa,0xab,0x15,0x71, - 0x1b,0x62,0xb3,0x13,0x24,0xdb,0x48,0x25,0x85,0x68,0x25,0xa2,0x92,0xbd,0x91,0x31, - 0xa5,0x5f,0xd9,0x06,0xa4,0xca,0x27,0x22,0x4f,0x0e,0xf4,0xac,0x03,0xbe,0x35,0xfb, - 0x1b,0xf2,0xdf,0xdf,0xd0,0x25,0x04,0xb2,0x19,0x08,0xd7,0xf2,0xa5,0xda,0xf0,0x49, - 0x5e,0x8f,0x8e,0x0e,0x1b,0xac,0x87,0xa0,0x4b,0x64,0x32,0x02,0x58,0x50,0x06,0xf6, - 0x51,0x8a,0x9c,0x90,0xba,0xf2,0x09,0x0c,0x93,0xa3,0x0e,0xba,0x8b,0x54,0x19,0xe8, - 0x9a,0x96,0x9a,0x0d,0xfb,0x34,0xe2,0x91,0x47,0x2d,0x0d,0x40,0x49,0x67,0x91,0x32, - 0x70,0xb6,0xeb,0x61,0x10,0x0c,0x4f,0xf1,0xdb,0xeb,0xe4,0xab,0x07,0xf4,0xf5,0x6e, - 0x91,0xa2,0xa8,0xe2,0x13,0x1f,0xfe,0x0d,0x5b,0xdd,0x6f,0xf0,0x05,0x4e,0x41,0x0d, - 0x48,0x32,0x62,0xbc,0xad,0xd2,0xb0,0x12,0x4e,0x00,0xcc,0xbd,0x60,0x13,0x9e,0x50, - 0x8e,0x1a,0x02,0x5f,0x9d,0xa9,0x36,0x34,0x9b,0xd4,0x89,0x14,0x49,0xca,0x51,0xa9, - 0x09,0x04,0xab,0x29,0x13,0x01,0xd1,0x9d,0x03,0x7a,0x83,0xb6,0x32,0x2a,0xd8,0x1e, - 0x7a,0xe0,0x1d,0x1e,0x72,0x3d,0x8b,0x01,0x1e,0x40,0x71,0x60,0x9b,0x7c,0xa3,0x4c, - 0xa5,0x87,0x4a,0x1f,0xc9,0x01,0x95,0x3b,0x49,0x8c,0x82,0x16,0xca,0x32,0xd2,0x60, - 0xad,0xca,0x45,0x38,0x64,0x2c,0xf9,0x65,0x31,0x2f,0x85,0x06,0xb8,0x2d,0x9c,0x0b, - 0xdc,0x3e,0xe3,0xf9,0xad,0x2f,0x45,0xe5,0x50,0xdb,0x10,0xc2,0x35,0x84,0x5f,0xda, - 0xa4,0x8c,0x42,0xfa,0x0e,0x53,0x88,0xba,0x60,0x32,0x72,0xc5,0xfd,0x48,0x42,0xb0, - 0xcd,0x80,0xb8,0x32,0x46,0x59,0xfa,0x09,0xbc,0x21,0x1f,0x0b,0x5d,0x55,0xfd,0x8c, - 0x6c,0x81,0xa3,0x27,0xa0,0x1f,0x42,0xb7,0x03,0x2f,0x44,0x6e,0xd7,0x0e,0x68,0xb6, - 0x50,0x16,0xd0,0xb2,0x36,0x12,0x20,0x47,0x91,0x16,0x7c,0xe6,0x76,0x92,0x3e,0xfa, - 0xf2,0xcc,0x3d,0x3a,0x6a,0xec,0x99,0xbb,0xee,0x99,0xd5,0x50,0xd9,0x3e,0xdc,0x4a, - 0xb3,0xa8,0xa2,0xe3,0x07,0x86,0x6f,0x7e,0xd4,0x32,0xe7,0x82,0x41,0x5e,0x8a,0xd7, - 0xc4,0x1e,0x01,0x99,0x72,0x47,0xd4,0x81,0x8b,0xac,0x32,0x36,0xb2,0x76,0x02,0xd6, - 0xdd,0x12,0x8b,0xea,0x8e,0xdf,0xa1,0x6a,0x57,0x86,0x03,0xf1,0x76,0x1b,0xfd,0xe5, - 0xe6,0xdd,0x4f,0x20,0xb4,0xe8,0x28,0xf3,0xe9,0xca,0xf9,0x94,0x7b,0x06,0x6f,0x1d, - 0x1d,0x35,0x7a,0xc6,0x6b,0x38,0xf3,0x33,0x41,0x02,0x17,0xbc,0x3d,0x8c,0x22,0x65, - 0xce,0x15,0xce,0xb5,0x71,0xbf,0x6d,0x50,0x6e,0x5c,0x51,0x05,0xa7,0xb0,0x5f,0x54, - 0x62,0x45,0xf3,0x35,0xb8,0xc3,0x20,0x01,0xd2,0x46,0x7b,0xa3,0x53,0x85,0x58,0x5a, - 0x06,0x93,0x2e,0x1b,0x2a,0x91,0x60,0xc0,0x48,0x88,0x7c,0xf5,0x2d,0x4c,0x49,0xd4, - 0x13,0x6d,0x10,0x12,0xc0,0x3a,0x87,0x8b,0x54,0x3f,0x7e,0x7c,0xfb,0xa6,0x41,0xfc, - 0xb5,0x0d,0x7a,0xe6,0x32,0xe3,0xdd,0xb2,0x60,0x3e,0x6f,0x32,0x86,0xdb,0x1d,0x49, - 0x83,0x2b,0x8c,0xd3,0x5b,0x0d,0xd9,0x54,0x0d,0x61,0x17,0x5b,0x02,0x8d,0xf7,0x68, - 0xcf,0xb2,0xd5,0x68,0xbe,0xfd,0x9a,0xca,0x57,0x8f,0x37,0x98,0x40,0x7d,0x90,0xf1, - 0xa8,0x09,0x6c,0xb0,0x75,0xb2,0x66,0x2a,0xb6,0xc1,0x2b,0xd8,0x0d,0x4a,0x32,0x6e, - 0x6e,0xdf,0x05,0x7d,0x70,0x05,0xaa,0x9d,0x1f,0x8f,0xdc,0x63,0x5b,0x43,0xd6,0xbb, - 0x9a,0xae,0x8b,0xda,0xc7,0x4d,0x72,0xc2,0xe9,0x50,0xf9,0x2b,0x39,0x1b,0xa0,0xb4, - 0x1b,0x72,0x5f,0x77,0x0f,0xa9,0x63,0x88,0xf1,0x9b,0x05,0x7a,0xbb,0xc0,0xb6,0xdd, - 0xce,0x96,0x8a,0x43,0x60,0x23,0xbe,0xbd,0x81,0x25,0x8b,0x6f,0xb2,0xf4,0xb6,0x6b, - 0x03,0xbb,0x97,0xb7,0x48,0x58,0xd6,0x4b,0x77,0x5f,0x49,0xde,0x6e,0x32,0x15,0xb6, - 0x81,0x1f,0xea,0x92,0x00,0xd0,0x3f,0x8d,0x3e,0x77,0xf4,0xa0,0xbc,0x9b,0x31,0x11, - 0x36,0xaf,0x9f,0xe3,0x64,0x1f,0x54,0x21,0x44,0x46,0xb7,0x91,0xe1,0xc5,0xc0,0x99, - 0x8e,0x5c,0xe1,0xa1,0x67,0xee,0x6e,0xf4,0xc2,0x96,0xa7,0x20,0x9e,0x62,0x79,0x42, - 0x3b,0x38,0x19,0x6f,0x48,0x84,0x2c,0x00,0xba,0xc2,0x41,0x4b,0xf4,0x8e,0xd2,0x51, - 0x8e,0xa2,0x8a,0x0f,0xb6,0x57,0xed,0xc9,0x3d,0xe9,0xef,0x12,0x4b,0x03,0x96,0xb4, - 0x36,0xd9,0xb8,0x5a,0x71,0xc0,0x39,0x93,0xb8,0xec,0xe9,0x72,0xcd,0xbc,0x60,0xec, - 0x8b,0x29,0xec,0x06,0xc6,0x00,0x3e,0x62,0x3a,0x58,0x60,0x16,0x37,0x51,0x84,0x75, - 0xf4,0xbc,0xab,0x08,0x66,0x5c,0xdb,0x64,0xf7,0x65,0xa3,0x00,0xa8,0x03,0x50,0xd2, - 0xa0,0x4d,0x55,0x24,0x2c,0x94,0x07,0x4c,0xf5,0x5f,0x46,0x84,0x90,0xde,0x03,0xb6, - 0x74,0x60,0xa6,0x05,0xa8,0x89,0x2e,0x20,0xd9,0x5d,0x34,0xbc,0xd4,0xba,0x34,0x66, - 0x13,0x8c,0x76,0x00,0x86,0x66,0xb5,0x36,0xba,0x02,0x33,0xb3,0x2a,0x35,0xa3,0x72, - 0x29,0x86,0xe5,0xf5,0x53,0x95,0xe3,0xe5,0x10,0x8c,0xe3,0x76,0x37,0x29,0x86,0x6f, - 0x98,0x0e,0x06,0xc5,0x0f,0x16,0x60,0xce,0xf3,0x45,0xcd,0x74,0x16,0x05,0x93,0x14, - 0x60,0x77,0x32,0xcc,0x89,0x54,0x2c,0xa9,0x62,0x98,0xdb,0xd5,0x77,0x86,0x09,0x37, - 0x60,0xfe,0xd2,0xd8,0x59,0x30,0xd8,0x68,0x5a,0xf1,0x0a,0xa0,0xbd,0x8b,0x1c,0x7c, - 0xf0,0x2f,0x47,0x47,0x5f,0xc8,0x3d,0x61,0xa0,0xb7,0x6c,0x14,0x69,0x88,0xf9,0x1c, - 0x35,0x84,0x0e,0x8b,0xf4,0x3e,0xec,0xfb,0xfb,0x2f,0x7e,0x3c,0x2b,0x2e,0xa3,0x8b, - 0xd3,0x53,0xd7,0x23,0xc4,0xd6,0x51,0x91,0x37,0xab,0x8d,0xa9,0xde,0x2d,0x3c,0xb8, - 0xfe,0xa4,0x1e,0x78,0x5f,0x24,0x91,0xbf,0x80,0x2b,0x06,0xff,0x40,0xc4,0xf9,0x99, - 0x70,0xe8,0xd8,0xf7,0xb6,0x0b,0x18,0xf6,0x72,0x6f,0xe1,0x2d,0x95,0xf2,0xac,0x01, - 0x08,0x0c,0x80,0xdc,0x35,0x85,0x41,0x75,0x88,0xfe,0x34,0xbd,0x65,0x58,0x5f,0x9f, - 0x81,0x37,0x1a,0xa0,0x4b,0xea,0x2a,0x53,0x72,0x0b,0x67,0xaa,0x18,0x4a,0xb9,0x81, - 0xb8,0x8b,0x8e,0xaa,0x6e,0x43,0xb8,0xad,0x36,0x30,0x87,0x45,0xae,0x4e,0x80,0x4f, - 0xc6,0xe4,0x1c,0xd4,0xc6,0x18,0x34,0x00,0x66,0x48,0x24,0x9c,0xa4,0x2f,0xc6,0x52, - 0x86,0x70,0x03,0x92,0x3a,0x15,0x2a,0x6a,0x20,0x95,0xae,0xc2,0xc7,0x86,0xfe,0x41, - 0x5c,0x23,0x4f,0xd9,0xc7,0xf9,0xb1,0x7d,0x94,0xd2,0x3b,0x1a,0xa1,0xf5,0x7a,0x6a, - 0x64,0xf4,0xf1,0x5d,0x43,0xa1,0x82,0x0f,0x98,0xea,0xf5,0x32,0xc2,0x58,0x6b,0x48, - 0xac,0x46,0x1f,0xd9,0x14,0x36,0xc7,0x0d,0x37,0x05,0xaa,0xda,0x6d,0x46,0xc7,0x30, - 0x85,0xce,0x6b,0xd3,0x7c,0x9d,0xdc,0x7b,0x2f,0x85,0xdf,0x6e,0xdd,0x49,0xe0,0x83, - 0xa6,0x94,0x71,0x16,0x08,0x87,0x03,0x9e,0x0b,0xa0,0x44,0xa5,0x09,0x25,0x66,0xe4, - 0x43,0x94,0xd9,0xac,0x98,0xc4,0xd9,0x09,0x22,0x48,0x05,0xea,0x18,0xe7,0xcb,0x1a, - 0x85,0x2b,0xf5,0x96,0xed,0x13,0x9a,0x36,0xe4,0xed,0x00,0xb2,0x0c,0xf6,0x90,0xf9, - 0x3c,0xdb,0xc0,0x9e,0x81,0xdc,0xe2,0x56,0xa9,0xad,0x45,0x64,0x77,0x0e,0x47,0xbe, - 0x81,0x6d,0x4f,0xd4,0xe3,0x1d,0x48,0x27,0x9c,0xe5,0xa8,0x51,0x6e,0xf6,0xe2,0xc7, - 0x93,0xa1,0x20,0x62,0xe8,0x72,0x5c,0xb5,0x3a,0xdf,0xbe,0x8c,0xb5,0x62,0x1d,0xf3, - 0xd9,0x40,0xe5,0xe5,0xec,0xe3,0xc5,0xb1,0x8d,0x16,0x64,0x81,0xdc,0x10,0x5f,0x7d, - 0x6f,0xcd,0x71,0x52,0x94,0x2b,0xb4,0x08,0xe5,0xaa,0x55,0xc6,0xcd,0x49,0xdd,0xb2, - 0x5e,0x93,0x2a,0xc6,0xd9,0x2a,0x59,0x2c,0xcd,0x14,0x80,0xf7,0x71,0x47,0xe9,0x45, - 0xd3,0xb4,0x5b,0x7a,0x99,0x52,0xaa,0x57,0xea,0x09,0xdf,0x6e,0x9c,0x30,0xdc,0x14, - 0xb4,0xe5,0x0e,0x55,0xae,0xfd,0x0d,0x98,0xe0,0xb4,0x88,0x46,0x24,0x23,0x8e,0xfb, - 0x21,0x68,0x93,0x7b,0xc2,0x1d,0x21,0xd8,0xb5,0x3d,0x9d,0x7f,0x52,0x60,0xd3,0x6b, - 0xb2,0x8d,0xad,0xda,0xb1,0x8e,0xea,0xac,0xc4,0x9d,0xa9,0x4e,0xbf,0x1a,0x95,0x21, - 0xdc,0x05,0xae,0x03,0xdb,0xb2,0xaa,0xea,0xef,0xab,0xad,0x40,0xc3,0x4f,0x3b,0x19, - 0x07,0x17,0xca,0x89,0xcb,0x88,0xd4,0xcb,0xfd,0x3d,0x06,0x64,0x52,0xc8,0xda,0x52, - 0xa1,0x92,0xa1,0xdd,0x5c,0xf4,0xbc,0x53,0x8e,0x92,0x1c,0x13,0x58,0x92,0xff,0x96, - 0xca,0x56,0xa9,0x4b,0x3a,0x4b,0x64,0xe5,0x25,0xb6,0xa2,0xb6,0x31,0xda,0xb5,0xfd, - 0x9c,0x5e,0x79,0x30,0x03,0x37,0xba,0x33,0xe8,0xff,0x84,0x92,0xe3,0x33,0xf0,0x99, - 0x7c,0x15,0x0e,0x12,0xa8,0xa8,0x6c,0x75,0xa3,0x05,0x9c,0x4b,0x6d,0x22,0x9d,0x7d, - 0x50,0xb2,0x3c,0x59,0xa8,0xc4,0x00,0x19,0xdf,0xab,0x1a,0xc2,0x76,0xd8,0x81,0x76, - 0x47,0x09,0xf9,0x44,0x2a,0x07,0x33,0xa1,0x0d,0xf3,0x74,0xe8,0x69,0x1c,0x66,0x63, - 0x57,0x13,0x41,0x00,0xcc,0x57,0x08,0xcc,0xc7,0xcb,0x70,0xa2,0x2a,0x80,0x6b,0x2a, - 0xdf,0x56,0x66,0x56,0x9a,0x34,0xc5,0x13,0xba,0xc1,0x26,0xc6,0x54,0xfe,0xa2,0x92, - 0xaf,0x63,0x80,0xf1,0x0d,0x00,0xb0,0x3b,0x3e,0x8b,0xeb,0xa2,0x02,0x2a,0xf0,0x72, - 0x5c,0xc4,0x70,0x57,0x8e,0x16,0x77,0x11,0x67,0x60,0x8c,0xe6,0x1c,0xd4,0x68,0x3e, - 0x33,0x4c,0x11,0xf1,0x5a,0xad,0x83,0xf7,0x1d,0xcb,0x8f,0x8e,0xd4,0x6f,0x1e,0x70, - 0x71,0x43,0x87,0x3d,0x97,0x67,0xe9,0xe0,0x7e,0xc7,0x12,0x9f,0x92,0x6f,0x14,0xcb, - 0xd5,0x04,0x3e,0xe5,0xfa,0xf6,0x7a,0x8d,0x28,0x59,0x60,0xf1,0x66,0x11,0xf8,0x49, - 0x37,0x54,0x05,0x23,0x2e,0xf5,0xaa,0xfe,0x8a,0x0f,0x88,0x3b,0x78,0x50,0xdc,0xb6, - 0x91,0x8b,0xe8,0xfe,0xde,0x81,0x1c,0x22,0xbf,0xd8,0x9f,0x08,0x81,0x30,0x44,0x76, - 0xd3,0x1a,0x38,0xe5,0x5f,0xc1,0x3e,0x63,0x9b,0x17,0xbe,0xbc,0xcf,0xcb,0x00,0x0b, - 0x58,0xce,0xa9,0x47,0xff,0xbb,0x9d,0x17,0xf6,0x40,0x34,0x9a,0xd7,0x65,0xc1,0x5f, - 0xa9,0x86,0xb2,0x3e,0x17,0xe0,0x69,0x61,0x7f,0x80,0x18,0xb7,0x01,0x16,0x93,0xd2, - 0x1d,0x97,0x0b,0x5f,0x23,0xf7,0xe5,0x74,0x8c,0xd7,0x14,0xb0,0x02,0xc7,0x67,0x7e, - 0xc5,0xd0,0xb2,0x3c,0xcd,0x32,0xba,0x1d,0xbe,0xb9,0x3f,0x43,0xa7,0x4c,0xde,0xb5, - 0x22,0xf4,0x81,0xe9,0x5e,0xc3,0x9d,0x9b,0x03,0xd8,0x57,0x36,0x79,0x5e,0xcc,0xe7, - 0xc0,0x66,0x5a,0x9b,0x6c,0x26,0xf8,0x8b,0x00,0x98,0x36,0x42,0xfb,0xbb,0x6b,0xd7, - 0x2e,0x78,0xf2,0x79,0x03,0x5e,0x9b,0x85,0x29,0x6e,0xaf,0xd5,0x4b,0xff,0xbe,0xca, - 0x10,0x3b,0x6e,0xd0,0x8e,0xe0,0x6f,0x4f,0xe8,0x97,0xf1,0xe5,0xc9,0xd2,0xdd,0xea, - 0x24,0x10,0x30,0xd5,0xd4,0xb8,0x35,0x29,0x78,0xe8,0x3a,0xf2,0x9e,0x44,0x29,0x72, - 0x09,0x5e,0x9e,0xd2,0xbd,0x11,0xb8,0x6c,0xf8,0xf7,0xfe,0xfe,0xd3,0x67,0xd7,0x9f, - 0x42,0x8c,0xc8,0xaa,0x4e,0x32,0x52,0x01,0x25,0xc8,0xfa,0x6f,0x5c,0x6f,0x2b,0xf8, - 0xc3,0xd5,0x04,0xbe,0xca,0x45,0xa6,0xd2,0x75,0xa6,0xa4,0xbd,0xca,0xb0,0x9a,0xfc, - 0x91,0x36,0x9e,0x75,0x93,0x58,0x5e,0x63,0xd5,0x38,0x48,0x7d,0xfc,0xe3,0xa1,0x7e, - 0x08,0x12,0x1f,0xff,0x6c,0xb4,0x4f,0xa2,0xf2,0xb6,0xee,0xba,0x5c,0xd4,0x8e,0xac, - 0x06,0xc0,0x54,0x60,0x58,0xb9,0xc6,0x0d,0x9b,0x71,0x99,0xc1,0xf5,0xe4,0x7a,0x57, - 0xb9,0xc6,0xaa,0xf4,0xbd,0x05,0xc8,0xa2,0xbc,0xb6,0xdf,0xe5,0xa8,0xc8,0x24,0x50, - 0xe8,0x28,0xe7,0x4d,0x6f,0x3d,0x8e,0xaa,0xcf,0x3a,0x5d,0xa6,0x75,0xdc,0xe4,0x7a, - 0x72,0xec,0x4c,0x40,0x47,0x8d,0xc0,0x23,0x50,0xc5,0x83,0x40,0x7f,0x12,0x68,0xe5, - 0xa5,0x19,0x82,0xc1,0xbc,0x40,0x62,0xab,0xaf,0xae,0xde,0x28,0x05,0x7b,0x22,0xf5, - 0x8f,0xbc,0x01,0xaa,0xbb,0x62,0x3a,0x05,0x05,0xf7,0x6e,0x3a,0x05,0xd5,0xd4,0x8e, - 0x62,0x29,0x51,0x0e,0x93,0x5f,0xae,0xca,0xe5,0x7b,0x4a,0xe5,0xb0,0xb2,0x99,0xa9, - 0xbb,0x41,0x7c,0xed,0x96,0xa1,0x3b,0xa8,0x12,0xfc,0xda,0xc3,0xa3,0xd4,0x40,0xb5, - 0x33,0x35,0xe0,0xa9,0x3c,0x0a,0x75,0x6b,0x63,0x9a,0x20,0x5d,0xcc,0xc7,0x28,0xd9, - 0xaa,0x44,0x70,0x1b,0xb6,0x95,0x03,0xfc,0xe4,0xcf,0xe3,0xf2,0x5b,0x7c,0xa3,0x13, - 0x4e,0xe8,0x4e,0x99,0x11,0x36,0x8e,0x4d,0xe2,0xee,0x98,0xf4,0x24,0x69,0xd7,0xad, - 0x50,0x58,0x28,0x13,0x8d,0x7c,0x5d,0xec,0xd5,0x67,0xb2,0xb2,0x0f,0x8c,0xf0,0x3b, - 0x91,0xb2,0x36,0xcd,0xe3,0xbd,0xb3,0xa4,0x9b,0x02,0x33,0x7f,0x8b,0x84,0x5f,0xc1, - 0x5d,0xae,0xa2,0xe1,0xc3,0x87,0xd7,0x0f,0x82,0xe6,0xdb,0xc5,0xa3,0xeb,0xf3,0xf6, - 0xdb,0xa3,0xc7,0xd7,0x67,0x81,0x4a,0x1e,0x15,0x32,0x4b,0x11,0x89,0x46,0x22,0xd4, - 0xf5,0x4d,0xcd,0x54,0x28,0x33,0x3e,0xf6,0xc9,0x5f,0xd2,0x07,0xea,0xc1,0xbd,0x01, - 0x7c,0x1b,0xa0,0x77,0xc6,0xe9,0x15,0x02,0x61,0x1f,0xff,0x06,0x0e,0x1a,0x18,0x30, - 0xcc,0x4d,0xf0,0xf9,0x4c,0x35,0x75,0x51,0x7f,0x42,0x34,0x10,0x7c,0x96,0xc7,0xc8, - 0xe0,0xbf,0xb5,0xce,0x17,0x44,0x67,0x0f,0x60,0x47,0x0e,0x9b,0xf2,0x3d,0x7f,0x54, - 0xf8,0xad,0x21,0xa3,0x7c,0x9f,0x0c,0x89,0x3b,0x19,0x44,0x23,0x72,0x1e,0xef,0xf2, - 0xb0,0x7a,0x85,0x17,0xbd,0x60,0x92,0xde,0xa2,0x8a,0x94,0x79,0x99,0xb0,0x2d,0xc6, - 0xd0,0x8b,0xab,0x8e,0x0e,0xa9,0x21,0x12,0x37,0x91,0x37,0xa6,0x99,0x8a,0x81,0x76, - 0x84,0xd8,0x2d,0xdf,0xc9,0xfe,0xd4,0x36,0xa5,0x76,0x48,0xec,0x25,0x03,0x5f,0x35, - 0x07,0x9b,0x43,0xdb,0x09,0xc6,0xf3,0xcb,0x47,0x94,0x51,0xc5,0xd4,0x9e,0xce,0x62, - 0xf5,0x2e,0xe1,0x4a,0xe8,0x0f,0xcc,0x3a,0x2c,0xa8,0x24,0x96,0x79,0x77,0x54,0x15, - 0xd0,0x09,0x2b,0x08,0xdf,0xee,0x5c,0xfd,0x25,0xba,0x33,0xa6,0xcb,0xdd,0xd7,0x2d, - 0x18,0x26,0x4e,0xdb,0x3b,0x12,0x95,0xdf,0x70,0x51,0x63,0x22,0xa6,0xc6,0x9f,0xc7, - 0x70,0x6c,0x70,0x2b,0x6c,0xf7,0xda,0x46,0xb5,0x6f,0x4d,0x19,0x78,0x75,0xa0,0x05, - 0xe8,0x0b,0xbe,0x59,0x60,0x1f,0x37,0x72,0xaa,0x6e,0xb3,0x39,0x68,0x0f,0xd9,0x43, - 0x9e,0xfe,0x59,0x75,0x31,0x9b,0x65,0x4c,0x9d,0x14,0x4a,0x50,0x37,0xb2,0x86,0x41, - 0x3b,0x53,0x37,0x5a,0xd7,0x03,0x93,0x6d,0x09,0x20,0xa4,0xe8,0xef,0x20,0x77,0x51, - 0xb4,0xd1,0xfa,0xed,0x0c,0xbb,0x22,0x30,0x07,0x0f,0x5c,0x5f,0xe0,0x46,0xce,0x00, - 0x93,0xde,0xf0,0xdf,0x80,0x9c,0xf6,0xc1,0x52,0x7d,0xf3,0xac,0xb3,0xd3,0xb3,0x8b, - 0xe1,0xe9,0x93,0xe1,0xd9,0x99,0x8b,0x5d,0x64,0xb2,0x13,0xc5,0xc2,0x1f,0xd1,0x11, - 0xca,0xbf,0xc7,0x54,0xa5,0x99,0x9e,0x87,0x73,0x95,0xa2,0x40,0xeb,0x21,0xee,0xef, - 0xb1,0xb4,0x80,0x05,0x46,0xf8,0xd4,0x60,0x83,0x7e,0x48,0xe5,0x1d,0xfe,0xfc,0xcb, - 0xd5,0x70,0xd4,0xd4,0x49,0x88,0xbd,0x61,0x57,0x07,0x15,0x0c,0x8f,0x4e,0xbd,0x0c, - 0x18,0xb4,0x2e,0xde,0x60,0xaf,0xfb,0x73,0xb8,0x21,0x50,0x99,0x5f,0xf6,0x51,0x1a, - 0xf2,0xe3,0x63,0x57,0x27,0x2f,0x9b,0x87,0x9f,0xf8,0xe7,0xee,0x4a,0x00,0x22,0xd3, - 0x07,0x99,0xb3,0xcc,0x0a,0x8c,0xdd,0x61,0x22,0x64,0x2b,0xbc,0xa8,0x51,0x09,0xa0, - 0xcb,0xf5,0xd8,0xcf,0x07,0x63,0x3c,0x77,0x5c,0xcd,0xec,0xd8,0x85,0xdb,0xcf,0x05, - 0x85,0x72,0xdc,0x10,0x80,0x3c,0xd4,0xa5,0xd6,0x1c,0x1c,0x4c,0xf8,0x7b,0x3d,0x02, - 0x9f,0xac,0x05,0x25,0xef,0xb2,0x33,0xa0,0x58,0x15,0x3c,0x96,0x91,0x5a,0xd8,0x93, - 0x59,0xaa,0x96,0x61,0x32,0xcb,0xa5,0x9c,0xab,0xb5,0x2d,0xc3,0x07,0x12,0x08,0xf0, - 0xdd,0xf6,0xf3,0x9e,0xa9,0x1a,0x76,0xde,0x25,0x94,0xa0,0x00,0xff,0xc9,0xc7,0x98, - 0x22,0xda,0xbd,0x1d,0x95,0x94,0x77,0xa3,0xaa,0xb3,0x89,0x7a,0x5e,0xe4,0xd4,0xb1, - 0x65,0xee,0xd0,0xb9,0xa0,0x9c,0xac,0xae,0xa4,0x27,0xd3,0x33,0xa3,0xfc,0x5c,0x2e, - 0x9d,0x22,0x27,0x72,0xb5,0x73,0x49,0xb1,0x17,0xf9,0xb5,0x4d,0x8e,0x6a,0x60,0x37, - 0x71,0x91,0xa2,0x57,0xb9,0xec,0x97,0x61,0x70,0x32,0xd0,0x89,0x29,0x49,0xb6,0xc3, - 0x66,0x96,0x60,0xf5,0xd3,0x1a,0xee,0x00,0x66,0x02,0x05,0xd2,0x68,0xd5,0xb5,0xbd, - 0x42,0x26,0xde,0x9a,0xb9,0x3b,0x50,0x02,0xe0,0xf5,0xe0,0x02,0x1f,0xa3,0x81,0x87, - 0x84,0xba,0xb9,0x0a,0x91,0x52,0x33,0x1e,0xa5,0x7a,0x77,0xe3,0x12,0x7f,0x57,0x2b, - 0xea,0xd7,0xb5,0xbc,0x52,0x3b,0x6f,0x94,0x35,0xd2,0x5c,0x8f,0x21,0x2f,0xbd,0x9d, - 0x65,0x74,0x2d,0x61,0x24,0xa7,0x22,0x5c,0xad,0x5e,0x11,0xef,0x23,0x97,0x18,0xa2, - 0xe1,0x17,0xc5,0x44,0xaa,0xde,0xab,0x72,0x5c,0x70,0xe6,0xd1,0xd1,0xa1,0x51,0x80, - 0x03,0xab,0x34,0x77,0x6c,0x9d,0xe8,0x28,0xac,0x01,0x28,0x40,0x72,0xed,0x06,0x58, - 0x12,0xb9,0xfe,0xd7,0xfc,0x5f,0xf3,0x8f,0x4d,0xbe,0x69,0x89,0x15,0x24,0x4c,0x3a, - 0x61,0x2b,0x46,0x59,0xe4,0x89,0xcc,0x4f,0x19,0x4d,0xda,0xcd,0x7f,0x36,0x9f,0xaa, - 0x50,0xb2,0xd3,0xc3,0x9a,0xf0,0x29,0xbd,0x60,0x52,0xb7,0x91,0x34,0x2a,0x3a,0x6c, - 0x8f,0x47,0x9d,0x58,0x40,0x50,0xeb,0x1a,0xf9,0xb4,0x32,0xa2,0xf6,0x1c,0xa3,0xb8, - 0xed,0x11,0x46,0x23,0x88,0xa5,0xf3,0x89,0xa3,0x12,0x6c,0x47,0x48,0x10,0x35,0xd4, - 0xef,0x4a,0x38,0xc6,0x2b,0x5f,0xdb,0x47,0x2a,0xad,0x1e,0x8d,0x28,0xad,0x44,0x78, - 0x7b,0xff,0xca,0xc7,0x1f,0x9a,0x53,0xe5,0xa7,0x71,0x8d,0x5e,0x4b,0xb9,0xa3,0x68, - 0xae,0x15,0xd5,0x61,0x82,0xbf,0xb9,0x65,0x50,0x26,0xc1,0xd7,0xdd,0x8b,0xaa,0x6d, - 0x64,0x31,0x88,0x22,0xad,0x68,0x4f,0x38,0x4d,0xc8,0xd0,0x6b,0xdb,0x5d,0xdc,0x0c, - 0x55,0x6b,0x47,0x08,0xcc,0x47,0x03,0xad,0xca,0x90,0x65,0x10,0x64,0x0a,0x59,0x27, - 0xc1,0x8a,0x34,0x21,0xa1,0x29,0x05,0xc1,0x77,0xa2,0x25,0x50,0xc6,0x35,0x72,0xb6, - 0xfa,0xb7,0xfb,0x74,0x4a,0x15,0x17,0x05,0x89,0x4a,0x97,0x97,0x98,0x36,0x5d,0xa6, - 0x2b,0xfc,0x13,0xcf,0x8a,0xe0,0x54,0xa7,0x4a,0x28,0x5b,0x4a,0xbf,0xe7,0x46,0xce, - 0x81,0x67,0x08,0x06,0x02,0x41,0x6c,0x44,0xe5,0x6a,0xaa,0x6d,0x92,0x1b,0xdd,0x9a, - 0xac,0x79,0xbc,0xb2,0xc6,0xb2,0x41,0x5a,0xb6,0x19,0x07,0x16,0xfd,0x06,0x9c,0x99, - 0x28,0x0c,0x7a,0x98,0xdb,0x68,0x81,0x9c,0x92,0x38,0x4a,0xd3,0x15,0x99,0x2d,0x06, - 0xcc,0x07,0xf1,0xbd,0x03,0x06,0x7a,0xc1,0xa6,0xf1,0x22,0xab,0x01,0x34,0x92,0xbb, - 0x8e,0x24,0x62,0x7d,0x81,0xae,0x36,0x6e,0x8c,0x5a,0xc3,0xea,0xaf,0x64,0xe1,0xae, - 0xe5,0x73,0xe2,0xf1,0xd7,0x53,0xb3,0xa9,0x9b,0xab,0x4a,0x28,0xe6,0x2c,0x34,0xef, - 0xea,0x8e,0xbe,0x2d,0x76,0xb7,0x9b,0x8a,0x8d,0xce,0xb4,0x13,0xdb,0x7f,0x95,0x6d, - 0xd5,0x5d,0x7e,0xd6,0x2c,0x37,0xf6,0xfa,0x5d,0x1b,0xd7,0x7d,0xb6,0x6e,0x9b,0xcf, - 0x5e,0xbc,0x7c,0xf3,0xf2,0xe3,0x4b,0xbb,0x6d,0x1a,0xdb,0xc7,0xa3,0x2a,0x47,0x86, - 0x6c,0x7a,0x6d,0x63,0x11,0xa7,0xa8,0x2d,0x79,0xcd,0x60,0x9b,0x55,0xe5,0xac,0xe2, - 0x16,0x68,0xa0,0x73,0x65,0xea,0x9d,0x38,0x14,0x8f,0x6f,0x50,0x5e,0x67,0xe2,0x3a, - 0x94,0xeb,0x2e,0xdf,0xf4,0x23,0x6c,0x60,0x56,0x7c,0x61,0xae,0x55,0x8f,0xbc,0xad, - 0x4e,0x36,0xb5,0xf9,0x6e,0x8d,0x52,0xff,0x76,0x63,0x57,0xfe,0x4f,0x68,0xaa,0x67, - 0xeb,0x1a,0x98,0x7d,0xcc,0x7f,0x57,0x62,0xcd,0x5f,0xc9,0xdb,0xc2,0x83,0x8e,0x26, - 0x76,0xd7,0x3b,0x75,0xb3,0x0c,0xd7,0xce,0x31,0x31,0xa7,0x02,0x17,0xcc,0x05,0x85, - 0x7e,0xa6,0xbd,0x68,0xf7,0xc1,0xc6,0xb1,0xae,0x25,0xd4,0x2f,0xdc,0xed,0x4d,0xa4, - 0x6a,0xee,0x40,0xc6,0xf3,0x5a,0x9c,0xf5,0x2f,0xc8,0xe1,0x18,0xa2,0x40,0xf3,0xba, - 0x82,0xd5,0xd4,0x26,0x55,0xfd,0x14,0x25,0xb1,0x6a,0xde,0x8b,0xc3,0xde,0xc4,0x95, - 0x6d,0x12,0x55,0xe5,0x58,0x4d,0xc1,0xa2,0x2d,0x65,0xff,0x9e,0x29,0x8c,0xa1,0x6e, - 0xbc,0x81,0xab,0x26,0x19,0x95,0xb6,0x28,0x52,0x36,0x8b,0x01,0xaa,0xa5,0x4b,0xb0, - 0xea,0x4e,0x16,0xc1,0x56,0xb2,0x53,0x01,0xbd,0x9a,0xa6,0xd7,0x00,0x25,0x02,0xf7, - 0x52,0x0d,0x3c,0x5c,0x34,0xe6,0x01,0xc1,0xf4,0xad,0x1f,0x59,0x96,0x04,0x4d,0x93, - 0xc3,0x6f,0x0b,0xb6,0x60,0x8d,0xbb,0x2a,0x9b,0x50,0x30,0x3b,0xa9,0xb2,0x88,0x35, - 0xf5,0x0e,0x23,0x52,0xe5,0x2d,0xf7,0xa2,0xb4,0x23,0xfa,0xed,0x7b,0x8e,0x66,0xaf, - 0xb0,0xc6,0x53,0x73,0x1d,0x32,0x18,0xa6,0xd4,0xca,0xbe,0xbf,0x1c,0x7b,0xec,0xca, - 0xa8,0xa5,0xcb,0x36,0x59,0x54,0x95,0x1a,0x66,0x8e,0x42,0x49,0x22,0xb9,0x39,0xde, - 0x08,0x49,0xb2,0x83,0x60,0xff,0xfd,0x6f,0xff,0x01,0xec,0xcc,0xf3,0x69,0xa1,0x59, - 0x71,0x4f,0x5b,0xd7,0x89,0xba,0x69,0xaf,0x29,0x15,0xb4,0x82,0xcc,0xa3,0x19,0xf7, - 0x56,0xdd,0x5b,0x5b,0xfd,0x5b,0x4d,0x92,0x01,0x18,0xad,0xf3,0x9b,0x9a,0x8e,0x4a, - 0x8e,0x6f,0x3a,0x76,0x91,0xd8,0x10,0xbe,0x60,0xa2,0xdd,0x29,0xdd,0xed,0x5c,0x3e, - 0x56,0x6f,0xf0,0xa3,0x5f,0xb1,0xac,0x88,0x51,0x09,0x77,0xba,0xc1,0xa4,0x60,0x21, - 0x1a,0x04,0xd5,0xba,0x5b,0x0c,0x27,0x5c,0x66,0xc7,0xe9,0xdd,0x0f,0x7c,0x75,0xde, - 0xa2,0xc4,0x33,0xc6,0x37,0x2a,0x97,0x8f,0xd8,0xa2,0x57,0x66,0x54,0xd7,0x76,0x53, - 0x59,0x6d,0xeb,0x1f,0x8a,0x86,0xde,0x76,0x99,0x0a,0x75,0x35,0xd5,0x39,0xba,0x55, - 0xa9,0xa0,0xc3,0xdd,0x8d,0x44,0x83,0xe1,0x30,0x52,0x64,0xad,0x54,0x1b,0xf9,0xb1, - 0x5d,0xae,0xae,0x6e,0xc9,0xdc,0x96,0xf3,0x54,0xec,0xb5,0x5e,0x70,0xe6,0x0e,0x03, - 0xa6,0x58,0x6c,0x1e,0x99,0x70,0x48,0x65,0x58,0xde,0x75,0xe0,0x90,0x83,0x45,0xa4, - 0x53,0x81,0x52,0x8c,0xb1,0xed,0x52,0xa5,0xa1,0xba,0xe2,0xa9,0x3b,0x15,0x8d,0x9e, - 0x4b,0x69,0xa9,0x65,0xcd,0x58,0xf7,0x40,0xa6,0x6e,0x60,0xc5,0x7a,0x27,0xd5,0xf1, - 0x9f,0x37,0xef,0x05,0xf9,0xf4,0xea,0x04,0xf8,0x7e,0x75,0x0a,0xb2,0x28,0x5b,0xdd, - 0xb0,0x23,0x48,0xbe,0x82,0x44,0xd8,0x4e,0x8a,0x65,0xee,0xcb,0xd6,0x34,0x58,0xa1, - 0xfb,0xbb,0x9c,0xc3,0xe2,0xfe,0x7e,0x7e,0x88,0x3f,0xa3,0x8a,0x77,0xba,0xbf,0x2f, - 0xef,0xe8,0x0b,0xa5,0x1a,0x25,0xe4,0x48,0xfb,0x68,0x4e,0x79,0x3b,0x7a,0x19,0xc5, - 0x86,0x05,0x4d,0x16,0xcf,0xec,0x10,0x6b,0xdc,0xe3,0xf2,0x4e,0x27,0x19,0x1e,0xe3, - 0x86,0xba,0x14,0x7f,0x71,0x6e,0x38,0x66,0x3f,0x42,0x90,0xdf,0x29,0x9d,0x00,0x63, - 0x3d,0x46,0x45,0x78,0x71,0x4e,0xbf,0xad,0x1c,0xc3,0x8e,0x95,0xe8,0xb9,0xd0,0x08, - 0xb9,0xe1,0x12,0xcf,0xdb,0x14,0xe3,0x47,0xdc,0xd6,0x44,0x27,0x0c,0x1b,0x8e,0xb1, - 0x7e,0x1d,0x80,0x50,0x16,0xec,0xaf,0xce,0xfa,0x46,0x3e,0x54,0x5f,0x8b,0xfa,0x64, - 0xac,0x8f,0x3b,0x93,0x93,0xa4,0x39,0xb5,0x3e,0x24,0xcf,0xbb,0x62,0x31,0xb9,0x4f, - 0xe0,0x53,0x04,0x0d,0xfa,0xae,0xed,0x0f,0x92,0xe4,0x26,0x88,0x7d,0xf0,0xe4,0xfb, - 0x10,0x00,0x37,0xae,0xb6,0x3e,0x30,0x2a,0x4b,0x81,0x0b,0x24,0x53,0xd0,0x8d,0x48, - 0x0d,0x24,0x95,0x3b,0xb8,0x83,0x59,0xe5,0x1d,0xb8,0x49,0xaa,0xe2,0xd9,0x8a,0x2c, - 0xa9,0x60,0x55,0x15,0x22,0xd5,0x7a,0x6d,0x5c,0x44,0xe2,0xa3,0xbd,0x07,0xfe,0x8c, - 0xd3,0x42,0x95,0x89,0x34,0x1a,0x67,0x05,0x70,0x0f,0xb2,0x0e,0x6a,0xdc,0xa0,0x15, - 0x63,0xdd,0xd8,0x20,0x95,0xfc,0xfe,0x78,0x40,0x77,0xa9,0x79,0x36,0x25,0x7f,0xa5, - 0xef,0x34,0xef,0xc5,0x03,0xe5,0xdd,0x96,0xb3,0x2f,0x5f,0xc7,0xf9,0x83,0xce,0x3e, - 0xf5,0xa2,0x7e,0xcb,0xdd,0xef,0xb6,0x68,0xf7,0x1d,0x76,0x64,0x49,0xd9,0xc9,0x76, - 0xec,0x34,0xc5,0x85,0x5e,0x2a,0x9b,0x94,0x9e,0xc1,0x63,0x2a,0x52,0x69,0xca,0x13, - 0x5b,0x9e,0x18,0x81,0x09,0x94,0x75,0xd5,0x01,0xdb,0xbe,0xb4,0xba,0x0a,0xce,0x69, - 0x91,0xb8,0x17,0x52,0xb9,0x8d,0x64,0x2a,0xa5,0x47,0x74,0xa3,0xa8,0x06,0x4b,0x3a, - 0x16,0xaa,0xaa,0xa9,0xb8,0xc7,0xde,0xc1,0x35,0xc8,0x34,0x81,0x6d,0xae,0x04,0x8e, - 0x98,0x15,0xb8,0x1d,0x52,0xbc,0x63,0xf2,0x30,0x2b,0xd6,0x57,0x52,0x60,0xff,0xb1, - 0x39,0x12,0x03,0x45,0xec,0x20,0x78,0x60,0x09,0x57,0xb6,0x4e,0x62,0xd1,0xb7,0x6d, - 0x4f,0xa4,0xe6,0x18,0x55,0x9a,0xe5,0x42,0xee,0xa5,0xfc,0x03,0x72,0x2d,0xb0,0xfd, - 0x44,0xc8,0x4e,0x4b,0xd5,0xc0,0x88,0xb7,0x73,0x65,0xdb,0x8b,0x53,0x7a,0x0f,0xb0, - 0xfd,0xe3,0x1b,0x4c,0xe0,0x50,0x73,0x5e,0x81,0xa5,0x00,0x19,0x89,0xb9,0xad,0x05, - 0x25,0xb3,0xb8,0x65,0x49,0xd7,0xea,0x17,0x9e,0x83,0xd1,0x63,0xd8,0x1b,0x22,0xa9, - 0x6d,0xb3,0xa9,0x5b,0x99,0x24,0xd1,0x48,0x96,0x7a,0x7d,0x97,0x7d,0xff,0xbb,0x69, - 0x5d,0xda,0x69,0xec,0xc9,0x86,0xb5,0xbe,0xb6,0xbe,0xdb,0xbc,0x2d,0x2a,0xec,0xfe, - 0x5d,0x6c,0x77,0xad,0x7e,0x2b,0x7d,0x65,0x32,0xd5,0xca,0xe9,0xfd,0xba,0xf5,0x0a, - 0x77,0xc2,0xf7,0x6f,0xda,0x5f,0x97,0x3f,0x91,0x3f,0x1a,0x72,0x22,0x7f,0xcb,0xfe, - 0x7f,0x00,0xca,0xe6,0xde,0x64,0xdc,0x5e,0x00,0x00, + 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xb5,0x3c,0x5b,0x72,0xdb,0x48, + 0x92,0xff,0x3a,0x05,0x44,0xcf,0x0a,0x44,0x0b,0x04,0x49,0xc9,0x92,0xd5,0x80,0x40, + 0xad,0x2c,0x59,0xd3,0x9e,0xb6,0xdb,0x0e,0xdb,0x1d,0x1d,0xd1,0x1e,0xc7,0x04,0x48, + 0x14,0x09,0x58,0x20,0x80,0x06,0x40,0xd1,0x1c,0x8a,0x11,0x73,0x88,0x39,0xc3,0x5e, + 0x61,0xff,0xf7,0x28,0x73,0x92,0xcd,0xcc,0x7a,0xa0,0x00,0x92,0x6e,0xf7,0x6e,0x4c, + 0x3f,0x44,0xa0,0x50,0x8f,0xac,0x7c,0x67,0x56,0x02,0x97,0x87,0x61,0x36,0xa9,0x56, + 0x39,0x33,0xa2,0x6a,0x9e,0x8c,0x0e,0x2e,0xf1,0xc7,0x48,0x82,0x74,0xe6,0x77,0x58, + 0xda,0xc1,0x06,0x16,0x84,0xa3,0xcb,0x39,0xab,0x02,0x63,0x12,0x05,0x45,0xc9,0x2a, + 0xbf,0xb3,0xa8,0xa6,0xbd,0x0b,0x7c,0x58,0x4e,0x8a,0x38,0xaf,0x8c,0xb2,0x98,0xf8, + 0x9d,0x7e,0x3e,0xed,0x4d,0xb2,0xb4,0xcc,0x12,0xe6,0x7c,0x2e,0xaf,0x22,0x9f,0x4d, + 0xa7,0xd3,0xf0,0x6c,0x70,0xd6,0x19,0x5d,0xf6,0x79,0xc7,0x91,0x18,0x30,0x8a,0xa7, + 0xdd,0xc3,0x65,0x9c,0x86,0xd9,0xd2,0x79,0x7b,0x67,0x75,0xa7,0x8b,0x74,0x52,0xc5, + 0x59,0xda,0xb5,0xd6,0x0f,0x41,0x61,0xfc,0xe2,0xf3,0x67,0xf6,0xcf,0xbe,0xd9,0x0f, + 0xf2,0xb8,0x5f,0x56,0x41,0xb5,0x28,0x4d,0xfb,0x95,0xff,0xf1,0x93,0xfd,0xda,0x3f, + 0x61,0xdf,0xdb,0xef,0xed,0x5f,0xed,0xb7,0xfe,0x2f,0x30,0xdc,0x5f,0xe3,0x63,0xe6, + 0x9a,0x49,0xfc,0xc0,0x4c,0x3b,0x8c,0x8b,0x6a,0xe5,0x1e,0x0e,0xed,0x07,0x37,0x5d, + 0x24,0x89,0x3d,0x63,0x95,0xfb,0x67,0x3b,0x4e,0xa7,0x49,0x3c,0x8b,0x2a,0xf7,0xa7, + 0xc5,0x7c,0xcc,0x0a,0x3b,0xca,0x92,0xd0,0x7d,0x33,0xfe,0xcc,0x26,0x95,0x5d,0x06, + 0x2b,0x57,0x41,0x50,0xd9,0xf7,0x36,0xb3,0xd6,0xec,0xe8,0xa8,0xcb,0x9c,0x8a,0x7d, + 0xa9,0x6e,0xb2,0xb4,0x62,0x69,0xe5,0x57,0xd6,0xc6,0x1e,0x2f,0x4a,0xad,0xeb,0xd8, + 0xce,0xad,0xb5,0xbc,0x33,0xa6,0x00,0xfc,0xd8,0x09,0xe3,0x32,0x18,0x27,0x2c,0xf4, + 0x0f,0x87,0x1b,0xfd,0x6e,0xe0,0xe5,0x4e,0x15,0xb1,0xb4,0x3b,0xb5,0xa7,0x96,0x57, + 0xb0,0x6a,0x51,0xa4,0x46,0xbe,0xb1,0xf3,0x2c,0x49,0xea,0x19,0x4b,0x7b,0x6e,0x4f, + 0xec,0x8c,0x63,0xa1,0xb2,0xa7,0xf6,0xcc,0x1f,0x7a,0x6a,0x85,0x77,0xb0,0xc2,0xec, + 0xe8,0xe8,0x70,0x0a,0xb0,0x4d,0xfd,0xa1,0x3d,0x49,0x58,0x50,0x7c,0x88,0xe7,0x2c, + 0x5b,0x54,0xdd,0xca,0xb2,0xbb,0xa5,0x33,0x09,0x92,0xe4,0xaa,0xec,0x5a,0xee,0x9f, + 0xbb,0xa5,0x65,0x89,0x15,0xe5,0xec,0xa1,0xb5,0x9e,0x74,0x43,0x1b,0xb1,0x02,0x7b, + 0x51,0xcd,0x0c,0x9b,0x09,0x55,0xcc,0xda,0x88,0x31,0x3f,0xda,0x3f,0x5a,0xd6,0x46, + 0xad,0xfc,0x23,0xac,0x3c,0xf5,0x07,0x5e,0x6b,0x45,0x0f,0xa0,0xe9,0x56,0x3e,0xb0, + 0x84,0x6c,0x7b,0x67,0xcf,0x61,0x5c,0x76,0x74,0x94,0x39,0xd3,0xb8,0x28,0x2b,0xdf, + 0x07,0x44,0x5c,0xc1,0x70,0x17,0x80,0x17,0xdb,0x06,0x72,0x65,0xb9,0xab,0x91,0x7c, + 0xb6,0x3d,0xf3,0xc6,0x86,0x49,0xeb,0x3e,0xa9,0xb5,0x9e,0xfb,0xa9,0x37,0x7d,0x7c, + 0x84,0xa9,0x36,0x76,0x9a,0x2d,0xdd,0x77,0x1b,0xe8,0x43,0x6c,0x51,0x77,0x9b,0xc0, + 0x4e,0x8e,0x8e,0x5e,0x39,0xf9,0xa2,0x8c,0xe0,0xc6,0x7b,0x7f,0x05,0xb7,0x93,0xee, + 0x7b,0xcb,0xfd,0xf5,0xea,0x57,0x07,0x46,0x01,0x1c,0xbf,0xfa,0x6f,0x1d,0x44,0x7a, + 0xf7,0x67,0xfb,0xb5,0x7d,0x0b,0x93,0x2d,0x83,0x6a,0x12,0xbd,0x6f,0xcd,0x34,0xb7, + 0xd6,0x6f,0x1d,0x3e,0x3d,0xc0,0xfd,0xab,0x03,0xd0,0x74,0x5f,0xfb,0xaf,0x83,0x2a, + 0x72,0xe6,0x31,0x3c,0xb6,0x5f,0x5b,0x34,0x34,0xae,0xee,0xb2,0xe2,0x96,0x3d,0xc4, + 0x13,0x56,0x0f,0x06,0xfa,0x65,0x7e,0xf6,0xf8,0xb8,0xde,0x48,0x42,0xa7,0x6c,0x69, + 0xbc,0x2d,0xb2,0x79,0x5c,0xb2,0x9a,0x1c,0x2b,0x3b,0xe5,0x84,0x8e,0x6a,0x90,0x4e, + 0xd8,0x69,0x4d,0x98,0xd2,0x5a,0x97,0x40,0xee,0x6e,0xe6,0x8c,0x17,0x71,0x12,0x1e, + 0x1d,0x95,0xfc,0xc2,0xf7,0x45,0x8b,0x05,0xe8,0x8f,0x1c,0x44,0x67,0xd7,0xb2,0x57, + 0x48,0xf1,0x8d,0xe5,0x69,0xd4,0xd0,0x70,0x2c,0xbb,0x79,0x69,0xf7,0x45,0x51,0x64, + 0x45,0xd7,0xac,0x78,0x27,0x13,0x37,0x92,0x39,0xe2,0xee,0xf1,0xf1,0x7b,0xf6,0x14, + 0x66,0xd9,0x6c,0x6a,0xb6,0xfb,0x73,0x77,0x81,0x2c,0x29,0xb6,0x32,0x65,0x80,0x2e, + 0x6a,0x69,0x71,0x57,0x61,0xad,0x51,0xaa,0x0b,0x27,0xbb,0xb7,0xaa,0xa8,0xc8,0x96, + 0x06,0x5f,0xa8,0x10,0x78,0x54,0x5c,0x4f,0xdc,0x81,0x92,0x75,0x55,0xd0,0x0f,0x10, + 0xa5,0x00,0x85,0x81,0x60,0x6e,0x34,0x9e,0xbb,0xc5,0xfd,0xc3,0x8c,0xf0,0xf7,0x3d, + 0xc8,0x79,0x3e,0xe5,0x34,0xf2,0x4b,0xef,0x95,0x33,0xcd,0x8a,0x17,0x01,0x80,0xa1, + 0x16,0x9f,0x02,0x7f,0x42,0x4f,0x04,0x7c,0x63,0x75,0x2d,0xa5,0x6f,0x0e,0xb8,0xe2, + 0x4a,0x83,0x39,0xf3,0x3b,0x0f,0x31,0x5b,0xe6,0x59,0x51,0x75,0x8c,0x89,0x90,0xe9, + 0xce,0x32,0x0e,0xab,0xc8,0x0f,0x89,0x80,0x3d,0xba,0x01,0x4d,0x11,0x57,0x71,0x90, + 0xf4,0x4a,0x90,0x25,0xe6,0x0f,0x51,0xcb,0x55,0x71,0x95,0xb0,0xd1,0xdb,0xa0,0xaa, + 0x58,0x01,0x7a,0x04,0xb6,0xd6,0x33,0x7e,0x89,0x7b,0x77,0xf1,0x65,0x9f,0x3f,0x02, + 0x45,0x58,0xad,0xf0,0xb7,0xff,0x9d,0x71,0xc3,0x55,0xa0,0x31,0x0e,0x4a,0xe6,0x1a, + 0x80,0x23,0xa3,0x84,0xd5,0x8d,0x71,0x92,0x4d,0xee,0x8d,0x2c,0x67,0x69,0x69,0xb0, + 0x07,0x56,0xac,0x00,0x88,0x82,0x19,0x79,0x30,0x63,0x8e,0xf1,0x0a,0x55,0x93,0x11, + 0xa7,0x86,0x5b,0x64,0x59,0x65,0x74,0x71,0xd4,0x04,0x70,0x38,0x67,0x66,0x79,0x60, + 0x18,0xf0,0x04,0x15,0x15,0x0b,0x0d,0xd2,0x61,0x30,0x28,0x61,0x00,0x8b,0x81,0x4a, + 0xac,0xc4,0x25,0x4a,0xb1,0xc8,0x43,0x90,0x2c,0x58,0xe9,0x1a,0xf7,0x8c,0xe5,0xb4, + 0x74,0xb5,0xcc,0x70,0xda,0xb2,0x62,0xb9,0x65,0xe3,0x4c,0x61,0x50,0xdc,0x1b,0x8b, + 0x34,0x64,0x05,0x29,0xfc,0x8f,0x61,0x50,0x05,0x3d,0xe8,0x09,0xf8,0xc1,0x47,0x9f, + 0x1c,0xe3,0xa7,0xcc,0x58,0xb2,0xb1,0x31,0x05,0x14,0x95,0x1c,0xfe,0x28,0xab,0xca, + 0x1c,0xc0,0x8a,0x82,0xd2,0x48,0x71,0x3e,0x44,0x03,0xab,0x1c,0xe3,0xbb,0xfe,0x01, + 0x01,0xbc,0x9e,0x64,0x49,0x56,0x00,0xc6,0x70,0x1e,0x97,0x60,0xf4,0x7a,0xbd,0x49, + 0xc1,0x82,0xb9,0xfb,0xe4,0xee,0xe9,0x8b,0xbb,0x17,0xe7,0x70,0x9f,0x07,0x29,0x4b, + 0xe0,0xfe,0xee,0xee,0xe6,0xee,0x1a,0xee,0xe3,0xf4,0xde,0x7d,0x32,0xbc,0x1e,0x5e, + 0x0c,0x9f,0xc2,0xdd,0x7c,0x01,0xfb,0x73,0x9f,0x9c,0x9f,0x9c,0xdd,0x9c,0x0d,0xe1, + 0x7e,0x1a,0xc0,0x3a,0xee,0x93,0x67,0xb7,0xcf,0xce,0xcf,0x2f,0xe0,0xbe,0x58,0x24, + 0xcc,0x7d,0x72,0x7b,0x7b,0x7b,0x76,0x73,0x2e,0x6e,0x7b,0x65,0x36,0x85,0x2e,0x2f, + 0x2e,0x5e,0x0c,0x6f,0x71,0x8a,0x59,0x94,0x95,0x78,0x7f,0x7a,0x7b,0x73,0xf3,0x02, + 0xee,0x13,0x9c,0xf0,0xee,0xee,0xec,0xe6,0x04,0xef,0xc6,0x01,0xdc,0x3d,0xbf,0x38, + 0xbd,0x19,0xde,0xc0,0x5d,0x06,0x6b,0x9f,0x3c,0x7f,0x76,0xfd,0xf4,0x39,0xdc,0x2c, + 0x83,0x22,0x75,0x9f,0x5c,0x9c,0x9d,0x0f,0x06,0x2f,0xbc,0x83,0x5e,0xaf,0x0c,0xd2, + 0xd2,0x2d,0x57,0x80,0xb5,0x79,0x6f,0x11,0xdb,0xbd,0x20,0xcf,0x71,0x35,0x6a,0xb0, + 0xcd,0xf7,0x6c,0x96,0x31,0xe3,0xe7,0x97,0xa6,0xfd,0x2e,0x1b,0x67,0x55,0x66,0x63, + 0xf7,0x5e,0xc9,0x8a,0x78,0x8a,0xfb,0xc8,0xd2,0xcc,0x5d,0xc4,0xf4,0x5b,0xe6,0xc1, + 0x84,0xd9,0xe6,0x4d,0x00,0xbc,0x14,0xc6,0x81,0xf1,0x1a,0xda,0x4c,0x98,0xe0,0x4e, + 0x5c,0xbd,0x66,0x69,0x92,0xd9,0x9c,0x61,0x82,0xd2,0x36,0xf9,0x7c,0xe2,0xa1,0x9a, + 0x60,0x73,0xb0,0x93,0x52,0x4d,0xa4,0x63,0x53,0x8d,0xf3,0xc1,0xcd,0xe0,0xf9,0xe0, + 0xfb,0x1a,0xe7,0xc3,0xd3,0xe1,0x70,0x38,0x90,0x38,0x7f,0x71,0xfb,0xe2,0xd9,0xed, + 0xf3,0x1a,0xe7,0xd7,0xa7,0xdf,0x3f,0xbf,0xb8,0xd6,0x70,0x7e,0xfd,0xec,0xf4,0xfc, + 0xa9,0xc2,0xf9,0xc9,0xf3,0x93,0x67,0x27,0xc3,0x26,0xce,0x87,0x77,0xc3,0x9b,0xe1, + 0x45,0x8d,0xf3,0x93,0xeb,0x93,0xf3,0x93,0x81,0xc4,0xf2,0xdd,0xdd,0xb3,0xeb,0xb3, + 0x33,0x81,0xe5,0xb3,0x67,0xcf,0x2f,0x9e,0xdd,0x29,0x2c,0xdf,0x7e,0x7f,0x3d,0x38, + 0xbd,0xdb,0x1c,0x7c,0xb7,0x1e,0x67,0x5f,0x7a,0x65,0xfc,0xf7,0x38,0x9d,0xb9,0xe3, + 0xac,0x00,0x8e,0xec,0x41,0xcb,0xe6,0x63,0x14,0x87,0x21,0x4b,0x3f,0xad,0xc1,0x76, + 0xe6,0x09,0x58,0xe6,0x34,0x4b,0xd9,0x61,0x3c,0x47,0xc1,0x0d,0xd2,0x6a,0x73,0x30, + 0xce,0xc2,0xd5,0x7a,0x1e,0x14,0xb3,0x38,0x75,0x07,0xde,0x38,0x98,0xdc,0xcf,0x8a, + 0x0c,0x38,0xda,0x05,0x55,0xda,0x15,0x18,0xb0,0x3c,0x42,0x8e,0x68,0x82,0x4d,0x5b, + 0x1e,0xf2,0xb3,0x3b,0x3c,0xcb,0xbf,0xf4,0x87,0xce,0x99,0xc1,0x1f,0x20,0xe1,0x2c, + 0xaf,0x07,0xec,0x7e,0x1f,0x57,0x3d,0xec,0xd1,0x2b,0xe7,0xc0,0xcf,0x11,0xc2,0x04, + 0x8b,0x81,0x1a,0x88,0x41,0x8a,0xc3,0xcd,0x41,0xc0,0xb1,0xed,0xc6,0x69,0x04,0x74, + 0xae,0x36,0xee,0x34,0x9b,0x2c,0xca,0xde,0x43,0x5c,0xc6,0x60,0xdf,0xd7,0xa0,0x39, + 0x93,0x38,0x65,0xee,0x49,0xfe,0xc5,0x00,0x5a,0xc6,0xa1,0x58,0x00,0x38,0xd0,0xf2, + 0xc4,0xc3,0x5e,0x36,0x9d,0xa2,0x51,0x83,0x3e,0x9b,0x03,0x67,0x59,0x04,0x39,0xec, + 0xe2,0x0b,0x57,0x3a,0xee,0xb3,0x93,0x41,0xfe,0xc5,0x93,0xbb,0x32,0x82,0x45,0x95, + 0x79,0x79,0x10,0x86,0x08,0x08,0x3e,0x32,0x86,0xe7,0xf0,0xe7,0xe9,0x05,0x8e,0x8d, + 0x4e,0xd4,0xf6,0x8d,0x81,0x01,0xed,0x1e,0x87,0x3c,0xfe,0x3b,0x73,0x87,0xa7,0xf2, + 0x76,0xc9,0xc8,0xdd,0x01,0x96,0x6e,0xe0,0x82,0x48,0x6e,0x01,0x00,0x93,0xa0,0x08, + 0xd7,0x5b,0xd8,0x23,0x7e,0xb1,0x3c,0x4e,0x0f,0x77,0xd8,0xda,0x0e,0x32,0x80,0x7c, + 0xd8,0x2b,0x80,0xa5,0xc1,0x64,0x0e,0x11,0x70,0x09,0x2a,0x42,0x09,0x73,0x8f,0xab, + 0x54,0x91,0x2f,0x4e,0x69,0xf3,0xd3,0x84,0x7d,0xf1,0x00,0x9d,0xb3,0xb4,0x17,0x83, + 0x14,0x95,0xee,0x84,0xa1,0x1a,0xf1,0x3e,0x2f,0xca,0x2a,0x9e,0xae,0x7a,0x42,0x23, + 0xcb,0xe6,0x59,0x90,0xbb,0xb8,0x33,0x30,0xb6,0xbd,0x88,0xef,0xe4,0xa9,0xbe,0xd0, + 0x80,0x10,0xf2,0x47,0xe0,0xbc,0xc0,0xee,0x7b,0xb6,0xbb,0x9b,0x59,0xce,0x06,0xb0, + 0xca,0x53,0x98,0x5a,0x67,0x16,0x34,0x58,0xbd,0x90,0x81,0xee,0x0e,0xd0,0xf0,0x10, + 0x77,0x7a,0x93,0x45,0x51,0xc2,0x04,0x79,0x46,0xaa,0xd1,0xab,0x0a,0xe8,0x1a,0xd3, + 0x63,0x01,0x03,0x2d,0x60,0x38,0xc3,0xb3,0xd2,0xae,0x61,0xe0,0xf7,0xf5,0x23,0x8e, + 0x38,0x27,0x2f,0xe2,0x6d,0xba,0x10,0x54,0xfa,0x64,0x7a,0xbb,0xde,0xc0,0xd9,0x7f, + 0x73,0xf0,0x9f,0x73,0x06,0x1a,0xa7,0x1b,0x65,0x60,0x6a,0x5c,0xfa,0x6b,0xad,0x71, + 0x7a,0x7e,0xbd,0xde,0x33,0xd5,0x46,0x42,0x20,0xbb,0xb5,0xe1,0x20,0x86,0xde,0x31, + 0x98,0xda,0x79,0xc3,0x13,0xf0,0xfa,0x37,0x53,0x90,0x22,0x30,0x31,0x81,0x98,0x67, + 0x6b,0x1d,0xbe,0x57,0x57,0xfa,0xc7,0xeb,0x0c,0x14,0x5d,0x0c,0x6e,0xbb,0xf3,0xf4, + 0x4c,0x62,0x33,0x64,0xd3,0x60,0x91,0x54,0xbb,0x56,0x23,0xfa,0x0a,0x74,0xc5,0x93, + 0x35,0x17,0xa1,0x26,0x7f,0xc0,0xd3,0x79,0x39,0x5b,0x73,0xa9,0x3f,0x51,0x44,0x44, + 0xa5,0xda,0x44,0x18,0xe9,0x3c,0xd8,0x38,0x04,0x2f,0xd9,0x7d,0x03,0xd0,0xec,0x9e, + 0x37,0xb3,0xa2,0xb9,0x01,0x50,0x71,0x24,0x40,0x51,0x9c,0xb7,0xb9,0x9c,0x8c,0xbc, + 0xc6,0xa4,0x17,0x7f,0x8c,0x47,0xbf,0xff,0x5e,0x48,0xaf,0x3b,0x84,0xee,0x7d,0x12, + 0xfc,0x7d,0x70,0x73,0x41,0xf6,0x96,0x11,0x88,0x53,0x8f,0xec,0x04,0xf0,0x22,0x6a, + 0x15,0x00,0x2d,0xcd,0x2a,0xf0,0x67,0x14,0x70,0x4d,0xa8,0x08,0x1b,0xc8,0xd7,0xdf, + 0x04,0x59,0xc2,0x40,0xdd,0x9f,0xee,0x52,0x6b,0xdf,0x2e,0x5e,0x9a,0x7a,0xc2,0x65, + 0x77,0x89,0xd0,0x46,0xc0,0x6c,0x8c,0xd7,0xba,0xf6,0x02,0x11,0xdc,0xb9,0x43,0xce, + 0x5e,0x6a,0x83,0xdf,0xaa,0x5c,0x68,0x92,0xde,0x98,0x55,0x4b,0xc6,0x52,0xd2,0x31, + 0xa4,0x45,0xb8,0x36,0xed,0x61,0x54,0x42,0x4c,0x24,0x76,0x86,0xf7,0xbb,0x71,0xf3, + 0xcd,0x5c,0x75,0x20,0xe5,0xe0,0x5b,0xd5,0x61,0x5b,0xdf,0xed,0xa0,0xf8,0x4e,0xf4, + 0x1d,0x60,0x94,0xfe,0x35,0x8c,0xa0,0x37,0x8a,0x2b,0x7b,0xf8,0xa4,0x87,0x58,0x74, + 0xf1,0x0f,0x21,0x01,0x75,0x1c,0xee,0x46,0x22,0x02,0x9c,0x90,0x2a,0x9b,0x93,0xdd, + 0x81,0x89,0x87,0x6b,0x1c,0xe2,0x0e,0x95,0x75,0xd2,0xe8,0x79,0x72,0xb2,0xc3,0xdc, + 0x90,0x6f,0x5a,0x10,0xc5,0x90,0xdf,0x7a,0xce,0x60,0xc8,0xe6,0xc0,0x95,0xe5,0x62, + 0xfc,0xed,0xf2,0x78,0x50,0x32,0xf2,0xec,0xd7,0x1a,0x71,0x4e,0xc8,0xfc,0x21,0xa7, + 0x30,0x69,0x01,0xa1,0x05,0x6c,0xe0,0xa0,0x6d,0x01,0x77,0x5a,0x3c,0xd4,0x16,0xe5, + 0x7c,0xad,0xa1,0xf8,0xf4,0xa4,0x69,0x52,0x4e,0xb6,0x6c,0xa9,0x18,0x16,0x06,0xe9, + 0x2e,0x15,0x10,0x4c,0xaa,0xb2,0x89,0xf2,0x16,0x76,0x77,0x50,0x18,0x11,0x7e,0xd1, + 0x64,0xba,0x21,0xb9,0x04,0x42,0x63,0x0b,0x23,0xe2,0x4e,0x32,0xcc,0xb5,0x70,0xa5, + 0x8d,0x60,0xe7,0x99,0x30,0x29,0x05,0x4b,0x80,0xf0,0x0f,0x6c,0x23,0x9e,0xb8,0x6e, + 0x30,0xad,0x48,0xc7,0x72,0x26,0xef,0x74,0x3c,0xd5,0x37,0x18,0x03,0xf3,0xc2,0xfe, + 0xbd,0x38,0x45,0xd7,0xa3,0x87,0x94,0x1e,0xa0,0xf2,0x9d,0xb6,0x94,0x83,0x40,0x27, + 0x51,0x66,0x60,0x3c,0xfd,0xba,0x4f,0x71,0xb6,0xc7,0xa7,0x88,0xd3,0x7c,0x51,0x01, + 0x3f,0x56,0xdd,0x8f,0x98,0x51,0xfa,0x64,0xd9,0xd4,0x42,0x37,0x3e,0xb2,0xed,0x27, + 0xbd,0x21,0x0f,0xca,0x72,0x09,0x92,0xf6,0x09,0x42,0xfd,0x04,0x88,0x2d,0xd4,0xf8, + 0x70,0x30,0xf8,0x8f,0xbd,0x66,0x1f,0xc9,0x3d,0x1c,0xfc,0xbb,0x0d,0x7f,0xdb,0xe8, + 0x6f,0xed,0xcc,0x07,0x9f,0x7b,0x72,0x0f,0xde,0xea,0x27,0x4b,0x6b,0xc4,0xf5,0x32, + 0x68,0x21,0xd7,0x50,0x6c,0x8a,0xdf,0x28,0xff,0x90,0xbc,0x85,0x7d,0xb6,0x17,0x4d, + 0xca,0xfd,0xb7,0x2a,0x0a,0xc5,0x46,0x2d,0x4c,0xb5,0x74,0xed,0xb6,0xaf,0xd0,0x70, + 0x55,0xf8,0x9a,0x06,0x6d,0x4f,0xe2,0x1f,0x67,0x15,0x33,0x0e,0x2f,0x34,0xa7,0xd4, + 0x0b,0x26,0xb8,0xf6,0x2e,0xb8,0x93,0xb8,0xac,0x6a,0x97,0x5c,0x09,0x94,0x87,0xed, + 0x3d,0x8a,0x8c,0x1b,0x3b,0xdf,0xab,0x58,0xc5,0x54,0xa3,0x24,0xfe,0x5d,0xd5,0x4e, + 0xca,0x7b,0xd0,0x42,0xc0,0x85,0xc6,0x2a,0xe8,0x2f,0x0f,0x3c,0x15,0x58,0x90,0x46, + 0xdb,0xb5,0x28,0x05,0x34,0x72,0x65,0xc3,0x49,0xe7,0x4a,0xdd,0xc1,0xc4,0x1c,0x25, + 0x03,0x0f,0x9d,0x18,0x8c,0xfb,0x5d,0x1e,0x9c,0x70,0x1d,0xac,0x1a,0x59,0x92,0xc4, + 0x79,0x19,0x97,0x3b,0x4c,0x55,0x8b,0x1e,0xf5,0x32,0xeb,0x7a,0xfa,0x93,0x81,0xb2, + 0xfa,0xdf,0xa2,0x18,0xc9,0xf1,0x70,0xc0,0x57,0xd9,0xc1,0x47,0x59,0xcb,0x1b,0x44, + 0x17,0xe6,0x20,0x64,0x55,0x10,0x27,0xa5,0xae,0x49,0x2f,0xb6,0x05,0x7c,0x97,0x40, + 0x97,0x8b,0x39,0x0c,0x5a,0xad,0x5b,0xfe,0xad,0xf2,0x24,0x06,0x84,0x63,0xe2,0x53, + 0x41,0x82,0x93,0xc1,0x9e,0xa9,0xfa,0xdf,0x19,0xff,0xfa,0xe7,0x3f,0xe0,0x3f,0x9e, + 0x38,0x91,0x37,0xdf,0xf5,0x41,0x9f,0xcf,0xed,0x27,0x65,0x19,0x87,0xf6,0x13,0x54, + 0x09,0xf6,0x93,0xa8,0xe4,0xbf,0x63,0xb0,0x9d,0xe0,0x1e,0x87,0xcc,0x26,0x95,0x6f, + 0x8c,0xed,0x96,0x93,0x30,0x0d,0xe6,0x71,0xb2,0x72,0x35,0x84,0x09,0xeb,0xb0,0xc3, + 0x8b,0xd8,0xe6,0x5a,0x3e,0x3f,0xad,0x29,0x48,0x6e,0xc0,0xbf,0xe7,0x92,0xa7,0x04, + 0xe9,0xa1,0xdf,0x94,0xcb,0x47,0x13,0x30,0x2d,0x76,0x3b,0x3d,0x27,0x43,0xe9,0x40, + 0x90,0x9f,0x22,0xeb,0xd6,0xfc,0xaf,0xf1,0xe6,0x40,0x74,0x30,0xc6,0x0b,0x60,0xc5, + 0x54,0x32,0xd9,0x1f,0x62,0x73,0xc9,0x8d,0x3a,0xcb,0x3f,0xd5,0x2d,0x98,0xae,0xe7, + 0x34,0x81,0x73,0xe5,0xf6,0x45,0xf4,0xca,0xd9,0x97,0x56,0x73,0xd1,0xbf,0xdb,0x56, + 0x0a,0x08,0x29,0x69,0x36,0x27,0x48,0x12,0xcb,0x48,0x62,0x37,0xad,0xa2,0x1e,0x30, + 0x5e,0x12,0x76,0xd3,0xe3,0x67,0x56,0x23,0x38,0x47,0x1b,0x09,0xb6,0x6a,0xbf,0xc8, + 0x92,0x51,0x64,0x69,0x48,0xbb,0x39,0xd1,0xd4,0x0b,0x0f,0x85,0x71,0xb0,0x11,0x0b, + 0xf5,0x73,0x5a,0x3f,0x7e,0x0a,0x86,0x60,0x67,0x20,0xa4,0xc6,0x1c,0xc7,0xeb,0x48, + 0xfa,0x1d,0xff,0xb1,0x51,0x8d,0x75,0xf3,0x45,0xb3,0xb9,0x7e,0x80,0x56,0x06,0xf7, + 0x39,0xc4,0x07,0xb6,0x53,0x9e,0xf0,0x0e,0x70,0x75,0xaa,0xba,0x6e,0xad,0x4d,0xb9, + 0x0e,0x5c,0x3d,0x5c,0xcd,0x6d,0xfc,0x63,0x00,0x43,0xa4,0xc7,0xf8,0xe7,0xff,0xe8, + 0x05,0x6c,0x70,0x96,0xb6,0x60,0xea,0x1a,0x4c,0xfe,0xcf,0x51,0xf5,0xe4,0x33,0x50, + 0x68,0xdd,0xf6,0x1c,0xa8,0x55,0x53,0x08,0x48,0xd2,0xb6,0x56,0x10,0x9d,0x30,0x94, + 0xd9,0xd7,0x8b,0xfb,0x34,0xd4,0xcf,0x70,0xc6,0xf1,0x6c,0x77,0x6c,0x23,0xb4,0xfc, + 0xb9,0x30,0xc4,0x06,0x57,0xb3,0x5c,0x7b,0x5d,0xb4,0xb4,0x97,0x54,0x90,0x1c,0x15, + 0x41,0xba,0x5a,0x02,0xfb,0x21,0xbb,0x94,0x6c,0xd6,0x44,0x98,0x64,0x8c,0x96,0x50, + 0xd5,0x29,0x90,0x3f,0x18,0x47,0xed,0x32,0xf9,0x32,0x32,0xc6,0xd5,0x8d,0x24,0x18, + 0xb3,0x44,0x0a,0xe1,0xb6,0x6b,0xc5,0x3b,0x71,0xb3,0xb8,0xed,0x4c,0xc9,0x60,0x75, + 0xa0,0x6c,0xa3,0x18,0xb0,0xcd,0x09,0xdf,0x9e,0xf1,0x68,0x1b,0xf2,0xe6,0x8e,0x9e, + 0xed,0x8e,0x05,0xda,0x5a,0xae,0x6d,0xfd,0xf7,0xe7,0x25,0xbe,0x96,0x85,0xc0,0xad, + 0xb8,0xe4,0xe2,0xb0,0x90,0x73,0xf7,0x37,0xfb,0x4f,0x94,0xd3,0x8b,0x82,0x10,0xac, + 0x22,0x26,0xa7,0xc0,0xa7,0x56,0x3c,0x41,0x84,0xb2,0xc9,0x11,0x85,0xf6,0x5e,0x6d, + 0xea,0x12,0xee,0x9e,0xd3,0xaa,0x8d,0xb4,0x1a,0x5f,0xfb,0x6b,0xb9,0x35,0x18,0x86, + 0x71,0xfb,0x74,0x8a,0x3d,0x8c,0x27,0x65,0x65,0x37,0xee,0xd1,0xd6,0x36,0x5b,0xa2, + 0x92,0xce,0x0a,0xeb,0x7c,0xc3,0xd9,0xfe,0x54,0x09,0x7a,0xfd,0xfb,0xd3,0x25,0x24, + 0x2e,0xc2,0x40,0xf2,0x5e,0xb6,0xe2,0x81,0x7d,0x59,0x0f,0xdd,0x02,0xf0,0x3e,0xe4, + 0x70,0xb4,0x23,0x3a,0x4a,0xcf,0x23,0xbc,0xe0,0xa9,0x5f,0xf6,0xf9,0xc9,0xc2,0x65, + 0x9f,0x9f,0xc3,0x62,0xf6,0x73,0x74,0x70,0x70,0x39,0x07,0x6f,0xc0,0x98,0x24,0x60, + 0x8f,0xfc,0x0e,0x8a,0x97,0x3c,0xa9,0x65,0xc5,0xe8,0x32,0x1a,0x8e,0xc4,0xe9,0x04, + 0x5c,0x5d,0x22,0x40,0xb2,0x27,0x84,0x60,0x1d,0x23,0x0e,0xe1,0xa2,0xea,0x8c,0x7a, + 0x30,0x37,0x3c,0x13,0x53,0xc3,0x40,0x98,0x56,0x44,0x5d,0xbc,0x4f,0xf0,0xc0,0xc2, + 0x8e,0xc1,0x5d,0x9e,0xd1,0x81,0x61,0x5c,0x46,0x27,0xa3,0xf7,0xd8,0x68,0xa4,0x10, + 0x42,0x67,0xc5,0x7d,0x09,0x43,0x4f,0xe8,0xc9,0x22,0x91,0x4b,0x20,0xce,0xf9,0x1a, + 0x74,0x05,0xb3,0x2f,0x12,0xea,0x92,0xcb,0x1e,0x68,0xa1,0x3b,0x02,0x2e,0xec,0x37, + 0x41,0xe8,0x05,0x2c,0x46,0x03,0xdc,0x79,0x39,0xab,0xa7,0xc2,0x9b,0x91,0x02,0x39, + 0xa7,0x39,0xc3,0xf8,0x81,0x9e,0xa3,0x45,0x06,0xd0,0x75,0x60,0xe1,0x29,0x09,0xb9, + 0x9c,0x6b,0xda,0x31,0xa6,0x59,0xc1,0xbb,0x76,0x46,0xcf,0xf1,0x98,0x45,0xec,0xc2, + 0x36,0xaa,0x22,0x86,0x4d,0xd1,0x81,0xa5,0x31,0x2d,0xb2,0x39,0x9d,0x7a,0xa4,0x40, + 0x15,0xa3,0x60,0xd8,0xff,0xb2,0x4f,0x53,0x89,0x69,0x71,0x51,0x31,0x29,0x06,0x80, + 0x1d,0x83,0x28,0x04,0xd0,0x0a,0x65,0xd0,0xe1,0xfd,0xa0,0x27,0x8f,0x01,0x14,0x84, + 0x04,0x3e,0x35,0xa9,0x1e,0x9c,0x17,0xe4,0x74,0xc0,0x74,0x1d,0x83,0x62,0x89,0x0e, + 0x7f,0xd0,0xa9,0x77,0x07,0x78,0xef,0x18,0x41,0x11,0x07,0x3d,0x82,0xc5,0xef,0x20, + 0x25,0x8c,0xb1,0xb6,0x8f,0x0e,0x11,0xe7,0xb2,0xcf,0x87,0xfe,0xb1,0x25,0xf8,0x3e, + 0x3b,0xa3,0x77,0x62,0xbf,0xad,0x39,0x76,0x12,0x05,0x7b,0xea,0x44,0xe1,0xd8,0xe9, + 0x03,0x7a,0x88,0x36,0xfc,0x02,0x77,0x4c,0x2c,0xd5,0xe6,0x2e,0xd0,0xec,0x1d,0xc9, + 0x54,0xd7,0x61,0x68,0x04,0x72,0x1b,0x8a,0xa7,0x80,0x5c,0x73,0xea,0x3a,0xed,0x68, + 0x98,0x27,0xce,0x04,0x31,0x02,0x4d,0xd3,0x24,0xb7,0xce,0x62,0x30,0xe2,0x27,0xc1, + 0xa2,0x44,0x4b,0x52,0x57,0x40,0x7f,0xd4,0x77,0x47,0xf3,0x30,0x28,0x23,0xcf,0xa8, + 0x82,0xdc,0x00,0xef,0x45,0xb0,0x12,0x8d,0x6f,0x72,0xb1,0x81,0xcb,0x74,0xd4,0x82, + 0x35,0x2b,0xef,0x46,0xab,0x51,0xce,0x77,0x61,0x76,0x9e,0x15,0x4c,0x02,0xda,0xe4, + 0x14,0x69,0xf0,0x71,0x62,0x1d,0xdf,0x0a,0x85,0xfb,0x58,0x18,0x9d,0x65,0xb5,0x41, + 0x3a,0xdb,0x6c,0x32,0x28,0xd9,0x2d,0x0e,0x37,0xf6,0x14,0xa7,0x9f,0xfc,0x1a,0x2c, + 0x6c,0xc2,0xd2,0x59,0x15,0xf9,0x9d,0xd3,0x93,0x0e,0xf0,0xf7,0x6f,0x8b,0xb8,0xa0, + 0x83,0xc5,0xb2,0x82,0x3e,0x8c,0xa5,0x1d,0xb1,0x43,0x3c,0x83,0x98,0x64,0xf3,0x3c, + 0x61,0x15,0x8c,0x06,0x0d,0xda,0xe1,0x4d,0x41,0x1e,0x57,0x60,0xd6,0xfe,0xce,0x50, + 0x92,0x53,0x26,0x5a,0xb3,0xa2,0x00,0xe2,0x8a,0x7e,0x65,0x0e,0x21,0x11,0x19,0x10, + 0x00,0x3a,0x48,0x4a,0xa6,0x08,0x18,0xe0,0xd0,0x52,0x00,0x87,0x8b,0xc1,0xde,0x65, + 0xe3,0xb6,0x78,0x09,0x77,0x1f,0x7c,0x24,0x8e,0x4b,0xba,0x10,0x34,0x27,0x9e,0x1c, + 0xdd,0x82,0x39,0x58,0x65,0x0b,0x63,0xce,0x80,0x41,0x8f,0x92,0xe0,0xb7,0x45,0xe6, + 0x5d,0x8e,0x65,0x67,0x9a,0x7e,0x3c,0x3a,0x2a,0xa8,0xfd,0x4a,0xe7,0x53,0xc1,0xd4, + 0xa3,0x6f,0xa6,0x23,0x4c,0xb7,0xc0,0x8d,0xfc,0x5c,0x32,0x23,0xae,0x25,0xe4,0x8f, + 0x8c,0xc7,0x53,0xd9,0xce,0xe8,0x47,0x3c,0x9b,0x05,0x6b,0x5f,0x4b,0xaa,0x52,0x6a, + 0xbf,0x43,0x77,0x8c,0x3e,0x3a,0xa3,0xb7,0x22,0x6f,0xf2,0x7f,0x55,0x4a,0x35,0x77, + 0xd0,0x7c,0x82,0x3b,0xf8,0x35,0x07,0x5b,0x66,0x66,0x1a,0xdc,0x72,0x7e,0x2a,0x19, + 0xe3,0xdf,0xc2,0x1a,0xdf,0xaa,0xa8,0xf2,0x65,0x25,0xd4,0x20,0xfa,0x4f,0x45,0x96, + 0x94,0x12,0x76,0x6a,0xcc,0x0b,0x56,0x96,0x2c,0x54,0x73,0xbf,0x8f,0xb2,0xe5,0x7e, + 0xe9,0x6a,0x23,0xed,0x2b,0xc2,0x9d,0x17,0xb1,0x04,0x07,0x8c,0xe8,0x3c,0x16,0x36, + 0x0e,0xb4,0x18,0x01,0xba,0xa5,0x98,0xbf,0xae,0x93,0x1b,0xe4,0x9d,0x44,0xf7,0x7c, + 0xb2,0x34,0x5b,0xa2,0x56,0x1b,0x09,0x12,0xf1,0xd5,0x64,0xaa,0x49,0x75,0x81,0x29, + 0x97,0x71,0x35,0x89,0x8c,0x14,0xb7,0xa6,0xf1,0xc0,0x3e,0x3d,0xfd,0x35,0x1d,0x8d, + 0x3a,0x56,0x59,0xd2,0x86,0xd4,0xf1,0xb1,0x18,0x0d,0xd4,0x22,0xa7,0xc6,0xed,0xb5, + 0xe5,0x00,0x13,0x6f,0x22,0x24,0x94,0x15,0x28,0x3f,0x88,0xbd,0x2a,0x23,0x00,0xc5, + 0x5b,0x45,0x71,0x49,0xf5,0x0e,0x54,0x9e,0x50,0x1a,0x88,0x1f,0x70,0xee,0x3d,0xa3, + 0xde,0x8f,0x11,0x16,0x59,0x5e,0xf2,0x9e,0x40,0xdf,0x54,0xd8,0x8b,0x2a,0x33,0x28, + 0x2c,0x89,0x2b,0x47,0xca,0x8a,0x5a,0x31,0x2a,0x69,0x41,0x09,0x23,0xad,0x8b,0xf6, + 0x9c,0x2f,0x5b,0x81,0x8a,0x9f,0x30,0xc7,0x78,0x39,0xd5,0x96,0xc7,0x4a,0x98,0x12, + 0x40,0x2a,0x97,0x10,0x0d,0xa7,0x33,0xbb,0x36,0x11,0x47,0x45,0x89,0x9a,0xa2,0x04, + 0xd5,0x5f,0x30,0xd4,0xd7,0xc0,0x3e,0xdc,0x82,0x00,0xa1,0x91,0xb5,0x10,0x14,0xac, + 0xe1,0xb0,0x0d,0x70,0x97,0x97,0xd1,0x0a,0x17,0x99,0x64,0x8b,0x04,0x5c,0x22,0x30, + 0xc4,0x14,0x63,0xb5,0x5d,0x14,0x9e,0x7d,0x01,0x88,0xb9,0xaf,0x38,0xfa,0x01,0xb6, + 0x59,0x36,0xbc,0x28,0xe0,0x1e,0x0e,0x33,0xc8,0xb4,0xec,0x45,0x58,0x1e,0xbd,0x4c, + 0x0d,0xf2,0x3c,0x6b,0xaf,0x84,0x0c,0x7e,0x99,0x64,0x95,0x6d,0xa0,0xdb,0x97,0x03, + 0xfc,0x30,0x1c,0x0d,0x9b,0x0d,0xde,0xb1,0x66,0xec,0x10,0x16,0xc0,0x71,0x14,0x03, + 0x03,0xa1,0xa3,0x09,0x80,0x4e,0xe3,0x34,0x2c,0x5d,0x23,0xca,0xe6,0x0c,0x3a,0x57, + 0x8b,0x30,0xce,0x6c,0xe3,0x81,0xa5,0x0b,0xe6,0x20,0xb4,0x40,0x5e,0x01,0xeb,0x4e, + 0xab,0x2d,0x8d,0xf5,0x0f,0xbc,0x1a,0x44,0x99,0xe9,0x26,0x2f,0xb4,0xf5,0xce,0x56, + 0x88,0xd0,0x11,0x54,0x23,0x3f,0x9c,0x9c,0xd0,0x7c,0x17,0x4b,0x7d,0xd8,0x22,0x09, + 0x70,0x56,0xed,0xb1,0x09,0x1d,0x0f,0xd3,0x90,0x2d,0xcc,0xeb,0xd2,0x9c,0xde,0x15, + 0xfc,0x83,0x5a,0xdf,0x95,0x3c,0x43,0xcc,0x87,0x44,0xc3,0x65,0x30,0x9f,0x34,0x8a, + 0xaa,0x2a,0x77,0xfb,0xfd,0xe1,0xf7,0x27,0xce,0xf0,0xfc,0xc2,0x79,0xea,0x0c,0xfb, + 0x97,0x7d,0x7a,0x62,0xd7,0x05,0x3b,0xa2,0x94,0xd1,0x90,0x71,0xab,0x63,0xbc,0x8d, + 0x40,0xa9,0x01,0x6f,0x54,0xc1,0xca,0xc8,0x68,0xe6,0x2a,0xca,0x16,0xb3,0x08,0xaf, + 0xda,0xb5,0x31,0xb0,0xd6,0x35,0x28,0x3f,0xa3,0x08,0xe2,0x52,0xf0,0xe2,0x18,0x22, + 0x19,0x63,0x78,0x66,0x00,0xbd,0x31,0x61,0xaf,0x3b,0x26,0x48,0x18,0x1c,0xce,0x73, + 0x63,0x08,0x2f,0x17,0x84,0x98,0xf3,0x2f,0xfe,0x72,0x7a,0x02,0x00,0x8e,0xc4,0x98, + 0xf2,0x8f,0xa2,0x52,0x79,0x48,0xba,0x07,0xf4,0x1a,0x36,0xa4,0xbc,0x1b,0x5d,0xc0, + 0x21,0x4c,0x91,0x54,0x98,0x43,0x1f,0xf0,0x02,0x32,0x24,0x19,0xe5,0xaf,0x31,0xca, + 0xcb,0x9b,0xfa,0x4c,0x10,0xdc,0xa0,0xbe,0x4d,0x15,0xd6,0x54,0x55,0x34,0x81,0x34, + 0x28,0x60,0x04,0xa9,0x1a,0x09,0x74,0x24,0xe0,0xa1,0x63,0x88,0x78,0x52,0xd8,0x6d, + 0xc4,0x8d,0x12,0x94,0xa6,0x0e,0xfb,0x03,0x13,0x27,0xcb,0x60,0x55,0x76,0xe4,0x94, + 0x74,0xf7,0xff,0x9e,0x14,0xad,0x94,0x98,0xf1,0xcd,0x74,0xba,0x6b,0xba,0xdf,0xb5, + 0xd3,0x3c,0x4f,0xb8,0xcf,0x52,0xd7,0xf6,0x57,0xf4,0x13,0xf0,0x60,0x14,0xb8,0xc7, + 0xe2,0xfe,0x5b,0x5c,0xb1,0xff,0xb7,0xed,0x03,0xe1,0xdb,0x1d,0x94,0x88,0x7a,0xb1, + 0x3d,0xb6,0x6f,0xa7,0x8d,0x02,0x4e,0xfc,0x5d,0x2b,0xd5,0x50,0x4a,0xfc,0x60,0x75, + 0x74,0x19,0x18,0x51,0xc1,0xa6,0x7e,0xa7,0xdf,0x19,0x89,0xc2,0xbb,0xcb,0x7e,0xa0, + 0x35,0xf3,0xda,0x43,0x00,0x85,0x7e,0xe9,0x59,0x5f,0x8c,0x85,0x09,0x31,0x8a,0x56, + 0x55,0xcc,0xa3,0x03,0x55,0x7b,0xf8,0xa7,0x6e,0xac,0x0a,0x1e,0xc3,0x6c,0xb2,0x98, + 0xb3,0xb4,0x72,0x66,0xac,0x7a,0x91,0x30,0xbc,0x7c,0xbe,0x7a,0x19,0x42,0x8f,0x4d, + 0x3d,0x80,0x95,0x93,0x6e,0xa5,0x86,0xbc,0xaf,0xd0,0xae,0x40,0x83,0x53,0xb0,0x3c, + 0x09,0x26,0xac,0xdb,0xff,0x78,0x74,0x39,0xea,0x7c,0xea,0xcf,0x6c,0xbd,0x58,0x15, + 0x36,0x27,0x46,0xac,0xcd,0x23,0xd3,0x35,0x8f,0x82,0x79,0xee,0x99,0xb6,0x79,0x89, + 0xd7,0x49,0x85,0x97,0x23,0xbc,0x9c,0xd1,0x65,0x07,0x2f,0x41,0x17,0xc2,0xcd,0xe6, + 0xe3,0xe4,0xd3,0xa6,0xb1,0x7e,0xaa,0xaf,0x0f,0x77,0x20,0xab,0x3f,0xbf,0x7b,0x79, + 0x03,0x4c,0x03,0x8c,0x91,0x52,0x49,0x6d,0xdd,0xfb,0x33,0x16,0x6b,0x8a,0xbe,0xaa, + 0xf4,0xb2,0x7e,0x9c,0x67,0x65,0xd5,0x5d,0xd8,0x98,0x6a,0xd8,0x2a,0xfb,0x5c,0xcf, + 0x19,0x28,0xbd,0xd0,0x35,0xdf,0xbe,0x79,0xff,0xc1,0xc4,0x92,0x42,0x9e,0x3c,0x28, + 0xdd,0xb5,0x29,0x2a,0xa5,0x7b,0x1f,0x80,0x55,0x00,0x56,0xac,0x9a,0x8b,0x27,0x94, + 0xd2,0xe8,0x7f,0xe9,0x2d,0x97,0xcb,0x1e,0xd2,0xb1,0xb7,0x28,0x12,0x0e,0x5f,0x68, + 0x6e,0x68,0x0d,0x17,0xff,0xc8,0xc2,0xe3,0xcf,0x3a,0x20,0x65,0xb0,0xc2,0x7a,0x6c, + 0x6b,0xfd,0xf6,0xce,0x11,0xd7,0x8f,0x8f,0x66,0x76,0x6f,0xda,0x7f,0xea,0x9a,0xc0, + 0x30,0x58,0xbb,0xda,0xe8,0xfd,0x43,0xb9,0xbf,0x3f,0xb1,0x58,0x73,0xc4,0xf8,0xab, + 0x0b,0x88,0xf8,0x96,0x86,0xf4,0xfb,0xc6,0x9b,0x34,0x01,0xb5,0xbf,0x28,0xc8,0x10, + 0x51,0x69,0x2b,0xf8,0x28,0x41,0x51,0xac,0x48,0x91,0xf3,0x12,0x52,0x93,0xbc,0x9a, + 0xb0,0x74,0xea,0x35,0xc0,0x49,0xc0,0x0a,0x6b,0x49,0x99,0xa3,0x23,0xe6,0x90,0xca, + 0xf1,0x7d,0x93,0x26,0x31,0xb1,0x65,0x0e,0xae,0x05,0x78,0x26,0xb0,0xf6,0x14,0x0c, + 0x30,0x62,0xe6,0x80,0x2f,0xd9,0xa8,0xbf,0xe4,0x65,0xa3,0x38,0xda,0x88,0xb5,0xb8, + 0xd6,0x03,0xab,0x00,0xa0,0x69,0x85,0xf2,0x88,0x0a,0xb4,0xfd,0x60,0xb5,0x8c,0x25, + 0x43,0xf7,0xc2,0x39,0xc0,0x42,0xe3,0x87,0x38,0xf8,0xa1,0xf4,0x49,0x0d,0xd8,0xc2, + 0xbd,0x02,0x5f,0xb9,0x2a,0x16,0xcc,0x06,0xbd,0xe3,0x9f,0x79,0xd4,0x0b,0xe3,0xb2, + 0x9f,0x60,0x91,0x12,0x8b,0xed,0xf1,0xe6,0x47,0xb6,0xf2,0x4d,0xd3,0x8e,0x4a,0x6c, + 0xe5,0x57,0xaf,0x32,0x20,0x7a,0xe8,0x63,0xd5,0xb8,0x87,0x90,0xfe,0x9c,0x72,0x97, + 0x26,0x8f,0x27,0x22,0xe4,0x06,0xf1,0x03,0x87,0x29,0x32,0x20,0x6a,0xaa,0xc8,0x39, + 0xc2,0x74,0xd7,0xb2,0x88,0x2b,0x01,0x0b,0x62,0xf7,0x16,0x4b,0xf5,0x05,0x3c,0x51, + 0xa9,0xdd,0x71,0x40,0xee,0x59,0x5e,0xe1,0x72,0x10,0x3a,0xfd,0x12,0xc4,0x95,0x3f, + 0xb0,0xd1,0x08,0x0a,0x68,0x30,0x62,0x14,0x97,0xd3,0x00,0x62,0x57,0x3e,0x0b,0xd0, + 0x23,0x48,0x67,0x00,0xd9,0xc0,0xab,0x49,0x40,0x6f,0x04,0x74,0x89,0xc8,0x74,0xe9, + 0xab,0xb5,0x1f,0x1f,0xc5,0xb2,0x8f,0x8f,0x87,0x87,0x5d,0xa0,0x39,0xba,0x13,0xa6, + 0xe5,0x90,0x2d,0x78,0x7c,0x84,0x06,0xd4,0xd0,0xb2,0xc1,0xe2,0x54,0xb9,0x2e,0xef, + 0x65,0xb6,0x48,0xf9,0x5c,0x08,0x4d,0x69,0x8a,0x14,0x12,0x0a,0xfd,0xca,0x08,0x92, + 0x02,0x24,0x63,0x65,0xdc,0xa7,0xe8,0x43,0x12,0xea,0x9d,0x03,0xe4,0x33,0x5e,0x55, + 0xae,0x57,0x79,0x73,0xba,0x1c,0x1e,0x96,0x0e,0x5e,0x71,0x6a,0x7b,0x58,0x4c,0xcd, + 0x51,0x8e,0x85,0xdf,0x82,0x07,0x2c,0x41,0x04,0xd5,0xe0,0x20,0xc4,0x1e,0x2c,0xf1, + 0x3c,0xfb,0x82,0xf5,0xd3,0x44,0x8d,0x57,0x18,0x62,0xa3,0x38,0x49,0xd6,0xb1,0xf1, + 0xd5,0x0d,0x08,0x39,0x43,0xa3,0x0b,0xea,0x40,0x77,0xad,0xc1,0x43,0x0e,0x0c,0x2c, + 0xfe,0xb6,0x3c,0xe3,0xc4,0x20,0x87,0x11,0x7c,0x1e,0xc4,0x33,0x68,0x30,0x4e,0x29, + 0x2c,0x4d,0xf7,0x01,0x70,0x2a,0x51,0xd7,0x4a,0xca,0x41,0xf6,0xf1,0xf1,0xd2,0xab, + 0xd5,0x18,0xd7,0x12,0xfc,0x9d,0x8d,0x65,0x3c,0x8d,0x4d,0x25,0xd5,0xdb,0xaf,0x22, + 0x2c,0xfd,0xd0,0xdb,0x31,0x4c,0x40,0x5c,0x8f,0xdc,0x58,0x64,0x0e,0x5a,0x13,0x44, + 0x4a,0xa4,0xd6,0x4b,0x77,0x69,0x47,0x6e,0xb4,0x69,0xbe,0xd2,0x00,0xe8,0x5b,0x5a, + 0x5a,0x97,0x8d,0xc7,0x8b,0xd2,0x19,0xe2,0x68,0x63,0x9f,0x0d,0x06,0x03,0x5b,0x07, + 0x07,0xfa,0xc3,0x5f,0x74,0xf8,0x7f,0x01,0xc0,0xbb,0xa1,0xb3,0xb4,0x90,0x04,0xa1, + 0x13,0x59,0xd8,0x08,0x9a,0x05,0x2f,0x37,0x38,0x1a,0x51,0x8c,0xfe,0xa9,0x10,0x36, + 0x94,0x78,0xa3,0xfb,0xd3,0x1b,0xe3,0xfd,0xfb,0x97,0xb7,0xb6,0x71,0xfd,0xf3,0x87, + 0x1f,0x8c,0xbb,0xeb,0x97,0xaf,0x1c,0xc7,0xb1,0x50,0x50,0x31,0x1f,0x1f,0xa2,0x67, + 0x40,0x9c,0xf2,0xea,0xc5,0xad,0xae,0x1e,0xca,0xea,0x03,0x96,0xc0,0x87,0x84,0x4e, + 0x5a,0x4f,0x09,0xa6,0x84,0xde,0x84,0x6e,0xe6,0x31,0x3c,0x58,0x80,0x61,0x4f,0xab, + 0x63,0xd3,0xf8,0x9f,0xff,0xa6,0x86,0x38,0xd7,0x50,0x6f,0x92,0x8c,0xa5,0xf2,0x78, + 0xf5,0x1f,0xff,0x84,0x2e,0xdd,0xc3,0xd0,0x91,0x41,0x86,0xc3,0xdd,0x8a,0x2b,0xec, + 0x87,0xf5,0xad,0x22,0x06,0x59,0xb1,0xca,0x74,0x09,0xc1,0xa1,0xe0,0x4c,0xd4,0x4c, + 0x62,0x33,0x26,0xf6,0x6e,0x06,0x2b,0x58,0x4d,0x4e,0x22,0xb6,0x63,0x94,0xda,0x39, + 0x8c,0x0b,0x5a,0xc3,0x40,0x1d,0x2c,0x20,0x30,0x17,0x5a,0x8b,0xfb,0x45,0x60,0x23, + 0xaa,0x62,0x85,0xb0,0x70,0xa7,0x5b,0x8f,0x89,0x4c,0xa4,0x92,0x40,0x34,0x46,0x47, + 0xca,0x57,0xe6,0xb1,0x5d,0x40,0xaf,0x54,0xc8,0xc9,0x45,0x98,0x47,0xae,0x3a,0xf8, + 0xe6,0x5d,0xac,0xac,0xff,0x1b,0xf2,0xdf,0xdf,0xd0,0xd3,0x07,0xb2,0x69,0x08,0x97, + 0xa2,0x22,0xde,0xbc,0x20,0xd1,0x3b,0x3a,0x3a,0x54,0x58,0xf7,0x40,0xe8,0x79,0x20, + 0x0e,0x2c,0xc8,0x83,0x4a,0x9f,0x37,0x61,0x60,0x52,0xb7,0x45,0x1e,0xd9,0x94,0x66, + 0xe3,0x61,0x84,0x3c,0x13,0x59,0x7c,0x00,0xb4,0x0b,0xaf,0x97,0x6b,0x27,0x50,0x1f, + 0x35,0xdd,0x15,0xa3,0x29,0x41,0x4a,0xfd,0x9a,0x5a,0x58,0x3e,0xe2,0x0b,0x1b,0x64, + 0x5a,0x36,0x06,0xcc,0xf0,0x14,0xef,0x5e,0x86,0x5f,0x80,0x6f,0x41,0x22,0x53,0x41, + 0xd1,0x11,0x3c,0x00,0xed,0x6d,0x03,0x7b,0xd8,0xf7,0xc8,0x10,0xa8,0xca,0xa9,0xc9, + 0xab,0x75,0xbc,0xc6,0x56,0xd8,0x05,0x35,0x1d,0x89,0x98,0xf6,0x7e,0x93,0xe2,0x44, + 0xec,0x40,0xc6,0x67,0x22,0xde,0x5f,0xa0,0x40,0x83,0xab,0x36,0xae,0x1e,0x4a,0x56, + 0x55,0x48,0xb6,0x45,0xee,0xd5,0xda,0xcf,0xc0,0xb7,0x61,0x48,0x21,0xc6,0x98,0x92, + 0xc6,0x98,0xf3,0xf3,0x62,0x9e,0x97,0x0e,0x67,0xec,0x43,0xa9,0x9a,0x69,0xbf,0xe0, + 0xd3,0x4a,0x4d,0x3d,0xf4,0xe8,0x1e,0xba,0x10,0x2d,0x40,0x13,0xcb,0x9d,0x21,0x1a, + 0x21,0xee,0x06,0x38,0xf3,0x00,0x39,0xff,0x27,0x70,0x1a,0x1c,0x3c,0x40,0x2a,0xaa, + 0xe7,0x0c,0x80,0x62,0x5d,0xd9,0x01,0xcd,0x35,0xf1,0x0f,0x18,0x6b,0x3e,0x5d,0xdd, + 0x20,0x69,0x23,0x0c,0x8b,0x61,0x6c,0x38,0x40,0x5d,0x81,0x5e,0x70,0x2a,0xeb,0x4e, + 0x72,0xe9,0xcb,0x13,0xeb,0xe8,0x48,0x99,0x09,0x6b,0xdd,0xb2,0x56,0x9e,0x30,0x29, + 0x38,0x95,0x64,0x28,0x81,0xb6,0x77,0x0c,0x5f,0xcd,0x21,0x51,0x04,0x9d,0x0b,0x3b, + 0x24,0xeb,0xec,0xa2,0x96,0x0d,0x72,0x0a,0xed,0x02,0x1e,0xc4,0xa3,0xa9,0x34,0xca, + 0x45,0xf1,0x10,0x83,0xcb,0x1c,0x48,0x7b,0x89,0xd8,0xba,0xf7,0xff,0xf2,0xfe,0xcd, + 0x4f,0x20,0x58,0xe8,0x45,0xc6,0xd3,0x55,0xf7,0x63,0x6a,0x6b,0x04,0x3c,0x3a,0x52, + 0xba,0xc0,0x56,0x3c,0xf1,0x89,0xd6,0x87,0x6d,0xdd,0x1f,0xfa,0xbe,0xb0,0x8d,0x02, + 0xd3,0xd2,0x52,0xde,0x2b,0x44,0x6b,0x1b,0x13,0x5e,0x39,0xcc,0xe7,0xe7,0x58,0x70, + 0xf6,0x12,0x7c,0x45,0xe0,0x3d,0x6e,0xf0,0xec,0xe1,0x40,0xa0,0x93,0x86,0x41,0xa7, + 0x4b,0x45,0x1b,0x62,0x49,0x68,0xf1,0x18,0xe0,0xe3,0x6b,0xf8,0xe1,0x08,0x27,0x8a, + 0x20,0x24,0x80,0xeb,0x18,0x36,0x52,0xfc,0xf0,0xe1,0xf5,0x2b,0x85,0xee,0x2b,0x13, + 0x74,0xc1,0x65,0x12,0xcb,0xec,0xc1,0x76,0xdd,0x4b,0x67,0xf4,0x53,0x5b,0x6f,0x41, + 0x58,0x15,0x8f,0x4c,0x0e,0x1f,0x82,0x5c,0x4f,0x6b,0x8a,0xd6,0x74,0xfb,0x45,0xa1, + 0x2f,0x76,0xac,0x36,0x8d,0x42,0x97,0xc4,0xbe,0x72,0xf0,0xf1,0x84,0xb8,0x62,0xc2, + 0xc7,0x47,0x68,0x4d,0xb5,0xfb,0x24,0xd6,0xa7,0x6f,0xc4,0x30,0x69,0x67,0x04,0x9a, + 0x36,0x3e,0x1e,0x5a,0xc7,0x66,0x23,0x3b,0x25,0x9f,0xcf,0x55,0x5c,0x63,0x1e,0xab, + 0x14,0x6a,0xb7,0x41,0xd0,0x2f,0x64,0xc6,0x41,0x87,0x2a,0xca,0x5e,0x35,0x17,0xc1, + 0x9a,0x1f,0x23,0xbb,0xef,0x8c,0xd4,0x20,0x39,0xa5,0x6b,0x9a,0x56,0x63,0x5a,0xc1, + 0x10,0x30,0x59,0xbc,0x63,0x92,0xce,0x88,0x1f,0xf0,0xec,0x1a,0x6c,0xee,0x4c,0x66, + 0x1b,0x61,0xd0,0xce,0xc4,0x8e,0xee,0xb2,0x62,0xc6,0xea,0x24,0xb8,0xa9,0xa1,0x89, + 0x8a,0x44,0x60,0x07,0x1f,0x87,0x9f,0x1a,0xea,0x85,0x6f,0x51,0xeb,0x08,0x6b,0x54, + 0x37,0xd8,0xd9,0x01,0xdd,0x0d,0x81,0xc2,0xbd,0xaf,0xf9,0x16,0x21,0x4b,0xba,0x7c, + 0x84,0x8d,0x79,0x3b,0x6b,0x23,0x07,0xd6,0x5c,0x04,0xe1,0x05,0x4b,0x43,0x9a,0xa1, + 0x9b,0xc4,0x8a,0x52,0xc8,0x09,0xa0,0x13,0xba,0x68,0x1f,0xde,0xe4,0x34,0x9d,0x20, + 0x8e,0x03,0x16,0x51,0xcc,0x19,0xdb,0xdc,0x5d,0x24,0x26,0x06,0x44,0x49,0xad,0xb1, + 0xb1,0xa4,0x82,0x80,0x75,0x20,0xbc,0x6e,0xa9,0x48,0xc9,0xae,0x60,0x82,0xb3,0x29, + 0xcc,0x06,0x3a,0x16,0x2e,0x31,0x1b,0x57,0x1a,0x68,0xdd,0x04,0x7d,0xbb,0xa8,0x9f, + 0xaf,0x4c,0x32,0xc2,0xbc,0x80,0x01,0xe4,0x1e,0xb8,0x17,0x34,0xa2,0x88,0x07,0xb9, + 0x8b,0x8c,0x18,0xc0,0x8c,0x0e,0x91,0xc1,0xd3,0x17,0x25,0x31,0x70,0x48,0x0a,0x7c, + 0x3e,0x19,0x97,0x05,0x7c,0x85,0xc6,0xc2,0xee,0xdc,0xf0,0xe3,0x39,0xf1,0x5f,0xc0, + 0x55,0x03,0xaa,0xa3,0xc7,0x46,0x26,0x53,0x3a,0x27,0x34,0xb9,0x34,0x90,0x25,0x40, + 0xcf,0x73,0x88,0x81,0xca,0x6b,0xd5,0x56,0x12,0x0c,0xa4,0x4d,0xfe,0xc9,0x70,0x80, + 0x07,0x13,0x3c,0x3d,0xa5,0x99,0x4c,0x6d,0xa1,0xcf,0xca,0x5a,0x81,0x81,0x44,0x03, + 0x85,0xeb,0x82,0xfe,0xcd,0xc0,0xf6,0x1d,0x7e,0x3e,0x3a,0xfa,0x4c,0xee,0x00,0x03, + 0x1d,0x64,0x62,0x46,0x02,0x82,0x9b,0xae,0x68,0x42,0x07,0x81,0x5b,0x7b,0xf3,0xf1, + 0xf1,0xb3,0x13,0xcc,0xb2,0x4b,0xff,0x7c,0x30,0xe0,0x6f,0xa5,0x19,0x95,0x9f,0xa5, + 0x6a,0xb4,0xd6,0xd5,0xbe,0x87,0x07,0x57,0x1f,0xc5,0x03,0xfb,0x33,0x27,0xdf,0x67, + 0x70,0x7d,0xe0,0x0f,0x84,0x56,0x9f,0x68,0xe3,0x5d,0xf3,0xd1,0xb4,0x00,0x2b,0x76, + 0x6a,0x2f,0xec,0xa5,0x50,0x84,0x15,0x00,0x81,0x91,0x81,0xb5,0xa6,0xf8,0xa0,0xf2, + 0xd0,0x7f,0xa5,0x17,0x39,0xab,0xab,0x13,0xf0,0xfe,0xb0,0x60,0x62,0x60,0x09,0x63, + 0x70,0x0f,0x6b,0x8a,0xe0,0x42,0xb8,0x5d,0x38,0x8b,0x0c,0x37,0xee,0xb1,0xae,0x41, + 0xd9,0xf8,0x2c,0x15,0x2b,0xc0,0x95,0xd6,0x39,0x05,0xbd,0x30,0x06,0x11,0xc7,0x54, + 0x00,0x87,0x93,0x14,0xc2,0x98,0x4b,0x07,0x4e,0x40,0x62,0xc5,0x63,0x28,0x9e,0x63, + 0x37,0x25,0xa8,0x42,0x25,0x61,0x27,0x4d,0xcd,0xfc,0x85,0x7b,0xe1,0xc0,0x68,0xe9, + 0xb1,0x79,0x14,0x51,0x99,0xa1,0xf7,0xad,0xa9,0x6c,0xca,0x48,0xce,0x33,0xd4,0x95, + 0x4a,0xed,0x98,0x15,0x46,0x2b,0x81,0xe2,0x0b,0xd7,0x28,0x79,0xea,0x9d,0x4f,0x88, + 0xe9,0x4d,0x4c,0x70,0xd3,0x7a,0x2a,0x6b,0xda,0x4c,0x7f,0xab,0xe9,0x79,0x6a,0xbc, + 0x9e,0x9a,0x12,0xa2,0x32,0x71,0x0e,0x0a,0x91,0x07,0x2a,0x20,0x05,0x5d,0x60,0x2c, + 0x40,0x8c,0xc8,0xb9,0x72,0xfc,0xf0,0x87,0x28,0x93,0x49,0x36,0x09,0x92,0x3e,0xa2, + 0x49,0xc4,0xab,0x18,0xde,0xf2,0xb3,0x01,0x8b,0xab,0x27,0xd3,0x21,0x34,0x6d,0xd0, + 0xce,0x20,0xb2,0x34,0x26,0x41,0xfa,0xa0,0x89,0xaf,0xb1,0xb7,0x85,0x62,0x50,0x9a, + 0x42,0x3b,0x2d,0x7c,0xb3,0x01,0x03,0x32,0x11,0xcc,0xde,0x17,0x8f,0x77,0xe0,0x9e, + 0x50,0x97,0xa2,0xe2,0x78,0xbf,0x17,0x4d,0x36,0x8f,0xb3,0x10,0x51,0x97,0xe3,0xa2, + 0xd6,0xf0,0xe6,0x65,0xa0,0xd4,0x68,0x3c,0xeb,0x88,0x74,0x94,0x79,0xbc,0x38,0x36, + 0xd1,0x5e,0x2c,0x90,0x35,0x82,0x6f,0x3f,0x3d,0x9c,0x64,0xf9,0x0a,0x33,0x5c,0xf9, + 0xaa,0x56,0xba,0x6a,0xa9,0x3d,0x39,0x35,0x1c,0xd3,0x28,0x9a,0x00,0xf8,0x3e,0xb4, + 0xe8,0xa7,0xd3,0xb6,0x41,0x41,0xd2,0x07,0x01,0xaa,0x83,0x05,0x44,0xec,0xa6,0x72, + 0xaa,0x70,0x52,0x50,0x50,0x3b,0x54,0xb6,0xf4,0x24,0xa0,0x43,0xb7,0xc6,0x34,0x62, + 0x19,0x91,0xdc,0x0e,0x00,0x55,0xca,0x05,0x67,0x8c,0x81,0x88,0xb6,0x4c,0xbb,0x08, + 0xb0,0xe9,0xbd,0x64,0x65,0x9a,0x76,0x8c,0xa3,0xa3,0x3e,0xe2,0x52,0x7c,0x0d,0xb6, + 0x7d,0x48,0x83,0xb3,0xc0,0x76,0x60,0x5a,0x56,0x14,0xed,0x79,0xa5,0xb6,0x57,0x7c, + 0xf5,0x35,0x06,0xc2,0xf1,0xbc,0xff,0xd2,0x27,0x9d,0xf3,0xf8,0x88,0x51,0x11,0x97, + 0x39,0xbd,0x5c,0x84,0x44,0x6a,0x37,0x37,0xdd,0x34,0x8e,0x88,0x38,0xe7,0xb8,0x06, + 0xe7,0xc3,0xa5,0x30,0x4d,0x62,0xaf,0xdd,0x25,0x72,0xf6,0xb2,0xc8,0x40,0xf0,0x55, + 0xa0,0x74,0x65,0xde,0x60,0x20,0xd1,0x88,0x9e,0x68,0xeb,0xa0,0xd8,0x43,0x3a,0x5c, + 0x98,0x81,0x97,0xe4,0x88,0x98,0x8c,0x40,0x45,0x0d,0x2c,0x2b,0x04,0x60,0x5d,0xaa, + 0x7d,0x68,0xcc,0x83,0x82,0x66,0xf3,0x03,0x22,0x8c,0x52,0x27,0x41,0xc9,0x7a,0x30, + 0x1d,0x16,0x88,0x3d,0xc0,0x03,0x7e,0x62,0x17,0x54,0xfa,0xe6,0xb0,0x9f,0x8c,0xff, + 0xb4,0xc5,0xcc,0x0f,0xc5,0x8a,0x43,0x00,0x3c,0x98,0x95,0x78,0xb4,0xc1,0xb3,0x22, + 0x45,0xb6,0x40,0x4b,0x62,0x0a,0xab,0xca,0x8d,0x93,0x60,0x0d,0x9c,0x0b,0x01,0x83, + 0x40,0x91,0x81,0xcf,0xc3,0xf8,0x3b,0xd9,0x5f,0x2a,0x17,0x00,0x7b,0x88,0x67,0x41, + 0x95,0x15,0x40,0x8c,0x38,0x1f,0x67,0x01,0xec,0x35,0x46,0x03,0xbb,0x08,0x92,0x64, + 0x05,0x2c,0x09,0xba,0x15,0x73,0x13,0xca,0x3e,0x11,0xcb,0x55,0x32,0x82,0xde,0x31, + 0xfc,0xe8,0x48,0x7c,0x6b,0x22,0x2e,0xdf,0xd3,0x62,0x37,0x7c,0x2d,0x19,0x61,0xef, + 0x18,0xe2,0x50,0xaa,0x8a,0x22,0xa2,0x8a,0xc0,0xa7,0xcc,0xd8,0x5e,0x5f,0x11,0x05, + 0x0c,0xcc,0xe0,0xcc,0x07,0xb7,0xe8,0x3d,0x95,0xf8,0x10,0xb3,0xda,0x45,0x7b,0xc4, + 0x3b,0xc4,0x1d,0x3c,0xc8,0xee,0xeb,0x80,0xa4,0x6c,0x7e,0x67,0x82,0x37,0x09,0x17, + 0xa0,0x2c,0x11,0x06,0xdf,0x54,0x55,0x88,0xd3,0xf8,0x0b,0xc4,0x70,0x58,0x3a,0x82, + 0x1f,0x4d,0x88,0x73,0x17,0x93,0xfd,0xdd,0x81,0x4d,0xff,0x36,0xdf,0x07,0x03,0x09, + 0x51,0x2f,0xb7,0x82,0x7b,0x52,0xf4,0xc4,0x3b,0x09,0xb8,0x9a,0xd7,0x6e,0x20,0xc6, + 0x55,0xc0,0x62,0x4a,0xb6,0xe1,0x61,0xe1,0xeb,0xfb,0x0e,0xef,0x8e,0x61,0x98,0x00, + 0xb6,0xc4,0xf6,0x99,0x53,0x30,0x34,0x34,0xd7,0x49,0x42,0xbb,0xc3,0x2f,0x26,0xcc, + 0xd0,0x07,0xe3,0x7b,0x2d,0x08,0x7d,0x60,0xcf,0xd7,0xb0,0x67,0xb5,0x00,0xfb,0xc2, + 0x26,0x37,0xd9,0x7c,0x0e,0x6c,0x26,0x95,0xca,0x66,0x82,0x5f,0x62,0xc0,0xdc,0x0d, + 0x1a,0xe5,0x5d,0xb3,0x36,0xc1,0xe3,0xcf,0x15,0x78,0x75,0x2a,0x24,0xbb,0xbf,0x12, + 0x1f,0x5b,0x80,0x3e,0xe0,0xeb,0x3c,0x00,0xc2,0xdd,0xba,0x05,0x5f,0xa5,0x97,0x1f, + 0x41,0xe0,0x2b,0x73,0xc7,0xa9,0x11,0x9b,0x63,0xbe,0x47,0xf9,0x3a,0x11,0xf8,0xe5, + 0x32,0x93,0x36,0xf1,0x23,0xe4,0x12,0xdc,0x3c,0x25,0x47,0x7d,0x70,0xbe,0xf0,0xf7, + 0xf1,0xf1,0xe3,0x27,0xcb,0x99,0x42,0xe8,0xc7,0x8a,0x46,0x72,0x4f,0x00,0x55,0x92, + 0x4b,0xb0,0x81,0x58,0xbe,0x1d,0xdd,0xe1,0x68,0x02,0x5f,0xe4,0xf6,0x22,0xee,0x29, + 0x53,0x7a,0x41,0xe4,0x23,0x75,0xfe,0x88,0x94,0x23,0xad,0xd2,0xb0,0x6b,0x3c,0x9a, + 0x73,0x23,0x07,0x7f,0x6c,0xd4,0x0f,0x6e,0xe8,0xe0,0xcf,0x46,0x3a,0x2a,0x22,0xcb, + 0x69,0xad,0xf3,0x45,0xd5,0xa5,0x89,0xa7,0x30,0xeb,0xdc,0xe6,0x43,0x2c,0x4f,0x35, + 0xf3,0x74,0xa7,0xcd,0x87,0x5b,0xc2,0x11,0x16,0x87,0xb5,0x5b,0x70,0x2c,0xf2,0x2b, + 0xf3,0x4d,0x8a,0x7a,0x8c,0xc3,0x84,0x6e,0x31,0x8f,0x7a,0xd1,0xc0,0x60,0xab,0xb8, + 0x96,0x29,0x2b,0xa9,0xe2,0x26,0x57,0x93,0xe3,0xee,0x04,0x54,0xd4,0x10,0xfc,0x03, + 0x91,0x39,0x77,0xe5,0x55,0x89,0x36,0x9f,0x1b,0x23,0x68,0x4c,0x33,0xa4,0xb5,0xb8, + 0xb5,0xe4,0x44,0x11,0x58,0x15,0xae,0x7e,0xf8,0x0e,0x50,0xdb,0x65,0xd3,0x29,0xe8, + 0xb7,0x37,0xd3,0x29,0x68,0xa6,0xba,0x15,0x4f,0xc4,0x78,0x33,0xb9,0xe3,0x8b,0x1c, + 0xdd,0x8c,0xb4,0xe5,0x26,0xc9,0x93,0x57,0x18,0xa9,0x7a,0xc2,0x96,0x0b,0x4c,0x72, + 0x38,0xd2,0x49,0x43,0x17,0x51,0x64,0xc3,0xa5,0xd7,0x47,0x01,0x3f,0x4f,0x75,0x14, + 0x22,0xec,0xe7,0x9f,0x56,0x80,0x60,0x3f,0x5a,0xcc,0xc7,0x28,0xc8,0x22,0x7f,0x7e, + 0xef,0xd5,0x69,0x75,0xbc,0x72,0xe6,0x41,0xfe,0x35,0x36,0x91,0x59,0x1a,0x74,0xa6, + 0xf4,0x88,0x19,0xdb,0x26,0x41,0xb3,0x8d,0x87,0x03,0x34,0xeb,0x56,0xbc,0x5b,0x0a, + 0xc3,0x8c,0x6c,0x9c,0xed,0x55,0x5f,0x19,0x05,0x4a,0x40,0xf8,0xdf,0x09,0x87,0xa5, + 0x41,0x1e,0xef,0xed,0xc5,0x9d,0x13,0xe8,0xf9,0x9b,0x5f,0x3a,0x05,0xec,0x65,0xe4, + 0xf7,0xce,0xce,0xae,0x9e,0xba,0xea,0xee,0xfc,0xd9,0xd5,0x69,0x7d,0xf7,0xec,0xe2, + 0xea,0xc4,0x15,0x29,0xa0,0x8c,0x67,0x1d,0xfc,0x52,0x09,0x80,0xd8,0xbe,0xae,0x88, + 0x32,0x61,0xbc,0xc7,0x0e,0x79,0x49,0x72,0x41,0xd9,0xb8,0x37,0x4a,0xaf,0xa3,0xf0, + 0x46,0x3b,0xbd,0x1c,0x50,0x9a,0xc7,0xbf,0x81,0x5f,0x26,0xce,0xc1,0xe3,0xf9,0xac, + 0x79,0xa8,0x59,0xc6,0xb3,0x34,0x40,0x86,0xfe,0xad,0x76,0xb9,0x20,0xfe,0x7b,0x8a, + 0x95,0x3a,0x30,0x69,0xbc,0xe7,0x47,0xc4,0xd8,0x12,0x32,0x4a,0xa0,0xf1,0x80,0xb7, + 0x91,0x76,0xd3,0xe2,0xe2,0xf1,0x2e,0xbf,0xaa,0x75,0x2a,0x21,0x07,0x4c,0xa2,0x7b, + 0xd4,0x88,0x3c,0xcf,0xe2,0xd5,0x27,0x15,0x54,0x41,0xdd,0x95,0x01,0x33,0xc4,0xd9, + 0x3a,0xf2,0xc6,0xd4,0x53,0x30,0xd0,0x8e,0x00,0xba,0xe6,0x3b,0x5e,0x61,0xa9,0x65, + 0x36,0x89,0xbd,0x78,0xf8,0x2b,0xfa,0x60,0x65,0x63,0xdd,0x41,0x7b,0x7e,0xf9,0x8c, + 0xd2,0x90,0x98,0xa0,0x93,0x59,0xa9,0xd6,0x26,0x2c,0x0e,0xfd,0x81,0x7e,0xe8,0x08, + 0x2a,0x88,0x25,0xf6,0x03,0x65,0xe2,0x65,0x02,0x0a,0x42,0xb8,0x07,0x4b,0xde,0xf8, + 0x0f,0x5a,0x77,0x3e,0xfb,0xba,0x06,0x43,0xc7,0x69,0xbd,0x47,0xa2,0x32,0x1e,0x87, + 0x60,0xb6,0xa5,0x02,0x0f,0xa5,0xec,0x9a,0xe0,0x45,0x98,0xd6,0x95,0x89,0xa5,0x61, + 0xc6,0x94,0x81,0x13,0x07,0x52,0x4f,0x37,0xf0,0x00,0x88,0xac,0xe4,0x54,0xec,0x66, + 0x73,0x50,0x2f,0xb2,0x87,0x3c,0xed,0xb5,0xaa,0x6c,0x36,0x4b,0x98,0x58,0xc9,0xe3, + 0xa0,0x6e,0xf8,0xb9,0xc1,0x35,0x77,0xb4,0xe8,0xc4,0x0e,0x3d,0x19,0x64,0x24,0xfe, + 0x7d,0x1a,0x3d,0xb6,0x62,0x58,0x32,0x82,0x59,0x6e,0xe0,0xf1,0x0c,0xa2,0x34,0x3a, + 0x75,0xa7,0x04,0xab,0x7e,0x76,0x90,0xb2,0xa0,0x10,0x02,0x8e,0x4a,0xbe,0x7c,0x7c, + 0xc4,0x34,0x3c,0x9e,0x9a,0xc1,0x95,0xda,0x05,0x78,0x3e,0xec,0xcb,0x1b,0xfc,0x3a, + 0xce,0xa8,0x37,0x54,0x67,0x0a,0xc4,0x96,0xa0,0x2d,0xba,0xa8,0x18,0x62,0x7f,0x60, + 0x27,0xc0,0x58,0x55,0xf6,0x2a,0x03,0x7c,0xdc,0x00,0x84,0x40,0x9d,0xf8,0xb2,0x8d, + 0x0a,0x2f,0x3e,0x3e,0xb6,0x64,0x12,0x51,0x3d,0xfc,0x18,0x7f,0x6a,0x8e,0x04,0x20, + 0x12,0xb9,0x90,0xde,0x4b,0x3f,0xad,0x30,0x1b,0xc4,0x47,0x76,0xc0,0xdd,0x69,0xb9, + 0x70,0xda,0x5c,0x8b,0x6d,0x1c,0xb0,0x99,0xf3,0xae,0x25,0x99,0x14,0x2b,0x3c,0xdb, + 0x19,0x1a,0x8f,0xb7,0x6b,0x8c,0x9b,0x7a,0xf2,0xfc,0x30,0x05,0x3f,0x10,0x7e,0xaf, + 0x86,0xe0,0x3a,0xd5,0xa0,0xa4,0x4d,0x36,0x04,0xf2,0x8a,0xc3,0x81,0xa5,0x2f,0x06, + 0xb6,0x64,0x8d,0x4e,0x96,0x30,0xc5,0x64,0x51,0xee,0xd3,0xd8,0x96,0xbd,0x03,0x0e, + 0x04,0xb8,0x58,0xfb,0x79,0x46,0x17,0xe9,0x9d,0x7b,0xf1,0x38,0x28,0xc0,0x37,0xfc, + 0x31,0xe6,0xaa,0x76,0x4f,0x47,0xe7,0xa4,0xbb,0x51,0xd5,0x98,0x44,0x3c,0xcf,0x52, + 0x2a,0x41,0xd1,0x67,0x68,0x6c,0x90,0x77,0x16,0x5b,0x92,0x9d,0xe9,0x99,0x76,0xa6, + 0x9a,0x2f,0xbb,0x59,0x4a,0xe4,0xaa,0xfb,0x92,0x42,0xce,0xd2,0x2b,0x93,0xfc,0x49, + 0xd7,0x54,0xe1,0x8b,0xa0,0x57,0xbe,0x6c,0x9f,0x39,0x60,0xe7,0x1f,0xe2,0x90,0x09, + 0x09,0x34,0x3d,0xd5,0xab,0x64,0xd5,0x75,0x05,0x7b,0x00,0xf5,0x8e,0x82,0xa4,0xd5, + 0x76,0x9a,0x76,0xc6,0x33,0x5d,0xaa,0xef,0x0e,0x94,0x00,0x78,0x2d,0xb8,0xc0,0x17, + 0x50,0xf0,0x90,0x30,0xaa,0xad,0x10,0x29,0x25,0xe3,0x51,0x1e,0x76,0x37,0x2e,0xf1, + 0xb3,0x63,0x7e,0xfb,0x64,0xc7,0xce,0xa5,0x8f,0x45,0x19,0x1f,0xc9,0xf5,0x18,0xa0, + 0xd2,0x7b,0x3d,0x75,0x5d,0x3b,0x09,0xb9,0x88,0x47,0xa5,0x5a,0x44,0xbc,0x0f,0x2d, + 0x62,0x08,0xc5,0x2f,0x82,0x89,0xc4,0xd9,0xa8,0xc8,0x4f,0xc1,0x9a,0x47,0x47,0x87, + 0xda,0x61,0x15,0x58,0x93,0x79,0xd7,0x94,0x79,0x89,0xcc,0xe8,0x80,0xe2,0x22,0x17, + 0xac,0x83,0x07,0x12,0x57,0x7f,0x4d,0xff,0x9a,0x7e,0x50,0x59,0xa2,0x65,0x0c,0x9a, + 0x0d,0x53,0x45,0xc0,0xf3,0xe0,0xc4,0xa6,0x21,0xcf,0x2a,0xa9,0xe8,0x5a,0xfb,0xc7, + 0x8c,0xa7,0x22,0xe2,0x5b,0xea,0x51,0x5f,0x18,0x4f,0xa7,0xac,0x50,0x59,0x44,0xec, + 0x81,0x59,0x10,0x2c,0xbd,0xc6,0xe2,0xc5,0x0c,0x62,0x4f,0x4b,0xcb,0x85,0xe5,0x3e, + 0xd5,0x90,0x68,0x07,0xc1,0x36,0x61,0xd4,0x87,0x90,0x37,0x9d,0x74,0x45,0x72,0xec, + 0x08,0x09,0x22,0x9a,0xda,0x47,0xed,0xc7,0xb8,0xe5,0x2b,0xf3,0x48,0xe4,0xbb,0xfd, + 0x21,0x25,0x83,0x08,0x6f,0x6f,0xef,0x1c,0xfc,0x0e,0x9f,0x38,0xfc,0x19,0x57,0xe8, + 0x6d,0xe4,0x3b,0x0e,0x98,0xa5,0xa2,0x3a,0x0c,0xf1,0x93,0x64,0x1a,0x65,0x42,0x7c, + 0x0f,0x2e,0x2b,0xea,0x6a,0x0b,0x8d,0x28,0xdc,0xfa,0xb5,0x84,0x53,0x87,0x0c,0xbd, + 0xad,0xdd,0xc7,0x7b,0x9e,0xa8,0x57,0xf0,0x80,0xf9,0xa8,0xa1,0x56,0x19,0xfc,0x8c, + 0x02,0x99,0x82,0x9f,0x5e,0xe0,0xe9,0x2d,0x21,0x41,0x1d,0xc9,0xc0,0x3d,0xd1,0x12, + 0x28,0x63,0x69,0xf9,0x56,0xf9,0x69,0x43,0x99,0x0e,0xc5,0x41,0x6e,0x28,0x92,0xd8, + 0x39,0xa6,0x3c,0x97,0xd1,0x0a,0x7f,0x82,0x59,0xe6,0x0e,0x64,0x62,0x83,0x32,0x9d, + 0xf4,0xb9,0x3b,0x32,0xea,0xb6,0x26,0x18,0x08,0x04,0xb1,0x11,0x1d,0xed,0xf2,0x4a, + 0x05,0x74,0x77,0x6b,0xe3,0x33,0x0f,0x56,0xc6,0x58,0x95,0x00,0x80,0xdb,0xed,0x1a, + 0xf4,0x89,0x3c,0x3d,0xbd,0xe7,0xb6,0x30,0xb7,0x91,0x02,0x39,0x25,0x71,0xe4,0xf6, + 0xca,0xd7,0x8f,0xe3,0x99,0x03,0xe2,0xfb,0x00,0x0c,0x74,0xcb,0x3f,0xeb,0x02,0xa0, + 0x91,0xdc,0x35,0x24,0x11,0xb3,0xfe,0xb4,0xb5,0xb1,0x32,0x6a,0x8a,0xd5,0xf9,0x91, + 0x83,0xc6,0xe7,0xc4,0xe3,0x2f,0xa7,0x5a,0xf5,0x0d,0x32,0x2a,0x56,0x0b,0x23,0xdf, + 0x2b,0xde,0xad,0xa8,0x5e,0xb3,0xdc,0x66,0x77,0x53,0x1d,0xa5,0x80,0xd3,0x5e,0xc5, + 0x49,0xfd,0xd2,0x0f,0xd6,0x5e,0x36,0xf9,0x59,0xb2,0xdc,0xd8,0x6e,0x57,0x38,0x5c, + 0xb5,0xd9,0xba,0xae,0x90,0xba,0x7d,0xf1,0xea,0xc5,0x87,0x17,0x66,0x5d,0xd9,0xb4, + 0x8f,0x47,0x45,0x46,0x0b,0xd9,0xf4,0xca,0x04,0x9b,0x3c,0xcb,0x2a,0x83,0x6f,0xd3, + 0xdd,0x66,0x55,0xde,0x2b,0xbb,0x07,0x1a,0xc8,0xcc,0x96,0x78,0x3b,0x0a,0xc5,0xe3, + 0x2b,0x94,0x97,0x79,0xb3,0x06,0xe5,0x9a,0xc3,0x37,0xed,0x40,0x18,0x98,0x15,0xdf, + 0x94,0xaa,0xd5,0x63,0x5c,0x9f,0x12,0xaa,0xd3,0xe9,0xe6,0x59,0xa1,0xfc,0xb4,0x65, + 0x53,0xfe,0xfb,0xd4,0xd5,0x36,0xe5,0xe1,0x94,0x79,0x1c,0xff,0xae,0xc4,0xea,0x1f, + 0x11,0xdc,0xc2,0x83,0x8c,0x02,0x76,0x9f,0x3b,0xca,0xc2,0x92,0x58,0x3a,0xb5,0xc4, + 0x9c,0x02,0x5c,0x30,0x17,0x74,0x30,0xab,0xdb,0x8b,0x7a,0x1e,0xac,0x86,0x6a,0x5a, + 0x42,0xf9,0xfa,0xd5,0xde,0xb4,0xa7,0xe4,0x0e,0x64,0x3c,0xbb,0xc6,0x59,0x7b,0x83, + 0x31,0x2c,0x43,0x14,0x50,0x35,0xdc,0x86,0x3a,0x38,0x14,0xa7,0x9a,0x28,0x89,0xfc, + 0x55,0x2c,0xd4,0xe9,0x58,0x40,0xb7,0x32,0x75,0xa2,0x8a,0x8c,0xa8,0x2e,0x58,0x34, + 0x25,0x2f,0x32,0xd3,0x85,0xd1,0x93,0xe7,0x40,0x5c,0xa8,0x41,0xef,0x63,0x3c,0x5b, + 0x82,0x64,0xe3,0xc1,0x39,0xb8,0x65,0xc5,0x03,0x3f,0x97,0x5a,0xf1,0x53,0x55,0xf4, + 0x64,0x3c,0x23,0x62,0x09,0xaf,0x23,0x97,0x45,0x22,0xbf,0x2d,0xd8,0x02,0xdc,0x3f, + 0x44,0x03,0x87,0x6b,0x2f,0x12,0x1a,0xc2,0xba,0xf5,0x6e,0x1a,0xa5,0x13,0xe5,0xce, + 0x14,0x54,0xa4,0xe2,0x75,0x39,0xe3,0xe5,0x67,0x29,0x96,0x7a,0xe5,0x7e,0x8d,0xc9, + 0x6d,0x44,0x8a,0x43,0x5f,0xe8,0x39,0xf4,0x38,0x52,0xf9,0xe4,0x08,0x33,0x22,0x71, + 0x07,0x8a,0xff,0xf5,0x8f,0xff,0x02,0x06,0x8c,0xd3,0x69,0x26,0x99,0x67,0x4f,0xd1, + 0x52,0x5f,0xec,0xb4,0x55,0xeb,0x08,0x72,0xcc,0x13,0x54,0xda,0xbe,0x45,0x6d,0xd2, + 0x56,0x75,0x92,0x0a,0xe7,0x81,0x35,0x1a,0x1f,0x09,0xed,0x8a,0xe4,0xf3,0xa6,0x61, + 0xc9,0x88,0x71,0xe0,0x06,0x13,0xd9,0xdd,0xdc,0xda,0xce,0x95,0xe3,0x29,0x09,0x5e, + 0x3a,0x05,0x4b,0xb2,0x00,0xd5,0x66,0xa3,0xd6,0x89,0x8b,0x02,0xa2,0xa1,0xa4,0xa3, + 0xe3,0x1a,0xc3,0x61,0xcc,0xd3,0xce,0x93,0x0c,0x3f,0x41,0x19,0x4c,0xa8,0x56,0x86, + 0x14,0xa4,0xcc,0x95,0x23,0xb6,0xc0,0xe6,0x8b,0x0a,0x73,0x16,0xaa,0xa3,0xca,0xfa, + 0x7c,0x41,0x55,0xdd,0x6f,0x1d,0x07,0xa1,0x76,0xa5,0x73,0x84,0xe6,0xe9,0x8f,0xdb, + 0xe0,0x47,0x25,0x83,0xa0,0xea,0x79,0x1d,0x66,0x16,0x32,0x5d,0x0e,0xb5,0xcc,0xd3, + 0x2e,0xe7,0x54,0x56,0x06,0x6e,0x4b,0x26,0x4f,0x63,0xed,0xb4,0x37,0xb0,0xe6,0x0e, + 0x93,0x23,0x58,0x6c,0xee,0x23,0x0a,0x9c,0xb9,0xd0,0x5c,0xf9,0x43,0x03,0x04,0xde, + 0x98,0xf9,0x32,0xbd,0xc6,0x65,0x8e,0xc7,0x6e,0xbc,0xa2,0x43,0x49,0x93,0x5e,0x9d, + 0x29,0x24,0x8b,0xd7,0x3e,0xa2,0x59,0xe5,0x07,0xac,0xb2,0x4e,0x2f,0xb2,0xb0,0x06, + 0x84,0x1f,0x1e,0xf1,0x97,0x07,0xa8,0xc4,0xdf,0xe1,0x55,0x54,0x70,0x29,0x4b,0x91, + 0xba,0x87,0xd9,0xe3,0xe3,0xfc,0x10,0x3f,0xf2,0x8a,0x88,0x7a,0x7c,0xcc,0x1f,0xe8, + 0x86,0x32,0x72,0x1c,0x16,0x24,0xa4,0x3f,0xa7,0xf4,0x16,0x15,0xbd,0x9b,0x30,0x40, + 0x25,0xbb,0xf4,0x62,0x26,0xf0,0x4e,0x09,0x72,0x7c,0x00,0x5e,0x60,0x15,0x01,0x08, + 0xbc,0x40,0x2c,0x89,0xd3,0x7b,0x23,0x61,0x20,0x62,0x44,0xc5,0x30,0x5b,0xa6,0x5c, + 0x88,0xf3,0x07,0x19,0xc5,0x5f,0xe0,0xd2,0xb2,0xc8,0xe8,0xfc,0x54,0xf3,0xa0,0x7e, + 0x80,0x28,0xba,0x71,0x14,0x01,0xfc,0x74,0x81,0x1a,0xeb,0xfc,0x94,0xbe,0x11,0x1d, + 0xc0,0xda,0x45,0xd9,0xf2,0x75,0x71,0x8f,0x9a,0xef,0x3a,0xaf,0x73,0x76,0x1f,0x70, + 0x5a,0x1d,0x95,0xd0,0xac,0x79,0xb0,0x84,0xb2,0x58,0xf0,0x98,0xbb,0xff,0xf0,0xd3, + 0xd1,0x12,0x8c,0x12,0x01,0x54,0x58,0xa2,0xe9,0x41,0x3d,0xdb,0xd7,0x50,0x74,0xe4, + 0x22,0x17,0x2c,0x20,0x3f,0x07,0x8c,0xbf,0xab,0x10,0x7d,0x65,0xbe,0xe3,0xe4,0xd6, + 0x41,0x6c,0x83,0xc7,0x5f,0xd7,0x00,0xb8,0x71,0xb4,0xf1,0x8e,0xd1,0x31,0x0f,0xf8, + 0x2a,0x3c,0xa5,0xab,0x24,0xa9,0xc3,0x89,0xd0,0xc0,0x1d,0xf4,0xca,0x1f,0xc0,0x9f, + 0x11,0x27,0x89,0xb5,0xa4,0xd2,0x4b,0x27,0xe2,0x94,0x85,0x34,0xea,0x95,0xb6,0x11, + 0x8e,0x8f,0x7a,0x1f,0x78,0x6c,0xbf,0x10,0xc7,0x2e,0x12,0x8d,0xb3,0x0c,0x88,0x1b, + 0xd2,0x7b,0x33,0xd9,0xd2,0xad,0xa5,0x57,0x56,0x00,0x54,0x7c,0x85,0xbd,0x8e,0xbb, + 0x2c,0xc5,0xb4,0x4d,0xca,0xa6,0x72,0x27,0x67,0xde,0x72,0xdc,0xf3,0x87,0x2d,0xaf, + 0x9c,0xbf,0x18,0xf0,0x07,0xbd,0x72,0x2a,0xb0,0xfc,0x9a,0x5f,0xde,0x2c,0x10,0x6e, + 0x7b,0xd6,0xc8,0x92,0xbc,0xe0,0xeb,0xb8,0xab,0x92,0xf5,0xad,0xdc,0x30,0xe9,0x3a, + 0x8d,0xc7,0x44,0x48,0xa1,0xd2,0xfd,0x5b,0x2e,0x13,0x81,0x09,0x94,0xb5,0xc4,0x02, + 0xdb,0x4e,0xaf,0xd8,0x0a,0xf6,0xa9,0x91,0xb8,0x17,0x52,0x3e,0x0d,0x67,0x2a,0xa1, + 0x43,0x64,0xf5,0xa3,0x04,0x8b,0x7b,0x00,0xe2,0x94,0x50,0x70,0x8f,0xb9,0x83,0x6b, + 0x90,0x69,0x5c,0x53,0x1f,0x09,0x1c,0x31,0xcb,0x70,0x3a,0xa4,0x78,0xc3,0xd2,0xa1, + 0xea,0x52,0x6f,0x1c,0xe1,0x1b,0xbf,0x0c,0x2b,0xf9,0x30,0x98,0xc3,0xb3,0xf9,0xa7, + 0x46,0x69,0xf1,0x3a,0x3f,0x3c,0x46,0x95,0x34,0x97,0x72,0x25,0x8f,0xe9,0x64,0x4c, + 0x88,0x45,0x1d,0xb2,0xa4,0x0f,0x37,0x62,0x61,0x2d,0x60,0xc2,0xba,0xb9,0xfd,0x14, + 0xcb,0x29,0xbe,0x42,0xef,0x2e,0x15,0xae,0x65,0x98,0x46,0xe7,0xd1,0x91,0x55,0xdb, + 0x48,0x32,0x7c,0x5b,0xb6,0x72,0x2d,0x3e,0x4a,0xed,0x0e,0x2f,0x60,0x6e,0x88,0x6e, + 0xb6,0x0d,0xa3,0x2c,0xfa,0xe1,0xf4,0x21,0xb1,0xc9,0x1a,0xba,0xc4,0x6c,0xfb,0xc4, + 0xaa,0xc8,0x67,0xa7,0x39,0x27,0x2b,0x55,0xfb,0xbf,0x72,0x6f,0xf3,0x3a,0x41,0xbf, + 0xfb,0x53,0xde,0xd6,0x5a,0x7c,0xde,0x7d,0xa5,0xf3,0xcf,0xaa,0xdb,0xfa,0x20,0xf7, + 0x0a,0x67,0xc2,0x17,0x37,0xea,0x0f,0xe2,0xf7,0xe9,0x8b,0x0e,0x97,0x7d,0xfe,0xf9, + 0xfd,0xff,0x05,0x0b,0x53,0xe7,0x7c,0x8f,0x5f,0x00,0x00, }; constexpr size_t WIFI_INDEX_HTML_GZ_LEN = sizeof(WIFI_INDEX_HTML_GZ); // diff --git a/firmware/toolchain/console_demo.py b/firmware/toolchain/console_demo.py index a44db1ec..63464450 100644 --- a/firmware/toolchain/console_demo.py +++ b/firmware/toolchain/console_demo.py @@ -1182,20 +1182,19 @@ def main(): watch(D); // The chrome marks the tab whose device path is this page's location; here // the location is the demo file's, so the tab is marked the way drawNav() - // would have, centred in a nav that scrolls (the phone's), before the - // first paint of every redraw. + // would have, before the first paint of every redraw. The nav wraps (no + // sideways scroll) and its setup group sits in a nested , + // so the links are found at any depth, not as the nav's children. function markNav(root) { - var nav = root.querySelector('nav'), on = null, i, a; + var nav = root.querySelector('nav'), on = null, i, a, l; if (!nav) return; - for (i = 0; i < nav.children.length; i++) { - a = nav.children[i]; + for (l = nav.querySelectorAll('a'), i = 0; i < l.length; i++) { + a = l[i]; if (a.pathname !== L.pathname) continue; on = a; if (a.className !== 'on') { a.className = 'on'; a.setAttribute('aria-current', 'page'); - var e = nav.getBoundingClientRect(), r = a.getBoundingClientRect(); - nav.scrollLeft += r.left + r.width / 2 - e.left - e.width / 2; } } return on; diff --git a/web/public/guide/console-demo/index.html b/web/public/guide/console-demo/index.html index 280f8d21..4c3b06e5 100644 --- a/web/public/guide/console-demo/index.html +++ b/web/public/guide/console-demo/index.html @@ -2,323 +2,152 @@ - + Patternflow - + - - -
              -

              Console

              device
              - - +
              +
              -
              -
              -
              - Now playing +
              +
              +
              +

              Now playing

              -
              - - -
              + +
              —
              -
              - - -
              - Panel -
              - - -
              -
              -
              -
              - Brightness - - — -
              - -
              -
              - Live Knobs - -
              -
              - K1 - -
              -
              - K2 - -
              -
              - K3 - -
              -
              - K4 - +
              + +
              +
              + Panel +
              + + +
              +
              +
              —
              +
              -
              -
              Patterns
              —
              -
              Storage
              —
              -
              -
              Wi-Fi
              —
              -
              Address
              —
              - - -
              Memory
              —
              -
              Uptime
              —
              -
              Firmware
              —
              - - - Edition -
              —
              -
              -
              +
              +
              Knobs
              +
              +
              +
              +
              - - update - how to update → + release manifest and hands the new image to this board over Wi-Fi. --> +
              - @@ -330,85 +159,68 @@ function $(i){return document.getElementById(i)} $('host').textContent=location.hostname; +// A range's filled part (--p) follows its value. +function fill(el){el.style.setProperty('--p',(el.value-el.min)/(el.max-el.min)*100+'%')} +document.addEventListener('input',function(e){if(e.target.type==='range')fill(e.target)}); + // ── What this build actually has ─────────────────────────────── -// Feature rows are not written into this page. Whatever features the firmware -// carries report their pages in /api/status featureNav — path, label, one -// line — and the Features group is built from that. A build with none gets -// no group, and a page the core has never heard of still gets a row. This -// used to work the other way round: rows for every feature in the markup, -// deleted when the capability was absent, which meant a core page naming -// features and a new feature's page getting no row at all. -// -// Rebuilt from scratch whenever featureNav changes (not on every status: the -// card polls, and a rebuild under the pointer drops hover and focus), then -// everything renumbers so the list still reads 01, 02, 03. +// Feature rows come from /api/status featureNav (path, label, one line), +// contributed by whatever features the firmware carries; a build with none +// gets none, and a page the core never heard of still gets a row. Rebuilt +// only when featureNav changes: the card polls, and a rebuild under the +// pointer drops hover and focus. var navKey; function gate(s){ - var i,nav=(s&&s.featureNav)||[],k=JSON.stringify(nav); + var i,nav=(s&&s.featureNav)||[],k=JSON.stringify(nav),f=$('featRows'); if(k===navKey)return; navKey=k; - var f=$('featRows'),fk=$('featKick'); - if(f){ - f.innerHTML=''; - for(i=0;i
              '; - a.querySelector('.pf-row-t').textContent=e[1]; - a.querySelector('.pf-row-d').textContent=e[2]||''; - f.appendChild(a); - } - f.hidden=fk.hidden=!f.querySelector('.pf-row'); + f.innerHTML=''; + for(i=0;i'; + a.firstChild.textContent=e[1]; + a.lastChild.textContent=e[2]||''; + f.appendChild(a); } - var ghosts=document.querySelectorAll('.rows .pf-ghost'); - for(i=0;i 100) v = 100; - var sl = $('sl-' + i); - if (sl) { - sl.value = v; - lastReported[i] = v; - } +// ── Knob sliders (K1..K4 · 0..100) ──────────────────────────── +var activeSlider=-1,inFlight=false,queuedParams={}; +function updateSliders(params){ + if(!params||params.length<4)return; + for(var i=0;i<4;i++){ + if(activeSlider===i)continue; + var v=Math.round(params[i]/10); + if(v<0)v=0;if(v>100)v=100; + var sl=$('sl-'+i);sl.value=v;fill(sl); } } - -function pumpParams() { - if (inFlight) return; // Drop redundant updates while in-flight; keep newest in queue - var keys = Object.keys(queuedParams); - if (!keys.length) return; - - var bodyParts = []; - for (var i = 0; i < keys.length; i++) { - var k = keys[i]; - bodyParts.push(k + '=' + encodeURIComponent(queuedParams[k])); - } - queuedParams = {}; - inFlight = true; - - fetch('/api/params', { - method: 'POST', - cache: 'no-store', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - body: bodyParts.join('&') - }).then(function(r) { - if (!r.ok) throw Error('refused'); - $('ctrlmsg').textContent = ''; - }).catch(function(x) { - // Next to the sliders, not swallowed: a drag that never arrived looks - // exactly like a pattern ignoring its knobs. - PF.say('not sent — ' + (x && x.message === 'refused' ? 'refused' : 'no answer'), 'err', $('ctrlmsg')); - }).then(function() { - inFlight = false; - if (Object.keys(queuedParams).length) { - pumpParams(); // Flush pending latest updates - } - }); -} - -function onSliderInput(idx, val) { - var v = parseInt(val, 10); - if (isNaN(v)) return; - lastReported[idx] = v; - - // pX on the 0..1000 bus. The device derives the clicks a legacy pattern - // reads from the change in the held value, so no dX alongside — sending - // both counted every move twice. - queuedParams['p' + (idx + 1)] = v * 10; - - pumpParams(); -} - -function initSliders() { - for (var i = 0; i < 4; i++) { - (function(idx) { - var sl = $('sl-' + idx); - if (!sl) return; - held(sl, function() { activeSlider = idx; }, function() { - if (activeSlider === idx) activeSlider = -1; - pumpParams(); - }); - sl.addEventListener('input', function() { - var v = sl.value; - onSliderInput(idx, v); - }); - })(i); - } +function pumpParams(){ + if(inFlight)return; // one in flight; the newest values wait in the queue + var keys=Object.keys(queuedParams),body=[],i; + if(!keys.length)return; + for(i=0;i 0 ? 'Next…' : 'Prev…'; - PF.get('/api/patterns/select?step=' + dir).then(function(d) { - $('now').textContent = d.name || prev; - $('nowsub').textContent = 'switched'; - $('stepmsg').textContent = ''; - }, function(x) { - $('now').textContent = prev; - if (!x || !x.nav) - PF.say(x && x.status === 404 ? 'nothing to switch to' : 'not switched', 'err', $('stepmsg')); +function stepPattern(dir){ + var prev=$('now').textContent; + $('now').textContent=dir>0?'Next…':'Prev…'; + PF.get('/api/patterns/select?step='+dir).then(function(d){ + $('now').textContent=d.name||prev; + $('nowsub').textContent='switched'; + $('stepmsg').textContent=''; + },function(x){ + $('now').textContent=prev; + if(!x||!x.nav) + PF.say(x&&x.status===404?'nothing to switch to':'not switched','err',$('stepmsg')); }); } -$('pat-prev').addEventListener('click', function() { stepPattern(-1); }); -$('pat-next').addEventListener('click', function() { stepPattern(1); }); +$('pat-prev').addEventListener('click',function(){stepPattern(-1)}); +$('pat-next').addEventListener('click',function(){stepPattern(1)}); +[].forEach.call(document.querySelectorAll('input[type=range]'),fill); PF.watchStatus(3000); PF.status(paint); diff --git a/web/public/guide/console-demo/knobs.html b/web/public/guide/console-demo/knobs.html index 3521e587..1b12b3db 100644 --- a/web/public/guide/console-demo/knobs.html +++ b/web/public/guide/console-demo/knobs.html @@ -1,97 +1,74 @@ - + Patternflow - Knobs
              -

              Knobs

              -
              -
              -

              Direction and click size

              - - - -
              PositionDirectionEdges per click
              -
              - - -
              -
              -

              Turn a knob clockwise. Its position should go up by one per click. - Goes down: set that knob to Reversed. Moves two per click, or needs two clicks to - move one: change Edges per click until one click is one step (most encoders are 4; - the edge counter under the position shows how many one click really makes). - These are properties of the encoder soldered in, stored on the device — nothing to - rebuild, and a saved change does not move the knob.

              -
              - +.pf-offline .pos,.pf-offline #st{opacity:.5} + +
              +

              Knobs

              -
              +

              Turn a knob one click clockwise: its position should go up by one.

              + + + +
              PositionDirectionEdges per click
              +
              + + +
              +

              Goes down: set it to Reversed. Moves two, or takes two clicks to move one: +change edges per click (most encoders are 4; the edge count under the position shows how many one click makes). +Saved on the panel: nothing to rebuild, and saving does not move a knob.

              + +
              diff --git a/web/public/guide/console-demo/patterns.html b/web/public/guide/console-demo/patterns.html index 6c2f4b4f..30a5c2a6 100644 --- a/web/public/guide/console-demo/patterns.html +++ b/web/public/guide/console-demo/patterns.html @@ -1,194 +1,149 @@ - + Patternflow - Patterns
              -

              Patterns

              -
              - - - -
              -

              Storage needs formatting

              -

              This board's pattern partition isn't readable — either it has never been - formatted, or its filesystem is damaged. Format it once, and patterns install - normally from then on.

              -
              - - -
              +/* Touch: no drag and drop on a phone, so arrows instead, in the room the + module chip leaves (the checkbox says it is a module). Narrow buttons keep + the name wide; their 40px hit areas meet in the 6px gaps. */ +@media(pointer:coarse){.btn.mv{display:inline-flex;width:34px;padding:0;font-size:16px}.chip.mod,.fine{display:none} +.list>li{gap:6px;padding:4px 6px}.list .btn.sm::after{inset:-4px -3px}.list .dan{padding:0 8px}#bulk{row-gap:10px}} +@media(min-width:960px){.wrap{max-width:1080px;padding-top:32px} +.grid{display:grid;grid-template-columns:380px minmax(0,1fr);gap:48px;align-items:start} +.grid section{margin-top:0}.lc{position:sticky;top:8px}.q{max-height:55vh;overflow:auto}} + + +
              +

              Patterns

              —
              + + + -
              -
              +
              +

              Upload

              -
                +
                -
                -
                - -
                +
                -
                +
                -

                Installed

                -
                - - - - - +
                +

                Installed

                +
                -
                -
                  +
                    + +

                    Tap or click a name to play it. Drag modules to reorder. Presets are built into the firmware and can’t be removed here.

                    -
                    Presets are built into the firmware and cannot be removed here. - Home
                    -
                    + +
                    \ No newline at end of file + diff --git a/web/public/guide/console-demo/pf-console.js b/web/public/guide/console-demo/pf-console.js index 696f93fa..64adfbf6 100644 --- a/web/public/guide/console-demo/pf-console.js +++ b/web/public/guide/console-demo/pf-console.js @@ -1,31 +1,33 @@ (function(){ if(window.PF)return; -var W=window,D=document,H=D.documentElement,L=location,light=false; +var W=window,D=document,H=D.documentElement,L=location,dark=false,cn=null,hm={},k, +st=D.createElement('style'),c; // Theme before first paint: this script is parser-blocking in . -try{light=localStorage.getItem('pf-theme')==='light'}catch(e){} -if(light)H.setAttribute('data-theme','light'); -var st=D.createElement('style'); -// --pf-chrome-h is the header's exact height (see the shadow CSS below). -st.textContent='html[data-theme=light]{color-scheme:light;--cream:#F4EFE6;--cream2:#FFFCFA;--ink:#1A1814;--muted:#6B6558;--faint:#9A9486;--rule:#D9D1C2;--rule-soft:#E8E2D6;--led:#FF5C2E;--ok:#2F8A55;--warn:#B88120;--panel:#FFFCFA;--bg:#F4EFE6;--ghost:#E0D9CC;--card:#FFFCFA;--card2:#E8E2D6;--fg:#1A1814;--mut:#6B6558;--ln:#D9D1C2;--bad:#B8402E;--bar:#E0D9CC;--bar-on:#FF5C2E;--accent:#FF5C2E}' -+':root{color-scheme:dark;--pf-chrome-h:81px}@media(min-width:720px){:root{--pf-chrome-h:41px}}' -+'html:not(.pf-mounted) body::before{content:"";display:block;box-sizing:border-box;height:var(--pf-chrome-h);border-bottom:1px solid var(--rule,#242118);background:var(--cream,var(--bg,#0C0B09))}' +try{dark=localStorage.getItem('pf-theme')==='dark';cn=JSON.parse(localStorage.getItem('pf-nav'));hm=cn&&cn.h||{}}catch(e){} +H.setAttribute('data-theme',dark?'dark':'light'); +// Light palette = the core pages' :root values; outranks any page's own. +c='html[data-theme]{--sans:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--mono:ui-monospace,"Cascadia Mono","SF Mono",Menlo,Consolas,"Roboto Mono",monospace}' ++'html:root[data-theme=light]{color-scheme:light;--cream:#F4EFE6;--panel:#FFFCFA;--ink:#1A1814;--muted:#625C51;--faint:#7D7668;--rule:#DDD5C6;--rule-soft:#E8E1D4;--ghost:#E3DCCE;--led:#FF5C2E;--bad:#B83C1C;--ok:#2B7A4B;--warn:#85600E;--cream2:#FFFCFA}' ++'html[data-theme=dark]{color-scheme:dark}:root{--pf-chrome-h:85px}@media(max-width:369px){:root{--pf-chrome-h:125px}}@media(min-width:1024px){:root{--pf-chrome-h:49px}}' ++'html:not(.pf-mounted) body::before{content:"";display:block;box-sizing:border-box;height:var(--pf-chrome-h);border-bottom:1px solid var(--rule,#DDD5C6);background:var(--cream,#F4EFE6)}' +'@media(pointer:coarse){input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]),select,textarea{font-size:16px!important}}' +'.pf-busy{opacity:.55;cursor:progress}'; +for(k in hm)c+='@media(min-width:'+(k-1)+'px) and (max-width:'+k+'.9px){:root{--pf-chrome-h:'+(hm[k]|0)+'px}}'; +st.textContent=c; (D.head||H).appendChild(st); var PF=W.PF={v:null,state:'connecting',dirty:false}, nf=W.fetch,T=[],cur=null,Q=[],lb=0,run=1,P=[],S=null,subs=[],sq=null,sb=0,wms=1/0,sp=null, rtt=null,fails=0,off=0,alien=0,rs=0,holds=0,guards=0,leaveOk=0,RH={},bc=null, me=Math.random().toString(36).slice(2),touched=0,pd=0,nv=0,nvT,pgT, -adopted=0,healed=0,stale=null,pft=0,ct=0,cn=null,fnav=[],drawn='', +adopted=0,healed=0,stale=null,pft=0,ct=0,fnav=[],drawn='', sr,hl,ver,vb,nav,ch,tg,pg,tw,tq,tt,SKIP={}, // The core's pages and nothing else; features add theirs via featureNav at // NAV_AT. Third field: prefetch order, smallest page first. -NAV=[['/','Console',5],['/patterns','Patterns',6],['/status','Status',2],['/wifi','Wi-Fi',4],['/knobs','Knobs',1],['/update','Update',3]],NAV_AT=2; +NAV=[['/','Console',5],['/patterns','Patterns',6],['/wifi','Wi-Fi',4],['/knobs','Knobs',1],['/update','Update',3],['/status','Status',2]],NAV_AT=2; try{PF.v=new URLSearchParams(L.search).get('v')}catch(e){} var docB=PF.v; H.classList.add('pf-connecting'); -try{cn=JSON.parse(localStorage.getItem('pf-nav'))}catch(e){} if(cn&&Array.isArray(cn.nav)&&(!PF.v||cn.build===PF.v))fnav=cn.nav; function now(){return Date.now()} @@ -147,10 +149,12 @@ else if(sp)sp.set(ms); else sp=PF.poll(stGet,ms,function(){},{first:false}); } function deliver(s){ +var fn=Array.isArray(s.featureNav)?s.featureNav:[],r=!S; S=W.pfStatus=s;sb=0; -var fn=Array.isArray(s.featureNav)?s.featureNav:[]; -if(s.build+JSON.stringify(fn)!==drawn){fnav=fn;try{localStorage.setItem('pf-nav',JSON.stringify({build:s.build,nav:fn}))}catch(x){}drawNav()} +if(s.build+JSON.stringify(fn)!==drawn){fnav=fn;drawNav();r=1} badge(); +if(r&&sr){sr.host.style.minHeight='';if(Object.keys(hm).length>7)hm={};hm[W.innerWidth]=sr.host.offsetHeight} +if(r)try{localStorage.setItem('pf-nav',JSON.stringify({build:s.build,nav:fn,h:hm}))}catch(x){} for(var i=0;i1);nav.classList.toggle('fr',s
                    '; ++'
                    '; function q(c){return sr.querySelector('.'+c)} hl=q('h');ver=q('ver');vb=q('vb');nav=q('n');ch=q('c');tg=q('tg');pg=q('pg');tw=q('tw'); +if(!S)host.style.minHeight='var(--pf-chrome-h)'; D.body.insertBefore(host,D.body.firstChild); H.classList.add('pf-mounted'); -nav.addEventListener('scroll',fades,{passive:true}); -W.addEventListener('resize',fades); -tg.onclick=function(){var l=H.getAttribute('data-theme')!=='light';H.setAttribute('data-theme',l?'light':'dark');try{localStorage.setItem('pf-theme',l?'light':'dark')}catch(x){}tgl()}; +tg.onclick=function(){var t=dk()?'light':'dark';H.setAttribute('data-theme',t);try{localStorage.setItem('pf-theme',t)}catch(x){}tgl()}; ch.onclick=function(){if(stale)L.replace(vurl(stale));else if(PF.state==='offline')fetchStatus()}; tgl();drawNav();badge();chip(); setTimeout(function(){ct=1;chip()},800); @@ -394,7 +394,7 @@ if(u.pathname+u.search===L.pathname+L.search)return; if(guards){if(!confirm('An upload is running \u2014 leave anyway?')){e.preventDefault();return}leaveOk=1} nv=1;run=0; for(i=T.length;i--;)if(!(T[i].k==='prefetch'&&T[i].u===u.href)){T[i].why='nav';T[i].c.abort()} -if(nav)for(i=0;i, + // so the links are found at any depth, not as the nav's children. function markNav(root) { - var nav = root.querySelector('nav'), on = null, i, a; + var nav = root.querySelector('nav'), on = null, i, a, l; if (!nav) return; - for (i = 0; i < nav.children.length; i++) { - a = nav.children[i]; + for (l = nav.querySelectorAll('a'), i = 0; i < l.length; i++) { + a = l[i]; if (a.pathname !== L.pathname) continue; on = a; if (a.className !== 'on') { a.className = 'on'; a.setAttribute('aria-current', 'page'); - var e = nav.getBoundingClientRect(), r = a.getBoundingClientRect(); - nav.scrollLeft += r.left + r.width / 2 - e.left - e.width / 2; } } return on; diff --git a/web/public/guide/console-demo/status.html b/web/public/guide/console-demo/status.html index 5b4b9793..fc962584 100644 --- a/web/public/guide/console-demo/status.html +++ b/web/public/guide/console-demo/status.html @@ -1,113 +1,109 @@ - + Patternflow - Status
                    -

                    Status

                    -
                    - - -
                    - - -

                    Device

                    -
                    Firmware
                    -
                    -
                    Build
                    -
                    -
                    Last restart
                    -
                    -
                    Busy
                    -
                    -
                    Panel size
                    -
                    +/* Console base: the same block opens every core page. Light in :root (the chrome's + injected light palette holds these same values: keep the two in step), + dark under html[data-theme=dark]. No web fonts: the hotspot has no internet. */ +:root{color-scheme:light;--cream:#F4EFE6;--panel:#FFFCFA;--ink:#1A1814;--muted:#625C51;--faint:#7D7668;--rule:#DDD5C6;--rule-soft:#E8E1D4;--ghost:#E3DCCE;--led:#FF5C2E;--bad:#B83C1C;--ok:#2B7A4B;--warn:#85600E; +--sans:system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;--mono:ui-monospace,'Cascadia Mono','SF Mono',Menlo,Consolas,'Roboto Mono',monospace} +html[data-theme=dark]{color-scheme:dark;--cream:#0C0B09;--panel:#131110;--ink:#EDE7DB;--muted:#A39B8A;--faint:#7A7364;--rule:#2B2721;--rule-soft:#1F1C18;--ghost:#2A2620;--bad:#FF7A55;--ok:#57B87F;--warn:#D9A03F} +*{box-sizing:border-box}[hidden]{display:none!important} +body{margin:0;background:var(--cream);color:var(--ink);font:15px/1.5 var(--sans);-webkit-font-smoothing:antialiased} +a{color:inherit}:focus-visible{outline:2px solid var(--led);outline-offset:2px} +.wrap{max-width:720px;margin:0 auto;padding:20px 16px 48px} +h2{margin:0 0 6px;font-size:13px;font-weight:600;color:var(--muted)} +.card{background:var(--panel);border:1px solid var(--rule);border-radius:10px;padding:16px} +.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:40px;padding:0 16px;border:1px solid var(--rule);border-radius:8px;background:var(--panel);color:var(--ink);font:500 14px var(--sans);text-decoration:none;cursor:pointer;transition:border-color .15s,background .15s,color .15s} +@media(hover:hover){.btn:hover{border-color:var(--ink)}footer a:hover{color:var(--ink)}} +.btn:disabled{opacity:.45;cursor:default;border-color:var(--rule)} +.msg{font:12px var(--mono);color:var(--faint)}.pf-ok{color:var(--ok)}.pf-err{color:var(--bad)} +footer{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:40px;border-top:1px solid var(--rule);font:12px var(--mono);color:var(--faint)} +footer a{display:inline-flex;align-items:center;min-height:40px;color:var(--muted);text-decoration:none} +header{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 12px;margin-bottom:20px} +h1{flex:1;margin:0;font-size:22px;font-weight:600;letter-spacing:-.01em} +.sub{font:12px var(--mono);color:var(--faint)} +section{margin-top:28px} +.note{margin:8px 0 0;font-size:13px;color:var(--muted)} +.btn.dan{color:var(--bad)}@media(hover:hover){.btn.dan:hover{border-color:var(--bad)}} +.acts{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:12px} +.kv{margin:0;border-top:1px solid var(--rule)} +.kv>div{display:flex;align-items:baseline;gap:12px;padding:8px 0;border-bottom:1px solid var(--rule-soft);font-size:13px} +.kv dt{flex:1 0 auto;color:var(--muted)}.kv dd{margin:0;min-width:0;font:12.5px var(--mono);text-align:right;overflow-wrap:anywhere} +/* ── Status ── */ +.kv .big{font-size:14px;font-weight:600} +.ok{color:var(--ok)}.warn{color:var(--warn)}.bad{color:var(--bad)} +.bar{display:block;height:3px;margin:5px 0 2px auto;max-width:160px;background:var(--ghost)}.bar i{display:block;height:100%;background:var(--led)} +#cptext{display:block;width:100%;height:180px;margin-top:12px;padding:8px 10px;resize:vertical;color:var(--ink);font:12px/1.45 var(--mono)} +.pf-offline .kv dd{opacity:.5} + +
                    +

                    Status

                    -
                    + +
                    + + +

                    Device

                    +
                    Firmware
                    -
                    +
                    Build
                    -
                    +
                    Last restart
                    -
                    +
                    Busy
                    -
                    +
                    Panel size
                    -
                    -

                    Render

                    -
                    Panel
                    -
                    -
                    Frame rate
                    -
                    -
                    Frame time
                    -
                    -
                    Active pattern
                    -
                    + + +

                    Render

                    +
                    Panel
                    -
                    +
                    Frame rate
                    -
                    +
                    Frame time
                    -
                    +
                    Active pattern
                    -

                    -

                    Patterns

                    -
                    Total
                    -
                    -
                    Built into firmware
                    -
                    -
                    Loaded from storage
                    -
                    -
                    Last load error
                    -
                    +

                    Patterns

                    +
                    Total
                    -
                    +
                    Built into firmware
                    -
                    +
                    Loaded from storage
                    -
                    +
                    Last load error
                    -

                    -

                    Memory

                    -
                    Internal heap free
                    -
                    -
                    Largest free block
                    -
                    -
                    PSRAM free
                    -
                    +

                    Memory

                    +
                    Internal heap free
                    -
                    +
                    Largest free block
                    -
                    +
                    PSRAM free
                    -
                    -

                    Internal heap is the scarce one - the LED panel's DMA buffers -live there. A pattern module loads only if it leaves 24 KB -of it free; run lower and the network is the first thing to go, while the -panel keeps drawing.

                    +

                    Internal heap is the scarce one: the panel’s DMA buffers live there. A module loads only if it +leaves 24 KB free; below that the network goes first, while the panel keeps drawing.

                    -

                    Storage

                    -
                    Pattern storage
                    -
                    -
                    Storage error
                    -
                    -
                    +

                    Storage

                    +
                    Pattern storage
                    -
                    +
                    Storage error
                    -
                    +
                    - -

                    Network

                    -
                    Network
                    -
                    -
                    Signal
                    -
                    -
                    Address
                    -
                    -
                    Names
                    -
                    -
                    Hotspot
                    -
                    -
                    Hotspot mode
                    -
                    -
                    Hotspot clients
                    -
                    -
                    Reached via
                    -
                    +

                    Network

                    +
                    Network
                    -
                    +
                    Signal
                    -
                    +
                    Address
                    -
                    +
                    Names
                    -
                    +
                    Hotspot
                    -
                    +
                    Hotspot mode
                    -
                    +
                    Hotspot clients
                    -
                    +
                    Reached via
                    -
                    - -
                    + +
                    + Patternflow — Firmware update -
                    -
                    -

                    Update

                    …
                    +
                    +

                    Update

                    …
                    +

                    Drop a firmware .bin: the panel flashes itself over the network and restarts on the new build.

                    -

                    Drop a firmware .bin — the device flashes itself over the LAN and reboots on the new build.

                    - - -
                    - Linked build -
                    - + + - Two steps -
                    01

                    Get a .bin: patternflow.work/update sends the latest release straight back to this page. Or bring your own — an arduino-cli export.

                    -
                    02

                    Drop it below. Keep the device powered; it verifies, flashes, and reboots itself.

                    - -
                    This build requires arming first. On the device: hold K2 → NETWORK, then turn K4 → UPDATE.
                    + -
                    - Drop .bin here - Checking the panel… +
                    + Drop a .bin here + Checking the panel…
                    - + does the same; an explicit any-type accept is what reliably brings + up the file manager. The JS checks extension and size instead. --> +
                    - + + +

                    No file? patternflow.work/update sends the + latest release straight back to this page. Your own arduino-cli export works too. Keep the panel + powered: it checks, flashes and restarts by itself.

                    + +
                    -
                    + Patternflow - Wi-Fi
                    -

                    Wi-Fi

                    -
                    +.s1 i+i,.s2 i+i+i,.s3 i+i+i+i{background:var(--ghost)} +.dym,.dym span+span{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.dym{margin-top:8px;padding:6px 6px 6px 12px} +#join{margin-top:12px}#join.ok{border-left-color:var(--ok)}#join.err{border-left-color:var(--bad)} +#join .big{display:inline-block;margin:6px 10px 6px 0;font:18px var(--mono);overflow-wrap:anywhere} +.seg{display:flex;gap:2px;max-width:360px;padding:2px;border:1px solid var(--rule);border-radius:9px;background:var(--cream)} +.seg label{flex:1;position:relative} +.seg input{position:absolute;opacity:0;margin:0} +.seg span{display:flex;align-items:center;justify-content:center;min-height:40px;border-radius:7px;color:var(--muted);font-weight:500;font-size:14px;cursor:pointer;transition:background .15s,color .15s} +.seg :checked+span{background:var(--panel);color:var(--ink);box-shadow:0 0 0 1px var(--rule),inset 0 -2px var(--led)} +.seg :focus-visible+span{outline:2px solid var(--led)} +.pf-offline #st,.pf-offline #list,.pf-offline #hsstate{opacity:.5} +@media(hover:hover){.btn.dan:hover{border-color:var(--bad)}summary:hover,.seg span:hover{color:var(--ink)}.scan button:hover .nm{text-decoration:underline}} + + +
                    +

                    Wi-Fi

                    -
                    - -

                    Add a network

                    -
                    - - Network name + + + + +
                    + - - +
                    -
                    - -
                    - - -
                    -
                    -
                    - - - - +
                    + + +
                    -
                    - -

                    Saved networks are tried in order starting from the boot slot, - wrapping around — so the device joins whichever one it can find, useful if it - moves between home, a studio and a venue. A new network is only stored; leave - switch now unticked and this page keeps working. Ticking it drops the - current connection immediately. On the panel's hotspot a network is tried at once, - and the panel shows the outcome on its screen as well as here: the address to open, - or why it could not join.

                    + +

                    Save stores it and this page keeps working; Switch now drops this connection to join it.

                    +
                    How saved networks are tried +

                    In order from the boot slot, wrapping around, so the panel joins whichever it finds: home, studio, venue.

                    Hotspot

                    -

                    -

                    +

                    -

                    +

                    The panel’s own network, patternflow-????: join it and open + http://192.168.4.1/, the same console anywhere. Phones stay on it though it has no internet. + Auto raises it about 15 s after the panel finds no Wi-Fi and drops it once it joins one.

                    -
                    - - -
                    -
                    - - +

                    Mode

                    +
                    + + +
                    -
                    - + + +
                    + +
                    -
                    -

                    The panel as a network of its own: patternflow-????. - Join it from a phone or a laptop and open http://192.168.4.1/ — the - same console, anywhere. auto raises it about fifteen seconds after the panel - finds no network and drops it once one is joined; a network added above from the - hotspot is tried at once. The phone is told the network works, so it stays on it; - it has no internet through the panel.

                    - -
                    + +
                    -Patternflow - Mic mapping - +Patternflow - Audio + -
                    - -
                    -
                    - - Patternflow Audio - MAPPING -
                    -
                    - - idle - patternflow.local:81 - -
                    -
                    - -
                    - - -
                    - Input gain - - 8.0 -
                    - - - - Extension ↗ - -
                    - - -
                    - - - -
                    - Attack - - quick -
                    -
                    - Damping - - balanced -
                    - -
                    - -
                    - -
                    B1·K1
                    -
                    B2·K2
                    -
                    B3·K3
                    -
                    B4·K4
                    -
                    - -
                    -
                    - RESPONSE - -
                    - -
                    - CURVE -
                    - - - - - - -
                    - - This band still runs its old boost curve — pick a preset to upgrade it. - Drag the two handles for a custom shape. Any curve saves as a 33-point table. -
                    - -
                    - -
                    -
                    - Band 1 - 62 – 375 Hz -
                    - -
                    -
                    - Output range - 0.30 – 0.85 -
                    -
                    -
                    -
                    -
                    -
                    -
                    -
                    - - - - - - -
                    -
                    - -
                    - Mute band - -
                    - -
                    -
                    - -
                    -
                    -
                    - - - - -
                    - - - - -
                    - +
                    +

                    Audio

                    +

                    Sources

                    +
                      +
                    • + + + +
                      + + +
                      - +

                      +
                    • +
                    • + + +The extension brings its own mapping; the phone app uses the one below. Same switch as AUD on the panel’s NETWORK screen. +Get the extension +
                    • +
                    +

                    Mapping

                    +

                    For the microphone and the phone app. Changes save to the panel as you make them.

                    +
                    +
                    + +Each box follows the loudness of what it hears. Drag a top or bottom edge to take all four over by hand. +
                    +
                    + + + +
                    +
                    + + + +
                    +
                    +
                    +
                    + +
                    K1
                    +
                    K2
                    +
                    K3
                    +
                    K4
                    + +
                    +
                    +
                    + + + + +
                    + +
                    +
                    +
                    +Knob 1 + +
                    +
                    +Response curve +
                    + +
                    +
                    + + + + + + +
                    + + +
                    +
                    +
                    +
                    +
                    +
                    +
                    +Output range + +
                    +
                    +
                    +
                    +
                    +
                    +
                    +
                    + + + + + + +
                    +
                    + +
                    +
                    +
                    + + +
                    +
                    + +
                    + diff --git a/firmware/patternflow/features/README.md b/firmware/patternflow/features/README.md index 703c965b..36126b31 100644 --- a/firmware/patternflow/features/README.md +++ b/firmware/patternflow/features/README.md @@ -83,7 +83,7 @@ each row says which port proved it. | hook | when | proven by | | --- | --- | --- | | `setup()` | boot, before Wi-Fi | show player, weather config, MQTT role | -| `onNetwork()` | Wi-Fi connected, and every reconnect — register HTTP routes here | `/show`, `/weather`, `/mqtt`, `/audio` | +| `onNetwork()` | Wi-Fi connected, and every reconnect — register HTTP routes here | `/show`, `/weather`, `/mqtt`, `/audio-in`, `/api/audio` | | `loop(frame)` | every frame; **must not block** | show cue table, weather polling, MQTT client | | `observeFrame(input, frame)` | the *finished* input frame, for features that mirror rather than produce | MQTT publishing knob values; OSC reporting outward | | `fillInput(input)` | before the pattern sees the frame — drive a lane from a reading | weather, audio bands, MQTT deltas | @@ -177,8 +177,8 @@ Then one line in the bundle that carries it — `firmware/bundles//feat | `show/` | player, HTTP page, night/wake schedule, library pull | The first port, deliberately the hardest. | | `weather/` | readings, HTTP page, corner clock | Grew the interface: `fillInput`, `chromeVisible`. | | `mqtt/` | client, all roles + FlowLocal, HTTP page | Grew it again: `observeFrame`, sleep in both directions, `appendStatus`. | -| `audio/` | FFT bands over a websocket, HTTP page | The one with a server of its own, and a row in the device's own menu. | -| `audio_in/` | the on-board PDM microphone: FFT on a Core-0 task, four bands onto the knob lanes, `/audio-in` | The first feature that did not already exist in the core; four hooks, no core edits. Its console page is assembled from the audio extension's editor (`toolchain/build_audio_in_page.py`). | +| `audio/` | the WebSocket on port 81 that a client capturing sound elsewhere (the browser extension, the phone app) writes the four knob lanes through, and the switch that lets it (`/api/audio`) | The one with a server of its own, and a row in the device's own menu. The analysis and the mapping happen in the client; no page is served from here. `docs/audio-ws-spec.md`. | +| `audio_in/` | the on-board PDM microphone: FFT on a Core-0 task, four bands onto the knob lanes, `/audio-in` and `/api/audio-in` | The first feature that did not already exist in the core; four hooks, no core edits. Its console page is assembled from the audio extension's mapping editor and the panel's own half in `console/_audio_in_*` (`toolchain/build_audio_in_page.py`, run by `console_pages.py build`). | | `osc/` | Max / TouchDesigner / Ableton, both directions | The fifth, and the first that did not fit — see below. | | `midi/` | MIDI in and out over RTP-MIDI (Wi-Fi) and, in the MIDI edition, USB: CC 20–23 absolute, 24–27 relative, notes, Program Change | Transport-agnostic mapping in `core_midi.h`; the network transport beside it (`core_midi_rtp.h`), and the USB one (`core_midi_usb.h`) that compiles in only when the build's USB port is the OTG stack — a build flag, which is why the MIDI edition has its own env (`bundles/midi/env`). `docs/midi-spec.md`. | | `clock/` | the time cut out of the running pattern, `/clock`, `/api/clock` | Settings in its own NVS namespace, a page with a live preview, and the first user of `composeFrame`: huge anti-aliased digits the pattern shows through (typefaces rasterised offline by `toolchain/build_clock_glyphs.py`, several faces), with what fills the digits and what surrounds them chosen separately. Owns the time zone as a POSIX string with its DST rule; the core keeps the time (`src/core_clock.h`), this shows it. | diff --git a/firmware/patternflow/features/audio/audio_config.h b/firmware/patternflow/features/audio/audio_config.h index 3b36ade1..5b7b4794 100644 --- a/firmware/patternflow/features/audio/audio_config.h +++ b/firmware/patternflow/features/audio/audio_config.h @@ -14,15 +14,19 @@ #pragma once #include "../../config.h" -// Hosts a tiny UI on the device. A browser (or the phone app) captures audio, -// runs an FFT, and pushes each band's energy as a normalized 0..1 value over -// WebSocket. The core's input layer turns that into virtual knob deltas, so -// EVERY encoder-driven pattern reacts to audio with no per-pattern code. +// A WebSocket for clients that capture sound where it is playing - the Chrome +// extension, the phone app. The client runs the FFT and the mapping and sends +// each knob a normalized 0..1 value; the core's input layer lerps that into +// the parameter's own range, so EVERY encoder-driven pattern reacts to audio +// with no per-pattern code. No page is served from here. #ifndef PF_AUDIO_ENABLED #define PF_AUDIO_ENABLED 1 #endif // The same port 80 the console lives on (PatternflowHttp::HTTP_PORT); this is -// the audio module's own alias for it and nothing else should need it. +// the audio module's own alias for it and nothing else should need it. Its one +// reader is the "[AUDIO] Ready" line in core_audio_ws.h - which is also the +// string firmware/bundles/build.sh scans an image for to prove this feature +// is in it, so neither goes without the other. #ifndef PF_AUDIO_HTTP_PORT #define PF_AUDIO_HTTP_PORT 80 #endif diff --git a/firmware/patternflow/features/audio/core_audio_ws.h b/firmware/patternflow/features/audio/core_audio_ws.h index e5bb17d9..64406b33 100644 --- a/firmware/patternflow/features/audio/core_audio_ws.h +++ b/firmware/patternflow/features/audio/core_audio_ws.h @@ -1,6 +1,8 @@ // Patternflow - Audio-react WebSocket server (single-threaded) // -// A WebSocket endpoint on port 81, and nothing else. +// Owns: the WebSocket on port 81 and the four lanes it writes. Nothing else - +// no page, no HTTP route (the on/off switch's two routes are in +// feature_audio.h, on the console's server). // // This used to serve a page at /audio too — file, tab and microphone capture // in the browser. It could never work: the device is plain HTTP on a LAN @@ -9,12 +11,13 @@ // could only ever apologise, and a file player is beside the point when the // whole value is being in sync with what is actually playing. // -// Sound reaches a panel two ways now, and neither is this page: the Chrome -// extension, which has an extension context and can capture a tab, and the -// on-board microphone in audio_in, which does not involve a browser at all. (core_web_update.h registers its -// /update routes on this same server.) Browsers connect, send normalized -// 0..1 knob values per frame, and patterns read those through -// InputFrame::knobAudioActive / knobAudioValue. +// Sound reaches a panel two ways now, and neither is that page: a client that +// can capture audio where it is playing (the Chrome extension, which has an +// extension context and can capture a tab; the phone capture app), and the +// on-board microphone in audio_in, which involves no client at all. This +// file is the first kind's way in. A client connects, does its own analysis +// and mapping, and sends each knob a normalized 0..1 value; patterns read +// those through InputFrame::knobAudioActive / knobAudioValue. // // Threading: everything runs in the main Arduino loop via handle(). An // earlier version pushed this into a pinned core-0 FreeRTOS task guarded by @@ -23,13 +26,19 @@ // inline is simpler and robust — the messages are tiny, so the per-frame // cost is negligible. // -// Message protocol: +// Message protocol (the contract is docs/audio-ws-spec.md; this is a copy): // a=F,F,F,F all four lanes at once; '-' leaves a lane alone // k=N,v=F set knob N (0..3) to value F (clamped to 0..1) -// d=N,v=F add normalized delta F to knob N (-1..1) +// d=N,v=F add normalized delta F to knob N (-1..1). Nothing in this tree +// sends it any more; it is in version 1 of the written contract +// and earlier extensions spoke nothing else, so it stays. // off=N release knob N back to encoder control // off release all four knobs // +// A lane holds for AUDIO_TIMEOUT_MS after its last message and is then handed +// back to the encoder. That is what covers a tab closing mid-track - and it +// means a client holding a steady value has to keep saying it. +// // `a=` exists because sending four `k=` messages per frame did not work. A // browser client checks `bufferedAmount` before each send so it cannot // outrun a one-connection server, and after the first send of a frame that @@ -54,17 +63,6 @@ #include "../../src/core_http.h" #endif -#include "../../src/core_send.h" - -// Forward declaration: the home page pauses a loaded pattern module the same -// way the other console pages do (see core_patterns_http.h for why), but this -// header is included first, so only the declaration is available here. The -// definition lands later in the same translation unit. -namespace PatternflowPatternsHttp { -bool noteConsolePageOpened(); -void sendConsoleWakePage(); -} - namespace PatternflowAudio { #if PF_AUDIO_ENABLED @@ -282,6 +280,8 @@ inline void begin() { initialized = true; + // "[AUDIO] Ready" is the literal firmware/bundles/build.sh looks for in an + // image to prove this feature is in it. Reword the rest, not those two words. String ip = WiFi.localIP().toString(); Serial.printf("[AUDIO] Ready — UI http://%s:%d WS ws://%s:%d\n", ip.c_str(), PF_AUDIO_HTTP_PORT, ip.c_str(), PF_AUDIO_WS_PORT); diff --git a/firmware/patternflow/features/audio/feature_audio.h b/firmware/patternflow/features/audio/feature_audio.h index f314e53b..43a836ac 100644 --- a/firmware/patternflow/features/audio/feature_audio.h +++ b/firmware/patternflow/features/audio/feature_audio.h @@ -95,11 +95,12 @@ inline void fillInput(InputFrame& input) { // thing that drives them, and what a source is sending is not what the // pattern ends up seeing. // -// Neither -// was visible from outside the device: a browser could complete a websocket -// handshake, send knob messages, and have every one of them silently dropped -// because the AUD row on the NETWORK screen was off — with nothing anywhere -// saying so. The page reported CONNECTED and the panel did not move. +// Neither used to be visible from outside the device: a browser could +// complete a websocket handshake, send knob messages, and have every one of +// them silently dropped because the AUD row on the NETWORK screen was off — +// with nothing anywhere saying so. The client reported CONNECTED and the +// panel did not move. `audioClients` counts open sockets, which is why it +// cannot answer "is it being driven" on its own: read it with `audioRuntime`. inline void appendStatus(String& json) { json += ",\"audioRuntime\":"; json += PatternflowAudio::isRuntimeEnabled() ? "true" : "false"; diff --git a/firmware/patternflow/features/audio_in/audio_in_index.h b/firmware/patternflow/features/audio_in/audio_in_index.h index 1574cde2..762fd888 100644 --- a/firmware/patternflow/features/audio_in/audio_in_index.h +++ b/firmware/patternflow/features/audio_in/audio_in_index.h @@ -14,1476 +14,1288 @@ static const char AUDIO_IN_INDEX_HTML[] PROGMEM = R"HTML( -Patternflow - Mic mapping - +Patternflow - Audio + + + +
                    +

                    Audio

                    +

                    Sources

                    +
                      +
                    • + + + +
                      + + + +
                      +

                      +
                    • +
                    • + + +The extension brings its own mapping; the phone app uses the one below. Same switch as AUD on the panel’s NETWORK screen. +Get the extension +
                    • +
                    +

                    Mapping

                    +

                    For the microphone and the phone app. Changes save to the panel as you make them.

                    +
                    +
                    + +Each box follows the loudness of what it hears. Drag a top or bottom edge to take all four over by hand. +
                    +
                    + + + +
                    +
                    + + + +
                    +
                    +
                    +
                    + +
                    K1
                    +
                    K2
                    +
                    K3
                    +
                    K4
                    + +
                    +
                    +
                    + + + + +
                    + +
                    +
                    +
                    +Knob 1 + +
                    +
                    +Response curve +
                    + +
                    +
                    + + + + + + +
                    + + +
                    +
                    +
                    +
                    +
                    +
                    +
                    +Output range + +
                    +
                    +
                    +
                    +
                    +
                    +
                    +
                    + + + + + + +
                    +
                    + +
                    +
                    +
                    + + +
                    +
                    + +
                    + + )HTML"; // GENERATED by firmware/toolchain/console_pages.py build — do not edit. -// gzip -9 of AUDIO_IN_INDEX_HTML (69547 bytes → 19920 bytes), served with Content-Encoding: gzip. +// gzip -9 of AUDIO_IN_INDEX_HTML (57490 bytes → 17217 bytes), served with Content-Encoding: gzip. static const uint8_t AUDIO_IN_INDEX_HTML_GZ[] PROGMEM = { - 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xd5,0x7d,0xdb,0x76,0x1b,0x47, - 0x92,0xe0,0xbb,0xbe,0x22,0x45,0xf7,0x18,0x80,0x05,0x14,0x01,0xf0,0x22,0x09,0x14, - 0xa5,0xa5,0x28,0xca,0xd2,0x5a,0x17,0x1e,0x91,0x6e,0xcd,0xb4,0x96,0xeb,0x29,0x00, - 0x05,0xa0,0xcc,0x42,0x15,0x5c,0x55,0x20,0x09,0xab,0xb9,0xa7,0x9f,0xe6,0x03,0x66, - 0xe7,0x9c,0x3d,0xfb,0x25,0xf3,0x3e,0x9f,0xd2,0x5f,0xb2,0x71,0xc9,0x6b,0x5d,0x40, - 0x48,0xf6,0xcc,0x76,0x77,0xdb,0x26,0xaa,0x2a,0x33,0x32,0x33,0x32,0x32,0x6e,0x19, - 0x19,0xf9,0xe4,0xfe,0x38,0x19,0xe5,0xab,0x45,0x20,0x66,0xf9,0x3c,0x7a,0x7a,0xef, - 0x09,0xfe,0x11,0x91,0x1f,0x4f,0x0f,0xb7,0x82,0x78,0x0b,0x5f,0x04,0xfe,0x18,0xfe, - 0xcc,0x83,0xdc,0x17,0xa3,0x99,0x9f,0x66,0x41,0x7e,0xb8,0xb5,0xcc,0x27,0x9d,0x47, - 0xf8,0x35,0x1b,0xa5,0xe1,0x22,0x17,0x59,0x3a,0x3a,0xdc,0xda,0x5e,0x4c,0x3a,0xa3, - 0x24,0xce,0x92,0x28,0xf0,0x7e,0xce,0x9e,0xcd,0x0e,0x83,0xc9,0x64,0x32,0xde,0xeb, - 0xee,0x6d,0x3d,0x7d,0xb2,0xcd,0x05,0x9f,0xca,0x0a,0x4f,0xc3,0x49,0xf3,0xfe,0x75, - 0x18,0x8f,0x93,0x6b,0xef,0xf4,0x65,0xab,0x39,0x59,0xc6,0xa3,0x3c,0x4c,0xe2,0x66, - 0xeb,0xf3,0x95,0x9f,0x8a,0x8f,0x87,0xfc,0xad,0xfd,0xe3,0x61,0x63,0xdb,0x5f,0x84, - 0xdb,0x59,0xee,0xe7,0xcb,0xac,0xd1,0x7e,0x73,0xf8,0xe9,0xa2,0xfd,0xf6,0xb0,0x1f, - 0x3c,0x6e,0x9f,0xb5,0xff,0xd4,0x3e,0x3d,0xfc,0x08,0xd5,0x0f,0x3f,0xe3,0xe7,0x60, - 0xd0,0x88,0xc2,0xab,0xa0,0xd1,0x1e,0x87,0x69,0xbe,0x1a,0xdc,0xef,0xb5,0xaf,0x06, - 0xf1,0x32,0x8a,0xda,0xd3,0x20,0x1f,0x7c,0xdf,0x0e,0xe3,0x49,0x14,0x4e,0x67,0xf9, - 0xe0,0xdd,0x72,0x3e,0x0c,0xd2,0xf6,0x2c,0x89,0xc6,0x83,0xf7,0xc3,0x9f,0x83,0x51, - 0xde,0xce,0xfc,0xd5,0x40,0xf7,0x20,0x6f,0x5f,0xb6,0x83,0xd6,0xe7,0xe0,0xdb,0x6f, - 0x9b,0x81,0x97,0x07,0x37,0xf9,0x71,0x12,0xe7,0x41,0x9c,0x1f,0xe6,0xad,0xdb,0xf6, - 0x70,0x99,0x59,0x45,0x87,0xed,0x45,0xeb,0xb3,0x7a,0x12,0x13,0xe8,0xfc,0xd0,0x1b, - 0x87,0x99,0x3f,0x8c,0x82,0xf1,0xe1,0xfd,0xde,0xad,0xfd,0xd4,0x3d,0x58,0x78,0xf9, - 0x2c,0x88,0x9b,0x93,0xf6,0xa4,0x75,0x90,0x06,0xf9,0x32,0x8d,0xc5,0xe2,0xb6,0xbd, - 0x48,0xa2,0xc8,0x40,0xcc,0xda,0xf3,0xf6,0xa8,0x9d,0x30,0x16,0xf2,0xf6,0xa4,0x3d, - 0x3d,0xec,0x1d,0xe8,0x16,0x3e,0x40,0x0b,0xd3,0x6f,0xbf,0xbd,0x3f,0x81,0xbe,0x4d, - 0x0e,0x7b,0xed,0x51,0x14,0xf8,0xe9,0x79,0x38,0x0f,0x92,0x65,0xde,0xcc,0x5b,0xed, - 0x66,0xe6,0x8d,0xfc,0x28,0x7a,0x96,0x35,0x5b,0x83,0xef,0x9b,0x59,0xab,0x25,0x5b, - 0x54,0xd0,0xc7,0xad,0xcf,0xa3,0xe6,0xb8,0x8d,0x58,0x81,0xb1,0xe8,0xd7,0x01,0xbe, - 0x26,0x54,0x05,0xad,0x5b,0x59,0xe7,0x87,0xf6,0x0f,0xad,0xd6,0xad,0x6e,0xf9,0x07, - 0x68,0x79,0x72,0xd8,0x3d,0x28,0xb4,0x78,0x00,0xbd,0x69,0xe6,0x87,0x40,0x12,0xea, - 0xdd,0x87,0xf6,0x1c,0xea,0x25,0xdf,0x7e,0x9b,0x78,0x93,0x30,0xcd,0xf2,0xc3,0x43, - 0x40,0xc4,0x33,0xa8,0x3e,0x80,0xce,0xcb,0x61,0xc3,0x74,0x25,0x8b,0x81,0x35,0xe5, - 0xd3,0x32,0xe4,0xdb,0x36,0x00,0x35,0x65,0xe2,0xd6,0xe7,0xf9,0x61,0x7c,0x30,0xf9, - 0xf3,0x9f,0x01,0xd4,0x6d,0x3b,0x4e,0xae,0x07,0x1f,0x6e,0xa1,0x0c,0x91,0x85,0x29, - 0x36,0x82,0x91,0x7c,0xfb,0xed,0x1b,0x6f,0xb1,0xcc,0x66,0xf0,0x70,0x70,0xf6,0x0c, - 0x1e,0x47,0xcd,0xb3,0xd6,0xe0,0x4f,0xcf,0xfe,0xe4,0x41,0x2d,0xe8,0xc7,0x9f,0x0e, - 0x4f,0x3d,0x44,0x7a,0xf3,0xc7,0xf6,0xdb,0xf6,0x0b,0x00,0x76,0xed,0xe7,0xa3,0xd9, - 0x59,0x01,0xd2,0xbc,0xf5,0xf9,0xd4,0x63,0xf0,0xd0,0xef,0x3f,0x79,0xd0,0x9b,0xe6, - 0xdb,0xc3,0xb7,0x7e,0x3e,0xf3,0xe6,0x21,0x7c,0x6e,0xbf,0x6d,0x51,0xd5,0x30,0x7f, - 0x99,0xa4,0x2f,0x82,0xab,0x70,0x14,0x98,0xca,0x30,0x7f,0xc9,0x61,0xf2,0xe7,0x3f, - 0x7f,0xbe,0x55,0x13,0x1d,0x07,0xd7,0xe2,0x34,0x4d,0xe6,0x61,0x16,0x98,0xe9,0x58, - 0xb5,0x63,0x9e,0xe8,0x99,0xe9,0x52,0x3f,0xd8,0x31,0x13,0x93,0xb5,0x3e,0x67,0x30, - 0xdd,0xcd,0xc4,0x1b,0x2e,0xc3,0x68,0xfc,0xed,0xb7,0x19,0xff,0x38,0x3c,0x94,0x6f, - 0x5a,0x80,0xfe,0x99,0x87,0xe8,0x6c,0xb6,0xda,0x2b,0x9c,0xf1,0xdb,0xd6,0x81,0x35, - 0x1b,0x16,0x8e,0x55,0xb1,0x83,0xb8,0x79,0x92,0xa6,0x49,0xda,0x6c,0xe4,0x5c,0xa8, - 0x81,0x03,0x49,0x3c,0xf9,0xf4,0xe7,0x3f,0x3f,0x0e,0x76,0x01,0xca,0xed,0xad,0x21, - 0xbb,0xef,0x9b,0x4b,0x24,0x49,0x39,0x94,0x49,0x00,0xe8,0xa2,0x37,0x05,0xea,0x4a, - 0x5b,0x9f,0x71,0x55,0xa7,0x5e,0x72,0xd9,0xca,0x67,0x69,0x72,0x2d,0xb8,0xa1,0x54, - 0xe2,0x51,0x53,0x3d,0x51,0x07,0xae,0xac,0x67,0x29,0xfd,0x81,0x49,0x49,0x81,0x61, - 0x60,0x37,0x6f,0x2d,0x9a,0x7b,0x81,0xe3,0x07,0x88,0xf0,0xdf,0x33,0x58,0xe7,0x8b, - 0x09,0xcf,0xd1,0x61,0x76,0xf0,0xc6,0x9b,0x24,0xe9,0x89,0x0f,0xdd,0xd0,0x8d,0x4f, - 0x80,0x3e,0xa1,0x24,0x76,0xfc,0xb6,0xd5,0x6c,0x69,0x7e,0x23,0x19,0x57,0xec,0xcf, - 0x83,0xc3,0xad,0xab,0x30,0xb8,0x5e,0x24,0x69,0xbe,0x25,0x46,0x72,0x4d,0x6f,0x5d, - 0x87,0xe3,0x7c,0x76,0x38,0xa6,0x09,0xec,0xd0,0x03,0x70,0x8a,0x30,0x0f,0xfd,0xa8, - 0x93,0xc1,0x5a,0x0a,0x0e,0x7b,0xc8,0xe5,0xf2,0x30,0x8f,0x82,0xa7,0xa7,0x7e,0x9e, - 0x07,0x29,0xf0,0x11,0x18,0x5a,0x47,0xbc,0x0d,0x47,0x62,0xee,0x2f,0x16,0x61,0x3c, - 0x7d,0xb2,0xcd,0x05,0xee,0x3d,0xb9,0xdf,0xe9,0x88,0xef,0x4f,0xde,0x9d,0x7c,0x38, - 0x3a,0x3f,0x79,0x21,0x86,0x2b,0x01,0x8b,0x60,0x7e,0xed,0xa7,0xc1,0x76,0x9e,0x24, - 0x11,0xb0,0xcf,0x30,0xde,0xa6,0x99,0xfb,0xc9,0x5f,0x8e,0xc3,0xe4,0xa7,0x30,0xfe, - 0x69,0xe1,0x4f,0x03,0x6f,0x01,0x25,0x81,0x3c,0xee,0x09,0xfc,0x1f,0x16,0xcd,0xb6, - 0x17,0xa6,0xb5,0x0e,0x15,0xee,0x00,0xaa,0x82,0x38,0x43,0xd4,0x34,0x83,0x71,0x98, - 0x27,0xa9,0xe8,0x3f,0xee,0x06,0x7b,0x7b,0xfd,0xdd,0xbd,0xfd,0x96,0xc7,0x75,0x4f, - 0xe0,0x83,0x80,0x79,0x11,0xb2,0x04,0xfc,0x4c,0x83,0xb6,0x48,0x83,0x74,0x19,0xd3, - 0x7b,0x6a,0x1d,0xf8,0x1f,0x3e,0xc4,0x42,0xb2,0x6b,0xea,0x44,0x86,0xbd,0xa0,0xcf, - 0x9e,0xe8,0x74,0x90,0xb7,0xe7,0x2b,0x1c,0xd4,0xf6,0x77,0xc2,0x1e,0xf9,0x11,0xf6, - 0x45,0xfc,0xf5,0x2f,0xff,0xa6,0x46,0x2f,0x9b,0xf2,0xc4,0x19,0x20,0x59,0x8c,0xd2, - 0xc0,0x9f,0x8b,0x30,0xce,0xf2,0x74,0x39,0x07,0x14,0x8b,0x05,0x60,0x11,0x6a,0x0b, - 0x3f,0xc3,0x26,0xb1,0x97,0x8b,0x64,0xb1,0x5c,0x88,0x26,0xfd,0xf1,0x46,0x59,0x26, - 0x42,0xfa,0x24,0xb2,0x64,0x99,0x8e,0x02,0x91,0x4c,0xf0,0x29,0x0b,0xc4,0x95,0x1f, - 0x2d,0x83,0xac,0xe5,0x89,0xef,0xb6,0xef,0x0d,0xd2,0x24,0xc9,0xc5,0x67,0xa8,0xde, - 0xe9,0x50,0x13,0x03,0xf1,0xcd,0x64,0x37,0x98,0x04,0xfb,0x07,0xe6,0x5d,0xa7,0x0f, - 0x6f,0x83,0x71,0xf0,0x70,0x3c,0xe4,0xb7,0x61,0x7c,0x09,0x6f,0x7a,0xbb,0xf8,0x7f, - 0x7e,0x33,0x5f,0xe6,0xc1,0x18,0xde,0xed,0x0f,0xf7,0xf7,0xf6,0x7c,0x7e,0x37,0x81, - 0x59,0xc9,0xe1,0x9d,0xbf,0xff,0x78,0xf2,0xb8,0xcb,0xef,0xd2,0x65,0x14,0xc0,0xab, - 0xf1,0xe3,0x71,0x6f,0x24,0x5f,0x45,0x54,0x31,0x78,0x04,0x08,0x0f,0xf8,0x4d,0x82, - 0xd0,0xfb,0xfb,0x0f,0xfd,0xdd,0x1d,0x7e,0x31,0xf4,0xb1,0xc8,0x70,0x77,0x67,0xd8, - 0x1f,0x4b,0xd8,0x61,0x10,0xe1,0xbb,0xc9,0x70,0xf2,0x30,0x98,0xc8,0x3e,0x24,0x71, - 0x32,0x10,0xcb,0x90,0x7e,0x64,0x0b,0x7f,0x04,0x13,0x74,0xf6,0xf2,0x2d,0x3c,0x74, - 0x3e,0x04,0xd3,0x65,0xe4,0xc3,0xec,0xbc,0x0d,0xe2,0x28,0x69,0x8b,0x63,0x9a,0x1f, - 0x3f,0x6b,0x0b,0x5d,0xf6,0xe0,0xde,0xed,0xbd,0x7b,0xdf,0x89,0xcf,0x62,0x98,0xdc, - 0x74,0xb2,0xf0,0x57,0x98,0x81,0x01,0xfc,0x4e,0x61,0x52,0x3b,0xf0,0xea,0x40,0xc0, - 0xe7,0x61,0x32,0x5e,0x11,0xb2,0xe6,0x7e,0x3a,0x0d,0xe3,0x81,0xa0,0x21,0x0c,0xfd, - 0xd1,0xe5,0x34,0x4d,0x96,0x31,0x74,0x08,0xd8,0x4e,0x53,0x62,0xad,0x85,0xdf,0x46, - 0x49,0x94,0xa4,0xea,0x35,0xa0,0x8d,0x5e,0x4e,0x12,0xc4,0x4b,0xaf,0xbf,0xb8,0xd9, - 0xee,0x79,0xbb,0x7b,0xe2,0x35,0x2c,0x1a,0xe8,0x1b,0xf4,0x3c,0xf3,0xe3,0xac,0x93, - 0x05,0x69,0x38,0x69,0x8b,0x6c,0x95,0xe5,0xc1,0xbc,0xb3,0x0c,0xe1,0xa7,0x7e,0x4d, - 0xbd,0xf4,0x90,0xac,0x64,0x3f,0x6e,0x78,0x75,0x21,0xb8,0x47,0xdd,0xc5,0xcd,0x81, - 0xdd,0x39,0xe1,0x2f,0xf3,0x04,0xdf,0x2c,0xfc,0xf1,0x98,0xc6,0xd3,0xdf,0xe5,0x22, - 0x20,0x3f,0x17,0x11,0x48,0x67,0x31,0x89,0x02,0x7a,0x81,0x7f,0x3b,0x20,0xe1,0x03, - 0x5a,0xf6,0x03,0xec,0xf7,0x72,0x1e,0xe3,0x97,0xa9,0xbf,0x00,0xe0,0x54,0x0f,0x9b, - 0x46,0x7c,0x01,0x92,0x70,0x08,0x30,0xc1,0xf3,0x30,0x5a,0xa9,0xd1,0xe1,0x97,0x16, - 0xa2,0x09,0xa4,0xf3,0xfc,0x1c,0x16,0x15,0x14,0x73,0x86,0x4f,0x34,0xc2,0x25,0x66, - 0x40,0x19,0x0a,0x0a,0xe0,0x1a,0x48,0xa2,0xd7,0x83,0x16,0xdc,0xf2,0x44,0x3f,0x5c, - 0x9e,0x66,0x28,0xc5,0x1a,0xd8,0x4f,0x40,0xf6,0x35,0xd4,0xa0,0x29,0x81,0x55,0xf4, - 0xd7,0x7f,0xfb,0x0b,0xfc,0x23,0x50,0xa1,0x82,0x32,0xf2,0x09,0x68,0x5b,0xbe,0xf8, - 0x5c,0x18,0xad,0xf0,0x41,0x61,0x89,0x3b,0x21,0x20,0x37,0x83,0x81,0x06,0x88,0xfc, - 0x03,0xf1,0xf3,0x32,0xcb,0xc3,0xc9,0xaa,0x23,0x39,0xd8,0x40,0x50,0x93,0x9d,0x61, - 0x90,0x5f,0x07,0x41,0x7c,0x20,0xd1,0xd0,0x5f,0x10,0x21,0x78,0xc3,0xd4,0x8f,0xc7, - 0x1b,0x42,0xa6,0x9a,0x8f,0x65,0x45,0x20,0x76,0xa8,0x26,0xa7,0xec,0x11,0xbe,0x9c, - 0x05,0xa4,0x3e,0xf1,0x43,0x99,0x94,0x22,0x42,0x99,0xa4,0xc3,0xd4,0x1f,0x87,0x20, - 0x4d,0x45,0x4f,0x42,0x23,0xf6,0x58,0xc0,0x23,0xce,0x14,0xbf,0xb8,0x96,0x90,0xf7, - 0xbb,0x5d,0x2a,0x7d,0x19,0x8e,0x2e,0x19,0x89,0xb5,0x93,0x67,0x03,0x42,0x6a,0x12, - 0xc4,0x63,0xd2,0x0e,0x22,0x83,0x08,0xa8,0xeb,0x75,0x1f,0x07,0xf3,0x83,0xda,0x89, - 0x1d,0x45,0x80,0xc7,0x8d,0x91,0x4e,0xa8,0x79,0xc4,0x83,0x81,0xba,0xb3,0x70,0x41, - 0x54,0xcd,0xa3,0xa5,0x61,0x02,0xf3,0x8a,0xc2,0xb1,0x6c,0x07,0x99,0x47,0x19,0x19, - 0xfd,0x6a,0xc4,0x11,0x87,0x68,0x39,0xd4,0xbf,0x07,0xf0,0x78,0x58,0x9b,0x61,0xa0, - 0x4c,0x92,0xbc,0x82,0x6f,0xb9,0xaf,0x48,0xe7,0x6b,0x68,0x3c,0xb9,0x3c,0xa6,0x01, - 0xa9,0xfe,0x3a,0xe5,0x40,0x96,0x17,0x40,0xd3,0x1b,0x5a,0xdc,0x69,0x08,0x2b,0x78, - 0xf5,0x3c,0x8f,0x09,0x19,0xcc,0x2c,0xc2,0x18,0x04,0x4e,0x98,0xbb,0xfd,0xa3,0x91, - 0x8f,0x96,0x69,0x86,0x50,0x16,0x49,0x48,0x48,0x5d,0x83,0x3f,0xea,0x7d,0x15,0xfa, - 0x2a,0x99,0x18,0x97,0x76,0xfa,0x28,0xf9,0x9a,0xc1,0xe8,0x3e,0x62,0x54,0xf2,0x06, - 0xab,0xe3,0x03,0xa5,0x9f,0xc3,0xe8,0x13,0x24,0x1d,0x30,0x1c,0x80,0x74,0x76,0xf6, - 0x4c,0x77,0xc7,0xc1,0xc4,0x5f,0x46,0x39,0x61,0x6a,0x3a,0x4b,0xb2,0x7c,0x83,0xf1, - 0xf6,0xbe,0x70,0xbc,0xf5,0xf4,0x52,0x39,0x60,0x49,0x31,0xd5,0x13,0xea,0x0e,0xb9, - 0x2f,0x87,0xac,0x7a,0x3e,0x98,0x25,0x57,0x44,0xf5,0x55,0x73,0xcd,0x4b,0xb8,0xe2, - 0x95,0xc3,0xbe,0x50,0x3b,0x19,0x82,0xd2,0xba,0x0d,0xbf,0xa6,0xd3,0x28,0xc8,0x2c, - 0x4e,0xe6,0xa9,0x8f,0x5f,0xb0,0xac,0x98,0xd0,0x91,0x1b,0xfb,0x73,0x52,0x27,0xbe, - 0x7c,0x49,0xea,0xaa,0x61,0xbc,0x58,0xe6,0x86,0x6f,0xf5,0x76,0x08,0xb6,0x3f,0xc2, - 0x4a,0x9d,0xca,0x81,0xe9,0xaa,0x8e,0xc0,0xb0,0xe7,0x11,0xd4,0x7d,0x25,0xba,0xf6, - 0xf6,0xf1,0x05,0xaa,0xac,0x1d,0xea,0xd3,0x40,0xa4,0xc8,0xb9,0x98,0xc5,0x11,0x32, - 0x3e,0xa6,0xfe,0xa2,0x8a,0x3a,0x8a,0xc4,0xb0,0xf9,0x10,0x1f,0x4a,0x2a,0xf8,0xd2, - 0xa5,0xb2,0x86,0x6e,0x5c,0x3e,0xd3,0x93,0x24,0xc2,0x03,0x78,0xe3,0x0f,0x83,0xa8, - 0x0a,0x0d,0x0e,0xa7,0xde,0x93,0x9c,0x9a,0xeb,0xd0,0x80,0x25,0x8a,0xfa,0x7d,0x5b, - 0x56,0xf4,0x6a,0x7a,0x52,0x4d,0xf0,0x72,0xa8,0x8b,0x24,0x0b,0x59,0xb8,0xa7,0x41, - 0xe4,0xe7,0x60,0xd3,0x5b,0xe8,0x0a,0xe3,0x28,0x8c,0x41,0xdc,0x45,0xc9,0xe8,0xf2, - 0x40,0x63,0xa5,0x5b,0x81,0x61,0x3d,0xca,0xae,0xd2,0x1b,0x06,0x22,0x4e,0xe2,0xc0, - 0x1a,0xac,0xf0,0xc6,0x49,0xfe,0x43,0x5b,0xd8,0x93,0x47,0xaf,0x68,0x44,0xa6,0x1f, - 0xfe,0x10,0x50,0x0e,0xeb,0x0b,0xc5,0xcc,0x24,0x97,0x62,0x0d,0x6d,0x58,0xfe,0xa5, - 0xa8,0xad,0xeb,0x0c,0xbd,0x7b,0xd7,0xf2,0x2d,0x8c,0x7e,0xaf,0xfb,0x0f,0x00,0x14, - 0xe4,0xb5,0x6a,0x15,0xdb,0x02,0x66,0xd4,0xeb,0x67,0x56,0x97,0xb9,0x8f,0x0a,0xef, - 0x6a,0xb4,0x9d,0xe0,0x0a,0x68,0x26,0x93,0x03,0x74,0xc9,0xd1,0x03,0x7b,0xc1,0x54, - 0x28,0x77,0x47,0xf2,0xf3,0x62,0x0d,0x46,0x83,0x1a,0xb0,0x16,0xe4,0x54,0xc8,0xcb, - 0xe6,0x7e,0x14,0x61,0xb1,0xbb,0x01,0x9a,0xb2,0xd5,0x20,0x2d,0xce,0x32,0x07,0x3d, - 0x4a,0x2c,0x22,0xd0,0xf3,0x2d,0x8e,0x82,0xcf,0x7a,0x55,0x55,0x91,0xc6,0x3a,0x89, - 0xfa,0x15,0x0c,0xf7,0xf6,0xde,0x37,0xd4,0x05,0x8b,0x0b,0x49,0x62,0x2b,0x49,0x84, - 0x3c,0x59,0x8e,0x66,0x1d,0x5f,0x6a,0xa2,0x06,0xf5,0xfe,0xb4,0x96,0x7e,0x36,0x5e, - 0xf6,0xfb,0x75,0xd4,0x23,0x0d,0x9d,0xd6,0xc1,0xd7,0x49,0x13,0xa3,0x61,0x43,0x2d, - 0x5c,0x70,0xd5,0x24,0x74,0x8f,0xc7,0xe1,0x65,0xc4,0x0c,0xea,0x85,0x85,0x2c,0x46, - 0xc2,0xe7,0x1c,0xc7,0x6d,0x8b,0xd1,0xbd,0x3d,0x55,0x40,0x6a,0xd9,0x5f,0xa0,0xcf, - 0x39,0x84,0x01,0x98,0xbf,0x0a,0xa0,0xeb,0x31,0xf4,0xc6,0x26,0x0d,0x7a,0xf1,0xb9, - 0x64,0x26,0x30,0x06,0xfb,0xdd,0xbb,0xf4,0xad,0xaf,0x50,0xdf,0x34,0xfa,0x7a,0x24, - 0x5e,0x1f,0x49,0xde,0x09,0x98,0x29,0x8b,0xad,0x1a,0x53,0xc5,0x95,0x5c,0xf0,0xd2, - 0x43,0x33,0xa1,0x64,0x32,0xb8,0x7a,0x3c,0x14,0xfb,0xe1,0xbf,0x40,0x2b,0xbe,0x4a, - 0x2d,0xe1,0xb9,0x96,0x75,0xc3,0x32,0xe1,0x59,0x29,0xaf,0x93,0xea,0x65,0x81,0x6a, - 0x17,0x18,0xf5,0x79,0x76,0x4c,0xb8,0x52,0xe2,0x62,0x5f,0x21,0x82,0xbf,0x7e,0x9f, - 0x86,0x8e,0xb9,0x32,0x85,0xe7,0x03,0xfa,0x6f,0x07,0x16,0x09,0xbc,0xcb,0x83,0x0e, - 0xe3,0x31,0x43,0x1e,0xb0,0x08,0xfc,0xbc,0xb9,0xd3,0x46,0x19,0x0d,0x16,0x66,0xb3, - 0xdb,0x16,0xbd,0x49,0xda,0x6a,0x15,0x70,0xcc,0xa0,0x37,0x11,0xcb,0x65,0x52,0xaa, - 0x9b,0xc4,0xfa,0x95,0xbb,0xb7,0x5e,0x60,0x7f,0x91,0x6d,0x60,0xec,0x73,0x4d,0x78, - 0x60,0xa0,0x89,0x5d,0xb9,0x76,0xef,0x99,0xc1,0xc1,0x14,0xc7,0x05,0xb1,0xdd,0xad, - 0x16,0xdb,0x65,0x3b,0xc1,0xe0,0x48,0xb2,0xf4,0x75,0xcb,0xdd,0x14,0xb4,0x9b,0x2c, - 0x9a,0x70,0x60,0x5b,0x2d,0xb2,0x0f,0x44,0xd6,0x5f,0xa4,0xe9,0xdc,0x61,0xd6,0x58, - 0xa4,0xaa,0x5a,0xf8,0x34,0x0b,0xc7,0xe3,0x20,0xbe,0xb0,0x5b,0xd2,0xac,0x58,0x77, - 0x63,0xb8,0xcc,0xf3,0x24,0xde,0x48,0x33,0x53,0xe4,0xef,0x18,0xbd,0xfc,0x64,0xa9, - 0x14,0x82,0xd4,0x10,0xfd,0xf9,0xf7,0x9e,0xf1,0x6a,0x6b,0xce,0x62,0x89,0x30,0x07, - 0x39,0x74,0x25,0x93,0x04,0x69,0xb3,0xc5,0x21,0x98,0xfc,0xaf,0x02,0xff,0x2e,0xb3, - 0x7f,0xe8,0x03,0x73,0x0f,0x11,0x51,0xce,0x62,0xc1,0xda,0xef,0xd0,0x91,0xe7,0x12, - 0xd3,0x4e,0xb5,0xb5,0x7e,0x3d,0x03,0x68,0xc4,0x5f,0x02,0x44,0xfb,0x35,0x08,0x6a, - 0x82,0x42,0x4c,0xf6,0x0b,0x59,0xe2,0xbe,0xec,0x01,0xd5,0xdd,0x9c,0x76,0x36,0x72, - 0x88,0x3c,0xb2,0x61,0xd7,0xea,0xb8,0x35,0xb4,0x06,0x74,0x14,0x54,0x98,0x25,0xe8, - 0xa9,0x88,0x93,0xe1,0x3a,0x7b,0x70,0x43,0xcb,0xfd,0xcb,0x2d,0xc5,0xcd,0xe8,0x46, - 0x0e,0xc1,0x66,0x1f,0xda,0x10,0x56,0xf4,0x88,0xda,0x98,0xb2,0x6f,0xba,0xc4,0x51, - 0xe4,0xa0,0x06,0xb4,0x7f,0xd3,0x19,0xcd,0x42,0x9a,0xc9,0x8a,0xe2,0x3d,0x0b,0x8c, - 0x45,0xd6,0xa2,0x0b,0xff,0x57,0x82,0x4b,0x01,0x8b,0xfc,0x32,0x2c,0x55,0x87,0x4a, - 0x73,0x4d,0xbb,0x4e,0x3d,0x33,0x92,0x46,0xcf,0x97,0x78,0x02,0x70,0x16,0x93,0x65, - 0x7e,0x9e,0x42,0x25,0xd2,0x9b,0xcb,0x8a,0xa4,0xbb,0xd6,0x4b,0x7c,0xa1,0x46,0xdb, - 0x03,0xa0,0x1f,0xfc,0x30,0x72,0x60,0x16,0xed,0x05,0xc2,0x77,0xca,0xd0,0x77,0xb5, - 0xed,0xe0,0x30,0x98,0xfe,0x1d,0xd2,0x16,0xdb,0x79,0x19,0x46,0x75,0xed,0x10,0xc0, - 0x87,0xde,0x9e,0x0d,0x72,0x67,0x9d,0xa3,0x8e,0x21,0xbe,0x82,0xc5,0x2e,0xed,0xb7, - 0x5a,0xa8,0xbb,0x96,0x89,0xf3,0xf8,0x6b,0x2c,0x9c,0x1a,0xa3,0xd5,0xe5,0x67,0x93, - 0x24,0x41,0x77,0x1c,0xba,0xab,0x1c,0x87,0x02,0xbf,0xf8,0x0a,0x97,0x00,0x56,0x3c, - 0xf6,0xd3,0xf1,0xd7,0x89,0xfd,0xf5,0xf0,0xbf,0x6a,0xd0,0x9b,0xa9,0xe5,0x0f,0x6d, - 0xaf,0x8d,0x1a,0xc3,0x26,0x6a,0xb8,0x2e,0x4b,0x8b,0x5e,0x7a,0xf4,0xca,0xca,0x38, - 0x16,0x7b,0x91,0x58,0x3e,0x92,0x7d,0x7b,0x4a,0xf7,0xbf,0xc2,0xb7,0xab,0x11,0x5d, - 0xeb,0x41,0x81,0x42,0x7e,0x2a,0x75,0xdc,0xa2,0x7e,0x52,0xe3,0x48,0xb7,0x28,0x03, - 0xc8,0x14,0x9d,0x3a,0x52,0x7b,0x14,0x0f,0xf0,0x17,0x6e,0xe4,0xd9,0x54,0x02,0x65, - 0x4e,0xe5,0xf7,0xcf,0x95,0xc6,0x80,0x92,0x2d,0xba,0xe0,0x5d,0x2e,0xbc,0xee,0x7f, - 0xae,0x0b,0x6f,0x1d,0xbb,0x36,0xc4,0x00,0x2b,0x58,0x28,0x13,0x43,0xf7,0xfc,0xab, - 0x5d,0x78,0xde,0xe2,0xea,0x3d,0xd4,0x04,0xd4,0x14,0x16,0xfc,0x24,0xbc,0x09,0x40, - 0xcb,0x0e,0x63,0x84,0x8e,0x3c,0xf8,0x57,0x58,0xa1,0x63,0xf4,0x97,0xec,0x95,0xf6, - 0x8d,0xd2,0xe9,0xd0,0x6f,0xf6,0x41,0xd1,0x56,0xff,0x76,0xbd,0xdd,0xbd,0xd6,0xa6, - 0x2b,0xa8,0x24,0xab,0xe5,0x07,0x52,0x64,0x55,0xef,0xd6,0x6a,0x74,0x8b,0x2b,0xbd, - 0xa8,0xeb,0xb1,0xfa,0x45,0xce,0xb2,0x9d,0xc2,0x0a,0x64,0xf6,0xff,0x25,0x8a,0x4b, - 0x4f,0x4e,0xb3,0x5a,0x51,0xbb,0x44,0x3c,0xd6,0x96,0xd7,0xe3,0xdd,0xab,0x6b,0x39, - 0xc6,0x6a,0xc5,0xec,0x2e,0x1d,0xa6,0x12,0x99,0x8c,0x8d,0x6a,0xfe,0xe8,0xda,0x3f, - 0x57,0x67,0xe1,0xf4,0x6f,0xd1,0x67,0xcd,0xf3,0x51,0xed,0x8e,0xa4,0x4e,0xdf,0x65, - 0x8f,0x54,0xd9,0x1e,0xdf,0x40,0xcd,0x51,0xb2,0xa8,0xb2,0x4c,0xbf,0x9a,0x69,0x53, - 0x7f,0xde,0x04,0xd3,0xa0,0x6a,0x33,0xcd,0x18,0x2f,0xf5,0xd3,0xf4,0x43,0xb0,0x7a, - 0x1d,0xb7,0x05,0xff,0x7a,0xef,0xf8,0xa8,0xf7,0x4b,0x32,0xbb,0xc6,0xd9,0x69,0x00, - 0x55,0xba,0xdd,0xac,0x5d,0x48,0xab,0x95,0x7a,0xf9,0xef,0x38,0x58,0x38,0x0c,0x40, - 0x64,0x97,0x61,0x2c,0x88,0xbd,0x98,0x10,0x82,0x46,0x26,0xf7,0xf4,0xf3,0xe4,0x32, - 0x88,0x6d,0xe1,0x5c,0xb5,0x27,0xdf,0x3d,0xee,0x3e,0xef,0x3e,0x2e,0xee,0xc9,0xf7, - 0x9e,0xf7,0x1e,0xab,0x1d,0x78,0xde,0x93,0x3f,0x79,0x71,0xf2,0xf0,0xc5,0x73,0x77, - 0x4f,0xfe,0xd1,0xd1,0xa3,0xfe,0xc3,0xbe,0xbb,0x27,0xbf,0x77,0xb4,0xb7,0xb7,0xbb, - 0xef,0xec,0xc9,0xf7,0x77,0xfb,0xbd,0xde,0x23,0x7b,0x4f,0xfe,0xe5,0xcb,0xbd,0xe3, - 0xfe,0x89,0xb5,0x27,0xbf,0xf7,0xf0,0xf9,0xa3,0x87,0x2f,0xed,0x3d,0xf9,0x97,0x2f, - 0xf7,0x9f,0xef,0x1d,0xb9,0x7b,0xf2,0xbd,0x9d,0x5e,0xaf,0x47,0x3a,0x2f,0x60,0xe2, - 0x1c,0x06,0x2c,0xd1,0x00,0x23,0x7e,0x83,0xd3,0x21,0x37,0x38,0x44,0x96,0xfb,0x73, - 0x58,0x64,0x18,0x19,0xf7,0x69,0xec,0xe7,0x7e,0x07,0x90,0x33,0x0f,0x0e,0x29,0x9c, - 0xec,0x42,0xe0,0x06,0x2b,0xa2,0x2c,0x0d,0xc7,0x81,0x0e,0x71,0x38,0x7e,0xff,0xee, - 0xec,0xfd,0x9b,0x93,0x0e,0xc6,0x9d,0x10,0x2d,0x85,0xb8,0xcd,0x94,0x89,0x26,0x55, - 0xfd,0x89,0xd8,0xab,0x37,0x6b,0x79,0xd4,0xac,0xc6,0x73,0x7e,0x9d,0x50,0xa4,0x4a, - 0x86,0x31,0x10,0x21,0x08,0xb3,0xe4,0x3a,0x46,0x68,0x71,0x00,0x40,0xa8,0x39,0x19, - 0x13,0x21,0x30,0xaa,0x43,0x70,0x78,0x07,0x7b,0x4c,0xd9,0xe0,0xc2,0xbe,0xe4,0x3e, - 0x58,0x85,0xd0,0xe5,0x95,0x18,0xfb,0xe9,0x25,0xd0,0x90,0xf0,0xb9,0x2e,0x85,0x5e, - 0xe0,0x86,0x7c,0x07,0xcd,0xb6,0xd1,0x0c,0x54,0x5f,0xe0,0x45,0x7e,0x26,0xb6,0x10, - 0x8a,0x1c,0xeb,0x38,0x01,0xe8,0x71,0x92,0xcf,0x60,0x45,0x6e,0x79,0xe2,0xd8,0x8f, - 0xaf,0xfc,0x8c,0x57,0x6d,0x06,0xcb,0x2d,0xc2,0x08,0x90,0x49,0x1a,0x04,0x03,0x84, - 0x26,0x03,0x3f,0x7e,0xce,0x08,0x54,0xa6,0xc3,0x36,0xd4,0x68,0xa1,0x60,0x36,0x13, - 0xb0,0x86,0x03,0xc0,0xcf,0x0a,0x1a,0x87,0x39,0xa5,0x68,0x8e,0x1a,0x54,0x7e,0x2e, - 0x90,0xcd,0xc9,0xa3,0x93,0xfe,0x8b,0x7d,0x77,0xd2,0x5e,0xbe,0x7c,0x79,0xfc,0xf2, - 0x48,0x4e,0x1a,0xc7,0xed,0x08,0xdc,0xdc,0x22,0xd5,0x11,0x23,0x49,0xe6,0x81,0x1f, - 0x43,0xe7,0xa1,0xfd,0x0c,0xc6,0x19,0x70,0xd4,0x0b,0x8d,0xfb,0xf5,0x19,0xfd,0xe6, - 0x4a,0x07,0x56,0xc8,0x09,0x8e,0x85,0xaa,0x23,0xfe,0xce,0x40,0xeb,0x95,0xae,0x25, - 0xa8,0xef,0xe7,0x56,0x1d,0x58,0x4d,0x38,0x4d,0x6f,0xc3,0x51,0x9a,0x2c,0x66,0x20, - 0x92,0x44,0x76,0x1d,0xe6,0x80,0x49,0xac,0x07,0x48,0x83,0x67,0x40,0x3b,0x8c,0xef, - 0x1b,0xec,0x11,0xb2,0xe6,0xb6,0xf8,0x86,0x9b,0x50,0x0f,0x00,0x9c,0x0c,0xc6,0x0a, - 0xd1,0xc6,0x6d,0x3c,0xc7,0xdd,0xb3,0x2f,0x51,0x48,0x7b,0xbb,0xbf,0x4d,0x23,0xd5, - 0x3c,0xbe,0xce,0xd3,0xd9,0xb5,0xf7,0x4e,0xbf,0x7c,0x5f,0x01,0x70,0xf6,0x36,0x9b, - 0x4a,0xdd,0x8f,0x05,0x4d,0x31,0x10,0xe3,0x1b,0x1e,0xfa,0x3b,0xc0,0xe0,0x20,0x98, - 0x2f,0xf2,0x15,0x70,0x4a,0xae,0xc6,0x8f,0xd5,0x9a,0xc0,0x04,0x9a,0x28,0x6e,0x6b, - 0xab,0x46,0xe1,0x23,0xac,0xc8,0xe2,0x57,0x60,0x05,0xf4,0x59,0x2d,0xf7,0x59,0x9a, - 0xcc,0x69,0xce,0x1c,0x4a,0x41,0xa7,0x32,0xd0,0xd1,0x32,0x06,0x3a,0x1c,0xcd,0x90, - 0x92,0x0f,0x0c,0x0d,0x25,0x71,0x04,0x0b,0x2b,0x9c,0x67,0x4c,0x1b,0x21,0xad,0xaa, - 0x91,0x1f,0x43,0xbf,0x44,0x94,0xc4,0x53,0x60,0x9d,0x57,0x68,0x28,0xc2,0x68,0xd3, - 0x36,0xd1,0xc5,0x18,0x68,0x85,0xe3,0x9b,0xb6,0x28,0xfa,0x0d,0x7f,0xcd,0x0d,0x05, - 0x25,0xf1,0x96,0xa0,0x28,0x13,0x9f,0x96,0xfa,0x32,0xf6,0xe3,0xec,0x1a,0x56,0xf7, - 0x58,0x60,0x44,0xa0,0xb8,0x4e,0x96,0xb0,0xae,0x13,0x0c,0xe3,0xba,0x0e,0x61,0x71, - 0x65,0xb3,0xe4,0x5a,0x2f,0x21,0xc2,0xc1,0x64,0x82,0x42,0x42,0xe8,0x8d,0x92,0xb6, - 0x28,0x7d,0xb2,0x28,0xcb,0x31,0x09,0x10,0x17,0xc5,0xc2,0xdf,0x8c,0xfc,0x05,0xf4, - 0x33,0x78,0xc5,0x91,0x2f,0x57,0x61,0x16,0x0e,0xc3,0x88,0x6a,0xb0,0x5e,0x26,0x11, - 0xf8,0x21,0xb9,0x06,0x1c,0xe0,0xc6,0xcc,0x30,0x80,0xb1,0x06,0x38,0xae,0x15,0x31, - 0x42,0x8a,0x12,0x6b,0x5a,0x31,0x68,0xd7,0xc0,0x41,0x22,0x1f,0xc8,0x0e,0x74,0x58, - 0xc4,0x0b,0x30,0x24,0x10,0x7e,0x50,0xc3,0x1f,0x72,0x70,0x97,0xe9,0x20,0xed,0xc5, - 0xd1,0x16,0x32,0x09,0x4b,0xd2,0x6e,0xe0,0x97,0xd1,0xef,0xdb,0x42,0x47,0xcb,0x90, - 0x4e,0x86,0x3d,0x18,0x08,0xe5,0x77,0xb2,0x64,0xbf,0x1d,0x71,0xd4,0xc5,0xad,0x35, - 0x25,0x62,0x31,0xd6,0x48,0xdc,0x0f,0xe7,0x18,0x08,0xe8,0xc7,0xb9,0x45,0x0f,0x33, - 0x28,0x10,0x00,0x27,0x41,0x17,0x18,0x72,0x63,0x7f,0x2a,0x66,0x3e,0xfa,0xd8,0x16, - 0x3e,0xbc,0xc5,0x20,0x42,0xb2,0x62,0x10,0xd1,0xf0,0x99,0xec,0x79,0x18,0xe2,0x14, - 0x64,0xd2,0x28,0x42,0xde,0x43,0xb4,0x40,0x01,0x77,0x22,0xf5,0xf1,0x2f,0x3c,0x00, - 0x65,0xe0,0x58,0x0d,0x17,0xf2,0x0a,0xbb,0x5a,0x1a,0x65,0x36,0x7e,0xff,0x1b,0x48, - 0x8d,0xd0,0x17,0x4d,0x77,0x10,0xb0,0x10,0x5b,0xc4,0x1b,0xd4,0xce,0x47,0x15,0x0a, - 0xe0,0xeb,0x55,0x5a,0xb5,0x60,0xe0,0x43,0x71,0xb3,0x61,0xe8,0x67,0x61,0xa6,0xf0, - 0x73,0xcb,0x2c,0xf5,0x14,0xa9,0x12,0x5e,0x22,0x6d,0xb2,0x96,0xcb,0x42,0x8a,0x79, - 0x04,0x90,0xe5,0x30,0xb9,0x01,0xd6,0x8e,0xe1,0x84,0x38,0x76,0x90,0x1b,0xf4,0xb7, - 0x2d,0x65,0x4a,0xc8,0x0b,0x03,0x31,0x11,0xa1,0x39,0x86,0xc3,0x86,0x99,0x5b,0x80, - 0x64,0x0d,0xe4,0x3e,0xce,0x24,0x44,0x64,0xee,0xec,0x77,0x05,0xf2,0x23,0xe0,0xf6, - 0x01,0x28,0xd4,0xf0,0x0e,0xaa,0xfa,0x6c,0x8b,0x88,0x9d,0xbd,0x7d,0xfc,0x38,0x22, - 0xe9,0x83,0xb0,0xae,0x81,0xa1,0x06,0x4a,0x2d,0x85,0xb9,0xcd,0x67,0x50,0x38,0xcb, - 0x96,0x73,0xa4,0x3b,0x58,0x87,0xa8,0xc4,0xb6,0x81,0xb9,0x21,0x9c,0x39,0xf0,0x60, - 0x60,0xc6,0x40,0x97,0x82,0x42,0x38,0x61,0x09,0x82,0x1c,0x25,0xbc,0x57,0xe0,0xf5, - 0xa1,0x83,0xd6,0x29,0x6d,0xaa,0x6a,0xd6,0xd7,0x97,0xd6,0x38,0xc7,0xa3,0xb9,0x7b, - 0x32,0x42,0x38,0x64,0x6b,0x96,0x9f,0xb5,0x2f,0x65,0xc7,0xb8,0x75,0xe4,0x66,0xb8, - 0xf1,0xa3,0x91,0xad,0xa5,0x78,0x2f,0x13,0x67,0xb7,0xa4,0x51,0x93,0x05,0xe6,0xb6, - 0x56,0xec,0xa2,0x15,0x48,0x61,0xf7,0xce,0xc4,0x62,0x54,0x7e,0x36,0xe0,0x54,0x0c, - 0x84,0x59,0x7c,0xd6,0x2b,0x8b,0x37,0x6b,0xae,0x0c,0x6f,0x71,0x15,0x49,0x16,0x51, - 0x45,0x4a,0x42,0x94,0x62,0x32,0x78,0x07,0xbe,0xa7,0x7d,0x49,0x14,0xf3,0x67,0x47, - 0x57,0x74,0x0b,0xfd,0x96,0xc1,0x74,0x56,0x63,0xf5,0xd2,0xa0,0xb8,0x26,0x6a,0x4d, - 0x35,0xd7,0x8f,0x8f,0x62,0xcd,0xc6,0x49,0xd5,0x16,0x15,0xf7,0x13,0x3f,0xeb,0x1d, - 0xaf,0xd2,0xa4,0xb2,0x74,0xce,0x82,0x68,0x62,0xeb,0xfd,0xb8,0xe2,0x8a,0xe6,0xd9, - 0xda,0x0d,0xad,0xde,0x24,0xc5,0x7f,0xf5,0x5a,0x3c,0x47,0x49,0x82,0x7c,0x01,0x16, - 0x0c,0x08,0xa3,0x4c,0xd0,0xe2,0x0d,0x63,0x62,0xca,0xd1,0x8a,0xc5,0x12,0xda,0x8c, - 0x69,0x12,0x65,0xe2,0x32,0x08,0x16,0xf8,0x26,0x4c,0x69,0x39,0x38,0x04,0x2f,0x57, - 0x0e,0x62,0x03,0x4f,0x70,0x48,0x7a,0x37,0xc2,0x1c,0xa6,0x56,0x85,0x08,0x11,0xe3, - 0x05,0xdb,0xab,0x2d,0xb4,0x6b,0xc7,0xe6,0xc0,0xf0,0xbb,0xb4,0xab,0x52,0xe9,0x4e, - 0xbd,0x75,0x5b,0x18,0x0c,0xfc,0x09,0x45,0x8f,0x9a,0x58,0x24,0xfd,0x86,0xda,0x33, - 0x8f,0xaa,0x59,0xf3,0xc6,0x38,0x3f,0xe4,0x2b,0x84,0x5d,0xe8,0x86,0x53,0x9a,0xfc, - 0xbc,0xe6,0x8d,0x1d,0x8a,0x20,0xdf,0xca,0xf5,0xa9,0x2d,0xee,0xad,0xad,0x83,0x4a, - 0x1f,0xa8,0xf4,0x8a,0x74,0x80,0x70,0x44,0x47,0x9a,0xb7,0xd6,0xd0,0x0a,0x30,0x75, - 0x71,0xda,0x1f,0xee,0x28,0xff,0x17,0x58,0x5b,0x4f,0xb6,0x65,0x38,0xf5,0x93,0x6d, - 0x79,0xa2,0x06,0x83,0x74,0xe1,0xcf,0x38,0xbc,0x02,0xf9,0x01,0xcc,0xec,0x70,0x0b, - 0xf9,0xcf,0xd6,0xd3,0x7b,0x00,0xfd,0x09,0x4b,0xb9,0xa7,0xd4,0x47,0xbb,0x08,0x05, - 0x74,0x6e,0xf1,0x7b,0xf8,0x42,0x7b,0x70,0xf2,0x13,0x70,0x3a,0x3a,0x68,0x03,0xaf, - 0x2a,0xbf,0x53,0x10,0xe6,0xd6,0xd3,0x52,0x2c,0xf7,0x9a,0x2a,0x1c,0x89,0xb9,0xf5, - 0xf4,0xed,0xd1,0xe9,0xe9,0xeb,0x77,0xdf,0xdb,0x25,0x9f,0x6c,0x43,0xaf,0xca,0xfd, - 0x93,0x71,0x95,0x85,0x1e,0x86,0x63,0xf8,0x62,0xf4,0x8a,0x2d,0x55,0x1a,0x15,0x9f, - 0xea,0x3e,0x63,0x0d,0xa3,0x39,0xeb,0x0a,0x48,0x1a,0x5b,0x4f,0xc3,0x71,0x14,0xd4, - 0x55,0x52,0x9a,0xb7,0x53,0x05,0x35,0xb6,0xad,0xa7,0x56,0x44,0xbd,0x07,0x26,0xb5, - 0x1f,0x0d,0x1e,0xf5,0x0a,0x60,0x24,0x45,0x53,0xeb,0xac,0xaa,0x6b,0x38,0x26,0x6a, - 0x70,0x4b,0xa8,0xb0,0xc1,0xa7,0x68,0x2c,0x3c,0xd9,0xe6,0x5a,0x05,0xbc,0xf0,0x3c, - 0xe3,0x1c,0xde,0x73,0x51,0xa4,0x19,0xaf,0x44,0x92,0xdd,0xa8,0xbf,0x1c,0x9f,0x13, - 0x5d,0xe9,0x66,0xcd,0x0a,0xda,0x12,0x78,0x4e,0x0b,0x48,0x80,0x8a,0xc3,0x13,0xce, - 0xe7,0xe1,0xd6,0x49,0x8c,0x5d,0x11,0x43,0x60,0x0d,0x19,0xaa,0x1c,0xfe,0x90,0xd4, - 0x4e,0x73,0x58,0x80,0x0e,0x0f,0xa0,0x85,0xc6,0xc7,0x2a,0x9a,0x47,0x3f,0xbe,0x68, - 0x55,0x53,0x10,0xb7,0x05,0x13,0x62,0xbf,0xc4,0xa8,0x1d,0x3d,0x47,0xeb,0xc8,0xcb, - 0xc4,0x8f,0x6d,0x3d,0x25,0xc2,0xea,0x7c,0xc0,0x36,0xb9,0x41,0x97,0x74,0x1c,0x84, - 0x59,0xc3,0x07,0xbd,0xf8,0x2b,0x87,0x9f,0xc4,0x9d,0x61,0x82,0x9e,0x41,0xa3,0x5a, - 0xff,0x67,0x8f,0xd1,0x98,0x81,0x6b,0x06,0x67,0xcf,0x3b,0x0b,0xc4,0xea,0x6e,0x99, - 0x8d,0xc9,0xad,0xa7,0xaf,0x49,0x62,0x4e,0xc1,0x5a,0x2e,0x74,0x85,0x45,0xa9,0x44, - 0xd4,0xf7,0xf0,0x5d,0xe1,0x04,0x98,0x02,0x70,0x0e,0x14,0xa6,0x87,0x5b,0xbd,0x2d, - 0xd4,0x7d,0xe1,0xef,0xfe,0x96,0x40,0x16,0x79,0xb8,0x05,0x9a,0x7e,0xc5,0x7a,0x94, - 0x20,0xfe,0xe8,0x47,0x1a,0xd9,0xe4,0xc0,0x97,0x41,0xf1,0x5b,0x4f,0x1f,0x79,0xdd, - 0xba,0x05,0xaf,0x81,0x18,0xe5,0x60,0xcd,0x9a,0x36,0xc5,0x59,0x7d,0xd0,0x45,0xd5, - 0x23,0x88,0xaf,0x00,0x17,0x1c,0x1e,0xef,0xa9,0xaa,0x2a,0x8b,0xb3,0x3e,0x50,0x28, - 0xe0,0x13,0x60,0xe8,0xf0,0xf7,0x4b,0xd0,0xb3,0xdf,0x84,0xf1,0xa5,0x06,0xaf,0x04, - 0x0d,0x18,0x58,0x69,0x30,0x81,0x9e,0xe5,0xf9,0x22,0x1b,0x6c,0x6f,0x4f,0xc3,0x7c, - 0xb6,0x1c,0x82,0x36,0x3c,0xdf,0x0e,0xe2,0xe9,0x7c,0x19,0x4f,0xb7,0x2d,0xa6,0xb8, - 0x9d,0x83,0x46,0xba,0x8d,0xb1,0x68,0xdb,0x77,0x1e,0xc4,0xf9,0x06,0xfd,0x1e,0x73, - 0x18,0x7b,0x0e,0x1a,0x01,0x9e,0x8b,0xfc,0x69,0x18,0xf9,0xd8,0x03,0x10,0x83,0x87, - 0x5b,0x71,0x02,0xa6,0x48,0x0c,0x3d,0x16,0xc4,0xfa,0x81,0x7c,0x30,0x72,0x74,0x1c, - 0x8c,0x12,0x30,0x0f,0x50,0xcc,0x90,0xf6,0xa2,0x54,0x03,0xe9,0xec,0x23,0x73,0xdf, - 0xb6,0xf6,0xa5,0x3e,0x81,0xea,0x0b,0x68,0x2b,0x9a,0xee,0x5f,0xc7,0x80,0x2f,0x30, - 0x10,0x8f,0xd9,0x88,0xe5,0x53,0x39,0x27,0xaa,0x63,0x5b,0x4f,0xf5,0x4f,0xf1,0xd7, - 0x7f,0xf9,0x3f,0x4f,0xb6,0xfd,0xf2,0x62,0x23,0x81,0x7a,0x14,0x45,0x15,0xf8,0x72, - 0x56,0xda,0xd3,0x0f,0xb4,0x61,0xa2,0xcf,0x3a,0x19,0xfa,0x96,0x24,0x51,0x64,0x70, - 0x52,0x81,0xab,0x64,0x6f,0x79,0xb2,0xe9,0x02,0xff,0x4f,0xe7,0x50,0x60,0xb9,0xd0, - 0xba,0x59,0xb3,0x7a,0x35,0xe1,0x2a,0x0d,0xf4,0x4e,0x2a,0x5f,0x47,0xaa,0x5f,0xc3, - 0x0b,0x8e,0xf2,0x1c,0x34,0x99,0x5a,0x3e,0xe0,0xd3,0xe7,0x2a,0x36,0xd0,0x55,0x6c, - 0xc0,0x70,0x81,0x6e,0xaf,0x82,0x0d,0x30,0x84,0x8f,0x60,0x74,0xd4,0xb0,0x81,0x5f, - 0x96,0xa1,0xdb,0x81,0x1a,0xc9,0xbf,0xf1,0x90,0x5e,0x70,0xc1,0xda,0x31,0x29,0x40, - 0xbf,0x61,0x50,0x12,0xc4,0x9a,0x51,0x0d,0x7d,0x58,0xa8,0xa3,0x60,0x5c,0x37,0x30, - 0x8b,0x68,0x71,0x11,0x9f,0xf2,0x9e,0xe3,0x5d,0x4b,0x45,0x76,0x84,0xff,0x27,0x17, - 0xea,0xd9,0x2a,0x06,0xa5,0x3c,0x0f,0x47,0x22,0x47,0xe7,0x42,0x06,0x2b,0xdb,0x8f, - 0xd0,0x30,0x4e,0x93,0xe5,0x74,0xc6,0x5e,0xc8,0x20,0x02,0x6b,0x05,0x6d,0x6b,0x94, - 0xdc,0x1d,0x78,0x0e,0x04,0xcf,0x4b,0x5b,0x28,0x33,0x8a,0x5c,0xbb,0x33,0x65,0x43, - 0xcf,0x13,0xf8,0x8f,0x2f,0x30,0x52,0x02,0x34,0x3a,0xee,0x5c,0xd5,0xca,0x94,0x53, - 0x84,0xc3,0x50,0x06,0xaa,0x51,0x68,0xd4,0x0b,0x39,0x64,0xb6,0xb6,0x75,0x59,0x24, - 0x5e,0x7e,0x55,0x9e,0xeb,0xdc,0x87,0xe9,0xc1,0x82,0xf0,0xa3,0x5b,0x58,0x8d,0x32, - 0xdc,0x73,0xeb,0xe9,0xf3,0xde,0x7f,0xfc,0xfb,0x0f,0x4a,0xc1,0x92,0xd0,0x0d,0xcc, - 0x1a,0x2a,0xb2,0x21,0xf7,0x6a,0x21,0xf7,0x01,0x72,0xff,0x37,0x40,0xee,0xd7,0x42, - 0xde,0x01,0xc8,0x3b,0xbf,0x01,0xf2,0x4e,0x2d,0xe4,0x5d,0x80,0xbc,0x7b,0x27,0xe4, - 0xc2,0xc4,0x69,0xc3,0x20,0xc6,0x95,0x53,0xd6,0xb6,0x93,0xa8,0x7a,0xbd,0xe9,0x78, - 0x51,0xe0,0xde,0x27,0x67,0xa7,0xef,0xdf,0x9d,0x9d,0x14,0xd6,0x9b,0x35,0xdb,0x44, - 0x52,0xa5,0xe9,0xd6,0x1d,0x29,0x35,0x29,0x8c,0x99,0x7c,0x67,0xeb,0xc7,0x3f,0x7e, - 0xf8,0x63,0xb1,0x69,0x7b,0x60,0x3a,0xea,0x53,0x43,0x32,0x8b,0xcf,0x29,0x03,0x4a, - 0x37,0xee,0x17,0xc0,0x9a,0xcf,0xe6,0x49,0x92,0xcf,0x8a,0xd2,0xa2,0x8c,0x52,0x6a, - 0xf3,0x8c,0x0a,0x6b,0xd9,0x60,0x73,0xf7,0x4d,0x9a,0x9a,0xf9,0xe9,0x62,0xd3,0x96, - 0xb0,0xec,0xd7,0x36,0x34,0xf1,0x51,0x0e,0x6f,0xd4,0xce,0x4b,0x28,0xfa,0xb5,0xcd, - 0x4c,0x7d,0x54,0xd4,0x36,0x6a,0xe6,0x7b,0x28,0xfa,0xd5,0x68,0x43,0xcb,0x7c,0x53, - 0xb4,0x61,0xd9,0xaf,0x6d,0xc8,0x4f,0x47,0x9b,0x12,0xc2,0x11,0x14,0xad,0x69,0xc6, - 0x5a,0xd6,0x16,0xbf,0x54,0xee,0x05,0xcd,0x2f,0xcd,0x0b,0x76,0xd4,0x5a,0xbd,0x24, - 0xb0,0x99,0x35,0x92,0xd2,0x00,0x34,0xc4,0xb7,0x61,0xbc,0x2c,0xe1,0xe6,0xdb,0x6f, - 0x1e,0x3d,0xec,0xf7,0x0f,0x2a,0xc6,0x6f,0x8c,0x61,0xac,0xfc,0xce,0x91,0x66,0x5b, - 0x4f,0x77,0xee,0x6c,0xee,0x34,0x2a,0xb7,0xf6,0x60,0x3d,0x02,0x74,0x93,0x51,0x30, - 0xf5,0x47,0xab,0x0a,0xb5,0xe7,0x7c,0x16,0x66,0x2c,0xab,0xb2,0x1c,0x63,0xd2,0xd2, - 0x65,0x9c,0xf1,0x7e,0x65,0x84,0xfe,0x61,0xda,0x8d,0x23,0x31,0x85,0xa7,0xc4,0x17, - 0xc0,0x09,0x40,0x54,0xc9,0x38,0x65,0x50,0xba,0x96,0x8b,0x69,0x0a,0x86,0x31,0x54, - 0xf0,0xd6,0x28,0x6b,0xdc,0xd2,0x8b,0xd4,0x9f,0x92,0xd8,0xc3,0xad,0xd1,0x19,0x45, - 0xab,0x65,0x72,0x0b,0x61,0xb4,0x04,0x0b,0x7d,0x2e,0x60,0x89,0x2e,0x02,0x4f,0x1c, - 0xc5,0x2b,0xd9,0x66,0xe6,0x5f,0x05,0xe8,0x1c,0x46,0x1f,0xf3,0x4e,0x87,0x1c,0x5f, - 0x68,0x14,0x47,0x81,0x57,0x21,0xeb,0x4b,0xec,0xed,0x8a,0x94,0xb6,0x7a,0xd6,0x87, - 0x1e,0xb8,0xad,0x2a,0x4e,0xa6,0xa2,0x6e,0xb7,0xaa,0x26,0x4f,0x05,0xd5,0x6e,0xd9, - 0xa5,0xe9,0xc5,0xd3,0xe7,0x88,0xc6,0x5e,0x69,0x1e,0x9d,0xaa,0x6f,0x83,0xdc,0xaf, - 0xd1,0x63,0xf6,0xfb,0x80,0xe4,0xff,0x2d,0x76,0x1e,0xee,0x89,0x57,0xbf,0x16,0xd0, - 0x69,0x0d,0xc3,0xed,0x2b,0x69,0x63,0x76,0x47,0x8b,0xdf,0x3e,0x58,0x83,0x5c,0xab, - 0xcb,0xbd,0xe7,0xe0,0xac,0x92,0x1e,0x5d,0x1c,0x45,0xb2,0xcc,0xb9,0x86,0x4b,0xbf, - 0x5d,0x6f,0xa7,0x4b,0xfd,0xef,0x7a,0x8f,0xf6,0x4a,0x38,0xb0,0xa9,0xd2,0x5a,0x98, - 0xca,0xbd,0xa7,0x61,0xe9,0x17,0x4e,0xdb,0xd6,0x98,0x64,0x8c,0xe6,0xd6,0xd3,0x02, - 0x48,0x17,0x28,0x86,0x57,0xda,0x30,0xe9,0x79,0x7d,0x95,0x37,0x89,0x5d,0x81,0xa3, - 0x29,0xef,0xa8,0xf2,0x2a,0xdc,0xa0,0x4a,0xd5,0xd0,0x4d,0x25,0xb9,0x15,0xe6,0x0e, - 0xd7,0x65,0x94,0xba,0x54,0xd1,0x6b,0x42,0x9c,0x33,0x4a,0x48,0x95,0xa6,0xdf,0xb3, - 0x10,0xd5,0xe9,0xa7,0x5d,0x60,0x41,0xfd,0x5e,0xef,0xa0,0x57,0xe6,0x41,0xbf,0x11, - 0x38,0x79,0x1f,0x14,0x78,0x6f,0xef,0xf7,0x81,0x0f,0x30,0x9d,0xee,0x7b,0x7b,0xbf, - 0x6f,0xff,0xbd,0xfe,0x9e,0x33,0x84,0x87,0x30,0x06,0x78,0xa7,0x46,0xf1,0xf0,0xf7, - 0x1a,0x46,0xcf,0x6d,0x66,0x1f,0x5a,0xe9,0xe9,0x56,0xf6,0x7f,0xa7,0x46,0x76,0x9c, - 0x36,0x1e,0xe1,0x50,0x76,0x54,0x1b,0x8f,0x2a,0x46,0xe2,0x8a,0x83,0xf5,0x5c,0xc4, - 0xe5,0x14,0xb5,0x7c,0xe2,0xed,0x32,0x0f,0x48,0x62,0xac,0x13,0x58,0x18,0x07,0x54, - 0xe9,0x1d,0x10,0xe4,0x64,0x2f,0x09,0xfa,0x35,0x3e,0x80,0x4a,0xf9,0x56,0x31,0x06, - 0x63,0xa7,0x17,0x55,0x80,0x35,0x83,0x2c,0xfa,0x50,0x90,0x85,0x6f,0xe8,0x44,0x61, - 0x14,0xd4,0x4a,0xdf,0x2a,0x33,0x00,0x53,0xca,0x48,0x0b,0x6f,0x20,0xb2,0xbb,0x8d, - 0xc9,0xb3,0x93,0x37,0x27,0xc7,0x94,0x7d,0x86,0xb7,0xb1,0x65,0x26,0x2d,0xd5,0x7d, - 0x16,0x92,0x28,0x74,0xa6,0x11,0x6e,0xc2,0x77,0x4c,0x90,0x0b,0x5a,0x93,0x50,0x1c, - 0x04,0xfa,0x38,0x69,0xab,0x6d,0x7d,0x1f,0x04,0xeb,0x7c,0x99,0x41,0x8b,0xe8,0xa5, - 0xca,0x38,0x35,0x8c,0x6d,0x56,0xaa,0xb0,0x4d,0x63,0x57,0x9a,0x37,0xb6,0xa2,0xe4, - 0xa8,0xfd,0x14,0xc5,0x59,0x29,0x47,0x39,0x44,0xb2,0x52,0x8a,0x2e,0xae,0xce,0x69, - 0x0b,0xa3,0x2c,0x44,0x4f,0x55,0x48,0x30,0xe8,0x1b,0x35,0x02,0xd5,0x9a,0x34,0x68, - 0x3d,0x4a,0xb2,0xe0,0xce,0x29,0xa3,0x52,0x77,0x2b,0x8b,0x66,0x4c,0xb8,0xd9,0xb7, - 0xc6,0x8e,0xa1,0x30,0xcc,0x24,0xae,0x5c,0xa9,0xf8,0x7d,0x19,0x41,0xa7,0x9e,0xa2, - 0xe5,0x24,0xe8,0x77,0x76,0xb7,0x3e,0x8c,0x20,0xeb,0xe0,0xc5,0x49,0x98,0xad,0xb6, - 0x9e,0xbe,0xc3,0x3f,0x22,0x4d,0x92,0xf9,0x6f,0x03,0x97,0x5d,0x07,0x28,0x0f,0xcf, - 0x70,0xdf,0x88,0x7e,0xaf,0xc7,0x8c,0xed,0x4d,0xe0,0xa0,0x8c,0xa2,0x85,0x59,0x44, - 0x1f,0xc7,0x57,0xd6,0x71,0x13,0x19,0xfa,0x68,0xd6,0x78,0x59,0x59,0x64,0x17,0x52, - 0x14,0x5c,0x05,0x51,0xb5,0x3e,0x65,0x83,0x02,0xcd,0x65,0x1d,0x2c,0x5a,0x0b,0x1c, - 0x7a,0x5e,0xa9,0x55,0xd5,0xad,0x56,0x5b,0x5d,0xb4,0xc8,0xa1,0x80,0x68,0xb5,0xc3, - 0xc9,0x6e,0x03,0x7c,0xea,0xae,0xe5,0x6e,0x32,0x6a,0xbf,0xba,0xc3,0xf8,0x91,0x4e, - 0x6c,0xb1,0x4e,0xf5,0xbc,0x57,0x57,0xe8,0xd5,0xaf,0xa2,0xa8,0x3c,0x82,0xee,0xb5, - 0xf3,0x70,0xaf,0xde,0x2b,0x51,0xb5,0x51,0x53,0x3b,0x86,0xde,0xef,0x37,0x86,0xfe, - 0xc6,0x63,0xe8,0xef,0x75,0x61,0x10,0xfd,0xcb,0xdf,0x69,0x0c,0xfd,0xdf,0x6f,0x0c, - 0x3b,0x9b,0x8f,0xe1,0x12,0x86,0xb0,0xf7,0x7b,0x0d,0x61,0xe7,0xf7,0x1b,0xc2,0xee, - 0xc6,0x43,0xd8,0xc3,0x21,0xf4,0xf6,0x37,0x1a,0x83,0x5a,0x2e,0xfa,0xaf,0xca,0xd5, - 0x76,0x6f,0x7b,0x5b,0x66,0xbc,0x02,0xb9,0x33,0xf6,0x17,0x14,0xb1,0x40,0x0e,0x52, - 0xec,0x53,0xb6,0x4c,0x27,0x20,0xad,0x65,0x54,0x59,0x47,0x16,0xc0,0xe8,0xd3,0x69, - 0x78,0xc5,0xa1,0xb7,0x66,0xd7,0xb3,0x8d,0xb0,0xb2,0x05,0x86,0x2c,0x73,0x40,0x33, - 0xa7,0xad,0xe3,0x6c,0x92,0xbc,0x8b,0x13,0xc6,0x0d,0x0c,0xc0,0x05,0xc3,0x12,0x6a, - 0xa5,0xbe,0xf8,0x39,0x19,0x66,0x02,0x53,0x48,0x52,0x74,0xed,0x00,0x00,0x20,0x0c, - 0x81,0xfe,0x58,0x0c,0x23,0xc2,0x50,0x01,0x00,0x84,0xc0,0x39,0x22,0x4a,0xa5,0x76, - 0xc3,0x88,0x53,0xe8,0x5b,0x90,0xb5,0x05,0xfa,0x57,0x32,0x12,0xae,0x73,0x7f,0x91, - 0x61,0xec,0xed,0x9b,0xd7,0xef,0x4e,0x8e,0x3e,0x30,0x20,0x21,0xfc,0xf9,0x22,0x0a, - 0xf3,0x25,0x88,0xdd,0x26,0x87,0xc4,0x62,0xc4,0x31,0x46,0xa1,0x61,0xd1,0x11,0x88, - 0x5b,0x93,0x16,0x0e,0x00,0x78,0x33,0x0a,0x9d,0x93,0xe0,0xc7,0x18,0x48,0x8b,0xc1, - 0x4e,0x0a,0x18,0xf7,0x8a,0xad,0x70,0x90,0xcc,0xad,0x03,0x37,0x68,0x1b,0xe0,0x83, - 0x9e,0xe0,0x47,0xc2,0xbf,0x09,0x29,0xc5,0xda,0xf8,0x79,0x27,0x4e,0x52,0xd0,0xa4, - 0xc2,0x5f,0x01,0x58,0x96,0x70,0x24,0x97,0x82,0x36,0x46,0x4b,0x3b,0x0a,0x2f,0x71, - 0xf4,0x7e,0x8a,0x1e,0xe7,0xeb,0x24,0xbd,0xcc,0x70,0xa8,0x50,0x77,0x12,0x6a,0x04, - 0x80,0x99,0x3f,0x4c,0x72,0xec,0xda,0x0a,0x86,0xca,0x9a,0xc3,0x10,0x03,0x3f,0xfd, - 0x74,0xe5,0x29,0x68,0x2f,0x9e,0xff,0xf4,0xf2,0xcd,0xfb,0xf7,0x1f,0xb6,0xe1,0xc7, - 0xd9,0xe9,0xd1,0x3b,0x8c,0x5f,0x61,0xf7,0x35,0x34,0x3f,0x94,0xdb,0x5f,0xe2,0x97, - 0x65,0x08,0x3a,0x11,0x8a,0x26,0x8c,0x6b,0xc4,0x40,0xc7,0x2c,0xcc,0xc5,0xff,0x42, - 0xb5,0x58,0x2c,0x17,0x0a,0x16,0x56,0xc3,0x31,0xb4,0xa1,0x7b,0x19,0x4c,0x2f,0xf4, - 0xad,0x73,0x85,0x21,0x33,0x81,0x58,0x04,0xfe,0x65,0x86,0x15,0x1e,0xe3,0x44,0xc2, - 0x83,0xe0,0x74,0x77,0x31,0xee,0x77,0x4f,0x80,0x5c,0x67,0x9e,0x35,0x8d,0x6e,0x20, - 0xaf,0x67,0xc7,0xf1,0x2e,0x92,0x6b,0xa0,0x11,0xc4,0x65,0xa8,0x37,0x5f,0x81,0x2c, - 0xa0,0x3d,0x8e,0xf8,0x24,0xd4,0x87,0x1a,0x59,0x19,0x68,0x4e,0x07,0x1c,0xf1,0x98, - 0xfb,0xd1,0x25,0x7a,0x35,0x34,0x99,0x1e,0x9d,0xbe,0x16,0x1c,0x7e,0x14,0x01,0x3e, - 0x74,0x86,0x42,0xd1,0xe4,0xa0,0x1b,0xcc,0xf7,0xa8,0xb0,0x23,0x0e,0x45,0x67,0x77, - 0xaf,0x2d,0x14,0x92,0x0e,0xc5,0xee,0x43,0x4a,0x56,0xa2,0xea,0xc0,0x8a,0x9b,0x2f, - 0xba,0xbd,0xe6,0x55,0x0b,0x43,0x31,0xe1,0x3b,0x27,0x2f,0xc5,0xe7,0x3f,0xff,0x19, - 0x03,0xa6,0x64,0x46,0xc5,0x2b,0xf1,0x44,0x74,0xc5,0x33,0xf8,0x77,0x00,0xbf,0x9f, - 0x8a,0x1e,0xfc,0xee,0xe1,0x6f,0x0e,0xc3,0xd1,0xf0,0xc6,0xc3,0xb8,0x89,0xc1,0x6e, - 0xaa,0x9e,0x82,0xdf,0xec,0x77,0xc5,0x77,0x82,0xb2,0x5b,0x46,0xc9,0xb4,0xd7,0x6d, - 0x72,0xa2,0x4b,0xff,0xa6,0x29,0x1b,0xbc,0xe1,0x06,0xdb,0xa2,0x17,0x74,0x76,0x5b, - 0x2d,0x40,0xa6,0x1a,0x43,0x4b,0x6c,0xab,0xfe,0xb7,0x0a,0xad,0x45,0x61,0xcc,0x3d, - 0x97,0xad,0x11,0x50,0xc0,0x74,0xb3,0x07,0x80,0x9a,0xd6,0xd8,0xbe,0xd3,0x18,0x78, - 0xe0,0xc0,0xed,0x77,0xf9,0xa4,0x02,0x63,0xed,0xf4,0xc3,0xc9,0xd9,0xc9,0xf9,0x4f, - 0xe4,0x51,0x3e,0x03,0x5c,0x70,0x00,0x0f,0x7b,0x83,0x07,0xd0,0x0a,0x32,0xbd,0x81, - 0x68,0x0c,0x83,0x5f,0xc3,0x20,0x6d,0xb4,0x81,0x1f,0xc2,0x13,0x7f,0x86,0xa7,0x55, - 0x77,0x80,0xfd,0x5f,0xf5,0x06,0xa2,0xd7,0x16,0x8b,0xde,0xcd,0x80,0x8e,0x2e,0xe1, - 0x4f,0x0a,0x86,0xed,0xe2,0xcf,0xfe,0x0d,0x1f,0x95,0xc3,0x9f,0xf4,0xf6,0xf1,0x9e, - 0xb8,0x65,0xd5,0x99,0x5c,0xc1,0x03,0x51,0xdb,0x0e,0x7e,0x86,0x87,0xea,0x76,0x70, - 0xc0,0xb2,0x9d,0x7d,0xd3,0xce,0x8e,0x6a,0xa7,0xe7,0x75,0xbb,0xaa,0x1d,0xf4,0x04, - 0x43,0x33,0x75,0xed,0xe0,0x67,0x6c,0x86,0xda,0xe9,0x71,0x3b,0xdd,0xaa,0xf1,0x3c, - 0xae,0x1c,0x4f,0x77,0x8f,0xa6,0xe8,0xf6,0xe0,0x9e,0x3d,0x51,0x41,0x3c,0x4a,0xc6, - 0x01,0x7a,0x99,0x9a,0x64,0x1e,0xb4,0x24,0x6e,0xc3,0x89,0x68,0xde,0x97,0x6f,0xe4, - 0x1c,0x36,0x1a,0x07,0xfa,0x13,0x7d,0xf1,0x28,0x79,0xf0,0xe1,0xe1,0x21,0xe0,0x00, - 0x1d,0x8e,0x0d,0x53,0x34,0x1b,0x34,0x60,0x42,0xb9,0x54,0x5c,0x5f,0x0d,0x9d,0xb8, - 0x56,0x2d,0x7f,0x4d,0x0b,0x12,0x17,0xaa,0x7f,0x76,0xa1,0x70,0x2c,0xbe,0xfd,0xd6, - 0xa5,0x91,0x4f,0xea,0xcb,0x85,0x81,0xbe,0xb0,0xfa,0x14,0x8e,0x0f,0x24,0x18,0xf5, - 0x75,0x48,0x5f,0x65,0xbd,0x15,0xe0,0x55,0xfe,0xea,0xa9,0x5f,0x80,0x67,0xf3,0x73, - 0xa5,0x7f,0xf6,0xcd,0xdb,0xfe,0xea,0x42,0x6b,0x9d,0xb0,0x82,0x16,0x16,0x03,0x28, - 0xad,0x05,0x8a,0x97,0x77,0x17,0x42,0xaf,0x4b,0x34,0xdf,0xf2,0x7e,0x4e,0x60,0xf5, - 0x34,0xda,0x8d,0x16,0xf7,0xf1,0xf6,0x9e,0xdd,0xcf,0x06,0x47,0xa1,0x39,0x4b,0x3b, - 0xd0,0x73,0x38,0x77,0xe6,0x6f,0xae,0x07,0x8f,0x29,0x7e,0x0d,0x6e,0xe7,0x12,0xfb, - 0x06,0xf5,0x9a,0xe4,0x68,0x46,0x24,0xc1,0xd1,0x6f,0x24,0x18,0x5d,0xcf,0xcb,0x22, - 0x60,0xa1,0x98,0x6c,0xa3,0xdf,0x92,0x13,0x3f,0xb0,0xa6,0x04,0x97,0x6a,0x0c,0xcb, - 0x53,0xb3,0x90,0x7e,0x5b,0xe8,0xbc,0xb9,0x8f,0x80,0x12,0x31,0x00,0xf1,0x75,0x9c, - 0x6b,0x40,0xfd,0x16,0xb0,0x95,0x2e,0x31,0x98,0x7e,0xab,0x55,0x98,0x12,0xdd,0x27, - 0x26,0x2e,0xee,0x54,0x4c,0xcd,0xf6,0x81,0xc9,0x35,0x50,0xe2,0x36,0x84,0xf5,0x1d, - 0xcf,0x66,0xab,0xee,0xde,0xae,0xeb,0xf4,0xa2,0xd8,0xe9,0x05,0x74,0xda,0xa5,0x1f, - 0xd3,0xc3,0x8b,0x42,0xb7,0x16,0xd0,0xf6,0x7f,0x3f,0x7b,0xff,0xce,0xa3,0xd1,0x34, - 0xe9,0x67,0x96,0xa3,0xd8,0x0c,0x27,0xab,0xe6,0x02,0x38,0xe4,0xc0,0x42,0xf7,0xda, - 0x7e,0x0c,0x8b,0xfd,0xf8,0x05,0xfa,0x61,0x5a,0xf6,0x32,0x54,0x19,0x88,0x12,0xd6, - 0x90,0x53,0x53,0x63,0xf5,0x4a,0x23,0xb3,0x8b,0x2c,0xb4,0x47,0x87,0xe2,0x34,0x56, - 0xb1,0x0f,0xbf,0x78,0x51,0x10,0x4f,0x41,0x82,0xdf,0x87,0xe6,0xf7,0x2b,0xa8,0xa3, - 0x8c,0x7c,0x97,0x07,0xb1,0xe7,0x5d,0xf2,0xd4,0x5f,0x3e,0x75,0x2f,0x98,0x0d,0xfd, - 0xf2,0xa9,0x77,0x21,0x39,0xd1,0x2f,0x9f,0xfa,0x17,0x92,0x13,0xfd,0xf2,0x69,0xe7, - 0x42,0x72,0xa2,0x5f,0x3e,0xed,0x5e,0x48,0x4e,0xf4,0xcb,0xa7,0xbd,0x0b,0x77,0x96, - 0x0a,0xbd,0xd0,0x5c,0x7f,0x92,0x82,0x50,0x7d,0x89,0x04,0xa5,0x3e,0xe1,0xdb,0x79, - 0x38,0x7a,0x8f,0xef,0x80,0x1d,0x66,0x81,0x7a,0x49,0xa2,0xfc,0x0d,0x2a,0x70,0x85, - 0x0f,0xa0,0x54,0xd9,0xa5,0xe1,0x2d,0xc8,0x71,0x54,0xe1,0xc8,0x56,0x04,0xa5,0x2f, - 0x49,0x16,0x14,0x3e,0x9b,0xa9,0x53,0x57,0x82,0x52,0xf5,0x82,0x9a,0x04,0xf8,0x13, - 0x73,0xd0,0x2d,0xc3,0x39,0xe8,0x07,0x98,0xd5,0x16,0xcf,0x4c,0x25,0x13,0x71,0xfa, - 0x92,0x32,0x36,0x0f,0x18,0x16,0x68,0x25,0xdc,0x51,0xdc,0x75,0xc8,0x60,0x25,0xa2, - 0x22,0x91,0x91,0xca,0x40,0x41,0xff,0xe8,0x86,0x99,0xa1,0x56,0x0b,0x3a,0x66,0xdb, - 0x6c,0xe5,0x53,0xe8,0x4e,0x03,0x0f,0x47,0xc4,0x01,0x03,0xe2,0xe3,0x1e,0xbf,0x2c, - 0x83,0x25,0xee,0x8f,0x88,0x61,0x00,0xd6,0xe8,0x58,0x1e,0x9f,0xe2,0xf8,0x28,0x3a, - 0x16,0xe2,0x89,0xd7,0x39,0x3e,0xa3,0x32,0x96,0xc4,0xa3,0x40,0x05,0x02,0x4f,0xc2, - 0x29,0x1d,0xc5,0x62,0x60,0x33,0x50,0x1e,0x31,0x4f,0x08,0x86,0xc0,0x37,0x7d,0xee, - 0xa0,0x39,0xad,0xe1,0xe7,0x7c,0x20,0x0b,0x21,0x40,0x97,0xc4,0x32,0xce,0x48,0x31, - 0xa4,0xe3,0x64,0xd8,0xc5,0x14,0x94,0x6d,0x75,0xa0,0x0d,0xa0,0xd1,0x69,0xb1,0x89, - 0x3a,0x73,0x86,0x1b,0xd2,0x8d,0x4c,0x9e,0x12,0x88,0x63,0x0e,0xb6,0x86,0x85,0x9c, - 0x45,0x84,0xc6,0xeb,0x19,0x2a,0x8c,0xb4,0x71,0xe3,0x0f,0x11,0x15,0xec,0x09,0x42, - 0xb8,0x0c,0x0d,0xa3,0x2b,0xa9,0x65,0x44,0x0f,0x7c,0x0c,0x3c,0x39,0x57,0xd8,0xcc, - 0x4a,0xcd,0x15,0x68,0xd4,0xd8,0x82,0x7e,0xc2,0xf4,0xeb,0xe6,0x89,0x27,0xe5,0x10, - 0x43,0xe4,0x6d,0x4e,0x08,0x5a,0xef,0x65,0x53,0x2d,0x29,0x37,0xad,0x38,0x56,0x90, - 0x6b,0xc1,0xaa,0xac,0x59,0x25,0xb7,0x0d,0x4b,0xe7,0xbe,0xa2,0x3a,0xf8,0x4d,0x3d, - 0x80,0xbf,0xd4,0x36,0xfc,0x1d,0x27,0x23,0x4a,0x6c,0xec,0xf1,0x90,0xd4,0xfa,0x61, - 0x30,0xb2,0x83,0x79,0xba,0x0c,0xf8,0x05,0x0e,0x09,0xb3,0x84,0xc3,0x4b,0x5c,0x8a, - 0x2c,0xe2,0x2b,0x4c,0x91,0x67,0x4c,0x8a,0x87,0xbd,0x46,0x21,0xad,0xb6,0x68,0xa6, - 0xd6,0x3a,0x57,0x79,0xb2,0x49,0x44,0x14,0xca,0xfd,0x6c,0xd8,0x08,0x20,0x18,0x33, - 0x6e,0x49,0x92,0x1c,0x61,0x80,0x18,0xa6,0x97,0xe6,0xa9,0x23,0x85,0xd7,0x5f,0x2c, - 0x80,0x10,0x23,0x1e,0x71,0x12,0xbb,0xa6,0x83,0x3c,0x76,0xc8,0x80,0x6c,0x9b,0x81, - 0x2c,0x8e,0x8e,0x32,0x04,0xd0,0x48,0xc0,0xf3,0x7b,0xc2,0x27,0x75,0x99,0x69,0xf7, - 0x1a,0x34,0xdf,0x4b,0x7a,0x4d,0x56,0x92,0x81,0xc3,0x9a,0x37,0x40,0x87,0xb5,0xab, - 0x8e,0x31,0xa2,0x55,0x80,0x51,0x6f,0x3e,0xeb,0xde,0xd3,0x40,0x9e,0xb6,0x7b,0x0e, - 0x18,0x0c,0xfc,0x9c,0xd0,0x6c,0x71,0x46,0x1c,0xd3,0xa1,0xf8,0xd9,0xa3,0xbf,0x87, - 0x36,0x9a,0x85,0xe6,0x08,0xf7,0xf1,0x23,0x68,0x02,0x3f,0x7b,0x32,0x9d,0x34,0x72, - 0xb9,0x46,0x32,0x99,0x34,0x54,0x49,0x9b,0x4d,0x40,0x61,0xf5,0x3a,0x5b,0xc5,0xa3, - 0xe7,0x7e,0xda,0xd4,0xbc,0x52,0x5f,0x4f,0x70,0x24,0x2d,0xcd,0x08,0x7d,0xd9,0x99, - 0x17,0xe9,0xaa,0x28,0x80,0xe8,0xe9,0x3f,0xfe,0x9d,0xa1,0x92,0x24,0x52,0x6f,0x4c, - 0x24,0xaa,0x6e,0x1a,0x07,0x81,0xc8,0xd3,0xd5,0xab,0xb9,0x39,0xaa,0xed,0x00,0x09, - 0xb4,0x75,0x9b,0x6f,0x4b,0x9a,0x6c,0x29,0x96,0xd8,0xfc,0xac,0x15,0x8d,0x74,0x19, - 0xc7,0x74,0xa0,0x01,0xa1,0x02,0x8d,0x12,0x32,0xb4,0xcb,0x57,0xad,0x50,0x3c,0x2b, - 0x5b,0x5d,0x80,0x89,0x6f,0x00,0x34,0xe4,0x49,0x96,0x08,0x65,0x3e,0x5d,0xb0,0xc4, - 0xc1,0x0e,0xb7,0x4c,0x59,0x76,0x8a,0x41,0xe1,0x9f,0x3d,0xf9,0x93,0x0b,0x9b,0x12, - 0x41,0x7c,0x45,0xa0,0xe0,0xaf,0x0d,0xc7,0x8c,0x35,0xb0,0xc6,0xfa,0x19,0xb8,0xef, - 0x80,0x90,0xd2,0x0c,0xc0,0xf8,0x00,0x16,0x32,0x0b,0xf5,0xf3,0x2c,0x6c,0x81,0x94, - 0x00,0x5a,0x37,0xc0,0xb3,0x05,0x8c,0x24,0x5d,0xce,0xa9,0x05,0xf5,0xb0,0xa6,0xbb, - 0x18,0xb9,0xf7,0x01,0xb7,0x27,0x07,0x44,0x2e,0xf2,0xbd,0x92,0x88,0xb0,0x8a,0x46, - 0x98,0xfe,0xbf,0xd0,0x39,0x43,0xb5,0x47,0xc3,0x24,0xcd,0x29,0x8f,0xbd,0xca,0x52, - 0x2e,0x4f,0x0d,0xe2,0x21,0x58,0xb9,0x00,0x2c,0x0e,0x28,0xf7,0xa6,0x81,0xa6,0x2f, - 0xe9,0x50,0xbf,0x01,0x34,0x8a,0x30,0x22,0x06,0x18,0x31,0x14,0x50,0x3c,0x0f,0x96, - 0xb1,0x8f,0x47,0xae,0xa7,0x72,0x05,0xc1,0x3f,0x52,0xde,0xf0,0x5a,0xca,0xfd,0x4b, - 0x16,0x03,0xfe,0xe8,0xd2,0x40,0xd2,0x2b,0x39,0xc6,0xc9,0xe4,0x33,0x65,0x67,0xb4, - 0x0f,0x4f,0x47,0xcf,0x00,0xc8,0x8e,0xc8,0xd8,0x6f,0x12,0xfb,0x57,0xe1,0x94,0x8c, - 0x6d,0xf2,0x24,0x8c,0x30,0xe4,0x2d,0x02,0x71,0xe0,0x59,0x64,0x15,0xe0,0x6a,0x01, - 0x05,0x1d,0x85,0x03,0x29,0x24,0x66,0xc8,0xa8,0x98,0x28,0xee,0xb5,0xd3,0xed,0x6a, - 0x7b,0xf3,0x40,0xca,0x6c,0xea,0xce,0x8f,0xe6,0x9c,0xe4,0x00,0x87,0xc3,0x02,0x49, - 0x89,0xc1,0x36,0x1d,0xc5,0x42,0xf9,0x88,0x0c,0x97,0x0f,0x40,0xeb,0x83,0x97,0x33, - 0x3c,0x43,0x18,0xe6,0x2a,0x77,0xbd,0xc5,0x28,0xbb,0xeb,0x09,0xdf,0x10,0xbc,0x14, - 0x05,0x16,0x85,0xcb,0x37,0x8a,0xa4,0x81,0x30,0x99,0x20,0xf1,0x87,0x21,0x9e,0x4f, - 0x17,0x36,0x0d,0x14,0x38,0xa9,0x43,0x01,0xc7,0xac,0x09,0xc0,0x40,0x50,0x0c,0xa3, - 0x40,0xa5,0x34,0xe8,0xc0,0xc1,0x06,0xb6,0x47,0x21,0x83,0x57,0x41,0x51,0x20,0xa2, - 0x7f,0xc4,0x37,0xa0,0x10,0x05,0x2c,0xfe,0x7d,0x29,0x7f,0x78,0x9e,0x33,0x0c,0xf5, - 0x03,0xdc,0x82,0xdc,0xcf,0xd0,0xbd,0xc2,0x52,0x1f,0x50,0x88,0xbe,0x76,0x80,0xa8, - 0xf0,0x63,0x8b,0x3f,0x1b,0x41,0xf7,0x49,0x46,0xc1,0x34,0xde,0x67,0x09,0xa7,0x85, - 0x9b,0x75,0x15,0x04,0x4a,0xc5,0x36,0x61,0x58,0x0f,0x5b,0x1d,0x65,0xd1,0x03,0x27, - 0x8d,0x02,0x47,0x6f,0x89,0x43,0x5e,0xaa,0x2c,0x93,0x89,0xdf,0x4a,0xf9,0x8a,0x2c, - 0x0a,0x2b,0x6b,0x71,0xe8,0x8f,0xc7,0x27,0x98,0x42,0xf2,0x0d,0x39,0x69,0x82,0xb4, - 0xd9,0x30,0x67,0x47,0x47,0x78,0x8e,0x32,0x00,0x8d,0xd1,0xc1,0x31,0xb7,0xa2,0xbb, - 0x2c,0xa1,0xb6,0x38,0x95,0x06,0xf1,0xde,0x32,0x4c,0xb5,0x74,0x4a,0xb0,0xa4,0xa2, - 0xc0,0x5d,0xac,0x92,0xfa,0x96,0xc4,0xdf,0xa4,0x11,0x24,0xce,0xca,0x0e,0x63,0x43, - 0x56,0x83,0x3c,0x19,0x36,0x52,0x5a,0x4a,0xc3,0x3c,0x21,0xb5,0x0d,0xa5,0x2a,0x71, - 0x21,0x0a,0x4c,0x39,0x40,0xcd,0x91,0x6e,0xa8,0x01,0x32,0x41,0x77,0x22,0xd1,0xd0, - 0xd4,0x5f,0x80,0xfe,0x05,0x6b,0xd8,0x3a,0x82,0x8c,0xda,0x5b,0x98,0xb7,0xa5,0xba, - 0x94,0xb8,0x1a,0xa3,0x74,0x44,0x62,0x9c,0x79,0x02,0x6a,0x19,0x93,0x26,0x9f,0x34, - 0x46,0x7a,0x11,0x47,0xd0,0xaf,0x30,0x5a,0x22,0x3b,0x00,0x1d,0x10,0xcf,0xde,0x22, - 0xb3,0x90,0xca,0x6a,0x52,0xf0,0x84,0x39,0x87,0x75,0x41,0x01,0x0e,0xa2,0x09,0xb5, - 0x1e,0x27,0x48,0x81,0x7c,0x64,0x57,0xae,0x52,0x14,0x60,0x30,0x0e,0x64,0x59,0x87, - 0xe8,0x77,0x40,0xb6,0x75,0x2e,0xf1,0xaa,0xf4,0x73,0x43,0x4e,0xfe,0xaa,0x89,0x21, - 0xef,0x6d,0x01,0x3c,0x6e,0x8c,0x38,0x83,0xb1,0xbb,0x2f,0xdb,0x86,0x7e,0x40,0xf8, - 0x9f,0x44,0x01,0xfe,0x7c,0xbe,0x7a,0x3d,0x6e,0x36,0xf8,0x70,0x40,0xa3,0x55,0xf4, - 0x2a,0x2d,0x92,0x2c,0x6f,0xe2,0xd9,0x29,0xb5,0x4a,0xb9,0x3f,0x0f,0x1e,0x30,0x59, - 0x6b,0xf4,0xda,0xea,0x81,0x73,0x75,0x49,0xc1,0x07,0xdc,0xd6,0x8b,0x7d,0x1e,0xe4, - 0xb3,0x04,0x0d,0x9c,0xd3,0xf7,0x67,0xe7,0x0d,0x25,0x42,0xf8,0x14,0x4f,0x86,0x1e, - 0xa6,0x86,0xbc,0x0a,0xa8,0x73,0x0e,0x66,0x51,0x03,0x8d,0xe3,0x05,0x18,0x67,0x23, - 0x62,0xb0,0xdb,0x37,0x9d,0xeb,0xeb,0xeb,0x0e,0xe0,0x6a,0xde,0x59,0xa6,0x11,0xbb, - 0x54,0xc6,0x0d,0xe5,0xd6,0xc1,0x43,0xf6,0x63,0xcc,0x44,0x02,0xff,0xad,0xe1,0x3a, - 0xa9,0xeb,0xd6,0xe0,0x8b,0x54,0x84,0x7d,0x93,0x4a,0xe3,0xd5,0xf9,0xf9,0xa9,0x40, - 0x17,0x85,0xb9,0x53,0xc5,0xaa,0x71,0x27,0x2a,0xed,0xeb,0x8c,0x5a,0x34,0x3d,0x0d, - 0x24,0xca,0x31,0xe0,0xa0,0x91,0x5c,0x36,0xea,0x65,0xa2,0xe9,0x19,0x55,0x42,0x96, - 0x4e,0x15,0x07,0x16,0xbd,0x8e,0xc3,0x31,0xf3,0x7a,0x16,0x5a,0x1e,0x32,0x4e,0x58, - 0xf4,0x28,0xbf,0x58,0xba,0x61,0xbc,0x7d,0x90,0xa7,0x2b,0x0f,0x9b,0x0b,0xd2,0xb4, - 0xb1,0x01,0xff,0x25,0x44,0x74,0x3a,0x92,0xe4,0x90,0xc3,0x69,0x8a,0x6b,0xd9,0x53, - 0x6d,0xb1,0x44,0xc5,0xd7,0xee,0x95,0x35,0x38,0xed,0x34,0x1c,0xf9,0x0b,0x98,0x50, - 0x77,0x6d,0x6b,0x7d,0x64,0xf6,0xeb,0x5b,0x3c,0xdc,0xb9,0xd3,0xf3,0xfa,0x7b,0x6d, - 0x7c,0xf2,0xc1,0x76,0x7d,0xd4,0x45,0x17,0xdd,0x81,0x9a,0x4e,0x56,0x05,0x91,0x26, - 0x50,0xdb,0xab,0x56,0xfa,0x54,0x59,0xeb,0xe0,0x1b,0x14,0x3c,0xaf,0xcc,0x01,0x80, - 0xc8,0x41,0xbf,0x3b,0x9f,0x97,0x4e,0x92,0xb9,0x27,0xe9,0x0f,0x97,0xf7,0x31,0x19, - 0x76,0x85,0xfe,0x1a,0xa9,0xf2,0x8e,0x16,0x7f,0x1a,0xe0,0x55,0x56,0x03,0x3c,0x42, - 0x0d,0x2b,0x1f,0x14,0x0d,0xb2,0xd7,0x30,0x64,0x2e,0x13,0xee,0xf2,0x56,0x09,0x8c, - 0x33,0x65,0x88,0x1a,0x50,0x74,0x00,0x9a,0x63,0xfa,0x70,0x5b,0x02,0xaa,0xb2,0xd7, - 0xbc,0x6c,0x27,0xc3,0x3c,0xd2,0xf1,0x60,0x65,0xcb,0x92,0x2e,0x82,0x34,0x61,0x80, - 0x5d,0xa7,0x61,0x2e,0xb7,0x65,0x60,0x25,0xe6,0x33,0x52,0x63,0x3c,0xf1,0x3e,0x0e, - 0x94,0xa8,0x23,0xf1,0x48,0x7c,0x79,0x60,0x59,0xb0,0xf2,0x6a,0x1a,0xa7,0x63,0x47, - 0x3f,0xbe,0x90,0xb9,0x36,0xcc,0x57,0xea,0x8e,0xe7,0x7a,0x2c,0x6a,0x76,0x79,0x7e, - 0xbb,0x45,0x65,0x19,0x18,0xf7,0x7f,0xf6,0xe8,0xf7,0x81,0xfe,0x84,0x5c,0x11,0xe9, - 0xf2,0x24,0x82,0xef,0xb5,0xab,0x50,0x1e,0xb8,0x6a,0xb4,0x4c,0x45,0xae,0xe4,0x91, - 0x35,0x04,0x55,0xcf,0xc8,0x83,0xd4,0x24,0xf8,0x58,0x14,0xd5,0xda,0x47,0x56,0xf1, - 0xbb,0x40,0xff,0xd1,0x8f,0xdc,0x45,0x6e,0x76,0x0c,0x0a,0x30,0xbd,0x3c,0x79,0x89, - 0x27,0xed,0x9b,0x3d,0x0b,0x7c,0x09,0x79,0x5f,0x8f,0x39,0xdf,0xc6,0x9c,0xd0,0x0e, - 0x98,0xfb,0xf7,0x7d,0x8f,0x20,0x7f,0x40,0x69,0x37,0x0f,0x0e,0xac,0x32,0x25,0xfb, - 0xab,0x8e,0x13,0xa9,0xd6,0x48,0x5b,0xb1,0x4a,0x57,0x00,0x50,0x6b,0xda,0x6a,0x06, - 0x63,0x3d,0x60,0x19,0x92,0x6b,0x46,0x9a,0xa4,0x6d,0xbb,0x17,0xb4,0x5f,0x40,0xaa, - 0x25,0x98,0x17,0xea,0x81,0xdc,0x69,0xe8,0xaf,0xb7,0xc7,0x44,0x07,0x34,0xb0,0x18, - 0xff,0xe2,0x32,0xfb,0x6e,0x19,0x63,0x7c,0x20,0xd9,0xe8,0x47,0xbb,0x0c,0x46,0xb1, - 0xb0,0xe9,0x45,0xbf,0xaa,0x2d,0xa6,0xa1,0x8b,0xcf,0xca,0x91,0xd1,0xe8,0x98,0x77, - 0x0d,0x3d,0xfa,0xa1,0xb9,0x17,0x3d,0xfb,0x37,0xed,0x42,0xe9,0x30,0xa6,0xd2,0xb8, - 0x2b,0x34,0xf4,0xe8,0x01,0xcc,0x2f,0xf8,0x8b,0x55,0xf4,0x4b,0xff,0xa6,0x55,0xac, - 0x87,0x64,0x8b,0x40,0xf1,0x6f,0x1b,0x0d,0x42,0xd9,0x28,0xff,0xe2,0x37,0xdc,0x2c, - 0xff,0x2a,0xd6,0xc7,0xe0,0x0a,0xfc,0x8a,0x7f,0xdb,0x42,0xa6,0x7f,0x1a,0x72,0xe6, - 0xc2,0x62,0x59,0x72,0xab,0x0f,0x6c,0xf7,0x36,0x14,0x84,0x3f,0xd0,0xd3,0x68,0x99, - 0xb3,0x97,0xd5,0xa9,0x72,0x6b,0x13,0xd5,0x6d,0xeb,0x5e,0xe9,0x7d,0x35,0x55,0x29, - 0xe5,0xf7,0xc0,0xf1,0x44,0x1a,0x23,0xa1,0xad,0x74,0x8d,0xa0,0xcc,0x8e,0x47,0x93, - 0x69,0xc1,0x95,0x4c,0x9e,0xb9,0x43,0xf1,0xa9,0x81,0x53,0x7e,0x88,0x12,0x1b,0x0b, - 0x19,0x02,0x90,0xfb,0x73,0x5d,0x0b,0xb5,0x0d,0x4d,0x6d,0x54,0x1e,0x8b,0xeb,0x37, - 0x7a,0xb9,0xee,0xd8,0x15,0x98,0xee,0x74,0x69,0x7e,0xb4,0x8a,0x6a,0xa7,0x35,0x7e, - 0x25,0xe2,0x2a,0xdd,0x9b,0x06,0x94,0x05,0x33,0x6e,0x13,0x17,0x75,0x9d,0x2f,0xd0, - 0x6b,0x10,0x11,0x21,0xf8,0x10,0xfe,0x6d,0x50,0x43,0x92,0xb2,0x2c,0xfe,0x61,0x2d, - 0xb7,0x42,0x5d,0xff,0xa6,0xa2,0xae,0x7f,0x73,0x77,0x5d,0x22,0x45,0xb7,0x2e,0xee, - 0x25,0x2a,0x1a,0xd5,0x00,0xf6,0xd6,0x00,0x28,0x36,0xae,0x01,0x00,0x3d,0xdf,0x0d, - 0x00,0x29,0xbb,0xd8,0x79,0x7c,0x67,0x61,0xb7,0xa6,0x26,0xaf,0x81,0x62,0x5d,0x7e, - 0xbb,0x59,0xed,0x32,0xda,0xf8,0xed,0xdd,0xb5,0x71,0x3d,0x15,0xeb,0xe2,0xbb,0x9a, - 0xe2,0xb4,0xde,0xdc,0xf2,0x4d,0xb9,0x0a,0x35,0x7d,0xd6,0x55,0x85,0x15,0xe8,0xd6, - 0x64,0x85,0xf7,0xc7,0x0f,0xaf,0x8f,0x93,0xf9,0x02,0x94,0x9a,0x38,0x6f,0x5a,0xdb, - 0x8a,0x43,0x8f,0xb7,0x11,0x6d,0x78,0xa8,0xdb,0x1d,0xa5,0xa9,0xbf,0xf2,0xc2,0x8c, - 0xfe,0x42,0x29,0x58,0xd2,0x2d,0x54,0xf3,0xe8,0x97,0xdc,0xa7,0x70,0x59,0x9f,0xdd, - 0x0b,0x28,0x53,0x1c,0x2e,0x56,0x2b,0x6f,0x93,0x54,0xb1,0xce,0xba,0x1d,0xb8,0xfe, - 0xde,0x5e,0xcb,0x65,0x21,0x66,0x2f,0xce,0x96,0x4d,0x05,0x4f,0x92,0xd9,0x1a,0x42, - 0xfb,0x84,0x7b,0xc9,0xf5,0xbe,0xd5,0xf5,0x24,0x13,0x49,0xe2,0x97,0xe8,0xc8,0xb0, - 0x39,0xc8,0x24,0x36,0xbd,0x34,0x3b,0x1e,0x13,0xad,0x63,0x48,0xf3,0xd2,0x86,0x22, - 0x75,0x28,0x79,0x71,0xa5,0xab,0x1c,0x2a,0x6e,0x45,0x09,0x7c,0x5d,0x36,0x47,0xdd, - 0x43,0x85,0xe1,0xb0,0xdb,0x90,0xa6,0xd5,0xad,0x32,0x58,0xd5,0x0d,0x3f,0xae,0x75, - 0xc8,0x6f,0xff,0x36,0xff,0x71,0xcc,0x4d,0x25,0xff,0x25,0x26,0xe5,0xce,0xcf,0xf9, - 0x3a,0x9d,0x4c,0xe7,0x5b,0x50,0x5a,0x19,0x12,0x25,0xbe,0x6c,0x51,0x55,0x8f,0x42, - 0x9e,0xd0,0x31,0x20,0xd3,0x7d,0xc0,0x0a,0x45,0x8b,0x91,0xf4,0x99,0x96,0xf1,0xf0, - 0xe7,0x77,0xe8,0x7d,0xe5,0x36,0x80,0xcc,0xf3,0x3a,0xe8,0xa4,0x5d,0x5a,0xd0,0x29, - 0xb3,0xdc,0x9a,0x06,0xcc,0x21,0x7c,0xbb,0x05,0xac,0x65,0x88,0x0a,0x9f,0x0a,0x9a, - 0x21,0x2b,0xb4,0xcf,0x44,0xa3,0xa1,0x89,0x7a,0x60,0x39,0xc7,0x9f,0x61,0x50,0x43, - 0x72,0xad,0x7c,0x9c,0x7a,0xdb,0xe0,0xaf,0x7f,0xf9,0xbf,0x19,0xe7,0x94,0xb0,0xeb, - 0x35,0x2c,0x73,0x26,0xc4,0xfc,0x85,0x13,0x0a,0xc6,0x75,0x32,0xaa,0xa1,0x75,0xa8, - 0x43,0x78,0x1a,0x66,0xf3,0x8f,0x6c,0xb5,0x35,0x7e,0xa4,0x17,0xef,0xdf,0xca,0x5e, - 0xbf,0x01,0x6b,0x88,0xcc,0xd5,0xb2,0x29,0x24,0x67,0x1b,0x93,0xeb,0x7d,0xc5,0x7c, - 0x43,0x35,0x83,0x2b,0x7e,0xae,0xe8,0x08,0xf9,0x70,0x2b,0x5b,0x37,0x5b,0x3d,0x84, - 0x5a,0xad,0xef,0xd2,0x8f,0xb5,0x2a,0x6a,0x59,0xe9,0x6e,0x3b,0xfc,0xaa,0xda,0x29, - 0xf1,0x7b,0x3a,0x26,0x8c,0x73,0x02,0xc8,0x8f,0xa5,0x00,0x0d,0x43,0x89,0x00,0x5b, - 0x1d,0xaf,0x32,0x07,0xbe,0xc0,0x59,0xb1,0xde,0xb7,0xa0,0xec,0x59,0xa9,0x73,0xa7, - 0x41,0x47,0xa5,0x95,0x44,0x27,0x96,0xb4,0xfe,0xb2,0x04,0xfd,0xeb,0x78,0xc4,0x4c, - 0x19,0x91,0xec,0x43,0x8d,0x02,0x50,0xcd,0xd0,0xd9,0x10,0xa1,0x61,0xea,0x59,0x20, - 0xe5,0x14,0xbf,0xe7,0xa8,0x01,0x1c,0x1a,0xf6,0x5a,0x4f,0xd1,0x35,0x25,0x81,0x33, - 0x33,0xa3,0x39,0xbb,0x76,0x77,0xa0,0xf1,0xa9,0xbc,0x1b,0xdc,0x8d,0x75,0x7e,0x8f, - 0x82,0x77,0xc3,0x95,0x11,0xb7,0x4e,0x38,0xc7,0x26,0x2c,0xe3,0x0b,0xc9,0x50,0x5b, - 0xa9,0x8e,0x89,0x5a,0xa2,0x3b,0x23,0x05,0x68,0xbe,0x15,0x2b,0x70,0x64,0xbe,0xea, - 0xeb,0xdd,0x06,0x6d,0x45,0x1f,0x29,0x8c,0xae,0xa6,0x8f,0xb8,0x50,0xac,0x60,0xb6, - 0x0d,0xe0,0x93,0x81,0xac,0x3b,0xff,0x35,0x66,0xf0,0x55,0x85,0xc5,0x5b,0xe9,0x2a, - 0x2c,0x6c,0x19,0x1b,0x77,0x93,0xfa,0x6c,0xbb,0x3c,0x2b,0xae,0x5a,0x96,0xde,0xe8, - 0xa2,0x5f,0xd4,0x60,0x1c,0x7b,0x48,0x58,0xbf,0x42,0x5a,0x6b,0x8b,0xde,0x5e,0x77, - 0x53,0x84,0xab,0x8c,0x1d,0x5f,0x4c,0x15,0x1c,0xc8,0x85,0x76,0x4b,0x3a,0x6f,0x36, - 0xf8,0x28,0x0a,0x07,0x15,0xa0,0x59,0xd0,0xb6,0x0e,0x85,0x20,0x5d,0x5b,0x21,0x90, - 0x79,0xa2,0xbd,0x45,0xcf,0x40,0x8d,0x71,0xf6,0xba,0x09,0x81,0xb8,0x25,0xd1,0xc4, - 0x05,0xda,0xae,0xf4,0xbd,0x6c,0x53,0x97,0x91,0xa5,0x15,0x18,0xd9,0x7a,0xff,0xe7, - 0xd7,0x78,0x40,0xd1,0x57,0xc6,0x1c,0xcf,0x63,0xaf,0x78,0xd3,0x5a,0x75,0x35,0x26, - 0x1f,0xae,0x6e,0xc6,0x06,0x3b,0xcd,0x36,0x5b,0xd7,0xd6,0xce,0x11,0xff,0x75,0x96, - 0x17,0xbe,0xc4,0x2b,0xa8,0x0f,0x28,0xe7,0x97,0xba,0x85,0x5a,0xfd,0x00,0xfe,0x56, - 0x7d,0x99,0x32,0xb9,0x04,0xdd,0x0b,0x95,0x65,0xe8,0x2a,0x3a,0xcc,0xe6,0xc9,0x78, - 0x19,0x71,0x60,0x2b,0xef,0x01,0x78,0xdf,0xc9,0xa4,0xb3,0x8c,0xf6,0x01,0x4f,0x27, - 0x33,0x4e,0x20,0xc7,0x8c,0xf2,0x6b,0xea,0xc8,0x5d,0x3f,0x4d,0x31,0x44,0x1a,0xa1, - 0xa9,0xa3,0x42,0x25,0xdf,0x68,0xb3,0x14,0x57,0x2d,0xd3,0x13,0xab,0xe4,0xd0,0x98, - 0x30,0x13,0x1e,0x16,0x61,0x90,0xe9,0x60,0x58,0x82,0x0e,0x2d,0x0f,0x01,0xf1,0x73, - 0x8e,0x45,0xbe,0xf6,0x65,0xba,0x53,0x05,0x48,0x0e,0x03,0x41,0xc1,0x30,0x82,0x08, - 0x5d,0x0c,0xb4,0x4f,0x96,0x61,0x66,0x9b,0x18,0x6f,0x8e,0xf1,0xf9,0x34,0x31,0x65, - 0x80,0x7c,0xfe,0xfe,0x1f,0x31,0x18,0xf9,0x3a,0x56,0x61,0x09,0xe4,0x5a,0x55,0x3b, - 0x77,0x08,0xa9,0x49,0x99,0xf9,0x70,0xd5,0xce,0x68,0x1f,0x16,0xc4,0x40,0x3c,0xc2, - 0x5e,0x85,0x4a,0xbf,0x80,0x0e,0x24,0x6d,0x99,0xf1,0x53,0x96,0x23,0x17,0xa6,0x1c, - 0x35,0x67,0x89,0x5c,0x64,0x2d,0x8a,0x12,0xe7,0xfd,0x38,0x95,0x26,0x41,0x50,0xec, - 0x17,0xc7,0xc7,0x20,0xad,0x67,0x3a,0x2b,0x5c,0x87,0x52,0x15,0x72,0xfd,0x18,0x16, - 0x86,0xfd,0x9e,0x77,0xc2,0x3b,0x08,0x8e,0xce,0xc2,0x7a,0xe2,0x78,0x49,0xfb,0x81, - 0x43,0xa4,0x9e,0x3c,0x29,0x1d,0x46,0x16,0xb4,0x3f,0x72,0x25,0x53,0xcb,0xfa,0xb1, - 0x1f,0xad,0x32,0x94,0x72,0x38,0x6f,0x48,0x0e,0x18,0x28,0x03,0xc0,0x30,0x3f,0x20, - 0x3b,0x85,0x75,0xb4,0x39,0x7e,0xa5,0x98,0x64,0xca,0xe8,0xb7,0x48,0xb0,0x48,0xc6, - 0x8e,0x58,0xde,0x06,0x42,0xf6,0x15,0xcb,0xfc,0xb4,0x80,0x58,0x0a,0xdd,0x02,0xd4, - 0x7a,0xf7,0xee,0x35,0x96,0x98,0x41,0x36,0x4f,0xc3,0x51,0x0e,0xea,0xd7,0x3d,0x0a, - 0x3e,0x17,0x47,0x80,0xa0,0x22,0x31,0x1c,0x50,0x28,0xbe,0x49,0x0e,0x8e,0x71,0x45, - 0x7f,0xcb,0x66,0xc0,0x1d,0x46,0x82,0x1c,0xe9,0xab,0x3f,0xfd,0xf4,0xe2,0xe4,0xe5, - 0xd1,0x8f,0x6f,0xce,0x31,0x7c,0xf8,0xd3,0xa7,0x7d,0x8c,0xc2,0xdb,0xc3,0xf0,0xb5, - 0x4f,0xf0,0x07,0xaf,0x33,0xe8,0xf2,0x03,0xfc,0x6d,0xe3,0x65,0x59,0xf4,0xb4,0x47, - 0x4f,0xbd,0x7d,0x7c,0xbc,0x38,0x90,0xa0,0xde,0xfc,0x78,0xfe,0xd3,0xe9,0xfb,0xd7, - 0xef,0x08,0xd2,0xce,0x8e,0x46,0x26,0xc7,0x0f,0xaa,0xe8,0x64,0x13,0x9b,0x4c,0xfb, - 0x05,0xc0,0xfb,0xce,0x54,0x38,0xb2,0x74,0x6b,0xfd,0xe7,0x45,0x2d,0xb3,0x7e,0x67, - 0xa2,0x96,0x75,0x0f,0x54,0xa0,0xf2,0x1d,0x3d,0xf8,0xed,0xf1,0xcc,0xdc,0x03,0x13, - 0xcf,0xac,0x7a,0xf0,0x52,0x85,0x30,0xaf,0xef,0xc1,0xef,0x10,0xe9,0xcc,0x3d,0xc0, - 0x10,0x51,0xb7,0x07,0x98,0xdb,0xa2,0xb2,0x07,0x2a,0x88,0x94,0x7b,0x30,0x95,0xc5, - 0xe2,0x81,0xe8,0x6b,0x84,0x62,0x09,0x17,0xa1,0xaa,0xce,0x7a,0x60,0x56,0x7c,0xea, - 0x8e,0x02,0x86,0xb1,0xb5,0x6e,0xcf,0x8e,0x38,0xf2,0xb6,0x0c,0xcc,0x57,0x1f,0xec, - 0xa0,0x5c,0xcc,0x2c,0xa9,0x49,0x4f,0x3a,0x31,0x80,0xf4,0xd0,0x8f,0x71,0xf8,0xd4, - 0x04,0xe0,0x76,0xad,0x00,0x5c,0x40,0xa4,0x7b,0x86,0x00,0xb5,0x3d,0x0b,0xc0,0xab, - 0x5f,0x2b,0x00,0x1c,0x1f,0x9d,0x9e,0x29,0x8f,0xb2,0x86,0xa4,0x5e,0xfa,0x37,0x05, - 0x90,0xa6,0x34,0xc2,0x96,0xc0,0xf1,0x25,0x40,0x3e,0xf2,0x70,0xeb,0x8d,0x84,0xa3, - 0x15,0xb9,0x4c,0x0a,0x06,0x9e,0xdb,0x6c,0x52,0x62,0x7c,0xd6,0x03,0xb8,0xde,0x27, - 0xdb,0x91,0x7d,0x01,0x10,0xac,0x45,0xfc,0x89,0x4a,0x8b,0x7f,0xb0,0xdf,0x49,0x9f, - 0x11,0xb9,0x3e,0x1d,0x1f,0xb9,0x0d,0x87,0x2d,0x1f,0xf6,0x42,0xeb,0xf1,0x10,0xb0, - 0xb6,0xd8,0x69,0x69,0x8f,0x34,0x47,0x92,0xdc,0xb3,0x3c,0xe5,0x5d,0xed,0x1e,0xef, - 0xb5,0xa5,0x17,0xbc,0x27,0x7d,0x3a,0xd2,0x09,0x8e,0x19,0x0d,0x8c,0x03,0x1c,0x4f, - 0x5b,0xcb,0x4d,0x40,0x9e,0x4f,0xd4,0x05,0x5d,0xc7,0xf5,0x2d,0x5d,0x84,0xa4,0x91, - 0xa1,0xa3,0xed,0x08,0x1d,0x20,0x06,0xb1,0xc5,0x02,0x4e,0x48,0x56,0x02,0x87,0x11, - 0x9e,0xe7,0x95,0x91,0xd7,0xc6,0xd7,0x58,0x13,0xe7,0xe2,0xf3,0x6d,0x8b,0x1d,0xdf, - 0x58,0x87,0x27,0x05,0x6a,0xca,0x99,0x6e,0x9a,0x97,0x74,0x9d,0x16,0x3f,0xf8,0x37, - 0x15,0x25,0xfc,0x1b,0xd2,0x6d,0x50,0x2b,0xb3,0x20,0x3d,0xb5,0x2a,0xb5,0xc4,0x27, - 0xf3,0xa5,0x6d,0x7d,0xc0,0x49,0xfb,0x64,0x1e,0xdb,0x56,0x57,0x2e,0x8a,0x30,0xa1, - 0xed,0x8e,0xdd,0xd5,0x27,0x14,0xcb,0xec,0xf4,0xac,0x92,0xfe,0xac,0x2a,0x0f,0xb0, - 0x8a,0x1e,0x31,0xcd,0x9b,0x1a,0x4f,0xb7,0xd7,0x34,0x2f,0xd5,0x88,0x69,0x3e,0x2b, - 0x4a,0x14,0x47,0xcc,0xe5,0x3a,0x36,0xd8,0x27,0xc8,0x66,0xfa,0x2d,0x17,0x8e,0xbd, - 0xd2,0xac,0xb2,0x0f,0xb8,0xac,0xee,0x18,0xd3,0x4b,0xb1,0x5d,0x7e,0xab,0xba,0xc6, - 0x54,0x54,0x55,0xa6,0xd8,0x39,0x59,0xb2,0xe3,0xc0,0xa6,0xee,0xed,0xb5,0x0a,0xb0, - 0x4a,0xfd,0x93,0xa5,0x1f,0x70,0xe9,0x03,0xf6,0x04,0xbe,0x4c,0x96,0x29,0xef,0x4c, - 0x81,0x5e,0x8f,0xbf,0x71,0xb1,0xc0,0x6f,0x54,0xdb,0x28,0x4d,0xbc,0xbc,0x9a,0x86, - 0x02,0x3d,0x07,0x52,0x7b,0x03,0xb5,0x8d,0x0e,0xe2,0xd1,0xd9,0xd9,0xd0,0x63,0x48, - 0x47,0x14,0x29,0x87,0xc9,0xba,0xc3,0x69,0x8c,0xa6,0x0c,0x1f,0xab,0x0a,0xf8,0xb2, - 0x0a,0x54,0x55,0x82,0xb1,0xba,0x70,0x02,0x33,0xf9,0x62,0x66,0x17,0xce,0x68,0x4c, - 0xa9,0xc5,0x6f,0x16,0x11,0xba,0xdd,0x15,0xda,0x08,0xf4,0x21,0x2f,0x09,0x8d,0x4b, - 0xf6,0x58,0x1f,0x3a,0x0f,0x56,0x74,0x28,0xbd,0x26,0x6b,0xc6,0x3a,0x94,0xd0,0xf5, - 0xec,0x63,0x09,0xbb,0x9a,0x85,0xe9,0xc2,0xc4,0xca,0xe4,0x0e,0x85,0xc6,0x33,0xdb, - 0x49,0xdf,0x7e,0x4b,0x5c,0x39,0x99,0x08,0xeb,0x25,0x87,0x99,0x0e,0x71,0x13,0xbe, - 0xd1,0xb2,0x3f,0x98,0xc0,0x18,0x0d,0x06,0xd6,0x3f,0x02,0x69,0xde,0x2f,0xb8,0xbf, - 0xe5,0x37,0x6a,0x5a,0x3d,0xa8,0x60,0xfd,0x27,0x78,0x38,0x42,0xbf,0xb5,0xa0,0x4a, - 0x2e,0x87,0x5f,0x6a,0x58,0x09,0x6f,0x58,0x21,0x4b,0xb0,0xb9,0x48,0x06,0xca,0x3e, - 0xa1,0xcd,0xed,0x04,0x32,0x0e,0xe8,0x1b,0xfc,0xe1,0x2d,0xa3,0x96,0x78,0x66,0x1e, - 0x04,0x06,0xce,0x1d,0x38,0x8c,0x88,0xb6,0xb9,0xe8,0x1d,0x86,0x09,0x35,0x23,0xb0, - 0xa5,0x42,0x0e,0xb2,0x0a,0xa1,0xcf,0xbb,0xf0,0xe7,0xc1,0x03,0xee,0xb7,0xf4,0xda, - 0xbb,0x1c,0x8e,0x7b,0xf1,0x29,0xbc,0xc0,0x6d,0xa8,0x56,0x99,0x6b,0xd3,0x6e,0xad, - 0xdd,0x29,0x7c,0x43,0x08,0x6a,0x94,0xd2,0xf9,0x4a,0xef,0x98,0xb5,0x85,0x6b,0x57, - 0xd4,0xaf,0x5b,0xee,0x6e,0x2e,0x58,0x21,0x63,0x15,0xd1,0xf7,0x36,0x2b,0xd4,0x71, - 0xbe,0x51,0xc5,0x9d,0x1d,0xae,0xe6,0x6c,0xed,0xda,0x75,0xf4,0x07,0xb9,0x55,0xa7, - 0xf6,0x89,0x2d,0xd2,0x43,0xad,0x4d,0xd3,0x1e,0x28,0x30,0x9a,0xfa,0x6c,0x30,0x54, - 0xad,0xa5,0x76,0x95,0x5b,0x12,0x1a,0xaf,0x49,0xfa,0xa9,0xd8,0xbc,0xac,0x30,0xf7, - 0xe3,0xa5,0x1f,0x9d,0xd0,0x51,0xd6,0x67,0x94,0xa4,0x5c,0x3f,0x0f,0x4a,0x05,0x30, - 0xbc,0xf8,0x33,0x6d,0x8e,0xb2,0xfc,0xb1,0xb4,0x7d,0x22,0x5a,0xa0,0x39,0x5c,0xe5, - 0x7f,0x3f,0x1a,0xbe,0x39,0xcb,0x06,0x53,0x45,0xb6,0x17,0x9f,0x0b,0x6b,0x8b,0x25, - 0x13,0xfd,0xd2,0xe2,0xa3,0x4b,0xbd,0xaa,0x0b,0xa7,0xdb,0x96,0xea,0x7d,0xdd,0xd1, - 0x36,0x9d,0x34,0x1c,0xa8,0x7f,0xdd,0x21,0x27,0x7b,0x73,0x89,0xcf,0xbf,0xb9,0xe7, - 0x9b,0x18,0xc2,0xa5,0xcd,0x8f,0x63,0x60,0xdf,0x3d,0x59,0x13,0x68,0x3a,0x49,0x9b, - 0x4b,0xf1,0x9d,0x88,0x55,0x0d,0xd9,0xc3,0x4b,0x01,0xf6,0x2f,0x15,0xd5,0xe1,0x9b, - 0x77,0x9f,0xa9,0x23,0x98,0x19,0xb4,0x41,0x3f,0x4e,0x5f,0x03,0x5c,0x83,0x82,0x3b, - 0xce,0xd8,0x61,0x04,0xec,0x72,0x18,0x8e,0x38,0xec,0x18,0x75,0xc9,0x15,0x88,0x64, - 0x60,0xcd,0x4d,0xd2,0xc9,0x41,0x56,0xdd,0xe0,0x66,0x06,0x5e,0xbc,0x93,0x00,0x1b, - 0x47,0x01,0xc1,0x87,0x3f,0xe8,0x90,0xb0,0x62,0xe5,0x37,0x99,0x02,0x46,0x37,0x13, - 0x01,0x2f,0xfe,0xd4,0x6d,0xe3,0x71,0x21,0x72,0xe7,0x66,0x33,0x74,0x2d,0x0c,0xc3, - 0x4c,0x46,0xcd,0xa6,0x81,0x8a,0x8d,0xe4,0x78,0xea,0x78,0x25,0x96,0x9e,0x85,0xb7, - 0xcf,0xd0,0x07,0x8e,0x3f,0x5c,0xa1,0xbe,0xcb,0x76,0x09,0xd9,0x03,0x64,0x09,0x90, - 0x0d,0x00,0x24,0x7e,0xc8,0xc4,0x6c,0x63,0x7c,0x88,0x22,0x10,0xfb,0x0b,0xea,0xed, - 0x0e,0xa0,0xa1,0xd9,0xc3,0x08,0xa7,0x96,0xf3,0x2b,0x87,0x7f,0x01,0x1e,0x48,0xc4, - 0x9d,0xd2,0x7b,0xfa,0xd6,0xc7,0x6f,0xea,0x29,0x77,0xc0,0xaf,0x0c,0xf8,0x2a,0xd0, - 0xe6,0x17,0x0c,0xe0,0xc1,0x1d,0x3d,0x58,0xad,0xe9,0xc1,0xca,0xee,0x01,0x82,0xeb, - 0x71,0x37,0x90,0xfd,0x46,0x09,0xe3,0x66,0x86,0x7c,0x58,0xbe,0xaf,0xe2,0xcd,0x7d, - 0xc5,0x9c,0x95,0xd7,0x8d,0xc7,0x30,0x0f,0x51,0x28,0x34,0x01,0xca,0x03,0x81,0xf1, - 0xf7,0xdb,0xa2,0x6f,0x07,0x19,0x0e,0x6f,0x9a,0x50,0xa2,0x05,0xf5,0x61,0x61,0x51, - 0x53,0x73,0xbc,0xd1,0x20,0x00,0x55,0x99,0x5b,0x9c,0xab,0x63,0x95,0xce,0xb9,0x2e, - 0xad,0xc2,0xac,0x9a,0x0e,0xe8,0x96,0x26,0x63,0xb3,0x04,0x6d,0x21,0xc6,0x39,0xe8, - 0x78,0x41,0xb3,0xaf,0x52,0xae,0xe7,0xe2,0x99,0x62,0xb3,0xb6,0xc1,0x58,0x07,0xc8, - 0x46,0x90,0xbb,0x00,0xf1,0x3d,0x81,0xfb,0x23,0xfa,0x94,0x2b,0x61,0x5a,0xc2,0xfb, - 0x99,0xc5,0x4f,0xcc,0x6b,0xaa,0x30,0xa8,0xec,0x5b,0xb1,0xb1,0xcb,0xe0,0xcd,0x32, - 0xb7,0x4f,0xd5,0x32,0x92,0x59,0x84,0xd7,0xcb,0x4d,0xe3,0x5f,0x70,0xe6,0x08,0xf5, - 0x01,0x12,0xa2,0x52,0x5e,0x94,0x98,0x5d,0x88,0xec,0xc1,0x72,0x4e,0x20,0x9f,0x30, - 0xe1,0x0e,0xbb,0xad,0x12,0xba,0x01,0x62,0x41,0x00,0xa0,0x5b,0x35,0xf8,0x3b,0xf6, - 0xf6,0x90,0x38,0x40,0x74,0x8e,0x26,0x18,0xa4,0x5c,0xd4,0x82,0x50,0x6d,0x02,0x24, - 0x60,0x01,0xbc,0x55,0x95,0x0e,0x80,0xe1,0x03,0x9f,0x8e,0x43,0xab,0xea,0xce,0x93, - 0x03,0xed,0x3b,0x8f,0x1f,0xa0,0x54,0xa5,0xa5,0xe8,0x67,0xf9,0x09,0x1d,0xf7,0xe1, - 0x4d,0x00,0xe2,0x80,0x73,0xde,0xbc,0xc2,0xbc,0xde,0x78,0x7f,0x49,0x87,0x2f,0x35, - 0x81,0x96,0xda,0xfa,0x78,0x1d,0xea,0x10,0x7f,0xfd,0x97,0x7f,0x65,0x89,0x4d,0x41, - 0x9c,0xc9,0x64,0xc2,0x7d,0xf6,0xaf,0x02,0x37,0xe0,0xda,0x50,0xdb,0x02,0x83,0xc2, - 0xb3,0x5c,0xfa,0xfd,0x9d,0x6d,0x0c,0x5d,0x8d,0xe6,0xdf,0x06,0x62,0x6d,0x61,0x34, - 0x89,0x6f,0x1d,0x79,0x26,0xc8,0x89,0x22,0x9b,0xd4,0x16,0x85,0x4d,0xd8,0x74,0x19, - 0xb2,0x4d,0xf9,0x16,0x85,0x3b,0xba,0xaf,0xe6,0xc0,0x96,0xe6,0xea,0xae,0x8a,0x02, - 0xf9,0x61,0xe2,0x75,0x3e,0x83,0x38,0x0d,0x92,0x39,0xc6,0x0b,0x8b,0xbf,0x6d,0xaf, - 0xe2,0x1f,0x90,0x5b,0x22,0x47,0x04,0xdc,0xd5,0xed,0xdc,0x84,0x63,0xed,0x65,0xc1, - 0xa1,0xc9,0x5b,0xf5,0x0e,0xc5,0x1f,0x9a,0x0d,0xba,0x4d,0xca,0x7c,0x1d,0xe5,0x28, - 0xa1,0x4c,0x21,0x84,0x44,0xbb,0x58,0x37,0x79,0xb3,0xd1,0x1f,0x9b,0x92,0x6f,0x99, - 0x56,0x07,0x62,0x17,0xd4,0x8d,0x74,0x20,0xf6,0xdb,0x02,0xaf,0x91,0x06,0x3d,0x64, - 0x08,0xef,0xba,0x8a,0x02,0x4f,0x3f,0xb2,0x30,0x38,0x7d,0xc5,0xcc,0x85,0xc3,0x7c, - 0xe9,0x88,0x67,0x1a,0xf8,0x30,0x6f,0x59,0x26,0x16,0x37,0xd6,0xcc,0xe2,0x21,0xd0, - 0x53,0xf8,0xde,0xb4,0xd9,0x15,0xdd,0xf3,0xa5,0xbb,0x8b,0x49,0xa3,0x79,0x7b,0x53, - 0x3a,0x8e,0xb2,0x0c,0x5b,0xc1,0x42,0xde,0x28,0x0a,0x61,0xd0,0x1f,0xd1,0x41,0xef, - 0x14,0xc0,0xe6,0x77,0xf9,0x58,0x0f,0xbf,0x1b,0x2f,0x52,0xe3,0x78,0xe6,0x08,0x86, - 0x53,0x60,0x52,0xd1,0x07,0xdc,0xc2,0x21,0xdb,0x8b,0x6e,0x65,0x35,0x88,0x50,0x4e, - 0x7f,0x5b,0xb5,0xc2,0x86,0xbf,0x43,0x50,0xad,0x42,0x61,0xed,0xfa,0x77,0x4b,0xbf, - 0xaa,0x2e,0x4d,0xe9,0xf9,0x75,0x03,0x04,0xf5,0x01,0xd8,0x17,0x37,0x8d,0xca,0x72, - 0x1a,0x36,0x01,0xb4,0x0a,0xc2,0xdc,0x79,0xb8,0x9c,0x52,0x3f,0xce,0x70,0xbb,0xbd, - 0x09,0x4d,0xb5,0x11,0xf9,0xf0,0x8f,0xfe,0x49,0x6d,0xd3,0xac,0x50,0x3b,0x1d,0xf1, - 0xd6,0x8b,0xe8,0xbf,0x74,0xdb,0x2a,0x4d,0x13,0xc1,0xc5,0x57,0x39,0xfd,0x77,0x48, - 0x2b,0x84,0xb1,0xf6,0xe2,0xe4,0xf8,0xe8,0x05,0x65,0xbf,0xb0,0x92,0x75,0x18,0x4f, - 0x08,0x70,0x7f,0xcb,0xfb,0xa6,0x48,0xe5,0xe6,0xfd,0x04,0x69,0x74,0xf6,0x2b,0x7b, - 0xf5,0xa0,0xbd,0x07,0xd8,0x03,0xd0,0x2c,0x2c,0x20,0xca,0xe3,0x83,0xa5,0x1c,0x28, - 0x98,0xdf,0x83,0x5b,0xd5,0x00,0x67,0xbf,0x32,0xc4,0x1b,0x02,0xa8,0x6a,0x9a,0x3a, - 0x2a,0x97,0x88,0xca,0xf5,0xa1,0x7a,0x0d,0x2d,0x36,0x6f,0x78,0xc8,0x08,0xf6,0xf4, - 0x63,0xcb,0x78,0x1f,0x57,0x0c,0x52,0x7a,0x1e,0x61,0xe8,0x0f,0x58,0xf1,0x31,0xb1, - 0x59,0xa8,0x01,0x9d,0xbe,0x52,0xe5,0xaf,0xb8,0xfc,0xca,0x74,0x01,0x0a,0x61,0x85, - 0xe6,0x8a,0x71,0x47,0x2d,0xbc,0x6a,0xf1,0x56,0xc6,0x6b,0xe0,0xcf,0x29,0x5d,0xbb, - 0x84,0xde,0x8b,0x8c,0x37,0x50,0xd4,0xb6,0x1b,0x18,0x79,0xb4,0x33,0xc3,0xe7,0x51, - 0x79,0xef,0x89,0xb4,0x5d,0x1c,0x51,0x5b,0x9d,0xbd,0xa1,0xe4,0x2e,0x98,0x87,0x06, - 0xe1,0x61,0x0c,0x85,0x3a,0xf2,0xe5,0xe4,0x1d,0x6a,0x64,0xa2,0x4f,0x09,0xa9,0xba, - 0x97,0x7a,0x3f,0xd5,0x3a,0x13,0x90,0x89,0x9d,0x1e,0x7c,0x7d,0x74,0xe9,0xc9,0x61, - 0x9c,0xbf,0x3e,0xfe,0x81,0x77,0x23,0x70,0x07,0xa2,0xb1,0xd7,0x6d,0xe0,0x9e,0x43, - 0x0f,0xb7,0x1c,0x1a,0xf0,0xdf,0x86,0xdc,0x8f,0x80,0xa7,0xbe,0x7c,0xda,0xeb,0x72, - 0x41,0x7c,0x02,0x8a,0xc1,0xb2,0x54,0xf8,0xb2,0x61,0xf6,0x2e,0x1a,0xfd,0xcb,0x86, - 0xd9,0xbb,0x68,0xec,0x5d,0x2a,0xa8,0x12,0x2e,0x3c,0x63,0x96,0x0a,0x6f,0x12,0x46, - 0x60,0xdc,0x36,0x9b,0x9f,0x66,0xbf,0x5e,0x10,0x22,0x67,0xbf,0x8a,0xa7,0xc2,0x99, - 0xc8,0x1e,0x26,0xe3,0x01,0x13,0x13,0xbe,0x3c,0x11,0x16,0xa5,0x7d,0x87,0xce,0xcd, - 0x87,0x7a,0xfa,0x5e,0x3c,0xff,0x09,0x53,0x1d,0xf1,0x50,0x40,0x21,0x6f,0x70,0x67, - 0x31,0x73,0x26,0x3c,0x74,0x7a,0x8f,0xe4,0x23,0x3d,0xed,0xec,0xc9,0xa7,0x3e,0x3d, - 0xee,0xed,0xf0,0x23,0xfe,0x7e,0x08,0xf5,0x2e,0x78,0xce,0xdc,0xbb,0x47,0x0b,0x87, - 0x98,0xf9,0x50,0xfd,0xf1,0xd9,0x99,0xb9,0x6e,0xb4,0x2d,0x8f,0xa8,0xd3,0xa5,0xa3, - 0x78,0x24,0x91,0xcf,0xb7,0xc3,0xfc,0xd1,0x2e,0x1f,0xb9,0xaa,0xf4,0x3d,0xa7,0x69, - 0x20,0x0f,0xbf,0x8f,0x92,0x54,0xe6,0xea,0xe1,0xbb,0x58,0xf5,0xb5,0x19,0x74,0x16, - 0x42,0x9d,0xf9,0xc4,0x2b,0x49,0x11,0x0a,0x66,0x00,0x48,0x89,0xc5,0x1f,0xd8,0x61, - 0x72,0x6a,0x8b,0x14,0x59,0x60,0x66,0xa8,0x85,0x77,0x6d,0xd1,0xda,0xa1,0x63,0x17, - 0x78,0x1d,0x2b,0x5f,0xa2,0xeb,0x59,0x92,0x14,0x7b,0xe5,0x30,0x5b,0x14,0x0c,0xc4, - 0xf5,0xe7,0x0b,0xf4,0x65,0x9d,0x21,0xd3,0x31,0x41,0x12,0x74,0xf2,0xc9,0xb0,0x51, - 0xd4,0x2d,0x9a,0x78,0x76,0xb3,0x4d,0x3b,0x2d,0x43,0xf2,0x19,0xa0,0xf5,0x41,0x92, - 0xe3,0x14,0xe8,0x2e,0x48,0xf3,0x15,0xeb,0xba,0x58,0x8c,0xcc,0x50,0x5d,0xd2,0xcb, - 0xd3,0x70,0xde,0xb4,0xc0,0x45,0xe4,0x11,0xba,0x6a,0x36,0xe8,0x6a,0x5d,0xdc,0xf2, - 0xfe,0x26,0x78,0xb4,0xb7,0xd7,0x0f,0x6c,0x7e,0x3f,0x87,0x22,0xdb,0xff,0xf3,0x9b, - 0x67,0xcd,0x4f,0xdd,0xce,0x63,0xbf,0x33,0xb9,0xf8,0xdc,0xbf,0x6d,0xd5,0x3f,0xfc, - 0x61,0x3b,0xf4,0x82,0x9b,0x60,0xd4,0xc4,0x83,0xa7,0x80,0xf7,0xc8,0x1f,0x05,0xcd, - 0xc6,0x37,0x08,0x5c,0x46,0x46,0xea,0xb6,0x3f,0x4c,0xd1,0xbb,0x37,0x07,0xb5,0xfb, - 0x9f,0xff,0xf0,0xd9,0x24,0x0a,0xa1,0xc4,0x12,0xbd,0xfd,0xd6,0x6d,0x5b,0x38,0xaf, - 0xfb,0xd5,0xaf,0x77,0xe4,0xeb,0x7f,0xc6,0xb8,0xb4,0xfe,0x0e,0x88,0xc4,0x47,0x40, - 0x67,0xbb,0xfb,0x8d,0x92,0x7b,0x49,0x5e,0x2a,0x4b,0xe3,0xa5,0xdf,0x34,0xe2,0xc9, - 0x70,0xf2,0x30,0x98,0x34,0xa4,0xc7,0x45,0xde,0x6c,0x4c,0x65,0xe8,0x37,0x97,0xd9, - 0x0d,0x26,0xc1,0xbe,0x2a,0x43,0x77,0x1a,0x53,0x09,0xf8,0x45,0xdf,0x7b,0xbb,0xf8, - 0x7f,0xf5,0x5d,0x6e,0x28,0x50,0x09,0x8e,0xba,0xc5,0x32,0xfb,0xc3,0xfd,0xbd,0x3d, - 0x5f,0x95,0x91,0x37,0x1e,0x73,0x5f,0xf0,0x37,0x95,0xf1,0xf7,0x1f,0x4f,0x1e,0x77, - 0x55,0x19,0xbe,0x01,0x99,0x8a,0xe0,0x4f,0x2a,0x31,0x7e,0x3c,0xee,0x8d,0x74,0x89, - 0x48,0x45,0xd0,0xc3,0x8f,0xa3,0x01,0x1d,0xc4,0x00,0x6a,0xf8,0x67,0xba,0xb6,0xfd, - 0x0f,0x9f,0x19,0xc5,0x84,0x2f,0xff,0xb6,0xf5,0xcf,0x06,0x68,0xb9,0xa8,0x49,0x28, - 0x52,0xd9,0x5a,0x69,0x22,0xed,0xc4,0x26,0x15,0xb3,0xf2,0x65,0x50,0x60,0xca,0x76, - 0x7f,0x3b,0x94,0xdd,0xb6,0xd8,0xb7,0xa0,0x98,0x11,0xc3,0x24,0xdd,0x35,0xe0,0xe2, - 0x3c,0x7e,0xd5,0x78,0x37,0x05,0xb2,0x76,0xb8,0x9b,0x02,0xa9,0x18,0xad,0xed,0xde, - 0x43,0xe6,0x26,0xa3,0x17,0x64,0xb4,0x05,0xa5,0xa8,0xe3,0x5b,0x4c,0x63,0xbc,0x7e, - 0x54,0xa5,0x3e,0x91,0x69,0xd6,0xdb,0xea,0x7e,0xe9,0x21,0xa6,0x62,0x40,0xc7,0x29, - 0x82,0x01,0x33,0x25,0x88,0xf0,0x86,0x55,0x76,0xf2,0xf8,0xfa,0x16,0x1d,0x4a,0x02, - 0xef,0xb9,0x76,0xf6,0x47,0x6a,0xaf,0x59,0xb7,0x81,0xa5,0x8f,0x25,0xf0,0x46,0x9e, - 0xde,0x0d,0x72,0x4e,0x4a,0xb8,0x3e,0xb7,0x80,0x8c,0x29,0x3e,0x11,0x4e,0xf9,0x05, - 0x40,0x32,0xe9,0x07,0x09,0x86,0x58,0x5c,0x53,0x99,0x5e,0x50,0x40,0xfe,0x54,0x9f, - 0x4d,0xe0,0x27,0xd4,0x69,0x15,0xf2,0x10,0x48,0x45,0x02,0xbe,0x58,0xc9,0x08,0xac, - 0x97,0x9c,0x91,0xe0,0x9e,0x93,0x24,0x07,0x2b,0x76,0xbd,0x1e,0x17,0x06,0x89,0xc7, - 0x05,0x2c,0x23,0x9b,0x8b,0x98,0xdd,0x20,0x2e,0x69,0x6d,0x1b,0x15,0x36,0x01,0x51, - 0x79,0xf4,0x73,0xa9,0x8c,0x59,0x8e,0x09,0x94,0xce,0x7c,0x3c,0x1e,0x38,0x24,0x7c, - 0xe4,0xfc,0x3e,0x5d,0x63,0xe0,0x73,0x81,0xc7,0x8f,0xf7,0x54,0x32,0xb8,0x9e,0x21, - 0x97,0xed,0xff,0xe1,0x75,0xff,0xb0,0x4d,0x14,0x83,0x4a,0xeb,0x25,0xe6,0xaa,0x90, - 0x07,0xce,0x2c,0x25,0x19,0x5a,0xac,0xb7,0xc8,0x50,0x35,0xc2,0x6d,0x9a,0xbf,0xf9, - 0x48,0x8f,0xb7,0xef,0xdf,0xbd,0x07,0x3a,0x69,0xd0,0x9d,0xa7,0xcb,0x90,0x6e,0x9a, - 0xa6,0x54,0xcf,0x6d,0x71,0xf6,0xf2,0x2d,0x3c,0x74,0x3e,0x04,0xd3,0x65,0x84,0x17, - 0xb7,0xbe,0x0d,0xe2,0x28,0x69,0xcb,0xb4,0x93,0x3e,0x50,0xbd,0x2e,0xdb,0x70,0x36, - 0xa9,0x61,0xe8,0x25,0xb3,0xe8,0x9c,0x63,0x8b,0x50,0x7e,0x1b,0x31,0x86,0xaa,0xbd, - 0xd6,0xb1,0x1f,0xa0,0x62,0xdf,0x16,0xaf,0xe8,0x1d,0xea,0xb4,0xa7,0xaf,0xe8,0xdd, - 0x50,0x1b,0x0c,0x64,0xa6,0x7f,0x00,0x0d,0xa4,0xc9,0x86,0xc2,0x47,0x28,0xdd,0xd2, - 0x5f,0x41,0x41,0x8b,0x48,0x01,0x00,0x00,0xe7,0x1e,0x89,0x28,0xe7,0x5b,0xb9,0x22, - 0xef,0xba,0xa1,0xa6,0xab,0xcb,0x25,0x14,0x01,0x89,0x38,0x31,0x66,0x4a,0x9e,0x82, - 0x22,0x62,0x20,0x93,0x0c,0x68,0x62,0x00,0x45,0x6d,0xdb,0x28,0x92,0xf4,0x37,0xd4, - 0xa2,0x3f,0x4a,0x7b,0xa9,0xa7,0x9d,0x58,0x72,0xcb,0xfe,0xaa,0xcd,0xf1,0x0c,0x17, - 0x98,0x28,0x49,0x29,0x86,0xee,0x3a,0x5e,0xb9,0xa6,0x19,0x28,0xff,0xa4,0xe0,0x3f, - 0xa0,0x5b,0xa9,0xf5,0xfa,0xc4,0x54,0x86,0x5d,0x5c,0xc1,0x98,0xdf,0xb0,0x67,0x1c, - 0x95,0xd4,0x85,0x61,0x30,0x0d,0xe3,0x53,0x80,0x81,0x31,0xbb,0xf4,0x06,0x2f,0x45, - 0x3a,0x4f,0x9a,0x80,0xfc,0xb6,0x58,0xa9,0x97,0xd8,0x53,0x7e,0x49,0x33,0x62,0x7d, - 0x61,0x1c,0x34,0x9d,0x88,0x5c,0xfa,0x80,0xc6,0xf6,0x11,0xde,0xc0,0x86,0x24,0x44, - 0x0c,0x52,0x06,0xab,0x6b,0xb4,0x60,0xce,0xd3,0x26,0x8d,0xb1,0x2d,0xed,0x37,0x30, - 0xc2,0xc9,0x5f,0xab,0xfd,0x6b,0x65,0x48,0x7c,0x91,0x5b,0xa3,0x88,0xad,0xd9,0xaf, - 0x36,0xba,0xc8,0x1e,0x70,0x71,0x75,0xe3,0xe2,0x0a,0xac,0x39,0x5a,0xa5,0x36,0xb2, - 0xd6,0x23,0xe4,0xa6,0x4d,0xf6,0x90,0x8b,0x10,0x7e,0x49,0x14,0x59,0x8d,0x90,0xca, - 0xc1,0x5a,0xb5,0x70,0xa7,0x7d,0x7f,0xcd,0x70,0xf1,0x86,0xe3,0x86,0x43,0x4c,0x04, - 0x48,0xf3,0x36,0xcb,0xc4,0x24,0x24,0x56,0x41,0x5e,0x37,0x1d,0x77,0x80,0xc5,0x63, - 0x8b,0xc2,0xcc,0x7a,0x0d,0xec,0xaa,0x75,0xa0,0x3f,0xae,0xa7,0x30,0x0b,0x22,0xcc, - 0x43,0x2d,0xb9,0x55,0x17,0x33,0xa8,0x96,0xf9,0x1d,0x54,0x22,0x9b,0x2c,0xf7,0xc3, - 0x74,0xe4,0x67,0x81,0x31,0x07,0xe0,0x13,0x9e,0x05,0x22,0x29,0xe7,0x26,0xbc,0x51, - 0x02,0x13,0xdf,0xaa,0x7d,0xe2,0xa7,0x66,0xa1,0x54,0xac,0x62,0xd4,0x7c,0x60,0x99, - 0xf7,0x76,0x5b,0x35,0x84,0x63,0xde,0x3a,0xab,0x09,0x68,0x0e,0x1b,0xf9,0xd4,0xbd, - 0x70,0x77,0xb0,0x86,0xd7,0x98,0x34,0xef,0xa3,0xe0,0x11,0xc8,0x3e,0xd4,0x6f,0x39, - 0xd8,0x85,0xaa,0xf6,0x1e,0x90,0x2d,0xe8,0xb6,0xc2,0x0b,0x13,0xae,0x5e,0x42,0x6d, - 0x08,0x06,0xe8,0xf0,0x9a,0x56,0x73,0x6d,0x99,0x26,0x1e,0x0c,0xeb,0xb5,0x0a,0x25, - 0xad,0x85,0x5e,0x3b,0x59,0x36,0x1e,0x4c,0xa1,0xea,0xef,0x23,0xcc,0x12,0x5f,0xc2, - 0x1e,0xa2,0xbd,0x69,0x32,0x11,0xc0,0x14,0x73,0xb6,0xdd,0xaa,0xc3,0x98,0xd2,0x85, - 0x1a,0x92,0x3a,0x6a,0xaf,0xfc,0x6b,0x8a,0x59,0xb0,0x35,0x29,0x07,0xf9,0x37,0xb8, - 0x09,0x86,0xec,0xc0,0x8a,0xe3,0x81,0x25,0xda,0x2b,0xbc,0x95,0xc1,0x22,0x1a,0xc7, - 0xe7,0xc9,0x42,0xa2,0x19,0xe0,0xa3,0x42,0x03,0xb8,0x79,0x9e,0xe4,0xd6,0x3b,0xd0, - 0x7c,0xec,0x1a,0x61,0x76,0x46,0x9e,0xf2,0x90,0x36,0x08,0xb3,0x20,0xb2,0x3f,0x32, - 0x25,0xe3,0x57,0x2a,0xf5,0x0c,0x88,0x0c,0x8d,0xc8,0x81,0x0c,0x75,0x50,0xa7,0x09, - 0xa5,0x00,0x81,0xf7,0x44,0x84,0x0e,0x7c,0x3f,0x5a,0xcc,0x7c,0x37,0x7e,0xe3,0x19, - 0x46,0xa3,0xec,0x22,0x14,0x05,0x16,0x88,0xb6,0x2f,0x28,0xb0,0xef,0x21,0xaf,0x9a, - 0x4a,0xfa,0x46,0xab,0xa7,0x49,0xf0,0x8a,0x93,0x41,0x92,0xf2,0x06,0xb7,0x0c,0x61, - 0xfc,0x84,0xa5,0x8e,0xa0,0x47,0x1c,0x7a,0x87,0xde,0x3a,0x70,0x5d,0xce,0xc0,0x4f, - 0x05,0xaa,0x50,0x02,0x50,0x75,0xb1,0xe7,0xed,0xa1,0xca,0xb5,0x11,0x4b,0x96,0x1d, - 0x29,0x32,0x65,0xd9,0xa1,0x35,0x1c,0xb9,0x1e,0x64,0xaf,0x1a,0x64,0x6f,0x1d,0xc8, - 0x0a,0x75,0x5b,0xb9,0x31,0xdf,0x40,0xfd,0x17,0x7e,0x36,0x6b,0x7e,0x42,0xe3,0xf9, - 0xa2,0xf5,0x5b,0x86,0x55,0xe8,0xda,0x17,0x0d,0xab,0x80,0x92,0x8d,0x86,0x55,0x1e, - 0xc3,0x85,0x9a,0x5c,0x0c,0xaa,0xc6,0x80,0x72,0x8e,0x07,0xa7,0x6b,0xa2,0x66,0x49, - 0x1a,0xfe,0x0a,0x4a,0x92,0x1f,0x71,0x6c,0x93,0x3f,0x4a,0x93,0x2c,0x93,0x89,0xad, - 0x6f,0xb4,0x9b,0x50,0xde,0xa7,0xe1,0x5f,0x05,0x29,0xe6,0xdc,0x52,0xd0,0x28,0x8f, - 0x24,0x56,0x7b,0x7e,0xf2,0xe6,0xfd,0xbb,0xef,0xcf,0x54,0x7e,0x1d,0xa8,0x0a,0x3a, - 0x7e,0x80,0x51,0xfe,0xb9,0xb1,0xbd,0x42,0xbc,0xb4,0x03,0x0c,0xad,0x45,0x18,0xc7, - 0x2a,0xa5,0x77,0xa0,0x40,0x0d,0x93,0x1c,0xaf,0xb4,0x0a,0xc6,0x60,0x4e,0x35,0xf1, - 0x6e,0x11,0x4a,0xb1,0x07,0x42,0x5f,0xc5,0x80,0x63,0x58,0xc0,0x16,0xac,0x57,0x7f, - 0x98,0xf0,0x61,0x27,0x19,0x22,0x9f,0x27,0x0b,0x4f,0xbc,0x20,0xc7,0xa5,0x9f,0x2b, - 0x68,0x94,0x4a,0xc4,0xbf,0xd6,0x71,0xea,0x58,0xfe,0xda,0x47,0x60,0xd8,0xf0,0x32, - 0x47,0x75,0x43,0xd9,0x7c,0xd0,0xd9,0x36,0x9a,0x74,0xa3,0x19,0x3b,0xd1,0x00,0x2f, - 0x43,0x44,0x68,0x6c,0x6f,0xbb,0x33,0xca,0xb4,0xf9,0x25,0x93,0x82,0x68,0x0b,0x8c, - 0x9f,0x91,0x6d,0x73,0x72,0x6a,0xbb,0xe6,0xca,0x8e,0x95,0x20,0x0e,0xf4,0x00,0x97, - 0x8b,0x15,0x34,0x21,0xd7,0x21,0xbd,0x44,0x3e,0x44,0xd0,0xf4,0x79,0xe1,0x4a,0x61, - 0x0d,0x8b,0xbd,0x66,0x45,0xf6,0x37,0x95,0x6e,0x37,0xb8,0x0d,0x0f,0xa4,0x14,0xad, - 0x2a,0x58,0x3e,0xf1,0x88,0xd2,0x47,0x47,0x74,0xf3,0x0a,0x22,0x06,0x50,0x50,0x4f, - 0x6b,0x34,0xf7,0xda,0xc1,0x00,0x53,0x2c,0x49,0x32,0x47,0xc3,0xd6,0x32,0x55,0xea, - 0x8d,0x23,0xcc,0x39,0xbc,0x22,0xa5,0xf1,0xd3,0x27,0xb5,0xf0,0xd0,0x8f,0xaa,0x56, - 0x1b,0xfd,0x96,0xab,0x47,0xbf,0xc7,0xdf,0x17,0xce,0x79,0x7f,0x87,0x41,0x8e,0xd0, - 0x3d,0xbf,0x83,0x73,0x30,0x5a,0xa9,0x5f,0x0f,0xe1,0x1f,0xfb,0x18,0xb8,0xe9,0xfd, - 0x66,0x55,0x6e,0xcd,0x41,0x4f,0x46,0x1a,0xd9,0xa3,0xe7,0xfe,0x94,0xe2,0x80,0x6d, - 0xbb,0xd7,0xfa,0xb0,0xc6,0xca,0xda,0x5c,0x7e,0xe6,0xfe,0x94,0x77,0xad,0xe0,0x07, - 0x1d,0x14,0x77,0xc4,0x4e,0xad,0x74,0x85,0xd2,0x72,0xab,0x07,0x75,0xd8,0xb2,0xf6, - 0x6d,0x89,0xdb,0x96,0xb5,0xff,0x63,0x57,0xcc,0x49,0xc6,0x16,0x2c,0x1c,0x29,0x6e, - 0x91,0xa8,0x7a,0xe5,0x8a,0xe5,0xc3,0xc0,0x20,0x69,0x31,0x18,0x5e,0x49,0xdd,0xd6, - 0xba,0xb2,0x24,0x36,0x01,0x75,0x8d,0xb6,0x25,0x46,0xad,0x1a,0xbf,0x2c,0x83,0x74, - 0x75,0x46,0xf7,0xcc,0xe2,0x31,0x2a,0x4f,0xde,0x4b,0x5a,0x3a,0x27,0xd7,0x78,0xde, - 0xb0,0x34,0xa7,0x07,0x05,0x29,0xde,0xf8,0x8f,0x7f,0x7f,0x4b,0x39,0x2e,0xd5,0xe9, - 0x46,0x34,0x8b,0xbf,0x8f,0x56,0x8b,0x59,0xb3,0xa2,0x11,0xbe,0xfa,0xa1,0xd1,0x6a, - 0xcb,0x53,0x66,0x3d,0x30,0x92,0x7a,0xfd,0xb6,0xa5,0x01,0xdc,0x6a,0x5f,0x03,0x70, - 0x3a,0x75,0x81,0xdf,0x14,0xe1,0xb5,0xc5,0x32,0xc3,0x0b,0x71,0x31,0xc1,0xfe,0x94, - 0x33,0x15,0x4d,0x92,0x04,0x0f,0xc3,0xd0,0xb5,0x2a,0xae,0x61,0xce,0x3d,0xe0,0xe6, - 0x54,0x63,0xa0,0xf1,0xcd,0xda,0xbc,0x79,0x60,0x13,0xd3,0x66,0xdb,0x8e,0x24,0x16, - 0xed,0x6d,0x47,0x8c,0xee,0xbc,0x96,0x9b,0x87,0x3a,0x87,0x94,0xb3,0x2d,0x29,0xbf, - 0x1e,0xa8,0xf7,0x7a,0x97,0x70,0x26,0x3f,0xd8,0x95,0xdc,0x0d,0xc7,0x6b,0x45,0x0b, - 0xee,0x67,0x0b,0x82,0xa1,0x95,0x5b,0x3d,0x12,0x24,0xed,0x51,0xdd,0x1e,0xb1,0x10, - 0xd3,0x0d,0xb7,0x22,0xa7,0x25,0x0f,0x04,0x62,0x4e,0x81,0x70,0x98,0x14,0x21,0x13, - 0x71,0x24,0x57,0xa3,0xe2,0x59,0x53,0x97,0x59,0x79,0xbb,0xe6,0xe5,0x31,0xed,0x1b, - 0x37,0x68,0x0d,0x34,0xf8,0x75,0x81,0x1f,0x57,0x98,0x09,0x00,0x63,0xdf,0x31,0x0f, - 0x78,0xc0,0x4b,0x52,0x41,0xb7,0xf1,0xa3,0xf5,0xf6,0x4a,0xae,0xe1,0x8a,0x98,0x9e, - 0x83,0x82,0x11,0xdd,0x07,0x3c,0x62,0x4c,0x5d,0xf3,0x1a,0x96,0xe0,0xae,0xab,0x14, - 0x13,0x9a,0x3b,0x50,0xa4,0x03,0x10,0xa1,0xc8,0xcc,0x2a,0x42,0x2c,0x9e,0x56,0x61, - 0xb7,0x05,0x03,0x30,0x56,0x35,0xba,0x12,0x28,0xf0,0x69,0x6a,0x59,0xd5,0x2b,0x6d, - 0x13,0x4f,0x2d,0x59,0x51,0xe3,0x51,0xa3,0x33,0x5c,0x3e,0x53,0xf2,0xdf,0xa4,0x27, - 0xed,0xe4,0xc5,0xf7,0x27,0x80,0x9b,0x87,0x1c,0x4d,0x40,0x97,0x84,0x94,0x03,0x4f, - 0x66,0x61,0x7e,0x0e,0xca,0x0a,0x8f,0x9e,0xe6,0x0c,0xc6,0x7a,0x66,0x5f,0x6a,0x0d, - 0x7a,0x13,0x6a,0x35,0x74,0x1b,0x19,0x1e,0x65,0x03,0xc8,0xa8,0x56,0x51,0xe6,0x50, - 0xd4,0x71,0x38,0x6d,0x2a,0x7b,0x9e,0xd5,0x5d,0x20,0x71,0x92,0xab,0xcc,0xd3,0x7c, - 0x41,0xb6,0x4c,0x34,0x06,0xab,0x62,0x88,0x21,0xe9,0xa4,0x17,0xc5,0xe8,0x9b,0xc6, - 0xe3,0x99,0x7a,0x5d,0x24,0xe9,0x98,0x02,0x5b,0x3e,0x65,0xe8,0xb0,0xf0,0x3c,0xcf, - 0x08,0x0c,0x4c,0x0c,0xd2,0xfc,0x49,0x49,0x8a,0xb0,0xa5,0xf7,0x3f,0xe5,0x0b,0x5a, - 0xe6,0xc8,0x69,0x2f,0x0a,0x4e,0x9a,0x10,0xa5,0x2c,0x01,0x76,0x49,0xb2,0xec,0xc8, - 0xbe,0x38,0xf8,0x1b,0xb4,0xdf,0x62,0x3c,0x56,0xf8,0x8f,0x08,0x56,0x3c,0xc5,0x56, - 0x3b,0x3c,0xad,0xa0,0xb9,0xdd,0x80,0x51,0x0e,0x0d,0x3e,0xa0,0x17,0xe5,0x3a,0xff, - 0x84,0x40,0xa1,0x0e,0xb5,0x69,0x6a,0xad,0xa0,0x16,0x35,0x69,0xd7,0xa3,0x70,0x5a, - 0xd5,0x14,0xe6,0xd0,0x96,0x20,0x5a,0x14,0x04,0x1a,0xc6,0x4b,0x27,0x10,0x13,0x73, - 0x3e,0xbf,0x51,0x22,0xd2,0x1f,0x66,0x14,0x17,0x70,0x03,0xeb,0x0b,0x56,0x3f,0xc2, - 0x6c,0x53,0x89,0x0f,0xa5,0x12,0x3d,0x5d,0xa2,0x08,0xed,0xdc,0x2e,0xbb,0x52,0x26, - 0x9d,0x0b,0xef,0x79,0xa9,0x0c,0x9a,0x10,0x2e,0x44,0xba,0x83,0x08,0xe8,0x2a,0xcd, - 0x2c,0x42,0xf5,0xc5,0x34,0xf5,0x87,0x48,0x80,0x29,0xee,0x1d,0x63,0x90,0x8c,0xbc, - 0x06,0xc7,0xbf,0x09,0xe8,0x1a,0x1c,0xcc,0x7a,0xeb,0x99,0xe4,0x1b,0x34,0x3c,0x40, - 0x15,0xf5,0xcc,0xda,0x64,0xc0,0x49,0x1d,0x88,0xb0,0x4d,0x47,0x61,0x31,0x0f,0x59, - 0xe4,0x5c,0xae,0xc0,0x83,0xde,0xa4,0x5e,0x5a,0xaa,0xa7,0xdb,0x7b,0xbe,0xa6,0xde, - 0x70,0x4d,0x7b,0x6b,0xeb,0x55,0xb4,0xb7,0xa6,0x78,0x45,0x2b,0x6b,0x4a,0x97,0x61, - 0xaf,0x1d,0x7a,0xa9,0xf4,0xda,0x8e,0x3b,0xa5,0xe5,0x02,0x30,0x94,0x4f,0xd4,0x2c, - 0x09,0xdc,0xa2,0xec,0x35,0x00,0x91,0xfd,0x37,0x4a,0x5b,0x3c,0xcc,0x12,0x99,0xcb, - 0x7f,0x0f,0xa4,0x32,0xa4,0xac,0xce,0x66,0xef,0x8c,0x8d,0x3a,0x19,0x4e,0x00,0x8c, - 0x10,0x33,0x42,0xf2,0x21,0xe3,0x0c,0xef,0x51,0xda,0x7a,0xdd,0x88,0x22,0x9d,0xef, - 0x19,0xc3,0x1c,0x10,0x10,0x52,0xdb,0xd6,0xc0,0xde,0x64,0xe3,0xf4,0x13,0x01,0x25, - 0x58,0xe1,0x33,0xbf,0xe6,0x18,0xbf,0xbe,0xeb,0x91,0x72,0xbe,0x06,0xc1,0x38,0x18, - 0xeb,0x80,0x09,0x67,0xeb,0x8e,0xec,0xc0,0x8c,0xf2,0x53,0x5b,0x1d,0xf4,0x73,0x0a, - 0x75,0x51,0x47,0x71,0x7e,0x5e,0xce,0x17,0xf6,0x7e,0x1e,0x9e,0xe2,0xf9,0x35,0x38, - 0x82,0xae,0x30,0x2f,0x73,0x75,0xf4,0xb5,0xfb,0x72,0xca,0x35,0xf9,0xcc,0xbc,0xc2, - 0xe8,0x59,0xde,0x95,0x6b,0x19,0x57,0xe6,0x17,0x68,0xf6,0x94,0x80,0x1d,0xb7,0xf4, - 0x2e,0x2c,0xe6,0x13,0x14,0x72,0xf1,0x57,0x1d,0x00,0x0b,0x0c,0x73,0xac,0x38,0xb6, - 0x05,0xc6,0x69,0xe9,0xcc,0x56,0xdb,0xaa,0x3b,0x93,0x67,0x54,0x6e,0xb5,0x25,0x62, - 0x32,0xba,0x59,0x49,0x48,0x31,0x1f,0x00,0x62,0x8a,0x73,0x78,0x94,0xad,0x9c,0x24, - 0x3f,0x4d,0x48,0xf2,0xe3,0x2d,0x60,0x94,0x8e,0x44,0x23,0x12,0x63,0x51,0x4a,0x01, - 0x80,0xcf,0x51,0x7d,0x82,0x49,0x39,0xa6,0xe0,0x3a,0x52,0xd5,0x9c,0xa3,0x32,0xe2, - 0x86,0xce,0xff,0xc7,0xb9,0x0c,0xbf,0xfb,0x47,0xe0,0x6c,0x08,0x88,0xec,0x17,0x90, - 0x0e,0xee,0xd7,0x7f,0x52,0x5f,0xd1,0x48,0xe1,0x9d,0x47,0xab,0xb9,0x8a,0x6c,0xc8, - 0xdc,0x57,0x98,0x73,0x4c,0x4e,0xa4,0xba,0x2c,0x27,0x44,0x05,0xe4,0xa3,0xe8,0xa7, - 0x90,0xfb,0xf2,0xe8,0xcc,0xd6,0xd8,0x8c,0xd2,0x7b,0x3b,0xda,0x82,0x3e,0x88,0x01, - 0x6f,0xed,0xe9,0xc3,0x77,0xf0,0x8a,0xe8,0x41,0x8b,0x65,0xc1,0x7a,0x00,0x1d,0x1c, - 0x52,0x1f,0x5b,0x95,0xbb,0xc6,0x14,0xb1,0x04,0x25,0x70,0xcd,0xf2,0xd1,0x2c,0x5e, - 0xb6,0xa5,0xd7,0x51,0xc5,0x3b,0x73,0xf8,0xa1,0x82,0xe8,0x0f,0x48,0x42,0xe0,0x91, - 0x04,0x29,0x11,0x30,0x4f,0x00,0x46,0xc3,0xd2,0xdd,0x1f,0x85,0xf5,0x8e,0x0b,0x3a, - 0xa3,0xfb,0xe7,0x1c,0xd5,0xbd,0xa4,0x36,0xa8,0xc1,0x58,0x67,0xab,0x4a,0xba,0x83, - 0x33,0x60,0xa9,0x88,0x7d,0x56,0x07,0x81,0x66,0x9c,0x29,0x5a,0x70,0x16,0xc3,0x7f, - 0x1c,0xe0,0x7c,0xd0,0xcf,0x7f,0x1a,0x88,0x55,0xfb,0x9e,0x9d,0x1a,0xd2,0x3a,0xa4, - 0xa9,0xb2,0x43,0x9a,0xc3,0x99,0x32,0xe7,0xec,0x40,0xb0,0x1a,0xc1,0x1b,0xd5,0xac, - 0x66,0xdc,0x93,0x29,0x14,0xed,0x78,0xc8,0x40,0x4d,0xf5,0x31,0xe7,0xb8,0xe5,0x19, - 0xf7,0x24,0xc5,0xbc,0xe6,0xbe,0xca,0x77,0x29,0xfd,0x7d,0xc1,0xe7,0x55,0x69,0x4d, - 0xa0,0x37,0x60,0x13,0xca,0xa3,0xa9,0xfb,0x5a,0xca,0x23,0xe2,0x42,0x74,0xb9,0x9a, - 0x5b,0x0d,0x29,0x56,0x84,0x7b,0x82,0x51,0x9a,0x25,0xa8,0x50,0x22,0x89,0xa2,0x0d, - 0x2c,0x8f,0xdc,0xaa,0xec,0x57,0x03,0x43,0x3d,0x87,0x86,0xd0,0x9e,0xc9,0x1f,0xba, - 0x50,0xd3,0x2d,0x85,0x72,0x1f,0x18,0x9f,0xfb,0x72,0x88,0x94,0x07,0x35,0xe3,0xeb, - 0x0c,0x73,0x1f,0xa1,0x96,0x51,0x0f,0x20,0xad,0x02,0x10,0x49,0x00,0x41,0x76,0x7d, - 0x17,0x80,0xaa,0x0e,0xc8,0xf6,0x03,0x5d,0x19,0x6d,0xfd,0x38,0x53,0x4f,0x76,0xdc, - 0xc3,0xc1,0x7a,0x8a,0x46,0x8c,0x17,0x49,0xfa,0xed,0xeb,0x77,0x1f,0xc8,0x40,0xec, - 0xf5,0x65,0x20,0x72,0xec,0xa7,0x69,0x72,0x8d,0x49,0x9c,0xc8,0x01,0x49,0xde,0x58, - 0x95,0xd0,0x63,0x25,0xe8,0x9a,0xc0,0x7b,0x72,0x0e,0x09,0x60,0x01,0xcb,0xd6,0x19, - 0x25,0xb2,0x74,0x31,0x15,0x06,0x46,0xdb,0x45,0xc9,0xb4,0xa3,0xc1,0x0c,0xb4,0x23, - 0xd7,0xdc,0xf0,0xf3,0xe1,0xe8,0xfc,0xf5,0x7b,0x41,0xf6,0xb7,0x72,0x7b,0x86,0xfa, - 0x84,0x92,0x4c,0x9c,0x01,0x40,0xf8,0xea,0xc4,0x79,0x00,0xa0,0xd1,0x13,0xb1,0xc5, - 0xd7,0x50,0x02,0x26,0x40,0x50,0xce,0x83,0x6b,0x52,0x06,0xd1,0xfe,0xdb,0xb2,0xbd, - 0xa4,0xd9,0x2c,0x24,0xa7,0x11,0xe9,0xab,0xd4,0x6b,0x5e,0x93,0x1c,0xf1,0x8a,0x77, - 0xdd,0x71,0x34,0xac,0x39,0xb0,0x43,0xe3,0x54,0x32,0x48,0xc5,0xcc,0x12,0x18,0x75, - 0xf6,0xcb,0x2e,0xe0,0x1e,0xc8,0x07,0xa0,0xd4,0x46,0xfd,0xe9,0x7c,0xab,0x04,0x1e, - 0x95,0x26,0x58,0x2d,0x5b,0x04,0xaa,0x53,0xe1,0x06,0x0e,0x74,0x92,0x8a,0xb9,0x85, - 0x48,0x4e,0x1a,0x50,0x6e,0x21,0x3e,0x4c,0x57,0x15,0xb8,0xa3,0x3d,0x2f,0xa8,0x21, - 0x5c,0x81,0x85,0xb2,0x42,0x0f,0x18,0xfe,0x30,0xc8,0xf9,0x27,0xed,0x2c,0x54,0x7b, - 0x9e,0xbe,0xe9,0x51,0xa8,0xf0,0x18,0x25,0x6e,0xa9,0xc8,0xc1,0x89,0x93,0xe5,0x00, - 0x2f,0xed,0x04,0x18,0x6d,0x55,0x11,0x64,0xf9,0xf8,0xca,0xa4,0x6f,0x74,0x54,0x03, - 0x03,0xd6,0xd1,0x08,0xa8,0x12,0x02,0xb1,0x12,0xd5,0xb1,0xb5,0xaf,0x89,0xee,0x84, - 0x4c,0x5a,0x24,0xfd,0x91,0xb4,0x18,0x30,0x6d,0x46,0x60,0x02,0x40,0xe9,0xe8,0x34, - 0x92,0x6a,0x76,0x40,0xe7,0x9a,0xb1,0x10,0xeb,0x5d,0xe3,0x04,0x23,0x87,0xaf,0x13, - 0x63,0x32,0x68,0x02,0x87,0x1e,0x8c,0xa2,0xe5,0x38,0xc8,0x9a,0xb0,0x46,0x5b,0x2d, - 0x77,0x92,0xf4,0x10,0x31,0x06,0xbb,0x79,0xd3,0xb2,0x4f,0xda,0xc3,0x4c,0xe3,0x12, - 0xb3,0xbc,0x16,0x55,0x30,0x53,0x1b,0xa6,0xab,0xfb,0x94,0x60,0x72,0x28,0xf7,0xdd, - 0x30,0x73,0x0d,0xb3,0xa4,0x4f,0xf1,0x8c,0xd7,0x9d,0x85,0xaf,0x07,0x39,0xb4,0x41, - 0xba,0x43,0x2f,0x82,0xa4,0x93,0xef,0x1a,0xe4,0x2d,0x8b,0x47,0x19,0xad,0xc3,0x6a, - 0x12,0x7a,0x0a,0xe8,0x76,0x6e,0xfb,0xc5,0x59,0x90,0xe3,0xfe,0x4a,0xa6,0x65,0x91, - 0xd2,0xc0,0xa2,0xc0,0xcf,0xe8,0x0c,0x04,0xae,0x62,0x2d,0x6f,0x2c,0x41,0x62,0x38, - 0xa0,0xe3,0x10,0x11,0xe6,0x04,0xce,0x01,0x26,0xe6,0xd8,0x44,0xb6,0x2d,0x31,0xc9, - 0x8a,0xd5,0x64,0x6b,0xb3,0x6a,0x7c,0x93,0x4b,0xa9,0x6a,0xe9,0x1c,0x2f,0xa7,0xb2, - 0xfa,0x3b,0xcc,0xd5,0x43,0xdd,0xb7,0xcf,0xc9,0xd0,0x0b,0x73,0xfc,0x65,0xc4,0x07, - 0x65,0xac,0x62,0xb5,0x27,0x65,0x8e,0xf5,0x51,0x19,0x4c,0xcd,0x91,0x0e,0x04,0xb2, - 0xd7,0x7c,0x40,0xae,0xe8,0xe1,0x40,0xf4,0xf7,0xd5,0x59,0x99,0x63,0x79,0x56,0xe6, - 0xf8,0x95,0x39,0x16,0x46,0x0d,0xbc,0xa8,0x76,0x7b,0xa1,0x24,0xe0,0x33,0x50,0x5f, - 0xee,0x61,0x76,0x4e,0xce,0xec,0xec,0xed,0xb7,0xd5,0x21,0x99,0x7e,0xef,0x11,0x7d, - 0xb7,0x06,0xe6,0x1c,0x4c,0x51,0x5e,0x66,0xeb,0xbb,0x7b,0x20,0x45,0x7b,0x9b,0xed, - 0x22,0xf5,0x27,0x5c,0x2a,0x8a,0xd5,0x1d,0x70,0x19,0x6d,0x7e,0xc0,0xe5,0xd8,0x3a, - 0xe0,0x72,0xcc,0x11,0x52,0xc7,0x78,0xc4,0x85,0x71,0x2b,0x0f,0xb8,0x1c,0xf3,0x09, - 0x97,0x63,0xf7,0x88,0xcb,0x48,0x1e,0x57,0x59,0xd2,0xca,0x3b,0xe6,0xe0,0x0c,0x73, - 0xba,0x13,0xc6,0x77,0xfc,0x51,0x53,0x81,0x73,0x6a,0xe4,0xb8,0xf6,0xd8,0xc8,0xf1, - 0xab,0x62,0x2c,0x5f,0x79,0xde,0x2a,0x83,0xf9,0x4a,0x7a,0x0d,0x58,0x20,0x17,0x6e, - 0xac,0x9f,0xec,0xe1,0x31,0x62,0xf4,0x58,0x47,0xfb,0xc9,0xbe,0x1c,0xbf,0xe2,0xb7, - 0x43,0x8d,0xbf,0x9a,0x78,0x3f,0xf5,0xd9,0xdd,0x36,0xa4,0x78,0xf3,0x03,0xfb,0x1b, - 0xd5,0x3c,0xa6,0x60,0x14,0x6c,0x02,0xfe,0xfb,0x11,0x09,0xb6,0x65,0xe6,0xa7,0x26, - 0xa2,0x69,0x54,0xb9,0xa9,0x38,0x2a,0x6c,0xe6,0xc9,0xc1,0xd0,0x39,0x0d,0x39,0x04, - 0xfe,0xfd,0x91,0xb7,0x42,0x8f,0x5f,0xe9,0xa3,0xe7,0xa3,0xb5,0x71,0x84,0xa6,0x88, - 0xb3,0xb3,0x3f,0xb2,0xf6,0x5e,0x71,0xa2,0xa9,0x28,0x37,0xa5,0xbe,0x4a,0x4f,0x7a, - 0xe1,0x2b,0xe1,0x52,0x15,0xb1,0x37,0xfb,0xd7,0xb7,0xc1,0x98,0x42,0x32,0x21,0x58, - 0x85,0x36,0xf4,0xd4,0x55,0x14,0x29,0x46,0x68,0xd1,0x32,0xa9,0x1b,0xb6,0xdc,0x08, - 0x19,0x55,0xee,0x43,0xeb,0xb7,0xa5,0xcd,0x90,0x51,0xc5,0xfe,0xb4,0x8a,0xaa,0x41, - 0x55,0xf5,0x50,0xb8,0x59,0x47,0xcc,0x53,0x29,0x35,0x81,0xa9,0xfa,0x8e,0xc2,0x55, - 0xb0,0xfa,0x33,0xcc,0x68,0x06,0x1a,0xfc,0xfe,0x6e,0xed,0x46,0xcb,0xbb,0x35,0xfb, - 0x2c,0xef,0xbe,0x72,0x9b,0x85,0x66,0x0e,0x8f,0x61,0xe3,0xa6,0xca,0x88,0x43,0x3b, - 0x2b,0x36,0x52,0x46,0x6e,0x84,0xa2,0xde,0x4b,0x19,0xb9,0x41,0x8a,0x66,0x3b,0xa5, - 0x72,0x5a,0x64,0x7a,0x3b,0x19,0xb3,0x5e,0x99,0xab,0xa5,0x12,0x6b,0x85,0x2c,0x07, - 0x92,0x9d,0x38,0x18,0x97,0xe3,0xaa,0x9a,0x6f,0x1d,0x0c,0x6b,0x98,0xa2,0x09,0x35, - 0x01,0xb1,0xb2,0xa3,0xc2,0x65,0x36,0x59,0x01,0x2d,0x49,0x7d,0x23,0x6f,0xd5,0x6d, - 0x55,0xad,0x82,0x11,0x5e,0x3b,0x6c,0x4a,0x2d,0x7a,0xab,0x56,0xd5,0x4a,0xd8,0xa8, - 0xb5,0x9e,0xd5,0x5a,0xaf,0xae,0xb5,0xbe,0xdd,0x5a,0x7f,0x6d,0x6b,0xa5,0x20,0x1b, - 0xfd,0xa5,0x14,0x98,0xb5,0x06,0x9f,0x3a,0xf8,0x61,0x54,0x13,0xfa,0xe0,0x04,0xcc, - 0x02,0x55,0xcc,0x54,0xe0,0xc3,0x48,0x5e,0xc9,0x8c,0x58,0xc1,0x20,0x87,0x91,0xbc, - 0x8c,0x99,0x2e,0x62,0xb6,0x02,0x1d,0x46,0x85,0x30,0x07,0x0c,0xa2,0xbd,0x69,0x99, - 0xc8,0x05,0x7c,0x5e,0xb5,0x2a,0xe3,0x17,0x46,0xa5,0x80,0x87,0x8d,0x2b,0xdf,0x5a, - 0xf1,0x7f,0x14,0x75,0xc4,0xce,0x84,0x81,0x60,0xdb,0x91,0x0e,0x07,0x2e,0xb3,0x70, - 0x44,0x29,0xb3,0xf9,0x8a,0x79,0xa9,0xb8,0xe9,0x73,0x19,0xf5,0x0e,0x21,0x15,0x12, - 0xf0,0x25,0xc1,0x39,0x28,0xbe,0x4c,0x78,0x8e,0x59,0xef,0xfa,0x22,0x78,0x06,0xd3, - 0x91,0xfe,0x1f,0xb4,0x59,0xed,0xbc,0x35,0x5d,0x10,0x01,0xec,0x0d,0x32,0x45,0x0a, - 0x87,0xd1,0xd6,0x30,0x89,0xd1,0x9a,0x20,0x9e,0x32,0x31,0xed,0xe8,0x65,0xb4,0x46, - 0x74,0xad,0x27,0xf6,0x65,0x95,0xf0,0xb0,0x69,0x7d,0xa9,0xe8,0xfc,0xaa,0x55,0x2b, - 0x5b,0x2a,0x28,0xbc,0x9e,0xbe,0x6b,0x3a,0xe5,0xa7,0xa3,0x52,0x83,0x6d,0xb1,0x8b, - 0xd4,0xa2,0xcc,0x56,0xca,0xca,0xd2,0x57,0x15,0x54,0xf8,0xa8,0x24,0x1d,0xba,0x6d, - 0x4a,0x37,0xec,0xc6,0xf3,0x8f,0xd6,0xc4,0xea,0x8f,0xea,0xa3,0xb2,0x47,0x4e,0xf8, - 0x74,0xf1,0x72,0x92,0x06,0x10,0x1b,0x3e,0x93,0x03,0x08,0x7e,0x63,0x50,0x08,0xcf, - 0xb7,0x3e,0x6b,0xd2,0x67,0xe4,0x46,0x6d,0x47,0xd7,0x91,0xc1,0xd5,0xa3,0x35,0x81, - 0xdb,0x77,0xb4,0x8c,0x4d,0x32,0x8d,0x95,0x9a,0x92,0xb2,0xba,0xae,0x3d,0x07,0xa6, - 0x51,0xd7,0x8a,0xd7,0x67,0x68,0x68,0x1d,0x3c,0x34,0x2f,0x81,0x3d,0xda,0x0c,0x8c, - 0x75,0x87,0x47,0x25,0x18,0x5b,0x13,0xdb,0x04,0xef,0x4b,0x0b,0x1c,0x6a,0xda,0xe2, - 0xaf,0xff,0xf2,0xaf,0x42,0x5f,0x17,0x53,0x6a,0x1c,0xb3,0x46,0x63,0x74,0x42,0xe5, - 0x00,0x51,0xeb,0xad,0xaa,0x64,0x25,0x00,0xb1,0x10,0x69,0xfa,0xdc,0xeb,0xf3,0x06, - 0x85,0x6d,0x08,0x7c,0xd5,0x2e,0x40,0xad,0xb2,0x4c,0xa6,0xb3,0x25,0x94,0x55,0x7a, - 0x33,0x4b,0x28,0xdf,0x77,0x84,0xb2,0x31,0xb0,0x9d,0x5d,0x91,0x82,0xb5,0x57,0xb7, - 0x2d,0x62,0x54,0x91,0x75,0x9b,0x22,0x85,0xcf,0xf6,0xae,0x88,0x65,0xa0,0x95,0x34, - 0x02,0xb3,0xe1,0x4c,0x67,0xea,0x49,0x16,0x99,0x6c,0x99,0xb3,0xd5,0x22,0xc9,0xc9, - 0xf3,0xa7,0xa4,0x04,0xb6,0xd4,0xd1,0x32,0x02,0xf3,0xe6,0xf4,0xfa,0x0a,0x27,0x08, - 0xa5,0x69,0x4b,0x30,0xf8,0x6e,0x1b,0x9c,0x8d,0x45,0x8f,0x68,0x86,0xf4,0x22,0xbb, - 0x82,0x16,0x71,0xa5,0x0a,0x7d,0x53,0xc1,0x42,0xa2,0x6d,0xe2,0xfd,0x76,0x9f,0xfd, - 0x46,0x84,0x52,0xed,0xb4,0x37,0x39,0xb7,0x5e,0x14,0x3c,0x29,0x5f,0x3f,0xd1,0x8e, - 0xfc,0xaa,0x9d,0x71,0x69,0x88,0x52,0x72,0x83,0x8f,0x05,0x99,0xe5,0xa4,0x0f,0xa8, - 0xdd,0x2a,0x63,0x83,0x95,0x00,0xbc,0xda,0xdc,0x44,0x2c,0x53,0x90,0x4e,0xba,0xc5, - 0x93,0x76,0xc8,0xf3,0x8c,0xf9,0xc8,0x89,0x14,0xa0,0xfc,0xf2,0x80,0xc9,0x01,0x1d, - 0xa6,0x7c,0x1f,0x01,0xfb,0x1d,0x69,0xce,0x4d,0x81,0xbe,0x55,0x60,0xe4,0x51,0xda, - 0xa6,0xc6,0x68,0x99,0xe5,0xc9,0xbc,0x51,0x97,0x71,0x45,0x6d,0x1e,0x29,0xfb,0xd7, - 0x78,0xc3,0x4e,0x29,0x53,0xbb,0xe5,0x24,0x73,0xa3,0x34,0x4b,0xfe,0xb1,0x63,0x99, - 0xe0,0xa5,0xb9,0xc9,0xdc,0x96,0x9c,0x28,0x8e,0xab,0xac,0xe4,0xa1,0xbb,0x3d,0xd8, - 0x8c,0xc6,0x6c,0xe7,0xd9,0xb1,0x4c,0x26,0xb3,0x51,0xc5,0xa2,0xfb,0x4c,0x55,0xb6, - 0xfc,0x67,0x0b,0xc2,0x47,0xd6,0x66,0x5b,0xaa,0x8d,0x79,0x72,0xc8,0x5b,0x88,0x51, - 0x70,0xcb,0xf9,0x7f,0x79,0xb4,0x96,0xe5,0xbe,0xa8,0x98,0xaf,0x4d,0x98,0xb0,0x8c, - 0xeb,0x19,0xbb,0x56,0xe5,0x33,0xdb,0x5a,0x42,0x1a,0xc2,0xcc,0x8a,0x92,0x88,0x30, - 0xc7,0x95,0x9a,0x2e,0x9d,0x7f,0xc0,0x89,0xf1,0x3c,0x02,0x2d,0xa5,0xe1,0x31,0xaa, - 0x1a,0x2d,0xb3,0x6d,0x8f,0x7b,0xb5,0x7a,0xc7,0x3e,0x88,0xea,0x2e,0xba,0x81,0x2f, - 0x63,0x3f,0x07,0xfc,0x03,0xab,0xa1,0x85,0x10,0x8e,0xad,0xed,0xf5,0x3f,0x34,0x1b, - 0x9c,0x61,0x0b,0x6f,0xce,0x04,0xe8,0xb3,0x70,0x3c,0x0e,0xf8,0x16,0x41,0x77,0x41, - 0x41,0x41,0x9a,0xa4,0x0f,0xc9,0xb5,0x53,0xac,0xb9,0xb1,0xf5,0x5c,0x93,0xe5,0x73, - 0x5d,0x0d,0xdd,0xea,0xbb,0x52,0x0c,0xad,0x3c,0x55,0x6b,0xd5,0xe6,0xdb,0x7c,0xee, - 0xc6,0xa1,0x50,0x21,0xb3,0x06,0x95,0xfc,0xa6,0x14,0x00,0x21,0xcb,0x1f,0xaa,0x8c, - 0xe3,0x9f,0x64,0x28,0xe8,0xc2,0x07,0xf2,0x50,0xb9,0x87,0x0c,0x76,0x2f,0x8a,0xe1, - 0xba,0x2a,0x58,0xf6,0xb3,0xca,0x4c,0xcc,0x00,0x55,0x7e,0x33,0x99,0xdb,0x18,0xef, - 0xa7,0xd8,0xc5,0x23,0xee,0xbb,0x6d,0x3b,0xe8,0xd3,0x8e,0xdd,0xfd,0x6a,0xc2,0x80, - 0xc9,0xaf,0xbf,0xc4,0xa2,0x79,0xf7,0x80,0x6d,0xe2,0xb1,0xa3,0x40,0xb8,0xa0,0x1b, - 0x0a,0x62,0xa5,0xab,0x72,0x17,0x06,0x2e,0xef,0x74,0x39,0x42,0x39,0x38,0x3e,0x8e, - 0x92,0x38,0x68,0xda,0x78,0x68,0x59,0x51,0xce,0x16,0xc3,0xac,0x65,0x99,0x05,0xa6, - 0x69,0x4a,0xba,0x65,0x6c,0xce,0x77,0xab,0x98,0xab,0x22,0x27,0x50,0xd8,0x96,0xd9, - 0xda,0x0b,0x3e,0x18,0x37,0x54,0xf8,0x68,0x8c,0x9b,0x49,0xcd,0x0e,0xe5,0xa9,0x55, - 0x10,0x4e,0xa3,0x2f,0x06,0x40,0xf5,0xad,0x6b,0xc0,0xcd,0x97,0x71,0x10,0xe5,0x7e, - 0xeb,0xf7,0x54,0xf2,0xd4,0xfa,0x31,0xf3,0x63,0x2f,0x94,0x35,0x39,0x35,0x9d,0x62, - 0x0f,0x04,0xf7,0xac,0x55,0x00,0x50,0xe0,0x6f,0x1e,0x5f,0xfa,0xd3,0x47,0xc3,0x82, - 0xd2,0xb9,0x8b,0x81,0xed,0x31,0xab,0x10,0x91,0xa6,0xee,0xd7,0xca,0xca,0x8a,0x49, - 0xb7,0xf7,0x85,0x4a,0x9c,0xdc,0xec,0x43,0x6d,0x82,0xe6,0x3f,0xe0,0x75,0xce,0xf1, - 0xf8,0x1d,0x18,0xf5,0x15,0xc1,0xfb,0x58,0x8b,0xcc,0x07,0xcc,0x6d,0xf7,0x40,0x7a, - 0x6a,0x65,0x15,0xbc,0x88,0xaf,0x54,0x45,0x9f,0x9b,0xb5,0x62,0x50,0xd9,0x10,0xf9, - 0xcb,0xff,0x26,0x48,0xa5,0x02,0x98,0xea,0x1b,0x0b,0xbc,0xfa,0x95,0x43,0x0b,0x2a, - 0xae,0xb6,0x6c,0xe0,0x4d,0xc8,0xb6,0x05,0x29,0x9f,0xe9,0x8a,0x3e,0xbd,0xa5,0x57, - 0x30,0x7d,0xa0,0x41,0xfb,0xbb,0x63,0xb0,0xa9,0x61,0x80,0x41,0xf3,0x06,0x6d,0xe1, - 0xd2,0x30,0xac,0x4c,0xd6,0x25,0x8b,0x4a,0x0e,0xc4,0x4a,0x83,0x6d,0x15,0x31,0x92, - 0x31,0x4f,0xf1,0x12,0xd7,0x43,0xd9,0xcc,0x39,0x3e,0xd9,0x49,0x6f,0xae,0xe9,0x96, - 0x20,0xbc,0x60,0xd3,0x4a,0x71,0x86,0xce,0xf0,0xae,0xd5,0x37,0xbc,0x31,0xd7,0x39, - 0x39,0xd2,0xdc,0xb3,0x5b,0xa6,0xed,0x54,0x0c,0x3e,0xdf,0xb3,0x8f,0x7f,0x70,0xdd, - 0x57,0xe1,0xfa,0xba,0xb4,0xe1,0x5e,0x53,0xf7,0x65,0x48,0x77,0x02,0xdd,0xd9,0xf2, - 0x1d,0x35,0x9d,0x0c,0x6b,0x72,0x4b,0xbd,0x3e,0xbf,0x78,0xab,0x02,0x22,0x9e,0x13, - 0xd1,0x17,0x57,0xd5,0x08,0x7d,0xe7,0x78,0xca,0x1d,0x02,0x04,0x5a,0x3a,0xfd,0x1d, - 0x65,0x48,0xed,0xa2,0x2a,0x26,0x65,0x57,0xe9,0x35,0x8d,0x88,0x71,0xa3,0x06,0x75, - 0x36,0xf5,0x72,0xc1,0x59,0xe8,0x70,0x7e,0x6b,0x93,0xd9,0xe1,0x25,0x05,0x1e,0x51, - 0x23,0x14,0xd0,0x5d,0x0f,0x6d,0x39,0xaa,0xb3,0x43,0x9f,0xbf,0xb3,0xa1,0xee,0x18, - 0x61,0x6e,0x43,0x77,0x9a,0x61,0x57,0x9b,0x9a,0x61,0x7b,0x68,0x42,0x35,0xe9,0xcd, - 0xb5,0x5e,0x44,0xbc,0xc4,0xcd,0x58,0x75,0x94,0xf6,0x55,0x91,0xea,0x9e,0xd4,0x7c, - 0x43,0xbe,0x04,0xac,0x27,0x62,0x8e,0x33,0x0b,0x2d,0x2a,0x57,0x63,0xf8,0xed,0xb6, - 0xef,0x86,0xc8,0x5f,0x63,0xfc,0xca,0x21,0x96,0x4d,0xdf,0xbf,0xd9,0x49,0xc1,0x6e, - 0xeb,0x89,0xa1,0xc8,0xb1,0xa4,0xd1,0x2a,0x2c,0x18,0x13,0x9b,0xd1,0x16,0x2e,0xc7, - 0xd0,0xb7,0x0a,0x90,0x09,0x5b,0x75,0x17,0x01,0x06,0x89,0xd4,0xde,0x45,0xb0,0x7e, - 0x15,0xd1,0x9c,0x38,0x66,0xe9,0xfb,0xa5,0x15,0xb5,0x61,0x77,0x1d,0xed,0xeb,0xc2, - 0x52,0xb2,0x16,0x1d,0xde,0xa5,0xb2,0xf1,0xec,0xda,0x66,0x27,0xb4,0xb7,0x39,0x59, - 0x14,0xcd,0x4e,0xae,0x7c,0xaf,0xc8,0x38,0x37,0x61,0x69,0x77,0xd0,0x8c,0x73,0x2f, - 0xc2,0x7d,0xf3,0x54,0x8d,0xd2,0x02,0x2f,0xb2,0xa2,0x67,0x1c,0xcd,0x45,0xf6,0x95, - 0x18,0x32,0x6a,0x1a,0x9b,0x76,0xd5,0xe9,0x1d,0x86,0x75,0x59,0x77,0x96,0xa8,0x4d, - 0x8c,0x2f,0xd0,0xd0,0xa5,0x01,0x20,0x13,0xfa,0xdb,0x9a,0xba,0x15,0x1e,0xac,0xe0, - 0x16,0xfb,0x6f,0x0c,0x7c,0xfb,0x38,0xe1,0xdf,0x63,0xa2,0x7b,0x67,0xd2,0x5c,0x44, - 0xdf,0x1d,0x3f,0x8f,0xa3,0x96,0x71,0x35,0xf0,0xcb,0x39,0x1b,0x0b,0xcf,0x1b,0x9f, - 0x45,0xad,0x29,0x4c,0xa4,0x86,0x3d,0xab,0x3a,0x8d,0x4a,0x75,0x8a,0xc7,0x51,0xf1, - 0x65,0x8d,0x4a,0x6b,0x9d,0x47,0xbd,0x03,0x00,0x68,0xa4,0x9b,0xaa,0xb7,0x52,0xd9, - 0xac,0x52,0x6e,0x4b,0x96,0x72,0x45,0x73,0x75,0x27,0x5b,0x95,0x8d,0x6c,0xc6,0x2b, - 0xad,0xe4,0x75,0x77,0x63,0x7c,0x66,0x39,0x65,0x26,0xe2,0x6e,0xd3,0xcd,0xd0,0x79, - 0xd8,0x2a,0xd8,0x14,0xf6,0x37,0x93,0x77,0x8d,0x53,0x5d,0x57,0xc6,0x4a,0xee,0xa8, - 0x1b,0x86,0xb4,0xbd,0x63,0x22,0xe7,0x36,0xb3,0x7e,0xca,0xe1,0x74,0x65,0x8f,0x5e, - 0xc1,0xb5,0x76,0x15,0x06,0xd7,0x7f,0xaf,0x39,0xc6,0xe5,0x7d,0x86,0x47,0x43,0x98, - 0xcf,0x24,0xee,0x90,0xee,0x3c,0xc0,0x33,0x1f,0x30,0xfb,0x79,0x38,0x12,0x39,0xc6, - 0x33,0xe3,0x6d,0x37,0x7e,0x94,0xe9,0xeb,0x16,0x71,0xab,0xf7,0xec,0xe4,0xcd,0xc9, - 0xf1,0xf9,0xc9,0x0b,0x7d,0x5a,0x67,0x96,0x44,0x74,0x32,0x67,0x34,0xc3,0x03,0xa1, - 0x1d,0x19,0x34,0xd6,0x16,0xd3,0x08,0xaf,0x01,0x1c,0xfa,0x11,0xde,0x66,0x18,0x8e, - 0x32,0x99,0x5e,0x9b,0xee,0x95,0xc2,0xab,0x39,0xf9,0x2c,0x50,0x47,0xa6,0xaa,0xc5, - 0xa8,0x69,0x84,0x92,0x8d,0xd2,0x04,0x6a,0xc4,0x53,0xf8,0x95,0x2c,0x02,0x4f,0x7c, - 0xa4,0xb3,0x09,0xd0,0x30,0xdd,0x9a,0x73,0x0d,0xaa,0xbe,0x18,0x27,0x74,0x79,0x75, - 0x88,0x37,0x10,0xf2,0xce,0x33,0x5e,0x71,0x89,0xa1,0xd2,0x21,0xf0,0x57,0x4f,0xf9, - 0x78,0x17,0x57,0xef,0xaf,0x82,0x34,0xf2,0x57,0x32,0xe9,0xb3,0x7a,0xb4,0x12,0x55, - 0x5f,0x9d,0x61,0x23,0xea,0x3b,0x3d,0xd8,0x5f,0x8f,0x39,0x8f,0x35,0x7f,0xa8,0x08, - 0xcd,0xc3,0xb5,0x00,0x5f,0x43,0xde,0xb5,0x58,0x82,0x6e,0xd0,0x50,0x2f,0x3f,0xf8, - 0x13,0x13,0x7f,0xb7,0xb8,0x52,0x89,0xca,0xcd,0x0b,0xfb,0xe1,0x8d,0x9f,0xe5,0xce, - 0xb3,0xdc,0x06,0xef,0xaa,0xae,0x9c,0xfe,0xf1,0xa7,0xb3,0x93,0xe3,0xf7,0xef,0x5e, - 0x60,0x6a,0xda,0x5d,0xfb,0xed,0xf9,0xc9,0x29,0xee,0x25,0x83,0xde,0xb3,0xa3,0xab, - 0xbf,0x8e,0x65,0x5a,0x7e,0x7e,0x7c,0xaf,0xd3,0xf4,0x5b,0xc7,0x77,0xb0,0xd7,0x30, - 0xb7,0x4d,0x79,0x6e,0x07,0x75,0x0c,0x39,0x92,0x43,0x3d,0x16,0x2b,0x32,0xfd,0x48, - 0x5c,0xc2,0xda,0x95,0xe7,0xb4,0xba,0xde,0x23,0x91,0x0d,0xf8,0xf6,0x4b,0xbc,0x61, - 0x4f,0x0c,0x97,0x69,0x96,0x13,0xe3,0x88,0x69,0x53,0xa9,0x93,0x85,0x78,0x45,0x73, - 0xc0,0xd9,0x68,0x73,0x3f,0x8c,0xec,0x04,0x21,0x72,0xfe,0xf1,0x5e,0x6e,0xce,0x88, - 0x9b,0x99,0x94,0xb8,0x44,0x34,0x26,0x9a,0x9d,0xd3,0xe4,0xd2,0x85,0x93,0xc9,0x44, - 0xe6,0xaa,0x9d,0x27,0x76,0xa0,0xfa,0x62,0x06,0x2a,0x08,0x5a,0xb5,0xe2,0x1f,0xb0, - 0x5f,0x4e,0x52,0x9f,0x45,0x48,0x39,0x7d,0xb8,0x08,0x5d,0x24,0xb5,0x4f,0x39,0x78, - 0x1e,0x61,0x86,0x9b,0xae,0x93,0xff,0xd0,0xbe,0x50,0xca,0x66,0x30,0x0c,0x83,0x54, - 0xb9,0x87,0xc8,0xc2,0x39,0x19,0x02,0xa6,0xb2,0x9f,0x37,0x5b,0xa4,0x18,0xee,0xb5, - 0x28,0x8b,0x70,0x77,0xa7,0xe5,0xdc,0x65,0x62,0x21,0x33,0x4e,0xc2,0x6c,0x55,0x08, - 0xd2,0x51,0x7d,0x6b,0x62,0xbf,0x7b,0xde,0xc3,0x96,0xdd,0xbf,0x8d,0xbb,0x27,0x63, - 0x3b,0xf0,0xba,0x36,0xea,0x63,0xaf,0xab,0x92,0x56,0xe3,0x3d,0x29,0x39,0x25,0x3e, - 0xde,0x69,0xad,0xed,0x77,0xbf,0x4f,0x01,0xe2,0xd0,0x1b,0xd3,0x7f,0x5c,0x86,0xd7, - 0x01,0x5d,0xec,0xb6,0x41,0xfb,0x78,0x8d,0x21,0xb5,0xbe,0xb3,0x57,0x6c,0xdd,0x8a, - 0x09,0xa0,0xc6,0x76,0xf6,0xd6,0x77,0xa6,0xbb,0x5b,0x14,0x04,0xb0,0x06,0x91,0xad, - 0x34,0x81,0x13,0xe9,0x33,0xd9,0x6f,0x43,0xbc,0x45,0xd7,0xdc,0xaa,0xba,0x08,0x17, - 0x01,0xc6,0x43,0x0c,0x80,0x89,0xac,0xe6,0x98,0x6d,0x1f,0x38,0x02,0x73,0x1f,0x99, - 0x59,0xe6,0xcd,0xc9,0x1f,0x4f,0xde,0x48,0xfa,0x94,0xec,0xc9,0x8a,0x87,0x73,0x39, - 0x92,0x39,0x83,0xed,0xd3,0xda,0xe7,0xb5,0xf8,0x04,0x79,0x21,0x0d,0xf7,0xd9,0xfa, - 0x3b,0x90,0xc8,0x8b,0xc4,0xb7,0x1e,0xf1,0x9d,0xe3,0x83,0xbb,0xcb,0x9b,0x4b,0x9d, - 0x58,0xdb,0x93,0x6d,0x3e,0x00,0xf2,0x80,0x56,0x01,0x41,0xf2,0x0d,0x22,0xc9,0xdf, - 0xc0,0xd6,0xc2,0x65,0xbf,0x5c,0x9b,0x87,0xd4,0xd9,0x6d,0x54,0xed,0x75,0x88,0x82, - 0xd0,0x84,0xc2,0x25,0xc2,0xd4,0x60,0x9f,0x15,0x50,0x67,0xaa,0xeb,0x2f,0xa3,0x73, - 0x8b,0xb9,0xd6,0x91,0x15,0x35,0xdf,0x6b,0x57,0x5d,0x54,0x27,0xab,0xd7,0x74,0x8d, - 0x5b,0x40,0xf3,0x4e,0xc5,0xca,0xf3,0x9b,0xe2,0x55,0x20,0xae,0x05,0x56,0x77,0x4f, - 0xca,0x77,0xeb,0x5c,0x42,0x45,0x0a,0xc4,0x94,0x44,0x77,0x07,0xd9,0xa2,0x6b,0x6d, - 0x1f,0x33,0x93,0x53,0xc8,0xe4,0x4e,0x97,0x67,0xf2,0xb8,0x22,0x58,0x56,0xa7,0xa6, - 0xe0,0xcf,0xeb,0xa3,0x4f,0xb9,0xcc,0xba,0x4c,0x95,0x57,0x14,0x43,0xc6,0x69,0xc8, - 0x29,0xcc,0x15,0xd3,0x95,0x5f,0xac,0xcd,0x54,0x39,0x93,0x09,0x22,0x66,0x6e,0xfe, - 0x45,0x6a,0xca,0xcd,0x61,0x45,0xaf,0x64,0x34,0x52,0x57,0xa6,0x9d,0xd4,0x3d,0x82, - 0x77,0xd7,0xf6,0x3b,0x3b,0xea,0xe8,0xd6,0x71,0x49,0x12,0xab,0xf3,0xd3,0x54,0xe6, - 0x32,0x69,0xf3,0xa9,0x25,0x4b,0xa1,0xaf,0x42,0x05,0x15,0xb5,0xbb,0x66,0x63,0xe1, - 0x5a,0x5d,0xce,0x50,0xd5,0xef,0xda,0xd4,0x7d,0xd0,0x85,0x75,0x99,0xfb,0xe8,0x5e, - 0x25,0xba,0x7d,0xc6,0x12,0xb8,0xdb,0x4a,0xce,0x52,0x10,0xf6,0xf5,0x41,0x29,0xd7, - 0xdf,0xcc,0x8a,0xd4,0x86,0x06,0x28,0x77,0x14,0xe0,0xd6,0xbe,0x6f,0x48,0xc7,0x8b, - 0x3a,0x08,0xb5,0x03,0x46,0x1d,0xac,0xde,0x94,0x12,0xfd,0x95,0xf1,0x4b,0xf6,0x26, - 0xa2,0xb6,0x89,0x02,0xbf,0xad,0x02,0xa6,0x40,0x85,0xf7,0xd8,0x21,0xac,0x3e,0x82, - 0xf8,0x6f,0x73,0x6c,0x17,0x66,0x79,0x2e,0x12,0xf7,0x39,0x88,0xf5,0x66,0x9c,0x5c, - 0xdb,0x6a,0x80,0xd4,0x93,0xe4,0x26,0x64,0xf1,0x40,0xeb,0x7d,0xd6,0x57,0x5a,0x46, - 0x6f,0x81,0xea,0xf2,0xc6,0xc5,0x8f,0xa0,0xed,0x75,0x46,0x51,0x02,0xaa,0x42,0x36, - 0x9a,0x05,0xe3,0x25,0x6a,0x72,0x6d,0x52,0xcf,0xc0,0x86,0xed,0xf0,0xf5,0x34,0x61, - 0x3c,0x4a,0x69,0x67,0x2f,0x1b,0x50,0x42,0xfb,0x34,0xc9,0x73,0xcc,0xb6,0x97,0xfb, - 0x43,0x30,0x93,0x43,0x92,0x3b,0x28,0x82,0xc2,0xf9,0x92,0xae,0x85,0x26,0x16,0xfe, - 0xe1,0xf5,0xf7,0xaf,0xce,0x85,0x3f,0x07,0xfa,0x65,0x5d,0x00,0x14,0x2a,0x0c,0x40, - 0x8c,0x39,0x34,0x30,0x03,0xa5,0x50,0x5e,0x10,0x8e,0x49,0x6f,0x16,0x0b,0x80,0xb7, - 0xa0,0x03,0xab,0x78,0xbf,0x37,0x35,0x4b,0x97,0x74,0x61,0xc2,0xf8,0x29,0x2d,0x02, - 0x6c,0x2a,0xa6,0xbd,0x4a,0xec,0x1d,0xa8,0x15,0x7c,0xd1,0x41,0xb2,0xcc,0xe8,0x3e, - 0x40,0x68,0x82,0xe3,0x8f,0x65,0x56,0x84,0x96,0x91,0x0b,0xb9,0x9f,0x4e,0x69,0x13, - 0x0f,0xb5,0x38,0x10,0x67,0x30,0x7c,0xe6,0xd1,0x84,0x15,0xce,0x66,0x2c,0xf9,0xb8, - 0x83,0x1f,0xa4,0xc5,0xe1,0x72,0xcc,0x75,0xf7,0xa9,0x08,0xe7,0x9f,0x6e,0x22,0xa0, - 0x27,0x0a,0x2e,0x6e,0xd9,0x52,0xa9,0x4e,0x07,0x33,0xc7,0xea,0x3c,0x98,0xd8,0xd8, - 0xa1,0xa2,0x45,0x47,0xcf,0x21,0xfd,0x53,0x6b,0x74,0x50,0x50,0xed,0xd1,0x01,0x61, - 0xf0,0x4d,0x4b,0x28,0x3e,0xd5,0xbb,0xf7,0xea,0xfa,0x25,0x5b,0xb6,0x3a,0xbc,0x7b, - 0x44,0x21,0xde,0x55,0x4b,0xc0,0xec,0x50,0x12,0x6c,0x9d,0xad,0x13,0x6a,0xa0,0x6b, - 0x8a,0x5e,0xd2,0x99,0x3f,0x66,0x1e,0xd8,0x94,0x7e,0xbc,0xb5,0xb4,0x23,0x89,0x86, - 0x27,0xbc,0x24,0x88,0x9f,0xd2,0xe0,0x19,0x6d,0xcc,0x70,0xf9,0xf7,0x19,0x93,0x91, - 0x95,0x7e,0x26,0x3d,0x7a,0xc9,0x13,0x4f,0x07,0xd4,0x96,0xe9,0x04,0xd9,0x0b,0xa8, - 0x8a,0xa8,0x0b,0xb4,0x91,0xa0,0x48,0xd5,0xc6,0x89,0xce,0x30,0xe0,0x85,0x8a,0x86, - 0x39,0x2b,0x93,0x8a,0xd4,0x92,0x94,0x32,0x13,0xf0,0x26,0x7b,0x87,0xb5,0x4c,0x69, - 0xcf,0xf1,0xf9,0x4a,0x58,0xa1,0x74,0xfe,0x39,0xc4,0x64,0x19,0xe2,0x1a,0x16,0x83, - 0xa3,0x3b,0xeb,0x4e,0xd1,0xe4,0x28,0x6d,0x9f,0x0e,0x6b,0x66,0xf9,0x51,0x1c,0xce, - 0xf1,0x98,0x4c,0xfc,0x12,0xe9,0xae,0xc9,0x6b,0x8c,0x25,0x85,0x7d,0x9b,0x91,0x34, - 0x0a,0xe4,0x38,0x6b,0x6f,0x32,0xd2,0x79,0x9a,0x46,0x41,0x54,0x82,0x0c,0xed,0xea, - 0x79,0xa5,0x95,0x0c,0x34,0x4f,0xee,0x00,0x54,0xbe,0x81,0xec,0x9a,0x52,0x3e,0xb6, - 0xc1,0x3a,0xe8,0x96,0xd6,0xfe,0xfb,0x45,0x10,0x7f,0xc5,0xa9,0x1f,0x65,0x0f,0xa9, - 0x9d,0x16,0x90,0x7a,0xea,0x40,0x8f,0xfa,0xa4,0x0f,0xdf,0x80,0x20,0x34,0x67,0x79, - 0xd4,0x57,0x77,0xa3,0xa6,0x01,0xf5,0xe9,0x0c,0x8f,0xfb,0x59,0x83,0x68,0x00,0x0c, - 0x75,0x39,0x0d,0xb3,0xc1,0x8d,0x0e,0xef,0x90,0x45,0x77,0x1e,0xe6,0x51,0x85,0x3b, - 0xe6,0x54,0xd9,0xee,0x7f,0xf9,0x37,0x51,0xbd,0xdb,0x68,0x8c,0x28,0xdb,0x80,0xd2, - 0x76,0x9b,0x6d,0xb3,0xb9,0xf6,0x9a,0x10,0x45,0xfe,0x69,0xe7,0x54,0x28,0xd1,0xb3, - 0xad,0xe8,0x62,0x0a,0x56,0x4d,0x51,0x25,0x18,0xea,0x22,0xd8,0x3b,0x28,0xa1,0x86, - 0xc4,0x6e,0xc9,0xe9,0x09,0xd8,0x8d,0xe5,0xd8,0xd7,0xba,0x3d,0x99,0x34,0xd8,0x25, - 0x2c,0x3b,0x76,0x47,0x79,0x2a,0x83,0xc7,0xfe,0x74,0xc7,0xd7,0xb8,0x7f,0x02,0xcb, - 0xb1,0x1d,0x78,0x8a,0x9d,0x1e,0x1e,0x9a,0x61,0xb7,0x0c,0x3e,0x0e,0xc8,0xfb,0xb4, - 0x36,0x40,0x03,0x39,0xdf,0x6f,0xdd,0x5b,0x53,0x66,0xbc,0xb5,0x09,0x96,0x49,0x27, - 0xda,0x97,0x34,0xcd,0x97,0x09,0xdd,0xd4,0x6d,0x1b,0xde,0xd0,0x30,0x31,0x25,0xa4, - 0xb3,0x43,0x66,0xbc,0x4a,0x94,0x25,0x85,0xab,0x50,0xee,0x83,0x7c,0x99,0xa1,0xb2, - 0x94,0xfe,0x7f,0x4e,0x58,0x6f,0xbb,0xe6,0x0a,0x69,0x41,0x94,0xe7,0xcf,0xd7,0xef, - 0xea,0x77,0x4d,0x5d,0x5b,0xe4,0xc0,0x54,0x94,0xc1,0x51,0xee,0x32,0x75,0x4a,0x4b, - 0xdb,0xab,0x41,0x09,0x88,0x65,0x86,0x0a,0xcc,0x47,0x9a,0xb3,0x57,0x2a,0x4d,0x92, - 0x39,0x2d,0x67,0x3a,0xcb,0xea,0x63,0x2e,0x51,0xbc,0xf9,0xc1,0xce,0x45,0x8a,0x88, - 0xc5,0xd4,0x34,0xf2,0x3e,0x3a,0x79,0xa9,0x67,0x43,0x1a,0x69,0x0d,0xf9,0x9a,0x99, - 0x5f,0x66,0xf2,0xa5,0x26,0x37,0x32,0xe9,0x17,0x9e,0x89,0x0e,0x6e,0x7c,0xbc,0x65, - 0x87,0x4f,0xd7,0xe3,0xd5,0x13,0x0d,0xb5,0xb4,0x9c,0xe1,0x6f,0x42,0x72,0x15,0xb6, - 0x59,0x55,0xa2,0x0e,0xb5,0xe7,0x54,0x4c,0xd3,0xa2,0xd8,0x41,0x39,0x4b,0x8b,0xe3, - 0xfe,0xac,0xda,0xae,0x75,0x7d,0x9c,0x15,0x7b,0x23,0x28,0x37,0x9f,0xe7,0xf1,0x06, - 0x03,0x39,0xf2,0xb0,0x2c,0x49,0x19,0x24,0xe2,0x17,0xa0,0x04,0x23,0xa5,0x1e,0xb2, - 0x71,0x4e,0x5c,0x51,0x1b,0xb7,0x7c,0x27,0x20,0x68,0x28,0x2b,0x68,0x4f,0xf8,0x11, - 0xa6,0x68,0x5d,0xd1,0x85,0x1b,0x60,0x1a,0xc4,0xe2,0xe4,0xed,0x11,0x9a,0xeb,0x98, - 0x4b,0x0d,0x41,0xb1,0xa9,0x36,0x0c,0x60,0x65,0x05,0x76,0xea,0x59,0x3a,0xa7,0x4e, - 0x9b,0x25,0x9e,0xf8,0x40,0x12,0x82,0x33,0x1b,0x8c,0xfc,0x08,0x38,0x1d,0xa7,0x49, - 0xc8,0xd0,0xf6,0x4f,0x1b,0x19,0x98,0x36,0x5e,0x0f,0x81,0xd1,0x25,0x21,0x30,0xff, - 0x9c,0xa3,0x19,0xec,0x6e,0xcf,0x63,0x5b,0x9c,0x74,0xc2,0x29,0x0c,0x10,0xaf,0x3d, - 0x4a,0x52,0x50,0x0a,0x01,0x0e,0xdd,0xab,0x84,0xb1,0x30,0x98,0xc8,0x21,0xa6,0xbd, - 0x71,0x50,0xe1,0xf0,0xca,0x22,0x84,0x75,0x4d,0x69,0xdd,0x2e,0x63,0x99,0x11,0x77, - 0x1c,0xa6,0xf2,0xbe,0xd7,0x64,0xe2,0x89,0xd7,0xb9,0x1c,0x2f,0x2b,0xad,0xaf,0xdf, - 0x9d,0xfe,0x78,0xce,0x78,0x60,0x25,0x18,0x5f,0x4a,0x67,0x03,0x10,0x18,0x82,0xc3, - 0x78,0x1e,0x1a,0x14,0x6b,0x9b,0x34,0xb4,0x8c,0xef,0x97,0x1d,0xa5,0x61,0xb6,0x20, - 0xaf,0x45,0x98,0xc2,0x7c,0x87,0xd3,0xa9,0x3a,0x77,0x8f,0x48,0xcf,0xc4,0x04,0xa7, - 0x22,0x40,0xd6,0xa0,0xee,0xe1,0x7a,0x71,0xf4,0xf6,0xf4,0xa7,0x8f,0xef,0x3f,0xbc, - 0xe0,0x1b,0xac,0xe4,0xd5,0x54,0x39,0x1d,0x5a,0x30,0x37,0x57,0x0d,0xfd,0x08,0x65, - 0xc8,0xd8,0xbe,0xdb,0x8a,0x7b,0xcd,0x17,0x6c,0x91,0x81,0xde,0x98,0xe2,0x12,0x5e, - 0xd1,0x3d,0x56,0x0c,0xfc,0xe8,0xfc,0x87,0x32,0xec,0x2c,0xf6,0x17,0x16,0xe8,0x5f, - 0x96,0x48,0x1d,0x36,0xdc,0x64,0x92,0xdb,0x50,0x23,0xff,0x57,0x86,0x69,0x1d,0x64, - 0x05,0xa2,0xf9,0x08,0xb8,0xc7,0xf3,0xaf,0x9f,0x0b,0xd7,0x0a,0xe4,0x98,0xe5,0x1a, - 0x27,0x86,0x6f,0x61,0xd0,0xc3,0x6b,0xc9,0x9b,0x15,0x9e,0xe0,0x42,0xd7,0x69,0xae, - 0xb0,0xa0,0x95,0x51,0x48,0x0d,0xa1,0xb0,0xb5,0x00,0x0b,0x46,0xd2,0xa9,0xa3,0xfb, - 0x38,0x9b,0xcc,0x40,0x22,0xf2,0x20,0x82,0x75,0xe1,0xb6,0xe5,0x17,0x81,0x45,0x32, - 0x66,0x18,0xb0,0x48,0xae,0xd0,0xb7,0x60,0x22,0x26,0xaf,0x0a,0x25,0x70,0x6c,0x25, - 0xde,0x66,0x0d,0xda,0xb8,0x10,0x2e,0xab,0xbb,0xa0,0x2e,0xd1,0x76,0xdb,0xe7,0xb7, - 0xe5,0xe6,0x2f,0xdd,0x02,0x95,0xad,0xeb,0xa9,0xf4,0x26,0xb0,0xaa,0x9a,0x4d,0xc4, - 0x33,0x5f,0x9d,0x76,0x29,0x51,0xfa,0xa9,0x77,0xa1,0x39,0x9b,0x6a,0xa8,0xcc,0x0c, - 0xc2,0x18,0x28,0xb9,0x62,0x47,0xd7,0xc6,0x65,0xa9,0xab,0x26,0xeb,0x14,0xbd,0x76, - 0xef,0xb3,0x2f,0x3b,0xc8,0x18,0x0f,0x57,0x7c,0x55,0xdb,0x5e,0xeb,0x37,0x8d,0xee, - 0xca,0x1e,0x5d,0x25,0xeb,0x33,0xb3,0xfa,0xd5,0xa3,0x2d,0x10,0x86,0x1e,0xae,0x61, - 0x84,0x5f,0x37,0xe2,0x2f,0x20,0xa7,0xe2,0xc0,0x8a,0xb1,0x7a,0xa4,0x57,0xb8,0xa9, - 0xcf,0x22,0xde,0x04,0xc9,0x92,0x65,0x3a,0x0a,0x68,0xd7,0x53,0x87,0x4d,0xf0,0xd9, - 0x3b,0x74,0xbc,0xa3,0x8d,0x07,0x0a,0x52,0x41,0x9b,0xc6,0x2f,0x82,0x2b,0x36,0x0e, - 0x74,0xa0,0xf4,0x3b,0xbe,0x89,0x96,0x77,0x04,0xad,0xf8,0x7f,0x03,0x51,0xde,0x3f, - 0x6b,0x8e,0xf7,0xe9,0x0b,0x68,0x2b,0xdb,0x69,0x1e,0x79,0x7c,0x84,0x0c,0x2b,0xa8, - 0xdf,0x1e,0x5a,0x7d,0x74,0x16,0xb0,0x41,0xbe,0xe0,0xff,0xf8,0x77,0x72,0x23,0xe0, - 0xee,0x50,0x52,0xd3,0x19,0x91,0x5c,0x1e,0xdf,0xd5,0xa7,0xea,0x81,0x8e,0x28,0xde, - 0x06,0xbb,0x0c,0xcd,0xc8,0xce,0xe2,0x4c,0xdf,0x3d,0xe8,0x2a,0x68,0xe1,0x38,0xba, - 0x03,0x5f,0x30,0x1f,0xb3,0x24,0xcb,0x79,0x36,0x2a,0x94,0x23,0xfc,0x88,0xfb,0xc0, - 0x83,0x47,0x3d,0x15,0x27,0xc4,0x5d,0x0c,0x2a,0xf5,0x29,0x17,0xeb,0x78,0x83,0x9e, - 0x9e,0x58,0x75,0x64,0xed,0xc8,0xb3,0x00,0xe8,0xa8,0x74,0xa5,0x0d,0x8c,0xc3,0x0c, - 0xef,0x28,0xa4,0x68,0x0c,0x07,0x18,0xb1,0x8a,0x23,0x4f,0x59,0x23,0x4d,0xba,0x7d, - 0x59,0xaf,0x12,0x75,0x29,0x31,0xdf,0xc9,0x0c,0xed,0x7e,0xbe,0x75,0x49,0xab,0x26, - 0xd5,0x5e,0xcb,0xba,0x79,0x58,0x7f,0xdb,0x70,0x7b,0x57,0x91,0xb8,0x5c,0x00,0xd2, - 0xa4,0x2d,0xaf,0x69,0x99,0x13,0xca,0x5e,0xd4,0xe6,0xee,0xd8,0x83,0x9a,0x24,0x2c, - 0xa5,0x9c,0x2b,0x4d,0x1f,0xa5,0x8a,0xd0,0xcb,0x2c,0x8c,0x43,0xf7,0x8e,0x25,0xc0, - 0x61,0x4a,0x78,0xf3,0xaf,0xfd,0x30,0x47,0xea,0x4d,0xfc,0xb1,0xbc,0x9d,0x58,0x31, - 0x88,0x8a,0x6b,0x9e,0xb9,0x9a,0x5e,0x88,0x47,0xde,0x4f,0x60,0x97,0xbc,0x80,0xf9, - 0xe2,0xef,0x2d,0x51,0x7c,0x43,0x57,0x1d,0x1f,0x94,0x06,0x61,0xe5,0xf8,0xa8,0xd3, - 0x19,0x1d,0xb1,0x58,0x08,0x43,0xe9,0x56,0x22,0x56,0x40,0xeb,0xd2,0xe3,0x61,0x63, - 0x9b,0x0e,0x7c,0x3e,0xd9,0xce,0x40,0x7b,0x59,0xe4,0x4f,0xe1,0x17,0x2a,0x4e,0xf8, - 0x77,0x96,0xcf,0xa3,0xa7,0xf7,0xfe,0x1f,0xa8,0x92,0x75,0xa8,0xab,0x0f,0x01,0x00, + 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xcd,0x7d,0xdb,0x72,0xdb,0x48, + 0x96,0xe0,0xbb,0xbe,0x02,0x96,0x7b,0x4d,0xa0,0x0c,0x52,0x24,0x25,0xca,0x32,0x69, + 0xca,0x2b,0x4b,0x76,0xd9,0x51,0xbe,0x28,0x2c,0x55,0xbb,0xbb,0xb5,0xea,0x1a,0x90, + 0x04,0x45,0x94,0x41,0x80,0x05,0x80,0xba,0x58,0xa5,0x88,0x79,0xda,0xd8,0xe7,0xd9, + 0xa7,0xfd,0x81,0xfd,0x85,0x7d,0xdf,0x4f,0xe9,0x2f,0xd9,0x73,0xc9,0x2b,0x00,0xd2, + 0xb2,0xbb,0x76,0x66,0x22,0xaa,0x2c,0x22,0x2f,0x27,0x33,0x4f,0x9e,0x3c,0xb7,0x3c, + 0x99,0xf9,0xec,0xc1,0x24,0x1d,0x17,0x37,0x8b,0xd0,0x99,0x15,0xf3,0x78,0x7f,0xe3, + 0x19,0xfe,0x71,0xe2,0x20,0xb9,0x18,0x6e,0x86,0xc9,0x26,0x26,0x84,0xc1,0x04,0xfe, + 0xcc,0xc3,0x22,0x70,0xc6,0xb3,0x20,0xcb,0xc3,0x62,0xb8,0xb9,0x2c,0xa6,0xcd,0x3d, + 0xcc,0xcd,0xc7,0x59,0xb4,0x28,0x9c,0x3c,0x1b,0x0f,0x37,0xb7,0x16,0xd3,0xe6,0x38, + 0x4d,0xf2,0x34,0x0e,0x5b,0xbf,0xe6,0xcf,0x67,0xc3,0x70,0x3a,0x9d,0x4e,0x7a,0xed, + 0xde,0xe6,0xfe,0xb3,0x2d,0x2e,0xb8,0x2f,0x2a,0xec,0x47,0x53,0xf7,0xc1,0x55,0x94, + 0x4c,0xd2,0xab,0xd6,0xf1,0x2b,0xcf,0x9d,0x2e,0x93,0x71,0x11,0xa5,0x89,0xeb,0xdd, + 0x5e,0x06,0x99,0xf3,0x69,0xc8,0x79,0xfe,0xcf,0xc3,0xc6,0x56,0xb0,0x88,0xb6,0xf2, + 0x22,0x28,0x96,0x79,0xc3,0x7f,0x3b,0x3c,0x3b,0xf7,0xdf,0x0d,0xbb,0xe1,0x53,0xff, + 0xc4,0xff,0x9b,0x7f,0x3c,0xfc,0x04,0xd5,0x87,0xb7,0x98,0x1d,0xf6,0x1b,0x71,0x74, + 0x19,0x36,0xfc,0x49,0x94,0x15,0x37,0xfd,0x07,0x1d,0xff,0xb2,0x9f,0x2c,0xe3,0xd8, + 0xbf,0x08,0x8b,0xfe,0x8f,0x7e,0x94,0x4c,0xe3,0xe8,0x62,0x56,0xf4,0xdf,0x2f,0xe7, + 0xa3,0x30,0xf3,0x67,0x69,0x3c,0xe9,0x7f,0x18,0xfd,0x1a,0x8e,0x0b,0x3f,0x0f,0x6e, + 0xfa,0xaa,0x07,0x85,0xff,0xd9,0x0f,0xbd,0xdb,0xf0,0xd1,0x23,0x37,0x6c,0x15,0xe1, + 0x75,0x71,0x98,0x26,0x45,0x98,0x14,0xc3,0xc2,0xbb,0xf3,0x47,0xcb,0xdc,0x28,0x3a, + 0xf2,0x17,0xde,0xad,0xfc,0x72,0xa6,0xd0,0xf9,0x51,0x6b,0x12,0xe5,0xc1,0x28,0x0e, + 0x27,0xc3,0x07,0x9d,0x3b,0xf3,0xab,0x3d,0x58,0xb4,0x8a,0x59,0x98,0xb8,0x53,0x7f, + 0xea,0x0d,0xb2,0xb0,0x58,0x66,0x89,0xb3,0xb8,0xf3,0x17,0x69,0x1c,0x6b,0x88,0xb9, + 0x3f,0xf7,0xc7,0x7e,0xca,0x58,0x28,0xfc,0xa9,0x7f,0x31,0xec,0x0c,0x54,0x0b,0x1f, + 0xa1,0x85,0x8b,0x47,0x8f,0x1e,0x4c,0xa1,0x6f,0xd3,0x61,0xc7,0x1f,0xc7,0x61,0x90, + 0x9d,0x46,0xf3,0x30,0x5d,0x16,0x6e,0xe1,0xf9,0x6e,0xde,0x1a,0x07,0x71,0xfc,0x3c, + 0x77,0xbd,0xfe,0x8f,0x6e,0xee,0x79,0xa2,0x45,0x09,0x7d,0xe2,0xdd,0x8e,0xdd,0x89, + 0x8f,0x58,0x81,0xb1,0xa8,0xe4,0x10,0x93,0x09,0x55,0xa1,0x77,0x27,0xea,0xfc,0xe4, + 0xff,0xe4,0x79,0x77,0xaa,0xe5,0x9f,0xa0,0xe5,0xe9,0xb0,0x3d,0x28,0xb5,0x38,0x80, + 0xde,0xb8,0xc5,0x10,0x48,0x42,0xa6,0x7d,0xf4,0xe7,0x50,0x2f,0x7d,0xf4,0x28,0x6d, + 0x4d,0xa3,0x2c,0x2f,0x86,0x43,0x40,0xc4,0x73,0xa8,0xde,0x87,0xce,0x8b,0x61,0xc3, + 0x74,0xa5,0x8b,0xbe,0x31,0xe5,0x17,0x55,0xc8,0x77,0x3e,0x00,0xd5,0x65,0x12,0xef, + 0x76,0x3e,0x4c,0x06,0xd3,0xdf,0x7f,0x07,0x50,0x77,0x7e,0x92,0x5e,0xf5,0x3f,0xde, + 0x41,0x19,0x22,0x0b,0x5d,0x6c,0x0c,0x23,0x79,0xf4,0xe8,0x6d,0x6b,0xb1,0xcc,0x67, + 0xf0,0x31,0x38,0x79,0x0e,0x9f,0x63,0xf7,0xc4,0xeb,0xff,0xed,0xf9,0xdf,0x5a,0x50, + 0x0b,0xfa,0xf1,0xb7,0xe1,0x71,0x0b,0x91,0xee,0xfe,0xec,0xbf,0xf3,0x8f,0x00,0xd8, + 0x55,0x50,0x8c,0x67,0x27,0x25,0x48,0x73,0xef,0xf6,0xb8,0xc5,0xe0,0xa1,0xdf,0x7f, + 0x6b,0x41,0x6f,0xdc,0x77,0xc3,0x77,0x41,0x31,0x6b,0xcd,0x23,0xc8,0xf6,0xdf,0x79, + 0x54,0x35,0x2a,0x5e,0xa5,0xd9,0x51,0x78,0x19,0x8d,0x43,0x5d,0x19,0xe6,0x2f,0x1d, + 0xa6,0xbf,0xff,0x7e,0x7b,0x27,0x27,0x3a,0x09,0xaf,0x9c,0xe3,0x2c,0x9d,0x47,0x79, + 0xa8,0xa7,0xe3,0xc6,0x4f,0x78,0xa2,0x67,0xba,0x4b,0xdd,0x70,0x5b,0x4f,0x4c,0xee, + 0xdd,0xe6,0x30,0xdd,0x6e,0xda,0x1a,0x2d,0xa3,0x78,0xf2,0xe8,0x51,0xce,0x3f,0x86, + 0x43,0x91,0xe2,0x01,0xfa,0x67,0x2d,0x44,0xa7,0xeb,0xf9,0x37,0x38,0xe3,0x77,0xde, + 0xc0,0x98,0x0d,0x03,0xc7,0xb2,0xd8,0x20,0x71,0x5f,0x66,0x59,0x9a,0xb9,0x8d,0x82, + 0x0b,0x35,0x70,0x20,0x69,0x4b,0x7c,0xfd,0xfe,0xfb,0xd3,0x70,0x07,0xa0,0xdc,0xdd, + 0x69,0xb2,0xfb,0xd1,0x5d,0x22,0x49,0x8a,0xa1,0x4c,0x43,0x40,0x17,0xa5,0x94,0xa8, + 0x2b,0xf3,0x6e,0x71,0x55,0x67,0xad,0xf4,0xb3,0x57,0xcc,0xb2,0xf4,0xca,0xe1,0x86, + 0x32,0x81,0x47,0x45,0xf5,0x44,0x1d,0xb8,0xb2,0x9e,0x67,0xf4,0x07,0x26,0x25,0x03, + 0x86,0x81,0xdd,0xbc,0x33,0x68,0xee,0x08,0xc7,0x0f,0x10,0xe1,0xdf,0x13,0x58,0xe7, + 0x8b,0x29,0xcf,0xd1,0x30,0x1f,0xbc,0x6d,0x4d,0xd3,0xec,0x65,0x00,0xdd,0x50,0x8d, + 0x4f,0x81,0x3e,0xa1,0x24,0x76,0xfc,0xce,0x73,0x3d,0xc5,0x6f,0x04,0xe3,0x4a,0x82, + 0x79,0x38,0xdc,0xbc,0x8c,0xc2,0xab,0x45,0x9a,0x15,0x9b,0xce,0x58,0xac,0xe9,0xcd, + 0xab,0x68,0x52,0xcc,0x86,0x13,0x9a,0xc0,0x26,0x7d,0x00,0xa7,0x88,0x8a,0x28,0x88, + 0x9b,0x39,0xac,0xa5,0x70,0xd8,0x41,0x2e,0x57,0x44,0x45,0x1c,0xee,0x1f,0x07,0x45, + 0x11,0x66,0xc0,0x47,0x60,0x68,0x4d,0xe7,0x60,0x39,0x89,0xd2,0x67,0x5b,0x9c,0xb5, + 0xf1,0xec,0x41,0xb3,0xe9,0xfc,0xf8,0xf2,0xfd,0xcb,0x8f,0x07,0xa7,0x2f,0x8f,0x9c, + 0xd1,0x8d,0x43,0x13,0xf4,0x4b,0x80,0xa5,0x7e,0x89,0x92,0x5f,0x16,0xc1,0x45,0xd8, + 0x5a,0xdc,0xf4,0x9d,0x70,0x12,0x15,0x4e,0x54,0xe4,0x4e,0x9e,0x2e,0xb3,0x71,0x98, + 0x3b,0xcd,0x26,0xf2,0xd1,0xe2,0x06,0xc1,0xfc,0x70,0x3b,0x4a,0xaf,0x9b,0x79,0xf4, + 0x25,0x4a,0x2e,0xfa,0xa3,0x34,0x9b,0x84,0x59,0x13,0x52,0xee,0x36,0x5a,0x58,0xff, + 0x76,0x1e,0x5c,0x73,0x27,0xfb,0x9d,0xee,0x5e,0x7b,0x71,0x3d,0x98,0x07,0xd9,0x45, + 0x94,0xf4,0xdb,0x4e,0xb0,0x2c,0xd2,0xc1,0x22,0x98,0x4c,0xb0,0x62,0x77,0x07,0xb2, + 0x80,0xf5,0x2c,0x62,0x64,0x6c,0x71,0x78,0x3d,0xc0,0x7f,0x9a,0xc0,0x18,0x43,0xc2, + 0x56,0x7f,0x9c,0xc6,0xcb,0x79,0x32,0xb8,0x08,0x16,0xfd,0x0e,0x94,0x05,0xf0,0xf3, + 0x34,0x49,0x6f,0xa7,0x80,0x95,0xe6,0x34,0x98,0x47,0xf1,0x4d,0x1f,0xe8,0xd2,0x6d, + 0x36,0x31,0xd9,0x83,0xec,0x49,0x34,0x3f,0x85,0x99,0xba,0x85,0x8a,0x69,0x26,0xf3, + 0x96,0x45,0x38,0xc1,0xcc,0x59,0x94,0x14,0x5c,0x17,0x3a,0x1e,0x42,0xd7,0xa0,0xf5, + 0x95,0x05,0xfb,0xe1,0x7c,0x51,0xdc,0xdc,0xca,0xde,0x25,0x69,0x12,0x42,0x4e,0xbe, + 0x08,0xc6,0x61,0x76,0x4b,0xdd,0xbc,0x00,0xd2,0xe9,0x77,0x20,0xf1,0x62,0x96,0xe6, + 0xc5,0x8b,0x22,0x21,0xd8,0xfd,0x28,0x99,0x85,0x59,0x54,0x0c,0x8c,0x86,0x3a,0xd8, + 0xd0,0x32,0xcb,0xa1,0xa5,0x45,0x0a,0xb0,0xc3,0x6c,0xc0,0x38,0xeb,0x43,0x0e,0xe0, + 0x37,0x8e,0x26,0x0e,0x77,0x21,0x5b,0xc6,0xa1,0x27,0x32,0x9b,0x59,0x30,0x89,0x60, + 0xad,0x63,0x37,0x47,0xc1,0xf8,0x33,0xb4,0xb7,0x4c,0x26,0xa2,0xaf,0xd3,0x28,0x84, + 0x65,0x55,0xd3,0x7d,0x85,0xdc,0x5d,0x00,0x8d,0x43,0x34,0x3a,0x78,0x16,0x64,0x51, + 0xd0,0x5c,0x64,0x61,0x9e,0x03,0xab,0x2f,0xb2,0x65,0x78,0x7e,0x2b,0xda,0x32,0x01, + 0xc5,0x61,0x09,0x72,0x94,0x7c,0xf6,0x0c,0x30,0xad,0x49,0x90,0x58,0x18,0x1e,0x05, + 0x84,0xb6,0x22,0x4d,0xe3,0x51,0x90,0xdd,0x56,0x67,0xf4,0x2a,0x83,0x19,0xc4,0x7f, + 0x06,0x01,0x08,0xb7,0xa4,0x19,0x15,0xe1,0x3c,0xef,0x8f,0x43,0x42,0x05,0xcd,0x6e, + 0x1b,0x7b,0x4b,0x53,0xfc,0x10,0x49,0xe4,0x35,0x4d,0x15,0x54,0xed,0x77,0x9c,0x8e, + 0xd3,0xed,0x86,0x73,0x6c,0x1f,0xf0,0x14,0xae,0x85,0xae,0x41,0xed,0xd1,0xc0,0x27, + 0xc1,0x7c,0x01,0xb8,0xb0,0xeb,0xac,0xe8,0x82,0x55,0xc3,0x89,0x92,0xc5,0xb2,0xb8, + 0x15,0x34,0xbc,0x8d,0x24,0x1c,0x8c,0xb1,0x70,0x05,0x51,0x46,0x1d,0x83,0x38,0xf5, + 0xbc,0x03,0x17,0x16,0x4b,0xa1,0xb7,0x4b,0x2d,0x14,0xe9,0xc5,0x45,0x1c,0x7e,0x82, + 0xee,0xda,0xf4,0xc2,0x80,0xd5,0x97,0x4d,0x2e,0xf7,0x19,0xc0,0x13,0xa4,0x93,0x7a, + 0xb2,0xc2,0x09,0xfc,0x06,0xaa,0x92,0x24,0xd4,0x43,0x4c,0x76,0x8c,0x5e,0xbf,0x0d, + 0x46,0x61,0x5c,0x1e,0x21,0x7d,0x5e,0x85,0xa4,0xb4,0xf4,0xda,0x6d,0x55,0x58,0x60, + 0xaf,0x8b,0x2d,0xcd,0x38,0xbb,0x53,0xdb,0x6a,0x1d,0xd1,0xe3,0x60,0x16,0x69,0x1e, + 0x11,0x1b,0xc8,0xc2,0x38,0x28,0x40,0x67,0xa2,0xe9,0xa6,0xa5,0x38,0x10,0x88,0x69, + 0x86,0x97,0x80,0x80,0x5c,0x2e,0xcf,0x49,0x5a,0xfc,0x74,0xab,0xaa,0x05,0x23,0xc0, + 0x01,0x2c,0x8a,0x41,0x1c,0x4e,0x0b,0xc4,0xc9,0x00,0xe5,0x39,0xfe,0x15,0xf3,0xda, + 0x36,0x7a,0xd6,0x5e,0x83,0x0f,0xbb,0x6b,0xbd,0xf6,0x7f,0x19,0x14,0x59,0x90,0x88, + 0x56,0x10,0xb8,0xd3,0x6e,0x75,0xba,0xb9,0x35,0xb9,0x2d,0x90,0x0c,0x12,0x11,0x15, + 0xb8,0xe9,0x67,0xaf,0x5a,0x98,0x3a,0xcf,0x5d,0x25,0x9c,0x3f,0xc4,0x05,0x7d,0xca, + 0x10,0x78,0xca,0xf3,0x30,0x9e,0x12,0x09,0x34,0x41,0x52,0x65,0x05,0x72,0xdb,0x38, + 0x2d,0x88,0x94,0xaa,0xb8,0x8a,0x60,0xf0,0x01,0x25,0xf1,0xaf,0xf0,0x2b,0xc3,0xbb, + 0x37,0x2f,0x4a,0x2f,0xc3,0x0c,0x65,0x4b,0x7f,0x16,0x4d,0x26,0x61,0x02,0x1d,0xc5, + 0x5e,0xa8,0x35,0x36,0x8a,0xd3,0xf1,0x67,0x49,0xbf,0x93,0x70,0x1a,0x2c,0xe3,0x42, + 0x21,0x1c,0x50,0x27,0x10,0x3e,0x8e,0x61,0xd5,0xb8,0xdd,0x1d,0xc0,0xbb,0xbf,0xd3, + 0xbb,0x9c,0xf9,0x3b,0x6d,0xf8,0x49,0x68,0x09,0x2e,0x9c,0x71,0x90,0x5c,0x06,0xb9, + 0xdf,0x1a,0xcf,0xa2,0xc5,0x61,0x90,0x4d,0x44,0x82,0x5c,0x90,0x7b,0x36,0x49,0x71, + 0xa5,0x9a,0x89,0xbf,0xcf,0xb2,0xd9,0xad,0x9b,0xf8,0x71,0x16,0x06,0xf3,0x66,0xf7, + 0x9b,0x71,0xa3,0x24,0x1b,0x94,0x67,0x12,0xae,0x90,0xe9,0xe0,0x6a,0x06,0x7d,0x68, + 0x92,0x24,0x81,0x04,0xe4,0x5b,0xdc,0x7f,0xd0,0xdd,0xe2,0x95,0xec,0xf8,0x0b,0xac, + 0xe1,0x09,0xb2,0x43,0x51,0x96,0x98,0xfd,0x29,0x0c,0x3a,0x05,0x38,0x11,0xd8,0x11, + 0xed,0x56,0xaf,0x87,0xf2,0x51,0xa4,0x4b,0x84,0x95,0xe4,0x17,0x54,0x25,0xf9,0xb8, + 0x42,0x82,0x9a,0x42,0xab,0x4d,0x78,0x5d,0x5c,0xd6,0xa0,0x35,0x4a,0x50,0xe9,0x6d, + 0xab,0x4e,0x75,0xef,0x23,0xc4,0x57,0x50,0x1f,0xb5,0xf1,0x1a,0x6c,0xb7,0x6f,0x15, + 0x1b,0xbf,0x2e,0xf3,0x22,0x9a,0xde,0x34,0x85,0x8a,0xd4,0x27,0x84,0x36,0x47,0x61, + 0x71,0x15,0x86,0x89,0xe4,0xe8,0x24,0x53,0xd4,0xac,0xb0,0x68,0xe8,0x8a,0x81,0x1d, + 0x02,0x6d,0xe5,0x5f,0x15,0x27,0x7b,0xa2,0xf4,0x49,0x74,0xf1,0x1f,0x2c,0xdf,0x89, + 0x89,0xd7,0xb0,0x66,0xea,0x1b,0x70,0x90,0x95,0xb4,0x63,0x32,0xe8,0x5d,0x64,0xd0, + 0x0f,0xa1,0xca,0x38,0x5d,0x84,0xa5,0x35,0xab,0xe4,0x6d,0x9b,0xa4,0x96,0x58,0x60, + 0x6d,0x63,0xf1,0x52,0x6b,0x6f,0xc3,0x8b,0x30,0x29,0x4d,0x97,0x94,0x3f,0xd5,0x79, + 0xa2,0x2a,0x3f,0x85,0x37,0x6f,0x12,0x9f,0x7f,0x7c,0xd0,0x72,0x75,0x57,0x2f,0xe3, + 0x6d,0x43,0x13,0x8c,0x92,0x38,0x4a,0x60,0x2a,0xb1,0x53,0xba,0x7a,0x95,0x8b,0x4e, + 0x03,0xc0,0xb5,0x27,0x4b,0x20,0xdc,0x4a,0x11,0x21,0xa1,0x3f,0x27,0xe9,0xe8,0x63, + 0x7a,0xf5,0x3d,0x9a,0x09,0xcf,0xff,0xb8,0x4a,0x2b,0x22,0x53,0x63,0x0d,0xf5,0x16, + 0x51,0x14,0x59,0xd6,0x1f,0x2c,0xdd,0xf7,0xbe,0x2a,0x9f,0xbe,0x99,0x49,0x3d,0xd1, + 0xab,0x41,0x76,0x7a,0x1d,0x0f,0x2a,0x15,0x73,0xe8,0xeb,0x3d,0x18,0x2c,0xb7,0x15, + 0x02,0xd3,0x05,0x89,0x1f,0xe1,0x4a,0x2b,0x33,0x2a,0x2c,0x71,0x94,0x4a,0x52,0x30, + 0x28,0xa1,0x96,0x1f,0x13,0x1d,0xdb,0x23,0xe9,0x58,0x1d,0xaf,0x55,0xbe,0xc8,0x1c, + 0x49,0x60,0x44,0x5f,0xd5,0x19,0x81,0x4b,0x38,0xdd,0xf6,0x1f,0x8f,0xe2,0xce,0xae, + 0x56,0x46,0x47,0x41,0x32,0x21,0x46,0x47,0x14,0xd3,0x76,0xda,0x0e,0xc9,0xc3,0xfb, + 0xd2,0xe4,0x28,0x00,0xa4,0xc3,0xba,0xa0,0x0e,0xa3,0x7c,0xd1,0x50,0xf5,0x24,0xf0, + 0xd0,0xb7,0x4b,0x5a,0x19,0xcc,0x49,0xbd,0xd4,0x81,0x29,0xbe,0xbd,0xa7,0xfd,0xb5, + 0x67,0xe9,0xb2,0x6d,0xae,0xdc,0x42,0x1b,0xe8,0xd6,0xe0,0x1b,0x84,0x4c,0x41,0x52, + 0xcb,0xec,0x32,0x3c,0x84,0x06,0x94,0xd2,0xc6,0x75,0x7e,0x8a,0xc6,0x9f,0xd1,0x84, + 0xba,0x97,0x04,0x02,0xd5,0x0d,0x6d,0x59,0xea,0x37,0xe2,0xb3,0xdd,0x6a,0x3f,0x0d, + 0xe7,0xf5,0x56,0xdb,0x65,0x26,0xf9,0xca,0x4a,0x25,0x53,0x76,0xeb,0x6b,0xbc,0x40, + 0x0e,0x83,0x68,0x02,0xf8,0x25,0x55,0xaa,0xe3,0x96,0x2c,0xd0,0xa9,0xd5,0x6d,0xd4, + 0xef,0x07,0x86,0xe5,0x6b,0x28,0x3b,0x5d,0x41,0x02,0x68,0x7a,0x85,0x45,0x8e,0x58, + 0x11,0xca,0xf1,0xae,0x62,0x21,0x04,0xea,0xfe,0x93,0xa1,0xa0,0xfd,0x98,0x45,0x9a, + 0x19,0x5f,0xc0,0xc7,0x00,0xff,0x69,0x02,0xcd,0x2c,0x50,0xeb,0x6b,0x72,0xb5,0x1c, + 0x14,0xc3,0x45,0x18,0x14,0xee,0xb6,0x0f,0xb3,0x08,0xbd,0x74,0xdb,0x7e,0x67,0x9a, + 0x79,0x5e,0x05,0x5e,0x89,0x6f,0xad,0xe1,0x54,0xf5,0xfd,0x5b,0xc1,0xbf,0x7a,0xab, + 0xad,0x93,0x7b,0x0b,0x45,0xd2,0xca,0xb4,0x0c,0x7c,0x0a,0x70,0x76,0x58,0xd1,0x52, + 0xbd,0xb7,0x15,0xc5,0x1d,0x43,0xc3,0xef,0xee,0x98,0xc5,0x80,0xa0,0x92,0xdb,0x12, + 0xad,0x95,0x0c,0x99,0x3a,0x13,0x98,0x6b,0xaf,0x11,0xb6,0x66,0x19,0xa3,0x11,0x8b, + 0x39,0xe6,0x45,0xb8,0xc8,0x2b,0x24,0xb8,0xc6,0xaa,0x2b,0xab,0x1a,0x75,0xd4,0x2f, + 0x81,0x3a,0xa3,0x65,0x51,0xa4,0xc9,0xda,0x59,0x14,0x04,0x6b,0x18,0x66,0xdb,0x26, + 0xd3,0x6a,0x0f,0x48,0xfe,0x4a,0x05,0xfb,0x8f,0x9a,0xb6,0x1a,0x74,0x12,0x73,0xbd, + 0x2f,0x07,0x62,0xf3,0x99,0xaa,0xdc,0x07,0x79,0xf7,0xd2,0x0f,0x25,0xc0,0x5a,0xc3, + 0xb6,0x16,0xcf,0xe9,0xb2,0x38,0xcd,0x60,0x84,0x35,0x16,0x97,0x44,0xd8,0x5e,0x55, + 0x1d,0x2c,0xd2,0xe5,0x78,0xd6,0x0c,0x78,0x4c,0x40,0x15,0xcd,0x1b,0x06,0xf5,0x31, + 0x88,0xe2,0x55,0x06,0x2b,0xae,0x98,0x8c,0x89,0x51,0x98,0xae,0x3d,0x83,0xa3,0x28, + 0xa7,0x5a,0x13,0x73,0x9a,0x6b,0x79,0x1e,0x34,0xf4,0x2a,0x8a,0xeb,0x1a,0x2a,0x41, + 0xdd,0x2e,0x43,0x6d,0xf5,0x56,0x49,0x63,0x06,0xfb,0x1a,0xa4,0x0f,0x98,0xa7,0xab, + 0x01,0x33,0xa9,0x3d,0x2d,0x19,0xda,0xc2,0x1d,0xd8,0x44,0x2d,0x16,0x05,0x61,0x73, + 0xa7,0xbe,0xa1,0xf5,0xc2,0x57,0x10,0x11,0x74,0xe3,0x98,0xf9,0xea,0x57,0x79,0x3a, + 0x93,0x90,0xaa,0xb0,0x52,0xa1,0x6f,0xff,0xf1,0x0a,0x7d,0xcd,0x22,0x28,0x39,0xec, + 0xb6,0x95,0x4c,0x07,0x3a,0xc9,0xbf,0x5b,0x57,0x7d,0x18,0xea,0x15,0x25,0x68,0x3f, + 0xa7,0xd4,0x33,0x58,0xd4,0x59,0x71,0xee,0xec,0x3b,0x3f,0x98,0xca,0x98,0x91,0x37, + 0x14,0x25,0xfa,0x51,0xee,0x0a,0xef,0x84,0x4f,0x8e,0x30,0x5f,0xcf,0xb5,0x4f,0xde, + 0x51,0xef,0xf6,0x32,0xca,0xa3,0x51,0x14,0x23,0x10,0xe9,0x07,0xf8,0xaf,0xf3,0x70, + 0x12,0x05,0x8e,0x6b,0xc8,0xc0,0x0e,0x19,0xf5,0xb7,0x28,0x9b,0x4b,0x96,0xa8,0x54, + 0x0f,0xfc,0x1a,0x3d,0x42,0x9a,0x1a,0x5a,0x5a,0x6a,0x57,0x20,0x02,0x14,0x54,0x45, + 0x0a,0x77,0x5d,0xb3,0x4f,0x44,0xab,0xe4,0x8b,0x36,0x55,0x31,0x43,0x3f,0x61,0xa7, + 0x05,0xd6,0x91,0x2b,0x6a,0xb7,0x6d,0x68,0x8c,0xaa,0xd6,0x8e,0xe1,0x46,0x45,0xff, + 0xa3,0xaf,0x9c,0x8a,0xe5,0xee,0x2a,0x37,0xa0,0xc1,0x51,0x2a,0xde,0x3f,0xdb,0xbf, + 0xc8,0x20,0x8c,0xe1,0x94,0x55,0x2c,0x32,0x3b,0x68,0xf2,0x41,0xfd,0x8b,0x72,0x56, + 0x2a,0x34,0x25,0x6b,0x5b,0xc3,0x36,0xdd,0x04,0x84,0x35,0xcc,0xb4,0x6d,0xf9,0x89, + 0xb5,0x11,0x00,0x2a,0x79,0xd5,0xeb,0x62,0x4f,0xdd,0x43,0xb0,0x1c,0x13,0x58,0x40, + 0xb8,0x4b,0x71,0x2b,0xb8,0x05,0x31,0xac,0xd2,0x7c,0x88,0x95,0x03,0xad,0xe2,0x66, + 0x2c,0x4c,0x87,0x62,0x9d,0x92,0xdb,0xa8,0xe5,0x28,0xd8,0x48,0xd5,0x2c,0xec,0x76, + 0x0d,0x6e,0x81,0x4c,0x99,0xd9,0x45,0x9d,0xaf,0xd6,0x30,0x59,0xb7,0x69,0x3c,0x06, + 0x15,0xa3,0x8b,0xcc,0x57,0xfe,0x6b,0x9f,0x4d,0x66,0x3d,0x4e,0x5f,0xb3,0x04,0xbf, + 0x2c,0x48,0xbd,0x2a,0xa3,0xff,0xc3,0x40,0xf7,0xfb,0xc1,0x14,0x30,0x74,0x2b,0x45, + 0x94,0xb3,0xb9,0x39,0x58,0xe5,0x6d,0xc1,0x31,0x3b,0x4d,0x1c,0x18,0x34,0x9f,0xa5, + 0xa9,0xd8,0xe3,0x68,0xe6,0xe3,0x59,0x38,0x0f,0xfb,0xb4,0x67,0x3c,0x10,0x6c,0xa6, + 0xff,0xf0,0xd5,0xce,0xcb,0x57,0x2f,0x77,0xe1,0x9b,0xa8,0x19,0xbe,0x5f,0xbd,0x3a, + 0x7c,0x75,0x30,0x20,0x9e,0xd9,0x7f,0xd8,0x39,0xe8,0xec,0x75,0x76,0x06,0x82,0x03, + 0xf5,0x1f,0xee,0x76,0x7b,0x87,0xbd,0xce,0x40,0x58,0xd4,0xfd,0x87,0x4f,0x8e,0x9e, + 0xec,0xee,0xee,0x0d,0x98,0xbb,0xf5,0x1f,0x1e,0x1d,0x1d,0xf5,0x0e,0x77,0xc5,0x67, + 0x33,0x4f,0x61,0xaa,0x1f,0xbe,0xdc,0x7b,0xd9,0x39,0x42,0x10,0x34,0x72,0xf8,0xde, + 0x3e,0x3a,0x3c,0x7c,0x39,0x20,0xd9,0x80,0xcd,0xf5,0x0e,0xbb,0xf8,0x35,0x0a,0xe0, + 0xeb,0xc5,0xde,0xf6,0x61,0xe7,0x70,0x80,0x6e,0xcf,0xfe,0xc3,0xee,0x8b,0x27,0x07, + 0x3b,0x2f,0xe0,0xe3,0x2a,0xc8,0x92,0xfe,0xc3,0xbd,0x1e,0xe8,0x44,0x58,0x32,0x0f, + 0x40,0x47,0xcd,0x6f,0x00,0x45,0xf3,0xe6,0x32,0xf2,0x9b,0xc1,0x62,0x81,0x8d,0x51, + 0x82,0xdf,0x38,0x09,0x2f,0xd2,0xd0,0xf9,0xf9,0x4d,0xc3,0xff,0x98,0x8e,0xd2,0x22, + 0xf5,0xb1,0x78,0x33,0x07,0xbe,0x3d,0x1d,0xb0,0xe5,0xd0,0x5f,0x46,0xf4,0x97,0xc4, + 0xbc,0xdf,0x38,0x0c,0xf2,0x71,0x80,0x64,0xf8,0x0e,0xd2,0x1a,0x00,0xe0,0x95,0xf8, + 0xf5,0x2e,0x4c,0xe2,0xd4,0x3f,0xa4,0xed,0xff,0x20,0xf7,0x1b,0x0c,0x4f,0x64,0x2a, + 0x00,0x03,0x21,0x7b,0x04,0xa7,0x26,0x2c,0x7a,0x03,0xe5,0x17,0x14,0xc9,0x34,0x76, + 0x10,0x41,0x18,0x8b,0x70,0x36,0x09,0x8a,0xa0,0x59,0xe0,0x64,0x0c,0x27,0x41,0xf6, + 0xf9,0xdc,0x9e,0x1f,0x4c,0xd2,0xd3,0xd3,0x3e,0x6c,0xbf,0x68,0x3f,0xd5,0xd3,0xd3, + 0xd9,0xee,0x00,0xab,0x94,0xd3,0xf3,0xf2,0xe8,0xe5,0x93,0xa3,0x17,0x7a,0x7a,0x0e, + 0xb6,0x9f,0xbe,0xd8,0x3b,0x30,0xa6,0xe7,0xe0,0xc9,0xf6,0xee,0x8e,0x9a,0x9e,0xee, + 0x8b,0xee,0x93,0x6e,0xc7,0x9e,0x9e,0xce,0xab,0xce,0x61,0x67,0x4f,0x4f,0x4f,0xf7, + 0xa0,0xbb,0xdb,0x6d,0xcb,0x09,0x79,0xf5,0xea,0xc9,0x41,0xaf,0x27,0x26,0xa4,0xf7, + 0xe4,0xc5,0xde,0x93,0x57,0x6a,0x42,0x8e,0x9e,0x1e,0xb4,0xb7,0x5f,0xdd,0x6d,0x9c, + 0x31,0x57,0x3f,0xb7,0x16,0xff,0x83,0x68,0x8e,0xfb,0x92,0x41,0x52,0xdc,0x6d,0x8c, + 0xd2,0xc9,0xcd,0xad,0xdc,0xd7,0xbb,0xb7,0xd2,0x47,0x52,0xb6,0xdf,0x01,0x69,0xbf, + 0x05,0xca,0x85,0x10,0xa2,0x38,0x99,0x80,0xdd,0xab,0x70,0xf4,0x39,0x02,0xa3,0x90, + 0xe4,0xf0,0x1c,0x48,0x7c,0x86,0xfc,0x09,0x1a,0x8b,0x40,0xde,0x81,0xf5,0x3b,0xb9, + 0xdb,0x08,0x6e,0x2d,0x47,0xca,0x5d,0x7f,0x9a,0x8e,0x97,0x79,0x93,0x84,0x11,0x30, + 0x10,0x58,0x6b,0xa8,0xba,0x92,0x79,0x6c,0x4a,0x69,0x72,0x1f,0x88,0xcc,0x66,0x3a, + 0x9d,0xe2,0x82,0x62,0x9e,0x87,0xe2,0xd4,0xdc,0xae,0x6c,0xaf,0xdb,0xae,0x24,0xf7, + 0x21,0xf2,0xcb,0x1d,0x62,0x40,0xb3,0xae,0x1c,0x3f,0x49,0x09,0xe0,0x4c,0x83,0xaf, + 0x18,0xe1,0xb5,0x1a,0xe5,0x3c,0x07,0x7e,0x91,0x2f,0x47,0xac,0x8d,0x90,0xd9,0x69, + 0x1a,0xc4,0x66,0x1d,0xe1,0xf1,0x6a,0x2d,0xa6,0x30,0x75,0xd6,0x16,0x1c,0xee,0x28, + 0x60,0x72,0x98,0x65,0x75,0x5b,0x73,0xc8,0x8e,0x6e,0xeb,0xfc,0x6b,0x5a,0xe9,0x77, + 0xf6,0xbe,0xcd,0x42,0x7b,0xfa,0x54,0x0c,0x90,0x94,0xe5,0x2d,0x42,0xce,0xaa,0x7e, + 0x0b,0x4d,0xa7,0xde,0x07,0x01,0x5d,0x6b,0xc1,0x68,0x6a,0x0c,0x2a,0x18,0xd4,0xa0, + 0x32,0x48,0x2a,0x2f,0x46,0x5a,0x53,0x07,0x07,0x3c,0xa8,0x60,0x80,0x6a,0xd5,0x6e, + 0xe9,0x4e,0x81,0xce,0xc2,0xec,0x0f,0xb0,0x26,0x3a,0xbb,0xb6,0xf2,0xdc,0xdd,0x55, + 0xf8,0x6c,0x8a,0x7d,0xa7,0x1a,0x9c,0xde,0x7b,0xce,0x45,0x47,0x9d,0xa0,0x3c,0x8d, + 0xab,0x7a,0x6c,0xc8,0x43,0x32,0x83,0x6b,0xe6,0x03,0x83,0x1a,0x9a,0x93,0x70,0x9c, + 0x66,0xbc,0x51,0xc4,0x18,0xc1,0x40,0xaa,0x75,0x18,0x51,0x8e,0xa8,0x1a,0x05,0x5b, + 0x6b,0x4b,0xb3,0x8e,0xd4,0x6e,0x14,0x8f,0xd0,0x8b,0x83,0xc4,0x7a,0x79,0x71,0x94, + 0x5c,0x3d,0xcd,0x56,0xbb,0x83,0xdb,0xbe,0x0b,0xc5,0x64,0x80,0x58,0xe2,0x28,0x2f, + 0x34,0xd3,0x31,0x0d,0xd6,0x1c,0x40,0x63,0x6c,0x02,0xfb,0x51,0xbe,0x86,0x77,0x01, + 0x6a,0x3f,0x8e,0xbe,0x47,0xcf,0x26,0xa7,0x5e,0x5b,0x38,0xc4,0x24,0x8e,0xf7,0x0c, + 0x0b,0x1a,0x0b,0xb4,0x07,0x2a,0x2e,0x02,0x84,0xfd,0xbc,0xb6,0x1f,0xc4,0xad,0xa1, + 0x33,0xa4,0xc1,0x9c,0x61,0x78,0xdb,0x30,0x0b,0x92,0x8b,0xf0,0xfc,0xb6,0x66,0xb7, + 0xb9,0xb4,0x0b,0xaf,0x54,0x0d,0x63,0x43,0x59,0x2f,0xe6,0xd2,0xce,0x7f,0x8d,0x5e, + 0x62,0x54,0x2b,0xa9,0x4e,0x83,0x9a,0x65,0x55,0xc7,0x01,0x6a,0x5d,0xd2,0x42,0x54, + 0xd6,0xf3,0xfd,0x5e,0x1b,0x7a,0xb6,0xad,0x88,0x9d,0xf9,0xbe,0xb1,0x97,0x6a,0x36, + 0xec,0xb4,0x3a,0xbd,0xdc,0x18,0x42,0x7f,0x86,0x1b,0x8f,0x86,0x3e,0xc5,0x09,0x75, + 0x3c,0x80,0x1a,0xfc,0x4a,0x00,0x83,0x6f,0x7d,0x09,0x58,0x55,0xbe,0x51,0x53,0x68, + 0x05,0xd3,0x01,0xb5,0x4c,0x46,0xd1,0x29,0xf3,0xaa,0xb5,0xd3,0x2b,0xed,0x84,0xda, + 0x01,0x00,0xd2,0xb1,0x2a,0xe6,0x8d,0xd5,0xe8,0xbd,0xf2,0x86,0x3b,0x9b,0x5c,0xfe, + 0x0a,0x4f,0x05,0xa0,0xf3,0xae,0x92,0xb5,0x66,0x3b,0xde,0xdc,0x3b,0x35,0x58,0xd4, + 0xba,0x39,0x55,0x1b,0x2d,0x7a,0x8b,0xba,0x2b,0x5c,0x12,0x5d,0xbd,0x9b,0xde,0xad, + 0x6e,0xca,0xde,0x6f,0x37,0x9c,0xdc,0x09,0x6b,0x76,0xc3,0x85,0xe3,0x4e,0x6c,0x75, + 0xfb,0xc2,0x42,0x2b,0xed,0x06,0xb4,0xe5,0x36,0xb0,0x2f,0xec,0xc6,0x75,0x9a,0xf7, + 0x6d,0x65,0xd0,0x22,0xb4,0xc8,0x97,0x3b,0xa4,0x7e,0x69,0x67,0xc1,0xb7,0xa3,0x3c, + 0x7c,0xd3,0x8f,0x58,0xdb,0x52,0x29,0xd0,0x68,0x85,0xa7,0xbe,0xc7,0x86,0x97,0xe5, + 0x15,0x47,0x66,0x58,0x5d,0x25,0x65,0x47,0xb8,0xe1,0xd6,0xa9,0x20,0x54,0x90,0xbb, + 0xdc,0x62,0xb1,0x05,0x9e,0xb0,0xe9,0x6c,0x47,0x35,0x2a,0x33,0x0e,0x6a,0x22,0x96, + 0x41,0xb7,0x57,0xe2,0xd2,0x3b,0x6d,0xc9,0x83,0x1d,0x11,0x4c,0xa5,0x4c,0xe0,0x5d, + 0x8a,0xd0,0x41,0xbd,0x64,0x3a,0x45,0xe1,0xe0,0x98,0xf3,0x65,0xa4,0x62,0x65,0x3b, + 0x05,0x35,0x1f,0xb5,0x5e,0x7a,0x77,0x1b,0xcf,0xb6,0x44,0x8c,0xd9,0xb3,0x2d,0x11, + 0xd2,0x8b,0x9a,0x26,0x06,0xc8,0x01,0x15,0x3a,0x63,0x50,0xda,0xf3,0xe1,0x26,0x72, + 0x67,0x07,0xcd,0x7b,0x19,0xf9,0x1b,0x66,0xfb,0xcf,0x66,0x9d,0x7d,0x11,0xec,0x06, + 0xbf,0x9e,0xe1,0xcc,0xc8,0xe2,0xd0,0xc6,0xa6,0x13,0x4d,0xe0,0x47,0x41,0x31,0xbe, + 0x90,0xb5,0xcf,0xe0,0xa1,0x1e,0x00,0xe8,0xee,0x9f,0x70,0x90,0x1b,0x24,0x76,0x21, + 0x61,0x19,0xcb,0x9a,0xd8,0x5f,0x6c,0x23,0x8e,0xb0,0x23,0x44,0x3c,0x04,0x68,0x1e, + 0x8d,0x39,0x34,0x63,0x53,0x96,0xd4,0xf4,0xbb,0xe9,0x48,0x46,0x80,0x01,0x73,0x46, + 0x37,0xb8,0xc8,0xa6,0xdd,0x37,0x24,0x74,0xa3,0x53,0xf4,0xa7,0xae,0x1a,0xad,0xee, + 0xcd,0xfd,0x77,0xd1,0x38,0x4b,0x17,0x33,0x98,0x4a,0x55,0x76,0x8b,0xfb,0x25,0x6b, + 0x89,0xee,0xe1,0xa6,0x9b,0xea,0x1c,0x92,0xc2,0x66,0x3d,0x74,0x0e,0x69,0x33,0x32, + 0x27,0xd1,0xa5,0xea,0x1b,0xd3,0x3c,0x21,0x00,0x9b,0x97,0xe9,0x9a,0xdd,0x6c,0x3a, + 0xd3,0x34,0xa3,0xf6,0x7e,0x84,0xe9,0xd9,0xdc,0x7f,0x83,0x92,0xcc,0xb9,0x80,0xdf, + 0xcf,0xb6,0xa8,0x0a,0x54,0x25,0xe9,0x26,0xbb,0x45,0xc5,0x1c,0x12,0x75,0x9b,0x24, + 0xeb,0x36,0x1d,0x10,0x3f,0xc3,0xcd,0x0e,0xfc,0x0d,0xae,0xe1,0xef,0xee,0xa6,0x83, + 0x6b,0x68,0xb8,0xd9,0x6e,0xf5,0xaa,0x98,0x34,0xa0,0xfc,0x39,0x88,0xd5,0xf8,0x70, + 0x4d,0x3a,0x22,0xf8,0xcf,0x18,0xca,0x16,0x8c,0x05,0xfe,0x2c,0xa8,0x1a,0x07,0x4f, + 0xbe,0x07,0x2d,0x4a,0x55,0x43,0x22,0xc6,0xe6,0x80,0xde,0x60,0x50,0xb6,0x9b,0x05, + 0xc1,0x2c,0x10,0x06,0x4d,0x7d,0x1c,0x11,0x0c,0x00,0x0f,0x6b,0x7b,0xd3,0xa6,0x85, + 0x60,0x39,0xf9,0x8f,0xa1,0x85,0x17,0x59,0x7a,0x05,0x36,0xb0,0x03,0xbd,0x0a,0x41, + 0x84,0x42,0x77,0x80,0xc5,0x38,0x44,0x1c,0x0e,0xd8,0xcf,0xeb,0x08,0x04,0xe3,0xc5, + 0xef,0x49,0x20,0x84,0xa4,0xfd,0xd3,0x59,0x68,0xb4,0x33,0xca,0x80,0x2c,0x72,0x0a, + 0x0f,0x4d,0xaf,0x12,0x98,0xb9,0x05,0xd2,0xc9,0xc0,0x01,0xfb,0x57,0xb7,0xef,0x2c, + 0xf3,0x30,0xa7,0x24,0x4c,0x80,0x1e,0xa7,0x57,0x2d,0xe7,0x04,0x38,0xa0,0x93,0x5f, + 0x45,0xc5,0x78,0xe6,0x04,0xb9,0x73,0xf0,0xf3,0x11,0xe4,0x72,0x3d,0x64,0xeb,0xff, + 0xf8,0xd7,0xff,0x95,0x3b,0xef,0x5f,0x9e,0x7e,0xfa,0xf0,0xf1,0x27,0x27,0x07,0x23, + 0x32,0x4c,0x5a,0x1b,0xcf,0x02,0x67,0x96,0x85,0x53,0xe8,0x4a,0x51,0x2c,0xf2,0xfe, + 0xd6,0xd6,0x45,0x54,0xcc,0x96,0x23,0xe0,0x9b,0xf3,0xad,0x30,0xb9,0x98,0x2f,0x93, + 0x8b,0x2d,0x23,0xe8,0x75,0xab,0x80,0x6a,0x5b,0xc8,0x2e,0xb6,0x30,0x24,0x31,0xdf, + 0x5a,0xe8,0xbc,0x26,0x05,0xba,0x36,0xd5,0x48,0x1e,0x82,0x99,0x3a,0x99,0xc3,0xcc, + 0x15,0xc0,0xf7,0xf0,0xc4,0xc0,0x2f,0xa3,0x38,0x48,0x3e,0x6f,0xee,0xff,0x08,0xcc, + 0xbd,0x30,0xc7,0xfc,0x6c,0x2b,0x30,0x08,0x8b,0x88,0x62,0x6b,0x19,0x33,0xf7,0x78, + 0xc7,0xe3,0xd7,0xe8,0x1d,0x05,0xd9,0xbb,0xfc,0x42,0x93,0x27,0xfe,0xce,0x52,0xa4, + 0x32,0x8e,0x31,0x36,0xb9,0x50,0x97,0x28,0xd4,0x42,0xf6,0x2b,0x50,0x7f,0xb0,0xf1, + 0xb9,0x5a,0xec,0x34,0xb3,0x16,0x76,0x5b,0xce,0xe1,0x0c,0xd7,0x4f,0xee,0xe4,0xc1, + 0x65,0xe8,0x14,0xa9,0x46,0x22,0x22,0xf6,0x26,0x5d,0xc2,0xb4,0x7c,0x0e,0x31,0x75, + 0xde,0x62,0x52,0xc6,0x95,0x4d,0x93,0x3f,0x01,0x6e,0x48,0x0e,0xdf,0x4d,0xfa,0xb3, + 0x69,0xaf,0x7a,0x11,0xc7,0x59,0xa1,0xf2,0x22,0x5d,0x4d,0xe6,0xff,0x1f,0xa8,0xfb, + 0x00,0x1a,0x74,0x88,0x45,0xac,0x23,0x64,0x19,0x2d,0x6a,0xaf,0xe9,0x7d,0x8c,0xba, + 0x76,0x46,0xe9,0x35,0xb0,0xa7,0x18,0xa6,0x9d,0xc9,0x30,0x4e,0x97,0x93,0x24,0xcc, + 0x81,0x66,0xa7,0xce,0xd5,0x2c,0xc0,0xf0,0x66,0x07,0x84,0x40,0x96,0xb7,0x9c,0xa3, + 0x2c,0xb8,0x70,0x02,0xc0,0xe2,0xc2,0x01,0xdc,0xb3,0xca,0xee,0x84,0x93,0x0b,0x46, + 0x2c,0xe2,0x31,0x88,0x63,0x00,0xb6,0xcc,0x1c,0x54,0x02,0x31,0x70,0x1a,0xb0,0x3f, + 0x69,0xd5,0x71,0x4d,0xf2,0x13,0x6f,0x7e,0x27,0x27,0x05,0x52,0x05,0x71,0x0e,0xa3, + 0xa7,0xbf,0x75,0x4c,0x54,0x94,0xa8,0xe1,0xa1,0x6d,0xc9,0x43,0x35,0x0b,0x6d,0x77, + 0x36,0x2d,0x6c,0x51,0xdd,0x4f,0xa0,0xfd,0xdc,0x93,0x75,0x7e,0xcf,0x10,0x54,0xc1, + 0x23,0xfe,0x51,0x37,0x08,0x59,0xe6,0xbb,0x46,0x21,0x2a,0x7f,0xc3,0x30,0xec,0x3f, + 0x72,0x1d,0x48,0x15,0x45,0x01,0x51,0x09,0x50,0x88,0xf5,0x24,0x55,0x0e,0x61,0x72, + 0x52,0x69,0xb1,0x04,0x17,0xac,0x5a,0xc0,0x8f,0x76,0x89,0xe0,0x85,0x2e,0xb9,0xb9, + 0xff,0x53,0x47,0x52,0xbd,0x00,0xa1,0x60,0xd5,0xe0,0xd9,0x84,0xd8,0x59,0x09,0xb1, + 0xfb,0x9d,0x10,0xbb,0x2b,0x21,0x6e,0x7f,0x27,0xc4,0xed,0x95,0x10,0x77,0xee,0x03, + 0x91,0x10,0x7c,0xa9,0xa7,0x00,0x7e,0xb2,0xeb,0xd1,0x6e,0x91,0x83,0x04,0x37,0xcb, + 0x89,0x14,0xc4,0x67,0x70,0x2a,0x95,0x01,0xd6,0x2e,0x08,0x16,0x10,0xbf,0xe8,0x96, + 0xc5,0x94,0x65,0x9c,0xc3,0xa2,0x44,0x3d,0xdb,0xa1,0xdf,0xb9,0xc1,0x4d,0x6a,0x2a, + 0xeb,0x9a,0x49,0x1a,0xe5,0x37,0x9b,0xfb,0xef,0xf1,0x0f,0x30,0xf1,0x74,0x7e,0xdf, + 0x8a,0xf9,0x55,0x18,0x03,0x1f,0x3b,0xc1,0x73,0x18,0xf4,0xdb,0xa8,0x58,0x45,0xa9, + 0x0c,0xac,0x2b,0xb3,0x52,0x11,0xfe,0xa6,0x19,0x67,0x55,0x36,0x17,0x21,0x68,0xe4, + 0x79,0x74,0x91,0x04,0x71,0x2d,0x5b,0x95,0xf1,0x71,0x25,0x18,0x8c,0x79,0x4c,0xb7, + 0xc1,0xfd,0xd4,0x71,0xc0,0xb4,0x80,0x95,0xba,0x62,0x15,0x99,0x2b,0x83,0x03,0x09, + 0xad,0xc5,0x51,0x5d,0x6b,0x02,0xba,0x88,0xc2,0x2b,0xcd,0xe1,0xb8,0x7e,0x06,0xa5, + 0xf9,0xc5,0x64,0x86,0x5f,0xe5,0xd5,0x25,0xcc,0x9b,0x7a,0xc4,0xc8,0xd8,0x34,0x07, + 0xf9,0x82,0xb9,0x00,0xcb,0x85,0x5e,0x7f,0x71,0x6c,0xd6,0xf1,0x28,0x19,0xe5,0x8b, + 0xc1,0x6a,0xca,0x5d,0x31,0xf7,0xd5,0xfe,0x76,0xfe,0x99,0xfe,0x76,0xff,0xfd,0xfb, + 0xdb,0xfd,0x67,0xfa,0xbb,0xfd,0xef,0xdf,0xdf,0xed,0x7f,0xa6,0xbf,0x3b,0x7f,0x7c, + 0x7f,0x05,0xc1,0x1b,0x2a,0x93,0xb1,0x51,0xaa,0x96,0x98,0x74,0x28,0x6d,0x3a,0xd6, + 0x61,0x9c,0xcd,0x69,0x80,0xfc,0x69,0x83,0x8e,0x69,0x0d,0x37,0x3f,0x2e,0x93,0x1c, + 0xd5,0x11,0xbd,0xb0,0x1d,0x3c,0xaa,0xb6,0xbc,0x98,0xc1,0xdf,0x28,0x77,0x70,0x29, + 0xf5,0x49,0xfd,0x66,0x89,0xee,0x3b,0x42,0x26,0xfa,0x0e,0x6d,0xac,0x93,0xba,0xc8, + 0x8b,0x98,0x55,0xa8,0xcd,0x7d,0xd1,0x91,0xf5,0x3c,0x08,0xb5,0xc7,0xd2,0xfa,0x94, + 0x61,0x8b,0x96,0x04,0x96,0xbe,0x8c,0x4d,0xb3,0x14,0x25,0xec,0xff,0x04,0x5d,0x73, + 0x3a,0x36,0x1f,0x92,0x55,0xde,0x85,0x45,0xf0,0xed,0x8a,0xc7,0x38,0x8d,0x1d,0x19, + 0x2e,0x50,0xe6,0x8e,0xca,0x75,0xb2,0xb9,0xff,0x31,0xcc,0x17,0x69,0x92,0x87,0x5c, + 0xb6,0x4e,0x31,0x93,0xb1,0x7f,0x25,0xf1,0x4e,0xc9,0xab,0xe4,0xbb,0x0e,0x42,0xd8, + 0xac,0xcb,0xc0,0xe8,0xbb,0x1a,0xf1,0x43,0x79,0x42,0x12,0x80,0x06,0xc3,0xbb,0x59, + 0x9b,0x35,0xe4,0x43,0x9d,0x3c,0xa1,0x6c,0xa5,0x18,0xaf,0x92,0x2e,0x65,0xa0,0xb3, + 0x20,0x5b,0xac,0x86,0x89,0xb9,0xdf,0x0a,0x12,0x88,0x30,0x5e,0x09,0xf1,0x55,0x10, + 0xc7,0xdf,0x0a,0xf0,0x22,0x28,0xc2,0x95,0x00,0x7f,0x84,0xcc,0x6f,0x1e,0x34,0xba, + 0xd7,0x56,0x0f,0x1a,0x73,0xbf,0x15,0x64,0x90,0x8d,0x57,0x4f,0xcd,0x01,0x64,0x56, + 0x01,0x96,0xd4,0x17,0xe9,0xf3,0x53,0xa4,0xad,0x13,0x94,0x2a,0x53,0xe9,0x9f,0xc5, + 0x29,0xa8,0xc2,0xbb,0x28,0x01,0xcb,0x90,0xf9,0x02,0x69,0xcc,0xc3,0xcd,0x57,0xe1, + 0x15,0x18,0x1b,0x62,0xd0,0x8f,0x1e,0xee,0x3d,0xe9,0x76,0x07,0x75,0x56,0x10,0x95, + 0x78,0x6f,0x2d,0xad,0xcd,0xfd,0xed,0x95,0x2d,0x1d,0xc7,0xe5,0x86,0xde,0xa5,0x59, + 0x28,0xdb,0x79,0x5c,0x1d,0xa9,0x6a,0x88,0xd6,0x4a,0x8d,0xbd,0xf5,0x75,0x85,0x5b, + 0x14,0xbf,0x24,0x57,0x53,0xed,0x1a,0xc7,0x20,0xa0,0xd2,0x22,0x23,0xdb,0xa2,0x2e, + 0x4d,0xac,0xe2,0x15,0xac,0xe0,0x83,0xc1,0xf9,0xaa,0x9c,0x08,0xf8,0xa2,0x30,0x57, + 0x2c,0x74,0xd5,0x71,0x20,0x51,0x9c,0xc2,0x56,0x54,0x71,0x95,0x60,0xf7,0x4b,0x84, + 0xf3,0x6d,0xee,0xd7,0x00,0x40,0x3f,0xad,0x59,0x9f,0xbe,0xeb,0x0a,0xbe,0x4d,0xcd, + 0x62,0x1c,0x17,0x53,0x5b,0xf0,0x75,0xb4,0xae,0x60,0x15,0xc1,0x3a,0x4a,0xae,0xca, + 0xae,0x54,0x9e,0x58,0x14,0x71,0x4a,0x56,0x18,0xfd,0x9e,0x45,0x68,0x89,0xed,0xb7, + 0x81,0xf8,0xba,0x9d,0xce,0xa0,0xb3,0x72,0x59,0x7d,0x0d,0x08,0xba,0xf3,0x14,0x98, + 0x56,0xef,0xdb,0xe0,0x90,0x2b,0xd0,0xe8,0x4e,0xab,0xf7,0x7d,0xfd,0x69,0x75,0x7b, + 0x56,0x97,0x9e,0x40,0x9f,0x20,0x4d,0xf6,0xea,0xc9,0xb7,0x76,0xab,0x63,0x83,0xdb, + 0x05,0x68,0x1d,0x05,0x6d,0xf7,0x1b,0x81,0x6d,0x5b,0xb0,0xf6,0xb0,0x6b,0xdb,0x12, + 0xd6,0x5e,0xaf,0xba,0x28,0xab,0x0a,0x87,0x3e,0x31,0xf8,0xef,0xe4,0xa3,0x79,0xb7, + 0x2c,0xea,0xbc,0x33,0x2b,0xa9,0x10,0x23,0x1b,0x4b,0x7e,0x25,0xc2,0xc3,0x0b,0xa0, + 0xdf,0xaa,0x8a,0x84,0x22,0x3d,0x2c,0x9c,0x9f,0x6a,0x26,0x59,0xd5,0x7c,0x67,0x98, + 0xef,0xb2,0x22,0xa0,0x31,0x51,0xac,0x97,0x61,0x08,0x0f,0xe5,0xca,0x3e,0xf2,0xee, + 0xfa,0xbe,0xf2,0x34,0x6e,0x6d,0xee,0x73,0x8c,0x50,0x48,0x7e,0x3f,0x95,0x2c,0xdd, + 0x77,0x7c,0xc6,0x9f,0x7d,0x82,0xa2,0x2e,0xc0,0x42,0x9f,0xa3,0xba,0x6c,0x64,0x7f, + 0x03,0xef,0x4c,0x38,0x7e,0x05,0x3d,0x74,0x86,0x8e,0xba,0x02,0xc0,0x71,0x3d,0xe7, + 0x76,0xa3,0xb1,0xcc,0x91,0xdf,0x66,0xd1,0xb8,0x68,0x0c,0x36,0xf0,0x36,0x92,0xc2, + 0xb9,0x8a,0x30,0xe2,0x05,0xcb,0x5e,0xfa,0x4e,0x9c,0xfa,0x30,0x02,0xcf,0x19,0xee, + 0x3b,0x7c,0x9b,0x43,0x70,0xed,0x62,0x9a,0xba,0xda,0x61,0x16,0xf9,0x0e,0xdf,0x11, + 0xe2,0x5e,0x7a,0xce,0xef,0xbf,0x3b,0x6d,0xcf,0x93,0x90,0xe8,0x70,0x65,0xbb,0x43, + 0xa0,0x08,0x04,0x83,0x46,0xb8,0x6d,0xdf,0xe9,0xa8,0x72,0xc7,0x1f,0x5f,0x9e,0xbc, + 0x3c,0x3d,0x81,0x72,0xb7,0x1b,0xac,0xa3,0xf4,0x9d,0x5b,0x72,0xc9,0xf4,0x9d,0xc6, + 0x28,0xfc,0x12,0x85,0x59,0xc3,0x07,0x5c,0xc3,0x17,0x67,0xc3,0xd7,0x4d,0xbb,0x8f, + 0x40,0x6e,0x3a,0x7d,0xa7,0xe3,0x3b,0x8b,0xce,0x35,0x7c,0xb6,0x76,0x7a,0xf8,0xf3, + 0x06,0x7f,0xb6,0xf1,0x67,0x97,0x52,0x7b,0xf4,0x93,0x52,0x9f,0xf6,0x9c,0x3b,0x7f, + 0x83,0x54,0x96,0xbe,0xb3,0xb2,0x0d,0xcc,0x86,0x8f,0xfa,0x36,0x3a,0x6d,0xd5,0xc6, + 0xae,0x6e,0x63,0x5b,0xb6,0xd1,0x69,0xb5,0xdb,0xd8,0x06,0xea,0x30,0xd0,0xc4,0xaa, + 0x36,0x30,0x1b,0x9b,0xa0,0x36,0x3a,0xdc,0x46,0xbb,0x6e,0x1c,0x4f,0x6b,0xc7,0xd1, + 0xa6,0x71,0xa0,0x5a,0x63,0xb5,0x41,0x92,0x13,0xc1,0x52,0x1b,0x98,0x8d,0x1f,0x49, + 0xdf,0xe9,0xd2,0xb0,0x31,0xb7,0xbf,0xb2,0xb8,0xfc,0x82,0xe2,0xdb,0x58,0x1c,0x15, + 0x12,0x0b,0x3a,0x26,0x50,0x9f,0xa9,0x38,0x7d,0x39,0x77,0x1b,0x77,0x83,0x0d,0x45, + 0x53,0xe1,0x65,0x10,0x1f,0xa2,0x68,0x76,0x49,0x40,0xfb,0xce,0x12,0x89,0x6c,0x09, + 0x13,0x2b,0x48,0xc1,0x5d,0xc2,0xa4,0x47,0x53,0xc7,0x7d,0x40,0x05,0x3c,0x47,0xdc, + 0x71,0xb1,0xe4,0x54,0x4a,0x6c,0xd1,0xfd,0x3a,0xc3,0xe1,0x50,0x76,0x09,0x61,0x30, + 0xa1,0x20,0x55,0x0a,0x1a,0x22,0x02,0xa4,0xdd,0x46,0x51,0x2b,0x21,0xea,0xeb,0xfa, + 0xf8,0xdf,0x1e,0xb4,0x22,0x20,0x2b,0x42,0x4d,0x9c,0x26,0x22,0x9a,0xbe,0xa7,0x71, + 0x9a,0x66,0xee,0xd2,0xf9,0xc1,0x49,0x3c,0xcf,0xd9,0x72,0x38,0x13,0x2a,0xdd,0xd5, + 0x76,0x83,0x86,0xaa,0xfa,0x4a,0x10,0x72,0xd9,0x85,0xe3,0x37,0x00,0x45,0x8e,0xaa, + 0x5c,0x51,0xcc,0xb9,0x1e,0xc0,0x2d,0xcc,0x37,0x8c,0x81,0x88,0x0a,0xfe,0x32,0x55, + 0xd1,0x5c,0xd3,0x2c,0xd3,0xfc,0x3a,0x77,0x88,0x2f,0x84,0x24,0xd7,0xc7,0xe8,0x1a, + 0x97,0x50,0x41,0x4b,0x68,0x1b,0x9a,0x73,0x3b,0xd0,0x5d,0xf8,0x34,0x7f,0x15,0xf0, + 0x3f,0xc0,0x72,0x1e,0x97,0x4a,0x14,0x32,0xaf,0x8b,0x79,0xf2,0xab,0x50,0xa0,0x6f, + 0x34,0xe8,0x3a,0xb0,0xfa,0x17,0x74,0xfc,0xf1,0x57,0x5a,0xbf,0x59,0xd3,0xfa,0x8d, + 0xd9,0x3a,0x82,0xeb,0x0c,0x36,0x62,0xe0,0x88,0x71,0xca,0xf8,0x98,0x45,0x88,0x0f, + 0xa0,0xa5,0x34,0x73,0x5c,0xcc,0xc0,0xef,0xf6,0x00,0xfe,0x3c,0x73,0xba,0x3b,0xf0, + 0xf7,0xf1,0x63,0x8d,0xc6,0x79,0x34,0xc1,0x6e,0x43,0xdd,0xc7,0xc4,0x9d,0xb6,0x9c, + 0x2e,0x4f,0xc0,0xe8,0xda,0x85,0x3c,0x0f,0xea,0x00,0xe5,0x11,0x68,0xf8,0x1c,0x38, + 0x21,0x18,0xb5,0xdc,0x02,0x7e,0xc2,0x2c,0x8b,0xa9,0x94,0x54,0x39,0xba,0x71,0x2d, + 0x60,0x9e,0x67,0x14,0x5a,0xe2,0x6f,0x45,0xe2,0xa3,0xe0,0x73,0xf8,0x76,0x59,0xb8, + 0x82,0x7e,0x65,0x8f,0x62,0xd0,0xf3,0x86,0xce,0xd9,0x79,0xed,0x00,0x86,0xce,0x76, + 0x57,0x8c,0x00,0xca,0xf1,0x75,0x3b,0x82,0x67,0x56,0x56,0x4c,0x04,0xed,0x6f,0x77, + 0xbd,0x56,0x91,0xbe,0x8a,0xae,0xc3,0x89,0xbb,0xe3,0x79,0x9a,0x98,0xa1,0x36,0x76, + 0x86,0x9b,0x7c,0xf7,0xe6,0xfd,0x2f,0x9f,0xde,0xbc,0x3f,0xfa,0xf0,0x09,0x1b,0x6a, + 0xb5,0xbb,0x03,0x23,0xe3,0xc3,0xcf,0xa7,0x9c,0xda,0x93,0xa9,0xc1,0x22,0x22,0x06, + 0x2b,0xc6,0xec,0x4b,0xae,0xeb,0xeb,0x55,0xeb,0xcb,0xd1,0xf9,0x06,0x70,0x5f,0xc2, + 0xf3,0x37,0xa8,0x8b,0x7f,0x0e,0xe2,0x65,0xe8,0xa2,0x19,0x2d,0x96,0xb7,0xe8,0x1b, + 0xa6,0x70,0x38,0xbd,0xf3,0xdc,0x60,0x04,0x3a,0x19,0x8b,0x6f,0xf4,0x79,0xf9,0x2c, + 0xd2,0x2b,0x57,0xb3,0x04,0x90,0x05,0x30,0x6a,0xb1,0xb0,0x05,0x62,0xa8,0x1e,0x6e, + 0xe0,0xd2,0xb2,0x86,0xee,0x82,0xd2,0xe4,0x3b,0x3b,0x34,0x33,0xfe,0x86,0x0c,0x4f, + 0x06,0x44,0x5f,0x86,0xb1,0xef,0x70,0x77,0xc2,0xe4,0x12,0x3b,0x84,0x84,0x20,0x7e, + 0x96,0xe6,0x59,0xb5,0xc9,0xf5,0x80,0x4a,0xa1,0x5c,0x2b,0x4e,0x71,0xd2,0x95,0x78, + 0x03,0xa4,0x21,0x7a,0x30,0x07,0x48,0x46,0x15,0xf1,0xe0,0x27,0x72,0x7f,0xe2,0x17, + 0x24,0x49,0xc4,0xb7,0xa7,0xa7,0x84,0x28,0x4e,0x11,0x15,0x8e,0x20,0x4a,0xc0,0x9c, + 0xd2,0x13,0x58,0x69,0xbf,0xd4,0xb6,0x89,0xf6,0x32,0x9c,0xe0,0xda,0xe3,0x0a,0x8c, + 0x02,0x76,0xab,0x98,0x13,0xb1,0xaa,0x0f,0x50,0xd2,0xea,0x04,0x51,0x3a,0x90,0x43, + 0xab,0x6e,0x3e,0x61,0xf5,0x56,0x2a,0xab,0x96,0xa9,0x61,0x11,0x42,0x84,0xba,0x92, + 0x4b,0x07,0xef,0xa1,0xab,0xc1,0x22,0x37,0xd0,0x9d,0xa4,0xd9,0x3c,0x88,0xa3,0x2f, + 0x21,0x95,0xa1,0xab,0xb2,0x1c,0xb3,0x24,0x81,0x51,0x85,0x40,0xc1,0x99,0x46,0x17, + 0x6e,0x16,0x5c,0x69,0x40,0x3c,0x94,0xbc,0x00,0x73,0x10,0x57,0x3a,0xe4,0x39,0x8f, + 0x1e,0x39,0x07,0x59,0x16,0xdc,0xb4,0xa2,0x9c,0xfe,0x62,0x05,0x0a,0x66,0x81,0x0a, + 0xcf,0xa9,0x04,0x2a,0x0d,0xb8,0x0f,0xf7,0x11,0xed,0xad,0xbe,0x83,0x17,0xcb,0x30, + 0x65,0x80,0xd0,0x3b,0x3b,0x77,0xee,0x14,0x02,0x6e,0x37,0x8c,0x62,0xdc,0x48,0x4b, + 0xa5,0x10,0xe7,0xa6,0xba,0x1b,0x3a,0xfa,0xb7,0x44,0x9c,0xa2,0x8e,0xca,0x67,0xc5, + 0x87,0x94,0x00,0xd6,0x3c,0x80,0x3e,0x3c,0x90,0xa0,0xe4,0x14,0x5b,0x51,0x99,0x33, + 0x45,0xcd,0xdd,0x52,0x4d,0xd9,0x6b,0x54,0x93,0x48,0xa2,0x6d,0x9f,0x03,0x7d,0x2c, + 0x5c,0x97,0x55,0x31,0x1b,0xc1,0x02,0x20,0xd5,0x39,0x8b,0xce,0x01,0xd7,0x02,0x91, + 0x1e,0x0a,0x67,0x92,0xd0,0x8c,0xcf,0xd7,0x7f,0x43,0x1e,0x75,0xb6,0x0b,0x50,0xbb, + 0xbd,0x36,0x14,0x3c,0x83,0x3f,0x3e,0x1e,0x66,0xe1,0x0f,0xf8,0xeb,0x3b,0x3d,0xf1, + 0xd5,0xa3,0xaf,0xce,0x2e,0x7e,0x9e,0x1b,0x32,0x7e,0x11,0x44,0x99,0xcb,0x6a,0xa1, + 0xef,0x90,0x20,0x85,0xd6,0xc2,0x28,0x26,0xaf,0xdf,0x45,0xb0,0xc0,0xe9,0x23,0x1a, + 0x14,0xa3,0xc6,0xa2,0x76,0x31,0x98,0x7f,0xe2,0xc5,0xa2,0x40,0x15,0x8e,0x90,0xa6, + 0x00,0x65,0x9f,0x38,0xf2,0x19,0x37,0x77,0x8e,0xbd,0xc7,0xd2,0x71,0x7a,0xce,0x25, + 0x68,0x7d,0x42,0xb1,0x67,0xb2,0x61,0x82,0xab,0x44,0xbe,0xea,0x16,0x51,0x3c,0x16, + 0x19,0x70,0xd7,0x54,0x09,0x06,0x0c,0x40,0x38,0x53,0xf1,0x7c,0xd9,0xa2,0xc5,0xfa, + 0x6d,0xac,0x13,0xbd,0x96,0xe8,0x5f,0xc8,0x54,0x4d,0xb1,0xa8,0x0a,0xa4,0x53,0xfa, + 0x22,0x85,0x20,0xa5,0x1b,0xf4,0x1a,0x4c,0xb0,0x1b,0x48,0xb0,0xbc,0x38,0x49,0x85, + 0x04,0x74,0xf3,0x6a,0xc3,0xaf,0xbd,0x9e,0xf0,0xa1,0x62,0xa1,0x56,0xab,0x25,0xb8, + 0xb5,0xa0,0x39,0xd0,0xcf,0x50,0x18,0xf4,0x95,0x38,0xb2,0xb3,0x3d,0x47,0xcd,0x39, + 0x86,0xc9,0x42,0x7f,0x46,0x2d,0xfa,0xf1,0xfc,0x39,0x35,0x24,0x33,0xcf,0x66,0x5f, + 0xa0,0x71,0x18,0xe9,0x17,0x68,0x15,0xd1,0x4b,0x93,0x3b,0x6a,0x51,0x32,0x16,0x7e, + 0xfd,0xb7,0x33,0x1a,0xe2,0xf9,0x19,0xd2,0x04,0x65,0x04,0xd7,0x76,0x46,0xe7,0x9c, + 0xc7,0xdf,0x12,0xb0,0xe4,0xef,0x00,0xf0,0x02,0xdc,0x51,0x35,0x45,0x9c,0x10,0x31, + 0x66,0x37,0x45,0xc9,0xd4,0x2f,0x84,0x4f,0xb9,0xf8,0xd5,0x61,0x13,0xc1,0x14,0x44, + 0x1a,0x14,0xe3,0x4c,0x62,0xcb,0x00,0xc6,0x19,0x58,0x1f,0x47,0x8b,0x00,0xb9,0x88, + 0x4c,0x01,0x2a,0x80,0x52,0xe4,0x8f,0x61,0x54,0xf4,0x7a,0x9e,0xd9,0x10,0x48,0x39, + 0xcf,0xe0,0x12,0x26,0x76,0xfc,0x0d,0xe1,0xec,0xa6,0x19,0xdf,0xe0,0x33,0x11,0xd0, + 0x00,0xfd,0x30,0x78,0x86,0x39,0x4c,0xd4,0xd0,0x71,0x6e,0x4b,0x92,0xad,0x4e,0xac, + 0x11,0x3f,0x37,0x06,0x25,0x84,0x2d,0xb6,0xc0,0x32,0x55,0x13,0x93,0x4c,0x29,0x11, + 0x94,0x4c,0xee,0x3b,0xc4,0x70,0x37,0x88,0x3c,0x6c,0x8e,0x39,0x6a,0x41,0xa2,0x87, + 0xa0,0xe8,0x57,0x2b,0x0e,0x93,0x0b,0xa0,0xa5,0x7d,0x10,0xbf,0xcf,0x39,0x49,0xd4, + 0x66,0xbe,0x21,0xf0,0x00,0x92,0x02,0xbe,0x3c,0x17,0x30,0x63,0xdc,0x13,0x27,0x7f, + 0x94,0x0c,0x4a,0xb4,0x35,0x8f,0x5e,0xfc,0xf2,0xea,0xed,0x87,0x0f,0x1f,0x61,0x5e, + 0x9a,0x68,0xc9,0xc0,0xf7,0xc9,0xf1,0xc1,0x7b,0xf8,0xdc,0x79,0x32,0xa0,0x12,0x7f, + 0x42,0xed,0x0d,0xf5,0x34,0xe0,0x65,0x93,0x74,0xbc,0x9c,0x87,0x49,0xd1,0xba,0x08, + 0x8b,0x97,0x71,0x88,0x3f,0x5f,0xdc,0xbc,0x99,0x60,0x36,0x17,0xd6,0x56,0x24,0x19, + 0xb1,0x2d,0xf1,0xcd,0x99,0x93,0x11,0x59,0xaa,0xd7,0x04,0x4a,0x49,0xd7,0x6e,0x1b, + 0xe4,0x18,0x2d,0xf2,0x38,0xbd,0xe8,0xb4,0x5d,0x25,0x5f,0xc5,0x14,0x5c,0x33,0xdb, + 0x85,0x79,0x0f,0x9b,0x3b,0x24,0xd9,0x65,0x9f,0x51,0x1a,0x8b,0xfe,0x8a,0xe6,0x63, + 0x61,0x0b,0x6b,0x1b,0x18,0x95,0x17,0xb4,0x02,0x95,0xa0,0xbc,0x44,0xb1,0x29,0x47, + 0xf9,0xd8,0x82,0xd5,0x6d,0x0b,0x30,0x79,0xc0,0x9a,0x36,0x06,0x75,0x3a,0x9f,0x81, + 0x8a,0x08,0xde,0xf1,0xab,0x16,0x64,0x18,0xa9,0xd8,0xaf,0x46,0x94,0x4c,0x53,0x30, + 0xb4,0xfe,0xe4,0x36,0x38,0x80,0xa7,0x81,0x22,0x5f,0x1b,0x59,0xc9,0x38,0x9d,0x84, + 0xb8,0x87,0xa1,0x95,0x50,0xc2,0x93,0x34,0x1b,0x68,0x6c,0x5a,0xe5,0xa8,0xd8,0x53, + 0x30,0xd9,0x8d,0xbc,0xdf,0x80,0x9e,0x8e,0x5b,0x09,0x30,0xa1,0x71,0xd9,0xd4,0xc1, + 0x02,0x41,0x43,0xe7,0x3c,0x30,0x6c,0x19,0xcc,0xc3,0x2c,0x97,0x27,0x43,0xf0,0x9d, + 0xb3,0x71,0x2b,0x9a,0x9c,0xb3,0xf9,0x5f,0xb5,0x7f,0xb0,0xce,0x42,0x34,0x18,0x4d, + 0x36,0xd0,0x18,0xa6,0x2f,0xa8,0x75,0x03,0x78,0x84,0x7f,0x3b,0xf8,0x2f,0x99,0x42, + 0xf8,0xe7,0x86,0xfe,0x74,0xf9,0xab,0x7b,0x23,0x44,0x9f,0x31,0x03,0xc2,0xee,0x33, + 0xd1,0xdf,0x69,0x0b,0x4d,0x4c,0xe1,0x09,0x4f,0x14,0x08,0x3c,0xcd,0x25,0x8e,0x7e, + 0x43,0x13,0xa0,0x95,0xc7,0xd1,0x38,0x74,0x41,0xc9,0xce,0x17,0x71,0x54,0xb8,0x0d, + 0xbf,0x01,0x5c,0x20,0x21,0x36,0x92,0xe5,0xe1,0x9b,0xa4,0x70,0x7f,0x23,0x7e,0x87, + 0xca,0x1e,0xdb,0x94,0x0b,0x45,0x7d,0x72,0xc0,0x58,0xe2,0x5c,0x60,0x1a,0xa1,0xfe, + 0x66,0x76,0xd2,0x55,0x80,0x2e,0x15,0x14,0x52,0x1c,0xb1,0x97,0x6a,0x66,0xe6,0x02, + 0xe5,0x88,0x9f,0xb2,0x91,0x6d,0x99,0xd8,0x7d,0x67,0xeb,0xef,0x79,0x7f,0xab,0x85, + 0xfb,0x70,0x38,0x96,0xe7,0x55,0x13,0x1e,0xcb,0x27,0x04,0xaf,0x8b,0xd8,0x26,0xd3, + 0xdf,0xb1,0x8d,0x7a,0xb5,0x08,0xba,0x86,0xfb,0x66,0xcf,0x27,0x13,0x98,0xdb,0x58, + 0x18,0x6d,0x00,0x93,0x58,0xd4,0xce,0x24,0x5f,0x02,0xdb,0x0a,0x72,0xdc,0x10,0x74, + 0x6f,0x41,0x10,0x2d,0x3c,0xaa,0x3d,0xb2,0x6b,0xff,0x26,0xd9,0x0b,0xd6,0xdf,0x35, + 0xfb,0x6c,0x7b,0x42,0xc6,0x4b,0xd0,0x5f,0xe6,0xc2,0xa3,0xc3,0x78,0x47,0x67,0xc8, + 0x6f,0x24,0x58,0xc8,0x1f,0xf2,0xdb,0x59,0xf7,0x5c,0xf8,0x43,0x7e,0x3b,0xdb,0x3e, + 0x17,0xfe,0x90,0xdf,0xce,0x76,0xce,0x85,0x3f,0xe4,0xb7,0xb3,0xde,0x39,0x0d,0x01, + 0x79,0x17,0xd2,0x00,0x4e,0x35,0x28,0x57,0x30,0x2d,0xac,0x7c,0xc2,0xb2,0x40,0xdb, + 0x87,0x85,0x66,0x2e,0x0c,0x35,0xba,0x4a,0xf4,0x0b,0x7e,0x6c,0x77,0x5a,0x5d,0xe0, + 0x53,0x7b,0xa8,0xea,0x70,0xfa,0x34,0x0b,0xe6,0xe1,0x2b,0x94,0x66,0xd3,0x0b,0xfc, + 0x43,0xea,0x7a,0xce,0x79,0x45,0x10,0xc5,0x48,0x0e,0x7c,0x3f,0x69,0x2b,0x0b,0xf3, + 0x34,0x06,0x43,0x47,0xac,0xf3,0x22,0x8b,0xc2,0x9c,0x4d,0xda,0x22,0x8d,0x51,0x79, + 0x6d,0x34,0xb0,0x7e,0x70,0x89,0x51,0xdb,0x43,0x87,0x36,0x58,0x05,0x4b,0xa0,0x60, + 0x5f,0x51,0x02,0x38,0x80,0xcc,0xf5,0x31,0xe0,0xee,0xa0,0x20,0xf3,0x91,0x7b,0x19, + 0xe4,0x07,0x4b,0x50,0xcf,0x83,0xe5,0x44,0x97,0x19,0xc7,0x11,0x9e,0xa9,0xe6,0xa6, + 0xf0,0xa2,0x5d,0x5d,0xfe,0xd5,0x9b,0x97,0x6f,0x8f,0x4e,0x48,0xd7,0x6b,0x90,0x0c, + 0x03,0xf8,0x88,0x4d,0xfa,0x0a,0xae,0xd5,0x17,0xc9,0x2a,0xf8,0xea,0xc9,0x2f,0xca, + 0xe3,0x2f,0x16,0x47,0x0d,0xd4,0x3c,0xe5,0x27,0xe5,0xf2,0x27,0x4a,0x30,0xfa,0x30, + 0x35,0xc3,0x1c,0x38,0x2b,0xe0,0x0b,0x07,0x8e,0xeb,0xad,0x48,0x49,0xa9,0x46,0xae, + 0x34,0xbd,0x30,0xf4,0x6b,0x20,0xcf,0x0e,0xd1,0x66,0xbb,0x31,0xc0,0x42,0x4a,0x8b, + 0x16,0x25,0xd5,0xb7,0xb2,0x81,0xb7,0x3d,0x2a,0xc8,0x1a,0xb3,0x84,0x47,0x1f,0x56, + 0x11,0x4c,0x26,0x25,0x58,0xdd,0x77,0xea,0x8e,0x80,0xc8,0x68,0x45,0xde,0x6e,0x30, + 0x52,0x74,0xd6,0x94,0xd3,0xa1,0xb3,0x67,0x53,0xa0,0x3a,0x60,0x47,0xa4,0x60,0xba, + 0x53,0x20,0x3c,0x10,0x89,0x3b,0xd0,0x4f,0x60,0xfd,0xee,0x88,0x72,0xcf,0x3d,0xe8, + 0xb0,0xfc,0xa9,0x1a,0xc5,0xa2,0xde,0xc0,0xb9,0xa3,0xee,0x9d,0x35,0x48,0x15,0x68, + 0x48,0x40,0x52,0x35,0x28,0x0d,0x17,0x8a,0x01,0x47,0x52,0xa5,0x0c,0x66,0x2e,0x04, + 0x38,0xea,0xa8,0x40,0xa4,0x67,0xdc,0x9b,0x07,0x23,0x65,0x53,0x83,0x09,0xd3,0x17, + 0x52,0xba,0x2c,0xc1,0x71,0x89,0x6d,0x6f,0x1b,0x42,0x9c,0x79,0x95,0x54,0x0e,0x25, + 0x64,0x6f,0xe3,0x3e,0x9c,0xb4,0x0b,0x4a,0x11,0x72,0xd2,0x12,0x37,0x8d,0xa6,0x53, + 0x37,0x07,0x8a,0x93,0xac,0x34,0x55,0x1e,0x0f,0xfc,0x5a,0xd0,0x97,0xfb,0x59,0x20, + 0x35,0x95,0x6e,0x8e,0xcf,0x30,0xd0,0xc6,0x10,0x87,0xcb,0x23,0xfd,0xf9,0xe3,0x9b, + 0xc3,0x74,0xbe,0x48,0x13,0x80,0x84,0xe2,0xeb,0xec,0xf3,0x39,0x34,0xe6,0x20,0x60, + 0xf8,0xc9,0x12,0x0c,0x7e,0x0c,0x50,0x81,0xa5,0x56,0x92,0x90,0xe0,0xc2,0x9a,0x00, + 0x96,0x26,0xa0,0x0b,0x57,0x1b,0x56,0x40,0xd1,0x04,0x74,0x80,0x3f,0x81,0xc7,0x62, + 0x22,0x96,0xd3,0xe9,0xf4,0xe5,0x61,0xf7,0xa0,0x6f,0x04,0x15,0x26,0x20,0x1a,0x03, + 0xed,0x36,0x90,0x22,0xf1,0xaf,0x88,0xe3,0xc6,0x9f,0x8a,0xf4,0x28,0x9f,0x28,0xac, + 0x71,0xae,0x49,0x86,0x47,0x07,0x5d,0x82,0x5f,0x5e,0xbd,0xab,0x4a,0x7b,0xaa,0x2a, + 0xf4,0x86,0x9c,0x56,0xd6,0x97,0x14,0x87,0x62,0xe7,0x19,0x70,0x47,0x98,0x50,0x2e, + 0x7f,0x96,0x38,0x7f,0x87,0xd5,0x29,0xb2,0xb1,0x15,0x2c,0x6e,0x90,0x96,0xf6,0x34, + 0x5a,0x94,0x24,0xc7,0x6b,0xa4,0x41,0x27,0x68,0xdc,0x3a,0x09,0x10,0xa0,0x26,0xa6, + 0x01,0x84,0x42,0x89,0x6a,0x82,0x04,0xd5,0x21,0x96,0xb4,0xf2,0x87,0xe5,0x7f,0x4d, + 0x61,0x1d,0x34,0x1e,0x35,0x3c,0xc9,0x5a,0x17,0x69,0x4e,0xb3,0xbd,0xcc,0xd0,0xf5, + 0x92,0x4e,0x6e,0x68,0x5c,0xe2,0xa6,0x63,0x4c,0xbb,0xdd,0x80,0x36,0x67,0x29,0xb2, + 0xf7,0xe3,0x0f,0x27,0xa7,0x0d,0x5f,0x9c,0xe6,0xcb,0xd1,0x98,0x69,0x88,0x1b,0xc2, + 0x9b,0xa7,0x20,0x0e,0x1a,0x28,0xe6,0x16,0x20,0x86,0xc7,0x74,0xf6,0x6f,0xeb,0xba, + 0x79,0x75,0x75,0xd5,0x04,0xa4,0xcd,0x9b,0x00,0x89,0x69,0x06,0x06,0x7e,0xe7,0xd3, + 0x41,0xdf,0x3e,0xb5,0x06,0x9a,0x52,0x18,0x2e,0x02,0xbc,0xbe,0xbc,0x2f,0x39,0x2b, + 0x18,0xeb,0x14,0x9f,0x02,0x2a,0xef,0x28,0xcd,0x8a,0x13,0xfa,0x90,0xb7,0x34,0xc3, + 0xc2,0xa8,0x49,0x75,0x3b,0x68,0xf0,0xe2,0xc2,0x86,0x25,0x10,0x4e,0xa3,0x24,0x9c, + 0x6c,0xc8,0xfb,0xbc,0xdd,0x4c,0x70,0x0d,0xf2,0x55,0xd3,0x1d,0xcd,0x4e,0xfd,0x25, + 0xcd,0x12,0x51,0xf2,0x4a,0x66,0x5e,0x38,0x9a,0x27,0x06,0x28,0x1a,0xb4,0x6b,0x44, + 0x08,0x0f,0xfc,0x23,0x5a,0x12,0x0d,0x91,0x40,0x00,0xac,0x08,0x39,0x85,0xe3,0x74, + 0x68,0x4a,0x91,0x36,0xf4,0xe2,0x1b,0x6c,0x80,0xca,0x48,0x57,0xb6,0x43,0xee,0x83, + 0x07,0x58,0x4c,0x38,0xd4,0x79,0x1e,0x64,0x33,0x28,0x7a,0xa0,0x22,0x29,0x97,0x52, + 0x0c,0xe9,0xce,0xe2,0x04,0xba,0x7c,0x55,0x3c,0x07,0xa2,0x13,0xf9,0x13,0x04,0xbb, + 0x57,0xb6,0xb0,0xa7,0x08,0x1f,0xd1,0x0d,0x6c,0x13,0x7f,0x82,0x16,0x31,0x46,0x4a, + 0x93,0x22,0xeb,0x08,0x16,0x1c,0x5f,0x1d,0x3e,0x10,0x52,0x93,0x2e,0x03,0x27,0xc5, + 0x47,0x26,0x88,0x6c,0x76,0xb6,0x63,0xf7,0x3c,0xea,0x68,0x03,0x91,0x35,0xc1,0xa5, + 0x97,0x7e,0x6e,0x10,0x4f,0x15,0x1d,0x87,0x9f,0x52,0xaa,0x96,0xc6,0x4f,0x88,0xb9, + 0x45,0x8c,0x4f,0xc0,0xa0,0x26,0xec,0xfb,0x8e,0xec,0xbc,0x31,0xf8,0xc7,0x8f,0x19, + 0xc2,0x33,0x56,0x8f,0x92,0xb4,0xa0,0x99,0x99,0x38,0x37,0x21,0x58,0x49,0x3a,0x62, + 0x7d,0x12,0x4d,0x1c,0xcc,0x0c,0x92,0xfc,0x2a,0xcc,0x5a,0xce,0x69,0x76,0x83,0x82, + 0x29,0x40,0x79,0xd7,0x42,0xb5,0x57,0x57,0xad,0xab,0x46,0x11,0xda,0x51,0x21,0x63, + 0xe2,0x31,0xb0,0x9b,0xaa,0x62,0xf4,0x36,0xa0,0x3e,0xbb,0x69,0xe1,0xe8,0xc2,0x2c, + 0x6b,0x08,0x0c,0x72,0xaf,0xc0,0x00,0xf3,0x94,0x29,0x00,0x1d,0xd6,0x65,0xee,0xaa, + 0x8c,0x78,0x4c,0xa0,0x91,0xa6,0xb4,0xae,0x31,0x70,0x0c,0xac,0xa0,0x1d,0x3a,0x90, + 0x84,0xc0,0xf4,0x87,0xb8,0xd6,0x1e,0xec,0x9b,0x50,0x99,0x6a,0xf7,0xa2,0xb8,0x0a, + 0x79,0x0d,0x36,0xd6,0x11,0xd0,0x18,0x2f,0x88,0x97,0x14,0x84,0x9d,0x5f,0x4d,0x44, + 0x77,0x1b,0xc1,0x64,0xf2,0x12,0x2f,0x25,0x7d,0x1b,0x81,0xa6,0x9a,0x80,0x02,0xd1, + 0xc0,0xe3,0x54,0xb3,0x68,0x82,0x3b,0x57,0x02,0x86,0xa1,0x3d,0xf1,0xd8,0x68,0x04, + 0x2c,0x77,0xeb,0xeb,0xe7,0xb3,0xf4,0xaa,0xb6,0x3e,0x6b,0x5f,0x8e,0xb5,0x44,0x71, + 0xd2,0xdc,0x5f,0xc9,0x7b,0x84,0xda,0xe0,0xaf,0xad,0xd9,0x17,0x56,0x54,0x40,0xa0, + 0xcc,0xbe,0x08,0x1b,0x74,0x7a,0xa1,0x2c,0x80,0xb2,0xe3,0xd2,0xf2,0x26,0xfe,0xaa, + 0x15,0x1d,0x18,0xa5,0xf6,0x1f,0xfe,0xaa,0xd5,0x1a,0xdf,0x91,0x7e,0xc1,0x5f,0x85, + 0x16,0xa3,0xfc,0x7d,0xbf,0x0a,0xfd,0x85,0xa4,0xf4,0x88,0x7a,0x5f,0x55,0xb7,0x47, + 0xc8,0x5f,0x49,0x75,0xeb,0xa3,0xf9,0x2b,0x7d,0x28,0x9e,0x70,0x3a,0x18,0x89,0xc1, + 0xb5,0x67,0xf8,0x11,0x80,0xbf,0x9f,0x84,0xc8,0x0b,0x0d,0xc3,0x08,0x94,0x14,0xf8, + 0xe3,0x29,0xb3,0x1f,0x5d,0x86,0x00,0xde,0x21,0xad,0xb1,0x0f,0x7f,0x48,0x1f,0x27, + 0xad,0x91,0xbe,0x40,0x35,0x22,0xac,0x93,0x1a,0x76,0x0b,0xd2,0x54,0xe9,0x7c,0xe8, + 0xcb,0xa4,0x0c,0x64,0x08,0x84,0x46,0xf8,0xfb,0x21,0xb1,0xd5,0x1f,0x91,0x8d,0xe2, + 0x56,0x16,0xc1,0xdf,0x4a,0xa1,0xa2,0x2d,0x61,0xd2,0xd5,0xab,0xc3,0xe6,0x06,0x94, + 0xce,0x0c,0x08,0xa5,0x9f,0x16,0x43,0x10,0xca,0x35,0x18,0xce,0x52,0xa8,0x7b,0xad, + 0x4b,0xf4,0x6f,0x33,0x61,0xcb,0xf6,0x64,0x09,0x8e,0x51,0x80,0x32,0xf2,0x70,0x14, + 0x14,0xb3,0xea,0x1a,0xe9,0x02,0xb4,0x64,0x33,0xd2,0xb8,0x9e,0x5e,0x58,0x8b,0x13, + 0x8f,0xf1,0xd0,0xe2,0xd2,0xd6,0xc7,0x80,0xf8,0x50,0xe3,0x23,0xe4,0x20,0x0d,0xda, + 0x47,0x8c,0x44,0x3c,0xc0,0x3f,0xfe,0xf5,0x7f,0x1b,0xdc,0xd9,0x7c,0xfd,0xc0,0x9d, + 0x80,0xfc,0x37,0x44,0x04,0x3e,0xa1,0x00,0x80,0xd9,0x55,0x9b,0x4d,0x88,0x28,0xf9, + 0x31,0x84,0xca,0x6a,0xc4,0xa2,0xb0,0x06,0x7e,0x35,0x24,0xd9,0xaf,0xb8,0xb4,0x5d, + 0x41,0x65,0xc2,0x5a,0x37,0x54,0xc8,0x1d,0x12,0x54,0x13,0xf9,0xf4,0x01,0x77,0x1c, + 0x3b,0x86,0x9d,0x70,0xc5,0x3a,0xc1,0x65,0xcb,0x1b,0x6a,0xcc,0x61,0x41,0x9c,0x2f, + 0x63,0x66,0x7f,0x38,0xfa,0xfa,0x01,0x96,0x39,0xa9,0xe6,0x70,0x74,0x8b,0x67,0xe1, + 0x8a,0x71,0x29,0xbb,0x94,0xbe,0x7f,0x40,0xd3,0x9b,0x3c,0xd0,0x6c,0xda,0xd7,0x70, + 0x43,0x0a,0xbe,0x70,0x99,0x39,0x7d,0x5d,0xc8,0xc2,0xe4,0x82,0x80,0xf1,0x5a,0x74, + 0xdc,0x48,0xb2,0x93,0x35,0x42,0x71,0x8b,0xc0,0xdb,0xa2,0x11,0x07,0x69,0xcb,0x98, + 0x06,0xc7,0x76,0x4c,0xa1,0xb9,0xf5,0x62,0xa1,0x61,0x32,0x76,0xd1,0x33,0xa0,0xa0, + 0x15,0x9d,0x13,0x14,0x67,0x51,0x5a,0x15,0x01,0x69,0xf2,0x96,0x84,0x2a,0x73,0x30, + 0xb2,0x5d,0x05,0x43,0x1f,0xa7,0xc9,0xa5,0x60,0xde,0x94,0x67,0x4b,0x63,0xf4,0x43, + 0x08,0x2b,0x17,0x4c,0x21,0xd9,0x0c,0x82,0x66,0x4b,0xf4,0xd7,0x16,0xfc,0xad,0x5d, + 0x6f,0x08,0x51,0x48,0x09,0x58,0xab,0xbc,0xdc,0x87,0x6a,0x7d,0x61,0xb2,0xd6,0x01, + 0x9c,0xa6,0x50,0x0c,0x40,0xc4,0xf5,0x50,0xd9,0x52,0x35,0x1c,0xcd,0x2a,0xb0,0x41, + 0xa0,0x45,0xd9,0x14,0xb9,0x35,0xa7,0x53,0xf2,0x1a,0xb5,0x89,0x75,0x74,0x1a,0x03, + 0xb3,0xf7,0x58,0xfe,0x39,0xee,0x60,0x40,0x9e,0x59,0x69,0x31,0x99,0x37,0x10,0x50, + 0x4d,0xf3,0xcf,0xa8,0x79,0xa8,0x05,0x23,0x87,0x5a,0xd4,0x17,0x1e,0x49,0x4d,0xe3, + 0x08,0x47,0x78,0xf3,0x2f,0x45,0xf7,0x9e,0x2b,0x2f,0x24,0xb1,0x57,0x40,0x5d,0x8b, + 0x3b,0x44,0x98,0x11,0x7d,0x43,0xae,0x8d,0x75,0x10,0xb3,0xad,0x7c,0x01,0xfc,0x2b, + 0x5b,0xce,0x19,0x75,0xe2,0xc3,0x2e,0x12,0x12,0x78,0x58,0x8e,0xf8,0x03,0xfa,0x70, + 0x06,0xa6,0x25,0x71,0x7e,0x5e,0xf0,0xa2,0x67,0x61,0x0b,0xf7,0x41,0x40,0xc8,0x23, + 0x66,0x43,0xdc,0x92,0xdc,0xe7,0x34,0xf4,0xa8,0xc4,0x69,0x9f,0xe6,0xd9,0xc5,0x14, + 0x0f,0xb7,0x2c,0xd4,0x37,0x6e,0x9c,0xdc,0x09,0xc6,0xae,0xc7,0x8a,0xe3,0x9a,0xb6, + 0x26,0xb8,0x45,0x71,0xd6,0xdc,0x03,0x1e,0xd2,0xec,0xa0,0xcf,0x43,0xac,0x68,0x31, + 0xb5,0x5c,0x88,0x37,0x18,0x79,0x84,0xe2,0x37,0xf6,0x1a,0x96,0x49,0x79,0xd0,0xe8, + 0xe5,0x8a,0x0c,0x26,0x45,0x7b,0x2c,0x8f,0xc9,0x1c,0x61,0x17,0x03,0xd9,0x23,0x95, + 0x4d,0x50,0xa4,0x00,0xf2,0x10,0xec,0x3b,0x38,0x35,0xae,0x84,0xf9,0x1e,0x6d,0x5f, + 0xbd,0xd9,0x8a,0x7b,0x21,0x30,0x0e,0xf7,0x52,0x6d,0x97,0xba,0x46,0x28,0x12,0x80, + 0xc6,0x83,0x59,0xbe,0x23,0x9b,0x0b,0xae,0xa5,0xf9,0xa3,0x36,0x4b,0x99,0x79,0x28, + 0xde,0x6d,0x92,0xbd,0x56,0xc2,0x70,0xea,0x3b,0x9e,0x54,0x98,0x84,0xa5,0xf3,0xfe, + 0xc3,0xe9,0x4b,0x8e,0x4b,0x22,0x92,0x04,0x5a,0x3c,0xb5,0xcf,0x43,0x46,0x78,0x8a, + 0x6f,0x0a,0xec,0x0d,0x93,0x99,0xd7,0xe1,0x75,0x65,0x4e,0x5e,0x44,0x71,0xec,0x8c, + 0x42,0x7a,0xbf,0x24,0x9c,0xc0,0xd2,0xdf,0x20,0xd5,0x71,0x12,0x16,0x40,0x0a,0xb0, + 0xce,0x01,0xd4,0xfb,0xd4,0x84,0x34,0xa5,0x93,0xf3,0xc4,0x3d,0x30,0xfc,0xce,0x01, + 0x50,0x8e,0xfb,0xf1,0x2f,0x1e,0x36,0x11,0x4d,0xe2,0x10,0x95,0xca,0x10,0x96,0x1d, + 0x16,0x38,0x3a,0x38,0x45,0xa5,0x46,0x83,0x65,0x7d,0x15,0x0d,0xd7,0xda,0x2e,0x5a, + 0x45,0x40,0x8f,0x35,0x63,0x76,0xa6,0x71,0xb4,0x70,0x23,0x60,0x69,0x69,0xe2,0x11, + 0x17,0x8a,0x26,0x5e,0x8b,0x22,0xd9,0x50,0xa7,0x12,0xf7,0x21,0xb8,0x8d,0x14,0x45, + 0x4a,0x8a,0xbb,0xc8,0x5c,0x02,0x16,0xe2,0x41,0x01,0x98,0x1b,0x81,0x65,0xea,0x36, + 0xcc,0x43,0x04,0xb2,0x9c,0xa5,0xb3,0x8a,0x36,0xd8,0xd1,0x0d,0xda,0x99,0x6e,0xca, + 0x78,0x33,0x0a,0x39,0x32,0x71,0x1d,0xa3,0x13,0x74,0x5a,0x02,0x16,0x25,0x82,0xc0, + 0x89,0x85,0xba,0xb6,0x5f,0x82,0x26,0x55,0x5a,0x6a,0x44,0xbc,0x92,0x95,0xb1,0xff, + 0x80,0x7d,0x0a,0xc4,0x6a,0xf6,0xa5,0x83,0x0c,0x57,0xe5,0x83,0x94,0x94,0x13,0x9c, + 0x56,0xd0,0xeb,0x57,0xf3,0x0c,0x58,0x82,0x5b,0x7f,0x77,0xa1,0xd8,0xef,0x84,0x4e, + 0xef,0x4f,0xc2,0xcb,0xc9,0x1c,0xc3,0x23,0x67,0x3a,0x3e,0x83,0x80,0xc8,0xdf,0xa8, + 0x61,0x48,0x90,0x1f,0x93,0x72,0x5a,0x5f,0xc0,0x71,0x13,0x22,0x03,0x68,0x56,0x4d, + 0x3b,0x4e,0xb7,0xd7,0x90,0x86,0x8a,0x22,0x19,0x69,0x7e,0xe8,0xc9,0xe6,0xd1,0x8c, + 0x02,0xd4,0x03,0xb6,0xfe,0x0e,0x79,0xa6,0x8f,0xb8,0xe1,0xf0,0xf5,0x44,0xc4,0x42, + 0xd1,0x05,0x9c,0x16,0x88,0xc9,0x07,0xc8,0x57,0x80,0x95,0x10,0x69,0x9f,0xcd,0xc9, + 0x6f,0x82,0x26,0x16,0xd1,0x81,0xa1,0x15,0x89,0x59,0xa4,0xa9,0x6b,0x88,0x83,0xfc, + 0x90,0x38,0xf7,0xa9,0x3d,0xa8,0xe4,0x0a,0xff,0xb5,0x1e,0x1d,0x35,0x0a,0xb6,0x1b, + 0x35,0xe8,0x79,0xa6,0x22,0xf6,0xe7,0x20,0x6e,0x94,0xe7,0x5a,0x4c,0x8b,0xd2,0xc8, + 0xf4,0xc9,0xf8,0x4a,0x51,0xec,0x7b,0xb5,0x8c,0x45,0x20,0x18,0x00,0x8e,0x04,0x02, + 0xbd,0xa3,0x92,0xf2,0x10,0x25,0x94,0xa3,0x93,0xf5,0x2d,0x71,0xbb,0x03,0xba,0xe6, + 0x02,0x74,0xcb,0xb5,0x5b,0x3d,0xea,0x28,0x95,0xe6,0x13,0xf5,0x50,0x96,0xc3,0x35, + 0xa1,0x10,0x3b,0x5d,0x69,0x88,0x5a,0xad,0x54,0x67,0xec,0x6d,0xe5,0xf0,0x01,0x17, + 0x96,0x48,0xd4,0xa5,0xc8,0x67,0xab,0xb0,0x28,0x4e,0xbb,0x43,0xaa,0xa8,0x40,0x9b, + 0x29,0xd0,0x89,0x07,0x01,0xff,0x26,0xb1,0xd7,0x17,0x12,0xa7,0xa1,0xce,0x58,0x63, + 0x9a,0x74,0xf7,0x42,0x3a,0x30,0xf8,0x84,0x29,0x02,0xfb,0x8f,0x9a,0x12,0x7b,0xac, + 0x10,0x08,0xca,0x08,0xae,0xad,0x27,0x82,0x7a,0x9e,0x17,0x15,0xa4,0x8a,0x3e,0x40, + 0x15,0x51,0x53,0xb6,0x01,0x3f,0x1f,0x08,0x28,0x81,0x33,0x12,0xa7,0xfb,0xd3,0xcc, + 0x51,0xfc,0x44,0xf7,0x00,0x77,0x82,0x6a,0xe9,0xc0,0x3e,0x37,0x6e,0x8c,0xca,0x3a, + 0x3d,0x4e,0x3d,0x4c,0x84,0xcf,0xcd,0x43,0x57,0x14,0xf6,0x8a,0x78,0x1c,0x6e,0xb7, + 0xe6,0x8d,0x92,0xae,0xc3,0xf1,0xae,0x2e,0x6d,0xb6,0xcb,0x09,0x72,0xe8,0x1d,0xb7, + 0x45,0x2e,0x45,0x68,0x94,0x8c,0xe3,0xe5,0x24,0xcc,0x69,0x1e,0xa2,0xb4,0xa1,0x2c, + 0xd8,0x65,0x0e,0x4a,0x22,0xfb,0xd0,0xf3,0x16,0xe5,0x7d,0x5c,0x26,0xe8,0x0c,0x82, + 0xf9,0x51,0xce,0x74,0x91,0x73,0xc8,0x09,0x86,0x5f,0xa1,0x6c,0x33,0xa4,0xd0,0x4c, + 0x44,0x5a,0xbe,0xd4,0x05,0xb5,0x6e,0x63,0x30,0x1c,0x5b,0x8b,0xa9,0xf1,0x92,0xa8, + 0x16,0xa4,0x61,0x3f,0x40,0xf6,0x6c,0x99,0x21,0x69,0xc2,0x27,0x96,0x2b,0x4d,0x09, + 0x43,0xca,0x7d,0x5c,0xb5,0x78,0x3c,0xcb,0xa8,0x2a,0xbb,0x07,0xf4,0xb0,0x2a,0x4d, + 0x71,0x37,0x70,0x10,0xf4,0xa3,0x42,0xf6,0xd5,0x71,0xb3,0x5d,0x42,0x24,0xc5,0xd8, + 0x45,0x72,0x1e,0x6c,0x20,0xbe,0x1f,0x3f,0xd6,0x4d,0xad,0xd0,0xca,0xcb,0x6a,0x37, + 0xf9,0x7f,0x12,0xf2,0x48,0xba,0x04,0x15,0x94,0x36,0x40,0x5f,0xdb,0x2b,0xbb,0xe6, + 0xb8,0xad,0xac,0x34,0x93,0x86,0xff,0x47,0x74,0x06,0x81,0x08,0x5b,0x86,0x9c,0x37, + 0x74,0xe9,0x43,0xbd,0xa2,0x2e,0xdc,0x3e,0x75,0x7a,0xba,0x80,0x89,0x83,0x6a,0x36, + 0x0d,0xfc,0x79,0x8c,0x44,0xb4,0xd9,0xde,0x2d,0x0b,0x72,0x62,0x7e,0x18,0xc1,0x7a, + 0xb9,0x04,0xc3,0xd8,0x35,0xfc,0xd5,0x42,0xe9,0x00,0x05,0x23,0x8c,0x61,0xe9,0x70, + 0xe0,0x0e,0x5e,0x51,0x05,0x06,0xf5,0x46,0x2b,0xe5,0x2a,0xae,0xda,0x0c,0x97,0x3f, + 0xc4,0x8e,0x38,0xda,0xe4,0x81,0x14,0xb7,0xaf,0xa2,0x18,0x2f,0x34,0x75,0xce,0x1a, + 0xfa,0xb2,0xc7,0x06,0x1b,0xe6,0xea,0x8d,0xc8,0x83,0x49,0xb0,0xc0,0x7b,0xda,0x86, + 0x14,0x8d,0x13,0x4c,0xd8,0x57,0xd1,0x27,0x13,0xcd,0xdf,0xc0,0xe5,0xd2,0x17,0x78, + 0x72,0x45,0x9c,0x43,0xad,0xb5,0x8f,0x5f,0x3f,0x06,0x8b,0xbe,0xc3,0x5b,0x64,0x1b, + 0x93,0x11,0x34,0x2b,0xf7,0xb7,0x7d,0xbd,0xd3,0xff,0x58,0x6e,0x7f,0x9f,0xfb,0xac, + 0xa9,0x2b,0x47,0x44,0xc7,0xf3,0x37,0xf0,0x86,0x26,0x0c,0xe7,0x29,0x87,0x91,0x43, + 0x35,0x76,0xa9,0x98,0x61,0x6f,0x58,0x29,0xa6,0xd0,0x1c,0x4f,0xe8,0x76,0x1e,0x06, + 0x44,0xf1,0xed,0x65,0x18,0xf2,0x63,0x40,0xa1,0xe8,0x21,0x90,0x9c,0xab,0xa1,0x60, + 0xf1,0xa6,0x80,0x02,0x93,0xe5,0x6f,0xa0,0x7e,0x27,0x91,0x61,0x18,0x5f,0x55,0xed, + 0x41,0x79,0x36,0x60,0xad,0x19,0xb1,0x73,0xc2,0x95,0xf4,0x5c,0xb8,0xd1,0xfa,0x8e, + 0xb1,0x6c,0xfd,0x8d,0x34,0x51,0xb0,0xa7,0x89,0x98,0x7d,0xda,0x42,0x44,0x7b,0x2e, + 0x19,0x38,0x54,0xe4,0x15,0x92,0x82,0x51,0x42,0x2a,0xa4,0x5c,0x66,0x43,0x19,0x16, + 0xf5,0x96,0xfd,0x73,0xce,0x1f,0x76,0x70,0x1b,0x0f,0xbd,0x00,0xd2,0x02,0xe4,0x65, + 0x2e,0x1e,0x61,0x94,0xac,0x92,0x13,0x8d,0x37,0x1b,0xdd,0x1e,0xdb,0x7e,0xd0,0x13, + 0x75,0xe4,0x01,0xfa,0xc2,0x58,0x65,0x6b,0xba,0x81,0xee,0x81,0x21,0xef,0x18,0x88, + 0x52,0x07,0x18,0xcc,0xee,0x8a,0xfb,0x62,0x35,0xc6,0x8e,0x5f,0xd1,0x70,0xb3,0xb9, + 0xc8,0x82,0x75,0x83,0x07,0x4a,0x72,0x36,0xf3,0xfb,0x0c,0x2f,0xd7,0x77,0x56,0x10, + 0x4f,0xf7,0x71,0xe1,0x45,0x19,0xc7,0x2a,0xe4,0x7e,0xf9,0xe8,0x28,0x9d,0x19,0x8d, + 0xd4,0xfd,0x3d,0xa0,0x47,0x40,0x63,0x30,0x06,0x5c,0x79,0xaa,0x19,0xd1,0xd1,0x46, + 0xc5,0x8a,0xe6,0xbd,0x21,0xfc,0x22,0xb4,0xd3,0x4f,0x5c,0x62,0xc2,0x04,0xb8,0x5b, + 0x13,0xc9,0x52,0x77,0x16,0xe2,0x80,0xc2,0xd4,0xec,0x35,0x35,0x50,0xb1,0xdc,0xf7, + 0x09,0xa5,0xa5,0x68,0x6e,0xa2,0x4f,0x8e,0x77,0x3e,0x3c,0x38,0x3e,0x51,0x9e,0x21, + 0x4c,0x38,0x7a,0x79,0x78,0x70,0x44,0x46,0x86,0x88,0x88,0x3e,0x7d,0x73,0xf8,0xd3, + 0x89,0x0c,0x26,0x36,0x1d,0x4b,0x87,0xb0,0x6a,0x5d,0x1d,0x66,0x86,0x82,0xe6,0x80, + 0x24,0x1f,0x0e,0x48,0xc0,0x55,0x8b,0x79,0xdc,0x32,0xa3,0x97,0xc4,0x37,0xc6,0x15, + 0xe1,0x12,0x1e,0xa3,0x05,0x08,0xe2,0x52,0x44,0x0a,0xa9,0x05,0x3b,0x6e,0xc9,0xdf, + 0x1c,0x9d,0xb4,0x21,0x56,0x3f,0x56,0x86,0x1f,0x1c,0x34,0xc3,0xcb,0x79,0xdc,0xc2, + 0x4b,0x4a,0x50,0x0d,0x94,0x0b,0xbb,0x76,0x3d,0x1b,0x4b,0x77,0xdc,0x12,0xf7,0x99, + 0x50,0x25,0xb1,0x8e,0x6b,0x97,0x2f,0xc5,0x2d,0x6a,0xbc,0x18,0x81,0x3c,0x38,0x4a, + 0x11,0x84,0xb6,0xe5,0xc8,0x0f,0x8a,0x6d,0x55,0x58,0x3b,0xc3,0x90,0xc6,0x46,0xaf, + 0xdd,0xc0,0x8d,0x6a,0x5a,0x20,0x0d,0xf8,0xb7,0x21,0x02,0x1c,0xe1,0xab,0x2b,0xbe, + 0x7a,0x6d,0x2e,0x88,0x5f,0x1b,0x58,0x92,0x8a,0x7e,0x6e,0xe8,0x50,0xc8,0x46,0xf7, + 0x73,0x43,0x87,0x42,0x36,0x7a,0x9f,0x25,0x4c,0x01,0x15,0xbe,0xcf,0xf1,0xe6,0x7e, + 0x64,0xc7,0xae,0x7b,0x36,0xfb,0x72,0xce,0x63,0xfa,0x02,0x82,0x5f,0x77,0x0e,0x83, + 0x53,0x5a,0x9d,0x1e,0x6a,0x55,0x90,0xf3,0xcc,0x31,0xc6,0xf0,0x03,0x1a,0xb7,0x4f, + 0x8c,0x00,0x62,0xa2,0xa8,0xd7,0x5f,0x4a,0x01,0x47,0xc8,0x2d,0x35,0x3c,0x23,0x7a, + 0x43,0x83,0x2a,0x1d,0xc2,0x31,0x50,0x63,0xba,0xba,0x71,0x61,0x1f,0xfe,0xd3,0x41, + 0xdc,0x6a,0x7f,0xb9,0x26,0x7e,0x18,0x87,0x82,0x44,0xcc,0x0e,0x73,0x4d,0xe5,0xf8, + 0x52,0x0f,0x6d,0xdf,0xe0,0x07,0xf1,0x3b,0xe1,0x40,0xa6,0x4c,0xe0,0xc9,0xf8,0x06, + 0x6b,0xc6,0x45,0x74,0xa8,0x69,0x98,0xe5,0xa0,0x54,0x32,0xcd,0x9b,0x0f,0xde,0xaa, + 0x0a,0xe4,0xa4,0xd4,0x95,0xcd,0xb7,0x5c,0xe3,0x65,0x3e,0xf3,0xd1,0x84,0xb3,0x4d, + 0x51,0x4a,0xd7,0x06,0xa3,0x86,0x24,0x77,0x4c,0xb8,0xcf,0xf7,0x6a,0x4e,0x07,0x59, + 0x1d,0xb4,0xb4,0x5c,0x61,0x9e,0x03,0x6d,0x0a,0xc6,0xb1,0x76,0x8b,0x83,0xba,0x63, + 0x4e,0x11,0x6e,0x86,0xde,0xe8,0x90,0x68,0x1a,0xfa,0x9a,0xcd,0x07,0x8a,0x42,0xc5, + 0xd9,0xc6,0xae,0xdd,0x24,0xe3,0x03,0x75,0x3d,0x92,0x2b,0x52,0xc4,0xed,0x37,0xf4, + 0x59,0x52,0x3d,0x4c,0xbc,0xd0,0xd3,0x10,0x7a,0xb6,0x45,0xf0,0x29,0x36,0x6f,0xd0, + 0x84,0x3a,0x97,0x42,0x69,0x7c,0xe6,0xc1,0x3e,0x10,0xa1,0x49,0xf9,0xde,0x31,0x7e, + 0x5c,0x1c,0xcd,0xb5,0x43,0x3e,0x0c,0x4f,0x4e,0x78,0xfc,0x6e,0xe8,0xdc,0x71,0x81, + 0x67,0x60,0x74,0x21,0x84,0x44,0x96,0xcc,0x35,0x88,0x81,0xee,0x44,0x97,0x7c,0x87, + 0x74,0xe5,0x80,0xb4,0xda,0xd9,0x03,0x31,0xd1,0x77,0x76,0x41,0xdc,0xf4,0x9d,0x2e, + 0xfc,0x01,0xbe,0xb7,0xd3,0x76,0x04,0xc9,0x1d,0x7f,0xe2,0xc0,0x99,0xe3,0xd7,0x3c, + 0x8f,0x5c,0xf9,0xf0,0xc3,0xc1,0xc7,0x93,0x97,0x18,0x23,0x86,0x02,0xf3,0x1d,0x5e, + 0x20,0xef,0x36,0xd4,0x0d,0xf2,0x8e,0xb8,0x42,0xbe,0x81,0x6e,0x3a,0xd4,0x21,0x73, + 0x59,0xef,0xe5,0xd1,0x8f,0x58,0x4b,0x54,0x07,0x85,0x75,0x0f,0xd6,0xc8,0x13,0x99, + 0xfb,0xe3,0xc7,0x37,0xc7,0x56,0x6e,0xc7,0xcc,0xfd,0xf8,0xf2,0xe0,0xf0,0xb5,0x99, + 0xdd,0xed,0xa2,0x87,0x52,0x9d,0xe6,0x78,0xfd,0xe6,0xfd,0xe9,0x2f,0x07,0x3f,0x9f, + 0x7e,0x40,0x23,0xf7,0x5b,0xef,0x93,0x6a,0x6c,0x80,0x16,0xad,0x20,0x37,0x4e,0xf8, + 0xc2,0x33,0x7d,0xa5,0x15,0x3a,0xaf,0x70,0x73,0x12,0xfd,0xd7,0x81,0xc3,0xd7,0x66, + 0xaa,0x4b,0xa5,0xc8,0x6a,0xf9,0xde,0x1b,0xa9,0xf4,0x8c,0xd0,0x00,0x5e,0x1f,0xbc, + 0x3f,0xc2,0x01,0x7c,0xa2,0xbb,0x1e,0xa9,0xdb,0xd3,0x2c,0xfc,0x6d,0x19,0x26,0x63, + 0x74,0xbe,0x05,0xa4,0x1a,0x38,0x6c,0x42,0xc2,0xa8,0xd2,0x96,0xf3,0x9a,0x2f,0x7b, + 0xa4,0xa2,0xbf,0x2d,0xa3,0xb0,0x68,0x16,0x69,0x13,0x87,0x2a,0x7a,0x8e,0xde,0x36, + 0x30,0xbe,0x81,0x06,0x52,0xf2,0xad,0x9b,0x9b,0xee,0xb0,0x3e,0x8e,0x81,0x54,0x68, + 0x99,0x1b,0x34,0xc3,0x7e,0x00,0x31,0x4a,0xde,0x58,0x16,0x6c,0x37,0xcf,0x3f,0xd9, + 0xe4,0xc5,0x06,0x21,0xf5,0xd6,0xc7,0xec,0xd7,0x75,0xd9,0xdc,0x45,0x09,0x64,0xb2, + 0xc8,0xb4,0xb6,0xc0,0x7e,0x8a,0x63,0x30,0xc0,0xe2,0x8f,0x68,0x14,0x90,0x3c,0x1d, + 0x98,0x9d,0xa1,0x5b,0x2f,0xa5,0x74,0x13,0x61,0x38,0xd8,0x8d,0x1f,0x10,0x90,0x67, + 0x15,0x55,0x3d,0xb6,0xcb,0xbe,0xae,0x2b,0x5b,0x1a,0x23,0x15,0x03,0xb3,0x7a,0x71, + 0x0d,0x83,0xc5,0x55,0x84,0x8e,0xbb,0x53,0xbc,0xea,0x16,0x63,0x2c,0x5c,0xa8,0x4e, + 0xf1,0xcf,0xf0,0x9f,0xfa,0x89,0x2a,0xe3,0x27,0xae,0xfa,0x09,0x84,0xf3,0xbb,0x56, + 0x4c,0xff,0x82,0xde,0x43,0x8b,0x85,0x20,0x62,0x42,0x41,0xff,0x8e,0xf4,0x8a,0xbf, + 0xfe,0x80,0x5b,0x0f,0xee,0xec,0x0b,0x4b,0x2e,0xa8,0xf7,0x18,0xd7,0xd9,0x0f,0xc2, + 0x5f,0xcb,0x12,0x5c,0x48,0x38,0x2a,0x65,0x89,0x70,0x0c,0xbc,0x65,0x91,0xaf,0x28, + 0x67,0xf6,0x85,0x21,0x1a,0xd1,0xbd,0x50,0xd3,0x92,0xac,0x56,0x40,0xae,0x54,0x19, + 0xa0,0x45,0xf7,0x9a,0xbb,0x8e,0x60,0x8f,0x3f,0x79,0xfa,0x4c,0xea,0x0d,0x83,0x14, + 0xd2,0x15,0x06,0xf1,0x98,0x8f,0xab,0xe9,0x10,0x28,0x8c,0x81,0x3a,0x7e,0x2d,0xcb, + 0x5f,0x72,0xf9,0x1b,0x2b,0xc0,0x18,0x2b,0xb8,0x37,0x8c,0x05,0x6a,0xe1,0xb5,0x82, + 0x1f,0x5c,0x47,0xf9,0xd1,0x48,0x59,0xc7,0x24,0xea,0x84,0xb6,0x45,0x1d,0x9f,0x8c, + 0x06,0xea,0x10,0x5b,0xb2,0x44,0x66,0xe7,0xb2,0x46,0x7d,0x52,0xa0,0x4b,0xcf,0x3c, + 0xd7,0x08,0xb2,0xbb,0x95,0x85,0x8b,0x38,0x18,0x87,0x6e,0xa3,0x89,0x46,0xe9,0x3f, + 0xfe,0xc7,0xbf,0x35,0x4c,0x61,0x31,0x19,0xe1,0xad,0x25,0xee,0xa5,0x56,0x0a,0xc9, + 0xb3,0xcf,0x7d,0x30,0xb6,0x29,0x21,0xf5,0x39,0xb7,0xe7,0x4e,0x46,0x1c,0x5b,0x74, + 0x89,0x58,0x82,0x8f,0x0e,0xba,0xda,0x29,0xd1,0xf3,0x84,0x3b,0xcc,0xf4,0xae,0x8e, + 0xde,0x46,0xc0,0x5a,0xdc,0x95,0x0d,0x88,0x33,0x47,0x58,0x48,0xa8,0xac,0x24,0x56, + 0x27,0x23,0x25,0x4f,0x29,0xcf,0x08,0x96,0x9a,0x48,0x3a,0xc6,0xd3,0x19,0xa2,0x3b, + 0x5b,0x14,0x24,0x8b,0x41,0xbc,0x03,0xc8,0x7f,0x36,0x74,0xa8,0x63,0xf8,0xfb,0xf1, + 0x90,0xb2,0xc0,0x88,0x45,0x30,0x1c,0xba,0x74,0xe6,0x4e,0x54,0x9f,0x71,0x37,0xc0, + 0x1e,0x85,0x2f,0x07,0xea,0x9d,0x9b,0x27,0x3a,0x44,0x37,0x4c,0x89,0x87,0x76,0xb3, + 0x31,0x32,0x1c,0x00,0x49,0x95,0xf9,0x02,0xa3,0xad,0x4e,0x70,0x21,0x69,0x83,0x9c, + 0x76,0x00,0x15,0x51,0xd0,0xb4,0xc1,0xcc,0xd2,0xcc,0x91,0x30,0x3a,0xce,0x52,0x50, + 0x57,0x8a,0x1b,0x56,0x87,0x28,0xaf,0x05,0x33,0x3a,0xd7,0x48,0x0a,0xe2,0xc5,0x2c, + 0xb0,0x2a,0x9a,0xc7,0x5a,0x75,0xc4,0xb0,0xa8,0xcc,0x41,0xca,0x1d,0x3c,0x1c,0xb7, + 0xab,0x67,0xd2,0x0d,0xa8,0xe6,0xbf,0x64,0x17,0xa3,0xc0,0xfd,0xd3,0x6d,0xe2,0xec, + 0xef,0x43,0xfe,0x9d,0xef,0x88,0xdf,0x7b,0xce,0x23,0x0c,0xe0,0x13,0x09,0xfa,0x77, + 0x70,0xe7,0xfd,0x0b,0x39,0x2a,0xd4,0xe1,0x06,0x7e,0x58,0xc2,0xb9,0x04,0xd2,0xe2, + 0x47,0x26,0x1a,0x18,0x2c,0x40,0x0f,0x43,0x70,0x22,0xfd,0xc6,0x44,0x7c,0x0d,0x82, + 0x93,0xe0,0x17,0x26,0x88,0xc3,0x0f,0x94,0xc4,0x91,0x69,0x1e,0x1e,0x78,0xc6,0x57, + 0x21,0x04,0x3c,0xfc,0x8d,0x89,0xf4,0x34,0x04,0xa7,0xe1,0x4f,0x4c,0x8a,0x55,0xd5, + 0x98,0x2b,0xc2,0x9f,0x83,0x3e,0x63,0xc7,0x48,0xc5,0xe2,0x66,0xb2,0xac,0x0e,0x5d, + 0x30,0x93,0xa9,0x47,0x7c,0x5c,0x41,0x4d,0x2c,0x06,0x86,0xbd,0x4c,0x2e,0xf9,0x70, + 0x9a,0x9e,0x5f,0xde,0x6e,0xb3,0x63,0x51,0x41,0x27,0xe7,0x15,0x8a,0x99,0xe6,0x87, + 0x38,0xdd,0xa2,0xf0,0x25,0xf2,0xc5,0xa1,0xc0,0x7d,0x71,0x28,0x50,0xef,0xc1,0x09, + 0xc6,0x20,0xce,0x0a,0x8a,0x8d,0x38,0x23,0xd1,0xdc,0x8d,0x2b,0x9d,0x27,0x4d,0x26, + 0x9f,0x48,0x66,0x94,0xfb,0x8b,0x39,0xa2,0xc3,0xe2,0x68,0x97,0xdd,0xa5,0xd2,0x30, + 0x81,0xc1,0x70,0x5f,0xf4,0xb9,0x43,0xee,0x86,0x3e,0x3f,0xe8,0xdc,0x69,0x66,0x8d, + 0x0a,0x02,0xc7,0xc4,0x30,0xa3,0x7a,0xf0,0x80,0x5d,0x54,0x72,0x5f,0x53,0x21,0x43, + 0xec,0xf3,0x71,0x98,0x40,0xd9,0x98,0x38,0x4e,0x73,0xdd,0x6d,0xe5,0xe6,0xa2,0x3d, + 0x42,0x05,0x00,0x3e,0x64,0x6d,0xa7,0xb4,0x03,0xa8,0x0a,0x88,0xb1,0x69,0x3a,0x67, + 0x6d,0x57,0x1d,0xf3,0x34,0xbb,0x22,0xca,0x8a,0x13,0x1c,0x65,0xf4,0xf8,0x25,0xbc, + 0x94,0xb4,0xff,0xa8,0x10,0xc8,0xc6,0x3a,0x4a,0xbb,0xe5,0x43,0x48,0x43,0xe3,0x0c, + 0xa8,0x61,0x64,0x99,0xf8,0x24,0x16,0xce,0x4a,0x10,0xcb,0x21,0x69,0x2f,0x93,0x84, + 0x31,0x30,0x3d,0x2c,0x19,0x69,0xb2,0x9c,0xaf,0xdb,0xd0,0xa5,0x05,0x5c,0x8c,0xba, + 0x30,0x0e,0x8d,0x96,0xbb,0x8e,0x9a,0x7f,0x21,0x24,0xa7,0x32,0xd8,0xd0,0xd6,0x44, + 0x16,0x49,0x9b,0xdb,0x90,0xc5,0x67,0x0c,0xda,0xda,0xfb,0xcb,0x05,0x9e,0x3e,0xed, + 0x61,0x01,0xda,0xfb,0xd6,0x42,0x65,0xeb,0xbf,0xb5,0xda,0x7f,0xda,0xf2,0x71,0x8f, + 0x00,0x75,0x04,0xda,0x2f,0xa8,0x8a,0x21,0x68,0xcf,0x50,0xeb,0xdf,0x7d,0x78,0x4f, + 0x9a,0x28,0xbd,0x82,0x64,0x3d,0x76,0xe3,0x9c,0xbc,0xc2,0xe7,0x6b,0x9a,0x1f,0xc3, + 0x8b,0x65,0x1c,0x80,0x32,0xc1,0x6f,0xdc,0x38,0xea,0x91,0x1b,0x47,0x95,0x35,0x95, + 0x35,0xf4,0xa4,0x2a,0x65,0x8d,0xdb,0xc0,0xa3,0xcb,0x82,0x3b,0x4b,0xe6,0x89,0x0a, + 0x89,0xd2,0x28,0x1e,0xa3,0x3a,0xe2,0x3b,0xaf,0x29,0x0d,0x25,0xf8,0xf1,0x6b,0x4a, + 0x1b,0x09,0x15,0x87,0x8c,0xb7,0x8f,0x60,0xea,0xb8,0xac,0xda,0x7c,0x82,0xb2,0x9e, + 0xc8,0x03,0x6b,0x3d,0x26,0xd6,0x0e,0x95,0x4f,0xf9,0xc2,0x7a,0x23,0x67,0x55,0xa5, + 0x94,0xbc,0xdb,0x38,0x76,0xa9,0x45,0x15,0x59,0xfa,0x39,0xd4,0x80,0x88,0x5d,0xb9, + 0x74,0xa0,0xac,0xb6,0x21,0x62,0x93,0x22,0x07,0x45,0xd1,0x27,0xa1,0xfd,0xc9,0x13, + 0xef,0xe2,0x64,0x1b,0xde,0xb8,0x81,0x57,0x9a,0x9c,0xa3,0x2e,0xaf,0x84,0xaf,0xc6, + 0xcc,0x8d,0xad,0x04,0x82,0x32,0x43,0x0a,0x0b,0xfa,0x49,0x7b,0x2c,0x7a,0x2f,0x69, + 0xd3,0x01,0x16,0xdf,0x25,0x6e,0x60,0x92,0x02,0x8c,0x6d,0x8e,0xc2,0x8b,0x28,0x39, + 0x86,0x9a,0x18,0x38,0x47,0x29,0x73,0x50,0xd7,0x4f,0x53,0x17,0x90,0xea,0x3b,0x37, + 0x32,0x11,0xbb,0xc6,0x89,0x84,0x69,0x23,0x87,0x07,0xcc,0x3b,0x21,0x94,0x80,0xa6, + 0xd7,0x01,0x3e,0x4c,0x81,0xd4,0x40,0x0f,0x04,0x36,0x8c,0x91,0x93,0x5e,0x42,0x43, + 0xf1,0x85,0x06,0x09,0xe6,0x18,0xdd,0x0f,0xf0,0x15,0x08,0x14,0x82,0x20,0xd4,0x0b, + 0xcf,0xb1,0xe1,0x35,0x26,0x2f,0x1a,0x06,0x38,0x56,0x41,0x9f,0x7a,0xe5,0x66,0x1b, + 0xaf,0xbf,0x94,0x8b,0x09,0x12,0x21,0x49,0x5a,0x6d,0x9b,0xdf,0xd4,0x68,0xd8,0x53, + 0x31,0xfb,0x62,0xce,0x05,0xb9,0x97,0xf4,0x3c,0x5c,0xdb,0xf3,0x00,0x9a,0x2f,0x2d, + 0x13,0x39,0x11,0xeb,0x51,0x7e,0x4d,0x7d,0x2a,0xa1,0xfc,0x5a,0x77,0xb4,0x8a,0xf2, + 0x5a,0xb4,0x5e,0x57,0x87,0x56,0x87,0x58,0xbc,0x42,0xbf,0x32,0x33,0x8a,0x99,0x18, + 0x0a,0x38,0xa1,0xec,0x3e,0xe8,0xaa,0x9f,0xec,0x0a,0x48,0x8c,0x3e,0x74,0x34,0x25, + 0xd5,0xc2,0xad,0x5b,0x46,0x83,0xfb,0x50,0xac,0x01,0x0d,0x30,0xbe,0x92,0x7c,0xeb, + 0x8b,0x69,0xc4,0x0a,0xcd,0x6f,0x11,0xa2,0x33,0x95,0x85,0x8c,0x0a,0xdc,0xa1,0xed, + 0x44,0x11,0xe8,0x0c,0x69,0xc6,0x69,0x49,0xb5,0xaa,0xec,0x35,0x8e,0xaa,0x09,0xb0, + 0x80,0xce,0x8e,0x57,0x33,0x84,0x8d,0xea,0xa2,0x03,0xa2,0x41,0xc0,0xa4,0x7a,0xab, + 0xe3,0xba,0x57,0xe8,0xea,0xf9,0x04,0x6c,0xdc,0x68,0xb3,0xfe,0xa8,0x81,0x59,0xc0, + 0xbe,0x1e,0x03,0xb9,0x84,0x82,0x8e,0x11,0xfd,0x1b,0x55,0xec,0x44,0xa0,0x6e,0x8f, + 0xae,0x68,0x81,0xd7,0xe4,0xba,0x78,0x2c,0xa0,0xe3,0x19,0x65,0xee,0x36,0xd6,0x63, + 0xb8,0x0a,0xa6,0x9a,0x37,0x8e,0xd3,0x3c,0xb4,0xf0,0x81,0x08,0x64,0x9e,0x52,0x77, + 0x78,0x87,0xfc,0x50,0x91,0xa5,0x2a,0x5f,0x91,0x9c,0x36,0x95,0x26,0x85,0xba,0x6b, + 0xbc,0x59,0x05,0x57,0x22,0xc9,0x50,0x49,0xd3,0xd7,0x9d,0x52,0x2a,0x90,0xa5,0xb2, + 0x05,0x4f,0xd3,0x85,0x40,0x15,0xc0,0x45,0x1d,0x0d,0xc6,0xfa,0x22,0x2d,0x8c,0x34, + 0xba,0xf4,0x80,0x4b,0x47,0xf9,0x09,0x39,0x31,0x23,0xda,0xee,0xce,0xc3,0x58,0x91, + 0x0f,0x91,0x13,0xe6,0x50,0x89,0xe7,0x40,0x0a,0x18,0x16,0x80,0x1b,0x26,0xd8,0xa6, + 0x3c,0x06,0x04,0xd2,0x06,0xd5,0x62,0x48,0x27,0x52,0xa9,0xd8,0x05,0x56,0xe1,0x76, + 0xab,0xbd,0x83,0x10,0x24,0x48,0x20,0x2b,0x74,0x0b,0x41,0xf2,0x93,0x7a,0x01,0x83, + 0x5a,0xb4,0x4b,0xa0,0xbc,0xb2,0x3c,0xbb,0xc6,0xeb,0x66,0x60,0xa8,0x84,0x8c,0xa6, + 0x43,0x9f,0x38,0xca,0x26,0xa5,0xd6,0x2f,0x45,0xfe,0xaa,0x11,0x58,0xb2,0x43,0x1d, + 0x8a,0x9e,0xe8,0x7c,0x95,0xd7,0x89,0xb6,0xcb,0xdc,0x4e,0xf4,0x61,0x05,0xab,0x5b, + 0x0d,0xae,0x53,0x0f,0xae,0xb3,0x0a,0x9c,0xd8,0x0e,0xd2,0x2a,0xbf,0x90,0x29,0x79, + 0x58,0xa0,0x70,0x3d,0x0a,0xd0,0x9e,0xec,0xf9,0xce,0xce,0xb9,0xf7,0xbd,0x43,0x29, + 0x75,0xe9,0xde,0x43,0x29,0xa1,0xe0,0xab,0x43,0xa9,0xf6,0xfb,0x5c,0x0c,0x50,0xe8, + 0xf2,0xa6,0xa2,0x10,0xdf,0x98,0xea,0x2c,0x11,0xfa,0x63,0x9c,0x33,0x43,0xaf,0x15, + 0x34,0x40,0x89,0xe2,0xb7,0x52,0xe9,0xe9,0x1e,0x10,0x93,0x48,0xbc,0x55,0x1c,0x3b, + 0xae,0x55,0x6b,0xba,0x5f,0xe3,0x80,0xd7,0x78,0x9b,0x10,0x0c,0x35,0x2e,0xf3,0x1f, + 0x22,0x51,0x2b,0xc3,0xd4,0x3c,0x70,0xb4,0x44,0x81,0x2b,0x58,0xb0,0xa9,0xcf,0x95, + 0x7b,0x0a,0x6b,0xee,0xeb,0x0a,0xd8,0x18,0x0f,0x1d,0xdf,0x90,0xc8,0x3f,0x3b,0x93, + 0x33,0x8e,0xbb,0x3e,0x72,0x9a,0xe9,0xb7,0x98,0x3a,0x95,0x8e,0xbf,0xcf,0xad,0x2e, + 0xd1,0xc2,0x1b,0xa3,0x13,0x8a,0xbc,0xbf,0x5b,0x18,0xc9,0x3c,0xbe,0xb1,0x3e,0xf1, + 0x17,0xff,0x6b,0x8f,0xf4,0x5b,0xab,0xde,0x89,0xc8,0x68,0xd2,0xe9,0x4f,0x83,0x8b, + 0xdc,0xb5,0x0d,0x07,0x23,0x7d,0x85,0x86,0x7d,0x3f,0xd6,0x5b,0x04,0x17,0xec,0x9a, + 0x87,0x1f,0xf2,0x28,0xda,0x1a,0xa6,0x0c,0xa5,0x6a,0xc2,0x08,0x81,0x6d,0xe2,0xc1, + 0x5f,0xc9,0x42,0x57,0x96,0x23,0x3e,0x08,0x9d,0x6e,0xf8,0x06,0x5f,0x14,0xa5,0x7f, + 0x5b,0x86,0xd9,0xcd,0x09,0xed,0x65,0xa4,0x99,0xdb,0x90,0x6f,0x25,0x55,0xe2,0x9b, + 0x1a,0x3f,0x35,0x0c,0x51,0xf6,0xb8,0xc4,0x8e,0x1b,0x8e,0x38,0x54,0x27,0x62,0xa4, + 0xd0,0x0e,0xf9,0x31,0xbe,0x59,0xcc,0xdc,0x9a,0x36,0xf8,0x32,0x56,0x3c,0x26,0xce, + 0x98,0xe9,0x80,0x5e,0xd9,0x81,0x89,0x90,0x9c,0x1c,0xab,0xb0,0xe7,0x15,0xd5,0x2d, + 0x5b,0x39,0x54,0x0b,0xae,0x22,0x9b,0x6c,0x83,0x06,0xef,0xcc,0x02,0x30,0xfc,0x2e, + 0x24,0x93,0x27,0x5e,0x4a,0xe6,0x29,0xf7,0xad,0x6e,0xa4,0x20,0xb9,0x55,0x32,0x04, + 0x84,0x08,0x83,0x4a,0xdd,0x8e,0xae,0x54,0x3e,0xc6,0xa9,0x46,0xc9,0x43,0x92,0x03, + 0x02,0x29,0x8f,0x8e,0x6e,0x7c,0x4c,0xcc,0xf0,0xf5,0xdd,0xc3,0xa3,0x4d,0x0c,0xd6, + 0xf4,0x68,0xe3,0x49,0xc4,0x2b,0xe1,0x99,0x46,0x48,0xb6,0xb7,0x5b,0xe4,0x0c,0xc4, + 0x9b,0xbe,0xda,0x51,0x3d,0x13,0x19,0xca,0xd0,0xa4,0xe3,0xc0,0xab,0xf6,0x7a,0x2e, + 0xee,0xe5,0xc6,0xbe,0xa8,0x58,0x82,0x38,0x4c,0xae,0x6e,0x31,0x07,0x1a,0x37,0x26, + 0x5b,0x9c,0xa1,0xb5,0x23,0x93,0x0e,0xe9,0xee,0xc4,0x06,0xe1,0xba,0x81,0x89,0x16, + 0x5f,0xab,0xbd,0xf1,0xab,0xb3,0x5b,0x52,0xca,0x96,0xa4,0x3a,0x6c,0x61,0x86,0xe1, + 0x45,0x5c,0xb1,0x23,0x3b,0x30,0xec,0x8c,0x2e,0xcc,0x25,0x5e,0x55,0xe7,0x5e,0xc1, + 0xd4,0xee,0x68,0xe5,0x85,0x90,0x06,0x93,0x0d,0xff,0x93,0x33,0x77,0x26,0xb2,0x89, + 0x47,0xd2,0x02,0x6b,0x7b,0xce,0x85,0x61,0x74,0xa0,0x2d,0x47,0x61,0xde,0x17,0x86, + 0xd1,0xc1,0xba,0xdd,0x85,0xc5,0x65,0xc9,0x4d,0x9b,0x05,0x7a,0x07,0x57,0x91,0xcf, + 0x2c,0x2a,0x4e,0x31,0xc0,0x94,0x2a,0xaa,0xa1,0xd1,0x2b,0x66,0xe8,0xfe,0xcd,0xd1, + 0x2e,0x69,0xb5,0x5a,0x9a,0xa3,0x50,0x78,0xf8,0x2f,0x92,0x95,0x44,0x9e,0xda,0x2d, + 0x17,0x09,0x44,0x2e,0xc8,0x08,0xce,0x2d,0x3e,0x1c,0x21,0x03,0x26,0xb0,0xeb,0xfc, + 0x61,0xe7,0x83,0xff,0x04,0x5a,0x61,0x92,0x47,0x93,0xf0,0x2f,0x08,0x0e,0x4c,0x03, + 0x68,0xad,0xc9,0xbb,0x81,0x60,0x81,0x5f,0x83,0x92,0x0e,0x0d,0x3d,0xa6,0x04,0xbb, + 0xfc,0x5f,0x11,0x18,0x94,0xa7,0xb6,0x74,0x8d,0x1b,0xa8,0x41,0x4d,0xc9,0x3a,0xe4, + 0x4c,0x97,0x4d,0xc0,0x82,0x13,0xbf,0xff,0xea,0x61,0x08,0x66,0x11,0x25,0xcb,0x50, + 0xc3,0xfd,0x8b,0xe9,0x74,0xc2,0xea,0xbe,0xe3,0x0a,0x85,0x0f,0xdd,0xe4,0xdb,0x74, + 0x40,0xec,0xaf,0x35,0x85,0x4c,0x39,0x4f,0x05,0x25,0xcc,0x04,0x16,0xcf,0x5b,0x1a, + 0x19,0x10,0x34,0x49,0x6c,0x68,0xc5,0xa7,0xe4,0x8f,0x3c,0xe0,0x21,0xab,0x94,0x90, + 0x3c,0x50,0x52,0x22,0x46,0x25,0xf9,0x81,0xdc,0x75,0xc4,0xb0,0x52,0x4b,0xff,0x32, + 0x81,0x93,0x18,0xc2,0x0a,0x3c,0xf6,0xa1,0x23,0x14,0x15,0xe8,0x27,0x37,0xf3,0xc2, + 0x2a,0x00,0xcd,0x89,0xbe,0x42,0x01,0x46,0x0e,0x77,0x11,0x72,0x09,0x9c,0x72,0x30, + 0xde,0x12,0x31,0xf4,0xf1,0x80,0xf5,0x3c,0x9d,0xe0,0xa5,0x13,0x45,0xdc,0x40,0xf7, + 0xa7,0xac,0xf3,0xf1,0x5e,0x75,0x32,0xab,0x8e,0x6a,0xe7,0xc5,0x9a,0x3a,0xa3,0x15, + 0xed,0xac,0xad,0x53,0x6a,0x67,0x4d,0xd1,0x12,0xf4,0x35,0x25,0x6d,0x98,0x6b,0x87, + 0x69,0x95,0x5c,0xdb,0x51,0x55,0x52,0x10,0xbb,0xa6,0x72,0x9e,0x20,0x9e,0x40,0x83, + 0x92,0xd7,0x00,0x43,0xc6,0xd4,0x70,0xcc,0x9b,0x86,0x2a,0xce,0x71,0xdc,0x5f,0xfe, + 0x80,0x91,0x94,0x22,0x0c,0xe2,0x3e,0x6a,0x0a,0xbb,0xf9,0x95,0x13,0x58,0x46,0xff, + 0xd2,0x85,0x80,0x32,0xb6,0xcf,0x72,0xfa,0xb2,0xcf,0xbe,0xe4,0xbd,0x65,0x9f,0x3d, + 0xf0,0x24,0xdb,0x61,0xcc,0xf2,0xd4,0xde,0x43,0x50,0xf1,0xe1,0xd5,0xf8,0x0b,0x4b, + 0x0b,0x4b,0x8b,0x63,0x0e,0x24,0x70,0xc3,0x4b,0x71,0x8f,0x02,0xf7,0x38,0x03,0xf9, + 0x54,0x09,0x6e,0x78,0x81,0xb2,0x06,0x94,0x7a,0x0e,0x44,0x26,0x11,0x66,0x5c,0x4d, + 0xe5,0x5c,0xf7,0x1d,0x82,0x22,0x76,0xa2,0xff,0x02,0x6b,0x02,0xc1,0x90,0xfa,0x01, + 0xec,0xca,0xce,0xfd,0xab,0xcc,0x45,0xbd,0xe1,0xae,0xac,0x0f,0x5c,0x7c,0x48,0x5e, + 0x47,0x85,0xd2,0x07,0x80,0xc5,0xe7,0x86,0xe0,0xae,0x46,0xaf,0x50,0xa4,0x08,0x1d, + 0x79,0xc0,0x23,0xb6,0x62,0x2c,0xc6,0x04,0x88,0xe1,0x8c,0xbf,0x32,0x14,0xc1,0x2e, + 0x10,0x18,0xe2,0x9b,0xbb,0x4b,0xb1,0x94,0x93,0x53,0x4c,0x0c,0xf3,0xb3,0xb6,0xba, + 0xe6,0xad,0xc8,0x5d,0x2a,0x59,0x3f,0x5c,0x33,0xcb,0x1c,0x2b,0xe8,0x4e,0x0c,0x77, + 0x91,0xd1,0xdf,0x23,0xbe,0xb9,0x50,0x1c,0x13,0xbf,0x75,0x16,0x78,0xbc,0x14,0x0f, + 0xc7,0xd2,0x04,0x3a,0xac,0x2a,0x69,0x8c,0xe8,0x09,0xf1,0xa5,0xe0,0xb3,0xf7,0xda, + 0x6b,0x22,0x7b,0x78,0x86,0x81,0x5e,0x92,0x7a,0xe4,0xdc,0xa2,0xdb,0x8e,0xaf,0x78, + 0xad,0x52,0x84,0xda,0xf7,0xa6,0xb3,0x90,0x96,0xac,0x15,0x54,0x0c,0x69,0x9a,0x8a, + 0x05,0x6a,0x68,0x51,0x28,0x39,0x6a,0xc6,0x17,0xcb,0x4c,0xd6,0x6e,0x2f,0x28,0x32, + 0x06,0xa4,0xf3,0x0c,0xcf,0x85,0xd2,0x04,0xfe,0xa5,0x8f,0xdd,0xa1,0x9f,0x7f,0xed, + 0x3b,0x37,0xbc,0x77,0xa2,0xd0,0x61,0xc7,0x15,0x84,0xb2,0xb3,0xa0,0x0c,0x41,0xfb, + 0xa1,0x2b,0x50,0xcb,0x89,0x6f,0xb0,0x91,0x95,0xc8,0x56,0x23,0x3b,0x79,0xfb,0x01, + 0x43,0x61,0x76,0xee,0x87,0x46,0xe2,0x10,0xdf,0x83,0x46,0xde,0x83,0x86,0x21,0xeb, + 0x45,0x56,0x8b,0xd3,0x4a,0xdc,0x04,0xbf,0x92,0x4b,0x27,0x3a,0x22,0x3a,0xad,0x20, + 0x2e,0xbb,0xc4,0x73,0x0e,0x88,0x4d,0x64,0x5d,0x7c,0xda,0x81,0xb9,0xd7,0x73,0xf1, + 0x63,0xa3,0xcf,0x53,0xa1,0xf3,0x51,0xde,0xe0,0x01,0x72,0x2b,0x71,0x84,0x77,0x01, + 0xe3,0xb1,0x9e,0xab,0x3c,0x6c,0x66,0x21,0xc6,0xa9,0xd4,0x55,0xcd,0xea,0xaa,0xc6, + 0xa2,0x6a,0x98,0x5f,0xad,0xae,0x5a,0xd7,0xa8,0x68,0x33,0x54,0xd5,0xe8,0xcc,0x45, + 0x2e,0xbf,0xcc,0xa3,0x9f,0x2b,0x14,0x2d,0xc4,0x24,0xfd,0x3c,0x37,0x50,0xdb,0x42, + 0x5a,0x91,0xdb,0x7e,0xa4,0x52,0xcc,0x6e,0x16,0x69,0x41,0x81,0x17,0x94,0xcf,0x14, + 0x86,0xd3,0x64,0x26,0xfc,0x15,0x2f,0xe7,0x45,0x32,0xb0,0xe9,0xb8,0xb2,0x2d,0xbb, + 0x75,0x56,0x8c,0xce,0xc5,0x71,0x26,0xaa,0x8d,0x03,0x82,0x05,0xad,0x45,0xc2,0x4a, + 0xe5,0x4f,0x75,0xb7,0x72,0xf7,0x00,0xe6,0xe0,0xc2,0x67,0x32,0xe7,0x0b,0x42,0x45, + 0xbc,0xac,0x56,0x0f,0x55,0xc8,0xac,0xd6,0x0d,0x7d,0xda,0x58,0x65,0xcd,0x8f,0x37, + 0x55,0x59,0x33,0x14,0x2c,0x43,0x5d,0xbb,0xfb,0x91,0xcc,0x86,0x8e,0xb8,0x8c,0x58, + 0x75,0xdb,0xa0,0x18,0x23,0xdc,0x60,0x16,0x91,0xa5,0x58,0x46,0x18,0x47,0xac,0xe0, + 0x85,0x72,0x1c,0xcd,0xc2,0xf1,0x6a,0xf4,0x34,0xba,0xd4,0xdd,0x64,0xbc,0x0b,0x81, + 0x40,0xa9,0x60,0x66,0xda,0xc1,0xa2,0x00,0x8c,0x60,0xaf,0x8e,0x1c,0x35,0x4a,0xe0, + 0x40,0x09,0x96,0xda,0xcc,0x64,0x18,0x43,0x03,0x06,0x74,0x8c,0x8a,0xe8,0x02,0xc6, + 0x6e,0x27,0x34,0xad,0x61,0xc9,0x92,0xbe,0x81,0x5b,0xd0,0xed,0x44,0xcb,0x3f,0xd2, + 0x85,0x9b,0x7c,0x15,0xb8,0xed,0x9f,0x53,0xd6,0x27,0xca,0xf1,0x4b,0xd0,0xb8,0x6f, + 0xd0,0xa6,0xc5,0x1f,0x26,0x15,0x69,0xdf,0x7d,0xa0,0x3b,0x18,0x49,0x54,0x9a,0xf2, + 0x7c,0xf5,0xce,0xae,0xb5,0x33,0x0b,0x55,0xe9,0x15,0x65,0x09,0x00,0xba,0x3a,0xb9, + 0xac,0xec,0xea,0x1a,0x40,0x1f,0x53,0xf9,0x3a,0x15,0x41,0x1f,0x90,0xb7,0xc8,0xc0, + 0x38,0x99,0x14,0x63,0x58,0xbb,0x85,0xe1,0xf5,0x81,0xbe,0x18,0x09,0xe5,0x5e,0x7b, + 0xbe,0x41,0x93,0x78,0x6d,0x30,0x50,0x9c,0x95,0xd4,0x34,0xb1,0xeb,0x0d,0x56,0x36, + 0x9f,0x99,0xcd,0xd7,0xec,0x56,0x0b,0x5a,0x50,0x7d,0xaa,0x34,0xcf,0xb1,0x57,0x56, + 0xf3,0xe5,0xc9,0x5d,0xd3,0x7c,0xa1,0x9a,0xbf,0xf7,0x66,0x39,0xd3,0xc1,0xea,0x8d, + 0xf2,0x55,0x4d,0x8d,0xcc,0xa6,0x56,0x53,0x82,0x05,0x5e,0xec,0xef,0x1b,0xf7,0x2e, + 0x7b,0x52,0x33,0x10,0x3b,0xd5,0xec,0x2d,0xe2,0x68,0x59,0xd2,0xca,0x12,0xb0,0x54, + 0xe9,0x0d,0x40,0xfd,0x79,0x12,0x16,0x78,0x2e,0x2f,0xb7,0x05,0x60,0x06,0xd2,0x39, + 0xc8,0x29,0x3a,0xd1,0x38,0x41,0x65,0xc8,0x2b,0xc9,0x14,0x45,0x8c,0x58,0x7a,0x49, + 0x07,0x0c,0x15,0xc3,0x55,0x92,0x9c,0x75,0x65,0xac,0x48,0x65,0x3c,0x1d,0x2c,0x4d, + 0x61,0x3e,0xf7,0x11,0xaf,0x4b,0x3c,0x89,0x68,0x74,0xe8,0x9e,0xca,0x0d,0x28,0x76, + 0x63,0xf2,0xe2,0xd9,0x55,0x45,0x24,0x25,0x3d,0x90,0x65,0xc4,0xf1,0x52,0x82,0x0e, + 0x06,0x1d,0x73,0x20,0xaf,0x51,0x6c,0x65,0x24,0xef,0xa1,0x0a,0xe5,0xdd,0xde,0xa1, + 0x50,0x5e,0x64,0x79,0x45,0x9f,0xfc,0x6e,0x23,0x0c,0xe9,0x95,0xb1,0xbc,0x87,0x22, + 0x96,0xf7,0xf0,0xb5,0x0e,0x31,0xa7,0x06,0x8e,0x6a,0x7d,0x18,0x28,0xf5,0xc4,0xd4, + 0x7d,0x93,0xa7,0xcb,0x0a,0x15,0x35,0x07,0x50,0x17,0x2b,0xda,0xed,0xec,0x0d,0x36, + 0xcc,0x42,0xd2,0x01,0xa6,0x63,0x3c,0x07,0x16,0x10,0x3b,0x62,0x53,0xf8,0xc2,0xc6, + 0xf7,0x0d,0xd8,0x3c,0x34,0x02,0x36,0x0f,0x79,0xe7,0xfb,0x10,0x43,0x36,0x19,0x27, + 0x22,0x64,0xf3,0x90,0x37,0xcc,0x0f,0xad,0xa0,0xcd,0xb1,0x88,0xda,0x5c,0x12,0x29, + 0x1e,0xb2,0x4b,0x52,0x5f,0xcd,0x0e,0x3d,0x39,0xfc,0xa4,0xc6,0x6e,0x05,0x4f,0x1e, + 0xae,0x8c,0x9e,0x3c,0x7c,0x5d,0x8a,0xef,0x28,0xa3,0xbb,0x26,0xc0,0xa3,0xa2,0x74, + 0x80,0x1e,0x7b,0x6e,0x46,0x7f,0x88,0xae,0x1d,0xa2,0xb7,0xf4,0x50,0xc5,0x7f,0x88, + 0x4e,0x1c,0xbe,0xe6,0xd4,0x91,0xc0,0xd9,0x8a,0x08,0x90,0x71,0x75,0xc7,0x80,0xa2, + 0xdc,0x8c,0x1c,0xaa,0x74,0x48,0xdb,0x97,0x08,0x1b,0xfe,0xfd,0x84,0x94,0x25,0x2b, + 0xd7,0x6f,0x58,0x8f,0x6b,0x76,0x15,0xc6,0x25,0x8f,0xbe,0xe8,0x7f,0x1b,0xb7,0x5b, + 0x44,0xaf,0xf9,0xf7,0x27,0xde,0xf0,0x38,0x7c,0x2d,0xde,0xa0,0x18,0xaf,0x8d,0x2f, + 0x91,0x05,0xac,0x7d,0xa5,0xb1,0xb1,0xb3,0x82,0x13,0x4a,0x05,0xb9,0x19,0x99,0x2b, + 0x3c,0x7e,0xa5,0x5c,0x42,0x9d,0x2c,0x62,0x6c,0x8b,0xaf,0x6d,0x81,0xb1,0x83,0xc4, + 0x40,0x90,0x4a,0x2d,0xa8,0x79,0xaa,0x29,0x52,0x6a,0xa1,0x76,0x87,0x66,0x5c,0xb3, + 0x97,0xa4,0xd2,0x4a,0x8e,0xd8,0x4a,0x3f,0xd5,0x8e,0x6c,0xb8,0xc8,0xa5,0xb4,0x56, + 0xf7,0x27,0xeb,0xaf,0xca,0x95,0xb8,0xb2,0xe2,0x7b,0xda,0xfa,0xc4,0xca,0xcf,0xf1, + 0x8e,0x1d,0xd0,0x94,0x77,0x77,0x56,0x38,0x78,0xdf,0xaf,0xf0,0xef,0xbe,0xff,0x46, + 0xf7,0x2e,0xcd,0x08,0xbe,0x81,0x80,0x0e,0xdd,0x31,0x47,0xf4,0x94,0x9c,0xb8,0x63, + 0x3b,0x78,0x44,0xf9,0x71,0xc7,0x76,0xfc,0x08,0xbb,0x72,0xc7,0xd5,0x0d,0xd0,0x7b, + 0xa0,0xa1,0xf2,0x52,0xc9,0xd8,0x42,0xdf,0x8a,0x09,0xa3,0x0d,0x6d,0xcd,0xa6,0xf4, + 0xce,0x24,0xdd,0x58,0x7f,0x4f,0x52,0xf5,0x04,0xa1,0xe0,0x65,0xc0,0x5e,0x1d,0xb9, + 0xd2,0xcd,0xc0,0xba,0xd4,0xa2,0x73,0xe3,0x7d,0x2b,0xc9,0x12,0x9c,0x8e,0xd1,0x52, + 0x67,0x55,0x4b,0x5d,0xb3,0xa5,0xee,0xca,0x96,0x2a,0xfb,0xb0,0xe3,0xda,0x2d,0xf9, + 0x6f,0x22,0xf4,0xd2,0x56,0xe4,0x0c,0xa6,0x74,0x26,0xb7,0x22,0xcd,0xdb,0x91,0x71, + 0xdb,0xd1,0xba,0x1f,0x99,0xb6,0x1e,0xc7,0xa5,0xad,0x47,0x0c,0x49,0xa2,0x77,0x1b, + 0xcc,0x5d,0x44,0x4c,0xbc,0xf1,0x56,0xef,0x25,0x8e,0x2b,0xdb,0x90,0xdf,0x05,0xe6, + 0x4e,0x89,0x97,0x8a,0x71,0xc6,0x9b,0x7e,0x2b,0x76,0xad,0x97,0xa2,0x2c,0xee,0x41, + 0x73,0xc1,0xfb,0x2c,0xa5,0x95,0xdb,0xd2,0xd5,0x99,0xda,0x36,0xe9,0xb2,0x8e,0x61, + 0xaf,0xa7,0xa0,0x65,0x1d,0xdb,0x34,0x09,0x68,0x29,0x89,0xe7,0xf2,0x8f,0x21,0x9c, + 0x6a,0x77,0x82,0x6c,0x5c,0x69,0xca,0x77,0x76,0x50,0x92,0x48,0x85,0x96,0x9e,0x24, + 0xea,0xca,0x0a,0x32,0xc4,0x46,0x6c,0xd5,0xd0,0x99,0x2d,0x8e,0x74,0x92,0x17,0xfc, + 0xa8,0x48,0x5d,0x91,0x20,0x23,0x9d,0x9e,0xdb,0xc9,0x24,0x91,0xd5,0xd9,0xbf,0xd2, + 0xf3,0x23,0x03,0x23,0xac,0x98,0x14,0x56,0x3e,0x99,0x60,0xc5,0xed,0x52,0x7d,0xba, + 0x74,0x4c,0x8e,0xda,0x0c,0xab,0x1c,0xaf,0x0c,0x9a,0x1c,0xaf,0x8a,0x69,0x1b,0x5b, + 0x01,0x68,0x2e,0xb7,0x8d,0xc7,0x2c,0xe9,0x07,0x5e,0x26,0x31,0x79,0xe1,0x70,0x6c, + 0xeb,0x3f,0xfe,0xfb,0xbf,0x39,0xb8,0x1b,0x2c,0x4e,0x49,0x42,0xef,0x75,0x88,0x6c, + 0x97,0x67,0x15,0xa5,0xd6,0xae,0x9a,0xdf,0x4e,0xb7,0xfc,0xae,0x8b,0x18,0x92,0xde, + 0xff,0xf9,0xe3,0x87,0x50,0xb9,0x28,0x39,0x50,0x27,0xb5,0xd0,0x6b,0x43,0xd1,0xb4, + 0x4a,0x35,0x91,0x6a,0x0f,0x45,0xd3,0x8d,0x57,0x46,0xe9,0xad,0x6b,0x01,0x77,0x94, + 0x28,0x8a,0x9d,0x6e,0x21,0x31,0x06,0x88,0xfb,0xc8,0x8c,0xbf,0x86,0xef,0x18,0x12, + 0xbd,0xbe,0x5d,0x05,0xdd,0x78,0x31,0xa6,0x8a,0xdd,0xa6,0x81,0xdd,0xbd,0xd5,0x55, + 0x8d,0xeb,0x00,0x6b,0xab,0x92,0x2e,0x66,0xde,0x2d,0xc4,0x4f,0x81,0x96,0xf7,0x24, + 0xc7,0x15,0x65,0x52,0x4a,0x32,0xf6,0x39,0xd0,0x75,0xc1,0xd5,0xeb,0xed,0xcb,0xc7, + 0x40,0xd5,0x56,0x15,0x9d,0x6c,0x22,0x8e,0xac,0xcf,0xe5,0x6a,0x87,0x97,0xe4,0x93, + 0xec,0xed,0x92,0x0c,0x12,0x5d,0x5d,0x74,0xbc,0xcf,0xb8,0xda,0x2f,0xc8,0x5c,0x93, + 0x97,0x93,0x6b,0x6e,0x41,0x37,0x24,0xca,0x3c,0xc5,0xd7,0x39,0xaf,0xdb,0x30,0x8e, + 0x0d,0x18,0xee,0x7a,0x6d,0x3b,0xf8,0x0a,0x07,0x9e,0x6d,0x73,0x7c,0x87,0x7f,0x5a, + 0x3a,0xef,0x6d,0xfb,0x6c,0x85,0x07,0xdf,0xb0,0xb1,0xd4,0x2c,0xac,0xd9,0x95,0x58, + 0xb5,0x25,0x61,0x3d,0x09,0x77,0x64,0x5b,0xc1,0x46,0x3f,0xfe,0x69,0x0f,0xf4,0x7d, + 0x30,0x53,0xe7,0x72,0x5e,0xd9,0xb9,0x6f,0xc7,0x98,0x92,0x72,0xea,0xa9,0x8a,0x95, + 0xf8,0x12,0x96,0x1c,0x9d,0x92,0xfb,0x64,0x49,0x42,0xeb,0x14,0xda,0xca,0x7d,0x1e, + 0xb6,0xf7,0xa8,0xfa,0xeb,0xfb,0x59,0x59,0x65,0x95,0x4f,0xbd,0x68,0xc7,0x73,0x4c, + 0x17,0x56,0x75,0x50,0x45,0xe4,0xb7,0x1a,0xa0,0xf4,0x72,0xc0,0x54,0x8c,0x8e,0x3a, + 0xbc,0x63,0x96,0xbd,0x5e,0xfc,0x78,0x83,0xca,0xee,0xaa,0x6c,0x7c,0xfd,0x81,0xe2, + 0xad,0xf9,0xca,0xff,0xfa,0x63,0xc4,0xf5,0xce,0x15,0x7e,0xa7,0x54,0xb9,0x58,0xec, + 0x58,0xa7,0xb2,0x77,0xe5,0x50,0x1c,0x56,0x76,0xbf,0x36,0x81,0x15,0x27,0x81,0xe1, + 0x44,0x29,0x39,0x75,0xee,0xee,0x49,0x40,0xa6,0x53,0xe5,0x50,0x1c,0x89,0xbe,0x57, + 0xc5,0xb2,0x5b,0x45,0x56,0x36,0xae,0x80,0xa8,0x20,0x62,0x75,0x6c,0x84,0x39,0xaf, + 0x84,0x74,0xeb,0x64,0xbf,0x61,0x11,0xe0,0x94,0xe0,0x0d,0x60,0x62,0x4e,0x3c,0xc5, + 0x6c,0xd4,0xc9,0x37,0x2b,0x14,0xea,0x00,0xef,0x23,0x69,0xf1,0xdb,0xd5,0x0d,0x4f, + 0xef,0xc4,0xe2,0xce,0x13,0xe1,0x3a,0x8c,0x57,0x5d,0x1e,0x07,0x39,0x78,0x5f,0x0d, + 0x54,0x6c,0x2d,0x88,0x9a,0xe8,0xf4,0x37,0xa4,0xae,0xbd,0x4a,0xae,0xbe,0xd6,0x1d, + 0x5f,0x6a,0xa5,0x9e,0x81,0xae,0xc4,0x7e,0x3d,0xb0,0xc6,0xdb,0x38,0x95,0xaf,0xd5, + 0x3b,0xcb,0x3c,0xe4,0x53,0xd3,0x62,0x67,0x07,0xaf,0x12,0xa1,0xf7,0xda,0xe9,0x7a, + 0xe7,0x75,0xb6,0x11,0xc2,0x21,0x62,0xc1,0xda,0xc5,0x55,0x4a,0xe7,0x9c,0x63,0x80, + 0x86,0x4a,0x7b,0xe0,0x30,0x02,0x9d,0x7c,0x16,0x2c,0x42,0x3e,0x3a,0xdd,0x10,0x17, + 0x6f,0xf1,0x23,0xdc,0xe6,0xdd,0x62,0x0f,0xdc,0x7b,0x5b,0xa6,0xf7,0x37,0xe1,0xe4, + 0x63,0x99,0xb2,0xcd,0xf7,0x15,0xa4,0x88,0xb3,0x3d,0x46,0xed,0xc4,0xbb,0xcf,0x44, + 0x3b,0x32,0xfc,0x4d,0xcf,0x37,0xa7,0x58,0xa2,0x43,0x94,0x1d,0x3a,0xea,0x4d,0x18, + 0xa6,0xf8,0x45,0x90,0xe9,0x8b,0x8c,0xf4,0x64,0x9e,0x9b,0x21,0x77,0x72,0xf3,0xf9, + 0x56,0xbe,0x79,0xc5,0xc0,0x7c,0x87,0xef,0x91,0xe9,0xe0,0x7b,0x57,0x3b,0xf8,0x54, + 0xd9,0x8e,0x2f,0x1d,0x47,0x22,0xf2,0x4e,0x6c,0xda,0x7e,0x37,0xb1,0x56,0xd7,0x23, + 0x5d,0x6f,0xa5,0x6f,0x8f,0x5e,0x35,0x3a,0x93,0x30,0xe5,0xbe,0x18,0x17,0xd2,0x0c, + 0xc6,0xb8,0x54,0xc1,0x5e,0x9a,0xb8,0xe9,0x9a,0x2d,0xc7,0x28,0xc5,0x26,0x87,0x31, + 0xde,0xae,0x2b,0xaa,0x7e,0x3b,0xf7,0x2b,0xf1,0x29,0xd3,0x0d,0xac,0x17,0x8a,0x7e, + 0xd8,0x1d,0xf0,0xf0,0xb5,0x21,0x53,0xe1,0x83,0xc9,0xaf,0x40,0xd0,0x6e,0xb3,0xe3, + 0x19,0x10,0xf0,0xc1,0xf6,0x6f,0x04,0xd0,0xb1,0x2e,0x20,0x31,0x73,0x26,0x61,0x8c, + 0x57,0x4f,0x7f,0x85,0x85,0xf1,0xd5,0x6d,0x9a,0xfa,0x81,0x57,0x95,0xa9,0xff,0x81, + 0x49,0xfd,0x56,0x88,0x87,0x20,0x72,0xd3,0xeb,0x5f,0x7a,0xfc,0xc6,0x2a,0xf6,0xd8, + 0xe1,0x3e,0x79,0x56,0xf5,0x12,0xfb,0x6c,0xad,0x7e,0x66,0xa7,0x56,0xa0,0xe9,0x9a, + 0x7f,0xe8,0xdc,0x96,0xe5,0x82,0xde,0x6e,0xb8,0x9f,0x50,0x30,0x4d,0x1a,0xeb,0xa5, + 0xca,0x3f,0xf1,0xfd,0x4f,0x78,0xad,0x62,0x4d,0x44,0x2d,0xb2,0x50,0x8a,0xaa,0xc5, + 0x0b,0x5d,0x1e,0x93,0xbf,0x52,0x54,0xc0,0xfb,0xc4,0x2b,0x15,0xd4,0xa1,0x20,0x23, + 0xfa,0x8e,0x0c,0x8b,0x7f,0xfc,0xeb,0xff,0x24,0x38,0x95,0x02,0xf8,0xd6,0x24,0x16, + 0x78,0xfd,0x85,0xee,0xae,0xa8,0x58,0x44,0xce,0xff,0xfd,0x3f,0x4e,0xd9,0x2a,0x42, + 0x96,0x48,0x19,0xf4,0x8c,0x45,0x4a,0xf5,0xa1,0x04,0x7e,0x95,0x46,0x28,0xa1,0x83, + 0x5d,0xc3,0x3d,0xc7,0xb7,0xee,0xf1,0x38,0x55,0xa5,0xe7,0xf5,0xf6,0x88,0xd5,0xf7, + 0x7a,0x6b,0x47,0x6d,0x4b,0xf3,0xfe,0x07,0xe4,0x9f,0x66,0xf8,0x8e,0x88,0x67,0xee, + 0x13,0xa0,0xab,0xb7,0xad,0x3a,0x90,0xaa,0x3b,0x2a,0x45,0xf4,0xb0,0xdb,0x33,0xc1, + 0xd3,0x66,0xdb,0x95,0x0e,0xe9,0xe5,0x5a,0xaf,0xa3,0xf5,0xb5,0x68,0x03,0xb6,0x52, + 0xeb,0x15,0xd8,0x5b,0xdf,0xd3,0x9a,0x55,0xcf,0xba,0xba,0x42,0x6c,0xa5,0x99,0xb6, + 0x9f,0x38,0x49,0x20,0x1f,0x1e,0xad,0xc0,0xd3,0xef,0xc3,0x37,0x56,0x5e,0x35,0x6b, + 0x45,0x7d,0x97,0xeb,0xac,0xd5,0x18,0xca,0x35,0xd5,0x35,0x67,0x55,0x72,0x16,0x0f, + 0xbb,0x57,0x09,0x7a,0x71,0xf9,0x61,0xb9,0x32,0xa0,0x5c,0x96,0x24,0x62,0x60,0x3f, + 0x48,0xe3,0x6b,0x42,0x08,0x8a,0x1d,0xff,0x21,0x72,0x68,0xc5,0xa2,0x36,0xa7,0x6f, + 0x28,0xbd,0x1c,0x86,0x88,0x22,0x8f,0x85,0x39,0x45,0x75,0x85,0x66,0x51,0xdd,0xee, + 0xa5,0xb9,0x83,0x33,0x70,0x6c,0x96,0xe4,0xd4,0x88,0x1b,0x74,0x94,0x43,0x23,0x96, + 0x5e,0x6d,0x2f,0x84,0xef,0xb0,0x4b,0xd7,0xf2,0x32,0x61,0x82,0xd9,0x8d,0x7c,0xc5, + 0x08,0xbb,0xbc,0xaf,0x11,0xd6,0xa3,0x3b,0x26,0x28,0xe5,0x4a,0x2d,0x5d,0x7a,0x98, + 0x47,0x8d,0x91,0xcf,0xdd,0xd3,0x6a,0x08,0x46,0x39,0x5d,0x54,0x6d,0xd1,0xff,0xb3, + 0x15,0x79,0x74,0x42,0xf2,0x2a,0xc0,0x87,0x5e,0x8d,0xf2,0xbe,0x59,0x80,0x9e,0xad, + 0xb5,0x07,0xf6,0xcf,0xda,0xc1,0xf7,0x9c,0x8b,0x95,0x96,0xb0,0x18,0x77,0xd9,0x0e, + 0xfe,0x4f,0x38,0x43,0xd8,0x5d,0xd1,0x5b,0x7a,0xe4,0xd9,0x5e,0x24,0x7a,0xf3,0xdf, + 0xc2,0xb8,0x75,0x1f,0x1d,0x3f,0x08,0x4a,0x66,0xad,0xbd,0x78,0x74,0x60,0x82,0x6f, + 0x81,0x7d,0x5c,0xa9,0xbc,0x7e,0x3d,0x7d,0xcb,0x8c,0x90,0x69,0x69,0xda,0xb4,0x6a, + 0x26,0x6e,0xcb,0x0b,0xce,0x58,0x97,0xce,0xdd,0xb7,0xb4,0xa1,0xac,0x50,0x77,0xed, + 0x94,0x9f,0x95,0x5c,0x6b,0x92,0x72,0x6b,0x92,0xf9,0x81,0x56,0x39,0x0d,0x40,0xed, + 0xe6,0xca,0x61,0xee,0x70,0x3f,0x14,0x59,0x12,0xe0,0x8f,0x60,0x97,0xe2,0xe9,0x56, + 0x61,0x2b,0x0a,0x4f,0x6d,0xb5,0x2f,0x25,0x8e,0x67,0x44,0x81,0x94,0xb9,0x5f,0x49, + 0xd8,0xac,0xee,0x63,0x80,0xa1,0xc2,0xfa,0x9e,0x5a,0x7a,0xec,0x42,0x5c,0x4c,0xa7, + 0x7d,0x8e,0xf4,0x0c,0x03,0xe7,0x1d,0xb4,0x14,0x5c,0x97,0xce,0x58,0xf0,0x15,0x73, + 0x1c,0xb2,0x8d,0x97,0xfa,0x9b,0xb7,0xc6,0x51,0x0a,0x77,0x08,0x0b,0x88,0xba,0x20, + 0x86,0xf8,0xce,0x75,0xee,0xe2,0x3b,0xba,0x18,0x5b,0x19,0xa4,0xfa,0x86,0x6b,0x23, + 0x77,0x75,0xff,0xad,0x37,0x5f,0x1d,0xdd,0x82,0x5b,0x80,0x9d,0x2d,0x5e,0xe6,0xa9, + 0x68,0xa8,0x86,0xcf,0xe2,0x7e,0x91,0xdc,0x78,0x69,0xb6,0x08,0x22,0x11,0x97,0xbf, + 0x47,0xe2,0x2a,0xed,0x7b,0x1d,0x2c,0xa3,0x82,0x6b,0x35,0x85,0x4a,0xe9,0x15,0xe7, + 0xd0,0xc4,0xa5,0xdd,0x96,0x62,0x41,0xe5,0xcb,0x27,0xd1,0x30,0x11,0x14,0xd7,0xfb, + 0x6a,0xc1,0xa0,0x48,0xae,0xd2,0x81,0x2d,0xe3,0xb8,0xa6,0xa9,0x55,0x07,0xd2,0xa4, + 0x71,0x2c,0xbb,0x29,0x66,0x62,0xed,0x4b,0x75,0x16,0x82,0xbf,0x6e,0xdc,0xe9,0xf8, + 0xe2,0xa8,0x74,0x45,0x89,0x99,0x25,0x2f,0x85,0xe1,0x8b,0x1f,0x6b,0x83,0xae,0xb6, + 0xc5,0xfb,0xd9,0xd2,0xe8,0x5d,0x13,0x5b,0x55,0x32,0x92,0xaa,0x11,0x56,0x65,0x6f, + 0x9d,0xb4,0xda,0x2f,0xc5,0x6d,0x82,0x97,0xc6,0x5d,0x82,0x97,0x27,0xe3,0x14,0x9d, + 0x26,0x9c,0x41,0x1f,0x66,0xee,0x21,0x5f,0x35,0xc8,0x19,0x35,0xd1,0x49,0x88,0xc7, + 0xc5,0xa5,0x88,0x39,0x5a,0x5c,0x1a,0x41,0x47,0x50,0x27,0x42,0xae,0xd6,0x58,0x2c, + 0x61,0x39,0x35,0x64,0xe2,0xc7,0x60,0x6a,0x96,0x31,0x6e,0x8f,0x14,0x09,0xe6,0xc7, + 0xdb,0x20,0x2f,0xac,0x6f,0xdc,0x3b,0x33,0xef,0x28,0x3c,0xfe,0xf3,0x2f,0x27,0x2f, + 0x0f,0x3f,0xbc,0xa7,0x07,0x3e,0x77,0xcc,0xd4,0xd3,0x97,0x18,0x5b,0xdd,0xc1,0x23, + 0x3c,0xaa,0xfa,0x9b,0x44,0x5c,0xcb,0xc5,0x9f,0x1f,0xd4,0xa3,0x8d,0xfa,0x60,0xc2, + 0x25,0x3f,0x8b,0xe7,0x16,0x32,0x98,0x57,0x0c,0x63,0xa8,0x06,0xa2,0x4d,0xca,0xc5, + 0x8c,0x9f,0x13,0x2f,0x9c,0xff,0x82,0x57,0x97,0xea,0x20,0xcc,0x88,0x0e,0xc0,0x73, + 0xf6,0x33,0x3c,0xa6,0xbe,0x4b,0x87,0xd6,0xe9,0xe5,0x8e,0x76,0xe5,0xe5,0x0f,0x2e, + 0x4f,0xb7,0x3b,0x3f,0x41,0x8d,0x9a,0x4f,0x32,0x02,0xdd,0xa4,0x73,0x97,0xef,0x6b, + 0xee,0x79,0x74,0x39,0x6a,0x7b,0x5b,0x1d,0xfb,0x35,0x7a,0x95,0xa4,0x51,0x7e,0x63, + 0x86,0xd2,0x8a,0xe6,0x5d,0xec,0x56,0xa7,0xf5,0xc4,0x33,0xbb,0x50,0xdf,0x03,0x7c, + 0x05,0x9d,0x3a,0xd0,0x51,0x4f,0x45,0xe7,0x40,0x92,0x05,0x5d,0xd6,0xba,0xed,0xad, + 0xed,0x54,0xb7,0x4b,0xb1,0x9f,0xd0,0xa6,0x79,0xc1,0x98,0x86,0xbc,0xd3,0x23,0xc8, + 0xdb,0xbd,0x32,0x64,0x63,0x77,0x96,0x00,0x6d,0xf7,0xd6,0x37,0xd4,0xde,0x29,0x9d, + 0x21,0xb9,0x3c,0x9c,0x05,0x00,0x2b,0x8f,0x8c,0xc0,0xf6,0x80,0x88,0x95,0xc9,0xe4, + 0x99,0x03,0x59,0xf8,0x58,0x8d,0x7a,0x20,0x15,0x2f,0xa8,0x36,0xdf,0x54,0x1d,0x6c, + 0xc8,0xb2,0x8f,0xf1,0xe2,0x7c,0x28,0xdd,0x94,0xb5,0xb1,0xcd,0xe0,0x2b,0xda,0x9c, + 0x75,0x3b,0x93,0xb5,0x05,0x5c,0xba,0xb0,0x49,0xc0,0x94,0xec,0xa9,0x6c,0xc6,0xb3, + 0xc6,0xdc,0xe6,0x58,0xea,0x8e,0x7e,0xa7,0xa6,0x3c,0xde,0x23,0xf9,0xba,0xc7,0xca, + 0xb8,0xb1,0x2b,0x1a,0xfe,0x27,0x80,0x44,0x3f,0x5e,0xe3,0x00,0x0f,0x6b,0x22,0xc0, + 0xc4,0xc9,0x4f,0xce,0x5c,0x17,0x5d,0xc5,0x25,0x56,0xc7,0x65,0x5c,0x52,0x40,0x46, + 0x9b,0x5e,0x0c,0xa6,0x00,0xae,0x76,0xeb,0x49,0xef,0x7c,0xe5,0x15,0x3d,0x33,0x71, + 0x3c,0x73,0xa6,0x2f,0x87,0xa1,0x06,0xec,0x7b,0x01,0x28,0x49,0x44,0x1a,0xb4,0xc5, + 0xad,0x3b,0xaa,0x1f,0x90,0x76,0x65,0xa6,0x99,0x47,0x35,0xc5,0x29,0x1a,0x50,0xeb, + 0x68,0x01,0x04,0x59,0x26,0x4e,0xf1,0xc2,0x88,0xb1,0xfb,0x42,0xa0,0xd6,0x0d,0x5b, + 0x1c,0x7a,0xad,0x8e,0x97,0x2a,0xd6,0xf5,0xb3,0x56,0x8e,0x40,0x93,0xf5,0xb7,0x90, + 0x5c,0xd3,0x05,0xb0,0xa8,0x9a,0x1b,0x2c,0x6b,0x4b,0x72,0x2a,0x0a,0x14,0xbc,0x2a, + 0x1f,0x66,0x55,0x4f,0x03,0x65,0x19,0x5e,0x5c,0x82,0x78,0x2b,0xc5,0x42,0x59,0xa8, + 0x32,0x83,0xa1,0x2c,0x7c,0xa9,0x68,0xa8,0x0a,0xc6,0xf0,0x2d,0x49,0xbc,0xfb,0x0a, + 0x59,0xa3,0x2f,0x43,0x98,0x40,0x76,0xb6,0xd0,0x73,0x23,0xb3,0x80,0x4d,0xfa,0x1c, + 0x87,0xe1,0x3b,0xdd,0x32,0x4d,0x9e,0x82,0x34,0x74,0x13,0x7e,0xc2,0x86,0x19,0x93, + 0xd0,0xa3,0xec,0x13,0x0d,0x0f,0x98,0x97,0x7b,0x9a,0xa7,0x27,0xe9,0x95,0x3e,0x25, + 0x99,0x5d,0x90,0x37,0x19,0xb9,0xff,0x63,0x7c,0x03,0xe6,0x8a,0x17,0x22,0xd5,0xe0, + 0x3b,0xbc,0x68,0xa9,0x1a,0x35,0x11,0xef,0xa3,0xe5,0x84,0xeb,0xed,0x42,0xf6,0xd5, + 0x2c,0x82,0x89,0x74,0x11,0xc4,0x33,0x09,0x11,0x37,0x07,0xa8,0x4c,0xb3,0x89,0x17, + 0x41,0xd1,0x9d,0x04,0xd8,0xc4,0x50,0xe2,0x5d,0xb1,0x6c,0x92,0x54,0x8a,0xf9,0x43, + 0x21,0xa2,0xfd,0x37,0x09,0xdf,0xb1,0x88,0x2c,0x06,0xbf,0x3f,0xc8,0xf7,0x62,0x4d, + 0xde,0xa3,0xa3,0x79,0x29,0x1c,0xaf,0x6e,0x7a,0x07,0x02,0x35,0x00,0x4f,0xdd,0x9b, + 0x03,0xa5,0xe9,0x4d,0x5a,0x4c,0xa4,0xa3,0x0b,0x4c,0xfa,0xd8,0x84,0xfa,0xbc,0x13, + 0xdc,0x5e,0x0c,0xf4,0x19,0x4f,0x39,0x9f,0x13,0xc5,0x01,0x62,0x9f,0x8e,0xc4,0xdb, + 0x0b,0x28,0xa2,0x67,0xe1,0x64,0x59,0x3d,0x6b,0x67,0x64,0x10,0x02,0x58,0x02,0xd3, + 0x7d,0xb3,0x79,0x71,0x90,0x44,0x73,0x7a,0xa7,0x81,0xee,0xe1,0x77,0x79,0x42,0xbd, + 0xd2,0x95,0xcf,0x42,0x4c,0x53,0x2b,0x35,0xb7,0x4b,0x2b,0x23,0x83,0xcc,0xa5,0x0a, + 0x44,0x68,0x4f,0xd4,0x04,0x52,0x01,0x23,0x81,0x34,0x3c,0x28,0xc9,0x4f,0x7e,0xf0, + 0xf1,0xb3,0xed,0x76,0xbb,0xd2,0xeb,0xe8,0xcb,0xb7,0x06,0x25,0xb3,0x22,0x22,0x95, + 0x15,0xc3,0xc3,0x38,0x10,0xaa,0x89,0x9d,0x25,0x6f,0xac,0x95,0xa9,0xd2,0x93,0x87, + 0x60,0x44,0x50,0xb2,0xcc,0x52,0x01,0xc9,0x08,0x47,0xc4,0x23,0x8b,0xd5,0x74,0x8f, + 0x80,0x64,0x7b,0x5c,0x61,0xe1,0xf2,0xeb,0x52,0x6a,0xad,0xf0,0x03,0x4c,0x6c,0x96, + 0x2e,0xc2,0x04,0xf4,0xbb,0xcb,0x28,0xbc,0x6a,0xdc,0xe7,0x5d,0xa9,0xb5,0x38,0x5f, + 0x31,0x89,0x6c,0xc5,0x1a,0x2b,0x54,0x22,0x9b,0x69,0x9e,0x75,0x22,0x53,0x3f,0x52, + 0x6a,0x99,0xa9,0x92,0xd9,0xea,0x58,0x99,0xfc,0x2a,0x43,0xf9,0x9a,0x26,0xcd,0x88, + 0xd1,0xec,0xc3,0xdc,0x8b,0xab,0xd6,0xfd,0x1c,0xde,0xd4,0xb9,0xc7,0xe8,0x5d,0x37, + 0x72,0x8e,0x40,0x01,0x56,0x8f,0x5e,0xe6,0xb0,0xd2,0xc2,0x06,0x3d,0xe3,0x63,0x30, + 0x27,0x6e,0x8e,0x2c,0x3d,0x61,0x18,0xac,0xdd,0x35,0x43,0xce,0xf0,0xfd,0xce,0x4a, + 0xa9,0x0a,0x1b,0xde,0xc5,0xfc,0x1b,0x1b,0xe4,0x5b,0x7f,0xaf,0x57,0x39,0x88,0xaf, + 0x69,0xb0,0x61,0xec,0x19,0xae,0x47,0x6d,0x89,0x94,0x8e,0xe2,0xb2,0x95,0x13,0xa8, + 0x94,0xd5,0x7e,0xe7,0xf2,0x61,0xf5,0x72,0xb5,0xb5,0xf4,0xb9,0xa2,0x72,0xed,0x0e, + 0x75,0x59,0x25,0xd2,0xf7,0x7c,0xf7,0xf5,0x95,0xd9,0x82,0xae,0xac,0x1e,0xdc,0xc3, + 0xf5,0x51,0x3a,0x9f,0x6c,0x9f,0xb0,0xaa,0x3b,0xa8,0x6c,0x3a,0x35,0x6a,0xdc,0xbd, + 0xa6,0xa5,0x55,0xf2,0x79,0x30,0xab,0x3a,0x3a,0x78,0x77,0xfc,0xcb,0xa7,0x0f,0x1f, + 0x8f,0xf8,0x09,0x06,0xd6,0x8e,0x1a,0x05,0x85,0xa0,0x61,0xb8,0x2a,0x29,0x4a,0x8d, + 0x51,0x10,0xe3,0xda,0x9d,0x88,0xa4,0x27,0x3d,0xf5,0xe4,0x3a,0x3f,0xac,0x40,0xef, + 0xf8,0x35,0x2e,0x70,0x62,0x6e,0x1a,0xe7,0xca,0x79,0x78,0x70,0xfa,0x53,0x15,0x76, + 0x9e,0x04,0x0b,0x03,0xf4,0x6f,0x4b,0x44,0x81,0x09,0x37,0x9d,0x16,0x26,0xd4,0x38, + 0xf8,0x62,0xc2,0xc4,0xc7,0x46,0x3e,0xa5,0x14,0xaa,0x28,0x8e,0x33,0xe8,0x21,0xb4, + 0xa6,0xc0,0x72,0x5d,0xf7,0xac,0x48,0x17,0xfc,0xa0,0x03,0x5e,0xa5,0x88,0x71,0x4a, + 0x78,0x27,0xb1,0x4d,0x63,0xea,0x72,0x7d,0xc5,0xb4,0x2d,0xaf,0x65,0xbb,0xf5,0x14, + 0x95,0x1a,0x53,0x01,0x97,0x2f,0x1a,0x32,0x75,0x88,0x37,0x4f,0x8c,0x67,0x6a,0x2f, + 0xcd,0x74,0xec,0x61,0x85,0x70,0x64,0xd7,0x29,0x4e,0x9c,0x1b,0xfd,0x5c,0xdf,0x28, + 0x9b,0x00,0x76,0x8b,0xe2,0x55,0x7b,0xdd,0xe0,0x67,0x23,0xb9,0xb6,0x3d,0x85,0xfe, + 0x0a,0x5e,0x3e,0x9b,0x78,0xb9,0xb3,0xa0,0x57,0x89,0x94,0x9e,0x74,0xa9,0xf8,0xe7, + 0x4c,0x74,0x55,0x7a,0x27,0x8f,0xda,0xb3,0x25,0x03,0x4c,0x97,0x46,0x76,0xc9,0xcf, + 0x66,0xf4,0xbe,0xbf,0xdf,0xd6,0x7c,0x56,0x7d,0x78,0x7a,0x52,0xbe,0x73,0x14,0xa5, + 0x59,0x15,0xc3,0x50,0x24,0x50,0x3f,0x92,0x7b,0x4f,0x79,0xa9,0xc3,0x2b,0x5f,0x99, + 0x10,0xe7,0x7b,0x4b,0xae,0x5c,0x7a,0x1b,0x47,0xbd,0x71,0xa4,0x2e,0xca,0xe7,0xdf, + 0xca,0xeb,0x22,0x14,0x58,0x53,0x76,0x08,0x71,0xf9,0x15,0x47,0x4d,0xf9,0xd4,0x9b, + 0x7a,0x3c,0x47,0x3c,0x14,0x84,0xde,0x30,0xe5,0x3c,0x94,0xaf,0xf9,0x04,0xf9,0x67, + 0xa9,0x4c,0x73,0x52,0xeb,0x97,0x20,0x9b,0x87,0x13,0x99,0x68,0x3d,0xce,0xa8,0x4a, + 0xa0,0x76,0x48,0x6f,0xca,0x0a,0xa3,0x54,0xf8,0x30,0x2d,0x0d,0xc0,0x06,0x87,0x6f, + 0x92,0x19,0xdf,0x2c,0xc6,0x45,0x52,0x69,0xf7,0x57,0x94,0xa3,0xab,0x36,0x95,0xd9, + 0xcb,0x4f,0xa7,0xdd,0x6d,0x58,0xb9,0xba,0xb4,0x01,0x62,0x05,0x58,0x18,0xa8,0xd1, + 0x87,0xf2,0x43,0x70,0xe5,0xce,0xd5,0xe8,0x9b,0xdf,0xd9,0x7f,0x8a,0x9e,0x21,0x7d, + 0xd3,0xc6,0x15,0x58,0x43,0x2e,0xfb,0xa2,0xd5,0xa4,0x44,0x49,0x64,0x5e,0xc5,0x9b, + 0x83,0x7c,0xa6,0x96,0xa4,0x23,0x5a,0x3f,0x26,0xc6,0x93,0x2e,0x9f,0x25,0x1a,0xac, + 0x7d,0xa6,0x84,0xc1,0xe8,0x97,0x4a,0x56,0xd1,0xdd,0xb7,0x3c,0x61,0xd2,0xe6,0xd5, + 0x4a,0x6f,0x26,0x67,0x21,0x5a,0x84,0x86,0x60,0xa6,0x47,0x94,0x1b,0xca,0x05,0x2e, + 0xdf,0xe5,0xf2,0x1c,0xfd,0xdb,0x35,0x9c,0xe6,0x50,0x10,0x33,0x58,0x97,0x74,0xf1, + 0x0d,0x2d,0xfb,0x86,0xf6,0x2b,0x3a,0xce,0x28,0xe2,0xa7,0xd4,0xf5,0xb4,0xe2,0x29, + 0x59,0x3a,0x33,0x04,0x35,0xe8,0x0a,0x6e,0x71,0x3f,0x4a,0xb9,0x28,0x5f,0x8b,0x85, + 0x11,0x53,0xd5,0x75,0xb2,0x72,0x49,0xb1,0x5a,0x53,0x7a,0xae,0x6a,0x0b,0x6f,0xa2, + 0xc7,0xbf,0xb3,0x62,0x1e,0xef,0x6f,0xfc,0x3f,0xa2,0x10,0x16,0xf7,0x92,0xe0,0x00, + 0x00, }; constexpr size_t AUDIO_IN_INDEX_HTML_GZ_LEN = sizeof(AUDIO_IN_INDEX_HTML_GZ); // diff --git a/firmware/patternflow/features/audio_in/core_audio_fft.h b/firmware/patternflow/features/audio_in/core_audio_fft.h index 55d3f516..6b060469 100644 --- a/firmware/patternflow/features/audio_in/core_audio_fft.h +++ b/firmware/patternflow/features/audio_in/core_audio_fft.h @@ -7,16 +7,22 @@ // and 5 of 7 either did not know it existed or had not tried it. What people // asked for is a different thing: the panel hearing the room on its own. // -// This is the analysis half, and it is written to run BEFORE any microphone -// exists, because the question that decides whether the feature is possible -// is not "can we read a mic" — it is "is there CPU left". The panel spends -// ~10 ms of every 16.6 ms frame pushing pixels. If a spectrum does not fit -// in what remains, no microphone helps. +// Owns: the transform and its buffers, the four raw band levels, the +// spectrum the page draws, and the verdict on what the input is (sourceLabel). +// Where the bands' edges are, and what a level becomes, is core_audio_in_map.h. // -// So `feed()` takes samples from wherever. A PDM mic on I2S would be the -// real source (GPIO43/44 are the only free header pins on this board — see -// the note in analyze()); until one is wired, synth() stands in and the cost -// measures the same, because an FFT does not know where its input came from. +// This is the analysis half, and it was written BEFORE any microphone +// existed, because the question that decided whether the feature was possible +// was not "can we read a mic" — it was "is there CPU left". The panel spends +// ~10 ms of every 16.6 ms frame pushing pixels. If a spectrum had not fitted +// in what remains, no microphone would have helped. +// +// So fill() takes a window from wherever. The real source is the PDM mic in +// core_audio_pdm.h; when that has nothing to give - the driver did not +// install, or the mic stopped answering - a synthetic three-tone source +// stands in, and the cost measures the same, because an FFT does not know +// where its input came from. What the synthetic source must not do is move a +// panel's knobs; the feature's fillInput sees to that. // // Deliberately naive: a plain radix-2 complex transform with the signal in // the real lane. A real-input FFT halves this and esp-dsp's assembly version @@ -180,12 +186,21 @@ inline void fill(uint32_t tick) { // edge that is halfway between the old value and the new one - 16 ms of a // slightly wrong band while somebody drags a handle. A mutex on the audio // path to avoid that would cost more than it saves. +// +// What an edge read here must never do is leave a band with no bins. A low +// edge in the last bin does (hzMin 7990: lo is N/2, and hi cannot pass it), +// whether it is stored that way or caught raw in the instant before the +// handler clamps it. The mean was then 0/0, and because each level is +// smoothed from the one before, that single NaN never left: `nan` in every +// poll and in /api/status until a reboot, and on the knob the band drives. +// A band over nothing hears nothing. inline void fold() { for (int b = 0; b < 4; b++) { const int lo = PFAudioInMap::binOf(PFAudioInMap::bands[b].hzMin); int hi = PFAudioInMap::binOf(PFAudioInMap::bands[b].hzMax); if (hi <= lo) hi = lo + 1; if (hi > N / 2) hi = N / 2; + if (hi <= lo) { bands[b] = 0.0f; continue; } float sum = 0.0f; for (int k = lo; k < hi; k++) sum += sqrtf(re[k] * re[k] + im[k] * im[k]); @@ -228,6 +243,11 @@ inline bool inputIsDeadRail() { // What the input actually is, for /api/status and the console page. Lives // here rather than beside the driver because the driver cannot see the // spectrum, and the spectrum is the only thing that tells these apart. +// +// The five strings this can return ("off", "pdm", the dead-rail one below, +// and PFAudioPdm::sourceName()'s "synth" and "synth (mic stalled)") are +// matched exactly by the page and listed in docs/rest-api.md. Add a sixth +// rather than rewording one. inline const char* sourceLabel() { if (!PFAudioInMap::micOn) return "off"; if (!PFAudioPdm::available()) return PFAudioPdm::sourceName(); diff --git a/firmware/patternflow/features/audio_in/core_audio_in_http.h b/firmware/patternflow/features/audio_in/core_audio_in_http.h index 83e954b5..e66f1002 100644 --- a/firmware/patternflow/features/audio_in/core_audio_in_http.h +++ b/firmware/patternflow/features/audio_in/core_audio_in_http.h @@ -1,11 +1,19 @@ // ═══════════════════════════════════════════════════════════ // PatternFlow - /audio-in: watching and shaping the microphone // -// Three routes: +// Owns: the page and its four routes. The settings they read and write live +// in core_audio_in_map.h; nothing is stored here but the phone's last frame. // -// GET /audio-in the page -// GET /api/audio-in live levels + the current shaping. Polled. -// POST /api/audio-in set one band, or the microphone switch +// GET /audio-in the page +// GET /api/audio-in the whole configuration, read once on load +// GET /api/audio-in?levels=1 live levels, mapped values, spectrum. Polled. +// POST /api/audio-in settings: the switch, gain, auto, the two +// speeds, and any band's fields +// POST /api/audio-in/reset the firmware's defaults - one band, or all +// +// The contract, field by field, is docs/rest-api.md ("Microphone"). The phone +// capture app reads the configuration and posts monitor frames through the +// same routes, so a field here is not ours alone to rename. // // ── Why polling and not the websocket ─────────────────────────────────── // @@ -16,11 +24,11 @@ // the browser path composed out - which is exactly the build someone with a // microphone would want. // -// So: a small GET, polled at ~10 Hz by the page. The response is deliberately -// tiny (four levels, four mapped values, a peak) because this device's web -// server is single-connection and every byte here is a byte the panel is not -// rendering. The shaping is sent once on load and only re-sent when the page -// changes it. +// So: a GET the page polls. The poll reply carries no configuration at all +// (levels, what they map to, and a 64-bucket spectrum to draw) because this +// device's web server is single-connection and every byte here is time the +// one connection is not free for anything else. The configuration is sent +// once on load and the page sends back only what it changed. // // License: MIT // ═══════════════════════════════════════════════════════════ @@ -74,14 +82,20 @@ inline bool pageWatching() { } // "l0,l1,l2,l3;lo0,hi0,..lo3,hi3;s0,..,s63" - 4+8+64 floats, three groups. -// A frame that does not parse to exactly that shape is dropped whole. +// A frame that does not parse to exactly that shape is dropped whole, and so +// is one with a `nan` or an `inf` in it: these are printed back into the poll +// as they came, and neither is JSON. inline void parseFrame(const String& s) { float vals[76]; int n = 0, start = 0; for (unsigned i = 0; i <= s.length() && n < 76; i++) { const char c = i < s.length() ? s[i] : ','; if (c == ',' || c == ';') { - if (i > (unsigned)start) vals[n++] = s.substring(start, i).toFloat(); + if (i > (unsigned)start) { + const float v = s.substring(start, i).toFloat(); + if (!isfinite(v)) return; + vals[n++] = v; + } start = i + 1; } } @@ -111,18 +125,26 @@ inline void handleIndex() { // dragged handle spring back to whatever the device last managed to save. // // Field names are the extension's — levels, outputs, spectrum — because the -// page's paint loop is lifted from popup.js and renaming them here would mean -// editing code whose whole value is that it is not edited. +// page IS the extension's editor (tools/patternflow-audio-extension/editor.*, +// assembled for the device by toolchain/build_audio_in_page.py) and it paints +// both sources through one frame shape. inline void handleGet() { const bool levelsOnly = server().hasArg("levels"); if (levelsOnly) { - // idle=1 marks the page's own low-power mode (its Monitor toggle off): - // it still wants a status trickle, but must not count as an audience - - // the phone reads that demand and throttles its frames accordingly. + // idle=1 is a poll that must not count as an audience: the phone reads + // that demand in every frame reply and throttles itself by it, so a + // client that only wants a trickle of status says so. Nothing in this + // tree sends it today (the page's Monitor toggle, which did, is gone); + // it stays because the demand signal is the phone's contract. if (!server().hasArg("idle")) pagePollMs = millis(); const bool ext = extFresh(); - String j = "{\"source\":\""; + // One allocation instead of one per `+=`: the reply is about 700 bytes + // and a String grows 16 at a time, so unreserved this was some forty + // reallocs of internal heap, ten times a second. + String j; + j.reserve(768); + j += "{\"source\":\""; j += ext ? "phone" : PFAudioFFT::sourceLabel(); j += "\",\"ext\":"; j += ext ? "true" : "false"; @@ -140,8 +162,11 @@ inline void handleGet() { if (i) j += ','; j += String(ext ? extLevels[i] : PFAudioInMap::smoothLevel[i], 4); } - // The level as the mapping consumes it in auto mode - the page paints - // its dot and meters from this so what you see is what the knob gets. + // The level as the mapping consumes it in auto mode - sent so a page can + // paint its cursor from what the knob gets rather than from its own + // re-derivation. This and `outputs` are always the MICROPHONE's: while + // `ext` frames are being served the phone is doing its own mapping, and + // these two do not describe it. j += "],\"levelsN\":["; for (int i = 0; i < 4; i++) { if (i) j += ','; @@ -197,7 +222,10 @@ inline void handleGet() { return; } - String j = "{\"source\":\""; + // About 1.3 KB with four empty metas; see the note on the poll reply. + String j; + j.reserve(1536); + j += "{\"source\":\""; j += PFAudioFFT::sourceLabel(); j += "\",\"micOn\":"; j += PFAudioInMap::micOn ? "true" : "false"; @@ -260,14 +288,17 @@ inline void handleGet() { j += PFAudioInMap::lutSet[i] ? "true" : "false"; j += '}'; } + // Two decimals: the low edge is one FFT bin, 31.25 Hz, and at one decimal + // a client taking its axis from here was handed a bound that is not the + // one clampRange() holds a band to. j += "],\"hzRange\":["; - j += String(PFAudioInMap::MIN_HZ, 1); + j += String(PFAudioInMap::MIN_HZ, 2); j += ','; - j += String(PFAudioInMap::MAX_HZ, 1); + j += String(PFAudioInMap::MAX_HZ, 2); - // Three decimals, not five: this is 40 numbers ten times a second and the - // page draws them as bars a few pixels wide. The precision that matters is - // in `level`, which is what the shaping actually consumes. + // Three decimals: these are drawn as bars a few pixels wide. (`spec`, + // `level`, `out`, `rawPeak`, `rawDc` and `windows` ride in this reply for + // scripts and for diagnosing a microphone; the page draws from the poll.) j += "],\"spec\":["; { float s[PFAudioFFT::SPEC_BUCKETS]; @@ -283,16 +314,41 @@ inline void handleGet() { server().send(200, "application/json", j); } +// A band's number, or the value it already has when the field is absent, +// empty, or not a finite number. toFloat() is atof(), which reads `nan` and +// `inf` as exactly that, and a NaN walks through every constrain() below; see +// PFAudioInMap::finiteOr for what one stored NaN cost. inline float argFloat(const char* name, float fallback) { if (!server().hasArg(name)) return fallback; const String v = server().arg(name); if (!v.length()) return fallback; - return v.toFloat(); + return PFAudioInMap::finiteOr(v.toFloat(), fallback); +} + +// Does this request say anything about band N in the suffixed form? Every +// field a band has is on the list. It used to be five of them - the ones a +// whole-config save always carries - which meant a request with only +// `inMax2`, the top edge of one box, was answered {"ok":true} and changed +// nothing. A page that sends only what moved needs that to work. +inline bool hasBandArgs(const String& suffix) { + static const char* const FIELDS[] = {"hzMin", "hzMax", "inMin", "inMax", + "gain", "outMin", "outMax", "knob", + "muted", "lut", "meta"}; + for (const char* f : FIELDS) + if (server().hasArg(String(f) + suffix)) return true; + return false; } -// Apply whatever band fields arrived under the given argument names. Shared -// by the single-band form (bare names + band=N) and the editor's whole-config -// form (suffixed names, hzMin0..hzMin3), so the two cannot drift. +// Apply whatever band fields arrived under the given argument names; a field +// that did not arrive keeps its value. Shared by the single-band form (bare +// names + band=N) and the suffixed form (hzMin0..hzMin3), so the two cannot +// drift. +// +// Two pairs are settled TOGETHER after the fields are in, whichever half +// arrived: hzMin/hzMax (ordered, inside the analysable range, a bin apart) +// and inMin/inMax (inMax at least 0.01 above inMin). So one half of a pair +// sent alone can move the other half; a client that wants to know what was +// stored sends both. inline void applyBandArgs(int b, const String& suffix) { PFAudioInMap::Band& x = PFAudioInMap::bands[b]; const String sHzMin = "hzMin" + suffix, sHzMax = "hzMax" + suffix; @@ -348,9 +404,11 @@ inline void applyBandArgs(int b, const String& suffix) { } } -// One band per POST, addressed by index, or `mic` on its own. Partial -// updates are allowed: the page sends only the handle that moved, so dragging -// one edge cannot clobber the other three by round-tripping a stale copy. +// Every field is optional and a request changes only what it names: `mic` +// on its own, one slider, one edge of one box, or everything at once. That +// is the point - a page that sends back its whole copy on every edit lets +// two open tabs revert each other, and a drag clobber three bands it never +// touched. inline void handleSet() { // Monitor frames are state, not settings: no NVS save, no other fields. // The reply carries the demand signal - see pageWatching(). @@ -362,6 +420,18 @@ inline void handleSet() { : "{\"ok\":true,\"watch\":false}"); return; } + // Refused before anything is applied: a 400 that had already flipped the + // microphone switch in memory would not be a refusal. + int single = -1; + if (server().hasArg("band")) { + single = server().arg("band").toInt(); + if (single < 0 || single > 3) { + server().sendHeader("Cache-Control", "no-store"); + server().send(400, "application/json", + "{\"ok\":false,\"error\":\"band must be 0-3\"}"); + return; + } + } if (server().hasArg("mic")) { const String v = server().arg("mic"); PFAudioInMap::micOn = (v == "1" || v == "true"); @@ -370,41 +440,39 @@ inline void handleSet() { const String v = server().arg("auto"); PFAudioInMap::autoRange = (v == "1" || v == "true"); } + // These three keep their value on `nan` or `inf`, like a band's fields. An + // EMPTY value is still read as 0 and lands on the low clamp, as documented; + // only what is not a finite number is refused. A NaN here was worse than in + // a band: as the gain it made every sample NaN, as a glide speed it made the + // damped levels NaN, and neither came back with a reset. if (server().hasArg("micGain")) { - PFAudioInMap::micGain = constrain(server().arg("micGain").toFloat(), - PFAudioInMap::MIC_GAIN_MIN, - PFAudioInMap::MIC_GAIN_MAX); + const float v = PFAudioInMap::finiteOr(server().arg("micGain").toFloat(), + PFAudioInMap::micGain); + PFAudioInMap::micGain = + constrain(v, PFAudioInMap::MIC_GAIN_MIN, PFAudioInMap::MIC_GAIN_MAX); } if (server().hasArg("smoothing")) { - PFAudioInMap::smoothing = - constrain(server().arg("smoothing").toFloat(), 0.05f, 0.9f); + const float v = PFAudioInMap::finiteOr(server().arg("smoothing").toFloat(), + PFAudioInMap::smoothing); + PFAudioInMap::smoothing = constrain(v, 0.05f, 0.9f); } if (server().hasArg("attack")) { - PFAudioInMap::attack = - constrain(server().arg("attack").toFloat(), 0.05f, 0.9f); + const float v = PFAudioInMap::finiteOr(server().arg("attack").toFloat(), + PFAudioInMap::attack); + PFAudioInMap::attack = constrain(v, 0.05f, 0.9f); } // Single-band form: band=N plus bare field names. The strip-era contract, // still honoured. - if (server().hasArg("band")) { - const int b = server().arg("band").toInt(); - if (b < 0 || b > 3) { - server().send(400, "application/json", "{\"error\":\"band must be 0-3\"}"); - return; - } - applyBandArgs(b, ""); - } + if (single >= 0) applyBandArgs(single, ""); - // Whole-config form: suffixed field names (hzMin0..hzMin3, lut2, meta1...). - // The editor saves everything it owns in one request - four sequential - // POSTs on a single-connection server was a drag stuttering the panel. + // Suffixed form: field names carrying their band (hzMin0..hzMin3, lut2, + // meta1...). Any number of bands in one request, any subset of each one's + // fields - four sequential POSTs on a single-connection server was a drag + // stuttering the panel. for (int b = 0; b < 4; b++) { const String suffix(b); - if (server().hasArg("hzMin" + suffix) || server().hasArg("lut" + suffix) || - server().hasArg("knob" + suffix) || server().hasArg("muted" + suffix) || - server().hasArg("outMin" + suffix)) { - applyBandArgs(b, suffix); - } + if (hasBandArgs(suffix)) applyBandArgs(b, suffix); } PFAudioInMap::save(); @@ -412,11 +480,39 @@ inline void handleSet() { server().send(200, "application/json", "{\"ok\":true}"); } +// The defaults live in the firmware (core_audio_in_map.h resetBand) and the +// page asks for them here rather than keeping a table of its own - the one it +// had was the extension's, and "Reset band" put a 5-16 kHz band on an axis +// that ends at 8. +// +// band=N that band only: its range, window, gain, output range, knob, +// mute and curve. Nothing else moves. The reply names the band, so +// a client can tell this from an older firmware that ignored the +// argument and reset everything. +// (none) all four bands and curves, damping, attack and the input gain. +// Not the microphone switch and not auto range. inline void handleReset() { + server().sendHeader("Cache-Control", "no-store"); + if (server().hasArg("band")) { + // Exactly one digit. toInt() reads "" and "x" as 0, and a reset is not + // the request to guess on. + const String v = server().arg("band"); + if (v.length() != 1 || v[0] < '0' || v[0] > '3') { + server().send(400, "application/json", + "{\"ok\":false,\"error\":\"band must be 0-3\"}"); + return; + } + PFAudioInMap::resetBand(v[0] - '0'); + PFAudioInMap::save(); + String j = "{\"ok\":true,\"band\":"; + j += v[0]; + j += '}'; + server().send(200, "application/json", j); + return; + } PFAudioInMap::resetBands(); - PFAudioInMap::micGain = 8.0f; + PFAudioInMap::micGain = PFAudioInMap::MIC_GAIN_DEFAULT; PFAudioInMap::save(); - server().sendHeader("Cache-Control", "no-store"); server().send(200, "application/json", "{\"ok\":true}"); } diff --git a/firmware/patternflow/features/audio_in/core_audio_in_map.h b/firmware/patternflow/features/audio_in/core_audio_in_map.h index c8abf314..2cb26cd3 100644 --- a/firmware/patternflow/features/audio_in/core_audio_in_map.h +++ b/firmware/patternflow/features/audio_in/core_audio_in_map.h @@ -5,20 +5,32 @@ // a knob: the highs carry far less energy than the bass, so band 4 sits near // zero while band 1 saturates, and a room's noise floor is never at zero. // -// Four numbers per band fix that, and they are deliberately the SAME four the -// Chrome extension uses, computed the same way: +// Owns: the four bands' settings, where they are kept (NVS), and the +// arithmetic from a band's level to its knob. No I2S and no HTTP in here. +// +// Five numbers per band fix that, and they are deliberately the SAME five the +// Chrome extension's mapper uses, applied in the same order - window, then +// curve, then output range: // // inMin ignore below this the room's noise floor // inMax full by this what counts as loud, for this band -// gain curve between them >1 lifts a quiet band +// gain curve between them >1 lifts a quiet band (the curve, until +// the editor gives the band a table - see +// "Response curves" below) // outMin where the knob rests what the pattern does in silence // outMax where the knob peaks // -// mapBandOutput() in tools/patternflow-audio-extension/popup.js is the -// reference implementation. If one of them changes, the other has to: a +// The extension's half is mapBandOutput() in tools/patternflow-audio-extension. +// If one of them changes its order or its edge cases, the other has to: a // person who has learned the response graph on one path must not find the -// same handles doing something else on the other. That is the entire reason -// this file repeats the extension's arithmetic instead of inventing its own. +// same handles doing something else on the other. +// +// What the two do NOT share is the unit a level is measured in. The extension +// reads decibels off the browser's analyser and normalizes them; this side +// measures LINEAR amplitude, and every constant below was measured on that +// scale. inMin/inMax are therefore linear here, and in manual mode the level +// is placed between them linearly. The /audio-in page draws a dB axis and +// converts at its own boundary; the numbers the API carries are these. // // ── On the S3's quiet PDM input ───────────────────────────────────────── // @@ -83,9 +95,10 @@ struct Band { // same digital multiply. So: a runtime gain, WLED-style, user-tunable on // /audio-in. Applied only to the microphone - the synthetic source is // already full-scale and would clip. -inline float micGain = 8.0f; +constexpr float MIC_GAIN_DEFAULT = 8.0f; constexpr float MIC_GAIN_MIN = 1.0f; constexpr float MIC_GAIN_MAX = 16.0f; +inline float micGain = MIC_GAIN_DEFAULT; inline Band bands[4]; // filled by resetBands() or load(); see below @@ -102,8 +115,8 @@ inline Band bands[4]; // filled by resetBands() or load(); see below // tuned set (bands8 -> bands9 both did exactly that). The tables live under // their own keys, so an upgrade keeps the windows people measured. // -// A band with no table (lutSet 0) keeps the legacy gain exponent - the -// upgrade is invisible until the editor touches a band. +// A band with no table (lutSet 0) runs its gain exponent - which is what the +// measured defaults are, not a leftover: a factory panel has four of them. constexpr int LUT_POINTS = 33; inline uint8_t luts[4][LUT_POINTS]; inline uint8_t lutSet[4] = {0, 0, 0, 0}; @@ -128,8 +141,10 @@ inline float lutValue(int b, float u) { // one number means one feel on both paths; this side converts to its own // frame rate at use. Higher alpha = snappier; the editor shows it reversed // as "damping", tight to glassy. -inline float smoothing = 0.35f; -inline float attack = 0.65f; +constexpr float SMOOTHING_DEFAULT = 0.35f; +constexpr float ATTACK_DEFAULT = 0.65f; +inline float smoothing = SMOOTHING_DEFAULT; +inline float attack = ATTACK_DEFAULT; inline float smoothLevel[4] = {0, 0, 0, 0}; inline void smoothLevels(const float* level) { @@ -168,22 +183,32 @@ inline void smoothLevels(const float* level) { // inMin also clears the measured quiet-room floor per band (0.135/0.088/ // 0.024/0.010) so silence does not wobble the knobs. // -// One function rather than two literal tables: the HTTP reset handler and -// the fresh-boot path both call this, and the two copies they used to keep -// in sync are exactly the kind of pair that drifts. -inline void resetBands() { - const Band d[4] = { +// One table rather than a copy per caller: the fresh-boot path, the HTTP +// reset and the one-band reset all read this, and the copies they would +// otherwise keep in sync are exactly the kind of pair that drifts. The page +// asks for these (POST /api/audio-in/reset) instead of carrying its own. +inline void resetBand(int i) { + static const Band d[4] = { { 62.0f, 375.0f, 0.200f, 0.900f, 1.0f, 0.30f, 0.85f, 0, false}, { 375.0f, 1500.0f, 0.120f, 0.650f, 1.2f, 0.30f, 0.85f, 1, false}, { 1500.0f, 5000.0f, 0.045f, 0.160f, 1.6f, 0.30f, 0.85f, 2, false}, { 5000.0f, 8000.0f, 0.012f, 0.030f, 1.8f, 0.30f, 0.85f, 3, false}, }; - for (int i = 0; i < 4; i++) bands[i] = d[i]; - for (int i = 0; i < 4; i++) { - lutSet[i] = 0; - metas[i][0] = 0; - } - smoothing = 0.35f; + if (i < 0 || i > 3) return; + bands[i] = d[i]; + // No table: the band is back on its gain exponent, the measured default. + lutSet[i] = 0; + metas[i][0] = 0; +} + +// Every band, and the two speeds that belong to the mapping as a whole. Not +// the microphone switch and not auto range: those are how the panel is being +// used, not how it is tuned, and a reset that flipped either would be a +// surprise. +inline void resetBands() { + for (int i = 0; i < 4; i++) resetBand(i); + smoothing = SMOOTHING_DEFAULT; + attack = ATTACK_DEFAULT; } // The analysis is 512 points at 16 kHz, so a bin is 31.25 Hz and the last @@ -202,8 +227,27 @@ inline int binOf(float hz) { return b; } -// Ordered, inside the analysable range, and at least one bin wide - a band -// whose edges met would divide by zero in fold(). +// A setting that is a number, or `fallback`. NaN and the infinities are not +// settings. constrain() passes a NaN straight through (both of its tests are +// false), String() prints it as `nan`, and `nan` is not JSON: one stored NaN +// made GET /api/audio-in unreadable for good, and the page that could not +// read it had no way to offer the reset that would have cleared it. So nothing +// that is not finite is taken - from a request (core_audio_in_http.h) or from +// NVS (load, below). +inline float finiteOr(float v, float fallback) { return isfinite(v) ? v : fallback; } + +inline bool allFinite(const Band& b) { + return isfinite(b.hzMin) && isfinite(b.hzMax) && isfinite(b.inMin) && + isfinite(b.inMax) && isfinite(b.gain) && isfinite(b.outMin) && + isfinite(b.outMax); +} + +// Ordered, inside the analysable range, and a bin apart where there is room +// for one. Against the top there is not: a low edge within a bin of MAX_HZ +// keeps a band narrower than that (hzMin 7990 is stored as 7990..8000), and +// one that rounds to the last bin covers no bin at all. fold() reads such a +// band as silent rather than dividing by its width; this does not move the +// edge, because what a client stored is what it reads back. inline void clampRange(Band& b) { b.hzMin = constrain(b.hzMin, MIN_HZ, MAX_HZ); b.hzMax = constrain(b.hzMax, MIN_HZ, MAX_HZ); @@ -327,8 +371,9 @@ constexpr float NORM_LO_K = 1.5f; // normalization floor = ref * this constexpr float NORM_MIN_SPAN = 0.02f; constexpr float ENV_ATTACK = 0.3f; constexpr float ENV_RELEASE = 0.002f; -// The relative response window the normalized level runs through (the -// page shows the same 0.10..0.95 as the fixed in-handles in auto mode). +// The relative response window the normalized level runs through. The poll +// reply carries that normalized level (`levelsN`), so a page can place it in +// this same 0.10..0.95 and show where the knob really is. constexpr float AUTO_LO = 0.10f; constexpr float AUTO_HI = 0.95f; @@ -390,7 +435,8 @@ inline float normalized(int b, float level) { // The extension's mapBandOutput, in C++. Same clamps, same order, same edge // cases - including inMax being forced at least 0.01 above inMin, which is -// what stops a dragged handle pair from dividing by zero. +// what stops a dragged handle pair from dividing by zero. The level is placed +// in the window LINEARLY (see the header: this side's unit is amplitude). inline float mappedWindow(int b, float level, float inMinRaw, float inMaxRaw) { const Band& x = bands[b]; const float inMin = clamp01(inMinRaw); @@ -414,19 +460,6 @@ inline float mapped(int b, float level) { return mappedWindow(b, level, x.inMin, x.inMax); } -// How much of its knob a band actually uses between silence and its own -// recent peak. The extension calls this "travel" and shows it as a bar, -// because "this band is not doing anything" is the question people actually -// have, and it is not answerable from four raw numbers. -inline float travel(int b, float peakLevel) { - const Band& x = bands[b]; - const float span = fabsf(x.outMax - x.outMin); - if (span < 0.001f) return 0.0f; - return clamp01(fabsf(mapped(b, peakLevel) - mapped(b, 0.0f)) / span); -} -// (mapped() already routes through the auto window when autoRange is on, so -// travel and the page's readouts follow whichever mode is live.) - // ── Persistence ───────────────────────────────────────────────────────── // // One blob rather than 21 keys: NVS entries are the scarce thing here, and @@ -479,14 +512,19 @@ inline void load() { p.getBytes(NVS_KEY, bands, sizeof(bands)); // Saved settings are trusted to be the right shape, not to be sane: a // blob written by a build with a different sample rate would put edges - // past Nyquist, and fold() would read off the end of the spectrum. + // past Nyquist, and fold() would read off the end of the spectrum. Nor + // to be numbers: earlier builds stored a NaN when a request sent one, + // and no clamp removes it. Such a band goes back to its default (its + // curve table, read below, is kept). for (int i = 0; i < 4; i++) { + if (!allFinite(bands[i])) resetBand(i); clampRange(bands[i]); bands[i].knob = constrain(bands[i].knob, 0, 3); } } micOn = p.getBool(NVS_MIC, false); - micGain = constrain(p.getFloat(NVS_GAIN, micGain), MIC_GAIN_MIN, MIC_GAIN_MAX); + micGain = constrain(finiteOr(p.getFloat(NVS_GAIN, micGain), MIC_GAIN_DEFAULT), + MIC_GAIN_MIN, MIC_GAIN_MAX); autoRange = p.getBool(NVS_AUTO, autoRange); if (p.getBytesLength(NVS_LUTS) == sizeof(luts) && p.getBytesLength(NVS_LSET) == sizeof(lutSet)) { @@ -497,8 +535,10 @@ inline void load() { p.getBytes(NVS_META, metas, sizeof(metas)); for (int i = 0; i < 4; i++) metas[i][sizeof(metas[i]) - 1] = 0; } - smoothing = constrain(p.getFloat(NVS_SMOOTH, smoothing), 0.05f, 0.9f); - attack = constrain(p.getFloat(NVS_ATTACK, attack), 0.05f, 0.9f); + smoothing = constrain(finiteOr(p.getFloat(NVS_SMOOTH, smoothing), SMOOTHING_DEFAULT), + 0.05f, 0.9f); + attack = constrain(finiteOr(p.getFloat(NVS_ATTACK, attack), ATTACK_DEFAULT), + 0.05f, 0.9f); p.end(); } diff --git a/firmware/patternflow/features/audio_in/core_audio_pdm.h b/firmware/patternflow/features/audio_in/core_audio_pdm.h index 52b07b86..07805aa7 100644 --- a/firmware/patternflow/features/audio_in/core_audio_pdm.h +++ b/firmware/patternflow/features/audio_in/core_audio_pdm.h @@ -224,6 +224,8 @@ inline void begin() { for (int i = 0; i < WINDOW; i++) ring[i] = 0.0f; live = true; + // "PDM up: CLK" is the literal firmware/bundles/build.sh looks for in an + // image to prove this feature is in it. Reword around it, not through it. Serial.printf("[AUDIO-IN] PDM up: CLK=%d DAT=%d %luHz mono left dsr=%d\n", PF_AUDIO_IN_PDM_CLK, PF_AUDIO_IN_PDM_DAT, (unsigned long)RATE, PF_AUDIO_IN_PDM_DSR16 ? 16 : 8); diff --git a/firmware/patternflow/features/audio_in/feature_audio_in.h b/firmware/patternflow/features/audio_in/feature_audio_in.h index 59af7d11..10f47007 100644 --- a/firmware/patternflow/features/audio_in/feature_audio_in.h +++ b/firmware/patternflow/features/audio_in/feature_audio_in.h @@ -1,31 +1,37 @@ // ═══════════════════════════════════════════════════════════ // PatternFlow - on-board audio input, as a feature // -// The fifth port onto the feature seam, and the first one that was not already -// living in the core — which makes it the more interesting test. The other -// four proved the hooks could carry features that already existed. This one -// asks whether they can carry a feature nobody has written yet. +// Owns: the descriptor, the analysis task, and the one place sound becomes +// knob lanes (fillInput). The parts it wires together each own one thing: // -// Answer so far: four hooks, no core edits, no sketch edits. +// core_audio_pdm.h the microphone - a PDM MEMS part on GPIO43/44 +// core_audio_fft.h a window of samples -> spectrum -> four band levels +// core_audio_in_map.h a band's level -> its knob; the settings and NVS +// core_audio_in_http.h /audio-in and /api/audio-in // -// setup - build the twiddle tables, and start the analysis task -// loop - run a window inline, when measuring the inline cost +// It was the first feature written on the seam rather than moved onto it, and +// it needed no core edit. The hooks it uses: +// +// setup - load the settings, build the FFT tables, start the task +// onNetwork - register the page and its API // fillInput - four bands drive the four knob lanes, exactly the way // the weather feature drives them from a temperature. A // pattern animates from sound without knowing what sound is. -// appendStatus - report what it costs, because that is the open question +// appendStatus - the `audioIn` block: what the analysis costs, and what the +// microphone is returning // -// PF_AUDIO_IN_CORE picks who pays: -// 1 the render loop (Core 1), inline. The naive placement. +// PF_AUDIO_IN_CORE picks who pays for the analysis: // 0 a task pinned to Core 0, where Wi-Fi lives and the panel does not. -// This is the arrangement that would ship, if it ships. +// What ships. +// 1 the render loop (Core 1), inline through the loop hook. Kept for +// measuring that placement against the other; no edition builds it. // -// There is no microphone yet, and that is deliberate. The panel spends -// ~10 ms of every 16.6 ms frame pushing pixels; if a spectrum does not fit -// in what is left, no microphone helps. So the cost gets measured first and -// the hardware question — a PDM mic on GPIO43/44, the only free header pins -// on this board, since N16R8's octal PSRAM claims 35-37 and everything else -// is HUB75 or an encoder — gets decided after, with a number in hand. +// The analysis was written and costed before there was a microphone - the +// panel spends ~10 ms of every 16.6 ms frame pushing pixels, and if a +// spectrum had not fitted in what is left no microphone would have helped. +// It fitted. The synthetic source that stood in for the microphone then is +// still in core_audio_fft.h, and is what the analysis runs on when the +// microphone is not delivering; see fillInput for why it stops there. // // License: MIT // ═══════════════════════════════════════════════════════════ @@ -41,8 +47,9 @@ #define PF_AUDIO_IN_CORE 0 #endif -// Off by default: while this is a measurement rather than a feature, it -// should cost a normal build exactly nothing. +// Off unless the composition says so: carrying this feature to measure it, or +// to watch the page, must not move anybody's knobs. The Audio edition turns +// it on in its overrides.h. #ifndef PF_AUDIO_IN_DRIVES_KNOBS #define PF_AUDIO_IN_DRIVES_KNOBS 0 #endif @@ -131,6 +138,16 @@ inline void fillInput(InputFrame& input) { // for. A hand on the encoder outranks both - the core drops any lane whose // knob moved this frame. if (!PFAudioInMap::micOn) return; + // Only a microphone that is delivering samples. When I2S would not install, + // or the mic stopped answering, the analysis carries on over the synthetic + // three-tone source (core_audio_fft.h fill()) - and without this line those + // tones reached the lanes as if the room were playing them: four knobs + // moving to nothing, while `source` said "synth (mic stalled)". It also + // covers the quarter second between the switch going on and the task + // installing the driver, when the levels are whatever the last session + // left. The synthetic source is for measuring the analysis, never for + // moving a panel. + if (!PFAudioPdm::available()) return; // Belt and braces over the default-off switch: somebody who ticks the box // on a panel with no microphone would otherwise pin all four knobs at // their resting position and find that turning one does not stick. diff --git a/firmware/toolchain/README.md b/firmware/toolchain/README.md index 45d1bcb9..e0ba2c07 100644 --- a/firmware/toolchain/README.md +++ b/firmware/toolchain/README.md @@ -4,7 +4,7 @@ The repository-level scripts around the firmware: what builds a module or a pack **Building things.** `build_module.py` compiles a module folder into a `.pfm` with the Xtensa toolchain; `port_preset.py` turns a curated preset header into a module folder; `make_pack.py` bundles built modules into the shareable Basics pack. `build_clock_glyphs.py` generates the Clock edition's digit glyphs. `release.py` is the two-command release (cut, publish) described in [`docs/RELEASING.md`](../../docs/RELEASING.md). -**Console pages.** The device serves each console page from a C string literal in a header. `console_pages.py` splices `../patternflow/console/*.html` into those headers (`build` to regenerate, `check` in CI); `console_serve.py` previews the pages locally; `build_audio_in_page.py` assembles the `/audio-in` page from the audio extension's editor in `tools/`. How to edit a page is [`../patternflow/console/README.md`](../patternflow/console/README.md). +**Console pages.** The device serves each console page from a C string literal in a header. `console_pages.py` splices `../patternflow/console/*.html` into those headers (`build` to regenerate, `check` in CI). One page is not written as a page: `/audio-in` is assembled by `build_audio_in_page.py` from the audio extension's mapping editor in `tools/patternflow-audio-extension/` and the panel's own half in `../patternflow/console/_audio_in_*`, with comments and indentation dropped on the way. `console_pages.py build` runs that step first, so one command regenerates everything; `console_pages.py check` and `build_audio_in_page.py --check` fail when the generated page is not what its sources assemble to, or is over its size budget (`BUDGET` in the script: bytes gzipped, as the panel sends the page). `console_serve.py` previews the pages locally against a mock panel, assembling `/audio-in` from its sources on every request; its audio endpoints are a port of the firmware's handlers, with `/mock?audio=` choosing what the panel hears, and when a handler in `features/audio_in/` or `features/audio/` changes that port changes with it. How to edit a page is [`../patternflow/console/README.md`](../patternflow/console/README.md). **Checks.** These are what `firmware-checks.yml` runs on every pull request that touches the firmware, and what you run before pushing: diff --git a/firmware/toolchain/build_audio_in_page.py b/firmware/toolchain/build_audio_in_page.py index dce59f60..ba1740c2 100644 --- a/firmware/toolchain/build_audio_in_page.py +++ b/firmware/toolchain/build_audio_in_page.py @@ -1,447 +1,476 @@ # -*- coding: utf-8 -*- -"""Assemble console/audio-in.html from the extension's mapping editor. - - python firmware/toolchain/build_audio_in_page.py - python firmware/toolchain/console_pages.py build # then bake the header - -The editor module (tools/patternflow-audio-extension/editor.js) is the single -source of truth for the mapping UI - the port philosophy is COPY, not -re-extract (port_audio_ui.py's function-lifting era ended with it; that script -is retired). This assembler: - - - reads editor.html, editor.css and editor.js from the extension, - - swaps the cream instrument tokens for the console's dark ones (editor.js - reads its canvas colors from CSS variables, so the theme travels free) - and adds the phone layout the extension's wide tab never needed, - - injects a device bar (microphone switch, input gain, reset) above the - editor - the two controls that exist only on this side, - - replaces the chrome adapter with a fetch('/api/audio-in') adapter that - also converts levels between the device's linear scale and the editor's - dB-normalized display axis (calibration constants live HERE, in JS, - tweakable without a reflash). - -Run it after editing the editor, then console_pages.py build. CI's page sync -check keeps the generated header honest; nothing checks that YOU reran this - -the marker comment carries the source hash so drift is at least visible. +"""Assemble console/audio-in.html, the panel's /audio-in page, from its sources. + + python firmware/toolchain/console_pages.py build # the build: this page, then every header + python firmware/toolchain/console_pages.py check # everything in sync, this page included + + python firmware/toolchain/build_audio_in_page.py # only assemble this page + python firmware/toolchain/build_audio_in_page.py --check # CI: page == sources, and inside its budget + --sketch DIR work on another copy of firmware/patternflow (as console_pages.py) + +/audio-in is the one console page that is not written as a page. Its editor is +the browser extension's mapping editor, copied, never re-extracted, so the two +cannot drift apart; what is the panel's own sits beside the other console +sources. This script holds none of their text: + + tools/patternflow-audio-extension/ + editor.html the markup: what is between its two EDITOR BODY comment lines + is taken (the editor itself; the extension's own source bar + is above them and stays behind), and the \n' - '\n' - 'Patternflow - Mic mapping\n' - '\n' - '\n' - '\n\n' - + body + - '\n\n' - '\n' - '\n\n' -) +SKETCH = ROOT / 'firmware' / 'patternflow' + +PAGE = 'audio-in' +EDITOR_HTML, EDITOR_CSS, EDITOR_JS = 'editor.html', 'editor.css', 'editor.js' +EXT_ADAPTER = 'editor-adapter.js' # the extension's PFAdapter; the panel's goes in its place +BAR_FILE, CSS_FILE, ADAPTER_FILE = '_audio_in_bar.html', '_audio_in.css', '_audio_in_adapter.js' +# The line a shared script is taken down to: a comment that says only this +# (a rule drawn around the words is fine; a sentence that mentions them is not). +EXTENSION_ONLY = re.compile(r'//\W*EXTENSION ONLY\W*') +EXTENSION_ONLY_CSS = re.compile(r'/\*\W*EXTENSION ONLY\W*\*/') +# editor.html: the editor itself is what is between these two lines. Above them +# is the extension's own source bar, which the panel replaces with its frame. +BODY_BLOCK = re.compile(r'(.*)', re.S) +# _audio_in_bar.html: the line where the editor's body goes. +BODY_SLOT = re.compile(r'') + +# Bytes of the page as the panel sends it: stamped by console_pages.py (the +# chrome's ?h= and the fallback PF), gzip -9. This is the heaviest page the +# console has, and on the panel's own hotspot (2-5 KB/s measured) a kilobyte is +# 0.2 to 0.5 s before anything paints - so, like check_footprint.py's PINS, it +# is pinned, and growing it is a decision somebody makes rather than something +# that happens. It was 19,920 before the page stopped shipping its sources' +# comments and about 15,300 right after. To raise it, change the number and say +# in the commit what the bytes bought. (zlib builds differ by tens of bytes for +# the same input; a page that close to the line is over it.) +BUDGET = 17500 + +# The panel's TCP send buffer (lwIP TCP_SND_BUF; console_serve.py's TCP_WINDOW +# is the same number, and its --slow link is where this was measured). A reply +# leaves one of these at a time and the next waits for the last to be +# acknowledged, so a page one byte into another window costs a whole round +# trip more: 0.4 s there, for the document and for everything behind it. The +# budget is the line the build holds; a multiple of this is the line worth +# getting under inside it, and weight() says how full the page's last window +# is: a few dozen bytes in it are a round trip that taking them out gives back. +# This is the mock's model of the link, counted on the body alone. On a panel +# the reply's headers go into the first window too, and lwIP may start with +# less than a full buffer; where the steps fall there has not been measured. +WINDOW = 5760 + +# The one comment that does travel: whoever opens the generated page is told +# not to edit it. Short, because the panel serves it too. +GENERATED = '' + + +class BuildError(ValueError): + """A source this page cannot be assembled from; the message says which.""" + + +# ── the sources ──────────────────────────────────────────────────────────── + +def console_dir(sketch=None) -> Path: + return Path(sketch or SKETCH) / 'console' + + +def out_path(sketch=None) -> Path: + return console_dir(sketch) / (PAGE + '.html') + + +def shown(path) -> str: + try: + return Path(path).resolve().relative_to(ROOT).as_posix() + except ValueError: + return str(path) + + +def text_of(path: Path) -> str: + try: + return path.read_text(encoding='utf-8') # universal newlines: LF from here on + except OSError as e: + raise BuildError('%s: %s' % (shown(path), e.strerror or e)) + + +SCRIPT_TAG = re.compile(r'') + + +def script_files(editor_html: str, sketch=None) -> list: + """(name, path) of each script the page carries: the ones editor.html + loads, in its order, with the extension's adapter swapped for the panel's.""" + names = SCRIPT_TAG.findall(editor_html) + if len(names) != editor_html.lower().count('; one here is not') + for need in (EXT_ADAPTER, EDITOR_JS): + if names.count(need) != 1: + raise BuildError('%s: must load %s exactly once' % (EDITOR_HTML, need)) + return [(ADAPTER_FILE, console_dir(sketch) / ADAPTER_FILE) if name == EXT_ADAPTER + else (name, EXT / name) for name in names] + + +def sources(sketch=None) -> list: + """The files the page is assembled from. A preview server watches these + to know the page changed; it never raises, so that it can.""" + console = console_dir(sketch) + try: + scripts = [path for _, path in script_files(text_of(EXT / EDITOR_HTML), sketch)] + except BuildError: + scripts = [console / ADAPTER_FILE, EXT / EDITOR_JS] + return [EXT / EDITOR_HTML, EXT / EDITOR_CSS, console / BAR_FILE, console / CSS_FILE] + scripts + + +# ── what does not travel ─────────────────────────────────────────────────── +# Each takes a source's text and the name to blame, and returns it lean. See +# the docstring for why these are line rules and what they refuse. + +def lean_lines(lines) -> str: + return '\n'.join(s for s in (line.strip() for line in lines) if s) + + +def lean_js(text: str, name: str) -> str: + out = [] + for n, line in enumerate(text.split('\n'), 1): + s = line.strip() + if EXTENSION_ONLY.fullmatch(s): + break + if s.startswith('//') and '*/' in s: + raise BuildError( + '%s:%d: a // line holding */. If it closes a block comment, dropping ' + 'the line would leave that comment open; reword it.' % (name, n)) + if not s or s.startswith('//'): + continue + if s.count('`') % 2: + raise BuildError( + '%s:%d: an odd number of backticks. A template literal that runs past ' + 'the end of its line would have its inside stripped; keep each on one ' + 'line (or build the string with +).' % (name, n)) + if s.endswith('\\'): + raise BuildError( + '%s:%d: the line ends in a backslash. A string continued onto the next ' + 'line would lose that line\'s indentation; join it with + instead.' % (name, n)) + out.append(s) + text = '\n'.join(out) + if ' early' % name) + return text + + +# A CSS line that is left as written: it holds a string, an escape or a url(), +# and telling the inside of one from the sheet's own punctuation is what would +# need a tokenizer. +CSS_AS_WRITTEN = re.compile(r'''["'\\]|url\(''', re.I) + + +def lean_css(text: str, name: str) -> str: + text = EXTENSION_ONLY_CSS.split(text, 1)[0] + out, at = [], 0 + while True: + a = text.find('/*', at) + if a < 0: + out.append(text[at:]) + break + out.append(text[at:a]) + before = ''.join(out).rsplit('\n', 1)[-1] # this line, earlier comments already gone + if before.count('"') % 2 or before.count("'") % 2: + raise BuildError( + '%s:%d: /* inside a quoted string; this build would cut it out as a comment' + % (name, text.count('\n', 0, a) + 1)) + b = text.find('*/', a + 2) + if b < 0: + raise BuildError('%s:%d: a /* comment that never closes' + % (name, text.count('\n', 0, a) + 1)) + # A comment separates tokens (`a/**/b` is not `ab`), and it keeps its + # line breaks so that a line number below is still the source's. + out.append(' ' + '\n' * text.count('\n', a, b)) + at = b + 2 + + # White space the sheet does not need. Inside a line: around { } ; and , + # and after a colon (never before one: `a :hover` is not `a:hover`), and + # the semicolon that ends a block. Between lines: a break goes where it + # follows { ; , or comes before { }, which leaves one rule to a line, as + # the console's pages are written. Such a break is always between tokens + # (a string cannot be open at the end of a line, and the one way to make + # it so is refused), and every other break stays: `.a` over `.b {` is + # still two selectors. + text, written = '', False # written: the line just added was left as written + for n, line in enumerate(''.join(out).split('\n'), 1): + s = line.strip() + if not s: + continue + if s.endswith('\\'): + raise BuildError( + '%s:%d: the line ends in a backslash. A string continued onto the next ' + 'line would be joined to it wrongly; keep it on one line.' % (name, n)) + as_written = bool(CSS_AS_WRITTEN.search(s)) + if not as_written: + s = re.sub(r'\s*([{};,])\s*', r'\1', s) + s = re.sub(r':\s+', ':', s).replace(';}', '}') + if text and (text[-1] in '{;,' or s[0] in '{}'): + if text[-1] == ';' and s[0] == '}' and not written: + text = text[:-1] + text += s + else: + text += ('\n' if text else '') + s + written = as_written + if ' early' % name) + return text + + +def lean_html(text: str, name: str) -> str: + for tag in ('pre', 'textarea', 'script', 'style'): + if re.search(r'<%s\b' % tag, text, re.I): + raise BuildError( + '%s: <%s> in the markup. This build strips indentation and comments ' + 'line by line, which is not safe inside one.' % (name, tag)) + text = re.sub(r'', '', text, flags=re.S) + if ' line and a line') + frame = BODY_SLOT.split(text_of(console / BAR_FILE)) + if len(frame) != 2: + raise BuildError(BAR_FILE + ': needs exactly one line, where the ' + 'editor\'s body goes') + body = '\n'.join(part for part in ( + lean_html(frame[0], BAR_FILE), + lean_html(block.group(1), EDITOR_HTML), + lean_html(frame[1], BAR_FILE)) if part) + + css = '\n'.join((lean_css(text_of(EXT / EDITOR_CSS), EDITOR_CSS), + lean_css(text_of(console / CSS_FILE), CSS_FILE))) + + # One '] + + return '\n'.join([ + '', + '', + '', + '', + '', + '', + 'Patternflow - Audio', + GENERATED, + '', + '', + '', + body, + ] + scripts + [ + '', + '', + '', + ]) + + +def stamped_gzip(page: str, sketch=None) -> int: + """Bytes of `page` as the panel sends it: console_pages.py's own stamp and + its own gzip, so this cannot measure something other than what ships.""" + if str(HERE) not in sys.path: + sys.path.insert(0, str(HERE)) + import console_pages as cp + + sk = Path(sketch or SKETCH) + name, rel, delim = cp.CHROME + try: + _, chrome, _ = cp.split(cp.read(str(sk / rel)), name, delim) + shim = cp.load_shim(str(sk / 'console' / cp.SHIM_FILE)) + stamped = cp.stamp(page, cp.crc_of(chrome), shim, PAGE) + except (OSError, ValueError) as e: + raise BuildError(str(e)) + return len(gzip.compress(cp.payload(stamped), compresslevel=9, mtime=0)) + + +def weight(page: str, sketch=None): + """(gzip bytes as the panel sends it, one line saying so against the budget + and against the send windows it takes).""" + gz = stamped_gzip(page, sketch) + windows = -(-gz // WINDOW) + last = gz - (windows - 1) * WINDOW + return gz, ('%d bytes, %d gzip -9 as the panel sends it (budget %d, %s; ' + '%d send windows of %d: %d in the last, %d left in it)' % ( + len(page.encode('utf-8')), gz, BUDGET, + '%d spare' % (BUDGET - gz) if gz <= BUDGET else '%d OVER' % (gz - BUDGET), + windows, WINDOW, last, WINDOW - last)) + + +def on_disk(sketch=None): + """The page as written, LF, or None when there is none.""" + out = out_path(sketch) + return out.read_text(encoding='utf-8') if out.exists() else None + + +def write(sketch=None): + """Assemble and write the page. Returns (page, changed). Line endings stay + the file's own (a Windows checkout is CRLF, as every file around it), and a + page that already says this is not rewritten, so a build with nothing to + do touches nothing.""" + page = assemble(sketch) + out = out_path(sketch) + if on_disk(sketch) == page: + return page, False + nl = '\r\n' if out.exists() and b'\r\n' in out.read_bytes() else '\n' + with io.open(out, 'w', encoding='utf-8', newline='') as f: + f.write(page.replace('\n', nl)) + return page, True + + +def check(sketch=None) -> list: + """What is wrong, as lines to print; [] when the page on disk is what the + sources assemble to and is inside its budget.""" + try: + page = assemble(sketch) + gz, _ = weight(page, sketch) + except BuildError as e: + return ['console/%s.html cannot be assembled: %s' % (PAGE, e)] + problems = [] + if on_disk(sketch) != page: + problems.append( + 'console/%s.html is not what its sources assemble to (one of them was ' + 'edited, or the page was edited by hand).\n' + ' run: python firmware/toolchain/console_pages.py build' % PAGE) + if gz > BUDGET: + problems.append( + 'console/%s.html is %d bytes gzip -9 as the panel sends it: %d over its ' + 'budget of %d.\n' + ' On the panel\'s own hotspot every kilobyte is 0.2 to 0.5 s before anything ' + 'paints.\n' + ' Take the bytes back out, or raise BUDGET in ' + 'firmware/toolchain/build_audio_in_page.py and say in the commit what they bought.' + % (PAGE, gz, gz - BUDGET, BUDGET)) + return problems + + +def main(argv=None) -> int: + ap = argparse.ArgumentParser( + description='Assemble console/audio-in.html from its sources. ' + 'The usual way in is console_pages.py build.') + ap.add_argument('--check', action='store_true', + help='write nothing: fail if the page on disk is not what the sources ' + 'assemble to, or is over its size budget') + ap.add_argument('--sketch', metavar='DIR', + help='another copy of firmware/patternflow to read console/_audio_in* ' + 'from and write the page into') + args = ap.parse_args(argv) + # Sources are UTF-8 and so are their names in a report; a cp949 console + # must not turn one into a traceback. + for stream in (sys.stdout, sys.stderr): + if hasattr(stream, 'reconfigure'): + stream.reconfigure(errors='replace') + + if args.check: + problems = check(args.sketch) + for problem in problems: + print(problem, file=sys.stderr) + if problems: + return 1 + print('console/%s.html is what its sources assemble to: %s' + % (PAGE, weight(assemble(args.sketch), args.sketch)[1])) + return 0 + + try: + page, changed = write(args.sketch) + gz, line = weight(page, args.sketch) + except BuildError as e: + print('build_audio_in_page: %s' % e, file=sys.stderr) + return 1 + print('%s %s: %s' % ('wrote' if changed else 'unchanged', shown(out_path(args.sketch)), line)) + if gz > BUDGET: + print(' over its size budget: --check (and CI) fails until it is not', file=sys.stderr) + if changed: + print('the header still has to be baked: python firmware/toolchain/console_pages.py build ' + '(which also does this step)') + return 0 -import sys -if '--check' in sys.argv: - # CI: the page on disk must be what this script would write now — so an - # edit to the extension's editor, or to the adapter/overrides above, that - # was not baked into console/audio-in.html fails the build instead of - # shipping a stale page under a fresh-looking header. - current = OUT.read_text(encoding='utf-8') if OUT.exists() else '' - if current == page: - print('console/audio-in.html is up to date (editor %s)' % src_hash) - sys.exit(0) - print('console/audio-in.html is stale: rerun firmware/toolchain/build_audio_in_page.py, ' - 'then firmware/toolchain/console_pages.py build', file=sys.stderr) - sys.exit(1) - -io.open(OUT, 'w', encoding='utf-8', newline='\n').write(page) -print('wrote', OUT.relative_to(ROOT).as_posix(), len(page), 'bytes (editor %s)' % src_hash) +if __name__ == '__main__': + sys.exit(main()) diff --git a/firmware/toolchain/console_pages.py b/firmware/toolchain/console_pages.py index bed53517..3b74d9b1 100644 --- a/firmware/toolchain/console_pages.py +++ b/firmware/toolchain/console_pages.py @@ -85,6 +85,13 @@ `extract` is lossless by construction (build right after it is a no-op), and `build` is idempotent. +One page is not written as a page. console/audio-in.html is assembled by +build_audio_in_page.py from the audio extension's mapping editor and the +console/_audio_in* files (an underscore marks a source that is not a page; +PAGES below is the list of pages). `build` assembles it first and `check` +holds it to its sources and to its size budget, so there is still one command +to build and one to check. Edit those sources, never audio-in.html. + --sketch DIR work on another copy of firmware/patternflow (a scratch copy to try a change of this script against) """ @@ -388,6 +395,18 @@ def unstamp(body, name="page"): return STAMPED_RE.sub(lambda m: CHROME_TAG, body) +# ── the page that is assembled ───────────────────────────────────────────── + +def assembled(): + """build_audio_in_page: console/audio-in.html is made by it, from sources + that are not pages (see the docstring). It takes the sketch as an argument + and reads this file's functions, never its state, so --sketch holds.""" + if HERE not in sys.path: + sys.path.insert(0, HERE) + import build_audio_in_page + return build_audio_in_page + + # ── commands ─────────────────────────────────────────────────────────────── def stamping(): @@ -417,6 +436,16 @@ def cmd_build(): crc, shim = stamping() changed = [] pages_gz = chrome_gz = 0 + gen = assembled() + try: + page, wrote = gen.write(SKETCH) + gz, weight = gen.weight(page, SKETCH) + except ValueError as e: + raise SystemExit("%s: %s" % (gen.PAGE, e)) + print(" %s.html %s its sources: %s" + % (gen.PAGE, "assembled from" if wrote else "already matches", weight)) + if gz > gen.BUDGET: + print(" %s: over its size budget; `check` (and CI) fails until it is not" % gen.PAGE) print(" stamping chrome h=%s, fallback %d bytes" % (crc, len(shim))) for name, rel, delim, src in targets(): dest = header_path(rel) @@ -480,13 +509,22 @@ def cmd_check(): problem = gz_problem(block, ident, storage, body) if problem: stale.append("%s (%s)" % (name, problem)) + # The assembled page against its own sources and its size budget. A header + # can match a page that no longer matches what it is made from. + gen = assembled() + problems = gen.check(SKETCH) if stale: print("out of sync: " + ", ".join(stale)) print("run: python firmware/toolchain/console_pages.py build") + for problem in problems: + print(problem) + if stale or problems: return 1 print("all %d console headers match their HTML, stamped with chrome h=%s; " "all %d gzip twins decompress to their literals" % (len(PAGES), crc, len(PAGES) + len(ASSETS))) + print("%s.html is what its sources assemble to: %s" + % (gen.PAGE, gen.weight(gen.assemble(SKETCH), SKETCH)[1])) return 0 diff --git a/firmware/toolchain/console_serve.py b/firmware/toolchain/console_serve.py index 98da06f6..51acca58 100644 --- a/firmware/toolchain/console_serve.py +++ b/firmware/toolchain/console_serve.py @@ -28,6 +28,40 @@ here, and a page that works against the mock still has to be tried on a device before you believe it. +One exception, because one page is an editor: /audio-in. Its endpoints +(/api/audio-in, /api/audio-in/reset, /api/audio) are a port of the firmware's +handlers, not a fixture: a request changes only the fields it carries, the +pairs settle as they do on the panel, a bad curve table is ignored with +{"ok":true}, replies have the handler's field order and decimals. The +sound is made up; what is done with it is not. And what the panel hears is +a state you pick, each entered as if it had been so for a while (each of +these addresses lands on /audio-in): + + /mock?audio=music the microphone on, a room with music in it (the default) + /mock?audio=silence on, a quiet room: the gates shut, every knob at rest + /mock?audio=off switched off after music: the analysis is parked and + the poll's numbers are the last window's, not zeros + /mock?audio=fresh a panel nobody has configured: off, nothing heard, + nothing learned, the factory mapping + /mock?audio=nomic on, nothing on the data pin: + source "pdm (no mic - data pin idle)" + /mock?audio=stalled on, the microphone stopped answering: source + "synth (mic stalled)", and the numbers are the + built-in test tones (levels far above 1), not a room + /mock?audio=phone off, the phone app posting monitor frames: source + "phone", ext:true, its own 0..1 units - while levelsN + and outputs stay the microphone's stale ones + /mock?audio=ext off, the browser extension holding the :81 socket + (audioClients 1); nothing of its sound reaches a page + /mock?audio=noread the configuration read (GET /api/audio-in) gets no + reply, and only that: the poll and every POST still + answer. Any other state ends it. + +The switches on the page work from any of them (mic=1 says "synth" for the +quarter second the driver takes, as on the panel), and the routes follow the +caps: /mock?caps=patterns,params,sleep,audio-in is the microphone without the +browser path, where /api/audio is a 404. + Pages and the chrome, though, go out exactly as the panel sends them (src/core_send.h): each page stamped by console_pages.py's own code (the chrome's ?h= and the fallback PF), with the same ETag, the same 304, and the @@ -36,7 +70,9 @@ `h`, and nothing cacheable under a Host that is not an address, a bare name or .local. The build here changes whenever a page, the chrome or the fallback is saved, so a saved edit still shows on refresh: the old `v` is -redirected. +redirected. /audio-in is not read off disk: it is assembled from its sources +(build_audio_in_page.py, on every request), so saving the editor, the +adapter or the panel's CSS shows on refresh like any other page. The link can be made as bad as the panel's. On the desk every request is instant and parallel; on the panel's own hotspot it is a phone in power @@ -54,16 +90,25 @@ --chrome404 /pf-console.js answers 404: the pages run on the fallback PF stamped into them --sketch DIR serve another copy of firmware/patternflow + +Timing something on the desk? Open it as http://127.0.0.1:8322. This listens +on IPv4 only, a browser tries IPv6 first under the name localhost, and every +request here is a connection of its own - so that detour is paid each time +(Chromium on Windows: /audio-in polls 9.4 times a second under 127.0.0.1 and +4.8 under localhost). """ import argparse import gzip import json +import math import threading import time import os import posixpath +import random import re +import struct import sys import urllib.parse import zlib @@ -75,6 +120,7 @@ sys.path.insert(0, HERE) import console_pages # noqa: E402 the stamp is its code, not a copy of it +import build_audio_in_page # noqa: E402 /audio-in is assembled, by its code PORT = int(os.environ.get("PF_CONSOLE_PORT", "8322")) @@ -110,7 +156,10 @@ class Link: REVALIDATE = "no-cache" NO_STORE = "no-store" DESK_CACHE = "no-cache" -TCP_WINDOW = 5760 # lwIP TCP_SND_BUF on the panel: one round trip per this many bytes +# lwIP TCP_SND_BUF on the panel: one round trip per this many bytes of a reply's +# body. build_audio_in_page.py counts /audio-in in the same number (its WINDOW), +# so the weight line it prints is in this link's steps; change them together. +TCP_WINDOW = 5760 def payload_etag(payload): @@ -168,7 +217,7 @@ def host_cacheable(host): CHROME_SRC = RAW_ASSETS["/pf-console.js"][:2] CAPS_FULL = ["patterns", "params", "sleep", "osc", "shows", "weather", "mqtt", "clock", - "audio-in", "midi"] + "audio", "audio-in", "midi"] CAPS_BARE = ["patterns", "params", "sleep"] @@ -201,13 +250,19 @@ def console_build(): """The panel's `build` changes whenever its pages could have; here, whenever a page, the chrome, the fallback or the stamping code is saved - so the self-heal path runs on the desk, and an immutable page never outlives - an edit.""" + an edit. The assembled page's sources count too: most of them are not in + console/ at all (the editor is the extension's).""" h = 0 for name in sorted(os.listdir(HTML_DIR)): if name.endswith((".html", ".js")): h = zlib.crc32(("%s:%d" % (name, os.stat(os.path.join(HTML_DIR, name)).st_mtime_ns)).encode(), h) for f in (os.path.join(SKETCH, "src", "theme_index.h"), os.path.join(HERE, "console_pages.py")): h = zlib.crc32(str(os.stat(f).st_mtime_ns).encode(), h) + for f in build_audio_in_page.sources(SKETCH) + [build_audio_in_page.__file__]: + try: + h = zlib.crc32(str(os.stat(f).st_mtime_ns).encode(), h) + except OSError: + h = zlib.crc32(b"missing", h) # assemble() says which, when the page is asked for return "%08x" % (h & 0xFFFFFFFF) # What the hotspot's channel scan "saw", for the /wifi page's name suggestions. SEEN_NETWORKS = ["wifiiii", "SK_WiFiGIGA7A1C", "olleh_WiFi_2F3B", "U+Net4E21", "iptime"] @@ -265,7 +320,7 @@ def __init__(self): def status(self): p = self.patterns[self.active] if self.patterns else None hs = getattr(self, "hotspot", {"mode": "auto", "up": False}) - return { + return dict({ "version": "3.10.4", "build": console_build(), "variant": self.variant, @@ -311,7 +366,7 @@ def status(self): "mqttRole": "off", "mqttState": "off", "mqttConnected": False, - } + }, **AUDIO.status(self.caps)) # appended by the features, when the build has them def show_state(self): cur = next((s for s in self.shows if s["slug"] == self.show_slug), None) @@ -333,6 +388,775 @@ def show_state(self): } +# ── the audio features: /api/audio-in and /api/audio ───────────────────── +# +# Everything else here answers with a fixture. This cannot: /audio-in is an +# editor, and what has to be right on the desk is what the firmware DOES with +# what the page sends it - a request carrying one edge of one box, a pair of +# fields that settle together, a curve table refused without a word, levels +# that are stale rather than zero. A kinder mock hides exactly the mistakes +# that lose somebody's mapping on a panel. +# +# So this part is a port, not a fixture: of features/audio_in/ +# core_audio_in_http.h (handleGet, handleSet, applyBandArgs, handleReset, +# parseFrame), core_audio_in_map.h (the defaults, clampRange, the gate, the +# mapping), the analysis task in feature_audio_in.h and the two /api/audio +# routes in features/audio/feature_audio.h - same order of fields, same +# decimals, same clamps, same refusals. docs/rest-api.md ("Microphone") is the +# contract in prose. WHEN ONE OF THOSE HANDLERS CHANGES, CHANGE THIS WITH IT. +# +# What is not ported is the sound. There is no FFT here: Room below is what one +# would have produced, for a room this file makes up. + +BIN_HZ = 16000.0 / 512.0 # a 512-point transform at 16 kHz +MAX_BIN = 256 +MIN_HZ, MAX_HZ = BIN_HZ, MAX_BIN * BIN_HZ +LUT_POINTS = 33 +SPEC_BUCKETS = 64 +BAND_FIELDS = ("hzMin", "hzMax", "inMin", "inMax", "gain", "outMin", "outMax", "knob", + "muted", "lut", "meta") +# core_audio_in_map.h resetBand(): hzMin hzMax inMin inMax gain outMin outMax +BAND_DEFAULTS = ((62.0, 375.0, 0.200, 0.900, 1.0, 0.30, 0.85), + (375.0, 1500.0, 0.120, 0.650, 1.2, 0.30, 0.85), + (1500.0, 5000.0, 0.045, 0.160, 1.6, 0.30, 0.85), + (5000.0, 8000.0, 0.012, 0.030, 1.8, 0.30, 0.85)) +AUDIO_ROUTES = ("/api/audio-in", "/api/audio-in/reset", "/api/audio") + +# /mock?audio=: the microphone switch, what is on the data pin, whether +# the phone app is posting monitor frames, how many senders hold the :81 +# socket. Each is entered as if the panel had been that way for a while. +# +# The start: the gate's noise reference is whatever the first two seconds of +# analysis bottom out at (trackEnvelopes' warm-up), and the first window is +# half empty with the transform's own smoothing climbing from zero - so a +# microphone that comes up in a steady room teaches the reference a fraction +# of the real level, and the gate then stands open on a sound that never +# changes. The real headers do exactly that when built on a host and fed a +# steady tone (reference at half the level, gate open, knob at its top). +# Whether a panel does it in a quiet room depends on what its microphone's +# first windows really hold, and nobody at this desk has measured that. The +# room here starts with a pop (see window()), which lands the reference on +# the floor: the behaviour the firmware's own notes describe. Until a panel +# says otherwise, "silence: every gate shut" is that assumption. +AUDIO_STATES = { + # switch, on the pin, phone frames, socket senders + "music": (True, "music", False, 0), + "silence": (True, "silence", False, 0), + "off": (False, "music", False, 0), + "fresh": (False, "music", False, 0), + "nomic": (True, "rail", False, 0), + "stalled": (True, "tones", False, 0), + "phone": (False, "music", True, 1), + "ext": (False, "music", False, 1), +} + + +def f32(v): + """A C float. Every number the firmware keeps is one, and what it prints is + the float's value, not the decimal the request carried.""" + try: + return struct.unpack("f", struct.pack("f", v))[0] + except OverflowError: + return math.copysign(math.inf, v) + + +def fstr(v, prec): + """Arduino's String(float, prec), which is the ESP32 core's dtostrf: half a + last digit is added and the rest cut off, digit by digit. Not printf: an + input gain of 8.25 reads back as 8.3 here and on the panel, 8.2 from '%.1f'.""" + if v != v: + return "nan" + if v in (math.inf, -math.inf): + return "inf" + neg = v < 0.0 + if neg: + v = -v + rounding = 2.0 + for _ in range(prec): + rounding *= 10.0 + v += 1.0 / rounding + tenpow, digits = 1.0, 1 + while v >= 10.0 * tenpow: + tenpow *= 10.0 + digits += 1 + v /= tenpow + out = ["-"] if neg else [] + left = digits + prec + while left > 0: + left -= 1 + d = min(9, int(v)) + out.append(chr(48 + d)) + if left == prec and prec > 0: + out.append(".") + v = (v - d) * 10.0 + return "".join(out) + + +ATOF = re.compile(r"[ \t\n\v\f\r]*([+-]?(?:[0-9]+\.?[0-9]*(?:[eE][+-]?[0-9]+)?" + r"|\.[0-9]+(?:[eE][+-]?[0-9]+)?|inf(?:inity)?|nan))", re.I) +ATOL = re.compile(r"[ \t\n\v\f\r]*([+-]?[0-9]+)") + + +def to_float(s): + """String::toFloat(): the number the text starts with, 0 when it starts + with none - so "abc" is 0, "1.5x" is 1.5 and "nan" is a NaN. Every clamp + lets a NaN through, so nothing takes one from here without finite_or().""" + m = ATOF.match(s) + return f32(float(m.group(1))) if m else 0.0 + + +def finite_or(v, fallback): + """PFAudioInMap::finiteOr(): NaN and the infinities are not settings. The + field keeps what it had (and a number too large for a float is an inf).""" + return v if math.isfinite(v) else fallback + + +def to_int(s): + m = ATOL.match(s) + return int(m.group(1)) if m else 0 + + +def constrain(v, lo, hi): + return lo if v < lo else hi if v > hi else v + + +def clamp01(v): + return 0.0 if v < 0.0 else 1.0 if v > 1.0 else v + + +def truthy(v): + return v in ("1", "true") + + +def bin_of(hz): + """core_audio_in_map.h binOf(). A NaN edge lands on bin 1 here; on the + panel that cast is undefined, and nothing sane depends on it.""" + b = int(hz / BIN_HZ + 0.5) if hz == hz else 1 + return 1 if b < 1 else MAX_BIN if b > MAX_BIN else b + + +class Args: + """server.hasArg() and server.arg(), over what the panel's web server + would have parsed (src/webserver/Parsing.cpp). Its rules, because a page + can be wrong about each of them and still work on a kinder parser: + + - the query string first, then the body, and arg() is the FIRST value; + - the body only under Content-Type: application/x-www-form-urlencoded. A + POST without that header reaches the handler with no body arguments at + all - a `band=2` reset sent that way resets every band; + - a name with no `=` is not an argument (`?levels` is the configuration); + - a name with an empty value is one (`lut2=` clears a table). + + Not read here, though the panel reads it: a multipart body (FormData). + + Values are kept as bytes-in-a-str (latin-1), as the panel keeps bytes: a + curve's `meta` is cut to 31 of them, not 31 characters.""" + + def __init__(self, query, body, ctype): + data = query + if body and ctype.startswith("application/x-www-form-urlencoded"): + data = (data + "&" if data else "") + body + self.list = [] + for part in data.split("&"): + k, eq, v = part.partition("=") + if eq: + self.list.append(tuple( + urllib.parse.unquote_to_bytes(x.replace("+", " ")).decode("latin-1") + for x in (k, v))) + + def has(self, name): + return any(k == name for k, _ in self.list) + + def get(self, name): + return next((v for k, v in self.list if k == name), "") + + def num(self, name, fallback): + """argFloat(): absent, empty, or not a finite number leaves the + stored value alone.""" + v = self.get(name) + return finite_or(to_float(v), fallback) if v else fallback + + +def parse_lut(csv): + """33 samples, 0..255, commas and digits only; anything else is no table.""" + out, acc, has = [], 0, False + for c in csv + ",": + if "0" <= c <= "9": + acc, has = acc * 10 + ord(c) - 48, True + if acc > 255: + return None + elif c == ",": + if not has or len(out) >= LUT_POINTS: + return None + out.append(acc) + acc, has = 0, False + else: + return None + return out if len(out) == LUT_POINTS else None + + +class Room: + """What a window of sound would have come out of the transform as: a + magnitude per FFT bin, in the firmware's unit (linear, unnormalized), built + from a few fixed shapes whose loudness is all that changes from one window + to the next. fold() and spectrum() are averages over bins, so the mock + takes the same averages of these. + + The numbers are sized from core_audio_in_map.h's own measurements at input + gain 8: the quiet-room medians (0.146 / 0.040 / 0.020 / 0.017 per default + band) for the floor, and music's p10..p90 (0.24..0.66, 0.16..0.49, + 0.05..0.12, 0.011..0.019) for the four voices - including the top band + barely clearing its own noise, which is the content and not a bug.""" + + FLOOR = ((31, 0.30), (62, 0.26), (125, 0.185), (250, 0.118), (375, 0.078), (750, 0.044), + (1500, 0.027), (3000, 0.019), (5000, 0.017), (8000, 0.016)) + # centre Hz, width in decades, loudness + VOICES = ((150.0, 0.45, 0.76), # kick and bass + (750.0, 0.26, 0.52), # the mids: chords, a voice + (2600.0, 0.22, 0.125), # presence + (6600.0, 0.10, 0.09)) # hats: the only thing the top band hears + # The built-in three-tone test signal (120 / 900 / 4200 Hz), which the + # analysis runs on when the microphone is not delivering: its 64-bucket + # spectrum as the real handler printed it on a host build (GET + # ?levels=1 with the I2S install failing). Nothing here is under 1.0 by + # accident - the transform is not normalized. + TONES = (0.89, 0.89, 0.89, 0.89, 0.89, 4.416, 4.416, 4.416, 4.416, 4.416, 4.416, 79.407, + 79.407, 79.407, 79.407, 125.878, 125.878, 125.878, 48.977, 48.977, 2.49, 2.49, + 0.699, 0.699, 0.295, 0.152, 0.089, 0.089, 0.056, 0.037, 0.021, 0.011, 0.006, + 0.003, 0.012, 0.034, 0.103, 0.513, 26.728, 34.585, 0.267, 0.043, 0.015, 0.006, + 0.003, 0.002, 0.001, 0.001, 0.0, 0.0, 0.0, 0.0, 0.0, 0.001, 0.001, 0.013, 8.995, + 0.023, 0.001, 0.0, 0.0, 0.0, 0.0, 0.0) + + def __init__(self): + # PFAudioFFT::spectrum(): which bins each of the 64 log buckets averages. + lg0, lg1 = math.log10(MIN_HZ), math.log10(MAX_HZ) + self.buckets = [] + for i in range(SPEC_BUCKETS): + k0 = bin_of(10 ** (lg0 + (lg1 - lg0) * i / SPEC_BUCKETS)) + k1 = bin_of(10 ** (lg0 + (lg1 - lg0) * (i + 1) / SPEC_BUCKETS)) + self.buckets.append((k0, min(MAX_BIN, max(k1, k0 + 1)))) + hz = [k * BIN_HZ for k in range(MAX_BIN)] + floor = [0.0] + [self.floor_at(f) for f in hz[1:]] + voices = [[0.0] + [amp * math.exp(-((math.log10(f / fc) / width) ** 2)) for f in hz[1:]] + for fc, width, amp in self.VOICES] + tones = [0.0] * MAX_BIN + for (k0, k1), v in zip(self.buckets, self.TONES): + tones[k0:k1] = [v] * (k1 - k0) + # Running sums, so a band of any width is two lookups. + self.sums = [self.running(bins) for bins in [floor] + voices + [tones]] + + def floor_at(self, f): + pts = self.FLOOR + for (f0, v0), (f1, v1) in zip(pts, pts[1:]): + if f <= f1: + u = math.log(max(f, f0) / f0) / math.log(f1 / f0) + return v0 * (v1 / v0) ** u + return pts[-1][1] + + @staticmethod + def running(bins): + out, s = [0.0], 0.0 + for v in bins: + s += v + out.append(s) + return out + + def mean(self, part, lo, hi): + """The average of one shape over bins lo..hi-1, as fold() takes it. A + band with no bins in it (a low edge in the top bin) hears nothing.""" + s = self.sums[part] + return (s[hi] - s[lo]) / (hi - lo) if hi > lo else 0.0 + + @staticmethod + def music(t): + """How loud each voice is at time t, on a 24 second loop at 120 bpm: + a verse with next to no treble (the top band's gate stays shut, as it + does on a panel at listening volume), a chorus with hats, then two + seconds of near silence - so every gate can be watched opening and + closing.""" + bar = t % 24.0 + kick = math.exp(-5.0 * ((t * 2.0) % 1.0)) + hat = math.exp(-2.2 * ((t * 2.0 + 0.5) % 1.0)) + swell = 0.5 + 0.5 * math.sin(t * 2 * math.pi / 5.3) + lead = 0.5 + 0.5 * math.sin(t * 2 * math.pi / 3.1 + 1.0) + k = 0.05 if bar >= 22.0 else 1.0 + return [k * (0.20 + 0.80 * kick), k * (0.40 + 0.60 * swell), k * (0.35 + 0.65 * lead), + k * (1.0 if bar >= 10.0 else 0.06) * (0.25 + 0.75 * hat)] + + +ROOM = Room() +NOISE = 0 # Room.sums: the floor, then the four voices, then the test tones + + +class Audio: + """The two audio features of a panel, as far as /audio-in can tell.""" + + def __init__(self): + self.lock = threading.Lock() + self.rng = random.Random(7) + self.runtime = True # AUD, /api/audio's switch (feature_audio.h: on by default) + self.clients = 0 # senders on the :81 socket + self.noread = False # /mock?audio=noread + self.luts = [[0] * LUT_POINTS for _ in range(4)] + self.factory() + self.scene("music") + + # ── settings (core_audio_in_map.h) ─────────────────────────────────── + def reset_band(self, i): + """resetBand(): the measured defaults, and the band back on its gain + exponent. The table's bytes stay; only lutSet says it is not used.""" + d = BAND_DEFAULTS[i] + self.bands[i] = {"hzMin": d[0], "hzMax": d[1], "inMin": f32(d[2]), "inMax": f32(d[3]), + "gain": f32(d[4]), "outMin": f32(d[5]), "outMax": f32(d[6]), + "knob": i, "muted": False} + self.lut_set[i] = False + self.metas[i] = "" + + def reset_bands(self): + for i in range(4): + self.reset_band(i) + self.smoothing, self.attack = f32(0.35), f32(0.65) + + def factory(self): + """A panel nobody has configured: load() with nothing in NVS.""" + self.bands, self.lut_set, self.metas = [None] * 4, [False] * 4, [""] * 4 + self.reset_bands() + self.mic_on, self.mic_gain, self.auto = False, 8.0, True + + @staticmethod + def clamp_range(x): + x["hzMin"] = constrain(x["hzMin"], MIN_HZ, MAX_HZ) + x["hzMax"] = constrain(x["hzMax"], MIN_HZ, MAX_HZ) + if x["hzMin"] > x["hzMax"]: + x["hzMin"], x["hzMax"] = x["hzMax"], x["hzMin"] + if f32(x["hzMax"] - x["hzMin"]) < BIN_HZ: + x["hzMax"] = min(MAX_HZ, f32(x["hzMin"] + BIN_HZ)) + + # ── /mock?audio= ───────────────────────────────────────────────────── + def scene(self, name): + mic, room, phone, clients = AUDIO_STATES[name] + self.noread = False + if name == "fresh": + self.factory() + # The analysis as it is at boot: nothing heard, no floor learned. + self.fft = [0.0] * 4 # PFAudioFFT::bands + self.noise_ref = [-1.0] * 4 # < 0 = unlearned + self.env_hi = [0.0] * 4 + self.gate = [False] * 4 + self.votes = [0] * 4 + self.warmup = 120 + self.smooth = [0.0] * 4 # smoothLevel + self.raw_peak = self.raw_dc = 0.0 + self.windows = self.passes = 0 + self.live = self.stalled = False + self.park = self.since = 0 # passes left asleep; windows since I2S came up + self.t = 0.0 + self.last = None # the window spectrum() would read + self.ext_levels, self.ext_env, self.ext_spec = [0.0] * 4, [0.0] * 8, [0.0] * 64 + self.ext_at = self.poll_at = None + self.phone, self.phone_at = phone, 0.0 + self.phone_lo, self.phone_hi = [1.0] * 4, [0.0] * 4 + self.clients = clients + self.state = name + # ...and then as if it had been in this state for a while. The states + # with the switch off (fresh aside) heard music first, so what they + # hold is what a panel holds: the last window, not zeros. So did the + # microphone that then stopped answering. + if name != "fresh": + self.mic_on = self.live = True + if room in ("music", "tones"): + self.hear("silence", 180) # the warm-up finds the floor + self.hear("music", 720) + if room != "music": + self.hear(room, 1800 if room == "silence" else 300) # envelopes settle slowly + self.room, self.mic_on = room, mic + if not mic: + self.live = self.stalled = False + self.clock = time.monotonic() + if phone: + for back in range(120, 0, -1): + self.phone_frame(self.clock - back * 0.25, True) + + def hear(self, room, windows): + self.room, self.stalled = room, room == "tones" + for _ in range(windows): + self.window() + + # ── the analysis task (feature_audio_in.h), 60 passes a second ─────── + def advance(self, now): + """Catch the analysis up to now. No thread: nothing changes that a + request cannot see, so it runs when one arrives - two seconds' worth at + most, which is all a tab that was away needs.""" + n = int((now - self.clock) * 60.0) + if n > 0: + self.clock = now if n > 120 else self.clock + n / 60.0 + for _ in range(min(n, 120)): + self.tick() + if self.phone: + self.phone_frame(now) + + def tick(self): + if self.park: + self.park -= 1 + return + if not self.mic_on: + # Parked: I2S released, and a look at the switch every 250 ms. + # That wait is why `source` says "synth" for a moment after mic=1. + self.live = self.stalled = False + self.park = 14 + return + if not self.live: # PFAudioPdm::begin() + self.live, self.stalled, self.since = True, self.room == "tones", 0 + self.window() + + def window(self): + """analyze(), then the gate and the damping, as the task runs them.""" + self.t += 1.0 / 60.0 + self.passes += 1 + jit = [1.0 + 0.16 * (self.rng.random() - 0.5) for _ in range(4)] + if self.room == "tones": + # The microphone is not delivering, so the window is the test + # signal: no input gain, and a little drift as the window slides. + wob = 1.0 + 0.015 * math.sin(self.passes * 0.61) + scale, amps, noisy = 1.0, [0.0] * 4 + [wob], False + self.raw_peak, self.raw_dc = 0.99439, -0.0158 + 0.006 * math.sin(self.passes * 0.61) + elif self.room == "rail": + # Nothing on the data pin: it floats to a rail, every sample is + # the same, and a constant has no energy outside bin 0. Measured. + scale, amps, noisy = 0.0, [0.0] * 5, False + self.raw_peak, self.raw_dc = 0.94406, -0.94406 + self.windows += 1 + else: + voices = ROOM.music(self.t) if self.room == "music" else [0.0] * 4 + scale, amps, noisy = self.mic_gain / 8.0, voices + [0.0], True + # A microphone starts with a pop: its first few windows are far + # above the room. That is an assumption about the part, and it + # decides what the gate learns - see "The start", above + # AUDIO_STATES. + pop = 10.0 * 0.45 ** self.since if self.since < 10 else 0.0 + jit = [j + pop for j in jit] + self.raw_peak = 0.0036 + 0.014 * voices[0] + 0.0004 * jit[0] + self.raw_dc = -0.0041 + 0.0003 * (jit[1] - 1.0 - pop) + self.windows += 1 + self.since += 1 + self.last = (scale, amps, noisy, self.passes) + for b in range(4): + lo, hi = self.bins(b) + if hi <= lo: # fold(): no bin, so 0 at once + self.fft[b] = 0.0 + continue + v = scale * self.heard((lo, hi), amps, jit[b] if noisy else 0.0) + self.fft[b] = f32(self.fft[b] * 0.7 + v * 0.3) # fold()'s own smoothing + self.track() + a30, k30 = constrain(self.smoothing, 0.05, 0.9), constrain(self.attack, 0.05, 0.9) + rel60, atk60 = 1.0 - math.sqrt(1.0 - a30), 1.0 - math.sqrt(1.0 - k30) + for i in range(4): # smoothLevels() + a = atk60 if self.fft[i] > self.smooth[i] else rel60 + self.smooth[i] = f32(self.smooth[i] + (self.fft[i] - self.smooth[i]) * a) + + def bins(self, b): + """fold(): the FFT bins band b is averaged over, lo..hi-1.""" + lo = bin_of(self.bands[b]["hzMin"]) + return lo, min(MAX_BIN, max(bin_of(self.bands[b]["hzMax"]), lo + 1)) + + @staticmethod + def heard(bins, amps, floor): + """The average magnitude over those bins: the voices (and the test + tones) at these loudnesses, over this much of the noise floor.""" + return floor * ROOM.mean(NOISE, *bins) + sum( + a * ROOM.mean(i + 1, *bins) for i, a in enumerate(amps)) + + def track(self): + """trackEnvelopes(): the noise reference, the peak envelope, the gate.""" + warming = self.warmup > 0 + if warming: + self.warmup -= 1 + for i in range(4): + v, ref = clamp01(self.fft[i]), self.noise_ref[i] + if ref < 0.0: + ref = v + elif warming: + ref = min(ref, v) + elif not self.gate[i] and v < ref * 1.5 + 0.005: + ref += (v - ref) * 0.005 + self.noise_ref[i] = ref + self.env_hi[i] += (v - self.env_hi[i]) * (0.3 if v > self.env_hi[i] else 0.002) + lo = ref * 1.5 + if self.env_hi[i] < lo + 0.02: + self.env_hi[i] = lo + 0.02 + open_abs = (0.012, 0.050, 0.015, 0.012)[i] + if not self.gate[i]: + self.votes[i] = self.votes[i] + 1 if v > ref * 1.8 + open_abs else 0 + if self.votes[i] >= 8: + self.gate[i], self.votes[i] = True, 0 + else: + self.votes[i] = self.votes[i] + 1 if v < ref * 1.4 + open_abs \ + else max(0, self.votes[i] - 3) + if self.votes[i] >= 25: + self.gate[i], self.votes[i] = False, 0 + + # ── a level to a knob (core_audio_in_map.h) ────────────────────────── + def normalized(self, b, level): + if not self.gate[b]: + return 0.0 + lo = self.noise_ref[b] * 1.5 + return clamp01((level - lo) / max(self.env_hi[b] - lo, 0.02)) + + def mapped_window(self, b, level, in_min, in_max): + x = self.bands[b] + in_min = clamp01(in_min) + in_max = max(in_min + f32(0.01), clamp01(in_max)) + u = clamp01((level - in_min) / (in_max - in_min)) + if self.lut_set[b] and u == u: + pos = clamp01(u) * (LUT_POINTS - 1) + i = int(pos) + j = min(i + 1, LUT_POINTS - 1) + u = (self.luts[b][i] * (1.0 - (pos - i)) + self.luts[b][j] * (pos - i)) / 255.0 + else: + u = u ** (1.0 / constrain(x["gain"], f32(0.2), 4.0)) + return f32(x["outMin"] + u * (x["outMax"] - x["outMin"])) + + def mapped(self, b, level): + if self.auto: + return self.mapped_window(b, self.normalized(b, level), f32(0.10), f32(0.95)) + return self.mapped_window(b, level, self.bands[b]["inMin"], self.bands[b]["inMax"]) + + def source(self): + """sourceLabel(): five strings, matched exactly by the page.""" + if not self.mic_on: + return "off" + if not self.live: + return "synth" + if self.stalled: + return "synth (mic stalled)" + dead = abs(self.raw_dc) >= 0.5 and not any(v > 1e-4 for v in self.fft) + return "pdm (no mic - data pin idle)" if dead else "pdm" + + def spectrum(self): + """PFAudioFFT::spectrum(): 64 log buckets of the LAST window - so with + the analysis parked it is what that window left, again and again.""" + if not self.last: + return [0.0] * SPEC_BUCKETS + scale, amps, noisy, seed = self.last + rng = random.Random(seed) + return [scale * self.heard(bucket, amps, 1.0 + 0.5 * (rng.random() - 0.5) if noisy else 0.0) + for bucket in ROOM.buckets] + + # ── the phone app's monitor frames ─────────────────────────────────── + def ext_fresh(self, now): + return self.ext_at is not None and now - self.ext_at < 3.0 and not self.mic_on + + def watching(self, now): + return self.poll_at is not None and now - self.poll_at < 2.5 + + def parse_frame(self, s, now): + """parseFrame(): 4 levels; 4 x lo,hi; 64 buckets. 76 finite numbers + or nothing.""" + vals = [to_float(tok) for tok in re.split("[,;]", s) if tok][:76] + if len(vals) != 76 or not all(math.isfinite(v) for v in vals): + return + self.ext_levels, self.ext_env, self.ext_spec = vals[:4], vals[4:12], vals[12:] + self.ext_at = now + + def phone_frame(self, now, due=False): + """/mock?audio=phone: what the capture app posts, in its own text and + through the same parser - four frames a second while a page is + polling, one every two seconds when none is (it reads `watch`). The + phone analyses on the phone, in its own unit: 0..1 across its dB axis.""" + if not due and now - self.phone_at < (0.25 if self.watching(now) else 2.0): + return + self.phone_at = now + + def unit(v): + return clamp01((20.0 * math.log10(max(v, 1e-4)) + 45.0) / 47.0) + + amps = ROOM.music(now % 240.0) + levels = [] + for b in range(4): + v = unit(self.heard(self.bins(b), amps, 1.0)) + levels.append(v) + self.phone_hi[b] = v if v > self.phone_hi[b] else \ + self.phone_hi[b] + (v - self.phone_hi[b]) * 0.03 + self.phone_lo[b] = v if v < self.phone_lo[b] else \ + self.phone_lo[b] + (v - self.phone_lo[b]) * 0.03 + self.phone_hi[b] = max(self.phone_hi[b], self.phone_lo[b] + 0.06) + spec = [unit(self.heard(bucket, amps, 1.0)) for bucket in ROOM.buckets] + self.parse_frame("%s;%s;%s" % ( + ",".join("%.3f" % v for v in levels), + ",".join("%.3f,%.3f" % (self.phone_lo[b], self.phone_hi[b]) for b in range(4)), + ",".join("%.2f" % v for v in spec)), now) + + # ── the replies (core_audio_in_http.h): field order and decimals are the + # handler's, because the page compares what it re-reads ────────────── + def poll_json(self, now): + ext = self.ext_fresh(now) + j = '{"source":"%s","ext":%s' % ("phone" if ext else self.source(), "true" if ext else "false") + j += ',"rawPeak":%s,"rawDc":%s,"dropped":0' % (fstr(self.raw_peak, 5), fstr(self.raw_dc, 5)) + j += ',"levels":[' + ",".join(fstr(v, 4) for v in (self.ext_levels if ext else self.smooth)) + # Always the microphone's, also while the phone's frames are served. + j += '],"levelsN":[' + ",".join(fstr(self.normalized(i, self.smooth[i]), 4) for i in range(4)) + j += '],"outputs":[' + ",".join(fstr(self.mapped(i, self.smooth[i]), 4) for i in range(4)) + if ext: + j += '],"env":[' + ",".join('{"lo":%s,"hi":%s}' % (fstr(self.ext_env[i * 2], 4), + fstr(self.ext_env[i * 2 + 1], 4)) + for i in range(4)) + elif self.auto: + j += '],"env":[' + ",".join('{"lo":%s,"hi":%s}' % (fstr(self.noise_ref[i] * 1.5, 4), + fstr(self.env_hi[i], 4)) + for i in range(4)) + j += '],"spectrum":[' + ",".join(fstr(v, 3) for v in (self.ext_spec if ext else self.spectrum())) + return j + "]}" + + def config_json(self): + j = '{"source":"%s","micOn":%s,"micGain":%s,"autoRange":%s,"smoothing":%s,"attack":%s' % ( + self.source(), "true" if self.mic_on else "false", fstr(self.mic_gain, 1), + "true" if self.auto else "false", fstr(self.smoothing, 3), fstr(self.attack, 3)) + j += ',"rawPeak":%s,"rawDc":%s,"windows":%d' % (fstr(self.raw_peak, 5), fstr(self.raw_dc, 5), + self.windows) + j += ',"level":[' + ",".join(fstr(v, 4) for v in self.fft) + j += '],"out":[' + ",".join(fstr(self.mapped(i, self.fft[i]), 4) for i in range(4)) + bands = [] + for i, b in enumerate(self.bands): + bands.append( + '{"hzMin":%s,"hzMax":%s,"inMin":%s,"inMax":%s,"gain":%s,"outMin":%s,"outMax":%s,' + '"knob":%d,"muted":%s,"meta":"%s","lutSet":%s}' % ( + fstr(b["hzMin"], 1), fstr(b["hzMax"], 1), fstr(b["inMin"], 4), + fstr(b["inMax"], 4), fstr(b["gain"], 3), fstr(b["outMin"], 3), + fstr(b["outMax"], 3), b["knob"], "true" if b["muted"] else "false", + self.metas[i].replace("\\", "\\\\").replace('"', '\\"'), + "true" if self.lut_set[i] else "false")) + j += '],"bands":[' + ",".join(bands) + j += '],"hzRange":[%s,%s' % (fstr(MIN_HZ, 2), fstr(MAX_HZ, 2)) + j += '],"spec":[' + ",".join(fstr(v, 3) for v in self.spectrum()) + return j + "]}" + + def apply_band(self, b, sfx, a): + """applyBandArgs(): whatever arrived under these names; the two pairs + (hzMin/hzMax, inMin/inMax) are settled after, whichever half came.""" + x = self.bands[b] + x["hzMin"] = a.num("hzMin" + sfx, x["hzMin"]) + x["hzMax"] = a.num("hzMax" + sfx, x["hzMax"]) + self.clamp_range(x) + x["inMin"] = constrain(a.num("inMin" + sfx, x["inMin"]), 0.0, 1.0) + x["inMax"] = constrain(a.num("inMax" + sfx, x["inMax"]), 0.0, 1.0) + x["gain"] = constrain(a.num("gain" + sfx, x["gain"]), f32(0.2), 4.0) + x["outMin"] = constrain(a.num("outMin" + sfx, x["outMin"]), 0.0, 1.0) + x["outMax"] = constrain(a.num("outMax" + sfx, x["outMax"]), 0.0, 1.0) + if a.has("knob" + sfx): + x["knob"] = constrain(to_int(a.get("knob" + sfx)), 0, 3) + if a.has("muted" + sfx): + x["muted"] = truthy(a.get("muted" + sfx)) + floor = f32(x["inMin"] + f32(0.01)) + if x["inMax"] < floor: + x["inMax"] = min(1.0, floor) + if a.has("lut" + sfx): + csv = a.get("lut" + sfx) + table = parse_lut(csv) if csv else None + if not csv: + self.lut_set[b] = False # empty clears; the band runs `gain` + elif table: + self.luts[b], self.lut_set[b] = table, True + # ...and anything else is ignored: the reply is still {"ok":true} + if a.has("meta" + sfx): + self.metas[b] = a.get("meta" + sfx).split("\0")[0][:31] + + def handle_set(self, a, now): + if a.has("frame"): + # A monitor frame is state, not settings: nothing else is read. + self.parse_frame(a.get("frame"), now) + return 200, '{"ok":true,"watch":%s}' % ("true" if self.watching(now) else "false") + single = -1 + if a.has("band"): + single = to_int(a.get("band")) + if single < 0 or single > 3: # refused before anything is applied + return 400, '{"ok":false,"error":"band must be 0-3"}' + if a.has("mic"): + self.mic_on = truthy(a.get("mic")) + if self.mic_on and not self.live: + # The parked task looks at the switch every 250 ms, so on a + # panel the driver is up some time inside that. Here it is + # always the whole quarter second: the "synth" a page must + # not take for a verdict is then there every time. + self.park = 15 + if a.has("auto"): + self.auto = truthy(a.get("auto")) + if a.has("micGain"): + self.mic_gain = constrain(finite_or(to_float(a.get("micGain")), self.mic_gain), 1.0, 16.0) + if a.has("smoothing"): + self.smoothing = constrain(finite_or(to_float(a.get("smoothing")), self.smoothing), + f32(0.05), f32(0.9)) + if a.has("attack"): + self.attack = constrain(finite_or(to_float(a.get("attack")), self.attack), + f32(0.05), f32(0.9)) + if single >= 0: + self.apply_band(single, "", a) + for b in range(4): + # A band is applied when the request names ANY of its fields. + if any(a.has(f + str(b)) for f in BAND_FIELDS): + self.apply_band(b, str(b), a) + return 200, '{"ok":true}' + + def handle_reset(self, a): + if a.has("band"): + v = a.get("band") + if len(v) != 1 or not "0" <= v <= "3": # one digit, or nothing happens + return 400, '{"ok":false,"error":"band must be 0-3"}' + self.reset_band(int(v)) + return 200, '{"ok":true,"band":%s}' % v + self.reset_bands() # every band and curve, damping, attack... + self.mic_gain = 8.0 # ...and the input gain. Not the switch, not auto. + return 200, '{"ok":true}' + + def request(self, method, path, a, caps): + """(status, body) as the firmware answers it, or None where this build + has no such route and the web server's own 404 goes out.""" + now = time.monotonic() + self.advance(now) + if path == "/api/audio" and "audio" in caps: + if method == "GET": + return 200, '{"audioRuntime":%s,"audioClients":%d}' % ( + "true" if self.runtime else "false", self.clients) + if method == "POST": + if a.has("on"): + self.runtime = truthy(a.get("on")) + return 200, '{"ok":true,"audioRuntime":%s}' % ("true" if self.runtime else "false") + if path == "/api/audio-in" and "audio-in" in caps: + if method == "GET" and a.has("levels"): + if not a.has("idle"): + self.poll_at = now # a page is watching: the phone reads this + return 200, self.poll_json(now) + if method == "GET": + return 200, self.config_json() + if method == "POST": + return self.handle_set(a, now) + if path == "/api/audio-in/reset" and "audio-in" in caps and method == "POST": + return self.handle_reset(a) + return None + + def status(self, caps): + """What the two features append to /api/status.""" + with self.lock: + self.advance(time.monotonic()) + out = {} + if "audio" in caps: + out.update(audioRuntime=self.runtime, audioClients=self.clients) + if "audio-in" in caps: + # The timings are of the right order (the transform measured + # 329 us on a panel), not a capture; the rest is the model's. + runs = max(0, self.passes - 60) + out["audioIn"] = { + "core": 0, "lastUs": 1764 if runs else 0, "avgUs": 1742 if runs else 0, + "fillUs": 1307 if runs else 0, "fftUs": 329 if runs else 0, + "foldUs": 96 if runs else 0, "maxUs": 2410 if runs else 0, "runs": runs, + "heap": 0, "staticBytes": 9472, "source": self.source(), + "micWindows": self.windows, "micDropped": 0, + "rawPeak": round(self.raw_peak, 5), "rawDc": round(self.raw_dc, 5), + "bands": [round(v, 4) for v in self.fft], + } + return out + + +AUDIO = Audio() DEV = Device() FEATURE_NAV = feature_nav() @@ -354,10 +1178,12 @@ def log_message(self, fmt, *a): sys.stderr.write(" %s %s\n" % (self.command, self.path)) def log_request(self, code="-", size="-"): - if Link.rtt or Link.serial: - sys.stderr.write(" %s %s -> %s\n" % (self.command, self.path, code)) + # `note`: what an audio request carried, or how it ended (see audio()). + note, self.note = getattr(self, "note", ""), "" + if Link.rtt or Link.serial or (note and code != 200): + sys.stderr.write(" %s %s%s -> %s\n" % (self.command, self.path, note, code)) else: - sys.stderr.write(" %s %s\n" % (self.command, self.path)) + sys.stderr.write(" %s %s%s\n" % (self.command, self.path, note)) # Each request is a connection of its own (Connection: close, here as on # the panel): the handshake and the request cost a round trip @@ -366,10 +1192,16 @@ def log_request(self, code="-", size="-"): def handle_one_request(self): if Link.rtt: time.sleep(Link.rtt) - if Link.serial: - with Link.lock: - return BaseHTTPRequestHandler.handle_one_request(self) - return BaseHTTPRequestHandler.handle_one_request(self) + try: + if Link.serial: + with Link.lock: + return BaseHTTPRequestHandler.handle_one_request(self) + return BaseHTTPRequestHandler.handle_one_request(self) + except ConnectionError: + # The browser left mid-reply: a link clicked, a tab closed. A page + # that polls ten times a second does that on most navigations, + # and a traceback for each one buries the log. + self.close_connection = True def write_body(self, body): if not (Link.rtt or Link.bps): @@ -432,14 +1264,18 @@ def send_console(self, text, ctype, cache, etag=True): def send_page(self, path, name): """PFSend::PAGE: a page stamped exactly as console_pages.py build - stamps it into the header.""" + stamps it into the header. One page is not a file to read: /audio-in + is assembled from its sources by the code `build` assembles it with, + here on every request, so its sources are save-and-refresh too.""" f = os.path.join(HTML_DIR, name + ".html") - if not os.path.exists(f): + assembled = name == build_audio_in_page.PAGE + if not assembled and not os.path.exists(f): return self.send("no console/%s.html — run console_pages.py extract" % name, "text/plain", 404) try: - text = console_pages.stamp(read(f), console_pages.crc_of(raw_literal(*CHROME_SRC)), - console_pages.load_shim(), name) + text = console_pages.stamp( + build_audio_in_page.assemble(SKETCH) if assembled else read(f), + console_pages.crc_of(raw_literal(*CHROME_SRC)), console_pages.load_shim(), name) except (ValueError, RuntimeError, OSError) as e: # build would refuse this page; show why instead of a page the # device could never have served @@ -539,6 +1375,18 @@ def do_GET(self): else DESK_CACHE, etag=False) if path == "/mock": + dest = "/" + if any(k == "audio" for k, _ in self.qlist): + want = self.arg("audio") + if want != "noread" and want not in AUDIO_STATES: + return self.send("audio= is one of: %s, noread\n" % ", ".join(AUDIO_STATES), + "text/plain", 400) + with AUDIO.lock: + if want == "noread": + AUDIO.noread = True + else: + AUDIO.scene(want) + dest = "/audio-in" if "variant" in q: DEV.variant = q["variant"] or "core" want = q.get("caps", "full") if "caps" in q else None @@ -549,9 +1397,12 @@ def do_GET(self): DEV.via_hotspot = q["hotspot"] in ("1", "true", "on") if any(k == "busy" for k, _ in self.qlist): DEV.busy = self.arg("busy") if self.arg("busy") in ("update", "storage") else "" - return self.reply(302, [("Content-Type", "text/plain"), ("Location", "/"), + return self.reply(302, [("Content-Type", "text/plain"), ("Location", dest), ("Cache-Control", NO_STORE), ("Content-Length", "0")]) + if path in AUDIO_ROUTES: + return self.audio(path) + if path.startswith("/api/") or path == "/update/status": return self.api(path, q, {}) @@ -559,14 +1410,48 @@ def do_GET(self): def do_POST(self): path, q = self.parts() + if path in AUDIO_ROUTES: + return self.audio(path) p = dict(q) p.update(self.body_params()) self.api(path, q, p) def do_DELETE(self): path, q = self.parts() + if path in AUDIO_ROUTES: + return self.audio(path) self.api(path, q, dict(q), delete=True) + def audio(self, path): + """The audio features' routes, answered by the port above. The body is + read here, raw: body_params() drops empty values, and to these + handlers `lut2=` and `meta1=` mean something.""" + n = int(self.headers.get("Content-Length") or 0) + body = self.rfile.read(n).decode("latin-1") if n else "" + ctype = self.headers.get("Content-Type") or "" + args = Args(urllib.parse.urlsplit(self.path).query, body, ctype) + # The log line says what was sent - a save is judged by what it + # carried - with a curve table or a phone frame cut short. And it says + # when a body was sent that the panel would not have read. + self.note = "".join(" " + (v if len(v) <= 60 else "%s...(%d bytes)" % (v[:44], len(v))) + for v in body.split("&") if v) + if body and ctype.startswith("multipart/"): + self.note = " (a multipart body: the panel reads those, this mock does not)" + elif body and not ctype.startswith("application/x-www-form-urlencoded"): + self.note += " (BODY NOT READ: Content-Type %r is not the form one)" % ctype + with AUDIO.lock: + if (AUDIO.noread and self.command == "GET" and path == "/api/audio-in" + and not args.has("levels") and "audio-in" in DEV.caps): + # /mock?audio=noread: no reply at all, which is what a failed + # read of a panel is - it has no error to send for this route. + self.note = " (/mock?audio=noread)" + self.close_connection = True + return self.log_request("no reply") + answer = AUDIO.request(self.command, path, args, DEV.caps) + if answer is None: + return self.not_found() + self.send(answer[1].encode("latin-1"), "application/json", answer[0]) + # ── the fake device ────────────────────────────────────────────────── def api(self, path, q, p, delete=False): d = DEV @@ -835,6 +1720,7 @@ def api(self, path, q, p, delete=False): print(" caps /mock?caps=bare /mock?caps=full") print(" variant /mock?variant=simone-pd /mock?variant=core") print(" status /mock?hotspot=1 /mock?busy=update (hotspot=0, busy= to clear)") + print(" audio /mock?audio=" + "|".join(AUDIO_STATES) + "|noread") print(" editing firmware/patternflow/console/*.html — just save and refresh") print(" shipping python firmware/toolchain/console_pages.py build") if Link.device or Link.rtt or Link.bps or Link.serial: diff --git a/tools/README.md b/tools/README.md index 09f9ffff..2ba25996 100644 --- a/tools/README.md +++ b/tools/README.md @@ -4,13 +4,13 @@ Clients that Patternflow ships and that run on their own — a browser extension | Folder | What it is | Contract | | :--- | :--- | :--- | -| [`patternflow-audio-extension/`](patternflow-audio-extension/README.md) | Chrome/Edge extension: captures the current tab's audio, splits it into four bands you shape on a response graph, streams the levels to the panel | [`audio-ws-spec.md`](../docs/audio-ws-spec.md) | -| [`patternflow-audio-android/`](patternflow-audio-android/README.md) | The phone-side twin: captures what the phone is playing and drives the knobs with it, for filming | [`audio-ws-spec.md`](../docs/audio-ws-spec.md) | +| [`patternflow-audio-extension/`](patternflow-audio-extension/README.md) | Chrome/Edge extension: captures the current tab's audio, splits it into four bands, one per knob, that you shape as boxes on the live spectrum, and streams the four knob values to the panel | [`audio-ws-spec.md`](../docs/audio-ws-spec.md) | +| [`patternflow-audio-android/`](patternflow-audio-android/README.md) | The phone-side twin: captures what the phone is playing and drives the knobs with it, for filming. It takes its mapping from the panel | [`audio-ws-spec.md`](../docs/audio-ws-spec.md), and the microphone endpoints of [`rest-api.md`](../docs/rest-api.md#microphone-audio-edition) | | [`rtpmidi-probe/`](rtpmidi-probe/README.md) | A plain-Python RTP-MIDI session initiator that walks the MIDI contract against a panel from a machine with no MIDI driver | [`midi-spec.md`](../docs/midi-spec.md) | ## The extension is also firmware source -The band editor in `patternflow-audio-extension/` (`editor.html`, `editor.css`, `editor.js`, `editor-adapter.js`) is the **authoring source of the device's own `/audio-in` console page**: `firmware/toolchain/build_audio_in_page.py` assembles `firmware/patternflow/console/audio-in.html` from those files, and the `console-sync` workflow fails if the two drift. Edit the editor here, never the generated page, and do not move this folder — the build script and the workflow hold its path. +The mapping editor in `patternflow-audio-extension/` is the **authoring source of the device's own `/audio-in` console page**. Four of its files travel to the panel: `editor.html` (the editor's body), `editor.css` and `mapping.js` (each down to its `EXTENSION ONLY` line) and `editor.js`. `editor-adapter.js` does not: the panel has its own adapter, frame and styles beside the other console sources (`firmware/patternflow/console/_audio_in_*`). `python firmware/toolchain/console_pages.py build` assembles `firmware/patternflow/console/audio-in.html` from both halves (the step is `firmware/toolchain/build_audio_in_page.py`) and bakes the header the panel serves; `python firmware/toolchain/console_serve.py` previews the page from the sources without building. The `console-sync` workflow fails when the generated page is not what its sources assemble to, or is over its size budget. Edit the editor here, never the generated page, and do not move this folder — the build script and the workflow hold its path. ## License diff --git a/tools/patternflow-audio-extension/README.md b/tools/patternflow-audio-extension/README.md index 92265107..664875e0 100644 --- a/tools/patternflow-audio-extension/README.md +++ b/tools/patternflow-audio-extension/README.md @@ -1,71 +1,194 @@ # Patternflow Audio Chrome Extension -Captures audio from the currently active Chrome/Edge tab, shows a live -spectrum, maps editable frequency bands to Patternflow knobs, and streams -the four knob lanes over WebSocket. The wire protocol is a written contract: +Captures the audio of a Chrome or Edge tab, splits it into four frequency +bands, and sends each band to one of the panel's four knobs over your local +network. The panel has to run the **Audio edition** +([patternflow.work/editions](https://patternflow.work/editions)). +[`AUDIO_GUIDE.md`](../../AUDIO_GUIDE.md) is the guide to everything around it; +the wire protocol is a written contract, [`docs/audio-ws-spec.md`](../../docs/audio-ws-spec.md). -The extension uses the same Patternflow mark as the web app for its toolbar -icon and popup header. +## Install + +It is not on the Chrome Web Store. Load it from this folder: + +1. Get the repository: `git clone`, or **Code → Download ZIP** on GitHub and + unzip it. +2. Open `chrome://extensions` (in Edge, `edge://extensions`). +3. Enable **Developer mode**. +4. Click **Load unpacked** and pick this folder, + `tools/patternflow-audio-extension`. + +**After pulling a newer copy, press Reload** on the extension's card in +`chrome://extensions`. Chrome goes on running the files it loaded until you +do. The card shows the version (`version` in `manifest.json`), which is how to +tell the copy that is loaded from the one on disk. + +**Reload keeps the mapping you had.** A copy before 0.2.0 started with Auto +range off and no curve, and unless you changed them its mapping still says so +after Reload: the Auto range switch is off, the four boxes are full height, +and under the curves it reads "This knob uses the default response." The new +defaults (Auto range on, the Smooth curve) are what a new install starts +with. To get them on a copy you already had, do one of: + +- in the mapping editor, select each knob in turn and press its Reset + (**Reset K1** to **Reset K4**), then switch **Auto range** on. Reset also + puts that knob's box and output range back to the default. The panel's + address is kept; +- **Remove** the extension on `chrome://extensions` and load it again from + this folder. That empties everything it stored, the panel's address + included. + +## Use + +1. Go to the tab that is playing: YouTube, SoundCloud, a DJ set, a web DAW. +2. Click the Patternflow Audio button in the toolbar, on that tab. +3. Under **Device**, type the panel's address: `patternflow.local`, or its IP + (the panel's NETWORK screen shows it). +4. Press **Start**. The button now reads **Stop**. + +The word in the popup's corner is the state, and the line under the address +says the rest: + +| | | +|---|---| +| **Idle** | Nothing is captured. | +| **Connecting** | The connection is not open yet, or the panel has not yet said whether it is listening. | +| **Live** | The tab is captured and the panel is being driven. The line reads `Capturing: `, or "No sound from this tab yet." / "... right now." while the tab is silent. | +| **Aud off** | Connected, but Audio-React is switched off on the panel, which then ignores what arrives. Press **Turn on**, which appears under the address. It is the same switch as `AUD` on the panel's NETWORK screen and *Browser extension and phone app* on the console's Audio page. | +| **Test** | The test connection (below) is up. | +| **Error** | The line says what: nothing at that address, a panel that does not run the Audio edition, a page Chrome does not let be captured. A connection that fails is retried by itself. | + +**While the tab is silent or paused the knobs are held**, each where its band +rests, until you press Stop. A knob you turn by hand during a pause goes back +there about five seconds after you let go. Stop hands all four back to the +encoders. Closing the captured tab ends the capture, and the popup says so. + +Enter in the address field starts a capture when nothing is running. While +one is running it only changes the address, and the capture follows it; it +never stops one. + +**Spectrum** is what the tab sounds like, 20 Hz to 20 kHz. + +**Test without audio** (click it open) connects without capturing anything: +**Connect**, then move K1 to K4. Each knob stays where its slider was put +until **Disconnect**. It is how to tell a panel that does not react from a +tab that is not being heard. ## The mapping editor -**Editor ↗** in the popup opens the full editor in its own tab -(`editor.html`): every band is a box drawn on the live spectrum — its width -is the frequencies it listens to, its height the level window it maps — and -a response curve turns position-in-window into knob position. Curves come as -presets (rise, fall, gate, steps, arch) or hand-dragged beziers, and every -shape bakes to a 33-point table the analysis side just interpolates — the -same table the device firmware will consume, which is the point: the editor -module (`editor.js`) is adapter-isolated (`editor-adapter.js`) and ports to -the device console by swapping the adapter only. Auto range makes the boxes -breathe with the room; grabbing a breathing edge takes manual control. -Opened outside the extension (plain http), it runs a synthesized demo -source — the fast way to iterate on the editor itself. - -## Install for local testing - -1. Open `chrome://extensions`. -2. Enable **Developer mode**. -3. Click **Load unpacked**. -4. Select this folder: `tools/patternflow-audio-extension`. -5. Open a tab that is playing audio. -6. Click the Patternflow Audio extension button. -7. Set the device host to `patternflow.local` or the board IP address. -8. Press **Start**. -9. Ensure **Audio-React (AUD)** is switched ON on the device (at the top of the console's `/audio-in` page or via the panel's NETWORK screen). - -Use the extension for YouTube, Spotify Web, browser games, or any other tab -or system audio. The built-in `http://patternflow.local/` page remains useful -for microphone input and audio-file experiments, but browser tab/system capture -is often blocked there because the ESP32 serves normal HTTP. - -For WebSocket-only debugging, press **WS Test** instead of **Start** and move -the K1-K4 sliders. This bypasses tab capture and audio analysis completely. - -## Controls - -- `Spectrum`: live frequency strength display. Drag across it to set the active band's range. -- `Add Band`: starts with one band, then adds more bands as needed. -- `Output`: min/max Patternflow knob output from 0.0 to 1.0. -- `Clamp / gain`: optional input low/high clamp and sensitivity. -- `K`: target Patternflow knob index. -- `Smoothing`: global response smoothing. -- `WS Test`: connect to the device and send manual K1-K4 movements. - -The extension sends delta messages like `d=0,v=0.125` to `ws://:81`. +**Mapping editor ↗** opens the editor in a tab of its own. From the top: + +- **Auto range**, **Attack** and **Damping** hold for all four knobs. With + Auto range on, each box follows the loudness of what it hears; with it off, + each has the window you set by hand. Attack is how fast a knob rises to a + hit, Damping how slowly it falls back. +- **The plot** is the live spectrum with four boxes on it, K1 to K4. A box's + width is the frequencies that knob listens to; its height is the + quiet-to-loud range mapped onto it, in dB. Drag a box to move it and an edge + to resize it. The line across a box is where the level sits in it now. +- **K1 to K4**, the tabs under the plot, select a knob. K1 is always knob 1. +- **Preview**, at the end of that row, puts a scope where the plot is: a test + signal (kick pulses, a noisy room, a slow swell) run through the selected + knob's attack, damping, curve and output range, which all stay adjustable + around it. The same button closes it, and so does Esc. +- **The knob's card**: its **response curve** (Smooth, Sharp, Fall, Gate, + Steps, Arch, or drag the two handles for a shape of your own), its **output + range** (how far the knob travels) and **Mute** (the knob goes back to its + encoder). +- **Reset K1** puts the selected knob back to its default. + +Every edit saves itself and reaches a running capture at once. A new install +starts with Auto range on and the Smooth curve on all four knobs. Switching +Auto range off goes back to the windows you set by hand; dragging a top or +bottom edge while it is on switches it off and starts all four windows from +where the boxes are at that moment. + +The mapping is kept in this browser (`chrome.storage`), not on the panel. The +panel's own Audio page has the same editor for its on-board microphone, with a +mapping of its own that is stored on the panel. + +The bar at the top says what is feeding the editor, in the popup's words, and +where it is going, and has a Stop. Opened outside the extension the editor +runs on a synthesized demo source, which is the fast way to work on the +editor itself: + + python -m http.server 8000 --bind 127.0.0.1 --directory tools/patternflow-audio-extension + # http://127.0.0.1:8000/editor.html + +Nothing is captured there and nothing is kept. + +## What it sends + +To `ws://
                    :81` (a port typed with the address is used instead), one +text message per frame: + + a=0.412,0.300,-,0.871 + +Four knob values from 0 to 1, with a `-` for a muted knob. The analysis runs +30 times a second. A frame that has not changed is sent again about every +210 ms, because the panel hands a knob back to its encoder 500 ms after the +last message that set it. Muting a knob sends `off=N` once, and Stop sends +`off`. The test sliders use the same `a=` message. Measured against a loopback +socket: 23–26 messages a second on music, 5 a second on silence. + +It also asks the panel three things over HTTP, on port 80 of the same address. +Each is asked once, never polled, because the panel serves one connection at +a time: + +- `GET /api/audio` when the socket opens, and once more when the popup is + opened while it reads *Aud off*: is Audio-React on? +- `POST /api/audio` with `on=1`: the **Turn on** button. +- `GET /api/status` once when the socket will not open: is anything there, + and does it run the Audio edition? + +Builds before 0.2.0 sent the test sliders as `k=N,v=F`, and the first ones +sent `d=N,v=F` deltas. The firmware still takes both. + +## The files + +| File | What it is | +|---|---| +| `manifest.json` | The extension itself. Permissions: `tabCapture`, `offscreen`, `storage`, `activeTab`, and `http://*/*` with `ws://*/*` to reach a panel on the local network. | +| `popup.html` `.css` `.js` | The capture console. It owns the panel's address (`patternflowAudioHost` in `chrome.storage.local`) and asks Chrome for the tab's stream. | +| `background.js` | The service worker: creates the offscreen document and relays messages between it and the pages. | +| `offscreen.html` `.js` | Holds the capture, runs the analysis and the mapping, owns the socket, and is the one place that knows the state every page prints (`phase`). | +| `mapping.js` | The mapping model, one object, `PFMap`: the defaults, what a stored mapping is turned into, the curves, and the chain from a level to a knob value. The mapping is stored under `patternflowAudioConfig`. | +| `editor.html` `.css` `.js` | The mapping editor. `editor.js` reaches its source only through `window.PFAdapter`; the contract is the comment at its top. | +| `editor-adapter.js` | `PFAdapter` for the extension (storage, the capture's frames), the editor's source bar, and the demo source. | +| `icons/` | The Patternflow mark, as the web app has it. | ## This folder is also firmware source -The editor (`editor.html`, `editor.css`, `editor.js`, `editor-adapter.js`) is -the authoring source of the panel's own `/audio-in` console page: -`firmware/toolchain/build_audio_in_page.py` assembles -`firmware/patternflow/console/audio-in.html` from these files, and the -`console-sync` workflow fails a pull request in which the two have drifted. -Edit the editor here and rebuild the page; never edit the generated page, and -do not move this folder. +The panel's own `/audio-in` console page is this editor. +`firmware/toolchain/build_audio_in_page.py` assembles that page from two +places: + +- here: `editor.html` (what is between its two `EDITOR BODY` lines), + `editor.css` and `mapping.js` (what is above their `EXTENSION ONLY` line) + and all of `editor.js`; +- the panel's half, in `firmware/patternflow/console/`: `_audio_in_bar.html` + (the page around the editor), `_audio_in.css` (the console's look) and + `_audio_in_adapter.js` (`PFAdapter` over `/api/audio-in`). + +So an edit to one of those four files here changes the panel's page as well. +After one: + + python firmware/toolchain/console_serve.py # preview: /audio-in is assembled from the sources on every request + python firmware/toolchain/console_pages.py build # regenerate the page and the header the panel serves + +Never edit the generated `firmware/patternflow/console/audio-in.html` or +`firmware/patternflow/features/audio_in/audio_in_index.h`, and do not move +this folder: the builder and the `console-sync` workflow hold its path. CI +fails a pull request whose generated page is not what its sources assemble +to, or whose page is over its size budget (17.5 KB gzipped, as the panel sends +it). Every byte of the shared half crosses the panel's Wi-Fi, so what only +the extension needs goes below the `EXTENSION ONLY` lines or into +`editor-adapter.js`. That includes the cream skin: above its line +`editor.css` is layout, and each surface brings its own colours. The rest is +in [`firmware/patternflow/console/README.md`](../../firmware/patternflow/console/README.md#the-page-that-is-assembled-audio-in). -The larger controller ideas that used to be listed here as "next" — spectrum +The larger controller ideas that used to be listed here as "next" (spectrum and waveform views, drag-to-select bands, per-band curves, gates and -smoothing — shipped as the mapping editor above; what remains open is tracked +smoothing) shipped as the mapping editor above. What remains open is tracked in the repository's issues. diff --git a/tools/patternflow-audio-extension/background.js b/tools/patternflow-audio-extension/background.js index 9d3f303f..653eadb0 100644 --- a/tools/patternflow-audio-extension/background.js +++ b/tools/patternflow-audio-extension/background.js @@ -1,26 +1,49 @@ +// Patternflow Audio — service worker: a relay. +// +// The popup and the editor talk to this; the offscreen document does the work +// and owns the truth about it (offscreen.js: is a capture running, to which +// address, did the socket open, why did it end). Chrome puts this worker to +// sleep when it likes and wakes it with empty memory, so nothing is kept here +// that cannot be asked for again. `state` is a copy of the offscreen +// document's last word, there so a `status` request is answered without a +// round trip; after a wake it is fetched afresh before anyone is told it. + const OFFSCREEN_URL = 'offscreen.html'; -let state = { +const IDLE = { running: false, - connected: false, manual: false, + connected: false, + phase: 'idle', + host: '', tabTitle: '', - host: 'patternflow.local', error: '', + note: '', + panelAudio: null, + heard: false, + silent: false, + held: [], levels: [], + pos: [], outputs: [], - spectrum: [] + spectrum: [], + env: [], + autoRange: false }; -async function ensureOffscreen() { - const offscreenUrl = chrome.runtime.getURL(OFFSCREEN_URL); +let state = { ...IDLE }; +let heard = false; // from the offscreen document, since this worker last woke + +async function offscreenExists() { const contexts = await chrome.runtime.getContexts({ contextTypes: ['OFFSCREEN_DOCUMENT'], - documentUrls: [offscreenUrl] + documentUrls: [chrome.runtime.getURL(OFFSCREEN_URL)] }); + return contexts.length > 0; +} - if (contexts.length > 0) return; - +async function ensureOffscreen() { + if (await offscreenExists()) return; await chrome.offscreen.createDocument({ url: OFFSCREEN_URL, reasons: ['USER_MEDIA'], @@ -28,109 +51,76 @@ async function ensureOffscreen() { }); } +function toOffscreen(message) { + return chrome.runtime.sendMessage({ ...message, target: 'offscreen' }); +} + +function take(patch) { + if (!patch) return; + state = { ...state, ...patch }; + heard = true; +} + +// Make `state` worth telling. With no offscreen document nothing is running, +// whatever the copy says; after a wake the copy is empty and the document is +// asked. +async function refresh() { + if (!(await offscreenExists())) { + state = { ...IDLE }; + heard = true; + return; + } + if (heard) return; + const reply = await toOffscreen({ type: 'status' }).catch(() => null); + take(reply && reply.state); +} + function broadcast() { chrome.runtime.sendMessage({ type: 'state', state }).catch(() => {}); } +// What the popup and the editor may ask the offscreen document to do. The +// message goes through as it came. +const COMMANDS = ['start', 'manual-connect', 'host', 'config', 'manual-value', 'panel-on', 'panel-check', 'stop']; + chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { (async () => { - if (message.type === 'start') { - await ensureOffscreen(); - state = { - ...state, - running: true, - connected: false, - manual: false, - tabTitle: message.tabTitle || '', - host: message.config.host, - error: '' - }; - await chrome.runtime.sendMessage({ - target: 'offscreen', - type: 'start', - streamId: message.streamId, - config: message.config - }); - broadcast(); - sendResponse({ ok: true, state }); - return; - } - - if (message.type === 'manual-connect') { - await ensureOffscreen(); - state = { - ...state, - running: false, - connected: false, - manual: true, - tabTitle: '', - host: message.config.host, - error: '' - }; - await chrome.runtime.sendMessage({ - target: 'offscreen', - type: 'manual-connect', - config: message.config - }); - broadcast(); - sendResponse({ ok: true, state }); - return; - } - - if (message.type === 'manual-value') { - await chrome.runtime.sendMessage({ - target: 'offscreen', - type: 'manual-value', - knob: message.knob, - value: message.value - }).catch(() => {}); - sendResponse({ ok: true, state }); - return; - } - - if (message.type === 'stop') { - await chrome.runtime.sendMessage({ target: 'offscreen', type: 'stop' }).catch(() => {}); - state = { ...state, running: false, connected: false, manual: false, error: '' }; + if (message.type === 'offscreen-state') { + take(message.patch); broadcast(); - sendResponse({ ok: true, state }); + sendResponse({ ok: true }); return; } - if (message.type === 'config') { - state = { ...state, host: message.config.host }; - await chrome.runtime.sendMessage({ - target: 'offscreen', - type: 'config', - config: message.config - }).catch(() => {}); - broadcast(); + if (message.type === 'status') { + await refresh(); sendResponse({ ok: true, state }); return; } - if (message.type === 'release') { - await chrome.runtime.sendMessage({ target: 'offscreen', type: 'release' }).catch(() => {}); - sendResponse({ ok: true, state }); + if (!COMMANDS.includes(message.type)) { + sendResponse({ ok: false, error: 'Unknown message' }); return; } - if (message.type === 'status') { + // Only a start makes the document. Anything else with no document has + // nothing to act on: a mapping saved in the editor while nothing runs, a + // Stop pressed twice. + if (message.type === 'start' || message.type === 'manual-connect') { + await ensureOffscreen(); + } else if (!(await offscreenExists())) { + await refresh(); sendResponse({ ok: true, state }); return; } - if (message.type === 'offscreen-state') { - state = { ...state, ...message.patch }; - broadcast(); - sendResponse({ ok: true }); - return; - } - - sendResponse({ ok: false, error: 'Unknown message' }); - })().catch((error) => { - state = { ...state, running: false, connected: false, error: String(error.message || error) }; - broadcast(); - sendResponse({ ok: false, error: state.error, state }); + const reply = await toOffscreen(message); + if (!reply) throw new Error('The capture page did not answer.'); + take(reply.state); + if (message.type !== 'manual-value') broadcast(); + sendResponse({ ok: reply.ok !== false, error: reply.error, state }); + })().catch((failure) => { + sendResponse({ ok: false, error: String(failure.message || failure), state }); }); return true; diff --git a/tools/patternflow-audio-extension/editor-adapter.js b/tools/patternflow-audio-extension/editor-adapter.js index 4db7562c..32cce65f 100644 --- a/tools/patternflow-audio-extension/editor-adapter.js +++ b/tools/patternflow-audio-extension/editor-adapter.js @@ -1,68 +1,141 @@ // Patternflow Audio — editor adapter, extension flavor. // -// The editor module (editor.js) knows nothing about Chrome, the device, or -// where audio comes from: it talks to exactly this surface. Porting the -// editor to the device console means swapping THIS file for one that speaks -// fetch('/api/audio-in') — the module itself moves verbatim. That boundary is -// the whole architecture; do not let editor.js grow a chrome.* call. +// The editor module (editor.js) knows nothing about Chrome, the panel, or +// where audio comes from: it talks to exactly window.PFAdapter. The panel's +// /audio-in page is the same editor over another adapter +// (firmware/patternflow/console/_audio_in_adapter.js, which speaks +// fetch('/api/audio-in')). That boundary is the whole architecture; do not +// let editor.js grow a chrome.* call. The contract both adapters keep is +// written at the top of editor.js. // -// caps() -> { hzMin, hzMax } the source can actually analyze -// loadConfig() -> the shared config (host, autoRange, bands[4]) -// saveConfig(config) -> persist + hand to the live analysis -// onFrame(fn) -> fn({running, connected, levels, env, spectrum, ...}) -// requestStatus() -> ask for one immediate state push -// stop() -> stop capture +// This file is also the extension's SOURCE BAR: the
                    in editor.html +// (what is feeding the editor, where it is going, Stop). The editor never +// looks in there; every state that arrives is drawn here first and then +// handed on. // -// Without chrome.* (opened as a plain file) it runs a demo: synthesized -// music-ish spectrum, config in memory. That is a preview of the editor, not -// of the product — nothing persists and nothing is captured. +// Without chrome.* (opened as a plain file, or from a static server) it runs +// a demo: a synthesized music-ish spectrum mapped by the same model, the +// mapping kept in memory. That is a preview of the editor, not of the +// product: nothing persists and nothing is captured. (function () { const hasChrome = typeof chrome !== 'undefined' && chrome.storage && chrome.runtime; + const $ = (id) => document.getElementById(id); + + // What this source is: tab audio through an AnalyserNode. The numbers are + // the model's (PFMap.SOURCE), the two edge rules are its minimum window, and + // a band is never narrower than the 10 Hz the model keeps on load. + const CAPS = { + hzMin: PFMap.SOURCE.hzMin, + hzMax: PFMap.SOURCE.hzMax, + db: PFMap.SOURCE.db, + levelMax: 1, + hzGap: 10, + top: (lo) => lo + PFMap.MIN_WINDOW, + bottom: (hi) => hi - PFMap.MIN_WINDOW + }; + + // ── the source bar ──────────────────────────────────────────────────── + // + // The chip is the capture's own phase (offscreen.js phase()), in the same + // word the popup prints for it, so the two cannot disagree about whether + // the panel is being driven: a socket that is open to a panel whose + // Audio-React switch is off is not "live". Beside it, one sentence when + // there is something to do or something wrong: + // error the capture's own sentence, and both it and the chip in red + // aud off what is off and where its switch is (Turn on is the popup's) + // idle why the last capture ended, if it ended by itself (the tab + // was closed), then how to start one + // otherwise nothing: a capture or the popup's test connection is up, + // and "start a capture" is not what to say beside it + const WORDS = { connecting: 'connecting', off: 'aud off', live: 'live', test: 'test', error: 'error' }; + + function drawBar(state, idleHint) { + const chip = $('sourceChip'); + const hint = $('captureHint'); + const bad = state.phase === 'error'; + chip.textContent = state.demo ? 'demo source' : WORDS[state.phase] || 'idle'; + chip.className = state.phase === 'live' ? 'chip okChip' : bad ? 'chip badChip' : 'chip'; + // Where the capture is being sent, as the socket has it. Nothing is + // connected: no chip, rather than an address nothing is using. + $('hostChip').textContent = state.host || ''; + $('hostChip').hidden = !state.host; + hint.textContent = state.demo ? '' + : state.phase === 'off' ? 'Connected, but Audio-React is off on the panel. Turn it on in the extension popup.' + : state.error || (state.running || state.manual ? '' : (state.note ? state.note + ' ' : '') + idleHint); + hint.classList.toggle('badText', bad); + $('stopBtn').disabled = !state.running || !!state.demo; + } + + // An envelope that is at its minimum span has learned nothing: the band has + // been silent, or has sat at one level, for as long as an envelope + // remembers. The editor is told there is none (see `env` in its contract), + // so it draws the band's own window, and a drag that takes the four windows + // over by hand leaves that one as it was. Seeded from such an envelope it + // became a 4 dB sliver at the floor, and the first sound pegged that knob at + // its top. (A band that has heard a single click does have an envelope, and + // is seeded from it: this guards silence, not thinness.) + const learned = (env) => (env || []).map((e) => + e && e.hi - e.lo > PFMap.ENV_MIN_SPAN + 1e-6 ? e : null); if (hasChrome) { + const HINT = 'Start capture from the extension popup, on the tab that is playing.'; let frameFn = null; + + const take = (state) => { + state = state || {}; + drawBar(state, HINT); + if (frameFn) frameFn({ ...state, env: learned(state.env) }); + }; + const ask = () => chrome.runtime.sendMessage({ type: 'status' }, (response) => { + void chrome.runtime.lastError; + if (response && response.state) take(response.state); + }); + chrome.runtime.onMessage.addListener((message) => { - if (message.type === 'state' && frameFn) frameFn(message.state || {}); + if (message.type === 'state') take(message.state); + }); + $('stopBtn').addEventListener('click', () => { + chrome.runtime.sendMessage({ type: 'stop' }, () => void chrome.runtime.lastError); }); window.PFAdapter = { caps() { - return { hzMin: 20, hzMax: 20000 }; + return CAPS; }, loadConfig() { return new Promise((resolve) => - chrome.storage.local.get('patternflowAudioConfig', (stored) => - resolve(stored.patternflowAudioConfig || null))); + chrome.storage.local.get(PFMap.CONFIG_KEY, (stored) => + resolve(stored[PFMap.CONFIG_KEY] || null))); }, + // Stored, then told to the capture: that message is how a running + // capture gets the edit (nothing listens to storage). saveConfig(config) { return new Promise((resolve) => - chrome.storage.local.set({ patternflowAudioConfig: config }, () => { + chrome.storage.local.set({ [PFMap.CONFIG_KEY]: config }, () => { chrome.runtime.sendMessage({ type: 'config', config }, () => { void chrome.runtime.lastError; // background may be asleep; storage holds resolve(); }); })); }, + resetBand(index, config) { + config.bands[index] = PFMap.defaultBand(index, CAPS); + return this.saveConfig(config).then(() => config); + }, + // The editor is up: one state now, without waiting for the next push. onFrame(fn) { frameFn = fn; - }, - requestStatus() { - chrome.runtime.sendMessage({ type: 'status' }, (response) => { - void chrome.runtime.lastError; - if (response && response.state && frameFn) frameFn(response.state); - }); - }, - stop() { - chrome.runtime.sendMessage({ type: 'stop' }, () => void chrome.runtime.lastError); - }, - captureHint: 'Start capture from the extension popup, on the tab that is playing.' + ask(); + } }; + ask(); return; } // ── demo adapter ────────────────────────────────────────────────────── - let demoConfig = null; + const HINT = 'Demo mode — open this page from the extension for live audio.'; + let demoConfig = PFMap.normalizeConfig(null, CAPS); let frameFn = null; let t = 0; @@ -86,42 +159,45 @@ return values; } - const envLo = [1, 1, 1, 1]; - const envHi = [0, 0, 0, 0]; + // The same envelope and the same level-to-knob chain the capture runs + // (offscreen.js), so the demo's cursor and readout are the model's too. + const envelopes = [0, 1, 2, 3].map(() => PFMap.newEnvelope()); function demoFrame() { - if (!frameFn) return; const spectrum = demoSpectrum(); - const bands = (demoConfig && demoConfig.bands) || []; - const levels = bands.map((band) => { + const auto = demoConfig.autoRange; + const levels = [], pos = [], outputs = []; + demoConfig.bands.forEach((band, i) => { const lo = Math.log10(band.hzMin / 20) / 3 * 64; const hi = Math.log10(band.hzMax / 20) / 3 * 64; let sum = 0, n = 0; - for (let i = Math.max(0, Math.floor(lo)); i <= Math.min(63, Math.ceil(hi)); i++) { sum += spectrum[i]; n++; } - return n ? sum / n : 0; - }); - levels.forEach((v, i) => { - if (v > envHi[i]) envHi[i] = v; else envHi[i] += (v - envHi[i]) * 0.01; - if (v < envLo[i]) envLo[i] = v; else envLo[i] += (v - envLo[i]) * 0.01; - if (envHi[i] < envLo[i] + 0.06) envHi[i] = envLo[i] + 0.06; + for (let k = Math.max(0, Math.floor(lo)); k <= Math.min(63, Math.ceil(hi)); k++) { sum += spectrum[k]; n++; } + levels[i] = n ? sum / n : 0; + PFMap.trackEnvelope(envelopes[i], levels[i], 0.01); + pos[i] = PFMap.position(levels[i], band, auto ? envelopes[i] : null); + outputs[i] = PFMap.output(band, pos[i]); }); - frameFn({ + const state = { running: true, connected: false, demo: true, - levels, outputs: [], - spectrum, - env: demoConfig && demoConfig.autoRange ? envLo.map((lo, i) => ({ lo, hi: envHi[i] })) : [], - autoRange: !!(demoConfig && demoConfig.autoRange) - }); + levels, pos, outputs, spectrum, + env: auto ? learned(envelopes.map((e) => ({ lo: e.lo, hi: e.hi }))) : [], + autoRange: auto + }; + drawBar(state, HINT); + if (frameFn) frameFn(state); } window.PFAdapter = { - caps() { return { hzMin: 20, hzMax: 20000 }; }, - loadConfig() { return Promise.resolve(demoConfig); }, + caps() { return CAPS; }, + // Nothing is stored: the editor starts as a first run does. + loadConfig() { return Promise.resolve(null); }, saveConfig(config) { demoConfig = config; return Promise.resolve(); }, - onFrame(fn) { frameFn = fn; setInterval(demoFrame, 120); }, - requestStatus() { demoFrame(); }, - stop() {}, - captureHint: 'Demo mode — open this page from the extension for live audio.', - _setDemoConfig(config) { demoConfig = config; } + resetBand(index, config) { + config.bands[index] = PFMap.defaultBand(index, CAPS); + demoConfig = config; + return Promise.resolve(config); + }, + onFrame(fn) { frameFn = fn; demoFrame(); setInterval(demoFrame, 120); } }; + drawBar({ demo: true }, HINT); })(); diff --git a/tools/patternflow-audio-extension/editor.css b/tools/patternflow-audio-extension/editor.css index 8aa3e9fe..da75d6c4 100644 --- a/tools/patternflow-audio-extension/editor.css +++ b/tools/patternflow-audio-extension/editor.css @@ -1,27 +1,25 @@ -/* Patternflow Audio — mapping editor. Same cream instrument palette as the - popup (popup.css is the source of these values). */ -:root { - --cream: #f4efe6; - --cream-2: #ede7db; - --ink: #141414; - --muted: #6b655a; - --faint: #a69f90; - --rule: #d9d1c0; - --led: #e8552e; - --ok: #267a43; - --bad: #b43b2d; - --field: #fbf7ef; - --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; -} +/* Patternflow Audio — mapping editor. -* { box-sizing: border-box; } + Two parts. Down to the line that says EXTENSION ONLY these are the editor's + own rules, the same on every surface: the panel's /audio-in page takes + exactly that part (firmware/toolchain/build_audio_in_page.py stops reading + at the line) and brings its own colours and its own bar. Below the line is + what only the extension's page has: the cream instrument palette and the + source bar. Every colour above the line is a variable, so that works. -body { - margin: 0; - background: var(--cream); - color: var(--ink); - font: 12px/1.45 Inter, ui-sans-serif, system-ui, sans-serif; -} + Three things the part above the line leaves to the surface, because a + console page has them already and would carry them twice: the page itself + (body: margin, background, type), --mono, and that the hidden attribute + hides ([hidden] { display: none !important }: three of the editor's parts + are flex boxes that come and go by that attribute, and a display of their + own would otherwise keep them on screen). + + The layout rules are here too, and not in either surface's own sheet: the + editor is used in a full tab, in half a screen beside the tab that is + playing, and on a phone, and it has to hold in all three wherever it is + shown. Three steps: everything in a row; at 1100 px the output range drops + under the curve; at 700 px each row of controls becomes a column. */ +* { box-sizing: border-box; } .page { max-width: 1280px; @@ -34,89 +32,143 @@ body { .mono { font-family: var(--mono); } .dimText { color: var(--muted); } -.hint { font-size: 11px; color: var(--faint); } +.hint { font-size: 12px; color: var(--muted); } +.hint:empty { display: none; } .spacer { flex-grow: 1; } -/* ── header ── */ -header { display: flex; align-items: center; justify-content: space-between; gap: 12px; } -.brand { display: flex; align-items: center; gap: 9px; } -.led { width: 8px; height: 8px; background: var(--led); border-radius: 1px; } -.title { font-size: 14px; font-weight: 600; } -.kicker { font-family: var(--mono); font-size: 10px; letter-spacing: 0.09em; color: var(--muted); } -.cluster { display: flex; align-items: center; gap: 8px; } - -.chip { - border: 1px solid var(--rule); border-radius: 2px; background: var(--field); - padding: 5px 10px; font-family: var(--mono); font-size: 11px; color: var(--ink); -} -.chip.dim { color: var(--muted); } -.okChip { border-color: var(--ok); color: var(--ok); } - -.primaryBtn { - font: inherit; font-size: 12px; cursor: pointer; - border: 1px solid var(--ink); border-radius: 2px; - background: var(--ink); color: var(--cream); padding: 6px 14px; -} -.primaryBtn:disabled { opacity: 0.35; cursor: default; } .ghostBtn { font: inherit; font-size: 11px; cursor: pointer; border: 1px solid var(--rule); border-radius: 2px; background: var(--field); color: var(--muted); padding: 6px 12px; } -.ghostBtn:hover { border-color: var(--led); color: var(--led); } +.ghostBtn[aria-pressed=true] { border-color: var(--led); color: var(--ink); } +.ghostBtn.dan { color: var(--bad); } /* ── toolbar / toggles ── */ -.toolbar { display: flex; align-items: center; gap: 10px; } +/* The hint belongs to the switch and takes what the row has left; the two + glide sliders stay together and drop to a line of their own before the + hint is squeezed. */ +.toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; } +#autoHint { flex: 1 1 22em; } +.glide { display: flex; flex-wrap: wrap; gap: 10px 18px; } .damping { display: flex; align-items: center; gap: 8px; } .damping input { width: 130px; accent-color: var(--led); } -.damping .mono { font-size: 11px; min-width: 56px; text-align: right; } +.damping .mono { font-size: 11px; min-width: 56px; } .toggleWrap { - font: inherit; cursor: pointer; display: flex; align-items: center; gap: 7px; + font: inherit; color: inherit; cursor: pointer; display: flex; align-items: center; gap: 7px; border: 1px solid var(--ink); border-radius: 2px; background: var(--field); padding: 5px 11px; } .toggleLabel { font-size: 11px; font-weight: 500; } .toggle { width: 22px; height: 12px; background: var(--rule); border-radius: 7px; - position: relative; display: inline-block; border: 0; cursor: pointer; padding: 0; - flex: none; + position: relative; flex: none; pointer-events: none; } -.toggle .dotK, .toggleWrap .dotK { +.dotK { position: absolute; left: 1px; top: 1px; width: 10px; height: 10px; background: var(--field); border-radius: 50%; transition: left 0.12s; } -.toggleWrap .toggle { pointer-events: none; } .toggleWrap.on .toggle { background: var(--ok); } .toggleWrap.on .dotK { left: 11px; } -.toggle.small.on { background: var(--ok); } -.toggle.small.on .dotK { left: 11px; } +/* Mute is the same switch as Auto range, the whole button its target; in its + column it is as wide as its words, not as the column. */ +#muteToggle { align-self: flex-start; } /* ── main plot ── */ +/* Clipped: the canvas, and the Preview layer that lies exactly over it, are + square, and a surface may round this box's corners; and a tag has no place + of its own until editor.js gives it one (until then it is below the canvas, + out of the box). Isolated: what is stacked in here (the selected tag over + its neighbours, Preview over them all) is stacked against nothing outside + it. */ .plotWrap { - position: relative; background: var(--field); - border: 1px solid var(--rule); border-radius: 2px; + position: relative; isolation: isolate; background: var(--field); + border: 1px solid var(--rule); border-radius: 2px; overflow: hidden; } -#plot { display: block; cursor: default; touch-action: none; } +/* No touch-action here or on #curve, on purpose. A finger that lands on a box + or a handle drags it and one that misses scrolls the page, and that is + decided per touch, by editor.js, in a touchstart listener. touch-action is + per element: `none` trapped every swipe that began on the plot, and `pan-y` + would hand the browser the vertical drag of a box's top or bottom edge. + + EVERY CANVAS HAS ITS BOX HERE, not from editor.js: the plot, the curve + (#curve) and the three kinds of glyph. A canvas is 300 x 150 until somebody + says otherwise, and editor.js says nothing until the mapping has been read, + which on the panel's own hotspot is seconds after the first paint: sized + there, the page came up with a 150 px plot and 131 px tabs and then jumped. + The plot is as wide as the page and 45% of the window tall, between 240 and + 400 px, so the plot, the knobs and the top of the card share one screen (a + phone gets 260 at the most: see the 700 px step). editor.js only makes the + pixels for the box it finds. */ +#plot { display: block; cursor: default; width: 100%; height: clamp(240px, 45vh, 400px); } +.tag canvas, .chipCard canvas { width: 18px; height: 12px; } .tag { position: absolute; display: flex; align-items: center; gap: 6px; background: var(--cream-2); border: 1px solid var(--rule); border-radius: 2px; - padding: 2px 7px; pointer-events: none; + padding: 2px 7px; pointer-events: none; white-space: nowrap; } -.tag.sel { border-color: var(--led); } +.tag.sel { border-color: var(--led); z-index: 1; } +/* A muted knob's tag says so, in the room its curve glyph took. */ .tag.mutedTag { opacity: 0.55; } +.mutedTag canvas { display: none; } .tagText { font-family: var(--mono); font-size: 10px; } -/* ── curve panel ── */ +/* ── preview: the scope, in the plot's place while it runs ── */ +.pv { + position: absolute; inset: 0; z-index: 2; display: flex; flex-direction: column; + background: var(--field); +} +.pvHead { + display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; + gap: 8px 14px; padding: 10px 12px; +} +.pvChips { display: flex; flex-wrap: wrap; gap: 8px; } +.pvSig { + font: inherit; font-size: 11px; cursor: pointer; + border: 1px solid var(--rule); border-radius: 2px; + background: var(--field); color: var(--ink); padding: 5px 11px; +} +.pvSig.on { border-color: var(--led); font-weight: 600; } +/* Sized by the column it is in, never by a style of its own: editor.js reads + the box it was given and draws to that. */ +#pvScope { display: block; flex: 1 1 0; min-height: 0; width: 100%; } +.pvLegend { display: flex; gap: 7px; align-items: center; } +.pvKeyIn, .pvKeyOut { width: 16px; height: 3px; display: inline-block; } +.pvKeyIn { background: var(--faint); } +.pvKeyOut { background: var(--led); } + +/* ── the knobs, as tabs under the plot ── */ +.knobRow { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; } +.chips { display: flex; gap: 8px; flex: 1 1 auto; } +.chipCard { + font: inherit; color: inherit; cursor: pointer; + display: flex; align-items: center; gap: 8px; + background: var(--field); border: 1px solid var(--rule); border-radius: 2px; + padding: 7px 12px; +} +.chipCard.sel { border-color: var(--led); } +.chipCard.sel .chipName { font-weight: 600; } +.chipCard.mutedChip { opacity: 0.55; } +.chipDot { width: 6px; height: 6px; background: var(--led); border-radius: 1px; } +.chipCard .mono { font-size: 11px; } + +/* ── the selected knob's card ── */ .panel { - display: flex; gap: 20px; background: var(--field); + display: flex; flex-wrap: wrap; gap: 14px 20px; background: var(--field); border: 1px solid var(--rule); border-radius: 2px; padding: 16px 18px; } -.col { display: flex; flex-direction: column; gap: 8px; } -.col.grow { flex-grow: 1; gap: 12px; } +.bandHead { flex: 0 0 100%; display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; } +.bandName { font-size: 13px; font-weight: 600; white-space: nowrap; } +.col { display: flex; flex-direction: column; gap: 8px; min-width: 0; } +.col.grow { flex: 1 1 0; gap: 12px; } +.curveCol { flex: none; } .colKicker { font-family: var(--mono); font-size: 10px; letter-spacing: 0.09em; color: var(--muted); } .vr { width: 1px; background: var(--rule); } -#curve { display: block; touch-action: none; } +/* The curve, and its shapes beside it while there is room for both. The + curve is 356 px wide where it has that, its row's width where it has not. */ +.curveRow { display: flex; flex-wrap: wrap; gap: 12px 20px; } +#curve { display: block; flex: none; width: 356px; max-width: 100%; height: 218px; } -.presetsCol { width: 268px; } +.presetsCol { width: 268px; flex: none; display: flex; flex-direction: column; gap: 8px; } .presetGrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; } .preset { font: inherit; cursor: pointer; @@ -124,85 +176,158 @@ header { display: flex; align-items: center; justify-content: space-between; gap border: 1px solid var(--rule); border-radius: 2px; background: var(--cream); padding: 9px 4px 7px; } +.preset canvas { width: 40px; height: 24px; } .preset span { font-size: 10px; font-weight: 500; color: var(--ink); } .preset.on { border-color: var(--led); } .preset.on span { font-weight: 600; } .stepsRow { display: flex; align-items: center; gap: 7px; font-size: 11px; color: var(--muted); } -.stepsRow[hidden] { display: none; } +/* Minus and plus, at 32 px: the size of a small button on the panel's + console, and a finger's. (The extension keeps its instrument's smaller + ones: below the line.) */ .stepsRow button { - font: inherit; cursor: pointer; width: 18px; height: 18px; padding: 0; line-height: 1; + font: inherit; cursor: pointer; width: 32px; height: 32px; padding: 0; line-height: 1; border: 1px solid var(--rule); border-radius: 2px; background: var(--cream); color: var(--ink); } -/* ── settings column ── */ -.bandHead { display: flex; align-items: baseline; gap: 8px; } -.bandName { font-size: 13px; font-weight: 600; white-space: nowrap; } .field { display: flex; flex-direction: column; gap: 6px; } .fieldRow { display: flex; align-items: center; justify-content: space-between; gap: 8px; } .fieldLabel { font-size: 11px; color: var(--muted); } -.seg { display: flex; } -.knobBtn { - font: inherit; font-family: var(--mono); font-size: 11px; cursor: pointer; - border: 1px solid var(--rule); background: var(--cream); color: var(--muted); - padding: 6px 14px; border-left-width: 0; -} -.knobBtn:first-child { border-left-width: 1px; border-radius: 2px 0 0 2px; } -.knobBtn:last-child { border-radius: 0 2px 2px 0; } -.knobBtn.on { border-color: var(--ink); background: var(--ink); color: var(--cream); } - -.outTrack { position: relative; height: 18px; cursor: pointer; touch-action: none; } -.outRail { position: absolute; left: 4px; right: 4px; top: 8px; height: 2px; background: var(--rule); } -.outFill { position: absolute; top: 7.5px; height: 3px; background: var(--led); } +/* A sideways drag is the track's, an up-and-down one is the page's. */ +.outTrack { position: relative; height: 18px; cursor: pointer; touch-action: pan-y; } +.outRail { position: absolute; left: 5px; right: 5px; top: 50%; height: 2px; margin-top: -1px; background: var(--rule); } +.outFill { position: absolute; top: 50%; height: 3px; margin-top: -1.5px; background: var(--led); } .outHandle { - position: absolute; top: 4px; width: 9px; height: 10px; + position: absolute; top: 50%; width: 9px; height: 10px; margin: -5px 0 0 -4.5px; background: var(--field); border: 1px solid var(--ink); } - -/* ── footer chips ── */ -.chips { display: flex; align-items: center; gap: 8px; } -.chipCard { - font: inherit; cursor: pointer; - display: flex; align-items: center; gap: 8px; - background: var(--field); border: 1px solid var(--rule); border-radius: 2px; - padding: 7px 12px; -} -.chipCard.sel { border-color: var(--led); } -.chipCard.mutedChip { opacity: 0.55; } -.chipDot { width: 6px; height: 6px; background: var(--led); border-radius: 1px; } -.chipCard .mono { font-size: 11px; } -.arrow { font-size: 10px; color: var(--faint); } - -/* ── output presets + preview ── */ -.outPresets { display: flex; gap: 6px; } +.outPresets { display: flex; flex-wrap: wrap; gap: 6px; } .outPreset { font: inherit; font-size: 10px; cursor: pointer; border: 1px solid var(--rule); border-radius: 2px; background: var(--cream); color: var(--muted); padding: 3px 8px; } -.outPreset:hover { border-color: var(--led); color: var(--led); } -.pvOverlay { - position: fixed; inset: 0; z-index: 50; - background: rgba(20, 20, 20, 0.45); - display: flex; align-items: center; justify-content: center; +/* ── the resets, at the foot ── */ +.acts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; } + +/* The editor body has no box of its own: its parts are laid out by .page. + Until editor.js has the mapping it is inert, and looks it. + + And until the FIRST mapping is in, the page says nothing it does not know: + no switch position, no slider thumb, no output handles, and the toolbar's + hint keeps its lines without showing its words. Everything keeps its box, + so nothing moves when the mapping arrives. That state is `inert="inert"`, + as editor.html writes it; a source that makes the editor inert again later + (the panel's adapter, around a reset) sets the property, which leaves the + attribute empty, so what is on screen then stays on screen. */ +#ed { display: contents; } +#ed[inert] > * { opacity: 0.5; } +#ed[inert=inert] :is(.toggle, input, .outHandle, .hint) { visibility: hidden; } + +/* ── narrower than a full tab ── */ +/* Half a screen: the output range goes under the curve, across the card. The + shapes stay beside the curve for as long as both fit, then wrap under it. */ +@media (max-width: 1100px) { + .vr { display: none; } + .curveCol, .col.grow { flex: 1 1 100%; } + .presetsCol { flex: 1 1 200px; width: auto; } } -.pvOverlay[hidden] { display: none; } -.pvCard { - background: var(--cream); border: 1px solid var(--ink); border-radius: 3px; - padding: 18px; display: flex; flex-direction: column; gap: 12px; - width: 640px; max-width: 94vw; +/* A phone: a 16 px gutter all round (never edge to edge: the gutter is where + a thumb scrolls from), one control to a row, the knobs four across. */ +@media (max-width: 700px) { + .page { padding: 16px; gap: 12px; } + #plot { max-height: 260px; } + .panel { padding: 14px 12px; } + .glide, .damping { flex: 1 1 100%; } + .damping .fieldLabel { min-width: 56px; } + .damping input { flex: 1; width: auto; min-width: 0; } + .chips { flex-basis: 100%; gap: 6px; } + .chipCard { flex: 1 1 0; min-width: 0; flex-direction: column; gap: 0; padding: 6px 2px; } + .chipDot, .chipCard canvas { display: none; } + #openPreview { margin-left: auto; } } -.pvHead { display: flex; justify-content: space-between; align-items: center; } -.pvChips { display: flex; gap: 8px; } -.pvSig { - font: inherit; font-size: 11px; cursor: pointer; - border: 1px solid var(--rule); border-radius: 2px; - background: var(--field); color: var(--ink); padding: 5px 11px; +/* Touch: what a finger drags is drawn larger, and what it presses gets a hit + area that grows invisibly while the control keeps its size. */ +@media (pointer: coarse) { + .outTrack { height: 36px; } + .outHandle { width: 16px; height: 22px; margin: -11px 0 0 -8px; } + .damping input { min-height: 32px; } + :is(.toggleWrap, .ghostBtn, .pvSig, .chipCard, .outPreset, .stepsRow button) { position: relative; } + :is(.toggleWrap, .ghostBtn, .pvSig, .chipCard, .outPreset, .stepsRow button)::after { + content: ""; + position: absolute; inset: -8px -2px; + } } -.pvSig.on { border-color: var(--led); font-weight: 600; } -#pvScope { display: block; background: var(--field); border: 1px solid var(--rule); } -.pvLegend { display: flex; gap: 7px; align-items: center; } -.pvKeyIn, .pvKeyOut { width: 16px; height: 3px; display: inline-block; } -.pvKeyIn { background: var(--faint); } -.pvKeyOut { background: var(--led); } + +/* ── EXTENSION ONLY ── */ + +/* The page itself and its type: a surface's own. The panel's /audio-in is a + console page and brings the console's (console/_audio_in.css), and with it + the rule that hidden means hidden. */ +[hidden] { display: none !important; } +/* Keyboard focus, as the popup has it: the browser's own ring is near black, + and on the filled Stop that is black on black. (The console's base block + has the same rule for the panel's page.) */ +:focus-visible { outline: 2px solid var(--led); outline-offset: 2px; } +body { + margin: 0; + background: var(--cream); + color: var(--ink); + font: 12px/1.45 Inter, ui-sans-serif, system-ui, sans-serif; +} + +/* The cream instrument palette, the same as the popup's (popup.css). */ +:root { + --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + --cream: #f4efe6; + --cream-2: #ede7db; + --ink: #141414; + --muted: #6b655a; + --faint: #a69f90; + --rule: #d9d1c0; + --led: #e8552e; + --ok: #267a43; + --bad: #b43b2d; + --field: #fbf7ef; +} + +/* The instrument's small capitals, on the two headings inside the card, and + its small steppers. */ +.colKicker { text-transform: uppercase; } +.stepsRow button { width: 18px; height: 18px; } + +/* A button under the mouse goes orange here. (On the panel orange is for what + is selected or on, never a hover, so this is not the shared part's to say.) + :where keeps it weaker than a button's own state: a pressed Preview stays + ink, as it did when this rule stood above the pressed one. */ +:where(.ghostBtn, .outPreset):hover { border-color: var(--led); color: var(--led); } + +/* ── the source bar ── */ +header { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; } +.brand { display: flex; align-items: center; gap: 9px; } +.led { width: 8px; height: 8px; background: var(--led); border-radius: 1px; } +.title { font-size: 14px; font-weight: 600; white-space: nowrap; } +.kicker { font-family: var(--mono); font-size: 10px; letter-spacing: 0.09em; color: var(--muted); } +.cluster { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; } + +.chip { + border: 1px solid var(--rule); border-radius: 2px; background: var(--field); + padding: 5px 10px; font-family: var(--mono); font-size: 11px; color: var(--ink); + white-space: nowrap; +} +.chip.dim { color: var(--muted); } +.okChip { border-color: var(--ok); color: var(--ok); } +/* An error looks like one: the chip, and the sentence beside it. */ +.badChip { border-color: var(--bad); color: var(--bad); } +.badText { color: var(--bad); } + +/* Stop is the popup's Stop: the same filled button, in the instrument's small + capitals. */ +.primaryBtn { + font: inherit; font-family: var(--mono); font-size: 10px; letter-spacing: .1em; + text-transform: uppercase; cursor: pointer; min-height: 32px; + border: 1px solid var(--ink); border-radius: 0; + background: var(--ink); color: var(--cream); padding: 0 14px; +} +.primaryBtn:disabled { opacity: 0.35; cursor: default; } diff --git a/tools/patternflow-audio-extension/editor.html b/tools/patternflow-audio-extension/editor.html index 5fb9e676..a8a299b9 100644 --- a/tools/patternflow-audio-extension/editor.html +++ b/tools/patternflow-audio-extension/editor.html @@ -2,12 +2,17 @@ + Patternflow Audio — Mapping
                    +
                    @@ -17,78 +22,125 @@
                    idle - patternflow.local:81 +
                    + + +
                    +
                    - - - -
                    - Attack - - quick -
                    -
                    - Damping - - balanced + Each box follows the loudness of what it hears. Drag a top or bottom edge to take all four over by hand. +
                    +
                    + + + +
                    +
                    + + + +
                    -
                    +
                    -
                    B1·K1
                    -
                    B2·K2
                    -
                    B3·K3
                    -
                    B4·K4
                    +
                    K1
                    +
                    K2
                    +
                    K3
                    +
                    K4
                    + +
                    + + +
                    +
                    + + + + +
                    +
                    -
                    - RESPONSE - +
                    + Knob 1 +
                    -
                    - CURVE -
                    - - - - - - -
                    - - - + diff --git a/tools/patternflow-audio-extension/editor.js b/tools/patternflow-audio-extension/editor.js index d815e02f..6cd2030c 100644 --- a/tools/patternflow-audio-extension/editor.js +++ b/tools/patternflow-audio-extension/editor.js @@ -1,137 +1,142 @@ // Patternflow Audio — the mapping editor. // -// One module, no chrome.* and no fetch: everything outside this file arrives -// through window.PFAdapter (editor-adapter.js). The console port copies this -// file verbatim and swaps the adapter. +// One module, no chrome.* and no fetch. It stands on two things: +// +// PFMap (mapping.js) the model: defaults, what a stored mapping is turned +// into, the curves, the level-to-knob chain. +// window.PFAdapter the SOURCE: the extension's is editor-adapter.js, the +// panel's is console/_audio_in_adapter.js. This file +// moves to the panel verbatim; only the adapter differs. // // The model, in one sentence: a band is a BOX drawn on the live spectrum // (width = the frequencies it listens to, height = the level window it maps), // and a RESPONSE CURVE that turns position-in-window into position-in-output- // range. Curves bake to a 33-point table on save; the analysis side — and -// later the firmware — only interpolates, and never learns what a bezier is. +// the firmware — only interpolates, and never learns what a bezier is. +// +// THE ADAPTER CONTRACT. The source owns its limits, its axis, its defaults +// and where a level sits in a window; the editor draws what it is told and +// asks rather than assumes. +// +// loadConfig() -> Promise +// { autoRange, smoothing, attack, bands[4] }, each band { hzMin, hzMax, +// inMin, inMax, gain, outMin, outMax, muted, curve, lut }. Levels are +// 0..1 along the source's own level axis. null means NOTHING IS STORED +// (a first run): the editor then starts from PFMap's defaults. A source +// that could not read must not answer null - it keeps the promise open +// until it can; the editor stays inert meanwhile. +// caps() -> asked once, after loadConfig() has settled +// hzMin, hzMax the ends of the frequency axis +// db [bottom, top]: the dB at 0 and at 1 of the level axis +// levelMax the highest a window's top edge is stored, 0..1 +// hzGap the narrowest band the source stores, in Hz +// top(lo) the lowest top edge it stores over a bottom at `lo` +// bottom(hi) the highest bottom edge it stores under a top at `hi` +// Only hzMin and hzMax are required; the rest default to an axis with no +// dB printed on it, the whole axis, and PFMap.MIN_WINDOW. +// saveConfig(config) -> Promise store it and hand it to what is mapping +// resetBand(i, config) -> Promise +// band i back to the SOURCE's default. Answers the whole mapping as it +// now stands (as loadConfig would); the editor takes that and does not +// save it back. +// resetAll(button) optional: the source's own "reset everything", where it +// has one. The editor then shows Reset mapping beside +// the knob's own Reset and calls this with the button +// pressed (for PFConfirm); what comes back goes in +// through onConfig. A source without it has no such +// button. +// onConfig(fn) optional: fn(config) replaces the editor's copy without +// saving it (after a reset the source did by itself) +// onFrame(fn) fn(frame), about ten times a second while there is +// something to show. Called once, when the editor is up. +// levels[4] each band's level, 0..1 on the level axis. Empty or +// missing = nothing is being heard: no level line, no +// cursor. +// spectrum[64] log-spaced over hzMin..hzMax, same axis +// env[4] { lo, hi } per band while auto range has a learned +// envelope; missing, or null for that band, otherwise +// (the stored window is drawn, dashed). "Learned" is +// the source's to say: what a band has while it has +// heard nothing is not an envelope and is not sent, for +// a drag that takes the windows over by hand seeds each +// window from what is sent here. +// pos[4] where each level sits in its window, 0..1, AS THE +// MAPPER COMPUTED IT: the curve's input +// outputs[4] what each knob is being sent +// db optional [bottom, top] when this frame's levels are on +// another axis than caps().db (the phone app's) +// pos and outputs are what make the cursor and the readout true. A frame +// without them (one the source did not map itself) gets the editor's own +// arithmetic: PFMap.position / PFMap.output on the frame's levels. 'use strict'; const A = window.PFAdapter; - -// ── config ────────────────────────────────────────────────────────────── - -const HZ_DEFAULTS = [[60, 250], [250, 2000], [2000, 5000], [5000, 16000]]; -const LUT_POINTS = 33; - -const PRESETS = { - smooth: { label: 'Smooth', curve: { type: 'bezier', id: 'smooth', y0: 0, y1: 1, p1x: 0.45, p1y: 0.05, p2x: 0.55, p2y: 0.95 } }, - sharp: { label: 'Sharp', curve: { type: 'bezier', id: 'sharp', y0: 0, y1: 1, p1x: 0.10, p1y: 0.65, p2x: 0.35, p2y: 1.00 } }, - fall: { label: 'Fall', curve: { type: 'bezier', id: 'fall', y0: 1, y1: 0, p1x: 0.45, p1y: 0.95, p2x: 0.55, p2y: 0.05 } }, - gate: { label: 'Gate', curve: { type: 'steps', id: 'gate', n: 2 } }, - steps: { label: 'Steps', curve: { type: 'steps', id: 'steps', n: 3 } }, - arch: { label: 'Arch', curve: { type: 'arch', id: 'arch' } } -}; - -const clamp01 = (v) => Math.max(0, Math.min(1, Number(v) || 0)); -const clampHz = (v) => Math.max(CAPS.hzMin, Math.min(CAPS.hzMax, Number(v) || CAPS.hzMin)); - -const CAPS = A.caps(); - -function defaultBand(index) { - const [hzMin, hzMax] = HZ_DEFAULTS[index % HZ_DEFAULTS.length]; - return { - hzMin, hzMax, - knob: Math.min(index, 3), muted: false, - inMin: 0, inMax: 1, gain: 1, - outMin: 0.30, outMax: 0.85, - curve: null, lut: null - }; -} - -function normalizeBand(raw, index) { - const band = { ...defaultBand(index), ...(raw || {}) }; - band.hzMin = clampHz(band.hzMin); band.hzMax = clampHz(band.hzMax); - if (band.hzMin > band.hzMax) [band.hzMin, band.hzMax] = [band.hzMax, band.hzMin]; - if (band.hzMax - band.hzMin < 10) band.hzMax = Math.min(CAPS.hzMax, band.hzMin + 10); - band.inMin = clamp01(band.inMin); band.inMax = clamp01(band.inMax); - if (band.inMax - band.inMin < 0.02) band.inMax = Math.min(1, band.inMin + 0.02); - band.outMin = clamp01(band.outMin); band.outMax = clamp01(band.outMax); - if (band.outMax - band.outMin < 0.05) band.outMax = Math.min(1, band.outMin + 0.05); - // Four bands, four knobs, one line between them: band i drives knob i. - // A free assignment existed and earned nothing but a control to explain. - band.knob = index; - band.muted = band.muted === true; - band.gain = Math.max(0.2, Math.min(4, Number(band.gain) || 1)); - if (band.curve && typeof band.curve !== 'object') band.curve = null; - if (band.lut && (!Array.isArray(band.lut) || band.lut.length < 2)) band.lut = null; - return band; -} - -function normalizeConfig(raw) { - const stored = Array.isArray(raw && raw.bands) ? raw.bands : []; - const bands = []; - for (let i = 0; i < 4; i++) bands.push(normalizeBand(stored[i], i)); - return { - host: (raw && raw.host) || 'patternflow.local', - smoothing: (raw && raw.smoothing) || 0.35, - sendIntervalMs: (raw && raw.sendIntervalMs) || 33, - autoRange: !!(raw && raw.autoRange), - attack: Math.max(0.05, Math.min(0.9, Number(raw && raw.attack) || 0.65)), - bands, - ...(raw && raw.manualExtra ? { manualExtra: raw.manualExtra } : {}) +const { clamp01, PRESETS, evalCurve, bakeLut } = PFMap; + +// What the source says about itself. Read once the mapping is in (the panel +// learns its frequency range from the same reply), so nothing above init() +// may use it at load. +let CAPS = null; +let DECADES = 1; +let TICKS = []; + +function readCaps() { + const c = A.caps(); + CAPS = { + hzMin: c.hzMin, hzMax: c.hzMax, + db: c.db || null, + levelMax: c.levelMax || 1, + hzGap: c.hzGap || 0, + top: c.top || ((lo) => lo + PFMap.MIN_WINDOW), + bottom: c.bottom || ((hi) => hi - PFMap.MIN_WINDOW) }; + DECADES = Math.log10(CAPS.hzMax / CAPS.hzMin); + // Inner gridlines only — the endpoints are drawn from CAPS, so the same + // axis code serves the extension's 20–20k and the microphone's 31–8k. + TICKS = [[50, '50'], [100, '100'], [200, '200'], [500, '500'], + [1000, '1k'], [2000, '2k'], [5000, '5k'], [10000, '10k']] + .filter(([hz]) => hz > CAPS.hzMin * 1.15 && hz < CAPS.hzMax * 0.87); } -// ── curve engine ──────────────────────────────────────────────────────── - -function evalCurve(curve, u) { - u = clamp01(u); - if (!curve) return u; - if (curve.type === 'steps') { - const n = Math.max(2, Math.min(8, Math.round(curve.n) || 2)); - const k = Math.min(n - 1, Math.floor(u * n)); - return k / (n - 1); - } - if (curve.type === 'arch') return Math.sin(Math.PI * u); - if (curve.type === 'bezier') { - // Cubic from (0, y0) to (1, y1); x(t) is monotone while both control xs - // stay in [0,1], so a short bisection recovers t for any u. - const { y0 = 0, y1 = 1, p1x, p1y, p2x, p2y } = curve; - const bx = (t) => 3 * (1 - t) * (1 - t) * t * p1x + 3 * (1 - t) * t * t * p2x + t * t * t; - const by = (t) => (1 - t) * (1 - t) * (1 - t) * y0 + 3 * (1 - t) * (1 - t) * t * p1y + 3 * (1 - t) * t * t * p2y + t * t * t * y1; - let lo = 0, hi = 1; - for (let i = 0; i < 24; i++) { - const mid = (lo + hi) / 2; - if (bx(mid) < u) lo = mid; else hi = mid; - } - return clamp01(by((lo + hi) / 2)); - } - return u; -} - -function legacyCurve(band, u) { - return Math.pow(clamp01(u), 1 / band.gain); -} +const clampHz = (v) => Math.max(CAPS.hzMin, Math.min(CAPS.hzMax, Number(v) || CAPS.hzMin)); +// What the editor DRAWS: the curve itself where there is one (a table would +// round a step's corner), the model's answer otherwise. function bandCurveValue(band, u) { - return band.curve ? evalCurve(band.curve, u) : legacyCurve(band, u); -} - -function bakeLut(curve) { - const lut = []; - for (let i = 0; i < LUT_POINTS; i++) { - lut.push(Number(evalCurve(curve, i / (LUT_POINTS - 1)).toFixed(4))); - } - return lut; + return band.curve ? evalCurve(band.curve, u) : PFMap.curveValue(band, u); } // ── state ─────────────────────────────────────────────────────────────── -let cfg = normalizeConfig(null); +// The mapping being edited (null until init() has it), and the knob selected. +let cfg = null; let sel = 0; -let frame = { levels: [], env: [], spectrum: [], running: false, connected: false }; -let lastEnv = null; // most recent non-empty env, for the auto→manual handoff -let saveTimer = null; +let frame = {}; +let saveTimer = 0; +// Every edit saves itself, 150 ms after the last one of a burst. function persist() { clearTimeout(saveTimer); - saveTimer = setTimeout(() => A.saveConfig(cfg), 150); + saveTimer = setTimeout(flush, 150); +} + +// Save now what is waiting to be saved. Also on the way out of the page, so +// an edit made in the last 150 ms is not left behind. +function flush() { + if (!saveTimer) return null; + clearTimeout(saveTimer); + saveTimer = 0; + return A.saveConfig(cfg); +} +window.addEventListener('pagehide', flush); + +// The source's copy replaces the editor's: after a reset. Not saved back. +function applyConfig(raw) { + cfg = PFMap.normalizeConfig(raw, CAPS); + syncAutoToggle(); + syncDamping(); + selectBand(sel); } function touchCurve(band, curve) { @@ -144,69 +149,132 @@ function touchCurve(band, curve) { const $ = (id) => document.getElementById(id); const plotCanvas = $('plot'); const pctx = plotCanvas.getContext('2d'); -const M = { l: 48, r: 6, t: 22, b: 40 }; -let PW = 0, PH = 0; // plot area, css px - +const M = { l: 48, r: 6, t: 26, b: 40 }; +// The plot area inside those margins, css px. +let PW = 0, PH = 0; + +// A finger, not a mouse: what it has to land on is made larger, here and in +// the stylesheet. EDGE is how far from a box's edge still grabs it, GRIP the +// square drawn on a corner or a curve handle, REACH how far from a curve +// handle still grabs that. +const COARSE = matchMedia('(pointer: coarse)').matches; +const EDGE = COARSE ? 18 : 7; +const GRIP = COARSE ? 11 : 7; +const REACH = COARSE ? 22 : 12; + +// What the toolbar says beside the Auto range switch, in each of its two +// states (syncAutoToggle). The first, as a mouse has it, is also written in +// editor.html in the hint's own place: unseen until the mapping is in, and +// there so that its lines are already taken and the plot under it does not +// move when the words arrive. +const HINT_AUTO = 'Each box follows the loudness of what it hears. ' + + (COARSE ? 'Switch Auto range off to set a height by hand.' : 'Drag a top or bottom edge to take all four over by hand.'); +const HINT_HAND = 'Width: the frequencies a knob listens to. Height: the quiet-to-loud range mapped onto it.'; + +// The plot's box is the stylesheet's (#plot in editor.css: as wide as the +// page, 45% of the window tall between 240 and 400 px, 260 at the most at the +// phone width), so it has its size before this file has run and nothing below +// it moves when the mapping arrives. That is the one rule for its height +// (Preview's scope is the same box). Here the height is only snapped to a +// whole pixel, so the canvas is not resampled, and the pixels are made. function sizePlot() { - const wrap = $('plotWrap'); - const cssW = wrap.clientWidth; - const cssH = 400; + plotCanvas.style.height = ''; + const cssW = plotCanvas.clientWidth, cssH = plotCanvas.clientHeight; const dpr = window.devicePixelRatio || 1; plotCanvas.width = Math.round(cssW * dpr); plotCanvas.height = Math.round(cssH * dpr); - plotCanvas.style.width = cssW + 'px'; plotCanvas.style.height = cssH + 'px'; pctx.setTransform(dpr, 0, 0, dpr, 0, 0); PW = cssW - M.l - M.r; PH = cssH - M.t - M.b; } -const DECADES = Math.log10(CAPS.hzMax / CAPS.hzMin); const xOf = (hz) => M.l + PW * (Math.log10(clampHz(hz) / CAPS.hzMin) / DECADES); const hzOf = (x) => clampHz(CAPS.hzMin * Math.pow(10, DECADES * ((x - M.l) / PW))); const yOf = (v) => M.t + (1 - clamp01(v)) * PH; const vOf = (y) => clamp01(1 - (y - M.t) / PH); -// Inner gridlines only — the endpoints are drawn from CAPS, so the same axis -// code serves the extension's 20–20k and the microphone's 31–8k. -const TICKS = [[50, '50'], [100, '100'], [200, '200'], [500, '500'], - [1000, '1k'], [2000, '2k'], [5000, '5k'], [10000, '10k']] - .filter(([hz]) => hz > CAPS.hzMin * 1.15 && hz < CAPS.hzMax * 0.87); -const DB_LINES = [[1, '0'], [0.75, '-18'], [0.5, '-35'], [0.25, '-53'], [0, '-70']]; +// The level axis is the source's own dB: [bottom, top], or null when it gave +// none. The frame may be on another axis than the source's usual one (see the +// contract). Every level the editor prints goes through these, so the axis, +// the knob's heading and the curve's labels are in one unit. +const axisDb = () => frame.db || CAPS.db; +const minus = (n) => String(Math.round(n)).replace('-', '−'); + +// A height on the level axis, 0..1, as dB: '−43'. '' on an axis without dB. +function dbText(v) { + const db = axisDb(); + return db ? minus(db[0] + v * (db[1] - db[0])) : ''; +} + +// A line every 10 dB: [[v, label]]. +function dbLines() { + const db = axisDb(); + const lines = []; + if (!db) return lines; + for (let d = Math.ceil(db[0] / 10) * 10; d <= db[1]; d += 10) { + lines.push([(d - db[0]) / (db[1] - db[0]), minus(d)]); + } + return lines; +} // Canvas colors come from the page's CSS variables, read fresh each paint so // a theme toggle repaints correctly. The extension page is the cream -// instrument; the device console wraps the same module in its dark tokens. +// instrument; the panel's console wraps the same module in its own tokens. +// Three of them are also painted see-through, which takes the colour apart: +// --led, --rule and --ink have to be written #rrggbb on every surface. function theme() { const s = getComputedStyle(document.body); - const v = (name, fallback) => (s.getPropertyValue(name) || fallback).trim(); - const led = v('--led', '#e8552e'); - const m = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(led.replace('#', '')); - const ledRgb = m ? `${parseInt(m[1], 16)}, ${parseInt(m[2], 16)}, ${parseInt(m[3], 16)}` : '232, 85, 46'; + const v = (name) => s.getPropertyValue(name).trim(); + const alpha = (name) => { + const n = parseInt(v(name).slice(1), 16); + return (a) => `rgba(${n >> 16}, ${n >> 8 & 255}, ${n & 255}, ${a})`; + }; return { - field: v('--field', '#fbf7ef'), - cream: v('--cream', '#f4efe6'), - ink: v('--ink', '#141414'), - muted: v('--muted', '#6b655a'), - faint: v('--faint', '#a69f90'), - rule: v('--rule', '#d9d1c0'), - led, - ledA: (a) => `rgba(${ledRgb}, ${a})`, - ruleA: (a) => `rgba(${parseInt(v('--rule', '#d9d1c0').replace('#', '').slice(0, 2), 16)}, ${parseInt(v('--rule', '#d9d1c0').replace('#', '').slice(2, 4), 16)}, ${parseInt(v('--rule', '#d9d1c0').replace('#', '').slice(4, 6), 16)}, ${a})`, - inkA: (a) => `rgba(${parseInt(v('--ink', '#141414').replace('#', '').slice(0, 2), 16)}, ${parseInt(v('--ink', '#141414').replace('#', '').slice(2, 4), 16)}, ${parseInt(v('--ink', '#141414').replace('#', '').slice(4, 6), 16)}, ${a})` + field: v('--field'), + cream: v('--cream'), + ink: v('--ink'), + muted: v('--muted'), + faint: v('--faint'), + rule: v('--rule'), + led: v('--led'), + ledA: alpha('--led'), + ruleA: alpha('--rule'), + inkA: alpha('--ink') }; } -// The window a band maps right now: its own handles, or the breathing -// envelope while auto range runs. +// The envelope auto range is mapping band `index` through right now, or null: +// auto range is off, the source has not learned one, or what it sent has no +// height (a panel that has never heard anything). +function liveEnv(index) { + const env = cfg.autoRange && frame.env && frame.env[index]; + return env && env.hi > env.lo ? { lo: clamp01(env.lo), hi: clamp01(env.hi) } : null; +} + +// The window a band is drawn with: the breathing envelope while auto range +// has one, the band's own hand-set window otherwise. Auto range without an +// envelope yet shows the stored window (dashed), never a made-up one. function bandWindow(index) { const band = cfg.bands[index]; - if (cfg.autoRange) { - const env = (frame.env && frame.env[index]) || (lastEnv && lastEnv[index]); - if (env) return { lo: clamp01(env.lo), hi: clamp01(env.hi) }; - return { lo: 0.1, hi: 0.7 }; - } - return { lo: band.inMin, hi: band.inMax }; + return liveEnv(index) || { lo: band.inMin, hi: band.inMax }; +} + +// Is anything being heard? Without levels there is no line and no cursor. +const hearing = () => !!(frame.levels && frame.levels.length); + +// Where band `index`'s level sits in its window, 0..1: the mapper's own +// figure when the frame carries it, the model's arithmetic when it does not. +function bandPos(index) { + if (frame.pos && frame.pos.length) return clamp01(frame.pos[index]); + return PFMap.position(frame.levels[index] || 0, cfg.bands[index], liveEnv(index)); +} + +// A window the source would store as it is: the top no higher than it keeps +// one, the two edges no closer than it keeps them. +function fitWindow(band) { + band.inMin = Math.max(0, Math.min(band.inMin, CAPS.bottom(CAPS.levelMax))); + band.inMax = Math.min(CAPS.levelMax, Math.max(band.inMax, CAPS.top(band.inMin))); } function formatHz(hz) { @@ -215,7 +283,10 @@ function formatHz(hz) { // ── main plot drawing ─────────────────────────────────────────────────── -const MONO = '10px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace'; +// Everything written on a canvas: 11 px, in --muted. (10 px in --faint, as it +// was, is 2.3:1 on the extension's cream; the axis and the one number that +// says what the knob gets were the least legible text on the page.) +const MONO = '11px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace'; function drawPlot() { const T = theme(); @@ -227,9 +298,9 @@ function drawPlot() { // grid pctx.font = MONO; pctx.strokeStyle = T.ruleA(0.55); - pctx.fillStyle = T.faint; + pctx.fillStyle = T.muted; pctx.lineWidth = 1; - for (const [v, label] of DB_LINES) { + for (const [v, label] of dbLines()) { const y = Math.round(yOf(v)) + 0.5; if (v > 0 && v < 1) { pctx.beginPath(); pctx.moveTo(M.l, y); pctx.lineTo(M.l + PW, y); pctx.stroke(); @@ -237,6 +308,11 @@ function drawPlot() { pctx.textAlign = 'right'; pctx.fillText(label, M.l - 8, y + 3); } + // The two units, once each, in the margin the level labels are in: dB heads + // their column, Hz starts the row of frequencies. + pctx.textAlign = 'right'; + if (axisDb()) pctx.fillText('dB', M.l - 8, M.t - 9); + pctx.fillText('Hz', M.l - 8, M.t + PH + 16); pctx.textAlign = 'center'; for (const [hz, label] of TICKS) { const x = Math.round(xOf(hz)) + 0.5; @@ -289,26 +365,30 @@ function drawPlot() { pctx.beginPath(); pctx.moveTo(x0, yBot); pctx.lineTo(x1, yBot); pctx.stroke(); pctx.setLineDash([]); - // live level as a horizontal line across the box — the band's average. - // The line BELONGS to the box: below the window it sits pinned on the - // bottom edge ("resting under the floor"), above it on the top. Drawn at - // the raw position it wandered out of its own box, which read as broken. - const level = (frame.levels && frame.levels[i]) || 0; - const ly = Math.max(yTop + 1.5, Math.min(yBot - 1.5, yOf(level))); - pctx.strokeStyle = T.led; - pctx.lineWidth = 2; - pctx.beginPath(); - pctx.moveTo(x0 + 1, ly); - pctx.lineTo(x1 - 1, ly); - pctx.stroke(); + // The live level, as a line across the box: how far through its window + // the band is, which is what the curve is fed and so what the knob gets. + // It is the mapper's position and not the level's height on the axis: the + // two differ wherever the mapper is not linear in this axis (the panel + // maps linear amplitude on a dB axis, and auto range squelches the floor), + // and a line drawn at the height says "fires" where the knob does not. + // Resting, it sits on the bottom edge; at full scale, on the top. + if (hearing()) { + const ly = Math.max(yTop + 1.5, Math.min(yBot - 1.5, yBot - bandPos(i) * (yBot - yTop))); + pctx.strokeStyle = T.led; + pctx.lineWidth = 2; + pctx.beginPath(); + pctx.moveTo(x0 + 1, ly); + pctx.lineTo(x1 - 1, ly); + pctx.stroke(); + } if (isSel) { pctx.fillStyle = T.field; pctx.strokeStyle = T.ink; pctx.lineWidth = 1; for (const [cx, cy] of [[x0, yTop], [x1, yTop], [x0, yBot], [x1, yBot]]) { - pctx.fillRect(cx - 3.5, cy - 3.5, 7, 7); - pctx.strokeRect(cx - 3.5, cy - 3.5, 7, 7); + pctx.fillRect(cx - GRIP / 2, cy - GRIP / 2, GRIP, GRIP); + pctx.strokeRect(cx - GRIP / 2, cy - GRIP / 2, GRIP, GRIP); } } }); @@ -316,31 +396,37 @@ function drawPlot() { placeTags(); } +// Band N drives knob N, and is named after it everywhere: K1..K4. A tag sits +// ON its box's top edge, outside the box: auto range can make a box thinner +// than the tag, which would otherwise cover it and its level line. It starts +// at the box's left edge, and stops at the plot's right one: on a phone the +// highest knob's box is narrower than its tag, which was cut off there. function placeTags() { const T = theme(); cfg.bands.forEach((band, i) => { const tag = $('tag' + i); const win = bandWindow(i); - tag.style.left = Math.round(xOf(band.hzMin)) + 'px'; - tag.style.top = Math.round(yOf(win.hi) - 11) + 'px'; tag.classList.toggle('sel', i === sel); tag.classList.toggle('mutedTag', band.muted); - tag.querySelector('.tagText').textContent = 'B' + (i + 1) + (band.muted ? '·M' : ''); + tag.querySelector('.tagText').textContent = 'K' + (i + 1) + (band.muted ? ' muted' : ''); drawGlyph(tag.querySelector('canvas'), band, 18, 12, T.ink); + tag.style.left = Math.round(Math.min(xOf(band.hzMin), M.l + PW + M.r - tag.offsetWidth - 1)) + 'px'; + tag.style.top = Math.round(yOf(win.hi) - 21) + 'px'; }); } -// tiny curve glyph, used by tags and footer chips +// The tiny curve glyph on tags, tabs and shapes. Its box (w x h css px) is the +// stylesheet's, so a glyph that is not drawn yet already has its size; here +// only the pixels are made. function drawGlyph(canvas, band, w, h, color) { const dpr = window.devicePixelRatio || 1; if (canvas.width !== w * dpr) { canvas.width = w * dpr; canvas.height = h * dpr; - canvas.style.width = w + 'px'; canvas.style.height = h + 'px'; } const g = canvas.getContext('2d'); g.setTransform(dpr, 0, 0, dpr, 0, 0); g.clearRect(0, 0, w, h); - g.strokeStyle = color || theme().ink; + g.strokeStyle = color; g.lineWidth = 1.4; g.lineCap = 'round'; g.beginPath(); @@ -356,7 +442,6 @@ function drawGlyph(canvas, band, w, h, color) { // ── main plot interaction ─────────────────────────────────────────────── -const EDGE = 7; let drag = null; function hitTest(x, y) { @@ -371,8 +456,18 @@ function hitTest(x, y) { const insideX = x > x0 - EDGE && x < x1 + EDGE; const insideY = y > yTop - EDGE && y < yBot + EDGE; if (!insideX || !insideY) continue; - const nearL = Math.abs(x - x0) <= EDGE, nearR = Math.abs(x - x1) <= EDGE; - const nearT = Math.abs(y - yTop) <= EDGE, nearB = Math.abs(y - yBot) <= EDGE; + // An edge is grabbed from EDGE px outside it, and from inside too, but + // never from further in than a third of the box: the middle third of + // even the smallest box stays "move", so a fat edge cannot swallow it. + const inX = Math.min(EDGE, (x1 - x0) / 3), inY = Math.min(EDGE, (yBot - yTop) / 3); + const nearL = x <= x0 + inX, nearR = x >= x1 - inX; + // Under a finger, in auto range, a top or bottom edge is not a handle: + // with a finger's EDGE those two zones are a quarter of the plot, and a + // thumb that only meant to scroll the page took all four knobs over (see + // takeOver). There the touch scrolls, or moves the box if it is inside it; + // a height is set by hand after the Auto range switch is put off. + const tall = !(COARSE && cfg.autoRange); + const nearT = tall && y <= yTop + inY, nearB = tall && y >= yBot - inY; // Corners first — a grab there resizes both axes at once. if (nearL && nearT) return { band: i, mode: 'tl' }; if (nearR && nearT) return { band: i, mode: 'tr' }; @@ -387,16 +482,22 @@ function hitTest(x, y) { return null; } -// Grabbing a breathing edge is the gesture that says "I'll take it from +// Dragging a breathing edge is the gesture that says "I'll take it from // here": auto range switches off, and every band's window is seeded from the -// envelope it was just breathing at, so nothing jumps. -function freezeAutoWindows() { - const env = (frame.env && frame.env.length ? frame.env : lastEnv) || []; +// envelope it was just breathing at, so nothing jumps. A band with no live +// envelope keeps the window it had (and a source sends none for a band that +// has learned nothing: seeded from silence, a window is a sliver at the floor +// that any sound pegs at its top). This is the ONLY thing that writes an +// envelope into a window: the Auto range switch itself just goes back to the +// hand-set windows, so trying auto costs nothing. With a mouse only: see +// hitTest. +function takeOver() { cfg.bands.forEach((band, i) => { - const e = env[i]; - if (!e) return; - band.inMin = clamp01(e.lo); - band.inMax = Math.max(band.inMin + 0.02, clamp01(e.hi)); + const env = liveEnv(i); + if (!env) return; + band.inMin = env.lo; + band.inMax = env.hi; + fitWindow(band); }); cfg.autoRange = false; syncAutoToggle(); @@ -407,26 +508,40 @@ function plotPointer(event) { return { x: event.clientX - rect.left, y: event.clientY - rect.top }; } +// A FINGER ON A CANVAS. One that lands on something draggable is a drag, and +// the page must not scroll under it; one that misses is the browser's, so the +// page still scrolls from anywhere else on the plot. That cannot be said with +// touch-action, which is per element and not per touch (`none` made the plot +// a trap no swipe got out of; `pan-y` would give the browser the vertical +// drag of a top or bottom edge, and it takes it with a pointercancel that +// preventDefault on pointerdown does not stop). What does decide it per touch +// is a touchstart listener that is not passive: prevented, that touch never +// scrolls and its pointer events run to the end. `hits(x, y)` says whether +// the point, in the canvas's own px, is on something. +function dragOnHit(canvas, hits) { + canvas.addEventListener('touchstart', (event) => { + const rect = canvas.getBoundingClientRect(); + const touch = event.changedTouches[0]; + if (hits(touch.clientX - rect.left, touch.clientY - rect.top)) event.preventDefault(); + }, { passive: false }); +} +dragOnHit(plotCanvas, hitTest); + plotCanvas.addEventListener('pointerdown', (event) => { const { x, y } = plotPointer(event); const hit = hitTest(x, y); if (!hit) return; if (hit.band !== sel) selectBand(hit.band); - if (cfg.autoRange && hit.mode !== 'move' && hit.mode !== 'l' && hit.mode !== 'r') { - freezeAutoWindows(); // any grab that touches a breathing edge takes over - } - const band = cfg.bands[hit.band]; - const win = bandWindow(hit.band); - drag = { - ...hit, - startX: x, startY: y, - hzMin: band.hzMin, hzMax: band.hzMax, - lo: win.lo, hi: win.hi - }; + // Armed, not moving: a press selects. Nothing is moved, resized or taken + // over until the pointer has travelled SLOP px, so a tap (or the jitter of + // one) changes nothing. + drag = { ...hit, startX: x, startY: y, live: false }; plotCanvas.setPointerCapture(event.pointerId); event.preventDefault(); }); +const SLOP = 4; + plotCanvas.addEventListener('pointermove', (event) => { const { x, y } = plotPointer(event); if (!drag) { @@ -439,7 +554,16 @@ plotCanvas.addEventListener('pointermove', (event) => { return; } const band = cfg.bands[drag.band]; - const MINR = 1.12; // narrowest box, as a frequency ratio + if (!drag.live) { + if (Math.hypot(x - drag.startX, y - drag.startY) < SLOP) return; + // A top or bottom edge of a box in auto range (or a corner, which is one + // too): this drag takes over. ('move' has neither letter in it.) + if (cfg.autoRange && /[tb]/.test(drag.mode)) takeOver(); + const win = bandWindow(drag.band); + Object.assign(drag, { live: true, hzMin: band.hzMin, hzMax: band.hzMax, lo: win.lo, hi: win.hi }); + } + // The narrowest box, as a frequency ratio. + const MINR = 1.12; if (drag.mode === 'move') { // Translate in log-frequency: the box keeps its RATIO width, which is @@ -448,30 +572,34 @@ plotCanvas.addEventListener('pointermove', (event) => { let ratio = Math.pow(10, shift); ratio = Math.max(CAPS.hzMin / drag.hzMin, Math.min(CAPS.hzMax / drag.hzMax, ratio)); band.hzMin = drag.hzMin * ratio; - band.hzMax = drag.hzMax * ratio; + band.hzMax = Math.max(drag.hzMax * ratio, band.hzMin + CAPS.hzGap); if (!cfg.autoRange) { const dv = vOf(y) - vOf(drag.startY); const span = drag.hi - drag.lo; - const lo = Math.max(0, Math.min(1 - span, drag.lo + dv)); - band.inMin = lo; - band.inMax = lo + span; + band.inMin = Math.max(0, Math.min(CAPS.levelMax - span, drag.lo + dv)); + band.inMax = band.inMin + span; + fitWindow(band); } } else { // Edges and corners share the same four moves; a corner just does two. - if (drag.mode.includes('l')) band.hzMin = Math.min(hzOf(x), band.hzMax / MINR); - if (drag.mode.includes('r')) band.hzMax = Math.max(hzOf(x), band.hzMin * MINR); - if (drag.mode.includes('t')) band.inMax = Math.max(vOf(y), band.inMin + 0.02); - if (drag.mode.includes('b')) band.inMin = Math.min(vOf(y), band.inMax - 0.02); + // Each edge stops where the source would stop it, so what is drawn is + // what is stored and nothing moves on the next load. + if (drag.mode.includes('l')) band.hzMin = Math.max(CAPS.hzMin, Math.min(hzOf(x), band.hzMax / MINR, band.hzMax - CAPS.hzGap)); + if (drag.mode.includes('r')) band.hzMax = Math.min(CAPS.hzMax, Math.max(hzOf(x), band.hzMin * MINR, band.hzMin + CAPS.hzGap)); + if (drag.mode.includes('t')) band.inMax = Math.min(CAPS.levelMax, Math.max(vOf(y), CAPS.top(band.inMin))); + if (drag.mode.includes('b')) band.inMin = Math.max(0, Math.min(vOf(y), CAPS.bottom(band.inMax))); } drawPlot(); + drawCurve(); renderChips(); renderSettings(); }); const releasePlot = () => { if (!drag) return; + const moved = drag.live; drag = null; - persist(); + if (moved) persist(); }; plotCanvas.addEventListener('pointerup', releasePlot); plotCanvas.addEventListener('pointercancel', releasePlot); @@ -480,15 +608,17 @@ plotCanvas.addEventListener('pointercancel', releasePlot); const curveCanvas = $('curve'); const cctx = curveCanvas.getContext('2d'); -const CM = { l: 30, r: 10, t: 12, b: 26 }; +const CM = { l: 34, r: 10, t: 12, b: 26 }; let CW = 0, CH = 0; let curveDrag = null; +// The curve's box is the stylesheet's too (#curve: 356 px wide where there is +// room, the width of its row where there is not, 218 tall). The pointer maths +// below go by CW and CH, so any size works. function sizeCurve() { const dpr = window.devicePixelRatio || 1; - const cssW = 356, cssH = 218; + const cssW = curveCanvas.clientWidth, cssH = 218; curveCanvas.width = cssW * dpr; curveCanvas.height = cssH * dpr; - curveCanvas.style.width = cssW + 'px'; curveCanvas.style.height = cssH + 'px'; cctx.setTransform(dpr, 0, 0, dpr, 0, 0); CW = cssW - CM.l - CM.r; CH = cssH - CM.t - CM.b; } @@ -538,47 +668,62 @@ function drawCurve() { cctx.strokeStyle = T.ink; cctx.lineWidth = 1; for (const [hx, hy] of [[c.p1x, c.p1y], [c.p2x, c.p2y]]) { - cctx.fillRect(cxOf(hx) - 3.5, cyOf(hy) - 3.5, 7, 7); - cctx.strokeRect(cxOf(hx) - 3.5, cyOf(hy) - 3.5, 7, 7); + cctx.fillRect(cxOf(hx) - GRIP / 2, cyOf(hy) - GRIP / 2, GRIP, GRIP); + cctx.strokeRect(cxOf(hx) - GRIP / 2, cyOf(hy) - GRIP / 2, GRIP, GRIP); } } - // live cursor: where the music is on this curve right now + // live cursor: where the music is on this curve right now, and (top + // left) what that is: the level heard, in the axis's dB, -> the knob's + // value. The position and the value are the mapper's own figures when the + // frame has them. const win = bandWindow(sel); - const level = (frame.levels && frame.levels[sel]) || 0; - const u = clamp01((level - win.lo) / Math.max(0.001, win.hi - win.lo)); - const v = bandCurveValue(band, u); - cctx.strokeStyle = T.led; - cctx.setLineDash([3, 3]); - cctx.lineWidth = 1; - cctx.beginPath(); cctx.moveTo(cxOf(u), CM.t + CH); cctx.lineTo(cxOf(u), cyOf(v)); cctx.stroke(); - cctx.setLineDash([]); - cctx.fillStyle = T.led; - cctx.beginPath(); cctx.arc(cxOf(u), cyOf(v), 4.5, 0, Math.PI * 2); cctx.fill(); + if (hearing()) { + const u = bandPos(sel); + const v = bandCurveValue(band, u); + cctx.strokeStyle = T.led; + cctx.setLineDash([3, 3]); + cctx.lineWidth = 1; + cctx.beginPath(); cctx.moveTo(cxOf(u), CM.t + CH); cctx.lineTo(cxOf(u), cyOf(v)); cctx.stroke(); + cctx.setLineDash([]); + cctx.fillStyle = T.led; + cctx.beginPath(); cctx.arc(cxOf(u), cyOf(v), 4.5, 0, Math.PI * 2); cctx.fill(); + const out = frame.outputs && frame.outputs.length ? frame.outputs[sel] : PFMap.output(band, u); + const heard = dbText(frame.levels[sel] || 0); + cctx.font = MONO; + cctx.fillStyle = T.muted; + cctx.textAlign = 'left'; + cctx.fillText((heard && heard + ' dB ') + '→ ' + Number(out).toFixed(2), CM.l + 6, CM.t + 12); + } - // labels + // labels: along the bottom the window this curve is spread over, quiet end + // to loud end, in the plot's dB (auto range keeps moving it, so it gets the + // word); up the side the two ends of the output range. + const lo = dbText(win.lo); cctx.font = MONO; - cctx.fillStyle = T.faint; + cctx.fillStyle = T.muted; cctx.textAlign = 'left'; - cctx.fillText(cfg.autoRange ? 'in auto' : 'in ' + win.lo.toFixed(2), CM.l, CM.t + CH + 16); + cctx.fillText(cfg.autoRange ? 'auto range' : lo, CM.l, CM.t + CH + 16); cctx.textAlign = 'right'; - cctx.fillText(cfg.autoRange ? '' : win.hi.toFixed(2), CM.l + CW, CM.t + CH + 16); - cctx.fillText(cfg.bands[sel].outMax.toFixed(2), CM.l - 6, CM.t + 8); - cctx.fillText(cfg.bands[sel].outMin.toFixed(2), CM.l - 6, CM.t + CH); - cctx.textAlign = 'left'; - cctx.fillText(u.toFixed(2) + ' → ' + (cfg.bands[sel].outMin + v * (cfg.bands[sel].outMax - cfg.bands[sel].outMin)).toFixed(2), CM.l + 6, CM.t + 12); + cctx.fillText(cfg.autoRange || !lo ? '' : dbText(win.hi) + ' dB', CM.l + CW, CM.t + CH + 16); + cctx.fillText(band.outMax.toFixed(2), CM.l - 6, CM.t + 8); + cctx.fillText(band.outMin.toFixed(2), CM.l - 6, CM.t + CH); +} + +// Which handle of the selected knob's curve is at this point: 'p1', 'p2', or +// nothing (only a bezier has handles). +function curveHit(x, y) { + const c = cfg.bands[sel].curve; + if (!c || c.type !== 'bezier') return null; + const near = (hx, hy) => Math.hypot(x - cxOf(hx), y - cyOf(hy)) < REACH; + return near(c.p1x, c.p1y) ? 'p1' : near(c.p2x, c.p2y) ? 'p2' : null; } +dragOnHit(curveCanvas, curveHit); curveCanvas.addEventListener('pointerdown', (event) => { - const band = cfg.bands[sel]; - if (!band.curve || band.curve.type !== 'bezier') return; const rect = curveCanvas.getBoundingClientRect(); - const x = event.clientX - rect.left, y = event.clientY - rect.top; - const c = band.curve; - const near = (hx, hy) => Math.hypot(x - cxOf(hx), y - cyOf(hy)) < 12; - if (near(c.p1x, c.p1y)) curveDrag = 'p1'; - else if (near(c.p2x, c.p2y)) curveDrag = 'p2'; - else return; + curveDrag = curveHit(event.clientX - rect.left, event.clientY - rect.top); + if (!curveDrag) return; curveCanvas.setPointerCapture(event.pointerId); event.preventDefault(); }); @@ -615,13 +760,18 @@ function renderPresetChips() { const id = band.curve ? (band.curve.id || 'custom') : null; document.querySelectorAll('.preset').forEach((el) => { el.classList.toggle('on', el.dataset.p === id); + el.setAttribute('aria-pressed', el.dataset.p === id); }); - $('legacyHint').hidden = !!band.curve; + // One line under the shapes, and only when it is true: a knob that has no + // shape is on the source's default response (nothing to fix, so nothing is + // asked), and only a bezier has handles to drag. + $('curveHint').textContent = !band.curve ? 'This knob uses the default response.' + : band.curve.type === 'bezier' ? 'Drag the two handles for a custom shape.' : ''; $('stepsRow').hidden = !(band.curve && band.curve.type === 'steps'); if (band.curve && band.curve.type === 'steps') $('stepsN').textContent = String(band.curve.n); document.querySelectorAll('.preset canvas').forEach((canvas) => { const preset = PRESETS[canvas.parentElement.dataset.p]; - drawGlyph(canvas, { curve: preset.curve, gain: 1 }, 40, 24, theme().ink); + drawGlyph(canvas, { curve: preset, gain: 1 }, 40, 24, theme().ink); }); } @@ -629,7 +779,7 @@ document.querySelectorAll('.preset').forEach((el) => { el.addEventListener('click', () => { const preset = PRESETS[el.dataset.p]; if (!preset) return; - touchCurve(cfg.bands[sel], structuredClone(preset.curve)); + touchCurve(cfg.bands[sel], structuredClone(preset)); drawCurve(); renderPresetChips(); placeTags(); @@ -653,19 +803,26 @@ function stepsAdjust(delta) { persist(); } +// The selected knob's card: which knob, what it listens to (its frequencies, +// and its window in the plot's dB unless auto range is setting that), its +// output range and its mute. The knob's name is also on its Reset and in +// Preview's legend. function renderSettings() { const band = cfg.bands[sel]; - $('bandName').textContent = 'Band ' + (sel + 1); + const lo = dbText(band.inMin); + $('bandName').textContent = 'Knob ' + (sel + 1); $('bandMeta').textContent = formatHz(band.hzMin) + ' – ' + formatHz(band.hzMax) + ' Hz' - + (cfg.autoRange ? ' · in auto' : ' · in ' + band.inMin.toFixed(2) + '–' + band.inMax.toFixed(2)); + + (cfg.autoRange ? ' · auto range' : lo && ' · ' + lo + ' to ' + dbText(band.inMax) + ' dB'); $('outLabel').textContent = band.outMin.toFixed(2) + ' – ' + band.outMax.toFixed(2); - const track = $('outTrack'); - const w = track.clientWidth - 10; - $('outLo').style.left = (5 + band.outMin * w - 5) + 'px'; - $('outHi').style.left = (5 + band.outMax * w - 5) + 'px'; + const w = $('outTrack').clientWidth - 10; + $('outLo').style.left = (5 + band.outMin * w) + 'px'; + $('outHi').style.left = (5 + band.outMax * w) + 'px'; $('outFill').style.left = (5 + band.outMin * w) + 'px'; $('outFill').style.width = Math.max(0, (band.outMax - band.outMin) * w) + 'px'; $('muteToggle').classList.toggle('on', band.muted); + $('muteToggle').setAttribute('aria-pressed', band.muted); + $('resetBand').textContent = 'Reset K' + (sel + 1); + $('pvOut').textContent = 'K' + (sel + 1) + ' output'; } document.querySelectorAll('.outPreset').forEach((el) => { @@ -677,12 +834,16 @@ document.querySelectorAll('.outPreset').forEach((el) => { }); }); +// The track is dragged sideways and lets the page scroll up and down +// (touch-action: pan-y). A touch that turns out to be a scroll ends in +// pointercancel after it has already moved the handle a little: that puts +// back what the press found and saves nothing. let outDrag = null; $('outTrack').addEventListener('pointerdown', (event) => { const band = cfg.bands[sel]; const rect = $('outTrack').getBoundingClientRect(); const v = clamp01((event.clientX - rect.left - 5) / (rect.width - 10)); - outDrag = Math.abs(v - band.outMin) < Math.abs(v - band.outMax) ? 'lo' : 'hi'; + outDrag = { lo: Math.abs(v - band.outMin) < Math.abs(v - band.outMax), was: [band.outMin, band.outMax] }; $('outTrack').setPointerCapture(event.pointerId); event.preventDefault(); }); @@ -691,13 +852,19 @@ $('outTrack').addEventListener('pointermove', (event) => { const band = cfg.bands[sel]; const rect = $('outTrack').getBoundingClientRect(); const v = clamp01((event.clientX - rect.left - 5) / (rect.width - 10)); - if (outDrag === 'lo') band.outMin = Math.min(v, band.outMax - 0.05); - else band.outMax = Math.max(v, band.outMin + 0.05); + if (outDrag.lo) band.outMin = Math.min(v, band.outMax - PFMap.MIN_OUT); + else band.outMax = Math.max(v, band.outMin + PFMap.MIN_OUT); + renderSettings(); drawCurve(); +}); +$('outTrack').addEventListener('pointerup', () => { + if (outDrag) { outDrag = null; persist(); } +}); +$('outTrack').addEventListener('pointercancel', () => { + if (!outDrag) return; + [cfg.bands[sel].outMin, cfg.bands[sel].outMax] = outDrag.was; + outDrag = null; renderSettings(); drawCurve(); }); -const releaseOut = () => { if (outDrag) { outDrag = null; persist(); } }; -$('outTrack').addEventListener('pointerup', releaseOut); -$('outTrack').addEventListener('pointercancel', releaseOut); $('muteToggle').addEventListener('click', () => { const band = cfg.bands[sel]; @@ -705,21 +872,30 @@ $('muteToggle').addEventListener('click', () => { renderSettings(); renderChips(); drawPlot(); persist(); }); -$('resetBand').addEventListener('click', () => { - cfg.bands[sel] = defaultBand(sel); - touchCurve(cfg.bands[sel], structuredClone(PRESETS.smooth.curve)); - selectBand(sel); - persist(); +// Reset band asks the SOURCE for its default: the editor has no table of its +// own, so this and the source's own "reset everything" cannot disagree. +// Whatever is waiting to be saved goes first, so the reset is the last word. +$('resetBand').addEventListener('click', async () => { + await flush(); + const next = await A.resetBand(sel, cfg); + if (next) applyConfig(next); }); -// ── footer chips ──────────────────────────────────────────────────────── +// The source's own "reset everything", where it has one (see the contract): +// the button is in the page, hidden, and only such a source brings it out. +if (A.resetAll) { + $('resetMap').hidden = false; + $('resetMap').addEventListener('click', function () { A.resetAll(this); }); +} + +// ── the knobs, as tabs under the plot ─────────────────────────────────── function renderChips() { cfg.bands.forEach((band, i) => { const chip = $('chip' + i); chip.classList.toggle('sel', i === sel); + chip.setAttribute('aria-pressed', i === sel); chip.classList.toggle('mutedChip', band.muted); - chip.querySelector('.chipName').textContent = 'B' + (i + 1); chip.querySelector('.chipHz').textContent = formatHz(band.hzMin) + '–' + formatHz(band.hzMax); drawGlyph(chip.querySelector('canvas'), band, 18, 12, theme().muted); }); @@ -740,13 +916,21 @@ function selectBand(index) { // ── preview ───────────────────────────────────────────────────────────── // -// Ableton-style: synthetic test signals through the SELECTED band's whole +// Ableton-style: synthetic test signals through the SELECTED knob's whole // chain - window, glide ballistics, curve, output range - drawn as a // scrolling scope. What the knob will do, audible music not required. +// +// The scope takes the plot's place while it runs (#pv lies over it: a test +// signal needs no spectrum), so everything it demonstrates - attack and +// damping above it, the knobs, the curve and the output range below - stays +// live around it. The Preview button, right under it, closes it again; so +// does Escape. -const pvOverlay = $('pvOverlay'); +const pv = $('pv'); const pvScope = $('pvScope'); const pvCtx = pvScope.getContext('2d'); +// The scope's box, css px: whatever the layer gives it (see pvSize). +let pvW = 0, pvH = 0; let pvSig = 'pulse'; let pvRaf = 0; let pvTimer = 0; @@ -764,40 +948,32 @@ function pvSignal(t) { // output shows comes from the glide, which is the point of the demo. const phase = t % 0.8; const spike = phase < 0.06 ? 0.85 : 0; - return Math.min(1, Math.max(0, spike + 0.07 + (Math.random() - 0.5) * 0.03)); + return clamp01(spike + 0.07 + (Math.random() - 0.5) * 0.03); } if (pvSig === 'noisy') { const spike = (t % 1.7) < 0.06 ? 0.5 : 0; - return Math.min(1, Math.max(0, - 0.30 + 0.10 * Math.sin(t * 1.3) + (Math.random() - 0.5) * 0.22 + spike)); + return clamp01(0.30 + 0.10 * Math.sin(t * 1.3) + (Math.random() - 0.5) * 0.22 + spike); } // swell - return Math.min(1, Math.max(0, - 0.45 + 0.35 * Math.sin(t * Math.PI * 2 * 0.35) + (Math.random() - 0.5) * 0.04)); + return clamp01(0.45 + 0.35 * Math.sin(t * Math.PI * 2 * 0.35) + (Math.random() - 0.5) * 0.04); } function pvChain(sig) { // Mirror the live pipeline: asymmetric glide on the LEVEL, then window, // curve, output range. - const a = pvLevel < sig - ? Math.max(0.05, Math.min(0.9, cfg.attack)) - : Math.max(0.05, Math.min(0.9, cfg.smoothing)); + // (Both alphas are already inside 0.05..0.9: the model holds them there on + // load and the two sliders cannot leave it.) + const a = pvLevel < sig ? cfg.attack : cfg.smoothing; pvLevel += (sig - pvLevel) * a; const band = cfg.bands[sel]; - let u; - if (cfg.autoRange) { - u = clamp01((pvLevel - 0.10) / 0.85); - } else { - const inMin = clamp01(band.inMin); - const inMax = Math.max(inMin + 0.01, clamp01(band.inMax)); - u = clamp01((pvLevel - inMin) / (inMax - inMin)); - } - return band.outMin + bandCurveValue(band, u) * (band.outMax - band.outMin); + // The model's own two functions. In auto range the test signal is taken + // as already sitting in its envelope. + return PFMap.output(band, PFMap.position(pvLevel, band, cfg.autoRange ? { lo: 0, hi: 1 } : null)); } function pvDraw() { const T = theme(); - const w = 600, h = 230; + const w = pvW, h = pvH; pvCtx.clearRect(0, 0, w, h); pvCtx.strokeStyle = T.ruleA(0.5); pvCtx.lineWidth = 1; @@ -821,7 +997,7 @@ function pvDraw() { } function pvTick(now) { - if (pvOverlay.hidden) return; + if (pv.hidden) return; if (!pvLast) pvLast = now; // Wall-clock scheduling, not per-frame increments: a throttled tab still // simulates the RIGHT amount of time when frames do arrive (capped per @@ -853,26 +1029,31 @@ function pvSchedule() { }, 300); } -function pvOpen() { +// The scope draws into the box the stylesheet gives it: what is left of the +// plot's box under the row of test signals. No size of its own. +function pvSize() { const dpr = window.devicePixelRatio || 1; - pvScope.width = 600 * dpr; pvScope.height = 230 * dpr; - pvScope.style.width = '600px'; pvScope.style.height = '230px'; + pvW = pvScope.clientWidth; pvH = pvScope.clientHeight; + pvScope.width = pvW * dpr; pvScope.height = pvH * dpr; pvCtx.setTransform(dpr, 0, 0, dpr, 0, 0); - $('pvTitle').textContent = 'Preview — Band ' + (sel + 1); - pvIn = []; pvOut = []; pvT = 0; pvLast = 0; pvLevel = 0; - pvOverlay.hidden = false; - pvSchedule(); } -function pvClose() { - pvOverlay.hidden = true; +// On, off: the one switch. The button says which it is (aria-pressed). +function pvSet(on) { + pv.hidden = !on; + $('openPreview').setAttribute('aria-pressed', on); cancelAnimationFrame(pvRaf); clearTimeout(pvTimer); + if (!on) return; + pvSize(); + pvIn = []; pvOut = []; pvT = 0; pvLast = 0; pvLevel = 0; + pvSchedule(); } -$('openPreview').addEventListener('click', pvOpen); -$('pvClose').addEventListener('click', pvClose); -pvOverlay.addEventListener('click', (e) => { if (e.target === pvOverlay) pvClose(); }); +$('openPreview').addEventListener('click', () => pvSet(pv.hidden)); +document.addEventListener('keydown', (event) => { + if (event.key === 'Escape' && !pv.hidden) pvSet(false); +}); document.querySelectorAll('.pvSig').forEach((el) => { el.addEventListener('click', () => { pvSig = el.dataset.s; @@ -882,23 +1063,23 @@ document.querySelectorAll('.pvSig').forEach((el) => { // ── auto toggle, status, wiring ───────────────────────────────────────── +// The switch, and beside it the one thing to know about the boxes in the mode +// it is in. function syncAutoToggle() { $('autoToggle').classList.toggle('on', cfg.autoRange); - $('autoHint').textContent = cfg.autoRange - ? 'boxes breathe with the room — drag a top or bottom edge to take manual control' - : 'manual windows — the box edges are exactly what maps'; + $('autoToggle').setAttribute('aria-pressed', cfg.autoRange); + $('autoHint').textContent = cfg.autoRange ? HINT_AUTO : HINT_HAND; } +// The switch only switches: off goes back to the windows set by hand, which +// auto range never touched. (Dragging an edge is what keeps an envelope.) $('autoToggle').addEventListener('click', () => { - if (cfg.autoRange) freezeAutoWindows(); - else cfg.autoRange = true; + cfg.autoRange = !cfg.autoRange; syncAutoToggle(); drawPlot(); drawCurve(); renderSettings(); persist(); }); -$('stopBtn').addEventListener('click', () => A.stop()); - // Damping = the level smoothing the analysis already runs (an EMA on each // band, before the window and curve). Right means calmer: the slider's 0..1 // maps to alpha 0.9..0.05, so a gentle word scale replaces a number nobody @@ -907,68 +1088,90 @@ $('stopBtn').addEventListener('click', () => A.stop()); const DAMP_WORDS = [[0.25, 'tight'], [0.5, 'balanced'], [0.75, 'smooth'], [1.01, 'glassy']]; const ATK_WORDS = [[0.25, 'snap'], [0.5, 'quick'], [0.75, 'soft'], [1.01, 'lazy']]; -function dampWord(v) { - for (const [top, word] of DAMP_WORDS) if (v < top) return word; - return 'glassy'; -} +const dampWord = (v) => DAMP_WORDS.find(([top]) => v < top)[1]; function syncDamping() { const v = clamp01((0.9 - cfg.smoothing) / 0.85); - $('damping').value = String(v); + $('damping').value = v; $('dampingWord').textContent = dampWord(v); const k = clamp01((0.9 - cfg.attack) / 0.85); - $('attack').value = String(k); + $('attack').value = k; $('attackWord').textContent = ATK_WORDS.find(([top]) => k < top)[1]; } $('attack').addEventListener('input', () => { const v = clamp01($('attack').value); - cfg.attack = Math.max(0.05, Math.min(0.9, 0.9 - v * 0.85)); + cfg.attack = 0.9 - v * 0.85; $('attackWord').textContent = ATK_WORDS.find(([top]) => v < top)[1]; persist(); }); $('damping').addEventListener('input', () => { const v = clamp01($('damping').value); - cfg.smoothing = Math.max(0.05, Math.min(0.9, 0.9 - v * 0.85)); + cfg.smoothing = 0.9 - v * 0.85; $('dampingWord').textContent = dampWord(v); persist(); }); -function renderStatus() { - const el = $('sourceChip'); - if (frame.demo) { el.textContent = 'demo source'; el.className = 'chip'; } - else if (frame.running && frame.connected) { el.textContent = (A.labels && A.labels.live) || 'live · tab audio'; el.className = 'chip okChip'; } - else if (frame.running) { el.textContent = 'capturing · connecting'; el.className = 'chip'; } - else { el.textContent = 'idle'; el.className = 'chip'; } - $('hostChip').textContent = cfg.host + ':81'; - $('captureHint').textContent = frame.running || frame.demo ? '' : A.captureHint; - $('stopBtn').disabled = !frame.running; -} - -A.onFrame((state) => { - frame = state || {}; - if (frame.env && frame.env.length) lastEnv = frame.env; - drawPlot(); - drawCurve(); - renderStatus(); -}); - +// Everything drawn is sized from the page, so a window made narrower (half a +// screen beside the music, a phone turned round) is measured again. window.addEventListener('resize', () => { + if (!cfg) return; sizePlot(); + sizeCurve(); + if (!pv.hidden) pvSize(); drawPlot(); + drawCurve(); renderSettings(); }); +// An in-page "are you sure": the first press arms the button and makes it ask, +// a second press within four seconds answers yes. A second press that comes +// within half a second of the first is the same double click or double tap, +// not an answer to a question nobody has had time to read: it is ignored, and +// the button stays armed. window.confirm is not used anywhere on these pages: +// the phone app shows /audio-in in a WebView that has none (it answers "no" +// without showing anything). Use: +// if (!PFConfirm(button, 'Reset everything? Press again')) return; +window.PFConfirm = function (button, ask) { + if (button._armed) { + if (Date.now() - button._at < 500) return false; + clearTimeout(button._armed); + button._armed = 0; + button.textContent = button._label; + return true; + } + button._label = button.textContent; + button.textContent = ask; + button._at = Date.now(); + button._armed = setTimeout(() => { + button._armed = 0; + button.textContent = button._label; + }, 4000); + return false; +}; + (async function init() { const stored = await A.loadConfig(); - cfg = normalizeConfig(stored); - if (A._setDemoConfig) A._setDemoConfig(cfg); + readCaps(); + cfg = PFMap.normalizeConfig(stored, CAPS); sizePlot(); sizeCurve(); syncAutoToggle(); syncDamping(); selectBand(0); - renderStatus(); - A.requestStatus(); + // The attribute, not the property: a browser too old to know `inert` would + // keep the attribute, and with it what the stylesheet hides before the + // first mapping. + $('ed').removeAttribute('inert'); + if (A.onConfig) A.onConfig(applyConfig); + A.onFrame((state) => { + const was = String(axisDb()); + frame = state || {}; + // A frame on another level axis (`db` in the contract) changes the dB the + // card prints, not only the plot's labels. + if (String(axisDb()) !== was) renderSettings(); + drawPlot(); + drawCurve(); + }); })(); diff --git a/tools/patternflow-audio-extension/manifest.json b/tools/patternflow-audio-extension/manifest.json index c4f409b7..8e2ac534 100644 --- a/tools/patternflow-audio-extension/manifest.json +++ b/tools/patternflow-audio-extension/manifest.json @@ -1,8 +1,8 @@ { "manifest_version": 3, "name": "Patternflow Audio", - "description": "Capture tab audio, map spectrum bands, and send knob deltas to Patternflow.", - "version": "0.1.0", + "description": "Capture a tab's audio, map four frequency bands onto the four knobs, and stream them to a Patternflow panel.", + "version": "0.2.0", "icons": { "16": "icons/icon-16.png", "32": "icons/icon-32.png", diff --git a/tools/patternflow-audio-extension/mapping.js b/tools/patternflow-audio-extension/mapping.js new file mode 100644 index 00000000..975fc629 --- /dev/null +++ b/tools/patternflow-audio-extension/mapping.js @@ -0,0 +1,236 @@ +// Patternflow Audio — the mapping model. +// +// What a mapping is, written once. Four bands, one per knob. A band listens +// to a range of frequencies and takes the level it hears there through +// +// level -> window -> response curve -> [rests at .. peaks at] +// +// where the window is the band's own (manual) or the envelope the band has +// recently moved in (auto range). offscreen.js runs that chain for the knobs; +// the editor draws it and previews it; both ask this file, so a box on the +// screen and a knob on the panel cannot be told two different things. +// +// It is ONE object on purpose. These are classic scripts sharing a global +// scope, where a second top-level `clamp01` in any file is a SyntaxError that +// kills the page at load and that `node --check` on each file cannot see. +// Everything here is reached as PFMap.something; nothing else is declared. +// +// Two halves. Down to the line that says so, this is the model: no chrome.*, +// no DOM, none of the extension's own numbers. That half also travels to the +// panel, inside its /audio-in page (firmware/toolchain/build_audio_in_page.py +// stops reading at the line), so every byte of it is sent over the panel's +// Wi-Fi: keep it to what the editor needs on both sides. Below the line is +// what only the extension's audio source knows. + +var PFMap = (function () { + 'use strict'; + + const within = (v, lo, hi) => Math.max(lo, Math.min(hi, Number(v) || 0)); + const clamp01 = (v) => within(v, 0, 1); + + // ── response curves ───────────────────────────────────────────────────── + // + // A curve is authored as one of these shapes and BAKED to a 33-point table. + // Whatever maps for real - offscreen.js here, the firmware on the panel - + // only interpolates the table, and never learns what a bezier is. + + const PRESETS = { + smooth: { type: 'bezier', id: 'smooth', y0: 0, y1: 1, p1x: 0.45, p1y: 0.05, p2x: 0.55, p2y: 0.95 }, + sharp: { type: 'bezier', id: 'sharp', y0: 0, y1: 1, p1x: 0.10, p1y: 0.65, p2x: 0.35, p2y: 1.00 }, + fall: { type: 'bezier', id: 'fall', y0: 1, y1: 0, p1x: 0.45, p1y: 0.95, p2x: 0.55, p2y: 0.05 }, + gate: { type: 'steps', id: 'gate', n: 2 }, + steps: { type: 'steps', id: 'steps', n: 3 }, + arch: { type: 'arch', id: 'arch' } + }; + + function evalCurve(curve, u) { + u = clamp01(u); + if (!curve) return u; + if (curve.type === 'steps') { + const n = within(Math.round(curve.n) || 2, 2, 8); + return Math.min(n - 1, Math.floor(u * n)) / (n - 1); + } + if (curve.type === 'arch') return Math.sin(Math.PI * u); + if (curve.type === 'bezier') { + // Cubic from (0, y0) to (1, y1); x(t) is monotone while both control xs + // stay in [0,1], so a short bisection recovers t for any u. + const { y0 = 0, y1 = 1, p1x, p1y, p2x, p2y } = curve; + const bx = (t) => 3 * (1 - t) * (1 - t) * t * p1x + 3 * (1 - t) * t * t * p2x + t * t * t; + const by = (t) => (1 - t) * (1 - t) * (1 - t) * y0 + 3 * (1 - t) * (1 - t) * t * p1y + 3 * (1 - t) * t * t * p2y + t * t * t * y1; + let lo = 0, hi = 1; + for (let i = 0; i < 24; i++) { + const mid = (lo + hi) / 2; + if (bx(mid) < u) lo = mid; else hi = mid; + } + return clamp01(by((lo + hi) / 2)); + } + return u; + } + + function bakeLut(curve) { + const lut = []; + for (let i = 0; i <= 32; i++) lut.push(Number(evalCurve(curve, i / 32).toFixed(4))); + return lut; + } + + // ── level to knob ─────────────────────────────────────────────────────── + + // The narrowest window and the shortest stretch of knob a band may have. + const MIN_WINDOW = 0.02; + const MIN_OUT = 0.05; + + const api = { + clamp01, PRESETS, evalCurve, bakeLut, MIN_WINDOW, MIN_OUT, + + // The response at a position in the window: the band's curve, or, for a + // band saved before there were curves, its boost exponent (above 1x a + // quiet band reaches its top early, below 1x a loud one holds back). + curveValue(band, u) { + return band.curve ? evalCurve(band.curve, u) + : Math.pow(clamp01(u), 1 / within(Number(band.gain) || 1, 0.2, 4)); + }, + + // Where a level sits in the band's window, 0..1: the input of the curve. + // `env` is the band's { lo, hi } envelope while auto range runs, null for + // the band's own inMin..inMax. Auto range maps a fixed slice of the + // envelope: under 0.10 of it is squelched, so the resting noise at the + // floor does not dance, and 0.95 of it is already full scale. + position(level, band, env) { + if (env) { + return clamp01((clamp01((level - env.lo) / Math.max(0.001, env.hi - env.lo)) - 0.10) / (0.95 - 0.10)); + } + const lo = clamp01(band.inMin); + return clamp01((level - lo) / Math.max(MIN_WINDOW, clamp01(band.inMax) - lo)); + }, + + // The knob value for a position in the window, through the curve. + output(band, u) { + const lo = clamp01(band.outMin); + return lo + api.curveValue(band, u) * (clamp01(band.outMax) - lo); + }, + + // The default band: what Reset gives, and what a first run starts with. + defaultBand(index, caps) { + return normalizeBand(null, index, caps); + }, + + // The whole mapping, made whole: { autoRange, smoothing, attack, bands[4] }. + // `caps` is the source's { hzMin, hzMax }. smoothing and attack are the + // two alphas of the level glide: how fast a level falls, how fast it rises. + // + // Nothing stored is a first run, and starts the way the panel does: auto + // range on, four default bands. Something stored is somebody's mapping + // and is not improved behind their back; in particular one saved before + // auto range existed has no `autoRange` and stays manual. + normalizeConfig(raw, caps) { + const stored = raw && Array.isArray(raw.bands) ? raw : { autoRange: true, bands: [] }; + return { + autoRange: stored.autoRange === true, + smoothing: within(Number(stored.smoothing) || 0.35, 0.05, 0.9), + attack: within(Number(stored.attack) || 0.65, 0.05, 0.9), + bands: [0, 1, 2, 3].map((i) => normalizeBand(stored.bands[i], i, caps)) + }; + } + }; + + const HZ = [[60, 250], [250, 2000], [2000, 5000], [5000, 16000]]; + + // lo and hi inside floor..ceiling, in that order, at least `gap` apart. + function pair(lo, hi, floor, ceiling, gap) { + lo = within(lo, floor, ceiling); + hi = within(hi, floor, ceiling); + if (lo > hi) [lo, hi] = [hi, lo]; + if (hi - lo < gap) { + hi = Math.min(ceiling, lo + gap); + lo = Math.min(lo, hi - gap); + } + return [lo, hi]; + } + + // One band, made whole. No band at all is the default: its slice of the + // spectrum, the full window, the Smooth curve already baked. A band that IS + // stored keeps what it has and gains nothing: saved before curves existed + // it has no curve and keeps its boost exponent, and saved when the output + // range was `base` + `range` it is read as that. + function normalizeBand(raw, index, caps) { + const b = raw && typeof raw === 'object' ? raw + : { outMin: 0.30, outMax: 0.85, curve: { ...PRESETS.smooth }, lut: bakeLut(PRESETS.smooth) }; + const base = b.base ?? 0.30; + const [hzMin, hzMax] = pair(b.hzMin ?? HZ[index][0], b.hzMax ?? HZ[index][1], caps.hzMin, caps.hzMax, 10); + const [inMin, inMax] = pair(b.inMin ?? 0, b.inMax ?? 1, 0, 1, MIN_WINDOW); + const [outMin, outMax] = pair(b.outMin ?? base, b.outMax ?? base + (b.range ?? 0.55), 0, 1, MIN_OUT); + return { + hzMin, hzMax, + // Four bands, four knobs, one line between them: band i drives knob i. + knob: index, + muted: b.muted === true, + inMin, inMax, + gain: within(Number(b.gain) || 1, 0.2, 4), + outMin, outMax, + curve: b.curve && typeof b.curve === 'object' ? b.curve : null, + lut: Array.isArray(b.lut) && b.lut.length > 1 ? b.lut : null + }; + } + + return api; +})(); + +// ── EXTENSION ONLY ──────────────────────────────────────────────────────── +// +// What the extension's audio source knows and the panel's does not. + +(function (M) { + 'use strict'; + + // Where the mapping is stored. The panel's address is not in it: that is the + // popup's, under a key of its own, so the editor and the popup never write + // the same value and neither can put the other's old one back. + M.CONFIG_KEY = 'patternflowAudioConfig'; + + // Tab audio through an AnalyserNode: the frequencies worth drawing, and the + // dB the level axis runs between, bottom then top. Levels everywhere in the + // extension are 0..1 along that axis. + M.SOURCE = { hzMin: 20, hzMax: 20000, db: [-80, -10] }; + + M.normalizeDb = function (db) { + return M.clamp01((db - M.SOURCE.db[0]) / (M.SOURCE.db[1] - M.SOURCE.db[0])); + }; + + // The knob gets the band's TABLE where it has one, interpolated the way the + // firmware interpolates it, and not the curve the table was baked from: a + // table rounds a step's corner, and what is sent should be what a panel + // running the same mapping would do. Whatever in the extension asks for a + // knob value gets this: PFMap.output() reaches it, so offscreen.js and the + // editor's Preview do. + const drawn = M.curveValue; + M.curveValue = function (band, u) { + const lut = band.lut; + if (!lut || lut.length < 2) return drawn(band, u); + const at = M.clamp01(u) * (lut.length - 1); + const i = Math.floor(at); + const j = Math.min(lut.length - 1, i + 1); + return M.clamp01(lut[i]) * (1 - (at - i)) + M.clamp01(lut[j]) * (at - i); + }; + + // Auto-range envelope, one per band: the floor and peak the band has + // recently seen, in the same units as its level. Both edges jump to a new + // extreme at once and drift back slowly (ENV_RELEASE per 33 ms tick is about + // 8 s, the panel's own time constant). ENV_MIN_SPAN stops silence from + // collapsing the window into a noise amplifier. There is no microphone gate + // here, unlike the panel: tab audio is digital, and silent means zero. + M.ENV_RELEASE = 0.004; + M.ENV_MIN_SPAN = 0.06; + + M.newEnvelope = function () { + return { lo: 1, hi: 0 }; + }; + + M.trackEnvelope = function (env, level, release) { + const v = M.clamp01(level); + const r = release || M.ENV_RELEASE; + if (v > env.hi) env.hi = v; else env.hi += (v - env.hi) * r; + if (v < env.lo) env.lo = v; else env.lo += (v - env.lo) * r; + if (env.hi < env.lo + M.ENV_MIN_SPAN) env.hi = env.lo + M.ENV_MIN_SPAN; + return env; + }; +})(PFMap); diff --git a/tools/patternflow-audio-extension/offscreen.html b/tools/patternflow-audio-extension/offscreen.html index 15521ab9..ab66731b 100644 --- a/tools/patternflow-audio-extension/offscreen.html +++ b/tools/patternflow-audio-extension/offscreen.html @@ -2,6 +2,7 @@ + diff --git a/tools/patternflow-audio-extension/offscreen.js b/tools/patternflow-audio-extension/offscreen.js index e216c148..dd3cf4d3 100644 --- a/tools/patternflow-audio-extension/offscreen.js +++ b/tools/patternflow-audio-extension/offscreen.js @@ -1,4 +1,47 @@ -let config = null; +// Patternflow Audio — offscreen document: the analysis, the socket, and the +// truth about both. +// +// Tab capture hands over a MediaStream, and a MediaStream needs a document to +// live in; a service worker has none and is put to sleep besides. So this +// page holds the capture, runs the mapping (mapping.js) 30 times a second and +// writes the four knob lanes to the panel. +// +// It is also the one place that KNOWS whether a capture is running, which +// address the socket points at, whether that socket opened, whether the panel +// on the other end is listening, and why a capture ended. Every state message +// it sends carries all of that (see status()), so the service worker, which +// Chrome restarts with empty memory whenever it likes, can rebuild from any +// single one of them, or ask. +// +// An offscreen document has chrome.runtime and nothing else. No +// chrome.storage: the mapping arrives in messages (the popup reads it at +// Start, the editor sends every save) and is normalised HERE, on receipt, +// whoever sent it. A `host` inside a mapping is ignored; the address comes +// only with start, manual-connect and host, which only the popup sends. + +const WS_PORT = 81; // where the panel's audio socket listens +const TICK_MS = 33; // analyse and send at about 30 Hz +const REPORT_MS = 120; // levels and spectrum to the popup and the editor + +// The panel hands a lane back to its encoder 500 ms after the last message +// that set it, and docs/audio-ws-spec.md asks for a resend at least every 250. +// A frame that has not changed is resent on the first tick past this. The +// timer's 33 ms come out nearer 35, so that is six ticks, about 210 ms; at +// 200 it was seven, 245, and once in eight minutes 251. +const HOLD_MS = 180; + +const QUIET_MS = 2000; // a spectrum flat for this long is "no sound" +const ASK_MS = 4000; // how long the panel gets to answer over HTTP + +let config = null; // the mapping: PFMap.normalizeConfig() of what arrived +let address = ''; // as the popup sent it: a name or an IP, a port if one was typed +let host = ''; // 'name:port' the socket is pointed at, '' when idle +let tabTitle = ''; +let error = ''; // what is wrong right now +let note = ''; // why the last capture ended, when nobody pressed Stop +let running = false; // a tab is being analysed +let manual = false; // the test connection: a socket, no audio + let audioCtx = null; let analyser = null; let sourceNode = null; @@ -8,109 +51,251 @@ let ws = null; let tickTimer = null; let reconnectTimer = null; let lastLevelReport = 0; -let smoothing = [0, 0, 0, 0]; -let running = false; -let manual = false; let wsWanted = false; let wsSerial = 0; -let lastSentValues = [-1, -1, -1, -1]; + +// What the panel was last told, and when. `driven` is the lanes this socket +// has set and not yet handed back. let lastSentBody = ''; +let lastSentAt = 0; +let driven = [false, false, false, false]; + +// The test connection's sliders: a knob that was moved is held where it was +// put, null is a knob nobody touched. +let manualLanes = [null, null, null, null]; + +// Audio-React on the panel (the AUD row of its NETWORK screen): true, false, +// or null when the panel has not said. The socket opens either way and the +// panel ignores every frame while it is off, so an open socket alone is not +// "live". +let panelAudio = null; +let checking = false; // that question is on its way + +// Socket attempts in a row that never opened. The first one asks the panel's +// HTTP side what is there, once; `streak` changes whenever the answer to that +// would no longer be about the current attempt. +let failures = 0; +let streak = 0; + +// Per band: the smoothed level, and the envelope auto range maps it through. +let levels = [0, 0, 0, 0]; +let envelopes = [0, 1, 2, 3].map(PFMap.newEnvelope); + +// Per band, the loudest tick since the last report: its level, where that sat +// in the window and what the knob got. A report every 120 ms that carried the +// latest tick showed a kick at anything from 42% to 100% of its height. +let peakLevels = [-1, -1, -1, -1]; +let peakPos = [0, 0, 0, 0]; +let peakOutputs = [0, 0, 0, 0]; + +let heard = false; // this capture has had sound at least once +let heardAt = 0; // when it last had + +function connected() { + return !!ws && ws.readyState === WebSocket.OPEN; +} -// Auto-range envelopes, one pair per band: the floor and peak the band has -// recently seen, in the same dbNorm units as the levels. Attack is instant on -// both edges, release is a slow exponential (~8 s at the 30 Hz tick — the -// device runs 0.002 at 60 Hz, this is the same time constant). MIN_SPAN stops -// silence from collapsing the window into a noise amplifier. Same idea as the -// device's auto range, minus its microphone gate — tab audio is digital and -// silent means zero, so there is no whine floor to fence off. -let envLo = [1, 1, 1, 1]; -let envHi = [0, 0, 0, 0]; -const ENV_RELEASE = 0.004; -const ENV_MIN_SPAN = 0.06; -const AUTO_LO = 0.10; // relative squelch inside the tracked window -const AUTO_HI = 0.95; // relative full-scale - -function resetEnvelopes() { - envLo = [1, 1, 1, 1]; - envHi = [0, 0, 0, 0]; +// The one word for all of it. The popup and the editor both print from this, +// so they cannot disagree about what "live" means: +// idle nothing is running +// connecting no open socket yet, or the panel has not yet said whether it listens +// off connected, and Audio-React is switched off on the panel +// live a tab is captured and the panel is being driven +// test the test connection is up +// error see `error` +function phase() { + if (error) return 'error'; + if (!running && !manual) return 'idle'; + if (!connected() || checking) return 'connecting'; + if (panelAudio === false) return 'off'; + return running ? 'live' : 'test'; } -function trackEnvelopes(levels) { - for (let i = 0; i < 4; i++) { - const v = clamp01(levels[i] || 0); - if (v > envHi[i]) envHi[i] = v; - else envHi[i] += (v - envHi[i]) * ENV_RELEASE; - if (v < envLo[i]) envLo[i] = v; - else envLo[i] += (v - envLo[i]) * ENV_RELEASE; - if (envHi[i] < envLo[i] + ENV_MIN_SPAN) envHi[i] = envLo[i] + ENV_MIN_SPAN; +function status() { + return { + running, + manual, + connected: connected(), + phase: phase(), + host, + tabTitle, + error, + note, + panelAudio, + heard, + silent: running && performance.now() - heardAt > QUIET_MS, + held: manual ? manualLanes.slice() : [] + }; +} + +// Always the whole status, plus whatever is live. A patch that carried only +// `connected` left the service worker to remember the rest, and after a +// restart it remembered nothing: the popup said Idle over a running capture. +function patchState(live) { + chrome.runtime.sendMessage({ type: 'offscreen-state', patch: { ...status(), ...live } }).catch(() => {}); +} + +// The popup sends a checked address, with a port only if one was typed. +function wsHost() { + return /:\d+$/.test(address) ? address : `${address}:${WS_PORT}`; +} + +// The same panel over HTTP. Never the socket's port: a port that was typed is +// where the audio socket is, and the panel's API is on 80 whatever that says. +function httpName() { + return address.replace(/:\d+$/, ''); +} + +// One question to the panel's HTTP API. Returns null when nobody answered in +// time, else { status, json } with json null for anything that is not JSON. +// The panel serves one HTTP connection at a time, so these are single +// requests at moments that matter, never a poll. +async function ask(path, options) { + const abort = new AbortController(); + const timer = setTimeout(() => abort.abort(), ASK_MS); + try { + const reply = await fetch(`http://${httpName()}${path}`, { ...options, cache: 'no-store', signal: abort.signal }); + return { status: reply.status, json: reply.ok ? await reply.json().catch(() => null) : null }; + } catch (failure) { + return null; + } finally { + clearTimeout(timer); } } -const MIN_HZ = 20; -const MAX_HZ = 20000; +// Is the panel listening? Asked once when the socket opens (`opening`: until +// the answer is in, nobody is told "live"), and again each time the popup +// opens onto an open socket: the switch is on the panel and may have been +// thrown either way since, so "off" and "live" are both old news by then. +// Anything but a clear yes or no (no answer, a 404 from firmware that has no +// such route) is "not known": nothing is claimed about it, and an earlier +// answer stands. +async function checkPanel(opening) { + const serial = wsSerial; + if (opening) { + checking = true; + patchState(); + } + const answer = await ask('/api/audio'); + if (serial !== wsSerial) return; + const on = answer && answer.json && answer.json.audioRuntime; + if (typeof on === 'boolean') panelAudio = on; + checking = false; + patchState(); +} -function patchState(patch) { - chrome.runtime.sendMessage({ type: 'offscreen-state', patch }).catch(() => {}); +// The popup's Turn on. Returns what to tell the person when it did not work. +async function turnOn() { + const serial = wsSerial; + const answer = await ask('/api/audio', { + method: 'POST', + // The panel's web server reads a body as arguments only under this type. + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: 'on=1' + }); + const on = answer && answer.json && answer.json.audioRuntime; + if (typeof on !== 'boolean') { + return 'The panel did not answer. Audio-React can also be switched on at the panel: the AUD row of its NETWORK screen.'; + } + if (serial === wsSerial) panelAudio = on; + return ''; } -function normalizeHost(host) { - let value = (host || 'patternflow.local').trim(); - value = value.replace(/^https?:\/\//, '').replace(/^wss?:\/\//, '').replace(/\/.*$/, ''); - if (!value.includes(':')) value += ':81'; - return value; +// A socket that will not open says nothing about why. One look at the +// panel's HTTP side does: nobody there, a panel without the audio feature, or +// something that answers and still refuses the socket. Asked once per run of +// failures: the socket retries every 1.2 s, and a question per retry would +// queue up on an address that never answers. +async function diagnose() { + const mine = streak; + const name = httpName(); + const answer = await ask('/api/status'); + if (mine !== streak) return; + const caps = answer && answer.json && answer.json.caps; + if (!answer) { + error = `No panel at ${name}. Check the address (the panel's NETWORK screen shows its IP) and that this computer is on the same Wi-Fi. Retrying.`; + } else if (Array.isArray(caps) && !caps.includes('audio')) { + error = `The panel at ${name} does not run the Audio edition. Get it at patternflow.work/editions.`; + } else { + // Firmware from before `caps`, a wrong port, or not a panel at all: no + // more is known than that the socket stays shut. + error = `${Array.isArray(caps) ? 'The panel' : 'Something'} at ${name} answers, but the audio connection to ${host} does not open. Retrying.`; + } + patchState(); } -function wsUrl() { - return `ws://${normalizeHost(config.host)}`; +// A new target, or the current one answered: what was learned about the last +// run of failures no longer applies. +function newStreak() { + failures = 0; + streak++; } function connectWs() { clearTimeout(reconnectTimer); const previous = ws; + ws = null; try { if (previous) { previous.onopen = null; - previous.onerror = null; previous.onclose = null; previous.close(); } - } catch (error) {} + } catch (failure) {} const serial = ++wsSerial; - const socket = new WebSocket(wsUrl()); + panelAudio = null; + checking = false; + + let socket; + try { + socket = new WebSocket(`ws://${host}`); + } catch (failure) { + // Not something a socket can be opened to. The popup checks what is + // typed, so this came from elsewhere; trying again would fail the same. + error = `"${host}" is not an address a connection can be made to.`; + patchState(); + return; + } ws = socket; + let opened = false; socket.onopen = () => { if (socket !== ws || serial !== wsSerial) return; - patchState({ connected: true, error: '' }); - }; - - socket.onerror = () => { - if (socket !== ws || serial !== wsSerial) return; - patchState({ connected: false, error: 'WebSocket error' }); + opened = true; + error = ''; + newStreak(); + // The panel let go of every lane when the last socket closed: it has been + // told nothing, so the next tick says everything again. + resetWire(); + checkPanel(true); }; socket.onclose = () => { if (socket !== ws || serial !== wsSerial) return; - patchState({ connected: false }); - if (wsWanted && config) reconnectTimer = setTimeout(connectWs, 1200); + if (!opened && ++failures === 1) diagnose(); + patchState(); + if (wsWanted) reconnectTimer = setTimeout(connectWs, 1200); }; + + // The old socket is gone and this one is not open yet: say so now, before + // anyone reads a `connected` that was about the old address. + patchState(); } function send(msg, options = {}) { - if (!ws || ws.readyState !== WebSocket.OPEN) return false; + if (!connected()) return false; if (!options.control && ws.bufferedAmount > 0) return false; ws.send(msg); return true; } -// -1 is "nothing sent yet", so the first real level always goes out. With -// absolute values there is no baseline to match — only a cache of what the -// lane was last told. -function resetOutputBaselines() { - lastSentValues = [-1, -1, -1, -1]; +// The panel on the other end has been told nothing (a new socket, or `off`). +function resetWire() { lastSentBody = ''; + lastSentAt = 0; + driven = [false, false, false, false]; } // Absolute, not a delta. @@ -131,24 +316,35 @@ function resetOutputBaselines() { // also the quietest one. // // A '-' leaves a lane alone, which is what a muted band sends. +// +// An unchanged frame is NOT news, but it still has to be said: the panel +// releases a lane 500 ms after the last message that set it. Skipping +// unchanged frames handed the knobs back half a second into any silence, any +// pause, any curve resting on one step, while the popup said Live. So a frame +// goes out when it differs from the last one or when HOLD_MS have passed. function sendLanes(values) { + // A lane this socket set and no longer drives is handed back now, once, + // and not left to the panel's timeout. + for (let i = 0; i < 4; i++) { + if (values[i] === null && driven[i] && send(`off=${i}`, { control: true })) driven[i] = false; + } + if (values.every((v) => v === null)) return; + const body = values .map((v) => (v === null ? '-' : Math.max(0, Math.min(1, v)).toFixed(3))) .join(','); - if (body === lastSentBody) return; - if (send(`a=${body}`)) lastSentBody = body; -} - -function sendOutputValue(knob, value) { - const idx = Math.max(0, Math.min(3, Number(knob) || 0)); - const normalized = Math.max(0, Math.min(1, Number(value) || 0)); - if (Math.abs(normalized - lastSentValues[idx]) < 0.002) return; - if (send(`k=${idx},v=${normalized.toFixed(3)}`)) { - lastSentValues[idx] = normalized; + const now = performance.now(); + if (body === lastSentBody && now - lastSentAt < HOLD_MS) return; + if (!send(`a=${body}`)) return; + lastSentBody = body; + lastSentAt = now; + for (let i = 0; i < 4; i++) { + if (values[i] !== null) driven[i] = true; } } -async function stop() { +// Everything off and forgotten. `why` is for a capture that ended by itself. +async function stop(why = '') { running = false; manual = false; wsWanted = false; @@ -157,27 +353,30 @@ async function stop() { tickTimer = null; reconnectTimer = null; wsSerial++; + newStreak(); send('off', { control: true }); - resetOutputBaselines(); + resetWire(); try { if (ws) { ws.onopen = null; - ws.onerror = null; ws.onclose = null; ws.close(); } - } catch (error) {} + } catch (failure) {} ws = null; try { if (sourceNode) sourceNode.disconnect(); - } catch (error) {} + } catch (failure) {} sourceNode = null; if (mediaStream) { - mediaStream.getTracks().forEach((track) => track.stop()); + mediaStream.getTracks().forEach((track) => { + track.onended = null; + track.stop(); + }); mediaStream = null; } @@ -188,65 +387,93 @@ async function stop() { analyser = null; freqBuf = null; - smoothing = [0, 0, 0, 0]; - resetEnvelopes(); - patchState({ running: false, manual: false, connected: false, levels: [], outputs: [], spectrum: [], env: [] }); + config = null; + address = ''; + host = ''; + tabTitle = ''; + error = ''; + note = why; + panelAudio = null; + checking = false; + heard = false; + manualLanes = [null, null, null, null]; + levels = [0, 0, 0, 0]; + peakLevels = [-1, -1, -1, -1]; + envelopes = [0, 1, 2, 3].map(PFMap.newEnvelope); + patchState({ levels: [], pos: [], outputs: [], spectrum: [], env: [] }); } -async function start(streamId, nextConfig) { +async function start(message) { await stop(); - config = nextConfig; - running = true; - manual = false; - wsWanted = true; - resetOutputBaselines(); - - audioCtx = new AudioContext(); - mediaStream = await navigator.mediaDevices.getUserMedia({ - audio: { - mandatory: { - chromeMediaSource: 'tab', - chromeMediaSourceId: streamId - } - }, - video: false - }); - - analyser = audioCtx.createAnalyser(); - analyser.fftSize = 2048; - analyser.smoothingTimeConstant = 0.3; - freqBuf = new Float32Array(analyser.frequencyBinCount); + try { + config = PFMap.normalizeConfig(message.config, PFMap.SOURCE); + address = String(message.host || '').trim(); + host = wsHost(); + tabTitle = message.tabTitle || ''; + running = true; + wsWanted = true; + + audioCtx = new AudioContext(); + mediaStream = await navigator.mediaDevices.getUserMedia({ + audio: { + mandatory: { + chromeMediaSource: 'tab', + chromeMediaSourceId: message.streamId + } + }, + video: false + }); - sourceNode = audioCtx.createMediaStreamSource(mediaStream); - sourceNode.connect(analyser); - analyser.connect(audioCtx.destination); + // The stream ends when its tab is closed. Nothing else says so: the + // analyser keeps returning silence and the socket stays open, so the popup + // went on reading Live over a tab that no longer existed. + mediaStream.getAudioTracks().forEach((track) => { + track.onended = () => stop('The captured tab was closed.'); + }); - connectWs(); - tickTimer = setInterval(tick, config.sendIntervalMs || 33); - patchState({ running: true, manual: false, error: '' }); + analyser = audioCtx.createAnalyser(); + analyser.fftSize = 2048; + analyser.smoothingTimeConstant = 0.3; + freqBuf = new Float32Array(analyser.frequencyBinCount); + + sourceNode = audioCtx.createMediaStreamSource(mediaStream); + sourceNode.connect(analyser); + analyser.connect(audioCtx.destination); + + // "No sound yet" is said after QUIET_MS of nothing, counted from here. + heardAt = performance.now(); + + connectWs(); + tickTimer = setInterval(tick, TICK_MS); + } catch (failure) { + // Half a capture is not one: undo what was set up, then let the caller + // say why. + await stop(); + throw failure; + } } -async function manualConnect(nextConfig) { +async function manualConnect(target) { await stop(); - config = nextConfig; + address = String(target || '').trim(); + host = wsHost(); manual = true; wsWanted = true; - resetOutputBaselines(); connectWs(); - patchState({ running: false, manual: true, error: '' }); -} - -function sendManualValue(knob, value) { - const idx = Math.max(0, Math.min(3, Number(knob) || 0)); - const normalized = Math.max(0, Math.min(1, Number(value) || 0)); - const outputs = [0, 0, 0, 0]; - outputs[idx] = normalized; - sendOutputValue(idx, normalized); - patchState({ outputs }); + tickTimer = setInterval(tick, TICK_MS); } -function clamp01(value) { - return Math.max(0, Math.min(1, Number(value) || 0)); +// The popup committed another address while something is connected: follow it. +function retarget(target) { + if (!wsWanted) return; + const was = host; + address = String(target || '').trim(); + host = wsHost(); + if (host === was) return; + error = ''; + newStreak(); + resetWire(); // a different panel has been told nothing yet + connectWs(); } function hzToBin(hz) { @@ -256,158 +483,95 @@ function hzToBin(hz) { // Raw level only. Gain used to be folded in here, which meant it scaled the // signal BEFORE the input window clipped it — so raising boost also slid the // band out of its own window, and the two controls fought. It shapes the -// curve now, in mapBandOutput, which is the curve the popup draws. -function normalizeDb(db) { - return clamp01((db + 80) / 70); -} - -function bandEnergy(band) { - const minBin = Math.max(0, hzToBin(band.hzMin)); - const maxBin = Math.min(freqBuf.length - 1, hzToBin(band.hzMax)); +// curve now (PFMap.curveValue), which is the curve the editor draws. +function binsLevel(minBin, maxBin) { + minBin = Math.max(0, minBin); + maxBin = Math.min(freqBuf.length - 1, maxBin); if (maxBin < minBin) return 0; let sum = 0; for (let i = minBin; i <= maxBin; i++) sum += freqBuf[i]; - const avgDb = sum / (maxBin - minBin + 1); - return normalizeDb(avgDb); -} - -// The whole chain: -// -// level -> window (manual in/full, or the auto-tracked envelope) -// -> response curve -> [rests at .. peaks at] -// -// The response curve has two generations. Bands the editor has touched carry -// a baked 33-point lookup table (band.lut) — any shape at all, including -// falling and non-monotonic ones — and this side only interpolates, exactly -// like the firmware will. Bands never touched keep the legacy boost exponent -// (band.gain): above 1x a quiet band reaches its top early, below 1x a loud -// one holds back. Ends stay put either way. -function curveValue(band, u) { - const lut = band.lut; - if (Array.isArray(lut) && lut.length >= 2) { - const pos = clamp01(u) * (lut.length - 1); - const i = Math.floor(pos); - const j = Math.min(lut.length - 1, i + 1); - const f = pos - i; - return clamp01(Number(lut[i]) || 0) * (1 - f) + clamp01(Number(lut[j]) || 0) * f; - } - const gain = Math.max(0.2, Math.min(4, Number(band.gain) || 1)); - return Math.pow(clamp01(u), 1 / gain); -} - -function mapBandOutput(energy, band, index) { - let u; - if (config.autoRange && index !== undefined) { - // The band's own recent floor..peak is the window; a fixed relative - // squelch keeps the resting noise of the window's bottom from dancing. - const lo = envLo[index]; - const span = Math.max(0.001, envHi[index] - envLo[index]); - u = clamp01((clamp01((energy - lo) / span) - AUTO_LO) / (AUTO_HI - AUTO_LO)); - } else { - const inMin = clamp01(band.inMin ?? 0); - const inMax = Math.max(inMin + 0.01, clamp01(band.inMax ?? 1)); - u = clamp01((energy - inMin) / (inMax - inMin)); - } - const outMin = clamp01(band.outMin ?? 0); - const outMax = clamp01(band.outMax ?? 1); - return outMin + curveValue(band, u) * (outMax - outMin); + return PFMap.normalizeDb(sum / (maxBin - minBin + 1)); } function computeSpectrum() { const count = 64; const values = []; - const logMin = Math.log10(MIN_HZ); - const logMax = Math.log10(MAX_HZ); + const logMin = Math.log10(PFMap.SOURCE.hzMin); + const logMax = Math.log10(PFMap.SOURCE.hzMax); for (let i = 0; i < count; i++) { - const t0 = i / count; - const t1 = (i + 1) / count; - const hz0 = 10 ** (logMin + (logMax - logMin) * t0); - const hz1 = 10 ** (logMin + (logMax - logMin) * t1); - const minBin = Math.max(0, hzToBin(hz0)); - const maxBin = Math.min(freqBuf.length - 1, hzToBin(hz1)); - if (maxBin < minBin) { - values.push(0); - continue; - } - let sum = 0; - for (let bin = minBin; bin <= maxBin; bin++) sum += freqBuf[bin]; - values.push(normalizeDb(sum / (maxBin - minBin + 1))); + const hz0 = 10 ** (logMin + (logMax - logMin) * (i / count)); + const hz1 = 10 ** (logMin + (logMax - logMin) * ((i + 1) / count)); + values.push(binsLevel(hzToBin(hz0), hzToBin(hz1))); } return values; } function tick() { + // The test connection has no audio: it keeps saying where the sliders are. + if (manual) { + sendLanes(manualLanes); + return; + } if (!running || !analyser || !freqBuf || !config) return; analyser.getFloatFrequencyData(freqBuf); - const bands = config.bands || []; - const outputs = []; - const levels = []; - const alpha = config.smoothing ?? 0.35; - - while (smoothing.length < bands.length) smoothing.push(0); - if (smoothing.length > bands.length) smoothing.length = bands.length; - - // A lane nothing drives stays null, and goes out as '-'. Two bands on the - // same knob: the last one wins, deterministically, rather than whichever - // happened to get the socket first. - const lanes = [null, null, null, null]; + const bands = config.bands; + const auto = config.autoRange; // Levels first, for every band including muted ones — the editor shows a // muted band's level so you can see what it WOULD do, and the auto-range // envelopes keep tracking so unmuting does not open on a stale window. - for (let i = 0; i < bands.length; i++) { - const raw = bandEnergy(bands[i]); + for (let i = 0; i < 4; i++) { + const raw = binsLevel(hzToBin(bands[i].hzMin), hzToBin(bands[i].hzMax)); // Glide ballistics: a hit ATTACKS at its own speed, the fall RELEASES at // the damping - two user-set alphas. Symmetric smoothing made percussive // music feel late; this is the VU-meter split every reactive light wants. - const atk = Math.max(0.05, Math.min(0.9, config.attack ?? 0.65)); - const a = raw > smoothing[i] ? atk : alpha; - smoothing[i] = a * raw + (1 - a) * smoothing[i]; - levels[i] = smoothing[i]; - } - if (config.autoRange) trackEnvelopes(levels); - - for (let i = 0; i < bands.length; i++) { - const band = bands[i]; - const idx = Math.max(0, Math.min(3, Number(band.knob) || 0)); - if (band.muted) { - outputs[i] = 0; - continue; - } - const mapped = mapBandOutput(levels[i], band, i); - outputs[i] = mapped; - lanes[idx] = mapped; + const a = raw > levels[i] ? config.attack : config.smoothing; + levels[i] = a * raw + (1 - a) * levels[i]; + if (auto) PFMap.trackEnvelope(envelopes[i], levels[i]); } - // Muting a band hands its lane back once, and only if this client had it. + // The mapping itself is PFMap's: where each level sits in its window, and + // what the knob gets for that. Both go out with the levels, so the editor + // can draw what was mapped instead of working it out a second time. + // + // A lane nothing drives stays null, and goes out as '-'. + const lanes = [null, null, null, null]; for (let i = 0; i < 4; i++) { - if (lanes[i] === null && lastSentValues[i] !== -1) { - send(`off=${i}`, { control: true }); - lastSentValues[i] = -1; - } else if (lanes[i] !== null) { - lastSentValues[i] = lanes[i]; + const pos = PFMap.position(levels[i], bands[i], auto ? envelopes[i] : null); + const output = PFMap.output(bands[i], pos); + if (!bands[i].muted) lanes[bands[i].knob] = output; + if (levels[i] > peakLevels[i]) { + peakLevels[i] = levels[i]; + peakPos[i] = pos; + peakOutputs[i] = output; } } sendLanes(lanes); const now = performance.now(); - if (now - lastLevelReport > 120) { + if (now - lastLevelReport > REPORT_MS) { lastLevelReport = now; + const spectrum = computeSpectrum(); + // Flat is what the plot shows as flat: nothing above a hundredth of it. + if (spectrum.some((v) => v > 0.01)) { + heard = true; + heardAt = now; + } patchState({ - levels, - outputs, - spectrum: computeSpectrum(), + levels: peakLevels.slice(), + pos: peakPos.slice(), + outputs: peakOutputs.slice(), + spectrum, // The editor draws these as each box's breathing top and bottom edge. - env: config.autoRange - ? envLo.map((lo, i) => ({ lo, hi: envHi[i] })) - : [], - autoRange: config.autoRange === true + env: auto ? envelopes.map((e) => ({ lo: e.lo, hi: e.hi })) : [], + autoRange: auto }); + peakLevels = [-1, -1, -1, -1]; } } @@ -415,49 +579,52 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.target !== 'offscreen') return; (async () => { - if (message.type === 'start') { - await start(message.streamId, message.config); - sendResponse({ ok: true }); - return; - } - - if (message.type === 'stop') { - await stop(); - config = null; - sendResponse({ ok: true }); - return; - } - - if (message.type === 'config') { - const oldUrl = config ? wsUrl() : ''; - config = message.config; - if (running) resetOutputBaselines(); - if (ws && oldUrl !== wsUrl()) connectWs(); - sendResponse({ ok: true }); - return; - } - - if (message.type === 'manual-connect') { - await manualConnect(message.config); - sendResponse({ ok: true }); - return; - } - - if (message.type === 'manual-value') { - sendManualValue(message.knob, message.value); - sendResponse({ ok: true }); - return; - } - - if (message.type === 'release') { - send('off', { control: true }); - resetOutputBaselines(); - sendResponse({ ok: true }); - return; + // What went wrong with the request itself, for whoever sent it. Not a + // fault of the capture, so it does not go into `error`. + let refused = ''; + + switch (message.type) { + case 'start': + await start(message); + break; + case 'manual-connect': + await manualConnect(message.host); + break; + case 'stop': + await stop(); + break; + case 'host': + retarget(message.host); + break; + case 'config': + // Only a running capture has a use for a mapping; the next Start + // brings its own. What changed goes out with the next tick: a new + // value as a new frame, a band that was muted as `off=N`. + if (running) config = PFMap.normalizeConfig(message.config, PFMap.SOURCE); + break; + case 'manual-value': + if (manual) { + manualLanes[Math.max(0, Math.min(3, Number(message.knob) || 0))] = PFMap.clamp01(message.value); + sendLanes(manualLanes); + } + break; + case 'panel-on': + refused = await turnOn(); + break; + case 'panel-check': + if (connected() && !checking) await checkPanel(false); + break; + case 'status': + break; + default: + sendResponse({ ok: false, error: 'Unknown message', state: status() }); + return; } - })().catch((error) => { - patchState({ running: false, connected: false, error: String(error.message || error) }); - sendResponse({ ok: false, error: String(error.message || error) }); + sendResponse({ ok: !refused, error: refused || undefined, state: status() }); + })().catch((failure) => { + error = String(failure.message || failure); + patchState(); + sendResponse({ ok: false, error, state: status() }); }); return true; diff --git a/tools/patternflow-audio-extension/popup.css b/tools/patternflow-audio-extension/popup.css index cc83cb1b..742541b6 100644 --- a/tools/patternflow-audio-extension/popup.css +++ b/tools/patternflow-audio-extension/popup.css @@ -1,9 +1,7 @@ :root { --cream: #f4efe6; - --cream-2: #ede7db; --ink: #141414; --muted: #6b655a; - --faint: #a69f90; --rule: #d9d1c0; --led: #e8552e; --ok: #267a43; @@ -15,6 +13,26 @@ box-sizing: border-box; } +/* `hidden` has to win over the display values set below. */ +[hidden] { + display: none !important; +} + +/* Keyboard focus. The browser's own ring is near black, and on the filled + buttons that is black on black. */ +:focus-visible { + outline: 2px solid var(--led); + outline-offset: 2px; +} + +/* A text field shows its ring on a mouse click too. In the accent colour + that read as a warning, right against the red border of text that is not + an address, so the address keeps an ink ring. */ +input[type="text"]:focus-visible { + outline-color: var(--ink); + outline-offset: 0; +} + body { width: 460px; max-height: 620px; @@ -27,9 +45,7 @@ body { } header, -.section-head, -.band-head, -.band-actions { +.section-head { display: flex; align-items: center; } @@ -69,12 +85,18 @@ section { background: transparent; } +/* Neutral unless it has something to claim: green is "the panel is being + driven" (or the test connection is up), red is something wrong. Idle and + connecting are neither. Colour is the only thing that tells Live from + Idle, so the word is heavy enough to carry it. */ .status { min-width: 82px; padding: 5px 8px 4px; border: 1px solid var(--ink); background: var(--field); - font-size: 10px; + color: var(--muted); + font-size: 11px; + font-weight: 600; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; letter-spacing: .12em; text-align: center; @@ -101,25 +123,26 @@ section { } input, -select, button { font: inherit; } -input[type="text"], -select { +input[type="text"] { width: 100%; + padding: 8px 9px; border: 1px solid var(--rule); background: var(--field); color: var(--ink); } -input[type="text"] { - padding: 8px 9px; +/* Text that is not an address: nothing was stored, nothing connects. The + ring of a focused field would hide a red border, so it turns red with it. */ +input[aria-invalid="true"] { + border-color: var(--bad); } -select { - padding: 3px 6px; +input[aria-invalid="true"]:focus-visible { + outline-color: var(--bad); } button { @@ -139,28 +162,25 @@ button:hover { color: var(--ink); } -.small-button, -.remove-band { - min-height: 26px; - padding: 5px 8px; -} - -.remove-band { +/* A control that has nothing to act on in the current state. */ +button:disabled { border-color: var(--rule); - background: transparent; + background: var(--rule); color: var(--muted); + cursor: default; } -.actions { - display: grid; - /* Two, since WS Test moved into the diagnostics fold. */ - grid-template-columns: 1fr 1fr; - gap: 7px; +/* The second button of a section: an action offered, not the main one. */ +button.quiet { margin-top: 8px; + padding: 0 14px; + background: transparent; + color: var(--ink); } -.actions button { - padding: 8px; +button.quiet:hover { + background: var(--ink); + color: var(--cream); } .detail { @@ -175,6 +195,13 @@ button:hover { gap: 8px; } +/* A test connection has no audio, so the plot has nothing to show, and with + it the open fold made the popup taller than the 600 px Chrome allows: K3 + and K4 ended up under the edge. The fold takes the plot's place. */ +body:has(#test[open]) .spectrum-section { + display: none; +} + .spectrum-wrap { position: relative; height: 132px; @@ -188,223 +215,29 @@ button:hover { height: 100%; } -.spectrum-bands { - position: absolute; - inset: 0; - pointer-events: none; -} - -.spectrum-band { - position: absolute; - top: 0; - bottom: 0; - border-left: 1px solid var(--led); - border-right: 1px solid var(--led); - background: rgba(232, 85, 46, .16); -} - -.spectrum-band span { - position: absolute; - left: 5px; - top: 5px; - color: var(--ink); - font-size: 10px; - font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; -} - +/* The plot is logarithmic, so the labels are placed, not spread: popup.js + gives each one its `left`. Spread evenly, "1k" sat over 317 Hz. */ .spectrum-scale { - display: grid; - grid-template-columns: repeat(5, 1fr); + position: relative; + height: 15px; margin-top: 5px; color: var(--muted); font-size: 10px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; } -.spectrum-scale span:last-child { - text-align: right; -} - -.global { - display: grid; - grid-template-columns: 1fr 42px; - align-items: center; - gap: 8px; -} - -.global label, -.manual-grid label { - display: grid; - align-items: center; - gap: 8px; - color: var(--muted); - font-size: 11px; -} - -.global label { - grid-template-columns: 74px 1fr; -} - -.manual-grid { - display: grid; - gap: 8px; -} - -.manual-grid label { - grid-template-columns: 28px 1fr 40px; -} - -.value, -output { - color: var(--ink); - text-align: right; - font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; - font-variant-numeric: tabular-nums; -} - -.band { - margin: 0; - padding-top: 12px; -} - -.band-head { - justify-content: space-between; - gap: 8px; - margin-bottom: 8px; -} - -.band-title { - font-size: 11px; - font-weight: 600; - text-transform: uppercase; -} - -.band-actions { - gap: 7px; -} - -.target { - display: grid; - grid-template-columns: auto 48px; - align-items: center; - gap: 5px; - color: var(--muted); - font-size: 11px; -} - -.band-strip, -.map-row { - display: grid; - align-items: center; - gap: 8px; - margin: 8px 0; -} - -.band-strip { - grid-template-columns: 1fr 1fr 92px; -} - -.map-row { - grid-template-columns: 48px 1fr 92px; -} - -.map-row > span, -.row span { - color: var(--muted); - font-size: 10px; - font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; - text-transform: uppercase; -} - -.band-readout { - display: grid; - grid-template-columns: 1fr auto 1fr; - gap: 4px; - align-items: center; - color: var(--muted); - font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; - font-size: 10px; -} - -.map-sliders { - display: grid; - gap: 4px; -} - -.row { - display: grid; - grid-template-columns: 54px 1fr 48px; - align-items: center; - gap: 8px; - margin: 6px 0; -} - -details.advanced { - margin-top: 8px; -} - -details.advanced summary { - color: var(--muted); - cursor: pointer; - font-size: 10px; - font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; - letter-spacing: .08em; - text-transform: uppercase; -} - -input[type="range"] { - width: 100%; - accent-color: var(--ink); -} - -.meter { - height: 6px; - margin-top: 8px; - overflow: hidden; - background: var(--cream-2); - border: 1px solid var(--rule); -} - -.meter.out { - height: 3px; - margin-top: 3px; -} - -.meter div { - width: 0; - height: 100%; - background: var(--led); - transition: width .08s linear; -} - -.meter.out div { - background: var(--ink); -} - -/* ── Named frequency ranges, per band ──────────────────────────────────── - The sliders are log-scaled now, so a range is reachable by hand — but - nobody should have to drag for "bass" when the name is the thing they - mean. Same six ranges the device's own audio page offers. */ -.hz-presets { - display: flex; - flex-wrap: wrap; - gap: 4px; - margin-top: 6px; +.spectrum-scale span { + position: absolute; + top: 0; + transform: translateX(-50%); } -.hz-presets button { - min-height: 0; - padding: 3px 7px; - font-size: 10px; - letter-spacing: 0.04em; - border-color: var(--rule); - background: transparent; - color: var(--muted); +.spectrum-scale span:first-child { + transform: none; } -.hz-presets button:hover { - color: var(--ink); - border-color: var(--ink); +.spectrum-scale span:last-child { + transform: translateX(-100%); } /* ── Diagnostics, folded ───────────────────────────────────────────────── @@ -428,241 +261,40 @@ input[type="range"] { width: 100%; } -/* ── Band selector ─────────────────────────────────────────────────────── - Four bands, one editor on screen. These say which one you are on, which - knob it drives, and whether it is muted — the three things worth knowing - before you switch. */ -.band-tabs { +.manual-grid { display: grid; - /* Four bands and All. */ - grid-template-columns: repeat(4, 1fr) 1.2fr; - gap: 6px; - margin-top: 10px; + gap: 8px; } -.band-tab { - display: flex; - flex-direction: column; +.manual-grid label { + display: grid; + grid-template-columns: 28px 1fr 40px; align-items: center; - gap: 1px; - padding: 6px 0 5px; - min-height: 0; - border-color: var(--rule); - background: transparent; - color: var(--muted); -} - -.band-tab strong { font-size: 13px; font-weight: 600; } -.band-tab span { font-size: 9px; letter-spacing: 0.08em; } - -.band-tab:hover { color: var(--ink); border-color: var(--ink); } - -.band-tab.active { - background: var(--ink); - border-color: var(--ink); - color: var(--cream); -} - -/* A muted band stays in place and stays reachable — it just is not driving - anything, and should not look like it is. */ -.band-tab.muted { opacity: 0.45; } -.band-tab.muted strong { text-decoration: line-through; } - -.spectrum-band { cursor: pointer; } -.spectrum-band.muted { opacity: 0.35; } - -.mute-band { - min-height: 26px; - padding: 5px 8px; - border-color: var(--rule); - background: transparent; - color: var(--muted); -} - -.mute-band.on { - border-color: var(--led); - color: var(--led); -} - -.hint { - font-size: 10px; - letter-spacing: 0.04em; - color: var(--faint); -} - -/* `hidden` loses to any explicit display, and .band sets one. Say it again. */ -.band[hidden] { display: none; } - -.band-tab.all strong { font-size: 11px; letter-spacing: 0.06em; } - -/* ── The response graph ────────────────────────────────────────────────── - Six sliders became one picture. Left to right is how loud the band is, - bottom to top is where the knob lands, and the line between them is every - number at once — which is the thing the sliders could not show. */ -.band-row { - display: flex; - align-items: baseline; - justify-content: space-between; - gap: 10px; - margin-bottom: 6px; -} - -.band-key { + gap: 8px; color: var(--muted); - font-size: 10px; - letter-spacing: 0.14em; - text-transform: uppercase; - font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; - white-space: nowrap; -} - -.band-note { color: var(--faint); font-size: 10px; } - -.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; } - -.plot-wrap { display: flex; gap: 10px; } - -.plot-axis { - display: flex; - flex-direction: column; - justify-content: space-between; - align-items: flex-end; - width: 26px; - height: 180px; - padding: 2px 0; - color: var(--faint); - font-size: 9px; - font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + font-size: 11px; } -.plot-col { flex: 1; min-width: 0; } - -.plot { - position: relative; - height: 180px; - border: 1px solid var(--ink); - background: var(--field); - overflow: hidden; - cursor: grab; - /* The handles are dragged; the popup must not pan or select instead. */ - touch-action: none; - user-select: none; +output { color: var(--ink); -} - -.plot:active { cursor: grabbing; } - -/* the stretch of knob the music is allowed to use */ -.plot-out { position: absolute; left: 0; right: 0; background: #f0e6d6; } -/* the levels this band responds to at all */ -.plot-in { - position: absolute; top: 0; bottom: 0; - border-left: 1px dashed var(--faint); - border-right: 1px dashed var(--faint); -} - -.plot-curve { position: absolute; inset: 0; width: 100%; height: 100%; } - -.plot-vline { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--led); opacity: .55; } -.plot-hline { position: absolute; left: 0; right: 0; height: 1px; background: var(--led); opacity: .55; } - -.plot-dot { - position: absolute; - width: 9px; height: 9px; - margin: -5px 0 0 -5px; - border-radius: 50%; - background: var(--led); - box-shadow: 0 0 0 2px var(--field); -} - -/* Handles: triangles pointing at the edge they move. Input on the floor, - output on the right wall — so which axis a handle belongs to is visible - before it is dragged. */ -.h { position: absolute; width: 14px; height: 14px; background: var(--ink); } -.h-in-min, .h-in-max { bottom: 0; margin-left: -7px; clip-path: polygon(50% 0, 100% 100%, 0 100%); } -.h-out-min, .h-out-max { right: 0; margin-top: -7px; clip-path: polygon(0 50%, 100% 0, 100% 100%); } -.h.on { background: var(--led); } - -.plot-scale { - display: flex; - justify-content: space-between; - margin-top: 3px; - color: var(--faint); - font-size: 9px; + text-align: right; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + font-variant-numeric: tabular-nums; } -/* The same four numbers as words, for anyone who wants to read rather than - aim — and so a value can be checked without hovering a handle. */ -.readout { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 7px 14px; - margin-top: 12px; - padding: 10px 11px; - background: var(--field); - border: 1px solid var(--rule); -} - -.readout > div { - display: flex; - align-items: baseline; - justify-content: space-between; - gap: 8px; -} - -.readout span { color: var(--muted); font-size: 11px; } -.readout output { font-size: 11px; } - -/* Boost bends the line rather than moving its ends, so it is not something - to drag on the plot. Seven steps, and the hint says what the shape means. */ -.boost-row { display: flex; align-items: center; gap: 12px; margin-top: 13px; } -.boost-steps { flex: 1; display: flex; gap: 3px; } - -.boost-steps button { - flex: 1; - min-height: 0; - height: 22px; - padding: 0; - border-color: var(--rule); - background: var(--field); +input[type="range"] { + width: 100%; + accent-color: var(--ink); } -.boost-steps button.soft { background: var(--cream-2); } -.boost-steps button.on { background: var(--ink); border-color: var(--ink); } -.boost-steps button:hover { border-color: var(--ink); } - -.boost-row .gainOut { width: 34px; text-align: right; font-size: 11px; } -.boost-hint { margin-top: 6px; color: var(--muted); font-size: 11px; } - -/* The meters said nothing about which was which. */ -.meter-row { display: flex; align-items: center; gap: 8px; margin-top: 8px; } -.meter-row .meter { flex: 1; margin-top: 0; } - -.meter-key { - width: 26px; - color: var(--faint); - font-size: 9px; - letter-spacing: 0.1em; - text-transform: uppercase; - font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; +input[type="range"]:disabled { + opacity: .45; } -/* How much of its knob this band actually uses. The number that names a - band which is technically working and doing nothing. */ -.travelOut { width: 42px; text-align: right; font-size: 10px; color: var(--muted); } -.travelOut.weak { color: var(--led); } - -/* The one road to the mapping editor — mapping no longer lives in the popup. */ -.editor-cta { +/* The one road to the mapping editor: mapping no longer lives in the popup. + Full width, and outlined like every second action (button.quiet), so the + one filled button of the popup's first screen is Start. */ +button.editor-cta { width: 100%; - font: inherit; - font-weight: 600; - cursor: pointer; - border: 1px solid var(--ink); - border-radius: 2px; - background: var(--ink); - color: var(--cream); - padding: 9px 12px; + margin-top: 0; } -.editor-cta:hover { background: var(--led); border-color: var(--led); } diff --git a/tools/patternflow-audio-extension/popup.html b/tools/patternflow-audio-extension/popup.html index af06a852..40940e9b 100644 --- a/tools/patternflow-audio-extension/popup.html +++ b/tools/patternflow-audio-extension/popup.html @@ -12,27 +12,27 @@

                    Patternflow Audio

                    -
                    Idle
                    +
                    Idle
                    -
                    + +
                    - -
                    + +
                    Open the tab you want to hear, then press Start.
                    -
                    - - -
                    + +
                    - -
                    Bands, boxes and response curves live there.
                    + +
                    Boxes and response curves for K1–K4 live there.
                    @@ -42,31 +42,27 @@

                    Patternflow Audio

                    -
                    - 20 - 100 - 1k - 10k - 20k -
                    + +
                    -
                    +
                    Test without audio - -
                    - - - - -
                    + +
                    + + + + +
                    + diff --git a/tools/patternflow-audio-extension/popup.js b/tools/patternflow-audio-extension/popup.js index 02ea9437..200fcd36 100644 --- a/tools/patternflow-audio-extension/popup.js +++ b/tools/patternflow-audio-extension/popup.js @@ -1,45 +1,37 @@ // Patternflow Audio — popup: the capture console. // -// This used to also be the mapping editor — band strips, drag handles, boost -// buttons — until the real editor moved to its own tab (editor.html), where -// boxes on a spectrum have room to be dragged. What remains here is what a -// popup is good at: start/stop the capture, point at the device, see that -// audio is flowing, and one button to the place where mapping actually -// happens. The popup never edits bands anymore; it only ships the stored -// config along with start/config messages. - -const MIN_HZ = 20; -const MAX_HZ = 20000; - -const DEFAULT_CONFIG = { - host: 'patternflow.local', - smoothing: 0.35, - sendIntervalMs: 33, - // Four, because the panel has four knobs. Shipping one meant a first run - // moved a single knob and looked broken; the device page has defaulted to - // four the whole time. - bands: [ - { hzMin: 60, hzMax: 250, knob: 0, outMin: 0.30, outMax: 0.85, inMin: 0, inMax: 1, gain: 1 }, - { hzMin: 250, hzMax: 2000, knob: 1, outMin: 0.30, outMax: 0.85, inMin: 0, inMax: 1, gain: 1 }, - { hzMin: 2000, hzMax: 5000, knob: 2, outMin: 0.30, outMax: 0.85, inMin: 0, inMax: 1, gain: 1 }, - { hzMin: 5000, hzMax: 16000, knob: 3, outMin: 0.30, outMax: 0.85, inMin: 0, inMax: 1, gain: 1 } - ] -}; - -let config = structuredClone(DEFAULT_CONFIG); +// What a popup is good at: start and stop the capture, say where the panel +// is, see that audio is flowing, and one button to the tab where mapping +// happens (editor.html). Two things are this file's and nobody else's. +// +// The panel's address. It has a storage key of its own, so the editor, +// which owns the mapping (PFMap.CONFIG_KEY), and the popup never write the +// same value, and an editor tab left open cannot put an old address back. +// It is committed on Enter, on leaving the field and on Start. Committing +// per keystroke dropped a live socket for every character and tried +// 192.168.0.4 on the way to 192.168.0.42. +// +// Asking for the capture. The tab's stream id needs the click that opened +// this popup. +// +// The mapping is read at Start and handed over as it is stored; nothing here +// edits it or writes it. What is running, what it is connected to, whether +// the panel is listening and why a capture ended belong to the offscreen +// document: it sums them up as one `phase`, and this file prints that. Every +// control here follows it too, so none is offered that has nothing to act on. + +const HOST_KEY = 'patternflowAudioHost'; +const DEFAULT_HOST = 'patternflow.local'; + +let host = DEFAULT_HOST; // the committed address +let hostError = ''; // why the field's text is not an address +let failure = ''; // what the last thing asked for here could not do let state = null; -let saveTimer = null; const $ = (id) => document.getElementById(id); -const clamp01 = (value) => Math.max(0, Math.min(1, Number(value) || 0)); -const clampHz = (value) => Math.max(MIN_HZ, Math.min(MAX_HZ, Number(value) || MIN_HZ)); -function storageGet(key) { - return new Promise((resolve) => chrome.storage.local.get(key, resolve)); -} - -function storageSet(value) { - return new Promise((resolve) => chrome.storage.local.set(value, resolve)); +function storageGet(keys) { + return new Promise((resolve) => chrome.storage.local.get(keys, resolve)); } function sendMessage(message) { @@ -60,123 +52,155 @@ function getStreamId(tabId) { }); } -function newBand(index = config.bands.length) { - const presets = [ - [60, 250], - [250, 2000], - [2000, 5000], - [5000, 16000] - ]; - const [hzMin, hzMax] = presets[index % presets.length]; - return { - hzMin, - hzMax, - knob: Math.min(index, 3), - outMin: 0.30, - outMax: 0.85, - inMin: 0.00, - inMax: 1.00, - gain: 1.00 - }; +// What someone typed, as the address to store: a host name or an IP, with a +// port only if they gave one. A pasted URL loses its scheme and path. Returns +// null when what is left is not an address. +// +// The shape is checked here and not left to `new URL`: Chrome's parser turns +// "not a host" into not%20a%20host and calls it valid. +const ADDRESS = /^(\[[0-9a-f:.]+\]|[\p{L}\p{N}](?:[\p{L}\p{N}._-]*[\p{L}\p{N}])?)(?::(\d+))?$/iu; + +function parseHost(text) { + const value = String(text || '').trim() + .replace(/^[a-z][a-z0-9+.-]*:\/\//i, '') + .replace(/[/?#].*$/, ''); + if (!value) return DEFAULT_HOST; + + const parts = ADDRESS.exec(value); + if (!parts) return null; + const [, name, port] = parts; + if (port !== undefined && !(Number(port) >= 1 && Number(port) <= 65535)) return null; + try { + // The parser's spelling of it: lower case, 192.168.1 written out in full. + return new URL(`ws://${name}`).hostname + (port === undefined ? '' : `:${Number(port)}`); + } catch (error) { + return null; + } } -function normalizeBand(raw, index) { - const legacyBase = Number.isFinite(Number(raw.base)) ? Number(raw.base) : 0.30; - const legacyRange = Number.isFinite(Number(raw.range)) ? Number(raw.range) : 0.55; - let outMin = Number.isFinite(Number(raw.outMin)) ? Number(raw.outMin) : legacyBase; - let outMax = Number.isFinite(Number(raw.outMax)) ? Number(raw.outMax) : legacyBase + legacyRange; - - outMin = clamp01(outMin); - outMax = clamp01(outMax); - if (outMin > outMax) [outMin, outMax] = [outMax, outMin]; - - let inMin = Number.isFinite(Number(raw.inMin)) ? clamp01(raw.inMin) : 0; - let inMax = Number.isFinite(Number(raw.inMax)) ? clamp01(raw.inMax) : 1; - if (inMin > inMax) [inMin, inMax] = [inMax, inMin]; - if (inMax - inMin < 0.01) inMax = Math.min(1, inMin + 0.01); - - let hzMin = clampHz(raw.hzMin ?? 60); - let hzMax = clampHz(raw.hzMax ?? 250); - if (hzMin > hzMax) [hzMin, hzMax] = [hzMax, hzMin]; - if (hzMax - hzMin < 10) hzMax = Math.min(MAX_HZ, hzMin + 10); - - const band = { - hzMin, - hzMax, - knob: Math.max(0, Math.min(3, Number(raw.knob ?? index) || 0)), - muted: raw.muted === true, - outMin, - outMax, - inMin, - inMax, - gain: Math.max(0.2, Math.min(4, Number(raw.gain) || 1)) - }; - // The editor's fields ride through untouched. Rebuilding the band without - // them meant every popup save quietly erased the curves — Start wiped the - // mapping it was about to use. - if (raw.curve && typeof raw.curve === 'object') band.curve = raw.curve; - if (Array.isArray(raw.lut) && raw.lut.length >= 2) band.lut = raw.lut; - return band; +// state.host is the address as the socket uses it, port included. In a +// sentence the port every panel has is left off: the address as it was typed. +function shown(socketHost) { + return String(socketHost || '').replace(/:81$/, ''); } -// Four bands, always, because the panel has four knobs. -function normalizeConfig(raw) { - const stored = Array.isArray(raw?.bands) ? raw.bands : []; - const bands = []; - for (let i = 0; i < 4; i++) { - bands.push(normalizeBand(stored[i] || newBand(i), i)); +// Chrome's own words for the two ways it refuses a capture, in plain ones. +// Anything else is passed on as it came. +function plain(message) { + const text = String(message || ''); + if (/active stream/i.test(text)) { + return 'This tab is already being captured. Press Stop first.'; } - - return { - ...DEFAULT_CONFIG, - ...raw, - smoothing: Math.max(0.05, Math.min(0.9, Number(raw?.smoothing) || DEFAULT_CONFIG.smoothing)), - bands - }; + if (/activeTab|cannot be captured/i.test(text)) { + return 'Chrome does not let this page be captured. Go to the tab that is playing, open this popup there and press Start.'; + } + return text; } -function persistConfig() { - clearTimeout(saveTimer); - saveTimer = setTimeout(async () => { - await storageSet({ patternflowAudioConfig: config }); - await sendMessage({ type: 'config', config }); - }, 120); +// Take the field's text as the address. Returns it, or null when the text is +// not one; then nothing is stored and nothing connects. +function commitHost() { + const field = $('host'); + const next = parseHost(field.value); + if (!next) { + hostError = `"${field.value.trim()}" is not an address. Use a name or an IP, like patternflow.local or 192.168.0.42.`; + field.setAttribute('aria-invalid', 'true'); + renderState(); + return null; + } + + hostError = ''; + field.removeAttribute('aria-invalid'); + field.value = next; + if (next !== host) { + host = next; + chrome.storage.local.set({ [HOST_KEY]: host }); + // A capture or a test connection that is up follows the address. + if (state && (state.running || state.manual)) { + sendMessage({ type: 'host', host }).then((response) => { + if (response && response.state) state = response.state; + renderState(); + }); + } + } + renderState(); + return host; } -function setStatus(text, ok) { +// `tone`: 'ok' is green, 'bad' is red, nothing is neutral. +function setStatus(text, tone) { const el = $('status'); el.textContent = text; - el.className = 'status ' + (ok ? 'ok' : 'bad'); + el.className = 'status' + (tone ? ' ' + tone : ''); } +// The status, the sentence under the address and every control, from the +// state. The words are per phase (offscreen.js phase()); the editor's chip +// uses the same ones. function renderState() { - if (!state) { - setStatus('Idle', false); - drawSpectrum([]); - return; + const s = state || {}; + const at = shown(s.host); + + let label = 'Idle'; + let tone = ''; + let detail = s.note || 'Open the tab you want to hear, then press Start.'; + + if (failure) { + label = 'Error'; + tone = 'bad'; + detail = failure; + } else if (s.phase === 'error') { + label = 'Error'; + tone = 'bad'; + detail = plain(s.error); + } else if (s.phase === 'connecting') { + label = 'Connecting'; + detail = `Connecting to ${at}.`; + } else if (s.phase === 'off') { + // The socket is open and the panel ignores every frame: not live. + label = 'Aud off'; + detail = 'Connected, but Audio-React is off on the panel.'; + } else if (s.phase === 'live') { + label = 'Live'; + tone = 'ok'; + if (!s.silent) detail = s.tabTitle ? `Capturing: ${s.tabTitle}` : 'Capturing this tab.'; + else detail = s.heard ? 'No sound from this tab right now.' : 'No sound from this tab yet.'; + } else if (s.phase === 'test') { + label = 'Test'; + tone = 'ok'; + detail = `Test without audio: connected to ${at}. Move a slider.`; } - if (state.error) { - setStatus('Error', false); - $('detail').textContent = state.error; - } else if (state.running && state.connected) { - setStatus('Live', true); - $('detail').textContent = state.tabTitle ? `Capturing: ${state.tabTitle}` : 'Capturing current tab.'; - } else if (state.manual && state.connected) { - setStatus('WS Test', true); - $('detail').textContent = `Manual test connected to ws://${config.host}:81`; - } else if (state.running) { - setStatus('Connecting', false); - $('detail').textContent = `Connecting to ws://${config.host}:81`; - } else if (state.manual) { - setStatus('Connecting', false); - $('detail').textContent = `Connecting manual test to ws://${config.host}:81`; - } else { - setStatus('Idle', false); - $('detail').textContent = 'Open the tab you want to hear, then press Start.'; - } + // Text in the field that is not an address is about the field, which has + // its red border. Nothing was stored and nothing reconnected, so the status + // word stays what is true: a capture to the old address is still Live. + if (hostError) detail = hostError; + + setStatus(label, tone); + $('detail').textContent = detail; + + // One button: Start until a tab is captured, Stop while one is. + $('connect').textContent = s.running ? 'Stop' : 'Start'; + $('panelOn').hidden = s.phase !== 'off' || !!hostError; - drawSpectrum(state.spectrum || []); + // The test connection and a capture are one or the other. Its button + // disconnects what it connected; its sliders move a panel only while the + // test is up and the panel listens. + $('manualConnect').textContent = s.manual ? 'Disconnect' : 'Connect'; + $('manualConnect').disabled = !!s.running; + $('manualConnect').title = s.running ? 'Stop the capture first.' : ''; + document.querySelectorAll('.manual').forEach((input) => { + input.disabled = s.phase !== 'test'; + // A knob that is being held shows where it is held, also in a popup + // opened later. Not under the hand that is moving it. + const held = s.held && s.held[Number(input.dataset.knob)]; + if (typeof held === 'number' && input !== document.activeElement) { + input.value = held; + input.parentElement.querySelector('output').textContent = held.toFixed(2); + } + }); + + drawSpectrum(s.spectrum || []); } function drawSpectrum(values) { @@ -201,39 +225,68 @@ function drawSpectrum(values) { const barCount = Math.max(1, values.length); const barWidth = width / barCount; for (let i = 0; i < barCount; i++) { - const v = clamp01(values[i] || 0); + const v = PFMap.clamp01(values[i]); const h = Math.max(1, v * (height - 12)); ctx.fillStyle = i % 2 ? '#6b655a' : '#141414'; ctx.fillRect(i * barWidth, height - h, Math.max(1, barWidth - 1), h); } } +// The frequency labels under the plot. Its bars are equal steps of log +// frequency from the source's lowest to its highest (offscreen.js +// computeSpectrum), so a label belongs at the same fraction of the width. +function placeScale() { + const { hzMin, hzMax } = PFMap.SOURCE; + const span = Math.log(hzMax / hzMin); + for (const [hz, text] of [[20, '20'], [100, '100'], [1000, '1k'], [10000, '10k'], [20000, '20k']]) { + const mark = document.createElement('span'); + mark.textContent = text; + mark.style.left = `${(Math.log(hz / hzMin) / span * 100).toFixed(2)}%`; + $('scale').append(mark); + } +} + +// The reply to a request: the state to draw, or the reason there is none. +function adopt(response, fallback) { + if (response && response.state) state = response.state; + if (!response || !response.ok) throw new Error((response && response.error) || fallback); + renderState(); +} + async function startCapture() { - config.host = $('host').value.trim() || 'patternflow.local'; - await storageSet({ patternflowAudioConfig: config }); + const address = commitHost(); + if (!address) return; const [tab] = await tabQuery({ active: true, currentWindow: true }); if (!tab || !tab.id) throw new Error('No active tab to capture.'); const streamId = await getStreamId(tab.id); - const response = await sendMessage({ + const stored = await storageGet(PFMap.CONFIG_KEY); + adopt(await sendMessage({ type: 'start', streamId, tabTitle: tab.title || '', - config - }); + host: address, + config: stored[PFMap.CONFIG_KEY] || null + }), 'Failed to start capture.'); +} - if (!response || !response.ok) throw new Error(response?.error || 'Failed to start capture.'); - state = response.state; +async function startManual() { + const address = commitHost(); + if (!address) return; + adopt(await sendMessage({ type: 'manual-connect', host: address }), 'Failed to connect.'); +} + +async function stopAll() { + const response = await sendMessage({ type: 'stop' }); + if (response && response.state) state = response.state; renderState(); } -async function startManual() { - config.host = $('host').value.trim() || 'patternflow.local'; - await storageSet({ patternflowAudioConfig: config }); - const response = await sendMessage({ type: 'manual-connect', config }); - if (!response || !response.ok) throw new Error(response?.error || 'Failed to connect manual test.'); - state = response.state; +// Something asked for here did not happen. The state is still the offscreen +// document's; this is said over it until the next thing is asked. +function showFailure(error) { + failure = plain(error.message || error); renderState(); } @@ -242,11 +295,14 @@ function bindManualControls() { const output = input.parentElement.querySelector('output'); const update = async () => { output.textContent = Number(input.value).toFixed(2); - await sendMessage({ + const response = await sendMessage({ type: 'manual-value', knob: parseInt(input.dataset.knob, 10), value: parseFloat(input.value) }); + // Not drawn (nothing else changed), but kept: it carries where each + // knob is now held. + if (response && response.state) state = response.state; }; input.addEventListener('input', update); input.addEventListener('change', update); @@ -254,55 +310,137 @@ function bindManualControls() { } async function init() { - const stored = await storageGet('patternflowAudioConfig'); - config = normalizeConfig(stored.patternflowAudioConfig); - - $('host').value = config.host; + const stored = await storageGet([HOST_KEY, PFMap.CONFIG_KEY]); + if (typeof stored[HOST_KEY] === 'string') { + host = parseHost(stored[HOST_KEY]) || DEFAULT_HOST; + } else { + // Before the address had a key of its own it rode inside the mapping. + // Move it across once; the copy left behind is never read again. + const legacy = stored[PFMap.CONFIG_KEY] && stored[PFMap.CONFIG_KEY].host; + const moved = typeof legacy === 'string' ? parseHost(legacy) : null; + if (moved) { + host = moved; + chrome.storage.local.set({ [HOST_KEY]: host }); + } + } + $('host').value = host; + + // `change` is Enter and leaving the field. The popup closing is neither (it + // closes with the field still focused), so that is asked for by name. + $('host').addEventListener('change', commitHost); + window.addEventListener('pagehide', commitHost); + // "Not an address" was about the text as it stood. Once it is being typed + // over, the sentence goes; the next commit judges the new text. $('host').addEventListener('input', () => { - config.host = $('host').value.trim() || 'patternflow.local'; - persistConfig(); + if (!hostError) return; + hostError = ''; + $('host').removeAttribute('aria-invalid'); + renderState(); + }); + + // The form makes Enter in the address a submit, the same event as a click + // on the button, and the two are not always the same wish. + let typedEnter = false; + $('host').addEventListener('keydown', (event) => { + typedEnter = event.key === 'Enter'; }); - $('connect').addEventListener('click', async () => { + $('device').addEventListener('submit', async (event) => { + event.preventDefault(); + const entered = typedEnter; + typedEnter = false; + failure = ''; + const s = state || {}; + // A capture is running and the button reads Stop. A click on it stops. + // Enter in the address never does: there it means "this address", and + // the capture moves to it. + if (s.running) { + if (entered) commitHost(); + else await stopAll(); + return; + } + // Enter over a test connection means the same, not "capture". + if (entered && s.manual) { + commitHost(); + return; + } try { - setStatus('Starting', false); + setStatus('Starting'); await startCapture(); } catch (error) { - state = { running: false, connected: false, error: String(error.message || error) }; - renderState(); + showFailure(error); } }); $('manualConnect').addEventListener('click', async () => { + failure = ''; + if (state && state.manual) { + await stopAll(); + return; + } try { - setStatus('Connecting', false); + setStatus('Connecting'); await startManual(); } catch (error) { - state = { running: false, connected: false, manual: false, error: String(error.message || error) }; - renderState(); + showFailure(error); } }); - $('stop').addEventListener('click', async () => { - const response = await sendMessage({ type: 'stop' }); - state = response.state; + // Audio-React is a switch on the panel (the AUD row of its NETWORK screen); + // this throws it from here. + $('panelOn').addEventListener('click', async () => { + failure = ''; + $('panelOn').disabled = true; + const response = await sendMessage({ type: 'panel-on' }); + $('panelOn').disabled = false; + if (response && response.state) state = response.state; + if (!response || !response.ok) failure = (response && response.error) || 'The panel did not answer.'; renderState(); }); - $('release').addEventListener('click', () => sendMessage({ type: 'release' })); - // The mapping editor gets a real tab: boxes dragged on a spectrum need // more room than a popup that closes the moment focus leaves it. - $('openEditor').addEventListener('click', () => { - chrome.tabs.create({ url: chrome.runtime.getURL('editor.html') }); + // + // One tab. Every editor tab holds its own copy of the mapping and saves the + // whole of it, so a second tab's next edit put its older copy over the + // first one's work. If the editor is open anywhere, that tab comes forward. + $('openEditor').addEventListener('click', async () => { + const url = chrome.runtime.getURL('editor.html'); + let open = []; + try { + const tabs = await chrome.runtime.getContexts({ contextTypes: ['TAB'] }); + open = tabs.filter((tab) => String(tab.documentUrl).split(/[?#]/)[0] === url); + } catch (error) {} + if (!open.length) { + chrome.tabs.create({ url }); + return; + } + // Both asked for before either lands: the popup closes as soon as focus + // leaves it, and takes whatever was still waiting with it. + chrome.windows.update(open[0].windowId, { focused: true }); + chrome.tabs.update(open[0].tabId, { active: true }); }); bindManualControls(); + placeScale(); drawSpectrum([]); const response = await sendMessage({ type: 'status' }); state = response?.state || null; + // A test connection that is up is what this popup is about: show it. + if (state && state.manual) $('test').open = true; renderState(); + + // Whether the panel listens was learned when the socket opened, and the + // switch is on the panel (its AUD row, its console), where it may have been + // thrown either way since: "off" that is on again, or Live over a panel + // that now ignores every frame. Opening the popup is the moment someone + // looks, so ask once more: one request per popup, never a poll. + if (state && ['off', 'live', 'test'].includes(state.phase)) { + const again = await sendMessage({ type: 'panel-check' }); + if (again && again.state) state = again.state; + renderState(); + } } chrome.runtime.onMessage.addListener((message) => { From 5922c29cdd70a6c0a72130ed55e6ef180c7d840f Mon Sep 17 00:00:00 2001 From: engmung <122682380+engmung@users.noreply.github.com> Date: Sun, 4 Oct 2026 14:43:19 +0900 Subject: [PATCH 06/10] firmware: modules are built at -O2 with exact inline maths, and Basics is rebuilt No pattern source is edited. What changes is how a .h becomes a .pfm: - build_module.py builds at -O2 (was -Os). On today's Basics presets, same board, same boot: 3..34 % more frames a second. - abi/pf_libm.h (new, included first by pf_module.h) gives floorf, ceilf, truncf, roundf, fminf, fmaxf and fmodf inline bodies that return what libm returns, bit for bit, and call the real symbol outside the range each proof covers. check_libm.py: 20,083,619,797 comparisons, 0 mismatches, MSVC and g++ with sanitizers. check_module_libm.py reads a module the real compiler built. _math_probe on a board: "math ok 9/9". - web/public/packs/basics.zip is rebuilt for the first time since 2026-08-15 (GCC 8.4, descriptor 2). All 33 against their August builds on one board: 1.11x..2.36x the frames, 1.52x at the median. - Old-style headers left untouched (floorf/fmodf per pixel), today's recipe -> this one: 0510 14.8 -> 10.3 ms, 0515-4 25.3 -> 17.5, 0520 26.9 -> 20.3, 0601 26.0 -> 20.2. - All 147 distinct public community headers build this way (the old recipe's compiler crashed on two) and each was loaded and run on a board: no reset, no refused load. What it costs, as accepted by the owner: - The pattern's own arithmetic can differ in the last bit (-O2 and inline code move where GCC fuses a*b+c). The seven functions are exact. - Code is larger (median 1.36x over 145 community patterns). Firmware before 3.10.5 places code in internal RAM and will refuse some that loaded; Basics now needs 3.5.1 (descriptor 2). CHANGELOG says which. Also: SHIPPED_CODE_CEILING becomes the 16 KB instruction cache plus an allow-list over the old 6144 B internal line; abi.sums re-pinned (no layout change; --update keeps its notes); the "module is 20 % slower" claim is replaced by a measurement (Origin: 9.56 ms compiled in, 9.81 as a module). Shared headers changed in comments only; the firmware image is unaffected. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/firmware-build.yml | 12 + .github/workflows/firmware-checks.yml | 13 + CHANGELOG.md | 44 ++ docs/rest-api.md | 2 +- firmware/README.md | 8 +- firmware/patternflow/abi/abi.sums | 9 +- firmware/patternflow/abi/pf_libm.h | 387 ++++++++++++++ firmware/patternflow/abi/pf_module.h | 38 +- firmware/patternflow/src/core_color.h | 9 +- firmware/patternflow/src/core_math.h | 33 +- firmware/patternflow/src/core_noise.h | 2 +- firmware/toolchain/README.md | 3 +- firmware/toolchain/build_module.py | 47 +- firmware/toolchain/check_abi_freeze.py | 65 ++- firmware/toolchain/check_libm.py | 58 ++ firmware/toolchain/check_module_libm.py | 356 +++++++++++++ firmware/toolchain/tests/libm_test.cpp | 500 ++++++++++++++++++ firmware/toolchain/tests/math_test.cpp | 2 +- firmware/toolchain/tests/module_elf_test.cpp | 104 +++- .../tests/modules/_libm_shapes/pattern.cpp | 106 ++++ .../tests/modules/_math_probe/pattern.cpp | 372 +++++++++++++ web/public/guide/console-demo/index.html | 2 +- web/public/guide/console-demo/knobs.html | 2 +- web/public/guide/console-demo/patterns.html | 2 +- web/public/guide/console-demo/pf-demo.js | 2 +- web/public/guide/console-demo/status.html | 2 +- web/public/guide/console-demo/update.html | 2 +- web/public/guide/console-demo/wifi.html | 2 +- web/public/packs/basics.json | 4 +- web/public/packs/basics.zip | Bin 121705 -> 165600 bytes web/src/lib/lab/cppPrompt.ts | 6 +- web/src/lib/pattern/packs.ts | 25 +- 32 files changed, 2133 insertions(+), 86 deletions(-) create mode 100644 firmware/patternflow/abi/pf_libm.h create mode 100644 firmware/toolchain/check_libm.py create mode 100644 firmware/toolchain/check_module_libm.py create mode 100644 firmware/toolchain/tests/libm_test.cpp create mode 100644 firmware/toolchain/tests/modules/_libm_shapes/pattern.cpp create mode 100644 firmware/toolchain/tests/modules/_math_probe/pattern.cpp diff --git a/.github/workflows/firmware-build.yml b/.github/workflows/firmware-build.yml index f0441056..5c8d8858 100644 --- a/.github/workflows/firmware-build.yml +++ b/.github/workflows/firmware-build.yml @@ -79,3 +79,15 @@ jobs: # of the split is that the blast radius differs. - name: Internal RAM this composition has already spent run: python firmware/toolchain/check_footprint.py --only ${{ matrix.composition }} + + # The one check of the pattern SDK that needs the Xtensa compiler, so it + # runs here, where the build above has just installed one, and once + # rather than five times. abi/pf_libm.h puts inline code behind floorf, + # fmodf and five more in every .pfm; firmware-checks.yml proves the + # arithmetic on the runner's own CPU, and cannot compile the half of the + # header that exists only in a module build. This builds a small module + # with build_module.py and reads the object: each spelling inline, the + # library call left only as its fallback, no fmaf import. A few seconds. + - name: Module SDK's libm is inline in a module the real compiler built + if: matrix.composition == 'default' + run: python firmware/toolchain/check_module_libm.py diff --git a/.github/workflows/firmware-checks.yml b/.github/workflows/firmware-checks.yml index 9d92b4ec..09a15e53 100644 --- a/.github/workflows/firmware-checks.yml +++ b/.github/workflows/firmware-checks.yml @@ -21,6 +21,17 @@ name: Core knows no features # what every pattern built afterwards renders — and reaches only newly built # modules, since an installed .pfm carries its own compiled copy. # +# check_libm.py — abi/pf_libm.h, which puts inline FPU code behind floorf, +# ceilf, truncf, roundf, fminf, fmaxf and fmodf in every .pfm so that a +# pattern nobody edits stops calling into the firmware's libm per pixel. The +# claim is that each of the seven returns exactly what libm returns, so this +# is equality of bits, not a band: all 2^32 floats through the one-argument +# functions and about three billion comparisons through the rest, against +# this runner's libm. One mismatch fails. It is the slow step here - a +# minute or two. (The half of that header only a module build compiles is +# read out of a built module by check_module_libm.py, in firmware-build.yml, +# where there is an Xtensa compiler.) +# # check_parser.py — the vendored HTTP request parser, the real Parsing.cpp # against a scripted socket and a fake clock. It runs on pf-net, where a loop # that waits for the peer without sleeping starves IDLE0 and the Core-0 @@ -93,6 +104,8 @@ jobs: run: python firmware/toolchain/check_oe.py --sanitize - name: Pattern SDK maths, colour and noise still measure the same run: python firmware/toolchain/check_math.py --sanitize + - name: Module SDK's inline floorf/fmodf return what libm returns, bit for bit + run: python firmware/toolchain/check_libm.py --sanitize - name: Thumbnail mailbox ownership and invalidation run: python firmware/toolchain/check_thumbs.py --sanitize - name: Wi-Fi and name-service recovery diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f32312c..f2f8ccfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,50 @@ All notable changes to Patternflow will be documented in this file, newest first - **What this takes away:** a pattern that wants a fresh start every time it is picked cannot have one. `setup()` runs once per load, as `firmware/CUSTOM_PATTERNS.md` now says. - **The console is light, and its six core pages look like one thing.** It opens light; dark is still the toggle in the header, and a choice made there is remembered. Console, Patterns, Status, Wi-Fi, Knobs and Update now share one set of parts - buttons, chips, list rows, fields, notices, section titles - from a base block every page opens with (`console/README.md`, "The look"), with one accent, the LED orange, kept for what is live: the current tab, the playing pattern, the panel being on. The home page leads with the panel itself: what is playing with its arrows, on/sleep, brightness and the four knobs, with the device's facts under them in the same card; the arrow keys step through patterns as the arrow buttons do. Which edition the panel runs has a card of its own instead of being one more row among the facts: its name, its versions, the feature pages it carries as links, the update notice when there is one, and a button to the other editions (or a line saying the panel's own hotspot has no internet). The numbered index of every page with a paragraph each is now a list of one-line links. The header no longer scrolls sideways on a phone: Console and Patterns, the build's own feature pages, then Wi-Fi, Knobs, Update and Status, wrapped onto rows. Long explanations are a line, with the rest behind a disclosure where it is needed. Windows showed every small label in Courier New because no font in the monospace list was a Windows one; the list now includes Cascadia Mono and Consolas. The Knobs page has an *All* row that sets direction and edges per click for the four at once (it reads *Mixed* while they differ). The Status page shows the crash record (`crash` in `/api/status`) when there is one, with a button to clear it. Feature pages are not edited and take the light palette from the header. Home is 8.9 KB gzipped (was 10.9), Knobs grew by 0.15 KB for its All row, the others are the same or slightly smaller, and the header script is 9.6 KB. On a panel on the home network a page still opens in about 0.1 s the first time and in under 0.01 s after. Every request, control and message the pages had is still there; checked on a panel by stepping through patterns, sleeping and waking it, dimming it, dragging a knob and playing a pattern from the list. The guide's live console demo is regenerated to match. +### Patterns + +- **Installed patterns run faster, and nobody has to edit one.** A pattern on a panel is a small compiled program (a `.pfm`). Two things about how it was compiled were costing frames, and both change where a module is built: + - It was built for size (`-Os`), on a note in the SDK that `-O2` bought about 2 %. Modules are now built at `-O2` (`build_module.py`). + - Every `floorf`, `ceilf`, `truncf`, `roundf`, `fminf`, `fmaxf` and `fmodf` in a pixel loop was a call out of the pattern into the firmware's maths library: 185 to 840 ns each as timed (`truncf` was not), 8,192 pixels a frame. The module SDK now gives those seven inline code (`abi/pf_libm.h`), so a header that calls them per pixel - most community patterns do - stops paying for the call. + + Frame time on one board, in one boot. The Basics presets as they are today, GCC 8.4: + + | | 0510 | 0512 | 0515-4 | 0520 | 0531 | 0601 | + |---|---|---|---|---|---|---| + | `-Os` | 11.9 ms | 23.2 | 15.0 | 23.4 | 13.7 | 15.0 | + | `-O2` | 10.3 ms | 22.6 | 11.2 | 19.7 | 12.4 | 13.6 | + + That is 3 to 34 % more frames a second; GCC 14.2 at `-O2` was another 1 to 8 % faster. Four presets as they stood before they were tuned by hand, with `floorf` and `fmodf` per pixel: + + | | 0510 | 0515-4 | 0520 | 0601 | + |---|---|---|---|---| + | built as before | 14.8 ms | 25.3 | 26.9 | 26.0 | + | `-O2` | 13.3 ms | 23.7 | 23.1 | 24.5 | + | `-O2`, maths inline | 10.3 ms | 17.5 | 20.3 | 20.2 | + + The last row was measured with a first version of the header. With the header as committed, all 147 distinct public community patterns build (the old recipe's compiler crashed on two of them), and each was loaded and run on a board: no reset, no refused load. +- **What is exact, and what is not.** The seven functions are exact: for every input, each returns the bits the library function returns. Each computes inline only the inputs that have one right answer, and hands the rest - a NaN, an infinity, a magnitude past the range its proof covers - to the call the pattern made before. `check_libm.py` holds them to that in CI: all 4,294,967,296 floats through `floorf`, `ceilf`, `truncf` and `roundf`, 419 million pairs through `fminf` and `fmaxf`, 481 million through `fmodf` by each of its two paths - twenty billion comparisons, no mismatch, under GCC with sanitizers and under MSVC. `check_module_libm.py` then reads a module the real compiler built, to see that this code is what a pattern's calls became, and `tests/modules/_math_probe` is the module that checks on a board what no PC can: that the panel's multiply-subtract is fused. It reported `math ok 9/9` on a board, over 1.17 million comparisons against the firmware's own library. One footnote: for `fminf`/`fmaxf` of a zero against a zero, or of a NaN, "the call the pattern made before" means what that call got from this compiler, which is not always newlib's answer for the arguments as written - GCC answers a call with constant arguments itself, and GCC 12 and later may swap the fallback's operands. + + What is not exact is the pattern's own arithmetic. `-O2` and inline code both move where GCC fuses `a*b+c` into one instruction (`-ffp-contract=fast`), so a value in a rebuilt pattern can differ in its last bit from the build before. Two cases, worked through: + - The cell hash written as one line, `sinf(floorf(x)*12.9898f + floorf(y)*78.233f)*43758.5453f`: 20 of 128 cells hash differently. + - A helper that ends in a multiply and that `-O2` inlines - a smoothstep: `mul.s` then `sub.s` becomes one `msub.s`. + + It shows only where a pattern amplifies the last bit: a float hash, state carried between frames, rarely the edge of a `floorf` band. Of 168 public community headers, one uses the 43758 float hash; 21 use the integer `PFNoise::cellHash`, which is unaffected. +- **The Basics pack is rebuilt**, for the first time since 15 August: the same 33 patterns in the same order, from today's preset sources, at `-O2`, with the firmware's own compiler. Against the August binaries on the same board, every one of the 33 is faster: 1.11 to 2.36 times the frames a second, 1.52 at the median (47 fps to 77 across the pack). + + | | 0510 | 0512 | 0515-4 | 0520 | 0531 | 0601 | + |---|---|---|---|---|---|---| + | August pack | 18.1 ms | 25.1 | 26.1 | 34.4 | 15.5 | 28.5 | + | rebuilt | 10.3 ms | 22.6 | 11.1 | 19.7 | 11.1 | 12.7 | + + It is also the first rebuild to carry the two SDK fixes of 3.10.1, and those change what is drawn. `cellHash`'s seed decorrelates, so Firefly Hollow and Midsummer Sea get a different random stream. `hsvToRgb` rounds, so the 16 patterns in the pack that colour through it are up to one level brighter on a channel. The pack is 166 KB where it was 122, and holds 104 KB of code where it held 63. +- **What the new builds need from the firmware.** + - **3.5.1 or later, for Basics.** Its modules are now stamped for the parameter bus (descriptor 2, where August's were 1), so a show can drive them - and firmware 3.2.0 to 3.4.0 refuses all 33. Update the firmware *before* reinstalling the pack: reinstalling replaces files that load with files that firmware will not. + - **3.10.5 or later, for the larger ones.** Firmware before 3.10.5 places a module's code in internal RAM, and the new builds are larger: 1.36 times the code at the median, over 145 community patterns built both ways with GCC 8.4. Thirteen of those 145 fitted an Audio build's budget of about 7.8 KB before and no longer do; nor does Breakout Arcade in Basics, at 14.2 KB where it was 5.4. From 3.10.5 code runs from PSRAM, and its size does not decide whether a module loads. + - Nothing else: a module built this way imports only names every loader since 3.2.0 resolves. +- **What you have to do.** A pattern already on a panel keeps the build it was installed with; nothing is rebuilt on the device. Update the firmware if the list above says to. Then install the Basics pack again from the site, and send a community pattern or a deck again: the community server keeps one build of each pattern, keyed by everything that goes into a build, so once it is redeployed each is compiled again the first time someone asks for it. +- **A module is 2.7 % slower than the same pattern compiled in, not 20 %.** The SDK said 20 % (a 2026-07 measurement: Origin, 53 fps against 43) and blamed the relocatable code model. Measured again on one board, A-B-B-A in one boot: Origin compiled in draws a frame in 9.56 ms, Origin as a module in 9.81. + ## [3.10.5] - 2026-10-02 ### Firmware diff --git a/docs/rest-api.md b/docs/rest-api.md index 05a4ff88..2f11c31f 100644 --- a/docs/rest-api.md +++ b/docs/rest-api.md @@ -282,7 +282,7 @@ An explicit pick here supersedes a pending console restore — without that, a p "abi": 2, "knobs": ["Waves", "Speed", "Sun", "Glitter"], "slug": "layer_stack", "absoluteReady": true, "panel_w": 128, "panel_h": 64, "module": "layer_stack.pfm", - "size": 6144, "opt": "-Os" + "size": 6144, "opt": "-O2" } ``` diff --git a/firmware/README.md b/firmware/README.md index 7652c57a..3b89cced 100644 --- a/firmware/README.md +++ b/firmware/README.md @@ -135,7 +135,8 @@ firmware/ │ ├── abi/ # Host ⇄ module contract for loadable patterns │ │ ├── pf_abi.h # Frozen C ABI: PFHostAPI, PFPatternModule, PF_ABI_VERSION │ │ ├── pf_params.h # The absolute parameter bus -│ │ └── pf_module.h # Module SDK — the ONE header a .pfm pattern includes +│ │ ├── pf_module.h # Module SDK — the ONE header a .pfm pattern includes +│ │ └── pf_libm.h # ...and what makes floorf/fmodf & co. exact inline code in it │ ├── patternflow_secrets.example.h # Template (copy to patternflow_secrets.h) │ ├── src/ # Foundation — the core, feature-free (see docs/EDITIONS.md) │ │ ├── core_display.h # HUB75 driver init + refresh-rate config @@ -304,6 +305,8 @@ The sin LUT is 4 KB (1024 entries, ~0.35° resolution) and shared. Do not build **`floorf`, `fminf` and `fmaxf` are function calls on this target**, not instructions - GCC emits a call into libm at every use, at every optimization level. That is what `ifloor`, `floorF`, `fract`, `clamp` and `clamp01` exist for: they truncate and correct, or compare, which the FPU does in one instruction each. Removing a single `floorf` from a per-pixel path measured *smaller* object code as well as faster, because the call sequence costs more than the inline does. +That is still how it is for code compiled into the firmware image (Origin, the features). **In a module the SDK now does it for a pattern that does not**: since 2026-10, `abi/pf_libm.h` puts inline code behind `floorf`, `ceilf`, `truncf`, `roundf`, `fminf`, `fmaxf` and `fmodf` - and behind `floor(x)`, `std::floor(x)`, `fmod(a, b)` and the like on floats - that returns, bit for bit, what the firmware's libm returns (`toolchain/check_libm.py` runs every float there is through it). A header nobody edits stops paying 185-840 ns for each of them (as timed; `truncf` was not). The PFMath forms are still the least code where they fit, with one exception worth knowing: `jsMod(x, m)` divides, which is a call unless `m` is a power of two, and in a module `fmodf(x, m)` with `m` a constant no longer does. + `approxLength` is an octagonal sqrt approximation — 6.8% error (measured by `toolchain/check_math.py`, which pins it; the 0.375 coefficient is the shift-friendly one, not the minimax one), no `sqrtf` in the pixel loop. Use it only when distance is a **secondary** signal. If distance IS the visual structure of the pattern (radial ripples, concentric rings, vortex centers, anything that uses `1/dist` for amplification), use real `sqrtf` instead — the octagonal contour shows up as visible polygonal artifacts in those cases. ### `core_color.h` — PFColor @@ -447,7 +450,8 @@ surface — the math headers are literally the same files, included with |---|---| | Switch latency (7.5 KB module) | 6.0 ms = read 4.4 + relocate 0.6 + setup 1.0 | | Switch latency (22 KB module) | 10.9 ms — still under one 60 fps frame | -| Runtime speed vs the same source compiled in | **~20 % slower** (Origin: 53.4 → 43.5 fps) — the cost of relocatable code (`-mlongcalls`); not fixable by `-O2` (~2 %) or memory placement | +| Runtime speed vs the same source compiled in | **2.7 % slower** — Origin draws a frame in 9.56 ms compiled in (`-Os`) and 9.81 ms as a module (`-O2`); one board, A-B-B-A in one boot, 2026-10-04. The 2026-07 figure of ~20 % (53.4 → 43.5 fps), which this row blamed on relocatable code (`-mlongcalls`), is not in today's build. | +| Build | `-O2` since 2026-10-04 (`build_module.py`; `--opt s` builds at `-Os` again). On the Basics presets, same board, same boot, `-Os` → `-O2`: 0510 11.9 → 10.3 ms a frame, 0512 23.2 → 22.6, 0515-4 15.0 → 11.2, 0520 23.4 → 19.7, 0531 13.7 → 12.4, 0601 15.0 → 13.6 — 3 to 34 % more frames a second, for a third more code in those builds (67 → 90 KB over the pack). The same change makes `floorf`/`fmodf` and their kin inline and exact in a module (`abi/pf_libm.h`): presets as they were written before PFMath, with those calls per pixel, went 0510 13.3 → 10.3 ms, 0515-4 23.7 → 17.5, 0520 23.1 → 20.3, 0601 24.5 → 20.2 at `-O2` with a first version of that header (a first version of the header; with the header as committed, all 33 Basics modules are faster than their August builds on the same board, 1.11 to 2.36 times the frames, 1.52 at the median). With both, the pack is 104 KB of code, and 145 community patterns built both ways are 1.36 times their old code at the median. Two costs. **Room:** from 3.10.5 that code is in PSRAM and its size does not decide whether a module loads; before 3.10.5 it has to fit in internal RAM (about 7.8 KB of budget on an Audio build), so a larger pattern that loaded as the old build can be refused as the new one - that firmware needs updating. **The last bit:** the seven functions are exact, but `-O2` and inline code move where GCC fuses a pattern's own `a*b+c`, so its arithmetic can differ in the last bit from the build before, which shows only where the pattern amplifies it (a float hash, state carried between frames, rarely a `floorf` band edge; `abi/pf_libm.h` has the cases). A module built this way imports nothing an older loader lacks. | | Comfortable module size | ~32 KB of statics on a core 2.x build — measured: 0–64 KB of static tables all render at the same 62 fps. They spend PSRAM since 2026-10, not internal heap: statics go to PSRAM first, which costs most modules nothing measurable and a few with small per-pixel state arrays 2–3 % (Burgers +2.6 %, Wave Cascade +2.2 %; `PF_MODULE_DATA_PSRAM_FIRST 0` puts small statics back in internal RAM). (The old "≲ 8 KB, then `.rodata` spills to PSRAM and ~14 fps" figure was the core 3.x build's 7.7 KB largest block talking; see [Required board package](#required-board-package).) | | Panel size | Baked in at build (`-DPF_PANEL_W/H`); the loader rejects a mismatch | | ABI | `PF_ABI_VERSION` must match; bump it on ANY layout change in `pf_abi.h` and rebuild every module | diff --git a/firmware/patternflow/abi/abi.sums b/firmware/patternflow/abi/abi.sums index 60568674..d578cd74 100644 --- a/firmware/patternflow/abi/abi.sums +++ b/firmware/patternflow/abi/abi.sums @@ -11,6 +11,13 @@ # uselessly. firmware/toolchain/check_math.py is the guard for that half: # it pins what those headers compute rather than what they contain, which # is the right test for a file whose comments are allowed to change. +# +# pf_libm.h is pinned here although it lays out nothing: it is compiled +# into every module, behind floorf, fmodf and five more, on the promise +# that it computes what libm computes. The hash makes an edit to it a +# deliberate one; firmware/toolchain/check_libm.py is what holds the +# promise, and has to pass before the hash is refreshed. 2fdca28c596418529252f340133343c708a9a8aa11078435f5c733cbc922ec1b pf_abi.h -b6788eb470841b19738ce3bf2f81281903dd9839b9a87078133b0ec42460c481 pf_module.h +0b225800b1211e52128c4de426be595d883384f4a39263a2562ce85773506d9b pf_libm.h +bfba1dcbd63f0ac8b311a10c5142d775a695ce0bdb12827d3593576902f7d000 pf_module.h 5456ff3504023a7f126f57d0712085e7d6facb85f5f576e2e8fc447dec8b0b4a pf_params.h diff --git a/firmware/patternflow/abi/pf_libm.h b/firmware/patternflow/abi/pf_libm.h new file mode 100644 index 00000000..2bf161e5 --- /dev/null +++ b/firmware/patternflow/abi/pf_libm.h @@ -0,0 +1,387 @@ +// ═══ PINNED WITH THE ABI ═══ Not a layout - but every .pfm built after an +// edit here computes with the edited code, so it changes the way the contract +// does: on purpose, with firmware/toolchain/check_libm.py and +// check_module_libm.py passing, and with abi.sums refreshed in the same commit +// (check_abi_freeze.py --update; it keeps the notes in that file). +// Patternflow module SDK — floorf, ceilf, truncf, roundf, fminf, fmaxf and +// fmodf as inline FPU code that returns what the C library returns, bit for bit. +// +// Why. A module links no libm: those names are imports the loader resolves +// against the firmware's copy, so each use is a windowed call into a generic C +// routine. Per call through a module, measured on a board 2026-10-04: floorf +// 251 ns, ceilf 273, roundf 185, fminf and fmaxf 611 for the pair, fmodf +// 700-840 (truncf was not timed) - and a frame is 8,192 pixels. Four presets +// as they stood before they were rewritten around PFMath (floorf and fmodf per +// pixel, the way most community headers are written), same board, -O2, with a +// first version of this file: 0510 13.3 -> 10.3 ms a frame, 0515-4 23.7 -> +// 17.5, 0520 23.1 -> 20.3, 0601 24.5 -> 20.2. With this file as it stands, +// the 33 Basics modules against their August builds, same board: every one +// faster, 1.11x to 2.36x the frames, 1.52x at the median (that is this file, +// -O2 and a month of preset edits together; the split is in +// toolchain/build_module.py). PFMath::ifloor, floorF, fract and clamp +// (src/core_math.h) are still the least code where a pattern is written with +// them; this is for the .h files nobody is going to edit. +// +// What is exact. These seven functions: for every input each returns the bits +// the library function returns. Nothing here is an approximation. Each handles +// inline only the inputs for which IEEE 754 leaves exactly one answer and the +// code below provably reaches it, and hands every other input - a NaN, an +// infinity, a magnitude past the proved range, a tie whose winner is the +// library's own choice - to the real function. The reasoning is beside each +// function. firmware/toolchain/check_libm.py runs it: all 2^32 float bit +// patterns through the four one-argument functions and about three billion +// comparisons through the others, as bits, against the libm of whatever +// machine runs the check. check_module_libm.py then reads a module the real +// compiler built, to see that this code is what a pattern's calls became. +// +// What a PC cannot check is the panel's own arithmetic: that MSUB.S is fused +// (one rounding - fmod's remainder depends on it) and that its conversions +// and compares do what IEEE says. toolchain/tests/modules/_math_probe is a +// module that checks those on a board, against the firmware's own libm +// (2026-10-04, one board: "math ok 9/9", 1.17 million comparisons). +// +// What is not exact: the pattern's own arithmetic, which this file changes +// without touching. Modules are compiled with GCC's default +// -ffp-contract=fast: a*b+c becomes one fused instruction - one rounding where +// there were two - when the compiler sees the multiply and the add in one +// basic block. The code here has branches, so a product computed before one of +// these calls and added after it no longer shares a block with its add; and +// -O2, the build default that arrived with this file, inlines helpers -Os left +// alone, which fuses products that were not fused before. Either way a value +// in the pattern can come out different in its last bit. Two cases, both +// worked through on the two compilers: +// +// sinf(floorf(x) * 12.9898f + floorf(y) * 78.233f) * 43758.5453f +// The shader cell hash written as one expression. The first product +// used to be the fused one; now the second is. On a 16x8 grid of cells +// the sum differs for 20 of 128, and the hash turns each of those into +// an unrelated value. (The same hash behind a helper, hash(floorf(x), +// floorf(y)), is unchanged; PFNoise::cellHash is integer and cannot be.) +// +// 1.0f - smooth(...) where smooth() ends in a multiply +// At -Os the helper stays a function: mul.s, return, sub.s. At -O2 it +// is inlined and the two become one msub.s. +// +// A last bit shows only where a pattern amplifies it: a float hash like the +// one above, state carried from one frame to the next, and - rarely - a value +// sitting on the edge of a floorf band. Everywhere else it is lost in the +// rounding to eight bits. +// +// Layout. PFLibm:: holds the algorithms as ordinary functions any C++17 +// compiler builds - that is what the host test runs, under GCC and MSVC. The +// second half exists only when a module is being built for the panel: it puts +// those functions behind the C names, so `floorf(x)` in an unedited pattern is +// the inline code. A firmware image never includes this file. +// +// Include it BEFORE (pf_module.h does): the redirection of +// libstdc++'s float overloads happens while that header is read. +// License: MIT +#pragma once + +#include + +// ── What the algorithms are written in ────────────────────────────── +// `real::` is the C library's own function - the answer outside what is +// proved below. +// +// On the panel's compiler these are GCC's builtins, for two reasons. A call to +// __builtin_floorf is the call an unedited `floorf(x)` always was - the same +// import, and folded by the compiler in exactly the cases it folded before - +// and it still means that after the C name has been given a body further +// down. And builtins can sit in a constexpr function, which these have to be: +// libstdc++'s std::floor(float) is constexpr and is about to be routed here. +// +// Anywhere else (the host test: GCC, Clang, MSVC) they are the C names from +// , and check_libm.py turns the compiler's builtin handling of those +// names off, so that the reference really is that machine's libm and not the +// compiler's inline idea of it. +#if defined(__XTENSA__) && defined(__GNUC__) && !defined(__clang__) +#define PF_LIBM_FN constexpr inline __attribute__((always_inline)) +namespace PFLibm { +namespace real { +PF_LIBM_FN float floor(float x) { return __builtin_floorf(x); } +PF_LIBM_FN float ceil(float x) { return __builtin_ceilf(x); } +PF_LIBM_FN float trunc(float x) { return __builtin_truncf(x); } +PF_LIBM_FN float round(float x) { return __builtin_roundf(x); } +PF_LIBM_FN float fmin(float x, float y) { return __builtin_fminf(x, y); } +PF_LIBM_FN float fmax(float x, float y) { return __builtin_fmaxf(x, y); } +PF_LIBM_FN float fmod(float x, float y) { return __builtin_fmodf(x, y); } +} // namespace real +PF_LIBM_FN float magnitude(float x) { return __builtin_fabsf(x); } +// The sign BIT: true for -0.0f, which `x < 0` is not. +PF_LIBM_FN bool negative(float x) { return __builtin_signbit(x) != 0; } +// x - q*y with ONE rounding. On the S3 this is MSUB.S; no call. +PF_LIBM_FN float fnma(float q, float y, float x) { return __builtin_fmaf(-q, y, x); } +} // namespace PFLibm +#else +#include +#define PF_LIBM_FN inline +namespace PFLibm { +namespace real { +inline float floor(float x) { return ::floorf(x); } +inline float ceil(float x) { return ::ceilf(x); } +inline float trunc(float x) { return ::truncf(x); } +inline float round(float x) { return ::roundf(x); } +inline float fmin(float x, float y) { return ::fminf(x, y); } +inline float fmax(float x, float y) { return ::fmaxf(x, y); } +inline float fmod(float x, float y) { return ::fmodf(x, y); } +} // namespace real +inline float magnitude(float x) { return std::fabs(x); } +inline bool negative(float x) { return std::signbit(x); } +inline float fnma(float q, float y, float x) { return std::fma(-q, y, x); } +} // namespace PFLibm +#endif + +namespace PFLibm { + +// 2^23. Below it a float converts to int and back without loss; from it up +// every float is already a whole number, so there is nothing to round - and +// that side, with the infinities and NaN (which fail the `<` too), is left to +// the library. +constexpr float WHOLE_FROM = 8388608.0f; + +// ── floor, ceil, trunc, round ─────────────────────────────────────── +// For |x| < 2^23 only. (int)x truncates toward zero and is exact, as is the +// conversion back; a negative x with a fraction lands one above its floor, and +// the subtraction is between whole numbers under 2^23, so exact too. That is +// floor(x) as a value. As bits it can be wrong in one case, x = -0.0f, where +// truncation gives +0.0f: a whole x is its own floor, so it is returned +// itself. +PF_LIBM_FN float floorSmall(float x) { + const float t = (float)(int)x; + const float f = t > x ? t - 1.0f : t; + return f == x ? x : f; +} + +PF_LIBM_FN float floor(float x) { + return magnitude(x) < WHOLE_FROM ? floorSmall(x) : real::floor(x); +} + +// ceil(x) = -floor(-x), signs of zero included: ceil of -0.3f is -0.0f, and +// floorSmall(0.3f) is +0.0f. Negation is exact. +PF_LIBM_FN float ceil(float x) { + return magnitude(x) < WHOLE_FROM ? -floorSmall(-x) : real::ceil(x); +} + +// A zero result carries x's sign - trunc and round of -0.3f are -0.0f - and +// the conversion from int only ever makes +0.0f. x * 0.0f is that zero: the +// product of a finite x and zero is exact and takes the sign of x. (A +// multiplication rather than a look at the sign bit, because reading a +// float's bits makes GCC 8.4 keep the value in memory for its whole life.) +PF_LIBM_FN float signedZero(float x) { + return x * 0.0f; +} + +PF_LIBM_FN float trunc(float x) { + if (!(magnitude(x) < WHOLE_FROM)) return real::trunc(x); + const float t = (float)(int)x; + return t == 0.0f ? signedZero(x) : t; +} + +// Half away from zero. x - t is the fraction of x, exact because both are +// multiples of x's last bit and the difference is under 1; the comparison +// with 0.5 is then of the true fraction, not of a sum that has already +// rounded (floor(x + 0.5f) gets 0.49999997f wrong, and every odd number from +// 2^23 up, where x + 0.5f is a tie that rounds to even). t +- 1 is between +// whole numbers no larger than 2^23. +PF_LIBM_FN float round(float x) { + if (!(magnitude(x) < WHOLE_FROM)) return real::round(x); + const float t = (float)(int)x; + const float d = x - t; + const float r = d >= 0.5f ? t + 1.0f : (d <= -0.5f ? t - 1.0f : t); + return r == 0.0f ? signedZero(x) : r; +} + +// ── fmin, fmax ────────────────────────────────────────────────────── +// When one argument is strictly less, the answer is that argument's bits. When +// they compare equal they are the same bits unless they are zeros of opposite +// sign - and which zero comes back from fmin(+0, -0) is the library's choice +// (newlib returns its second argument, other libraries the negative one), as +// is everything about a NaN. Those two cases go to the call the pattern always +// made, and get what it always got from this compiler - which is not always +// newlib's answer for the arguments in the order they were written: GCC +// answers the call itself when both arguments are constants, and from GCC 12 +// it may hand the library the two operands the other way round. +PF_LIBM_FN float fmin(float x, float y) { + if (x < y) return x; + if (y < x) return y; + if (x == y && negative(x) == negative(y)) return x; + return real::fmin(x, y); +} + +PF_LIBM_FN float fmax(float x, float y) { + if (x > y) return x; + if (y > x) return y; + if (x == y && negative(x) == negative(y)) return x; + return real::fmax(x, y); +} + +// ── fmod ──────────────────────────────────────────────────────────── +// fmod(x, y) is x - n*y for the whole number n = trunc(x / y) of the TRUE +// quotient, carries x's sign, and is always exactly representable. Write +// ax = |x|, ay = |y|, and R = ax - n*ay, 0 <= R < ay, for the answer's +// magnitude. +// +// |x| < |y| returns x itself (n = 0; this is also x = +-0 and y = +-inf). +// Otherwise the quotient is estimated - `p`, from a division or from a +// multiplication by 1/ay - and only its whole part q is kept. The remainder +// is then taken with the fused multiply-subtract, which rounds the exact +// ax - q*ay once: +// +// q = n the exact value is R, representable, so r = R. +// q = n + 1 the exact value is R - ay, in [-ay, 0): a multiple of ay's last +// bit no larger than ay, so representable, so r is negative. +// q = n - 1 the exact value is R + ay, in [ay, 2*ay). It may round, but +// rounding is monotonic and ay is a float, so r >= ay. +// +// So a single look at r says which way q is off, and after stepping q by one +// the remainder is computed AGAIN from ax - never by adding or subtracting ay +// from r, which in the third case has already lost its low bit. +// +// What that needs is |p - ax/ay| < 1, so that q is within one of n. p is a +// rounded division (relative error 2^-24 when it is correctly rounded, which +// _math_probe checks of the panel's; twice that would do), or ax times 1/ay +// (2^-24 for each of the two roundings - and where 1/ay is subnormal, an +// absolute 2^-150 instead, which ax < 2^128 turns into at most 2^-22). Either +// way |p - ax/ay| is under 2^-23 * (ax/ay) + 2^-21, which for a quotient below +// 2^22 + 1 is under 0.51. p < 2^22 is therefore the fast path's whole +// condition: it puts the true quotient below 2^22 + 1; it fails for a NaN +// anywhere, for x = +-inf, for y = 0 (p is inf or NaN) and when 1/ay +// overflowed; and everything it fails for goes to the library. q is at most +// 2^22, so the conversions are exact and so is q +- 1. +// +// The sign: here ax >= ay > 0, so x is not a zero and `x < 0` is its sign +// bit; an exact multiple leaves r = +0.0f, which negation turns into the +// -0.0f fmod returns for a negative x. +constexpr float FMOD_QUOTIENT_BELOW = 4194304.0f; // 2^22 + +PF_LIBM_FN float fmodFrom(float x, float y, float ax, float ay, float p) { + if (!(p < FMOD_QUOTIENT_BELOW)) return real::fmod(x, y); + float q = (float)(int)p; + float r = fnma(q, ay, ax); + if (r < 0.0f) { + q -= 1.0f; + r = fnma(q, ay, ax); + } else if (r >= ay) { + q += 1.0f; + r = fnma(q, ay, ax); + } + return x < 0.0f ? -r : r; +} + +// Any divisor: the quotient costs a division (__divsf3, 327 ns on the S3). +PF_LIBM_FN float fmod(float x, float y) { + const float ax = magnitude(x); + const float ay = magnitude(y); + if (ax < ay) return x; + return fmodFrom(x, y, ax, ay, ax / ay); +} + +// A divisor known when the pattern is compiled: `reciprocal` is 1.0f / |y| +// rounded to nearest, which the compiler folds, and the division is gone. +PF_LIBM_FN float fmodRecip(float x, float y, float reciprocal) { + const float ax = magnitude(x); + const float ay = magnitude(y); + if (ax < ay) return x; + return fmodFrom(x, y, ax, ay, ax * reciprocal); +} + +// y is 1.0f or -1.0f - the hue wrap. The remainder is the fraction of |x|, +// exact as in round() above, with nothing to correct; |x| >= 1 here, so +// `x < 0` is again the sign. +PF_LIBM_FN float fmodOne(float x, float y) { + const float ax = magnitude(x); + if (ax < 1.0f) return x; + if (!(ax < WHOLE_FROM)) return real::fmod(x, y); + const float r = ax - (float)(int)ax; + return x < 0.0f ? -r : r; +} + +} // namespace PFLibm + +// ═════════════════════════════════════════════════════════════════════ +// Module builds only: the C names become the functions above. +// ═════════════════════════════════════════════════════════════════════ +// __XTENSA__ as well as PF_MODULE_BUILD: a host test defines the latter to get +// at the shared headers, and on a PC these names belong to its own libc. +#if defined(PF_MODULE_BUILD) && defined(__XTENSA__) && defined(__GNUC__) && !defined(__clang__) + +namespace PFLibm { +// The divisor is a constant far more often than not (`fmodf(h, 1.0f)`, +// `fmodf(a, TWO_PI)`), and after inlining the compiler knows which calls +// those are. +PF_LIBM_FN float fmodAny(float x, float y) { + if (__builtin_constant_p(y)) { + if (y == 1.0f || y == -1.0f) return fmodOne(x, y); + return fmodRecip(x, y, 1.0f / magnitude(y)); + } + return fmod(x, y); +} +} // namespace PFLibm + +// 1. The spellings that go through libstdc++. In C++, `floor(x)`, +// `std::floor(x)`, `fmod(a, b)` and the rest on float arguments are +// 's float overloads, each one line: `return __builtin_floorf(x);`. +// A builtin cannot be given a body, so for the length of that header the +// builtin's name is a macro for the function above. PFLibm's own `real::` +// fallbacks were defined before this point and still mean the builtin. +// Checked with libstdc++ 8.4 and 14.2 - the versions between are let in on +// the strength of those two - and check_module_libm.py reads the result out +// of a built module. Outside that range the redirection is off, and those +// spellings simply stay calls. +#if __GNUC__ >= 8 && __GNUC__ <= 14 +#define __builtin_floorf(x) PFLibm::floor(x) +#define __builtin_ceilf(x) PFLibm::ceil(x) +#define __builtin_truncf(x) PFLibm::trunc(x) +#define __builtin_roundf(x) PFLibm::round(x) +#define __builtin_fminf(x, y) PFLibm::fmin(x, y) +#define __builtin_fmaxf(x, y) PFLibm::fmax(x, y) +#define __builtin_fmodf(x, y) PFLibm::fmodAny(x, y) +#include +#undef __builtin_floorf +#undef __builtin_ceilf +#undef __builtin_truncf +#undef __builtin_roundf +#undef __builtin_fminf +#undef __builtin_fmaxf +#undef __builtin_fmodf +#else +#include +#endif + +// 2. The C names themselves. `extern inline` with gnu_inline is a definition +// used for inlining and for nothing else: no copy of it is emitted, and +// anything that is not a call - `float (*f)(float) = floorf;` - still +// refers to the firmware's symbol. always_inline makes every call the +// inline one at any optimisation level (and is what makes GCC use this +// body in place of its own idea of the builtin). +// +// The imports stay within what every loader resolves: each fallback is +// the symbol the call would have imported anyway, and fmodf with a divisor +// that is not a constant adds __divsf3. All eight have been in the host +// symbol table (src/core_module_loader.h) since the first loader, v3.2.0. +extern "C" { +extern inline __attribute__((gnu_inline, always_inline)) float floorf(float x) { + return PFLibm::floor(x); +} +extern inline __attribute__((gnu_inline, always_inline)) float ceilf(float x) { + return PFLibm::ceil(x); +} +extern inline __attribute__((gnu_inline, always_inline)) float truncf(float x) { + return PFLibm::trunc(x); +} +extern inline __attribute__((gnu_inline, always_inline)) float roundf(float x) { + return PFLibm::round(x); +} +extern inline __attribute__((gnu_inline, always_inline)) float fminf(float x, float y) { + return PFLibm::fmin(x, y); +} +extern inline __attribute__((gnu_inline, always_inline)) float fmaxf(float x, float y) { + return PFLibm::fmax(x, y); +} +extern inline __attribute__((gnu_inline, always_inline)) float fmodf(float x, float y) { + return PFLibm::fmodAny(x, y); +} +} // extern "C" + +#endif // module build diff --git a/firmware/patternflow/abi/pf_module.h b/firmware/patternflow/abi/pf_module.h index 2847c1a5..126a8d84 100644 --- a/firmware/patternflow/abi/pf_module.h +++ b/firmware/patternflow/abi/pf_module.h @@ -14,18 +14,44 @@ // present() crosses per frame. Calling setPixel through a function pointer // instead would be far worse. // -// It is still NOT free. Measured on a 128x64 panel, the Origin pattern runs at -// 53 fps compiled in and 43 fps as a module — about 20% slower for identical -// source. That gap is not memory placement (it holds with every section in -// internal RAM), not optimisation level (-O2 buys ~2%), and not the framebuffer -// indirection (caching it in a module global made things worse). It is the cost -// of the relocatable code model itself, chiefly -mlongcalls. Budget for it. +// What being a module costs, measured 2026-10-04 on one board, A-B-B-A in +// one boot: Origin compiled into the firmware (-Os) draws a frame in 9.56 ms, +// Origin built as a module (-O2, this SDK) in 9.81 - 2.7% slower as a module. +// This comment used to say 20% (2026-07: 53 fps against 43) and blame the +// relocatable code model, chiefly -mlongcalls; whatever that was, it is not +// in today's build. Two things the old comment said still hold: where a +// module's sections live is not what a frame's time goes on +// (src/core_module_memory.h has the numbers), and caching the framebuffer +// pointer in a module global makes things worse (setPixel, below). +// +// What does cost a module is what costs a preset: the calls its pixel loop +// makes, and how hard the compiler worked on it. Both are dealt with where a +// module is BUILT, so that no pattern has to be edited for them: +// - toolchain/build_module.py compiles at -O2. This comment said -O2 bought +// ~2%; on the Basics presets it is 3..34% more frames a second than -Os +// (measured 2026-10-04, the numbers are beside DEFAULT_OPT). +// - pf_libm.h, included first below, makes floorf, ceilf, truncf, roundf, +// fminf, fmaxf and fmodf inline code that returns exactly what the +// firmware's libm returns - 185-840 ns a call, for the ones that were +// timed, that a pixel no longer pays. +// Neither leaves a rebuilt pattern's own arithmetic as it was: both move +// where GCC fuses a*b+c into one instruction, so a value in the pattern can +// differ in its last bit from the build before. pf_libm.h says where that +// shows. +// +// The rest of libm - sinf, sqrtf, powf, atan2f - is still a call into the +// host, about a microsecond for sinf. PFMath's tables and fast* functions are +// for those. // // Panel size is baked in at build time (-DPF_PANEL_W / -DPF_PANEL_H) because // patterns use PANEL_RES_W/H as array bounds. The loader rejects a module // whose panel size differs from the running firmware's. #pragma once +// First, and before : it is what makes floorf/fmodf and their kin +// inline in a module, and part of that happens while is read. +#include "pf_libm.h" + #include #include #include diff --git a/firmware/patternflow/src/core_color.h b/firmware/patternflow/src/core_color.h index 22054709..6e96cd1b 100644 --- a/firmware/patternflow/src/core_color.h +++ b/firmware/patternflow/src/core_color.h @@ -12,7 +12,7 @@ #include #include -#include "core_math.h" // ifloor/clamp: floorf and fminf are libm calls here +#include "core_math.h" // ifloor/clamp: floorf and fminf are libm calls in the firmware image namespace PFColor { @@ -27,9 +27,10 @@ inline void hsvToRgb(float h, float s, float v, float hh = h * 6.0f; // Sector and position within it. hh is in [0, 6]: 6.0f happens when h // rounds up to just under 1, and lands in sector 5 at f = 1 - the same - // red that sector 0 at f = 0 gives. No fmodf: this runs once per pixel in - // a module's inner loop, and fmodf there is a call into the host's libm, - // a hundred-odd cycles, where this is one truncation. + // red that sector 0 at f = 0 gives. No fmodf: this runs once per pixel, and + // fmodf is a call into libm in the firmware image, a hundred-odd cycles (in + // a module abi/pf_libm.h has made it inline since 2026-10), where this is + // one truncation either way. int i = (int)hh; if (i > 5) i = 5; float f = hh - (float)i; diff --git a/firmware/patternflow/src/core_math.h b/firmware/patternflow/src/core_math.h index 8dfce742..da1ead5d 100644 --- a/firmware/patternflow/src/core_math.h +++ b/firmware/patternflow/src/core_math.h @@ -40,9 +40,12 @@ inline void buildSinLUT() { // Round toward negative infinity, as an int. On this target floorf() is not an // instruction: GCC emits `call8 floorf` into a ~50-instruction newlib routine at // every use, under -O2, -Os and even -ffast-math, and __builtin_floorf makes no -// difference. The FPU does have a FLOOR.S, but reaching it needs inline asm, -// and asm cannot be checked by a host test - which for a file that IS the pattern -// SDK is the more expensive problem. +// difference. (That is the compiler, and still how it is in code compiled into +// the firmware. In a module, abi/pf_libm.h has given floorf an exact inline +// body since 2026-10 - bigger than what follows, because it has to be right +// for every float.) The FPU does have a FLOOR.S, but reaching it needs inline +// asm, and asm cannot be checked by a host test - which for a file that IS the +// pattern SDK is the more expensive problem. // // So: truncate, which IS one instruction (TRUNC.S), and correct the one case // where truncation and flooring differ - a negative non-integer, where trunc @@ -66,8 +69,11 @@ inline float fract(float x) { return x - t; } -// fminf/fmaxf are libm calls too - two register-window frames for a comparison -// the FPU does in one OLT.S. Written as a comparison, GCC emits exactly that. +// fminf/fmaxf are libm calls too in the firmware image - two register-window +// frames for a comparison the FPU does in one OLT.S - and in a module, where +// abi/pf_libm.h makes them inline, still up to three compares, because they +// keep the library's rules for NaN and signed zeros. Written as a comparison, +// GCC emits exactly that. inline float clamp(float x, float lo, float hi) { return x < lo ? lo : (x > hi ? hi : x); } @@ -77,13 +83,16 @@ inline float clamp01(float x) { } // JavaScript's `%` on floats: the sign of the dividend, the magnitude below -// |m|. A pattern ported from the lab reaches for fmodf here, and in a module -// that is a call into the host's libm on every pixel; this is one division -// and one truncation. The truncation is one instruction (TRUNC.S). The -// division is NOT - GCC emits a call into __divsf3 for any non-power-of-two -// divisor, verified on the shipping compiler. Still far cheaper than fmodf, -// but the comment used to claim both halves were single instructions and -// only one of them is. The same value +// |m|. A pattern ported from the lab reaches for fmodf here. This is one +// division and one truncation. The truncation is one instruction (TRUNC.S). +// The division is NOT - GCC emits a call into __divsf3 for any +// non-power-of-two divisor, verified on the shipping compiler; the comment +// used to claim both halves were single instructions and only one of them is. +// Against fmodf as a call into libm on every pixel - which it is in code +// compiled into the firmware, and was in a module until 2026-10 - this is far +// cheaper. In a module the comparison has since changed: abi/pf_libm.h makes +// fmodf inline there, and fmodf by a constant multiplies by a reciprocal the +// compiler folded, where this still divides. The same value // as fmodf to a last-bit rounding for anything a pattern feeds it; |x / m| // has to stay under 2^31, and m must not be 0. inline float jsMod(float x, float m) { diff --git a/firmware/patternflow/src/core_noise.h b/firmware/patternflow/src/core_noise.h index 9b077288..9fb144ae 100644 --- a/firmware/patternflow/src/core_noise.h +++ b/firmware/patternflow/src/core_noise.h @@ -12,7 +12,7 @@ #include #include -#include "core_math.h" // ifloor: floorf is a libm call on this target +#include "core_math.h" // ifloor: floorf is a libm call in the firmware image namespace PFNoise { diff --git a/firmware/toolchain/README.md b/firmware/toolchain/README.md index 45d1bcb9..1d7d5ebe 100644 --- a/firmware/toolchain/README.md +++ b/firmware/toolchain/README.md @@ -10,6 +10,7 @@ The repository-level scripts around the firmware: what builds a module or a pack - the boundary rule — `check_boundaries.py`: the core references no feature, no feature flag, no feature name on a core page (the rule itself is [`docs/EDITIONS.md`](../../docs/EDITIONS.md)); - the frozen host ⇄ module ABI — `check_abi_freeze.py`, `check_module_elf.py`; +- the module SDK's inline libm — `check_libm.py` and `check_module_libm.py`: `abi/pf_libm.h` puts inline code behind `floorf`, `fmodf` and five others in every `.pfm`, on the claim that each returns the libm result bit for bit. `tests/libm_test.cpp` holds the seven to that: every one of the 2^32 floats through the one-argument functions and about three billion comparisons through the rest, against the libm of the machine running it; it takes a minute or two. What a PC cannot compile is the half of the header only a module build has, so `check_module_libm.py` builds `tests/modules/_libm_shapes` with the Xtensa compiler and reads the object: every spelling the header claims is inline, with the library call left only as its fallback. It needs the toolchain, and CI runs it in the firmware build job. What the two hold is the seven functions; a rebuilt pattern's own arithmetic can still differ in its last bit, because `-O2` and inline code move where GCC fuses `a*b+c` (`abi/pf_libm.h` says where that shows); - the preset twins — `check_presets.py`: `web/src/lib/presets/` and `../patternflow/presets/` stay in step, with the deliberate exceptions listed inside it; - versions — `check_versions.py`: the version the firmware reports, the editions, `AGENTS.md`, the flasher manifest and the shelf all agree; - images — `check_footprint.py` (each edition's size against its baseline); @@ -17,6 +18,6 @@ The repository-level scripts around the firmware: what builds a module or a pack - the vendored web server — `check_parser.py`: the real `src/webserver/Parsing.cpp` against a scripted socket and a fake clock, failing on a wait that does not sleep or does not end. Its `KNOWN:` lines are what the parser does today that the test would otherwise fail, pinned so that fixing one turns the check red until the pin is removed; - `check_sources.py`, a fast pre-compile sanity pass. -`tests/` also holds `modules/_ctor_probe/`, a module that exists only to exercise the loader's `.init_array` path; build it with `build_module.py` and inspect the ELF as its header comment says. Beside it, `modules/_crash_probe/` writes through a null pointer from `draw()` when a knob moves: the bench case for the crash record in `/api/status`. And `modules/_hang_probe/` is a module whose `draw()` stops returning eight seconds after it is picked - the bench tool for "the console outlives a hung render loop" (`src/core_loop_sync.h`), which no well-behaved pattern can show. With K1 or K2 turned while it counts down the stop ends after thirty or twenty seconds, for the other half: what the loop does when it comes back to requests that gave up on it. Its header comment has the three commands. +`tests/` also holds `modules/_ctor_probe/`, a module that exists only to exercise the loader's `.init_array` path; build it with `build_module.py` and inspect the ELF as its header comment says. Beside it, `modules/_crash_probe/` writes through a null pointer from `draw()` when a knob moves: the bench case for the crash record in `/api/status`. And `modules/_hang_probe/` is a module whose `draw()` stops returning eight seconds after it is picked - the bench tool for "the console outlives a hung render loop" (`src/core_loop_sync.h`), which no well-behaved pattern can show. With K1 or K2 turned while it counts down the stop ends after thirty or twenty seconds, for the other half: what the loop does when it comes back to requests that gave up on it. Its header comment has the three commands. `modules/_math_probe/` is the on-board half of `check_libm.py`: it runs the SDK's inline `floorf`/`fmodf` and the firmware's own libm side by side for 1.3 s in `setup()` and puts the verdict in its own name (`"active": "math ok 9/9 ..."` in `/api/status`), then keeps comparing every frame, green or red. It is how to tell that a board's FPU does what the PC proof assumes - above all that its multiply-subtract is fused. `module.ld` is the linker script every `.pfm` is linked with. diff --git a/firmware/toolchain/build_module.py b/firmware/toolchain/build_module.py index 8dc8584e..c7207de3 100644 --- a/firmware/toolchain/build_module.py +++ b/firmware/toolchain/build_module.py @@ -62,10 +62,37 @@ # no hardware). pf_module.h includes these rather than carrying a second copy. SHARED_HEADERS = ["core_color.h", "core_math.h", "core_noise.h"] -# -Os matches how the Arduino core builds the firmware, but a module is not -# competing for the app partition: it is 6-22 KB in a 10 MB filesystem, so -# trading size for speed is nearly free here. --opt selects it. -DEFAULT_OPT = "s" +# -O2. The default was -Os until 2026-10-04, because that is how the firmware +# itself is built and because abi/pf_module.h said -O2 bought about 2 %. It +# does not: measured on one board in one boot, the Basics presets as modules, +# GCC 8.4, frame time -Os -> -O2: +# 0510 11.9 -> 10.3 ms 0520 23.4 -> 19.7 ms +# 0512 23.2 -> 22.6 ms 0531 13.7 -> 12.4 ms +# 0515-4 15.0 -> 11.2 ms 0601 15.0 -> 13.6 ms +# which is 3 to 34 % more frames a second. (GCC 14.2 at -O2 was another 1 to +# 8 % faster than GCC 8.4 at -O2 on the same six.) --opt still selects another +# level. It costs two things. +# +# Size. The builds timed above are 67 -> 90 KB of code across the 33 Basics +# modules; with abi/pf_libm.h compiled in as well - the other half of the same +# change: floorf, fmodf and their kin as inline code instead of calls into the +# firmware's libm - the same 33 are 75 KB at -Os and 104 KB at -O2, and 145 +# community patterns built both ways came out at 1.36 times their old code +# (the median; GCC 8.4, 2026-10-04). From firmware 3.10.5 a module's code runs +# from PSRAM (src/core_module_memory.h) and its size does not decide whether it +# loads. Before 3.10.5 code is placed in internal RAM and admitted against +# what the services leave - about 7.8 KB on an Audio build - so a module that +# fitted there as an -Os build can be refused as an -O2 one. Nothing here +# builds a large module smaller for that firmware; it is told to update. +# +# The last bit. -O2 inlines helpers -Os left out of line, and GCC fuses a*b+c +# into one instruction - one rounding where there were two +# (-ffp-contract=fast) - wherever it then sees both halves together. A rebuilt +# pattern's own arithmetic can therefore differ in its last bit, anywhere in +# it. That shows only where the pattern amplifies it: a float hash, state +# carried between frames, rarely the edge of a floorf band. abi/pf_libm.h has +# the worked cases. +DEFAULT_OPT = "2" CXXFLAGS = [ "-std=gnu++17", @@ -87,9 +114,13 @@ def toolchain_roots() -> list[Path]: """Where an xtensa-esp32s3 toolchain may live, most specific first. - Patternflow's firmware and the community build worker are both arduino-cli, - so the Arduino core's copy is the one that matches what devices actually - run. PlatformIO is kept as a fallback for the fork this came from. + The order is the community build worker's: the compiler it runs is the + Arduino core's (docs/SERVICES.md), so that is looked for before + PlatformIO's, and nothing here should reorder them under it. The firmware + itself is a PlatformIO build (bundles/build.sh) and its compiler - + toolchain-xtensa-esp32s3, GCC 8.4 - is therefore the LAST place looked; + PF_XTENSA_BIN names it when a build has to be the firmware compiler's, as + the committed Basics pack is (web/src/lib/pattern/packs.ts). """ roots: list[Path] = [] explicit = os.environ.get("PF_XTENSA_BIN") @@ -309,7 +340,7 @@ def main() -> None: ap.add_argument("--compile-only", action="store_true", help="Skip link + manifest output") ap.add_argument("--clean", action="store_true", help="Remove previous build output first") ap.add_argument("--opt", default=DEFAULT_OPT, choices=["s", "1", "2", "3"], - help="Optimisation level (default: s, matching the firmware)") + help="Optimisation level (default: 2 - see DEFAULT_OPT)") ap.add_argument("--out", type=Path, default=OUT, help="Where to write .pfm/.json (default: the sketch data dir)") args = ap.parse_args() diff --git a/firmware/toolchain/check_abi_freeze.py b/firmware/toolchain/check_abi_freeze.py index c736fd65..fb32e889 100644 --- a/firmware/toolchain/check_abi_freeze.py +++ b/firmware/toolchain/check_abi_freeze.py @@ -26,6 +26,16 @@ A comment-only edit trips this too. That is intended: refreshing the sums is the two-second acknowledgement that you know which directory you are in. +One header here lays out nothing: pf_libm.h is inline code every module compiles +into itself, behind floorf, fmodf and five more, and it is pinned because an +edit to it changes what every module built afterwards computes. What an edit +there owes is not a version bump but check_libm.py (and check_module_libm.py, +where there is an xtensa toolchain) passing first. + +--update rewrites the hashes and nothing else: the comment lines in abi.sums +are notes people wrote about what the file does and does not cover, and they +are kept as they stand. + License: MIT """ @@ -39,6 +49,26 @@ ABI = ROOT / "patternflow" / "abi" SUMS = ABI / "abi.sums" +# Written only when abi.sums has no comment of its own to keep. +DEFAULT_HEADER = [ + "# sha256 of each LF-normalized header in abi/. Verified in CI by", + "# check_abi_freeze.py; regenerate with --update ONLY alongside a", + "# deliberate, append-only ABI change. The file exists so no change", + "# to the one contract installed modules read can be an accident.", +] + +# Headers that compute rather than lay out, and what a change to one owes. +# Anything not named here gets the layout rule, which is the strict one. +COMPUTES = { + "pf_libm.h": ( + "pf_libm.h lays out nothing, but every module built after an edit to it\n" + "computes with the edited code. Run\n" + " python firmware/toolchain/check_libm.py\n" + " python firmware/toolchain/check_module_libm.py (needs an xtensa toolchain)\n" + "and only when they pass:\n" + " python firmware/toolchain/check_abi_freeze.py --update"), +} + if hasattr(sys.stdout, "reconfigure"): sys.stdout.reconfigure(errors="replace") @@ -57,13 +87,18 @@ def main() -> int: now = current() if "--update" in sys.argv[1:]: - lines = ["# sha256 of each LF-normalized header in abi/. Verified in CI by", - "# check_abi_freeze.py; regenerate with --update ONLY alongside a", - "# deliberate, append-only ABI change. The file exists so no change", - "# to the one contract installed modules read can be an accident."] + # Every comment line already in the file is kept, in order. They are + # hand-written - what the hashes do not cover, what pf_libm.h is doing + # here - and this command used to replace them with four lines of its + # own, which is how a note gets lost by the person following it. + kept = [] + if SUMS.exists(): + kept = [line.rstrip() for line in SUMS.read_text(encoding="utf-8").splitlines() + if line.lstrip().startswith("#")] + lines = list(kept or DEFAULT_HEADER) lines += [f"{h} {n}" for n, h in now.items()] SUMS.write_text("\n".join(lines) + "\n", encoding="utf-8") - print(f"pinned {len(now)} abi header(s)") + print(f"pinned {len(now)} abi header(s), {len(kept)} comment line(s) kept") return 0 if not SUMS.exists(): @@ -79,24 +114,32 @@ def main() -> int: pinned[n] = h problems = [] + moved = [] for name, h in now.items(): if name not in pinned: problems.append(f" {name}: new abi header, not pinned") + moved.append(name) elif pinned[name] != h: problems.append(f" {name}: content changed") + moved.append(name) for name in pinned: if name not in now: problems.append(f" {name}: pinned but gone") + moved.append(name) if problems: print("the module ABI moved:\n") print("\n".join(problems)) - print( - "\nEvery installed .pfm on every panel reads this layout without\n" - "recompiling. If this change is deliberate: append-only, bump\n" - "PF_ABI_MODULE_VERSION, teach the loader the new range, then\n" - " python firmware/toolchain/check_abi_freeze.py --update\n" - "in the same commit. If it is not deliberate, revert it.") + for name in moved: + if name in COMPUTES: + print("\n" + COMPUTES[name]) + if any(name not in COMPUTES for name in moved): + print( + "\nEvery installed .pfm on every panel reads this layout without\n" + "recompiling. If this change is deliberate: append-only, bump\n" + "PF_ABI_MODULE_VERSION, teach the loader the new range, then\n" + " python firmware/toolchain/check_abi_freeze.py --update\n" + "in the same commit. If it is not deliberate, revert it.") return 1 print(f"abi frozen: {len(now)} header(s) match abi.sums") diff --git a/firmware/toolchain/check_libm.py b/firmware/toolchain/check_libm.py new file mode 100644 index 00000000..7c886101 --- /dev/null +++ b/firmware/toolchain/check_libm.py @@ -0,0 +1,58 @@ +"""Prove that the module SDK's inline floorf/fmodf and kin return what libm returns. + +python firmware/toolchain/check_libm.py [--sanitize] +No board required. Takes a minute or two: it runs every float there is. + +abi/pf_libm.h puts inline FPU code behind floorf, ceilf, truncf, roundf, fminf, +fmaxf and fmodf in every .pfm, so that a pattern nobody edits stops calling into +the firmware's libm per pixel. The header's claim is that each of the seven +returns exactly what libm returns, so this is not a tolerance check like +check_math.py: tests/libm_test.cpp compares bit patterns against this machine's +libm - all 2^32 floats through the one-argument functions, about three billion +comparisons through the others - and one mismatch fails. + +Two things it does not do. It cannot compile the part of the header that only a +module build has (the bodies behind the C names, the fmod dispatch): that is +check_module_libm.py, which needs the Xtensa compiler. And it cannot check that +the S3's multiply-subtract is fused: that is tests/modules/_math_probe, on a +board. +""" +import argparse +from pathlib import Path +import subprocess +import tempfile + +from check_module_elf import ROOT, compiler_environment + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--sanitize', action='store_true') + args = parser.parse_args() + compiler, env = compiler_environment() + headers = ROOT / 'firmware/patternflow/abi' + source = ROOT / 'firmware/toolchain/tests/libm_test.cpp' + with tempfile.TemporaryDirectory(prefix='patternflow-libm-') as directory: + work = Path(directory) + exe = work / ('libm_test.exe' if Path(compiler).suffix.lower() == '.exe' else 'libm_test') + if Path(compiler).stem.lower() == 'cl': + if args.sanitize: + raise SystemExit('--sanitize requires GCC or Clang') + command = [compiler, '/nologo', '/std:c++17', '/EHsc', '/O2', '/W4', '/WX', '/utf-8', + f'/I{headers}', str(source), f'/Fe:{exe}'] + else: + # The names under test stay calls into this machine's libm. Left as + # builtins, GCC answers some of them inline on a PC, and its floor + # hands a signalling NaN back unquieted where glibc's does not. + calls = [f'-fno-builtin-{name}' for name in + ('floorf', 'ceilf', 'truncf', 'roundf', 'fminf', 'fmaxf', 'fmodf')] + command = [compiler, '-std=c++17', '-O2', '-Wall', '-Wextra', '-Werror', '-pthread', + *calls, f'-I{headers}', str(source), '-o', str(exe)] + if args.sanitize: + command += ['-fsanitize=address,undefined', '-fno-omit-frame-pointer'] + subprocess.run(command, cwd=work, env=env, check=True) + subprocess.run([str(exe)], cwd=work, env=env, check=True) + + +if __name__ == '__main__': + main() diff --git a/firmware/toolchain/check_module_libm.py b/firmware/toolchain/check_module_libm.py new file mode 100644 index 00000000..cbfbbc4c --- /dev/null +++ b/firmware/toolchain/check_module_libm.py @@ -0,0 +1,356 @@ +"""Read the module SDK's inline libm out of a module the real toolchain built. + + python firmware/toolchain/check_module_libm.py + +check_libm.py proves abi/pf_libm.h's algorithms on a PC: twenty billion +comparisons against libm. What it cannot do is compile the half of that header +a module actually uses - the bodies behind floorf, ceilf, truncf, roundf, fminf, +fmaxf and fmodf, the redirection of libstdc++'s float overloads, and the choice +between fmod's three paths - because that half exists only under +PF_MODULE_BUILD on the Xtensa compiler. Swap two wrappers there, or break one +of the __builtin_ macros, and check_libm.py still says twenty billion matches. + +So this builds tests/modules/_libm_shapes with build_module.py - the same +flags, linker script and import check a pattern gets - and reads the result +(the code out of the object file, where the assembler's own record of what is +an instruction and what is padding is still attached; the imports out of the +linked .pfm): + + - the fixture's static_asserts are evaluated through the module-only wiring, + so a wrapper bound to the wrong function does not compile; + - for every spelling the header claims, the function is disassembled and + walked: there has to be a way from its entry to its return that makes no + call (one call, to __divsf3, for fmodf by a divisor that is not a + constant), it has to contain the FPU instructions the inline code is made + of, and the only library function it may call at all is the one it stands + in for - the fallback; + - the three controls (`__builtin_floorf(x)`, a call through a pointer to + floorf, lroundf) have to be plain calls still, which is what shows the + walk can tell a call from inline code; + - the module imports the seven names and __divsf3 and does not import fmaf: + the fused multiply-subtract is an instruction (MSUB.S) or it is a symbol + no firmware exports. + +It says nothing about the values the inline code computes on a panel - that is +tests/modules/_math_probe, on a board. + +Needs the xtensa-esp32s3 toolchain, found the way build_module.py finds it +(PF_XTENSA_BIN, an Arduino core, PlatformIO). CI runs it in the firmware build +job, which has PlatformIO's. +""" + +from __future__ import annotations + +import re +import subprocess +import sys +import tempfile +from dataclasses import dataclass, field +from pathlib import Path + +import build_module + +if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="replace") + +HERE = Path(__file__).resolve().parent +FIXTURE = HERE / "tests" / "modules" / "_libm_shapes" + +RETURNS = {"retw", "retw.n", "ret", "ret.n"} +CALLS = {"call0", "call4", "call8", "call12", "callx0", "callx4", "callx8", "callx12"} +LOOPS = {"loop", "loopnez", "loopgtz"} + +SECTION = re.compile(r"^Disassembly of section (\S+):") +FUNCTION = re.compile(r"^([0-9a-f]+) <([^>]+)>:\s*$") +INSTRUCTION = re.compile(r"^\s*([0-9a-f]+):\t[0-9a-f ]+\t([a-z_.0-9]+)(?:\t(.*?))?\s*$") +RELOCATION = re.compile(r"^\s+([0-9a-f]+): (R_XTENSA_\w+)\s+(\S+)") +ADDRESS = re.compile(r"\b([0-9a-f]+) <([^>+-]+)") + + +@dataclass +class Instruction: + address: int + mnemonic: str + operands: str + following: int = -1 # the next instruction's address + + +@dataclass +class Function: + name: str + start: int + section: str + code: dict[int, Instruction] = field(default_factory=dict) + # call instruction address -> what it calls ("?" when it cannot be named) + calls: dict[int, str] = field(default_factory=dict) + + def mnemonics(self) -> set[str]: + return {i.mnemonic for i in self.code.values()} + + def targets(self) -> set[str]: + return set(self.calls.values()) + + +def disassemble(obj: Path, objdump: Path) -> dict[str, Function]: + text = subprocess.run([str(objdump), "-dr", str(obj)], capture_output=True, + text=True, errors="replace", check=True).stdout + functions: dict[str, Function] = {} + # Keyed by section as well as address: an object has several code sections + # (libstdc++'s out-of-line overloads get one each), all starting at zero. + literal: dict[tuple[str, int], str] = {} # where a literal is -> the symbol stored there + expanded: dict[tuple[str, int], str] = {} # where an l32r is -> the symbol it is about to call + section = "" + current: Function | None = None + previous: Instruction | None = None + for line in text.splitlines(): + match = SECTION.match(line) + if match: + section = match.group(1) + current = previous = None + continue + match = FUNCTION.match(line) + if match: + current = Function(match.group(2), int(match.group(1), 16), section) + functions[current.name] = current + previous = None + continue + match = RELOCATION.match(line) + if match: + address, kind, symbol = int(match.group(1), 16), match.group(2), match.group(3) + if kind == "R_XTENSA_32": + literal[(section, address)] = symbol + elif kind == "R_XTENSA_ASM_EXPAND": + expanded[(section, address)] = symbol + continue + match = INSTRUCTION.match(line) + if match and current is not None: + instruction = Instruction(int(match.group(1), 16), match.group(2), match.group(3) or "") + current.code[instruction.address] = instruction + if previous is not None: + previous.following = instruction.address + previous = instruction + + # Name every call. With -mlongcalls a call to another section is + # `l32r aN, ` ... `callx8 aN`; a call inside the module may have + # been relaxed to a direct `call8 `. + for function in functions.values(): + loaded: dict[str, str] = {} + for address in sorted(function.code): + instruction = function.code[address] + if instruction.mnemonic == "l32r": + register = instruction.operands.split(",")[0].strip() + target = ADDRESS.search(instruction.operands) + symbol = expanded.get((function.section, address)) + if symbol is None and target: + symbol = literal.get((function.section, int(target.group(1), 16))) + if symbol is None: + loaded.pop(register, None) + else: + loaded[register] = symbol + elif instruction.mnemonic in CALLS: + if instruction.mnemonic.startswith("callx"): + function.calls[address] = loaded.get(instruction.operands.strip(), "?") + else: + target = ADDRESS.search(instruction.operands) + function.calls[address] = target.group(2) if target else "?" + return functions + + +def reaches_return(function: Function, allowed: set[str]) -> bool: + """Is there a way from entry to return that calls nothing outside `allowed`?""" + seen: set[int] = set() + pending = [function.start] + while pending: + address = pending.pop() + if address in seen or address not in function.code: + continue + seen.add(address) + instruction = function.code[address] + mnemonic = instruction.mnemonic + if mnemonic in RETURNS: + return True + if mnemonic in CALLS: + if function.calls.get(address, "?") in allowed: + pending.append(instruction.following) + continue + if mnemonic == "jx": + continue # an indirect jump: not followed + target = ADDRESS.search(instruction.operands) + if mnemonic == "j": + if target: + pending.append(int(target.group(1), 16)) + continue + if (mnemonic.startswith("b") and mnemonic != "break") or mnemonic in LOOPS: + if target: + pending.append(int(target.group(1), 16)) + pending.append(instruction.following) + return False + + +@dataclass +class Shape: + symbol: str + written: str + fallback: set[str] # every library call it may contain + needs: set[str] # instructions the inline code is made of + fast: set[str] = field(default_factory=set) # calls allowed on the way through + never: set[str] = field(default_factory=set) # instructions or calls that mean a wrong path + libstdcxx: bool = False # reached through 's float overloads + + +CONVERT = {"trunc.s", "float.s"} +SHAPES = [ + Shape("pf_shape_floorf", "floorf(x)", {"floorf"}, CONVERT), + Shape("pf_shape_ceilf", "ceilf(x)", {"ceilf"}, CONVERT), + Shape("pf_shape_truncf", "truncf(x)", {"truncf"}, CONVERT), + Shape("pf_shape_roundf", "roundf(x)", {"roundf"}, CONVERT), + Shape("pf_shape_fminf", "fminf(x, y)", {"fminf"}, {"olt.s"}), + Shape("pf_shape_fmaxf", "fmaxf(x, y)", {"fmaxf"}, {"olt.s"}), + Shape("pf_shape_fmodf", "fmodf(x, y)", {"fmodf", "__divsf3"}, CONVERT | {"msub.s"}, + fast={"__divsf3"}), + Shape("pf_shape_fmodf_one", "fmodf(x, 1.0f)", {"fmodf"}, CONVERT, + never={"msub.s", "mul.s", "__divsf3"}), + Shape("pf_shape_fmodf_const", "fmodf(x, 6.2831853f)", {"fmodf"}, CONVERT | {"msub.s", "mul.s"}, + never={"__divsf3"}), + Shape("pf_shape_fmodf_negconst", "fmodf(x, -360.0f)", {"fmodf"}, CONVERT | {"msub.s", "mul.s"}, + never={"__divsf3"}), + Shape("pf_shape_floor", "floor(x)", {"floorf"}, CONVERT, libstdcxx=True), + Shape("pf_shape_std_floor", "std::floor(x)", {"floorf"}, CONVERT, libstdcxx=True), + Shape("pf_shape_ceil", "ceil(x)", {"ceilf"}, CONVERT, libstdcxx=True), + Shape("pf_shape_trunc", "trunc(x)", {"truncf"}, CONVERT, libstdcxx=True), + Shape("pf_shape_round", "round(x)", {"roundf"}, CONVERT, libstdcxx=True), + Shape("pf_shape_fmin", "fmin(x, y)", {"fminf"}, {"olt.s"}, libstdcxx=True), + Shape("pf_shape_fmax", "fmax(x, y)", {"fmaxf"}, {"olt.s"}, libstdcxx=True), + Shape("pf_shape_fmod", "fmod(x, y)", {"fmodf", "__divsf3"}, CONVERT | {"msub.s"}, + fast={"__divsf3"}, libstdcxx=True), + Shape("pf_shape_std_fmod", "std::fmod(x, y)", {"fmodf", "__divsf3"}, CONVERT | {"msub.s"}, + fast={"__divsf3"}, libstdcxx=True), + Shape("pf_shape_std_fmod_const", "std::fmod(x, 6.2831853f)", {"fmodf"}, + CONVERT | {"msub.s", "mul.s"}, never={"__divsf3"}, libstdcxx=True), +] + +# symbol -> (what was written, what it has to call; None for a call that +# cannot be named from the object) +CONTROLS = { + "pf_control_builtin": ("__builtin_floorf(x)", "floorf"), + "pf_control_pointer": ("a call through a pointer to floorf", None), + "pf_control_lroundf": ("lroundf(x)", "lroundf"), +} + +IMPORTED = {"floorf", "ceilf", "truncf", "roundf", "fminf", "fmaxf", "fmodf", "__divsf3"} + + +def build(opt: str, gxx: Path, work: Path) -> tuple[Path, Path]: + """The fixture as a linked module and as the object it was linked from.""" + broken = (f"_libm_shapes does not build at -O{opt}: the module half of abi/pf_libm.h " + "is broken, or one of the fixture's static_asserts no longer holds") + # The whole pipeline, as a pattern gets it: this is what proves it links + # and imports nothing the loader lacks. + out = work / f"O{opt}" + command = [sys.executable, str(HERE / "build_module.py"), "--opt", opt, "--out", str(out), + str(FIXTURE)] + result = subprocess.run(command, capture_output=True, text=True, errors="replace") + if result.returncode != 0: + print(result.stdout + result.stderr) + raise SystemExit(broken) + # And the same compile again, kept as an object. The linked module has + # lost the assembler's map of instructions and padding, and a disassembler + # reading it falls out of step after the first literal pool. + objects = work / f"O{opt}-obj" + _, ok, log = build_module.build_one(FIXTURE, gxx, True, build_module.ABI, objects, out, opt) + if not ok: + print(log) + raise SystemExit(broken) + return out / "_libm_shapes.pfm", objects / FIXTURE.name / "pattern.o" + + +def check(opt: str, redirected: bool, gxx: Path, tools: dict[str, Path], work: Path) -> list[str]: + """Every problem found in the fixture built at -O.""" + pfm, obj = build(opt, gxx, work) + functions = disassemble(obj, tools["objdump"]) + problems: list[str] = [] + + for shape in SHAPES: + if shape.libstdcxx and not redirected: + continue + function = functions.get(shape.symbol) + if function is None: + problems.append(f"-O{opt} {shape.written}: {shape.symbol} is not in the module") + continue + found: list[str] = [] + if not reaches_return(function, shape.fast): + found.append("every way through it makes a library call - it is not inline") + missing = shape.needs - function.mnemonics() + if missing: + found.append("no " + ", ".join(sorted(missing)) + " in it") + stray = function.targets() - shape.fallback + if stray: + found.append("calls " + ", ".join(sorted(stray)) + ", which is not its fallback") + wrong = shape.never & (function.mnemonics() | function.targets()) + if wrong: + found.append("has " + ", ".join(sorted(wrong)) + " - the wrong fmod path") + if found: + problems.append(f"-O{opt} {shape.written}: " + "; ".join(found)) + else: + through = f", through {'/'.join(sorted(shape.fast))} only" if shape.fast else "" + print(f" ok -O{opt} {shape.written:<26} inline{through}; fallback " + f"{'/'.join(sorted(function.targets() - shape.fast)) or '-'}") + + for symbol, (written, target) in CONTROLS.items(): + function = functions.get(symbol) + if function is None: + problems.append(f"-O{opt} control {written}: {symbol} is not in the module") + elif (reaches_return(function, set()) or not function.calls + or (target is not None and target not in function.targets()) + or "trunc.s" in function.mnemonics()): + problems.append(f"-O{opt} control {written}: expected a plain call and found " + "something else - the walk cannot be trusted") + else: + print(f" ok -O{opt} {written:<34} still a call") + + listed = subprocess.run([str(tools["nm"]), "-u", str(pfm)], capture_output=True, text=True, + check=True).stdout + imports = {line.split()[-1] for line in listed.splitlines() if line.strip()} + if "fmaf" in imports: + problems.append(f"-O{opt}: the module imports fmaf - the multiply-subtract is a call, " + "and no firmware exports that name") + if not IMPORTED <= imports: + problems.append(f"-O{opt}: expected imports missing: {', '.join(sorted(IMPORTED - imports))}") + unknown = imports - build_module.host_symbol_table() + if unknown: + problems.append(f"-O{opt}: imports no loader resolves: {', '.join(sorted(unknown))}") + print(f" -O{opt} imports: {' '.join(sorted(imports))}") + return problems + + +def main() -> int: + gxx = build_module.find_tool("g++") + tools = {"objdump": build_module.find_tool("objdump"), "nm": build_module.find_tool("nm")} + version = subprocess.run([str(gxx), "-dumpversion"], capture_output=True, text=True, + check=True).stdout.strip() + major = int(version.split(".")[0]) + # The same range abi/pf_libm.h redirects libstdc++'s overloads for. + redirected = 8 <= major <= 14 + print(f"xtensa g++ {version}" + ("" if redirected else + " - outside 8..14, so floor()/std::floor() and kin are expected to stay calls")) + + problems: list[str] = [] + with tempfile.TemporaryDirectory(prefix="patternflow-module-libm-") as directory: + work = Path(directory) + # The default level, every spelling. Then -Os, where the C names still + # have to be inline (always_inline) but GCC is free to keep libstdc++'s + # overloads as functions of the module's own. + problems += check(build_module.DEFAULT_OPT, redirected, gxx, tools, work) + problems += check("s", False, gxx, tools, work) + + if problems: + print("\nthe module half of abi/pf_libm.h is not what it claims:") + for problem in problems: + print(" " + problem) + return 1 + print("module libm inline: every claimed spelling, library kept as the fallback only") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/firmware/toolchain/tests/libm_test.cpp b/firmware/toolchain/tests/libm_test.cpp new file mode 100644 index 00000000..c9a97bf9 --- /dev/null +++ b/firmware/toolchain/tests/libm_test.cpp @@ -0,0 +1,500 @@ +// Proves that abi/pf_libm.h returns what libm returns - as bits, not as +// values within a tolerance. +// +// WHY THIS EXISTS. pf_module.h puts the functions in pf_libm.h behind floorf, +// ceilf, truncf, roundf, fminf, fmaxf and fmodf in every .pfm built from now +// on, so that a pattern nobody edits gets inline FPU code where it used to get +// a call into the firmware's libm. The claim that makes that acceptable is +// that each of the seven returns exactly what the library function returns. +// An approximation would be measured in bands (toolchain/check_math.py does +// that for core_math.h); this is not one, so the test is equality of bit +// patterns and any single mismatch fails. +// +// WHAT IT RUNS. The reference is this machine's libm: floorf, fmodf and the +// rest, called as functions - check_libm.py passes -fno-builtin- for each, +// because left alone GCC answers some of them itself on a PC, and its inline +// floor does not quiet a signalling NaN the way glibc's function does. +// pf_libm.h handles inline only inputs whose answer IEEE 754 fixes, and hands +// the rest to libm - so on any machine with a correct libm the two must agree +// everywhere, NaN payloads and signed zeros included, and no NaN is ever +// "treated as equal to any NaN" here: where a NaN comes back it came from the +// same libm call on both sides. +// +// floor, ceil, trunc, round every one of the 2^32 float bit patterns. +// fmin, fmax every pair of a set of edge values, random bit +// patterns, and for a stride through all floats +// x against itself, its neighbour and its +// negation - the ties are where the care is. +// fmod the path a variable divisor takes (a division) +// AND the path a constant divisor takes (the +// reciprocal, instantiated explicitly: the test +// passes 1.0f / |y|, which is what the compiler +// folds), on the same pairs: edge values, +// random bits, quotients spread from under 1 to +// past the fast path's 2^22 limit, x = k*y +- 0..4 +// ulp for k up to 2^24, the divisors patterns +// actually write (1, 2*pi, 360, 0.1 ...), divisors +// so large their reciprocal is subnormal and so +// small it overflows. fmodOne - the y = +-1 path - +// over every float in [1, 2^23), both signs. +// +// The run also counts which way each fmod went (returned x, no correction, +// stepped down, stepped up, library), because a correction branch that no +// input reaches is a branch this file has not tested. +// +// WHAT IT CANNOT RUN. The module-only half of the header - the bodies behind +// the C names and the choice between fmod's paths exist only under the Xtensa +// compiler; check_module_libm.py builds a module and reads them out of it. And +// the panel's arithmetic: that the S3's MSUB.S is fused and its conversions +// round as IEEE says. tests/modules/_math_probe checks those on a board, +// against the firmware's own libm. +// +// License: MIT +#include "pf_libm.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +uint32_t bitsOf(float f) { + uint32_t u; + std::memcpy(&u, &f, sizeof u); + return u; +} + +float fromBits(uint32_t u) { + float f; + std::memcpy(&f, &u, sizeof f); + return f; +} + +// SplitMix64: every block of work seeds its own, from its own index, so the +// inputs are the same whatever number of threads happens to run them. +struct Random { + uint64_t state; + explicit Random(uint64_t seed) : state(seed * 0x9E3779B97F4A7C15ull + 0x1234567ull) {} + uint64_t next() { + uint64_t z = (state += 0x9E3779B97F4A7C15ull); + z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ull; + z = (z ^ (z >> 27)) * 0x94D049BB133111EBull; + return z ^ (z >> 31); + } + uint32_t bits() { return (uint32_t)(next() >> 32); } + uint32_t below(uint32_t n) { return (uint32_t)((next() >> 32) * (uint64_t)n >> 32); } +}; + +enum Route { EARLY, PLAIN, DOWN, UP, LIBRARY, ROUTES }; + +struct Miss { + const char* what; + uint32_t x, y, got, want; +}; + +struct Tally { + uint64_t checked = 0; + uint64_t wrong = 0; + uint64_t inlined = 0; // unary / min-max inputs the library never saw + uint64_t divided[ROUTES] = {}; // fmod with a division + uint64_t multiplied[ROUTES] = {}; // fmod with a reciprocal + Miss first[6] = {}; + int misses = 0; + + void same(const char* what, float x, float y, float got, float want) { + ++checked; + if (bitsOf(got) == bitsOf(want)) return; + ++wrong; + if (misses < (int)(sizeof first / sizeof first[0])) + first[misses++] = Miss{what, bitsOf(x), bitsOf(y), bitsOf(got), bitsOf(want)}; + } + + void merge(const Tally& other) { + checked += other.checked; + wrong += other.wrong; + inlined += other.inlined; + for (int r = 0; r < ROUTES; ++r) { + divided[r] += other.divided[r]; + multiplied[r] += other.multiplied[r]; + } + for (int i = 0; i < other.misses && misses < (int)(sizeof first / sizeof first[0]); ++i) + first[misses++] = other.first[i]; + } +}; + +template +Tally inParallel(uint64_t blocks, Work work) { + unsigned count = std::thread::hardware_concurrency(); + if (count == 0) count = 1; + if (count > 32) count = 32; + std::atomic next{0}; + std::vector tallies(count); + std::vector threads; + for (unsigned t = 0; t < count; ++t) { + threads.emplace_back([&next, &tallies, &work, blocks, t] { + Tally mine; // on this thread's stack: no cache line shared with a neighbour + for (;;) { + const uint64_t block = next.fetch_add(1); + if (block >= blocks) break; + work(block, mine); + } + tallies[t] = mine; + }); + } + for (auto& thread : threads) thread.join(); + Tally total; + for (const Tally& tally : tallies) total.merge(tally); + return total; +} + +int failures = 0; + +void report(const char* title, const Tally& tally) { + std::printf("%-28s %14llu checks, %llu mismatches\n", title, + (unsigned long long)tally.checked, (unsigned long long)tally.wrong); + for (int i = 0; i < tally.misses; ++i) { + const Miss& m = tally.first[i]; + std::printf(" %s(%08x, %08x) = %08x, libm says %08x\n", m.what, m.x, m.y, m.got, m.want); + } + if (tally.wrong) ++failures; +} + +void require(bool ok, const char* what) { + if (ok) return; + std::printf(" NOT COVERED: %s\n", what); + ++failures; +} + +// ── Values every list of floats should contain ────────────────────── +const uint32_t EDGES[] = { + 0x00000000u, 0x80000000u, // +-0 + 0x00000001u, 0x80000001u, // smallest subnormal + 0x00000002u, 0x00000003u, 0x00400000u, 0x80400000u, + 0x007fffffu, 0x807fffffu, // largest subnormal + 0x00800000u, 0x80800000u, // smallest normal + 0x00800001u, 0x00ffffffu, 0x01000000u, + 0x3e800000u, 0x3effffffu, 0x3f000000u, 0xbf000000u, // 0.25, just under 0.5, +-0.5 + 0x3f000001u, 0x3f7fffffu, 0xbf7fffffu, // just over 0.5, just under 1 + 0x3f800000u, 0xbf800000u, 0x3f800001u, 0xbf800001u, // +-1 and a bit + 0x3fc00000u, 0xbfc00000u, 0x40000000u, 0xc0000000u, // +-1.5, +-2 + 0x40200000u, 0xc0200000u, 0x40490fdbu, 0x40c90fdbu, // +-2.5, pi, 2*pi + 0x43b40000u, 0x3dcccccdu, 0x3a83126fu, // 360, 0.1, 0.001 + 0x4a7ffffcu, 0x4a7ffffeu, 0x4a800000u, 0xca800000u, // around 2^22 + 0x4a800002u, 0x4afffffeu, 0x4affffffu, 0xcaffffffu, // ... and under 2^23 + 0x4b000000u, 0xcb000000u, 0x4b000001u, 0xcb000001u, // 2^23 and a bit + 0x4b7fffffu, 0x4b800000u, 0xcb800000u, 0x4b800001u, // around 2^24 + 0x4f000000u, 0xcf000000u, 0x4effffffu, 0x4f800000u, // 2^31, just under, 2^32 + 0x5f000000u, 0x7e800000u, 0x7effffffu, 0x7f000000u, // 2^63, 2^126, 2^127 + 0x7f7fffffu, 0xff7fffffu, // +-FLT_MAX + 0x7f800000u, 0xff800000u, // +-inf + 0x7fc00000u, 0xffc00000u, // quiet NaN, both signs + 0x7f800001u, 0xff800001u, // signalling NaN + 0x7fa00000u, 0x7fffffffu, 0xffffffffu, 0x7fc12345u, // payloads +}; +const int EDGE_COUNT = (int)(sizeof EDGES / sizeof EDGES[0]); + +// A float with every exponent equally likely - random bits already are, but +// this one can be steered. +float anyExponent(Random& random, int exponentField) { + if (exponentField < 0) exponentField = 0; + if (exponentField > 254) exponentField = 254; + return fromBits((random.bits() & 0x807fffffu) | ((uint32_t)exponentField << 23)); +} + +int exponentFieldOf(float f) { + return (int)((bitsOf(f) >> 23) & 0xffu); +} + +// d units in the last place away, by magnitude; never past zero or FLT_MAX. +float stepped(float x, int d) { + const uint32_t u = bitsOf(x); + int64_t magnitude = (int64_t)(u & 0x7fffffffu) + d; + if (magnitude < 0) magnitude = 0; + if (magnitude > 0x7f7fffff) magnitude = 0x7f7fffff; + return fromBits((u & 0x80000000u) | (uint32_t)magnitude); +} + +// ── floor, ceil, trunc, round: every float ────────────────────────── +const uint64_t UNARY_BLOCKS = 4096; // of 2^20 bit patterns each + +void unaryBlock(uint64_t block, Tally& tally) { + const uint32_t base = (uint32_t)(block << 20); + for (uint32_t i = 0; i < (1u << 20); ++i) { + const float x = fromBits(base + i); + tally.same("floor", x, 0.0f, PFLibm::floor(x), ::floorf(x)); + tally.same("ceil", x, 0.0f, PFLibm::ceil(x), ::ceilf(x)); + tally.same("trunc", x, 0.0f, PFLibm::trunc(x), ::truncf(x)); + tally.same("round", x, 0.0f, PFLibm::round(x), ::roundf(x)); + if (std::fabs(x) < PFLibm::WHOLE_FROM) ++tally.inlined; + } +} + +// ── fmin, fmax ────────────────────────────────────────────────────── +void minMax(float x, float y, Tally& tally) { + tally.same("fmin", x, y, PFLibm::fmin(x, y), ::fminf(x, y)); + tally.same("fmax", x, y, PFLibm::fmax(x, y), ::fmaxf(x, y)); + // What the header's last test decides: equal values with the same sign bit. + if (x < y || y < x || (x == y && std::signbit(x) == std::signbit(y))) ++tally.inlined; +} + +void minMaxEdges(uint64_t, Tally& tally) { + for (int i = 0; i < EDGE_COUNT; ++i) + for (int j = 0; j < EDGE_COUNT; ++j) minMax(fromBits(EDGES[i]), fromBits(EDGES[j]), tally); +} + +const uint64_t MINMAX_RANDOM_BLOCKS = 64; // of 2^20 pairs +void minMaxRandomBlock(uint64_t block, Tally& tally) { + Random random(0x100000 + block); + for (uint32_t i = 0; i < (1u << 20); ++i) minMax(fromBits(random.bits()), fromBits(random.bits()), tally); +} + +const uint64_t MINMAX_NEAR_BLOCKS = 256; // each a 2^24 slice of the float line, every 61st +void minMaxNearBlock(uint64_t block, Tally& tally) { + const uint32_t base = (uint32_t)(block << 24); + for (uint32_t i = (uint32_t)(block % 61); i < (1u << 24); i += 61) { + const float x = fromBits(base + i); + minMax(x, x, tally); + minMax(x, fromBits(base + i + 1), tally); + minMax(fromBits(base + i + 1), x, tally); + minMax(x, -x, tally); + minMax(-x, x, tally); + } +} + +// ── fmod ──────────────────────────────────────────────────────────── +// Which branch fmodFrom() takes for this estimate of the quotient. It repeats +// the header's conditions on purpose: this is bookkeeping about coverage, and +// the answers themselves are compared separately, against libm. +Route routeOf(float ax, float ay, float p) { + if (ax < ay) return EARLY; + if (!(p < PFLibm::FMOD_QUOTIENT_BELOW)) return LIBRARY; + const float q = (float)(int)p; + const float r = PFLibm::fnma(q, ay, ax); + if (r < 0.0f) return DOWN; + if (r >= ay) return UP; + return PLAIN; +} + +void mod(float x, float y, Tally& tally) { + const float want = ::fmodf(x, y); + const float ax = std::fabs(x); + const float ay = std::fabs(y); + const float reciprocal = 1.0f / ay; // rounded to nearest: what a compiler folds + tally.same("fmod", x, y, PFLibm::fmod(x, y), want); + tally.same("fmodRecip", x, y, PFLibm::fmodRecip(x, y, reciprocal), want); + ++tally.divided[routeOf(ax, ay, ax / ay)]; + ++tally.multiplied[routeOf(ax, ay, ax * reciprocal)]; + if (ay == 1.0f) tally.same("fmodOne", x, y, PFLibm::fmodOne(x, y), want); +} + +void modAllSigns(float x, float y, Tally& tally) { + mod(x, y, tally); + mod(-x, y, tally); + mod(x, -y, tally); + mod(-x, -y, tally); +} + +void modEdges(uint64_t, Tally& tally) { + for (int i = 0; i < EDGE_COUNT; ++i) + for (int j = 0; j < EDGE_COUNT; ++j) mod(fromBits(EDGES[i]), fromBits(EDGES[j]), tally); +} + +// Random bit patterns: mostly |x| < |y| or a quotient far past the limit, so +// mostly a test that those are routed to "return x" and to the library. +const uint64_t MOD_RANDOM_BLOCKS = 16; // of 2^20 pairs +void modRandomBlock(uint64_t block, Tally& tally) { + Random random(0x200000 + block); + for (uint32_t i = 0; i < (1u << 20); ++i) mod(fromBits(random.bits()), fromBits(random.bits()), tally); +} + +// Any divisor at all - subnormal to FLT_MAX - and a dividend whose exponent is +// -1 to +25 above it: quotients from under one, through the whole fast path, +// to eight times its limit. +const uint64_t MOD_SPREAD_BLOCKS = 192; // of 2^20 pairs +void modSpreadBlock(uint64_t block, Tally& tally) { + Random random(0x300000 + block); + for (uint32_t i = 0; i < (1u << 20); ++i) { + const float y = anyExponent(random, (int)random.below(255)); + const float x = anyExponent(random, exponentFieldOf(y) - 1 + (int)random.below(27)); + mod(x, y, tally); + } +} + +// The divisors patterns write. +const float DIVISORS[] = { + 1.0f, 2.0f, 3.0f, 0.5f, 0.25f, 1.5f, 0.1f, + 0.01f, 0.001f, 1e-6f, 3.14159265f, 6.2831853f, 1.57079633f, 2.71828183f, + 360.0f, 180.0f, 255.0f, 256.0f, 100.0f, 1000.0f, 10.0f, + 6.0f, 60.0f, 64.0f, 128.0f, 0.33333334f, 1e6f, 7.0f, +}; +const int DIVISOR_COUNT = (int)(sizeof DIVISORS / sizeof DIVISORS[0]); + +// x = k*y, and the four floats either side of it. k is drawn three ways: +// anywhere up to 2^24, small, and on the boundaries the proof turns on. +uint32_t multiple(Random& random) { + static const uint32_t BOUNDARY[] = { + 1u, 2u, 3u, 4u, 5u, 7u, 255u, 256u, 65535u, 65536u, + (1u << 22) - 3, (1u << 22) - 2, (1u << 22) - 1, (1u << 22), (1u << 22) + 1, (1u << 22) + 2, + (1u << 23) - 2, (1u << 23) - 1, (1u << 23), (1u << 23) + 1, (1u << 24) - 1, (1u << 24), + }; + switch (random.below(4)) { + case 0: return 1u + random.below(1u << 24); + case 1: return 1u + random.below(1u << 22); // all of it inside the fast path + case 2: return 1u + random.below(1u << (1 + random.below(22))); + default: return BOUNDARY[random.below((uint32_t)(sizeof BOUNDARY / sizeof BOUNDARY[0]))]; + } +} + +void nearMultiples(Random& random, float y, uint32_t count, Tally& tally) { + for (uint32_t i = 0; i < count; ++i) { + const double product = (double)multiple(random) * (double)y; + if (!(product < 3.0e38)) continue; + const float x = (float)product; + for (int d = -4; d <= 4; ++d) { + const float beside = stepped(x, d); + if (random.below(8) == 0) modAllSigns(beside, y, tally); + else mod(beside, y, tally); + } + } +} + +const uint64_t MOD_CONSTANT_BLOCKS = (uint64_t)DIVISOR_COUNT * 4; +void modConstantBlock(uint64_t block, Tally& tally) { + Random random(0x400000 + block); + nearMultiples(random, DIVISORS[block % DIVISOR_COUNT], 60000, tally); +} + +const uint64_t MOD_MULTIPLE_BLOCKS = 96; +void modMultipleBlock(uint64_t block, Tally& tally) { + Random random(0x500000 + block); + for (int i = 0; i < 6000; ++i) { + // Exponents -40..+40: k*y stays finite and x keeps all its bits. + const float y = anyExponent(random, 87 + (int)random.below(81)); + nearMultiples(random, y, 10, tally); + } +} + +// Every 67th float from y/4 up to y * 2^24, for each written divisor. +const uint64_t MOD_SWEEP_BLOCKS = (uint64_t)DIVISOR_COUNT; +void modSweepBlock(uint64_t block, Tally& tally) { + const float y = DIVISORS[block]; + const uint32_t from = bitsOf(y * 0.25f); + const uint32_t to = bitsOf(y * 16777216.0f); + for (uint32_t u = from + (uint32_t)(block % 67); u < to; u += 67) { + const float x = fromBits(u); + if ((u & 0x100u) != 0) mod(-x, y, tally); + else mod(x, y, tally); + } +} + +// Divisors at the two ends of the range. From 2^126 up, 1/y is subnormal and +// its error is absolute, not relative; below 2^-128 it overflows to infinity. +const uint64_t MOD_EXTREME_BLOCKS = 16; // of 2^20 pairs +void modExtremeBlock(uint64_t block, Tally& tally) { + Random random(0x600000 + block); + for (uint32_t i = 0; i < (1u << 20); ++i) { + const bool huge = (i & 1u) != 0; + const float y = anyExponent(random, huge ? 251 + (int)random.below(4) : (int)random.below(4)); + const float x = anyExponent(random, exponentFieldOf(y) + (int)random.below(huge ? 4 : 26)); + mod(x, y, tally); + } +} + +// fmod(x, +-1): every float in [1, 2^23), both signs and both divisors, which +// is all of what fmodOne computes itself; under 1 it returns x, past 2^23 it +// asks the library, and a stride through each is enough to see that it does. +const uint64_t MOD_ONE_BLOCKS = 23 * 8 + 128 + 16; +void modOneBlock(uint64_t block, Tally& tally) { + uint32_t from, to, step; + if (block < 23 * 8) { // [1, 2^23): 23 binades, each in eight slices + from = 0x3f800000u + (uint32_t)block * (1u << 20); + to = from + (1u << 20); + step = 1; + } else if (block < 23 * 8 + 128) { // [0, 1), every 16th + from = (uint32_t)(block - 23 * 8) * (0x3f800000u / 128); + to = from + 0x3f800000u / 128; + step = 16; + } else { // 2^23 and up, infinities and NaN included, every 4099th + from = 0x4b000000u + (uint32_t)(block - 23 * 8 - 128) * (0x35000000u / 16); + to = from + 0x35000000u / 16; + step = 4099; + } + for (uint32_t u = from; u < to; u += step) { + const float x = fromBits(u); + for (int sign = 0; sign < 4; ++sign) { + const float sx = (sign & 1) ? -x : x; + const float sy = (sign & 2) ? -1.0f : 1.0f; + tally.same("fmodOne", sx, sy, PFLibm::fmodOne(sx, sy), ::fmodf(sx, sy)); + } + // The general paths on the same input now and then: a divisor of one is + // also just a divisor. + if ((u & 0x3fu) == 0) mod(x, 1.0f, tally); + } +} + +void routes(const char* title, const uint64_t* count) { + std::printf(" %-22s returned x %llu, exact at once %llu, stepped down %llu, " + "stepped up %llu, library %llu\n", + title, (unsigned long long)count[EARLY], (unsigned long long)count[PLAIN], + (unsigned long long)count[DOWN], (unsigned long long)count[UP], + (unsigned long long)count[LIBRARY]); +} + +} // namespace + +int main() { + // Unary: all of them. + const Tally unary = inParallel(UNARY_BLOCKS, unaryBlock); + report("floor ceil trunc round", unary); + std::printf(" every float bit pattern through each; %llu of 4294967296 inputs inline, " + "the rest (2^23 and up, inf, NaN) the library's\n", + (unsigned long long)unary.inlined); + require(unary.checked == 4ull * 4294967296ull, "not every float was run"); + require(unary.inlined == 2ull * 150ull * 8388608ull, "the inline range is not |x| < 2^23"); + + Tally minmax = inParallel(1, minMaxEdges); + minmax.merge(inParallel(MINMAX_RANDOM_BLOCKS, minMaxRandomBlock)); + minmax.merge(inParallel(MINMAX_NEAR_BLOCKS, minMaxNearBlock)); + report("fmin fmax", minmax); + std::printf(" %llu pairs; %llu settled inline, %llu (a NaN, or +0 against -0) by the library\n", + (unsigned long long)(minmax.checked / 2), (unsigned long long)minmax.inlined, + (unsigned long long)(minmax.checked / 2 - minmax.inlined)); + require(minmax.checked / 2 > minmax.inlined, "no pair reached the library"); + + Tally fmod = inParallel(1, modEdges); + fmod.merge(inParallel(MOD_RANDOM_BLOCKS, modRandomBlock)); + fmod.merge(inParallel(MOD_SPREAD_BLOCKS, modSpreadBlock)); + fmod.merge(inParallel(MOD_CONSTANT_BLOCKS, modConstantBlock)); + fmod.merge(inParallel(MOD_MULTIPLE_BLOCKS, modMultipleBlock)); + fmod.merge(inParallel(MOD_SWEEP_BLOCKS, modSweepBlock)); + fmod.merge(inParallel(MOD_EXTREME_BLOCKS, modExtremeBlock)); + report("fmod (both paths)", fmod); + uint64_t pairs = 0; + for (int r = 0; r < ROUTES; ++r) pairs += fmod.divided[r]; + std::printf(" %llu pairs, each through the division path and the reciprocal path\n", + (unsigned long long)pairs); + routes("division:", fmod.divided); + routes("reciprocal:", fmod.multiplied); + for (int r = 0; r < ROUTES; ++r) { + // A correctly rounded quotient is never under the true one by a whole + // step, so the division path has no reason to step up; the branch is + // there for a divider that rounds less well than this machine's. + if (r != UP) require(fmod.divided[r] > 1000, "a branch of the division path saw under 1000 pairs"); + require(fmod.multiplied[r] > 1000, "a branch of the reciprocal path saw under 1000 pairs"); + } + + const Tally one = inParallel(MOD_ONE_BLOCKS, modOneBlock); + report("fmod by +-1", one); + + if (failures) { + std::printf("pf_libm.h does NOT match libm\n"); + return 1; + } + std::printf("pf_libm.h exact: %llu comparisons, bit for bit\n", + (unsigned long long)(unary.checked + minmax.checked + fmod.checked + one.checked)); + return 0; +} diff --git a/firmware/toolchain/tests/math_test.cpp b/firmware/toolchain/tests/math_test.cpp index ff22419f..8a438eef 100644 --- a/firmware/toolchain/tests/math_test.cpp +++ b/firmware/toolchain/tests/math_test.cpp @@ -2,7 +2,7 @@ // core_color.h, core_noise.h — against double-precision references, and pins // every number it measures. // -// WHY THIS EXISTS. abi/pf_module.h:241-243 includes these three files into every +// WHY THIS EXISTS. abi/pf_module.h:260-262 includes these three files into every // .pfm, so they are not internal helpers: they are the published pattern SDK. Up // to this file, nothing in the repository ran a single number through them. Their // accuracy was asserted only in doc-comments, and two of those comments turned out diff --git a/firmware/toolchain/tests/module_elf_test.cpp b/firmware/toolchain/tests/module_elf_test.cpp index fbc00f5a..836758fe 100644 --- a/firmware/toolchain/tests/module_elf_test.cpp +++ b/firmware/toolchain/tests/module_elf_test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include using namespace PFModuleLoader; @@ -80,31 +81,72 @@ static T read(const std::vector& image, size_t offset) { return value; } -// The largest executable-section total a module shipped from this repository may -// have. It is NOT a guarantee that a board will admit it: the device compares -// codeBytes against budget() = serviceFree() - PF_MODULE_INTERNAL_RESERVE, and -// serviceFree() is ambient - an HTTP response in flight, an rtpMIDI session and a -// DHCP renew all move it. This is a floor of observations, and its job is to stop -// a module being added here that the tightest edition cannot load. +// What a module shipped from this repository may cost in code, as the loader +// prices it (the sum of its executable sections). Two numbers, because since +// 3.10.5 there are two places code can go. // -// Set 2026-09-10 from docs/investigations/2026-09-firmware-runtime.md: +// SHIPPED_CODE_CEILING - every module, no exceptions. Code is placed in PSRAM +// (PF_MODULE_CODE_PSRAM_FIRST, src/core_module_memory.h) and charged nothing +// against internal RAM, and the loader keeps megabytes of PSRAM free before a +// load, so whether a module comes on no longer depends on its size. What still +// does is what it costs to run: code in PSRAM is fetched through the 16 KB +// instruction cache (CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE 0x4000). Measured +// 2026-10-01, A-B-B-A on one boot (core_module_memory.h has the table): nine +// catalogue modules ran within -0.1..+0.8 % of their internal-RAM frame time; +// 10, 23 and 32 KB with every byte executed every frame cost 2.6..5.3 %. The +// ceiling is the cache: a module under it can sit in the cache whole, one over +// it refetches part of itself from PSRAM every frame. Going over is allowed +// and is a decision, not a formality - measure that module's frame time with +// its code placed both ways and say in the commit what it cost. +// +// INTERNAL_PLACEMENT_LINE - where the ceiling used to be, and why it is still +// written down. Code goes to internal RAM wherever PSRAM is not used for it: +// on every firmware before 3.10.5, and on a unit that has demoted itself after +// a failed read-back (codeDemoted). There it is admitted against +// budget() = serviceFree() - PF_MODULE_INTERNAL_RESERVE, and serviceFree() is +// ambient - an HTTP response in flight, an rtpMIDI session and a DHCP renew +// all move it. Set 2026-09-10 from docs/investigations/2026-09-firmware-runtime.md: // the module's internal share with none resident measures 7,816 B (section 4.4) // boot-to-boot ambient variance is about 700 B (section 4.1) -// so the worst reasonable budget is about 7,116 B -// the largest module currently shipped, breakout_arcade.pfm, is 5,364 B -// 6,144 sits 780 B above what ships and 972 B below the worst budget. Section 4.2 -// is what the absence of this number cost: a firmware that could not load its own -// pack, 24,576 + 5,364 = 29,940 against ~28,320 free, found by hardware bisect. +// so the worst reasonable budget is about 7,116 B - on the Audio edition, the +// tightest (41,036 B internal free after smoke, against Default's 73,172 B) +// and 6,144 sits 972 B below that. Section 4.2 is what the absence of this +// number once cost: a firmware that could not load its own pack, 24,576 + +// 5,364 = 29,940 against ~28,320 free, found by hardware bisect. +// +// A module over the line loads wherever code runs from PSRAM. Where it does +// not, it is refused once it is past the budget: about 7.8 KB on an Audio +// build before 3.10.5 (7.1 on a bad boot), some 48 KB on the default one. +// Nothing builds a module smaller for that firmware - it is told to update - +// so this is a real cost, and it is taken by name: a module over the line has +// to be listed in OVER_INTERNAL_LINE to pass, and listing one is the decision +// to give up loading it there, said in the commit. // -// Raising it is allowed and is a decision, not a formality: re-measure -// moduleMemory.budget from /api/status on the Audio edition (the tightest - 41,036 B -// internal free after smoke, against Default's 73,172 B), with the console open and -// a module resident, sample repeatedly against the ambient variance, and say in the -// commit which observation the new number came from. -static constexpr size_t SHIPPED_CODE_CEILING = 6144; +// breakout_arcade was listed 2026-10-04, when modules began to be built at -O2 +// with libm inline (build_module.py DEFAULT_OPT, abi/pf_libm.h): 5,564 B the +// old way, 6,568 B at -Os with libm inline, 14,204 B at -O2. The other 32 +// modules in the pack are under 4.5 KB. +static constexpr size_t SHIPPED_CODE_CEILING = 16384; +static constexpr size_t INTERNAL_PLACEMENT_LINE = 6144; +static const char* const OVER_INTERNAL_LINE[] = {"breakout_arcade"}; static size_t largestShippedCode = 0; static const char* largestShippedName = ""; +static std::string overInternalLine; + +// "dir/26-breakout_arcade.pfm" -> "breakout_arcade": check_module_elf.py names +// each fixture -. +static std::string slugOf(const char* path) { + std::string name = path; + const size_t slash = name.find_last_of("/\\"); + if (slash != std::string::npos) name.erase(0, slash + 1); + const size_t dash = name.find('-'); + if (dash != std::string::npos && name.find_first_not_of("0123456789") == dash) + name.erase(0, dash + 1); + const size_t dot = name.rfind(".pfm"); + if (dot != std::string::npos) name.erase(dot); + return name; +} // Exercise the production bounds functions on the modules actually shipped // in Basics. This checks compatibility of the file checks, not Xtensa execution. @@ -162,12 +204,27 @@ static void shippedModule(const char* path) { if (codeBytes > SHIPPED_CODE_CEILING) { std::cerr << path << ": " << codeBytes << " B of executable sections, over the " << SHIPPED_CODE_CEILING << " B ceiling for a module shipped from this\n" - << "repository. A board admits code only against " - << "serviceFree() - PF_MODULE_INTERNAL_RESERVE, so this one may simply\n" - << "not come on. Read the ceiling's provenance in this file before " - << "raising it.\n"; + << "repository - more than the instruction cache holds, so part of it " + << "is fetched from PSRAM again every frame.\n" + << "Read the ceiling's provenance in this file before raising it.\n"; throw std::runtime_error("shipped module over the code ceiling"); } + if (codeBytes > INTERNAL_PLACEMENT_LINE) { + const std::string slug = slugOf(path); + bool listed = false; + for (const char* name : OVER_INTERNAL_LINE) listed = listed || slug == name; + if (!listed) { + std::cerr << path << ": " << codeBytes << " B of executable sections, over the " + << INTERNAL_PLACEMENT_LINE << " B internal RAM can be counted on to take.\n" + << "It loads where code runs from PSRAM (3.10.5 and later) and may be " + << "refused where it does not.\n" + << "If that is meant, list it in OVER_INTERNAL_LINE and say so in the " + << "commit; the reasoning is in this file.\n"; + throw std::runtime_error("shipped module over the internal placement line, unlisted"); + } + if (!overInternalLine.empty()) overInternalLine += ", "; + overInternalLine += slug + " " + std::to_string(codeBytes) + " B"; + } } int main(int argc, char** argv) { @@ -184,6 +241,9 @@ int main(int argc, char** argv) { << "), ceiling " << SHIPPED_CODE_CEILING << " B, headroom " << (SHIPPED_CODE_CEILING - largestShippedCode) << " B\n"; + std::cout << "over the " << INTERNAL_PLACEMENT_LINE + << " B internal placement line, so PSRAM only: " + << (overInternalLine.empty() ? "none" : overInternalLine) << '\n'; } return 0; } catch (const std::exception& error) { diff --git a/firmware/toolchain/tests/modules/_libm_shapes/pattern.cpp b/firmware/toolchain/tests/modules/_libm_shapes/pattern.cpp new file mode 100644 index 00000000..8cbed6a7 --- /dev/null +++ b/firmware/toolchain/tests/modules/_libm_shapes/pattern.cpp @@ -0,0 +1,106 @@ +// Build-time fixture for firmware/toolchain/check_module_libm.py, not a +// showable pattern. check_libm.py proves abi/pf_libm.h's algorithms on a PC, +// but the half of that header a module actually uses - the bodies behind the C +// names, the redirection of libstdc++'s float overloads, the choice between +// the three fmod paths - exists only under PF_MODULE_BUILD on the Xtensa +// compiler, and no PC test compiles it. This file is that half, one spelling a +// function, so the check can read each one out of the built .pfm: +// +// pf_shape_ what a pattern writes; must be inline code with the +// library call left only as the fallback +// pf_control_ what must STILL be a plain call - there so the check +// is known to tell the two apart +// +// The static_asserts are evaluated by the compiler THROUGH the module-only +// wiring (std::floor on a float is PFLibm::floor once pf_module.h has been +// read, std::fmod is fmodAny and whichever path it picks), so a wrapper bound +// to the wrong function, or a wrong test in the fmod dispatch, does not build. +#include "pf_module.h" + +#define SHAPE extern "C" __attribute__((noinline)) + +// ── values, through the wiring ────────────────────────────────────── +static_assert(std::floor(2.5f) == 2.0f && std::floor(-2.5f) == -3.0f, "floor"); +static_assert(std::ceil(2.5f) == 3.0f && std::ceil(-2.5f) == -2.0f, "ceil"); +static_assert(std::trunc(2.7f) == 2.0f && std::trunc(-2.7f) == -2.0f, "trunc"); +static_assert(std::round(2.5f) == 3.0f && std::round(-2.5f) == -3.0f, "round"); +static_assert(std::round(0.49999997f) == 0.0f && std::round(2.4999998f) == 2.0f, "round below a half"); +static_assert(std::fmin(1.0f, 2.0f) == 1.0f && std::fmin(2.0f, 1.0f) == 1.0f, "fmin"); +static_assert(std::fmax(1.0f, 2.0f) == 2.0f && std::fmax(2.0f, 1.0f) == 2.0f, "fmax"); +static_assert(std::fmod(7.5f, 2.0f) == 1.5f && std::fmod(-7.5f, 2.0f) == -1.5f, "fmod, reciprocal path"); +static_assert(std::fmod(7.5f, -2.0f) == 1.5f && std::fmod(10.0f, 3.0f) == 1.0f, "fmod, reciprocal path"); +static_assert(std::fmod(7.25f, 1.0f) == 0.25f && std::fmod(-7.25f, -1.0f) == -0.25f, "fmod by one"); +static_assert(std::fmod(0.25f, 2.0f) == 0.25f && std::fmod(-0.25f, 2.0f) == -0.25f, "fmod under the divisor"); +// (Nothing here goes past the inline range: there the answer is the builtin's, +// and GCC 8.4 does not fold a constant fmodf at all.) +// signs of zero: the cases the inline code has to get right by hand +static_assert(__builtin_signbit(std::floor(-0.0f)) && !__builtin_signbit(std::floor(0.3f)), "floor zero"); +static_assert(__builtin_signbit(std::ceil(-0.3f)) && !__builtin_signbit(std::ceil(0.0f)), "ceil zero"); +static_assert(__builtin_signbit(std::trunc(-0.3f)) && !__builtin_signbit(std::trunc(0.3f)), "trunc zero"); +static_assert(__builtin_signbit(std::round(-0.3f)) && !__builtin_signbit(std::round(0.3f)), "round zero"); +static_assert(__builtin_signbit(std::fmod(-6.0f, 3.0f)) && !__builtin_signbit(std::fmod(6.0f, 3.0f)), "fmod zero"); +static_assert(__builtin_signbit(std::fmod(-2.0f, 1.0f)) && __builtin_signbit(std::fmod(-0.0f, 1.0f)), "fmod-by-one zero"); + +// ── the C names ───────────────────────────────────────────────────── +SHAPE float pf_shape_floorf(float x) { return floorf(x); } +SHAPE float pf_shape_ceilf(float x) { return ceilf(x); } +SHAPE float pf_shape_truncf(float x) { return truncf(x); } +SHAPE float pf_shape_roundf(float x) { return roundf(x); } +SHAPE float pf_shape_fminf(float x, float y) { return fminf(x, y); } +SHAPE float pf_shape_fmaxf(float x, float y) { return fmaxf(x, y); } +SHAPE float pf_shape_fmodf(float x, float y) { return fmodf(x, y); } +SHAPE float pf_shape_fmodf_one(float x) { return fmodf(x, 1.0f); } +SHAPE float pf_shape_fmodf_const(float x) { return fmodf(x, 6.2831853f); } +SHAPE float pf_shape_fmodf_negconst(float x) { return fmodf(x, -360.0f); } + +// ── the spellings that go through libstdc++'s float overloads ──────── +SHAPE float pf_shape_floor(float x) { return floor(x); } +SHAPE float pf_shape_std_floor(float x) { return std::floor(x); } +SHAPE float pf_shape_ceil(float x) { return ceil(x); } +SHAPE float pf_shape_trunc(float x) { return trunc(x); } +SHAPE float pf_shape_round(float x) { return round(x); } +SHAPE float pf_shape_fmin(float x, float y) { return fmin(x, y); } +SHAPE float pf_shape_fmax(float x, float y) { return fmax(x, y); } +SHAPE float pf_shape_fmod(float x, float y) { return fmod(x, y); } +SHAPE float pf_shape_std_fmod(float x, float y) { return std::fmod(x, y); } +SHAPE float pf_shape_std_fmod_const(float x) { return std::fmod(x, 6.2831853f); } + +// ── what stays a call ─────────────────────────────────────────────── +SHAPE float pf_control_builtin(float x) { return __builtin_floorf(x); } +SHAPE float pf_control_pointer(float x) { + float (*volatile through)(float) = floorf; // not a call to floorf: the firmware's symbol + return through(x); +} +SHAPE long pf_control_lroundf(float x) { return lroundf(x); } + +namespace LibmShapes { + +const char* NAME = "Libm Shapes"; +const char* const KNOB_LABELS[4] = {"-", "-", "-", "-"}; + +volatile float in = 1.25f; +float out; + +void setup() {} + +void update(float dt, const InputFrame& input) { + (void)dt; + (void)input; +} + +void draw() { + const float a = in, b = in; + out = pf_shape_floorf(a) + pf_shape_ceilf(a) + pf_shape_truncf(a) + pf_shape_roundf(a) + + pf_shape_fminf(a, b) + pf_shape_fmaxf(a, b) + pf_shape_fmodf(a, b) + + pf_shape_fmodf_one(a) + pf_shape_fmodf_const(a) + pf_shape_fmodf_negconst(a) + + pf_shape_floor(a) + pf_shape_std_floor(a) + pf_shape_ceil(a) + pf_shape_trunc(a) + + pf_shape_round(a) + pf_shape_fmin(a, b) + pf_shape_fmax(a, b) + pf_shape_fmod(a, b) + + pf_shape_std_fmod(a, b) + pf_shape_std_fmod_const(a) + pf_control_builtin(a) + + pf_control_pointer(a) + (float)pf_control_lroundf(a); + PFCanvas::clear(); + PFCanvas::present(); +} + +} // namespace LibmShapes + +PF_REGISTER_PATTERN(LibmShapes) diff --git a/firmware/toolchain/tests/modules/_math_probe/pattern.cpp b/firmware/toolchain/tests/modules/_math_probe/pattern.cpp new file mode 100644 index 00000000..27a1719e --- /dev/null +++ b/firmware/toolchain/tests/modules/_math_probe/pattern.cpp @@ -0,0 +1,372 @@ +// Bench probe for the module SDK's inline libm (abi/pf_libm.h), not a showable +// pattern. check_libm.py proves on a PC that floorf, ceilf, truncf, roundf, +// fminf, fmaxf and fmodf compute what libm computes - given arithmetic that +// behaves as IEEE 754 says. Whether the panel's does is the part a PC cannot +// see: that MSUB.S multiplies and subtracts with ONE rounding (fmod's +// remainder is wrong in half of all cases if it does not), that TRUNC.S and +// FLOAT.S convert exactly, that the compares treat zeros and NaN properly, +// and that __divsf3 rounds to nearest (the reciprocal the compiler folds for +// `fmodf(x, TWO_PI)` is the one the board would compute). This module runs +// the inline code and the firmware's own libm side by side, on the board, +// and compares bits. +// +// python firmware/toolchain/build_module.py --out firmware/toolchain/tests/modules/_math_probe +// curl -X PUT --data-binary @/_math_probe.pfm -H "X-PF-Name: _math_probe.pfm" http:///api/patterns +// curl "http:///api/patterns/select?index=" # N: its index in GET /api/patterns +// curl http:///api/status # "active": "math ok 9/9 1532k" +// +// setup() spends 1.3 s on it, by the clock - a setup past 5 s trips the +// loader's watchdog, and a call into libm is 0.2-0.8 us, so that is on the +// order of two million comparisons, not the twenty billion a PC does - and +// writes the verdict into the pattern's NAME, which the registry copies once +// setup() returns: +// +// math ok 9/9 1532k nine checks, 1,532,000 comparisons, all equal +// math FAIL fmodf 1234 the first check that differed and how often +// math FAIL fmodf 1234 +2 ... and two more checks differed as well +// +// It then keeps going, a few thousand comparisons a frame with fresh inputs: +// the panel is green while everything has matched and red from the first +// mismatch on, the bar across the top fills at eight million comparisons, +// and the serial log gets a line every few seconds with the totals and the +// first mismatches as bits. +// +// The nine: floorf ceilf truncf roundf fminf fmaxf, "fmodf" (any divisor - +// the division path - and the same pairs through the reciprocal path with +// the reciprocal divided on the board), "fmodf const" (divisors written as +// literals, so the compiler folds the reciprocal: 1, 2*pi, 360, 0.1 ...), and +// "div" (__divsf3 rounds to nearest, and gives the folded reciprocals). +#include "pf_module.h" + +#include + +// The firmware's libm, under names the SDK has not put inline code behind. +extern "C" { +float host_floorf(float) __asm__("floorf"); +float host_ceilf(float) __asm__("ceilf"); +float host_truncf(float) __asm__("truncf"); +float host_roundf(float) __asm__("roundf"); +float host_fminf(float, float) __asm__("fminf"); +float host_fmaxf(float, float) __asm__("fmaxf"); +float host_fmodf(float, float) __asm__("fmodf"); +} + +namespace MathProbe { + +char verdict[40] = "math probe (not run)"; +const char* NAME = verdict; +const char* const KNOB_LABELS[4] = {"-", "-", "-", "-"}; + +enum Check { FLOOR, CEIL, TRUNC, ROUND, FMIN, FMAX, FMOD, FMOD_CONST, DIV, CHECKS }; +const char* const CHECK_NAMES[CHECKS] = { + "floorf", "ceilf", "truncf", "roundf", "fminf", "fmaxf", "fmodf", "fmodf const", "div", +}; + +uint32_t done[CHECKS]; +uint32_t wrong[CHECKS]; +int logged = 0; +uint32_t lastLogMs = 0; + +uint32_t bitsOf(float f) { + uint32_t u; + memcpy(&u, &f, sizeof u); + return u; +} + +float fromBits(uint32_t u) { + float f; + memcpy(&f, &u, sizeof f); + return f; +} + +// xorshift32, fixed seed: every board runs the same inputs in setup(). +uint32_t randomState = 0x9E3779B9u; +uint32_t randomBits() { + uint32_t x = randomState; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + return randomState = x; +} + +void same(Check check, float x, float y, float got, float want) { + ++done[check]; + if (bitsOf(got) == bitsOf(want)) return; + ++wrong[check]; + if (logged < 12) { + ++logged; + Serial.printf("[MATH] %s(%08x, %08x) inline %08x, libm %08x\n", CHECK_NAMES[check], + (unsigned)bitsOf(x), (unsigned)bitsOf(y), (unsigned)bitsOf(got), + (unsigned)bitsOf(want)); + } +} + +float withExponent(int field) { + if (field < 0) field = 0; + if (field > 254) field = 254; + return fromBits((randomBits() & 0x807fffffu) | ((uint32_t)field << 23)); +} + +int exponentOf(float f) { + return (int)((bitsOf(f) >> 23) & 0xffu); +} + +// d units in the last place away, by magnitude. +float stepped(float x, int d) { + const uint32_t u = bitsOf(x); + int32_t magnitude = (int32_t)(u & 0x7fffffffu) + d; + if (magnitude < 0) magnitude = 0; + if (magnitude > 0x7f7fffff) magnitude = 0x7f7fffff; + return fromBits((u & 0x80000000u) | (uint32_t)magnitude); +} + +const uint32_t EDGES[] = { + 0x00000000u, 0x80000000u, 0x00000001u, 0x80000001u, 0x007fffffu, 0x00800000u, + 0x3effffffu, 0x3f000000u, 0xbf000000u, 0x3f000001u, 0x3f7fffffu, 0xbf7fffffu, + 0x3f800000u, 0xbf800000u, 0x3f800001u, 0x3fc00000u, 0xbfc00000u, 0x40200000u, + 0xc0200000u, 0x4a800000u, 0x4affffffu, 0xcaffffffu, 0x4b000000u, 0xcb000000u, + 0x4b000001u, 0x4b800000u, 0x4f000000u, 0xcf000000u, 0x7f7fffffu, 0xff7fffffu, + 0x7f800000u, 0xff800000u, 0x7fc00000u, 0xffc00000u, 0x7f800001u, 0x7fffffffu, +}; +const int EDGE_COUNT = (int)(sizeof EDGES / sizeof EDGES[0]); + +// What a pattern feeds these functions, and what breaks an implementation. +float anyInput() { + const uint32_t r = randomBits(); + switch (r & 7u) { + case 0: // any bit pattern: huge, tiny, NaN, infinity + return fromBits(randomBits()); + case 1: // a whole number and the floats beside it + return stepped((float)((int)(randomBits() >> 9) - (1 << 22)), (int)((r >> 3) % 5u) - 2); + case 2: // n + 0.5 and the floats beside it: where round() decides + return stepped((float)((int)(randomBits() >> 10) - (1 << 21)) + 0.5f, + (int)((r >> 3) % 5u) - 2); + case 3: // around 2^23, where the inline range ends + return withExponent(148 + (int)((r >> 3) % 5u)); + case 4: // under 4: fractions, and the zero results whose sign matters + return withExponent(110 + (int)((r >> 3) % 19u)); + default: // 2^-23 .. 2^24, all of pixel arithmetic + return withExponent(104 + (int)((r >> 3) % 48u)); + } +} + +void unary(float x) { + same(FLOOR, x, 0.0f, floorf(x), host_floorf(x)); + same(CEIL, x, 0.0f, ceilf(x), host_ceilf(x)); + same(TRUNC, x, 0.0f, truncf(x), host_truncf(x)); + same(ROUND, x, 0.0f, roundf(x), host_roundf(x)); +} + +void minMax(float x, float y) { + same(FMIN, x, y, fminf(x, y), host_fminf(x, y)); + same(FMAX, x, y, fmaxf(x, y), host_fmaxf(x, y)); +} + +void minMaxInput() { + const float x = anyInput(); + const uint32_t r = randomBits(); + switch (r & 7u) { + case 0: minMax(x, x); break; + case 1: minMax(x, -x); break; + case 2: minMax(x, stepped(x, 1)); break; + case 3: minMax(stepped(x, 1), x); break; + case 4: minMax(x, fromBits(EDGES[(r >> 3) % (uint32_t)EDGE_COUNT])); break; + case 5: minMax(fromBits(EDGES[(r >> 3) % (uint32_t)EDGE_COUNT]), x); break; + default: minMax(x, anyInput()); break; + } +} + +// A multiplier for "x is k times y": anywhere in the fast path, small, or on +// the boundaries the proof turns on. +uint32_t multiplier() { + static const uint32_t BOUNDARY[] = { + 1u, 2u, 3u, 255u, 65536u, (1u << 22) - 2, (1u << 22) - 1, (1u << 22), + (1u << 22) + 1, (1u << 23) - 1, (1u << 23), (1u << 24) - 1, + }; + const uint32_t r = randomBits(); + switch (r & 3u) { + case 0: return 1u + (randomBits() >> 10); // up to 2^22 + case 1: return 1u + (randomBits() >> (10 + (r >> 2) % 22u)); // small + case 2: return 1u + (randomBits() >> 8); // up to 2^24, past the limit + default: return BOUNDARY[(r >> 2) % (uint32_t)(sizeof BOUNDARY / sizeof BOUNDARY[0])]; + } +} + +void mod(float x, float y) { + const float want = host_fmodf(x, y); + same(FMOD, x, y, fmodf(x, y), want); // y is not a constant here: the division path + same(FMOD, x, y, PFLibm::fmodRecip(x, y, 1.0f / fabsf(y)), want); +} + +void modInput() { + const uint32_t r = randomBits(); + if ((r & 3u) == 0) { // any divisor at all, quotients from under 1 to 2^25 + const float y = withExponent((int)((r >> 2) % 255u)); + mod(withExponent(exponentOf(y) - 1 + (int)((r >> 10) % 27u)), y); + return; + } + // x = k*y and its neighbours, for a y a pattern might hold. + const float y = withExponent(100 + (int)((r >> 2) % 40u)); + mod(stepped((float)multiplier() * y, (int)((r >> 10) % 9u) - 4), y); +} + +// A divisor written as a literal: the shadow sees a constant and multiplies by +// a reciprocal the compiler folded (and, for 1.0f, takes the fraction). +#define PROBE_LITERAL(C) \ + do { \ + const uint32_t r = randomBits(); \ + float x = stepped((float)multiplier() * (C), (int)((r >> 2) % 9u) - 4); \ + if ((r & 3u) == 0) x = withExponent(exponentOf(C) - 2 + (int)((r >> 6) % 27u)); \ + if ((r & 0x100u) != 0) x = -x; \ + same(FMOD_CONST, x, (C), fmodf(x, (C)), host_fmodf(x, (C))); \ + same(FMOD_CONST, x, -(C), fmodf(x, -(C)), host_fmodf(x, -(C))); \ + } while (0) + +void modLiterals() { + PROBE_LITERAL(1.0f); + PROBE_LITERAL(6.2831853f); + PROBE_LITERAL(3.14159265f); + PROBE_LITERAL(360.0f); + PROBE_LITERAL(0.1f); + PROBE_LITERAL(2.0f); + PROBE_LITERAL(255.0f); + PROBE_LITERAL(0.001f); +} + +// The folded reciprocal is the one this board's divider gives. +#define PROBE_RECIPROCAL(C) \ + do { \ + volatile float one = 1.0f, divisor = (C); \ + same(DIV, 1.0f, (C), one / divisor, 1.0f / (C)); \ + } while (0) + +void reciprocals() { + PROBE_RECIPROCAL(6.2831853f); + PROBE_RECIPROCAL(3.14159265f); + PROBE_RECIPROCAL(360.0f); + PROBE_RECIPROCAL(0.1f); + PROBE_RECIPROCAL(255.0f); + PROBE_RECIPROCAL(0.001f); +} + +// q = a / b is the nearest float to the quotient exactly when neither float +// beside it leaves a smaller remainder a - q*b. The remainders are taken +// fused; rounding them cannot reorder them. +void division() { + volatile float a = withExponent(100 + (int)(randomBits() % 50u)); + volatile float b = withExponent(100 + (int)(randomBits() % 50u)); + const float x = a, y = b; + const float q = a / b; + const float here = fabsf(PFLibm::fnma(q, y, x)); + const float above = fabsf(PFLibm::fnma(stepped(q, 1), y, x)); + const float below = fabsf(PFLibm::fnma(stepped(q, -1), y, x)); + ++done[DIV]; + if (here <= above && here <= below) return; + ++wrong[DIV]; + if (logged < 12) { + ++logged; + Serial.printf("[MATH] div %08x / %08x gave %08x, not the nearest float\n", + (unsigned)bitsOf(x), (unsigned)bitsOf(y), (unsigned)bitsOf(q)); + } +} + +// Run `body` in batches until `ms` have passed. +template +void spend(uint32_t ms, Body body) { + const uint32_t start = millis(); + do { + for (int i = 0; i < 32; ++i) body(); + } while (millis() - start < ms); +} + +void run(uint32_t unaryMs, uint32_t minMaxMs, uint32_t modMs, uint32_t literalMs, + uint32_t divisionMs) { + spend(unaryMs, [] { unary(anyInput()); }); + spend(minMaxMs, minMaxInput); + spend(modMs, modInput); + spend(literalMs, modLiterals); + spend(divisionMs, division); +} + +uint32_t total(const uint32_t* counts) { + uint32_t sum = 0; + for (int c = 0; c < CHECKS; ++c) sum += counts[c]; + return sum; +} + +void writeVerdict() { + int failed = 0, first = -1; + for (int c = 0; c < CHECKS; ++c) { + if (!wrong[c]) continue; + if (first < 0) first = c; + ++failed; + } + if (first < 0) { + snprintf(verdict, sizeof verdict, "math ok %d/%d %uk", (int)CHECKS, (int)CHECKS, + (unsigned)(total(done) / 1000u)); + } else if (failed == 1) { + snprintf(verdict, sizeof verdict, "math FAIL %s %u", CHECK_NAMES[first], + (unsigned)wrong[first]); + } else { + snprintf(verdict, sizeof verdict, "math FAIL %s %u +%d", CHECK_NAMES[first], + (unsigned)wrong[first], failed - 1); + } +} + +void logTotals() { + Serial.printf("[MATH] %s - %u comparisons, %u differ\n", verdict, (unsigned)total(done), + (unsigned)total(wrong)); + for (int c = 0; c < CHECKS; ++c) { + Serial.printf("[MATH] %-11s %8u differ %u\n", CHECK_NAMES[c], (unsigned)done[c], + (unsigned)wrong[c]); + } +} + +void setup() { + for (int i = 0; i < EDGE_COUNT; ++i) { + const float x = fromBits(EDGES[i]); + unary(x); + for (int j = 0; j < EDGE_COUNT; ++j) { + const float y = fromBits(EDGES[j]); + minMax(x, y); + mod(x, y); + } + } + reciprocals(); + run(450, 200, 350, 250, 80); + writeVerdict(); + logTotals(); + lastLogMs = millis(); +} + +void update(float dt, const InputFrame& input) { + (void)dt; + (void)input; +} + +void draw() { + // The inputs carry on from where setup() left the generator. NAME is not + // rewritten here: the registry took its copy when setup() returned, and a + // name that changed afterwards would only be seen by half the readers. + run(2, 1, 2, 2, 1); + const bool ok = total(wrong) == 0; + const uint32_t comparisons = total(done); + const int bar = comparisons >= (8u << 20) ? PANEL_RES_W : (int)(comparisons >> 16); + for (int y = 0; y < PANEL_RES_H; ++y) { + for (int x = 0; x < PANEL_RES_W; ++x) { + const bool lit = y < 4 && x < bar; + const uint8_t level = lit ? 200 : 40; + PFCanvas::setPixel(x, y, ok ? 0 : level, ok ? level : 0, 0); + } + } + PFCanvas::present(); + if (millis() - lastLogMs >= 5000) { + lastLogMs = millis(); + Serial.printf("[MATH] %s so far: %u comparisons, %u differ\n", ok ? "ok" : "FAIL", + (unsigned)comparisons, (unsigned)total(wrong)); + } +} + +} // namespace MathProbe + +PF_REGISTER_PATTERN(MathProbe) diff --git a/web/public/guide/console-demo/index.html b/web/public/guide/console-demo/index.html index 37c903d0..eb45384c 100644 --- a/web/public/guide/console-demo/index.html +++ b/web/public/guide/console-demo/index.html @@ -2,7 +2,7 @@ - + Patternflow diff --git a/web/public/guide/console-demo/knobs.html b/web/public/guide/console-demo/knobs.html index bfc3ed17..adfc0530 100644 --- a/web/public/guide/console-demo/knobs.html +++ b/web/public/guide/console-demo/knobs.html @@ -1,7 +1,7 @@ - + Patternflow - Knobs