From c615193286f45de23c4e565b1ab32324bea6348d Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Fri, 5 Jun 2026 15:45:18 +0800 Subject: [PATCH 01/17] feat(displayengine): render text-input caret instead of native cursor ReadString's edit caret used gST->ConOut->EnableCursor, which draws straight to the GraphicsConsole framebuffer and is invisible/misplaced behind an off-screen canvas (the LVGL backend). Suppress the native cursor and paint a thin accent caret at the edit cell via a new renderer helper, ModernDisplayDrawTextCaret (declared in FormDisplay.h, implemented in ModernUiCustomizedDisplayLib alongside the row-cue helpers), redrawn each keystroke after the field text so it leaves no trail. This closes the last interaction surface that bypassed the renderer: the LVGL backend now composites the full FormBrowser interaction set (rows, one-of and dialog popups, and input editing) end-to-end, identically on the GOP backend. App-local; no HII/value/storage semantics touched. Validated: OVMF X64 lvgl-mode screendump of the DriverSample string editor showing the caret, GOP + lvgl builds, and smoke. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 11 +++++ Docs/MODULE_BOUNDARIES.md | 8 ++++ .../CustomizedDisplayLibInternal.c | 48 +++++++++++++++++++ .../ModernDisplayEngineDxe/FormDisplay.h | 21 ++++++++ .../ModernDisplayEngineDxe/InputHandler.c | 15 +++++- 5 files changed, 102 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73e7077..aaef3d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,17 @@ this file as both a release log and a lightweight development progress record. ### Added +- 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, 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/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c index 3123826..1d9fc88 100644 --- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c +++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c @@ -1136,6 +1136,54 @@ 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 + ); +} + /** Draw the modern DisplayEngine shell behind the native FormBrowser content. diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.h b/Universal/ModernDisplayEngineDxe/FormDisplay.h index 317b52a..efb2f3d 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.h +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.h @@ -129,6 +129,27 @@ 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 + ); + // // 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); } From 5cba7fe51475a8f49112e392a1cbfd485a1341fc Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Fri, 5 Jun 2026 17:39:10 +0800 Subject: [PATCH 02/17] feat(lvgl): map one-of opcode to a real lv_dropdown widget (display-only) First IFR-opcode -> LVGL-widget mapping. A new renderer entry point, ModernUiRenderOneOf, abstracts a one-of control: the LVGL backend builds a transient display-only lv_dropdown (rounded box, border, LV_SYMBOL_DOWN arrow), renders it via lv_snapshot_take (enables LV_USE_SNAPSHOT + adds lv_snapshot.c), and alpha-composites the ARGB8888 snapshot over the row background in the shadow canvas; the GOP backend keeps composing the value box from primitives, so there is no GOP regression. ModernUiEngineDrawValue routes one-of values to it (front-page App path); the in-setup DisplayEngine overlays it on the value lane via the new ModernDisplayDrawOneOfWidget, using the option string FormBrowser just printed (NARROW_CHAR/WIDE_CHAR glyph markers stripped). The one-of affordance cue is skipped for these rows since the rendered control carries its own arrow. Display-only: edk2 FormBrowser still owns the selection popup, ConfigAccess, and callbacks. This is the reusable widget pipeline (create -> snapshot -> alpha-composite) for further opcode->widget mappings. Validated: OVMF X64 lvgl + GOP screendumps of the DriverSample VFR form and the App preferences page (one-of renders as a real dropdown on LVGL, a value box on GOP, with clean option text), both builds clean, smoke PASS. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 17 +++ .../Library/LvglLib/LvglCoreLib.inf | 1 + .../LvglSpikePkg/Library/LvglLib/lv_conf.h | 2 +- Include/ModernUi/ModernUiRenderer.h | 38 ++++++ .../CustomizedDisplayLibInternal.c | 74 ++++++++++ Library/ModernUiEngineLib/ModernUiEngineLib.c | 13 +- .../ModernUiRendererLib.c | 127 ++++++++++++++++++ .../ModernUiRendererLib/ModernUiRendererLib.c | 29 ++++ .../ModernDisplayEngineDxe/FormDisplay.c | 16 +++ .../ModernDisplayEngineDxe/FormDisplay.h | 30 +++++ 10 files changed, 344 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aaef3d8..80666a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,23 @@ this file as both a release log and a lightweight development progress record. ### Added +- First IFR-opcode -> LVGL-widget mapping: one-of (choice) controls now render as + a real `lv_dropdown` widget on the LVGL backend, in both the front-page App and + real in-setup VFR forms. A new renderer entry point, `ModernUiRenderOneOf`, + abstracts the control: the LVGL backend builds a transient display-only + `lv_dropdown` (its own rounded box, border, and `LV_SYMBOL_DOWN` arrow), + renders it via `lv_snapshot_take` (newly enabled `LV_USE_SNAPSHOT`), and + alpha-composites the ARGB8888 result over the row background in the shadow + canvas; the GOP backend keeps composing the value box from primitives, so there + is no GOP regression. `ModernUiEngineDrawValue` routes one-of values to it (App + path) and the in-setup DisplayEngine overlays it on the value lane via the new + `ModernDisplayDrawOneOfWidget` (using the option string FormBrowser just + printed, with its NARROW_CHAR/WIDE_CHAR glyph markers stripped); the one-of + affordance cue is skipped for these rows since the control carries its own + arrow. Display-only: edk2 FormBrowser still owns the selection popup, + ConfigAccess, and callbacks. This is the reusable widget pipeline for further + opcode mappings. Verified by OVMF X64 lvgl + GOP screendumps of the DriverSample + form and the App preferences page, plus 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 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..ac96d24 100644 --- a/Include/ModernUi/ModernUiRenderer.h +++ b/Include/ModernUi/ModernUiRenderer.h @@ -418,6 +418,44 @@ 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 + ); + /** Draw a drop-down list frame. diff --git a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c index 1d9fc88..5f74474 100644 --- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c +++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c @@ -1108,6 +1108,14 @@ ModernDisplayDrawStatementRowCue ( return; } + // + // One-of (choice) rows render as a real drop-down via ModernDisplayDrawOneOfWidget, + // which carries its own arrow, so skip the separate chevron cue for them. + // + if (FormRow.Kind == ModernDisplayFormRowChoice) { + return; + } + Theme = ModernUiGetTheme (); ModernDisplayGetCellMetrics (&CellWidth, &CellHeight); @@ -1184,6 +1192,72 @@ ModernDisplayDrawTextCaret ( ); } +/** + 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 +ModernDisplayDrawOneOfWidget ( + 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; + + if ((ValueText == NULL) || (Width == 0) || EFI_ERROR (ModernDisplayEnsureRenderer ())) { + 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 + // drop-down shows clean option 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; + + ModernUiRenderOneOf (&mModernRenderContext, Rect, Clean, (BOOLEAN)(Highlight || Selected), Theme); +} + /** Draw the modern DisplayEngine shell behind the native FormBrowser content. diff --git a/Library/ModernUiEngineLib/ModernUiEngineLib.c b/Library/ModernUiEngineLib/ModernUiEngineLib.c index 5ff3874..a6af2f2 100644 --- a/Library/ModernUiEngineLib/ModernUiEngineLib.c +++ b/Library/ModernUiEngineLib/ModernUiEngineLib.c @@ -984,7 +984,7 @@ 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)) { + if ((Value->Type != ModernUiValueText) && (Value->Type != ModernUiValueOneOf) && (Rect.X > Value->Rect.X)) { CueSide = MIN ((Rect.Height > 6) ? (Rect.Height - 6) : 0, 14); if (CueSide >= 6) { ModernUiEngineDrawControlCue ( @@ -997,7 +997,16 @@ ModernUiEngineDrawValue ( } } - if ((Value->Type == ModernUiValueOneOf) || (Value->Type == ModernUiValueText)) { + // + // One-of renders as the backend's best-available drop-down: a real lv_dropdown + // widget on the LVGL backend, a composed value box on GOP. The control carries + // its own arrow, so the external one-of cue above is intentionally skipped. + // + if (Value->Type == ModernUiValueOneOf) { + return ModernUiRenderOneOf (Context, Rect, Value->Text, Value->Selected, Theme); + } + + if (Value->Type == ModernUiValueText) { return ModernUiDrawValueBox (Context, Rect, Value->Text, Value->Selected, Theme); } diff --git a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c index 2604f74..e668a56 100644 --- a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c +++ b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c @@ -756,3 +756,130 @@ ModernUiDrawText ( return ReturnStatus; } + + +/** + 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; + lv_draw_buf_t *Snap; + CHAR8 Label[128]; + UINTN Index; + UINTN SnapW; + UINTN SnapH; + UINTN Stride; + UINTN RowIdx; + UINTN ColIdx; + UINT8 *SrcRow; + UINT8 *SrcPix; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Dst; + UINT32 Alpha; + + 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); + } + + // + // UCS-2 -> ASCII for the LVGL (Latin) label; non-ASCII code points become '?'. + // CJK option text is a known prototype limitation of the widget path. + // + for (Index = 0; (Index < (sizeof (Label) - 1)) && (Value[Index] != CHAR_NULL); Index++) { + Label[Index] = ((Value[Index] >= 0x20) && (Value[Index] < 0x7F)) ? (CHAR8)Value[Index] : '?'; + } + + Label[Index] = '\0'; + + 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); + lv_obj_set_size (Dropdown, (int32_t)Rect.Width, (int32_t)Rect.Height); + lv_obj_set_pos (Dropdown, 0, 0); + lv_obj_set_style_bg_color (Dropdown, ToLvColor (Selected ? Theme->SelectedBand : Theme->Surface), 0); + lv_obj_set_style_bg_opa (Dropdown, LV_OPA_COVER, 0); + lv_obj_set_style_border_color (Dropdown, ToLvColor (Selected ? Theme->PopupBorder : Theme->Border), 0); + lv_obj_set_style_text_color (Dropdown, ToLvColor (Theme->Text), 0); + lv_obj_update_layout (Dropdown); + + Snap = lv_snapshot_take (Dropdown, LV_COLOR_FORMAT_ARGB8888); + if (Snap == NULL) { + lv_obj_delete (Dropdown); + 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 (Dropdown); + + BltCanvasRegion ( + Rect.X, + Rect.Y, + MIN (SnapW, mCanvasW - Rect.X), + MIN (SnapH, mCanvasH - Rect.Y) + ); + + return EFI_SUCCESS; +} diff --git a/Library/ModernUiRendererLib/ModernUiRendererLib.c b/Library/ModernUiRendererLib/ModernUiRendererLib.c index 5f5b4a5..442fdc6 100644 --- a/Library/ModernUiRendererLib/ModernUiRendererLib.c +++ b/Library/ModernUiRendererLib/ModernUiRendererLib.c @@ -379,3 +379,32 @@ 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); +} diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.c b/Universal/ModernDisplayEngineDxe/FormDisplay.c index 8fafe54..301000b 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.c +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.c @@ -2523,6 +2523,22 @@ DisplayOneMenu ( } } + // + // One-of rows render as the backend's best drop-down over the value lane, + // using the option string FormBrowser just printed (still valid here, and + // Highlight not yet cleared). The cue overlay skips the chevron for one-of. + // + if (Statement->OpCode->OpCode == EFI_IFR_ONE_OF_OP) { + ModernDisplayDrawOneOfWidget ( + MenuOption->OptCol, + MenuOption->Row, + gOptionBlockWidth, + OptionString, + Highlight, + (BOOLEAN)(gUserInput->SelectedStatement == Statement) + ); + } + Highlight = FALSE; FreePool (OptionString); diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.h b/Universal/ModernDisplayEngineDxe/FormDisplay.h index efb2f3d..938aabe 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.h +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.h @@ -150,6 +150,36 @@ ModernDisplayDrawTextCaret ( IN UINTN Row ); +/** + Overlay a one-of (choice) row's value lane with the backend's best drop-down. + + This is the in-setup half of the one-of -> drop-down mapping. The native + FormBrowser prints the selected option as plain text in the value lane; + `DisplayOneMenu` calls this immediately afterwards (while the option string is + still in scope) to paint a real drop-down over that lane -- a true `lv_dropdown` + widget on the LVGL backend, a composed value box on GOP -- via the shared + ModernUiRenderOneOf renderer entry point. Display-only: edk2 still owns the + selection popup, ConfigAccess, and callbacks. The companion cue overlay skips + the one-of chevron for the same row, since the rendered control carries its own. + + @param[in] Column Text-grid column where the value (option) 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 (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 +ModernDisplayDrawOneOfWidget ( + IN UINTN Column, + IN UINTN Row, + IN UINTN Width, + IN CONST CHAR16 *ValueText OPTIONAL, + IN BOOLEAN Highlight, + IN BOOLEAN Selected + ); + // // Screen definitions // From 4b3fb8483ce0ee746fd51235131bc725c98cb603 Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Fri, 5 Jun 2026 18:04:28 +0800 Subject: [PATCH 03/17] feat(lvgl): map checkbox/numeric/string/password opcodes to LVGL widgets Extends the IFR-opcode -> LVGL-widget mapping beyond one-of to the rest of the value-bearing controls. On the LVGL backend: checkbox -> a checked lv_checkbox; numeric/string/password -> a styled lv_obj field with an lv_label (password masked). All share a new LvglComposeSnapshot helper (lv_snapshot_take + ARGB8888 alpha-composite) and LvglStyleControl/LvglAsciiLabel helpers. Renderer layer gains per-control entry points (ModernUiRenderCheckbox/Numeric/ String/Password) plus an arrow-less ModernUiDrawFieldBox; the GOP backend implements them as themed value/field boxes (no regression). The App path (ModernUiEngineDrawValue) dispatches per value type, and the in-setup DisplayEngine generalizes ModernDisplayDrawOneOfWidget into ModernDisplayDrawValueWidget (opcode-dispatched over the value lane). The affordance cue is skipped for all mapped rows. Date/time and ordered-list keep the cue (no clean single-widget mapping yet); action/reference keep the arrow. Display-only throughout: edk2 FormBrowser still owns selection/editing, ConfigAccess, and callbacks. Validated: OVMF X64 lvgl + GOP screendumps of the DriverSample VFR form (every value control renders as a real widget on LVGL / a themed box on GOP, with clean text), both builds clean, smoke PASS. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 39 +- Include/ModernUi/ModernUiRenderer.h | 92 ++++ .../CustomizedDisplayLibInternal.c | 51 ++- Library/ModernUiEngineLib/ModernUiEngineLib.c | 39 +- .../ModernUiRendererLib.c | 395 +++++++++++++++--- .../ModernUiRendererCommon.c | 52 +++ .../ModernUiRendererLib/ModernUiRendererLib.c | 73 ++++ .../ModernDisplayEngineDxe/FormDisplay.c | 26 +- .../ModernDisplayEngineDxe/FormDisplay.h | 32 +- 9 files changed, 682 insertions(+), 117 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80666a8..f74e2af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,23 +14,28 @@ this file as both a release log and a lightweight development progress record. ### Added -- First IFR-opcode -> LVGL-widget mapping: one-of (choice) controls now render as - a real `lv_dropdown` widget on the LVGL backend, in both the front-page App and - real in-setup VFR forms. A new renderer entry point, `ModernUiRenderOneOf`, - abstracts the control: the LVGL backend builds a transient display-only - `lv_dropdown` (its own rounded box, border, and `LV_SYMBOL_DOWN` arrow), - renders it via `lv_snapshot_take` (newly enabled `LV_USE_SNAPSHOT`), and - alpha-composites the ARGB8888 result over the row background in the shadow - canvas; the GOP backend keeps composing the value box from primitives, so there - is no GOP regression. `ModernUiEngineDrawValue` routes one-of values to it (App - path) and the in-setup DisplayEngine overlays it on the value lane via the new - `ModernDisplayDrawOneOfWidget` (using the option string FormBrowser just - printed, with its NARROW_CHAR/WIDE_CHAR glyph markers stripped); the one-of - affordance cue is skipped for these rows since the control carries its own - arrow. Display-only: edk2 FormBrowser still owns the selection popup, - ConfigAccess, and callbacks. This is the reusable widget pipeline for further - opcode mappings. Verified by OVMF X64 lvgl + GOP screendumps of the DriverSample - form and the App preferences page, 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. Date/time and ordered-list keep the cue vocabulary (no clean single-widget + mapping yet); 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. - 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 diff --git a/Include/ModernUi/ModernUiRenderer.h b/Include/ModernUi/ModernUiRenderer.h index ac96d24..1ca3f84 100644 --- a/Include/ModernUi/ModernUiRenderer.h +++ b/Include/ModernUi/ModernUiRenderer.h @@ -456,6 +456,98 @@ ModernUiRenderOneOf ( 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 + ); + +/** + 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. diff --git a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c index 5f74474..6473b13 100644 --- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c +++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c @@ -1109,10 +1109,17 @@ ModernDisplayDrawStatementRowCue ( } // - // One-of (choice) rows render as a real drop-down via ModernDisplayDrawOneOfWidget, - // which carries its own arrow, so skip the separate chevron cue for them. + // Widget-mapped rows (one-of/checkbox/numeric/string/password) render as real + // controls via ModernDisplayDrawValueWidget, which carry their own affordance, + // so skip the separate cue for them. Date/time, ordered-list, and action keep + // the cue. // - if (FormRow.Kind == ModernDisplayFormRowChoice) { + if ((FormRow.Kind == ModernDisplayFormRowChoice) || + (FormRow.Kind == ModernDisplayFormRowCheckbox) || + (FormRow.Kind == ModernDisplayFormRowNumeric) || + (FormRow.Kind == ModernDisplayFormRowString) || + (FormRow.Kind == ModernDisplayFormRowPassword)) + { return; } @@ -1210,7 +1217,8 @@ ModernDisplayDrawTextCaret ( **/ VOID EFIAPI -ModernDisplayDrawOneOfWidget ( +ModernDisplayDrawValueWidget ( + IN UINT8 OpCode, IN UINTN Column, IN UINTN Row, IN UINTN Width, @@ -1226,11 +1234,23 @@ ModernDisplayDrawOneOfWidget ( 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)) + { + return; + } + ModernDisplayGetCellMetrics (&CellWidth, &CellHeight); if ((CellWidth == 0) || (CellHeight < 10)) { return; @@ -1239,7 +1259,7 @@ ModernDisplayDrawOneOfWidget ( // // FormBrowser embeds glyph-width markers (NARROW_CHAR/WIDE_CHAR, >= 0xFFF0) in // option strings; they are layout hints, not printable text. Strip them so the - // drop-down shows clean option text on both backends. + // 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) { @@ -1254,8 +1274,27 @@ ModernDisplayDrawOneOfWidget ( Rect.Y = Row * CellHeight; Rect.Width = Width * CellWidth; Rect.Height = CellHeight; + Sel = (BOOLEAN)(Highlight || Selected); - ModernUiRenderOneOf (&mModernRenderContext, Rect, Clean, (BOOLEAN)(Highlight || Selected), Theme); + 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; + default: + break; + } } /** diff --git a/Library/ModernUiEngineLib/ModernUiEngineLib.c b/Library/ModernUiEngineLib/ModernUiEngineLib.c index a6af2f2..f76417b 100644 --- a/Library/ModernUiEngineLib/ModernUiEngineLib.c +++ b/Library/ModernUiEngineLib/ModernUiEngineLib.c @@ -984,7 +984,17 @@ ModernUiEngineDrawValue ( // or action control reads the same here as in the in-setup DisplayEngine. // Plain text values carry no affordance. // - if ((Value->Type != ModernUiValueText) && (Value->Type != ModernUiValueOneOf) && (Rect.X > Value->Rect.X)) { + // Widget-mapped controls (one-of/checkbox/numeric/string/password) render as + // real backend widgets that carry their own affordance, so the external cue is + // drawn only for the remaining cued types (date/time, ordered-list, action). + if ((Value->Type != ModernUiValueText) && + (Value->Type != ModernUiValueOneOf) && + (Value->Type != ModernUiValueCheckbox) && + (Value->Type != ModernUiValueNumeric) && + (Value->Type != ModernUiValueString) && + (Value->Type != ModernUiValuePassword) && + (Rect.X > Value->Rect.X)) + { CueSide = MIN ((Rect.Height > 6) ? (Rect.Height - 6) : 0, 14); if (CueSide >= 6) { ModernUiEngineDrawControlCue ( @@ -998,16 +1008,25 @@ ModernUiEngineDrawValue ( } // - // One-of renders as the backend's best-available drop-down: a real lv_dropdown - // widget on the LVGL backend, a composed value box on GOP. The control carries - // its own arrow, so the external one-of cue above is intentionally skipped. + // 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. // - if (Value->Type == ModernUiValueOneOf) { - return ModernUiRenderOneOf (Context, Rect, Value->Text, Value->Selected, Theme); - } - - if (Value->Type == ModernUiValueText) { - return ModernUiDrawValueBox (Context, Rect, Value->Text, Value->Selected, Theme); + 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 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 e668a56..93af81a 100644 --- a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c +++ b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c @@ -759,40 +759,97 @@ ModernUiDrawText ( /** - LVGL one-of renderer: render a real `lv_dropdown` widget into the shadow canvas. + Convert a UCS-2 run to an ASCII label for LVGL's Latin fonts. - 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. + 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] Rect Control rectangle (value lane). - @param[in] Value Selected option text. 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). - @retval EFI_INVALID_PARAMETER Context, Value, or Theme is NULL, or Rect empty. + @retval EFI_SUCCESS Widget composited (or fell back successfully). **/ +STATIC 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 +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_obj_t *Dropdown; lv_draw_buf_t *Snap; - CHAR8 Label[128]; - UINTN Index; UINTN SnapW; UINTN SnapH; UINTN Stride; @@ -803,41 +860,11 @@ ModernUiRenderOneOf ( EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Dst; UINT32 Alpha; - 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); - } + lv_obj_update_layout (Obj); - // - // UCS-2 -> ASCII for the LVGL (Latin) label; non-ASCII code points become '?'. - // CJK option text is a known prototype limitation of the widget path. - // - for (Index = 0; (Index < (sizeof (Label) - 1)) && (Value[Index] != CHAR_NULL); Index++) { - Label[Index] = ((Value[Index] >= 0x20) && (Value[Index] < 0x7F)) ? (CHAR8)Value[Index] : '?'; - } - - Label[Index] = '\0'; - - 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); - lv_obj_set_size (Dropdown, (int32_t)Rect.Width, (int32_t)Rect.Height); - lv_obj_set_pos (Dropdown, 0, 0); - lv_obj_set_style_bg_color (Dropdown, ToLvColor (Selected ? Theme->SelectedBand : Theme->Surface), 0); - lv_obj_set_style_bg_opa (Dropdown, LV_OPA_COVER, 0); - lv_obj_set_style_border_color (Dropdown, ToLvColor (Selected ? Theme->PopupBorder : Theme->Border), 0); - lv_obj_set_style_text_color (Dropdown, ToLvColor (Theme->Text), 0); - lv_obj_update_layout (Dropdown); - - Snap = lv_snapshot_take (Dropdown, LV_COLOR_FORMAT_ARGB8888); + Snap = lv_snapshot_take (Obj, LV_COLOR_FORMAT_ARGB8888); if (Snap == NULL) { - lv_obj_delete (Dropdown); + lv_obj_delete (Obj); return ModernUiDrawValueBox (Context, Rect, Value, Selected, Theme); } @@ -872,7 +899,7 @@ ModernUiRenderOneOf ( } lv_draw_buf_destroy (Snap); - lv_obj_delete (Dropdown); + lv_obj_delete (Obj); BltCanvasRegion ( Rect.X, @@ -883,3 +910,257 @@ ModernUiRenderOneOf ( 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; + CHAR8 Label[128]; + BOOLEAN Checked; + CONST CHAR16 *Text; + + 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, then drop a leading + // "[.]" so the label is just the human-readable text. + // + Checked = (BOOLEAN)((StrStr (Value, L"X") != NULL) || (StrStr (Value, L"x") != NULL)); + Text = Value; + if ((Text[0] == L'[') && (Text[1] != CHAR_NULL) && (Text[2] == L']')) { + Text += 3; + while (*Text == L' ') { + Text++; + } + } + + LvglAsciiLabel (Label, sizeof (Label), Text); + + 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, Label); + 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; + lv_obj_t *Label; + CHAR8 Text[128]; + UINTN Index; + + 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); + if (PasswordMode) { + for (Index = 0; Text[Index] != '\0'; Index++) { + if (Text[Index] != ' ') { + Text[Index] = '*'; + } + } + } + + // + // A styled lv_obj container plus an lv_label is the reliable display-only + // "field" rendering: a real LVGL widget surface, without lv_textarea's editing + // cursor/scroll behavior (which obscures short text at row height). + // + 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, Text); + 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, 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); +} diff --git a/Library/ModernUiRendererLib/ModernUiRendererCommon.c b/Library/ModernUiRendererLib/ModernUiRendererCommon.c index 8509fe5..5b8ae44 100644 --- a/Library/ModernUiRendererLib/ModernUiRendererCommon.c +++ b/Library/ModernUiRendererLib/ModernUiRendererCommon.c @@ -1046,6 +1046,58 @@ 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 + ); +} + /** Draw a drop-down list frame. diff --git a/Library/ModernUiRendererLib/ModernUiRendererLib.c b/Library/ModernUiRendererLib/ModernUiRendererLib.c index 442fdc6..0eb720f 100644 --- a/Library/ModernUiRendererLib/ModernUiRendererLib.c +++ b/Library/ModernUiRendererLib/ModernUiRendererLib.c @@ -408,3 +408,76 @@ ModernUiRenderOneOf ( { 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); +} diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.c b/Universal/ModernDisplayEngineDxe/FormDisplay.c index 301000b..9820c29 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.c +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.c @@ -2524,20 +2524,20 @@ DisplayOneMenu ( } // - // One-of rows render as the backend's best drop-down over the value lane, - // using the option string FormBrowser just printed (still valid here, and - // Highlight not yet cleared). The cue overlay skips the chevron for one-of. + // 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. // - if (Statement->OpCode->OpCode == EFI_IFR_ONE_OF_OP) { - ModernDisplayDrawOneOfWidget ( - MenuOption->OptCol, - MenuOption->Row, - gOptionBlockWidth, - OptionString, - Highlight, - (BOOLEAN)(gUserInput->SelectedStatement == Statement) - ); - } + ModernDisplayDrawValueWidget ( + Statement->OpCode->OpCode, + MenuOption->OptCol, + MenuOption->Row, + gOptionBlockWidth, + OptionString, + Highlight, + (BOOLEAN)(gUserInput->SelectedStatement == Statement) + ); Highlight = FALSE; diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.h b/Universal/ModernDisplayEngineDxe/FormDisplay.h index 938aabe..6f5003e 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.h +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.h @@ -151,27 +151,31 @@ ModernDisplayDrawTextCaret ( ); /** - Overlay a one-of (choice) row's value lane with the backend's best drop-down. - - This is the in-setup half of the one-of -> drop-down mapping. The native - FormBrowser prints the selected option as plain text in the value lane; - `DisplayOneMenu` calls this immediately afterwards (while the option string is - still in scope) to paint a real drop-down over that lane -- a true `lv_dropdown` - widget on the LVGL backend, a composed value box on GOP -- via the shared - ModernUiRenderOneOf renderer entry point. Display-only: edk2 still owns the - selection popup, ConfigAccess, and callbacks. The companion cue overlay skips - the one-of chevron for the same row, since the rendered control carries its own. - - @param[in] Column Text-grid column where the value (option) lane starts. + 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 Selected option text. May be NULL (then no-op). + @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 -ModernDisplayDrawOneOfWidget ( +ModernDisplayDrawValueWidget ( + IN UINT8 OpCode, IN UINTN Column, IN UINTN Row, IN UINTN Width, From c2fb71160ad1d221afd636e8c626bb3410ee0a79 Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Fri, 5 Jun 2026 23:45:48 +0800 Subject: [PATCH 04/17] feat(lvgl): map ordered-list + date/time opcodes to LVGL widgets Completes the IFR-opcode -> LVGL-widget mapping for the remaining value-bearing controls: - ordered-list -> a real list-style lv_obj field (LV_SYMBOL_LIST prefix + the current option order), wired into both the App draw path and the in-setup DisplayEngine overlay; its affordance cue is dropped since the widget carries its own. - date/time -> a segmented field (value spaced around / : - 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 native per-segment rendering + 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 on both backends (GOP draws themed field boxes -- no regression). Display-only throughout: edk2 FormBrowser still owns the reorder popup and segment editing. Validated: OVMF X64 lvgl + GOP (DriverSample) builds clean, smoke PASS. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 15 +- Include/ModernUi/ModernUiRenderer.h | 40 ++++++ .../CustomizedDisplayLibInternal.c | 16 ++- Library/ModernUiEngineLib/ModernUiEngineLib.c | 13 +- .../ModernUiRendererLib.c | 136 ++++++++++++++++++ .../ModernUiRendererLib/ModernUiRendererLib.c | 36 +++++ 6 files changed, 245 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f74e2af..f4ffcc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,11 +31,22 @@ this file as both a release log and a lightweight development progress record. 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. Date/time and ordered-list keep the cue vocabulary (no clean single-widget - mapping yet); action/reference keep the `>` arrow. Display-only throughout: edk2 + 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 diff --git a/Include/ModernUi/ModernUiRenderer.h b/Include/ModernUi/ModernUiRenderer.h index 1ca3f84..e22c950 100644 --- a/Include/ModernUi/ModernUiRenderer.h +++ b/Include/ModernUi/ModernUiRenderer.h @@ -522,6 +522,46 @@ ModernUiRenderNumeric ( 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. diff --git a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c index 6473b13..a05f1dd 100644 --- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c +++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c @@ -1109,16 +1109,17 @@ ModernDisplayDrawStatementRowCue ( } // - // Widget-mapped rows (one-of/checkbox/numeric/string/password) render as real - // controls via ModernDisplayDrawValueWidget, which carry their own affordance, - // so skip the separate cue for them. Date/time, ordered-list, and action keep - // the cue. + // 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 == ModernDisplayFormRowPassword) || + (FormRow.Kind == ModernDisplayFormRowOrderedList)) { return; } @@ -1246,7 +1247,7 @@ ModernDisplayDrawValueWidget ( // 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_PASSWORD_OP) && (OpCode != EFI_IFR_ORDERED_LIST_OP)) { return; } @@ -1292,6 +1293,9 @@ ModernDisplayDrawValueWidget ( 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; } diff --git a/Library/ModernUiEngineLib/ModernUiEngineLib.c b/Library/ModernUiEngineLib/ModernUiEngineLib.c index f76417b..f953079 100644 --- a/Library/ModernUiEngineLib/ModernUiEngineLib.c +++ b/Library/ModernUiEngineLib/ModernUiEngineLib.c @@ -984,15 +984,18 @@ ModernUiEngineDrawValue ( // or action control reads the same here as in the in-setup DisplayEngine. // Plain text values carry no affordance. // - // Widget-mapped controls (one-of/checkbox/numeric/string/password) render as - // real backend widgets that carry their own affordance, so the external cue is - // drawn only for the remaining cued types (date/time, ordered-list, action). + // 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); @@ -1023,6 +1026,10 @@ ModernUiEngineDrawValue ( 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: diff --git a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c index 93af81a..7e8e0cc 100644 --- a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c +++ b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c @@ -1164,3 +1164,139 @@ ModernUiRenderNumeric ( { 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; + CHAR8 Text[128]; + CHAR8 Decorated[160]; + + 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); + // + // 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, 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, 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, Value, 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); +} diff --git a/Library/ModernUiRendererLib/ModernUiRendererLib.c b/Library/ModernUiRendererLib/ModernUiRendererLib.c index 0eb720f..309cd7e 100644 --- a/Library/ModernUiRendererLib/ModernUiRendererLib.c +++ b/Library/ModernUiRendererLib/ModernUiRendererLib.c @@ -481,3 +481,39 @@ ModernUiRenderNumeric ( { 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 + ) +{ + return ModernUiDrawFieldBox (Context, Rect, Value, 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); +} From 11893e75553aea656d9fd2beedffc25035bc8136 Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Sat, 6 Jun 2026 10:39:54 +0800 Subject: [PATCH 05/17] fix(displayengine): don't paint empty rows below menu with the highlight band When the highlighted statement is the last visible row (e.g. Reset on the front page), the form's 'clean the remain field' loop cleared the rows below the menu while the highlight display attribute was still set. The modern renderer paints cleared rows with the current background, so that empty area was filled with the highlight band color (SelectedBand) -- a large spurious tan block below the menu. Reset the display attribute to the normal field color (GetFieldTextColor, which maps to Theme->Surface) before the clear loop, mirroring the reset already done before the scroll down-arrow. Backend-agnostic; fixes any form whose last visible row is highlighted. Validated: OVMF X64 lvgl + GOP builds clean, smoke PASS, front-page screendump with Reset highlighted shows a dark empty area (no tan block). Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 9 +++++++++ Universal/ModernDisplayEngineDxe/FormDisplay.c | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4ffcc4..8fe436c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -497,6 +497,15 @@ this file as both a release log and a lightweight development progress record. ### Fixed +- 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/Universal/ModernDisplayEngineDxe/FormDisplay.c b/Universal/ModernDisplayEngineDxe/FormDisplay.c index 9820c29..c058dd6 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.c +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.c @@ -2921,6 +2921,13 @@ 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. + // + 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); From 6026f7da53d2dfc6b31bb391650b2508c85a623c Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Sat, 6 Jun 2026 10:40:15 +0800 Subject: [PATCH 06/17] fix(lvgl): join ordered-list options with ' / ' instead of raw CR (shown as ?) FormBrowser builds an ordered-list value by joining options with CHAR_CARRIAGE_RETURN (ProcessOptions.c). That 0x0D passes the >= 0xFFF0 glyph-width marker filter but is < 0x20, so LvglAsciiLabel rendered each separator as '?' (??). Add a shared ModernUiNormalizeOrderedListText helper (in the common surface compiled into both backends): strip glyph-width markers, collapse each run of CR/LF into a single ' / ', and drop leading/trailing separators. Both the GOP and LVGL ordered-list renderers normalize the value before drawing, so the box reads ' / / '. Display-only; minimal scope (no multi-row list box). Validated: OVMF X64 lvgl + GOP builds clean, smoke PASS. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 7 ++ .../ModernUiRendererLib.c | 15 +++-- .../ModernUiRendererCommon.c | 65 +++++++++++++++++++ .../ModernUiRendererInternal.h | 22 +++++++ .../ModernUiRendererLib/ModernUiRendererLib.c | 13 +++- 5 files changed, 117 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fe436c..e9c6778 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -497,6 +497,13 @@ this file as both a release log and a lightweight development progress record. ### Fixed +- 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 diff --git a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c index 7e8e0cc..11647c2 100644 --- a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c +++ b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c @@ -1186,6 +1186,7 @@ ModernUiRenderOrderedList ( { lv_obj_t *Field; lv_obj_t *Label; + CHAR16 Norm[160]; CHAR8 Text[128]; CHAR8 Decorated[160]; @@ -1193,11 +1194,17 @@ ModernUiRenderOrderedList ( 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, Value, Selected, Theme); + return ModernUiDrawFieldBox (Context, Rect, Norm, Selected, Theme); } - LvglAsciiLabel (Text, sizeof (Text), Value); + 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. @@ -1206,7 +1213,7 @@ ModernUiRenderOrderedList ( Field = lv_obj_create (lv_display_get_screen_active (mDisplay)); if (Field == NULL) { - return ModernUiDrawFieldBox (Context, Rect, Value, Selected, Theme); + return ModernUiDrawFieldBox (Context, Rect, Norm, Selected, Theme); } LvglStyleControl (Field, Rect, Selected, Theme); @@ -1221,7 +1228,7 @@ ModernUiRenderOrderedList ( lv_obj_align (Label, LV_ALIGN_LEFT_MID, 8, 0); } - return LvglComposeSnapshot (Context, Field, Rect, Value, Selected, Theme); + return LvglComposeSnapshot (Context, Field, Rect, Norm, Selected, Theme); } /** diff --git a/Library/ModernUiRendererLib/ModernUiRendererCommon.c b/Library/ModernUiRendererLib/ModernUiRendererCommon.c index 5b8ae44..fbc5022 100644 --- a/Library/ModernUiRendererLib/ModernUiRendererCommon.c +++ b/Library/ModernUiRendererLib/ModernUiRendererCommon.c @@ -1098,6 +1098,71 @@ ModernUiDrawFieldBox ( ); } +/** + 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 309cd7e..e7403ce 100644 --- a/Library/ModernUiRendererLib/ModernUiRendererLib.c +++ b/Library/ModernUiRendererLib/ModernUiRendererLib.c @@ -497,7 +497,18 @@ ModernUiRenderOrderedList ( IN CONST MODERN_UI_THEME *Theme ) { - return ModernUiDrawFieldBox (Context, Rect, Value, Selected, 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); } /** From 09d1d2ef5ed3a44fd99176a46b0064fb199177a1 Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Sat, 6 Jun 2026 11:05:49 +0800 Subject: [PATCH 07/17] fix(displayengine): clear value lane before native editing; checkbox empty label Two in-setup widget issues found in live testing: 1. Numeric in-place editing and string/password input popups collided with the composited value-lane widget: native FormBrowser's initial editor draw is narrower than (and a different color from) the widget, so the widget box remnant showed beside/under the editor (digits looked invisible on the band; the string popup left the old-value widget peeking out to its left). Add ModernDisplayClearValueLane, called from the edit entry in the form key handler, to repaint the value lane to the plain field background (Theme->Surface, matching what native editing erases to) right before the editor runs. The full form repaint after editing restores the widget. 2. The lv_checkbox widget leaked a stray ']' from the raw '[X]' value text. Render the box indicator with an empty label -- the box conveys the state and the row's left prompt already names the control. Validated: OVMF X64 lvgl + GOP builds clean, smoke PASS. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 10 +++++ .../CustomizedDisplayLibInternal.c | 38 +++++++++++++++++++ .../ModernUiRendererLib.c | 19 +++------- .../ModernDisplayEngineDxe/FormDisplay.c | 6 +++ .../ModernDisplayEngineDxe/FormDisplay.h | 26 +++++++++++++ 5 files changed, 85 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9c6778..b783998 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -497,6 +497,16 @@ this file as both a release log and a lightweight development progress record. ### Fixed +- 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 diff --git a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c index a05f1dd..e440e30 100644 --- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c +++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c @@ -1301,6 +1301,44 @@ ModernDisplayDrawValueWidget ( } } +/** + 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. diff --git a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c index 11647c2..abc8eeb 100644 --- a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c +++ b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c @@ -995,9 +995,7 @@ ModernUiRenderCheckbox ( ) { lv_obj_t *Checkbox; - CHAR8 Label[128]; BOOLEAN Checked; - CONST CHAR16 *Text; if ((Context == NULL) || (Value == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) { return EFI_INVALID_PARAMETER; @@ -1008,26 +1006,19 @@ ModernUiRenderCheckbox ( } // - // Infer checked state from the "[X]"/"[ ]" marker, then drop a leading - // "[.]" so the label is just the human-readable text. + // 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)); - Text = Value; - if ((Text[0] == L'[') && (Text[1] != CHAR_NULL) && (Text[2] == L']')) { - Text += 3; - while (*Text == L' ') { - Text++; - } - } - - LvglAsciiLabel (Label, sizeof (Label), Text); 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, Label); + lv_checkbox_set_text (Checkbox, ""); if (Checked) { lv_obj_add_state (Checkbox, LV_STATE_CHECKED); } diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.c b/Universal/ModernDisplayEngineDxe/FormDisplay.c index c058dd6..e6d2ed1 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.c +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.c @@ -3488,6 +3488,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 6f5003e..dc44082 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.h +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.h @@ -184,6 +184,32 @@ ModernDisplayDrawValueWidget ( 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 + ); + // // Screen definitions // From 6d22458606f9ee55a2c67e646ee8bb0a9606979e Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Sat, 6 Jun 2026 11:23:45 +0800 Subject: [PATCH 08/17] refactor(lvgl): render string/numeric/password as real lv_textarea Per the 'prefer LVGL built-in widgets' direction, replace the hand-composed lv_obj+lv_label field with a real single-line lv_textarea for the string/numeric/password value widgets (one-of already uses lv_dropdown, checkbox uses lv_checkbox). The earlier reason for the lv_obj+label fallback (textarea caret/scroll obscuring short text at row height) is addressed by configuration: - lv_textarea_set_one_line(true) - scrollbar off (LV_SCROLLBAR_MODE_OFF) - caret hidden (LV_PART_CURSOR opacity transparent) -- display-only snapshot - native password masking (lv_textarea_set_password_mode) replaces the manual '*' loop - cursor moved to position 0 so the start of the text shows, not the scrolled end Display-only; edk2 still owns editing. Verified by an OVMF X64 lvgl DriverSample screendump: [0]/[21]/[12]/[16]/[18] fields render cleanly at row height. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 8 ++++ .../ModernUiRendererLib.c | 45 ++++++++++--------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b783998..1a7eaac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -360,6 +360,14 @@ this file as both a release log and a lightweight development progress record. ### Changed +- 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) diff --git a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c index abc8eeb..afddf0b 100644 --- a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c +++ b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c @@ -1059,9 +1059,7 @@ LvglRenderTextField ( ) { lv_obj_t *Field; - lv_obj_t *Label; CHAR8 Text[128]; - UINTN Index; if ((Context == NULL) || (Value == NULL) || (Theme == NULL) || (Rect.Width == 0) || (Rect.Height == 0)) { return EFI_INVALID_PARAMETER; @@ -1072,35 +1070,38 @@ LvglRenderTextField ( } LvglAsciiLabel (Text, sizeof (Text), Value); - if (PasswordMode) { - for (Index = 0; Text[Index] != '\0'; Index++) { - if (Text[Index] != ' ') { - Text[Index] = '*'; - } - } - } // - // A styled lv_obj container plus an lv_label is the reliable display-only - // "field" rendering: a real LVGL widget surface, without lv_textarea's editing - // cursor/scroll behavior (which obscures short text at row height). + // 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_obj_create (lv_display_get_screen_active (mDisplay)); + 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_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, Text); - lv_obj_set_style_text_color (Label, ToLvColor (Selected ? Theme->Text : Theme->MutedText), 0); - lv_obj_align (Label, LV_ALIGN_LEFT_MID, 8, 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); } From 754c085543bfafaa365b13a7239d4f79374dd405 Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Sat, 6 Jun 2026 21:55:24 +0800 Subject: [PATCH 09/17] feat(branding): OEM watermark slot composited into in-setup whitespace Add an OEM branding watermark slot to the modern DisplayEngine. A new renderer entry point ModernUiDrawOemWatermark composites an original, theme-tinted brand mark (document glyph + "MODERN UEFI SETUP * OPEN SOURCE" + the project URL) into the content-area whitespace, low-opacity, so it fills empty space without fighting the setup text. The asset is 100% original geometry + the project URL -- no IBV/commercial reuse. Assets/Branding/oem-watermark.svg is the scalable design source; Scripts/gen-oem-watermark.py rasterizes it to an A8 coverage map (OemWatermarkData.c/.h). The LVGL backend alpha-blends the A8 map (tinted with the theme muted-text color) directly into the shadow canvas and BLTs the region; the GOP backend is a no-op for now. Because the native FormBrowser repaints the content area after the chrome (rows, the empty-row clear, and the help-string update), drawing the mark at chrome time gets wiped. So the DisplayEngine draws it *after* the statement rows via ModernDisplayDrawOemWatermarkOverlay (invoked at the end of the CfRepaint pass) and confines it to the statement column -- the help/right-rail columns are repainted by later form states and would clip the mark. Display-only throughout: parses no HII, owns no FormBrowser state, no ConfigAccess. Verified by OVMF X64 lvgl screendump of a DriverSample sub-form with content whitespace, plus smoke. Co-Authored-By: Claude Opus 4.8 --- Assets/Branding/oem-watermark.svg | 35 + CHANGELOG.md | 15 + Include/ModernUi/ModernUiRenderer.h | 36 + .../CustomizedDisplayLibInternal.c | 54 + .../ModernUiRendererLib.c | 99 + .../ModernUiRendererLib.inf | 2 + .../OemWatermarkData.c | 2864 +++++++++++++++++ .../OemWatermarkData.h | 22 + .../ModernUiRendererLib/ModernUiRendererLib.c | 22 + Scripts/gen-oem-watermark.py | 93 + .../ModernDisplayEngineDxe/FormDisplay.c | 8 + .../ModernDisplayEngineDxe/FormDisplay.h | 15 + 12 files changed, 3265 insertions(+) create mode 100644 Assets/Branding/oem-watermark.svg create mode 100644 Library/ModernUiLvglRendererLib/OemWatermarkData.c create mode 100644 Library/ModernUiLvglRendererLib/OemWatermarkData.h create mode 100644 Scripts/gen-oem-watermark.py 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 1a7eaac..2068169 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,21 @@ this file as both a release log and a lightweight development progress record. ### Added +- 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. Display-only: parses no HII, owns no FormBrowser state. Verified + by OVMF X64 lvgl screendump of a DriverSample sub-form with content whitespace, + 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 diff --git a/Include/ModernUi/ModernUiRenderer.h b/Include/ModernUi/ModernUiRenderer.h index e22c950..4e278ad 100644 --- a/Include/ModernUi/ModernUiRenderer.h +++ b/Include/ModernUi/ModernUiRenderer.h @@ -630,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 e440e30..37a656b 100644 --- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c +++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c @@ -1441,6 +1441,60 @@ 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. It computes the same + content rectangle the chrome uses and forwards to the renderer's + ModernUiDrawOemWatermark, which no-ops on backends/regions that cannot host it. + + Display-only; parses no HII and owns no FormBrowser state. Safe to call on + every form refresh. +**/ +VOID +ModernDisplayDrawOemWatermarkOverlay ( + VOID + ) +{ + CONST MODERN_UI_THEME *Theme; + UINTN CellWidth; + UINTN CellHeight; + UINTN HelpStartColumn; + 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; + } + + Content.X = Layout.ContentLeftColumn * CellWidth; + Content.Y = Layout.ContentTopRow * CellHeight; + Content.Width = (HelpStartColumn - Layout.ContentLeftColumn) * CellWidth; + Content.Height = (Layout.ContentBottomRow - Layout.ContentTopRow) * CellHeight; + + ModernUiDrawOemWatermark (&mModernRenderContext, Content, Theme); +} + // // Browser Global Strings // diff --git a/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c b/Library/ModernUiLvglRendererLib/ModernUiRendererLib.c index afddf0b..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 @@ -1299,3 +1300,101 @@ ModernUiRenderDateTime ( 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/ModernUiRendererLib.c b/Library/ModernUiRendererLib/ModernUiRendererLib.c index e7403ce..6fbce28 100644 --- a/Library/ModernUiRendererLib/ModernUiRendererLib.c +++ b/Library/ModernUiRendererLib/ModernUiRendererLib.c @@ -528,3 +528,25 @@ ModernUiRenderDateTime ( { 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/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 e6d2ed1..7c13a84 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.c +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.c @@ -2955,6 +2955,14 @@ 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 so it is not wiped by the repaint. Display-only no-op on + // backends that cannot host it. + // + ModernDisplayDrawOemWatermarkOverlay (); + MenuOption = NULL; } diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.h b/Universal/ModernDisplayEngineDxe/FormDisplay.h index dc44082..9e4bc2d 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.h +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.h @@ -210,6 +210,21 @@ ModernDisplayClearValueLane ( 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. Display-only; parses no HII and owns no FormBrowser state. No-op (no + error) on backends or regions that cannot host the mark. +**/ +VOID +EFIAPI +ModernDisplayDrawOemWatermarkOverlay ( + VOID + ); + // // Screen definitions // From 19f729df390a2fe80ab00544fd1dce6dbfb16556 Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Sat, 6 Jun 2026 22:17:41 +0800 Subject: [PATCH 10/17] fix(displayengine): modern popups render full text, no dashed border In-setup confirm/error dialogs looked retro and clipped under the modern renderer: 1. Text truncated with "..." -- the native DisplayEngine sizes popups in character columns, but the modern proportional font advances wider than a text-grid cell, so a budget derived from the char count clipped the dialog's own message ("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. Dashed-border seam -- the native engine frames popups and multi-string boxes with Unicode box-drawing glyphs (U+2500..U+257F), which the modern glyph renderer painted as dashes on top of the panel surface that already supplies the frame. ModernDisplayCopyPrintable now drops that block in modern mode. Renderer-layer only: edk2 still owns the dialog control flow, key handling, and message strings. Verified by OVMF X64 lvgl screendump of the F9 "Load defaults" confirm dialog, plus smoke. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 12 +++++++++ .../CustomizedDisplayLibInternal.c | 26 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2068169..2447d14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -520,6 +520,18 @@ 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 diff --git a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c index 37a656b..fda5a51 100644 --- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c +++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c @@ -726,6 +726,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]; } @@ -2319,6 +2329,7 @@ PrintInternal ( UINTN TextY; UINTN TextMaxWidth; UINTN TextInset; + UINTN MeasuredWidth; CHAR16 *Printable; EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground; EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background; @@ -2398,6 +2409,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, From 50005a46e3d63f49af0466164db00796bdba7379 Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Sat, 6 Jun 2026 22:26:33 +0800 Subject: [PATCH 11/17] docs: add productization status & roadmap A living, checklist-style read on how far the engine (GOP "modern" and LVGL "beautiful" lines) and the ModernSetupApp front page are from shipping on real platforms, with ordered remaining work, effort sizing, and the decisions that gate the rest. Complements the existing feature/validation matrices rather than duplicating them; records the LVGL backend graduation, CJK font, memory budget, and hardware-validation thresholds as the real product gates, plus the known watermark-on-dense-form regression and the LvglDisplayEngineDxe cleanup backlog. Co-Authored-By: Claude Opus 4.8 --- Docs/PRODUCTIZATION_STATUS.md | 141 ++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 Docs/PRODUCTIZATION_STATUS.md diff --git a/Docs/PRODUCTIZATION_STATUS.md b/Docs/PRODUCTIZATION_STATUS.md new file mode 100644 index 0000000..861cda9 --- /dev/null +++ b/Docs/PRODUCTIZATION_STATUS.md @@ -0,0 +1,141 @@ + + +# 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** — LVGL bundled fonts are Latin-only; CJK falls back to HII font | M–L | Must clear for an XArch + Chinese-string product. | +| [ ] | **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. | +| [ ] | Fix watermark-on-dense-form regression (see Known issues) | S | | + +## 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** — the OEM watermark is anchored in the content + region's bottom whitespace, but on a form whose rows fill the content area it + tints faintly over the last rows. Fix: only composite when the anchor band is + genuinely empty (suppress when statement rows reach it). Effort: **S**. +- 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". From 51ed4c86d6aebc599f66708262d803c4a740b175 Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Sat, 6 Jun 2026 22:33:43 +0800 Subject: [PATCH 12/17] fix(branding): confine OEM watermark to genuine content whitespace The watermark was anchored in the content region's bottom whitespace, but on a form whose statement rows fill the content area it tinted faintly over the last rows (a regression from the watermark feature). The DisplayEngine now passes the first empty row (FirstEmptyRow, captured before the empty-row clear loop) to ModernDisplayDrawOemWatermarkOverlay, which confines the mark to the whitespace band from that row down to the content bottom. When the rows reach the content bottom the band collapses below the renderer's minimum-size guard, so the mark is suppressed instead of painting over a statement row. Placement on forms that do have whitespace is unchanged. Verified by OVMF X64 lvgl screendumps: dense DriverSample form (mark suppressed) and short dynamic sub-form (mark still shown in whitespace), plus smoke. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 9 ++++-- Docs/PRODUCTIZATION_STATUS.md | 9 +++--- .../CustomizedDisplayLibInternal.c | 32 +++++++++++++++---- .../ModernDisplayEngineDxe/FormDisplay.c | 14 ++++++-- .../ModernDisplayEngineDxe/FormDisplay.h | 11 +++++-- 5 files changed, 55 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2447d14..fd4d971 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,9 +26,12 @@ this file as both a release log and a lightweight development progress record. 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. Display-only: parses no HII, owns no FormBrowser state. Verified - by OVMF X64 lvgl screendump of a DriverSample sub-form with content whitespace, - plus smoke. + 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 diff --git a/Docs/PRODUCTIZATION_STATUS.md b/Docs/PRODUCTIZATION_STATUS.md index 861cda9..24a4dcb 100644 --- a/Docs/PRODUCTIZATION_STATUS.md +++ b/Docs/PRODUCTIZATION_STATUS.md @@ -83,7 +83,7 @@ This is the north-star look (mature graphics library). Critical path is ordered. | [ ] | **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. | -| [ ] | Fix watermark-on-dense-form regression (see Known issues) | S | | +| [x] | Watermark confined to genuine whitespace (suppressed on dense forms) | — | 2026-06-06. | ## Track C — Front-page app, ModernSetupApp (~57%) @@ -110,10 +110,9 @@ Architecturally complete and boundary-guarded; the gap is "filling in", not desi ## Known issues / regressions -- **Watermark on dense forms** — the OEM watermark is anchored in the content - region's bottom whitespace, but on a form whose rows fill the content area it - tints faintly over the last rows. Fix: only composite when the anchor band is - genuinely empty (suppress when statement rows reach it). Effort: **S**. +- ~~**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) diff --git a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c index fda5a51..fa7a86d 100644 --- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c +++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c @@ -1457,22 +1457,27 @@ ModernDisplayDrawPageChrome ( 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. It computes the same - content rectangle the chrome uses and forwards to the renderer's - ModernUiDrawOemWatermark, which no-ops on backends/regions that cannot host it. + 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 ModernDisplayDrawOemWatermarkOverlay ( - VOID + IN UINTN FirstEmptyRow ) { CONST MODERN_UI_THEME *Theme; UINTN CellWidth; UINTN CellHeight; UINTN HelpStartColumn; + UINTN WhitespaceTopRow; MODERN_DISPLAY_LAYOUT Layout; MODERN_UI_RECT Content; @@ -1497,10 +1502,25 @@ ModernDisplayDrawOemWatermarkOverlay ( 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 = Layout.ContentTopRow * CellHeight; + Content.Y = WhitespaceTopRow * CellHeight; Content.Width = (HelpStartColumn - Layout.ContentLeftColumn) * CellWidth; - Content.Height = (Layout.ContentBottomRow - Layout.ContentTopRow) * CellHeight; + Content.Height = (Layout.ContentBottomRow - WhitespaceTopRow) * CellHeight; ModernUiDrawOemWatermark (&mModernRenderContext, Content, Theme); } diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.c b/Universal/ModernDisplayEngineDxe/FormDisplay.c index 7c13a84..621b93e 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.c +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.c @@ -2696,6 +2696,7 @@ UiDisplayMenu ( UINTN Temp2; UINTN TopRow; UINTN BottomRow; + UINTN FirstEmptyRow; UINTN Index; CHAR16 *StringPtr; CHAR16 *StringRightPtr; @@ -2927,6 +2928,12 @@ UiDisplayMenu ( // 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) { @@ -2958,10 +2965,11 @@ UiDisplayMenu ( // // The content area (rows + empty-row clear above) has now been fully // painted. Composite the OEM brand watermark on top of the cleared - // whitespace so it is not wiped by the repaint. Display-only no-op on - // backends that cannot host it. + // 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 (); + ModernDisplayDrawOemWatermarkOverlay (FirstEmptyRow); MenuOption = NULL; } diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.h b/Universal/ModernDisplayEngineDxe/FormDisplay.h index 9e4bc2d..3673295 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.h +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.h @@ -216,13 +216,18 @@ ModernDisplayClearValueLane ( 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. Display-only; parses no HII and owns no FormBrowser state. No-op (no - error) on backends or regions that cannot host the mark. + 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 ( - VOID + IN UINTN FirstEmptyRow ); // From dd8f3eed2a48c4897e64b36366b98a18556245e9 Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Sat, 6 Jun 2026 23:07:08 +0800 Subject: [PATCH 13/17] feat(displayengine): localize in-setup chrome via ModernUiStringLib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The modern DisplayEngine chrome (header product/mode names and the tab-hint labels) was pinned to English even when the active language is Simplified Chinese, so entering a setup form broke the localization the front-page app already had. Route those labels through ModernUiGetString so the header reads "现代UEFI设置工具 / 高级模式" with tabs "设置分类 / 设备 / 启动 / 安全 / 退出" under the zh-Hans default (PcdModernSetupDefaultLanguage). The CJK glyphs come from the existing embedded Noto Sans CJK SC subset. Labels are a visual hint only -- no change to form navigation, HII GUID binding, callbacks, or storage. To make this linkable from the DisplayEngine: - ModernUiStringLib now declares DXE_DRIVER (was UEFI_APPLICATION only); - it is added to the modern/lvgl DisplayEngine overlay library block (moved out of the app-only block, which is always co-applied) in all four target build scripts, and to the CustomizedDisplayLib LibraryClasses. Verified by an OVMF X64 lvgl screendump of a DriverSample form with the chrome in Chinese, the modern (GOP) build, and smoke. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 12 ++++++++++ Docs/PRODUCTIZATION_STATUS.md | 2 +- .../CustomizedDisplayLibInternal.c | 24 ++++++++++++------- .../CustomizedDisplayLibInternal.h | 1 + .../ModernUiCustomizedDisplayLib.inf | 1 + .../ModernUiStringLib/ModernUiStringLib.inf | 2 +- Scripts/build-armvirt.sh | 2 +- Scripts/build-loongarchvirt.sh | 2 +- Scripts/build-ovmf-x64.sh | 2 +- Scripts/build-riscvvirt.sh | 2 +- 10 files changed, 35 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd4d971..0d14407 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,18 @@ 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 diff --git a/Docs/PRODUCTIZATION_STATUS.md b/Docs/PRODUCTIZATION_STATUS.md index 24a4dcb..f125acb 100644 --- a/Docs/PRODUCTIZATION_STATUS.md +++ b/Docs/PRODUCTIZATION_STATUS.md @@ -79,7 +79,7 @@ This is the north-star look (mature graphics library). Critical path is ordered. | [ ] | **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** — LVGL bundled fonts are Latin-only; CJK falls back to HII font | M–L | Must clear for an XArch + Chinese-string product. | +| [~] | **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. | diff --git a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c index fa7a86d..3b456d2 100644 --- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c +++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c @@ -1371,13 +1371,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); @@ -1428,13 +1422,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); 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/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: From b21250658045357e8e3e46ca67ec09919140dbf0 Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Sun, 7 Jun 2026 23:19:27 +0800 Subject: [PATCH 14/17] feat(displayengine): reveal modern selection styling on highlighted row The highlighted statement row rendered as a flat, muddy SelectedBand band even though ModernDisplayDrawStatementRow already paints a modern row-level selection (inset bar, top/bottom sheen, left accent, framed border) underneath -- the native per-cell text print buried it under a solid fill. The per-cell print path (PrintInternal) now suppresses that flat highlight fill on the single row that just received selection styling, tracked by mModernStyledHighlightRow (set in ModernDisplayDrawStatementRow, cleared when the row de-highlights). The skip is scoped to that exact row, so other EFI_RED-background text -- a highlighted selectable-popup option, which has no row-level styling beneath it -- still fills normally and keeps its highlight. Display-only; no change to navigation, editing, or HII ownership. Applies to both the GOP "modern" and LVGL backends. Verified by OVMF X64 lvgl screendumps: selection at rest, after a highlight move (no stale band on the previous row), and an open one-of popup (highlighted option unchanged), plus the modern build and smoke. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 13 ++++++ .../CustomizedDisplayLibInternal.c | 40 ++++++++++++++++--- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d14407..51e1130 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -390,6 +390,19 @@ this file as both a release log and a lightweight development progress record. ### Changed +- 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 / diff --git a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c index 3b456d2..610fb2e 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 @@ -1057,6 +1065,17 @@ 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; + } } /** @@ -2420,11 +2439,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) { From 96369bc50400b07591534b663779b14c91bbc5f5 Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Sun, 7 Jun 2026 23:35:22 +0800 Subject: [PATCH 15/17] feat(renderer): clean single-intent selected-row styling Refine the selected row from a busy, muddy treatment (full SelectedBand band + inset blend + top/bottom sheens + framed border + inner highlight line) into a clean, single-intent look: a subtle warm-tinted fill plus one solid 6px left accent stripe. The selection color is sourced once in ModernUiGetSelectableRowBackground (Surface blended ~30% toward AccentYellow instead of BackgroundBlack+SelectedBand at 74%), so the row fill and the per-cell text anti-alias background stay matched and there are no glyph halos. ModernUiDrawSelectableRow's selected branch is reduced to the left accent stripe. Shared visual primitive: applies to both the GOP and LVGL backends and to selectable rows in both the front-page app and the in-setup browser. Verified by OVMF X64 lvgl screendumps (selection clear and clean, text legible), the modern build, and smoke. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 9 +++ .../ModernUiRendererCommon.c | 71 +++++-------------- 2 files changed, 27 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51e1130..0b47ab4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -390,6 +390,15 @@ this file as both a release log and a lightweight development progress record. ### Changed +- 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 diff --git a/Library/ModernUiRendererLib/ModernUiRendererCommon.c b/Library/ModernUiRendererLib/ModernUiRendererCommon.c index fbc5022..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)) { From 53c90dd8aff655a2dca5e789eba7618c1d3c7098 Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Sun, 7 Jun 2026 23:51:05 +0800 Subject: [PATCH 16/17] feat(displayengine): soft accent for the CONTEXT HELP rail label The "CONTEXT HELP" label rendered as plain muted body text, reading as an oversight next to the gold CPU/Memory/Voltage rail headers. Give it a soft muted-gold accent (AccentYellow blended 50% toward MutedText) so it reads as a styled section header while staying deliberately subdued below the primary telemetry rail in the visual hierarchy. Display-only label color; keeps the MutedText token the right-help-rail smoke guard requires. Verified by an OVMF X64 lvgl screendump and smoke. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 5 +++++ .../CustomizedDisplayLibInternal.c | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b47ab4..7196d39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -390,6 +390,11 @@ 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 diff --git a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c index 610fb2e..a3cff13 100644 --- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c +++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c @@ -479,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 ); From 1b47c2e7586f1d2f448fd734f0656127294dbf62 Mon Sep 17 00:00:00 2001 From: MarsDoge Date: Mon, 8 Jun 2026 00:19:54 +0800 Subject: [PATCH 17/17] fix(displayengine): correct watermark-overlay ABI + popup highlight-row reset Two issues found in self-review of this branch: 1. ABI mismatch: ModernDisplayDrawOemWatermarkOverlay was declared EFIAPI in FormDisplay.h (and called through that prototype) but defined without EFIAPI. The defining TU does not include FormDisplay.h, so no diagnostic fired. On toolchains where EFIAPI differs from the default (e.g. GCC X64 ms_abi vs SysV), FirstEmptyRow would be read from the wrong register, defeating the watermark whitespace-confinement. Add EFIAPI to the definition to match the declaration and the sibling functions in the file. 2. Stale highlight-row tracking across popups: the per-cell print path skips the highlight fill on the row recorded by ModernDisplayDrawStatementRow. A selectable-option popup prints its highlighted option with an EFI_RED background via PrintStringAt without going through ModernDisplayDrawStatementRow, so if that option shares the recorded grid row its fill was wrongly skipped, leaving the option without a highlight. Add ModernDisplayResetHighlightRowTracking and call it at CreatePopup entry so popup lines are never mistaken for the styled statement row. Verified by OVMF X64 lvgl screendumps: watermark still shown on a short form and suppressed on a dense form (FirstEmptyRow passed correctly), and a one-of option popup with the highlighted option correctly filled, plus smoke. Co-Authored-By: Claude Opus 4.8 --- .../CustomizedDisplayLibInternal.c | 21 +++++++++++++++++++ .../ModernDisplayEngineDxe/FormDisplay.h | 15 +++++++++++++ Universal/ModernDisplayEngineDxe/Popup.c | 8 +++++++ 3 files changed, 44 insertions(+) diff --git a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c index a3cff13..5a1c320 100644 --- a/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c +++ b/Library/ModernUiCustomizedDisplayLib/CustomizedDisplayLibInternal.c @@ -1084,6 +1084,26 @@ ModernDisplayDrawStatementRow ( } } +/** + 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; +} + /** Draw a per-opcode control affordance over an already-painted statement row. @@ -1500,6 +1520,7 @@ ModernDisplayDrawPageChrome ( begins. **/ VOID +EFIAPI ModernDisplayDrawOemWatermarkOverlay ( IN UINTN FirstEmptyRow ) diff --git a/Universal/ModernDisplayEngineDxe/FormDisplay.h b/Universal/ModernDisplayEngineDxe/FormDisplay.h index 3673295..f4b9924 100644 --- a/Universal/ModernDisplayEngineDxe/FormDisplay.h +++ b/Universal/ModernDisplayEngineDxe/FormDisplay.h @@ -230,6 +230,21 @@ 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/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);