diff --git a/.github/ISSUE_TEMPLATE/guide_stuck.yml b/.github/ISSUE_TEMPLATE/guide_stuck.yml new file mode 100644 index 00000000..4d704b37 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/guide_stuck.yml @@ -0,0 +1,53 @@ +name: Stuck in the guide +description: A step of the guide at patternflow.work/guide didn't get you through. +title: "[guide] " +labels: ["area:docs", "type:bug"] +body: + - type: markdown + attributes: + value: | + Thanks — a report like this shows exactly where the guide needs to be better. If you came from a "Stuck here?" link, the step is already filled in below. + + Need an answer right now rather than a better guide? The [hardware-help channel on Discord](https://discord.com/channels/1497757947827327067/1499907910707187833) is quicker. Writing in Korean is fine too — 한국어로 써도 돼요. + - type: input + id: where + attributes: + label: Where in the guide + description: The chapter and step. Filled in for you if you came from the guide. + placeholder: "01 Flash, step 3 — Hold BOOT, tap RST, let go." + validations: + required: true + - type: textarea + id: what-happened + attributes: + label: What happened? + description: What you did, and what you saw instead of what the guide said you'd see. + placeholder: "After flashing, the Wi-Fi box never appeared. Pressing RST didn't bring it up either." + validations: + required: true + - type: textarea + id: tried + attributes: + label: What did you try? + description: Anything you tried to get past it, and whether it helped. + - type: dropdown + id: board + attributes: + label: Board + description: The version is printed on the board's silkscreen. + options: + - v3.9 + - v3.0 + - v2.x + - not sure + - type: input + id: browser + attributes: + label: Browser and computer + description: Filled in for you if you came from the guide. Change it if you did the step on another device. + placeholder: "Chrome 140 on Windows" + - type: textarea + id: photos + attributes: + label: Photos or a screen recording + description: A photo of the panel, or of the screen you were stuck on, often says more than a paragraph. Drag them in here. diff --git a/AUDIO_GUIDE.md b/AUDIO_GUIDE.md index f6bcf373..f0448d77 100644 --- a/AUDIO_GUIDE.md +++ b/AUDIO_GUIDE.md @@ -48,7 +48,7 @@ the active tab) → enter your panel's address (`patternflow.local` or its IP) → the knobs move with the music. (Make sure **Audio-React (AUD)** is turned on at the top of the console's **Audio** page or via the panel's NETWORK screen.) -**Then open the editor** (*Editor ↗* in the popup) — this is where it gets +**Then open the editor** (*Mapping editor ↗* in the popup) — this is where it gets good. Each of the four knobs is a **box drawn on the live spectrum**: the box's width is the frequencies it listens to, its height the loudness window it maps. Drag a box over the bass and knob 1 becomes a bass knob. Inside @@ -67,7 +67,7 @@ Boxes map to knobs 1:1 and that's fixed on purpose — box 2 *is* knob 2. A small PDM microphone soldered to the DevKit lets the panel react to the room itself — no browser, no phone, nothing else running. This is an optional add-on: the firmware ships with the mic **off** and costs nothing -until you build and enable it. +until you solder one on and switch it on. ### What to buy @@ -125,7 +125,7 @@ Stick the mic wherever sound reaches it. Done. ### Turn it on -Console → **Audio** page (`/audio-in`) → flip **Microphone** or **Audio-React (AUD)** on. That's the +Console → **Audio** page (`/audio-in`) → flip **Microphone** on. (**Audio-React (AUD)** beside it is the other input, the extension and the phone app.) That's the whole switch: on means listening and driving the knobs, off releases the hardware completely. The **gain** slider (1–16, default 8) is there if your room runs quiet — PDM mics on this chip are famously low-amplitude, and gain @@ -175,8 +175,8 @@ computer's address so it reconnects itself after a reboot — is This is the missing half of [`docs/director-midi.md`](docs/director-midi.md): the Director's `.mid` export writes CC 20–23, so drop the clip on a MIDI track, set the track's output to the panel's port, and the show plays on the -panel from Live's transport. The `MIDI` row on the panel's NETWORK screen -switches it off without reflashing; `/api/status` reports the session, +panel from Live's transport. The switch on the console's **MIDI** page turns it +off without reflashing; `/api/status` reports the session, sensitivity and message counts under `midi`. ## OSC — Ableton today, anything tomorrow diff --git a/BUILD_GUIDE.md b/BUILD_GUIDE.md index 39d6f5c9..fedb1b51 100644 --- a/BUILD_GUIDE.md +++ b/BUILD_GUIDE.md @@ -244,13 +244,16 @@ The ESP32-S3 module is flashed **separately, outside the PCB**. Already seated i No installation required — desktop **Chrome or Edge** only (Web Serial; Firefox/Safari won't work). -> 🔌 **Use the LEFT USB-C port** — the one on your left when the two ports face you. On the ESP32-S3 DevKit that's the board's **native USB** port (labeled `USB`); the browser flasher (Web Serial + Improv) talks to it directly. The right-hand port goes through a separate USB-to-UART bridge chip and is the one Arduino IDE uses (§8.2) — the browser flasher won't see the board on that one. +> 🎬 **See it before you do it.** [patternflow.work/guide](https://patternflow.work/guide) walks through this section — the port, BOOT and RST, the Wi-Fi step, the Basics pack — on a Patternflow you can turn, and every step has a link for telling us where you got stuck. + +> 🔌 **Use the LEFT USB-C port** — the one on your left when the two ports face you. On the ESP32-S3 DevKit that's the board's **native USB** port (labeled `USB`); the browser flasher (Web Serial + Improv) talks to it directly. The right-hand port goes through a separate USB-to-UART bridge chip and is the one Arduino IDE uses (§8.2) — the flasher may still write the firmware through it, but the Wi-Fi step never appears there, because the firmware only listens for it on the left port. 1. Visit **[patternflow.work](https://patternflow.work)** on a desktop browser. 2. Connect the ESP32-S3 to your computer with a USB-C **data cable**, using the **left port** (see above). -3. Scroll to the **Patterns** section, click **"Flash Patternflow"**, pick the serial port, and follow the on-screen steps. Wi-Fi can be provisioned right there too (Improv-Serial). -4. Disconnect, seat the module back into the board sockets (orientation per silkscreen), and connect power. -5. **Load the patterns.** The image ships with **Origin only** — the rest live on the device's filesystem instead of inside the firmware, which is what freed the memory for everything else. Open **[the decks shelf](https://community.patternflow.work/community/decks)** and press **Install to my board** on the **Basics** pack: 33 patterns, one click, no account. Your browser fetches the pack and hands it to the board over your Wi-Fi, so the board is never talking to the internet itself. +3. Open the **Pattern** tab, find **Got the hardware?**, click **"Flash Patternflow"**, pick the serial port, and follow the on-screen steps. A new install erases the module first; a module already running Patternflow is updated in place and keeps its patterns and Wi-Fi. +4. **Wi-Fi.** When the install finishes, press **Next** and the flasher asks for your network (Improv-Serial). Type the name exactly — there is no list to pick from, and it is case-sensitive — and use a **2.4 GHz** network; the ESP32-S3 cannot see 5 GHz. If the install ends without asking, press **RST** on the module once, click **Flash Patternflow** again, pick the port, and choose **Connect to Wi-Fi**. Some modules do not restart into Patternflow on their own after flashing; the button does it. +5. Disconnect, seat the module back into the board sockets (orientation per silkscreen), and connect power. +6. **Load the patterns.** The image ships with **Origin only** — the rest live on the device's filesystem instead of inside the firmware, which is what freed the memory for everything else. Open **[the decks shelf](https://community.patternflow.work/community/decks)** and press **Install to my board** on the **Basics** pack: 33 patterns, one click, no account. Your browser fetches the pack and hands it to the board over your Wi-Fi, so the board is never talking to the internet itself. On a freshly flashed board the device's page first says **Storage needs formatting**: press **Format storage**, confirm, and the pack installs by itself as soon as the format is done. On Android, `patternflow.local` does not resolve — type the board's IP address (hold **K2**) into the **Device address** field on the Basics card instead. > 🎛️ **One pattern after flashing is correct, not a failed install.** It used to be 34 baked into the image. They moved out so that patterns can be added and removed without reflashing, which is also how anything you make yourself reaches the panel. @@ -262,11 +265,13 @@ No installation required — desktop **Chrome or Edge** only (Web Serial; Firefo > > The picker should now offer a line like `USB JTAG/serial debug unit (COM4) – Paired`. The number depends on which USB port you used. > +> In download mode the firmware cannot answer the flasher, so it treats the module as new and **erases it** — installed patterns and saved Wi-Fi included. Press **RST** alone to bring a module back to normal first if you only meant to update it. +> > Still nothing? It is almost always the cable — a charge-only USB-C one enumerates nothing at all. **There is no driver to install on this port**: the ESP32-S3 handles USB itself, so the CP2102 / CH34x links on the flasher's troubleshooting screen do not apply here. -> 📶 **Changing Wi-Fi later.** The network you set during flashing is **saved on the device and reused on every boot** — it stays until you overwrite it. To move Patternflow to a different Wi-Fi, either **re-flash from the browser** (you'll set the new network during Improv provisioning), or in Arduino IDE do a **full erase** (Tools → *Erase All Flash Before Sketch Upload* → *Enabled*) and re-upload. A plain re-upload does **not** clear the stored credentials. +> 📶 **Changing Wi-Fi later.** The network you set during flashing is **saved on the device and reused on every boot**. The panel remembers up to five networks — home, studio, a venue — and tries the most recent first, so moving it does not mean reflashing. Add or forget networks on the device's **Wi-Fi** page (the console at `patternflow.local`, or the board's IP address). A plain Arduino IDE re-upload does **not** clear the stored networks; **Tools → *Erase All Flash Before Sketch Upload*** does. -> 📡 **No Wi-Fi where you are? The panel is one.** About fifteen seconds after it finds no known network, the panel raises its own hotspot: `patternflow-xxxx` (the name on its NETWORK screen - hold K2), password `patternflow`. Join it from a phone or a laptop and open `http://192.168.4.1/` - the whole console, including the Wi-Fi page, so you can add the network for wherever you are next and the panel joins it at once. The phone will say the network has no internet; that is true, and it stays connected. Mode (`auto`, `always`, `off`) and the password are on the console's Wi-Fi page. +> 📡 **No Wi-Fi where you are? The panel is one.** *(Firmware after v3.10.4; the Performance edition v0.4.0 has it already.)* About fifteen seconds after it finds no known network, the panel raises its own hotspot: `patternflow-xxxx` (the name on its NETWORK screen - hold K2), password `patternflow`. Join it from a phone or a laptop and open `http://192.168.4.1/` - the whole console, including the Wi-Fi page, so you can add the network for wherever you are next and the panel joins it at once. The phone will say the network has no internet; that is true, and it stays connected. Mode (`auto`, `always`, `off`) and the password are on the console's Wi-Fi page. *Photos from the v2 guide — the flashing flow is identical on v3.* @@ -290,7 +295,7 @@ OSC, network MIDI and audio-react ship in the **Audio** edition: open [patternfl 2. The panel lights up with the default pattern (Origin) within a second or two. 3. Turn all four knobs — each should visibly change the pattern. 4. Press-click each encoder once; long-press **K4** (~1s) to enter pattern select, rotate to browse, long-press again to exit. -5. Long-press **K1** for the global brightness mode; **K2** long-press shows the OSC info screen. +5. Long-press **K1** for the global brightness mode; **K2** long-press shows the NETWORK screen (Wi-Fi state and IP address); **K3** long-press puts each knob's number on the panel. 6. Power-cycle once and confirm it boots cleanly with no RESET press needed (see the GPIO0 note in Section 5 if it doesn't). 7. All good? **Close the back panel**: hook the right edge in first, then press along the snap-fit until it clicks shut (shown at **09:11** in the [assembly video](https://youtu.be/J9C9bZgkNKs)). Press the knobs onto the shafts last. diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f500374..eb34f42c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ All notable changes to Patternflow will be documented in this file, newest first ### Firmware +- **No more stray letters on the panel's own screens.** A portrait line holds ten characters, and Adafruit GFX wraps an eleventh onto the next line by itself: the KNOB MAP's "TURN = SHOW" put a lone "W" in front of "K3 = EXIT", the install screen's "web console" did the same, and the default host name "patternflow" lost its "w" on the hotspot and UPDATE screens. The labels are shorter now ("TURN=SHOW", "console"), and names that can be longer than a line are broken into lines of ten by `drawCenteredFit` — "pattern" / "flow-a1b2", "pattern" / "flow.local" — keeping every line where it was. +- **A deck sent from the community's dock keeps its order.** The console's one-click install from a link (`/patterns?src=`) took only `.pfm` and `.json` from a build's file list, so the `catalog.txt` every deck build carries was left behind and the deck landed in alphabetical order. It now takes exactly what a dropped zip does (`catalog.txt` and `.pfs` too) - one rule, `installable()`, for every way in. - **A firmware upload survives a Wi-Fi hitch.** The `/update` connection now waits up to two minutes for a stalled upload instead of five seconds, and the page gives up after five minutes with a message instead of waiting forever. Checked on a panel with a 12 s stall halfway through a flash. `PUT /update` takes a raw image, for `curl -T`. From Simone Majocchi ([#450](https://github.com/engmung/Patternflow/pull/450)). - **Two 64×64 modules chained make a 128×64 panel.** `PANEL_GEOMETRY` in `config.h` picks the stock 128×64, one 64×64, or two 64×64 daisy-chained (the `firmware64x2` PlatformIO env). The driver is told the module and the chain, and everything else sees the canvas; the stock build is unchanged. From Simone Majocchi ([#446](https://github.com/engmung/Patternflow/pull/446)). - **Performance v0.4.0 carries the clock and a Weather face**, and its show catalogue holds 100 sequences instead of 48. An MQTT subscriber following a fast sequence stream now drains the broker and applies the latest value per knob each frame instead of falling one message per frame behind (a jump of more than 16 clicks in one frame is capped), and a publisher no longer replays its own retained snapshot when it reconnects. From Simone Majocchi ([#445](https://github.com/engmung/Patternflow/pull/445), [#448](https://github.com/engmung/Patternflow/pull/448), [#449](https://github.com/engmung/Patternflow/pull/449)). @@ -20,6 +22,8 @@ All notable changes to Patternflow will be documented in this file, newest first ### Web +- **A guide you can play along with, at [/guide](https://patternflow.work/guide)** (work in progress, marked WIP). The first page is the first hour, 01 Flash, 02 Knobs, 03 Patterns, 04 Console, on the real v3.9 hardware in 3D, running a port of the firmware's input logic and screens, with the real flasher dialogs and a live copy of the device console. The second, [/guide/make](https://patternflow.work/guide/make), is 05 Community and 06 Pattern Lab: the community's real screens, and a board that plays your own Pattern Lab draft (read, never written) while the real Lab opens in a window beside it. English and Korean. Every step has a "Stuck here?" link to a GitHub issue that already says where (`guide_stuck.yml`). +- **The community's Performances note says .pfs**, which is what the Director saves, instead of "Save-JSON". - **A moderator can take a pattern or deck off the wall without deleting it.** Somebody else's public pattern or deck now offers moderators *Make private*, with an optional reason: the softer removal, for things like the same pattern posted a fifth time. Nothing about the work changes and its author keeps it — they can still open it, edit it, take it into the lab — it just stops being shown to anyone else. On a pattern the reason is posted underneath as the moderator's comment, where the author can answer it; either way the author is told in their alerts. While the take-down stands the author cannot make it public again (a take-down its subject can undo in one click is a request); *Restore to public* puts it back exactly as it was. A moderator still cannot publish what an author made private themselves. A deck slot left empty by a take-down reads "made private by a moderator", not "by its author". Moderators can now comment on private patterns and keep their alerts about them, so the thread under a take-down works both ways. Migration `0025` adds `hidden_at` to patterns and decks; `check:hidemod` drives it all through the real routes. - **One press of Publish is one post.** A double-click on *Publish to the wall*, or a mouse switch that bounces, could put the same pattern on the wall twice in the same second ([#455](https://github.com/engmung/Patternflow/issues/455)). The button's disabled state was React state, a render too late for the second click, and after a successful publish it came back enabled while the page changed. The publish, thread, reply, deck, header, performance and report forms now refuse a second press in the same tick (`useSubmitLatch`), and a published pattern keeps its button down until the page changes; a thread whose files failed to attach offers *Open the thread* instead of posting it again. Behind them the server answers an identical submission from the same account within a minute with the post it already made, looked up and inserted in one synchronous transaction so two requests arriving together cannot both get through. `check:publish` fires two identical publishes into the route at the same instant; a version that awaits between the lookup and the insert fails it. diff --git a/README.md b/README.md index 512b0114..c5012907 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ You don't need hardware to start. The **[Live Editor](https://patternflow.work/p Live Editor: a full Patternflow simulator in the browser, code beside the device

-**[Pattern Lab](https://patternflow.work/pattern-lab)** is the full studio, and where a pattern reaches the hardware. Generate variations in batches, shape color ramps, retune knob ranges, then send it to your device: it builds into a small `.pfm` module and installs over Wi-Fi, about ten seconds start to finish. You never plug in a cable, reflash the board, or open an IDE. The Capture panel takes the same pattern off the panel: a PNG at print size for a business card, or an MP4 loop for a post, rendered in your browser with nothing uploaded. +**[Pattern Lab](https://patternflow.work/pattern-lab)** is the full studio, and where a pattern reaches the hardware. Generate variations in batches (in the Lab with your own Gemini key, or through any AI chat), shape color ramps, retune knob ranges, then send it to your device: it builds into a small `.pfm` module and installs over Wi-Fi, about ten seconds start to finish. You never plug in a cable, reflash the board, or open an IDE. The Graphic Export panel takes the same pattern off the panel: a PNG at print size for a business card, or an MP4 loop for a post, rendered in your browser with nothing uploaded. When it looks right, publish it to the **[Community](https://community.patternflow.work/community)**. More than a hundred patterns are up already and the range keeps widening, from quiet waves to chaos-theory studies, every one written as code and every one playable under the same four knobs. Collect patterns into a deck and send it to your board in one click. Browsing needs no account, and publishing asks a username and password, no email. The **[Pattern Guide](PATTERN_GUIDE.md)** walks the whole loop. @@ -143,6 +143,8 @@ What a knob does to a running pattern is the pattern's own decision, so the same The device functions themselves are fixed. Encoder 1 is brightness. Encoder 4 opens the pattern list, where you turn to browse the names and long-press again to load one, choosing from whatever is installed at the time. Encoder 2 puts the board's IP address on the panel, and typing that into a browser opens the web console, which carries every feature the device has and works from a phone. +[patternflow.work/guide](https://patternflow.work/guide) has all of this on a Patternflow you can turn, press and hold, from flashing the ESP32 to the console. + ## On the device A new board boots into **Origin**, concentric sine waves sampled by an emergent grid, and long-pressing encoder 4 opens the list of whatever else is installed. Patterns live on the filesystem rather than inside the program. The firmware compiles in Origin alone, as the failsafe a board can always boot into, and everything else installs as **`.pfm` modules over Wi-Fi**, up to 128 of them, no reflash. Adding a pattern never costs a firmware update, and a firmware update never touches your patterns, your Wi-Fi, or your storage. diff --git a/docs/EDITIONS.md b/docs/EDITIONS.md index 06bd50f3..a4469d33 100644 --- a/docs/EDITIONS.md +++ b/docs/EDITIONS.md @@ -57,14 +57,15 @@ itself and any settings it needs different. **An edition** is a composition somebody published — a firmware with a name, a version of its own, and a card on [patternflow.work/editions](https://patternflow.work/editions) that installs it -in one click. Four exist: +in one click. Three are on the shelf: | | carries | whose | |---|---|---| | **Patternflow** | nothing — the device itself | the product | | **Audio** | OSC, MIDI, browser audio, the on-board microphone | SeungHun Lee | | **Performance** | sequences, MQTT, FlowLocal, the Director, weather, the clock | Simone Majocchi | -| **Clock** | the time, cut out of the running pattern | SeungHun Lee | + +The clock and USB MIDI also build as bundles of their own, with a try-out image each on the features page and no card (below). The word "addon" is retired. It suggested something optional or third-party, and none of these are: they are first-class capabilities that happen to live diff --git a/docs/LICENSE-SUMMARY.md b/docs/LICENSE-SUMMARY.md index 6a7d2a64..d6661299 100644 --- a/docs/LICENSE-SUMMARY.md +++ b/docs/LICENSE-SUMMARY.md @@ -52,7 +52,7 @@ These are different things and are governed by different documents. | Where | GitHub PR / issue | The community site, from the Pattern Lab | | What | Code, hardware files, docs, build-map entries | Patterns | | License | Inbound = outbound: MIT for code, CC BY-SA 4.0 for the rest | The author's choice, above | -| Governed by | [CONTRIBUTING.md](../CONTRIBUTING.md) | Terms of use *(not yet written)* | +| Governed by | [CONTRIBUTING.md](../CONTRIBUTING.md) | [Terms of use](https://patternflow.work/terms) | ## Trademark diff --git a/docs/mqtt-spec.md b/docs/mqtt-spec.md index 533efc43..97252a56 100644 --- a/docs/mqtt-spec.md +++ b/docs/mqtt-spec.md @@ -68,7 +68,7 @@ mqtt: Node-RED, driving knob 2 of an `absoluteReady` pattern from a slider: an `mqtt out` node on topic `patternflow/param/2` with the slider's `0`–`1000` value; put the panel on Broadcast in Subscriber role first. -Two panels following each other: point both at the same broker, same prefix on a show channel (`patternflow1`), one as Publisher and the other as Subscriber. +Two panels following each other: point both at the same broker, same prefix on Live (`patternflow5`), one as Publisher and the other as Subscriber. Not channels 1–4: they force every panel on them to Subscriber, so neither would lead. ## Version history diff --git a/docs/pfst-v2-spec.md b/docs/pfst-v2-spec.md index 71fad293..f1d74888 100644 --- a/docs/pfst-v2-spec.md +++ b/docs/pfst-v2-spec.md @@ -16,7 +16,7 @@ layout, which is why v1 tables still load unchanged. **Status:** shipped in Patternflow firmware v3.6.3 (`firmware/patternflow/features/show/core_show.h`) and in the site's encoder/decoder -(`web/src/lib/community/performance.ts`). v1 tables are byte-identical to +(`web/src/lib/pattern/pfst.ts`). v1 tables are byte-identical to what they always were. --- diff --git a/docs/rest-api.md b/docs/rest-api.md index f11dc7d8..a07557e1 100644 --- a/docs/rest-api.md +++ b/docs/rest-api.md @@ -358,7 +358,7 @@ toggles — from the console's `/audio-in` bar. | `GET /api/audio` | `audioRuntime` (the switch) and `audioClients` (WebSocket senders connected on :81). | | `POST /api/audio` | `on=0/1`. Persisted in NVS; answers with the new state. | -## Clock (Clock edition) +## Clock (Performance edition) Gated on `"clock"` in `caps`; the page is `/clock`. Settings persist in NVS under the feature's own namespace, and `/api/status` carries a `clock` block diff --git a/firmware/patternflow/console/patterns.html b/firmware/patternflow/console/patterns.html index 3fcfa98d..f3f4fc16 100644 --- a/firmware/patternflow/console/patterns.html +++ b/firmware/patternflow/console/patterns.html @@ -777,18 +777,21 @@

Installed

// on — writes "\" on Windows, and a pack made that way arrives with its // whole path stuck to the filename: the junk filter stops matching, the // duplicate check stops matching, and the queue shows "a\b\wave.pfm". +// What goes onto the device, by file name — one rule for every way in: a +// drop, a zip, a link. +// catalog.txt rides along: it is the pack's running order (deck order). +// .pfs is a Director show table — installed to /show alongside the pack. +// performance.json is that show's editable source (Director / site), not +// a module sidecar: the device has no use for it, so it stays behind. +function installable(n){ + if(/^performance\.json$/i.test(n)||/\.perf\.json$/i.test(n))return false; + return /\.(pfm|json|pfs)$/i.test(n)||/^catalog\.txt$/i.test(n) +} + function expandFiles(fileList){ var list=Array.prototype.slice.call(fileList||[]); - // catalog.txt rides along: it is the pack's running order (deck order). - // .pfs is a Director show table — installed to /show alongside the pack. - // performance.json is that show's editable source (Director / site), not - // a module sidecar: the device has no use for it, so it stays behind. - var keep=function(n){ - if(/^performance\.json$/i.test(n)||/\.perf\.json$/i.test(n))return false; - return /\.(pfm|json|pfs)$/i.test(n)||/^catalog\.txt$/i.test(n) - }; if(!list.some(function(f){return /\.zip$/i.test(f.name)})) - return Promise.resolve(list.filter(function(f){return keep(f.name)})); + return Promise.resolve(list.filter(function(f){return installable(f.name)})); say('unpacking zip…'); return loadFflate().then(function(){ @@ -796,12 +799,12 @@

Installed

var push=function(f){if(!seen[f.name]){seen[f.name]=1;out.push(f)}}; var chain=Promise.resolve(); list.forEach(function(f){ - if(!/\.zip$/i.test(f.name)){if(keep(f.name))push(f);return} + if(!/\.zip$/i.test(f.name)){if(installable(f.name))push(f);return} chain=chain.then(function(){return f.arrayBuffer()}).then(function(buf){ var unzipped=fflate.unzipSync(new Uint8Array(buf)); Object.keys(unzipped).forEach(function(name){ var base=name.split(/[\\/]/).pop(); - if(!base||base.charAt(0)==='.'||!keep(base))return; + if(!base||base.charAt(0)==='.'||!installable(base))return; total+=unzipped[name].length; if(total>ZIP_MAX_BYTES) throw new Error('zip holds more than '+(ZIP_MAX_BYTES>>20)+' MB of patterns'); @@ -884,8 +887,11 @@

Installed

fetch(src+sep+'list=1').then(function(r){ if(!r.ok)throw 0;return r.json(); }).then(function(d){ - var names=(d.files||[]).filter(function(n){return /\.(pfm|json)$/.test(n)}); - if(!names.length)throw 0; + // The same rule as a dropped zip. It used to be .pfm/.json only, which + // left a deck's catalog.txt behind: a deck sent from the community's + // dock arrived in alphabetical order instead of the order it was built in. + var names=(d.files||[]).filter(installable); + if(!names.some(function(n){return /\.pfm$/i.test(n)}))throw 0; holdBatch(true); items=names.map(function(n){return {f:null,name:n,st:'get',pct:0,tries:0}}); retryBtn.style.display='none'; diff --git a/firmware/patternflow/patternflow.ino b/firmware/patternflow/patternflow.ino index 12bb6c2c..8e2ea235 100644 --- a/firmware/patternflow/patternflow.ino +++ b/firmware/patternflow/patternflow.ino @@ -615,6 +615,35 @@ void drawCenteredText(const char* text, int y, uint16_t color, int textSize = 1) // One fillRect + one text draw per label — cheap enough not to slow the frame // (a per-glyph outline tripled the per-frame pixel writes and tore the // double-buffered panel). +// A line of 1x text is 6 px a character, so a portrait line (64 px) holds ten. +// An eleven-character string does not clip: Adafruit GFX wraps its last letter +// onto the next line by itself, over whatever is drawn there ("TURN = SHOW" +// left a stray "W" in front of "K3 = EXIT"; the default host name +// "patternflow" did the same on the hotspot and UPDATE screens). Text that can +// be longer than a line comes through here instead: it is broken into lines +// of at most ten, before a '-' or '.' when one is in reach, else before "flow" +// in the product's own name, else hard at ten. Returns the y below the last line. +int drawCenteredFit(const String& text, int y, uint16_t color, int lineH = 10) { + const unsigned maxChars = dma_display->width() / 6; + String rest = text; + while (rest.length() > maxChars) { + int cut = -1; + for (int i = maxChars; i >= 2; i--) { + if (rest[i] == '-' || rest[i] == '.') { cut = i; break; } + } + if (cut < 0) { + int f = rest.indexOf("flow"); + if (f >= 2 && f <= (int)maxChars) cut = f; + } + if (cut < 0) cut = maxChars; + drawCenteredText(rest.substring(0, cut).c_str(), y, color, 1); + y += lineH; + rest = rest.substring(cut); + } + drawCenteredText(rest.c_str(), y, color, 1); + return y + lineH; +} + void drawCenteredTextScrim(const char* text, int y, uint16_t color, int textSize = 1) { int16_t x1, y1; uint16_t w, h; @@ -787,14 +816,10 @@ void drawNetworkInfo() { bool wifiUp = PatternflowWifi::isConnected(); if (!wifiUp && PatternflowHotspot::up) { // No station link, but the panel is a network of its own: the name to - // join, split at the dash so it fits the portrait width. The password - // is the documented default unless the owner changed it on /wifi. + // join, broken to fit the portrait width ("pattern" / "flow-a1b2"). The + // password is the documented default unless the owner changed it on /wifi. drawCenteredText("HOTSPOT", 50, pfGreenC(), 1); - String name = PatternflowHotspot::name(); - int dash = name.indexOf('-'); - if (dash < 0) dash = name.length(); - drawCenteredText(name.substring(0, dash).c_str(), 62, pfWhiteC(), 1); - drawCenteredText(name.substring(dash).c_str(), 72, pfWhiteC(), 1); + drawCenteredFit(PatternflowHotspot::name(), 62, pfWhiteC()); } else { drawCenteredText(PatternflowWifi::statusText(), 50, wifiUp ? pfGreenC() : pfBlueC(), 1); String ip = PatternflowWifi::ipString(); @@ -875,7 +900,7 @@ void drawPausedScreen() { if (consolePaused) { drawCenteredText("PAUSED", 26, pfWhiteC(), 1); - drawCenteredText("web console", 42, pfDimC(), 1); + drawCenteredText("console", 42, pfDimC(), 1); drawCenteredText("is open", 52, pfDimC(), 1); dma_display->drawFastHLine(4, h - 28, w - 8, pfRuleC()); drawCenteredText("RESUMES", h - 23, pfDimC(), 1); @@ -944,17 +969,19 @@ void drawUpdateScreen(int uploadPct) { } if (wifiUp) { drawCenteredText("DROP .BIN:", 36, pfDimC(), 1); - drawCenteredText(PF_OTA_HOSTNAME, 48, pfWhiteC(), 1); - drawCenteredText(".local", 58, pfWhiteC(), 1); - drawCenteredText("/update", 68, pfWhiteC(), 1); + // "pattern" / "flow.local" / "/update" for the default name; a longer + // one takes more lines and the address below moves down with it. + int y = drawCenteredFit(String(PF_OTA_HOSTNAME) + ".local", 48, pfWhiteC()); + drawCenteredText("/update", y, pfWhiteC(), 1); + y += 14; // Raw IP as the mDNS fallback, split like the NETWORK screen. String ip = PatternflowWifi::ipString(); if (ip.length() <= 10) { - drawCenteredText(ip.c_str(), 82, pfGrayC(), 1); + drawCenteredText(ip.c_str(), y, pfGrayC(), 1); } else { int cut = ip.indexOf('.', ip.indexOf('.') + 1) + 1; - drawCenteredText(ip.substring(0, cut).c_str(), 82, pfGrayC(), 1); - drawCenteredText(ip.substring(cut).c_str(), 92, pfGrayC(), 1); + drawCenteredText(ip.substring(0, cut).c_str(), y, pfGrayC(), 1); + drawCenteredText(ip.substring(cut).c_str(), y + 10, pfGrayC(), 1); } } else { drawCenteredText(PatternflowWifi::statusText(), 52, pfBlueC(), 1); @@ -992,7 +1019,7 @@ void drawKnobMap() { dma_display->setCursor(x + 6, y); dma_display->print(title); } - drawCenteredText("TURN = SHOW", (h / 2) + 2, pfDimC(), 1); + drawCenteredText("TURN=SHOW", (h / 2) + 2, pfDimC(), 1); drawCenteredText("K3 = EXIT", (h / 2) + 12, pfDimC(), 1); // Front-view corners: K1 top-right, K2 top-left, K3 bottom-right, diff --git a/firmware/patternflow/src/patterns_index.h b/firmware/patternflow/src/patterns_index.h index 8d6b40ce..a48a988a 100644 --- a/firmware/patternflow/src/patterns_index.h +++ b/firmware/patternflow/src/patterns_index.h @@ -804,18 +804,21 @@ function loadFflate(){ // on — writes "\" on Windows, and a pack made that way arrives with its // whole path stuck to the filename: the junk filter stops matching, the // duplicate check stops matching, and the queue shows "a\b\wave.pfm". +// What goes onto the device, by file name — one rule for every way in: a +// drop, a zip, a link. +// catalog.txt rides along: it is the pack's running order (deck order). +// .pfs is a Director show table — installed to /show alongside the pack. +// performance.json is that show's editable source (Director / site), not +// a module sidecar: the device has no use for it, so it stays behind. +function installable(n){ + if(/^performance\.json$/i.test(n)||/\.perf\.json$/i.test(n))return false; + return /\.(pfm|json|pfs)$/i.test(n)||/^catalog\.txt$/i.test(n) +} + function expandFiles(fileList){ var list=Array.prototype.slice.call(fileList||[]); - // catalog.txt rides along: it is the pack's running order (deck order). - // .pfs is a Director show table — installed to /show alongside the pack. - // performance.json is that show's editable source (Director / site), not - // a module sidecar: the device has no use for it, so it stays behind. - var keep=function(n){ - if(/^performance\.json$/i.test(n)||/\.perf\.json$/i.test(n))return false; - return /\.(pfm|json|pfs)$/i.test(n)||/^catalog\.txt$/i.test(n) - }; if(!list.some(function(f){return /\.zip$/i.test(f.name)})) - return Promise.resolve(list.filter(function(f){return keep(f.name)})); + return Promise.resolve(list.filter(function(f){return installable(f.name)})); say('unpacking zip…'); return loadFflate().then(function(){ @@ -823,12 +826,12 @@ function expandFiles(fileList){ var push=function(f){if(!seen[f.name]){seen[f.name]=1;out.push(f)}}; var chain=Promise.resolve(); list.forEach(function(f){ - if(!/\.zip$/i.test(f.name)){if(keep(f.name))push(f);return} + if(!/\.zip$/i.test(f.name)){if(installable(f.name))push(f);return} chain=chain.then(function(){return f.arrayBuffer()}).then(function(buf){ var unzipped=fflate.unzipSync(new Uint8Array(buf)); Object.keys(unzipped).forEach(function(name){ var base=name.split(/[\\/]/).pop(); - if(!base||base.charAt(0)==='.'||!keep(base))return; + if(!base||base.charAt(0)==='.'||!installable(base))return; total+=unzipped[name].length; if(total>ZIP_MAX_BYTES) throw new Error('zip holds more than '+(ZIP_MAX_BYTES>>20)+' MB of patterns'); @@ -911,8 +914,11 @@ function installFromUrl(src){ fetch(src+sep+'list=1').then(function(r){ if(!r.ok)throw 0;return r.json(); }).then(function(d){ - var names=(d.files||[]).filter(function(n){return /\.(pfm|json)$/.test(n)}); - if(!names.length)throw 0; + // The same rule as a dropped zip. It used to be .pfm/.json only, which + // left a deck's catalog.txt behind: a deck sent from the community's + // dock arrived in alphabetical order instead of the order it was built in. + var names=(d.files||[]).filter(installable); + if(!names.some(function(n){return /\.pfm$/i.test(n)}))throw 0; holdBatch(true); items=names.map(function(n){return {f:null,name:n,st:'get',pct:0,tries:0}}); retryBtn.style.display='none'; @@ -986,964 +992,972 @@ if(srcParam&&/^https?:\/\//.test(srcParam)){ load(); )HTML"; // GENERATED by firmware/toolchain/console_pages.py build — do not edit. -// gzip -9 of PATTERNS_INDEX_HTML (42860 bytes → 15286 bytes), served with Content-Encoding: gzip. +// gzip -9 of PATTERNS_INDEX_HTML (43203 bytes → 15416 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,0xdb,0x56, - 0x96,0xe6,0xbd,0x9e,0x02,0x66,0xaa,0x04,0x22,0x02,0x21,0x52,0xfe,0x49,0x42,0x1a, - 0x52,0xdb,0xb1,0xdd,0x49,0x97,0x9d,0xb8,0x2d,0x67,0xaa,0x3a,0x8e,0xab,0x16,0x48, - 0x82,0x22,0x22,0x10,0x60,0x00,0x50,0xb2,0x4a,0x62,0xaf,0xbe,0x9a,0x07,0x98,0xe9, - 0xd5,0x73,0x33,0xd7,0xf3,0x00,0x73,0x3d,0x4f,0x93,0x27,0x99,0xfd,0xed,0x7d,0xce, - 0xc1,0x01,0x08,0xd9,0xaa,0x9f,0x59,0x3d,0xb5,0x52,0x32,0x01,0x9c,0xff,0xb3,0xcf, - 0xfe,0xdf,0xfb,0x3c,0xbe,0x37,0xcf,0x67,0xd5,0xd5,0x3a,0x76,0x96,0xd5,0x2a,0x3d, - 0xde,0x7b,0x8c,0x7f,0x9c,0x34,0xca,0xce,0xc2,0x5e,0x9c,0xf5,0xf0,0x22,0x8e,0xe6, - 0xc7,0x8f,0x57,0x71,0x15,0x39,0xb3,0x65,0x54,0x94,0x71,0x15,0xf6,0x36,0xd5,0x62, - 0xf0,0x25,0x3e,0x96,0xb3,0x22,0x59,0x57,0x4e,0x59,0xcc,0xc2,0xde,0xe1,0x7a,0x31, - 0x98,0xe5,0x59,0x99,0xa7,0x71,0xf0,0x73,0x79,0xb2,0x0c,0xe7,0xc3,0xa3,0xe9,0xfd, - 0xfb,0x47,0x47,0xbd,0xe3,0xc7,0x87,0x52,0xf0,0x58,0x55,0x38,0x4e,0x16,0xfd,0x7b, - 0x97,0x49,0x36,0xcf,0x2f,0x83,0xd7,0x2f,0xbc,0xfe,0x62,0x93,0xcd,0xaa,0x24,0xcf, - 0xfa,0xde,0xf5,0x45,0x54,0x38,0xbf,0x0f,0xe5,0x9b,0xff,0x43,0xe8,0x1e,0x46,0xeb, - 0xe4,0xb0,0xac,0xa2,0x6a,0x53,0xba,0xfe,0xcb,0xf0,0xdd,0x7b,0xff,0x55,0x78,0x14, - 0x7f,0xe5,0x9f,0xfa,0x3f,0xfa,0xaf,0xc3,0xdf,0x53,0xf5,0xf0,0x1a,0x9f,0xe3,0xb1, - 0x9b,0x26,0x17,0xb1,0xeb,0xcf,0x93,0xa2,0xba,0x1a,0xdf,0x1b,0xf9,0x17,0xe3,0x6c, - 0x93,0xa6,0xfe,0x59,0x5c,0x8d,0xff,0xd1,0x4f,0xb2,0x45,0x9a,0x9c,0x2d,0xab,0xf1, - 0x77,0x9b,0xd5,0x34,0x2e,0xfc,0x65,0x9e,0xce,0xc7,0xdf,0x4f,0x7f,0x8e,0x67,0x95, - 0x5f,0x46,0x57,0x63,0x33,0x82,0xca,0x3f,0xf7,0x63,0xef,0x3a,0xde,0xdf,0xef,0xc7, - 0x41,0x15,0x7f,0xa8,0xbe,0xce,0xb3,0x2a,0xce,0xaa,0xb0,0xf2,0xb6,0xfe,0x74,0x53, - 0x5a,0x45,0xa7,0xfe,0xda,0xbb,0xd6,0x4f,0xce,0x82,0x06,0x3f,0x0d,0xe6,0x49,0x19, - 0x4d,0xd3,0x78,0x1e,0xde,0x1b,0x6d,0xed,0xa7,0xe1,0x64,0x1d,0x54,0xcb,0x38,0xeb, - 0x2f,0xfc,0x85,0x37,0x29,0xe2,0x6a,0x53,0x64,0xce,0x7a,0xeb,0xaf,0xf3,0x34,0xad, - 0x5b,0x2c,0xfd,0x95,0x3f,0xf3,0x73,0x59,0x85,0xca,0x5f,0xf8,0x67,0xe1,0x68,0x62, - 0x7a,0x78,0x43,0x3d,0x9c,0xed,0xef,0xdf,0x5b,0xd0,0xd8,0x16,0xe1,0xc8,0x9f,0xa5, - 0x71,0x54,0xbc,0x4d,0x56,0x71,0xbe,0xa9,0xfa,0x95,0xe7,0xf7,0xcb,0x60,0x16,0xa5, - 0xe9,0x49,0xd9,0xf7,0xc6,0xff,0xd8,0x2f,0x3d,0x4f,0xf5,0xa8,0x5b,0x9f,0x7b,0xd7, - 0xb3,0xfe,0xdc,0xc7,0xaa,0xd0,0x5c,0xcc,0xeb,0x18,0xaf,0x79,0xa9,0x62,0x6f,0xab, - 0xea,0xfc,0xce,0xff,0x9d,0xe7,0x6d,0x4d,0xcf,0xbf,0xa3,0x9e,0x17,0xe1,0x70,0xd2, - 0xea,0x71,0x42,0xa3,0xe9,0x57,0x21,0x81,0x84,0x7e,0xf7,0xc6,0x5f,0x51,0xbd,0x7c, - 0x7f,0x3f,0x0f,0x16,0x49,0x51,0x56,0x61,0x48,0x0b,0x71,0x42,0xd5,0xc7,0x34,0x78, - 0x35,0x6d,0xda,0xae,0x7c,0x3d,0xb6,0xb6,0xfc,0x6c,0xb7,0xe5,0xad,0x4f,0x8d,0xd6, - 0x65,0x32,0xef,0x7a,0x15,0x66,0x93,0xc5,0xcd,0x0d,0x35,0xb5,0xf5,0xb3,0xfc,0x72, - 0xfc,0x66,0x4b,0x65,0x18,0x2c,0xea,0x62,0x33,0x9a,0xc9,0xfe,0xfe,0xcb,0x60,0xbd, - 0x29,0x97,0xf4,0x30,0x39,0x3d,0xa1,0xc7,0x59,0xff,0xd4,0x1b,0xff,0x78,0xf2,0x63, - 0x40,0xb5,0x68,0x1c,0x3f,0x86,0xaf,0x03,0x2c,0x7a,0xff,0x07,0xff,0x95,0xff,0x8c, - 0x1a,0xbb,0x8c,0xaa,0xd9,0xf2,0xb4,0xd5,0xd2,0xca,0xbb,0x7e,0x1d,0x48,0xf3,0x34, - 0xee,0x1f,0x03,0x1a,0x4d,0xff,0x55,0xf8,0x2a,0xaa,0x96,0xc1,0x2a,0xa1,0xcf,0xfe, - 0x2b,0x8f,0xab,0x26,0xd5,0x8b,0xbc,0x78,0x16,0x5f,0x24,0xb3,0xb8,0xae,0x4c,0xfb, - 0x97,0x87,0xf9,0xcd,0xcd,0xf5,0x56,0x6f,0x74,0x16,0x5f,0x3a,0xaf,0x8b,0x7c,0x95, - 0x94,0x71,0xbd,0x1d,0x57,0x7e,0x26,0x1b,0xbd,0xac,0x87,0x74,0x14,0xdf,0xaf,0x37, - 0xa6,0xf4,0xae,0x4b,0xda,0xee,0x7e,0x1e,0x4c,0x37,0x49,0x3a,0xdf,0xdf,0x2f,0xe5, - 0x47,0x18,0xaa,0x37,0x1e,0x2d,0xff,0x32,0xc0,0x72,0xf6,0x3d,0xff,0x0a,0x3b,0xbe, - 0xf5,0x26,0xd6,0x6e,0x58,0x6b,0xac,0x8b,0x4d,0xb2,0xfe,0xf3,0xa2,0xc8,0x8b,0xbe, - 0x5b,0x49,0x21,0x17,0x13,0xc9,0x03,0xf5,0x74,0x73,0xf3,0x55,0xfc,0x80,0x5a,0xd9, - 0x6e,0x6b,0xb0,0xfb,0xc7,0xfe,0x06,0x20,0xa9,0xa6,0xb2,0x88,0x69,0xb9,0xf8,0x4d, - 0x0b,0xba,0x0a,0xef,0x1a,0xa7,0xba,0x08,0xf2,0x73,0xaf,0x5a,0x16,0xf9,0xa5,0x23, - 0x1d,0x15,0x6a,0x1d,0x0d,0xd4,0x33,0x74,0xe0,0x64,0x9d,0x14,0xfc,0x0f,0x6d,0x4a, - 0x41,0x08,0x03,0xc3,0xdc,0x5a,0x30,0xf7,0x0c,0xf3,0xa7,0x16,0xe9,0xef,0x29,0x9d, - 0xf3,0xf5,0x42,0xf6,0x28,0x2c,0x27,0x2f,0x83,0x45,0x5e,0x3c,0x8f,0x68,0x18,0xa6, - 0xf3,0x05,0xc1,0x27,0x95,0xc4,0xc0,0xb7,0x5e,0xdf,0x33,0xf8,0x66,0x4f,0x10,0x57, - 0x16,0xad,0xe2,0xb0,0x77,0x91,0xc4,0x97,0xeb,0xbc,0xa8,0x7a,0xce,0x4c,0x9d,0xe9, - 0xde,0x65,0x32,0xaf,0x08,0x51,0xf1,0x06,0x0e,0xf8,0x81,0x30,0x45,0x52,0x25,0x51, - 0x3a,0x28,0xe9,0x2c,0xc5,0xe1,0x08,0x58,0xae,0x4a,0xaa,0x34,0x3e,0x7e,0x1d,0x55, - 0x55,0x5c,0x10,0x1e,0xa1,0xa9,0x0d,0x1c,0xf5,0x54,0x3e,0x3e,0x94,0xaf,0x84,0x0b, - 0xab,0x2b,0xfc,0x7b,0xf8,0xb9,0xf3,0x2c,0x2a,0xce,0x9d,0x24,0x2b,0xab,0x62,0xb3, - 0xa2,0x6e,0x9c,0x2a,0x3f,0x8f,0xb3,0xd2,0xf9,0xf5,0xdf,0xfe,0xdd,0x29,0x69,0x24, - 0x3c,0x9c,0xd2,0x89,0x2f,0xe2,0xe2,0xca,0x51,0x18,0xd3,0x59,0x47,0x67,0xb1,0xb3, - 0x29,0xe9,0x7d,0x7f,0x30,0x98,0x15,0x71,0xb4,0x72,0x92,0x72,0xcf,0x71,0x9c,0x1e, - 0x2d,0xb3,0x7c,0x9d,0x46,0xb3,0xf3,0xb3,0x22,0xdf,0x64,0xf3,0x9e,0x33,0xbd,0x72, - 0x96,0x09,0x6d,0x69,0x71,0xe5,0xf9,0x4e,0x06,0xcc,0xe6,0x5c,0x44,0xe9,0x26,0x2e, - 0x03,0xe7,0x2d,0x95,0x5f,0xd1,0x08,0xe2,0x2a,0xc9,0xce,0x9c,0x32,0xa9,0x62,0x87, - 0x76,0xe0,0x8a,0x1b,0x5b,0x47,0xeb,0xb8,0x98,0x38,0x68,0x52,0x26,0x4d,0x9d,0xf0, - 0x53,0xb5,0x44,0xe1,0x33,0x9a,0x1b,0xfe,0x4d,0x32,0x27,0x72,0xe6,0x98,0x45,0x91, - 0xe7,0xab,0xc0,0xf9,0xfc,0x70,0x6f,0x4c,0xbf,0xaa,0x6b,0x35,0xb4,0xf1,0x67,0xc3, - 0xaf,0x87,0x4f,0x87,0x5f,0x4d,0x06,0x83,0x24,0x3b,0x1f,0x7f,0xf6,0xfc,0xd9,0xf3, - 0x2f,0x9e,0x3d,0xa5,0xa7,0xd5,0xa6,0x8a,0xe7,0xe3,0xcf,0xbe,0x7c,0xf2,0xe5,0xd1, - 0x17,0x47,0xf4,0xbc,0x88,0x92,0xac,0x1a,0x7f,0xf6,0xf0,0xc9,0xc3,0x87,0x0f,0x1e, - 0x4d,0xf6,0x06,0x83,0x62,0x93,0xc6,0xe3,0xcf,0x8e,0x1e,0x1c,0x8d,0x46,0x5f,0x4e, - 0xe4,0x71,0x50,0xe6,0x0b,0x2a,0x33,0x7a,0x3a,0xfa,0x6a,0xf4,0x80,0xde,0xa5,0x68, - 0xe1,0xc5,0x8b,0x87,0x5f,0x1f,0x3d,0xa7,0xa7,0x9c,0x9a,0x7f,0xf8,0xc5,0xd3,0x2f, - 0xbf,0x78,0x41,0x0f,0x97,0x51,0x91,0x8d,0x3f,0x7b,0xf6,0xd5,0x93,0xe1,0xfd,0x17, - 0x68,0x6d,0x1d,0x65,0x71,0x4a,0x55,0xef,0x8f,0x46,0xa3,0x21,0x5e,0x94,0x51,0x56, - 0x8e,0xdd,0x6f,0x69,0x77,0x0b,0xd7,0xdf,0x24,0xfc,0x3c,0x28,0xe3,0x22,0x59,0xf8, - 0xe5,0x55,0x59,0xc5,0xab,0xc1,0x26,0xf1,0xeb,0x97,0xa8,0xb2,0xca,0xb3,0x7c,0xec, - 0xfe,0x53,0x5c,0x3d,0x2d,0x68,0xb0,0xa5,0xf3,0x8a,0x9e,0xb9,0x2e,0x3e,0x94,0xeb, - 0x68,0x16,0xfb,0xa7,0x2f,0xf0,0x72,0xf0,0x26,0x3e,0xdb,0xa4,0x51,0xe1,0xbf,0x8a, - 0xb3,0x34,0xf7,0xcd,0xe7,0xed,0xde,0xe7,0xd7,0xd3,0xfc,0xc3,0xa0,0x4c,0xfe,0x4c, - 0x6b,0x37,0x9e,0xe6,0xc5,0x3c,0x2e,0x06,0xf4,0x66,0xbb,0x37,0xcd,0xe7,0x57,0xd7, - 0xb4,0x17,0x67,0x49,0x36,0x1e,0x4e,0xea,0xfd,0x1b,0xd3,0xb1,0xd7,0xdb,0xec,0x4d, - 0x66,0x79,0x9a,0x17,0xea,0x15,0x2d,0xa7,0x37,0x59,0x10,0x78,0xd2,0xd2,0xad,0x92, - 0xf4,0x4a,0xbd,0xc6,0x90,0xbd,0xc9,0x5e,0x9a,0x64,0xf1,0x60,0x19,0x33,0x21,0x1b, - 0x05,0x0f,0x27,0x83,0xcb,0x78,0x7a,0x9e,0x50,0x59,0x54,0x28,0x57,0xb4,0x43,0xd8, - 0xc6,0x71,0x94,0x01,0x82,0x93,0xa8,0x8c,0xe7,0xdb,0xbd,0xe0,0xb2,0x88,0xd6,0x34, - 0x88,0x0f,0x02,0xdf,0xe3,0x47,0x5f,0x0e,0xd7,0x1f,0x26,0x7a,0x50,0x4e,0xb4,0xa9, - 0xf2,0xc9,0x3a,0x9a,0xcf,0x51,0xf1,0xfe,0xd1,0xfa,0x83,0x73,0x44,0xdf,0x9d,0x47, - 0x0f,0xd6,0x34,0x7e,0xd0,0xfe,0xb8,0xb8,0x26,0x32,0xb6,0x4e,0x41,0x24,0xd3,0xf8, - 0xc3,0x84,0x1a,0x3e,0xcb,0x06,0x04,0x55,0xab,0x72,0x3c,0x8b,0xb1,0xd2,0x93,0xb3, - 0x68,0x3d,0xfe,0x92,0x1a,0x55,0xcd,0xd0,0xdc,0xab,0x2a,0x5f,0x8d,0x47,0xd4,0xda, - 0x64,0xcf,0xac,0x87,0xbc,0xa3,0xb6,0x09,0xde,0x93,0xb9,0x23,0x13,0x03,0x00,0x78, - 0x34,0xc8,0x39,0x01,0x97,0x8c,0xef,0x0b,0xaa,0xa4,0xa6,0x88,0x9f,0x3b,0x8b,0x46, - 0xe0,0xe1,0x4d,0x54,0xa3,0x45,0x34,0x4f,0x08,0x6d,0x8f,0x78,0xac,0xa3,0x6b,0x59, - 0x86,0xe4,0xcf,0xf1,0x78,0xf4,0x90,0xaa,0xf2,0xe3,0xa5,0x34,0xf5,0x68,0x38,0x9c, - 0xa4,0x31,0x8e,0xec,0x00,0x9b,0x86,0xc9,0x06,0xc3,0x51,0xbc,0x32,0x0b,0x31,0xc1, - 0xe4,0xc6,0x23,0x1a,0x4a,0xb9,0x99,0x5e,0xef,0xee,0x00,0xb6,0x5b,0xed,0x8c,0xf4, - 0x40,0x9d,0x36,0x76,0x8e,0x41,0x9d,0xa6,0x52,0xc6,0x8c,0x92,0xd4,0xb6,0x0f,0x40, - 0xeb,0x8e,0xbe,0xe4,0x01,0x1e,0x5d,0xb7,0xaa,0x7f,0x72,0x80,0x5f,0xd1,0x00,0x81, - 0x22,0x07,0x55,0x41,0x00,0x40,0x58,0x6f,0x35,0xde,0xac,0xe9,0x04,0xcf,0x68,0x6b, - 0x27,0x7b,0x76,0xef,0x7c,0xf0,0xbc,0x7a,0x5b,0x87,0xce,0x68,0x88,0x4e,0x83,0x79, - 0x91,0xaf,0xcd,0x06,0x4e,0xd3,0x7c,0x76,0xae,0x16,0x8f,0xb7,0x62,0x1e,0x95,0xcb, - 0xb8,0xb1,0x17,0xad,0xa5,0xbd,0x5f,0x6f,0xeb,0xf8,0xe8,0x11,0xd5,0x18,0x61,0xa3, - 0x79,0x4c,0x0c,0x08,0x1a,0x04,0xf6,0xac,0x7d,0x2a,0xce,0xa6,0x51,0xff,0xe8,0xe1, - 0x43,0x5f,0xff,0x3f,0x18,0x1e,0x79,0x13,0x9e,0x42,0x82,0xa5,0xd1,0x47,0x84,0xc7, - 0xef,0x04,0xa3,0x87,0xa5,0x5f,0xd7,0xe6,0xe7,0xc9,0x6c,0x53,0x94,0x34,0xb7,0x75, - 0x9e,0xa0,0x75,0x35,0x8d,0x20,0x27,0x8c,0x79,0x6d,0x57,0x6e,0x80,0x44,0xc7,0x00, - 0xbe,0x3a,0xf2,0x1f,0x3c,0xa2,0xee,0x1f,0x79,0xaa,0x09,0x67,0x5d,0x1f,0x47,0x6b, - 0x33,0xee,0xb7,0xf6,0x52,0x56,0x53,0xd7,0x99,0x5e,0x77,0x9f,0xd0,0x7a,0xe7,0xa8, - 0x24,0x1d,0xbc,0xea,0xaf,0x07,0x9b,0x89,0x05,0x2d,0x8f,0xb0,0x6f,0x49,0xb6,0xde, - 0x54,0xef,0xc0,0x98,0x87,0x8b,0x24,0x8d,0xdf,0x9b,0x2d,0xcc,0xf2,0x8c,0x30,0xce, - 0x26,0xbd,0x4e,0x09,0xfd,0x0f,0x98,0xe6,0xf0,0xbb,0x1a,0x90,0xf5,0x76,0x0d,0xf5, - 0x56,0xa2,0xd1,0xae,0x73,0xc7,0x88,0x97,0x66,0x99,0x26,0x77,0x3a,0xe1,0x00,0x28, - 0xd3,0xf8,0x57,0x40,0x14,0x77,0x3b,0xde,0xd2,0x4d,0x6b,0xb9,0xd1,0xab,0x13,0x64, - 0x7f,0xcb,0x8a,0xd1,0x72,0x09,0xc6,0x38,0x7a,0x60,0xda,0x5b,0x5d,0xcb,0x31,0x9e, - 0x00,0x54,0x40,0xa9,0xc7,0xcb,0x64,0x3e,0x8f,0x33,0x81,0x58,0xf3,0x32,0x4e,0xd3, - 0x64,0x5d,0x26,0xe5,0xe4,0x72,0x49,0xd3,0xe4,0x03,0x87,0x55,0x04,0xa6,0xa4,0xad, - 0xac,0xa2,0xb3,0xbb,0x8c,0x0b,0xcb,0xb1,0x73,0x62,0x1f,0x7d,0xf4,0xc4,0xea,0xd5, - 0xc3,0x32,0x3d,0x02,0x72,0xab,0x4f,0xe2,0x0e,0x52,0x6c,0x1d,0xc4,0xa3,0xdb,0x40, - 0x94,0x46,0x1b,0xac,0xf2,0xf9,0xad,0xe7,0xa2,0xfd,0x02,0x2b,0x15,0x10,0x7e,0xfa, - 0xd8,0x79,0xf9,0x8a,0x4a,0x11,0x1f,0x03,0x4e,0x02,0xbc,0x8a,0x66,0x12,0x00,0x22, - 0xcc,0x3b,0x15,0x79,0xea,0xd0,0x72,0x4d,0x88,0xcf,0x38,0x07,0xef,0x10,0x55,0x0e, - 0x41,0xd0,0x0c,0xeb,0x0b,0x79,0x87,0x19,0x06,0xb5,0x1f,0xed,0x93,0x2c,0xaf,0xc7, - 0x4b,0x3e,0xcb,0x9d,0x63,0x9b,0x17,0xb4,0xfe,0x39,0x56,0x94,0xe4,0xb8,0xe0,0xfe, - 0x43,0x19,0xf0,0x05,0x96,0x22,0xbf,0xbc,0xb6,0x60,0xfa,0xa8,0xb5,0x6c,0xd2,0xc2, - 0x74,0x43,0x90,0x98,0x05,0xf3,0x38,0xe5,0x4d,0x1c,0x27,0xd9,0x92,0x48,0x7d,0xf5, - 0x31,0x88,0x52,0xc8,0xd3,0x5a,0x11,0x3e,0x51,0x7b,0x7f,0xe1,0xf6,0x18,0x3c,0x49, - 0xe5,0x81,0x25,0x9b,0x53,0xef,0x84,0xb5,0x7a,0xb0,0x6a,0x45,0xee,0xbe,0x8b,0x56, - 0x55,0x2d,0x66,0xd6,0xab,0xf6,0x40,0x77,0x3e,0x8f,0x17,0xd1,0x26,0xad,0x26,0x1d, - 0xed,0xca,0x34,0xba,0x60,0x0a,0x7b,0xff,0x2d,0xb1,0xaf,0x24,0x4c,0x3a,0xbf,0x6c, - 0xe2,0x4d,0x3c,0x76,0x68,0x3d,0x1c,0xf0,0xf4,0x04,0xca,0x0e,0x10,0x92,0xef,0xb0, - 0xd0,0x5d,0x3a,0xa8,0xbf,0x41,0xc3,0xf3,0x78,0x2e,0xbc,0xe7,0x94,0x44,0x1a,0x5a, - 0x43,0x2a,0x18,0x65,0xe0,0x39,0x37,0xeb,0x34,0x8f,0xb0,0x30,0xdc,0x00,0x81,0x52, - 0x52,0x95,0x4e,0x7e,0x49,0xe2,0x6f,0x91,0x9f,0x15,0x71,0x59,0x12,0x03,0x9b,0x57, - 0xc4,0x70,0x12,0xf7,0x39,0x8d,0x52,0x74,0xc5,0x00,0x14,0x70,0xd7,0xf6,0x86,0x5b, - 0x78,0x4e,0x90,0x1a,0x56,0xbd,0x89,0x18,0xa5,0x92,0x63,0xa1,0x34,0xa1,0x79,0x7a, - 0x6f,0x1e,0x29,0xbc,0xb5,0x8b,0xb6,0x76,0x48,0xa1,0xc2,0x5b,0x7b,0x77,0x41,0x51, - 0xc1,0x43,0x26,0xb6,0xbf,0x00,0x42,0xef,0x8a,0x4b,0x51,0x3e,0xfb,0x9b,0xf1,0x55, - 0x37,0x52,0xf8,0xa5,0xbc,0xee,0x44,0x6d,0xbf,0x94,0xc1,0x59,0x5c,0xf9,0xf8,0x17, - 0xc2,0xeb,0x75,0x17,0x03,0x83,0x8f,0x9b,0xf5,0x0e,0xcd,0x93,0x0f,0x24,0xc3,0x15, - 0x57,0x8d,0x6f,0xe0,0xc9,0xd5,0xc7,0xfc,0xbc,0xf1,0x25,0xd7,0x95,0xa8,0xe5,0xb4, - 0xe3,0xac,0x07,0xbf,0x10,0xa8,0x5c,0x2b,0x5e,0xef,0xa8,0x8b,0xd7,0xb3,0xb6,0xc1, - 0xda,0x76,0xb5,0xd6,0x80,0xb3,0xf6,0x36,0x6b,0xde,0x78,0x38,0xfc,0xed,0x44,0x88, - 0xc3,0xb0,0x9b,0x83,0x44,0x03,0x71,0x51,0xd8,0x5c,0x5a,0x9b,0x09,0xe0,0x73,0x67, - 0xe3,0x7b,0x6c,0x72,0x6b,0x07,0x8a,0x55,0x94,0xd2,0x79,0x09,0x56,0xe5,0xd9,0x5d, - 0x49,0x19,0xe8,0x96,0x1e,0x26,0x93,0x7a,0x54,0x26,0xf1,0x76,0x80,0xe1,0x74,0x2c, - 0x92,0xfa,0xda,0xb5,0xb6,0x9f,0xa1,0xdb,0xd6,0x79,0xa0,0xb7,0xa9,0xf5,0x5a,0x01, - 0x38,0x33,0xa0,0x74,0xaa,0xbf,0x86,0x9a,0x05,0x47,0x31,0x72,0xa6,0xc9,0x19,0x1d, - 0x93,0x69,0x11,0x91,0x10,0x4a,0x87,0xf2,0xfb,0xef,0x9e,0x3b,0x45,0x4c,0xa7,0xa7, - 0xac,0x6c,0xf1,0x90,0x88,0xd8,0x65,0x5c,0xd0,0x79,0xcd,0xd2,0x2b,0xfa,0x03,0x81, - 0xb1,0x72,0x96,0x11,0x0b,0x93,0x0b,0x12,0x95,0x71,0x66,0x08,0x17,0xe4,0xa8,0x53, - 0x30,0xa1,0xc8,0x72,0x73,0xb0,0x49,0xf0,0xa5,0x36,0x21,0x72,0x3b,0x8b,0x22,0x5f, - 0x41,0x24,0x4e,0xe6,0xdc,0x02,0x44,0xe1,0x08,0xc8,0x04,0x67,0x82,0x64,0x5b,0x34, - 0xc7,0x0d,0x5c,0xe6,0x9b,0x74,0xee,0x4c,0xa9,0x50,0x76,0x81,0xe3,0xc2,0x38,0x05, - 0x38,0xa3,0xa4,0x11,0xd1,0x70,0x89,0xc0,0x54,0x31,0x0d,0x25,0x21,0x04,0x43,0x87, - 0x89,0x16,0x13,0xaa,0x3f,0x34,0x59,0x92,0x88,0xeb,0xf4,0xca,0x2a,0x49,0x53,0xb4, - 0x76,0x99,0x17,0xe7,0x34,0xd1,0x9e,0xef,0xd0,0x8e,0xcd,0x96,0x9a,0x84,0xf1,0x3c, - 0x48,0x2e,0xd7,0x12,0x6f,0x74,0x41,0xb0,0x09,0xe4,0xe9,0xd3,0x54,0xe7,0x68,0x67, - 0x45,0xa7,0xae,0xac,0x6b,0x71,0x5b,0x20,0x70,0xd0,0x9f,0x94,0x4e,0x09,0xa9,0x9d, - 0x90,0xd4,0x2a,0x07,0x27,0x9b,0x62,0x92,0xc4,0xf0,0xe7,0xd9,0xbc,0x94,0x29,0x92, - 0x44,0xc7,0xa8,0x2e,0x2a,0x69,0x7e,0xcb,0x28,0x3b,0x13,0x54,0x46,0x8b,0x18,0xaf, - 0xff,0x0a,0x50,0x07,0x19,0x69,0xa3,0x86,0x16,0xc2,0xe3,0xa6,0x41,0xd0,0x1b,0x27, - 0x41,0x7f,0xb8,0xc3,0x09,0xb9,0xff,0xe0,0xb7,0xb7,0x48,0x59,0x7b,0x51,0x96,0xac, - 0x22,0x66,0xd9,0xa5,0xb1,0x51,0x30,0x2a,0x9d,0x98,0x58,0x19,0xc2,0x08,0x83,0x7c, - 0x53,0xd1,0x36,0x00,0x08,0x2a,0x1a,0xc7,0x3f,0x9c,0xc7,0x57,0x8b,0x82,0x15,0x1b, - 0x32,0x59,0x2c,0xc7,0x75,0xcd,0x05,0xf1,0xaf,0x94,0x36,0xeb,0x0f,0xfd,0x01,0x09, - 0xeb,0xbf,0xf5,0xb6,0x55,0xde,0xfd,0xf9,0xc1,0x10,0x5f,0x19,0x5c,0xdf,0xe4,0x97, - 0x00,0x3d,0xec,0x5c,0x52,0x38,0x97,0xc4,0x7d,0x50,0xa7,0x3e,0xf1,0x1a,0xab,0x15, - 0xa1,0x6a,0xec,0x27,0xb4,0x2c,0x24,0xee,0x3a,0x57,0xf9,0x06,0x9c,0xc9,0x22,0x29, - 0x68,0x0f,0x22,0x00,0x23,0xd8,0x92,0x8c,0xb6,0x2e,0xe6,0xea,0xd8,0x46,0x02,0x45, - 0xda,0xfc,0x34,0xc2,0x66,0x01,0x00,0x51,0x7f,0x96,0x26,0xb3,0x73,0x27,0x8b,0x63, - 0x7a,0x47,0xc5,0x05,0xdc,0xc1,0xdb,0x08,0x51,0x4a,0x32,0x82,0xf2,0x8b,0x58,0xef, - 0xb1,0x62,0x6c,0x82,0x33,0x22,0xe9,0x36,0x8f,0xb2,0x35,0x2f,0x1d,0x8b,0xfd,0xb8, - 0x48,0xca,0x64,0x9a,0xa4,0x28,0x22,0x5b,0x47,0x9b,0x12,0xb1,0x70,0x58,0x36,0x89, - 0x04,0xfe,0x0c,0x80,0xa1,0xc7,0x8c,0xd1,0xb5,0x38,0xdd,0x82,0x83,0x5d,0x52,0xa2, - 0xc4,0x84,0xa0,0xa4,0xce,0x64,0x2f,0x47,0x0f,0x6a,0xe9,0x99,0x7f,0x47,0x33,0x14, - 0xdd,0xe5,0x27,0xb4,0xb4,0xc0,0x70,0xd2,0x18,0x0d,0x50,0xce,0x45,0x4b,0xdc,0xf8, - 0x6c,0xba,0x49,0xcf,0x5b,0xef,0x02,0xbc,0x7b,0x9b,0xd7,0x02,0x55,0x2d,0x73,0xe2, - 0xcb,0x77,0x79,0x15,0xff,0x2d,0x62,0x34,0xed,0xfe,0x0b,0x68,0x90,0x9d,0x62,0x93, - 0x05,0xce,0x13,0x67,0x1d,0x15,0x15,0x4b,0x8f,0xc2,0x6e,0x12,0x0a,0xa2,0x5d,0xa3, - 0x93,0x41,0xb8,0x82,0x76,0x18,0x30,0x04,0x85,0xdc,0xdc,0x99,0x45,0x19,0x36,0x0e, - 0xfa,0x7d,0xda,0xcd,0x2b,0x3e,0xe5,0x3e,0x76,0x1f,0xc7,0xdb,0x60,0x00,0xe2,0x8e, - 0x18,0x59,0x45,0x16,0x56,0x21,0xb8,0x8a,0xa1,0xb2,0xa3,0x1d,0xa2,0x1d,0x97,0x7d, - 0x14,0x9d,0x5d,0x2e,0x7d,0xaa,0x57,0x9b,0x32,0x9e,0xa3,0x41,0x42,0x6e,0x24,0xcf, - 0x3a,0x91,0xe0,0xcb,0x45,0x4e,0xbd,0xe6,0x0b,0xfe,0x2d,0x1c,0x0f,0x58,0xa3,0xcd, - 0x2a,0xf3,0x01,0x44,0x78,0xcb,0xaa,0x3f,0xc2,0x8b,0x57,0x40,0x0e,0xbd,0x37,0x20, - 0xa4,0x0e,0x28,0x63,0x3c,0xef,0xf1,0x00,0x05,0xce,0x99,0xd3,0x02,0xe4,0x54,0x80, - 0xdd,0x82,0xb1,0xa5,0x8d,0xbb,0x34,0xfb,0xcd,0x23,0xe2,0x39,0x17,0x04,0x96,0xdf, - 0xab,0x65,0x61,0xa6,0x8c,0xaa,0xa0,0xbd,0x59,0x8e,0xc3,0x58,0xe5,0xa2,0xdf,0x23, - 0x39,0x16,0x2b,0xc0,0x58,0x92,0xf1,0x19,0xb7,0xab,0x54,0x81,0x90,0x72,0xff,0x8c, - 0x8e,0xcf,0x72,0x61,0xe9,0x80,0x82,0x69,0xe5,0x80,0x10,0x79,0x6c,0xd3,0x78,0x16, - 0xd1,0xbc,0xb1,0x5e,0x28,0x2b,0xc8,0x9e,0x96,0x5a,0xc6,0x44,0xf8,0x7e,0xbe,0x01, - 0xb1,0x10,0x6e,0x11,0xcb,0x30,0x8b,0x8b,0x2a,0xc2,0xe9,0xa1,0x09,0xd2,0x5a,0xcb, - 0xc9,0x11,0x9b,0x00,0x6d,0x68,0x03,0x94,0x6c,0x38,0x3f,0xb2,0x65,0x4c,0x00,0xb0, - 0x03,0x1a,0x79,0x2b,0x27,0xce,0xbc,0x47,0x87,0xc6,0x62,0x47,0xb6,0x19,0x7d,0xe1, - 0x8f,0x1e,0x0d,0xfd,0x47,0xf7,0xb5,0x32,0x40,0x8f,0xa4,0x0b,0x71,0xea,0x6f,0xce, - 0xf2,0x68,0x97,0xd3,0xb1,0x55,0x2c,0x42,0xbe,0x4d,0xf1,0xbf,0x50,0xb7,0x60,0xea, - 0x19,0xa4,0x60,0x93,0x72,0xd6,0x69,0xd5,0xc8,0x24,0x58,0x17,0xc9,0xaa,0x4b,0x3a, - 0x90,0x41,0x75,0x30,0x64,0xad,0xba,0x5a,0xbe,0xf8,0xc8,0xca,0x8c,0x8e,0x3c,0x23, - 0xcf,0xdf,0xa9,0x0b,0xa5,0x95,0x59,0x2c,0x3a,0x04,0x0f,0x3a,0x84,0x03,0x92,0x1f, - 0xf2,0xcb,0x78,0xae,0x37,0x48,0x94,0x15,0xbc,0x7f,0xdb,0x3d,0x9c,0x97,0xb8,0xc9, - 0x7f,0x3d,0xb2,0x54,0x88,0x86,0xbd,0xff,0x84,0x0e,0xe3,0x8e,0xfc,0xf9,0x2d,0x48, - 0x26,0xba,0xee,0xda,0x19,0x98,0x40,0x99,0xe5,0x5a,0x2c,0xa0,0x70,0x75,0x3e,0x83, - 0xaa,0xc5,0xdf,0x79,0xbb,0x28,0xeb,0x69,0x3f,0x14,0x79,0x39,0xdf,0xcc,0x96,0x63, - 0xe7,0x01,0xe0,0xb6,0x8a,0xe8,0xc0,0x11,0x37,0xa0,0xa4,0x1b,0xe2,0xb6,0xce,0x08, - 0x59,0xa9,0xd3,0x4b,0xc7,0xe1,0xbb,0xdc,0x81,0xa0,0xcb,0x87,0x92,0xcf,0x54,0x0e, - 0x9d,0xfb,0x7a,0x49,0x07,0x82,0x4f,0x1c,0x21,0x9d,0x5f,0xff,0xe3,0x7f,0xff,0xfa, - 0x1f,0xff,0x87,0x49,0x1c,0x71,0x15,0x06,0x8f,0x40,0x25,0xcf,0x3f,0x48,0xea,0xa7, - 0x15,0xa0,0x9e,0x88,0x91,0x8b,0xa3,0x0b,0x98,0x0e,0x60,0xa3,0x8d,0x67,0xe7,0xd3, - 0xfc,0x83,0x9c,0xf4,0xa4,0xf2,0xf8,0xe4,0xfd,0x03,0xd1,0xcb,0x24,0xea,0x2b,0x51, - 0x74,0x3c,0xcb,0x61,0xc8,0xf5,0xae,0xa1,0xfa,0x31,0xa7,0xed,0x48,0x44,0x23,0xa3, - 0x49,0x69,0x7c,0x18,0x6a,0xb8,0x1f,0xa8,0x47,0x5b,0x15,0x7d,0x24,0x68,0x9f,0x08, - 0x89,0xa9,0xf3,0xb0,0xd6,0x31,0x0f,0x46,0x0f,0x9b,0xb0,0x7c,0xbd,0xce,0x95,0x22, - 0xb0,0x88,0x89,0xe4,0x13,0xb6,0x6d,0x48,0xb3,0xe3,0x68,0x51,0xb1,0x6e,0x80,0x6d, - 0x34,0xe3,0x5e,0x6f,0x62,0xca,0x47,0x53,0xda,0x7f,0xda,0xa5,0x09,0xc0,0x61,0xc0, - 0xdb,0xaa,0x18,0x5c,0x79,0x48,0xe3,0x45,0x45,0xa7,0xaf,0xe0,0x51,0x0d,0x9b,0x94, - 0x4c,0xd8,0x1f,0xa5,0x31,0xfa,0xb2,0x25,0xae,0x0f,0xcd,0x08,0x56,0x17,0x7a,0x00, - 0xdc,0xd8,0x00,0x25,0xa5,0xbd,0xc1,0x97,0xc2,0xad,0x5f,0x1c,0xa0,0x59,0x05,0xb8, - 0x5c,0x48,0xf0,0x80,0x56,0xc4,0x74,0x91,0x4e,0x92,0x0b,0x07,0x2c,0xf7,0x41,0x55, - 0xc5,0xb0,0xf2,0x2c,0x2e,0xcf,0x31,0x0b,0x4d,0x2c,0xd6,0x49,0x96,0x11,0xf9,0x42, - 0x7b,0x3e,0xef,0xae,0xe6,0xcd,0xb9,0x73,0xc3,0xaf,0x5c,0x2e,0x8d,0xb1,0xe8,0x32, - 0xa9,0x96,0xc4,0x0e,0x31,0xb0,0xcc,0x08,0xa8,0x52,0x50,0x3a,0x0d,0x2d,0xc0,0xc1, - 0x0a,0x9c,0x14,0x1d,0xe2,0xf2,0x4e,0x34,0x23,0x64,0x4c,0xe8,0x5c,0x31,0xe2,0x36, - 0x70,0xd4,0x0a,0xb5,0xaf,0x1e,0xd1,0x86,0x12,0x74,0xb4,0x4d,0x07,0xa3,0xd1,0x03, - 0xd9,0x69,0x6a,0xb1,0x66,0x61,0xce,0x8a,0x64,0x3e,0xc1,0x9f,0x01,0xb1,0x26,0x6b, - 0xf0,0x70,0x03,0xe9,0xb1,0x1c,0x3f,0xb8,0x0f,0x5b,0x02,0x35,0x4c,0x6d,0xf4,0x87, - 0xfe,0x68,0x51,0x78,0xcc,0xdd,0x3c,0x68,0xf3,0x33,0x44,0xb7,0x8a,0x4a,0x1a,0x7e, - 0x59,0x83,0x07,0x31,0xf3,0xb3,0xf3,0x2b,0xde,0xec,0xd1,0x97,0xba,0xe3,0x37,0x4e, - 0x87,0x86,0x9d,0x25,0xa9,0xed,0xde,0xe3,0x43,0x31,0xc2,0x3d,0x3e,0x14,0xaf,0x05, - 0xd8,0x5f,0x8e,0x1f,0xcf,0x93,0x0b,0xe2,0xf3,0xa2,0xb2,0x0c,0x7b,0x98,0x90,0x76, - 0x6a,0x88,0x8b,0xe3,0xc7,0x24,0xc7,0x65,0xfa,0xdb,0x3c,0xaf,0xd8,0x53,0x81,0x5e, - 0x1d,0x3f,0x5e,0x8e,0x8e,0x6b,0x0b,0x1f,0x3d,0x34,0x4a,0x96,0x9b,0x69,0xcf,0x49, - 0xe6,0x61,0x6f,0x51,0xf6,0x8e,0x07,0xba,0xca,0xa1,0x6a,0x74,0x8f,0xfe,0x67,0xf7, - 0xa9,0xf1,0xbc,0xaa,0x82,0xa7,0x37,0x1b,0xb8,0x56,0x38,0xce,0xe3,0xe5,0xd1,0xf1, - 0x69,0x95,0x17,0xd8,0x4e,0xe1,0x41,0x15,0x23,0x43,0x5b,0x49,0xed,0x1d,0x71,0x99, - 0xf5,0x31,0x4b,0x40,0x53,0x3a,0xb3,0x73,0xb7,0xa4,0xbd,0xe7,0x61,0x59,0x0c,0x51, - 0x52,0x66,0x6e,0xc5,0x92,0x07,0x04,0x19,0x06,0x95,0x38,0x61,0x16,0x38,0x69,0x33, - 0x4a,0xd4,0x9e,0x61,0x95,0x7c,0x27,0x2f,0x58,0x17,0x03,0x7d,0x8e,0x58,0xc7,0x58, - 0xcc,0x8a,0x56,0x34,0x1c,0x92,0xbb,0x5e,0x70,0x41,0xb4,0x01,0xb9,0x4f,0xe4,0x23, - 0xd5,0x79,0x29,0x7c,0x37,0x4b,0x5a,0x22,0x04,0x13,0x17,0xc0,0xf2,0x0f,0x6c,0xc2, - 0x54,0x3e,0x78,0x7c,0xb8,0xe6,0xc1,0x5b,0xeb,0xa0,0xa8,0x1c,0x4f,0x9c,0xbe,0x28, - 0x6e,0x4a,0x2f,0x7e,0x9c,0x3a,0x20,0x53,0x6a,0x91,0x56,0xb4,0x15,0xaa,0xff,0x52, - 0xd6,0xe7,0xf1,0xa1,0x54,0x50,0xb5,0xed,0xed,0xd0,0xec,0xa6,0xa9,0xcb,0x0f,0x7a, - 0x2b,0x31,0x8a,0x43,0x1a,0x06,0xed,0xba,0xfc,0xd3,0xd8,0x1c,0x40,0x32,0x00,0xa2, - 0xf9,0xea,0x25,0xfb,0xb6,0x08,0x98,0xe9,0x7d,0xfa,0x81,0xcf,0xa9,0xd9,0x15,0x12, - 0x1a,0x69,0xc8,0x7a,0xf4,0x84,0xc0,0xa5,0x77,0xfe,0xa5,0xc6,0xc8,0xcc,0xb9,0xc3, - 0x3a,0xfc,0x1e,0xd6,0x58,0x03,0x00,0x7e,0x81,0x2f,0x5f,0x57,0x61,0xef,0xf3,0xc3, - 0xcf,0x7b,0xce,0x6a,0x93,0x56,0xc9,0x1a,0xc6,0x63,0xae,0xb7,0x3e,0x7e,0x06,0x82, - 0xf0,0x78,0x7a,0x4c,0xf4,0x66,0x45,0x13,0x3f,0x96,0x2d,0xc2,0x7e,0x45,0xfc,0xfa, - 0xcf,0xc9,0x9a,0x5f,0x13,0xf9,0x39,0x67,0xb9,0x99,0xf7,0x52,0x64,0x19,0x62,0xf8, - 0x66,0xcb,0x3c,0x2f,0x63,0xb5,0x05,0x68,0x50,0x8f,0x13,0x46,0x8a,0xde,0xb1,0xd0, - 0x8d,0xd2,0x39,0x50,0x72,0x15,0x1b,0xdf,0x1d,0x60,0x84,0x19,0x91,0x05,0xda,0xe8, - 0x34,0x05,0x57,0xcb,0xd2,0xfe,0xfe,0x8a,0x24,0x97,0xbc,0x9a,0x38,0xd4,0xa5,0xb3, - 0xc9,0xd0,0x61,0xa9,0x09,0xd1,0x94,0xb0,0x5a,0x19,0x17,0x7a,0xab,0x0f,0x79,0x49, - 0xf8,0xe7,0xc6,0xac,0x0c,0x33,0x84,0x32,0xf1,0x5f,0xb0,0x25,0x9b,0xb4,0x0d,0x16, - 0xab,0xf2,0x4c,0xbe,0xe3,0xc7,0xb1,0xda,0xa3,0x66,0x11,0x16,0x28,0xa5,0x90,0xfc, - 0x3c,0x7e,0x9c,0x50,0xc9,0xa4,0xbb,0xf4,0xa7,0xe0,0x4c,0x1a,0x62,0x45,0x56,0xcf, - 0x61,0x7c,0x41,0xaf,0x2d,0x9c,0xdd,0x3b,0xb6,0x79,0x73,0x1b,0xee,0x0c,0x1c,0x19, - 0xd0,0xb8,0x05,0xa4,0xde,0x74,0xc0,0x8f,0x52,0xa8,0xc6,0x35,0x08,0xed,0x8e,0xd9, - 0x51,0x32,0x95,0x0c,0x11,0x0f,0x9f,0x98,0x05,0x49,0x7e,0x4f,0xd2,0xb4,0x77,0x7c, - 0x1a,0xa7,0xd4,0x1b,0x76,0xae,0x75,0x4e,0x6e,0xa9,0x87,0xa6,0x7f,0x4c,0x68,0x21, - 0x9f,0xe5,0x97,0x19,0xd3,0x9f,0x1f,0xbf,0x7d,0x7d,0xf7,0xaa,0xcf,0xe8,0xe1,0x98, - 0xfe,0xc4,0xf0,0x2d,0xe0,0xae,0x9b,0x0b,0xf5,0x91,0x01,0x13,0x9f,0xf2,0x7d,0x31, - 0xbf,0x65,0xe1,0x4f,0xe9,0xab,0xc3,0x0c,0xdf,0x9d,0x8f,0x3b,0x3f,0x75,0x1c,0xf6, - 0x5b,0x80,0x2c,0x6d,0x41,0x19,0x41,0x2a,0xbf,0x26,0x0e,0x4f,0x83,0xe7,0xee,0xf6, - 0x9a,0x5d,0x16,0xa6,0xf5,0xf8,0x35,0xd1,0xd0,0x98,0x10,0x27,0xf1,0x77,0x0e,0x1c, - 0x71,0xa0,0x27,0x50,0x72,0x16,0x14,0x10,0x97,0x78,0x0f,0x6c,0xa9,0x64,0xd1,0x29, - 0xf1,0x6c,0x31,0xd4,0x4a,0x73,0x3e,0xab,0xc1,0xde,0x7e,0x36,0x2d,0xd7,0x93,0xc7, - 0x91,0xb3,0x2c,0xe2,0x45,0xd8,0x3b,0xec,0x1d,0x7f,0x43,0xb2,0xda,0xe3,0xc3,0x88, - 0x46,0xa0,0xba,0x30,0x5d,0x6b,0x47,0x16,0xe3,0x17,0xf3,0x9b,0x7e,0x62,0x9c,0x71, - 0xe6,0xf9,0x8c,0x3d,0x4c,0xa0,0xd4,0x7d,0x9e,0xc6,0xf8,0xf9,0xf4,0xea,0xdb,0x39, - 0x95,0xd8,0xee,0xc1,0xb3,0x88,0x26,0x1b,0xfe,0xa6,0xef,0xd2,0x3f,0xae,0xe7,0xa7, - 0xea,0x29,0x55,0x8f,0x34,0xe5,0xe7,0x29,0xbf,0xa0,0x5f,0xf4,0x02,0xa8,0x0b,0x8f, - 0xf8,0x97,0x1e,0x81,0x72,0xf0,0x88,0x7f,0xf1,0x58,0xf2,0x43,0x49,0x3f,0x79,0x4b, - 0x7e,0x91,0xba,0xbf,0xd0,0x33,0x1f,0xa5,0xa7,0x55,0x86,0x67,0xfe,0x4d,0xef,0xb0, - 0x2d,0x78,0xc6,0xbf,0xea,0x91,0xe0,0x45,0xbf,0xa1,0x9f,0xea,0xe5,0x77,0xfa,0xd5, - 0x77,0xba,0x61,0x01,0x69,0xbc,0x96,0x5f,0xaa,0x20,0x41,0xab,0x2e,0x4a,0x3f,0x79, - 0x7c,0x42,0x48,0x65,0x8c,0xf2,0x1b,0xaf,0x05,0xfd,0xf3,0x5b,0xf9,0x69,0x1a,0x16, - 0xd0,0xe3,0x96,0xe5,0xa7,0x4b,0xd2,0xc3,0xde,0xe1,0xa1,0x03,0xe7,0x37,0x42,0x6e, - 0x55,0x92,0xea,0x3d,0x2c,0x2b,0x87,0x1d,0x0f,0x0d,0xbd,0xb3,0x74,0x47,0xe0,0xdd, - 0x45,0x79,0xb8,0x8a,0xae,0x1c,0x42,0x9a,0x60,0xa5,0x48,0x56,0x07,0xc5,0x45,0x6b, - 0x04,0xa9,0x8a,0x3a,0xb2,0x84,0x4c,0xc2,0xf1,0x8c,0x48,0x3b,0x41,0x01,0x51,0xde, - 0x58,0x08,0x24,0x48,0x34,0xb1,0xec,0x25,0x6b,0x0c,0x50,0x90,0x55,0x51,0xf9,0x6a, - 0xb5,0xc9,0x48,0x9c,0xa0,0x36,0xe3,0xf5,0x80,0xd8,0xb9,0x73,0x34,0x47,0x38,0x15, - 0xda,0x28,0xd1,0x47,0xd2,0xd0,0x62,0xd6,0x88,0x31,0x07,0xc8,0x07,0x97,0xd5,0x96, - 0xa5,0x13,0x7f,0x20,0x1c,0x42,0x43,0x64,0xd9,0x3e,0x92,0x39,0x0c,0xf4,0x38,0x58, - 0x9f,0x90,0xcb,0xe8,0x8a,0x22,0xb9,0xe0,0x36,0x02,0x01,0x11,0x92,0x05,0xe9,0xf4, - 0x86,0xec,0x00,0xb8,0x8e,0x33,0xb0,0xc4,0xa7,0xc5,0x8c,0x9f,0x65,0x75,0xbe,0x87, - 0x88,0xaf,0x69,0x06,0x01,0x9a,0x63,0x09,0x19,0x98,0xc8,0x5a,0x9d,0x06,0xb8,0x5f, - 0x8a,0xc2,0x4c,0x8e,0x40,0x30,0x85,0x1b,0x11,0x8d,0x0e,0xc7,0x81,0xce,0x01,0xda, - 0x9a,0x03,0x67,0x18,0x2e,0x45,0xd4,0xc6,0x50,0x2b,0xe0,0xc0,0xa4,0xf2,0x48,0xeb, - 0x40,0x23,0xc2,0xc2,0x5c,0x8a,0xd2,0x25,0x3d,0x77,0x34,0x7a,0xc4,0x7a,0x56,0x10, - 0xb2,0x82,0xfa,0x3c,0x10,0x94,0x3c,0xcd,0x3f,0xc4,0x65,0xdf,0x9c,0x0a,0x81,0x6c, - 0x58,0x82,0x8a,0x2b,0x41,0x8c,0x79,0x41,0x80,0xd4,0x77,0x8d,0xb6,0xcc,0x85,0x91, - 0xcb,0x6e,0x81,0x31,0xd8,0x69,0xba,0x39,0x43,0x33,0x04,0x2d,0x58,0x19,0xe2,0xad, - 0xc3,0x77,0xef,0x27,0xf4,0xf4,0xe9,0x06,0xc7,0xbc,0x22,0x31,0x41,0xd4,0xae,0x6f, - 0xda,0xcc,0xbb,0xa6,0xa6,0x94,0x53,0x62,0x30,0x8f,0xaa,0x88,0x96,0x2b,0x28,0xa9, - 0x33,0xb8,0xeb,0xed,0x41,0x2f,0x29,0x7e,0x71,0x9b,0x6a,0xb2,0xb7,0xe5,0x25,0xd7, - 0x66,0x34,0xda,0x57,0x56,0x22,0xa6,0x0c,0x60,0xc2,0xc6,0x19,0x45,0xbb,0xd6,0x6e, - 0xa9,0xf1,0x8b,0x12,0x1b,0xf8,0xe6,0xe7,0x4d,0x29,0xd4,0x1b,0x4d,0x95,0x84,0x59, - 0xa4,0x58,0x52,0x9a,0x99,0x8e,0x9d,0x5e,0x4d,0x31,0x7a,0xcc,0x23,0x12,0xfe,0x62, - 0x3c,0x45,0x43,0xe7,0xfd,0x61,0x6e,0xee,0xcf,0x71,0x91,0x2b,0xd0,0x43,0x5b,0x16, - 0x98,0xb1,0x42,0x8b,0x95,0x4d,0xd0,0xbc,0x62,0xff,0x12,0xa5,0x6c,0x8d,0x08,0x2c, - 0xb3,0x33,0x5e,0x33,0xc5,0xd3,0xce,0xb4,0xd1,0x01,0xcb,0x50,0x2f,0xfb,0x66,0x4d, - 0x6b,0x11,0x3f,0xa5,0xfd,0xad,0xd7,0xbc,0xca,0x09,0x5e,0xc3,0x7a,0x4b,0x83,0x34, - 0xce,0xce,0xaa,0xe5,0x44,0x7d,0xce,0xc2,0xd6,0x5e,0x59,0xdf,0x01,0x28,0x01,0x53, - 0x95,0x40,0x11,0x95,0x90,0x5b,0x3b,0x71,0xa1,0xd5,0x74,0xc7,0x2e,0x48,0x8c,0xab, - 0x4b,0x12,0x06,0x6a,0x78,0xf7,0xba,0x2d,0x6a,0xe6,0xf4,0xdd,0x83,0xec,0xc0,0xf5, - 0x1a,0x15,0x8c,0x3b,0x6f,0x16,0x86,0xe1,0x50,0x7f,0x21,0x74,0xd4,0x6a,0xca,0xa2, - 0xa9,0x3b,0xed,0xa0,0xf4,0x6e,0x3b,0x82,0xea,0x1a,0xcd,0xf4,0xf1,0x91,0x67,0xb0, - 0xbf,0xcf,0xff,0x1c,0x0f,0xbd,0x13,0x97,0x0d,0x38,0x6a,0x94,0xb4,0x88,0x34,0xad, - 0x7a,0x23,0x4d,0x1f,0xdf,0x35,0x1d,0x97,0x79,0x15,0xfa,0xd9,0x89,0xab,0x4f,0x6a, - 0x4d,0x97,0xf8,0x3c,0x12,0xd8,0x8e,0xb9,0xd0,0x81,0xab,0xce,0xb9,0x7b,0xd0,0x97, - 0x9d,0x08,0xc3,0xd1,0x89,0x4b,0x9d,0x10,0xda,0xf7,0xc6,0xae,0xcb,0xf0,0xa9,0xc6, - 0x4a,0x00,0x06,0x7e,0x33,0xb4,0x9c,0x4c,0xd5,0x2e,0x4d,0xb1,0x77,0xd6,0x26,0xea, - 0xdd,0xbb,0x8c,0xb2,0xea,0x96,0x0d,0xbc,0x17,0x86,0x5c,0xcb,0xde,0x4f,0x7e,0xee, - 0x3a,0x4d,0xb3,0x40,0x9d,0xb6,0x10,0x2d,0xca,0x19,0xb2,0x81,0x89,0x46,0x29,0x98, - 0xeb,0x19,0x61,0x4b,0x9c,0x55,0xe7,0xd5,0x3f,0xbf,0x7d,0xab,0x16,0x8d,0x5d,0x23, - 0x4b,0x83,0xcf,0x98,0x20,0x3b,0x6f,0xe2,0x0b,0x38,0xb7,0x67,0x67,0x71,0xa9,0x81, - 0x18,0x2e,0xbb,0x0c,0xc3,0x0a,0x61,0x0a,0xb6,0x54,0x08,0x92,0xca,0x87,0x83,0xd1, - 0xa4,0x86,0xe5,0x68,0x4d,0xe4,0xe1,0xb5,0xc2,0x9e,0x3c,0x33,0x9c,0xef,0x92,0x48, - 0xe3,0x85,0x8f,0xc5,0xde,0x40,0x82,0xa2,0xb9,0xcc,0x62,0x5e,0x25,0x38,0xca,0xf2, - 0x93,0xb3,0xbf,0x4f,0x67,0xee,0x82,0xd6,0xb9,0x6e,0xd9,0x13,0x7c,0xa0,0x57,0x8d, - 0x3e,0x7f,0xcd,0x43,0x9b,0x87,0xf4,0xf3,0x9e,0x5d,0x12,0x45,0xac,0x11,0x15,0xf2, - 0xe6,0x82,0x01,0xa4,0x0a,0xaf,0xb7,0x78,0x92,0x81,0xdc,0xdc,0xbc,0x7b,0xdf,0x81, - 0x9a,0xe0,0x61,0x1c,0x57,0xef,0x4e,0x2b,0x1c,0x4f,0x7a,0x0a,0xaa,0xfc,0x65,0x7e, - 0x19,0x17,0x5f,0x13,0x8a,0xea,0x7b,0xef,0xc3,0xd1,0xd6,0xab,0x8f,0x9e,0x06,0x54, - 0x7d,0x34,0xbb,0xb6,0x86,0x09,0x2d,0x23,0xcf,0x2c,0xbc,0x77,0xcf,0x6a,0xbb,0x89, - 0xf8,0x6e,0x6e,0x5c,0xb7,0xdd,0xd9,0x84,0xeb,0xd6,0x7b,0x9b,0x67,0xf2,0x86,0xd6, - 0x2a,0xcf,0xbc,0xec,0xe0,0x00,0x8f,0x5d,0x9b,0xcd,0x45,0xf4,0x22,0xd3,0xfa,0x2c, - 0x88,0x92,0xe8,0x85,0x55,0x2b,0x87,0x27,0x7b,0x21,0x04,0xca,0xac,0xe1,0xae,0x92, - 0xb2,0xa4,0x3e,0x77,0xcb,0x0c,0xd4,0x28,0x18,0x39,0x85,0xee,0x5b,0x56,0xcc,0x64, - 0xe7,0xe2,0x60,0x3b,0x77,0xf8,0x70,0xd7,0x87,0x26,0xb3,0x0f,0x0c,0x7d,0xa0,0x25, - 0x22,0x1e,0x4d,0xb0,0x81,0x6b,0xa6,0x23,0x9d,0xd1,0x71,0xae,0x0e,0x42,0xd7,0xa7, - 0x36,0xe4,0x05,0x95,0xc7,0xa9,0x64,0x33,0x40,0x52,0x32,0xf0,0xa9,0x3a,0x65,0x74, - 0xd5,0xaf,0x7c,0x3a,0xc0,0xf9,0x39,0x35,0x1d,0x17,0x85,0xcb,0xcc,0x1c,0xcf,0x7d, - 0xab,0x48,0xc6,0x9b,0xb8,0x24,0x29,0xb2,0x64,0x93,0xc4,0xf4,0x4a,0x49,0x76,0xac, - 0xb4,0x1f,0x3b,0xb0,0x13,0xf3,0x58,0x14,0x3f,0x40,0x32,0x1e,0x1b,0x89,0xf9,0x9d, - 0xe8,0x9a,0x4a,0x1b,0x33,0x4b,0x7f,0xe7,0x7e,0x9c,0x7a,0xd7,0xaf,0x5f,0x04,0xea, - 0x91,0x36,0x2d,0xc9,0x16,0xb9,0x4b,0xaf,0x6f,0x6e,0xd0,0xbd,0x74,0xfc,0xc4,0x81, - 0x27,0x81,0xd2,0x2e,0xc1,0x7a,0xca,0x56,0xb0,0xa8,0x10,0xd2,0x6f,0xac,0xa3,0x4c, - 0xd5,0x03,0xe7,0x07,0x9a,0xa8,0xe9,0x56,0xd9,0x9b,0xd9,0xba,0x21,0xdc,0xc1,0xae, - 0xcd,0x99,0x8f,0xa3,0xd8,0x40,0xe6,0x50,0x66,0x69,0x45,0x18,0x33,0x40,0x0a,0x91, - 0x95,0xcb,0xfc,0x12,0xa4,0x2b,0x35,0x96,0x67,0xb4,0x26,0xbd,0x90,0x20,0xec,0xc3, - 0x72,0x83,0x36,0xc0,0x3e,0x70,0x59,0xb6,0x95,0xc0,0xe5,0x1d,0xcd,0x4e,0x63,0x8c, - 0x78,0x26,0x7c,0x50,0xc3,0x78,0x98,0xe6,0x58,0x16,0x45,0x8f,0x85,0x2d,0x61,0x45, - 0x55,0x09,0xf1,0xf8,0xa8,0x04,0xff,0x42,0x9c,0x16,0xd8,0x38,0x61,0x0f,0x85,0x40, - 0x2f,0x52,0x78,0x92,0xc0,0xb6,0x94,0x71,0xac,0x89,0x60,0x0e,0x16,0x5c,0x85,0x67, - 0xe6,0x9f,0xcc,0xd6,0x96,0x57,0x70,0xd5,0x2f,0x14,0xb3,0x65,0xd6,0x1f,0x1f,0xfa, - 0x40,0xe1,0xbc,0x03,0x9a,0x34,0x0e,0xc3,0x67,0x04,0xf5,0x12,0xc6,0x80,0x9d,0x27, - 0x76,0x5a,0xed,0x84,0x3c,0x05,0x6b,0x22,0xc3,0x19,0xb1,0xbc,0xf3,0x38,0xa0,0x8d, - 0x8e,0x8b,0xea,0x29,0xb3,0x9c,0x7d,0xd5,0x35,0x35,0x16,0x64,0xd4,0xe8,0x29,0xf1, - 0x13,0x34,0x63,0x6e,0x43,0x7d,0x0a,0x58,0x4c,0x7a,0x09,0x28,0x88,0xe6,0xf3,0xbe, - 0x4b,0x84,0xc5,0x1c,0xfc,0x6a,0x17,0xc9,0x2b,0x1c,0x23,0xf1,0x10,0x6c,0x4c,0xe8, - 0xf7,0xeb,0xb1,0x0d,0xaa,0xa1,0x77,0x38,0x1a,0x0e,0x87,0x5e,0x0d,0xbd,0xe5,0x71, - 0x78,0x74,0x82,0x19,0x11,0x90,0x63,0x07,0xdd,0x83,0xf2,0x80,0xce,0xc8,0x58,0x5e, - 0xfd,0xfa,0x6f,0xff,0xcb,0xf5,0x0d,0x70,0x09,0x58,0xe3,0x0f,0xba,0x36,0x27,0xdc, - 0xac,0x96,0xc7,0xfc,0x04,0xfb,0x78,0x5f,0x44,0xa9,0xf5,0x5e,0xc8,0x9f,0x5e,0x53, - 0xc2,0x35,0xa6,0x0c,0x1a,0xf2,0x1f,0xf2,0x88,0xb6,0xcd,0x65,0x7e,0x46,0x30,0xd5, - 0xd7,0x38,0xb9,0x6e,0xea,0xfa,0xd6,0x3e,0x9a,0x9b,0xb6,0xed,0x5c,0x43,0x91,0xf6, - 0xf4,0x32,0x6e,0x15,0x17,0xcd,0xfe,0x73,0xb3,0x58,0x49,0x0c,0xca,0x0a,0x47,0x50, - 0xb6,0xc9,0x36,0xcc,0x0e,0x38,0x17,0xd0,0x9a,0x82,0xab,0xcf,0xcf,0x71,0xfc,0xcf, - 0xe9,0xe4,0xb2,0x9a,0x85,0x80,0x1c,0xce,0x54,0x95,0x36,0xe4,0xf9,0xcc,0xc7,0x53, - 0x3b,0xd1,0xbc,0x36,0xdd,0xf9,0xea,0xbc,0xd5,0x52,0x04,0xe3,0xa9,0x65,0x9c,0x36, - 0x61,0xba,0x5c,0x23,0x22,0x81,0xd9,0x2f,0x60,0x25,0x3e,0x29,0x7c,0x1c,0xd4,0x59, - 0x82,0x88,0xa3,0x75,0x7f,0x12,0x40,0x80,0xd8,0x01,0xcb,0x4c,0x2a,0x16,0x0b,0xcb, - 0x52,0xaa,0x4f,0xa4,0xe6,0xfb,0x59,0xa2,0xe2,0x93,0x30,0x87,0x35,0x11,0xf8,0x48, - 0x6c,0x89,0xc4,0x29,0x16,0x1c,0xc4,0xe0,0xf4,0x95,0x5c,0xf5,0xa7,0x22,0x3e,0xa3, - 0x05,0x2b,0xae,0x82,0xa5,0xb6,0x4c,0x5e,0x79,0xb5,0x68,0x90,0x08,0x0e,0x40,0x83, - 0xdc,0x1e,0x9d,0xee,0xd5,0xba,0x2a,0x1b,0xcc,0x7f,0xf5,0x4a,0x0e,0x2e,0x42,0x76, - 0x68,0x33,0xb4,0x38,0x73,0xef,0xde,0x0a,0xe0,0xa0,0x05,0x43,0xd9,0x9c,0xef,0x10, - 0x06,0xa2,0x4a,0x9c,0xb8,0x5a,0x2f,0x4b,0x28,0xd5,0x98,0xe2,0x68,0xc7,0x50,0x8d, - 0xed,0x5a,0x1d,0x55,0x58,0x34,0x1e,0xbb,0x62,0xaf,0x59,0x2c,0x5c,0xe9,0x42,0x38, - 0x4e,0x15,0xe8,0xa5,0xca,0xf2,0x17,0x91,0x3f,0x9b,0x5c,0x9d,0x2e,0xb0,0xbf,0x5f, - 0x0b,0x5b,0xde,0x09,0x1f,0x14,0x37,0x12,0x85,0x1e,0x4d,0x1b,0x28,0x15,0x8b,0x8f, - 0xa5,0x00,0xf2,0x53,0x78,0x1b,0x96,0xe3,0x32,0x07,0xbf,0x51,0xca,0xf2,0x28,0xac, - 0xe8,0x32,0x6f,0x26,0xc4,0xa5,0xa3,0xf9,0x6b,0x39,0xae,0xf5,0x9b,0x49,0x5b,0xd0, - 0xe3,0xa0,0x39,0x44,0x68,0x6d,0x32,0x7a,0x87,0x48,0x9a,0x3d,0x8d,0xdd,0x65,0xb2, - 0xd0,0x3c,0x32,0x40,0x91,0x30,0x90,0xb2,0x14,0xab,0xc1,0x95,0x86,0x60,0x20,0x58, - 0xbc,0x77,0xe2,0x4c,0xcc,0xc0,0x11,0x6d,0x76,0x45,0x42,0x2b,0xc0,0x8b,0x11,0x72, - 0x94,0xa4,0x25,0xdb,0xb7,0xb1,0x66,0x0e,0xcb,0xa9,0x8c,0x84,0x01,0x51,0x50,0x5f, - 0xf3,0xfc,0x7a,0xb5,0xbf,0x20,0x90,0x73,0x81,0xd8,0x99,0x1e,0x58,0xb4,0x05,0x0c, - 0xd0,0x5a,0x1b,0x8d,0xf6,0x36,0x6b,0x48,0x29,0x59,0xa5,0x54,0xd3,0xb0,0x6d,0xe9, - 0x53,0x22,0x66,0x0f,0xcb,0x52,0xbe,0x48,0x3e,0x30,0x2c,0xda,0xb0,0x23,0x8a,0xe5, - 0x37,0xd4,0xf1,0x95,0x41,0x01,0x6a,0xf9,0x14,0x0f,0xc6,0x9e,0x42,0xcd,0x85,0x25, - 0x0a,0xcf,0x01,0x74,0xd7,0x40,0x6b,0x2e,0xbb,0x1b,0x89,0x38,0x8c,0x01,0x5b,0x8e, - 0x53,0x7c,0x2a,0x8a,0x2b,0xe9,0x3d,0x3a,0x83,0x2d,0x9c,0xa3,0x6a,0x56,0x39,0xb4, - 0x34,0x84,0xee,0x40,0xc6,0x4d,0x4c,0x14,0xf3,0x2c,0x8c,0x4c,0xd0,0xea,0xa2,0xa1, - 0xf9,0x56,0xfa,0x08,0x7d,0xcc,0x94,0x62,0x2d,0x29,0x2d,0x8c,0x20,0x8e,0x07,0x49, - 0xc9,0x54,0xd1,0xb4,0x6d,0xc3,0xbf,0x58,0x88,0x08,0xa1,0xe5,0xff,0x25,0x89,0x2f, - 0xfb,0xd7,0x6c,0x0d,0x23,0x99,0x88,0xb0,0x1c,0x1d,0x65,0xb7,0x21,0x88,0xf2,0x60, - 0x26,0x86,0xaf,0x80,0x8e,0x01,0x06,0x31,0x07,0xb2,0xa1,0x62,0x93,0x7d,0x75,0xc2, - 0x11,0xb6,0x46,0xc0,0xce,0x64,0x10,0xda,0x52,0xde,0x46,0xb4,0x53,0x24,0xb1,0xf6, - 0xdc,0x71,0x40,0x74,0x1c,0x09,0x02,0x13,0x5a,0x08,0x76,0xe3,0x05,0x97,0x17,0x66, - 0x8d,0x75,0x51,0x6f,0xe2,0x5f,0xda,0x74,0x10,0x70,0x20,0x3b,0xa3,0x0b,0x10,0x37, - 0x72,0x16,0x57,0x7d,0xb7,0xa1,0x9c,0x71,0xfd,0x6b,0x15,0xbe,0x36,0x1e,0x11,0x92, - 0x1f,0x6e,0x3b,0x02,0x1f,0x35,0xef,0x55,0x77,0xed,0xf1,0x52,0x1b,0xba,0x63,0x18, - 0x2a,0x67,0x67,0x78,0xf2,0x76,0x51,0x36,0x0e,0xf2,0x3c,0xd0,0x58,0xa1,0x6f,0x91, - 0xc1,0x79,0xb0,0x28,0xe2,0x98,0xa8,0xdf,0xd1,0x03,0xf0,0x7f,0xbf,0x7b,0xea,0xe0, - 0xd9,0x25,0xd9,0x49,0x6f,0x26,0x70,0xac,0xaa,0xa9,0xb9,0xbb,0x1a,0x87,0x99,0x46, - 0xad,0x91,0x10,0x65,0x81,0x69,0xb0,0xf8,0xe6,0xed,0xab,0x97,0xa1,0x5b,0xd7,0xf9, - 0x1e,0x6a,0xd2,0x67,0x7c,0x6e,0x79,0x94,0xde,0xc4,0x71,0x18,0xf3,0x5e,0xc2,0xcf, - 0xb6,0x1c,0x43,0x3f,0x40,0x27,0x13,0xaa,0x2e,0xa8,0x60,0x0a,0x6c,0x1b,0x47,0xa3, - 0x11,0x98,0x9c,0xd1,0xf9,0xe0,0x76,0xe6,0x81,0x5e,0x44,0xe2,0xcb,0x09,0x6c,0x89, - 0xad,0x2f,0xb0,0xb1,0xe0,0xc8,0x77,0x19,0xfc,0xb5,0x5a,0x47,0xa1,0xff,0x69,0x12, - 0x1a,0xfd,0x23,0x22,0x99,0xaa,0x58,0xa9,0x20,0xa1,0x51,0x74,0xd5,0x0c,0x78,0xd1, - 0xd7,0x01,0xdc,0xf5,0x3e,0xd0,0xd1,0x99,0xb3,0xaf,0xc3,0x45,0xec,0xa5,0x89,0x85, - 0x5f,0x5d,0x85,0x76,0x75,0xcb,0xd9,0xad,0x0d,0x43,0xc9,0x4b,0x4d,0xdb,0xf8,0xdc, - 0xa5,0xba,0x59,0x63,0x6b,0x54,0x77,0x07,0xa3,0x46,0x9b,0xab,0x4f,0x36,0xba,0x6a, - 0xb4,0xba,0x72,0xf1,0xa6,0xd9,0x2e,0x9c,0xe1,0x75,0xa3,0xf8,0x88,0xc8,0xbf,0xd0, - 0x85,0xae,0xc1,0xb5,0x5e,0x77,0x48,0xc6,0x28,0xa2,0x97,0xc1,0x97,0x76,0xbc,0xad, - 0x3d,0xbc,0xea,0xec,0x53,0xc3,0x53,0x85,0xab,0x33,0x7b,0x94,0x55,0x74,0x46,0x62, - 0xc7,0x3a,0x10,0x09,0xe4,0x84,0x45,0x11,0x10,0x03,0xbb,0x78,0x73,0x0a,0xba,0xa4, - 0x92,0x59,0xc6,0x4a,0x29,0xe0,0x36,0xb6,0x4b,0x3e,0x9a,0xdd,0x56,0xfc,0xde,0xe5, - 0xed,0xfb,0x0d,0xcb,0x0f,0x75,0x5a,0x5e,0xda,0x83,0x2b,0x2f,0x4d,0xab,0xd2,0xc2, - 0xec,0xd6,0x06,0x58,0x91,0x46,0x0d,0xcc,0x02,0x36,0x97,0xb9,0x5a,0xc1,0xe8,0xd2, - 0x1b,0xbb,0xc5,0x38,0xb5,0x9a,0x6c,0xca,0x94,0x66,0x6e,0x54,0x85,0x76,0x80,0xd1, - 0x54,0x58,0x4b,0x8a,0x75,0x35,0x1a,0x24,0x89,0xeb,0x44,0x00,0xbf,0x26,0x52,0x36, - 0x47,0x9c,0x30,0x01,0xa3,0xfd,0xa6,0xbc,0xf4,0xea,0xd2,0x2a,0x20,0xe1,0x0c,0xf4, - 0x2d,0xd4,0xe4,0xa0,0xfe,0xd4,0x39,0x00,0x53,0xe2,0x32,0x29,0xe2,0x67,0x54,0x9b, - 0xd0,0x8e,0x69,0x72,0x1b,0xd3,0x61,0x6d,0xad,0xec,0xfa,0x53,0x9b,0x5f,0xae,0x95, - 0x6a,0x4b,0x02,0x56,0x5d,0xf8,0x11,0xb8,0x3b,0xe3,0x5e,0xd7,0x9d,0xec,0x99,0x21, - 0xda,0x25,0xb2,0x9d,0xb9,0x66,0xab,0x9d,0x57,0xd5,0x99,0xf7,0x71,0x60,0x68,0x95, - 0x07,0xaf,0x5b,0xd0,0x0c,0x7d,0xac,0x8e,0xb7,0xd3,0x9c,0xf9,0x2c,0x58,0xca,0x6b, - 0x82,0xc4,0xf4,0xd6,0x99,0x0b,0x9d,0xa3,0xb9,0x4f,0x6d,0x08,0x98,0x03,0x02,0xa6, - 0x4d,0x7d,0x9b,0x28,0xb1,0x2c,0xc0,0x98,0x76,0x1d,0x41,0x2a,0x65,0x26,0xa3,0x8e, - 0xa0,0x3f,0xad,0x0f,0xe1,0xce,0xb4,0xa6,0x1d,0x8b,0xc9,0xd8,0xd8,0x2e,0x64,0xf6, - 0x75,0xab,0xfe,0xa5,0x2f,0x4a,0xe3,0xe5,0x74,0x28,0x85,0x08,0xdd,0xca,0x23,0x54, - 0x0c,0xbe,0x63,0x1e,0xdf,0xc4,0x17,0x37,0x37,0x43,0x5f,0x28,0xaf,0xcf,0x5c,0x87, - 0x6a,0xa3,0xad,0xea,0x20,0xda,0x36,0x03,0x53,0xd5,0x6f,0x4b,0x64,0x16,0xd1,0xaa, - 0xa1,0x94,0x49,0xdc,0x8c,0x99,0x32,0xd0,0x1d,0x26,0xce,0x5a,0xde,0x67,0x86,0x82, - 0xcd,0x35,0x34,0x00,0xc5,0x33,0x58,0x6a,0x85,0x36,0x0d,0xf5,0xae,0x1b,0x44,0x9a, - 0xe5,0xe0,0x7e,0x53,0x81,0xad,0x0a,0x68,0xce,0xe1,0x75,0x0e,0x8e,0x95,0x0b,0x2a, - 0x06,0xa2,0x36,0xae,0xf0,0x00,0x30,0x9c,0x71,0x3d,0x9e,0xa4,0xb4,0x78,0x98,0x52, - 0x15,0x8c,0xca,0x73,0x25,0x3f,0xa3,0x9d,0x9a,0x22,0x5b,0x5c,0x1c,0x0f,0x44,0xb1, - 0x6f,0xaa,0x94,0xa5,0x42,0xd3,0xf5,0xf4,0xa2,0x40,0x9f,0x21,0x71,0xfd,0x79,0x76, - 0xaa,0x02,0xd3,0xe5,0xb5,0x95,0x08,0xa0,0x7f,0x5f,0x8b,0xaf,0xf4,0x9e,0x43,0xf3, - 0x9b,0x1c,0xc7,0xa1,0xda,0x37,0xd7,0x3f,0x22,0x86,0xc3,0xef,0x62,0x34,0xe6,0x5e, - 0xd7,0xf6,0x1b,0xfd,0x12,0x36,0xbf,0x50,0xbb,0x6e,0xb6,0x7b,0xeb,0x5f,0xf3,0xac, - 0xc7,0xc2,0x0e,0x7a,0xb6,0x39,0x80,0x44,0xeb,0x01,0xa8,0x88,0xd8,0x9d,0x8a,0x73, - 0x28,0x1a,0x72,0xf8,0xd7,0xa9,0xd0,0x2c,0x44,0x42,0xc3,0xff,0xeb,0x3c,0xcb,0xa7, - 0x0e,0x26,0x0f,0xae,0x38,0x17,0xb9,0x2f,0x9a,0x7a,0xac,0xcf,0x17,0x59,0x2f,0x76, - 0xca,0x25,0x71,0x7d,0x73,0xc5,0x92,0xf9,0xda,0x91,0x88,0xf6,0x63,0xa0,0xdd,0xd7, - 0x6b,0xa5,0x10,0x6b,0x3d,0x13,0xd6,0xc8,0x89,0x89,0x88,0x7f,0x3f,0xa9,0xa0,0x0e, - 0x34,0x9b,0xa0,0x97,0x12,0x0a,0x45,0x9a,0xc7,0x32,0x2a,0x4f,0x97,0x34,0xb2,0x90, - 0x33,0x52,0xac,0x95,0x42,0x8d,0x89,0xdf,0xf7,0x0b,0xc2,0x69,0xf8,0xe6,0x7a,0xc7, - 0xa2,0x51,0x6c,0x30,0x65,0xfb,0xfb,0xf7,0x14,0x14,0x79,0xc2,0xfc,0x69,0x2d,0x44, - 0x14,0x96,0x8a,0x75,0x50,0x75,0xca,0x40,0x49,0x09,0x37,0x37,0xf7,0xa2,0x9b,0x9b, - 0x88,0x98,0x0b,0x77,0xe0,0x5a,0x1b,0xcf,0xc2,0x8b,0x72,0x89,0x58,0xb2,0x54,0xbd, - 0x16,0x67,0x18,0xc4,0x1a,0xb1,0x8a,0x9f,0x06,0x7e,0x15,0x57,0x63,0x48,0x50,0xae, - 0xf8,0xfd,0x8b,0x5b,0x9d,0xac,0x2e,0x04,0xd5,0x40,0xfa,0x92,0x39,0xef,0xef,0x47, - 0xd0,0xbe,0xaa,0xdf,0x96,0xbe,0x43,0x2f,0xc9,0x63,0x30,0x9f,0xd6,0x08,0xac,0x65, - 0xd3,0xd3,0x58,0x26,0x55,0xcd,0x53,0xde,0x6a,0x56,0x02,0xfb,0xb4,0xcb,0x7d,0x11, - 0xae,0xa9,0x95,0x2f,0xc4,0xce,0x10,0xbe,0x6a,0x54,0xed,0xbb,0x01,0x31,0x2d,0xde, - 0xa4,0xa1,0x83,0xa5,0x0e,0x69,0x4d,0xef,0x65,0xab,0xfd,0xfd,0x16,0x37,0x13,0x86, - 0x11,0xaf,0x76,0x93,0x86,0x85,0xe1,0x3d,0xbd,0xd0,0xdf,0x96,0xaf,0x2c,0x72,0x26, - 0x6a,0x58,0x8c,0xbf,0x46,0x2f,0x9a,0x89,0x63,0xa5,0x47,0x95,0x9f,0x9d,0xa5,0xa2, - 0xf4,0xf0,0xa9,0xa4,0xd6,0xd6,0x0a,0x04,0xff,0xfa,0xef,0xff,0x46,0xff,0x39,0xaf, - 0x11,0x40,0xd8,0x97,0x4d,0x91,0xac,0x0c,0x9e,0xfa,0xf4,0x9f,0xf5,0x1f,0x06,0x77, - 0x0a,0xc7,0x6c,0x3a,0xa7,0x22,0x41,0x36,0x4c,0xb1,0x2e,0xcb,0xab,0x03,0x19,0xb1, - 0xb6,0xa6,0x22,0x4b,0x83,0x84,0xba,0x29,0x59,0x8f,0xc5,0xdd,0xd2,0x9c,0x2e,0x3a, - 0x4f,0x24,0x28,0x69,0x7f,0x73,0x06,0xbc,0x75,0x5c,0x40,0xa8,0x83,0x04,0xea,0x1b, - 0xdd,0x86,0x40,0x4a,0x69,0x59,0x86,0x95,0x26,0x19,0x2d,0x01,0x54,0x89,0x13,0xcf, - 0xc4,0xbf,0x9d,0x31,0xb7,0x96,0x00,0x97,0xc9,0xd9,0x92,0x93,0xd9,0x48,0xac,0x8a, - 0x93,0xaf,0x49,0xfc,0x49,0xe0,0x2c,0xc7,0x7e,0x58,0xe8,0x58,0x0e,0x0f,0xda,0xb9, - 0x40,0x9e,0x03,0x08,0x63,0x74,0xea,0x0a,0x58,0xee,0x18,0x15,0x5b,0x62,0x30,0xb3, - 0xa6,0xc2,0x98,0xf2,0x86,0x5c,0x6b,0x29,0x54,0xe6,0xc1,0xd8,0x20,0x87,0xa2,0x9b, - 0x3e,0x36,0x55,0x75,0x86,0x58,0x48,0x4e,0x90,0x16,0x8a,0x14,0x73,0xcb,0x89,0x70, - 0xfe,0xee,0x81,0xf4,0x70,0x3d,0x23,0x90,0x8e,0x61,0x8b,0x1b,0x40,0x20,0x8a,0x49, - 0xf0,0x64,0x48,0xda,0xcd,0x25,0xa2,0x68,0x4a,0x9d,0x19,0xa4,0xab,0xdc,0xdc,0x70, - 0x25,0xb0,0xa8,0xcc,0x91,0x7a,0x84,0xe5,0xf2,0x79,0x10,0x23,0xf7,0xc8,0xcd,0x8d, - 0x9a,0x84,0x92,0x4e,0x9b,0x54,0x4e,0x7a,0xd0,0xc4,0x5d,0x1d,0xd6,0x39,0x33,0x06, - 0x37,0x37,0xcc,0xe9,0x1b,0x5c,0xd7,0x54,0xbc,0x1a,0xca,0x9a,0x21,0x20,0x52,0x70, - 0xf2,0x98,0x56,0x48,0x8a,0xfb,0xd0,0xd2,0xdb,0xe2,0xe4,0x5f,0x7c,0xd0,0xa1,0xf4, - 0x8d,0x6f,0xd3,0x27,0x6e,0x3d,0x5b,0x6c,0x80,0xa4,0x17,0x7e,0xa4,0x79,0x27,0xb0, - 0x44,0x07,0x14,0xee,0xee,0xcd,0xf0,0x40,0x40,0x76,0x70,0x0d,0xfe,0x96,0x38,0xb0, - 0xa6,0x85,0xd4,0x1f,0x0d,0x3d,0xc2,0x0e,0x4a,0xb2,0xf2,0x8c,0xba,0x59,0xf1,0x6b, - 0xb7,0x69,0x90,0x6d,0xde,0xa8,0x8b,0x77,0x51,0xeb,0xa8,0x14,0xe8,0x6c,0x74,0x96, - 0x43,0xd5,0xd8,0xab,0x1d,0x44,0xf2,0x44,0xe4,0x59,0xa7,0xcf,0x3e,0xd4,0x98,0x98, - 0x2f,0x9e,0x15,0xb5,0x07,0xd1,0xdf,0x15,0xb3,0xb0,0x35,0x11,0x62,0x80,0x52,0x4b, - 0x3d,0xfb,0xf6,0xf4,0xf5,0xcb,0x27,0xff,0x22,0x3d,0xd9,0xf9,0x54,0x80,0x30,0xf0, - 0x4e,0xc7,0x6c,0x28,0x69,0xda,0xe9,0x6b,0x8a,0xca,0x36,0xf9,0xa5,0x26,0xdb,0x29, - 0x8c,0x07,0xda,0xa3,0x93,0x69,0xbf,0x6f,0x62,0x2d,0x7a,0x50,0x62,0x81,0x0a,0x0d, - 0x44,0x2b,0x83,0xb5,0xf9,0xbe,0x48,0x68,0x08,0x3d,0xd5,0x3a,0xda,0x9a,0xa5,0x79, - 0x89,0x98,0xbd,0x32,0xcd,0x91,0x68,0x06,0x31,0x67,0x73,0x2f,0xd0,0xce,0x2e,0xc4, - 0x79,0x7b,0xce,0x26,0x1b,0xa8,0x61,0x18,0x5c,0x73,0x59,0xb0,0x7e,0x11,0xb8,0x88, - 0x1b,0x21,0x12,0x90,0xe6,0x24,0x2a,0x7e,0xa8,0x94,0x22,0xce,0x28,0x95,0x94,0xb2, - 0x2e,0x34,0xa3,0x3c,0xf2,0x1b,0xbe,0x26,0xa8,0xde,0xa1,0xcd,0x8d,0x3f,0xac,0x09, - 0x0e,0x15,0x9a,0xe4,0x16,0xaa,0x82,0x86,0x94,0x62,0xdc,0x45,0xbe,0x39,0x5b,0x8a, - 0x9a,0xae,0x20,0x0a,0x0e,0x27,0x67,0xd1,0xf9,0xa9,0xb6,0x96,0x62,0x4c,0xfa,0xc3, - 0xe0,0xf5,0x8b,0x01,0xb8,0xfe,0x71,0x63,0x7c,0xc0,0x82,0x04,0x30,0xf3,0x78,0x4e, - 0xf8,0x0e,0x64,0x5c,0x63,0x6e,0xe1,0x55,0xe6,0x6a,0x97,0x84,0x5b,0xc9,0x8d,0x92, - 0x44,0x93,0x5d,0xf4,0xf1,0x83,0xd2,0x8a,0xc8,0x4e,0xb1,0x6e,0x53,0x2b,0x5c,0xa1, - 0xe3,0x14,0x9e,0x74,0x46,0xe3,0x24,0xba,0xb0,0x82,0x33,0x85,0x30,0xcf,0x6c,0xd3, - 0xd7,0xb6,0x27,0x0b,0x83,0x2a,0xe5,0x29,0x4c,0x65,0xfc,0x33,0xac,0x7b,0x25,0xe6, - 0xe4,0x5e,0xad,0x6b,0xdd,0x36,0x14,0xd7,0x96,0x02,0x87,0xe8,0x25,0xce,0xa0,0x35, - 0xda,0x3c,0x33,0x3a,0xd9,0x3d,0xe3,0xba,0xd4,0x72,0x6f,0xc8,0x33,0x36,0x35,0x2a, - 0xbf,0x06,0xab,0x71,0x6e,0x47,0x99,0x3e,0x85,0x35,0x6e,0x76,0x27,0x0c,0x67,0x2d, - 0xaa,0xf0,0x21,0x94,0xc5,0x98,0x29,0x83,0xa9,0xac,0x72,0xe5,0xc8,0x42,0x11,0x9b, - 0xd4,0xc6,0xfa,0xea,0x38,0x4a,0x88,0x42,0x9f,0x9d,0x72,0x58,0x59,0xef,0xc3,0xfa, - 0xf8,0xf5,0xe9,0xa9,0x37,0xe6,0x60,0xa1,0x88,0x60,0x4c,0xc7,0x8e,0x1b,0x85,0x6f, - 0xe0,0xbc,0x52,0xe6,0x77,0x38,0x8e,0x40,0x4f,0x9b,0x9c,0x6d,0xf2,0x8d,0xad,0xd8, - 0x37,0x52,0xe3,0x66,0x5d,0xfb,0x15,0x7c,0x5a,0x56,0x84,0x05,0xa8,0x25,0x2e,0x3a, - 0xab,0x8b,0xb6,0xc4,0xb8,0x59,0x9f,0xb8,0x34,0x72,0x5a,0x3b,0x1a,0xbc,0x78,0x4d, - 0x20,0xc3,0xd7,0x93,0xaa,0x2a,0x12,0x6a,0x8a,0x30,0x6d,0x54,0x24,0xd1,0x40,0xb4, - 0x1a,0x3e,0x4a,0x33,0x73,0xb8,0x81,0xee,0x9f,0x7f,0xc1,0xa6,0xab,0x7b,0xeb,0xf6, - 0x83,0x50,0x82,0x7d,0x32,0x45,0x67,0xc4,0x27,0xad,0xe9,0x04,0x26,0x34,0x45,0x35, - 0x64,0x65,0x83,0x1b,0xd3,0x17,0x68,0x47,0x9b,0x6f,0x0d,0xc3,0x75,0x8f,0xea,0x13, - 0x04,0xd1,0xdf,0xa6,0xdb,0x50,0xcd,0x62,0x5a,0x2a,0x42,0xcb,0xe0,0xc7,0xcb,0x76, - 0x42,0xd5,0xc6,0xa8,0xda,0xb6,0xf9,0x61,0xd0,0x0b,0x5a,0x48,0x23,0xa7,0x36,0xc1, - 0xc5,0x58,0xdf,0x14,0x05,0x9e,0x36,0x40,0x4b,0x80,0x46,0xef,0x48,0xf1,0x31,0xda, - 0xf3,0x0e,0x63,0x1e,0x60,0xc0,0xef,0x95,0x32,0x9a,0x78,0x54,0xd4,0x4a,0x88,0xf1, - 0x4f,0x1e,0x17,0xda,0xd7,0x23,0x39,0x38,0x50,0x4b,0x56,0xbc,0x4b,0xde,0xef,0xf0, - 0xb4,0xb4,0x7d,0x5e,0x6d,0x5f,0x49,0xb4,0xc7,0x4c,0x57,0x69,0xee,0x98,0x2b,0xbc, - 0x1b,0xbd,0x6f,0xd6,0xd1,0xbd,0x0d,0x46,0xc6,0x68,0x6e,0xe6,0x64,0x6b,0x69,0x44, - 0xd9,0x0c,0x1a,0xf6,0x1c,0xf1,0xc7,0x20,0x68,0x71,0x46,0x90,0xe8,0x02,0x94,0x59, - 0x96,0x74,0x7d,0x5b,0xa9,0xa0,0xb1,0x4d,0x9a,0x4c,0x1a,0xdc,0x30,0x13,0x41,0x7c, - 0xd5,0x14,0xfb,0xd6,0x46,0x69,0x45,0x1b,0x4d,0xee,0x72,0xd6,0x9a,0xfc,0x4b,0x73, - 0x8d,0x6d,0xff,0xdb,0x59,0x0a,0x95,0x57,0x43,0x0f,0xf3,0x13,0x83,0x45,0x71,0x6b, - 0xb4,0xf1,0x45,0x2d,0xf0,0xde,0xd3,0x6b,0x71,0x73,0x63,0x56,0x25,0xa4,0x75,0x69, - 0x40,0x6b,0x7c,0xc1,0x27,0x81,0xda,0x7d,0x26,0x89,0x29,0xfa,0x5e,0x87,0x28,0x21, - 0x1c,0x84,0x19,0xd9,0x1d,0xc6,0xc5,0xf1,0x4f,0x8d,0x65,0xec,0x5c,0xc1,0xf6,0x6c, - 0x6f,0x69,0x2f,0x5f,0x77,0xcd,0xf1,0x6e,0x63,0xdf,0xed,0x6a,0xf2,0x17,0xad,0x50, - 0xd7,0x79,0xd6,0xa5,0x7d,0xa3,0x6e,0xea,0x38,0xb2,0x06,0x27,0xeb,0x80,0x12,0xd0, - 0x78,0xc4,0x84,0x41,0xd6,0xf0,0x95,0xa7,0x17,0xfd,0x10,0xe3,0x92,0xaf,0xed,0xbf, - 0x1e,0xe3,0x60,0x22,0x5d,0x88,0x98,0xed,0x7b,0xe5,0x98,0x6d,0x3a,0x62,0x81,0x14, - 0xf7,0x53,0xb6,0xdd,0x12,0xd9,0x5b,0x89,0x9d,0x0d,0x4b,0xcd,0x4a,0x88,0x64,0x3e, - 0xe0,0x2e,0xa0,0xa3,0x51,0xea,0x9a,0x60,0x4f,0x53,0xaa,0xdb,0xbd,0xc3,0x58,0x05, - 0xf2,0x29,0xc7,0xca,0x16,0xf6,0xe8,0x06,0x68,0x6e,0x49,0xfc,0x2a,0xe1,0x9c,0xb7, - 0xeb,0x58,0x29,0x05,0x8c,0x41,0x43,0x0c,0x24,0x8a,0x7a,0x2a,0xe2,0xff,0xeb,0x7f, - 0xfd,0x6f,0x5a,0x8a,0x93,0x17,0xfd,0x32,0x66,0x23,0x0d,0x4d,0x6b,0x4a,0x7b,0xe8, - 0x69,0x2f,0x08,0x42,0xa2,0xa1,0xfb,0x99,0x63,0x27,0x01,0x2c,0x36,0x59,0xc6,0x6e, - 0x8d,0xd2,0x12,0x51,0x4c,0xad,0xdc,0xca,0xd8,0x2c,0x6a,0x38,0xa6,0x9f,0x32,0xf7, - 0x40,0xc6,0xf2,0x33,0x31,0x2a,0x7d,0x97,0x9e,0xbd,0x03,0xfc,0x35,0xc4,0xb7,0x94, - 0x35,0xe5,0x96,0x3a,0x45,0x2c,0xda,0x20,0xf6,0x0a,0x51,0xeb,0xeb,0xeb,0x0d,0xeb, - 0xcc,0x2c,0x09,0x93,0xb0,0x45,0x85,0x3e,0x2c,0x8b,0x10,0xe5,0xfe,0xf0,0xea,0xe5, - 0x37,0x55,0xb5,0x7e,0x23,0x5e,0x37,0x1a,0x7a,0xe9,0x6b,0x90,0x13,0x8f,0xd2,0x77, - 0x5f,0xff,0xf0,0x96,0x3a,0x6e,0x9a,0xd6,0xac,0x42,0xb4,0xb8,0xaa,0xea,0x37,0x1c, - 0xe8,0xd4,0x77,0x0d,0x87,0x46,0xd5,0x2c,0x16,0xed,0x0e,0x95,0x5e,0x12,0xdf,0x4b, - 0x95,0x46,0x76,0xd1,0x9c,0xdd,0xa4,0x76,0xe8,0xa8,0xcc,0x41,0xa9,0x51,0x90,0x7c, - 0x64,0x1e,0xfe,0xd3,0xe9,0xf7,0xdf,0x05,0x2c,0xa7,0xf4,0x51,0xb1,0x88,0xcb,0x75, - 0x4e,0xe7,0xe5,0x2d,0xed,0x91,0xb7,0x15,0x11,0x83,0xe6,0xbf,0xad,0x45,0xc3,0xf9, - 0xfe,0xbe,0x12,0x0e,0xbb,0xec,0x66,0xb5,0x65,0xa0,0xe6,0x83,0x98,0xef,0x71,0x6d, - 0x59,0xce,0xca,0xab,0x89,0x71,0xfa,0x5f,0x0d,0x87,0x9e,0xee,0x02,0x2a,0x7d,0xae, - 0x2d,0x3d,0xb1,0xf0,0xe9,0x41,0xfa,0x84,0x34,0xd2,0x25,0x7b,0xaa,0x7a,0x73,0xf6, - 0x3e,0x51,0xd2,0x91,0xbd,0x12,0xdc,0x42,0xf8,0x17,0xcb,0x49,0x13,0x69,0x70,0x6b, - 0xaf,0x7f,0x26,0x40,0xf2,0x34,0xcd,0xa7,0xfd,0x77,0x00,0xe3,0xf7,0x9e,0x42,0x18, - 0xfe,0xf5,0xd9,0x26,0x2a,0xe6,0x63,0xb0,0x83,0x5b,0xaf,0x76,0x9b,0x54,0x32,0x16, - 0x94,0xce,0x0a,0x6d,0xfc,0x27,0x2b,0x69,0x3e,0x26,0x95,0xd9,0x79,0x4b,0xb4,0x5f, - 0x99,0x04,0x49,0x1a,0x27,0x59,0x95,0x42,0x04,0x71,0xfb,0x90,0x90,0x2e,0xa3,0x54, - 0x54,0x82,0x6b,0xc4,0x24,0xd3,0xb1,0x64,0xe1,0xee,0xf9,0xcb,0xe7,0x6f,0x9f,0x6b, - 0x2f,0xb6,0x29,0xd8,0xcb,0x25,0xc7,0xcc,0x55,0x97,0xd0,0xbf,0xc0,0xf4,0x2d,0xe8, - 0x4f,0xb2,0x76,0x82,0xa5,0x65,0xf1,0x88,0x84,0x2f,0x67,0xc6,0xae,0x19,0x2b,0x02, - 0x6f,0xad,0x02,0x52,0x18,0x85,0x00,0x13,0x2e,0x67,0x2f,0x9e,0xbc,0x7d,0x71,0xaa, - 0x9c,0x1c,0x8c,0x0c,0xa1,0x91,0x87,0x0a,0xe2,0x55,0x3e,0x2f,0xc6,0x55,0x3a,0x42, - 0x53,0x3a,0x04,0x94,0x7a,0x5a,0x24,0x8b,0x8a,0x04,0x2e,0x4e,0x2b,0xb2,0x4a,0x32, - 0x62,0x52,0xd9,0x43,0x3e,0xd2,0x1a,0x1a,0xad,0x44,0x2f,0x62,0x22,0x16,0x97,0xb6, - 0x76,0x8a,0xdd,0x71,0xe0,0xf3,0x16,0x9d,0xc7,0xa5,0x29,0xe8,0xab,0x90,0x94,0xd2, - 0x88,0x78,0x1c,0xd6,0x85,0x79,0xad,0x23,0xa4,0x64,0x92,0xe1,0x62,0xfc,0x25,0x7b, - 0x5c,0xc0,0x0f,0x8e,0xa9,0x8b,0x48,0x33,0x4e,0xef,0xf3,0x9e,0x1d,0x6b,0xda,0xd4, - 0xe2,0xeb,0x2d,0x50,0x13,0x18,0xdb,0x8b,0xc2,0x53,0x64,0x65,0x19,0xc4,0x47,0xf6, - 0x22,0x40,0x98,0x9b,0x1a,0x03,0x47,0x02,0xcc,0xaa,0x0d,0x6b,0xb2,0x58,0xb6,0x2a, - 0xcf,0x75,0xf0,0x03,0x47,0x08,0xf0,0xf1,0x8e,0x6b,0x07,0x5e,0x25,0x06,0x63,0x5d, - 0x63,0x38,0xcb,0xfe,0x2c,0xee,0xdb,0x88,0x1c,0x40,0x46,0x06,0xd1,0xc2,0x89,0xa7, - 0x44,0x21,0xb2,0xaf,0x78,0x2e,0xc0,0x8a,0x03,0x5e,0xd4,0xf2,0xb6,0xb4,0x45,0x3a, - 0x06,0x7b,0xdb,0x93,0xd7,0x61,0x69,0x80,0x71,0x92,0xd2,0xc8,0x43,0xeb,0xe0,0x9c, - 0xe5,0xc8,0x46,0xa2,0x3d,0x1d,0x98,0xe6,0xf9,0xb5,0x1b,0x67,0x2c,0xe7,0x15,0xde, - 0x2b,0xca,0x31,0x52,0xf6,0x51,0x0d,0x5e,0xda,0xaa,0x37,0x46,0xfb,0x3f,0x3a,0x0b, - 0x3a,0xb0,0xda,0x71,0x52,0xa5,0xa5,0xd1,0xae,0x8e,0x44,0xb9,0xe0,0xc1,0xb8,0x80, - 0x4e,0x9c,0x1d,0xed,0xd9,0x37,0x92,0x05,0x79,0x69,0x4d,0xfb,0x46,0x6a,0x2f,0x4a, - 0x79,0x51,0xb0,0x03,0x24,0x3b,0x64,0x9d,0x03,0x1a,0x38,0x83,0x4a,0xc2,0xb9,0x74, - 0xc6,0x56,0x10,0x86,0xf2,0x9d,0x51,0x23,0x93,0x8c,0x26,0xd1,0x65,0x74,0x15,0x68, - 0x35,0x7c,0x9a,0x86,0x42,0xc9,0x84,0x9d,0x86,0xbf,0xeb,0xfe,0x3e,0xbf,0x79,0x37, - 0x7c,0x0f,0x1d,0xfc,0xe7,0xee,0xdd,0x22,0x26,0xdc,0x8f,0x38,0x10,0xc3,0x9f,0x37, - 0x4d,0x6f,0x6e,0xa4,0x27,0x6d,0x37,0x68,0xc5,0x4e,0x1c,0x87,0xc3,0x06,0x85,0xa0, - 0xed,0x08,0x61,0x2c,0x66,0x75,0xc8,0x8e,0x0b,0x02,0x7d,0xf5,0xe8,0xff,0x6d,0x26, - 0x93,0x67,0xa8,0x0b,0x6e,0x15,0x1b,0xa5,0xdc,0x08,0xfb,0x62,0x58,0xc4,0x12,0xb8, - 0xce,0x81,0xec,0x3f,0x81,0x81,0xc6,0xdf,0xed,0xa0,0x00,0x27,0x74,0x2c,0x1b,0x13, - 0x13,0xe7,0x4e,0xbd,0xa8,0xb2,0x56,0xfa,0xd7,0x88,0xcb,0xc8,0xe7,0x63,0xf7,0xf5, - 0xf7,0xa7,0x44,0x77,0x11,0xaa,0x3c,0x6e,0x33,0x09,0x7f,0x2f,0xed,0x68,0xed,0xe9, - 0x38,0x31,0x6f,0x5a,0x21,0x0d,0x96,0xa7,0x8b,0xad,0x4d,0x35,0xb4,0x91,0xc0,0xe1, - 0x5b,0xf6,0xe2,0xb9,0x42,0xf8,0xc8,0x86,0x90,0xc0,0x8a,0x83,0x4e,0xcd,0xc1,0x17, - 0xb7,0xc5,0x78,0xb5,0xae,0x12,0xed,0x6b,0xd8,0x48,0x33,0x1c,0x58,0x86,0xd6,0x5b, - 0xb9,0xbe,0x40,0x6d,0xc8,0x2e,0x6c,0x60,0xd2,0x1d,0x6c,0xb6,0x2a,0xbf,0x6d,0x51, - 0xf1,0x5a,0x01,0xac,0x08,0xd8,0xed,0x0a,0xe0,0xb6,0x95,0x57,0x3c,0xbd,0xe7,0xaa, - 0x87,0xb9,0xed,0xde,0x6d,0x5e,0xb6,0xdc,0xbc,0xd5,0x5b,0xdb,0x87,0x62,0x1e,0xc0, - 0xa9,0x1b,0x22,0xb7,0x76,0xf2,0x36,0x6f,0x94,0x9f,0xf7,0x02,0x0e,0x43,0xae,0xad, - 0x4f,0xae,0x7c,0x53,0xe6,0x84,0xc7,0x39,0xde,0x55,0x25,0x6b,0xdc,0x23,0x94,0x85, - 0xb3,0x62,0x2d,0xa8,0xa8,0x58,0xb3,0xac,0xf5,0x66,0x36,0x56,0xd1,0xc5,0x37,0x4c, - 0x75,0x3c,0x9d,0xa6,0xab,0x6e,0x49,0x23,0x6c,0x76,0xb4,0x96,0x3c,0x03,0xda,0x41, - 0xcd,0xb2,0xd8,0x0a,0x0a,0xd3,0xe3,0xec,0xe0,0x82,0xb4,0x76,0x57,0x60,0xb0,0xdb, - 0x3c,0xdd,0x05,0x83,0xff,0x4f,0xe1,0xe0,0x16,0x00,0xbf,0x23,0x1f,0xa5,0x66,0xd4, - 0xe4,0x90,0x58,0xc0,0xd2,0xed,0x7e,0x4a,0xc0,0x69,0xc5,0xb9,0x28,0xab,0xe5,0x3d, - 0x1b,0x79,0xb6,0x02,0x3d,0x3e,0x12,0xfb,0x44,0x7b,0x65,0x32,0xb7,0x31,0x03,0x62, - 0x22,0xba,0xb4,0xb5,0x0a,0xa1,0xb6,0x84,0x1b,0xb5,0xb8,0x26,0xe9,0xdd,0x0c,0x07, - 0xe4,0x6b,0x6b,0x94,0xb4,0xa5,0x29,0x71,0x84,0x08,0x52,0x47,0x39,0xef,0xc3,0x02, - 0x2c,0xae,0xf0,0x15,0xf2,0xff,0x08,0xa1,0xe2,0x4c,0xe5,0xca,0x0a,0xda,0xc2,0xfb, - 0x8d,0xd0,0xa4,0x23,0x4b,0x0f,0xa0,0xd2,0x70,0xf5,0x75,0x48,0x15,0x4c,0x66,0xee, - 0x41,0x33,0xc0,0xa8,0x3c,0x51,0xaa,0x6c,0x71,0x2f,0x0e,0x5c,0xaf,0x21,0x04,0xdb, - 0xe4,0xf7,0x1d,0x91,0x94,0xf7,0xb4,0x39,0xcc,0x77,0xa9,0xa3,0xa8,0x36,0xa8,0xae, - 0xb2,0xdd,0xeb,0xee,0x5b,0xcb,0x5d,0x32,0x6a,0xfb,0x2c,0xb7,0xa9,0x98,0x39,0xce, - 0x06,0x8f,0xc8,0xff,0x5c,0x67,0x30,0x70,0x9a,0xe2,0x1b,0x9d,0x66,0x3a,0xf5,0x27, - 0x8d,0x31,0xef,0x32,0x0c,0x7f,0x69,0xc7,0x8a,0xff,0xae,0xef,0x93,0x00,0xf1,0x50, - 0xe2,0xe6,0x0b,0x42,0x5e,0x5c,0xd1,0x87,0x88,0x73,0x6d,0xb9,0x6a,0x76,0x51,0x18, - 0x70,0x52,0x27,0x6c,0xcd,0x75,0x0f,0xe2,0x0c,0x99,0x39,0x7f,0x78,0xf3,0xed,0xd7, - 0xf9,0x8a,0x84,0x24,0x68,0x4b,0x99,0x7a,0x1e,0xb8,0xfb,0x2c,0xd1,0x1e,0x20,0xca, - 0xe0,0xee,0x56,0x39,0x8b,0xa0,0x2a,0x37,0x0a,0x9a,0xc2,0x83,0xe1,0x03,0xed,0x2f, - 0xab,0x6d,0xdd,0x1a,0x16,0xac,0xdb,0x00,0x20,0x84,0xa8,0xab,0x07,0x5a,0x1e,0x29, - 0xb2,0xba,0x07,0x6e,0xc0,0xa3,0xa9,0xcd,0x55,0x9a,0xc6,0xc1,0x79,0xf1,0xea,0xe9, - 0x66,0xb1,0x80,0x35,0xa3,0x35,0xa6,0xa9,0xa1,0x85,0x68,0xff,0x87,0x24,0xab,0xbe, - 0x84,0x6d,0xe8,0x8a,0x3e,0x6c,0x2d,0xd7,0x1c,0xa5,0x19,0x01,0x3e,0xe4,0xdc,0xe8, - 0x1c,0x42,0xbb,0x29,0xd6,0x79,0xc9,0x4e,0xf6,0x74,0x90,0xbe,0x79,0xfb,0xf6,0x35, - 0x1d,0x98,0xe2,0x42,0x6c,0x37,0x6c,0xf5,0xcd,0xb3,0x4c,0x4b,0x10,0xaf,0xa3,0x02, - 0xc1,0xfb,0x29,0xfb,0x31,0xc7,0xc2,0x82,0xae,0x61,0xd6,0xd8,0xac,0xeb,0xe4,0x5e, - 0x48,0x50,0x17,0x49,0x1c,0x2c,0xeb,0x7b,0x69,0x44,0x9c,0x44,0x01,0xbe,0xb6,0xf1, - 0xbc,0xf6,0xd3,0x08,0x9c,0x6f,0xe2,0x94,0xad,0x1d,0xfd,0x4d,0xc6,0x18,0x06,0x34, - 0x55,0x2b,0x56,0x98,0x83,0x51,0x89,0x0a,0x97,0xb1,0x89,0x1f,0xf2,0x80,0xbe,0x6b, - 0xdd,0x0c,0x9d,0xd2,0x3c,0xd8,0xd3,0x11,0x85,0x7f,0x5f,0x6c,0x24,0xdc,0x0f,0x7c, - 0xd1,0x31,0x9e,0x3f,0x27,0x6b,0x0b,0x2d,0xee,0xc4,0x30,0xb6,0x99,0x1e,0x8c,0xf5, - 0xc5,0x02,0x69,0x60,0xfa,0xbb,0x3e,0x44,0x46,0x27,0xc1,0xdc,0xbe,0x0a,0x51,0x53, - 0xce,0x81,0xcb,0x28,0xc9,0x42,0xa5,0xcb,0x80,0x4c,0x9f,0xa7,0x17,0x86,0x58,0xc8, - 0x40,0x77,0xe3,0xd7,0x70,0x24,0x12,0x03,0x96,0xd2,0x04,0xff,0xed,0xee,0xd9,0x08, - 0xf9,0xd6,0xdc,0x54,0x3c,0x4a,0x3f,0x39,0x18,0xd1,0xa9,0x38,0x6c,0x62,0x8c,0x0e, - 0xef,0x60,0x0b,0x34,0xbb,0x8f,0xa8,0x4b,0xd2,0x8c,0xdb,0x9e,0x3a,0xbd,0xb3,0xc6, - 0x20,0xab,0x8f,0x77,0xed,0xb3,0xa1,0x4e,0x02,0x04,0x22,0x25,0x45,0x28,0xf2,0x64, - 0xf5,0x2e,0x31,0x07,0xe5,0xbb,0xba,0xac,0xfb,0x3e,0xa4,0xbf,0x76,0x89,0x8f,0x8f, - 0x10,0x5c,0xa3,0xdd,0xe2,0x8e,0xb7,0xd7,0xcf,0x65,0x7b,0xb4,0xf4,0xa6,0xd1,0x2b, - 0x37,0xf1,0x3e,0xfc,0xb9,0xb4,0x5b,0xd9,0xb5,0xf8,0xda,0x88,0xda,0xf9,0xe8,0xce, - 0x58,0x57,0x02,0x2d,0x18,0x7c,0x6e,0x6e,0xe0,0x0b,0x0a,0xd9,0x97,0x1f,0x91,0xf4, - 0xe4,0xf4,0x2a,0x9b,0xdd,0x23,0x21,0x43,0xd7,0x76,0x3d,0xd3,0xf9,0x0e,0x92,0xc1, - 0xd6,0x6a,0x01,0x5a,0x71,0x55,0x8e,0x6a,0xc2,0x6d,0xd8,0xd0,0xe9,0xe5,0x1a,0xfc, - 0x41,0xa3,0x97,0x3e,0x4f,0xd6,0xbf,0x4e,0x89,0xee,0xa4,0xe3,0x47,0x4d,0xab,0xfb, - 0x34,0xcd,0xa7,0x61,0xad,0x54,0x91,0x06,0xde,0xfb,0xd7,0x18,0xef,0xd8,0x85,0xdf, - 0x17,0x4c,0x93,0x34,0xbe,0x43,0x9c,0x9d,0x66,0xdd,0xe8,0x56,0x23,0x56,0x54,0x0f, - 0x2b,0x0a,0x38,0x33,0xc4,0x0f,0x6f,0x5e,0xaa,0x42,0x72,0x53,0x11,0x3d,0xf7,0xd1, - 0xb7,0x55,0x4e,0x63,0x87,0xd0,0x5d,0xd7,0x9a,0xc9,0x01,0xc0,0x1b,0x33,0x71,0x6b, - 0x45,0x93,0xea,0x13,0x62,0x46,0xc3,0x83,0x31,0xb2,0x1a,0x63,0x1c,0xd2,0xb7,0x5e, - 0x28,0xee,0xaa,0xf6,0x7a,0xe8,0xbc,0x5b,0x06,0xc3,0x24,0x74,0x97,0x9f,0x5b,0xc3, - 0x94,0x19,0x78,0x5b,0xff,0xa8,0x0e,0x04,0xbb,0x4d,0x0e,0x69,0xa0,0x93,0x86,0x1c, - 0xd2,0xf6,0x7e,0x34,0xe7,0x57,0x4f,0x3b,0x9e,0xff,0x15,0x24,0x7e,0xc7,0x43,0x63, - 0x7b,0x8b,0x6b,0xa5,0x56,0xa2,0xb6,0x87,0xfd,0xb1,0x41,0xef,0x0e,0x99,0xf5,0x82, - 0xf1,0xfe,0x7e,0x1c,0x10,0x2f,0x55,0x92,0x68,0x0e,0xcd,0x20,0xa0,0xf3,0x16,0xc5, - 0xe0,0x76,0x87,0x15,0x80,0xeb,0x2a,0x1f,0x5c,0x71,0x5a,0xad,0x32,0x13,0x44,0xdc, - 0xe6,0x77,0x7a,0xda,0x4f,0xa7,0xd7,0x64,0x4f,0xb4,0xfa,0x98,0xea,0xfa,0x1f,0x93, - 0x4e,0x3f,0xc5,0x36,0xd4,0x52,0xab,0x28,0xcc,0xfe,0x02,0xff,0x9d,0x5b,0x85,0x53, - 0x91,0xd7,0xf2,0xf3,0x13,0x25,0x70,0x9b,0x3d,0xf5,0xc6,0xb7,0xca,0x71,0x9e,0xcf, - 0x35,0xba,0x02,0x62,0x2d,0x29,0xc9,0xa8,0xe1,0xf8,0xb6,0x24,0x49,0x3c,0xce,0x32, - 0x4f,0xbe,0x10,0x8d,0x15,0x13,0x7d,0xf6,0x38,0xf8,0xd7,0xd1,0xc3,0xe1,0x8a,0xbe, - 0x46,0xec,0x1c,0xd5,0x2d,0xeb,0x7c,0x61,0xc9,0x3a,0xb7,0x78,0xb2,0xdc,0x2e,0x6d, - 0x76,0xa9,0x5b,0x6d,0x6d,0x6b,0x23,0xdf,0xba,0xf3,0xff,0xa3,0xa6,0x55,0x32,0xb5, - 0x39,0xd7,0x8b,0x31,0x28,0xc9,0x0d,0xfb,0x57,0xb0,0x80,0x80,0x5c,0xf0,0x63,0xf7, - 0x2c,0xae,0xdc,0x1b,0x17,0xac,0x09,0xfd,0xb3,0x59,0xd3,0x1f,0xc9,0x05,0x73,0x83, - 0x4d,0xba,0x71,0xb1,0x24,0xc4,0x39,0xaf,0x67,0x95,0xef,0xd0,0xaa,0x48,0x7e,0x1a, - 0x6e,0x92,0x6d,0x41,0xe8,0xe0,0xf7,0x92,0x43,0x45,0xf8,0x31,0x93,0x48,0x87,0x93, - 0x53,0xd0,0x5e,0x09,0xf3,0x36,0x83,0x27,0x1b,0x78,0x54,0x5f,0xa2,0x6f,0x89,0xfa, - 0x95,0x12,0x58,0xc5,0xa1,0x73,0x10,0x69,0xa6,0xac,0x10,0x2c,0x38,0x5e,0x6c,0xae, - 0x35,0xba,0xc8,0xc4,0x98,0x67,0xcd,0xec,0x78,0x69,0x12,0x07,0xce,0xef,0x95,0xe8, - 0x23,0x7e,0xb1,0xd0,0xac,0x11,0xbe,0xdd,0x88,0x2a,0x8c,0xf3,0x6c,0x88,0xfe,0x54, - 0xd2,0xc1,0xb0,0xe3,0x8e,0x68,0x33,0x5f,0xff,0xf0,0x16,0xc9,0x50,0x64,0x6c,0xc4, - 0x01,0xb3,0xd2,0xcd,0x77,0x6a,0xd3,0x84,0x84,0xbb,0x19,0xc9,0x4b,0x36,0x56,0x46, - 0x86,0x8c,0xd8,0xa5,0xd3,0xeb,0x12,0x43,0x7b,0x5a,0xf0,0xbe,0xcc,0x25,0xa2,0x8d, - 0x53,0x4c,0xab,0x80,0xaa,0xc0,0x79,0x52,0x96,0x88,0xb9,0xbb,0x12,0x6f,0x43,0x49, - 0x59,0x13,0x29,0x47,0x5e,0xa7,0xf6,0x68,0x96,0x60,0x4a,0xf6,0xfe,0xbd,0x04,0x37, - 0xc5,0x8b,0x6d,0xbc,0x72,0x85,0x63,0xd3,0x41,0xa9,0x9c,0x29,0x17,0x61,0x06,0xa5, - 0x0e,0xd8,0xf3,0x95,0x1d,0x4b,0xdc,0x76,0x72,0x76,0x52,0x0a,0xb8,0xac,0xc4,0xf3, - 0x19,0x3f,0x8e,0xb1,0x89,0xef,0x66,0x75,0x2e,0x73,0xf5,0x9c,0x60,0x92,0xcd,0xb1, - 0xb2,0xf4,0xc6,0xe7,0x5b,0x06,0x41,0x74,0xe7,0x29,0x1a,0x69,0x87,0x7a,0x61,0x14, - 0xfc,0x41,0xfb,0xc2,0xb0,0xbf,0xe9,0xfe,0xfe,0x3d,0x5d,0xc1,0xbb,0x83,0xc5,0xcb, - 0x34,0x8e,0xc7,0x5d,0xe9,0x5d,0xd9,0x69,0x80,0x37,0xd1,0xb4,0x69,0xd9,0xd4,0xeb, - 0xb3,0x53,0x4c,0x3d,0x3e,0x1d,0x04,0x29,0xa9,0xdf,0xf4,0x8d,0x07,0xcc,0x99,0x83, - 0x69,0x34,0xea,0x41,0x91,0x17,0x8c,0x19,0x02,0xfa,0x55,0x51,0x9f,0xcb,0x46,0xb3, - 0xd2,0x1e,0xfc,0x87,0x78,0x76,0xc2,0x3c,0xc8,0xd0,0x9b,0xa0,0x28,0x67,0x4b,0x81, - 0xa5,0x21,0x2f,0x0a,0xf1,0x0a,0xa3,0xd6,0x18,0x56,0x64,0xc1,0x4e,0xdf,0x3e,0x79, - 0xfb,0xfc,0x4f,0x2f,0x9f,0x3c,0x7d,0xfe,0x32,0xbc,0xc6,0x5d,0x86,0x2e,0xe3,0x6d, - 0x6a,0x8d,0xed,0x84,0x38,0x6f,0x63,0x57,0x79,0x2f,0xc1,0x57,0x65,0xec,0x9a,0xf8, - 0x49,0xd7,0x6f,0xc9,0xb2,0x60,0x41,0xe2,0x62,0xec,0xb2,0x4f,0xe8,0x95,0x6e,0x82, - 0x8f,0xe9,0xd8,0xd5,0xa1,0x00,0xfc,0x2e,0x3f,0x1f,0xbb,0xbf,0xfe,0xcf,0xff,0x2e, - 0xc1,0xa5,0x3e,0x20,0x19,0xcf,0xff,0x43,0x23,0xb6,0x06,0x75,0x2a,0x62,0x5c,0xf6, - 0xf0,0xcf,0xc2,0xc9,0xfd,0xf2,0x3c,0x6d,0x79,0x29,0xf1,0x19,0x57,0x54,0xf8,0xc4, - 0xe5,0xb8,0x43,0x3b,0x19,0xcb,0x2f,0x1d,0xf1,0x6d,0x52,0x65,0x87,0xdb,0x4f,0x2a, - 0x4b,0x80,0xb8,0x53,0xf4,0x99,0xd6,0x0b,0xdf,0x56,0x72,0x9e,0x5c,0x20,0x06,0x33, - 0x6f,0x84,0x2d,0xe1,0x12,0x07,0x77,0xb2,0xf7,0xd7,0x06,0x8e,0xfd,0x92,0xed,0x04, - 0x8e,0x25,0x95,0x15,0x39,0x26,0xc1,0x0c,0x77,0x8a,0xf6,0x2a,0xab,0x46,0xc3,0x25, - 0x8b,0x29,0x55,0xc0,0xd7,0x2a,0x62,0x13,0xdd,0x13,0x20,0xda,0x31,0xbf,0xaa,0xab, - 0xb4,0x7a,0x96,0xd2,0x54,0x8e,0xe8,0x6b,0x1d,0x5a,0x2b,0x2d,0x11,0x36,0xbe,0xb9, - 0x19,0x92,0xd8,0xf3,0x5b,0xd7,0x1b,0x5b,0x90,0xf6,0x8e,0xeb,0xa9,0x94,0x1c,0x58, - 0x9e,0x76,0xc8,0x50,0xfb,0x1d,0xfa,0x6f,0xc5,0xcf,0x40,0xe3,0x6e,0x5c,0x1f,0xec, - 0x71,0x34,0xb4,0xf6,0xd3,0x4f,0xec,0x4d,0xc3,0x9b,0x0b,0x57,0x3e,0x34,0x02,0x05, - 0x17,0xb7,0x07,0x94,0x51,0xdd,0x45,0x23,0x66,0xaa,0x35,0x5f,0xc3,0x80,0x36,0x06, - 0xbd,0xd8,0x99,0xc6,0xd4,0x32,0x0e,0x34,0xa7,0xc2,0x14,0x6d,0x7f,0x9f,0x9e,0x89, - 0x9e,0x35,0x26,0x15,0x7f,0x62,0x52,0x71,0x63,0x52,0xe0,0x11,0x26,0x71,0x7b,0xdb, - 0xe8,0xed,0xa4,0x3b,0x88,0x2b,0x6e,0x8c,0xe8,0x97,0xee,0x88,0x24,0xa5,0xf4,0xa8, - 0xb5,0x49,0x7c,0x57,0x83,0xc2,0x72,0x1c,0xa3,0x61,0x10,0x6e,0x6d,0x05,0xe7,0xa0, - 0x81,0xf3,0x70,0xc8,0x07,0x5e,0x45,0x67,0xdc,0x7e,0x14,0xed,0xb5,0x20,0x12,0xef, - 0xe5,0xe7,0x07,0x07,0x13,0x8d,0x61,0x9b,0xab,0xe4,0xe1,0xef,0xc1,0xc1,0x56,0x2b, - 0x1e,0xb8,0xfd,0x10,0x06,0x1c,0x70,0x4d,0x54,0xd1,0x65,0x62,0x43,0x40,0x49,0xdd, - 0x37,0x75,0xeb,0x89,0x4e,0x9b,0x28,0xc6,0x78,0x36,0xb9,0x73,0x04,0x9d,0xa9,0x69, - 0x4a,0x40,0xcb,0xce,0x1d,0xb9,0x4d,0x06,0x8c,0xeb,0xe8,0x24,0x75,0x9d,0xd8,0x09, - 0x49,0xb2,0x9a,0x93,0x53,0xec,0x6b,0xc7,0x66,0x2f,0xb6,0x9e,0xed,0x76,0x79,0x1b, - 0x9b,0xb8,0xa3,0x71,0xba,0xcd,0xb4,0x2c,0x76,0x4f,0xf1,0xed,0x27,0xd4,0xff,0xfb, - 0x78,0x7a,0x2a,0x5a,0x28,0x92,0x47,0x61,0x18,0xe4,0xab,0x74,0x98,0x6f,0x20,0x0e, - 0x64,0xae,0x1c,0x82,0xf3,0x01,0xe7,0x51,0x90,0xc4,0xa1,0x30,0xee,0xc1,0x88,0x44, - 0x1c,0xc0,0xbf,0x8e,0xc0,0x0c,0x8d,0x8e,0x9c,0x79,0x12,0xab,0xf8,0x01,0x4e,0xa0, - 0xb2,0x8c,0xa3,0xb4,0x5a,0x5e,0x79,0x9c,0xcd,0xe4,0x85,0xca,0xc9,0xae,0x02,0x5f, - 0x70,0xb1,0x85,0x4a,0x34,0x51,0x21,0x7d,0xb5,0xe4,0x98,0xbe,0x94,0x5c,0xf0,0x85, - 0x66,0xa1,0xc4,0x12,0xc0,0x4c,0x94,0xd6,0x25,0x33,0x2f,0x53,0xc2,0x34,0x59,0xb0, - 0x49,0x1c,0x69,0xfa,0xe7,0x12,0xff,0x0d,0xae,0xa6,0xaf,0xd8,0xef,0x4d,0x29,0xd6, - 0x5c,0x66,0xdb,0xe6,0xb5,0x4b,0x71,0x94,0x5d,0x5d,0x46,0x57,0x1e,0x73,0x51,0x6c, - 0x38,0xbf,0xcc,0x35,0xa3,0x33,0x11,0x8e,0x2d,0x65,0x76,0x4a,0x19,0x75,0x01,0xc5, - 0x62,0xba,0xd5,0xdc,0x90,0x45,0x82,0x36,0xd9,0x3f,0xf7,0x45,0x0f,0xc4,0xf9,0x09, - 0xfa,0xc9,0x63,0x9b,0xec,0x60,0xdf,0xe8,0x09,0xfe,0x82,0x65,0x05,0xfd,0x01,0x73, - 0xa9,0x3b,0x6f,0x55,0xee,0xc2,0x44,0x52,0x0d,0x01,0x88,0x8f,0x1b,0xd4,0xcb,0xbb, - 0x6e,0x9c,0x22,0x2b,0x80,0x40,0x78,0xd9,0x50,0xb7,0xa7,0xcf,0x52,0x52,0xc2,0xcf, - 0xc5,0x68,0xc8,0xb4,0xff,0xe3,0xcf,0x61,0x72,0x30,0x9a,0xfc,0xdc,0x18,0xe2,0xe4, - 0xe7,0x83,0x03,0x4f,0xa3,0x98,0xbe,0x34,0xf4,0xf3,0x7b,0x05,0x7c,0xc2,0x54,0xdf, - 0xb4,0xde,0xaa,0xe1,0x12,0x8f,0x74,0xf8,0x13,0xd8,0xe0,0xdf,0x1c,0x26,0x84,0x44, - 0xca,0xaa,0xae,0xcd,0xf1,0x1c,0x9e,0x1a,0x85,0x91,0x51,0x05,0xa6,0x81,0x89,0x27, - 0x82,0x12,0xe9,0xa4,0x1b,0x1a,0xce,0xd6,0xcf,0x4f,0x39,0x0d,0x21,0x2d,0x40,0x74, - 0x09,0x16,0x58,0x6c,0xdd,0x06,0x0c,0x1b,0x86,0x7e,0x03,0xc9,0x6e,0x69,0x01,0x2a, - 0xf3,0xc6,0x85,0xba,0x06,0x4a,0xda,0x02,0xa0,0x27,0xb1,0x38,0xc2,0x2f,0x9d,0x3e, - 0x97,0x1d,0xcc,0x96,0x9b,0xec,0x9c,0xb8,0x22,0x06,0x64,0xfa,0xa3,0xc0,0xd0,0xf0, - 0xcc,0x39,0xb1,0xc9,0x70,0x47,0x15,0x5f,0xf2,0x9c,0x6f,0x22,0x93,0xe6,0x4c,0xb2, - 0x8c,0x45,0x1c,0xa7,0x2a,0x81,0x84,0x07,0xd8,0x2c,0x68,0xcc,0xd0,0x7f,0x70,0xaa, - 0x5b,0x92,0x03,0xd6,0x48,0xaa,0x4c,0xc7,0x0b,0x1a,0x22,0x0c,0x8b,0xad,0x2b,0x74, - 0x58,0x8b,0x58,0xec,0x5d,0x38,0x2a,0x04,0x4c,0x7c,0x03,0x9a,0xe6,0xe2,0x85,0x03, - 0xa6,0x11,0x9f,0x29,0x87,0x76,0x70,0x77,0x92,0xf8,0x99,0xa0,0x16,0x9c,0x72,0x38, - 0xa2,0x2f,0x9c,0xed,0xbd,0x6c,0x5b,0x5c,0xdc,0x52,0xb1,0x81,0x60,0x83,0x07,0xf9, - 0x62,0x20,0xad,0x89,0x31,0x4f,0x7a,0xd4,0x81,0x6b,0x2c,0xcd,0x20,0xbf,0xa4,0x1c, - 0x2e,0x16,0x73,0x24,0x75,0x11,0x34,0x0e,0x56,0x06,0xef,0xda,0x13,0x42,0x50,0x08, - 0x1c,0x52,0xce,0x72,0x75,0xed,0x83,0xb4,0xd6,0x92,0x9c,0xea,0x84,0xf2,0x7a,0x52, - 0xca,0x9a,0xc8,0xb3,0x52,0x97,0x4c,0x90,0x68,0x21,0xa2,0x0d,0x03,0x93,0xac,0x93, - 0xda,0xad,0xbc,0x68,0xe5,0xc6,0xec,0x2b,0x31,0xcc,0xb8,0xca,0x97,0x97,0x9c,0xf9, - 0xbf,0x5e,0x30,0x57,0x33,0xc8,0xe8,0xc7,0x0b,0xcc,0xf1,0x78,0xbd,0x28,0xc3,0x1d, - 0xe0,0x15,0xb0,0xd5,0x47,0x10,0x65,0x08,0xc4,0xb5,0xf0,0xa2,0xed,0x4c,0x02,0xc3, - 0x8c,0x95,0x6b,0x28,0xd6,0x9f,0x08,0xe9,0x87,0x6e,0x53,0x8a,0x54,0xee,0x13,0xec, - 0xf9,0xc7,0x83,0xad,0xd1,0x2e,0xcd,0x3c,0x9e,0x27,0x2a,0x8e,0x51,0xc9,0x81,0x71, - 0xba,0x40,0x15,0x57,0xab,0x2f,0xf5,0xe9,0xe8,0x56,0x80,0x09,0xfa,0x39,0x18,0x79, - 0x5b,0xff,0xfe,0xc3,0xa1,0x6d,0x58,0x06,0x72,0x68,0x39,0xd8,0xf1,0x8c,0x4e,0xdc, - 0x5a,0x9e,0x24,0x5a,0xd2,0xe1,0x73,0xf7,0x49,0x8f,0xbb,0xd6,0x42,0xdd,0xe3,0x76, - 0xbd,0x4f,0xfa,0xdc,0x09,0x36,0x38,0x71,0x47,0xd4,0xed,0xd0,0xd5,0xc7,0xf9,0x2d, - 0x5f,0xc4,0x03,0xbf,0x37,0x0e,0x4d,0x19,0x0e,0xbe,0x1a,0xfe,0x36,0x70,0x7a,0xb8, - 0x25,0x88,0x23,0x4a,0xc4,0x73,0x4a,0x92,0x79,0x54,0xb8,0x5a,0xa9,0x27,0x57,0x3d, - 0x55,0x4e,0xcf,0x90,0xdf,0x1e,0x56,0x53,0x9a,0x8b,0x38,0x01,0xd8,0x5a,0x72,0xa4, - 0xd1,0xa2,0x52,0x3b,0x56,0xe2,0x18,0x85,0x1f,0xe0,0xcc,0x24,0xf9,0x53,0x54,0x34, - 0x0a,0x09,0xb0,0x05,0x53,0x6e,0x98,0xcd,0xd9,0x34,0xa4,0x5a,0xa3,0x72,0x9b,0x19, - 0xc1,0xaf,0x0a,0x27,0xe1,0xa0,0x99,0x11,0x8d,0x2c,0x29,0x5b,0x91,0x37,0x97,0x99, - 0xbe,0x04,0x88,0xd5,0xaf,0x81,0x5a,0x47,0x61,0x7b,0x83,0x3c,0xd3,0xe9,0xc1,0xc2, - 0x1d,0x15,0x1f,0x56,0x30,0x56,0xb8,0x18,0x3a,0xaf,0x0d,0x9f,0xb3,0x86,0x51,0x52, - 0x81,0x99,0x95,0xed,0x23,0x0e,0x44,0x07,0x79,0x48,0xdc,0x1b,0xcc,0x9b,0x9f,0x7f, - 0x35,0xac,0x59,0x5e,0xfd,0x91,0x50,0xb5,0xfa,0xec,0x29,0xa8,0x05,0x4a,0x6c,0x03, - 0x96,0x76,0xba,0x67,0x89,0x03,0x96,0x39,0x5b,0xb3,0x74,0x17,0xa0,0x33,0xb5,0x41, - 0x81,0xdf,0x00,0x45,0xee,0x78,0x52,0x52,0xf7,0x4c,0x38,0x99,0x15,0xe6,0x5f,0xcc, - 0x0c,0x8f,0x1a,0xd3,0x1b,0xda,0x3c,0x3b,0x17,0x7a,0x1c,0x1e,0x11,0xb3,0x27,0x43, - 0x17,0x9a,0x33,0x69,0x8c,0xfb,0x76,0xc5,0xb0,0x22,0xcb,0x5b,0x61,0x89,0xec,0x78, - 0xbb,0xf6,0xf9,0xe5,0x13,0xdb,0x69,0x96,0xb7,0xfa,0xca,0xf8,0xb2,0x70,0xb3,0x54, - 0x1f,0xf1,0x19,0xfd,0x9b,0x3c,0x46,0x6d,0x7f,0x51,0x35,0x4e,0x62,0x3c,0x35,0x96, - 0x21,0x50,0xde,0x19,0x92,0xd4,0xd3,0xac,0xaf,0xe5,0x02,0x7a,0xdd,0x35,0x4f,0xf5, - 0xf1,0x63,0xad,0x98,0x3d,0xdc,0x99,0xae,0x38,0x86,0x9a,0xef,0x35,0xa6,0x20,0x70, - 0x04,0x73,0xba,0x13,0x71,0x6b,0x6e,0x0b,0x40,0xe2,0xf6,0x3e,0x8c,0x02,0xff,0xa9, - 0x21,0xb7,0x7b,0x35,0x75,0xe3,0x14,0xb6,0x75,0x08,0x18,0x34,0xe2,0xf9,0x42,0x7c, - 0x01,0x0f,0x54,0x4e,0x7a,0xa0,0xe7,0x4b,0xe5,0xbd,0x67,0x65,0x36,0x7b,0x16,0xcf, - 0x38,0x35,0x72,0xfc,0x81,0xef,0x96,0x5b,0xf2,0x8d,0x5e,0x57,0xf9,0xa6,0x11,0x94, - 0x2b,0xbc,0x62,0x19,0x2b,0xdf,0xba,0xa8,0x98,0x2d,0x93,0x0b,0xb9,0x2a,0x8e,0xf3, - 0xd8,0xae,0x19,0xad,0x71,0xa8,0x6d,0x5c,0xd4,0x04,0x7e,0x15,0x23,0x67,0x5f,0xe9, - 0xc0,0xd4,0x5f,0x5b,0x76,0x75,0x42,0x2b,0xa2,0x1f,0xf4,0x5a,0x38,0x14,0x95,0x4f, - 0x14,0xd1,0xc0,0xbe,0x64,0xda,0xb5,0x2f,0x7f,0x62,0x5e,0x86,0x73,0x37,0xab,0x0c, - 0x6a,0x44,0x51,0x11,0x24,0x85,0x9b,0x15,0xc4,0xd4,0xa4,0x2e,0x68,0xd2,0xd7,0x26, - 0x58,0x09,0x10,0xfb,0x72,0x1f,0xe6,0xd7,0xcf,0xbe,0xf3,0x4c,0xb0,0x30,0x90,0x6e, - 0x29,0x97,0xc4,0xbc,0x7c,0xf2,0x9d,0x61,0x86,0x58,0xdd,0x46,0x38,0xd9,0x5c,0x5f, - 0x27,0x0a,0x4b,0xa6,0xe2,0x62,0xa7,0x9e,0xeb,0x8c,0xa6,0x58,0x60,0xe3,0x5a,0x29, - 0x78,0x7e,0xb3,0x16,0x25,0xd3,0x8f,0xdf,0xbe,0xfe,0xd3,0xab,0x27,0x7f,0xf8,0xd3, - 0xd3,0x7f,0x79,0xfb,0xfc,0x34,0xfc,0xf2,0x73,0xe4,0x2f,0xe2,0x3f,0xb6,0x9e,0xc7, - 0x36,0xec,0x2a,0x0d,0x5d,0xc3,0x5e,0xa7,0x7d,0x00,0x3a,0x4d,0xb8,0x96,0x91,0x7e, - 0x47,0x79,0x47,0x05,0x7d,0xe2,0xf1,0x1b,0xa9,0x05,0x6f,0x55,0x8f,0x70,0x3a,0x74, - 0xa3,0x20,0x09,0xca,0x62,0x16,0xba,0x96,0xeb,0x83,0x18,0xf1,0x7e,0x2e,0x75,0x9e, - 0xa4,0x0e,0x0c,0x51,0xc0,0xb9,0x66,0x5b,0x7f,0xdf,0xf1,0xb5,0xa6,0xb1,0xf4,0x3b, - 0xbd,0x15,0x8c,0xf3,0xee,0x26,0xb3,0xac,0x8b,0xae,0xa7,0x5b,0x33,0x83,0x06,0x43, - 0xd8,0xd4,0x8f,0xb4,0x62,0x34,0xd4,0x1a,0x30,0x33,0x15,0x81,0xf1,0xaa,0x98,0xd5, - 0x7c,0xf7,0x7e,0xcc,0xdb,0xa4,0x81,0x50,0x43,0xa9,0x0f,0xef,0xba,0x52,0xfb,0xe9, - 0xc2,0x41,0x57,0x20,0x57,0xc5,0x52,0x22,0x5f,0x5f,0x0a,0x0e,0x14,0x57,0xbd,0xa4, - 0xd1,0xba,0x64,0xb5,0xed,0x34,0x2a,0x99,0x77,0x15,0x17,0xd2,0x79,0x5e,0x49,0x6d, - 0x62,0x0e,0xe1,0xd1,0x69,0xdd,0x70,0xa8,0x5c,0x71,0x39,0xd3,0x9b,0x1c,0x96,0x3f, - 0x11,0x34,0x7c,0xfd,0xfd,0xe9,0x1f,0x0e,0x83,0x3f,0x7d,0xee,0xfc,0x0c,0x46,0x3c, - 0x72,0x5e,0x45,0xb3,0x01,0x7c,0x9c,0x79,0x80,0xe0,0x4a,0x59,0x04,0x53,0x4e,0xc1, - 0xeb,0x94,0x13,0xb3,0x39,0x4f,0xbf,0x7f,0xfb,0x0d,0x9d,0x39,0xc2,0xb4,0x11,0xb1, - 0x9a,0x8a,0x5e,0xa3,0x42,0xb9,0x8e,0x67,0xa2,0x95,0xa6,0xf5,0x29,0x94,0x63,0x91, - 0xc3,0x61,0xae,0x87,0x3d,0x4e,0xd0,0x89,0x76,0x82,0xef,0x9e,0xbf,0x25,0x3a,0xfe, - 0x35,0xef,0xf9,0x0b,0x5a,0x23,0x9d,0xc1,0xf7,0xaa,0x46,0x05,0xaf,0x91,0x33,0xf6, - 0x94,0x38,0xb4,0x14,0x25,0x89,0x54,0x83,0xa0,0x0f,0x9e,0xc8,0xf1,0xe6,0x94,0x71, - 0xc8,0xc8,0x2f,0x87,0x40,0x6a,0x49,0x1c,0x4c,0xef,0xa7,0x1e,0xde,0xfc,0x9e,0x41, - 0xb6,0xd4,0xe9,0x12,0x15,0x9f,0x3d,0x57,0xb7,0x18,0xb3,0x07,0x87,0xca,0x90,0xce, - 0x47,0x2c,0xa9,0xd4,0xfa,0xc8,0xb5,0x3b,0xf4,0xa6,0xac,0x36,0x72,0xcb,0x86,0x16, - 0x64,0x33,0x0e,0x51,0xc5,0x13,0xaf,0x14,0xbd,0x82,0x02,0x5f,0xae,0x8b,0x5c,0x29, - 0x07,0x6d,0xdf,0x9c,0xf0,0x8d,0x18,0x87,0x63,0x49,0x1a,0xb7,0x53,0xac,0x61,0x2d, - 0x50,0xa7,0xb4,0x17,0xfd,0x34,0xfd,0xe9,0x92,0x84,0x0d,0xe0,0xc6,0x9e,0x25,0xf6, - 0x0a,0x78,0x00,0x70,0x4a,0xb6,0x57,0xc3,0x23,0xce,0x38,0x7e,0xc0,0xd0,0x15,0xb2, - 0x2f,0x4c,0x40,0x6c,0x0f,0x31,0x20,0x57,0xeb,0x58,0x92,0x7c,0x05,0x70,0x58,0x37, - 0x15,0x38,0x39,0x87,0x62,0x03,0x1b,0x71,0xc0,0x9c,0xa4,0x92,0x7d,0x8c,0xc7,0xd6, - 0x25,0x74,0x58,0x30,0x5a,0xf8,0x66,0xec,0x0b,0x89,0xfa,0x34,0x17,0x09,0xbb,0x56, - 0x92,0x93,0x18,0x66,0xa0,0xf9,0x36,0x59,0x98,0x6b,0xf9,0x45,0xf2,0x1a,0x6a,0xc6, - 0x11,0x8b,0xc9,0xac,0xb0,0xf4,0xc6,0x82,0x8d,0xee,0x4a,0xb5,0xa6,0xf2,0x27,0x44, - 0x70,0x44,0x67,0xca,0xc0,0xa3,0x89,0x24,0xf5,0x2b,0x0d,0x07,0x0c,0x3c,0x37,0x5c, - 0xe6,0x1b,0xa4,0x55,0xee,0x9b,0x4e,0x0f,0x91,0x11,0x37,0xf6,0x58,0x50,0xd5,0xcc, - 0xa9,0xf2,0xb9,0x57,0x37,0x9e,0x34,0x84,0x56,0xc9,0x10,0xc2,0x80,0xc9,0x09,0x73, - 0x2b,0xad,0xa9,0x17,0x24,0x2e,0xee,0x75,0x5a,0x80,0x39,0x8f,0xe3,0x75,0x8d,0x38, - 0xb2,0x9a,0x95,0x3c,0xfc,0xa3,0x35,0xe0,0x9f,0x78,0xc4,0x46,0xc0,0xc9,0xbc,0x9b, - 0x1b,0xc8,0x3c,0x54,0x60,0xe7,0x8b,0xd7,0xcc,0xc0,0x67,0xb9,0x4e,0x50,0x0d,0xf8, - 0x90,0xdc,0xa0,0xc2,0x0d,0x2d,0xad,0xd7,0x6c,0xef,0x8f,0x6a,0xe7,0x7e,0xc2,0xd6, - 0x59,0x9f,0x34,0xf3,0x00,0xf6,0x96,0x5d,0xdc,0x9b,0x9a,0xae,0x85,0x51,0x74,0x51, - 0xfb,0x74,0x4c,0x4d,0xcd,0x85,0x4a,0x51,0xe6,0x79,0xf6,0x20,0xda,0x98,0x9d,0x5b, - 0x14,0x78,0xef,0x6a,0x13,0xcb,0x63,0xb5,0xc4,0xaa,0x05,0xb6,0x92,0xca,0x3d,0x32, - 0xca,0x21,0x03,0xf6,0x86,0x46,0x16,0xa1,0x3b,0xf9,0x0f,0x49,0x72,0x7e,0x9f,0xc8, - 0x7b,0x16,0x5e,0x6f,0x7d,0xf1,0x9d,0x1c,0xd6,0x1a,0x76,0x44,0x85,0x85,0xf6,0x98, - 0xd8,0xdd,0x89,0x4a,0xbf,0x93,0x01,0xbd,0x07,0x5b,0x5d,0x3f,0x85,0xa3,0x89,0xc9, - 0xd1,0xbf,0xf0,0xb6,0x77,0x75,0x4b,0x92,0x05,0x68,0x2b,0x47,0x17,0x0d,0x9f,0x96, - 0xee,0x95,0xe5,0x01,0xd9,0x0b,0xe4,0xa9,0xbe,0x5b,0x69,0x29,0x3e,0xe6,0xd2,0xa4, - 0x81,0xa5,0xe9,0x20,0xb7,0x63,0x69,0x9f,0x6e,0x16,0xad,0x4c,0x6e,0x4c,0xbe,0x2c, - 0x9f,0x17,0x7e,0x66,0xaf,0x97,0xb6,0x13,0x1d,0x55,0xb5,0xdc,0x84,0xc4,0xbd,0x23, - 0x38,0x8f,0xaf,0xca,0xbe,0x6e,0xa3,0xc3,0x45,0xd7,0xa4,0x11,0x69,0x24,0xfa,0x22, - 0x6a,0x14,0xe2,0x4b,0x50,0x82,0x58,0xf4,0x0f,0xdf,0xfd,0xf4,0xd3,0xe1,0xfb,0x43, - 0x2f,0x58,0xe7,0xeb,0x7e,0xc3,0xb9,0x09,0x8b,0x86,0xd2,0x37,0x37,0xf8,0x1b,0xd0, - 0xdc,0x8b,0x27,0x55,0x9f,0xb3,0x4f,0xb8,0x81,0x7b,0x73,0x73,0x8f,0x97,0x0d,0xdf, - 0x9a,0x4e,0xa3,0xca,0x0f,0x88,0xfd,0x4c,0x43,0x3d,0xbc,0x77,0xbc,0xbd,0x96,0x2b, - 0xad,0xd5,0x8b,0xb8,0xae,0x36,0x78,0x1f,0xaf,0x61,0x31,0xeb,0xf4,0x29,0x82,0xe2, - 0x1c,0x4a,0x17,0x36,0x11,0x13,0x03,0xeb,0x1e,0xf4,0x1b,0x4d,0x1c,0x1f,0x1f,0xc1, - 0xc2,0xe0,0xbc,0x7a,0x0a,0x76,0xb6,0x1d,0x48,0xa7,0x92,0x8d,0x60,0xaf,0xd1,0x2e, - 0xfb,0x64,0xbd,0x6b,0x0e,0xf6,0xbd,0x2f,0x73,0xfb,0x9b,0x1d,0xab,0xea,0x7b,0x25, - 0xb6,0x2d,0xf6,0xe3,0x39,0x3b,0xd3,0x0a,0x25,0x56,0x59,0x6f,0x72,0x8b,0xec,0xb0, - 0xe6,0x57,0xe7,0x69,0x60,0xee,0x98,0x6d,0xed,0x98,0x3d,0x67,0x7b,0xc5,0xe9,0x15, - 0x06,0x44,0x67,0x82,0x90,0x1b,0xc2,0xf8,0xc2,0xd2,0x0b,0xb9,0x77,0x6c,0x06,0xb6, - 0x19,0xbc,0xad,0x9d,0x6a,0x26,0x99,0x9d,0x77,0x50,0x2b,0x3e,0x9a,0x8d,0x64,0xac, - 0xd6,0xbe,0x42,0x92,0x36,0x86,0x5a,0xc6,0x1e,0xd6,0xfd,0x2a,0x49,0x4d,0x88,0x58, - 0x93,0x33,0x9f,0xab,0x58,0x16,0x9d,0x35,0x1c,0xe8,0x5c,0x5f,0x53,0xdd,0xca,0xb9, - 0xca,0x86,0x84,0x2e,0x02,0xda,0x5a,0x47,0xe6,0x9a,0x2c,0x2d,0x01,0x3f,0x1b,0x8d, - 0xb0,0xf2,0x27,0xaf,0x74,0x9e,0x1c,0x3d,0x32,0x95,0xa5,0x02,0x14,0xdb,0x57,0xc2, - 0x4c,0x5e,0x18,0x6f,0x85,0x4a,0xb3,0x5b,0x1d,0x63,0x52,0x29,0xcb,0x94,0x6d,0x86, - 0x3b,0xbf,0xd5,0x3b,0xa9,0xd3,0xb5,0x68,0x27,0xdf,0x1b,0xf5,0xc5,0x3e,0x9c,0xca, - 0x18,0xd2,0xb2,0x0c,0xb5,0x7a,0x33,0xbb,0x52,0x1b,0x88,0x4c,0x7e,0xb2,0xda,0x5d, - 0xa3,0x1d,0xcc,0xaf,0x6b,0xda,0x31,0xfd,0x4a,0xd0,0x87,0x8e,0x9b,0xe1,0xfd,0x7a, - 0x31,0xd6,0xc5,0xde,0x25,0xef,0xd9,0x97,0xc9,0x7e,0x21,0x19,0xf9,0x4a,0x65,0xcd, - 0x76,0x7d,0x12,0xb6,0xc7,0x43,0x9f,0x35,0x10,0xe3,0xa1,0xc9,0x33,0xd7,0x65,0xc3, - 0xb1,0x4c,0x31,0x9c,0xd2,0xd5,0xb3,0x44,0x6b,0x56,0x41,0x0c,0xad,0x4c,0x6a,0xcc, - 0x20,0x72,0x06,0x5d,0x96,0x91,0xac,0x58,0x30,0x91,0xae,0x76,0xf2,0x71,0xeb,0xb0, - 0x09,0x07,0x97,0x9e,0x8a,0xb5,0x9f,0x39,0x42,0xe2,0x2a,0x2b,0xb9,0x79,0x98,0x97, - 0xb8,0x19,0xe3,0xa6,0x72,0x69,0xc3,0xd7,0x48,0x2e,0xdb,0xd5,0xc9,0x70,0x0b,0x66, - 0xcd,0x2b,0xe2,0x5e,0xf9,0xe2,0x14,0x9d,0x41,0x45,0x5f,0xa2,0x12,0x4d,0xd9,0x17, - 0x25,0x67,0x27,0x60,0xe1,0x06,0x59,0xe4,0x5b,0x10,0xe1,0x59,0xca,0x15,0x80,0x92, - 0x02,0x0a,0x41,0x5a,0x95,0xbe,0xae,0x3a,0x61,0x67,0x12,0x86,0x41,0x62,0x0f,0xe5, - 0xe6,0x23,0xd7,0xbb,0xc5,0x29,0xb8,0xe1,0x36,0xa6,0xee,0xd8,0xd3,0x91,0xca,0xea, - 0x14,0x9e,0xfc,0x94,0xfd,0x94,0xf1,0x52,0x29,0xde,0x59,0x0f,0xc0,0xba,0x29,0x50, - 0x21,0x0c,0x97,0x77,0xf9,0xc0,0xdd,0xb9,0x95,0x30,0x70,0x9e,0x98,0xfb,0x69,0x58, - 0xc9,0x97,0x67,0xfa,0xe2,0xf7,0x84,0xc6,0xb5,0x99,0xd7,0xc1,0x8f,0x8d,0xe0,0x37, - 0xdd,0xa0,0x5a,0xc2,0xd9,0xa6,0x40,0x96,0x21,0xc4,0xa7,0xe8,0x14,0x58,0x1c,0xf4, - 0x52,0x56,0x45,0x7e,0x05,0x59,0xfa,0x7b,0x7d,0x59,0x87,0x59,0x1c,0x7d,0x0d,0xbd, - 0x74,0xae,0xdb,0x33,0x6b,0x8f,0x95,0x6d,0xc6,0x1b,0xe8,0x14,0x60,0xe5,0x32,0x5a, - 0xc7,0x8e,0x72,0x37,0x9a,0xd6,0xd1,0xaf,0x63,0x49,0x27,0x1d,0xb1,0xbf,0x93,0x75, - 0xbb,0x7d,0xf3,0x4e,0x7b,0xde,0x2d,0x69,0x8d,0xe3,0xf2,0xb4,0x69,0x42,0xee,0x63, - 0x92,0x35,0x50,0xb7,0x36,0x21,0x50,0x4a,0xec,0x12,0x81,0xf1,0xb6,0xae,0x2f,0x7e, - 0x74,0x1b,0x01,0xdf,0x1c,0xbd,0xff,0xd1,0x80,0x32,0xa9,0xd9,0x0e,0x28,0xfb,0x3b, - 0x38,0xe6,0xed,0x7a,0x6b,0x1a,0x57,0x3d,0x93,0xce,0x18,0xbb,0x72,0xe5,0x0c,0x2c, - 0xad,0x87,0xd8,0x04,0x32,0x62,0xcb,0x6d,0xf7,0x3d,0x95,0xd2,0xda,0xb8,0xef,0x59, - 0xc4,0xb0,0xe5,0xc9,0xd7,0xa5,0x53,0xdc,0x09,0x35,0xda,0x75,0xbf,0xb3,0x06,0x6b, - 0xe7,0xd0,0x6e,0x19,0x82,0xbb,0x63,0x9e,0x0d,0x5e,0xb9,0xdd,0x8d,0xbe,0x88,0xe7, - 0xb9,0xc2,0x7c,0x77,0x34,0x89,0x5b,0x16,0x63,0x0f,0xb5,0x05,0x09,0xf2,0xa3,0xb1, - 0x83,0xf3,0x7b,0x45,0x4a,0x2c,0x3c,0x8c,0xd7,0x75,0x38,0xb6,0x7d,0x55,0xe4,0x98, - 0xad,0x15,0x1f,0x08,0xf1,0x94,0xac,0x92,0x01,0x82,0x59,0xb1,0x99,0xf8,0x49,0x46, - 0xf4,0x24,0xe1,0x0b,0x42,0x91,0x86,0xac,0x70,0x38,0xbe,0x73,0x00,0x24,0x47,0x14, - 0x18,0x39,0xea,0x4d,0x52,0x5c,0x6b,0x76,0xb0,0xc5,0xe3,0x5b,0x83,0xa8,0x35,0xc9, - 0xb4,0x7c,0x83,0x8a,0x43,0x79,0x55,0xb2,0xf1,0x56,0xee,0xb6,0xc4,0x51,0xd4,0xe1, - 0x8f,0xa2,0xdf,0xdf,0x64,0x2a,0x83,0xb5,0x2f,0xe1,0xcc,0x49,0x9d,0x18,0x5d,0x6e, - 0xcc,0x84,0x25,0x44,0xf9,0xd4,0xc9,0x01,0x15,0xc1,0x3e,0xe1,0xf4,0x41,0x6c,0xcf, - 0x82,0x16,0x1f,0xe6,0xc1,0x6c,0x8e,0x9c,0x76,0xd9,0xd9,0x86,0xa8,0x77,0x7d,0x25, - 0x55,0xa4,0x4e,0x8e,0x24,0x61,0xa2,0x83,0x8b,0x34,0x54,0x34,0x45,0x4e,0xd9,0xbf, - 0x9b,0xcc,0x83,0x47,0xd0,0x48,0x0c,0x02,0xfc,0xa7,0xb3,0x6c,0x37,0xb9,0x0e,0x6c, - 0xcb,0x3b,0x95,0x93,0xa5,0x42,0x9e,0x93,0x3a,0xe5,0xc9,0xfb,0x8e,0x0c,0x14,0x0c, - 0x1b,0xdd,0xdd,0xc6,0xcd,0xf4,0x21,0xb7,0x66,0x0e,0xb1,0x12,0xce,0xd7,0x57,0x0e, - 0x34,0x53,0xa0,0x00,0x68,0xeb,0x81,0xa9,0x3c,0x27,0x92,0xa3,0xe4,0xef,0x3f,0xa8, - 0xd6,0x20,0xec,0x5c,0x26,0x7a,0x1c,0xb7,0xac,0x73,0x77,0xd2,0x14,0x30,0x6f,0x17, - 0x1c,0xb6,0xab,0x0d,0x4c,0xb7,0x41,0x5a,0x67,0x31,0xee,0x50,0xf9,0x29,0xb6,0x72, - 0x30,0x6a,0xad,0xa9,0xa5,0x15,0x86,0x9c,0x3f,0x76,0x2c,0x57,0xe6,0x62,0x16,0x3e, - 0x56,0x14,0x66,0xb0,0x29,0xd2,0xe3,0xc0,0x70,0x00,0x8c,0x87,0x89,0x35,0x30,0x57, - 0x99,0xaa,0x0b,0xf2,0xdc,0x52,0x5f,0x6a,0xaa,0xd5,0x63,0xb0,0x8b,0xf2,0xa5,0x68, - 0x44,0x5f,0x94,0x17,0x44,0x7f,0x59,0x55,0xeb,0x92,0x93,0x2b,0xd6,0x9d,0x8b,0xde, - 0x86,0x9a,0xe6,0xaf,0x9e,0x7d,0x0b,0x00,0x9d,0x83,0x6f,0xdf,0x4a,0xe8,0x35,0xab, - 0x8c,0x08,0x13,0x49,0xc6,0x40,0xc6,0xe6,0x46,0x8d,0xb4,0xa7,0x02,0x32,0x55,0x22, - 0x3b,0xee,0x13,0xef,0xd5,0xb3,0x51,0x45,0x2b,0x4c,0x2b,0x9c,0x3a,0x13,0x4e,0x7d, - 0x05,0x48,0x9d,0x98,0xd2,0xd2,0x25,0xab,0x4b,0xe3,0xa2,0xf4,0xbc,0xd4,0x34,0x5b, - 0xeb,0x8c,0x8d,0xb2,0x49,0xcd,0xde,0x84,0x1a,0x19,0xea,0x69,0xf1,0xee,0x6a,0xe1, - 0xa1,0x94,0xfb,0xa1,0x48,0xfb,0x65,0x31,0xfb,0x34,0xef,0x2e,0x88,0x58,0xb9,0x2b, - 0x6a,0xad,0x0b,0xe3,0xac,0xdd,0xed,0x33,0x6a,0x00,0xb9,0xbe,0x6a,0x1d,0x52,0x0f, - 0x75,0xca,0xd8,0x13,0x4e,0x17,0x7b,0xe2,0xee,0x13,0x91,0x38,0x71,0xeb,0x9c,0x93, - 0x54,0xe8,0x80,0x0a,0x1f,0xf0,0x1d,0x96,0xe1,0x68,0x27,0xec,0xa6,0xb0,0x18,0x77, - 0x2b,0x16,0x6d,0x38,0x69,0x51,0xc1,0xce,0x94,0xc7,0x73,0x3b,0xdf,0x2a,0xf4,0x95, - 0x21,0xf2,0xfb,0x03,0x30,0xd5,0x75,0x5a,0x2d,0xcd,0x47,0x66,0x6b,0x53,0x8c,0xb6, - 0xc6,0xfb,0xcd,0xa1,0xd6,0xc6,0x6c,0xad,0x5c,0x40,0x12,0x59,0xa9,0xce,0x81,0x1e, - 0x15,0x7f,0xed,0x60,0xbc,0x35,0xeb,0x2d,0x95,0x56,0xd1,0xba,0xab,0x53,0xe2,0xaf, - 0xd9,0x27,0x9b,0x19,0xeb,0xcc,0xd7,0x3e,0xd9,0x2d,0x46,0xda,0x92,0x1c,0x3f,0xce, - 0x4b,0x77,0x71,0xd3,0x77,0xd3,0x8a,0x7c,0xca,0x7d,0xf3,0x8e,0x81,0x5a,0x8d,0x10, - 0x47,0xb3,0xd1,0x7c,0x2d,0x69,0x67,0x80,0x82,0x36,0x88,0xdb,0x32,0xfc,0x2e,0x38, - 0xdc,0x0e,0x09,0x88,0xac,0x31,0xa1,0xf4,0x9d,0xd5,0xa7,0x6c,0xd0,0x5b,0x84,0xb5, - 0xe4,0x3e,0x7d,0x5f,0xdb,0xe1,0x95,0xad,0x8f,0xa5,0x97,0x7a,0xcd,0x9a,0xed,0xed, - 0xb0,0x2d,0x9d,0x86,0xd0,0x5a,0x82,0x13,0x14,0xc1,0xa7,0xa5,0xce,0x49,0x6b,0x37, - 0xfe,0xd7,0x29,0x06,0x44,0x28,0xda,0x7e,0x3c,0xa3,0x78,0x97,0x87,0xe0,0x4e,0x4a, - 0x71,0x19,0xa0,0xe6,0xe3,0xcd,0xb1,0xe6,0xab,0x62,0x14,0xb3,0x2e,0xdc,0x74,0x02, - 0x2f,0x73,0x66,0x82,0xa3,0x0b,0x9a,0x2c,0x08,0xfa,0x89,0x7d,0x53,0x89,0x88,0xa5, - 0x9d,0xb8,0x9e,0x9d,0xf5,0x5f,0x3f,0xf9,0xfa,0x77,0x3b,0xd8,0x9d,0xb0,0xba,0x7c, - 0x85,0x8a,0xed,0x58,0x5b,0x23,0xde,0x6a,0x54,0xa9,0x51,0x2d,0x7b,0x60,0x23,0x9b, - 0x93,0x5f,0xdf,0x3e,0xd3,0x8a,0x04,0x28,0xcd,0x75,0x3b,0xb8,0x58,0x09,0x2a,0x6e, - 0xc6,0xa1,0xfa,0x26,0x47,0x22,0x78,0xcc,0xf2,0x6b,0x8c,0x09,0x5a,0xa3,0x1c,0x0e, - 0xd6,0x0d,0x0b,0x2b,0x5f,0x09,0x0c,0x4a,0x21,0x96,0x42,0x1a,0x56,0xa9,0x93,0x6c, - 0x22,0xeb,0x36,0x0f,0x06,0x9c,0x2d,0xb2,0x7c,0xb2,0xf9,0x4f,0x5d,0xab,0x63,0x5f, - 0xd1,0xd4,0x33,0xdd,0x4a,0xea,0x2e,0xc6,0xff,0x9c,0xe8,0x54,0x52,0x72,0x41,0x92, - 0xe9,0x89,0x69,0x45,0x59,0x35,0x9b,0x1a,0x1b,0x43,0x55,0xb5,0xee,0xda,0x52,0xda, - 0x20,0x3b,0xa3,0x52,0xda,0xe8,0x64,0x35,0x38,0x48,0x9c,0xab,0x31,0x87,0x0e,0x4a, - 0x2e,0xfa,0x2e,0xe1,0x83,0xa7,0x39,0x34,0x96,0x9c,0x90,0x35,0x44,0xdf,0x59,0x25, - 0x46,0xda,0xc4,0x98,0x7f,0x9e,0xf0,0x92,0x51,0x79,0xf6,0xae,0x82,0xce,0xc5,0x8a, - 0xcf,0xba,0x8a,0x2b,0xeb,0x82,0x51,0x9a,0xf4,0x9a,0x2f,0x8a,0x51,0xc9,0x4e,0x4d, - 0x7e,0x16,0x1a,0x7a,0x25,0x17,0x96,0x42,0xcf,0x4e,0xe3,0x66,0xf3,0xcb,0xd1,0xf0, - 0xa8,0xb1,0x34,0xec,0x3e,0x0e,0xc2,0xc4,0xd9,0xe5,0x95,0xef,0xfd,0x0c,0xf2,0xfb, - 0x7c,0x4c,0x68,0x15,0xdc,0x21,0x43,0x9a,0x92,0xd1,0xe3,0xf9,0x19,0x73,0xa2,0x92, - 0x36,0xbd,0xc4,0x08,0xa2,0x8a,0xbd,0xf1,0xd7,0xec,0x73,0x2e,0x5d,0x6b,0xaf,0x42, - 0x46,0x62,0xe5,0x2e,0xcd,0xfb,0x31,0x59,0x5b,0x64,0x4f,0x30,0x29,0x9f,0x11,0xf1, - 0xa6,0xd0,0x9e,0x14,0x9a,0xe2,0xf1,0xf3,0x89,0xcb,0x03,0xd1,0xbc,0x2f,0x16,0x1f, - 0x14,0xae,0xf6,0xde,0x6f,0xbc,0xf6,0x1a,0x14,0xad,0x2b,0x1e,0xfb,0x76,0xba,0x66, - 0x05,0x62,0xd3,0x6a,0xd9,0xaa,0x67,0x1e,0xc8,0x71,0xf8,0x60,0xb8,0x1b,0x81,0xad, - 0x3b,0xe7,0x4b,0x61,0xf9,0x54,0x9a,0xe1,0xea,0x8b,0x8b,0xec,0x3b,0x8b,0x38,0xe1, - 0x90,0xdb,0x8e,0xcc,0xbe,0xcd,0x98,0xdb,0xf0,0x58,0x81,0x71,0x97,0x63,0x00,0x2d, - 0x44,0x78,0x9b,0xa6,0xf2,0x23,0xeb,0x0d,0x3f,0x97,0xb6,0x27,0xf6,0x27,0xa3,0xcb, - 0x35,0x83,0xc5,0x1a,0x0e,0x5c,0x3b,0xe6,0x1e,0xe8,0xd5,0xc2,0x95,0xac,0x4d,0x54, - 0xa9,0x09,0xc0,0x2e,0xce,0xb7,0x03,0x0f,0xeb,0x45,0xa8,0x79,0xd7,0x77,0x0d,0x7a, - 0xe0,0x9a,0xe0,0x4b,0xef,0xfd,0x1d,0xe3,0x0b,0x3f,0xa1,0xc6,0x6b,0x4d,0x63,0x17, - 0x6b,0x36,0x1c,0x61,0xf9,0xfe,0x2e,0xc5,0x9d,0xd1,0x19,0x78,0xc5,0x2e,0x86,0xca, - 0xb1,0x8d,0x0d,0x98,0x10,0x09,0xc7,0x16,0xd2,0xfb,0xe1,0xcd,0x4b,0xf1,0x32,0xe4, - 0xb4,0x4e,0x27,0x04,0x8f,0xe1,0x07,0x8c,0xbf,0x57,0x3b,0xf4,0x4d,0x95,0x27,0x21, - 0xb2,0x8c,0x47,0xe7,0x4a,0xeb,0x25,0xc6,0xd3,0xc0,0x79,0x0a,0x74,0xc7,0xba,0x13, - 0x75,0xcb,0xa3,0x42,0xa3,0x8c,0x66,0x41,0x1a,0xe7,0x4e,0x6f,0x1a,0x95,0xc9,0xac, - 0x94,0x56,0x8d,0x9a,0x44,0x63,0x5a,0x39,0xfb,0x9a,0xe3,0x46,0x86,0x51,0x80,0x5d, - 0xef,0x90,0x4b,0x6b,0x47,0x87,0x5a,0xe8,0x8d,0xf8,0xb2,0x5b,0x6d,0x83,0xa3,0xa9, - 0xbe,0xa6,0x59,0x31,0xbb,0x28,0x96,0x05,0x30,0x8b,0xef,0x86,0xef,0xf5,0xd3,0x67, - 0xfc,0xa4,0x04,0xee,0xc3,0x77,0xc1,0xe1,0x7b,0xdb,0x1c,0xa3,0xaa,0x7b,0x5e,0x27, - 0xec,0x59,0x41,0x43,0xbb,0xec,0x2f,0xaf,0xbc,0x19,0x42,0x11,0xad,0x98,0x2f,0xa0, - 0xd5,0x3c,0x8d,0x81,0x96,0xf9,0x55,0xd9,0x27,0x84,0x25,0xbe,0x68,0x25,0xbf,0xf5, - 0xe4,0xfe,0x2a,0xaa,0x82,0x0d,0x44,0x56,0x0d,0x55,0x79,0x7f,0xff,0xf0,0x8f,0x2c, - 0x58,0x9c,0x8c,0x7f,0x3a,0xfc,0xe9,0xf0,0xd0,0x1a,0x1e,0x7d,0xf5,0xf4,0x76,0x3e, - 0x03,0xb3,0x4f,0x6f,0x45,0x23,0xaf,0xf2,0x89,0x41,0xb6,0x80,0x27,0x77,0x11,0xab, - 0x61,0x4e,0xd8,0xf6,0xe6,0x5c,0x48,0xda,0x69,0x95,0xc9,0x58,0x12,0x3b,0x13,0x17, - 0xa6,0x97,0x0e,0x78,0x5d,0x8f,0xb9,0x1e,0x27,0xc7,0xed,0x62,0xde,0x7c,0x35,0x6e, - 0x69,0xcd,0x25,0x10,0x75,0x98,0x19,0x3d,0x15,0x49,0x80,0x9f,0xae,0x02,0xb8,0x6d, - 0x45,0xb3,0x18,0xd1,0x67,0x71,0x5f,0xbf,0xe4,0x70,0x29,0xdf,0x75,0x7d,0x6e,0x08, - 0xa0,0xc7,0xa1,0xa9,0x56,0xb3,0xf2,0x9b,0x88,0xc3,0x52,0x1b,0xa0,0x91,0x17,0x41, - 0x7c,0x8a,0x09,0x92,0xc7,0xf6,0xd5,0x58,0x1e,0xdf,0x5c,0xc8,0x13,0x90,0xa4,0x0a, - 0xf5,0x65,0x22,0xe2,0x34,0xc6,0x74,0xa3,0xbe,0x97,0x4e,0x1b,0xb4,0x33,0xce,0xaf, - 0x65,0xb9,0x7b,0x12,0xe4,0xaa,0x54,0x37,0xf5,0x9d,0x24,0x4a,0x57,0x24,0x86,0x02, - 0x22,0x9b,0x44,0x49,0xea,0x94,0x5b,0x44,0xc0,0x82,0xfa,0xa2,0x5d,0x5c,0x99,0xa7, - 0x77,0x85,0x13,0x7f,0xe8,0x2c,0xcd,0x04,0x0c,0xfa,0xca,0x8a,0xc7,0x87,0xe2,0xa6, - 0x72,0xfc,0xf8,0x10,0x14,0x91,0xfe,0x59,0x56,0xab,0xf4,0xf8,0xff,0x02,0xa7,0x32, - 0xf1,0x7a,0x6c,0xa7,0x00,0x00, + 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, }; constexpr size_t PATTERNS_INDEX_HTML_GZ_LEN = sizeof(PATTERNS_INDEX_HTML_GZ); // diff --git a/firmware/toolchain/console_demo.py b/firmware/toolchain/console_demo.py new file mode 100644 index 00000000..dad45d86 --- /dev/null +++ b/firmware/toolchain/console_demo.py @@ -0,0 +1,1284 @@ +"""The device console as static files, for the guide's live demo. + + python firmware/toolchain/console_demo.py # write web/public/guide/console-demo/ + python firmware/toolchain/console_demo.py --check # is what is there current? + +The guide at /guide shows the console a core board serves - the real pages, +not screenshots - in a window over the page, wired to the 3D board beside it. +This writes what that window loads: + + index.html patterns.html status.html wifi.html knobs.html update.html + the core's pages, stamped exactly as console_pages.py + stamps them into their headers (console_serve.py serves + them the same way), plus two edits to their : the + chrome's src made relative, and pf-demo.js loaded first + pf-console.js the shared chrome, the PF_CONSOLE_JS literal as the panel + sends it + fflate.js the zip library /patterns loads, the FFLATE literal + pf-demo.js the device: every endpoint those pages and the chrome + call, answered from state kept in sessionStorage, and the + bridge to the guide (its header comment documents both) + +Nothing in a page or in the chrome is rewritten beyond those two tags: the +pages still ask for /api/status, /patterns and the rest, and pf-demo.js +answers them, so the demo is the console as it is, not a copy of it. + +Which pages: the ones console_pages.py builds into src/ headers - a core build +serves those and no feature's. What the board says about itself comes from +where the truth already lives, so a release moves the demo with it: + + version, hostname, hotspot net_config.h + build id the core image in web/public/flash/bin (the + ELF SHA-256 at 0xb0, as src/core_build.h reads it) + newest release web/public/flash/manifest.json + brightness config.h DEFAULT_BRIGHTNESS + Wi-Fi slots src/core_wifi.h MAX_NETWORKS + modules, names, sizes, order web/public/packs/basics.zip (read here; not copied: + the folder has a budget, and the pack's bytes + would be a third of it for "Download ZIP" alone) + the board's address web/src/lib/guide/deviceSim.ts SIM_IP + +Rerun it after any change to a console page, the chrome, the fallback shim, +those sources, or MOCK_JS below; `--check` exits 1 when the folder is stale +(page/chrome/pack edits land there, and the next release bumps the version). +The folder is this script's alone: it is emptied and rewritten each run. +""" + +import argparse +import hashlib +import json +import os +import re +import sys +import zipfile + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +import console_pages # noqa: E402 the stamp is its code, not a copy of it +import console_serve # noqa: E402 the chrome's source and the device's routes + +REPO = os.path.normpath(os.path.join(HERE, "..", "..")) +SKETCH = console_serve.SKETCH +WEB = os.path.join(REPO, "web") +OUT = os.path.join(WEB, "public", "guide", "console-demo") +BUDGET = 350 * 1024 # the whole folder, bytes on disk + +# The neighbours a channel scan would hear, once the hotspot has come up +# (/api/hotspot "seen"). The panel's own network first; the rest are the +# default names routers ship with here. +NEIGHBOURS = [("iptime", -71), ("U+Net4E21", -77), ("SK_WiFiGIGA7A1C", -83)] +ALIAS = "patternflow-5c2e" # PF_OTA_HOSTNAME + the last two MAC bytes +FS_TOTAL = 10240000 # FFat.totalBytes() of the 0x9E0000 ffat partition, off a real panel +FLASH_ID = "c84018" + + +def read(path): + with open(path, encoding="utf-8", newline="") as f: + return f.read() + + +def define(rel, name): + m = re.search(r'#define\s+%s\s+("?)([^"\s]+)\1' % name, read(os.path.join(SKETCH, rel))) + if not m: + raise SystemExit("%s: no #define %s" % (rel, name)) + return m.group(2) + + +def core_pages(): + """(device path, page name, file) for every page the core serves: the + console_pages.py targets whose header lives in src/, in nav order.""" + path_of = {name: path for path, name in console_serve.ROUTES.items()} + out = [] + for name, rel in console_pages.PAGES: + if not rel.startswith("src/"): + continue + if name not in path_of: + raise SystemExit("console_serve.ROUTES has no path for the core page %s" % name) + path = path_of[name] + out.append((path, name, "index.html" if path == "/" else name + ".html")) + return out + + +def core_image(): + """The app image the flasher installs for this release, from its manifest.""" + manifest = json.loads(read(os.path.join(WEB, "public", "flash", "manifest.json"))) + for build in manifest.get("builds", []): + for part in build.get("parts", []): + if part.get("offset") == 0x10000: + return manifest, os.path.join(WEB, "public", "flash", part["path"].replace("/", os.sep)) + raise SystemExit("flash/manifest.json names no app image at 0x10000") + + +def build_id(image): + """PFBuild::id(): the first four bytes of the ELF SHA-256 esptool stamps + into esp_app_desc_t, 0xb0 into the image.""" + with open(image, "rb") as f: + head = f.read(180) + if len(head) < 180 or head[0] != 0xE9: + raise SystemExit("%s: not an ESP32 app image" % image) + return head[176:180].hex() + + +def basics(): + """(modules [{slug, name, pfm, json}], catalog [slugs]) off the pack.""" + path = os.path.join(WEB, "public", "packs", "basics.zip") + z = zipfile.ZipFile(path) + sizes = {i.filename: i.file_size for i in z.infolist()} + mods = [] + for name in sorted(sizes): + if not name.endswith(".pfm"): + continue + slug = name[:-4] + side = slug + ".json" + display = slug + if side in sizes: + display = json.loads(z.read(side).decode("utf-8")).get("name") or slug + mods.append({"slug": slug, "name": display[:39], "pfm": sizes[name], + "json": sizes.get(side, 0)}) + catalog = [] + if "catalog.txt" in sizes: + for line in z.read("catalog.txt").decode("utf-8").splitlines(): + line = line.strip() + if line and not line.startswith("#"): + catalog.append(line) + return mods, catalog + + +def sim_ip(): + text = read(os.path.join(WEB, "src", "lib", "guide", "deviceSim.ts")) + m = re.search(r'export const SIM_IP = "([0-9.]+)"', text) + if not m: + raise SystemExit("deviceSim.ts: no SIM_IP") + return m.group(1) + + +def guide_ssid(): + """The network the guide's flashing step joins (Extras.tsx, WifiForm).""" + try: + m = re.search(r'const ssid = "([^"]+)"', + read(os.path.join(WEB, "src", "components", "guide", "Extras.tsx"))) + if m: + return m.group(1) + except OSError: + pass + print(" note: Extras.tsx names no ssid; using Studio_2.4G", file=sys.stderr) + return "Studio_2.4G" + + +def seed(): + manifest, image = core_image() + mods, catalog = basics() + pages = core_pages() + ssid = guide_ssid() + s = { + "version": define("net_config.h", "PF_IMPROV_FW_VERSION"), + "build": build_id(image), + "manifestVersion": str(manifest.get("version", "")).lstrip("v"), + "host": define("net_config.h", "PF_OTA_HOSTNAME"), + "alias": ALIAS, + "ip": sim_ip(), + "ssid": ssid, + "neighbours": [[ssid, -48]] + [[n, r] for n, r in NEIGHBOURS], + "hotspotPass": define("net_config.h", "PF_HOTSPOT_PASS"), + "maxNetworks": int(re.search(r"MAX_NETWORKS\s*=\s*(\d+)", + read(os.path.join(SKETCH, "src", "core_wifi.h"))).group(1)), + "brightness": int(define("config.h", "DEFAULT_BRIGHTNESS")), + "fsTotal": FS_TOTAL, + "flashId": FLASH_ID, + "modules": mods, + "catalog": catalog, + "pages": {path: f for path, _, f in pages}, + "assets": {"/pf-console.js": "pf-console.js", "/patterns/fflate.js": "fflate.js"}, + } + s["id"] = hashlib.sha1(json.dumps(s, sort_keys=True).encode()).hexdigest()[:10] + return s, pages + + +def demo_page(html, name, chrome_crc, shim, mock_tag): + """A page as its header carries it, with the chrome's src made relative + and the device loaded before it.""" + text = console_pages.stamp(html, chrome_crc, shim, name) + src = '' % ( + __import__("zlib").crc32(mock) & 0xFFFFFFFF) + crc = console_pages.crc_of(chrome) + shim = console_pages.load_shim() + files = { + "pf-console.js": payload(chrome), + "fflate.js": payload(fflate), + "pf-demo.js": mock, + } + for _, name, fname in pages: + html = read(os.path.join(console_serve.HTML_DIR, name + ".html")) + files[fname] = payload(demo_page(html, name, crc, shim, mock_tag)) + total = sum(len(b) for b in files.values()) + if total > BUDGET: + raise SystemExit("console demo is %d bytes, over the %d budget" % (total, BUDGET)) + return files, total + + +def main(): + for stream in (sys.stdout, sys.stderr): + try: + stream.reconfigure(encoding="utf-8", errors="replace") + except (AttributeError, ValueError): + pass + ap = argparse.ArgumentParser(description="Write the guide's console demo.") + ap.add_argument("--check", action="store_true", help="exit 1 if the folder is stale") + args = ap.parse_args() + files, total = render() + if args.check: + have = set(os.listdir(OUT)) if os.path.isdir(OUT) else set() + stale = sorted(n for n, b in files.items() + if n not in have or open(os.path.join(OUT, n), "rb").read() != b) + stale += sorted(have - set(files)) + if stale: + print("console demo is stale: %s\nrun: python firmware/toolchain/console_demo.py" + % ", ".join(stale)) + sys.exit(1) + print("console demo current (%d files, %d bytes)" % (len(files), total)) + return + os.makedirs(OUT, exist_ok=True) + for n in os.listdir(OUT): + p = os.path.join(OUT, n) + if os.path.isfile(p): + os.remove(p) + for n, b in sorted(files.items()): + with open(os.path.join(OUT, n), "wb") as f: + f.write(b) + print("wrote %d files, %d bytes -> %s" % (len(files), total, os.path.relpath(OUT, REPO))) + for n, b in sorted(files.items()): + print(" %-14s %7d" % (n, len(b))) + + +# ── the device ───────────────────────────────────────────────────────────── +# pf-demo.js, with /*SEED*/null replaced by seed() above. + +MOCK_JS = r'''/* Patternflow console demo: a core board, simulated in the page. + * GENERATED by firmware/toolchain/console_demo.py -- edit MOCK_JS there, rerun. + * + * Loaded first on every page of the demo, before the console's own chrome + * (pf-console.js), which therefore wraps this fetch instead of the browser's. + * The pages and the chrome are the device's, unmodified: they ask for + * /api/status, /api/patterns, /update/status ... and this answers them the way + * the firmware does (the handlers below cite the C++ they follow), from one + * board's state in sessionStorage - so every demo page and every demo frame + * in the tab sees the same board, and it survives navigation and reloads. + * + * fetch / XMLHttpRequest device URLs are answered here; the demo's own + * files go to the network; anything else fails + * like an offline LAN (and is logged). Nothing + * leaves /guide/console-demo/. + * links, + +Patternflow + + + + + +
+

Console

device
+ + + +
+
+
+
+ Now playing + +
+ + +
+
+
—
+
+ + +
+ Panel +
+ + +
+
+
+
+ Brightness + + — +
+ +
+
+ Live Knobs + +
+
+ K1 + +
+
+ K2 + +
+
+ K3 + +
+
+ K4 + +
+
+ +
+
Patterns
—
+
Storage
—
+
+
Wi-Fi
—
+
Address
—
+ + +
Memory
—
+
Uptime
—
+
Firmware
—
+ + + Edition +
—
+
+
+
+
+ + + + update + how to update → +
+ + +
+ + +
+ + + diff --git a/web/public/guide/console-demo/knobs.html b/web/public/guide/console-demo/knobs.html new file mode 100644 index 00000000..28fe630e --- /dev/null +++ b/web/public/guide/console-demo/knobs.html @@ -0,0 +1,145 @@ + + + + + +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.

+
+ +
+ diff --git a/web/public/guide/console-demo/patterns.html b/web/public/guide/console-demo/patterns.html new file mode 100644 index 00000000..2a748e13 --- /dev/null +++ b/web/public/guide/console-demo/patterns.html @@ -0,0 +1,966 @@ + + + + + +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.

+
+ + +
+
+ +
+
+
+

Upload

+ +
    +
    +
    +
    + +
    +
    +
    + +
    +
    +

    Installed

    +
    + + + + + +
    +
    +
      +
      +
      +
      + + +
      + \ 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 new file mode 100644 index 00000000..696f93fa --- /dev/null +++ b/web/public/guide/console-demo/pf-console.js @@ -0,0 +1,419 @@ +(function(){ +if(window.PF)return; +var W=window,D=document,H=D.documentElement,L=location,light=false; +// 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))}' ++'@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}'; +(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='', +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; +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()} +function call(f,a,b){try{f(a,b)}catch(x){setTimeout(function(){throw x})}} +function ev(n,d){D.dispatchEvent(new CustomEvent(n,{detail:d}))} +function drop(e){var i=T.indexOf(e);if(i>-1)T.splice(i,1)} + +// fetch wrapper: same-origin GETs get a controller a tab switch can abort. +function tf(u,o,k){ +var c=new AbortController(),e={c:c,u:new URL(u,L.href).href,t:now(),k:k},i={},n; +for(n in o)i[n]=o[n]; +i.signal=c.signal; +for(n=T.length;n--;)if(e.t-T[n].t>6e4)T.splice(n,1); +T.push(e);if(cur)cur.push(e); +e.p=nf.call(W,u,i); +return e; +} +W.fetch=function(u,o){ +var m=String(o&&o.method||'GET').toUpperCase(),ok=false,e; +try{ok=(typeof u==='string'||u instanceof URL)&&(m==='GET'||m==='HEAD')&&!(o&&(o.signal||o.keepalive))&&new URL(u,L.href).origin===L.origin}catch(x){} +if(!ok)return nf.apply(W,arguments); +e=tf(u,o||{},cur?'bg':'fg'); +e.p.then(function(){drop(e)},function(){drop(e)}); +return e.p; +}; +// 12 s at least: on the hotspot with the station also up, a small reply +// queued behind a page on the one-connection server took 4-5 s (bench +// 2026-09-24), and a 5 s floor called that link dead. +function tmo(){return Math.min(3e4,Math.max(12e3,4*rtt))} +// A PF request (mode json|text|st|pre): tracked until its body is read; the +// timeout bounds the reply and then the body, so a big body on a slow link +// is not "offline". Only replies from this origin (the panel) feed the RTT +// and the connection state; another site failing says nothing about it. +function rq(u,k,mode,ms){ +var pre=mode==='pre',e=tf(u,pre?{}:{cache:'no-store'},k),t0=now(),to,same=new URL(e.u).origin===L.origin; +function arm(){clearTimeout(to);to=setTimeout(function(){e.why='t';e.c.abort()},ms||tmo())} +function fin(){clearTimeout(to);drop(e)} +arm(); +return e.p.then(function(r){ +arm(); +if(pre)return r.arrayBuffer(); +if(same){var d=now()-t0;rtt=rtt===null?d:rtt*.7+d*.3} +if(mode==='st')return r.text().then(function(t){var s=null;try{s=JSON.parse(t)}catch(x){} +// Broken JSON is the panel's own reply gone wrong, not another device. +if(!s&&/^\s*\{/.test(t)){seen();throw Error('unreadable status')} +if(!s||!s.version){foreign();throw Error('not a Patternflow panel')}alien=0;seen();return s}); +if(same)seen(); +if(!r.ok)return r.text().then(function(t){var x=Error(t||'HTTP '+r.status);x.status=r.status;throw x}); +return mode==='text'?r.text():r.json(); +}).then(function(d){fin();return d},function(x){fin(); +if(e.why==='t'){x=Error('timeout');x.timeout=1} +if(e.why==='nav')x.nav=1; +else if(same&&!pre&&(x.timeout||x.name==='TypeError'))fail(x.timeout); +throw x}); +} + +// Background lane: one request in flight, FIFO. The panel serves one +// connection at a time; parallel polls would only queue there. +function enq(f,dead){return new Promise(function(y,n){Q.push({f:f,y:y,n:n,d:dead});pump()})} +function pump(){var j;while(!lb&&run&&!holds&&Q.length){j=Q.shift();if(j.d&&j.d())j.n(SKIP);else go(j)}} +function go(j){var p;lb=1;try{p=Promise.resolve(j.f())}catch(x){p=Promise.reject(x)} +p.then(function(d){lb=0;j.y(d);pump()},function(x){lb=0;j.n(x);pump()})} +// A function source: the fetches it starts synchronously are tracked as +// background and share the lane's timeout. +function fsrc(f){ +var c=cur=[],p; +try{p=Promise.resolve(f())}catch(x){p=Promise.reject(x)} +cur=null; +return new Promise(function(y,n){ +var to=setTimeout(function(){var x=Error('timeout');x.timeout=1;c.forEach(function(e){e.why='t';e.c.abort()});fail(1);n(x)},tmo()); +p.then(function(d){clearTimeout(to);seen();y(d)},function(x){clearTimeout(to); +if(c.some(function(e){return e.why==='nav'})){x=Error('aborted');x.nav=1} +else if(x&&x.name==='TypeError')fail(); +n(x)}); +}); +} +function rhold(){for(var k in RH)if(now()-RH[k]<6e5)return true;return false} +PF.poll=function(src,ms,cb,o){ +var h={ms:ms,ew:0,t:0,on:1,q:0,w:0}; +function next(){return Math.max(h.ms,2*h.ew,S&&S.busy||rhold()?5e3:0)} +function sched(d){clearTimeout(h.t);h.t=setTimeout(h.go,d)} +h.go=function(){ +clearTimeout(h.t);h.t=0; +if(!h.on||h.q)return; +if(D.hidden||!run){h.w=1;return} +var t0;h.q=1; +enq(function(){t0=now();return typeof src==='function'?(src.pf?src():fsrc(src)):rq(src,'bg','json')},function(){return !h.on}) +.then(function(d){done(1,d)},function(x){done(0,x)}); +function done(ok,v){ +h.q=0; +if(v===SKIP||!h.on)return; +if(!ok&&v&&v.nav){h.w=1;return} +if(ok){var d=now()-t0;h.ew=h.ew?h.ew*.7+d*.3:d} +sched(next()); +ok?call(cb,v,null):call(cb,null,v); +} +}; +P.push(h); +if(o&&o.first===false)sched(ms);else h.go(); +return{stop:function(){h.on=0;clearTimeout(h.t);var i=P.indexOf(h);if(i>-1)P.splice(i,1)}, +now:h.go,set:function(n){h.ms=n;if(h.t)sched(next())}}; +}; +function resume(){for(var i=0;i5e3)toast('back online','ok');setState('live')} +// Two in a row, timeouts included: one slow reply is a slow link, not a +// dead one, and calling it offline made a working console look broken. +function fail(){if(++fails>1&&!rs)setState('offline')} +function foreign(){alien=1;if(!rs)setState('offline');chip()} +PF.waitForDevice=function(o){ +o=o||{}; +var end=now()+(o.timeout||9e4),t0; +rs++;setState('restarting'); +return new Promise(function(y,n){ +function again(){setTimeout(go,Math.max(0,t0+2e3-now()))} +function go(){ +if(now()>=end){if(!--rs){fails=0;setState('offline')}chip();n(Error('timeout'));return} +if(nv){setTimeout(go,500);return} +t0=now(); +rq('/api/status','bg','st',3e3).then(function(s){ +var ok=!(o.build&&s.build===o.build); +if(ok){rs--;seen()} +deliver(s); +ok?y(s):again(); +},again); +} +go(); +}); +}; + +// Holds: an upload owns the link. This tab's lane waits; other tabs are told. +function tx(h,q){var m={id:me,h:h?1:0,q:q?1:0,t:now()};try{bc?bc.postMessage(m):localStorage.setItem('pf-hold',JSON.stringify(m))}catch(x){}} +function rx(m){if(!m||m.id===me)return;if(m.h)RH[m.id]=now();else delete RH[m.id];if(m.q&&holds)tx(1)} +try{bc=new BroadcastChannel('pf');bc.onmessage=function(e){rx(e.data)}}catch(x){bc=null} +W.addEventListener('storage',function(e){if(e.key==='pf-hold'&&e.newValue)try{rx(JSON.parse(e.newValue))}catch(x){}}); +tx(0,1); +function bu(e){if(guards&&!leaveOk){e.preventDefault();e.returnValue='';return ''}} +PF.hold=function(p,o){ +var g=o&&o.guard,d=0,t; +holds++; +if(g&&!guards++)W.addEventListener('beforeunload',bu); +tx(1); +function fin(){if(d)return;d=1;clearTimeout(t);holds--;if(g&&!--guards)W.removeEventListener('beforeunload',bu);tx(holds>0);pump()} +t=setTimeout(fin,6e5); +Promise.resolve(p).then(fin,fin); +return p; +}; + +// Version check: a page older than the firmware replaces itself, once. +function vurl(b){var u=new URL(L.href);u.searchParams.set('v',b);return u.href} +function navType(){ +try{var n=performance.getEntriesByType('navigation')[0];if(n&&n.type)return n.type}catch(x){} +try{return ['navigate','reload','back_forward'][performance.navigation.type]||'navigate'}catch(x){} +return 'navigate'; +} +function vcheck(b){ +if(!docB&&!adopted){adopted=1;var t=navType();if(t==='navigate'||t==='reload'){docB=PF.v=b;try{history.replaceState(history.state,'',vurl(b))}catch(x){}}} +if(docB===b){if(stale){stale=null;chip()}return} +stale=b; +var a=D.activeElement,k='pf-heal:'+L.pathname+':'+b,ok=0; +if(!healed&&!holds&&!PF.dirty&&!touched&&!(a&&/^(INPUT|TEXTAREA|SELECT)$/.test(a.tagName))){ +try{if(!sessionStorage.getItem(k)){sessionStorage.setItem(k,'1');ok=1}}catch(x){} +if(ok){healed=1;L.replace(vurl(b));return} +} +chip(); +} + +// Prefetch: versioned pages are immutable, so one fetched now is a tab +// switch that costs no request later. Only on a quiet, fast home link. +function pfOk(b){ +var s=S,c=navigator.connection,i,l; +if(!s||s.build!==b||s.viaHotspot||s.busy||holds||rhold()||D.hidden||!run||PF.state!=='live'||c&&c.saveData||!(s.uptime>30)||rtt===null||rtt>=150||now()-pd<2e3)return false; +for(i=0;i=l.length){try{sessionStorage.setItem('pf-pf:'+b,'1')}catch(x){}return} +enq(function(){return rq(l[n++]+'?v='+b,'prefetch','pre')}).then(function(){setTimeout(step,1e3)},function(){}); +})(); +} + +// Shared UI. +function toast(t,k){ +if(!tw){tq=[t,k];return} +clearTimeout(tt);tw.textContent=''; +var d=D.createElement('div');d.className='t'+(k==='err'?' e':'');d.textContent=t;tw.appendChild(d); +tt=setTimeout(function(){tw.textContent=''},k==='err'?6e3:3500); +} +PF.say=function(t,k,el){ +k=k||'info'; +if(!el){toast(t,k);return} +clearTimeout(el._pfT); +el.textContent=t; +el.classList.remove('pf-ok','pf-err','pf-info'); +el.classList.add('pf-'+k); +if(k==='ok')el._pfT=setTimeout(function(){if(el.textContent===t){el.textContent='';el.classList.remove('pf-ok')}},4e3); +}; +PF.busy=function(b,p){ +function f(on){if(!b)return;b.disabled=on;b.classList.toggle('pf-busy',on);if(on)b.setAttribute('aria-busy','true');else b.removeAttribute('aria-busy')} +f(true); +Promise.resolve(p).then(function(){f(false)},function(){f(false)}); +return p; +}; + +// The header, in a shadow root. Fixed heights, matching --pf-chrome-h: +// phone 40px brand row + 40px nav row + 1px rule = 81; desktop 40 + 1 = 41. +var CSS=':host{all:initial;display:block!important;position:relative;box-sizing:border-box!important;height:var(--pf-chrome-h)!important;' ++'--a:var(--led,#FF5C2E);--i:var(--ink,var(--fg,#EDE7DB));--u:var(--rule,#242118);--k:var(--cream,var(--bg,#0C0B09));' ++'border-bottom:1px solid var(--u);background:var(--k);color:var(--muted,#8A8272);font:10px/1 var(--mono,ui-monospace,SFMono-Regular,Menlo,monospace)}' ++'[hidden]{display:none!important}a{color:inherit;text-decoration:none}a:focus-visible,button:focus-visible{outline:2px solid var(--a);outline-offset:-2px}' ++'.in{max-width:1140px;height:80px;margin:0 auto;padding:0 16px;display:grid;grid-template:"b c t" 40px "n n n" 40px/minmax(0,1fr) auto auto;column-gap:12px;align-items:center}' ++'.b{grid-area:b;display:flex;align-items:center;gap:8px;min-width:0;overflow:hidden;white-space:nowrap}' ++'.h{display:flex;align-items:center;gap:8px;letter-spacing:.14em;text-transform:uppercase}' ++'.d{flex:none;width:5px;height:5px;border-radius:50%;background:var(--a);box-shadow:0 0 6px var(--a)}.ver{color:var(--faint,#5A5546);letter-spacing:.08em}' ++'.vb{padding:1px 6px;border:1px solid var(--a);border-radius:2px;color:var(--a);letter-spacing:.1em;text-transform:uppercase}.vb:hover{background:var(--a);color:var(--k)}' ++'.n{grid-area:n;min-width:0;height:40px;display:flex;overflow-x:auto;scrollbar-width:none;scroll-snap-type:x proximity;margin:0 -16px;padding:0 6px;font-size:11px;letter-spacing:.04em;' ++'--p:#000;--q:#000;--m:linear-gradient(90deg,var(--p),#000 24px,#000 calc(100% - 24px),var(--q));-webkit-mask-image:var(--m);mask-image:var(--m)}' ++'.n::-webkit-scrollbar{display:none}.fl{--p:transparent}.fr{--q:transparent}' ++'.n a{flex:none;display:flex;align-items:center;padding:0 10px;white-space:nowrap;scroll-snap-align:center}.n a:hover{color:var(--a)}.n a.on{color:var(--i);box-shadow:inset 0 -2px var(--a)}' ++'button{all:unset;box-sizing:border-box;height:24px;padding:0 7px;border:1px solid transparent;border-radius:2px;cursor:pointer;white-space:nowrap;letter-spacing:.1em;text-transform:uppercase}' ++'.c{grid-area:c;max-width:46vw;overflow:hidden;text-overflow:ellipsis;border-color:var(--u);letter-spacing:.04em;text-transform:none}.c.w{border-color:var(--a);color:var(--a)}.tg{grid-area:t}.tg:hover{color:var(--i)}' ++'.pg{position:absolute;left:0;top:0;width:0;height:2px;background:var(--a)}.pg.on{animation:pg 4s cubic-bezier(.1,.8,.2,1) forwards}@keyframes pg{to{width:92%}}' ++'.tw{position:fixed;left:0;right:0;bottom:24px;display:flex;justify-content:center;pointer-events:none;z-index:2147483647}' ++'.t{max-width:calc(100vw - 32px);box-sizing:border-box;padding:8px 12px;font-size:11px;line-height:1.4;border:1px solid var(--u);border-radius:2px;background:var(--panel,var(--cream2,#131110));color:var(--i)}.t.e{border-color:var(--a)}' ++'@media(max-width:479px){.ver{display:none}}' ++'@media(min-width:720px){.in{height:40px;padding:0 20px;grid-template:"b n c t" 40px/auto minmax(0,1fr) auto auto;column-gap:18px}.n{margin:0;padding:0}}'; +function here(){return L.pathname.replace(/\/+$/,'')||'/'} +function bld(){return S&&S.build||PF.v||cn&&cn.build||''} +function href(p){var b=bld();return p+(b?'?v='+b:'')} +function drawNav(){ +if(!nav)return; +var l=NAV.slice(),p=here(),i,j=0,a,e,r; +for(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'); +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()}; +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); +if(tq){toast(tq[0],tq[1]);tq=null} +// The page's own first requests go before status (up to 1.2 s). +var t0=now(); +(function w(){if(S||sq)return;if(PF.inflight()&&now()-t0<1200)setTimeout(w,50);else fetchStatus()})(); +} + +// Navigation. +function anchor(e){ +var p=e.composedPath?e.composedPath():[],i,t=e.target; +for(i=0;i, device paths (/patterns, /pf-console.js, http:// + * history, navigation /) become the demo's files, so a + * click never lands on the site outside the demo. + * the footer's host name what the frame was told to be (below), not the + * site's. + * + * The frame's name tells it where it is: name="pf-demo host=192.168.0.42" + * (default patternflow.local). + * + * BRIDGE - window.postMessage between this frame and its parent, both ways + * only when event.origin === location.origin (and from window.parent). + * + * demo -> parent {type:'pf-console', action:'ready', page, modules:[slug], inv:[4], sub:[4]} + * {type:'pf-console', action:'select', index, name, slug} + * slug 'origin' for the built-in; index is the device's + * {type:'pf-console', action:'knob', knob:0..3, value:0..1000} + * POST /api/params pN: the absolute bus, 0..1000 + * {type:'pf-console', action:'brightness', percent, level} + * level: the panel's brightness byte, 5..255 + * {type:'pf-console', action:'sleep', on} + * {type:'pf-console', action:'modules', modules:[slug]} + * the installed modules in device order, after any change + * {type:'pf-console', action:'knobSettings', inv:[4], sub:[4]} + * {type:'pf-console', action:'escape'} Esc pressed in the page + * parent -> demo {type:'pf-sim', sid, patternIndex, patternName, patternSlug, + * knobs:[4], brightness, level, sleeping, off} + * knobs: detents each encoder has turned (clockwise +) + * since the parent's page loaded, sid naming that load; + * brightness in percent, level the byte; off: no power. + * The board follows: what plays, how bright, asleep, + * where the encoders are. A value the console itself + * just set wins for 1.5 s over a message already in flight. + * + * window.PFDemo (for tests): state(), reset(), log - every request seen, + * {kind, method, url} with kind device|demo|site|refused. + */ +(function () { + 'use strict'; + var SEED = {"version":"3.10.4","build":"8d5edc7b","manifestVersion":"3.10.4","host":"patternflow","alias":"patternflow-5c2e","ip":"192.168.0.42","ssid":"Studio_2.4G","neighbours":[["Studio_2.4G",-48],["iptime",-71],["U+Net4E21",-77],["SK_WiFiGIGA7A1C",-83]],"hotspotPass":"patternflow","maxNetworks":5,"brightness":204,"fsTotal":10240000,"flashId":"c84018","modules":[{"slug":"0510","name":"0510","pfm":6224,"json":315},{"slug":"0511","name":"0511","pfm":6780,"json":317},{"slug":"0512","name":"0512","pfm":6428,"json":310},{"slug":"0513","name":"0513","pfm":6272,"json":312},{"slug":"0514","name":"0514","pfm":7688,"json":312},{"slug":"0515","name":"0515","pfm":6192,"json":312},{"slug":"0515_3","name":"0515-3","pfm":5908,"json":319},{"slug":"0515_4","name":"0515-4","pfm":6012,"json":319},{"slug":"0518","name":"0518","pfm":6304,"json":312},{"slug":"0519_1","name":"0519-1","pfm":6044,"json":319},{"slug":"0520","name":"0520","pfm":6052,"json":312},{"slug":"0521","name":"0521","pfm":6380,"json":312},{"slug":"0522","name":"0522","pfm":6352,"json":312},{"slug":"0527","name":"0527","pfm":7016,"json":339},{"slug":"0528","name":"0528","pfm":5716,"json":312},{"slug":"0531","name":"0531","pfm":5064,"json":312},{"slug":"0601","name":"0601","pfm":5896,"json":312},{"slug":"0602","name":"0602","pfm":5608,"json":312},{"slug":"a_big_hit","name":"a big hit","pfm":5824,"json":328},{"slug":"breakout_arcade","name":"Breakout Arcade","pfm":17772,"json":344},{"slug":"chromatic_vortex","name":"Chromatic Vortex","pfm":5896,"json":389},{"slug":"firefly_hollow","name":"Firefly Hollow","pfm":12200,"json":339},{"slug":"lissajous_weave","name":"Lissajous Weave","pfm":6712,"json":363},{"slug":"magvortex","name":"MagVortex","pfm":8032,"json":338},{"slug":"midsummer_sea","name":"Midsummer Sea","pfm":8908,"json":336},{"slug":"poincar_sphere","name":"Poincar\u00e9 Sphere","pfm":5224,"json":359},{"slug":"retro_digital_tapestry","name":"Retro Digital Tapestry","pfm":6324,"json":384},{"slug":"tilewaves","name":"TileWaves","pfm":7016,"json":333},{"slug":"tri_march","name":"Tri March","pfm":5972,"json":342},{"slug":"untitled_pattern","name":"Untitled pattern","pfm":6168,"json":351},{"slug":"vector_field_flow","name":"Vector Field Flow","pfm":6256,"json":378},{"slug":"warped_wave","name":"Warped Wave","pfm":6476,"json":333},{"slug":"wave_saw","name":"Wave Saw","pfm":6888,"json":316}],"catalog":["wave_saw","0510","0511","0512","0513","0514","0515","0515_3","0515_4","0518","0519_1","0520","0521","0522","0527","0528","0531","0601","0602","retro_digital_tapestry","chromatic_vortex","vector_field_flow","lissajous_weave","untitled_pattern","tilewaves","midsummer_sea","breakout_arcade","firefly_hollow","poincar_sphere","tri_march","warped_wave","magvortex","a_big_hit"],"pages":{"/":"index.html","/patterns":"patterns.html","/status":"status.html","/wifi":"wifi.html","/knobs":"knobs.html","/update":"update.html"},"assets":{"/pf-console.js":"pf-console.js","/patterns/fflate.js":"fflate.js"},"id":"f18252f462"}; + var W = window, D = document, L = location; + if (W.PFDemo) return; + var BASE = L.pathname.replace(/[^\/]*$/, ''); + var FILE = L.pathname.slice(BASE.length) || 'index.html'; + var HOST = (/(?:^|\s)host=(\S+)/.exec(W.name || '') || [0, SEED.host + '.local'])[1]; + var DEVICE_HOSTS = [SEED.ip, SEED.host, SEED.host + '.local', SEED.alias, SEED.alias + '.local', HOST]; + var EMBEDDED = W.parent !== W; + var MANIFEST = /^https:\/\/patternflow\.work\/flash\/manifest\.json(?:[?#]|$)/; + var KEY = 'pf-demo:board'; + var realFetch = W.fetch; + var RealXHR = W.XMLHttpRequest; + var log = []; + function now() { return Date.now(); } + function note(kind, method, url) { log.push({ kind: kind, method: method, url: String(url) }); if (log.length > 400) log.shift(); } + + // ── where a URL goes ──────────────────────────────────────────────────── + function norm(p) { return p.length > 1 ? p.replace(/\/+$/, '') : p; } + // The device path a URL means, or null when it is not the device's. + function devicePath(u) { + if (u.protocol !== 'http:' && u.protocol !== 'https:') return null; + if (u.origin === L.origin) return u.pathname.indexOf(BASE) === 0 ? null : norm(u.pathname); + return DEVICE_HOSTS.indexOf(u.hostname) >= 0 ? norm(u.pathname) : null; + } + // The demo file for a device page or asset URL, or null. + function toDemo(v) { + var u; + try { u = new URL(v, L.href); } catch (e) { return null; } + var p = devicePath(u); + if (p === null) return null; + var f = SEED.pages[p] || SEED.assets[p]; + return f ? BASE + f + u.search + u.hash : null; + } + function external(v) { + try { + var u = new URL(v, L.href); + return (u.protocol === 'http:' || u.protocol === 'https:') && devicePath(u) === null && u.origin !== L.origin; + } catch (e) { return false; } + } + + // ── the board ─────────────────────────────────────────────────────────── + function fresh() { + var t = now(); + return { + id: SEED.id, build: SEED.build, bootAt: t - 1380e3, resetReason: 'poweron', + off: false, reboot: null, sleep: false, brightness: SEED.brightness, + params: [500, 500, 500, 500], held: [false, false, false, false], heldAt: [0, 0, 0, 0], + active: 'origin', load: { total: 0, read: 0, relocate: 0, setup: 0, internal: 0, psram: 0 }, loads: 0, + mounted: true, modules: SEED.modules.map(function (m) { return { slug: m.slug, name: m.name, pfm: m.pfm, json: m.json }; }), + catalog: SEED.catalog.slice(), storageUntil: 0, + wifi: { networks: [{ ssid: SEED.ssid, pass: 'studio-guest' }], bootIdx: 0, current: SEED.ssid, join: null }, + hotspot: { mode: 'auto', pass: SEED.hotspotPass, up: false, scanned: false }, + knob: { inv: [false, false, false, false], sub: [4, 4, 4, 4], raw: [0, 0, 0, 0], baseRaw: [0, 0, 0, 0], baseClicks: [0, 0, 0, 0], sid: null, turns: [0, 0, 0, 0] }, + update: { uploading: false, attempts: 0, lastOk: false, lastError: '', lastRejected: false, received: 0, expected: 0 }, + localAt: { pattern: 0, brightness: 0, sleep: 0 } + }; + } + var memory = null; + function load() { + var s = null; + try { s = JSON.parse(sessionStorage.getItem(KEY)); } catch (e) { s = memory; } + if (!s && memory) s = memory; + if (!s || s.id !== SEED.id) s = fresh(); + settle(s); + return s; + } + function save(s) { + memory = s; + try { sessionStorage.setItem(KEY, JSON.stringify(s)); } catch (e) {} + } + // Read, change, write in one go: every frame of the demo shares the board, + // and frames of one origin share one thread, so this cannot interleave. + function tx(fn) { var s = load(); var r = fn(s); save(s); return r; } + + // Timed things resolve when the board is next looked at. + function settle(s) { + var t = now(); + if (s.reboot && t >= s.reboot.until) { + var build = s.reboot.build || s.build; + s.build = build; s.bootAt = s.reboot.until; s.resetReason = s.reboot.reason || 'sw'; s.reboot = null; + s.sleep = false; s.held = [false, false, false, false]; + s.knob.raw = [0, 0, 0, 0]; s.knob.baseRaw = [0, 0, 0, 0]; s.knob.baseClicks = [0, 0, 0, 0]; + s.load = { total: 0, read: 0, relocate: 0, setup: 0, internal: 0, psram: 0 }; + s.update = { uploading: false, attempts: 0, lastOk: false, lastError: '', lastRejected: false, received: 0, expected: 0 }; + var w = s.wifi, n = w.networks.length; + for (var i = 0; i < n; i++) { + var net = w.networks[(w.bootIdx + i) % n]; + if (inRange(net.ssid) && passOk(net)) { w.current = net.ssid; break; } + } + w.join = null; + } + var j = s.wifi.join; + if (j && !j.done && t - j.at >= 3000) { + j.done = true; + if (j.ok) s.wifi.current = j.ssid; + } + } + function down(s) { return s.off || !!(s.reboot && now() >= s.reboot.at); } + + function inRange(ssid) { return SEED.neighbours.some(function (n) { return n[0] === ssid; }); } + function passOk(net) { return net.ssid !== SEED.ssid || net.pass.length >= 8; } + + // ── patterns (pattern_registry.h) ──────────────────────────────────────── + // FAT order is sorted by path, then catalog.txt moves the listed ones to the + // front in file order (applyCatalogOrder); names come from the sidecar. + function modules(s) { + if (!s.mounted) return []; + var m = s.modules.filter(function (x) { return x.pfm > 0; }).sort(function (a, b) { + return a.slug < b.slug ? -1 : a.slug > b.slug ? 1 : 0; + }); + var placed = 0; + s.catalog.forEach(function (line) { + if (placed >= m.length) return; + for (var i = placed; i < m.length; i++) { + if (m[i].slug !== line) continue; + var x = m.splice(i, 1)[0]; + m.splice(placed++, 0, x); + break; + } + }); + return m; + } + function list(s) { + var out = [{ index: 0, name: 'Origin', module: null }]; + modules(s).forEach(function (m, i) { out.push({ index: i + 1, name: m.name || fromSlug(m.slug), module: m.slug }); }); + return out; + } + function fromSlug(slug) { // displayNameFromSlug + var out = '', up = true; + for (var i = 0; i < slug.length && out.length < 39; i++) { + var c = slug.charAt(i); + if (c === '_' || c === '-') { out += ' '; up = true; } + else { out += up && c >= 'a' && c <= 'z' ? c.toUpperCase() : c; up = false; } + } + return out; + } + function activeIndex(s, l) { + if (s.active === 'origin') return 0; + for (var i = 1; i < l.length; i++) if (l[i].module === s.active) return i; + return 0; + } + function hash(t) { var h = 2166136261; for (var i = 0; i < t.length; i++) { h ^= t.charCodeAt(i); h = Math.imul(h, 16777619); } return h >>> 0; } + function setActive(s, slug, local) { + if (slug !== 'origin' && !modules(s).some(function (m) { return m.slug === slug; })) slug = 'origin'; + if (slug !== s.active && slug !== 'origin') { + var m = s.modules.filter(function (x) { return x.slug === slug; })[0], h = hash(slug); + var total = 21000 + h % 24000, read = Math.round(total * (0.34 + (h >>> 8) % 12 / 100)); + var relocate = Math.round(total * 0.18), setup = total - read - relocate; + s.load = { total: total, read: read, relocate: relocate, setup: setup, + internal: 1200 + (h >>> 4) % 2600, psram: Math.round((m ? m.pfm : 6000) * 1.3) }; + s.loads++; + } + s.active = slug; + if (local) s.localAt.pattern = now(); + } + function moduleSlugs(s) { return modules(s).map(function (m) { return m.slug; }); } + function slugOf(name) { // slugFromFilename + var base = String(name).split(/[\\\/]/).pop(), dot = base.lastIndexOf('.'); + if (dot > 0) base = base.slice(0, dot); + return base.replace(/[^A-Za-z0-9_-]/g, '').slice(0, 39); + } + function fsUsed(s) { + if (!s.mounted) return 0; + var c = function (n) { return n ? Math.ceil(n / 4096) * 4096 : 0; }, u = 16384; + s.modules.forEach(function (m) { u += c(m.pfm) + c(m.json); }); + if (s.catalog.length) u += 4096; + return u; + } + + // ── knobs (core_encoders.h): clicks = edges / edges-per-click, re-based on + // every settings change so a saved change does not move the knob. + function clicks(s) { + var k = s.knob; + return k.raw.map(function (r, i) { return k.baseClicks[i] + Math.trunc((k.inv[i] ? -1 : 1) * (r - k.baseRaw[i]) / k.sub[i]); }); + } + + // ── /api/status (core_status_http.h handleStatus, field for field) ────── + function status(s) { + var t = now(), up = Math.max(0, Math.floor((t - s.bootAt) / 1000)), l = list(s), a = activeIndex(s, l); + var mod = a > 0, h = hash(s.active), frameUs = s.active === 'origin' ? 12048 : 11800 + h % 4800; + var jit = function (n, k) { return n + ((hash(String(Math.floor(t / 3000)) + k) % 400) - 200); }; + var hs = s.hotspot, w = s.wifi, busy = s.update.uploading || s.reboot ? 'update' : t < s.storageUntil ? 'storage' : ''; + var c = clicks(s); + return { + version: SEED.version, build: s.build, variant: 'core', variantVersion: '', + caps: ['patterns', 'params', 'sleep'], featureNav: [], + uptime: up, resetReason: s.resetReason, panel: '128x64', + wifi: true, ssid: w.current, ip: SEED.ip, rssi: w.current === SEED.ssid ? -52 + (hash(String(Math.floor(t / 6000))) % 5) - 2 : -69, + host: SEED.host, hostAlias: SEED.alias, + hotspot: hotspotJson(s), viaHotspot: false, + network: { disconnects: 0, retries: 0, reconnectMs: 0, namesReady: true, announcements: 1 }, + txDbm: 19.5, + heapInternal: jit(mod ? 71836 - s.load.internal : 74212, 'hi'), heapLargest: mod ? 61440 : 65536, + heapPsram: 8336335 - (mod ? s.load.psram + 16384 : 0), + fsMounted: s.mounted, fsTotal: s.mounted ? SEED.fsTotal : 0, fsUsed: fsUsed(s), fsError: '', flashId: SEED.flashId, + patterns: l.length, presets: 1, modules: l.length - 1, + active: l[a].name, activeIsModule: mod, loading: false, + sleep: s.sleep, brightness: s.brightness, + knobs: c, params: s.params.slice(), + laneActive: [false, false, false, false], lanes: [0, 0, 0, 0], paramActive: s.held.slice(), + consolePaused: false, busy: busy, + frameUs: jit(frameUs, 'fu'), presentUs: 9947, loopCore: 1, httpCore: 0, + netMaintenance: { calls: up * 50, maxGapMs: 38 }, netStackMin: 4376, + runtime: { loops: Math.floor(up * 1e6 / frameUs), lastUs: frameUs, maxUs: 41872, over50ms: 0, housekeepingMaxUs: 2911, syncMaxUs: 386 }, + loopSyncServed: up * 3, loopSyncMaxUs: 412, + colorBits: 8, refreshHz: 300, loadError: '', + load: s.load, + moduleMemory: { reserve: 24576, runtimeBytes: mod ? 3072 : 0, runtimePeakBytes: s.loads ? 5120 : 0, runtimeLimit: 4194304, + loaderStackBytes: 8192, loaderStackMin: s.loads ? 5264 : 8192, loaderRetries: 0, + serviceFree: jit(mod ? 43008 : 47104, 'sf'), budget: 22528, codeBytes: mod ? s.load.internal : 0, + execLargest: mod ? 30720 : 32768, refusals: 0 }, + nvs: { usable: true, failures: 0 }, + thumbs: { captures: s.loads, reads: 0, writes: s.loads, captureMaxUs: s.loads ? 1840 : 0, ioMaxUs: s.loads ? 21960 : 0 } + }; + } + function hotspotJson(s) { + var h = s.hotspot; + return { mode: h.mode, up: h.up, ssid: SEED.alias, ip: h.up ? '192.168.4.1' : '', channel: h.up ? 11 : 0, clients: 0, dns: 0 }; + } + + // ── the handlers ──────────────────────────────────────────────────────── + function J(obj, status) { return { status: status || 200, type: 'application/json', body: JSON.stringify(obj) }; } + var NOT_FOUND = { status: 404, type: 'text/plain', body: 'Not found' }; // core_http.h onNotFound + function toInt(v) { var n = parseInt(v, 10); return isNaN(n) ? 0 : n; } + function truthy(v) { return v === '1' || v === 'true' || v === 'on'; } + + // WebServer's arg(): the query, then a form body; `plain` is a body that is + // not a form. + function args(u, b) { + var q = new URLSearchParams(u.search), f = null; + if (b.form) f = b.form; + else if (b.text !== null && /^application\/x-www-form-urlencoded/i.test(b.ctype)) f = new URLSearchParams(b.text); + return { + has: function (k) { return q.has(k) || !!(f && f.has(k)); }, + get: function (k) { return q.has(k) ? q.get(k) : f && f.has(k) ? String(f.get(k)) : ''; }, + plain: b.text !== null && !f ? b.text : '' + }; + } + + // A route first (/update is a page for GET and the upload for POST), then + // a page - which only the chrome's prefetch asks for, and which it only + // keeps for the cache. + function device(method, u, path, b, H) { + var R = ROUTES[method + ' ' + path]; + if (R) return R(args(u, b), b, H, u); + if (SEED.pages[path] && method === 'GET') return { status: 200, type: 'text/html', body: '' }; + if (path === '/favicon.ico') return { status: 204, type: 'text/html', body: '' }; + return NOT_FOUND; + } + + var ROUTES = { + 'GET /api/status': function () { return J(status(load())); }, + + // core_status_http.h handleSleep: queued, performed on the next loop pass + 'POST /api/sleep': function (A) { + var on = (A.has('on') ? A.get('on') : '1').toLowerCase().trim(); + return tx(function (s) { + var was = s.sleep, want; + if (on === 'toggle') want = !was; + else if (on === '1' || on === 'true' || on === 'sleep') want = true; + else if (on === '0' || on === 'false' || on === 'wake') want = false; + else return J({ ok: false, error: 'on must be 1, 0, or toggle' }, 400); + s.sleep = want; s.localAt.sleep = now(); + tell({ action: 'sleep', on: want }); + return J({ ok: true, requested: want, sleep: was }); + }); + }, + + // handleParams: pN 0..1000 holds the lane; dN clicks; rN releases + 'POST /api/params': function (A) { + return tx(function (s) { + var written = 0, error = '', i, sent = []; + for (i = 0; i < 4 && !error; i++) { + var k = 'p' + (i + 1); + if (A.has(k)) { + var raw = A.get(k).trim(), v = toInt(raw); + if (!raw.length || v < 0 || v > 1000) { error = k + ' must be 0..1000'; break; } + s.params[i] = v; s.held[i] = true; s.heldAt[i] = now(); written++; sent.push([i, v]); + } + var d = 'd' + (i + 1); + if (A.has(d)) { + var dv = toInt(A.get(d)); + if (dv < -100 || dv > 100) { error = d + ' must be -100..100'; break; } + written++; + } + var r = 'r' + (i + 1); + if (A.has(r) && A.get(r) !== '0') { s.held[i] = false; written++; } + } + if (error) return J({ ok: false, error: error }, 400); + if (!written) return J({ ok: false, error: 'send at least one of p1..p4' }, 400); + sent.forEach(function (p) { tell({ action: 'knob', knob: p[0], value: p[1] }); }); + return J({ ok: true, params: s.params.slice(), active: s.held.slice() }); + }); + }, + + // core_display_http.h: brightness 5..255, and the display state back + 'GET /api/display': function (A) { + return tx(function (s) { + if (A.has('brightness')) { + var v = toInt(A.get('brightness')); + if (v >= 5 && v <= 255) { + s.brightness = v; s.localAt.brightness = now(); + tell({ action: 'brightness', level: v, percent: Math.trunc((v * 100 + 127) / 255) }); + } + } + return J({ wb_r: 1, wb_g: 1, wb_b: 1, gamma_r: 2.2, gamma_g: 2.2, gamma_b: 2.2, sat: 1.62, + brightness: s.brightness, calib: 0, screen: 0, level: 255, sleep: s.sleep ? 1 : 0, + power_limit: 1, power_budget: 3000, power_ma: 0, power_demand: 0, power_limiting: 0, power_applied: s.brightness }); + }); + }, + + // core_patterns_http.h + 'GET /api/patterns': function () { + var s = load(), l = list(s); + return J({ active: activeIndex(s, l), presets: 1, mounted: s.mounted, + free: s.mounted ? SEED.fsTotal - fsUsed(s) : 0, patterns: l, pendingRev: 0, pending: [] }); + }, + 'GET /api/patterns/select': function (A) { + return tx(function (s) { + var l = list(s), n = l.length, cur = activeIndex(s, l), idx = -1, i; + if (A.has('step')) idx = ((cur + (toInt(A.get('step')) >= 0 ? 1 : -1)) % n + n) % n; + else if (A.has('index')) idx = toInt(A.get('index')); + else if (A.has('name')) for (i = 0; i < n; i++) if (l[i].name === A.get('name')) { idx = i; break; } + if (idx < 0 || idx >= n) return J({ ok: false, error: 'no such pattern' }, 404); + setActive(s, l[idx].module || 'origin', true); + tell({ action: 'select', index: idx, name: l[idx].name, slug: l[idx].module || 'origin' }); + return J({ ok: true, index: idx, name: l[idx].name }); + }); + }, + 'GET /api/patterns/pending': function () { return J({ rev: 0, slugs: [] }); }, + 'GET /api/patterns/file': function (A) { + var s = load(); + if (!s.mounted) return J({ ok: false, error: 'storage not mounted' }, 409); + if (!A.has('slug')) return J({ ok: false, error: 'missing slug' }, 400); + var slug = slugOf(A.get('slug') + '.pfm'), ext = (A.has('ext') ? A.get('ext') : 'pfm').toLowerCase(); + if (!slug) return J({ ok: false, error: 'invalid slug' }, 400); + if (ext !== 'pfm' && ext !== 'json' && ext !== 'thumb') return J({ ok: false, error: 'ext must be pfm, json or thumb' }, 400); + var m = s.modules.filter(function (x) { return x.slug === slug; })[0]; + if (ext === 'thumb' || !m || !m[ext]) return J({ ok: false, error: 'not found' }, 404); + // A file this session uploaded comes back as it went in. The pack's own + // bytes are not in the demo (see console_demo.py), so its modules + // cannot be read out: the answer FFat.open failing gets. + return fileBytes(m, ext).then(function (bytes) { + if (!bytes) return J({ ok: false, error: 'cannot open' }, 500); + return { status: 200, type: ext === 'json' ? 'application/json' : 'application/octet-stream', body: bytes, + headers: { 'Content-Disposition': 'attachment; filename="' + slug + '.' + ext + '"' } }; + }); + }, + 'PUT /api/patterns': function (A, b, H) { return upload(b, H['x-pf-name'] || '', H['x-pf-last']); }, + 'POST /api/patterns': function (A, b) { return upload(b, b.name || '', A.has('last') ? A.get('last') : undefined); }, + 'DELETE /api/patterns': function (A) { + if (!A.has('slug')) return J({ ok: false, error: 'missing slug' }, 400); + var slug = slugOf(A.get('slug') + '.pfm'); + if (!slug) return J({ ok: false, error: 'invalid slug' }, 400); + return tx(function (s) { + if (!s.mounted || !remove(s, slug)) return J({ ok: false, error: 'no such module' }, 404); + rescanned(s); + return J({ ok: true }); + }); + }, + 'POST /api/patterns/delete': function (A) { + return tx(function (s) { + if (!s.mounted) return J({ ok: false, error: 'storage not mounted' }, 409); + var body = A.plain.trim(), removed = 0, missing = 0; + if (!body) return J({ ok: false, error: 'no slugs given' }, 400); + if (body === '*') { + // Every .pfm on the volume, each with its sidecar; a sidecar with no + // module beside it is not what this pass looks for. + s.modules.filter(function (m) { return m.pfm > 0; }).forEach(function (m) { + if (remove(s, m.slug)) removed++; + }); + } else { + body.split('\n').forEach(function (line) { + line = line.trim(); + if (!line) return; + var slug = slugOf(line + '.pfm'); + if (slug && remove(s, slug)) removed++; else missing++; + }); + } + s.storageUntil = now() + 400 + removed * 40; + rescanned(s); + return J({ ok: true, removed: removed, missing: missing }); + }); + }, + 'POST /api/patterns/format': function () { + return tx(function (s) { + s.modules = []; s.catalog = []; s.mounted = true; s.storageUntil = now() + 2600; + dropFiles(); + rescanned(s); + return J({ ok: true }); + }); + }, + + // core_wifi_http.h + 'GET /api/wifi': function () { + var s = load(), w = s.wifi, j = w.join, t = now(), + join = { state: 'none', ssid: '', ip: '', why: '', reason: 0, ago: 0 }; + if (j) { + var since = Math.floor((t - j.at) / 1000); + join.ssid = j.ssid; + if (!j.done) { join.state = 'trying'; join.ago = since; } + else if (j.ok) { join.state = 'joined'; join.ip = SEED.ip; join.ago = Math.max(0, since - 3); } + else { join.state = 'failed'; join.why = j.why; join.reason = j.reason; join.ago = Math.max(0, since - 3); } + } + return J({ max: SEED.maxNetworks, connected: true, current: w.current, ip: SEED.ip, status: 'CONNECTED', + bootIdx: bootIdx(w), join: join, networks: w.networks.map(function (n) { return { ssid: n.ssid }; }) }); + }, + 'POST /api/wifi': function (A) { + if (!A.has('ssid')) return J({ ok: false, error: 'missing ssid' }, 400); + var ssid = A.get('ssid'), pass = A.has('pass') ? A.get('pass') : ''; + if (!ssid.length || ssid.length > 32) return J({ ok: false, error: 'ssid must be 1-32 characters' }, 400); + if (pass.length > 63) return J({ ok: false, error: 'password too long' }, 400); + var connect = A.has('connect') && A.get('connect') === '1'; + return tx(function (s) { + var w = s.wifi; + addNetwork(w, ssid, pass); + if (connect) { + var found = inRange(ssid), ok = found && passOk({ ssid: ssid, pass: pass }); + w.join = { ssid: ssid, at: now(), done: false, ok: ok, + why: !found ? 'network not found' : ok ? '' : 'wrong password', reason: !found ? 201 : ok ? 0 : 15 }; + } + return J({ ok: true, ssid: ssid, saved: w.networks.length, switching: connect }); + }); + }, + 'DELETE /api/wifi': function (A) { + if (!A.has('ssid')) return J({ ok: false, error: 'missing ssid' }, 400); + var ssid = A.get('ssid'); + return tx(function (s) { + return removeNetwork(s.wifi, ssid) ? J({ ok: true }) : J({ ok: false, error: 'not saved' }, 404); + }); + }, + 'POST /api/wifi/boot': function (A) { + if (!A.has('bootIdx')) return J({ ok: false, error: 'missing bootIdx' }, 400); + var i = toInt(A.get('bootIdx')); + return tx(function (s) { + var w = s.wifi; + if (!w.networks.length || i < 0 || i >= w.networks.length) return J({ ok: false, error: 'invalid boot index' }, 400); + w.bootIdx = i; + return J({ ok: true, bootIdx: i, reboot: true }); + }); + }, + 'POST /api/wifi/reboot': function () { + return tx(function (s) { var t = now(); s.reboot = { at: t + 400, until: t + 6400 }; return J({ ok: true, rebooting: true }); }); + }, + 'POST /api/wifi/reconnect': function () { return J({ ok: true, reconnecting: true }); }, + + // core_hotspot.h + 'GET /api/hotspot': function () { return J(hotspotReply(load())); }, + 'POST /api/hotspot': function (A) { + return tx(function (s) { + var h = s.hotspot; + if (A.has('mode')) { + var m = A.get('mode'); + if (m !== 'off' && m !== 'auto' && m !== 'always') return J({ ok: false, error: 'mode is off, auto or always' }, 400); + h.mode = m; + } + if (A.has('pass')) { + var p = A.get('pass'); + if (p.length < 8 || p.length > 63) return J({ ok: false, error: 'password is 8 to 63 characters' }, 400); + h.pass = p; + } + // The panel is on Wi-Fi: auto keeps the hotspot down, always raises it + // after a channel scan, which is what fills "seen". + h.up = h.mode === 'always'; + if (h.up) h.scanned = true; + return J(hotspotReply(s)); + }); + }, + + // core_knobs_http.h + 'GET /api/knobs': function () { return J(knobsJson(load())); }, + 'POST /api/knobs': function (A) { + return tx(function (s) { + var k = s.knob, inv = k.inv.slice(), sub = k.sub.slice(), changed = [false, false, false, false], any = false, i, key; + for (i = 0; i < 4; i++) { + key = 'inv' + i; + if (A.has(key)) { inv[i] = truthy(A.get(key)); changed[i] = true; } + else if (A.has('inv')) { inv[i] = truthy(A.get('inv')); changed[i] = true; } + key = 'sub' + i; + if (A.has(key)) { sub[i] = toInt(A.get(key)); changed[i] = true; } + else if (A.has('sub')) { sub[i] = toInt(A.get('sub')); changed[i] = true; } + if (changed[i] && sub[i] !== 4 && sub[i] !== 2 && sub[i] !== 1) return J({ ok: false, error: 'sub must be 4, 2 or 1' }, 400); + any = any || changed[i]; + } + if (!any) return J({ ok: false, error: 'nothing to set: invN, subN, inv or sub' }, 400); + var c = clicks(s); + for (i = 0; i < 4; i++) if (changed[i]) { + k.baseClicks[i] = c[i]; k.baseRaw[i] = k.raw[i]; k.inv[i] = inv[i]; k.sub[i] = sub[i]; + } + tell({ action: 'knobSettings', inv: k.inv.slice(), sub: k.sub.slice() }); + return J(knobsJson(s)); + }); + }, + + // core_web_update.h (always armed: PF_WEBUPDATE_ALWAYS_ARMED) + 'GET /update/status': function () { + var u = load().update; + return J({ armed: true, busy: u.uploading || !!load().reboot, version: SEED.version, lastError: u.lastError, + lastRejected: u.lastRejected, lastOk: u.lastOk, received: u.received, expected: u.expected, attempts: u.attempts }); + }, + 'POST /update': function (A, b) { return flash(b); }, + 'PUT /update': function (A, b) { return flash(b); } + }; + + function hotspotReply(s) { + var seen = s.hotspot.scanned ? SEED.neighbours.map(function (n) { return { ssid: n[0], rssi: n[1] }; }) : []; + return { ok: true, hotspot: hotspotJson(s), seen: seen, pass: s.hotspot.pass }; + } + function knobsJson(s) { + return { ok: true, inv: s.knob.inv.slice(), sub: s.knob.sub.slice(), clicks: clicks(s), raw: s.knob.raw.slice() }; + } + + // core_wifi.h addNetwork / removeNetwork / clampBootIdx, line for line + function clampBoot(w) { var n = w.networks.length; if (n <= 0) w.bootIdx = 0; else if (w.bootIdx < 0 || w.bootIdx >= n) w.bootIdx = 0; } + function bootIdx(w) { clampBoot(w); return w.bootIdx; } + // The new one goes to the front; a name already saved moves there (with its + // new password); a full list gives up its last slot. + function addNetwork(w, ssid, pass) { + var MAX = SEED.maxNetworks, n = w.networks.length, existing = -1, i; + for (i = 0; i < n; i++) if (w.networks[i].ssid === ssid) { existing = i; break; } + if (existing < 0 && n >= MAX) existing = MAX - 1; + if (existing < 0 && n > 0) w.bootIdx = Math.min(w.bootIdx + 1, MAX - 1); + var from = existing >= 0 ? existing : n; + if (existing >= 0) w.networks.splice(existing, 1); + w.networks.unshift({ ssid: ssid, pass: pass }); + if (existing >= 0 && from > 0) { // adjustBootIdxOnInsertAtFront + if (w.bootIdx === from) w.bootIdx = 0; else if (w.bootIdx < from) w.bootIdx++; + } + clampBoot(w); + } + function removeNetwork(w, ssid) { + for (var i = 0; i < w.networks.length; i++) { + if (w.networks[i].ssid !== ssid) continue; + w.networks.splice(i, 1); + if (i < w.bootIdx) w.bootIdx--; + else if (i === w.bootIdx) w.bootIdx = Math.min(w.bootIdx, Math.max(w.networks.length - 1, 0)); + clampBoot(w); + return true; + } + return false; + } + + // ── storage writes ────────────────────────────────────────────────────── + function remove(s, slug) { + var m = s.modules.filter(function (x) { return x.slug === slug; })[0]; + if (!m || !m.pfm) return false; + s.modules = s.modules.filter(function (x) { return x !== m; }); + dropFiles(slug); + return true; + } + // After the rescan (requestReload): a running module that is gone leaves + // Origin playing; the board beside the page follows. + function rescanned(s) { + var l = list(s); + if (s.active !== 'origin' && !l.some(function (p) { return p.module === s.active; })) { + setActive(s, 'origin', true); + tell({ action: 'select', index: 0, name: 'Origin', slug: 'origin' }); + } + tell({ action: 'modules', modules: moduleSlugs(s) }); + } + function upload(b, name, last) { + var lowered = String(name).toLowerCase(), isJson = /\.json$/.test(lowered), isCatalog = lowered === 'catalog.txt'; + if (!isJson && !isCatalog && !/\.pfm$/.test(lowered)) return J({ ok: false, error: 'only .pfm, .json or catalog.txt accepted' }, 400); + var slug = isCatalog ? 'catalog' : slugOf(name); + if (!slug) return J({ ok: false, error: 'invalid X-PF-Name' }, 400); + var bytes = b.bytes || new Uint8Array(0); + return tx(function (s) { + if (!s.mounted) return J({ ok: false, error: 'filesystem not mounted' }, 400); + if (!bytes.length) return J({ ok: false, error: 'empty upload' }, 400); + var count = list(s).length; + if (isCatalog) { + s.catalog = new TextDecoder().decode(bytes).split('\n').map(function (x) { return x.trim(); }) + .filter(function (x) { return x && x.charAt(0) !== '#'; }); + } else { + if (!isJson) { + // PFModuleLoader::looksLikeModule + if (bytes.length < 52) return J({ ok: false, error: 'too small to be a module (' + bytes.length + ' bytes)' }, 400); + if (bytes[0] !== 0x7f || bytes[1] !== 0x45 || bytes[2] !== 0x4c || bytes[3] !== 0x46) return J({ ok: false, error: 'not an ELF file (corrupt upload?)' }, 400); + if (bytes[4] !== 1 || (bytes[18] | bytes[19] << 8) !== 94) return J({ ok: false, error: 'unsupported or truncated ELF - rebuild with build_module.py' }, 400); + } + var m = s.modules.filter(function (x) { return x.slug === slug; })[0]; + if (!m) { m = { slug: slug, name: '', pfm: 0, json: 0 }; s.modules.push(m); } + m[isJson ? 'json' : 'pfm'] = bytes.length; + if (isJson) { + var nm = ''; + try { nm = String(JSON.parse(new TextDecoder().decode(bytes)).name || ''); } catch (e) {} + m.name = nm.slice(0, 39); + } else if (!m.json) m.name = ''; + keepFile(slug, isJson ? 'json' : 'pfm', bytes); + } + s.storageUntil = now() + 300; + if (last !== '0') rescanned(s); + return J({ ok: true, slug: slug, bytes: bytes.length, patterns: count }); + }); + } + // Uploaded files, kept for "Download ZIP" while they fit the session. + function keepFile(slug, ext, bytes) { + var s = ''; + for (var i = 0; i < bytes.length; i += 0x8000) s += String.fromCharCode.apply(null, bytes.subarray(i, i + 0x8000)); + try { sessionStorage.setItem('pf-demo:file:' + slug + '.' + ext, btoa(s)); } catch (e) {} + } + function dropFiles(slug) { + try { + for (var i = sessionStorage.length; i--;) { + var k = sessionStorage.key(i); + if (k && k.indexOf('pf-demo:file:') === 0 && (!slug || k.indexOf('pf-demo:file:' + slug + '.') === 0)) sessionStorage.removeItem(k); + } + } catch (e) {} + } + function fileBytes(m, ext) { + var kept = null; + try { kept = sessionStorage.getItem('pf-demo:file:' + m.slug + '.' + ext); } catch (e) {} + if (!kept) return Promise.resolve(null); + var bin = atob(kept), out = new Uint8Array(bin.length); + for (var i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i); + return Promise.resolve(out); + } + + // core_web_update.h: a multipart .bin; the first chunk must be an app image + // (Update's magic byte), and 1.2 s after the answer the panel restarts on it. + function flash(b) { + var bytes = b.bytes || new Uint8Array(0); + return tx(function (s) { + var u = s.update; + u.uploading = false; u.received = bytes.length; u.expected = bytes.length; + if (!bytes.length || bytes[0] !== 0xE9) { + u.lastOk = false; u.lastError = 'write: Wrong Magic Byte'; + return J({ error: u.lastError }, 500); + } + var id = ''; + for (var i = 176; i < 180 && i < bytes.length; i++) id += (bytes[i] < 16 ? '0' : '') + bytes[i].toString(16); + u.lastOk = true; u.lastError = ''; + var t = now(); + s.reboot = { at: t + 1200, until: t + 7800, build: /^[0-9a-f]{8}$/.test(id) && /[^0]/.test(id) ? id : s.build }; + return J({ ok: true }); + }); + } + + // ── the wire ──────────────────────────────────────────────────────────── + function abortError() { try { return new DOMException('The user aborted a request.', 'AbortError'); } catch (e) { var x = Error('aborted'); x.name = 'AbortError'; return x; } } + function later(signal, ms, fn) { + return new Promise(function (y, n) { + if (signal && signal.aborted) { n(abortError()); return; } + var t = setTimeout(function () { + if (signal) signal.removeEventListener('abort', ab); + try { y(fn()); } catch (x) { n(x); } + }, ms); + function ab() { clearTimeout(t); n(abortError()); } + if (signal) signal.addEventListener('abort', ab); + }); + } + function lat() { return 18 + Math.random() * 30; } + function headersOf(h) { + var out = {}; + if (!h) return out; + if (typeof Headers !== 'undefined' && h instanceof Headers) h.forEach(function (v, k) { out[k.toLowerCase()] = v; }); + else if (Array.isArray(h)) h.forEach(function (p) { out[String(p[0]).toLowerCase()] = String(p[1]); }); + else for (var k in h) out[k.toLowerCase()] = String(h[k]); + return out; + } + // A body as the server gets it: text, a form, or a file's bytes. + function readBody(body, H) { + var b = { text: null, form: null, bytes: null, name: null, ctype: H['content-type'] || '' }; + if (body == null) return Promise.resolve(b); + if (typeof body === 'string') { b.text = body; if (!b.ctype) b.ctype = 'text/plain;charset=UTF-8'; return Promise.resolve(b); } + if (body instanceof URLSearchParams) { b.text = body.toString(); b.ctype = 'application/x-www-form-urlencoded;charset=UTF-8'; return Promise.resolve(b); } + if (body instanceof FormData) { + b.form = new URLSearchParams(); b.ctype = 'multipart/form-data'; + var file = null; + body.forEach(function (v, k) { if (typeof v === 'string') b.form.append(k, v); else if (!file) file = v; }); + if (!file) return Promise.resolve(b); + b.name = file.name; + return file.arrayBuffer().then(function (buf) { b.bytes = new Uint8Array(buf); return b; }); + } + if (body instanceof Blob) return body.arrayBuffer().then(function (buf) { b.bytes = new Uint8Array(buf); b.text = new TextDecoder().decode(b.bytes); return b; }); + if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) { b.bytes = new Uint8Array(body.buffer || body); return Promise.resolve(b); } + b.text = String(body); + return Promise.resolve(b); + } + function respond(r) { + var h = new Headers(r.headers || {}); + h.set('Content-Type', r.type || 'text/plain'); + h.set('Cache-Control', 'no-store'); + return new Response(r.status === 204 ? null : r.body, { status: r.status, headers: h }); + } + + W.fetch = function (input, init) { + init = init || {}; + var isReq = typeof Request !== 'undefined' && input instanceof Request; + var url = isReq ? input.url : String(input); + var method = String(init.method || (isReq ? input.method : 'GET')).toUpperCase(); + var signal = init.signal || (isReq ? input.signal : null); + var u; + try { u = new URL(url, L.href); } catch (e) { return Promise.reject(new TypeError('Failed to fetch')); } + var path = devicePath(u); + if (path === null) { + if (u.origin === L.origin) { note('demo', method, u); return realFetch.apply(W, arguments); } + if (MANIFEST.test(u.href)) { + // The console's update check (home.html checkUpdate) reads the site's + // release manifest: answered with the release the flasher names. + note('site', method, u); + return later(signal, 90, function () { return respond(J({ name: 'Patternflow', version: 'v' + SEED.manifestVersion })); }); + } + note('refused', method, u); + return later(signal, 40, function () { throw new TypeError('Failed to fetch'); }); + } + note('device', method, u); + if (SEED.assets[path]) return realFetch.call(W, BASE + SEED.assets[path] + u.search, { signal: signal || undefined }); + var H = headersOf(init.headers || (isReq ? input.headers : null)); + return readBody(isReq ? null : init.body, H).then(function (b) { + if (down(load())) return later(signal, 1500, function () { throw new TypeError('Failed to fetch'); }); + return later(signal, lat(), function () { return device(method, u, path, b, H); }).then(function (r) { + return Promise.resolve(r).then(function (x) { + if (signal && signal.aborted) throw abortError(); + return respond(x); + }); + }); + }); + }; + + // XMLHttpRequest, for the uploads (patterns: raw PUT; update: multipart + // POST), with upload progress at a LAN's pace. + function Target() { this._l = {}; } + Target.prototype.addEventListener = function (t, f) { (this._l[t] = this._l[t] || []).push(f); }; + Target.prototype.removeEventListener = function (t, f) { var a = this._l[t]; if (a && a.indexOf(f) >= 0) a.splice(a.indexOf(f), 1); }; + Target.prototype.dispatchEvent = function () { return true; }; + Target.prototype._fire = function (type, extra) { + var e = { type: type, target: this, currentTarget: this, lengthComputable: false, loaded: 0, total: 0 }, self = this; + for (var k in extra) e[k] = extra[k]; + var list = [], h = this['on' + type]; + if (typeof h === 'function') list.push(h); + list = list.concat(this._l[type] || []); + list.forEach(function (f) { try { f.call(self, e); } catch (x) { setTimeout(function () { throw x; }); } }); + }; + function XHR() { + Target.call(this); + this.upload = new Target(); + this.readyState = 0; this.status = 0; this.statusText = ''; this.responseText = ''; this.response = ''; + this.responseType = ''; this.responseURL = ''; this.timeout = 0; this.withCredentials = false; + this._h = {}; this._rh = {}; this._timers = []; + } + XHR.prototype = Object.create(Target.prototype); + XHR.prototype.constructor = XHR; + XHR.UNSENT = 0; XHR.OPENED = 1; XHR.HEADERS_RECEIVED = 2; XHR.LOADING = 3; XHR.DONE = 4; + XHR.prototype.open = function (m, url) { this._m = String(m).toUpperCase(); this._url = String(url); this.readyState = 1; this._fire('readystatechange'); }; + XHR.prototype.setRequestHeader = function (k, v) { this._h[String(k).toLowerCase()] = String(v); }; + XHR.prototype.getResponseHeader = function (k) { var v = this._rh[String(k).toLowerCase()]; return v === undefined ? null : v; }; + XHR.prototype.getAllResponseHeaders = function () { var o = '', k; for (k in this._rh) o += k + ': ' + this._rh[k] + '\r\n'; return o; }; + XHR.prototype.overrideMimeType = function () {}; + XHR.prototype._later = function (f, ms) { var t = setTimeout(f, ms); this._timers.push(t); return t; }; + XHR.prototype._stop = function () { this._timers.forEach(clearTimeout); this._timers = []; }; + XHR.prototype.abort = function () { + if (this.readyState === 4 || this._over) return; + this._stop(); this._over = true; this.readyState = 4; this.status = 0; + if (this._update) tx(function (s) { s.update.uploading = false; }); + this._fire('readystatechange'); this.upload._fire('abort'); this._fire('abort'); this._fire('loadend'); + }; + XHR.prototype._fail = function (type) { + if (this._over) return; + if (this._update) tx(function (s) { s.update.uploading = false; }); + this._stop(); this._over = true; this.readyState = 4; this.status = 0; + this._fire('readystatechange'); this.upload._fire(type); this._fire(type); this._fire('loadend'); + }; + XHR.prototype.send = function (body) { + var self = this, u, path; + try { u = new URL(this._url, L.href); } catch (e) { u = null; } + path = u ? devicePath(u) : null; + if (path === null) { note('refused', this._m, this._url); this._later(function () { self._fail('error'); }, 30); return; } + note('device', this._m, u); + this._update = path === '/update'; + if (this._update) tx(function (s) { s.update.uploading = true; s.update.attempts++; s.update.lastError = ''; s.update.lastOk = false; }); + var t0 = now(); + if (this.timeout) this._later(function () { self._fail('timeout'); }, this.timeout); + readBody(body, this._h).then(function (b) { + if (self._over) return; + var total = b.bytes ? b.bytes.length : b.text ? b.text.length : 0; + var rate = 150 * 1024; // bytes per second up to the panel + var ms = total ? Math.max(120, total / rate * 1000) : 30; + if (down(load())) { self._later(function () { self._fail('error'); }, 1500); return; } + self.upload._fire('loadstart', { lengthComputable: true, loaded: 0, total: total }); + (function step() { + var f = Math.min(1, (now() - t0) / ms); + self.upload._fire('progress', { lengthComputable: true, loaded: Math.round(total * f), total: total }); + if (f < 1) { self._later(step, 90); return; } + self.upload._fire('load', { lengthComputable: true, loaded: total, total: total }); + self.upload._fire('loadend', { lengthComputable: true, loaded: total, total: total }); + // The device answers once it has checked what it wrote. + self._later(function () { + Promise.resolve(device(self._m, u, path, b, self._h)).then(function (r) { + if (self._over) return; + if (self._update) tx(function (s) { s.update.uploading = false; }); + self._stop(); self._over = true; + self.status = r.status; self.statusText = r.status === 200 ? 'OK' : ''; + self._rh = { 'content-type': r.type || 'text/plain', 'cache-control': 'no-store' }; + self.responseText = typeof r.body === 'string' ? r.body : ''; + self.response = self.responseText; self.responseURL = u.href; + self.readyState = 2; self._fire('readystatechange'); + self.readyState = 4; self._fire('readystatechange'); + self._fire('load'); self._fire('loadend'); + }); + }, path === '/update' ? 700 : 60 + Math.random() * 60); + })(); + }); + }; + W.XMLHttpRequest = XHR; + + // ── links, scripts, history ───────────────────────────────────────────── + var aHref = Object.getOwnPropertyDescriptor(HTMLAnchorElement.prototype, 'href'); + Object.defineProperty(HTMLAnchorElement.prototype, 'href', { + configurable: true, enumerable: true, get: aHref.get, + set: function (v) { aHref.set.call(this, toDemo(v) || String(v)); outward(this); } + }); + var sSrc = Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype, 'src'); + Object.defineProperty(HTMLScriptElement.prototype, 'src', { + configurable: true, enumerable: true, get: sSrc.get, + set: function (v) { sSrc.set.call(this, toDemo(v) || String(v)); } + }); + var setAttr = Element.prototype.setAttribute; + Element.prototype.setAttribute = function (name, value) { + var n = String(name).toLowerCase(); + if ((n === 'href' && this instanceof HTMLAnchorElement) || (n === 'src' && this instanceof HTMLScriptElement)) { + var m = toDemo(value); + if (m) value = m; + } + return setAttr.call(this, name, value); + }; + // A link off the board and off the demo opens beside it, never in the frame. + function outward(a) { + var h = a.getAttribute('href'); + if (h && external(h) && a.getAttribute('target') !== '_blank') { setAttr.call(a, 'target', '_blank'); setAttr.call(a, 'rel', 'noopener'); } + } + function link(a) { + var m = toDemo(a.getAttribute('href')); + if (m) setAttr.call(a, 'href', m); + outward(a); + } + function fix(el) { + if (el.tagName === 'A' && el.hasAttribute('href')) link(el); + var list = el.querySelectorAll ? el.querySelectorAll('a[href]') : []; + for (var i = 0; i < list.length; i++) link(list[i]); + } + // The observer runs before the next paint, so a link is never shown, and + // the footer never reads the site's host, even for a frame. + function watch(root) { + new MutationObserver(function (records) { + records.forEach(function (r) { + for (var i = 0; i < r.addedNodes.length; i++) if (r.addedNodes[i].nodeType === 1) fix(r.addedNodes[i]); + // home.html: $('host').textContent=location.hostname + if (r.target.id === 'host' && r.target.textContent === L.hostname) r.target.textContent = HOST; + }); + }).observe(root, { childList: true, subtree: true }); + } + 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. + function markNav(root) { + var nav = root.querySelector('nav'), on = null, i, a; + if (!nav) return; + for (i = 0; i < nav.children.length; i++) { + a = nav.children[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; + } + var attach = Element.prototype.attachShadow; + Element.prototype.attachShadow = function (o) { + var r = attach.call(this, o); + watch(r); + new MutationObserver(function () { markNav(r); }).observe(r, { childList: true, subtree: true }); + return r; + }; + ['pushState', 'replaceState'].forEach(function (k) { + var f = History.prototype[k]; + History.prototype[k] = function (state, title, url) { + return f.call(this, state, title, url == null ? url : toDemo(url) || url); + }; + }); + // A script that navigates by location (update.html's "Open console": + // location.replace('/?v=...')) is caught by the Navigation API where there + // is one, and by its click everywhere. + if (W.navigation && W.navigation.addEventListener) { + W.navigation.addEventListener('navigate', function (e) { + var to = toDemo(e.destination.url); + if (!to || !e.cancelable || e.hashChange) return; + e.preventDefault(); + setTimeout(function () { L.replace(to); }); + }); + } + W.addEventListener('click', function (e) { + var t = e.target; + if (FILE === 'update.html' && t && t.id === 'open') { + e.preventDefault(); e.stopImmediatePropagation(); + L.replace(BASE + 'index.html?v=' + load().build); + } + }, true); + D.addEventListener('keydown', function (e) { + if (e.key === 'Escape' && !e.defaultPrevented) tell({ action: 'escape' }); + }); + // Inside the guide, a page scrolled to its end does not scroll the guide. + if (EMBEDDED) D.documentElement.style.overscrollBehavior = 'contain'; + + // ── the bridge ────────────────────────────────────────────────────────── + function tell(m) { + if (!EMBEDDED) return; + m.type = 'pf-console'; + try { W.parent.postMessage(m, L.origin); } catch (e) {} + } + W.addEventListener('message', function (e) { + if (e.origin !== L.origin || e.source !== W.parent) return; + var m = e.data; + if (!m || m.type !== 'pf-sim') return; + tx(function (s) { + var t = now(), i; + if (m.off) { s.off = true; return; } + if (s.off) { s.off = false; s.reboot = { at: t, until: t + 2500, reason: 'poweron' }; } + if (typeof m.patternSlug === 'string' && t - s.localAt.pattern > 1500) { + var slug = m.patternSlug; + if (slug === 'origin' || modules(s).some(function (x) { return x.slug === slug; })) setActive(s, slug, false); + } + if (typeof m.level === 'number' && t - s.localAt.brightness > 1500) s.brightness = Math.max(5, Math.min(255, Math.round(m.level))); + if (typeof m.sleeping === 'boolean' && t - s.localAt.sleep > 1500) s.sleep = m.sleeping; + if (Array.isArray(m.knobs) && m.knobs.length === 4) { + var k = s.knob; + if (m.sid !== k.sid) { k.sid = m.sid; k.turns = m.knobs.slice(); } + for (i = 0; i < 4; i++) { + var d = Math.round(m.knobs[i] - k.turns[i]); + if (!d) continue; + k.raw[i] += d * 4; // four edges a detent + // A hand on the encoder takes the lane back (PatternflowBus::releaseAbsolute). + if (s.held[i] && t - s.heldAt[i] >= 250) s.held[i] = false; + } + k.turns = m.knobs.slice(); + } + }); + }); + + W.PFDemo = { state: load, reset: function () { try { sessionStorage.removeItem(KEY); } catch (e) {} memory = null; dropFiles(); }, log: log }; + var s0 = load(); + save(s0); + tell({ action: 'ready', page: FILE, modules: moduleSlugs(s0), inv: s0.knob.inv.slice(), sub: s0.knob.sub.slice() }); +})(); diff --git a/web/public/guide/console-demo/status.html b/web/public/guide/console-demo/status.html new file mode 100644 index 00000000..536d9e70 --- /dev/null +++ b/web/public/guide/console-demo/status.html @@ -0,0 +1,257 @@ + + + + + +Patternflow - Status +
      +

      Status

      -
      + + +
      + + +

      Device

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

      Render

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

      + +

      Patterns

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

      + +

      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.

      + +

      Storage

      +
      Pattern storage
      -
      +
      Storage error
      -
      +
      + + +

      Network

      +
      Network
      -
      +
      Signal
      -
      +
      Address
      -
      +
      Names
      -
      +
      Hotspot
      -
      +
      Hotspot mode
      -
      +
      Hotspot clients
      -
      +
      Reached via
      -
      +
      + + +
      + diff --git a/web/public/guide/console-demo/update.html b/web/public/guide/console-demo/update.html new file mode 100644 index 00000000..3d7fcf4f --- /dev/null +++ b/web/public/guide/console-demo/update.html @@ -0,0 +1,270 @@ + + + + + + +Patternflow — Firmware update + + +
      +
      +

      Update

      …
      + +

      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… +
      + + +
      +
      + +
      +
      + + + diff --git a/web/public/guide/console-demo/wifi.html b/web/public/guide/console-demo/wifi.html new file mode 100644 index 00000000..9fe2e782 --- /dev/null +++ b/web/public/guide/console-demo/wifi.html @@ -0,0 +1,466 @@ + + + + + +Patternflow - Wi-Fi +
      +

      Wi-Fi

      -
      + + + + + +
      +

      Add a network

      +
      + +
      + + + + +
      +
      + +
      + + +
      +
      +
      + + + + +
      +
      +
      + +

      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.

      +
      + +
      +

      Hotspot

      +

      -

      +
      +
      + + +
      +
      + + +
      +
      + +
      +
      +
      +

      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.

      +
      + + +
      + diff --git a/web/public/guide/devkit.glb b/web/public/guide/devkit.glb new file mode 100644 index 00000000..60b72ce2 Binary files /dev/null and b/web/public/guide/devkit.glb differ diff --git a/web/public/guide/flasher/dashboard-wifi-form.webp b/web/public/guide/flasher/dashboard-wifi-form.webp new file mode 100644 index 00000000..58a1efb9 Binary files /dev/null and b/web/public/guide/flasher/dashboard-wifi-form.webp differ diff --git a/web/public/guide/flasher/dashboard.webp b/web/public/guide/flasher/dashboard.webp new file mode 100644 index 00000000..1ff0a888 Binary files /dev/null and b/web/public/guide/flasher/dashboard.webp differ diff --git a/web/public/guide/flasher/install-complete.webp b/web/public/guide/flasher/install-complete.webp new file mode 100644 index 00000000..5f59b97e Binary files /dev/null and b/web/public/guide/flasher/install-complete.webp differ diff --git a/web/public/guide/flasher/install-confirm.webp b/web/public/guide/flasher/install-confirm.webp new file mode 100644 index 00000000..df7245fb Binary files /dev/null and b/web/public/guide/flasher/install-confirm.webp differ diff --git a/web/public/guide/flasher/install-dashboard.webp b/web/public/guide/flasher/install-dashboard.webp new file mode 100644 index 00000000..9b668cbe Binary files /dev/null and b/web/public/guide/flasher/install-dashboard.webp differ diff --git a/web/public/guide/flasher/install-erasing.webp b/web/public/guide/flasher/install-erasing.webp new file mode 100644 index 00000000..2a847833 Binary files /dev/null and b/web/public/guide/flasher/install-erasing.webp differ diff --git a/web/public/guide/flasher/install-wrapping.webp b/web/public/guide/flasher/install-wrapping.webp new file mode 100644 index 00000000..74fdaf19 Binary files /dev/null and b/web/public/guide/flasher/install-wrapping.webp differ diff --git a/web/public/guide/flasher/install-writing.webp b/web/public/guide/flasher/install-writing.webp new file mode 100644 index 00000000..e8f8203d Binary files /dev/null and b/web/public/guide/flasher/install-writing.webp differ diff --git a/web/public/guide/flasher/wifi-connected.webp b/web/public/guide/flasher/wifi-connected.webp new file mode 100644 index 00000000..18e4b629 Binary files /dev/null and b/web/public/guide/flasher/wifi-connected.webp differ diff --git a/web/public/guide/flasher/wifi-connecting.webp b/web/public/guide/flasher/wifi-connecting.webp new file mode 100644 index 00000000..1d123573 Binary files /dev/null and b/web/public/guide/flasher/wifi-connecting.webp differ diff --git a/web/public/guide/flasher/wifi-form.webp b/web/public/guide/flasher/wifi-form.webp new file mode 100644 index 00000000..83d159aa Binary files /dev/null and b/web/public/guide/flasher/wifi-form.webp differ diff --git a/web/public/guide/flasher/wifi-scanning.webp b/web/public/guide/flasher/wifi-scanning.webp new file mode 100644 index 00000000..0b05999a Binary files /dev/null and b/web/public/guide/flasher/wifi-scanning.webp differ diff --git a/web/public/guide/lab-window/lab.webp b/web/public/guide/lab-window/lab.webp new file mode 100644 index 00000000..123eb115 Binary files /dev/null and b/web/public/guide/lab-window/lab.webp differ diff --git a/web/public/guide/lab/code.webp b/web/public/guide/lab/code.webp new file mode 100644 index 00000000..2cb12603 Binary files /dev/null and b/web/public/guide/lab/code.webp differ diff --git a/web/public/guide/lab/convert.webp b/web/public/guide/lab/convert.webp new file mode 100644 index 00000000..2901e3ea Binary files /dev/null and b/web/public/guide/lab/convert.webp differ diff --git a/web/public/guide/lab/director.webp b/web/public/guide/lab/director.webp new file mode 100644 index 00000000..07ca91e7 Binary files /dev/null and b/web/public/guide/lab/director.webp differ diff --git a/web/public/guide/lab/export.webp b/web/public/guide/lab/export.webp new file mode 100644 index 00000000..c02e2857 Binary files /dev/null and b/web/public/guide/lab/export.webp differ diff --git a/web/public/guide/lab/gallery.webp b/web/public/guide/lab/gallery.webp new file mode 100644 index 00000000..9dbda496 Binary files /dev/null and b/web/public/guide/lab/gallery.webp differ diff --git a/web/public/guide/lab/hw-layers.webp b/web/public/guide/lab/hw-layers.webp new file mode 100644 index 00000000..a390ffc7 Binary files /dev/null and b/web/public/guide/lab/hw-layers.webp differ diff --git a/web/public/guide/lab/knobs.webp b/web/public/guide/lab/knobs.webp new file mode 100644 index 00000000..4bc65318 Binary files /dev/null and b/web/public/guide/lab/knobs.webp differ diff --git a/web/public/guide/lab/layers-blend.webp b/web/public/guide/lab/layers-blend.webp new file mode 100644 index 00000000..cfc3c225 Binary files /dev/null and b/web/public/guide/lab/layers-blend.webp differ diff --git a/web/public/guide/lab/layers.webp b/web/public/guide/lab/layers.webp new file mode 100644 index 00000000..8498ab37 Binary files /dev/null and b/web/public/guide/lab/layers.webp differ diff --git a/web/public/guide/lab/name-saved.webp b/web/public/guide/lab/name-saved.webp new file mode 100644 index 00000000..fccea3d8 Binary files /dev/null and b/web/public/guide/lab/name-saved.webp differ diff --git a/web/public/guide/lab/name.webp b/web/public/guide/lab/name.webp new file mode 100644 index 00000000..a0446e17 Binary files /dev/null and b/web/public/guide/lab/name.webp differ diff --git a/web/public/guide/lab/pasted.webp b/web/public/guide/lab/pasted.webp new file mode 100644 index 00000000..bb7f756f Binary files /dev/null and b/web/public/guide/lab/pasted.webp differ diff --git a/web/public/guide/lab/ports.webp b/web/public/guide/lab/ports.webp new file mode 100644 index 00000000..73f70e06 Binary files /dev/null and b/web/public/guide/lab/ports.webp differ diff --git a/web/public/guide/lab/preview-bw.webp b/web/public/guide/lab/preview-bw.webp new file mode 100644 index 00000000..4f428eb6 Binary files /dev/null and b/web/public/guide/lab/preview-bw.webp differ diff --git a/web/public/guide/lab/preview-color.webp b/web/public/guide/lab/preview-color.webp new file mode 100644 index 00000000..41814701 Binary files /dev/null and b/web/public/guide/lab/preview-color.webp differ diff --git a/web/public/guide/lab/preview-layers.webp b/web/public/guide/lab/preview-layers.webp new file mode 100644 index 00000000..dc2da0f8 Binary files /dev/null and b/web/public/guide/lab/preview-layers.webp differ diff --git a/web/public/guide/lab/ramp-random.webp b/web/public/guide/lab/ramp-random.webp new file mode 100644 index 00000000..85d9a87c Binary files /dev/null and b/web/public/guide/lab/ramp-random.webp differ diff --git a/web/public/guide/lab/ramp.webp b/web/public/guide/lab/ramp.webp new file mode 100644 index 00000000..465a230c Binary files /dev/null and b/web/public/guide/lab/ramp.webp differ diff --git a/web/public/guide/lab/ready-apply.webp b/web/public/guide/lab/ready-apply.webp new file mode 100644 index 00000000..5b596f41 Binary files /dev/null and b/web/public/guide/lab/ready-apply.webp differ diff --git a/web/public/guide/lab/ready-upload.webp b/web/public/guide/lab/ready-upload.webp new file mode 100644 index 00000000..ae83af3b Binary files /dev/null and b/web/public/guide/lab/ready-upload.webp differ diff --git a/web/public/guide/lab/recent.webp b/web/public/guide/lab/recent.webp new file mode 100644 index 00000000..14237284 Binary files /dev/null and b/web/public/guide/lab/recent.webp differ diff --git a/web/public/guide/pcb-v39.glb b/web/public/guide/pcb-v39.glb new file mode 100644 index 00000000..e5461b05 Binary files /dev/null and b/web/public/guide/pcb-v39.glb differ diff --git a/web/src/app/api/community/patterns/[id]/performance/route.ts b/web/src/app/api/community/patterns/[id]/performance/route.ts index 819d9774..d903fa64 100644 --- a/web/src/app/api/community/patterns/[id]/performance/route.ts +++ b/web/src/app/api/community/patterns/[id]/performance/route.ts @@ -138,7 +138,7 @@ async function handlePost(request: Request, context: { params: Promise<{ id: str const raw = body as Record; if (typeof raw.performanceJson !== "string" || raw.performanceJson.length === 0) { - return Response.json({ error: "performanceJson (a Director Save-JSON string) is required." }, { status: 400 }); + return Response.json({ error: "performanceJson (a Director show, as its JSON string) is required." }, { status: 400 }); } if (raw.performanceJson.length > 64 * 1024) { return Response.json({ error: "Performance JSON is too large (max 64 KB)." }, { status: 400 }); diff --git a/web/src/app/community/p/[id]/PatternDetailClient.tsx b/web/src/app/community/p/[id]/PatternDetailClient.tsx index b4a9c752..1d8f6fe5 100644 --- a/web/src/app/community/p/[id]/PatternDetailClient.tsx +++ b/web/src/app/community/p/[id]/PatternDetailClient.tsx @@ -1098,9 +1098,9 @@ function PerformancesSection({ {pattern.performances.length === 0 ? (

      - No recordings yet. A performance is a timed ride through the knobs (Director's - Save-JSON) that a panel replays exactly — publish one and it is live immediately, - credited to you. + No recordings yet. A performance is a timed ride through the knobs (the .pfs the + Director saves) that a panel replays exactly — publish one and it is live + immediately, credited to you.

      ) : (
        diff --git a/web/src/app/guide/ko/page.tsx b/web/src/app/guide/ko/page.tsx new file mode 100644 index 00000000..b1b866ae --- /dev/null +++ b/web/src/app/guide/ko/page.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from "next"; +import GuideExperience from "@/components/guide/GuideExperience"; +import { COPY } from "@/components/guide/copy"; + +const copy = COPY.ko; + +export const metadata: Metadata = { + title: `${copy.meta.title} / Patternflow`, + description: copy.meta.description, + alternates: { + canonical: "/guide/ko", + languages: { en: "/guide", ko: "/guide/ko", "x-default": "/guide" }, + }, + openGraph: { title: copy.meta.title, description: copy.meta.description, url: "/guide/ko", locale: "ko_KR" }, +}; + +export const dynamic = "force-static"; + +export default function GuidePageKo() { + return ; +} diff --git a/web/src/app/guide/make/ko/page.tsx b/web/src/app/guide/make/ko/page.tsx new file mode 100644 index 00000000..6cae8352 --- /dev/null +++ b/web/src/app/guide/make/ko/page.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from "next"; +import GuideExperience from "@/components/guide/GuideExperience"; +import { MAKE_COPY } from "@/components/guide/copy/make"; + +const copy = MAKE_COPY.ko; + +export const metadata: Metadata = { + title: `${copy.meta.title} / Patternflow`, + description: copy.meta.description, + alternates: { + canonical: "/guide/make/ko", + languages: { en: "/guide/make", ko: "/guide/make/ko", "x-default": "/guide/make" }, + }, + openGraph: { title: copy.meta.title, description: copy.meta.description, url: "/guide/make/ko", locale: "ko_KR" }, +}; + +export const dynamic = "force-static"; + +export default function GuideMakePageKo() { + return ; +} diff --git a/web/src/app/guide/make/page.tsx b/web/src/app/guide/make/page.tsx new file mode 100644 index 00000000..8c935aab --- /dev/null +++ b/web/src/app/guide/make/page.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from "next"; +import GuideExperience from "@/components/guide/GuideExperience"; +import { MAKE_COPY } from "@/components/guide/copy/make"; + +const copy = MAKE_COPY.en; + +export const metadata: Metadata = { + title: `${copy.meta.title} / Patternflow`, + description: copy.meta.description, + alternates: { + canonical: "/guide/make", + languages: { en: "/guide/make", ko: "/guide/make/ko", "x-default": "/guide/make" }, + }, + openGraph: { title: copy.meta.title, description: copy.meta.description, url: "/guide/make" }, +}; + +export const dynamic = "force-static"; + +export default function GuideMakePage() { + return ; +} diff --git a/web/src/app/guide/page.tsx b/web/src/app/guide/page.tsx new file mode 100644 index 00000000..ad72819a --- /dev/null +++ b/web/src/app/guide/page.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from "next"; +import GuideExperience from "@/components/guide/GuideExperience"; +import { COPY } from "@/components/guide/copy"; + +const copy = COPY.en; + +export const metadata: Metadata = { + title: `${copy.meta.title} / Patternflow`, + description: copy.meta.description, + alternates: { + canonical: "/guide", + languages: { en: "/guide", ko: "/guide/ko", "x-default": "/guide" }, + }, + openGraph: { title: copy.meta.title, description: copy.meta.description, url: "/guide" }, +}; + +export const dynamic = "force-static"; + +export default function GuidePage() { + return ; +} diff --git a/web/src/app/sitemap.ts b/web/src/app/sitemap.ts index 0901cef1..00ccac40 100644 --- a/web/src/app/sitemap.ts +++ b/web/src/app/sitemap.ts @@ -13,9 +13,15 @@ export default function sitemap(): MetadataRoute.Sitemap { { url: `${siteUrl}/build`, lastModified: now, changeFrequency: "monthly", priority: 0.8 }, { url: `${siteUrl}/inside`, lastModified: now, changeFrequency: "monthly", priority: 0.7 }, { url: `${siteUrl}/roadmap`, lastModified: now, changeFrequency: "weekly", priority: 0.6 }, - // The shelf of firmwares built on core. A device running a variant links + { url: `${siteUrl}/guide`, lastModified: now, changeFrequency: "monthly", priority: 0.8 }, + { url: `${siteUrl}/guide/ko`, lastModified: now, changeFrequency: "monthly", priority: 0.7 }, + // The guide's second page: the community and Pattern Lab. + { url: `${siteUrl}/guide/make`, lastModified: now, changeFrequency: "monthly", priority: 0.7 }, + { url: `${siteUrl}/guide/make/ko`, lastModified: now, changeFrequency: "monthly", priority: 0.6 }, + // The shelf of firmwares built on core. A device running an edition links // here from its own console, so this needs to be findable from outside too. - { url: `${siteUrl}/variants`, lastModified: now, changeFrequency: "monthly", priority: 0.6 }, + // (/variants only redirects here.) + { url: `${siteUrl}/editions`, lastModified: now, changeFrequency: "monthly", priority: 0.6 }, // The catalogue of features, with a reel of each - the other axis of the shelf. { url: `${siteUrl}/features`, lastModified: now, changeFrequency: "monthly", priority: 0.6 }, { url: `${siteUrl}/contact`, lastModified: now, changeFrequency: "yearly", priority: 0.5 }, diff --git a/web/src/components/community/AddPerformanceModal.tsx b/web/src/components/community/AddPerformanceModal.tsx index 19092af6..bc9ab90b 100644 --- a/web/src/components/community/AddPerformanceModal.tsx +++ b/web/src/components/community/AddPerformanceModal.tsx @@ -11,7 +11,7 @@ import AuthModal from "./AuthModal"; import styles from "./Community.module.css"; // Publish a performance recording for a pattern — a Director timeline (the -// Save-JSON file) that rides the same social rails as firmware ports: live +// .pfs it saves, or its JSON form) that rides the same social rails as firmware ports: live // immediately, credited to the recorder, and the pattern's author outranks or // pins. Authoring happens in the Director tool; this modal only takes the // finished JSON, and the server re-validates it against the device player's diff --git a/web/src/components/guide/CommunityShots.module.css b/web/src/components/guide/CommunityShots.module.css new file mode 100644 index 00000000..45494d26 --- /dev/null +++ b/web/src/components/guide/CommunityShots.module.css @@ -0,0 +1,219 @@ +/* Real community screens inside a guide card (CommunityShots.tsx). Each is a + crop of the live site, so the frame takes the site's own background: an + image that stops short reads as more of the same page, not as a hole in + the card. Tokens come from .page in Guide.module.css; the fallbacks keep + it legible anywhere else. */ + +.shots { + margin: 18px 0 4px; + padding: 0; +} + +.frame { + position: relative; + width: 100%; + margin: 0 auto; + aspect-ratio: 3 / 2; + border-radius: 12px; + border: 1px solid var(--g-hair-2, rgba(239, 233, 221, 0.18)); + background: #0b0b0c; + overflow: hidden; + isolation: isolate; +} + +/* Never taller than a share of the screen: on a phone the card sits under + the stage and has to leave the board room. */ +@media (min-width: 900px) { + .frame { + width: min(100%, 49.5vh); + } +} +@media (max-width: 899px) { + .frame { + width: min(100%, 40.5vh); + } +} + +.shot { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + max-width: none; + object-fit: cover; + opacity: 0; + pointer-events: none; + user-select: none; + /* The next screen comes up over the last one, which only goes once it is + covered: never a frame with nothing in it. */ + z-index: 1; + transition: opacity 0.12s linear 0.34s; +} +.shot[data-on="1"] { + z-index: 2; + opacity: 1; + transition: opacity 0.34s ease; +} + +/* The control the screen is about. It glides when the next screen is the + same page, and arrives fresh when it is a new one. */ +.ring { + position: absolute; + z-index: 3; + border: 2px solid var(--g-led, #ff6a3d); + border-radius: 8px; + box-shadow: + inset 0 0 0 1px rgba(0, 0, 0, 0.55), + 0 0 0 1px rgba(0, 0, 0, 0.55), + 0 0 18px rgba(255, 106, 61, 0.45); + pointer-events: none; + transition: + left 0.45s cubic-bezier(0.2, 0.7, 0.2, 1), + top 0.45s cubic-bezier(0.2, 0.7, 0.2, 1), + width 0.45s cubic-bezier(0.2, 0.7, 0.2, 1), + height 0.45s cubic-bezier(0.2, 0.7, 0.2, 1); + animation: + ringIn 0.4s cubic-bezier(0.2, 0.7, 0.2, 1) 0.3s both, + ringPulse 2.4s ease-in-out 0.7s infinite; +} + +@keyframes ringIn { + from { + opacity: 0; + transform: scale(1.12); + } + to { + opacity: 1; + transform: scale(1); + } +} +@keyframes ringPulse { + 0%, + 100% { + box-shadow: + inset 0 0 0 1px rgba(0, 0, 0, 0.55), + 0 0 0 1px rgba(0, 0, 0, 0.55), + 0 0 18px rgba(255, 106, 61, 0.45); + } + 50% { + box-shadow: + inset 0 0 0 1px rgba(0, 0, 0, 0.55), + 0 0 0 1px rgba(0, 0, 0, 0.55), + 0 0 26px 3px rgba(255, 106, 61, 0.6); + } +} + +.caption { + margin-top: 12px; +} + +.dots { + display: flex; + align-items: center; + gap: 6px; +} +.dot { + position: relative; + display: grid; + place-items: center; + width: 24px; + height: 24px; + padding: 0; + border: 1px solid var(--g-hair-2, rgba(239, 233, 221, 0.18)); + border-radius: 999px; + background: transparent; + color: var(--g-ink-3, rgba(239, 233, 221, 0.52)); + font: 600 10.5px/1 var(--pf-mono, ui-monospace, monospace); + cursor: pointer; + transition: + background 0.2s, + border-color 0.2s, + color 0.2s; +} +/* A bigger hit area than the dot itself, without spreading the row. */ +.dot::before { + content: ""; + position: absolute; + inset: -6px -3px; +} +.dot[data-done="1"] { + border-color: rgba(255, 106, 61, 0.35); + color: var(--g-ink-2, rgba(239, 233, 221, 0.78)); +} +.dot[data-on="1"] { + border-color: var(--g-led, #ff6a3d); + background: var(--g-led, #ff6a3d); + color: #150a06; +} +.dot:hover:not([data-on="1"]) { + border-color: var(--g-ink-3, rgba(239, 233, 221, 0.52)); + color: var(--g-ink, #efe9dd); +} +.dot:focus-visible { + outline: 2px solid var(--g-led, #ff6a3d); + outline-offset: 2px; +} +.where { + margin-left: auto; + font: 500 11px/1 var(--pf-mono, ui-monospace, monospace); + letter-spacing: 0.06em; + color: var(--g-ink-3, rgba(239, 233, 221, 0.52)); + white-space: nowrap; +} + +/* Every caption sits in the same grid cell, so the block is as tall as the + longest one and nothing below it jumps when the screen changes. */ +.texts { + display: grid; + margin-top: 10px; +} +.text { + grid-area: 1 / 1; + margin: 0; + font-size: 13px; + line-height: 1.5; + color: var(--g-ink-2, rgba(239, 233, 221, 0.78)); + opacity: 0; + visibility: hidden; + transition: + opacity 0.25s ease, + visibility 0s linear 0.25s; +} +.text[data-on="1"] { + opacity: 1; + visibility: visible; + transition: + opacity 0.3s ease 0.12s, + visibility 0s; +} +/* The UI's own words, as it writes them. */ +.text b { + display: block; + margin-bottom: 2px; + font-weight: 600; + color: var(--g-ink, #efe9dd); +} + +@media (max-width: 899px) { + .caption { + margin-top: 10px; + } + .text { + font-size: 12.5px; + line-height: 1.45; + } +} + +@media (prefers-reduced-motion: reduce) { + .shot, + .shot[data-on="1"], + .text, + .text[data-on="1"], + .dot, + .ring { + transition: none; + } + .ring { + animation: none; + } +} diff --git a/web/src/components/guide/CommunityShots.tsx b/web/src/components/guide/CommunityShots.tsx new file mode 100644 index 00000000..0bc2fb4e --- /dev/null +++ b/web/src/components/guide/CommunityShots.tsx @@ -0,0 +1,391 @@ +"use client"; + +// 05 Community — the community as it really is, inside a step's card: crops +// of the live public site (community.patternflow.work, logged out), captured +// at 2x by community_shots.py into web/public/guide/community/, shown one +// after another the way FlasherShots shows the flasher's dialog. A ring marks +// the control each screen is about, and the caption's bold line is the UI's +// own words, as it writes them. Nothing here is redrawn — if the site +// changes, re-run the script rather than editing the images; the rings are +// the fractions it prints. +// +// Used by every step of the chapter (copy/community.ts, extra +// "communityShots"); `step` picks that step's screens. They step on their +// own only while that step is on stage (the store's scene and step) and the +// frame is on screen, never under the pointer or keyboard focus, and not at +// all for reduced motion. Off stage, the set goes back to its first screen. + +import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from "react"; +import { useGuideStore, type GuideLang } from "./store"; +import styles from "./CommunityShots.module.css"; + +/** Where the control is, as fractions of the image (community_shots.py prints these). */ +type Ring = { x: number; y: number; w: number; h: number }; + +type Shot = { + /** web/public/guide/community/.webp — a 3:2 crop at 2x. Two shots may share one. */ + file: string; + rings: Ring[]; + /** The UI's own words, quoted exactly (English in both languages). */ + title: string; + en: string; + ko: string; + /** Which page of the site it is. */ + where: Record; + /** How long this screen stays up before the next one (ms). */ + ms?: number; +}; + +const BASE = "/guide/community/"; +const STEP_MS = 3600; +const LAST_HOLD_MS = 1200; + +const WALL = { en: "Patterns", ko: "Patterns" }; +const PATTERN = { en: "a pattern's page", ko: "패턴 페이지" }; +const DECK_BAR = { en: "the bar at the bottom", ko: "아래쪽 바" }; +const DECKS = { en: "Decks", ko: "Decks" }; +const DECK = { en: "a deck's page", ko: "덱 페이지" }; +const LAB = { en: "Pattern Lab", ko: "Pattern Lab" }; + +// One list per step of the chapter, in the step's order. +const STEPS: Shot[][] = [ + // 0 — the wall + [ + { + file: "wall-sorts", + rings: [{ x: 0.2456, y: 0.1964, w: 0.7172, h: 0.1082 }], + title: "Newest · Oldest · Most liked · Most forked · In decks", + en: "The orders the wall comes in. Oldest goes back to the very first patterns.", + ko: "벽을 늘어놓는 순서예요. Oldest를 누르면 맨 처음 패턴부터 나와요.", + where: WALL, + }, + { + file: "wall-search", + rings: [ + { x: 0.0332, y: 0.056, w: 0.5752, h: 0.1671 }, + { x: 0.031, y: 0.2557, w: 0.4948, h: 0.0928 }, + ], + title: "Search titles or @author", + en: "A title, or @ and a name. @engmung is the person who made Patternflow.", + ko: "제목으로, 또는 @와 이름으로 찾아요. @engmung은 패턴플로우를 만든 사람이에요.", + where: WALL, + }, + { + file: "wall-hover", + rings: [{ x: 0.5259, y: 0.0573, w: 0.4664, h: 0.2538 }], + title: "scroll on a screen to turn its knobs · hover to play", + en: "The screen is split K1 to K4, left to right. The wheel turns the knob under the pointer.", + ko: "화면이 왼쪽부터 K1–K4로 나뉘어 있어요. 휠은 포인터 아래 노브를 돌려요.", + where: WALL, + ms: 4200, + }, + ], + // 1 — .h + [ + { + file: "h-badge", + rings: [{ x: 0.5238, y: 0.0542, w: 0.0681, h: 0.0863 }], + title: "Hardware ready — ships a .h firmware header", + en: "The right one can go on a board. The left one is JS only: it plays here, not there.", + ko: "오른쪽은 보드에 올라가요. 왼쪽은 JS뿐이라 여기서만 돌아요.", + where: WALL, + }, + { + file: "h-filter", + rings: [{ x: 0.6393, y: 0.1326, w: 0.2907, h: 0.096 }], + title: ".h Flashable now", + en: "The same wall, only the patterns that ship a .h.", + ko: "같은 벽에서 .h가 있는 패턴만 보여줘요.", + where: WALL, + }, + { + file: "h-port", + rings: [{ x: 0.2694, y: 0.4027, w: 0.296, h: 0.1108 }], + title: "Port this pattern (.h)", + en: "On a pattern with no .h yet. Ran it on your own board? Propose the .h: signed in, and credited to you.", + ko: "아직 .h가 없는 패턴에 있어요. 내 보드에서 돌려 봤다면 .h를 제안해요. 로그인해야 하고, 내 이름으로 올라가요.", + where: PATTERN, + ms: 4200, + }, + ], + // 2 — one pattern onto the board + [ + { + file: "p-actions", + rings: [{ x: 0.5395, y: 0.8552, w: 0.426, h: 0.1352 }], + title: "↗ Send to my Patternflow", + en: "On the page of any pattern with a .h. No account needed.", + ko: ".h가 있는 패턴 페이지마다 있어요. 계정이 필요 없어요.", + where: PATTERN, + }, + { + file: "p-send-dialog", + rings: [{ x: 0.0668, y: 0.6516, w: 0.8664, h: 0.1641 }], + title: "Send over Wi-Fi", + en: "Opens your board's Patterns page with this pattern linked. That page fetches it and installs it.", + ko: "보드의 Patterns 페이지가 열리고, 그 페이지가 이 패턴을 받아서 설치해요.", + where: PATTERN, + ms: 4200, + }, + { + file: "p-send-dialog", + rings: [{ x: 0.0668, y: 0.8097, w: 0.4352, h: 0.1641 }], + title: "Download .zip", + en: "Board out of reach from here, on a VPN say? Drop the .zip on the board's Patterns page, as it is — don't unzip it.", + ko: "여기서 보드에 닿지 않으면(VPN 등) .zip을 받아 보드의 Patterns 페이지에 그대로 올려요. 압축은 풀지 않아요.", + where: PATTERN, + ms: 4200, + }, + ], + // 3 — your own deck + [ + { + file: "d-plus", + rings: [{ x: 0.4834, y: 0.5399, w: 0.083, h: 0.1246 }], + title: "Add to your deck", + en: "The + on a card with a .h. Pressed, it turns into a −.", + ko: ".h가 있는 카드의 +예요. 누르면 −로 바뀌어요.", + where: WALL, + }, + { + file: "d-dock", + rings: [{ x: 0.0056, y: 0.8, w: 0.5752, h: 0.1917 }], + title: "Your deck 4 / 20", + en: "Along the bottom of every page with patterns on it. The numbers are the order.", + ko: "패턴이 있는 페이지마다 아래에 붙어 있어요. 숫자가 순서예요.", + where: DECK_BAR, + }, + { + file: "d-drag", + rings: [{ x: 0.3006, y: 0.8028, w: 0.0778, h: 0.1889 }], + title: "drag to rearrange · ✕ removes", + en: "Carry a slot sideways and the others make room. Let go on ✕ and it's out.", + ko: "칸을 옆으로 끌면 다른 칸이 비켜 줘요. ✕ 위에서 놓으면 빠져요.", + where: DECK_BAR, + }, + { + file: "d-empty", + rings: [{ x: 0.5696, y: 0.8, w: 0.4248, h: 0.1917 }], + title: "press ✕ again to empty all 4", + en: "✕ pressed on its own asks first. A second press empties the deck, and there is no undo.", + ko: "✕만 누르면 먼저 물어요. 한 번 더 누르면 덱이 비워지고, 되돌릴 수 없어요.", + where: DECK_BAR, + }, + { + file: "d-dock-end", + rings: [{ x: 0.6359, y: 0.8441, w: 0.2993, h: 0.1256 }], + title: "Send to my board", + en: "Builds the deck as modules for your board. Needs you signed in — and so does Share deck, beside it.", + ko: "덱을 보드용 모듈로 빌드해요. 로그인이 필요해요. 옆의 Share deck도 마찬가지예요.", + where: DECK_BAR, + ms: 4200, + }, + ], + // 4 — other people's decks + [ + { + file: "k-shelf", + rings: [{ x: 0.5317, y: 0.229, w: 0.4633, h: 0.4827 }], + title: "Community decks", + en: "Everyone's public decks: the first few patterns, in order, then how many more.", + ko: "모두의 공개 덱이에요. 앞의 패턴 몇 개가 순서대로, 나머지는 개수로 보여요.", + where: DECKS, + }, + { + file: "k-deck", + rings: [{ x: 0.0268, y: 0.266, w: 0.2757, h: 0.1256 }], + title: "Install to my board", + en: "On a public deck. No sign-in: your board's Patterns page opens with the whole deck queued.", + ko: "공개 덱에 있어요. 로그인 없이, 보드의 Patterns 페이지가 덱 전체를 담은 채로 열려요.", + where: DECK, + }, + { + file: "k-deck", + rings: [{ x: 0.0536, y: 0.8708, w: 0.9411, h: 0.0783 }], + title: "A deck's .zip also carries its running order", + en: "On the board its patterns come first — right after Origin, in the deck's order.", + ko: "보드에선 덱의 패턴이 맨 앞, Origin 바로 다음부터 덱 순서대로 놓여요.", + where: DECK, + }, + { + file: "k-copy", + rings: [{ x: 0.0341, y: 0.1351, w: 0.4904, h: 0.1256 }], + title: "Press again — this replaces your deck", + en: "Copy into my deck, with a deck already in your bar: it asks before it replaces yours.", + ko: "바에 이미 덱이 있으면, Copy into my deck은 내 덱을 바꾸기 전에 한 번 물어요.", + where: DECK, + ms: 4200, + }, + ], + // 5 — open it in the Lab + [ + { + file: "p-actions", + rings: [{ x: 0.1975, y: 0.8552, w: 0.3462, h: 0.1352 }], + title: "Open in Pattern Lab", + en: "On every pattern's page, with a .h or without.", + ko: "모든 패턴 페이지에 있어요. .h가 있든 없든요.", + where: PATTERN, + }, + { + file: "lab-header", + rings: [{ x: 0.3136, y: 0.0863, w: 0.2273, h: 0.0648 }], + title: "forking from koi pond", + en: "The copy arrives marked as a fork. If it's no longer a remix, × takes the mark off.", + ko: "복사본에 포크 표시가 붙어서 와요. 더는 리믹스가 아니면 ×로 떼요.", + where: LAB, + ms: 4200, + }, + { + file: "lab-header", + rings: [{ x: 0.6982, y: 0.0275, w: 0.1094, h: 0.105 }], + title: "Share", + en: "Publishes it to the community as your fork. Needs you signed in.", + ko: "커뮤니티에 내 포크로 올려요. 로그인이 필요해요.", + where: LAB, + }, + ], +]; + +const NONE: Shot[] = []; + +const UI = { + en: { label: "The community, screen by screen", step: "Screen" }, + ko: { label: "커뮤니티 화면 순서", step: "화면" }, +} as const; + +function subscribeReducedMotion(cb: () => void) { + const mq = window.matchMedia("(prefers-reduced-motion: reduce)"); + mq.addEventListener("change", cb); + return () => mq.removeEventListener("change", cb); +} +const getReducedMotion = () => window.matchMedia("(prefers-reduced-motion: reduce)").matches; +// On the server nothing moves; the client decides after hydration. +const getReducedMotionServer = () => true; + +export default function CommunityShots({ lang, step }: { lang: GuideLang; step: number }) { + const shots = STEPS[step] ?? NONE; + const n = shots.length; + const ui = UI[lang]; + // Each image once, however many shots look at it. + const files = shots.map((s) => s.file).filter((f, i, all) => all.indexOf(f) === i); + + const rootRef = useRef(null); + const [index, setIndex] = useState(0); + const [visible, setVisible] = useState(false); + const [hovered, setHovered] = useState(false); + const [focused, setFocused] = useState(false); + const reduced = useSyncExternalStore(subscribeReducedMotion, getReducedMotion, getReducedMotionServer); + + // This step on stage. Leaving it puts the set back to its first screen, so + // a reader who comes back sees it from the start. + const onStage = useGuideStore((s) => s.page === "make" && s.scene === "community" && s.step === step); + const [wasOnStage, setWasOnStage] = useState(onStage); + if (wasOnStage !== onStage) { + setWasOnStage(onStage); + if (!onStage) setIndex(0); + } + + const active = n ? index % n : 0; + const running = n > 1 && onStage && visible && !hovered && !focused && !reduced; + + useEffect(() => { + const el = rootRef.current; + if (!el) return; + const io = new IntersectionObserver(([entry]) => setVisible(entry.isIntersecting && entry.intersectionRatio >= 0.35), { + threshold: [0, 0.35], + }); + io.observe(el); + return () => io.disconnect(); + }, []); + + // One timeout per screen, so a click restarts the clock on the new one. + useEffect(() => { + if (!running) return; + const ms = (shots[active].ms ?? STEP_MS) + (active === n - 1 ? LAST_HOLD_MS : 0); + const t = window.setTimeout(() => setIndex((i) => (i + 1) % n), ms); + return () => window.clearTimeout(t); + }, [running, active, n, shots]); + + const onBlur = useCallback((e: React.FocusEvent) => { + if (!e.currentTarget.contains(e.relatedTarget as Node | null)) setFocused(false); + }, []); + + if (!n) return null; + const on = shots[active]; + + return ( +
        setHovered(true)} + onMouseLeave={() => setHovered(false)} + onFocus={() => setFocused(true)} + onBlur={onBlur} + > +
        + {files.map((file) => ( + // eslint-disable-next-line @next/next/no-img-element + {file + ))} + {on.rings.map((r, i) => ( +
        + +
        +
        + {shots.map((s, i) => ( + + ))} + {on.where[lang]} +
        + {/* Every caption in one grid cell: the block is as tall as the longest. */} +
        + {shots.map((s, i) => ( +

        + {s.title} + {s[lang]} +

        + ))} +
        +
        +
        + ); +} diff --git a/web/src/components/guide/ConsoleWindow.module.css b/web/src/components/guide/ConsoleWindow.module.css new file mode 100644 index 00000000..aecf701b --- /dev/null +++ b/web/src/components/guide/ConsoleWindow.module.css @@ -0,0 +1,561 @@ +/* The console window: a browser the guide's colours, around the device's own + pages. Tokens are local because the lifted window is portalled to , + outside the guide's .page where --g-* live. */ + +.root, +.layer { + --cw-ink: #efe9dd; + --cw-ink-2: rgba(239, 233, 221, 0.72); + --cw-ink-3: rgba(239, 233, 221, 0.46); + --cw-hair: rgba(239, 233, 221, 0.1); + --cw-hair-2: rgba(239, 233, 221, 0.18); + --cw-led: #ff6a3d; + /* The console's own ground (home.html --bg), so a frame that has not + painted yet is already the right colour. */ + --cw-page: #0c0b09; + --cw-chrome: #1b1a18; + --cw-chrome-2: #131210; + --cw-field: #0f0e0d; + --cw-shadow: 0 22px 60px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.35); +} + +.root { + margin: 18px 0 4px; +} + +/* ── the miniature: one button, the whole window ── */ + +.opener { + appearance: none; + display: block; + width: 100%; + margin: 0; + padding: 0; + border: 0; + background: none; + color: inherit; + font: inherit; + text-align: left; + cursor: pointer; + border-radius: 12px; + transition: + opacity 0.22s ease, + transform 0.35s cubic-bezier(0.2, 0.7, 0.2, 1); +} +.root[data-variant="phone"] .opener { + width: 232px; + margin: 0 auto; + border-radius: 32px; +} +/* On a phone the card sits under the board: a smaller phone, showing the + top of its page, leaves the board room. The lifted phone shows all of it. */ +@media (max-width: 899px) { + .root[data-variant="phone"] .opener { + width: 184px; + } + .root[data-variant="phone"] .opener .mini { + aspect-ratio: 390 / 430 !important; + } + /* The desktop window too shows the top of its page: Now playing and the + sliders are up there, and the card stays short enough to leave the + board above it. */ + .root[data-variant="desktop"] .opener .mini { + aspect-ratio: 1024 / 540 !important; + } + /* The address from K2 has to read in full: the chip keeps only its icon. */ + .root[data-variant="phone"] .openChip { + gap: 0; + padding: 0 5px; + font-size: 0; + } +} +.opener:focus-visible { + outline: 2px solid var(--cw-led); + outline-offset: 4px; +} +/* It has left the card while it floats. */ +.opener[data-lifted="1"] { + opacity: 0; +} +@media (hover: hover) and (prefers-reduced-motion: no-preference) { + .opener:hover { + transform: translateY(-2px); + } +} + +.frame { + display: block; + border: 0; + background: var(--cw-page); + color-scheme: dark; +} + +.mini { + position: relative; + display: block; + overflow: hidden; + background: var(--cw-page); +} +.mini .frame { + position: absolute; + left: 0; + top: 0; + transform-origin: 0 0; + pointer-events: none; +} + +/* ── desktop: tab strip, toolbar, page ── */ + +.window { + display: flex; + flex-direction: column; + overflow: hidden; + border: 1px solid var(--cw-hair-2); + border-radius: 11px; + background: var(--cw-chrome); + box-shadow: var(--cw-shadow); + transition: border-color 0.25s; +} +.opener:hover .window, +.opener:focus-visible .window { + border-color: rgba(255, 106, 61, 0.45); +} + +.bar { + display: block; + flex: none; + font-family: var(--pf-sans, system-ui, sans-serif); +} +.tabs { + display: flex; + align-items: flex-end; + height: 28px; + padding: 0 8px 0 10px; + background: var(--cw-chrome-2); +} +.lights { + display: flex; + gap: 5px; + align-self: center; + margin-right: 12px; +} +.lights i { + width: 8px; + height: 8px; + border-radius: 50%; + background: rgba(239, 233, 221, 0.16); +} +.tab { + display: flex; + align-items: center; + gap: 7px; + min-width: 0; + max-width: 190px; + height: 22px; + padding: 0 14px 0 10px; + border-radius: 7px 7px 0 0; + background: var(--cw-chrome); + font-size: 11px; + color: var(--cw-ink-2); +} +.favicon { + flex: none; + width: 7px; + height: 7px; + border-radius: 50%; + background: #ff5c2e; + box-shadow: 0 0 5px rgba(255, 92, 46, 0.7); +} +.tabTitle { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.barEnd { + display: flex; + align-items: center; + align-self: center; + margin-left: auto; +} +.toolbar { + display: flex; + align-items: center; + gap: 10px; + height: 30px; + padding: 0 10px; + border-bottom: 1px solid rgba(0, 0, 0, 0.5); + background: var(--cw-chrome); +} +.navIcons { + display: flex; + gap: 6px; + color: var(--cw-ink-3); +} +.navIcons svg { + width: 13px; + height: 13px; +} +.navIcons svg:nth-child(2) { + opacity: 0.45; +} + +.address { + display: flex; + align-items: center; + gap: 7px; + flex: 1; + min-width: 0; + height: 21px; + padding: 0 10px; + border-radius: 999px; + background: var(--cw-field); + font-family: var(--pf-mono, ui-monospace, monospace); + font-size: 10.5px; + letter-spacing: 0.01em; + color: var(--cw-ink); +} +.info { + flex: none; + width: 12px; + height: 12px; + color: var(--cw-ink-3); +} +.url { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.path { + color: var(--cw-ink-3); +} + +.openChip { + display: inline-flex; + align-items: center; + gap: 4px; + height: 18px; + padding: 0 7px 0 8px; + border: 1px solid var(--cw-hair-2); + border-radius: 999px; + font-family: var(--pf-mono, ui-monospace, monospace); + font-size: 9.5px; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--cw-ink-2); + transition: + color 0.2s, + border-color 0.2s, + background 0.2s; +} +.openChip svg { + width: 10px; + height: 10px; +} +.opener:hover .openChip, +.opener:focus-visible .openChip { + color: var(--cw-led); + border-color: var(--cw-led); + background: rgba(255, 106, 61, 0.1); +} + +/* ── phone ── */ + +.phone { + --bezel: 7px; + display: flex; + flex-direction: column; + padding: var(--bezel); + border: 1px solid var(--cw-hair-2); + border-radius: 32px; + background: #0d0c0b; + box-shadow: var(--cw-shadow); + transition: border-color 0.25s; +} +.opener:hover .phone, +.opener:focus-visible .phone { + border-color: rgba(255, 106, 61, 0.45); +} +.phoneTop { + display: block; + flex: none; + overflow: hidden; + border-radius: 24px 24px 0 0; + background: var(--cw-chrome); + font-family: var(--pf-sans, system-ui, sans-serif); +} +.status { + position: relative; + display: flex; + align-items: center; + justify-content: space-between; + height: 20px; + padding: 0 16px 0 20px; + font-size: 9px; + font-weight: 600; + color: var(--cw-ink); +} +.clock { + font-variant-numeric: tabular-nums; +} +.island { + position: absolute; + left: 50%; + top: 4px; + width: 54px; + height: 14px; + margin-left: -27px; + border-radius: 999px; + background: #000; +} +.statusIcons { + display: flex; + align-items: center; + gap: 4px; +} +.statusIcons svg { + width: 11px; + height: 8px; +} +.battery { + position: relative; + width: 15px; + height: 7px; + border: 1px solid var(--cw-ink-2); + border-radius: 2px; +} +.battery::after { + content: ""; + position: absolute; + inset: 1px 3px 1px 1px; + border-radius: 1px; + background: var(--cw-ink); +} +.phoneBar { + display: flex; + align-items: center; + gap: 6px; + height: 30px; + padding: 0 7px 3px; +} +.phoneBar .address { + justify-content: center; + height: 22px; + font-size: 10px; +} +.phone > .mini { + border-radius: 0 0 3px 3px; +} +.homeBar { + position: relative; + display: block; + flex: none; + height: 14px; +} +.homeBar::after { + content: ""; + position: absolute; + left: 50%; + top: 6px; + width: 64px; + height: 3px; + margin-left: -32px; + border-radius: 2px; + background: rgba(239, 233, 221, 0.4); +} + +/* ── lifted ── */ + +.layer { + position: fixed; + inset: 0; + z-index: 1000; +} +.backdrop { + position: absolute; + inset: 0; + /* The board, on the left of a wide stage, stays in the light: the window + is there to be used beside it. */ + background: linear-gradient(90deg, rgba(8, 7, 6, 0.05) 0%, rgba(8, 7, 6, 0.3) 34%, rgba(8, 7, 6, 0.78) 58%, rgba(8, 7, 6, 0.86) 100%); + opacity: 0; + transition: opacity 0.4s ease; +} +.layer[data-narrow="1"] .backdrop { + background: rgba(8, 7, 6, 0.84); +} +.layer[data-shown="1"] .backdrop { + opacity: 1; +} + +.lift { + position: absolute; + transform-origin: 0 0; + transition: + transform 0.44s cubic-bezier(0.22, 0.8, 0.2, 1), + opacity 0.26s ease; +} +.layer[data-shown="1"] .lift { + transition: + transform 0.44s cubic-bezier(0.22, 0.8, 0.2, 1), + opacity 0.18s ease; +} + +.big.window { + width: 100%; + height: 100%; + border-radius: 12px; + border-color: rgba(239, 233, 221, 0.22); + box-shadow: + 0 40px 120px rgba(0, 0, 0, 0.62), + 0 4px 16px rgba(0, 0, 0, 0.4); +} +.big .tabs { + height: 36px; + padding: 0 10px 0 14px; +} +.big .lights { + gap: 7px; + margin-right: 16px; +} +.big .lights i { + width: 11px; + height: 11px; +} +.big .tab { + gap: 8px; + max-width: 240px; + height: 28px; + padding: 0 18px 0 12px; + border-radius: 9px 9px 0 0; + font-size: 12.5px; +} +.big .toolbar { + height: 40px; + gap: 14px; + padding: 0 12px; +} +.big .navIcons { + gap: 10px; +} +.big .navIcons svg { + width: 16px; + height: 16px; +} +.big .address { + height: 28px; + padding: 0 14px; + font-size: 13px; +} +.big .info { + width: 14px; + height: 14px; +} +.viewport { + position: relative; + flex: 1; + min-height: 0; + background: var(--cw-page); +} + +.close { + appearance: none; + display: grid; + place-items: center; + width: 28px; + height: 28px; + margin: 0; + padding: 0; + border: 1px solid var(--cw-hair-2); + border-radius: 50%; + background: rgba(239, 233, 221, 0.04); + color: var(--cw-ink-2); + cursor: pointer; + transition: + color 0.2s, + border-color 0.2s, + background 0.2s; +} +.close svg { + width: 14px; + height: 14px; +} +.close:hover { + color: var(--cw-ink); + border-color: var(--cw-led); + background: rgba(255, 106, 61, 0.14); +} +.close:focus-visible { + outline: 2px solid var(--cw-led); + outline-offset: 2px; +} + +.phoneScale { + transform-origin: 0 0; +} +.big.phone { + --bezel: 10px; + width: 100%; + height: 100%; + border-radius: 50px; + border-color: rgba(239, 233, 221, 0.22); + box-shadow: + 0 40px 120px rgba(0, 0, 0, 0.62), + 0 4px 16px rgba(0, 0, 0, 0.4); +} +.big .phoneTop { + height: var(--top); + border-radius: 40px 40px 0 0; +} +.big .status { + height: 40px; + padding: 0 30px 0 36px; + font-size: 14px; +} +.big .island { + top: 9px; + width: 104px; + height: 26px; + margin-left: -52px; +} +.big .statusIcons { + gap: 7px; +} +.big .statusIcons svg { + width: 17px; + height: 12px; +} +.big .battery { + width: 24px; + height: 11px; + border-radius: 3px; +} +.big .phoneBar { + height: 52px; + gap: 10px; + padding: 0 12px 8px; +} +.big .phoneBar .address { + height: 38px; + font-size: 14px; +} +.phoneView { + flex: none; + overflow: hidden; + background: var(--cw-page); +} +.big .homeBar { + height: var(--foot); +} +.big .homeBar::after { + top: 10px; + width: 134px; + height: 5px; + margin-left: -67px; + border-radius: 3px; +} + +@media (prefers-reduced-motion: reduce) { + .lift, + .layer[data-shown="1"] .lift { + transition: opacity 0.18s ease; + } +} diff --git a/web/src/components/guide/ConsoleWindow.tsx b/web/src/components/guide/ConsoleWindow.tsx new file mode 100644 index 00000000..8421e54d --- /dev/null +++ b/web/src/components/guide/ConsoleWindow.tsx @@ -0,0 +1,720 @@ +"use client"; + +import { useCallback, useEffect, useRef, useState, type CSSProperties, type ReactNode, type RefObject } from "react"; +import { createPortal } from "react-dom"; +import { SIM_IP } from "@/lib/guide/deviceSim"; +import { getSim, useGuideStore, type GuideLang } from "./store"; +import styles from "./ConsoleWindow.module.css"; + +// The device console, working, in a browser window on the page. +// +// The window holds the demo in public/guide/console-demo/ (written by +// firmware/toolchain/console_demo.py): the core's real console pages with a +// simulated board behind them — one board per browser tab, kept in +// sessionStorage, so every window on the page shows the same one. This file +// is the other end of the demo's bridge (documented at the top of +// pf-demo.js): what the console does reaches the 3D board through getSim(), +// and the board's state goes back to the console, so a knob turned on the +// model and a slider dragged in the window act on the same device. +// +// In the card the window is a live miniature: its pages run and follow the +// board, but the card scrolls with the story, so it takes no input. A click +// lifts it — a full-size window floats over the page beside the board, with +// a frame of its own on the same board — until Esc, the close button or a +// click beside it. + +export type ConsoleVariant = "desktop" | "phone"; +export type ConsolePage = "home" | "patterns" | "wifi" | "knobs" | "update"; +type Variant = ConsoleVariant; +type Page = ConsolePage; + +const DEMO = "/guide/console-demo/"; +const FILE: Record = { + home: "index.html", + patterns: "patterns.html", + wifi: "wifi.html", + knobs: "knobs.html", + update: "update.html", +}; +// The address bar shows the device's own paths, not the demo's files. +const DEVICE_PATH: Record = { + "index.html": "", + "patterns.html": "/patterns", + "status.html": "/status", + "wifi.html": "/wifi", + "knobs.html": "/knobs", + "update.html": "/update", +}; +// A laptop opens the name; a phone, as the guide says, the address from K2. +const HOST: Record = { desktop: "patternflow.local", phone: SIM_IP }; +// The page's viewport in CSS pixels. The miniature scales it into the card; +// the lifted phone shows it at this size, the lifted desktop at the window's. +const VIEW: Record = { + desktop: { w: 1024, h: 640 }, + phone: { w: 390, h: 720 }, +}; +// The lifted phone: bezel, the browser's top (status row + address bar), and +// the home indicator strip, around VIEW.phone. +// The miniature phone's bezel, in card pixels. +const MINI_BEZEL = 7; +const PHONE_BEZEL = 10; +const PHONE_TOP = 92; +const PHONE_FOOT = 22; +const PHONE_W = VIEW.phone.w + 2 * PHONE_BEZEL; +const PHONE_H = VIEW.phone.h + PHONE_TOP + PHONE_FOOT + 2 * PHONE_BEZEL; +// Names this page load in pf-sim: its encoder counts start at zero here. +const SID = Math.random().toString(36).slice(2, 10); +const LIFT_MS = 440; + +const UI: Record = { + en: { open: "Open", close: "Close", label: "The device console" }, + ko: { open: "열기", close: "닫기", label: "기기 콘솔" }, +}; + +type Msg = { + type?: string; + action?: string; + modules?: string[]; + inv?: boolean[]; + sub?: number[]; + slug?: string; + knob?: number; + value?: number; + level?: number; + on?: boolean; +}; + +// ── the bridge ────────────────────────────────────────────────────────────── + +/** + * Drives the board from the frames' pf-console messages, and posts the + * board's state (pf-sim) to the frames whenever it changes, at most four + * times a second. What the console stores on the board — which modules it + * has, how the knobs count — holds while the reader is in this window's + * scene; the guide's other chapters keep the board they describe. + */ +function useBridge(frames: RefObject[], root: RefObject, onEscape: () => void) { + const stored = useRef<{ modules: string[] | null; inv: boolean[] | null; sub: number[] | null }>({ + modules: null, + inv: null, + sub: null, + }); + const here = useRef(null); + const last = useRef({ key: "", at: 0 }); + const escape = useRef(onEscape); + useEffect(() => { + escape.current = onEscape; + }, [onEscape]); + + const post = useCallback( + (force: boolean) => { + const state = getSim().consoleState(); + const key = JSON.stringify(state); + const t = performance.now(); + if (!force && (key === last.current.key || t - last.current.at < 250)) return; + last.current = { key, at: t }; + const msg = { type: "pf-sim", sid: SID, ...state }; + for (const f of frames) f.current?.contentWindow?.postMessage(msg, window.location.origin); + }, + [frames], + ); + + const apply = useCallback(() => { + if (!here.current) return; + const sim = getSim(); + const s = stored.current; + if (s.modules) sim.setModules(s.modules); + if (s.inv && s.sub) sim.setKnobSettings(s.inv, s.sub); + }, []); + + // In this scene, the console's board; out of it, the guide's. + useEffect(() => { + const scene = root.current?.closest("[data-scene]")?.dataset.scene ?? null; + const follow = (current: string) => { + const now = scene === null || current === scene; + if (now === here.current) return; + here.current = now; + if (now) apply(); + else { + const sim = getSim(); + sim.setModules(null); + sim.setKnobSettings([false, false, false, false], [4, 4, 4, 4]); + } + }; + follow(useGuideStore.getState().scene); + return useGuideStore.subscribe((s) => follow(s.scene)); + }, [root, apply]); + + useEffect(() => { + const onMessage = (e: MessageEvent) => { + if (e.origin !== window.location.origin) return; + if (!frames.some((f) => f.current && f.current.contentWindow === e.source)) return; + const m = e.data as Msg; + if (!m || m.type !== "pf-console") return; + const sim = getSim(); + // The reader has the board: the scripted demos stand aside. + const hands = () => useGuideStore.getState().setHandsOn(true); + switch (m.action) { + case "ready": + stored.current = { modules: m.modules ?? null, inv: m.inv ?? null, sub: m.sub ?? null }; + apply(); + post(true); + break; + case "select": + if (typeof m.slug === "string") sim.selectPattern(m.slug); + hands(); + break; + case "knob": + if (typeof m.knob === "number" && typeof m.value === "number") sim.applyRemoteParam(m.knob, m.value); + hands(); + break; + case "brightness": + if (typeof m.level === "number") sim.setBrightnessLevel(m.level); + hands(); + break; + case "sleep": + sim.setSleeping(Boolean(m.on)); + hands(); + break; + case "modules": + stored.current.modules = m.modules ?? null; + apply(); + break; + case "knobSettings": + stored.current.inv = m.inv ?? null; + stored.current.sub = m.sub ?? null; + apply(); + break; + case "escape": + escape.current(); + break; + } + }; + window.addEventListener("message", onMessage); + const timer = window.setInterval(() => post(false), 200); + return () => { + window.removeEventListener("message", onMessage); + window.clearInterval(timer); + }; + }, [frames, post, apply]); +} + +/** Which demo page a frame is on, for its tab and address bar. */ +function useFramePage(frame: RefObject, initial: string) { + const [file, setFile] = useState(initial); + const [title, setTitle] = useState("Patternflow"); + const onLoad = useCallback(() => { + try { + const path = frame.current?.contentWindow?.location.pathname ?? ""; + if (path.startsWith(DEMO)) setFile(path.slice(DEMO.length) || "index.html"); + const t = frame.current?.contentDocument?.title; + if (t) setTitle(t); + } catch { + /* not ours to read */ + } + }, [frame]); + return { file, title, onLoad }; +} + +// ── browser chrome ────────────────────────────────────────────────────────── + +function OpenIcon() { + return ( + + ); +} + +function CloseButton({ label, onClick, btnRef }: { label: string; onClick: () => void; btnRef: RefObject }) { + return ( + + ); +} + +function Address({ host, file }: { host: string; file: string }) { + return ( + + + + {host} + {DEVICE_PATH[file] ?? ""} + + + ); +} + +function DesktopBar({ host, file, title, end }: { host: string; file: string; title: string; end: ReactNode }) { + return ( + + + + +