diff --git a/Assets/Branding/oem-watermark.svg b/Assets/Branding/oem-watermark.svg new file mode 100644 index 0000000..a7c2cbb --- /dev/null +++ b/Assets/Branding/oem-watermark.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + MODERN UEFI SETUP · OPEN SOURCE + + + github.com/MarsDoge/ModernSetupPkg + diff --git a/CHANGELOG.md b/CHANGELOG.md index 73e7077..7196d39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,80 @@ this file as both a release log and a lightweight development progress record. ### Added +- The in-setup DisplayEngine chrome is now localized. The header product/mode + names and the tab-hint labels are resolved through `ModernUiStringLib` + (`ModernUiGetString`) instead of being pinned to English, so when the active + language is Simplified Chinese (the `PcdModernSetupDefaultLanguage` default) + the setup header reads "现代UEFI设置工具 / 高级模式" with tabs + "设置分类 / 设备 / 启动 / 安全 / 退出", matching the front-page app. The labels + are a visual hint only -- form navigation, HII GUID binding, callbacks, and + storage are unchanged; the CJK glyphs come from the existing embedded + Noto Sans CJK SC subset. `ModernUiStringLib` is now usable from `DXE_DRIVER` + modules and is wired into the modern/lvgl DisplayEngine overlay (all targets). + Verified by an OVMF X64 lvgl screendump of a DriverSample form with the chrome + in Chinese, plus the modern (GOP) build and smoke. +- OEM branding watermark slot (display-only, original art). A new renderer entry + point `ModernUiDrawOemWatermark` composites an original, theme-tinted brand + mark into the in-setup content-area whitespace. The asset is 100% original + geometry + the project URL -- no IBV/commercial reuse: an SVG design source + (`Assets/Branding/oem-watermark.svg`) rasterized to an A8 coverage map + (`OemWatermarkData.c/.h`) by `Scripts/gen-oem-watermark.py`. The LVGL backend + alpha-blends the A8 map (tinted with the theme muted-text color, low opacity) + directly into the shadow canvas; the GOP backend is a no-op for now. Because + the native FormBrowser repaints the content area after the chrome, the + DisplayEngine draws the mark *after* the statement rows (new + `ModernDisplayDrawOemWatermarkOverlay`, invoked at the end of the `CfRepaint` + pass) and confines it to the statement column so the help/right-rail repaints + do not clip it. It is also confined vertically to the empty band below the last + menu row (`FirstEmptyRow`), so on a form whose rows fill the content area the + band is too short and the mark is suppressed -- it never tints over a statement + row. Display-only: parses no HII, owns no FormBrowser state. Verified by OVMF + X64 lvgl screendumps of a short sub-form (mark shown in whitespace) and a dense + form (mark suppressed), plus smoke. +- IFR-opcode -> LVGL-widget mapping for the value-bearing controls: one-of, + checkbox, numeric, string, and password now render as real LVGL widgets on the + LVGL backend, in both the front-page App and real in-setup VFR forms -- one-of + as `lv_dropdown` (rounded box + `LV_SYMBOL_DOWN`), checkbox as a checked + `lv_checkbox`, and numeric/string/password as a styled `lv_obj` field with an + `lv_label` (password masked). Each is built as a transient display-only widget, + rendered via `lv_snapshot_take` (newly enabled `LV_USE_SNAPSHOT`), and + alpha-composited (ARGB8888) over the row background in the shadow canvas by a + shared `LvglComposeSnapshot` helper. Per-control renderer entry points + (`ModernUiRenderOneOf`/`Checkbox`/`Numeric`/`String`/`Password`, plus the + arrow-less `ModernUiDrawFieldBox`) keep the abstraction at the renderer layer: + the GOP backend composes themed value/field boxes from primitives instead, so + there is no GOP regression. `ModernUiEngineDrawValue` dispatches per value type + (App path) and the in-setup DisplayEngine overlays the widget on the value lane + via `ModernDisplayDrawValueWidget` (opcode-dispatched, using the option string + FormBrowser just printed with its NARROW_CHAR/WIDE_CHAR glyph markers stripped); + the affordance cue is skipped for the mapped rows since each control carries its + own. Action/reference keep the `>` arrow. Display-only throughout: edk2 + FormBrowser still owns selection/editing, ConfigAccess, and callbacks. Verified + by OVMF X64 lvgl + GOP screendumps of the DriverSample form and the App + preferences page, plus smoke. +- Ordered-list and date/time opcodes complete the IFR-opcode -> LVGL-widget + mapping. Ordered-list renders as a real list-style field (`LV_SYMBOL_LIST` + prefix + the current option order) in both the App and in-setup DisplayEngine, + dropping its cue. Date/time renders as a segmented field (value laid out with + spaced `/ : -` delimiters so month/day/year or H:M:S read as discrete cells) on + the app-facing draw path; in the in-setup DisplayEngine date/time deliberately + keeps its native per-segment rendering and the type cue, because FormBrowser + highlights the active segment in place and a full-lane widget overlay would mask + that editing feedback. New renderer entry points `ModernUiRenderOrderedList` / + `ModernUiRenderDateTime` (GOP draws themed field boxes -- no regression). edk2 + still owns the reorder popup and segment editing. Verified by OVMF X64 lvgl + + GOP builds and smoke. +- DisplayEngine text-input edit caret is now drawn by the Modern renderer + (`ModernDisplayDrawTextCaret`) instead of the native `EFI_SIMPLE_TEXT_OUTPUT` + cursor. `ReadString` suppresses the native cursor (which draws straight to the + GraphicsConsole framebuffer and is invisible/misplaced behind an off-screen + canvas) and paints a thin accent caret at the edit cell each keystroke, so the + string/password editor's cursor renders identically on the GOP and LVGL + backends. This closes the last interaction surface that bypassed the renderer: + the LVGL backend now composites the full FormBrowser interaction set + (rows, one-of/dialog popups, and input editing) end-to-end. App-local, no HII + or value semantics touched. Verified by an OVMF X64 lvgl-mode screendump of the + DriverSample string editor showing the caret, plus GOP/lvgl builds and smoke. - DisplayEngine per-opcode control affordances: each editable FormBrowser statement now shows a distinct, non-semantic cue glyph keyed on its control kind — checkbox box, numeric `+`, one-of/choice `▼`, ordered-list up/down, @@ -316,6 +390,41 @@ this file as both a release log and a lightweight development progress record. ### Changed +- The in-setup "CONTEXT HELP" rail label now uses a soft muted-gold accent + (`AccentYellow` blended 50% toward `MutedText`) instead of plain muted body + text, so it reads as a styled section header -- consistent with, but + deliberately subdued below, the primary CPU/Memory/Voltage telemetry rail + headers. Verified by an OVMF X64 lvgl screendump and smoke. +- Refined the selected-row look into a clean, single-intent treatment: a subtle + warm-tinted fill (`Surface` blended ~30% toward `AccentYellow`) plus one solid + 6px left accent stripe, replacing the older muddy `SelectedBand` band drawn + with an inset blend, two sheens, a framed border, and an inner highlight line. + The selection color is sourced once in `ModernUiGetSelectableRowBackground`, so + the row fill and the per-cell text anti-alias background stay matched (no glyph + halos). Applies to both backends and to selectable rows in the app and the + in-setup browser. Verified by OVMF X64 lvgl screendumps, the modern build, and + smoke. +- The highlighted in-setup statement row now shows the modern row-level selection + styling (inset bar, top/bottom sheen, left accent, framed border) instead of a + flat muddy highlight band. `ModernDisplayDrawStatementRow` already painted that + styling underneath, but the native per-cell text print then buried it under a + solid `SelectedBand` fill. The per-cell print path now suppresses that flat + fill on the one row that just received selection styling (tracked by + `mModernStyledHighlightRow`), so the styling shows through. The guard is scoped + to that exact row, so other `EFI_RED`-background text -- notably a highlighted + popup option, which has no row-level styling -- still fills normally. Applies + to both the GOP "modern" and LVGL backends. Verified by OVMF X64 lvgl + screendumps of the selection at rest, after a highlight move (no stale band), + and an open one-of popup (highlighted option unchanged), plus smoke. + +- String/numeric/password value widgets now render as a real single-line + `lv_textarea` (LVGL built-in control) instead of a hand-composed + `lv_obj`+`lv_label`. The earlier row-height legibility concern (textarea caret / + scrolling obscuring short text) is handled by configuration: one-line mode, the + scrollbar off, the caret hidden (display-only snapshot), and native password + masking. Keeps the "prefer LVGL built-in widgets" direction alongside the + existing `lv_dropdown` (one-of) and `lv_checkbox` (checkbox). Display-only; edk2 + still owns editing. Verified by an OVMF X64 lvgl DriverSample screendump. - Modern UI engine: added a `ModernUiEngineDrawStatusPill` primitive (second entry in the base shape vocabulary) and refactored the footer status badge onto it. The badge is now sized to comfortably contain one text line (height = line + 6) @@ -453,6 +562,44 @@ this file as both a release log and a lightweight development progress record. ### Fixed +- Modern popups/dialogs no longer truncate their text or show a retro dashed + border. (1) The native DisplayEngine sizes popups in character columns, but the + modern proportional font advances wider than a text-grid cell, so confirm/error + dialogs were clipped with "..." ("Load default configurat..."). `PrintInternal` + now grows the text budget to the measured proportional width when the caller + imposes no column constraint (`Width == 0`), so unconstrained prints render in + full. (2) `ModernDisplayCopyPrintable` drops the Unicode box-drawing block + (U+2500..U+257F): the native engine frames popups/multi-string boxes with those + glyphs, but the modern panel/surface already supplies the frame, so they only + added a dashed-border seam over it. Both fixes are renderer-layer only; edk2 + still owns the dialog control flow, keys, and message strings. Verified by OVMF + X64 lvgl screendump of the F9 "Load defaults" confirm dialog, plus smoke. +- Fixed in-setup widget vs native-editing conflicts. (1) The value-lane widget is + now cleared to the field background (`Theme->Surface`) right before native + FormBrowser editing starts (`ModernDisplayClearValueLane`, called from the edit + entry in `DisplayOneMenu`'s key handler), so the in-place numeric editor and the + string/password input popup start on a clean lane instead of colliding with the + composited widget (which left it half-covered / the old value peeking out beside + the popup). The full form repaint after editing restores the widget with the new + value. (2) The `lv_checkbox` widget now renders the box indicator with an empty + label, so it no longer leaks a stray `]` from the raw `[X]` value text (the row's + left prompt already names the control). +- Ordered-list widgets now show their option order joined by a ` / ` separator + (` / / `) instead of the raw `?` glyphs. FormBrowser joins ordered-list + options with `CHAR_CARRIAGE_RETURN`, which passed the `>= 0xFFF0` marker filter but + was rendered as `?` by the ASCII label path. A shared + `ModernUiNormalizeOrderedListText` helper (strip markers, collapse CR/LF runs to a + single ` / `, trim) now feeds both backends' ordered-list renderer. Display-only; + no change to the multi-row native fallback. +- Fixed a spurious highlight-colored block filling the empty area below a menu + when the highlighted statement is the last visible row (e.g. `Reset` on the + front page). The DisplayEngine "clean the remain field" loop cleared the rows + below the menu with whatever display attribute the last-drawn option left set; + when that option was the highlighted one, the modern renderer painted those + empty rows with the highlight band (`SelectedBand`). The loop now resets to the + normal field background (`GetFieldTextColor`, → `Theme->Surface`) first, mirroring + the reset already done before the scroll down-arrow. Backend-agnostic (GOP and + LVGL); verified by an OVMF X64 front-page screendump with `Reset` highlighted. - ModernSetupApp Dashboard no longer echoes the generic platform name as the form factor: when SMBIOS Type 3 is unavailable the platform provider now reports an empty form factor and the app surfaces its localized Unknown/N/A diff --git a/Docs/MODULE_BOUNDARIES.md b/Docs/MODULE_BOUNDARIES.md index c01120f..a8d4521 100644 --- a/Docs/MODULE_BOUNDARIES.md +++ b/Docs/MODULE_BOUNDARIES.md @@ -77,6 +77,14 @@ identically in each: Do not add a second copy of these shapes in either consumer — extend the shared vocabulary and add the value-type mapping instead. +The text-input **edit caret** is likewise renderer-drawn: `ReadString` suppresses +the native `EFI_SIMPLE_TEXT_OUTPUT` cursor and calls `ModernDisplayDrawTextCaret`, +so no backend paints a cursor straight to the framebuffer. This keeps the full +FormBrowser interaction set (rows, popups, input editing) on the renderer, which +is what lets the off-screen LVGL backend composite it end-to-end. Any new +interactive surface must route its cursor/caret through the renderer the same +way rather than calling `gST->ConOut->EnableCursor`. + ## What not to do - App code must not parse IFR or write HII varstores. Real setup pages should enter native FormBrowser with `EFI_FORM_BROWSER2_PROTOCOL.SendForm()`. diff --git a/Docs/PRODUCTIZATION_STATUS.md b/Docs/PRODUCTIZATION_STATUS.md new file mode 100644 index 0000000..f125acb --- /dev/null +++ b/Docs/PRODUCTIZATION_STATUS.md @@ -0,0 +1,140 @@ + + +# Productization Status & Roadmap + +A living, checklist-style read on how far ModernSetupPkg is from being shippable +on real platforms, and the ordered work remaining. It complements — and does not +duplicate — the capability inventories: + +- `Docs/ProductizationFeatureMatrix.md` — where a given feature belongs. +- `Docs/ProductizationValidationMatrix.md` — what validation each target owes. +- `Docs/MODULE_BOUNDARIES.md` — the layer contract this work must not break. +- `Docs/BASELINE.md` — pinned edk2 baseline + the validation ladder. + +This file answers a different question: *"what is done, what is left, how big, in +what order."* Percentages are an engineering judgment, not a measured metric. + +Last updated: 2026-06-06. + +## What "productized" means here + +ModernSetupPkg is a **display-backend replacement** (plus an optional front-page +shell). edk2 keeps HII/IFR/FormBrowser/ConfigAccess ownership. "Productized" +therefore means, for each deliverable: + +1. **Complete** — every interaction path the native DisplayEngine handles is + rendered (no fall-through to retro text-grid output). +2. **Correct** — no truncation/clipping/seams; behavior matches native semantics. +3. **Localized** — CJK and other non-Latin strings render (the package is XArch + and carries Chinese strings). +4. **Bounded** — fits a real platform's DXE memory/perf budget. +5. **Validated on hardware** — not only QEMU virtual targets. +6. **Regression-guarded** — covered beyond the current smoke gate. + +## Snapshot + +| Track | Estimate | One line | +| --- | --- | --- | +| Engine — GOP "modern" line | ~72% | Default backend; renders all forms; close to "usable product", not yet "modern-looking". | +| Engine — LVGL "beautiful" line | ~57% | Widgets + dialogs modernized; still gated `experimental/lvgl-spike`. **Priority line.** | +| Front-page app — ModernSetupApp | ~57% | Clean architecture/boundaries; owes real provider data + hardware validation. | + +The two engine "lines" are the **same** `ModernDisplayEngineDxe` with a swapped +renderer **library** (`ModernUiRendererLib` GOP vs `ModernUiLvglRendererLib`), +selected by `MODERN_SETUP_DISPLAY_ENGINE=modern|lvgl`. There is no separate LVGL +DXE on the product path (`Experimental/.../LvglDisplayEngineDxe` is an orphaned +early probe — see "Cleanup backlog"). + +## Track A — Engine, GOP "modern" line (~72%) + +Effort key: **S** ≈ <1 day, **M** ≈ days, **L** ≈ week+ / external dependency. + +| ✓ | Item | Effort | Note | +| --- | --- | --- | --- | +| [x] | Full edk2 DisplayEngine fork (FormDisplay/Input/Popup/ProcessOptions) | — | Inherits all FormBrowser display semantics. | +| [x] | Modern chrome (header, tabs, right rail, themed surfaces) | — | | +| [x] | Themed value rendering for all value opcodes (GOP primitives) | — | | +| [x] | Popups: modern panel surface, no truncation, no box-draw seam | — | Shared with LVGL line. | +| [ ] | Aesthetic polish pass (row rhythm, selection bar, value alignment) | M | Shared with LVGL line. | +| [ ] | CJK / multilingual verification (uses HII font here) | M | Less acute than LVGL line. | +| [ ] | Multi-resolution + GOP-absent robustness | M | | +| [ ] | Hardware validation | L | Depends on real hardware. | + +## Track B — Engine, LVGL "beautiful" line (~57%) — PRIORITY + +This is the north-star look (mature graphics library). Critical path is ordered. + +| ✓ | Item | Effort | Note | +| --- | --- | --- | --- | +| [x] | LVGL UEFI bridge + shadow-canvas BLT pipeline | — | | +| [x] | Real widgets: dropdown / checkbox / textarea / ordered-list / date-time | — | `lv_dropdown`/`lv_checkbox`/`lv_textarea`. | +| [x] | In-setup edit vs widget conflict fixes | — | | +| [x] | OEM watermark slot (original art, A8 composite) | — | | +| [x] | Confirm/error dialogs: clean modern panel (no truncation / box-draw) | — | 2026-06-06. | +| [ ] | **Backend graduation decision** — promote `ModernUiLvglRendererLib` out of `experimental/lvgl-spike` so it can enter a default overlay | S (decision) | **Gates everything below.** | +| [ ] | Selectable-option popup + password + multi-string help verified/cleaned | S–M | Same machinery as the confirm dialog; verify each. | +| [ ] | Dialog visual elevation (accent title, Y/N affordances) — optional | S–M | Gilding; current dialogs already clean. | +| [~] | **CJK / multilingual font** — demand-driven Noto Sans CJK SC subset (182 glyphs, 18px A8) + HII fallback; app fully renders zh-Hans. Chrome localized 2026-06-06. Remaining: arbitrary-platform coverage strategy + single-size. | M–L | Foundation strong; gate is arbitrary HII coverage. | +| [ ] | **Memory / perf budget** — DXEFV near-full with DEBUG; per-refresh snapshot allocations | M | Measure, then trim. | +| [ ] | Aesthetic polish pass | M | Shared with Track A. | +| [ ] | **Hardware + multi-resolution validation** | L | Currently 0 hardware coverage. | +| [x] | Watermark confined to genuine whitespace (suppressed on dense forms) | — | 2026-06-06. | + +## Track C — Front-page app, ModernSetupApp (~57%) + +Architecturally complete and boundary-guarded; the gap is "filling in", not design. + +| ✓ | Item | Effort | Note | +| --- | --- | --- | --- | +| [x] | Front-page dashboard, tabs, footer/status chrome | — | | +| [x] | `SendForm()` handoff to native FormBrowser; boot launch; language select | — | | +| [x] | 11× typed read-only provider DataLibs + app-private snapshot | — | Boundaries smoke-enforced. | +| [ ] | **Real provider data** — Platform/Security/Firmware/Power etc. expose N/A / placeholders | M–L | Wire real SMBIOS/ACPI/sensor sources. | +| [ ] | Boot-manager completeness (boot-option types, Secure Boot state, one-time boot) | M | | +| [ ] | Localization of app strings | M | | +| [ ] | Default-on decision (currently opt-in `MODERN_SETUP_REPLACE_UIAPP`) | S (decision) | | +| [ ] | Hardware validation | L | | + +## Cross-cutting (blocks "product" for both engine and app) + +| ✓ | Item | Effort | Note | +| --- | --- | --- | --- | +| [ ] | **Real-hardware validation** across the XArch targets | L | Today everything is QEMU virtual. | +| [ ] | **CJK / i18n font story** | M–L | | +| [ ] | Regression suite beyond smoke (per-driver HII render checks) | M | Smoke is the only gate today. | + +## Known issues / regressions + +- ~~**Watermark on dense forms**~~ — fixed 2026-06-06: the overlay now receives + the first empty row and confines the mark to the whitespace band below the last + menu row, so it is suppressed when the rows fill the content area. +- See `Docs/ISSUE_BACKLOG.md` for the broader list. + +## Cleanup backlog (no rush) + +- `Experimental/LvglSpikePkg/LvglDisplayEngineDxe` — an early ~10 KB probe that + renders prompt labels and waits for ESC (no editing/popups/widgets). The + product LVGL path is `ModernDisplayEngineDxe` + `ModernUiLvglRendererLib`; the + probe is wired into no product overlay (only the standalone + `LvglSpikeLoongArch.dsc`). Can be retired with its references + (`LvglSpikeLoongArch.dsc`, `Tests/Smoke/smoke_validate.py` token, README / + REFERENCES / CHANGELOG mentions) when convenient. + +## Recommended near-term sequence + +Small, stable steps first; the two "decisions" unblock the most: + +1. Fix the watermark-on-dense-form regression (**S**, clears a self-inflicted regression). +2. Verify + clean the remaining popups — selectable-option, password, multi-string help (**S–M**). +3. Make the **LVGL backend graduation decision** (**S**); it gates real productization of the look. +4. Stand up the **CJK font** story (**M–L**) — the first true product gate. +5. **Memory/perf budget** measurement + trim (**M**). +6. First **hardware** bring-up on one target (**L**). + +The first three are days of work and visibly move the LVGL line; items 4–6 are the +real thresholds between "great-looking sample" and "shippable product". diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/LvglCoreLib.inf b/Experimental/LvglSpikePkg/Library/LvglLib/LvglCoreLib.inf index c651b67..ab1716f 100644 --- a/Experimental/LvglSpikePkg/Library/LvglLib/LvglCoreLib.inf +++ b/Experimental/LvglSpikePkg/Library/LvglLib/LvglCoreLib.inf @@ -73,6 +73,7 @@ lvgl/src/draw/lv_draw_triangle.c lvgl/src/draw/lv_draw_vector.c lvgl/src/draw/lv_image_decoder.c + lvgl/src/draw/snapshot/lv_snapshot.c lvgl/src/draw/nanovg/lv_draw_nanovg_3d.c lvgl/src/draw/nanovg/lv_draw_nanovg_arc.c lvgl/src/draw/nanovg/lv_draw_nanovg_border.c diff --git a/Experimental/LvglSpikePkg/Library/LvglLib/lv_conf.h b/Experimental/LvglSpikePkg/Library/LvglLib/lv_conf.h index 0343725..1f2b192 100644 --- a/Experimental/LvglSpikePkg/Library/LvglLib/lv_conf.h +++ b/Experimental/LvglSpikePkg/Library/LvglLib/lv_conf.h @@ -1093,7 +1093,7 @@ /* Documentation for several of the below items can be found here: https://docs.lvgl.io/master/auxiliary-modules/index.html . */ /** 1: Enable API to take snapshot for object */ -#define LV_USE_SNAPSHOT 0 +#define LV_USE_SNAPSHOT 1 /** 1: Enable system monitor component */ #define LV_USE_SYSMON 0 diff --git a/Include/ModernUi/ModernUiRenderer.h b/Include/ModernUi/ModernUiRenderer.h index 52bd828..4e278ad 100644 --- a/Include/ModernUi/ModernUiRenderer.h +++ b/Include/ModernUi/ModernUiRenderer.h @@ -418,6 +418,176 @@ ModernUiDrawValueBox ( IN CONST MODERN_UI_THEME *Theme ); +/** + Render a one-of (choice) control as the backend's best available drop-down. + + Display-only: this paints the closed drop-down showing the currently selected + option text; it never opens a list or owns selection/input. edk2 FormBrowser + still owns the actual choice (its own selection popup, ConfigAccess, callbacks). + Backends diverge by capability: + + - GOP backend composes the drop-down from primitives (value box + an in-box + chevron), matching the rest of the GOP chrome. + - LVGL backend renders a real `lv_dropdown` widget (its own box, border, and + `LV_SYMBOL_DOWN` arrow) snapshotted into the shadow canvas, so a one-of reads + as a genuine toolkit control rather than a hand-composed box. + + The caller must not also draw the separate one-of affordance cue for this value; + the rendered control carries its own arrow. + + @param[in] Context Initialized render context. Must not be NULL. + @param[in] Rect Control rectangle (the value lane). + @param[in] Value Selected option text. Must not be NULL. + @param[in] Selected TRUE when the owning row is selected/focused. + @param[in] Theme Theme token table. Must not be NULL. + + @retval EFI_SUCCESS Control was drawn (or clipped outside view). + @retval EFI_INVALID_PARAMETER Context, Value, or Theme is NULL, or Rect empty. + @retval EFI_OUT_OF_RESOURCES Temporary widget/snapshot allocation failed. + @retval others Status returned by the underlying renderer. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderOneOf ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ); + +/** + Render a checkbox/boolean control as the backend's best widget (display-only). + + LVGL renders a real `lv_checkbox` (checked state inferred from the "[X]"/"[ ]" + value text); GOP draws a bordered field with the value text. edk2 owns the + toggle. Same NULL/Rect contract as ModernUiRenderOneOf. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderCheckbox ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ); + +/** + Render a string control as the backend's best widget (display-only). + + LVGL renders a real one-line `lv_textarea` showing the current text; GOP draws + a bordered field. edk2 owns editing. Same NULL/Rect contract as + ModernUiRenderOneOf. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderString ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ); + +/** + Render a password control as the backend's best widget (display-only). + + LVGL renders an `lv_textarea` in password mode (dots); GOP draws a bordered + field with the value text (already masked by FormBrowser). edk2 owns editing. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderPassword ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ); + +/** + Render a numeric control as the backend's best widget (display-only). + + LVGL renders a real `lv_spinbox`-styled field showing the current number; GOP + draws a bordered field with the value text. edk2 owns the adjustment. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderNumeric ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ); + +/** + Render an ordered-list control as the backend's best widget (display-only). + + LVGL renders a real list-style field (an `LV_SYMBOL_LIST`-prefixed `lv_obj` + field) showing the current option order; GOP draws a bordered field. edk2 owns + the reorder popup. Same NULL/Rect contract as ModernUiRenderOneOf. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderOrderedList ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ); + +/** + Render a date/time control as the backend's best widget (display-only). + + LVGL renders a segmented field (the value laid out with spaced `/ : -` + delimiters so the month/day/year or hour/minute/second segments read as + discrete cells); GOP draws a bordered field. edk2 owns segment editing. + + Note: in the in-setup DisplayEngine, date/time keeps its native per-segment + rendering and the type cue, because FormBrowser highlights the active segment + in place and a full-lane widget overlay would mask that feedback. This entry + point completes the engine value vocabulary for the app-facing draw path. + Same NULL/Rect contract as ModernUiRenderOneOf. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderDateTime ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ); + +/** + Draw a bordered value field (no drop-down arrow) with inset text. + + The arrow-less companion to ModernUiDrawValueBox, used by the GOP backend to + present non-drop-down controls (checkbox/string/password/numeric) as boxed + fields consistent with the drop-down value box. + + @param[in] Context Initialized render context. Must not be NULL. + @param[in] Rect Field rectangle. + @param[in] Value Field text. Must not be NULL. + @param[in] Selected TRUE when the owning row is selected. + @param[in] Theme Theme token table. Must not be NULL. + + @retval EFI_SUCCESS Field was drawn. + @retval EFI_INVALID_PARAMETER Context, Value, or Theme is NULL, or Rect empty. +**/ +EFI_STATUS +EFIAPI +ModernUiDrawFieldBox ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ); + /** Draw a drop-down list frame. @@ -460,4 +630,40 @@ ModernUiDrawProgress ( IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Fill ); +/** + Composite the OEM branding watermark into a region's whitespace (display-only). + + This is the renderer half of the OEM branding slot: an original, theme-tinted + watermark drawn low-opacity and centered toward the bottom of Region, so it + fills the empty content area without fighting the setup text. The asset ships + no IBV/commercial art -- it is an A8 coverage map generated from + Assets/Branding/oem-watermark.svg by Scripts/gen-oem-watermark.py. + + - LVGL backend alpha-blends the A8 coverage map (tinted with the theme's muted + text color) directly into the shadow canvas and BLTs the affected region. + - GOP backend is currently a no-op (returns EFI_SUCCESS); a primitive composite + is a follow-up. + + Because the native FormBrowser repaints the content area after the chrome, the + DisplayEngine caller invokes this *after* the content rows are painted and + confines Region to the statement column (the help/right-rail columns are + repainted by later form states and would clip the mark). + + @param[in] Context Initialized render context. Must not be NULL. + @param[in] Region Pixel region to anchor the watermark within (e.g. the + statement content panel). A region too small for the mark + is skipped. + @param[in] Theme Theme token table (supplies the tint). Must not be NULL. + + @retval EFI_SUCCESS Watermark composited, or skipped as a no-op. + @retval EFI_INVALID_PARAMETER Context or Theme is NULL. +**/ +EFI_STATUS +EFIAPI +ModernUiDrawOemWatermark ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Region, + IN CONST MODERN_UI_THEME *Theme + ); + #endif diff --git a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c index 3123826..5a1c320 100644 --- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c +++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c @@ -23,6 +23,14 @@ STATIC MODERN_UI_RENDER_CONTEXT mModernRenderContext; STATIC BOOLEAN mModernRenderReady; STATIC UINTN mModernCursorColumn; STATIC UINTN mModernCursorRow; +// +// Text-grid row that most recently received row-level selection styling from +// ModernDisplayDrawStatementRow. The per-cell print path suppresses its flat +// highlight fill only on this row, so the styled selection bar shows through +// without affecting other EFI_RED-background text (e.g. highlighted popup +// options, which have no row-level styling underneath). (UINTN)-1 means none. +// +STATIC UINTN mModernStyledHighlightRow = (UINTN)-1; #define MODERN_DISPLAY_HELP_LEFT_SKIPPED_COLUMNS 3 @@ -471,13 +479,19 @@ ModernDisplayDrawRightHelpRailContext ( LabelY = (Layout->ContentTopRow * CellHeight) + MIN (6, MAX (2, CellHeight / 5)); LabelWidth = (Layout->Statement.RightColumn - HelpLeftColumn) * CellWidth; + // + // Give the "CONTEXT HELP" label a soft accent (a muted gold, between the plain + // muted body text and the full accent used by the primary CPU/Memory/Voltage + // rail headers), so it reads as a styled section header while staying below the + // telemetry rail in the visual hierarchy. + // ModernUiDrawTextFit ( &mModernRenderContext, LabelX, LabelY, LabelWidth, L"CONTEXT HELP", - Theme->MutedText, + ModernUiBlendColor (Theme->AccentYellow, Theme->MutedText, 50), Theme->BackgroundBlack ); @@ -726,6 +740,16 @@ ModernDisplayCopyPrintable ( continue; } + // + // Drop Unicode box-drawing glyphs (U+2500..U+257F). The native DisplayEngine + // frames popups and multi-string boxes with these characters; under the + // modern renderer the surrounding panel/surface already supplies the frame, + // so rendering the glyphs only adds a retro dashed-border seam on top. + // + if ((Input[Index] >= 0x2500) && (Input[Index] <= 0x257F)) { + continue; + } + Output[OutIndex++] = Input[Index]; } @@ -1047,6 +1071,37 @@ ModernDisplayDrawStatementRow ( ModernUiEngineDrawRows (&mModernRenderContext, &RowModel, 1, Theme); ModernDisplayDrawStatementRowAccents (&RowRect, &FormRow, Theme); + + // + // Record the row that just received selected styling so the per-cell print + // path knows to let it show through (and clear the record when this row is no + // longer the selected one). + // + if (RowModel.Role == ModernUiRowSelected) { + mModernStyledHighlightRow = Row; + } else if (mModernStyledHighlightRow == Row) { + mModernStyledHighlightRow = (UINTN)-1; + } +} + +/** + Forget any tracked selection-styled row. + + The per-cell print path suppresses the highlight fill on the row recorded by + ModernDisplayDrawStatementRow. That record is only valid while a form's + statement rows are being drawn; a popup drawn on top prints its own + EFI_RED-background text (e.g. a highlighted selectable option) without going + through ModernDisplayDrawStatementRow, and could share that grid row. Callers + invoke this at popup entry so a popup line is never mistaken for the styled + statement row and left without its background fill. +**/ +VOID +EFIAPI +ModernDisplayResetHighlightRowTracking ( + VOID + ) +{ + mModernStyledHighlightRow = (UINTN)-1; } /** @@ -1108,6 +1163,22 @@ ModernDisplayDrawStatementRowCue ( return; } + // + // Widget-mapped rows (one-of/checkbox/numeric/string/password/ordered-list) + // render as real controls via ModernDisplayDrawValueWidget, which carry their + // own affordance, so skip the separate cue for them. Date/time (native + // per-segment rendering) and action keep the cue. + // + if ((FormRow.Kind == ModernDisplayFormRowChoice) || + (FormRow.Kind == ModernDisplayFormRowCheckbox) || + (FormRow.Kind == ModernDisplayFormRowNumeric) || + (FormRow.Kind == ModernDisplayFormRowString) || + (FormRow.Kind == ModernDisplayFormRowPassword) || + (FormRow.Kind == ModernDisplayFormRowOrderedList)) + { + return; + } + Theme = ModernUiGetTheme (); ModernDisplayGetCellMetrics (&CellWidth, &CellHeight); @@ -1136,6 +1207,193 @@ ModernDisplayDrawStatementRowCue ( ); } +/** + Draw the text-input edit caret at a text-grid cell through the Modern renderer. + + Paints a thin vertical accent bar at the left edge of cell (Column, Row), using + the same cell metrics as the themed text printer so it lands exactly on the + character the caller is about to write. `ReadString` suppresses the native + EFI_SIMPLE_TEXT_OUTPUT cursor (which would draw straight to the GraphicsConsole + framebuffer and be invisible behind an off-screen canvas such as the LVGL + backend) and calls this each keystroke after redrawing the field, so the caret + renders identically on every backend. No-op (no error) when no renderer is + available or the cell geometry is degenerate. + + @param[in] Column Text-grid column of the caret cell. + @param[in] Row Text-grid row of the caret cell. +**/ +VOID +EFIAPI +ModernDisplayDrawTextCaret ( + IN UINTN Column, + IN UINTN Row + ) +{ + CONST MODERN_UI_THEME *Theme; + UINTN CellWidth; + UINTN CellHeight; + UINTN CaretWidth; + UINTN Inset; + + if (EFI_ERROR (ModernDisplayEnsureRenderer ())) { + return; + } + + ModernDisplayGetCellMetrics (&CellWidth, &CellHeight); + if ((CellWidth == 0) || (CellHeight < 6)) { + return; + } + + Theme = ModernUiGetTheme (); + CaretWidth = MAX (2, CellWidth / 8); + Inset = (CellHeight > 8) ? 2 : 1; + + ModernUiFillRect ( + &mModernRenderContext, + (MODERN_UI_RECT){ Column * CellWidth, Row * CellHeight + Inset, CaretWidth, CellHeight - (2 * Inset) }, + Theme->AccentYellow + ); +} + +/** + Overlay a one-of row's value lane with the backend's best drop-down. + + Converts the text-grid value lane to pixels using the same cell metrics as the + themed printer, then delegates to the shared ModernUiRenderOneOf, which renders + a real lv_dropdown on the LVGL backend and a composed value box on GOP. See the + contract on ModernDisplayDrawOneOfWidget in FormDisplay.h. No-op (no error) when + no renderer is available, the value text is NULL, or the lane is degenerate. + + @param[in] Column Text-grid column where the value lane starts. + @param[in] Row Text-grid row of the statement. + @param[in] Width Text-grid column count of the value lane. + @param[in] ValueText Selected option text. May be NULL. + @param[in] Highlight TRUE when the row currently has keyboard highlight. + @param[in] Selected TRUE when the row is in edit/selection mode. +**/ +VOID +EFIAPI +ModernDisplayDrawValueWidget ( + IN UINT8 OpCode, + IN UINTN Column, + IN UINTN Row, + IN UINTN Width, + IN CONST CHAR16 *ValueText OPTIONAL, + IN BOOLEAN Highlight, + IN BOOLEAN Selected + ) +{ + CONST MODERN_UI_THEME *Theme; + UINTN CellWidth; + UINTN CellHeight; + MODERN_UI_RECT Rect; + CHAR16 Clean[128]; + UINTN Src; + UINTN Dst; + BOOLEAN Sel; + + if ((ValueText == NULL) || (Width == 0) || EFI_ERROR (ModernDisplayEnsureRenderer ())) { + return; + } + + // + // Only the widget-mapped opcodes are overlaid; everything else keeps its + // native text plus the cue overlay. + // + if ((OpCode != EFI_IFR_ONE_OF_OP) && (OpCode != EFI_IFR_CHECKBOX_OP) && + (OpCode != EFI_IFR_NUMERIC_OP) && (OpCode != EFI_IFR_STRING_OP) && + (OpCode != EFI_IFR_PASSWORD_OP) && (OpCode != EFI_IFR_ORDERED_LIST_OP)) + { + return; + } + + ModernDisplayGetCellMetrics (&CellWidth, &CellHeight); + if ((CellWidth == 0) || (CellHeight < 10)) { + return; + } + + // + // FormBrowser embeds glyph-width markers (NARROW_CHAR/WIDE_CHAR, >= 0xFFF0) in + // option strings; they are layout hints, not printable text. Strip them so the + // widget shows clean text on both backends. + // + for (Src = 0, Dst = 0; (ValueText[Src] != CHAR_NULL) && (Dst < (ARRAY_SIZE (Clean) - 1)); Src++) { + if (ValueText[Src] < 0xFFF0) { + Clean[Dst++] = ValueText[Src]; + } + } + + Clean[Dst] = CHAR_NULL; + + Theme = ModernUiGetTheme (); + Rect.X = Column * CellWidth; + Rect.Y = Row * CellHeight; + Rect.Width = Width * CellWidth; + Rect.Height = CellHeight; + Sel = (BOOLEAN)(Highlight || Selected); + + switch (OpCode) { + case EFI_IFR_ONE_OF_OP: + ModernUiRenderOneOf (&mModernRenderContext, Rect, Clean, Sel, Theme); + break; + case EFI_IFR_CHECKBOX_OP: + ModernUiRenderCheckbox (&mModernRenderContext, Rect, Clean, Sel, Theme); + break; + case EFI_IFR_NUMERIC_OP: + ModernUiRenderNumeric (&mModernRenderContext, Rect, Clean, Sel, Theme); + break; + case EFI_IFR_STRING_OP: + ModernUiRenderString (&mModernRenderContext, Rect, Clean, Sel, Theme); + break; + case EFI_IFR_PASSWORD_OP: + ModernUiRenderPassword (&mModernRenderContext, Rect, Clean, Sel, Theme); + break; + case EFI_IFR_ORDERED_LIST_OP: + ModernUiRenderOrderedList (&mModernRenderContext, Rect, Clean, Sel, Theme); + break; + default: + break; + } +} + +/** + Clear a statement's value lane to the field background before native editing. + + See the contract on ModernDisplayClearValueLane in FormDisplay.h. + + @param[in] Column Text-grid column where the value lane starts. + @param[in] Row Text-grid row of the statement. + @param[in] Width Text-grid column count of the value lane. +**/ +VOID +EFIAPI +ModernDisplayClearValueLane ( + IN UINTN Column, + IN UINTN Row, + IN UINTN Width + ) +{ + CONST MODERN_UI_THEME *Theme; + UINTN CellWidth; + UINTN CellHeight; + + if ((Width == 0) || EFI_ERROR (ModernDisplayEnsureRenderer ())) { + return; + } + + ModernDisplayGetCellMetrics (&CellWidth, &CellHeight); + if ((CellWidth == 0) || (CellHeight == 0)) { + return; + } + + Theme = ModernUiGetTheme (); + ModernUiFillRect ( + &mModernRenderContext, + (MODERN_UI_RECT){ Column * CellWidth, Row * CellHeight, Width * CellWidth, CellHeight }, + Theme->Surface + ); +} + /** Draw the modern DisplayEngine shell behind the native FormBrowser content. @@ -1158,13 +1416,7 @@ ModernDisplayDrawPageChrome ( MODERN_DISPLAY_LAYOUT Layout; MODERN_UI_LAYOUT EngineLayout; MODERN_UI_PAGE_MODEL PageModel; - STATIC CONST MODERN_UI_TAB_MODEL Tabs[] = { - { L"Main" }, - { L"Devices" }, - { L"Boot" }, - { L"Security" }, - { L"Save & Exit" } - }; + MODERN_UI_TAB_MODEL Tabs[5]; UINTN HeaderHeight; ASSERT (FormData != NULL); @@ -1215,13 +1467,25 @@ ModernDisplayDrawPageChrome ( ZeroMem (&EngineLayout.RightRail, sizeof (EngineLayout.RightRail)); } + // + // Localize the chrome through ModernUiStringLib so the in-setup header and + // tab hints follow the active language (matching the front-page app), instead + // of being pinned to English. The label set is a visual hint only; it does not + // alter form navigation, HII GUID binding, callbacks, or storage. + // + Tabs[0].Text = ModernUiGetString (ModernUiStringPageDashboard); + Tabs[1].Text = ModernUiGetString (ModernUiStringPageDevices); + Tabs[2].Text = ModernUiGetString (ModernUiStringPageBoot); + Tabs[3].Text = ModernUiGetString (ModernUiStringPageSecurity); + Tabs[4].Text = ModernUiGetString (ModernUiStringPageExit); + CopyMem (&PageModel.Layout, &EngineLayout, sizeof (PageModel.Layout)); PageModel.Rect = EngineLayout.Header; PageModel.Tabs = Tabs; PageModel.TabCount = ARRAY_SIZE (Tabs); PageModel.SelectedTab = ModernDisplaySelectChromeTab (PrintableTitle); - PageModel.ProductName = L"MODERN SETUP"; - PageModel.ModeName = L"ADVANCED MODE"; + PageModel.ProductName = ModernUiGetString (ModernUiStringHeaderTitle); + PageModel.ModeName = ModernUiGetString (ModernUiStringHeaderMode); PageModel.StatusText = ModernDisplayPageStatusText (FormData); PageModel.DrawRightRail = TRUE; ModernUiEngineDrawPage (&mModernRenderContext, &PageModel, Theme); @@ -1238,6 +1502,81 @@ ModernDisplayDrawPageChrome ( } } +/** + Composite the OEM brand watermark into the content-area whitespace. + + Unlike the chrome (which the native FormBrowser repaints over via the + statement rows and the empty-row clear loop), this overlay is meant to be + invoked *after* the form content has been painted, so the mark lands on top of + the freshly cleared whitespace rather than being wiped. The region handed to + the renderer is the empty band from FirstEmptyRow down to the content bottom, + so on a form whose rows fill the content area the band is too short and the + renderer no-ops -- the mark never tints over a statement row. + + Display-only; parses no HII and owns no FormBrowser state. Safe to call on + every form refresh. + + @param[in] FirstEmptyRow Text-grid row where the empty area below the menu + begins. +**/ +VOID +EFIAPI +ModernDisplayDrawOemWatermarkOverlay ( + IN UINTN FirstEmptyRow + ) +{ + CONST MODERN_UI_THEME *Theme; + UINTN CellWidth; + UINTN CellHeight; + UINTN HelpStartColumn; + UINTN WhitespaceTopRow; + MODERN_DISPLAY_LAYOUT Layout; + MODERN_UI_RECT Content; + + if (EFI_ERROR (ModernDisplayEnsureRenderer ())) { + return; + } + + Theme = ModernUiGetTheme (); + ModernDisplayGetCellMetrics (&CellWidth, &CellHeight); + if (EFI_ERROR (ModernDisplayCalculateLayout (&Layout))) { + return; + } + + // + // Confine the mark to the statement value area (left of the native help + // block). The help/right-rail columns are repainted by later control-flow + // states in the same form pass, which would clip any mark that strayed into + // them. + // + HelpStartColumn = ModernDisplayRightHelpStartColumn (&Layout); + if (HelpStartColumn <= Layout.ContentLeftColumn) { + return; + } + + // + // Vertically confine the mark to the empty band below the last menu row. + // Clamp FirstEmptyRow into the content area; if the rows reach (or pass) the + // content bottom there is no whitespace and the band height collapses, so the + // renderer's minimum-size guard skips the mark instead of tinting a row. + // + WhitespaceTopRow = FirstEmptyRow; + if (WhitespaceTopRow < Layout.ContentTopRow) { + WhitespaceTopRow = Layout.ContentTopRow; + } + + if (WhitespaceTopRow >= Layout.ContentBottomRow) { + return; + } + + Content.X = Layout.ContentLeftColumn * CellWidth; + Content.Y = WhitespaceTopRow * CellHeight; + Content.Width = (HelpStartColumn - Layout.ContentLeftColumn) * CellWidth; + Content.Height = (Layout.ContentBottomRow - WhitespaceTopRow) * CellHeight; + + ModernUiDrawOemWatermark (&mModernRenderContext, Content, Theme); +} + // // Browser Global Strings // @@ -2062,6 +2401,7 @@ PrintInternal ( UINTN TextY; UINTN TextMaxWidth; UINTN TextInset; + UINTN MeasuredWidth; CHAR16 *Printable; EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground; EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background; @@ -2126,11 +2466,22 @@ PrintInternal ( Foreground = ModernDisplayForeground (Attribute); Background = ModernDisplayBackground (Attribute); - ModernUiFillRect ( - &mModernRenderContext, - (MODERN_UI_RECT){ DrawColumn * CellWidth, DrawRow * CellHeight, DrawWidth * CellWidth, CellHeight }, - Background - ); + // + // For the highlighted statement row (EFI_RED background nibble on the row + // that ModernDisplayDrawStatementRow just styled) skip the flat per-cell + // fill: the row-level selection styling (inset bar, top/bottom sheen, left + // accent) is already painted underneath, and a flat fill would bury it under + // a solid band. The guard is scoped to that exact row so other EFI_RED text + // (e.g. a highlighted popup option, which has no row styling) still fills + // normally. The text below keeps Background for anti-alias blending. + // + if ((((Attribute >> 4) & 0x07) != EFI_RED) || (DrawRow != mModernStyledHighlightRow)) { + ModernUiFillRect ( + &mModernRenderContext, + (MODERN_UI_RECT){ DrawColumn * CellWidth, DrawRow * CellHeight, DrawWidth * CellWidth, CellHeight }, + Background + ); + } Printable = AllocateZeroPool ((StrLen (Buffer) + 1) * sizeof (CHAR16)); if (Printable != NULL) { @@ -2141,6 +2492,21 @@ PrintInternal ( TextMaxWidth = (DrawWidth * CellWidth > (4 + TextInset)) ? (DrawWidth * CellWidth - 4 - TextInset) : DrawWidth * CellWidth; + // + // Width == 0 means the caller imposed no column constraint. The modern + // proportional font advances wider than a text-grid cell, so a budget + // derived from the character count would clip the caller's own string + // (popups size themselves exactly to the text and were truncated as + // "..."). Grow the budget to the measured text width so unconstrained + // prints render in full. + // + if (Width == 0) { + MeasuredWidth = ModernUiMeasureText (Printable); + if ((MeasuredWidth + 4) > TextMaxWidth) { + TextMaxWidth = MeasuredWidth + 4; + } + } + ModernUiDrawTextFit ( &mModernRenderContext, TextX, diff --git a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.h b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.h index dec0e70..685a578 100644 --- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.h +++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.h @@ -48,6 +48,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include #include "Colors.h" diff --git a/Library/ModernUiCustomizedDisplayLib/ModernUiCustomizedDisplayLib.inf b/Library/ModernUiCustomizedDisplayLib/ModernUiCustomizedDisplayLib.inf index b1b48bb..9d067aa 100644 --- a/Library/ModernUiCustomizedDisplayLib/ModernUiCustomizedDisplayLib.inf +++ b/Library/ModernUiCustomizedDisplayLib/ModernUiCustomizedDisplayLib.inf @@ -48,6 +48,7 @@ ModernUiEngineLib ModernUiRendererLib ModernUiThemeLib + ModernUiStringLib [Guids] gEfiIfrTianoGuid ## SOMETIMES_CONSUMES ## UNDEFINED diff --git a/Library/ModernUiEngineLib/ModernUiEngineLib.c b/Library/ModernUiEngineLib/ModernUiEngineLib.c index 5ff3874..f953079 100644 --- a/Library/ModernUiEngineLib/ModernUiEngineLib.c +++ b/Library/ModernUiEngineLib/ModernUiEngineLib.c @@ -984,7 +984,20 @@ ModernUiEngineDrawValue ( // or action control reads the same here as in the in-setup DisplayEngine. // Plain text values carry no affordance. // - if ((Value->Type != ModernUiValueText) && (Rect.X > Value->Rect.X)) { + // Widget-mapped controls render as real backend widgets that carry their own + // affordance, so the external cue is drawn only for the remaining cued type + // (action). One-of/checkbox/numeric/string/password/ordered-list/date-time all + // map to widgets on the app-facing draw path. + if ((Value->Type != ModernUiValueText) && + (Value->Type != ModernUiValueOneOf) && + (Value->Type != ModernUiValueCheckbox) && + (Value->Type != ModernUiValueNumeric) && + (Value->Type != ModernUiValueString) && + (Value->Type != ModernUiValuePassword) && + (Value->Type != ModernUiValueOrderedList) && + (Value->Type != ModernUiValueDateTime) && + (Rect.X > Value->Rect.X)) + { CueSide = MIN ((Rect.Height > 6) ? (Rect.Height - 6) : 0, 14); if (CueSide >= 6) { ModernUiEngineDrawControlCue ( @@ -997,8 +1010,30 @@ ModernUiEngineDrawValue ( } } - if ((Value->Type == ModernUiValueOneOf) || (Value->Type == ModernUiValueText)) { - return ModernUiDrawValueBox (Context, Rect, Value->Text, Value->Selected, Theme); + // + // Route each widget-mapped control to the backend's best rendering: real LVGL + // widgets (lv_dropdown / lv_checkbox / lv_textarea) on the LVGL backend, themed + // value/field boxes on GOP. + // + switch (Value->Type) { + case ModernUiValueOneOf: + return ModernUiRenderOneOf (Context, Rect, Value->Text, Value->Selected, Theme); + case ModernUiValueCheckbox: + return ModernUiRenderCheckbox (Context, Rect, Value->Text, Value->Selected, Theme); + case ModernUiValueNumeric: + return ModernUiRenderNumeric (Context, Rect, Value->Text, Value->Selected, Theme); + case ModernUiValueString: + return ModernUiRenderString (Context, Rect, Value->Text, Value->Selected, Theme); + case ModernUiValuePassword: + return ModernUiRenderPassword (Context, Rect, Value->Text, Value->Selected, Theme); + case ModernUiValueOrderedList: + return ModernUiRenderOrderedList (Context, Rect, Value->Text, Value->Selected, Theme); + case ModernUiValueDateTime: + return ModernUiRenderDateTime (Context, Rect, Value->Text, Value->Selected, Theme); + case ModernUiValueText: + return ModernUiDrawValueBox (Context, Rect, Value->Text, Value->Selected, Theme); + default: + break; } return ModernUiDrawTextFit ( diff --git a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c index 2604f74..b72320c 100644 --- a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c +++ b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c @@ -44,6 +44,7 @@ #include #include "../ModernUiRendererLib/ModernUiGlyphs.h" #include "../ModernUiRendererLib/ModernUiRendererInternal.h" +#include "OemWatermarkData.h" #define MODERN_UI_TEXT_CELL_HEIGHT MODERN_UI_BUILTIN_GLYPH_HEIGHT @@ -756,3 +757,644 @@ ModernUiDrawText ( return ReturnStatus; } + + +/** + Convert a UCS-2 run to an ASCII label for LVGL's Latin fonts. + + Glyph-width markers and non-ASCII code points are dropped/replaced; CJK in a + widget label is a known limitation of the widget path (handled elsewhere for + primitive text). + + @param[out] Out Destination ASCII buffer. + @param[in] Cap Capacity of Out in bytes (>= 1). + @param[in] Src Null-terminated UCS-2 source. May be NULL (empty result). +**/ +STATIC +VOID +LvglAsciiLabel ( + OUT CHAR8 *Out, + IN UINTN Cap, + IN CONST CHAR16 *Src + ) +{ + UINTN SrcIdx; + UINTN DstIdx; + + DstIdx = 0; + if (Src != NULL) { + for (SrcIdx = 0; (Src[SrcIdx] != CHAR_NULL) && (DstIdx < (Cap - 1)); SrcIdx++) { + if (Src[SrcIdx] >= 0xFFF0) { + continue; + } + + Out[DstIdx++] = ((Src[SrcIdx] >= 0x20) && (Src[SrcIdx] < 0x7F)) ? (CHAR8)Src[SrcIdx] : '?'; + } + } + + Out[DstIdx] = '\0'; +} + +/** + Apply the shared display-only control styling to an LVGL widget. + + Sizes the widget to the value lane and themes its surface/border to match the + surrounding chrome. Per-widget text/symbol colors are set by the caller. + + @param[in] Obj Widget object. Must not be NULL. + @param[in] Rect Control rectangle. + @param[in] Selected TRUE when the owning row is selected. + @param[in] Theme Theme token table. Must not be NULL. +**/ +STATIC +VOID +LvglStyleControl ( + IN lv_obj_t *Obj, + IN MODERN_UI_RECT Rect, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + lv_obj_set_size (Obj, (int32_t)Rect.Width, (int32_t)Rect.Height); + lv_obj_set_pos (Obj, 0, 0); + lv_obj_set_style_bg_color (Obj, ToLvColor (Selected ? Theme->SelectedBand : Theme->Surface), 0); + lv_obj_set_style_bg_opa (Obj, LV_OPA_COVER, 0); + lv_obj_set_style_border_color (Obj, ToLvColor (Selected ? Theme->PopupBorder : Theme->Border), 0); +} + +/** + Snapshot a display-only widget and alpha-composite it into the shadow canvas. + + Lays out Obj, renders it to an ARGB8888 draw buffer via lv_snapshot_take, and + alpha-blends the result over the row background already in the canvas (so the + widget's rounded corners blend cleanly), then BLTs the region and deletes Obj. + Falls back to the themed value box if layout/snapshot fails. + + @param[in] Context Initialized render context. Must not be NULL. + @param[in] Obj Widget object (deleted by this call). Must not be NULL. + @param[in] Rect Control rectangle. + @param[in] Value Original value text (for the fallback path). + @param[in] Selected TRUE when the owning row is selected. + @param[in] Theme Theme token table. Must not be NULL. + + @retval EFI_SUCCESS Widget composited (or fell back successfully). +**/ +STATIC +EFI_STATUS +LvglComposeSnapshot ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN lv_obj_t *Obj, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + lv_draw_buf_t *Snap; + UINTN SnapW; + UINTN SnapH; + UINTN Stride; + UINTN RowIdx; + UINTN ColIdx; + UINT8 *SrcRow; + UINT8 *SrcPix; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Dst; + UINT32 Alpha; + + lv_obj_update_layout (Obj); + + Snap = lv_snapshot_take (Obj, LV_COLOR_FORMAT_ARGB8888); + if (Snap == NULL) { + lv_obj_delete (Obj); + return ModernUiDrawValueBox (Context, Rect, Value, Selected, Theme); + } + + SnapW = Snap->header.w; + SnapH = Snap->header.h; + Stride = Snap->header.stride; + + // + // Alpha-composite ARGB8888 (B,G,R,A byte order, matching EFI BLT pixels) over + // the row background already present in the canvas. + // + for (RowIdx = 0; (RowIdx < SnapH) && ((Rect.Y + RowIdx) < mCanvasH); RowIdx++) { + Dst = mCanvasBuf + (Rect.Y + RowIdx) * mCanvasW + Rect.X; + SrcRow = Snap->data + RowIdx * Stride; + for (ColIdx = 0; (ColIdx < SnapW) && ((Rect.X + ColIdx) < mCanvasW); ColIdx++, Dst++) { + SrcPix = SrcRow + ColIdx * 4; + Alpha = SrcPix[3]; + if (Alpha == 0) { + continue; + } + + if (Alpha >= 255) { + Dst->Blue = SrcPix[0]; + Dst->Green = SrcPix[1]; + Dst->Red = SrcPix[2]; + } else { + Dst->Blue = (UINT8)((SrcPix[0] * Alpha + Dst->Blue * (255 - Alpha)) / 255); + Dst->Green = (UINT8)((SrcPix[1] * Alpha + Dst->Green * (255 - Alpha)) / 255); + Dst->Red = (UINT8)((SrcPix[2] * Alpha + Dst->Red * (255 - Alpha)) / 255); + } + } + } + + lv_draw_buf_destroy (Snap); + lv_obj_delete (Obj); + + BltCanvasRegion ( + Rect.X, + Rect.Y, + MIN (SnapW, mCanvasW - Rect.X), + MIN (SnapH, mCanvasH - Rect.Y) + ); + + return EFI_SUCCESS; +} + + +/** + LVGL one-of renderer: render a real `lv_dropdown` widget into the shadow canvas. + + This is the first IFR-opcode->LVGL-widget mapping (one-of -> lv_dropdown). The + widget is display-only: a transient closed drop-down is created, labelled with + the selected option, themed, and rendered to an off-screen buffer via + `lv_snapshot_take`, then alpha-composited over the row background already in the + canvas (so the widget's rounded corners blend cleanly). edk2 FormBrowser still + owns the actual selection; we never route input into the widget. Falls back to + the composed value box when LVGL is not ready, the rect is off-screen, or + widget/snapshot allocation fails. + + @param[in] Context Initialized render context. Must not be NULL. + @param[in] Rect Control rectangle (value lane). + @param[in] Value Selected option text. Must not be NULL. + @param[in] Selected TRUE when the owning row is selected. + @param[in] Theme Theme token table. Must not be NULL. + + @retval EFI_SUCCESS Widget composited (or fell back successfully). + @retval EFI_INVALID_PARAMETER Context, Value, or Theme is NULL, or Rect empty. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderOneOf ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + lv_obj_t *Dropdown; + CHAR8 Label[128]; + + if ((Context == NULL) || (Value == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) { + return EFI_INVALID_PARAMETER; + } + + if (!mLvglReady || (mCanvas == NULL) || (Rect.X >= mCanvasW) || (Rect.Y >= mCanvasH)) { + return ModernUiDrawValueBox (Context, Rect, Value, Selected, Theme); + } + + LvglAsciiLabel (Label, sizeof (Label), Value); + + Dropdown = lv_dropdown_create (lv_display_get_screen_active (mDisplay)); + if (Dropdown == NULL) { + return ModernUiDrawValueBox (Context, Rect, Value, Selected, Theme); + } + + lv_dropdown_set_text (Dropdown, Label); + LvglStyleControl (Dropdown, Rect, Selected, Theme); + lv_obj_set_style_text_color (Dropdown, ToLvColor (Theme->Text), 0); + + return LvglComposeSnapshot (Context, Dropdown, Rect, Value, Selected, Theme); +} + +/** + Render an LVGL checkbox (display-only) for a checkbox/boolean control. + + The checkbox's checked state is inferred from an 'X'/'x' in the value text + (the FormBrowser "[X]"/"[ ]" convention); the value text becomes the label with + a leading "[.]" marker stripped. edk2 still owns the toggle. Falls back to the + value box when LVGL is unavailable. + + @param[in] Context Initialized render context. Must not be NULL. + @param[in] Rect Control rectangle. + @param[in] Value Value text (e.g. "[X] Enabled"). Must not be NULL. + @param[in] Selected TRUE when the owning row is selected. + @param[in] Theme Theme token table. Must not be NULL. + + @retval others Status from the snapshot composite or value-box fallback. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderCheckbox ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + lv_obj_t *Checkbox; + BOOLEAN Checked; + + if ((Context == NULL) || (Value == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) { + return EFI_INVALID_PARAMETER; + } + + if (!mLvglReady || (mCanvas == NULL) || (Rect.X >= mCanvasW) || (Rect.Y >= mCanvasH)) { + return ModernUiDrawValueBox (Context, Rect, Value, Selected, Theme); + } + + // + // Infer checked state from the "[X]"/"[ ]" marker. The box indicator alone + // conveys the state (the prompt is already in the row's left label), so the + // widget carries no text -- an empty label avoids leaking the raw "[X]" + // bracket characters next to the box. + // + Checked = (BOOLEAN)((StrStr (Value, L"X") != NULL) || (StrStr (Value, L"x") != NULL)); + + Checkbox = lv_checkbox_create (lv_display_get_screen_active (mDisplay)); + if (Checkbox == NULL) { + return ModernUiDrawValueBox (Context, Rect, Value, Selected, Theme); + } + + lv_checkbox_set_text (Checkbox, ""); + if (Checked) { + lv_obj_add_state (Checkbox, LV_STATE_CHECKED); + } + + LvglStyleControl (Checkbox, Rect, Selected, Theme); + lv_obj_set_style_bg_opa (Checkbox, LV_OPA_TRANSP, 0); + lv_obj_set_style_border_width (Checkbox, 0, 0); + lv_obj_set_style_text_color (Checkbox, ToLvColor (Selected ? Theme->Text : Theme->MutedText), 0); + + return LvglComposeSnapshot (Context, Checkbox, Rect, Value, Selected, Theme); +} + +/** + Render an LVGL text field (display-only) for string/numeric/password controls. + + Builds a one-line `lv_textarea` showing the current value (password mode masks + it). edk2 still owns editing. Shared by the string, numeric, and password + renderers. Falls back to the field box when LVGL is unavailable. + + @param[in] Context Initialized render context. Must not be NULL. + @param[in] Rect Control rectangle. + @param[in] Value Value text. Must not be NULL. + @param[in] Selected TRUE when the owning row is selected. + @param[in] Theme Theme token table. Must not be NULL. + @param[in] PasswordMode TRUE to mask the text as a password field. + + @retval others Status from the snapshot composite or field-box fallback. +**/ +STATIC +EFI_STATUS +LvglRenderTextField ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme, + IN BOOLEAN PasswordMode + ) +{ + lv_obj_t *Field; + CHAR8 Text[128]; + + if ((Context == NULL) || (Value == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) { + return EFI_INVALID_PARAMETER; + } + + if (!mLvglReady || (mCanvas == NULL) || (Rect.X >= mCanvasW) || (Rect.Y >= mCanvasH)) { + return ModernUiDrawFieldBox (Context, Rect, Value, Selected, Theme); + } + + LvglAsciiLabel (Text, sizeof (Text), Value); + + // + // Display-only single-line lv_textarea: a real LVGL input control. one-line + // mode plus an off scrollbar and a hidden caret keep short text legible at row + // height; password mode masks the text natively. edk2 owns actual editing. + // + Field = lv_textarea_create (lv_display_get_screen_active (mDisplay)); + if (Field == NULL) { + return ModernUiDrawFieldBox (Context, Rect, Value, Selected, Theme); + } + + lv_textarea_set_one_line (Field, true); + if (PasswordMode) { + lv_textarea_set_password_mode (Field, true); + lv_textarea_set_password_show_time (Field, 0); + } + + lv_textarea_set_text (Field, Text); + lv_textarea_set_cursor_pos (Field, 0); + lv_obj_set_scrollbar_mode (Field, LV_SCROLLBAR_MODE_OFF); + + LvglStyleControl (Field, Rect, Selected, Theme); + lv_obj_set_style_radius (Field, 4, 0); + lv_obj_set_style_pad_top (Field, 0, 0); + lv_obj_set_style_pad_bottom (Field, 0, 0); + lv_obj_set_style_pad_left (Field, 8, 0); + lv_obj_set_style_pad_right (Field, 4, 0); + lv_obj_set_style_text_color (Field, ToLvColor (Selected ? Theme->Text : Theme->MutedText), 0); + // + // Hide the textarea caret -- this is a display-only snapshot, not an editor. + // + lv_obj_set_style_opa (Field, LV_OPA_TRANSP, LV_PART_CURSOR); + + return LvglComposeSnapshot (Context, Field, Rect, Value, Selected, Theme); +} + +/** + LVGL string renderer: a real one-line lv_textarea. See ModernUiRenderString. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderString ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + return LvglRenderTextField (Context, Rect, Value, Selected, Theme, FALSE); +} + +/** + LVGL password renderer: a masked lv_textarea. See ModernUiRenderPassword. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderPassword ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + return LvglRenderTextField (Context, Rect, Value, Selected, Theme, TRUE); +} + +/** + LVGL numeric renderer: a real lv_textarea field showing the number. + + See ModernUiRenderNumeric. A spinbox-style numeric widget is a future + refinement; the field already presents the value as a genuine LVGL control. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderNumeric ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + return LvglRenderTextField (Context, Rect, Value, Selected, Theme, FALSE); +} + +/** + LVGL ordered-list renderer: a real list-style field showing the option order. + + Builds a styled `lv_obj` field with an `LV_SYMBOL_LIST` glyph prefixing the + current option order, so an ordered list reads as a genuine list control rather + than a cue glyph over native text. edk2 FormBrowser still owns the reorder popup + and the actual ordering. Falls back to the field box when LVGL is unavailable. + See ModernUiRenderOrderedList in ModernUiRenderer.h. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderOrderedList ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + lv_obj_t *Field; + lv_obj_t *Label; + CHAR16 Norm[160]; + CHAR8 Text[128]; + CHAR8 Decorated[160]; + + if ((Context == NULL) || (Value == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) { + return EFI_INVALID_PARAMETER; + } + + // + // Join the CR-separated option order onto one line so it reads as a sequence + // instead of showing the raw separators (see ModernUiNormalizeOrderedListText). + // + ModernUiNormalizeOrderedListText (Norm, ARRAY_SIZE (Norm), Value); + + if (!mLvglReady || (mCanvas == NULL) || (Rect.X >= mCanvasW) || (Rect.Y >= mCanvasH)) { + return ModernUiDrawFieldBox (Context, Rect, Norm, Selected, Theme); + } + + LvglAsciiLabel (Text, sizeof (Text), Norm); + // + // LV_SYMBOL_LIST is a UTF-8 glyph from the bundled Montserrat symbol set; it is + // copied verbatim ahead of the ASCII order text to mark the field as a list. + // + AsciiSPrint (Decorated, sizeof (Decorated), "%a %a", LV_SYMBOL_LIST, Text); + + Field = lv_obj_create (lv_display_get_screen_active (mDisplay)); + if (Field == NULL) { + return ModernUiDrawFieldBox (Context, Rect, Norm, Selected, Theme); + } + + LvglStyleControl (Field, Rect, Selected, Theme); + lv_obj_set_style_radius (Field, 4, 0); + lv_obj_set_style_pad_all (Field, 0, 0); + lv_obj_remove_flag (Field, LV_OBJ_FLAG_SCROLLABLE); + + Label = lv_label_create (Field); + if (Label != NULL) { + lv_label_set_text (Label, Decorated); + lv_obj_set_style_text_color (Label, ToLvColor (Selected ? Theme->Text : Theme->MutedText), 0); + lv_obj_align (Label, LV_ALIGN_LEFT_MID, 8, 0); + } + + return LvglComposeSnapshot (Context, Field, Rect, Norm, Selected, Theme); +} + +/** + LVGL date/time renderer: a segmented field showing month/day/year or H:M:S. + + Spaces the value around its `/ : -` delimiters so the segments read as discrete + cells, then renders them centered in a styled `lv_obj` field. edk2 owns segment + editing. In the in-setup DisplayEngine date/time keeps native per-segment + rendering (see ModernUiRenderDateTime in ModernUiRenderer.h); this entry point + serves the app-facing draw path. Falls back to the field box when LVGL is + unavailable. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderDateTime ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + lv_obj_t *Field; + lv_obj_t *Label; + CHAR8 Raw[64]; + CHAR8 Spaced[128]; + UINTN Src; + UINTN Dst; + CHAR8 Ch; + + if ((Context == NULL) || (Value == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) { + return EFI_INVALID_PARAMETER; + } + + if (!mLvglReady || (mCanvas == NULL) || (Rect.X >= mCanvasW) || (Rect.Y >= mCanvasH)) { + return ModernUiDrawFieldBox (Context, Rect, Value, Selected, Theme); + } + + LvglAsciiLabel (Raw, sizeof (Raw), Value); + // + // Pad each date/time delimiter with surrounding spaces so the segments read as + // discrete cells (e.g. "06 / 05 / 2026"), without parsing the field layout. + // + for (Src = 0, Dst = 0; (Raw[Src] != '\0') && (Dst < (sizeof (Spaced) - 4)); Src++) { + Ch = Raw[Src]; + if ((Ch == '/') || (Ch == ':') || (Ch == '-')) { + if ((Dst > 0) && (Spaced[Dst - 1] != ' ')) { + Spaced[Dst++] = ' '; + } + + Spaced[Dst++] = Ch; + Spaced[Dst++] = ' '; + } else { + Spaced[Dst++] = Ch; + } + } + + Spaced[Dst] = '\0'; + + Field = lv_obj_create (lv_display_get_screen_active (mDisplay)); + if (Field == NULL) { + return ModernUiDrawFieldBox (Context, Rect, Value, Selected, Theme); + } + + LvglStyleControl (Field, Rect, Selected, Theme); + lv_obj_set_style_radius (Field, 4, 0); + lv_obj_set_style_pad_all (Field, 0, 0); + lv_obj_remove_flag (Field, LV_OBJ_FLAG_SCROLLABLE); + + Label = lv_label_create (Field); + if (Label != NULL) { + lv_label_set_text (Label, Spaced); + lv_obj_set_style_text_color (Label, ToLvColor (Selected ? Theme->Text : Theme->MutedText), 0); + lv_obj_align (Label, LV_ALIGN_CENTER, 0, 0); + } + + return LvglComposeSnapshot (Context, Field, Rect, Value, Selected, Theme); +} + +/** + LVGL OEM watermark: composite the A8 brand mark into a region's whitespace. + + Renders a real `lv_image` from the generated A8 coverage map, tinted with the + theme's muted text color and drawn at low opacity, anchored bottom-right of + Region, then alpha-composited into the shadow canvas. Statement rows paint + opaquely afterwards, so the watermark only shows through the empty content area. + Display-only, no asset shipped beyond the original generated coverage map. See + ModernUiDrawOemWatermark in ModernUiRenderer.h. +**/ +EFI_STATUS +EFIAPI +ModernUiDrawOemWatermark ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Region, + IN CONST MODERN_UI_THEME *Theme + ) +{ + CONST EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Tint; + UINTN AnchorX; + UINTN AnchorY; + UINTN RowIdx; + UINTN ColIdx; + CONST UINT8 *SrcRow; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Dst; + UINT32 Coverage; + UINT32 Alpha; + + // + // Global opacity applied on top of the A8 coverage map. Kept low so the mark + // is a subtle background brand, never competing with the setup text. + // + CONST UINT32 GlobalOpa = 100; + + if ((Context == NULL) || (Theme == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (!mLvglReady || (mCanvas == NULL)) { + return EFI_SUCCESS; + } + + // + // Need room for the mark plus a margin; otherwise skip (no-op). + // + if ((Region.Width < (OEM_WATERMARK_WIDTH + 32)) || (Region.Height < (OEM_WATERMARK_HEIGHT + 24))) { + return EFI_SUCCESS; + } + + // + // Horizontally centered within the (statement-column) region, anchored toward + // the bottom of the whitespace so it sits below the form rows. + // + AnchorX = Region.X + (Region.Width - OEM_WATERMARK_WIDTH) / 2; + AnchorY = Region.Y + Region.Height - OEM_WATERMARK_HEIGHT - 16; + if ((AnchorX >= mCanvasW) || (AnchorY >= mCanvasH)) { + return EFI_SUCCESS; + } + + // + // Composite the alpha-only coverage map straight into the shadow canvas: the + // tint supplies the (muted, theme) fill, the A8 byte supplies the per-pixel + // coverage, GlobalOpa keeps the whole mark faint. No LVGL image object or + // snapshot is needed for a static background brand mark, and a direct blend + // is deterministic across backends. Statement rows paint opaquely afterwards, + // so the mark only shows through the empty content area. + // + Tint = &Theme->MutedText; + for (RowIdx = 0; (RowIdx < OEM_WATERMARK_HEIGHT) && ((AnchorY + RowIdx) < mCanvasH); RowIdx++) { + Dst = mCanvasBuf + (AnchorY + RowIdx) * mCanvasW + AnchorX; + SrcRow = gOemWatermarkAlpha + RowIdx * OEM_WATERMARK_WIDTH; + for (ColIdx = 0; (ColIdx < OEM_WATERMARK_WIDTH) && ((AnchorX + ColIdx) < mCanvasW); ColIdx++, Dst++) { + Coverage = SrcRow[ColIdx]; + if (Coverage == 0) { + continue; + } + + Alpha = (Coverage * GlobalOpa) / 255; + if (Alpha == 0) { + continue; + } + + Dst->Blue = (UINT8)((Tint->Blue * Alpha + Dst->Blue * (255 - Alpha)) / 255); + Dst->Green = (UINT8)((Tint->Green * Alpha + Dst->Green * (255 - Alpha)) / 255); + Dst->Red = (UINT8)((Tint->Red * Alpha + Dst->Red * (255 - Alpha)) / 255); + } + } + + BltCanvasRegion ( + AnchorX, + AnchorY, + MIN ((UINTN)OEM_WATERMARK_WIDTH, mCanvasW - AnchorX), + MIN ((UINTN)OEM_WATERMARK_HEIGHT, mCanvasH - AnchorY) + ); + + return EFI_SUCCESS; +} diff --git a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.inf b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.inf index 206ed8f..db68bd1 100644 --- a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.inf +++ b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.inf @@ -27,6 +27,8 @@ [Sources] ModernUiRendererLib.c + # Generated original OEM-watermark coverage map (Scripts/gen-oem-watermark.py). + OemWatermarkData.c # The backend-agnostic renderer surface and glyph table live in the GOP # renderer dir (single source of truth) and are compiled into both renderers. ../ModernUiRendererLib/ModernUiRendererCommon.c diff --git a/Library/ModernUiLvglRendererLib/OemWatermarkData.c b/Library/ModernUiLvglRendererLib/OemWatermarkData.c new file mode 100644 index 0000000..a5895d1 --- /dev/null +++ b/Library/ModernUiLvglRendererLib/OemWatermarkData.c @@ -0,0 +1,2864 @@ +/** @file + Generated OEM watermark alpha coverage map. DO NOT EDIT. + Regenerate via Scripts/gen-oem-watermark.py. + + Copyright (c) 2026, MarsDoge. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "OemWatermarkData.h" + +CONST UINT8 gOemWatermarkAlpha[OEM_WATERMARK_WIDTH * OEM_WATERMARK_HEIGHT] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0,0, + 255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0, + 0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255, + 0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255, + 255,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255, + 255,255,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,112,210,180,0,0,0,0,2,190,210,102, + 0,0,0,0,0,3,92,171,203,199,161,71,0,0,0,0,0,0,112,210, + 210,209,198,172,120,31,0,0,0,0,0,112,210,210,210,210,210,210,82,0, + 0,0,0,112,210,210,210,194,157,55,0,0,0,0,0,112,210,153,0,0, + 0,0,145,158,0,0,0,0,0,0,0,0,0,0,0,148,168,0,0,0, + 0,0,171,142,0,0,0,0,112,210,210,210,210,210,210,82,0,0,0,0, + 112,210,210,210,210,210,158,0,0,0,112,201,0,0,0,0,0,0,0,0, + 0,0,0,7,100,175,201,187,142,50,0,0,0,0,0,112,210,210,210,210, + 210,210,82,0,10,210,210,210,210,210,210,210,210,210,43,0,0,0,148,168, + 0,0,0,0,0,171,142,0,0,0,0,112,210,210,210,190,147,35,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,3,92,171,203,199,161,71,0,0,0,0,0,0,112,210,210,210, + 190,147,35,0,0,0,0,112,210,210,210,210,210,210,82,0,0,0,112,210, + 153,0,0,0,0,145,158,0,0,0,0,0,0,0,0,0,0,0,7,100, + 175,201,187,142,50,0,0,0,0,0,0,3,92,171,203,199,161,71,0,0, + 0,0,0,0,148,168,0,0,0,0,0,171,142,0,0,0,0,112,210,210, + 210,194,157,55,0,0,0,0,0,0,2,82,162,199,200,172,110,20,0,0, + 0,112,210,210,210,210,210,210,82,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, + 255,255,255,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,112,200,205,47,0,0,0,61,198,207,102, + 0,0,0,0,3,151,190,68,9,15,87,203,114,0,0,0,0,0,112,201, + 0,0,12,49,144,204,69,0,0,0,0,112,201,0,0,0,0,0,0,0, + 0,0,0,112,201,0,0,22,138,204,34,0,0,0,0,112,208,210,54,0, + 0,0,145,158,0,0,0,0,0,0,0,0,0,0,0,148,168,0,0,0, + 0,0,171,142,0,0,0,0,112,201,0,0,0,0,0,0,0,0,0,0, + 112,201,0,0,0,0,0,0,0,0,112,201,0,0,0,0,0,0,0,0, + 0,0,0,137,193,61,10,18,64,158,6,0,0,0,0,112,201,0,0,0, + 0,0,0,0,0,0,0,0,33,210,69,0,0,0,0,0,0,0,148,168, + 0,0,0,0,0,171,142,0,0,0,0,112,201,0,0,30,161,192,15,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,3,151,190,68,9,15,87,203,114,0,0,0,0,0,112,201,0,0, + 30,161,192,15,0,0,0,112,201,0,0,0,0,0,0,0,0,0,112,208, + 210,54,0,0,0,145,158,0,0,0,0,0,0,0,0,0,0,0,137,193, + 61,10,18,64,158,6,0,0,0,0,3,151,190,68,9,15,87,203,114,0, + 0,0,0,0,148,168,0,0,0,0,0,171,142,0,0,0,0,112,201,0, + 0,22,138,204,34,0,0,0,0,2,144,192,77,16,8,55,170,138,0,0, + 0,112,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, + 255,255,255,255,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,112,191,142,124,0,0,0,138,128,204,102, + 0,0,0,0,96,210,45,0,0,0,0,85,210,57,0,0,0,0,112,201, + 0,0,0,0,0,137,201,17,0,0,0,112,201,0,0,0,0,0,0,0, + 0,0,0,112,201,0,0,0,24,210,92,0,0,0,0,112,191,152,165,0, + 0,0,145,158,0,0,0,0,0,0,0,0,0,0,0,148,168,0,0,0, + 0,0,171,142,0,0,0,0,112,201,0,0,0,0,0,0,0,0,0,0, + 112,201,0,0,0,0,0,0,0,0,112,201,0,0,0,0,0,0,0,0, + 0,0,0,205,111,0,0,0,0,0,0,0,0,0,0,112,201,0,0,0, + 0,0,0,0,0,0,0,0,33,210,69,0,0,0,0,0,0,0,148,168, + 0,0,0,0,0,171,142,0,0,0,0,112,201,0,0,0,43,210,79,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,96,210,45,0,0,0,0,85,210,57,0,0,0,0,112,201,0,0, + 0,43,210,79,0,0,0,112,201,0,0,0,0,0,0,0,0,0,112,191, + 152,165,0,0,0,145,158,0,0,0,0,0,0,0,0,0,0,0,205,111, + 0,0,0,0,0,0,0,0,0,0,96,210,45,0,0,0,0,85,210,57, + 0,0,0,0,148,168,0,0,0,0,0,171,142,0,0,0,0,112,201,0, + 0,0,24,210,92,0,0,0,0,94,207,40,0,0,0,0,7,86,0,0, + 0,112,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 255,255,255,255,255,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,112,191,63,196,6,0,12,203,51,204,102, + 0,0,0,0,183,154,0,0,0,0,0,4,189,142,0,0,0,0,112,201, + 0,0,0,0,0,36,210,87,0,0,0,112,201,0,0,0,0,0,0,0, + 0,0,0,112,201,0,0,0,24,210,98,0,0,0,0,112,191,42,210,65, + 0,0,145,158,0,0,0,0,0,0,0,0,0,0,0,148,168,0,0,0, + 0,0,171,142,0,0,0,0,112,201,0,0,0,0,0,0,0,0,0,0, + 112,201,0,0,0,0,0,0,0,0,112,201,0,0,0,0,0,0,0,0, + 0,0,0,183,161,13,0,0,0,0,0,0,0,0,0,112,201,0,0,0, + 0,0,0,0,0,0,0,0,33,210,69,0,0,0,0,0,0,0,148,168, + 0,0,0,0,0,171,142,0,0,0,0,112,201,0,0,0,13,210,104,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,183,154,0,0,0,0,0,4,189,142,0,0,0,0,112,201,0,0, + 0,13,210,104,0,0,0,112,201,0,0,0,0,0,0,0,0,0,112,191, + 42,210,65,0,0,145,158,0,0,0,0,0,0,0,0,0,0,0,183,161, + 13,0,0,0,0,0,0,0,0,0,183,154,0,0,0,0,0,4,189,142, + 0,0,0,0,148,168,0,0,0,0,0,171,142,0,0,0,0,112,201,0, + 0,0,24,210,98,0,0,0,0,182,147,0,0,0,0,0,0,0,0,0, + 0,112,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,112,191,3,193,69,0,83,183,1,204,102, + 0,0,0,16,210,112,0,0,0,0,0,0,152,187,0,0,0,0,112,201, + 0,0,0,0,0,1,202,126,0,0,0,112,201,0,0,0,0,0,0,0, + 0,0,0,112,201,0,0,21,138,202,30,0,0,0,0,112,191,0,142,174, + 2,0,145,158,0,0,0,0,0,0,0,0,0,0,0,148,168,0,0,0, + 0,0,171,142,0,0,0,0,112,201,0,0,0,0,0,0,0,0,0,0, + 112,201,0,0,0,0,0,0,0,0,112,201,0,0,0,0,0,0,0,0, + 0,0,0,58,192,203,159,115,52,0,0,0,0,0,0,112,201,0,0,0, + 0,0,0,0,0,0,0,0,33,210,69,0,0,0,0,0,0,0,148,168, + 0,0,0,0,0,171,142,0,0,0,0,112,201,0,0,0,42,210,79,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,16,210,112,0,0,0,0,0,0,152,187,0,0,0,0,112,201,0,0, + 0,42,210,79,0,0,0,112,201,0,0,0,0,0,0,0,0,0,112,191, + 0,142,174,2,0,145,158,0,0,0,0,0,0,0,0,0,0,0,58,192, + 203,159,115,52,0,0,0,0,0,16,210,112,0,0,0,0,0,0,152,187, + 0,0,0,0,148,168,0,0,0,0,0,171,142,0,0,0,0,112,201,0, + 0,21,138,202,30,0,0,0,16,210,100,0,0,0,0,0,0,0,0,0, + 0,112,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,112,191,0,119,147,0,161,106,0,204,102, + 0,0,0,29,210,92,0,0,0,0,0,0,132,200,0,0,0,0,112,201, + 0,0,0,0,0,0,191,138,0,0,0,112,210,210,210,210,210,210,33,0, + 0,0,0,112,210,210,210,210,198,44,0,0,0,0,0,112,191,0,33,208, + 76,0,145,158,0,0,0,0,0,0,0,0,0,0,0,148,168,0,0,0, + 0,0,171,142,0,0,0,0,112,210,210,210,210,210,210,33,0,0,0,0, + 112,210,210,210,210,210,59,0,0,0,112,201,0,0,0,0,0,0,0,0, + 0,0,0,0,8,61,109,161,210,147,4,0,0,0,0,112,210,210,210,210, + 210,210,33,0,0,0,0,0,33,210,69,0,0,0,0,0,0,0,148,168, + 0,0,0,0,0,171,142,0,0,0,0,112,201,0,0,29,160,193,16,0, + 0,0,0,0,0,0,0,0,82,210,33,0,0,0,0,0,0,0,0,0, + 0,29,210,92,0,0,0,0,0,0,132,200,0,0,0,0,112,201,0,0, + 29,160,193,16,0,0,0,112,210,210,210,210,210,210,33,0,0,0,112,191, + 0,33,208,76,0,145,158,0,0,0,0,0,0,0,0,0,0,0,0,8, + 61,109,161,210,147,4,0,0,0,29,210,92,0,0,0,0,0,0,132,200, + 0,0,0,0,148,168,0,0,0,0,0,171,142,0,0,0,0,112,210,210, + 210,210,198,44,0,0,0,0,29,210,88,0,0,0,0,0,0,0,0,0, + 0,112,210,210,210,210,210,210,33,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,112,191,0,40,207,47,209,30,0,204,102, + 0,0,0,16,210,112,0,0,0,0,0,0,152,187,0,0,0,0,112,201, + 0,0,0,0,0,1,203,125,0,0,0,112,201,0,0,0,0,0,0,0, + 0,0,0,112,201,0,2,41,184,148,1,0,0,0,0,112,191,0,0,130, + 182,4,145,158,0,0,0,0,0,0,0,0,0,0,0,147,169,0,0,0, + 0,0,172,141,0,0,0,0,112,201,0,0,0,0,0,0,0,0,0,0, + 112,201,0,0,0,0,0,0,0,0,112,201,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,75,210,90,0,0,0,0,112,201,0,0,0, + 0,0,0,0,0,0,0,0,33,210,69,0,0,0,0,0,0,0,147,169, + 0,0,0,0,0,172,141,0,0,0,0,112,210,210,210,191,147,37,0,0, + 0,0,0,0,0,0,0,0,82,210,33,0,0,0,0,0,0,0,0,0, + 0,16,210,112,0,0,0,0,0,0,152,187,0,0,0,0,112,210,210,210, + 191,147,37,0,0,0,0,112,201,0,0,0,0,0,0,0,0,0,112,191, + 0,0,130,182,4,145,158,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,75,210,90,0,0,0,16,210,112,0,0,0,0,0,0,152,187, + 0,0,0,0,147,169,0,0,0,0,0,172,141,0,0,0,0,112,201,0, + 2,41,184,148,1,0,0,0,16,210,100,0,0,0,0,0,0,0,0,0, + 0,112,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,112,191,0,0,173,184,162,0,0,204,102, + 0,0,0,0,184,153,0,0,0,0,0,4,189,143,0,0,0,0,112,201, + 0,0,0,0,0,37,210,86,0,0,0,112,201,0,0,0,0,0,0,0, + 0,0,0,112,201,0,0,0,54,210,71,0,0,0,0,112,191,0,0,25, + 205,87,145,158,0,0,0,0,0,0,0,0,0,0,0,138,185,0,0,0, + 0,0,189,131,0,0,0,0,112,201,0,0,0,0,0,0,0,0,0,0, + 112,201,0,0,0,0,0,0,0,0,112,201,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,192,134,0,0,0,0,112,201,0,0,0, + 0,0,0,0,0,0,0,0,33,210,69,0,0,0,0,0,0,0,138,185, + 0,0,0,0,0,189,131,0,0,0,0,112,201,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,184,153,0,0,0,0,0,4,189,143,0,0,0,0,112,201,0,0, + 0,0,0,0,0,0,0,112,201,0,0,0,0,0,0,0,0,0,112,191, + 0,0,25,205,87,145,158,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,192,134,0,0,0,0,184,153,0,0,0,0,0,4,189,143, + 0,0,0,0,138,185,0,0,0,0,0,189,131,0,0,0,0,112,201,0, + 0,0,54,210,71,0,0,0,0,183,147,0,0,0,0,0,0,0,0,0, + 0,112,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,112,191,0,0,95,210,85,0,0,204,102, + 0,0,0,0,97,210,44,0,0,0,0,83,210,58,0,0,0,0,112,201, + 0,0,0,0,0,138,200,16,0,0,0,112,201,0,0,0,0,0,0,0, + 0,0,0,112,201,0,0,0,0,159,172,0,0,0,0,112,191,0,0,0, + 119,189,153,158,0,0,0,0,0,0,0,0,0,0,0,97,208,23,0,0, + 0,27,208,90,0,0,0,0,112,201,0,0,0,0,0,0,0,0,0,0, + 112,201,0,0,0,0,0,0,0,0,112,201,0,0,0,0,0,0,0,0, + 0,0,0,107,0,0,0,0,7,204,124,0,0,0,0,112,201,0,0,0, + 0,0,0,0,0,0,0,0,33,210,69,0,0,0,0,0,0,0,97,208, + 23,0,0,0,27,208,90,0,0,0,0,112,201,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,97,210,44,0,0,0,0,83,210,58,0,0,0,0,112,201,0,0, + 0,0,0,0,0,0,0,112,201,0,0,0,0,0,0,0,0,0,112,191, + 0,0,0,119,189,153,158,0,0,0,0,0,0,0,0,0,0,0,107,0, + 0,0,0,7,204,124,0,0,0,0,97,210,44,0,0,0,0,83,210,58, + 0,0,0,0,97,208,23,0,0,0,27,208,90,0,0,0,0,112,201,0, + 0,0,0,159,172,0,0,0,0,95,207,39,0,0,0,0,7,86,0,0, + 0,112,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,112,191,0,0,0,0,0,0,0,204,102, + 0,0,0,0,3,153,189,67,8,14,86,203,117,0,0,0,0,0,112,201, + 0,0,11,49,143,203,67,0,0,0,0,112,201,0,0,0,0,0,0,0, + 0,0,0,112,201,0,0,0,0,61,210,60,0,0,0,112,191,0,0,0, + 18,200,208,158,0,0,0,0,0,0,0,0,0,0,0,16,189,156,36,8, + 38,161,186,12,0,0,0,0,112,201,0,0,0,0,0,0,0,0,0,0, + 112,201,0,0,0,0,0,0,0,0,112,201,0,0,0,0,0,0,0,0, + 0,0,0,204,150,44,7,32,142,206,44,0,0,0,0,112,201,0,0,0, + 0,0,0,0,0,0,0,0,33,210,69,0,0,0,0,0,0,0,16,189, + 156,36,8,38,161,186,12,0,0,0,0,112,201,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,3,153,189,67,8,14,86,203,117,0,0,0,0,0,112,201,0,0, + 0,0,0,0,0,0,0,112,201,0,0,0,0,0,0,0,0,0,112,191, + 0,0,0,18,200,208,158,0,0,0,0,0,0,0,0,0,0,0,204,150, + 44,7,32,142,206,44,0,0,0,0,3,153,189,67,8,14,86,203,117,0, + 0,0,0,0,16,189,156,36,8,38,161,186,12,0,0,0,0,112,201,0, + 0,0,0,61,210,60,0,0,0,2,147,192,77,16,7,55,170,138,0,0, + 0,112,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,112,191,0,0,0,0,0,0,0,204,102, + 0,0,0,0,0,4,94,172,203,201,161,73,0,0,0,0,0,0,112,210, + 210,209,199,173,120,31,0,0,0,0,0,112,210,210,210,210,210,210,109,0, + 0,0,0,112,201,0,0,0,0,0,173,158,0,0,0,112,191,0,0,0, + 0,108,210,158,0,0,0,0,0,0,0,0,0,0,0,0,27,137,193,208, + 191,134,24,0,0,0,0,0,112,210,210,210,210,210,210,109,0,0,0,0, + 112,201,0,0,0,0,0,0,0,0,112,201,0,0,0,0,0,0,0,0, + 0,0,0,41,128,180,203,187,145,44,0,0,0,0,0,112,210,210,210,210, + 210,210,109,0,0,0,0,0,33,210,69,0,0,0,0,0,0,0,0,27, + 137,193,208,191,134,24,0,0,0,0,0,112,201,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,4,94,172,203,201,161,73,0,0,0,0,0,0,112,201,0,0, + 0,0,0,0,0,0,0,112,210,210,210,210,210,210,109,0,0,0,112,191, + 0,0,0,0,108,210,158,0,0,0,0,0,0,0,0,0,0,0,41,128, + 180,203,187,145,44,0,0,0,0,0,0,4,94,172,203,201,161,73,0,0, + 0,0,0,0,0,27,137,193,208,191,134,24,0,0,0,0,0,112,201,0, + 0,0,0,0,173,158,0,0,0,0,2,84,164,200,201,173,110,21,0,0, + 0,112,210,210,210,210,210,210,109,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,252,255,255,255,56,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,252,255,255,255,56,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,252,255,255,255,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,7,243,255,155,0,0,204,255,255,255,255,255,39,0, + 0,0,0,0,0,68,255,255,255,255,255,172,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,204,255, + 255,255,255,252,247,234,214,180,127,39,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,7,243,255,155,0,0,204,255,255, + 255,255,255,39,0,0,0,0,0,0,68,255,255,255,255,255,172,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,12,255,255,255,255,44,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,63,161,217,243,250,234,216,189,142,94,22,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,204, + 255,255,255,255,255,255,255,243,219,167,79,1,0,0,0,0,252,255,255,255, + 56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,252,255,255,255,56,0,0,0,152,255,255,255,152, + 0,0,0,0,0,0,0,252,255,255,255,56,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,252,255,255,255,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,75,255,255,76,0,0,204,255,255,255,255,255,141,0, + 0,0,0,0,0,171,255,255,255,255,255,172,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,204,255, + 255,255,255,255,255,255,255,255,255,254,180,27,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,75,255,255,76,0,0,204,255,255, + 255,255,255,141,0,0,0,0,0,0,171,255,255,255,255,255,172,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,12,255,255,255,255,44,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,155,255,255,255,255,255,255,255,255,255,255,96,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,152,255,255,255,152,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,204, + 255,255,255,255,255,255,255,255,255,255,255,191,17,0,0,0,252,255,255,255, + 56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,252,255,255,255,56,0,0,0,152,255,255,255,152, + 0,0,0,0,0,0,0,252,255,255,255,56,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,252,255,255,255,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,154,255,245,8,0,0,204,255,255,255,255,255,236,7, + 0,0,0,0,23,250,255,255,255,255,255,172,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,204,255, + 255,255,255,255,255,255,255,255,255,255,255,233,54,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,154,255,245,8,0,0,204,255,255, + 255,255,255,236,7,0,0,0,0,23,250,255,255,255,255,255,172,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,12,255,255,255,255,44,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 126,255,255,255,255,255,255,255,255,255,255,255,96,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,152,255,255,255,152,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,204, + 255,255,255,255,255,255,255,255,255,255,255,255,191,0,0,0,252,255,255,255, + 56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,252,255,255,255,56,0,0,0,152,255,255,255,152, + 0,0,0,0,0,0,0,252,255,255,255,56,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,252,255,255,255,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,1,231,255,174,0,0,0,204,255,255,255,255,255,255,90, + 0,0,0,0,121,255,255,255,255,255,255,172,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,204,255, + 255,255,184,0,4,25,82,191,255,255,255,255,231,27,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,1,231,255,174,0,0,0,204,255,255, + 255,255,255,255,90,0,0,0,0,121,255,255,255,255,255,255,172,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,12,255,255,255,255,44,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, + 241,255,255,255,168,46,11,14,54,131,232,255,96,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,152,255,255,255,152,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,204, + 255,255,255,184,0,0,11,68,221,255,255,255,255,66,0,0,252,255,255,255, + 56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,152,255,255,255,152, + 0,0,0,0,0,0,0,252,255,255,255,56,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,252,255,255,255,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,56,255,255,95,0,0,0,204,255,255,255,255,255,255,193, + 0,0,0,1,222,255,255,255,255,255,255,172,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,204,255, + 255,255,184,0,0,0,0,0,134,255,255,255,255,163,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,56,255,255,95,0,0,0,204,255,255, + 255,255,255,255,193,0,0,0,1,222,255,255,255,255,255,255,172,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,12,255,255,255,255,44,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50, + 255,255,255,238,3,0,0,0,0,0,7,120,85,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,152,255,255,255,152,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,204, + 255,255,255,184,0,0,0,0,68,255,255,255,255,130,0,0,252,255,255,255, + 56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,16,138,219,248,234,175,59,12,255, + 255,255,255,44,0,0,0,252,255,255,255,56,0,176,255,255,255,255,255,255, + 255,255,255,236,0,0,0,252,255,255,255,56,29,151,224,249,234,169,41,0, + 0,0,0,32,255,255,255,255,24,0,0,0,32,255,255,255,255,20,0,0, + 0,252,255,255,255,56,37,160,227,249,229,159,34,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,47,144,204,237,250,227,191,107,18,0,0, + 0,0,0,0,63,158,216,242,250,233,190,117,17,0,0,0,0,0,255,255, + 255,255,56,48,173,236,245,206,103,1,0,22,145,224,249,229,158,29,0,0, + 0,0,0,0,0,135,255,252,20,0,0,0,204,255,255,255,203,255,255,255, + 40,0,0,71,255,255,255,202,255,255,255,172,0,0,0,0,22,91,160,210, + 241,252,243,219,168,79,0,0,0,0,0,0,252,255,255,255,56,44,165,229, + 251,191,0,0,12,115,191,232,249,244,217,186,131,59,2,0,0,0,204,255, + 255,255,184,0,0,0,0,0,1,197,255,255,255,252,26,0,0,0,0,0, + 63,158,216,242,250,233,190,117,17,0,0,0,0,0,0,0,16,138,219,248, + 234,175,59,12,255,255,255,255,44,0,0,0,0,0,58,156,214,241,250,231, + 179,90,3,0,0,0,0,0,0,0,135,255,252,20,0,0,0,204,255,255, + 255,203,255,255,255,40,0,0,71,255,255,255,202,255,255,255,172,0,0,0, + 0,0,0,63,158,216,242,250,233,190,117,17,0,0,0,0,0,0,17,139, + 220,248,234,175,59,12,255,255,255,255,44,0,0,0,0,0,58,156,214,241, + 250,231,179,90,3,0,0,0,0,0,0,252,255,255,255,56,44,165,229,251, + 191,0,252,255,255,255,56,29,151,224,249,234,169,41,0,0,0,0,0,67, + 255,255,255,227,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,58, + 156,214,241,250,231,179,90,3,0,0,0,176,255,255,255,255,255,255,255,255, + 255,236,0,0,32,255,255,255,255,24,0,0,0,32,255,255,255,255,20,0, + 0,0,252,255,255,255,56,37,160,227,249,229,159,34,0,0,0,0,0,204, + 255,255,255,184,0,0,0,0,23,255,255,255,255,150,0,0,252,255,255,255, + 56,0,0,0,118,255,255,255,253,100,0,0,0,16,138,219,248,234,175,59, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,34,223,255,255,255,255,255,254,125,255, + 255,255,255,44,0,0,0,252,255,255,255,56,0,176,255,255,255,255,255,255, + 255,255,255,236,0,0,0,252,255,255,255,127,243,255,255,255,255,255,241,43, + 0,0,0,32,255,255,255,255,23,0,0,0,32,255,255,255,255,20,0,0, + 0,252,255,255,255,131,247,255,255,255,255,255,243,63,0,0,0,0,0,0, + 0,0,0,0,0,0,0,7,153,255,255,255,255,255,255,255,255,160,0,0, + 0,0,12,171,255,255,255,255,255,255,255,255,235,72,0,0,0,0,255,255, + 255,255,137,250,255,255,255,255,255,157,45,234,255,255,255,255,255,230,26,0, + 0,0,0,0,0,214,255,193,0,0,0,0,204,255,255,255,127,228,255,255, + 142,0,0,174,255,255,203,152,255,255,255,172,0,0,0,0,208,255,255,255, + 255,255,255,255,255,255,179,6,0,0,0,0,252,255,255,255,136,250,255,255, + 255,192,0,18,216,255,255,255,255,255,255,255,255,255,68,0,0,0,204,255, + 255,255,184,0,0,0,0,0,0,88,255,255,255,255,95,0,0,0,12,171, + 255,255,255,255,255,255,255,255,235,72,0,0,0,0,0,34,223,255,255,255, + 255,255,254,125,255,255,255,255,44,0,0,0,10,165,255,255,255,255,255,255, + 255,255,198,25,0,0,0,0,0,0,214,255,193,0,0,0,0,204,255,255, + 255,127,228,255,255,142,0,0,174,255,255,203,152,255,255,255,172,0,0,0, + 0,12,171,255,255,255,255,255,255,255,255,235,72,0,0,0,0,34,224,255, + 255,255,255,255,254,125,255,255,255,255,44,0,0,0,10,165,255,255,255,255, + 255,255,255,255,198,25,0,0,0,0,0,252,255,255,255,136,250,255,255,255, + 192,0,252,255,255,255,127,243,255,255,255,255,255,241,43,0,0,0,0,45, + 255,255,255,255,145,21,0,0,0,0,0,0,0,0,0,0,0,10,165,255, + 255,255,255,255,255,255,255,198,25,0,0,176,255,255,255,255,255,255,255,255, + 255,236,0,0,32,255,255,255,255,23,0,0,0,32,255,255,255,255,20,0, + 0,0,252,255,255,255,131,247,255,255,255,255,255,243,63,0,0,0,0,204, + 255,255,255,184,0,0,0,0,68,255,255,255,255,130,0,0,252,255,255,255, + 56,0,0,121,255,255,255,249,85,0,0,0,34,223,255,255,255,255,255,254, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,4,206,255,255,255,255,255,255,255,255,255, + 255,255,255,44,0,0,0,252,255,255,255,56,0,176,255,255,255,255,255,255, + 255,255,255,236,0,0,0,252,255,255,255,255,255,255,255,255,255,255,255,184, + 0,0,0,32,255,255,255,255,22,0,0,0,32,255,255,255,255,20,0,0, + 0,252,255,255,255,255,255,255,255,255,255,255,255,235,23,0,0,0,0,0, + 0,0,0,0,0,0,0,171,255,255,255,255,255,255,255,255,255,160,0,0, + 0,1,183,255,255,255,255,255,255,255,255,255,255,248,58,0,0,0,255,255, + 255,255,255,255,255,255,255,255,255,255,239,255,255,255,255,255,255,255,156,0, + 0,0,0,0,36,255,255,114,0,0,0,0,204,255,255,255,124,129,255,255, + 237,8,25,251,255,255,100,152,255,255,255,172,0,0,0,0,208,255,255,255, + 255,255,255,255,255,255,255,133,0,0,0,0,252,255,255,255,255,255,255,255, + 255,193,0,132,255,255,255,255,255,255,255,255,255,255,68,0,0,0,204,255, + 255,255,184,0,0,0,0,0,0,29,255,255,255,255,142,0,0,1,183,255, + 255,255,255,255,255,255,255,255,255,248,58,0,0,0,4,206,255,255,255,255, + 255,255,255,255,255,255,255,255,44,0,0,0,178,255,255,255,255,255,255,255, + 255,255,255,206,8,0,0,0,0,36,255,255,114,0,0,0,0,204,255,255, + 255,124,129,255,255,237,8,25,251,255,255,100,152,255,255,255,172,0,0,0, + 1,183,255,255,255,255,255,255,255,255,255,255,248,58,0,0,4,206,255,255, + 255,255,255,255,255,255,255,255,255,255,44,0,0,0,178,255,255,255,255,255, + 255,255,255,255,255,206,8,0,0,0,0,252,255,255,255,255,255,255,255,255, + 193,0,252,255,255,255,255,255,255,255,255,255,255,255,184,0,0,0,0,2, + 224,255,255,255,255,252,203,155,102,39,0,0,0,0,0,0,0,178,255,255, + 255,255,255,255,255,255,255,255,206,8,0,176,255,255,255,255,255,255,255,255, + 255,236,0,0,32,255,255,255,255,22,0,0,0,32,255,255,255,255,20,0, + 0,0,252,255,255,255,255,255,255,255,255,255,255,255,235,23,0,0,0,204, + 255,255,255,184,0,0,10,67,220,255,255,255,255,66,0,0,252,255,255,255, + 56,0,124,255,255,255,244,70,0,0,0,4,206,255,255,255,255,255,255,255, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,90,255,255,255,255,164,35,18,99,246,255, + 255,255,255,44,0,0,0,252,255,255,255,56,0,0,0,152,255,255,255,152, + 0,0,0,0,0,0,0,252,255,255,255,255,141,29,29,177,255,255,255,252, + 11,0,0,32,255,255,255,255,20,0,0,0,32,255,255,255,255,20,0,0, + 0,252,255,255,255,253,122,24,25,124,254,255,255,255,137,0,0,0,0,0, + 0,0,0,0,0,0,79,255,255,255,255,213,78,24,14,49,119,134,0,0, + 0,85,255,255,255,255,163,36,14,79,234,255,255,255,208,0,0,0,255,255, + 255,255,253,111,17,55,241,255,255,255,255,197,41,17,170,255,255,255,235,0, + 0,0,0,0,116,255,255,36,0,0,0,0,204,255,255,255,124,29,252,255, + 255,92,124,255,255,241,11,152,255,255,255,172,0,0,0,0,178,139,64,35, + 9,12,46,161,255,255,255,239,3,0,0,0,252,255,255,255,255,183,45,9, + 58,135,0,183,255,255,255,90,15,7,32,62,126,200,65,0,0,0,204,255, + 255,255,184,0,0,0,0,0,0,5,255,255,255,255,162,0,0,85,255,255, + 255,255,163,36,14,79,234,255,255,255,208,0,0,0,90,255,255,255,255,164, + 35,18,99,246,255,255,255,255,44,0,0,82,255,255,255,252,118,25,10,64, + 220,255,255,255,115,0,0,0,0,116,255,255,36,0,0,0,0,204,255,255, + 255,124,29,252,255,255,92,124,255,255,241,11,152,255,255,255,172,0,0,0, + 85,255,255,255,255,163,36,14,79,234,255,255,255,208,0,0,90,255,255,255, + 255,158,34,17,94,244,255,255,255,255,44,0,0,82,255,255,255,252,118,25, + 10,64,220,255,255,255,115,0,0,0,0,252,255,255,255,255,183,45,9,58, + 135,0,252,255,255,255,255,141,29,27,176,255,255,255,252,11,0,0,0,0, + 76,252,255,255,255,255,255,255,255,255,208,82,0,0,0,0,82,255,255,255, + 252,118,25,10,64,220,255,255,255,115,0,0,0,152,255,255,255,152,0,0, + 0,0,0,0,32,255,255,255,255,20,0,0,0,32,255,255,255,255,20,0, + 0,0,252,255,255,255,253,122,24,25,124,254,255,255,255,137,0,0,0,204, + 255,255,255,255,255,255,255,255,255,255,255,255,193,0,0,0,252,255,255,255, + 56,127,255,255,255,238,57,0,0,0,0,90,255,255,255,255,164,35,18,99, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,172,255,255,255,216,2,0,0,0,126,255, + 255,255,255,44,0,0,0,252,255,255,255,56,0,0,0,152,255,255,255,152, + 0,0,0,0,0,0,0,252,255,255,255,184,0,0,0,36,255,255,255,255, + 44,0,0,32,255,255,255,255,20,0,0,0,32,255,255,255,255,20,0,0, + 0,252,255,255,255,165,0,0,0,0,169,255,255,255,219,0,0,0,0,0, + 0,0,0,0,0,0,174,255,255,255,234,20,0,0,0,0,0,0,0,0, + 0,178,255,255,255,213,2,0,0,0,87,255,255,255,255,44,0,0,255,255, + 255,255,166,0,0,0,175,255,255,255,252,30,0,0,51,255,255,255,255,16, + 0,0,0,0,195,255,212,0,0,0,0,0,204,255,255,255,124,0,179,255, + 255,196,224,255,255,150,0,152,255,255,255,172,0,0,0,0,0,0,0,0, + 0,0,0,5,247,255,255,255,45,0,0,0,252,255,255,255,225,6,0,0, + 0,0,0,175,255,255,254,70,3,0,0,0,0,0,0,0,0,0,204,255, + 255,255,184,0,0,0,0,0,0,5,255,255,255,255,161,0,0,178,255,255, + 255,213,2,0,0,0,87,255,255,255,255,44,0,0,172,255,255,255,216,2, + 0,0,0,126,255,255,255,255,44,0,0,176,255,255,255,143,0,0,0,0, + 78,255,255,255,210,0,0,0,0,195,255,212,0,0,0,0,0,204,255,255, + 255,124,0,179,255,255,196,224,255,255,150,0,152,255,255,255,172,0,0,0, + 178,255,255,255,213,2,0,0,0,87,255,255,255,255,44,0,172,255,255,255, + 213,1,0,0,0,121,255,255,255,255,44,0,0,176,255,255,255,143,0,0, + 0,0,78,255,255,255,210,0,0,0,0,252,255,255,255,225,6,0,0,0, + 0,0,252,255,255,255,184,0,0,0,35,255,255,255,255,44,0,0,0,0, + 0,66,213,255,255,255,255,255,255,255,255,255,129,0,0,0,176,255,255,255, + 143,0,0,0,0,78,255,255,255,210,0,0,0,152,255,255,255,152,0,0, + 0,0,0,0,32,255,255,255,255,20,0,0,0,32,255,255,255,255,20,0, + 0,0,252,255,255,255,165,0,0,0,0,169,255,255,255,219,0,0,0,204, + 255,255,255,255,255,255,255,255,255,255,255,195,19,0,0,0,252,255,255,255, + 180,255,255,255,231,45,0,0,0,0,0,172,255,255,255,216,2,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,217,255,255,255,138,0,0,0,0,43,255, + 255,255,255,44,0,0,0,252,255,255,255,56,0,0,0,152,255,255,255,152, + 0,0,0,0,0,0,0,252,255,255,255,94,0,0,0,8,255,255,255,255, + 55,0,0,32,255,255,255,255,20,0,0,0,32,255,255,255,255,20,0,0, + 0,252,255,255,255,86,0,0,0,0,91,255,255,255,255,9,0,0,0,0, + 0,0,0,0,0,0,225,255,255,255,146,0,0,0,0,0,0,0,0,0, + 0,227,255,255,255,134,0,0,0,0,8,254,255,255,255,94,0,0,255,255, + 255,255,88,0,0,0,150,255,255,255,204,0,0,0,24,255,255,255,255,27, + 0,0,0,20,253,255,133,0,0,0,0,0,204,255,255,255,124,0,76,255, + 255,255,255,255,255,47,0,152,255,255,255,172,0,0,0,0,10,105,179,221, + 244,253,255,255,255,255,255,255,69,0,0,0,252,255,255,255,120,0,0,0, + 0,0,0,101,255,255,255,255,249,217,181,136,71,4,0,0,0,0,204,255, + 255,255,184,0,0,0,0,0,0,30,255,255,255,255,141,0,0,227,255,255, + 255,134,0,0,0,0,8,254,255,255,255,94,0,0,217,255,255,255,138,0, + 0,0,0,43,255,255,255,255,44,0,0,226,255,255,255,255,255,255,255,255, + 255,255,255,255,255,8,0,0,20,253,255,133,0,0,0,0,0,204,255,255, + 255,124,0,76,255,255,255,255,255,255,47,0,152,255,255,255,172,0,0,0, + 227,255,255,255,134,0,0,0,0,8,254,255,255,255,94,0,217,255,255,255, + 137,0,0,0,0,43,255,255,255,255,44,0,0,226,255,255,255,255,255,255, + 255,255,255,255,255,255,255,8,0,0,0,252,255,255,255,120,0,0,0,0, + 0,0,252,255,255,255,94,0,0,0,7,255,255,255,255,55,0,0,0,0, + 0,0,1,61,133,192,244,255,255,255,255,255,253,38,0,0,226,255,255,255, + 255,255,255,255,255,255,255,255,255,255,8,0,0,152,255,255,255,152,0,0, + 0,0,0,0,32,255,255,255,255,20,0,0,0,32,255,255,255,255,20,0, + 0,0,252,255,255,255,86,0,0,0,0,91,255,255,255,255,9,0,0,204, + 255,255,255,255,255,255,255,245,221,169,82,1,0,0,0,0,252,255,255,255, + 255,255,255,222,35,0,0,0,0,0,0,217,255,255,255,138,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,231,255,255,255,115,0,0,0,0,20,255, + 255,255,255,44,0,0,0,252,255,255,255,56,0,0,0,152,255,255,255,152, + 0,0,0,0,0,0,0,252,255,255,255,63,0,0,0,1,255,255,255,255, + 56,0,0,32,255,255,255,255,21,0,0,0,39,255,255,255,255,20,0,0, + 0,252,255,255,255,63,0,0,0,0,68,255,255,255,255,23,0,0,0,0, + 0,0,0,0,0,0,242,255,255,255,114,0,0,0,0,0,0,0,0,0, + 0,243,255,255,255,111,0,0,0,0,0,240,255,255,255,110,0,0,255,255, + 255,255,62,0,0,0,144,255,255,255,175,0,0,0,27,255,255,255,255,28, + 0,0,0,97,255,255,54,0,0,0,0,0,204,255,255,255,124,0,2,226, + 255,255,255,255,200,0,0,152,255,255,255,172,0,0,0,28,219,255,255,255, + 255,255,255,255,255,255,255,255,79,0,0,0,252,255,255,255,80,0,0,0, + 0,0,0,2,148,253,255,255,255,255,255,255,255,220,47,0,0,0,204,255, + 255,255,184,0,0,0,0,0,0,90,255,255,255,255,94,0,0,243,255,255, + 255,111,0,0,0,0,0,240,255,255,255,110,0,0,231,255,255,255,115,0, + 0,0,0,20,255,255,255,255,44,0,0,243,255,255,255,255,255,255,255,255, + 255,255,255,255,255,28,0,0,97,255,255,54,0,0,0,0,0,204,255,255, + 255,124,0,2,226,255,255,255,255,200,0,0,152,255,255,255,172,0,0,0, + 243,255,255,255,111,0,0,0,0,0,240,255,255,255,110,0,231,255,255,255, + 115,0,0,0,0,20,255,255,255,255,44,0,0,243,255,255,255,255,255,255, + 255,255,255,255,255,255,255,28,0,0,0,252,255,255,255,80,0,0,0,0, + 0,0,252,255,255,255,63,0,0,0,1,255,255,255,255,56,0,0,0,0, + 0,0,0,0,0,0,4,62,183,255,255,255,255,109,0,0,243,255,255,255, + 255,255,255,255,255,255,255,255,255,255,28,0,0,152,255,255,255,152,0,0, + 0,0,0,0,32,255,255,255,255,21,0,0,0,39,255,255,255,255,20,0, + 0,0,252,255,255,255,63,0,0,0,0,68,255,255,255,255,23,0,0,204, + 255,255,255,184,0,0,0,0,0,0,0,0,0,0,0,0,252,255,255,255, + 255,255,255,226,34,0,0,0,0,0,0,231,255,255,255,115,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,217,255,255,255,137,0,0,0,0,43,255, + 255,255,255,44,0,0,0,252,255,255,255,56,0,0,0,152,255,255,255,152, + 0,0,0,0,0,0,0,252,255,255,255,56,0,0,0,0,255,255,255,255, + 56,0,0,31,255,255,255,255,28,0,0,0,70,255,255,255,255,20,0,0, + 0,252,255,255,255,86,0,0,0,0,91,255,255,255,255,9,0,0,0,0, + 0,0,0,0,0,0,225,255,255,255,146,0,0,0,0,0,0,0,0,0, + 0,227,255,255,255,134,0,0,0,0,8,254,255,255,255,94,0,0,255,255, + 255,255,56,0,0,0,144,255,255,255,168,0,0,0,28,255,255,255,255,28, + 0,0,0,176,255,230,1,0,0,0,0,0,204,255,255,255,124,0,0,126, + 255,255,255,255,97,0,0,152,255,255,255,172,0,0,0,167,255,255,255,255, + 255,255,255,255,255,255,255,255,80,0,0,0,252,255,255,255,57,0,0,0, + 0,0,0,0,0,30,107,157,193,225,254,255,255,255,211,0,0,0,204,255, + 255,255,184,0,0,0,0,0,1,199,255,255,255,252,26,0,0,227,255,255, + 255,134,0,0,0,0,8,254,255,255,255,94,0,0,217,255,255,255,137,0, + 0,0,0,43,255,255,255,255,44,0,0,226,255,255,255,255,255,255,255,255, + 255,255,255,255,255,32,0,0,176,255,230,1,0,0,0,0,0,204,255,255, + 255,124,0,0,126,255,255,255,255,97,0,0,152,255,255,255,172,0,0,0, + 227,255,255,255,134,0,0,0,0,8,254,255,255,255,94,0,217,255,255,255, + 137,0,0,0,0,43,255,255,255,255,44,0,0,226,255,255,255,255,255,255, + 255,255,255,255,255,255,255,32,0,0,0,252,255,255,255,57,0,0,0,0, + 0,0,252,255,255,255,56,0,0,0,0,255,255,255,255,56,0,0,0,0, + 0,0,0,0,0,0,0,0,6,236,255,255,255,130,0,0,226,255,255,255, + 255,255,255,255,255,255,255,255,255,255,32,0,0,152,255,255,255,152,0,0, + 0,0,0,0,31,255,255,255,255,28,0,0,0,70,255,255,255,255,20,0, + 0,0,252,255,255,255,86,0,0,0,0,91,255,255,255,255,9,0,0,204, + 255,255,255,184,0,0,0,0,0,0,0,0,0,0,0,0,252,255,255,255, + 234,255,255,255,224,31,0,0,0,0,0,217,255,255,255,137,0,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,172,255,255,255,211,1,0,0,0,125,255, + 255,255,255,44,0,0,0,252,255,255,255,56,0,0,0,150,255,255,255,156, + 0,0,0,0,0,0,0,252,255,255,255,56,0,0,0,0,255,255,255,255, + 56,0,0,20,255,255,255,255,57,0,0,0,159,255,255,255,255,20,0,0, + 0,252,255,255,255,163,0,0,0,0,168,255,255,255,220,0,0,0,140,255, + 255,255,172,0,0,0,175,255,255,255,234,20,0,0,0,0,0,0,0,0, + 0,178,255,255,255,212,1,0,0,0,86,255,255,255,255,44,0,0,255,255, + 255,255,56,0,0,0,144,255,255,255,168,0,0,0,28,255,255,255,255,28, + 0,0,9,245,255,152,0,0,0,0,0,0,204,255,255,255,124,0,0,27, + 252,255,255,240,10,0,0,152,255,255,255,172,0,0,0,233,255,255,255,159, + 34,6,0,8,247,255,255,255,80,0,0,0,252,255,255,255,56,0,0,0, + 0,0,0,0,0,0,0,0,0,0,31,238,255,255,255,24,0,0,204,255, + 255,255,184,0,0,0,0,0,137,255,255,255,255,163,0,0,0,178,255,255, + 255,212,1,0,0,0,86,255,255,255,255,44,0,0,172,255,255,255,211,1, + 0,0,0,125,255,255,255,255,44,0,0,177,255,255,255,131,0,0,0,0, + 0,0,0,0,0,0,0,9,245,255,152,0,0,0,0,0,0,204,255,255, + 255,124,0,0,27,252,255,255,240,10,0,0,152,255,255,255,172,0,0,0, + 178,255,255,255,212,1,0,0,0,86,255,255,255,255,44,0,173,255,255,255, + 212,1,0,0,0,120,255,255,255,255,44,0,0,177,255,255,255,131,0,0, + 0,0,0,0,0,0,0,0,0,0,0,252,255,255,255,56,0,0,0,0, + 0,0,252,255,255,255,56,0,0,0,0,255,255,255,255,56,0,0,0,30, + 170,39,0,0,0,0,0,0,1,234,255,255,255,113,0,0,177,255,255,255, + 131,0,0,0,0,0,0,0,0,0,0,0,0,150,255,255,255,156,0,0, + 0,0,0,0,20,255,255,255,255,57,0,0,0,159,255,255,255,255,20,0, + 0,0,252,255,255,255,163,0,0,0,0,168,255,255,255,220,0,0,0,204, + 255,255,255,184,0,0,0,0,0,0,0,0,0,0,0,0,252,255,255,255, + 75,213,255,255,255,222,30,0,0,0,0,172,255,255,255,211,1,0,0,0, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,88,255,255,255,255,155,32,17,96,245,255, + 255,255,255,44,0,0,0,252,255,255,255,56,0,0,0,134,255,255,255,215, + 30,1,0,0,0,0,0,252,255,255,255,56,0,0,0,0,255,255,255,255, + 56,0,0,1,240,255,255,255,192,33,23,121,253,255,255,255,255,20,0,0, + 0,252,255,255,255,253,120,23,24,121,253,255,255,255,138,0,0,0,140,255, + 255,255,172,0,0,0,79,255,255,255,255,213,78,23,13,47,123,137,0,0, + 0,86,255,255,255,255,160,35,14,77,232,255,255,255,208,0,0,0,255,255, + 255,255,56,0,0,0,144,255,255,255,168,0,0,0,28,255,255,255,255,28, + 0,0,78,255,255,73,0,0,0,0,0,0,204,255,255,255,124,0,0,0, + 176,255,255,147,0,0,0,152,255,255,255,172,0,0,0,237,255,255,255,147, + 19,7,49,180,255,255,255,255,80,0,0,0,252,255,255,255,56,0,0,0, + 0,0,0,131,175,100,52,28,6,14,80,249,255,255,255,28,0,0,204,255, + 255,255,184,0,4,24,82,192,255,255,255,255,231,27,0,0,0,86,255,255, + 255,255,160,35,14,77,232,255,255,255,208,0,0,0,88,255,255,255,255,155, + 32,17,96,245,255,255,255,255,44,0,0,83,255,255,255,251,126,38,9,13, + 36,63,121,188,119,0,0,78,255,255,73,0,0,0,0,0,0,204,255,255, + 255,124,0,0,0,176,255,255,147,0,0,0,152,255,255,255,172,0,0,0, + 86,255,255,255,255,160,35,14,77,232,255,255,255,208,0,0,90,255,255,255, + 255,155,32,16,92,243,255,255,255,255,44,0,0,83,255,255,255,251,126,38, + 9,13,36,63,121,188,119,0,0,0,0,252,255,255,255,56,0,0,0,0, + 0,0,252,255,255,255,56,0,0,0,0,255,255,255,255,56,0,0,0,32, + 255,254,189,103,43,13,9,45,166,255,255,255,255,56,0,0,83,255,255,255, + 251,126,38,9,13,36,63,121,188,119,0,0,0,134,255,255,255,215,30,1, + 0,0,0,0,1,240,255,255,255,192,33,23,121,253,255,255,255,255,20,0, + 0,0,252,255,255,255,253,120,23,24,121,253,255,255,255,138,0,0,0,204, + 255,255,255,184,0,0,0,0,0,0,0,0,0,0,0,0,252,255,255,255, + 56,26,221,255,255,255,220,28,0,0,0,88,255,255,255,255,155,32,17,96, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,4,206,255,255,255,255,255,255,255,255,255, + 255,255,255,44,0,0,0,252,255,255,255,56,0,0,0,85,255,255,255,255, + 255,255,255,144,0,0,0,252,255,255,255,56,0,0,0,0,255,255,255,255, + 56,0,0,0,162,255,255,255,255,255,255,255,255,255,255,255,255,20,0,0, + 0,252,255,255,255,255,255,255,255,255,255,255,255,237,24,0,0,0,140,255, + 255,255,172,0,0,0,0,172,255,255,255,255,255,255,255,255,255,160,0,0, + 0,1,186,255,255,255,255,255,255,255,255,255,255,249,60,0,0,0,255,255, + 255,255,56,0,0,0,144,255,255,255,168,0,0,0,28,255,255,255,255,28, + 0,0,157,255,243,7,0,0,0,0,0,0,204,255,255,255,124,0,0,0, + 0,0,0,0,0,0,0,152,255,255,255,172,0,0,0,176,255,255,255,255, + 255,255,255,255,255,255,255,255,80,0,0,0,252,255,255,255,56,0,0,0, + 0,0,0,144,255,255,255,255,255,255,255,255,255,255,223,1,0,0,204,255, + 255,255,255,255,255,255,255,255,255,255,255,233,54,0,0,0,0,1,186,255, + 255,255,255,255,255,255,255,255,255,249,60,0,0,0,4,206,255,255,255,255, + 255,255,255,255,255,255,255,255,44,0,0,0,180,255,255,255,255,255,255,255, + 255,255,255,255,128,0,0,157,255,243,7,0,0,0,0,0,0,204,255,255, + 255,124,0,0,0,0,0,0,0,0,0,0,152,255,255,255,172,0,0,0, + 1,186,255,255,255,255,255,255,255,255,255,255,249,60,0,0,5,208,255,255, + 255,255,255,255,255,255,255,255,255,255,44,0,0,0,180,255,255,255,255,255, + 255,255,255,255,255,255,128,0,0,0,0,252,255,255,255,56,0,0,0,0, + 0,0,252,255,255,255,56,0,0,0,0,255,255,255,255,56,0,0,0,32, + 255,255,255,255,255,255,255,255,255,255,255,255,196,0,0,0,0,180,255,255, + 255,255,255,255,255,255,255,255,255,128,0,0,0,85,255,255,255,255,255,255, + 255,144,0,0,0,162,255,255,255,255,255,255,255,255,255,255,255,255,20,0, + 0,0,252,255,255,255,255,255,255,255,255,255,255,255,237,24,0,0,0,204, + 255,255,255,184,0,0,0,0,0,0,0,0,0,0,0,0,252,255,255,255, + 56,0,32,228,255,255,255,218,26,0,0,4,206,255,255,255,255,255,255,255, + 0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,34,224,255,255,255,255,255,254,125,255, + 255,255,255,43,0,0,0,252,255,255,255,56,0,0,0,8,219,255,255,255, + 255,255,255,144,0,0,0,252,255,255,255,56,0,0,0,0,255,255,255,255, + 56,0,0,0,31,234,255,255,255,255,255,249,121,255,255,255,255,20,0,0, + 0,252,255,255,255,132,247,255,255,255,255,255,244,65,0,0,0,0,140,255, + 255,255,172,0,0,0,0,7,154,255,255,255,255,255,255,255,255,160,0,0, + 0,0,13,175,255,255,255,255,255,255,255,255,237,75,0,0,0,0,255,255, + 255,255,56,0,0,0,144,255,255,255,168,0,0,0,28,255,255,255,255,28, + 0,2,233,255,171,0,0,0,0,0,0,0,204,255,255,255,124,0,0,0, + 0,0,0,0,0,0,0,152,255,255,255,172,0,0,0,39,237,255,255,255, + 255,255,255,147,236,255,255,255,80,0,0,0,252,255,255,255,56,0,0,0, + 0,0,0,144,255,255,255,255,255,255,255,255,255,243,66,0,0,0,204,255, + 255,255,255,255,255,255,255,255,255,254,180,26,0,0,0,0,0,0,13,175, + 255,255,255,255,255,255,255,255,237,75,0,0,0,0,0,34,224,255,255,255, + 255,255,254,125,255,255,255,255,43,0,0,0,10,164,255,255,255,255,255,255, + 255,255,255,255,128,0,2,233,255,171,0,0,0,0,0,0,0,204,255,255, + 255,124,0,0,0,0,0,0,0,0,0,0,152,255,255,255,172,0,0,0, + 0,13,175,255,255,255,255,255,255,255,255,237,75,0,0,0,0,36,226,255, + 255,255,255,255,254,124,255,255,255,255,44,0,0,0,10,164,255,255,255,255, + 255,255,255,255,255,255,128,0,0,0,0,252,255,255,255,56,0,0,0,0, + 0,0,252,255,255,255,56,0,0,0,0,255,255,255,255,56,0,0,0,27, + 250,255,255,255,255,255,255,255,255,255,255,207,25,0,0,0,0,10,164,255, + 255,255,255,255,255,255,255,255,255,128,0,0,0,8,219,255,255,255,255,255, + 255,144,0,0,0,31,234,255,255,255,255,255,249,121,255,255,255,255,20,0, + 0,0,252,255,255,255,132,247,255,255,255,255,255,244,65,0,0,0,0,204, + 255,255,255,184,0,0,0,0,0,0,0,0,0,0,0,0,252,255,255,255, + 56,0,0,40,234,255,255,255,216,24,0,0,34,224,255,255,255,255,255,254, + 0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,17,139,221,249,234,176,59,42,255, + 255,255,255,28,0,0,0,252,255,255,255,56,0,0,0,0,25,153,223,249, + 255,255,255,144,0,0,0,252,255,255,255,56,0,0,0,0,255,255,255,255, + 56,0,0,0,0,32,160,230,250,230,161,39,32,255,255,255,255,20,0,0, + 0,252,255,255,255,56,38,160,228,250,230,161,36,0,0,0,0,0,140,255, + 255,255,172,0,0,0,0,0,0,47,145,205,239,250,228,191,109,18,0,0, + 0,0,0,0,66,160,217,243,251,234,192,118,18,0,0,0,0,0,255,255, + 255,255,56,0,0,0,144,255,255,255,168,0,0,0,28,255,255,255,255,28, + 0,59,255,255,92,0,0,0,0,0,0,0,204,255,255,255,124,0,0,0, + 0,0,0,0,0,0,0,152,255,255,255,172,0,0,0,0,30,156,228,251, + 237,188,82,0,236,255,255,255,80,0,0,0,252,255,255,255,56,0,0,0, + 0,0,0,10,71,139,195,221,244,251,236,199,132,28,0,0,0,0,204,255, + 255,255,255,253,248,235,215,181,129,40,0,0,0,0,0,0,0,0,0,0, + 66,160,217,243,251,234,192,118,18,0,0,0,0,0,0,0,17,139,221,249, + 234,176,59,42,255,255,255,255,28,0,0,0,0,0,54,150,208,240,251,236, + 214,187,129,65,8,0,59,255,255,92,0,0,0,0,0,0,0,204,255,255, + 255,124,0,0,0,0,0,0,0,0,0,0,152,255,255,255,172,0,0,0, + 0,0,0,66,160,217,243,251,234,192,118,18,0,0,0,0,0,0,18,140, + 221,249,234,176,59,12,255,255,255,255,44,0,0,0,0,0,54,150,208,240, + 251,236,214,187,129,65,8,0,0,0,0,252,255,255,255,56,0,0,0,0, + 0,0,252,255,255,255,56,0,0,0,0,255,255,255,255,56,0,0,0,0, + 14,84,144,192,225,245,253,244,221,172,90,4,0,0,0,0,0,0,0,54, + 150,208,240,251,236,214,187,129,65,8,0,0,0,0,25,153,223,249,255,255, + 255,144,0,0,0,0,32,160,230,250,230,161,39,32,255,255,255,255,20,0, + 0,0,252,255,255,255,56,38,160,228,250,230,161,36,0,0,0,0,0,204, + 255,255,255,184,0,0,0,0,0,0,0,0,0,0,0,0,252,255,255,255, + 56,0,0,0,49,240,255,255,255,214,22,0,0,17,139,221,249,234,176,59, + 0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,255, + 255,255,241,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,138,255,251,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,127,255,255,255,241,4,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,138,255,251,18,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,252,255,255,255,56,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,75,183,95,44,14,6,38,126,251,255, + 255,255,159,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,217,255,191,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,75,183,95,44,14, + 6,38,126,251,255,255,255,159,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,217,255,191,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,252,255,255,255,56,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,75,183,95,44,14,6,38,126, + 0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,80,255,255,255,255,255,255,255,255,255, + 255,234,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,255,255,255,255, + 255,255,255,255,255,255,234,28,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,252,255,255,255,56,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,80,255,255,255,255,255,255,255, + 0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,80,255,255,255,255,255,255,255,255,255, + 210,43,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,255,255,255,255, + 255,255,255,255,255,210,43,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,252,255,255,255,56,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,80,255,255,255,255,255,255,255, + 0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,4,68,151,206,233,251,241,214,164,82, + 4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,68,151,206,233, + 251,241,214,164,82,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,252,255,255,255,56,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,4,68,151,206,233,251,241,214, + 0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; diff --git a/Library/ModernUiLvglRendererLib/OemWatermarkData.h b/Library/ModernUiLvglRendererLib/OemWatermarkData.h new file mode 100644 index 0000000..ce73564 --- /dev/null +++ b/Library/ModernUiLvglRendererLib/OemWatermarkData.h @@ -0,0 +1,22 @@ +/** @file + Generated OEM watermark alpha coverage map. DO NOT EDIT. + Regenerate via Scripts/gen-oem-watermark.py. + + Copyright (c) 2026, MarsDoge. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef OEM_WATERMARK_DATA_H_ +#define OEM_WATERMARK_DATA_H_ + +#include + +#define OEM_WATERMARK_WIDTH 620 +#define OEM_WATERMARK_HEIGHT 92 + +// +// Row-major 8-bit alpha coverage (0 = transparent, 255 = solid). +// +extern CONST UINT8 gOemWatermarkAlpha[OEM_WATERMARK_WIDTH * OEM_WATERMARK_HEIGHT]; + +#endif // OEM_WATERMARK_DATA_H_ diff --git a/Library/ModernUiRendererLib/ModernUiRendererCommon.c b/Library/ModernUiRendererLib/ModernUiRendererCommon.c index 8509fe5..e816457 100644 --- a/Library/ModernUiRendererLib/ModernUiRendererCommon.c +++ b/Library/ModernUiRendererLib/ModernUiRendererCommon.c @@ -824,7 +824,13 @@ ModernUiGetSelectableRowBackground ( } if (Selected) { - RowColor = ModernUiBlendColor (Theme->BackgroundBlack, Theme->SelectedBand, 74); + // + // A clean, subtle warm-tinted selection fill over the normal surface -- + // distinct enough to read as selected, but far less muddy than the older + // heavy SelectedBand band. This is the single source for both the row fill + // and the per-cell text anti-alias background, so they stay matched. + // + RowColor = ModernUiBlendColor (Theme->Surface, Theme->AccentYellow, 30); } else if (Action || Subtitle) { RowColor = Theme->SurfaceRaised; } else { @@ -883,58 +889,17 @@ ModernUiDrawSelectableRow ( } if (Selected && (Rect.Width > 6) && (Rect.Height > 4)) { - if ((Rect.Width > 10) && (Rect.Height > 8)) { - Status = ModernUiFillRect ( - Context, - (MODERN_UI_RECT){ Rect.X + 6, Rect.Y + 3, Rect.Width - 6, Rect.Height - 6 }, - ModernUiBlendColor (RowColor, Theme->AccentOrange, 18) - ); - if (EFI_ERROR (Status)) { - return Status; - } - } - - Status = ModernUiFillRect ( - Context, - (MODERN_UI_RECT){ Rect.X, Rect.Y, Rect.Width, 2 }, - ModernUiBlendColor (Theme->AccentYellow, Theme->AccentOrange, 45) - ); - if (EFI_ERROR (Status)) { - return Status; - } - - Status = ModernUiFillRect ( - Context, - (MODERN_UI_RECT){ Rect.X, Rect.Y + Rect.Height - 3, Rect.Width, 2 }, - ModernUiBlendColor (Theme->AccentOrange, Theme->SelectedBand, 35) - ); - if (EFI_ERROR (Status)) { - return Status; - } - - Status = ModernUiFillRect ( - Context, - (MODERN_UI_RECT){ Rect.X, Rect.Y + 2, 7, Rect.Height - 4 }, - Theme->AccentYellow - ); - if (EFI_ERROR (Status)) { - return Status; - } - - if (Rect.Width > 20) { - Status = ModernUiStrokeRect (Context, Rect, Theme->PopupBorder); - if (EFI_ERROR (Status)) { - return Status; - } - - return ModernUiFillRect ( - Context, - (MODERN_UI_RECT){ Rect.X + 8, Rect.Y + 2, Rect.Width - 8, 1 }, - ModernUiBlendColor (Theme->AccentYellow, Theme->AccentOrange, 45) - ); - } - - return EFI_SUCCESS; + // + // The row is already filled with the subtle warm-tinted selection color. + // Add a single solid left accent stripe as the "selected" marker. This + // replaces an older multi-layer treatment (inset blend + top/bottom sheens + + // framed border + inner highlight line) that read busy and muddy. + // + return ModernUiFillRect ( + Context, + (MODERN_UI_RECT){ Rect.X, Rect.Y + 1, 6, (Rect.Height > 2) ? (Rect.Height - 2) : Rect.Height }, + Theme->AccentYellow + ); } if (Subtitle && (Rect.Width > 6)) { @@ -1046,6 +1011,123 @@ ModernUiDrawValueBox ( ); } +/** + Draw a bordered value field (no drop-down arrow) with inset text. + + See the contract on ModernUiDrawFieldBox in ModernUiRenderer.h. + + @param[in] Context Initialized render context. Must not be NULL. + @param[in] Rect Field rectangle. + @param[in] Value Field text. Must not be NULL. + @param[in] Selected TRUE when the owning row is selected. + @param[in] Theme Theme token table. Must not be NULL. + + @retval EFI_SUCCESS Field was drawn. + @retval EFI_INVALID_PARAMETER Context, Value, or Theme is NULL, or Rect empty. + @retval others Status returned by text rendering. +**/ +EFI_STATUS +EFIAPI +ModernUiDrawFieldBox ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + EFI_STATUS Status; + + if ((Context == NULL) || (Value == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) { + return EFI_INVALID_PARAMETER; + } + + Status = ModernUiFillRect (Context, Rect, Selected ? Theme->SelectedBand : Theme->Surface); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = ModernUiStrokeRect (Context, Rect, Selected ? Theme->PopupBorder : Theme->Border); + if (EFI_ERROR (Status)) { + return Status; + } + + return ModernUiDrawTextFit ( + Context, + Rect.X + 16, + Rect.Y + ((Rect.Height > 18) ? ((Rect.Height - 18) / 2) : 0), + (Rect.Width > 24) ? (Rect.Width - 24) : Rect.Width, + Value, + Theme->Text, + Selected ? Theme->SelectedBand : Theme->Surface + ); +} + +/** + Normalize an ordered-list value string into a single-line, separator-joined form. + + See the contract on ModernUiNormalizeOrderedListText in ModernUiRendererInternal.h. +**/ +VOID +ModernUiNormalizeOrderedListText ( + OUT CHAR16 *Dst, + IN UINTN Cap, + IN CONST CHAR16 *Src + ) +{ + UINTN SrcIdx; + UINTN DstIdx; + BOOLEAN PendingSep; + CHAR16 Ch; + + if ((Dst == NULL) || (Cap == 0)) { + return; + } + + DstIdx = 0; + PendingSep = FALSE; + if (Src != NULL) { + for (SrcIdx = 0; (Src[SrcIdx] != CHAR_NULL) && (DstIdx < (Cap - 1)); SrcIdx++) { + Ch = Src[SrcIdx]; + + // + // Drop NARROW_CHAR/WIDE_CHAR glyph-width markers (layout hints, not text). + // + if (Ch >= 0xFFF0) { + continue; + } + + // + // Collapse each run of CR/LF separators into one " / "; defer emitting it so a + // leading run (DstIdx == 0) and the trailing run (no further printable text) are + // dropped rather than shown as stray separators. + // + if ((Ch == CHAR_CARRIAGE_RETURN) || (Ch == CHAR_LINEFEED)) { + if (DstIdx > 0) { + PendingSep = TRUE; + } + + continue; + } + + if (PendingSep) { + PendingSep = FALSE; + if (DstIdx < (Cap - 4)) { + Dst[DstIdx++] = L' '; + Dst[DstIdx++] = L'/'; + Dst[DstIdx++] = L' '; + } else { + break; + } + } + + Dst[DstIdx++] = Ch; + } + } + + Dst[DstIdx] = CHAR_NULL; +} + /** Draw a drop-down list frame. diff --git a/Library/ModernUiRendererLib/ModernUiRendererInternal.h b/Library/ModernUiRendererLib/ModernUiRendererInternal.h index 2ef7492..4b5499a 100644 --- a/Library/ModernUiRendererLib/ModernUiRendererInternal.h +++ b/Library/ModernUiRendererLib/ModernUiRendererInternal.h @@ -92,4 +92,26 @@ ModernUiDrawTextModeGraphicGlyph ( IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background ); +/** + Normalize an ordered-list value string into a single-line, separator-joined form. + + FormBrowser builds an ordered-list value as a sequence of options each followed by a + CHAR_CARRIAGE_RETURN (and may embed NARROW_CHAR/WIDE_CHAR glyph-width markers). A + carriage return is below 0x20, so it would render as '?' through the ASCII label path, + and the markers are layout hints, not text. This copies Src to Dst while stripping + glyph-width markers (>= 0xFFF0), collapsing each run of CR/LF into a single " / " + separator, and dropping any leading/trailing separator, so the value reads as + "
/ / " on one line. Shared by both renderer backends' ordered-list path. + + @param[out] Dst Destination buffer. Must not be NULL. Always NUL-terminated. + @param[in] Cap Number of CHAR16 entries in Dst. Must be at least 1. + @param[in] Src Source value string. NULL yields an empty result. +**/ +VOID +ModernUiNormalizeOrderedListText ( + OUT CHAR16 *Dst, + IN UINTN Cap, + IN CONST CHAR16 *Src + ); + #endif // MODERN_UI_RENDERER_INTERNAL_H_ diff --git a/Library/ModernUiRendererLib/ModernUiRendererLib.c b/Library/ModernUiRendererLib/ModernUiRendererLib.c index 5f5b4a5..6fbce28 100644 --- a/Library/ModernUiRendererLib/ModernUiRendererLib.c +++ b/Library/ModernUiRendererLib/ModernUiRendererLib.c @@ -379,3 +379,174 @@ ModernUiDrawText ( return ReturnStatus; } + +/** + GOP one-of renderer: compose the closed drop-down from primitives. + + The GOP backend has no widget toolkit, so the best available drop-down is the + shared themed value box, which already paints a bordered field, the selected + option text, and a right-aligned chevron. Display-only; see the contract on + ModernUiRenderOneOf in ModernUiRenderer.h. + + @param[in] Context Initialized render context. Must not be NULL. + @param[in] Rect Control rectangle. + @param[in] Value Selected option text. Must not be NULL. + @param[in] Selected TRUE when the owning row is selected. + @param[in] Theme Theme token table. Must not be NULL. + + @retval others Status from ModernUiDrawValueBox. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderOneOf ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + return ModernUiDrawValueBox (Context, Rect, Value, Selected, Theme); +} + +/** + GOP checkbox renderer: a bordered field with the value text. + + See ModernUiRenderCheckbox in ModernUiRenderer.h. The GOP backend has no widget + toolkit, so the best available rendering is the arrow-less field box. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderCheckbox ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + return ModernUiDrawFieldBox (Context, Rect, Value, Selected, Theme); +} + +/** + GOP string renderer: a bordered field with the value text. + + See ModernUiRenderString in ModernUiRenderer.h. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderString ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + return ModernUiDrawFieldBox (Context, Rect, Value, Selected, Theme); +} + +/** + GOP password renderer: a bordered field with the (already masked) value text. + + See ModernUiRenderPassword in ModernUiRenderer.h. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderPassword ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + return ModernUiDrawFieldBox (Context, Rect, Value, Selected, Theme); +} + +/** + GOP numeric renderer: a bordered field with the value text. + + See ModernUiRenderNumeric in ModernUiRenderer.h. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderNumeric ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + return ModernUiDrawFieldBox (Context, Rect, Value, Selected, Theme); +} + +/** + GOP ordered-list renderer: a bordered field with the current option order. + + See ModernUiRenderOrderedList in ModernUiRenderer.h. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderOrderedList ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + CHAR16 Norm[160]; + + if (Value == NULL) { + return ModernUiDrawFieldBox (Context, Rect, Value, Selected, Theme); + } + + // + // Join the CR-separated option order onto one line so it reads as a sequence + // instead of showing the raw separators (see ModernUiNormalizeOrderedListText). + // + ModernUiNormalizeOrderedListText (Norm, ARRAY_SIZE (Norm), Value); + return ModernUiDrawFieldBox (Context, Rect, Norm, Selected, Theme); +} + +/** + GOP date/time renderer: a bordered field with the value text. + + See ModernUiRenderDateTime in ModernUiRenderer.h. +**/ +EFI_STATUS +EFIAPI +ModernUiRenderDateTime ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Rect, + IN CONST CHAR16 *Value, + IN BOOLEAN Selected, + IN CONST MODERN_UI_THEME *Theme + ) +{ + return ModernUiDrawFieldBox (Context, Rect, Value, Selected, Theme); +} + +/** + GOP OEM watermark: currently a no-op. + + The watermark needs per-pixel alpha compositing, which the GOP backend does not + yet expose; a primitive-composite implementation is a follow-up. See + ModernUiDrawOemWatermark in ModernUiRenderer.h. +**/ +EFI_STATUS +EFIAPI +ModernUiDrawOemWatermark ( + IN MODERN_UI_RENDER_CONTEXT *Context, + IN MODERN_UI_RECT Region, + IN CONST MODERN_UI_THEME *Theme + ) +{ + if ((Context == NULL) || (Theme == NULL)) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} diff --git a/Library/ModernUiStringLib/ModernUiStringLib.inf b/Library/ModernUiStringLib/ModernUiStringLib.inf index 0b30f49..af138ef 100644 --- a/Library/ModernUiStringLib/ModernUiStringLib.inf +++ b/Library/ModernUiStringLib/ModernUiStringLib.inf @@ -14,7 +14,7 @@ FILE_GUID = 08F6E245-48C6-4A5F-A8E2-9B4A42D870E0 MODULE_TYPE = UEFI_APPLICATION VERSION_STRING = 0.1 - LIBRARY_CLASS = ModernUiStringLib|UEFI_APPLICATION + LIBRARY_CLASS = ModernUiStringLib|UEFI_APPLICATION DXE_DRIVER [Sources] ModernUiStringLib.c diff --git a/Scripts/build-armvirt.sh b/Scripts/build-armvirt.sh index eaa32c5..4cdfad0 100755 --- a/Scripts/build-armvirt.sh +++ b/Scripts/build-armvirt.sh @@ -80,6 +80,7 @@ driver_sample_fdf_inf = " INF MdeModulePkg/Universal/DriverSampleDxe/DriverSamp library_block = """ ModernUiEngineLib|ModernSetupPkg/Library/ModernUiEngineLib/ModernUiEngineLib.inf ModernUiRendererLib|ModernSetupPkg/Library/ModernUiRendererLib/ModernUiRendererLib.inf ModernUiThemeLib|ModernSetupPkg/Library/ModernUiThemeLib/ModernUiThemeLib.inf + ModernUiStringLib|ModernSetupPkg/Library/ModernUiStringLib/ModernUiStringLib.inf """ app_library_block = """ ModernUiPlatformDataLib|ModernSetupPkg/Library/ModernUiPlatformDataLib/ModernUiPlatformDataLib.inf ModernUiBootDataLib|ModernSetupPkg/Library/ModernUiBootDataLib/ModernUiBootDataLib.inf @@ -95,7 +96,6 @@ app_library_block = """ ModernUiPlatformDataLib|ModernSetupPkg/Library/ModernUi ModernUiPcieDataLib|ModernSetupPkg/Library/ModernUiPcieDataLib/ModernUiPcieDataLib.inf ModernUiInputLib|ModernSetupPkg/Library/ModernUiInputLib/ModernUiInputLib.inf ModernUiPreferencesLib|ModernSetupPkg/Library/ModernUiPreferencesLib/ModernUiPreferencesLib.inf - ModernUiStringLib|ModernSetupPkg/Library/ModernUiStringLib/ModernUiStringLib.inf """ def replace_regex_once(text: str, pattern: str, replacement: str, description: str) -> str: diff --git a/Scripts/build-loongarchvirt.sh b/Scripts/build-loongarchvirt.sh index f6a13e0..1e9ce38 100755 --- a/Scripts/build-loongarchvirt.sh +++ b/Scripts/build-loongarchvirt.sh @@ -145,6 +145,7 @@ library_block = ( " ModernUiEngineLib|ModernSetupPkg/Library/ModernUiEngineLib/ModernUiEngineLib.inf\n" f" ModernUiRendererLib|{renderer_inf}\n" " ModernUiThemeLib|ModernSetupPkg/Library/ModernUiThemeLib/ModernUiThemeLib.inf\n" + " ModernUiStringLib|ModernSetupPkg/Library/ModernUiStringLib/ModernUiStringLib.inf\n" ) app_library_block = """ ModernUiPlatformDataLib|ModernSetupPkg/Library/ModernUiPlatformDataLib/ModernUiPlatformDataLib.inf ModernUiBootDataLib|ModernSetupPkg/Library/ModernUiBootDataLib/ModernUiBootDataLib.inf @@ -160,7 +161,6 @@ app_library_block = """ ModernUiPlatformDataLib|ModernSetupPkg/Library/ModernUi ModernUiPcieDataLib|ModernSetupPkg/Library/ModernUiPcieDataLib/ModernUiPcieDataLib.inf ModernUiInputLib|ModernSetupPkg/Library/ModernUiInputLib/ModernUiInputLib.inf ModernUiPreferencesLib|ModernSetupPkg/Library/ModernUiPreferencesLib/ModernUiPreferencesLib.inf - ModernUiStringLib|ModernSetupPkg/Library/ModernUiStringLib/ModernUiStringLib.inf """ dsc_path = workspace / "OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc" diff --git a/Scripts/build-ovmf-x64.sh b/Scripts/build-ovmf-x64.sh index eac2849..c51fcd2 100755 --- a/Scripts/build-ovmf-x64.sh +++ b/Scripts/build-ovmf-x64.sh @@ -132,6 +132,7 @@ library_block = ( " ModernUiEngineLib|ModernSetupPkg/Library/ModernUiEngineLib/ModernUiEngineLib.inf\n" f" ModernUiRendererLib|{renderer_inf}\n" " ModernUiThemeLib|ModernSetupPkg/Library/ModernUiThemeLib/ModernUiThemeLib.inf\n" + " ModernUiStringLib|ModernSetupPkg/Library/ModernUiStringLib/ModernUiStringLib.inf\n" ) app_library_block = """ ModernUiPlatformDataLib|ModernSetupPkg/Library/ModernUiPlatformDataLib/ModernUiPlatformDataLib.inf ModernUiBootDataLib|ModernSetupPkg/Library/ModernUiBootDataLib/ModernUiBootDataLib.inf @@ -147,7 +148,6 @@ app_library_block = """ ModernUiPlatformDataLib|ModernSetupPkg/Library/ModernUi ModernUiPcieDataLib|ModernSetupPkg/Library/ModernUiPcieDataLib/ModernUiPcieDataLib.inf ModernUiInputLib|ModernSetupPkg/Library/ModernUiInputLib/ModernUiInputLib.inf ModernUiPreferencesLib|ModernSetupPkg/Library/ModernUiPreferencesLib/ModernUiPreferencesLib.inf - ModernUiStringLib|ModernSetupPkg/Library/ModernUiStringLib/ModernUiStringLib.inf """ def replace_once(text: str, old: str, new: str, description: str) -> str: diff --git a/Scripts/build-riscvvirt.sh b/Scripts/build-riscvvirt.sh index 16b3bb9..53afd1f 100755 --- a/Scripts/build-riscvvirt.sh +++ b/Scripts/build-riscvvirt.sh @@ -85,6 +85,7 @@ boot_manager_menu_fdf_inf = "INF MdeModulePkg/Application/BootManagerMenuApp/Bo library_block = """ ModernUiEngineLib|ModernSetupPkg/Library/ModernUiEngineLib/ModernUiEngineLib.inf ModernUiRendererLib|ModernSetupPkg/Library/ModernUiRendererLib/ModernUiRendererLib.inf ModernUiThemeLib|ModernSetupPkg/Library/ModernUiThemeLib/ModernUiThemeLib.inf + ModernUiStringLib|ModernSetupPkg/Library/ModernUiStringLib/ModernUiStringLib.inf """ app_library_block = """ ModernUiPlatformDataLib|ModernSetupPkg/Library/ModernUiPlatformDataLib/ModernUiPlatformDataLib.inf ModernUiBootDataLib|ModernSetupPkg/Library/ModernUiBootDataLib/ModernUiBootDataLib.inf @@ -100,7 +101,6 @@ app_library_block = """ ModernUiPlatformDataLib|ModernSetupPkg/Library/ModernUi ModernUiPcieDataLib|ModernSetupPkg/Library/ModernUiPcieDataLib/ModernUiPcieDataLib.inf ModernUiInputLib|ModernSetupPkg/Library/ModernUiInputLib/ModernUiInputLib.inf ModernUiPreferencesLib|ModernSetupPkg/Library/ModernUiPreferencesLib/ModernUiPreferencesLib.inf - ModernUiStringLib|ModernSetupPkg/Library/ModernUiStringLib/ModernUiStringLib.inf """ def replace_regex_once(text: str, pattern: str, replacement: str, description: str) -> str: diff --git a/Scripts/gen-oem-watermark.py b/Scripts/gen-oem-watermark.py new file mode 100644 index 0000000..94ebf56 --- /dev/null +++ b/Scripts/gen-oem-watermark.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# Copyright (c) 2026, MarsDoge. All rights reserved. +# Author: MarsDoge (Dongyan Qian) +# Open source: https://github.com/MarsDoge/ModernSetupPkg +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# Rasterize the original OEM watermark (Assets/Branding/oem-watermark.svg content) +# into an 8-bit alpha coverage map and emit it as a C array the LVGL renderer wraps +# in an A8 lv_image. A8 keeps it tiny (1 byte/pixel) and lets the firmware tint it +# with the active theme color. We re-draw the (simple, monochrome) design with PIL +# because no SVG rasterizer is available here; the SVG remains the canonical source +# and the layout constants below mirror it. Regenerate with: +# +# python3 Scripts/gen-oem-watermark.py +# +# Ships NO third-party / IBV art -- 100% original geometry + the project URL text. + +import os +from PIL import Image, ImageDraw, ImageFont + +W, H = 620, 92 +PKG = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +OUT_DIR = os.path.join(PKG, "Library", "ModernUiLvglRendererLib") + +FONT_BOLD = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" +FONT_REG = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf" + +SUB_TEXT = "MODERN UEFI SETUP · OPEN SOURCE" +URL_TEXT = "github.com/MarsDoge/ModernSetupPkg" + + +def build_alpha() -> Image.Image: + img = Image.new("L", (W, H), 0) + d = ImageDraw.Draw(img) + + # Original brand mark: rounded panel + scan lines + a corner-cut accent. + d.rounded_rectangle([8, 16, 68, 76], radius=12, outline=255, width=3) + d.line([24, 34, 44, 34], fill=255, width=3) + d.line([24, 46, 52, 46], fill=255, width=3) + d.line([24, 58, 47, 58], fill=255, width=3) + d.line([52, 16, 68, 32], fill=255, width=3) + + sub = ImageFont.truetype(FONT_REG, 15) + url = ImageFont.truetype(FONT_BOLD, 24) + # Letter-spacing the sub-label by drawing char by char. + x = 88 + for ch in SUB_TEXT: + d.text((x, 20), ch, font=sub, fill=210) + x += d.textlength(ch, font=sub) + 2 + d.text((88, 46), URL_TEXT, font=url, fill=255) + return img + + +def emit_c(img: Image.Image) -> None: + data = img.tobytes() + assert len(data) == W * H + + h_path = os.path.join(OUT_DIR, "OemWatermarkData.h") + c_path = os.path.join(OUT_DIR, "OemWatermarkData.c") + + with open(h_path, "w") as f: + f.write("/** @file\n") + f.write(" Generated OEM watermark alpha coverage map. DO NOT EDIT.\n") + f.write(" Regenerate via Scripts/gen-oem-watermark.py.\n\n") + f.write(" Copyright (c) 2026, MarsDoge. All rights reserved.
\n") + f.write(" SPDX-License-Identifier: BSD-2-Clause-Patent\n**/\n\n") + f.write("#ifndef OEM_WATERMARK_DATA_H_\n#define OEM_WATERMARK_DATA_H_\n\n") + f.write("#include \n\n") + f.write(f"#define OEM_WATERMARK_WIDTH {W}\n") + f.write(f"#define OEM_WATERMARK_HEIGHT {H}\n\n") + f.write("//\n// Row-major 8-bit alpha coverage (0 = transparent, 255 = solid).\n//\n") + f.write("extern CONST UINT8 gOemWatermarkAlpha[OEM_WATERMARK_WIDTH * OEM_WATERMARK_HEIGHT];\n\n") + f.write("#endif // OEM_WATERMARK_DATA_H_\n") + + with open(c_path, "w") as f: + f.write("/** @file\n") + f.write(" Generated OEM watermark alpha coverage map. DO NOT EDIT.\n") + f.write(" Regenerate via Scripts/gen-oem-watermark.py.\n\n") + f.write(" Copyright (c) 2026, MarsDoge. All rights reserved.
\n") + f.write(" SPDX-License-Identifier: BSD-2-Clause-Patent\n**/\n\n") + f.write('#include "OemWatermarkData.h"\n\n') + f.write("CONST UINT8 gOemWatermarkAlpha[OEM_WATERMARK_WIDTH * OEM_WATERMARK_HEIGHT] = {\n") + for i in range(0, len(data), 20): + chunk = data[i:i + 20] + f.write(" " + ",".join(str(b) for b in chunk) + ",\n") + f.write("};\n") + + print(f"wrote {h_path}") + print(f"wrote {c_path} ({len(data)} bytes)") + + +if __name__ == "__main__": + emit_c(build_alpha()) diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.c b/Universal/ModernDisplayEngineDxe/FormDisplay.c index 8fafe54..621b93e 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.c +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.c @@ -2523,6 +2523,22 @@ DisplayOneMenu ( } } + // + // Widget-mapped controls render as the backend's best widget over the value + // lane, using the option string FormBrowser just printed (still valid here, + // and Highlight not yet cleared). The function no-ops for unmapped opcodes; + // the cue overlay skips the affordance for the mapped ones. + // + ModernDisplayDrawValueWidget ( + Statement->OpCode->OpCode, + MenuOption->OptCol, + MenuOption->Row, + gOptionBlockWidth, + OptionString, + Highlight, + (BOOLEAN)(gUserInput->SelectedStatement == Statement) + ); + Highlight = FALSE; FreePool (OptionString); @@ -2680,6 +2696,7 @@ UiDisplayMenu ( UINTN Temp2; UINTN TopRow; UINTN BottomRow; + UINTN FirstEmptyRow; UINTN Index; CHAR16 *StringPtr; CHAR16 *StringRightPtr; @@ -2905,6 +2922,19 @@ UiDisplayMenu ( // // 3. Menus in this form may not cover all form, clean the remain field. // + // Reset to the normal field background first: the last drawn option may have + // left the highlight attribute set (when the highlighted statement is the last + // visible row, e.g. Reset on the front page), and the modern renderer paints the + // cleared empty rows with the current background. Without this reset that empty + // area below the menu is filled with the highlight band color. + // + // + // Remember where the empty area below the menu begins, so the OEM + // watermark overlay can be confined to genuine whitespace (and + // suppressed when the rows fill the content area). + // + FirstEmptyRow = Row; + gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ()); while (Row <= BottomRow) { if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) { PrintStringAtWithWidth (gStatementDimensions.LeftColumn + gModalSkipColumn, Row++, L"", gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn - 2 * gModalSkipColumn); @@ -2932,6 +2962,15 @@ UiDisplayMenu ( gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ()); } + // + // The content area (rows + empty-row clear above) has now been fully + // painted. Composite the OEM brand watermark on top of the cleared + // whitespace (from FirstEmptyRow down) so it is not wiped by the + // repaint and never lands on a statement row. Display-only no-op on + // backends that cannot host it or when the whitespace is too short. + // + ModernDisplayDrawOemWatermarkOverlay (FirstEmptyRow); + MenuOption = NULL; } @@ -3465,6 +3504,12 @@ UiDisplayMenu ( // Editable Questions: oneof, ordered list, checkbox, numeric, string, password // RefreshKeyHelp (gFormData, Statement, TRUE); + // + // Clear the composited value-lane widget before native editing so the + // in-place/popup editor starts on a clean field lane (the native + // initial draw is narrower than the widget and leaves remnants). + // + ModernDisplayClearValueLane (MenuOption->OptCol, MenuOption->Row, gOptionBlockWidth); Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE); if (OptionString != NULL) { diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.h b/Universal/ModernDisplayEngineDxe/FormDisplay.h index 317b52a..f4b9924 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.h +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.h @@ -129,6 +129,122 @@ ModernDisplayDrawStatementRowCue ( IN BOOLEAN Selected ); +/** + Draw the text-input edit caret at a text-grid cell through the Modern renderer. + + The native EFI_SIMPLE_TEXT_OUTPUT cursor draws straight to the GraphicsConsole + framebuffer and is invisible/misplaced when the Modern engine composites through + an off-screen canvas (e.g. the LVGL backend). `ReadString` suppresses that native + cursor and calls this instead, so the editing caret renders identically on every + backend. Paints a thin vertical bar at the cell; draws nothing (no error) when no + renderer is available. The caller redraws the field text each keystroke, which + erases the previous caret, so this only ever paints (never explicitly erases). + + @param[in] Column Text-grid column of the caret cell. + @param[in] Row Text-grid row of the caret cell. +**/ +VOID +EFIAPI +ModernDisplayDrawTextCaret ( + IN UINTN Column, + IN UINTN Row + ); + +/** + Overlay a control row's value lane with the backend's best widget. + + This is the in-setup half of the IFR-opcode -> LVGL-widget mapping. The native + FormBrowser prints the value as plain text in the value lane; `DisplayOneMenu` + calls this immediately afterwards (while the option string is still in scope) to + paint a real widget over that lane for the mapped opcodes -- one-of -> + `lv_dropdown`, checkbox -> `lv_checkbox`, string/password/numeric -> + `lv_textarea` on the LVGL backend, themed value/field boxes on GOP. Other + opcodes are a no-op (the cue overlay handles them). Display-only: edk2 still + owns selection/editing, ConfigAccess, and callbacks. The companion cue overlay + skips the affordance for the mapped opcodes, since the rendered control carries + its own. + + @param[in] OpCode IFR opcode of the statement (EFI_IFR_*_OP). + @param[in] Column Text-grid column where the value lane starts. + @param[in] Row Text-grid row of the statement. + @param[in] Width Text-grid column count of the value lane. + @param[in] ValueText Value text. May be NULL (then no-op). + @param[in] Highlight TRUE when the row currently has keyboard highlight. + @param[in] Selected TRUE when the row is in edit/selection mode. +**/ +VOID +EFIAPI +ModernDisplayDrawValueWidget ( + IN UINT8 OpCode, + IN UINTN Column, + IN UINTN Row, + IN UINTN Width, + IN CONST CHAR16 *ValueText OPTIONAL, + IN BOOLEAN Highlight, + IN BOOLEAN Selected + ); + +/** + Clear a statement's value lane to the field background before native editing. + + `DisplayOneMenu` composites a display-only widget over the value lane. When the + user activates the statement to edit it, native FormBrowser draws its editor + (in-place `[value]` for numeric/date/time, or a popup for string/password) over + that lane -- but the native initial draw is narrower than, and differently + colored from, the composited widget, leaving widget remnants beside/under the + editor. The form loop calls this just before entering the editor to repaint the + value lane to the plain field background (`Theme->Surface`, matching the color + native editing erases to), so the editor starts on a clean lane. The full form + repaint after editing restores the widget with the new value. No-op (no error) + when no renderer is available or the lane geometry is degenerate. + + @param[in] Column Text-grid column where the value lane starts. + @param[in] Row Text-grid row of the statement. + @param[in] Width Text-grid column count of the value lane. +**/ +VOID +EFIAPI +ModernDisplayClearValueLane ( + IN UINTN Column, + IN UINTN Row, + IN UINTN Width + ); + +/** + Composite the OEM brand watermark into the content-area whitespace. + + Called at the end of a full form repaint, after the statement rows and the + empty-row clear loop have painted the content area, so the (subtle, theme) + mark lands on top of the freshly cleared whitespace instead of being wiped by + it. The mark is confined to the empty band starting at FirstEmptyRow, so on a + form whose rows fill the content area it is suppressed (no tinting over a + statement row). Display-only; parses no HII and owns no FormBrowser state. + No-op (no error) on backends, or when the whitespace is too short for the mark. + + @param[in] FirstEmptyRow Text-grid row where the empty area below the menu + begins (the first row the clear loop blanks). +**/ +VOID +EFIAPI +ModernDisplayDrawOemWatermarkOverlay ( + IN UINTN FirstEmptyRow + ); + +/** + Forget any tracked selection-styled statement row. + + Call at popup entry: a popup prints its own EFI_RED-background text (e.g. a + highlighted selectable option) without re-running the statement-row draw, and + could share the grid row recorded for the form's selection styling. Resetting + here keeps the per-cell print path from suppressing that popup line's + background fill. Display-only; no FormBrowser state. +**/ +VOID +EFIAPI +ModernDisplayResetHighlightRowTracking ( + VOID + ); + // // Screen definitions // diff --git a/Universal/ModernDisplayEngineDxe/InputHandler.c b/Universal/ModernDisplayEngineDxe/InputHandler.c index 182842f..02b0f52 100644 --- a/Universal/ModernDisplayEngineDxe/InputHandler.c +++ b/Universal/ModernDisplayEngineDxe/InputHandler.c @@ -129,8 +129,14 @@ ReadString ( CreateMultiStringPopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter); gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); + // + // Suppress the native EFI_SIMPLE_TEXT_OUTPUT caret: it draws straight to the + // GraphicsConsole framebuffer and is invisible/misplaced behind an off-screen + // canvas (the LVGL backend). We render our own caret via ModernDisplayDrawTextCaret + // so the edit cursor looks identical on every backend. + // CursorVisible = gST->ConOut->Mode->CursorVisible; - gST->ConOut->EnableCursor (gST->ConOut, TRUE); + gST->ConOut->EnableCursor (gST->ConOut, FALSE); CurrentCursor = GetStringWidth (StringPtr) / 2 - 1; if (CurrentCursor != 0) { @@ -166,6 +172,12 @@ ReadString ( gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3); } + // + // Paint the initial caret before the first keystroke (the loop redraws it on + // each subsequent key). CurrentCursor was set from the saved string above. + // + ModernDisplayDrawTextCaret (Start + CurrentCursor + 1, Top + 3); + do { Status = WaitForKeyStroke (&Key); ASSERT_EFI_ERROR (Status); @@ -313,6 +325,7 @@ ReadString ( gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); gST->ConOut->SetCursorPosition (gST->ConOut, Start + CurrentCursor + 1, Top + 3); + ModernDisplayDrawTextCaret (Start + CurrentCursor + 1, Top + 3); } while (TRUE); } diff --git a/Universal/ModernDisplayEngineDxe/Popup.c b/Universal/ModernDisplayEngineDxe/Popup.c index 995cc75..b1fa939 100644 --- a/Universal/ModernDisplayEngineDxe/Popup.c +++ b/Universal/ModernDisplayEngineDxe/Popup.c @@ -723,6 +723,14 @@ CreatePopup ( ConOut->EnableCursor (ConOut, FALSE); ConOut->SetAttribute (ConOut, GetPopupColor ()); + // + // This popup draws over the form. Its highlighted selectable option prints + // with an EFI_RED background and could share the grid row recorded for the + // form's selection styling; forget that record so the option's background + // fill is not suppressed (which would leave it without a highlight). + // + ModernDisplayResetHighlightRowTracking (); + CalculatePopupPosition (PopupType, &gPopupDimensions); Status = DrawMessageBox (PopupStyle);