Kaynağa Gözat

Add tigr graphics backend and a multi-line editor to tvision-m2

tigr graphics backend (tvg + tvfont):
- tv gained InitVirtual(cols,rows) and CellAt so any driver can set the
  virtual screen size and read the cell buffer without touching the tty.
- tvg.def/tvg.mod render the same view tree, widgets, menus and dialogs
  into a tigr window: text from a bundled 8x16 monospaced VGA font,
  box-drawing as line segments, tigr keyboard/mouse mapped to tv events.
- tvfont.def/tvfont.mod carry the public-domain IBM VGA 8x16 glyphs and a
  code-point lookup, so no system font is required.
- examples/gfx.mod demonstrates the backend; terminal programs stay free
  of any graphics dependency.

Editor widget (VEditor + EditorData):
- A multi-line editor with insert/overwrite, Enter/Backspace/Delete with
  line join/split, arrows/Home/End/PgUp/PgDn, Tab indent, mouse cursor
  placement and wheel scroll, and its own Ln/Col/Insert/Modified row.
- EditorLoad/EditorSave read and write text files (via a small libc
  binding in tvtty.def); EditorInit/EditorAddLine/EditorGetLine/EditorDirty
  complete the API.
- examples/edit.mod is a full-screen editor with a File menu
  (New/Save/Quit) and a status bar.

Docs updated: API.md (graphics backend, editor), TUTORIAL.md (editor,
graphics sections), README.md, SUMMARY.md.
Eric Streit 3 hafta önce
ebeveyn
işleme
40d6d3a609

+ 68 - 0
tvision-m2/API.md

@@ -95,6 +95,42 @@ TYPE ListData = RECORD
      END;  ListDataPtr = POINTER TO ListData;
 ```
 
+## Editor
+
+```
+TYPE EditorData = RECORD ... END; EditorDataPtr = POINTER TO EditorData;
+```
+
+Declare one `EditorData` (a few tens of KB) per editor, attach it to a
+`VEditor` view, and it becomes a full multi-line editor with its own frame
+and a Ln/Col/Insert/Modified status row.
+
+```
+VAR ed : tv.EditorData; edp : tv.EditorDataPtr;
+...
+edp := CAST(tv.EditorDataPtr, ADR(ed));
+tv.EditorInit(edp);                    (* empty; or EditorLoad below *)
+tv.EditorAddLine(edp, "MODULE hello;");  (* build sample text *)
+ev := tv.NewView(tv.VEditor, 2, 2, 60, 20);
+tv.EditorAttach(ev, edp);
+tv.AddView(win, ev);
+tv.FocusView(ev);
+```
+
+| procedure | description |
+|---|---|
+| `EditorAttach(v, data)` | tie an editor buffer to a `VEditor` view |
+| `EditorInit(data)` | clear to a single empty line |
+| `EditorAddLine(data, s)` | append a line (for building text) |
+| `EditorGetLine(data, i, VAR s)` | read a line back |
+| `EditorLoad(data, path) : BOOLEAN` | load a text file into the buffer |
+| `EditorSave(data, path) : BOOLEAN` | save the buffer to a text file |
+| `EditorDirty(data) : BOOLEAN` | TRUE if modified since load/save |
+
+Keys: printable text, Enter, Backspace, Delete, arrows, Home/End, PgUp/PgDn,
+Tab (indent to a 4-column stop), Ins (insert/overwrite).  The mouse places
+the cursor and the wheel scrolls.
+
 ## Menus
 
 `MenuBarInit`, `MenuAdd(title)`, `MenuItemAdd(text, tag)`, `MenuSep`,
@@ -128,8 +164,40 @@ the close box.
 `mbOKCancel` or `mbYesNo`; returns `cmOK`, `cmCancel`, `cmYes` or `cmNo`.
 `Message(title, text)` is shorthand for `MessageBox(..., mbOK)`.
 
+## Graphics backend (tvg)
+
+`tvg` renders the same view tree into a tigr window instead of a terminal.
+Terminal programs do not link tigr.
+
+```
+IMPORT tv, tvg;
+...
+tvg.InitGfx("my app", 90, 30);   (* title, grid cols x rows *)
+... build views with tv as usual ...
+tvg.Finish;
+WHILE ... DO
+    IF tvg.ReadEvent(e) THEN cmd := tv.HandleEvent(e); ...; tvg.Finish END;
+    IF tvg.Closed() THEN quit := TRUE END
+END;
+tvg.Done
+```
+
+Use `tv.InitVirtual(cols, rows)` (not `tv.Init`) when driving `tv` from a
+non-terminal backend; it sets the virtual screen size without touching the
+tty.  `tvg` maps tigr keys and mouse to the same `tv.Event`; the cell grid
+is `tv.Cols()` x `tv.Rows()`, each cell `CellW()` x `CellH()` pixels.  Text
+is drawn from `tvfont` (a bundled 8x16 monospaced VGA font, so no system font
+is required); box-drawing cells are rendered as line segments.
+
 ## Building against the library
 
     gm2 -fiso -c tvtty.def
     gm2 -fiso -I. -c tv.mod
     gm2 -fiso -I. tv.o myapp.mod -o myapp
+
+For the graphics backend also build `tvg.o` (needs the tigr binding):
+
+    gm2 -fiso -I. -c tvfont.mod
+    gm2 -fiso -I. -I../modula2 -c tvg.mod
+    gm2 -fiso -I. -I../modula2 tv.o tvg.o tvfont.o \
+         ../modula2/tigr.o ../modula2/helper.o myapp.mod -o myapp -lGL -lX11

+ 7 - 1
tvision-m2/Makefile

@@ -1,7 +1,7 @@
 GM2 = gm2
 FLAGS = -fiso -I.
 
-all: demo
+all: demo tvg.o tvfont.o
 
 tv.o: tv.mod tv.def tvtty.def
 	$(GM2) $(FLAGS) -c tv.mod
@@ -9,6 +9,12 @@ tv.o: tv.mod tv.def tvtty.def
 demo: tv.o demo.mod
 	$(GM2) $(FLAGS) tv.o demo.mod -o demo
 
+tvfont.o: tvfont.mod tvfont.def
+	$(GM2) $(FLAGS) -c tvfont.mod
+
+tvg.o: tvg.mod tvg.def tvfont.o tv.o
+	$(GM2) -fiso -I. -I../modula2 -c tvg.mod
+
 ttysize: ttysize.mod tvtty.def
 	$(GM2) $(FLAGS) ttysize.mod -o ttysize
 

+ 18 - 3
tvision-m2/README.md

@@ -16,6 +16,8 @@ the terminal in raw mode and to query its size (`termios`, `ioctl`, `read`,
 |---|---|
 | `tvtty.def` | libc binding (raw mode, winsize, read/write) |
 | `tv.def` / `tv.mod` | the toolkit: screen, view tree, widgets, events |
+| `tvg.def` / `tvg.mod` | tigr graphics backend (renders the view tree in a window) |
+| `tvfont.def` / `tvfont.mod` | bundled 8x16 monospaced bitmap font for the backend |
 | `demo.mod` | demo application |
 | `ttysize.mod` | diagnostic: checks the tty binding |
 
@@ -28,7 +30,12 @@ the terminal in raw mode and to query its size (`termios`, `ioctl`, `read`,
 
     make -C examples
 
-or simply `make`.  Run it from a real terminal; `Esc` exits.  See
+or simply `make`.  The graphics example needs the tigr object from the
+sibling project:
+
+    make tvg.o tvfont.o
+    make -C examples gfx
+    ./examples/gfx  Run it from a real terminal; `Esc` exits.  See
 `TUTORIAL.md` to write your own and `API.md` for the full reference.
 
 ## What works
@@ -41,6 +48,10 @@ or simply `make`.  Run it from a real terminal; `Esc` exits.  See
 - Windows: double-line frame, title, ` X ` close box, draggable by the title
   bar with the mouse.
 - Menu bar + drop-down menus (mouse and keyboard).
+- Multi-line editor widget (`VEditor`): insert/overwrite, arrows/Home/End/
+  PgUp/PgDn, Enter/Backspace/Delete, Tab indent, mouse positioning, wheel
+  scroll, its own Ln/Col/Insert/Modified status row, plus load/save to a
+  file (`EditorLoad`/`EditorSave`).
 - Widgets: static text, single/double frame, input line (insert, backspace,
   delete, Home/End/arrows), push button, check box, radio buttons, list box
   with selection and wheel scrolling, vertical scroll bar.
@@ -55,6 +66,11 @@ or simply `make`.  Run it from a real terminal; `Esc` exits.  See
   `DlgButton`/`DlgRun`/`DlgTextAt`/`DlgValue`) and `MessageBox` (OK /
   OK-Cancel / Yes-No), plus the `Message` shorthand.
 - SIGWINCH-driven resize detection (`Resized`), no polling required.
+- Optional **tigr graphics backend** (`tvg`): the same views, widgets, menus
+  and dialogs render inside a tigr window (colours, box drawing and text via
+  a bundled 8x16 monospaced VGA font, box drawing as line segments); tigr
+  keyboard/mouse are turned into the same events.
+  Terminal programs stay free of any graphics dependency.
 - Menu bar with drop-down menus: click a title (or press `F10`), navigate
   with Left/Right/Up/Down, select with Enter/Space or a mouse click;
   item separators (`MenuSep`) are supported.  The selected item's tag is
@@ -64,9 +80,8 @@ or simply `make`.  Run it from a real terminal; `Esc` exits.  See
 
 - Form validation and a file/directory dialog.
 - Menu item hotkeys (Alt+letter) and check/radio menu items.
-- A tigr graphics backend so the same UI can run in a window.
 - Nested clipping groups and a desktop with many windows / tiling.
-- More widgets: multi-line editor, tabs, combo box, progress bar.
+- Tabs, combo box, progress bar, syntax highlighting, search/replace.
 - `SIGWINCH`-driven relayout (today the app polls the size).
 - Mouse hover highlight and resizable windows.
 

+ 12 - 3
tvision-m2/SUMMARY.md

@@ -44,8 +44,16 @@ from the captured terminal stream).
   check boxes (self-exclusive radio groups) and tagged buttons; `MessageBox`
   (OK / OK-Cancel / Yes-No) and the `Message` shorthand.
 - SIGWINCH-driven resize detection via a libc `signal` handler.
-- Example programs (`empty`, `window`, `dialog`, `menus`); API reference
-  (`API.md`) and tutorial (`TUTORIAL.md`).
+- Multi-line editor widget (`VEditor`) with insert/overwrite, navigation,
+  Tab indent, mouse positioning, a Ln/Col/Insert/Modified status row and
+  file load/save; demo `examples/edit`.
+- Example programs (`empty`, `window`, `dialog`, `menus`, `edit`, `gfx`); API
+  reference (`API.md`) and tutorial (`TUTORIAL.md`).
+- tigr graphics backend (`tvg`): the same view tree rendered in a window.
+  Text uses a bundled 8x16 monospaced VGA font (`tvfont`, public-domain IBM
+  VGA glyphs) so no system font is needed; box drawing is line segments;
+  tigr keyboard/mouse are mapped to tv events.  `tv.InitVirtual` lets any driver set the
+  virtual screen size without touching the terminal.
 - Menu bar with drop-down menus: click or `F10` to open, Left/Right switch
   menus, Up/Down move, Enter/Space or click selects (returns the item tag);
   separators supported.
@@ -66,7 +74,8 @@ Driving the demo through a pty and reconstructing the screen:
 
 - Menu items have no hotkeys; no check/radio menu items.
 - No form validation or file/directory dialog.
-- No tigr graphics backend yet.
+- The graphics window uses integer scaling (TIGR_FIXED); no per-window
+  font size or resizable grid yet.
 - Windows are not resizable; no hover highlight.
 - Terminal size is polled (no `SIGWINCH`-driven relayout).
 - Nested clipping groups beyond windows are untested.

+ 44 - 1
tvision-m2/TUTORIAL.md

@@ -142,7 +142,50 @@ The mouse works automatically: click to focus/press buttons, drag window
 titles, click list rows and scroll with the wheel.  You only need
 `HandleEvent`; the toolkit does the hit-testing.
 
-## 7. More examples
+## 7. A text editor
+
+```modula2
+VAR ed : tv.EditorData; edp : tv.EditorDataPtr; ev : tv.ViewPtr;
+...
+edp := CAST(tv.EditorDataPtr, ADR(ed));
+IF NOT tv.EditorLoad(edp, "notes.txt") THEN
+    tv.EditorInit(edp); tv.EditorAddLine(edp, "Type here...")
+END;
+ev := tv.NewView(tv.VEditor, 2, 2, 60, 20);
+tv.EditorAttach(ev, edp);
+tv.AddView(win, ev);
+tv.FocusView(ev);
+...
+IF tv.EditorSave(edp, "notes.txt") THEN ... END;
+```
+
+See `examples/edit.mod` for a full-screen editor with a File menu.
+
+## 8. Running in a graphics window (tigr)
+
+`tvg` is a drop-in replacement for the terminal loop:
+
+```modula2
+IMPORT tv, tvg;
+...
+IF NOT tvg.InitGfx("my app", 90, 30) THEN HALT END;
+tv.MenuBarInit; ... build views on tv.Desk() ...
+tvg.Finish;
+WHILE NOT quit DO
+    IF tvg.ReadEvent(e) THEN
+        cmd := tv.HandleEvent(e);          (* same events, same commands *)
+        IF (e.kind = tv.evKey) AND (e.key = tv.kEsc) THEN quit := TRUE END;
+        tvg.Finish
+    END;
+    IF tvg.Closed() THEN quit := TRUE END
+END;
+tvg.Done
+```
+
+Build it with `make tvg.o` then `make -C examples gfx`; see `examples/gfx.mod`.
+The toolkit code (windows, widgets, menus, dialogs) is identical.
+
+## 9. More examples
 
 See `examples/` (`empty`, `window`, `dialog`, `menus`) and build them with
 `make`.  See `API.md` for the full reference.

BIN
tvision-m2/demo


+ 7 - 3
tvision-m2/examples/Makefile

@@ -1,14 +1,18 @@
 GM2 = gm2
 FLAGS = -fiso -I ..
 TV = ../tv.o
-PROGS = empty window dialog menus
+PROGS = empty window dialog menus edit
 
-all: $(PROGS)
+all: $(PROGS) gfx
 
 %: %.mod $(TV)
 	$(GM2) $(FLAGS) $(TV) $< -o $@
 
+gfx: gfx.mod ../tvg.o ../tvfont.o $(TV) ../../modula2/tigr.o ../../modula2/helper.o
+	$(GM2) -fiso -I .. -I ../../modula2 ../tvg.o ../tvfont.o $(TV) \
+	     ../../modula2/tigr.o ../../modula2/helper.o gfx.mod -o gfx -lGL -lX11
+
 clean:
-	rm -f $(PROGS)
+	rm -f $(PROGS) gfx
 
 .PHONY: all clean

BIN
tvision-m2/examples/dialog


BIN
tvision-m2/examples/edit


+ 111 - 0
tvision-m2/examples/edit.mod

@@ -0,0 +1,111 @@
+MODULE edit;
+
+(* A small full-screen editor, Turbo-Pascal style: a window containing a
+   multi-line editor with its own status row, plus a File menu
+   (New / Save / Quit).
+
+   Arrows, Home/End, PgUp/PgDn move; Ins toggles insert/overwrite; Tab
+   indents; the mouse positions the cursor and the wheel scrolls.  It loads
+   and saves "tvision-edit.txt". *)
+
+FROM InOut IMPORT WriteString, WriteLn;
+FROM SYSTEM IMPORT ADR, CAST;
+IMPORT tv;
+
+CONST
+    mNew   = 100;
+    mSave  = 101;
+    mQuit  = 102;
+
+VAR
+    ed : tv.EditorData;
+    edp : tv.EditorDataPtr;
+    w, edView, bar : tv.ViewPtr;
+    e : tv.Event;
+    quit : BOOLEAN;
+    cmd : INTEGER;
+    sender : tv.ViewPtr;
+    status : ARRAY [0..95] OF CHAR;
+
+PROCEDURE Sample;
+BEGIN
+    tv.EditorInit(edp);
+    tv.EditorAddLine(edp, "MODULE hello;");
+    tv.EditorAddLine(edp, "");
+    tv.EditorAddLine(edp, "FROM InOut IMPORT WriteString, WriteLn;");
+    tv.EditorAddLine(edp, "");
+    tv.EditorAddLine(edp, "BEGIN");
+    tv.EditorAddLine(edp, "    WriteString('Hello, world.'); WriteLn");
+    tv.EditorAddLine(edp, "END hello.");
+    ed.dirty := FALSE
+END Sample;
+
+PROCEDURE Refresh;
+BEGIN
+    IF tv.EditorDirty(edp) THEN
+        tv.SetText(bar, " Ins/arrows/Tab edit   F10: menu   * modified")
+    ELSE
+        tv.SetText(bar, " Ins/arrows/Tab edit   F10: menu     saved")
+    END;
+    tv.Finish
+END Refresh;
+
+BEGIN
+    IF NOT tv.Init() THEN
+        WriteString("not a tty"); WriteLn; HALT
+    END;
+
+    edp := CAST(tv.EditorDataPtr, ADR(ed));
+
+    tv.MenuBarInit;
+    tv.MenuAdd("File");
+    tv.MenuItemAdd("New", mNew);
+    tv.MenuItemAdd("Save", mSave);
+    tv.MenuSep;
+    tv.MenuItemAdd("Quit", mQuit);
+
+    bar := tv.NewView(tv.VText, 0, tv.Rows() - 1, tv.Cols(), 1);
+    tv.AddView(tv.Desk(), bar);
+
+    w := tv.NewView(tv.VWindow, 1, 1, tv.Cols() - 2, tv.Rows() - 3);
+    tv.SetText(w, "Editor");
+    tv.AddView(tv.Desk(), w);
+
+    IF NOT tv.EditorLoad(edp, "tvision-edit.txt") THEN Sample END;
+
+    edView := tv.NewView(tv.VEditor, 2, 2, tv.Cols() - 4, tv.Rows() - 5);
+    tv.EditorAttach(edView, CAST(tv.EditorDataPtr, ADR(ed)));
+    tv.AddView(w, edView);
+    tv.FocusView(edView);
+
+    Refresh;
+    quit := FALSE;
+    WHILE NOT quit DO
+        IF tv.Resized() THEN Refresh END;
+        IF tv.ReadEvent(e) THEN
+            IF (e.kind = tv.evKey) AND (e.key = tv.kEsc) THEN
+                quit := TRUE
+            ELSE
+                cmd := tv.HandleEvent(e);
+                sender := tv.Sender();
+                IF cmd = mQuit THEN
+                    quit := TRUE
+                ELSIF cmd = mNew THEN
+                    Sample; Refresh
+                ELSIF cmd = mSave THEN
+                    IF tv.EditorSave(edp, "tvision-edit.txt") THEN
+                        tv.Message("Save", "Saved tvision-edit.txt.")
+                    ELSE
+                        tv.Message("Save", "Could not save the file.")
+                    END;
+                    Refresh
+                ELSIF cmd = tv.cmClose THEN
+                    quit := TRUE
+                END
+            END;
+            IF NOT quit THEN Refresh END
+        END
+    END;
+
+    tv.Done
+END edit.

BIN
tvision-m2/examples/empty


BIN
tvision-m2/examples/gfx


+ 127 - 0
tvision-m2/examples/gfx.mod

@@ -0,0 +1,127 @@
+MODULE gfx;
+
+(* The tv toolkit running on the tigr graphics backend instead of a terminal.
+
+   Build (from tvision-m2/examples):
+       make gfx
+   Needs tigr.o and helper.o built in ../modula2 (gcc -c ...). *)
+
+FROM InOut IMPORT WriteString, WriteLn;
+FROM SYSTEM IMPORT ADR, CAST;
+IMPORT tv, tvg;
+
+CONST
+    mNew   = 100;
+    mQuit  = 101;
+    mAbout = 102;
+    mCut   = 103;
+    mCopy  = 104;
+
+VAR
+    w1, w2, status : tv.ViewPtr;
+    input, check, r1, r2, listv : tv.ViewPtr;
+    t : tv.ViewPtr;
+    listData : tv.ListData;
+    e : tv.Event;
+    quit : BOOLEAN;
+    cmd : INTEGER;
+    sender : tv.ViewPtr;
+    discard : INTEGER;
+    tmp, msgbuf : ARRAY [0..63] OF CHAR;
+
+PROCEDURE SetStatus(s : ARRAY OF CHAR);
+BEGIN tv.SetText(status, s); tvg.Finish END SetStatus;
+
+BEGIN
+    IF NOT tvg.InitGfx("tvision-m2 - tigr backend", 90, 30) THEN
+        WriteString("cannot open the graphics window"); WriteLn; HALT
+    END;
+
+    (* menu bar *)
+    tv.MenuBarInit;
+    tv.MenuAdd("File");
+    tv.MenuItemAdd("New", mNew);
+    tv.MenuSep;
+    tv.MenuItemAdd("Quit", mQuit);
+    tv.MenuAdd("Edit");
+    tv.MenuItemAdd("Cut", mCut);
+    tv.MenuItemAdd("Copy", mCopy);
+    tv.MenuAdd("Help");
+    tv.MenuItemAdd("About", mAbout);
+
+    status := tv.NewView(tv.VText, 0, tv.Rows() - 1, tv.Cols(), 1);
+    tv.SetText(status, " F10/click: menu   Tab: next   mouse: drag/click   Esc: quit");
+    tv.AddView(tv.Desk(), status);
+
+    w1 := tv.NewView(tv.VWindow, 3, 2, 56, 16);
+    tv.SetText(w1, "Editor");
+    t := tv.NewView(tv.VText, 5, 4, 24, 1);
+    tv.SetText(t, "Name:"); tv.AddView(w1, t);
+    input := tv.NewView(tv.VInput, 12, 4, 32, 1);
+    tv.SetText(input, "Modula-2"); tv.AddView(w1, input);
+    check := tv.NewView(tv.VCheck, 12, 6, 24, 1);
+    tv.SetText(check, "Enabled"); check^.flags := tv.vfSelected; tv.AddView(w1, check);
+    t := tv.NewView(tv.VText, 5, 8, 6, 1);
+    tv.SetText(t, "Mode:"); tv.AddView(w1, t);
+    r1 := tv.NewView(tv.VRadio, 12, 8, 12, 1);
+    tv.SetText(r1, "Fast"); r1^.flags := tv.vfSelected; tv.AddView(w1, r1);
+    r2 := tv.NewView(tv.VRadio, 26, 8, 12, 1);
+    tv.SetText(r2, "Safe"); tv.AddView(w1, r2);
+
+    listData.items[0] := "Alpha";   listData.items[1] := "Bravo";
+    listData.items[2] := "Charlie"; listData.items[3] := "Delta";
+    listData.items[4] := "Echo";    listData.items[5] := "Foxtrot";
+    listData.count := 6;
+    listv := tv.NewView(tv.VList, 5, 10, 22, 5);
+    listv^.list := CAST(tv.ListDataPtr, ADR(listData));
+    tv.AddView(w1, listv);
+
+    t := tv.NewView(tv.VButton, 30, 15, 8, 1);
+    tv.SetText(t, "OK"); tv.SetTag(t, tv.cmOK); tv.AddView(w1, t);
+    t := tv.NewView(tv.VButton, 41, 15, 10, 1);
+    tv.SetText(t, "Close"); tv.SetTag(t, tv.cmCancel); tv.AddView(w1, t);
+    tv.AddView(tv.Desk(), w1);
+
+    w2 := tv.NewView(tv.VWindow, 42, 8, 34, 7);
+    tv.SetText(w2, "About");
+    t := tv.NewView(tv.VText, 44, 10, 30, 1);
+    tv.SetText(t, "tvision-m2 on tigr"); tv.AddView(w2, t);
+    t := tv.NewView(tv.VText, 44, 11, 30, 1);
+    tv.SetText(t, "Same view tree, windowed output."); tv.AddView(w2, t);
+    tv.AddView(tv.Desk(), w2);
+
+    tv.BringToFront(w1);
+    tv.FocusView(input);
+    tvg.Finish;
+
+    quit := FALSE;
+    WHILE NOT quit DO
+        IF tvg.ReadEvent(e) THEN
+            IF (e.kind = tv.evKey) AND (e.key = tv.kEsc) THEN
+                quit := TRUE
+            ELSE
+                cmd := tv.HandleEvent(e);
+                sender := tv.Sender();
+                IF cmd = mQuit THEN
+                    quit := TRUE
+                ELSIF cmd = mAbout THEN
+                    discard := tv.MessageBox("About", "tvision-m2 - tigr backend", tv.mbOK);
+                    SetStatus(" About closed")
+                ELSIF cmd = tv.cmOK THEN
+                    discard := tv.MessageBox("Info", "You pressed OK.", tv.mbOK)
+                ELSIF cmd = tv.cmCancel THEN
+                    tv.DelView(w1)
+                ELSIF cmd >= 100 THEN
+                    tv.CopyText(msgbuf, "Command #");
+                    tv.IntToText(tmp, cmd, 0);
+                    tv.AppendText(msgbuf, tmp);
+                    SetStatus(msgbuf)
+                END
+            END;
+            IF NOT quit THEN tvg.Finish END
+        END;
+        IF tvg.Closed() THEN quit := TRUE END
+    END;
+
+    tvg.Done
+END gfx.

BIN
tvision-m2/examples/menus


BIN
tvision-m2/examples/window


+ 31 - 1
tvision-m2/tv.def

@@ -56,6 +56,8 @@ CONST
 
     MAXLINE  = 128;
     MAXVIEWS = 128;
+    EDMAXLINES = 512;
+    EDMAXCOL   = 160;
 
 TYPE
     Attr  = CARDINAL;
@@ -78,6 +80,9 @@ TYPE
 (* ---- screen ------------------------------------------------------------ *)
 
 PROCEDURE Init() : BOOLEAN;
+(* Initialise for a non-terminal driver (e.g. the tigr backend): sets the
+   virtual screen size and resets state without touching the terminal. *)
+PROCEDURE InitVirtual (c, r : INTEGER) : BOOLEAN;
 PROCEDURE Done;
 PROCEDURE Cols() : INTEGER;
 PROCEDURE Rows() : INTEGER;
@@ -87,6 +92,7 @@ PROCEDURE A (fg, bg : INTEGER; blink : BOOLEAN) : Attr;
 PROCEDURE Clear (attr : Attr);
 PROCEDURE Fill (x, y, w, h : INTEGER; cp : CARDINAL; attr : Attr);
 PROCEDURE DrawCh (x, y : INTEGER; cp : CARDINAL; attr : Attr);
+PROCEDURE CellAt (x, y : INTEGER; VAR cp, attr : CARDINAL);
 PROCEDURE DrawText (x, y : INTEGER; s : ARRAY OF CHAR; attr : Attr);
 PROCEDURE DrawBox (r : Rect; style : INTEGER; attr : Attr);
 PROCEDURE DrawShadow (r : Rect; attr : Attr);
@@ -108,7 +114,7 @@ PROCEDURE IntToText (VAR dest : ARRAY OF CHAR; n : INTEGER; width : INTEGER);
 
 TYPE
     VKind = (VGroup, VWindow, VText, VFrame, VInput, VButton,
-             VCheck, VRadio, VList, VScroll);
+             VCheck, VRadio, VList, VScroll, VEditor);
 
     ListData = RECORD
                    items : ARRAY [0..255] OF ARRAY [0..63] OF CHAR;
@@ -116,6 +122,19 @@ TYPE
                END;
     ListDataPtr = POINTER TO ListData;
 
+    (* Multi-line editor buffer.  Declare one per editor (it is a few tens of
+       KB) at module scope and attach it to a VEditor view. *)
+    EditorData = RECORD
+                     line  : ARRAY [0..EDMAXLINES - 1] OF ARRAY [0..EDMAXCOL - 1] OF CHAR;
+                     len   : ARRAY [0..EDMAXLINES - 1] OF INTEGER;
+                     count : INTEGER;
+                     cx, cy : INTEGER;     (* cursor: column, line *)
+                     top, left : INTEGER;  (* scroll *)
+                     ins   : BOOLEAN;      (* insert mode *)
+                     dirty : BOOLEAN;
+                 END;
+    EditorDataPtr = POINTER TO EditorData;
+
     ViewPtr = POINTER TO View;
     View = RECORD
                kind   : VKind;
@@ -127,6 +146,7 @@ TYPE
                value, minv, maxv, tag : INTEGER;
                flags  : CARDINAL;
                list   : ListDataPtr;
+               ed     : EditorDataPtr;
            END;
 
 PROCEDURE NewView (kind : VKind; x, y, w, h : INTEGER) : ViewPtr;
@@ -180,4 +200,14 @@ PROCEDURE MessageBox (title : ARRAY OF CHAR; text : ARRAY OF CHAR;
 (* Modal helper: a message box with an OK button. *)
 PROCEDURE Message (title : ARRAY OF CHAR; text : ARRAY OF CHAR);
 
+(* ---- editor ------------------------------------------------------------ *)
+
+PROCEDURE EditorAttach (v : ViewPtr; data : EditorDataPtr);
+PROCEDURE EditorInit (data : EditorDataPtr);
+PROCEDURE EditorAddLine (data : EditorDataPtr; s : ARRAY OF CHAR);
+PROCEDURE EditorGetLine (data : EditorDataPtr; i : INTEGER; VAR s : ARRAY OF CHAR);
+PROCEDURE EditorLoad (data : EditorDataPtr; path : ARRAY OF CHAR) : BOOLEAN;
+PROCEDURE EditorSave (data : EditorDataPtr; path : ARRAY OF CHAR) : BOOLEAN;
+PROCEDURE EditorDirty (data : EditorDataPtr) : BOOLEAN;
+
 END tv.

+ 385 - 18
tvision-m2/tv.mod

@@ -4,7 +4,8 @@ IMPLEMENTATION MODULE tv;
    See tv.def.  Pure ISO GNU Modula-2 apart from the libc binding tvtty.def. *)
 
 FROM SYSTEM IMPORT ADDRESS, ADR, ADDADR, CAST, BYTE;
-FROM tvtty IMPORT tcgetattr, tcsetattr, ioctl, read, write, signal;
+FROM tvtty IMPORT tcgetattr, tcsetattr, ioctl, read, write, signal,
+                    fopen, fgets, fputs, fputc, fclose;
 
 CONST
     MAXROWS  = 120;
@@ -80,6 +81,7 @@ VAR
 
     winch    : BOOLEAN;
     oldWinch : ADDRESS;
+    virtual  : BOOLEAN;
 
     dlg        : ViewPtr;
     dlgW       : INTEGER;
@@ -214,8 +216,25 @@ BEGIN
     winch := TRUE
 END OnWinch;
 
+PROCEDURE CommonInit;
+    VAR i : INTEGER;
+BEGIN
+    prevValid := FALSE;
+    inLen := 0; inPos := 0;
+    cursorX := 0; cursorY := 0; cursorShown := FALSE;
+    clipN := 0;
+    modal := NIL; dragWin := NIL; lastSender := NIL;
+    menuCount := 0; menuOpen := -1; menuSel := 0; menuShown := FALSE;
+    winch := FALSE;
+    dlg := NIL; dlgCount := 0;
+    FOR i := 0 TO MAXVIEWS - 1 DO used[i] := FALSE END;
+    desk := NIL;
+    Clear(A(LightGray, Blue, FALSE));
+    desk := NewView(VGroup, 0, 0, cols, rows)
+END CommonInit;
+
 PROCEDURE Init() : BOOLEAN;
-    VAR lf, iff : CARDINAL; i : INTEGER;
+    VAR lf, iff : CARDINAL;
 BEGIN
     IF tcgetattr(0, ADR(term)) # 0 THEN RETURN FALSE END;
     lf := GetDWord(ADR(term), 12);
@@ -230,30 +249,30 @@ BEGIN
     term[CC_OFF + VTIME] := VAL(BYTE, 1);
     IF tcsetattr(0, TCSAFLUSH, ADR(term)) # 0 THEN RETURN FALSE END;
     GetWinSize(rows, cols);
-    prevValid := FALSE;
-    inLen := 0; inPos := 0;
-    cursorX := 0; cursorY := 0; cursorShown := FALSE;
-    clipN := 0;
-    modal := NIL; dragWin := NIL; lastSender := NIL;
-    menuCount := 0; menuOpen := -1; menuSel := 0; menuShown := FALSE;
-    winch := FALSE;
     oldWinch := signal(28, ADR(OnWinch));
-    dlg := NIL; dlgCount := 0;
-    (* reset view pool *)
-    FOR i := 0 TO MAXVIEWS - 1 DO used[i] := FALSE END;
-    desk := NIL;
+    virtual := FALSE;
+    CommonInit;
     OutCh(ESCc); OutStr("[?1049h");
     OutCh(ESCc); OutStr("[2J");
     OutCh(ESCc); OutStr("[?1002h");   (* button/mouse-drag reporting *)
     OutCh(ESCc); OutStr("[?1006h");   (* SGR mouse encoding *)
     OutCh(ESCc); OutStr("[?25l");
     FlushOut;
-    Clear(A(LightGray, Blue, FALSE));
     Present;
-    desk := NewView(VGroup, 0, 0, cols, rows);
     RETURN TRUE
 END Init;
 
+PROCEDURE InitVirtual (c, r : INTEGER) : BOOLEAN;
+BEGIN
+    IF (c < 10) OR (r < 3) THEN RETURN FALSE END;
+    IF c > MAXCOLS THEN c := MAXCOLS END;
+    IF r > MAXROWS THEN r := MAXROWS END;
+    cols := c; rows := r;
+    virtual := TRUE;
+    CommonInit;
+    RETURN TRUE
+END InitVirtual;
+
 PROCEDURE Done;
 BEGIN
     OutCh(ESCc); OutStr("[?1006l");
@@ -299,6 +318,16 @@ END A;
 PROCEDURE Idx(x, y : INTEGER) : INTEGER;
 BEGIN RETURN y * cols + x END Idx;
 
+PROCEDURE CellAt (x, y : INTEGER; VAR cp, attr : CARDINAL);
+BEGIN
+    IF (x >= 0) AND (x < cols) AND (y >= 0) AND (y < rows) THEN
+        cp := cells[Idx(x, y)].cp;
+        attr := cells[Idx(x, y)].attr
+    ELSE
+        cp := 0; attr := 0
+    END
+END CellAt;
+
 PROCEDURE InClip(x, y : INTEGER) : BOOLEAN;
 BEGIN
     IF (x < 0) OR (x >= cols) OR (y < 0) OR (y >= rows) THEN RETURN FALSE END;
@@ -752,7 +781,7 @@ BEGIN
     pool[i].clipKids := FALSE;
     pool[i].text[0] := 0C; pool[i].len := 0; pool[i].pos := 0;
     pool[i].value := 0; pool[i].minv := 0; pool[i].maxv := 0; pool[i].tag := 0;
-    pool[i].flags := 0; pool[i].list := NIL;
+    pool[i].flags := 0; pool[i].list := NIL; pool[i].ed := NIL;
     RETURN ADR(pool[i])
 END NewView;
 
@@ -839,7 +868,8 @@ PROCEDURE IsFocusable(v : ViewPtr) : BOOLEAN;
 BEGIN
     RETURN (v # NIL) AND ((v^.flags DIV vfDisabled) MOD 2 = 0) AND
            ((v^.kind = VInput) OR (v^.kind = VButton) OR (v^.kind = VCheck) OR
-            (v^.kind = VRadio) OR (v^.kind = VList) OR (v^.kind = VScroll))
+            (v^.kind = VRadio) OR (v^.kind = VList) OR (v^.kind = VScroll) OR
+            (v^.kind = VEditor))
 END IsFocusable;
 
 PROCEDURE CollectFocus(v : ViewPtr);
@@ -1036,6 +1066,310 @@ BEGIN
     DrawText(v^.rect.x, v^.rect.y, v^.text, A(Black, Cyan, FALSE))
 END DrawTextCtl;
 
+(*========================================================================*)
+(*  Editor                                                                 *)
+(*========================================================================*)
+
+PROCEDURE EdClrLine (VAR l : ARRAY OF CHAR);
+    VAR i : INTEGER;
+BEGIN
+    FOR i := 0 TO EDMAXCOL - 1 DO l[i] := 0C END
+END EdClrLine;
+
+PROCEDURE EdEnsure (data : EditorDataPtr);
+BEGIN
+    IF data = NIL THEN RETURN END;
+    IF data^.count <= 0 THEN
+        data^.count := 1;
+        EdClrLine(data^.line[0]);
+        data^.len[0] := 0;
+        data^.cx := 0; data^.cy := 0
+    END;
+    IF data^.cy < 0 THEN data^.cy := 0 END;
+    IF data^.cy >= data^.count THEN data^.cy := data^.count - 1 END;
+    IF data^.cx < 0 THEN data^.cx := 0 END;
+    IF data^.cx > data^.len[data^.cy] THEN data^.cx := data^.len[data^.cy] END
+END EdEnsure;
+
+PROCEDURE EdInsertChar (data : EditorDataPtr; cp : CARDINAL);
+    VAR ln, i : INTEGER;
+BEGIN
+    EdEnsure(data);
+    IF cp >= 256 THEN RETURN END;
+    ln := data^.cy;
+    IF data^.len[ln] >= EDMAXCOL - 1 THEN RETURN END;
+    IF data^.ins OR (data^.cx >= data^.len[ln]) THEN
+        i := data^.len[ln];
+        WHILE i > data^.cx DO
+            data^.line[ln][i] := data^.line[ln][i - 1];
+            i := i - 1
+        END;
+        data^.line[ln][data^.cx] := CHR(cp);
+        data^.len[ln] := data^.len[ln] + 1
+    ELSE
+        data^.line[ln][data^.cx] := CHR(cp)
+    END;
+    data^.cx := data^.cx + 1;
+    data^.dirty := TRUE
+END EdInsertChar;
+
+PROCEDURE EdNewLine (data : EditorDataPtr);
+    VAR ln, i, k, tail : INTEGER;
+BEGIN
+    EdEnsure(data);
+    IF data^.count >= EDMAXLINES THEN RETURN END;
+    ln := data^.cy;
+    i := data^.count;
+    WHILE i > ln + 1 DO
+        FOR k := 0 TO EDMAXCOL - 1 DO data^.line[i][k] := data^.line[i - 1][k] END;
+        data^.len[i] := data^.len[i - 1];
+        i := i - 1
+    END;
+    tail := data^.len[ln] - data^.cx;
+    FOR k := 0 TO tail - 1 DO data^.line[ln + 1][k] := data^.line[ln][data^.cx + k] END;
+    data^.line[ln + 1][tail] := 0C;
+    data^.len[ln + 1] := tail;
+    FOR k := data^.cx TO EDMAXCOL - 1 DO data^.line[ln][k] := 0C END;
+    data^.len[ln] := data^.cx;
+    data^.count := data^.count + 1;
+    data^.cy := data^.cy + 1;
+    data^.cx := 0;
+    data^.dirty := TRUE
+END EdNewLine;
+
+PROCEDURE EdBackspace (data : EditorDataPtr);
+    VAR ln, i, plen, k : INTEGER;
+BEGIN
+    EdEnsure(data);
+    ln := data^.cy;
+    IF data^.cx > 0 THEN
+        i := data^.cx - 1;
+        WHILE i < data^.len[ln] - 1 DO
+            data^.line[ln][i] := data^.line[ln][i + 1];
+            i := i + 1
+        END;
+        data^.len[ln] := data^.len[ln] - 1;
+        data^.line[ln][data^.len[ln]] := 0C;
+        data^.cx := data^.cx - 1;
+        data^.dirty := TRUE
+    ELSIF ln > 0 THEN
+        plen := data^.len[ln - 1];
+        IF plen + data^.len[ln] < EDMAXCOL - 1 THEN
+            FOR i := 0 TO data^.len[ln] - 1 DO
+                data^.line[ln - 1][plen + i] := data^.line[ln][i]
+            END;
+            data^.len[ln - 1] := plen + data^.len[ln];
+            data^.line[ln - 1][data^.len[ln - 1]] := 0C;
+            FOR i := ln TO data^.count - 2 DO
+                FOR k := 0 TO EDMAXCOL - 1 DO
+                    data^.line[i][k] := data^.line[i + 1][k]
+                END;
+                data^.len[i] := data^.len[i + 1]
+            END;
+            data^.count := data^.count - 1;
+            data^.cy := ln - 1;
+            data^.cx := data^.len[data^.cy];
+            data^.dirty := TRUE
+        END
+    END
+END EdBackspace;
+
+PROCEDURE EdDelete (data : EditorDataPtr);
+    VAR ln, i, k : INTEGER;
+BEGIN
+    EdEnsure(data);
+    ln := data^.cy;
+    IF data^.cx < data^.len[ln] THEN
+        i := data^.cx;
+        WHILE i < data^.len[ln] - 1 DO
+            data^.line[ln][i] := data^.line[ln][i + 1];
+            i := i + 1
+        END;
+        data^.len[ln] := data^.len[ln] - 1;
+        data^.line[ln][data^.len[ln]] := 0C;
+        data^.dirty := TRUE
+    ELSIF ln < data^.count - 1 THEN
+        FOR i := 0 TO data^.len[ln + 1] - 1 DO
+            IF data^.len[ln] < EDMAXCOL - 1 THEN
+                data^.line[ln][data^.len[ln]] := data^.line[ln + 1][i];
+                data^.len[ln] := data^.len[ln] + 1
+            END
+        END;
+        data^.line[ln][data^.len[ln]] := 0C;
+        FOR i := ln + 1 TO data^.count - 2 DO
+            FOR k := 0 TO EDMAXCOL - 1 DO
+                data^.line[i][k] := data^.line[i + 1][k]
+            END;
+            data^.len[i] := data^.len[i + 1]
+        END;
+        data^.count := data^.count - 1;
+        data^.cx := data^.len[ln];
+        data^.dirty := TRUE
+    END
+END EdDelete;
+
+PROCEDURE EdMove (data : EditorDataPtr; v : ViewPtr; key : INTEGER);
+    VAR step : INTEGER;
+BEGIN
+    EdEnsure(data);
+    step := v^.rect.h - 3;
+    IF step < 1 THEN step := 1 END;
+    IF key = kLeft THEN
+        IF data^.cx > 0 THEN data^.cx := data^.cx - 1
+        ELSIF data^.cy > 0 THEN data^.cy := data^.cy - 1; data^.cx := data^.len[data^.cy] END
+    ELSIF key = kRight THEN
+        IF data^.cx < data^.len[data^.cy] THEN data^.cx := data^.cx + 1
+        ELSIF data^.cy < data^.count - 1 THEN data^.cy := data^.cy + 1; data^.cx := 0 END
+    ELSIF key = kUp THEN
+        IF data^.cy > 0 THEN data^.cy := data^.cy - 1 END;
+        IF data^.cx > data^.len[data^.cy] THEN data^.cx := data^.len[data^.cy] END
+    ELSIF key = kDown THEN
+        IF data^.cy < data^.count - 1 THEN data^.cy := data^.cy + 1 END;
+        IF data^.cx > data^.len[data^.cy] THEN data^.cx := data^.len[data^.cy] END
+    ELSIF key = kHome THEN data^.cx := 0
+    ELSIF key = kEnd THEN data^.cx := data^.len[data^.cy]
+    ELSIF key = kPgUp THEN
+        data^.cy := data^.cy - step;
+        IF data^.cy < 0 THEN data^.cy := 0 END;
+        IF data^.cx > data^.len[data^.cy] THEN data^.cx := data^.len[data^.cy] END
+    ELSIF key = kPgDn THEN
+        data^.cy := data^.cy + step;
+        IF data^.cy > data^.count - 1 THEN data^.cy := data^.count - 1 END;
+        IF data^.cx > data^.len[data^.cy] THEN data^.cx := data^.len[data^.cy] END
+    END
+END EdMove;
+
+PROCEDURE DrawEditor (v : ViewPtr);
+    VAR x0, y0, w, h, vis, r, ln, c : INTEGER;
+        ed : EditorDataPtr; s, t : ARRAY [0..95] OF CHAR;
+BEGIN
+    DrawBox(v^.rect, SingleFrame, A(White, Cyan, FALSE));
+    x0 := v^.rect.x + 1; y0 := v^.rect.y + 1;
+    w := v^.rect.w - 2; h := v^.rect.h - 2;
+    IF (w <= 0) OR (h <= 0) THEN RETURN END;
+    vis := h - 1;
+    IF vis < 1 THEN vis := h END;
+    ed := v^.ed;
+    IF ed = NIL THEN RETURN END;
+    EdEnsure(ed);
+    IF ed^.cy < ed^.top THEN ed^.top := ed^.cy END;
+    IF ed^.cy >= ed^.top + vis THEN ed^.top := ed^.cy - vis + 1 END;
+    IF ed^.cx < ed^.left THEN ed^.left := ed^.cx END;
+    IF ed^.cx >= ed^.left + w THEN ed^.left := ed^.cx - w + 1 END;
+    IF ed^.top < 0 THEN ed^.top := 0 END;
+    IF ed^.left < 0 THEN ed^.left := 0 END;
+    FOR r := 0 TO vis - 1 DO
+        Fill(x0, y0 + r, w, 1, VAL(CARDINAL, ORD(' ')), A(Black, Cyan, FALSE));
+        ln := ed^.top + r;
+        IF ln < ed^.count THEN
+            c := 0;
+            WHILE (c < w) AND (ed^.left + c < ed^.len[ln]) DO
+                DrawCh(x0 + c, y0 + r,
+                       VAL(CARDINAL, ORD(ed^.line[ln][ed^.left + c])),
+                       A(Black, Cyan, FALSE));
+                c := c + 1
+            END
+        END
+    END;
+    Fill(x0, y0 + vis, w, 1, VAL(CARDINAL, ORD(' ')), A(Black, LightGray, FALSE));
+    CopyText(s, " Ln ");
+    IntToText(t, ed^.cy + 1, 0); AppendText(s, t);
+    AppendText(s, " Col ");
+    IntToText(t, ed^.cx + 1, 0); AppendText(s, t);
+    IF ed^.ins THEN AppendText(s, "  Insert") ELSE AppendText(s, "  Overwrite") END;
+    IF ed^.dirty THEN AppendText(s, "  Modified") END;
+    DrawText(x0, y0 + vis, s, A(Black, LightGray, FALSE));
+    IF IsFocused(v) THEN
+        SetCursor(x0 + (ed^.cx - ed^.left), y0 + (ed^.cy - ed^.top))
+    END
+END DrawEditor;
+
+PROCEDURE EditorAttach (v : ViewPtr; data : EditorDataPtr);
+BEGIN
+    IF v # NIL THEN v^.ed := data END
+END EditorAttach;
+
+PROCEDURE EditorInit (data : EditorDataPtr);
+BEGIN
+    IF data # NIL THEN
+        data^.count := 1;
+        EdClrLine(data^.line[0]);
+        data^.len[0] := 0;
+        data^.cx := 0; data^.cy := 0; data^.top := 0; data^.left := 0;
+        data^.ins := TRUE; data^.dirty := FALSE
+    END
+END EditorInit;
+
+PROCEDURE EditorAddLine (data : EditorDataPtr; s : ARRAY OF CHAR);
+    VAR i, n : INTEGER;
+BEGIN
+    IF data = NIL THEN RETURN END;
+    IF data^.count >= EDMAXLINES THEN RETURN END;
+    i := data^.count;
+    n := TextLen(s);
+    IF n > EDMAXCOL - 1 THEN n := EDMAXCOL - 1 END;
+    CopyText(data^.line[i], s);
+    data^.len[i] := n;
+    data^.count := data^.count + 1
+END EditorAddLine;
+
+PROCEDURE EditorGetLine (data : EditorDataPtr; i : INTEGER; VAR s : ARRAY OF CHAR);
+BEGIN
+    IF (data # NIL) AND (i >= 0) AND (i < data^.count) THEN
+        CopyText(s, data^.line[i])
+    ELSE
+        s[0] := 0C
+    END
+END EditorGetLine;
+
+PROCEDURE EditorLoad (data : EditorDataPtr; path : ARRAY OF CHAR) : BOOLEAN;
+    VAR f : ADDRESS; buf : ARRAY [0..EDMAXCOL] OF CHAR; n : INTEGER;
+        discard : INTEGER;
+BEGIN
+    IF data = NIL THEN RETURN FALSE END;
+    f := fopen(path, "r");
+    IF f = NIL THEN RETURN FALSE END;
+    data^.count := 0;
+    WHILE fgets(ADR(buf), EDMAXCOL, f) # NIL DO
+        n := TextLen(buf);
+        WHILE (n > 0) AND ((buf[n - 1] = CHR(10)) OR (buf[n - 1] = CHR(13))) DO
+            buf[n - 1] := 0C;
+            n := n - 1
+        END;
+        EditorAddLine(data, buf)
+    END;
+    discard := fclose(f);
+    IF data^.count = 0 THEN
+        data^.count := 1;
+        EdClrLine(data^.line[0]);
+        data^.len[0] := 0
+    END;
+    data^.cx := 0; data^.cy := 0; data^.top := 0; data^.left := 0;
+    data^.dirty := FALSE;
+    RETURN TRUE
+END EditorLoad;
+
+PROCEDURE EditorSave (data : EditorDataPtr; path : ARRAY OF CHAR) : BOOLEAN;
+    VAR f : ADDRESS; i : INTEGER; d1, d2 : INTEGER;
+BEGIN
+    IF data = NIL THEN RETURN FALSE END;
+    f := fopen(path, "w");
+    IF f = NIL THEN RETURN FALSE END;
+    FOR i := 0 TO data^.count - 1 DO
+        d1 := fputs(data^.line[i], f);
+        d2 := fputc(10, f)
+    END;
+    d1 := fclose(f);
+    data^.dirty := FALSE;
+    RETURN TRUE
+END EditorSave;
+
+PROCEDURE EditorDirty (data : EditorDataPtr) : BOOLEAN;
+BEGIN
+    IF data = NIL THEN RETURN FALSE END;
+    RETURN data^.dirty
+END EditorDirty;
+
 PROCEDURE DrawView(v : ViewPtr);
     VAR c : ViewPtr;
 BEGIN
@@ -1060,6 +1394,8 @@ BEGIN
         VList : DrawList(v)
         |
         VScroll : DrawScroll(v)
+        |
+        VEditor : DrawEditor(v)
     END;
     IF v^.first # NIL THEN
         IF (v^.kind = VWindow) OR v^.clipKids THEN
@@ -1435,13 +1771,28 @@ BEGIN
         ELSIF e.key = kDown THEN
             IF v^.value < v^.maxv THEN v^.value := v^.value + 1 END
         END
+    ELSIF v^.kind = VEditor THEN
+        IF v^.ed # NIL THEN
+            IF e.key = kChar THEN EdInsertChar(v^.ed, e.ch)
+            ELSIF e.key = kEnter THEN EdNewLine(v^.ed)
+            ELSIF e.key = kBack THEN EdBackspace(v^.ed)
+            ELSIF e.key = kDel THEN EdDelete(v^.ed)
+            ELSIF e.key = kIns THEN v^.ed^.ins := NOT v^.ed^.ins
+            ELSIF e.key = kTab THEN
+                EdInsertChar(v^.ed, VAL(CARDINAL, ORD(' ')));
+                WHILE (v^.ed^.cx MOD 4) # 0 DO
+                    EdInsertChar(v^.ed, VAL(CARDINAL, ORD(' ')))
+                END
+            ELSE EdMove(v^.ed, v, e.key)
+            END
+        END
     END;
     IF cmd # cmNone THEN lastSender := v END;
     RETURN cmd
 END WidgetKey;
 
 PROCEDURE WidgetMouse(v : ViewPtr; VAR e : Event) : INTEGER;
-    VAR cmd : INTEGER; rel : INTEGER;
+    VAR cmd : INTEGER; rel, ln, col : INTEGER;
 BEGIN
     cmd := cmNone;
     IF v^.kind = VButton THEN
@@ -1496,6 +1847,22 @@ BEGIN
             IF v^.value < 0 THEN v^.value := 0 END;
             IF v^.value > v^.maxv THEN v^.value := v^.maxv END
         END
+    ELSIF v^.kind = VEditor THEN
+        IF v^.ed # NIL THEN
+            IF e.mwheel # 0 THEN
+                v^.ed^.top := v^.ed^.top + e.mwheel * 3;
+                IF v^.ed^.top < 0 THEN v^.ed^.top := 0 END
+            ELSIF e.mpressed THEN
+                ln := v^.ed^.top + (e.my - (v^.rect.y + 1));
+                IF (ln >= 0) AND (ln < v^.ed^.count) THEN
+                    v^.ed^.cy := ln;
+                    col := e.mx - (v^.rect.x + 1) + v^.ed^.left;
+                    IF col < 0 THEN col := 0 END;
+                    IF col > v^.ed^.len[ln] THEN col := v^.ed^.len[ln] END;
+                    v^.ed^.cx := col
+                END
+            END
+        END
     END;
     IF cmd # cmNone THEN lastSender := v END;
     RETURN cmd

BIN
tvision-m2/tv.o


+ 20 - 0
tvision-m2/tvfont.def

@@ -0,0 +1,20 @@
+DEFINITION MODULE tvfont;
+
+FROM SYSTEM IMPORT BYTE;
+
+(* Bundled 8x16 monospaced bitmap font for the tigr backend (no system
+   dependency at run time).
+
+   Glyph data derived from the public-domain IBM VGA 8x16 console font
+   (via the Lat15-VGA16 console font).  Box-drawing code points are drawn
+   as line segments by the backend, not from this font. *)
+
+CONST
+    CW = 8;      (* cell width  in pixels *)
+    CH = 16;     (* cell height in pixels *)
+    NG = 256;    (* number of glyphs *)
+
+PROCEDURE Index (cp : CARDINAL) : INTEGER;   (* glyph number, or -1 *)
+PROCEDURE Row (g : INTEGER; r : INTEGER) : BYTE;
+
+END tvfont.

+ 4654 - 0
tvision-m2/tvfont.mod

@@ -0,0 +1,4654 @@
+IMPLEMENTATION MODULE tvfont;
+
+FROM SYSTEM IMPORT BYTE;
+
+CONST NC = 528;
+
+VAR data : ARRAY [0..NG*CH-1] OF BYTE;
+    codes : ARRAY [0..NC-1] OF CARDINAL;
+    gidx  : ARRAY [0..NC-1] OF INTEGER;
+
+PROCEDURE Index (cp : CARDINAL) : INTEGER;
+    VAR lo, hi, mid : INTEGER;
+BEGIN
+    lo := 0; hi := NC - 1;
+    WHILE lo <= hi DO
+        mid := (lo + hi) DIV 2;
+        IF codes[mid] = cp THEN RETURN gidx[mid]
+        ELSIF codes[mid] < cp THEN lo := mid + 1
+        ELSE hi := mid - 1 END
+    END;
+    RETURN -1
+END Index;
+
+PROCEDURE Row (g : INTEGER; r : INTEGER) : BYTE;
+BEGIN
+    RETURN data[g * CH + r]
+END Row;
+
+BEGIN
+    data[0] := 0;
+    data[1] := 0;
+    data[2] := 60;
+    data[3] := 66;
+    data[4] := 153;
+    data[5] := 165;
+    data[6] := 161;
+    data[7] := 161;
+    data[8] := 165;
+    data[9] := 153;
+    data[10] := 66;
+    data[11] := 60;
+    data[12] := 0;
+    data[13] := 0;
+    data[14] := 0;
+    data[15] := 0;
+    data[16] := 0;
+    data[17] := 0;
+    data[18] := 0;
+    data[19] := 0;
+    data[20] := 0;
+    data[21] := 0;
+    data[22] := 0;
+    data[23] := 255;
+    data[24] := 0;
+    data[25] := 0;
+    data[26] := 0;
+    data[27] := 0;
+    data[28] := 0;
+    data[29] := 0;
+    data[30] := 0;
+    data[31] := 0;
+    data[32] := 0;
+    data[33] := 0;
+    data[34] := 0;
+    data[35] := 0;
+    data[36] := 0;
+    data[37] := 0;
+    data[38] := 0;
+    data[39] := 0;
+    data[40] := 0;
+    data[41] := 0;
+    data[42] := 219;
+    data[43] := 219;
+    data[44] := 0;
+    data[45] := 0;
+    data[46] := 0;
+    data[47] := 0;
+    data[48] := 0;
+    data[49] := 0;
+    data[50] := 241;
+    data[51] := 91;
+    data[52] := 85;
+    data[53] := 81;
+    data[54] := 0;
+    data[55] := 0;
+    data[56] := 0;
+    data[57] := 0;
+    data[58] := 0;
+    data[59] := 0;
+    data[60] := 0;
+    data[61] := 0;
+    data[62] := 0;
+    data[63] := 0;
+    data[64] := 0;
+    data[65] := 0;
+    data[66] := 0;
+    data[67] := 0;
+    data[68] := 16;
+    data[69] := 56;
+    data[70] := 124;
+    data[71] := 254;
+    data[72] := 124;
+    data[73] := 56;
+    data[74] := 16;
+    data[75] := 0;
+    data[76] := 0;
+    data[77] := 0;
+    data[78] := 0;
+    data[79] := 0;
+    data[80] := 0;
+    data[81] := 0;
+    data[82] := 204;
+    data[83] := 207;
+    data[84] := 237;
+    data[85] := 255;
+    data[86] := 252;
+    data[87] := 223;
+    data[88] := 204;
+    data[89] := 204;
+    data[90] := 204;
+    data[91] := 204;
+    data[92] := 0;
+    data[93] := 0;
+    data[94] := 0;
+    data[95] := 0;
+    data[96] := 0;
+    data[97] := 0;
+    data[98] := 3;
+    data[99] := 62;
+    data[100] := 102;
+    data[101] := 207;
+    data[102] := 219;
+    data[103] := 219;
+    data[104] := 243;
+    data[105] := 102;
+    data[106] := 124;
+    data[107] := 192;
+    data[108] := 0;
+    data[109] := 0;
+    data[110] := 0;
+    data[111] := 0;
+    data[112] := 0;
+    data[113] := 0;
+    data[114] := 0;
+    data[115] := 0;
+    data[116] := 0;
+    data[117] := 0;
+    data[118] := 24;
+    data[119] := 60;
+    data[120] := 60;
+    data[121] := 24;
+    data[122] := 0;
+    data[123] := 0;
+    data[124] := 0;
+    data[125] := 0;
+    data[126] := 0;
+    data[127] := 0;
+    data[128] := 0;
+    data[129] := 0;
+    data[130] := 0;
+    data[131] := 0;
+    data[132] := 102;
+    data[133] := 60;
+    data[134] := 102;
+    data[135] := 102;
+    data[136] := 102;
+    data[137] := 60;
+    data[138] := 102;
+    data[139] := 0;
+    data[140] := 0;
+    data[141] := 0;
+    data[142] := 0;
+    data[143] := 0;
+    data[144] := 0;
+    data[145] := 0;
+    data[146] := 24;
+    data[147] := 24;
+    data[148] := 24;
+    data[149] := 24;
+    data[150] := 0;
+    data[151] := 24;
+    data[152] := 24;
+    data[153] := 24;
+    data[154] := 24;
+    data[155] := 24;
+    data[156] := 0;
+    data[157] := 0;
+    data[158] := 0;
+    data[159] := 0;
+    data[160] := 0;
+    data[161] := 0;
+    data[162] := 108;
+    data[163] := 108;
+    data[164] := 0;
+    data[165] := 0;
+    data[166] := 0;
+    data[167] := 0;
+    data[168] := 0;
+    data[169] := 0;
+    data[170] := 0;
+    data[171] := 0;
+    data[172] := 0;
+    data[173] := 0;
+    data[174] := 0;
+    data[175] := 0;
+    data[176] := 0;
+    data[177] := 0;
+    data[178] := 56;
+    data[179] := 68;
+    data[180] := 186;
+    data[181] := 178;
+    data[182] := 170;
+    data[183] := 68;
+    data[184] := 56;
+    data[185] := 0;
+    data[186] := 0;
+    data[187] := 0;
+    data[188] := 0;
+    data[189] := 0;
+    data[190] := 0;
+    data[191] := 0;
+    data[192] := 0;
+    data[193] := 0;
+    data[194] := 0;
+    data[195] := 124;
+    data[196] := 0;
+    data[197] := 0;
+    data[198] := 0;
+    data[199] := 0;
+    data[200] := 0;
+    data[201] := 0;
+    data[202] := 0;
+    data[203] := 0;
+    data[204] := 0;
+    data[205] := 0;
+    data[206] := 0;
+    data[207] := 0;
+    data[208] := 0;
+    data[209] := 112;
+    data[210] := 216;
+    data[211] := 48;
+    data[212] := 24;
+    data[213] := 216;
+    data[214] := 112;
+    data[215] := 0;
+    data[216] := 0;
+    data[217] := 0;
+    data[218] := 0;
+    data[219] := 0;
+    data[220] := 0;
+    data[221] := 0;
+    data[222] := 0;
+    data[223] := 0;
+    data[224] := 0;
+    data[225] := 0;
+    data[226] := 12;
+    data[227] := 24;
+    data[228] := 0;
+    data[229] := 0;
+    data[230] := 0;
+    data[231] := 0;
+    data[232] := 0;
+    data[233] := 0;
+    data[234] := 0;
+    data[235] := 0;
+    data[236] := 0;
+    data[237] := 0;
+    data[238] := 0;
+    data[239] := 0;
+    data[240] := 0;
+    data[241] := 0;
+    data[242] := 0;
+    data[243] := 0;
+    data[244] := 0;
+    data[245] := 0;
+    data[246] := 0;
+    data[247] := 0;
+    data[248] := 0;
+    data[249] := 0;
+    data[250] := 0;
+    data[251] := 0;
+    data[252] := 24;
+    data[253] := 12;
+    data[254] := 56;
+    data[255] := 0;
+    data[256] := 0;
+    data[257] := 48;
+    data[258] := 112;
+    data[259] := 48;
+    data[260] := 48;
+    data[261] := 48;
+    data[262] := 120;
+    data[263] := 0;
+    data[264] := 0;
+    data[265] := 0;
+    data[266] := 0;
+    data[267] := 0;
+    data[268] := 0;
+    data[269] := 0;
+    data[270] := 0;
+    data[271] := 0;
+    data[272] := 0;
+    data[273] := 224;
+    data[274] := 48;
+    data[275] := 98;
+    data[276] := 54;
+    data[277] := 236;
+    data[278] := 24;
+    data[279] := 48;
+    data[280] := 102;
+    data[281] := 206;
+    data[282] := 158;
+    data[283] := 62;
+    data[284] := 6;
+    data[285] := 6;
+    data[286] := 0;
+    data[287] := 0;
+    data[288] := 96;
+    data[289] := 48;
+    data[290] := 0;
+    data[291] := 16;
+    data[292] := 56;
+    data[293] := 108;
+    data[294] := 198;
+    data[295] := 198;
+    data[296] := 254;
+    data[297] := 198;
+    data[298] := 198;
+    data[299] := 198;
+    data[300] := 0;
+    data[301] := 0;
+    data[302] := 0;
+    data[303] := 0;
+    data[304] := 0;
+    data[305] := 0;
+    data[306] := 102;
+    data[307] := 102;
+    data[308] := 102;
+    data[309] := 102;
+    data[310] := 102;
+    data[311] := 102;
+    data[312] := 102;
+    data[313] := 0;
+    data[314] := 102;
+    data[315] := 102;
+    data[316] := 0;
+    data[317] := 0;
+    data[318] := 0;
+    data[319] := 0;
+    data[320] := 0;
+    data[321] := 0;
+    data[322] := 127;
+    data[323] := 219;
+    data[324] := 219;
+    data[325] := 219;
+    data[326] := 123;
+    data[327] := 27;
+    data[328] := 27;
+    data[329] := 27;
+    data[330] := 27;
+    data[331] := 27;
+    data[332] := 0;
+    data[333] := 0;
+    data[334] := 0;
+    data[335] := 0;
+    data[336] := 0;
+    data[337] := 124;
+    data[338] := 198;
+    data[339] := 96;
+    data[340] := 56;
+    data[341] := 108;
+    data[342] := 198;
+    data[343] := 198;
+    data[344] := 108;
+    data[345] := 56;
+    data[346] := 12;
+    data[347] := 198;
+    data[348] := 124;
+    data[349] := 0;
+    data[350] := 0;
+    data[351] := 0;
+    data[352] := 12;
+    data[353] := 24;
+    data[354] := 0;
+    data[355] := 16;
+    data[356] := 56;
+    data[357] := 108;
+    data[358] := 198;
+    data[359] := 198;
+    data[360] := 254;
+    data[361] := 198;
+    data[362] := 198;
+    data[363] := 198;
+    data[364] := 0;
+    data[365] := 0;
+    data[366] := 0;
+    data[367] := 0;
+    data[368] := 16;
+    data[369] := 56;
+    data[370] := 108;
+    data[371] := 16;
+    data[372] := 56;
+    data[373] := 108;
+    data[374] := 198;
+    data[375] := 198;
+    data[376] := 254;
+    data[377] := 198;
+    data[378] := 198;
+    data[379] := 198;
+    data[380] := 0;
+    data[381] := 0;
+    data[382] := 0;
+    data[383] := 0;
+    data[384] := 0;
+    data[385] := 0;
+    data[386] := 24;
+    data[387] := 60;
+    data[388] := 126;
+    data[389] := 24;
+    data[390] := 24;
+    data[391] := 24;
+    data[392] := 24;
+    data[393] := 24;
+    data[394] := 24;
+    data[395] := 24;
+    data[396] := 0;
+    data[397] := 0;
+    data[398] := 0;
+    data[399] := 0;
+    data[400] := 0;
+    data[401] := 0;
+    data[402] := 24;
+    data[403] := 24;
+    data[404] := 24;
+    data[405] := 24;
+    data[406] := 24;
+    data[407] := 24;
+    data[408] := 24;
+    data[409] := 126;
+    data[410] := 60;
+    data[411] := 24;
+    data[412] := 0;
+    data[413] := 0;
+    data[414] := 0;
+    data[415] := 0;
+    data[416] := 0;
+    data[417] := 0;
+    data[418] := 0;
+    data[419] := 0;
+    data[420] := 0;
+    data[421] := 12;
+    data[422] := 6;
+    data[423] := 255;
+    data[424] := 6;
+    data[425] := 12;
+    data[426] := 0;
+    data[427] := 0;
+    data[428] := 0;
+    data[429] := 0;
+    data[430] := 0;
+    data[431] := 0;
+    data[432] := 0;
+    data[433] := 0;
+    data[434] := 0;
+    data[435] := 0;
+    data[436] := 0;
+    data[437] := 48;
+    data[438] := 96;
+    data[439] := 255;
+    data[440] := 96;
+    data[441] := 48;
+    data[442] := 0;
+    data[443] := 0;
+    data[444] := 0;
+    data[445] := 0;
+    data[446] := 0;
+    data[447] := 0;
+    data[448] := 118;
+    data[449] := 220;
+    data[450] := 0;
+    data[451] := 16;
+    data[452] := 56;
+    data[453] := 108;
+    data[454] := 198;
+    data[455] := 198;
+    data[456] := 254;
+    data[457] := 198;
+    data[458] := 198;
+    data[459] := 198;
+    data[460] := 0;
+    data[461] := 0;
+    data[462] := 0;
+    data[463] := 0;
+    data[464] := 48;
+    data[465] := 24;
+    data[466] := 0;
+    data[467] := 254;
+    data[468] := 102;
+    data[469] := 98;
+    data[470] := 104;
+    data[471] := 120;
+    data[472] := 104;
+    data[473] := 98;
+    data[474] := 102;
+    data[475] := 254;
+    data[476] := 0;
+    data[477] := 0;
+    data[478] := 0;
+    data[479] := 0;
+    data[480] := 16;
+    data[481] := 56;
+    data[482] := 68;
+    data[483] := 254;
+    data[484] := 102;
+    data[485] := 98;
+    data[486] := 104;
+    data[487] := 120;
+    data[488] := 104;
+    data[489] := 98;
+    data[490] := 102;
+    data[491] := 254;
+    data[492] := 0;
+    data[493] := 0;
+    data[494] := 0;
+    data[495] := 0;
+    data[496] := 108;
+    data[497] := 108;
+    data[498] := 0;
+    data[499] := 254;
+    data[500] := 102;
+    data[501] := 98;
+    data[502] := 104;
+    data[503] := 120;
+    data[504] := 104;
+    data[505] := 98;
+    data[506] := 102;
+    data[507] := 254;
+    data[508] := 0;
+    data[509] := 0;
+    data[510] := 0;
+    data[511] := 0;
+    data[512] := 0;
+    data[513] := 0;
+    data[514] := 0;
+    data[515] := 0;
+    data[516] := 0;
+    data[517] := 0;
+    data[518] := 0;
+    data[519] := 0;
+    data[520] := 0;
+    data[521] := 0;
+    data[522] := 0;
+    data[523] := 0;
+    data[524] := 0;
+    data[525] := 0;
+    data[526] := 0;
+    data[527] := 0;
+    data[528] := 0;
+    data[529] := 0;
+    data[530] := 24;
+    data[531] := 60;
+    data[532] := 60;
+    data[533] := 60;
+    data[534] := 24;
+    data[535] := 24;
+    data[536] := 24;
+    data[537] := 0;
+    data[538] := 24;
+    data[539] := 24;
+    data[540] := 0;
+    data[541] := 0;
+    data[542] := 0;
+    data[543] := 0;
+    data[544] := 0;
+    data[545] := 102;
+    data[546] := 102;
+    data[547] := 102;
+    data[548] := 36;
+    data[549] := 0;
+    data[550] := 0;
+    data[551] := 0;
+    data[552] := 0;
+    data[553] := 0;
+    data[554] := 0;
+    data[555] := 0;
+    data[556] := 0;
+    data[557] := 0;
+    data[558] := 0;
+    data[559] := 0;
+    data[560] := 0;
+    data[561] := 0;
+    data[562] := 0;
+    data[563] := 108;
+    data[564] := 108;
+    data[565] := 254;
+    data[566] := 108;
+    data[567] := 108;
+    data[568] := 108;
+    data[569] := 254;
+    data[570] := 108;
+    data[571] := 108;
+    data[572] := 0;
+    data[573] := 0;
+    data[574] := 0;
+    data[575] := 0;
+    data[576] := 24;
+    data[577] := 24;
+    data[578] := 124;
+    data[579] := 198;
+    data[580] := 194;
+    data[581] := 192;
+    data[582] := 124;
+    data[583] := 6;
+    data[584] := 6;
+    data[585] := 134;
+    data[586] := 198;
+    data[587] := 124;
+    data[588] := 24;
+    data[589] := 24;
+    data[590] := 0;
+    data[591] := 0;
+    data[592] := 0;
+    data[593] := 0;
+    data[594] := 0;
+    data[595] := 0;
+    data[596] := 194;
+    data[597] := 198;
+    data[598] := 12;
+    data[599] := 24;
+    data[600] := 48;
+    data[601] := 96;
+    data[602] := 198;
+    data[603] := 134;
+    data[604] := 0;
+    data[605] := 0;
+    data[606] := 0;
+    data[607] := 0;
+    data[608] := 0;
+    data[609] := 0;
+    data[610] := 56;
+    data[611] := 108;
+    data[612] := 108;
+    data[613] := 56;
+    data[614] := 118;
+    data[615] := 220;
+    data[616] := 204;
+    data[617] := 204;
+    data[618] := 204;
+    data[619] := 118;
+    data[620] := 0;
+    data[621] := 0;
+    data[622] := 0;
+    data[623] := 0;
+    data[624] := 0;
+    data[625] := 48;
+    data[626] := 48;
+    data[627] := 48;
+    data[628] := 32;
+    data[629] := 0;
+    data[630] := 0;
+    data[631] := 0;
+    data[632] := 0;
+    data[633] := 0;
+    data[634] := 0;
+    data[635] := 0;
+    data[636] := 0;
+    data[637] := 0;
+    data[638] := 0;
+    data[639] := 0;
+    data[640] := 0;
+    data[641] := 0;
+    data[642] := 12;
+    data[643] := 24;
+    data[644] := 48;
+    data[645] := 48;
+    data[646] := 48;
+    data[647] := 48;
+    data[648] := 48;
+    data[649] := 48;
+    data[650] := 24;
+    data[651] := 12;
+    data[652] := 0;
+    data[653] := 0;
+    data[654] := 0;
+    data[655] := 0;
+    data[656] := 0;
+    data[657] := 0;
+    data[658] := 48;
+    data[659] := 24;
+    data[660] := 12;
+    data[661] := 12;
+    data[662] := 12;
+    data[663] := 12;
+    data[664] := 12;
+    data[665] := 12;
+    data[666] := 24;
+    data[667] := 48;
+    data[668] := 0;
+    data[669] := 0;
+    data[670] := 0;
+    data[671] := 0;
+    data[672] := 0;
+    data[673] := 0;
+    data[674] := 0;
+    data[675] := 0;
+    data[676] := 0;
+    data[677] := 102;
+    data[678] := 60;
+    data[679] := 255;
+    data[680] := 60;
+    data[681] := 102;
+    data[682] := 0;
+    data[683] := 0;
+    data[684] := 0;
+    data[685] := 0;
+    data[686] := 0;
+    data[687] := 0;
+    data[688] := 0;
+    data[689] := 0;
+    data[690] := 0;
+    data[691] := 0;
+    data[692] := 0;
+    data[693] := 24;
+    data[694] := 24;
+    data[695] := 126;
+    data[696] := 24;
+    data[697] := 24;
+    data[698] := 0;
+    data[699] := 0;
+    data[700] := 0;
+    data[701] := 0;
+    data[702] := 0;
+    data[703] := 0;
+    data[704] := 0;
+    data[705] := 0;
+    data[706] := 0;
+    data[707] := 0;
+    data[708] := 0;
+    data[709] := 0;
+    data[710] := 0;
+    data[711] := 0;
+    data[712] := 0;
+    data[713] := 24;
+    data[714] := 24;
+    data[715] := 24;
+    data[716] := 48;
+    data[717] := 0;
+    data[718] := 0;
+    data[719] := 0;
+    data[720] := 0;
+    data[721] := 0;
+    data[722] := 0;
+    data[723] := 0;
+    data[724] := 0;
+    data[725] := 0;
+    data[726] := 0;
+    data[727] := 254;
+    data[728] := 0;
+    data[729] := 0;
+    data[730] := 0;
+    data[731] := 0;
+    data[732] := 0;
+    data[733] := 0;
+    data[734] := 0;
+    data[735] := 0;
+    data[736] := 0;
+    data[737] := 0;
+    data[738] := 0;
+    data[739] := 0;
+    data[740] := 0;
+    data[741] := 0;
+    data[742] := 0;
+    data[743] := 0;
+    data[744] := 0;
+    data[745] := 0;
+    data[746] := 24;
+    data[747] := 24;
+    data[748] := 0;
+    data[749] := 0;
+    data[750] := 0;
+    data[751] := 0;
+    data[752] := 0;
+    data[753] := 0;
+    data[754] := 0;
+    data[755] := 0;
+    data[756] := 2;
+    data[757] := 6;
+    data[758] := 12;
+    data[759] := 24;
+    data[760] := 48;
+    data[761] := 96;
+    data[762] := 192;
+    data[763] := 128;
+    data[764] := 0;
+    data[765] := 0;
+    data[766] := 0;
+    data[767] := 0;
+    data[768] := 0;
+    data[769] := 0;
+    data[770] := 56;
+    data[771] := 108;
+    data[772] := 198;
+    data[773] := 198;
+    data[774] := 214;
+    data[775] := 214;
+    data[776] := 198;
+    data[777] := 198;
+    data[778] := 108;
+    data[779] := 56;
+    data[780] := 0;
+    data[781] := 0;
+    data[782] := 0;
+    data[783] := 0;
+    data[784] := 0;
+    data[785] := 0;
+    data[786] := 24;
+    data[787] := 56;
+    data[788] := 120;
+    data[789] := 24;
+    data[790] := 24;
+    data[791] := 24;
+    data[792] := 24;
+    data[793] := 24;
+    data[794] := 24;
+    data[795] := 126;
+    data[796] := 0;
+    data[797] := 0;
+    data[798] := 0;
+    data[799] := 0;
+    data[800] := 0;
+    data[801] := 0;
+    data[802] := 124;
+    data[803] := 198;
+    data[804] := 6;
+    data[805] := 12;
+    data[806] := 24;
+    data[807] := 48;
+    data[808] := 96;
+    data[809] := 192;
+    data[810] := 198;
+    data[811] := 254;
+    data[812] := 0;
+    data[813] := 0;
+    data[814] := 0;
+    data[815] := 0;
+    data[816] := 0;
+    data[817] := 0;
+    data[818] := 124;
+    data[819] := 198;
+    data[820] := 6;
+    data[821] := 6;
+    data[822] := 60;
+    data[823] := 6;
+    data[824] := 6;
+    data[825] := 6;
+    data[826] := 198;
+    data[827] := 124;
+    data[828] := 0;
+    data[829] := 0;
+    data[830] := 0;
+    data[831] := 0;
+    data[832] := 0;
+    data[833] := 0;
+    data[834] := 12;
+    data[835] := 28;
+    data[836] := 60;
+    data[837] := 108;
+    data[838] := 204;
+    data[839] := 254;
+    data[840] := 12;
+    data[841] := 12;
+    data[842] := 12;
+    data[843] := 30;
+    data[844] := 0;
+    data[845] := 0;
+    data[846] := 0;
+    data[847] := 0;
+    data[848] := 0;
+    data[849] := 0;
+    data[850] := 254;
+    data[851] := 192;
+    data[852] := 192;
+    data[853] := 192;
+    data[854] := 252;
+    data[855] := 6;
+    data[856] := 6;
+    data[857] := 6;
+    data[858] := 198;
+    data[859] := 124;
+    data[860] := 0;
+    data[861] := 0;
+    data[862] := 0;
+    data[863] := 0;
+    data[864] := 0;
+    data[865] := 0;
+    data[866] := 56;
+    data[867] := 96;
+    data[868] := 192;
+    data[869] := 192;
+    data[870] := 252;
+    data[871] := 198;
+    data[872] := 198;
+    data[873] := 198;
+    data[874] := 198;
+    data[875] := 124;
+    data[876] := 0;
+    data[877] := 0;
+    data[878] := 0;
+    data[879] := 0;
+    data[880] := 0;
+    data[881] := 0;
+    data[882] := 254;
+    data[883] := 198;
+    data[884] := 6;
+    data[885] := 6;
+    data[886] := 12;
+    data[887] := 24;
+    data[888] := 48;
+    data[889] := 48;
+    data[890] := 48;
+    data[891] := 48;
+    data[892] := 0;
+    data[893] := 0;
+    data[894] := 0;
+    data[895] := 0;
+    data[896] := 0;
+    data[897] := 0;
+    data[898] := 124;
+    data[899] := 198;
+    data[900] := 198;
+    data[901] := 198;
+    data[902] := 124;
+    data[903] := 198;
+    data[904] := 198;
+    data[905] := 198;
+    data[906] := 198;
+    data[907] := 124;
+    data[908] := 0;
+    data[909] := 0;
+    data[910] := 0;
+    data[911] := 0;
+    data[912] := 0;
+    data[913] := 0;
+    data[914] := 124;
+    data[915] := 198;
+    data[916] := 198;
+    data[917] := 198;
+    data[918] := 126;
+    data[919] := 6;
+    data[920] := 6;
+    data[921] := 6;
+    data[922] := 12;
+    data[923] := 120;
+    data[924] := 0;
+    data[925] := 0;
+    data[926] := 0;
+    data[927] := 0;
+    data[928] := 0;
+    data[929] := 0;
+    data[930] := 0;
+    data[931] := 0;
+    data[932] := 24;
+    data[933] := 24;
+    data[934] := 0;
+    data[935] := 0;
+    data[936] := 0;
+    data[937] := 24;
+    data[938] := 24;
+    data[939] := 0;
+    data[940] := 0;
+    data[941] := 0;
+    data[942] := 0;
+    data[943] := 0;
+    data[944] := 0;
+    data[945] := 0;
+    data[946] := 0;
+    data[947] := 0;
+    data[948] := 24;
+    data[949] := 24;
+    data[950] := 0;
+    data[951] := 0;
+    data[952] := 0;
+    data[953] := 24;
+    data[954] := 24;
+    data[955] := 48;
+    data[956] := 0;
+    data[957] := 0;
+    data[958] := 0;
+    data[959] := 0;
+    data[960] := 0;
+    data[961] := 0;
+    data[962] := 0;
+    data[963] := 6;
+    data[964] := 12;
+    data[965] := 24;
+    data[966] := 48;
+    data[967] := 96;
+    data[968] := 48;
+    data[969] := 24;
+    data[970] := 12;
+    data[971] := 6;
+    data[972] := 0;
+    data[973] := 0;
+    data[974] := 0;
+    data[975] := 0;
+    data[976] := 0;
+    data[977] := 0;
+    data[978] := 0;
+    data[979] := 0;
+    data[980] := 0;
+    data[981] := 126;
+    data[982] := 0;
+    data[983] := 0;
+    data[984] := 126;
+    data[985] := 0;
+    data[986] := 0;
+    data[987] := 0;
+    data[988] := 0;
+    data[989] := 0;
+    data[990] := 0;
+    data[991] := 0;
+    data[992] := 0;
+    data[993] := 0;
+    data[994] := 0;
+    data[995] := 96;
+    data[996] := 48;
+    data[997] := 24;
+    data[998] := 12;
+    data[999] := 6;
+    data[1000] := 12;
+    data[1001] := 24;
+    data[1002] := 48;
+    data[1003] := 96;
+    data[1004] := 0;
+    data[1005] := 0;
+    data[1006] := 0;
+    data[1007] := 0;
+    data[1008] := 0;
+    data[1009] := 0;
+    data[1010] := 124;
+    data[1011] := 198;
+    data[1012] := 198;
+    data[1013] := 12;
+    data[1014] := 24;
+    data[1015] := 24;
+    data[1016] := 24;
+    data[1017] := 0;
+    data[1018] := 24;
+    data[1019] := 24;
+    data[1020] := 0;
+    data[1021] := 0;
+    data[1022] := 0;
+    data[1023] := 0;
+    data[1024] := 0;
+    data[1025] := 0;
+    data[1026] := 0;
+    data[1027] := 124;
+    data[1028] := 198;
+    data[1029] := 198;
+    data[1030] := 222;
+    data[1031] := 222;
+    data[1032] := 222;
+    data[1033] := 220;
+    data[1034] := 192;
+    data[1035] := 124;
+    data[1036] := 0;
+    data[1037] := 0;
+    data[1038] := 0;
+    data[1039] := 0;
+    data[1040] := 0;
+    data[1041] := 0;
+    data[1042] := 16;
+    data[1043] := 56;
+    data[1044] := 108;
+    data[1045] := 198;
+    data[1046] := 198;
+    data[1047] := 254;
+    data[1048] := 198;
+    data[1049] := 198;
+    data[1050] := 198;
+    data[1051] := 198;
+    data[1052] := 0;
+    data[1053] := 0;
+    data[1054] := 0;
+    data[1055] := 0;
+    data[1056] := 0;
+    data[1057] := 0;
+    data[1058] := 252;
+    data[1059] := 102;
+    data[1060] := 102;
+    data[1061] := 102;
+    data[1062] := 124;
+    data[1063] := 102;
+    data[1064] := 102;
+    data[1065] := 102;
+    data[1066] := 102;
+    data[1067] := 252;
+    data[1068] := 0;
+    data[1069] := 0;
+    data[1070] := 0;
+    data[1071] := 0;
+    data[1072] := 0;
+    data[1073] := 0;
+    data[1074] := 60;
+    data[1075] := 102;
+    data[1076] := 194;
+    data[1077] := 192;
+    data[1078] := 192;
+    data[1079] := 192;
+    data[1080] := 192;
+    data[1081] := 194;
+    data[1082] := 102;
+    data[1083] := 60;
+    data[1084] := 0;
+    data[1085] := 0;
+    data[1086] := 0;
+    data[1087] := 0;
+    data[1088] := 0;
+    data[1089] := 0;
+    data[1090] := 248;
+    data[1091] := 108;
+    data[1092] := 102;
+    data[1093] := 102;
+    data[1094] := 102;
+    data[1095] := 102;
+    data[1096] := 102;
+    data[1097] := 102;
+    data[1098] := 108;
+    data[1099] := 248;
+    data[1100] := 0;
+    data[1101] := 0;
+    data[1102] := 0;
+    data[1103] := 0;
+    data[1104] := 0;
+    data[1105] := 0;
+    data[1106] := 254;
+    data[1107] := 102;
+    data[1108] := 98;
+    data[1109] := 104;
+    data[1110] := 120;
+    data[1111] := 104;
+    data[1112] := 96;
+    data[1113] := 98;
+    data[1114] := 102;
+    data[1115] := 254;
+    data[1116] := 0;
+    data[1117] := 0;
+    data[1118] := 0;
+    data[1119] := 0;
+    data[1120] := 0;
+    data[1121] := 0;
+    data[1122] := 254;
+    data[1123] := 102;
+    data[1124] := 98;
+    data[1125] := 104;
+    data[1126] := 120;
+    data[1127] := 104;
+    data[1128] := 96;
+    data[1129] := 96;
+    data[1130] := 96;
+    data[1131] := 240;
+    data[1132] := 0;
+    data[1133] := 0;
+    data[1134] := 0;
+    data[1135] := 0;
+    data[1136] := 0;
+    data[1137] := 0;
+    data[1138] := 60;
+    data[1139] := 102;
+    data[1140] := 194;
+    data[1141] := 192;
+    data[1142] := 192;
+    data[1143] := 222;
+    data[1144] := 198;
+    data[1145] := 198;
+    data[1146] := 102;
+    data[1147] := 58;
+    data[1148] := 0;
+    data[1149] := 0;
+    data[1150] := 0;
+    data[1151] := 0;
+    data[1152] := 0;
+    data[1153] := 0;
+    data[1154] := 198;
+    data[1155] := 198;
+    data[1156] := 198;
+    data[1157] := 198;
+    data[1158] := 254;
+    data[1159] := 198;
+    data[1160] := 198;
+    data[1161] := 198;
+    data[1162] := 198;
+    data[1163] := 198;
+    data[1164] := 0;
+    data[1165] := 0;
+    data[1166] := 0;
+    data[1167] := 0;
+    data[1168] := 0;
+    data[1169] := 0;
+    data[1170] := 60;
+    data[1171] := 24;
+    data[1172] := 24;
+    data[1173] := 24;
+    data[1174] := 24;
+    data[1175] := 24;
+    data[1176] := 24;
+    data[1177] := 24;
+    data[1178] := 24;
+    data[1179] := 60;
+    data[1180] := 0;
+    data[1181] := 0;
+    data[1182] := 0;
+    data[1183] := 0;
+    data[1184] := 0;
+    data[1185] := 0;
+    data[1186] := 30;
+    data[1187] := 12;
+    data[1188] := 12;
+    data[1189] := 12;
+    data[1190] := 12;
+    data[1191] := 12;
+    data[1192] := 204;
+    data[1193] := 204;
+    data[1194] := 204;
+    data[1195] := 120;
+    data[1196] := 0;
+    data[1197] := 0;
+    data[1198] := 0;
+    data[1199] := 0;
+    data[1200] := 0;
+    data[1201] := 0;
+    data[1202] := 230;
+    data[1203] := 102;
+    data[1204] := 102;
+    data[1205] := 108;
+    data[1206] := 120;
+    data[1207] := 120;
+    data[1208] := 108;
+    data[1209] := 102;
+    data[1210] := 102;
+    data[1211] := 230;
+    data[1212] := 0;
+    data[1213] := 0;
+    data[1214] := 0;
+    data[1215] := 0;
+    data[1216] := 0;
+    data[1217] := 0;
+    data[1218] := 240;
+    data[1219] := 96;
+    data[1220] := 96;
+    data[1221] := 96;
+    data[1222] := 96;
+    data[1223] := 96;
+    data[1224] := 96;
+    data[1225] := 98;
+    data[1226] := 102;
+    data[1227] := 254;
+    data[1228] := 0;
+    data[1229] := 0;
+    data[1230] := 0;
+    data[1231] := 0;
+    data[1232] := 0;
+    data[1233] := 0;
+    data[1234] := 198;
+    data[1235] := 238;
+    data[1236] := 254;
+    data[1237] := 254;
+    data[1238] := 214;
+    data[1239] := 198;
+    data[1240] := 198;
+    data[1241] := 198;
+    data[1242] := 198;
+    data[1243] := 198;
+    data[1244] := 0;
+    data[1245] := 0;
+    data[1246] := 0;
+    data[1247] := 0;
+    data[1248] := 0;
+    data[1249] := 0;
+    data[1250] := 198;
+    data[1251] := 230;
+    data[1252] := 246;
+    data[1253] := 254;
+    data[1254] := 222;
+    data[1255] := 206;
+    data[1256] := 198;
+    data[1257] := 198;
+    data[1258] := 198;
+    data[1259] := 198;
+    data[1260] := 0;
+    data[1261] := 0;
+    data[1262] := 0;
+    data[1263] := 0;
+    data[1264] := 0;
+    data[1265] := 0;
+    data[1266] := 124;
+    data[1267] := 198;
+    data[1268] := 198;
+    data[1269] := 198;
+    data[1270] := 198;
+    data[1271] := 198;
+    data[1272] := 198;
+    data[1273] := 198;
+    data[1274] := 198;
+    data[1275] := 124;
+    data[1276] := 0;
+    data[1277] := 0;
+    data[1278] := 0;
+    data[1279] := 0;
+    data[1280] := 0;
+    data[1281] := 0;
+    data[1282] := 252;
+    data[1283] := 102;
+    data[1284] := 102;
+    data[1285] := 102;
+    data[1286] := 124;
+    data[1287] := 96;
+    data[1288] := 96;
+    data[1289] := 96;
+    data[1290] := 96;
+    data[1291] := 240;
+    data[1292] := 0;
+    data[1293] := 0;
+    data[1294] := 0;
+    data[1295] := 0;
+    data[1296] := 0;
+    data[1297] := 0;
+    data[1298] := 124;
+    data[1299] := 198;
+    data[1300] := 198;
+    data[1301] := 198;
+    data[1302] := 198;
+    data[1303] := 198;
+    data[1304] := 198;
+    data[1305] := 214;
+    data[1306] := 222;
+    data[1307] := 124;
+    data[1308] := 12;
+    data[1309] := 14;
+    data[1310] := 0;
+    data[1311] := 0;
+    data[1312] := 0;
+    data[1313] := 0;
+    data[1314] := 252;
+    data[1315] := 102;
+    data[1316] := 102;
+    data[1317] := 102;
+    data[1318] := 124;
+    data[1319] := 108;
+    data[1320] := 102;
+    data[1321] := 102;
+    data[1322] := 102;
+    data[1323] := 230;
+    data[1324] := 0;
+    data[1325] := 0;
+    data[1326] := 0;
+    data[1327] := 0;
+    data[1328] := 0;
+    data[1329] := 0;
+    data[1330] := 124;
+    data[1331] := 198;
+    data[1332] := 198;
+    data[1333] := 96;
+    data[1334] := 56;
+    data[1335] := 12;
+    data[1336] := 6;
+    data[1337] := 198;
+    data[1338] := 198;
+    data[1339] := 124;
+    data[1340] := 0;
+    data[1341] := 0;
+    data[1342] := 0;
+    data[1343] := 0;
+    data[1344] := 0;
+    data[1345] := 0;
+    data[1346] := 126;
+    data[1347] := 126;
+    data[1348] := 90;
+    data[1349] := 24;
+    data[1350] := 24;
+    data[1351] := 24;
+    data[1352] := 24;
+    data[1353] := 24;
+    data[1354] := 24;
+    data[1355] := 60;
+    data[1356] := 0;
+    data[1357] := 0;
+    data[1358] := 0;
+    data[1359] := 0;
+    data[1360] := 0;
+    data[1361] := 0;
+    data[1362] := 198;
+    data[1363] := 198;
+    data[1364] := 198;
+    data[1365] := 198;
+    data[1366] := 198;
+    data[1367] := 198;
+    data[1368] := 198;
+    data[1369] := 198;
+    data[1370] := 198;
+    data[1371] := 124;
+    data[1372] := 0;
+    data[1373] := 0;
+    data[1374] := 0;
+    data[1375] := 0;
+    data[1376] := 0;
+    data[1377] := 0;
+    data[1378] := 198;
+    data[1379] := 198;
+    data[1380] := 198;
+    data[1381] := 198;
+    data[1382] := 198;
+    data[1383] := 198;
+    data[1384] := 198;
+    data[1385] := 108;
+    data[1386] := 56;
+    data[1387] := 16;
+    data[1388] := 0;
+    data[1389] := 0;
+    data[1390] := 0;
+    data[1391] := 0;
+    data[1392] := 0;
+    data[1393] := 0;
+    data[1394] := 198;
+    data[1395] := 198;
+    data[1396] := 198;
+    data[1397] := 198;
+    data[1398] := 214;
+    data[1399] := 214;
+    data[1400] := 214;
+    data[1401] := 254;
+    data[1402] := 238;
+    data[1403] := 108;
+    data[1404] := 0;
+    data[1405] := 0;
+    data[1406] := 0;
+    data[1407] := 0;
+    data[1408] := 0;
+    data[1409] := 0;
+    data[1410] := 198;
+    data[1411] := 198;
+    data[1412] := 108;
+    data[1413] := 124;
+    data[1414] := 56;
+    data[1415] := 56;
+    data[1416] := 124;
+    data[1417] := 108;
+    data[1418] := 198;
+    data[1419] := 198;
+    data[1420] := 0;
+    data[1421] := 0;
+    data[1422] := 0;
+    data[1423] := 0;
+    data[1424] := 0;
+    data[1425] := 0;
+    data[1426] := 102;
+    data[1427] := 102;
+    data[1428] := 102;
+    data[1429] := 102;
+    data[1430] := 60;
+    data[1431] := 24;
+    data[1432] := 24;
+    data[1433] := 24;
+    data[1434] := 24;
+    data[1435] := 60;
+    data[1436] := 0;
+    data[1437] := 0;
+    data[1438] := 0;
+    data[1439] := 0;
+    data[1440] := 0;
+    data[1441] := 0;
+    data[1442] := 254;
+    data[1443] := 198;
+    data[1444] := 134;
+    data[1445] := 12;
+    data[1446] := 24;
+    data[1447] := 48;
+    data[1448] := 96;
+    data[1449] := 194;
+    data[1450] := 198;
+    data[1451] := 254;
+    data[1452] := 0;
+    data[1453] := 0;
+    data[1454] := 0;
+    data[1455] := 0;
+    data[1456] := 0;
+    data[1457] := 0;
+    data[1458] := 60;
+    data[1459] := 48;
+    data[1460] := 48;
+    data[1461] := 48;
+    data[1462] := 48;
+    data[1463] := 48;
+    data[1464] := 48;
+    data[1465] := 48;
+    data[1466] := 48;
+    data[1467] := 60;
+    data[1468] := 0;
+    data[1469] := 0;
+    data[1470] := 0;
+    data[1471] := 0;
+    data[1472] := 0;
+    data[1473] := 0;
+    data[1474] := 0;
+    data[1475] := 128;
+    data[1476] := 192;
+    data[1477] := 224;
+    data[1478] := 112;
+    data[1479] := 56;
+    data[1480] := 28;
+    data[1481] := 14;
+    data[1482] := 6;
+    data[1483] := 2;
+    data[1484] := 0;
+    data[1485] := 0;
+    data[1486] := 0;
+    data[1487] := 0;
+    data[1488] := 0;
+    data[1489] := 0;
+    data[1490] := 60;
+    data[1491] := 12;
+    data[1492] := 12;
+    data[1493] := 12;
+    data[1494] := 12;
+    data[1495] := 12;
+    data[1496] := 12;
+    data[1497] := 12;
+    data[1498] := 12;
+    data[1499] := 60;
+    data[1500] := 0;
+    data[1501] := 0;
+    data[1502] := 0;
+    data[1503] := 0;
+    data[1504] := 16;
+    data[1505] := 56;
+    data[1506] := 108;
+    data[1507] := 198;
+    data[1508] := 0;
+    data[1509] := 0;
+    data[1510] := 0;
+    data[1511] := 0;
+    data[1512] := 0;
+    data[1513] := 0;
+    data[1514] := 0;
+    data[1515] := 0;
+    data[1516] := 0;
+    data[1517] := 0;
+    data[1518] := 0;
+    data[1519] := 0;
+    data[1520] := 0;
+    data[1521] := 0;
+    data[1522] := 0;
+    data[1523] := 0;
+    data[1524] := 0;
+    data[1525] := 0;
+    data[1526] := 0;
+    data[1527] := 0;
+    data[1528] := 0;
+    data[1529] := 0;
+    data[1530] := 0;
+    data[1531] := 0;
+    data[1532] := 0;
+    data[1533] := 255;
+    data[1534] := 0;
+    data[1535] := 0;
+    data[1536] := 48;
+    data[1537] := 48;
+    data[1538] := 24;
+    data[1539] := 0;
+    data[1540] := 0;
+    data[1541] := 0;
+    data[1542] := 0;
+    data[1543] := 0;
+    data[1544] := 0;
+    data[1545] := 0;
+    data[1546] := 0;
+    data[1547] := 0;
+    data[1548] := 0;
+    data[1549] := 0;
+    data[1550] := 0;
+    data[1551] := 0;
+    data[1552] := 0;
+    data[1553] := 0;
+    data[1554] := 0;
+    data[1555] := 0;
+    data[1556] := 0;
+    data[1557] := 120;
+    data[1558] := 12;
+    data[1559] := 124;
+    data[1560] := 204;
+    data[1561] := 204;
+    data[1562] := 204;
+    data[1563] := 118;
+    data[1564] := 0;
+    data[1565] := 0;
+    data[1566] := 0;
+    data[1567] := 0;
+    data[1568] := 0;
+    data[1569] := 0;
+    data[1570] := 224;
+    data[1571] := 96;
+    data[1572] := 96;
+    data[1573] := 120;
+    data[1574] := 108;
+    data[1575] := 102;
+    data[1576] := 102;
+    data[1577] := 102;
+    data[1578] := 102;
+    data[1579] := 124;
+    data[1580] := 0;
+    data[1581] := 0;
+    data[1582] := 0;
+    data[1583] := 0;
+    data[1584] := 0;
+    data[1585] := 0;
+    data[1586] := 0;
+    data[1587] := 0;
+    data[1588] := 0;
+    data[1589] := 124;
+    data[1590] := 198;
+    data[1591] := 192;
+    data[1592] := 192;
+    data[1593] := 192;
+    data[1594] := 198;
+    data[1595] := 124;
+    data[1596] := 0;
+    data[1597] := 0;
+    data[1598] := 0;
+    data[1599] := 0;
+    data[1600] := 0;
+    data[1601] := 0;
+    data[1602] := 28;
+    data[1603] := 12;
+    data[1604] := 12;
+    data[1605] := 60;
+    data[1606] := 108;
+    data[1607] := 204;
+    data[1608] := 204;
+    data[1609] := 204;
+    data[1610] := 204;
+    data[1611] := 118;
+    data[1612] := 0;
+    data[1613] := 0;
+    data[1614] := 0;
+    data[1615] := 0;
+    data[1616] := 0;
+    data[1617] := 0;
+    data[1618] := 0;
+    data[1619] := 0;
+    data[1620] := 0;
+    data[1621] := 124;
+    data[1622] := 198;
+    data[1623] := 254;
+    data[1624] := 192;
+    data[1625] := 192;
+    data[1626] := 198;
+    data[1627] := 124;
+    data[1628] := 0;
+    data[1629] := 0;
+    data[1630] := 0;
+    data[1631] := 0;
+    data[1632] := 0;
+    data[1633] := 0;
+    data[1634] := 56;
+    data[1635] := 108;
+    data[1636] := 100;
+    data[1637] := 96;
+    data[1638] := 240;
+    data[1639] := 96;
+    data[1640] := 96;
+    data[1641] := 96;
+    data[1642] := 96;
+    data[1643] := 240;
+    data[1644] := 0;
+    data[1645] := 0;
+    data[1646] := 0;
+    data[1647] := 0;
+    data[1648] := 0;
+    data[1649] := 0;
+    data[1650] := 0;
+    data[1651] := 0;
+    data[1652] := 0;
+    data[1653] := 118;
+    data[1654] := 204;
+    data[1655] := 204;
+    data[1656] := 204;
+    data[1657] := 204;
+    data[1658] := 204;
+    data[1659] := 124;
+    data[1660] := 12;
+    data[1661] := 204;
+    data[1662] := 120;
+    data[1663] := 0;
+    data[1664] := 0;
+    data[1665] := 0;
+    data[1666] := 224;
+    data[1667] := 96;
+    data[1668] := 96;
+    data[1669] := 108;
+    data[1670] := 118;
+    data[1671] := 102;
+    data[1672] := 102;
+    data[1673] := 102;
+    data[1674] := 102;
+    data[1675] := 230;
+    data[1676] := 0;
+    data[1677] := 0;
+    data[1678] := 0;
+    data[1679] := 0;
+    data[1680] := 0;
+    data[1681] := 0;
+    data[1682] := 24;
+    data[1683] := 24;
+    data[1684] := 0;
+    data[1685] := 56;
+    data[1686] := 24;
+    data[1687] := 24;
+    data[1688] := 24;
+    data[1689] := 24;
+    data[1690] := 24;
+    data[1691] := 60;
+    data[1692] := 0;
+    data[1693] := 0;
+    data[1694] := 0;
+    data[1695] := 0;
+    data[1696] := 0;
+    data[1697] := 0;
+    data[1698] := 6;
+    data[1699] := 6;
+    data[1700] := 0;
+    data[1701] := 14;
+    data[1702] := 6;
+    data[1703] := 6;
+    data[1704] := 6;
+    data[1705] := 6;
+    data[1706] := 6;
+    data[1707] := 6;
+    data[1708] := 102;
+    data[1709] := 102;
+    data[1710] := 60;
+    data[1711] := 0;
+    data[1712] := 0;
+    data[1713] := 0;
+    data[1714] := 224;
+    data[1715] := 96;
+    data[1716] := 96;
+    data[1717] := 102;
+    data[1718] := 108;
+    data[1719] := 120;
+    data[1720] := 120;
+    data[1721] := 108;
+    data[1722] := 102;
+    data[1723] := 230;
+    data[1724] := 0;
+    data[1725] := 0;
+    data[1726] := 0;
+    data[1727] := 0;
+    data[1728] := 0;
+    data[1729] := 0;
+    data[1730] := 56;
+    data[1731] := 24;
+    data[1732] := 24;
+    data[1733] := 24;
+    data[1734] := 24;
+    data[1735] := 24;
+    data[1736] := 24;
+    data[1737] := 24;
+    data[1738] := 24;
+    data[1739] := 60;
+    data[1740] := 0;
+    data[1741] := 0;
+    data[1742] := 0;
+    data[1743] := 0;
+    data[1744] := 0;
+    data[1745] := 0;
+    data[1746] := 0;
+    data[1747] := 0;
+    data[1748] := 0;
+    data[1749] := 236;
+    data[1750] := 254;
+    data[1751] := 214;
+    data[1752] := 214;
+    data[1753] := 214;
+    data[1754] := 214;
+    data[1755] := 198;
+    data[1756] := 0;
+    data[1757] := 0;
+    data[1758] := 0;
+    data[1759] := 0;
+    data[1760] := 0;
+    data[1761] := 0;
+    data[1762] := 0;
+    data[1763] := 0;
+    data[1764] := 0;
+    data[1765] := 220;
+    data[1766] := 102;
+    data[1767] := 102;
+    data[1768] := 102;
+    data[1769] := 102;
+    data[1770] := 102;
+    data[1771] := 102;
+    data[1772] := 0;
+    data[1773] := 0;
+    data[1774] := 0;
+    data[1775] := 0;
+    data[1776] := 0;
+    data[1777] := 0;
+    data[1778] := 0;
+    data[1779] := 0;
+    data[1780] := 0;
+    data[1781] := 124;
+    data[1782] := 198;
+    data[1783] := 198;
+    data[1784] := 198;
+    data[1785] := 198;
+    data[1786] := 198;
+    data[1787] := 124;
+    data[1788] := 0;
+    data[1789] := 0;
+    data[1790] := 0;
+    data[1791] := 0;
+    data[1792] := 0;
+    data[1793] := 0;
+    data[1794] := 0;
+    data[1795] := 0;
+    data[1796] := 0;
+    data[1797] := 220;
+    data[1798] := 102;
+    data[1799] := 102;
+    data[1800] := 102;
+    data[1801] := 102;
+    data[1802] := 102;
+    data[1803] := 124;
+    data[1804] := 96;
+    data[1805] := 96;
+    data[1806] := 240;
+    data[1807] := 0;
+    data[1808] := 0;
+    data[1809] := 0;
+    data[1810] := 0;
+    data[1811] := 0;
+    data[1812] := 0;
+    data[1813] := 118;
+    data[1814] := 204;
+    data[1815] := 204;
+    data[1816] := 204;
+    data[1817] := 204;
+    data[1818] := 204;
+    data[1819] := 124;
+    data[1820] := 12;
+    data[1821] := 12;
+    data[1822] := 30;
+    data[1823] := 0;
+    data[1824] := 0;
+    data[1825] := 0;
+    data[1826] := 0;
+    data[1827] := 0;
+    data[1828] := 0;
+    data[1829] := 220;
+    data[1830] := 118;
+    data[1831] := 102;
+    data[1832] := 96;
+    data[1833] := 96;
+    data[1834] := 96;
+    data[1835] := 240;
+    data[1836] := 0;
+    data[1837] := 0;
+    data[1838] := 0;
+    data[1839] := 0;
+    data[1840] := 0;
+    data[1841] := 0;
+    data[1842] := 0;
+    data[1843] := 0;
+    data[1844] := 0;
+    data[1845] := 124;
+    data[1846] := 198;
+    data[1847] := 96;
+    data[1848] := 56;
+    data[1849] := 12;
+    data[1850] := 198;
+    data[1851] := 124;
+    data[1852] := 0;
+    data[1853] := 0;
+    data[1854] := 0;
+    data[1855] := 0;
+    data[1856] := 0;
+    data[1857] := 0;
+    data[1858] := 16;
+    data[1859] := 48;
+    data[1860] := 48;
+    data[1861] := 252;
+    data[1862] := 48;
+    data[1863] := 48;
+    data[1864] := 48;
+    data[1865] := 48;
+    data[1866] := 54;
+    data[1867] := 28;
+    data[1868] := 0;
+    data[1869] := 0;
+    data[1870] := 0;
+    data[1871] := 0;
+    data[1872] := 0;
+    data[1873] := 0;
+    data[1874] := 0;
+    data[1875] := 0;
+    data[1876] := 0;
+    data[1877] := 204;
+    data[1878] := 204;
+    data[1879] := 204;
+    data[1880] := 204;
+    data[1881] := 204;
+    data[1882] := 204;
+    data[1883] := 118;
+    data[1884] := 0;
+    data[1885] := 0;
+    data[1886] := 0;
+    data[1887] := 0;
+    data[1888] := 0;
+    data[1889] := 0;
+    data[1890] := 0;
+    data[1891] := 0;
+    data[1892] := 0;
+    data[1893] := 102;
+    data[1894] := 102;
+    data[1895] := 102;
+    data[1896] := 102;
+    data[1897] := 102;
+    data[1898] := 60;
+    data[1899] := 24;
+    data[1900] := 0;
+    data[1901] := 0;
+    data[1902] := 0;
+    data[1903] := 0;
+    data[1904] := 0;
+    data[1905] := 0;
+    data[1906] := 0;
+    data[1907] := 0;
+    data[1908] := 0;
+    data[1909] := 198;
+    data[1910] := 198;
+    data[1911] := 214;
+    data[1912] := 214;
+    data[1913] := 214;
+    data[1914] := 254;
+    data[1915] := 108;
+    data[1916] := 0;
+    data[1917] := 0;
+    data[1918] := 0;
+    data[1919] := 0;
+    data[1920] := 0;
+    data[1921] := 0;
+    data[1922] := 0;
+    data[1923] := 0;
+    data[1924] := 0;
+    data[1925] := 198;
+    data[1926] := 108;
+    data[1927] := 56;
+    data[1928] := 56;
+    data[1929] := 56;
+    data[1930] := 108;
+    data[1931] := 198;
+    data[1932] := 0;
+    data[1933] := 0;
+    data[1934] := 0;
+    data[1935] := 0;
+    data[1936] := 0;
+    data[1937] := 0;
+    data[1938] := 0;
+    data[1939] := 0;
+    data[1940] := 0;
+    data[1941] := 198;
+    data[1942] := 198;
+    data[1943] := 198;
+    data[1944] := 198;
+    data[1945] := 198;
+    data[1946] := 198;
+    data[1947] := 126;
+    data[1948] := 6;
+    data[1949] := 12;
+    data[1950] := 248;
+    data[1951] := 0;
+    data[1952] := 0;
+    data[1953] := 0;
+    data[1954] := 0;
+    data[1955] := 0;
+    data[1956] := 0;
+    data[1957] := 254;
+    data[1958] := 204;
+    data[1959] := 24;
+    data[1960] := 48;
+    data[1961] := 96;
+    data[1962] := 198;
+    data[1963] := 254;
+    data[1964] := 0;
+    data[1965] := 0;
+    data[1966] := 0;
+    data[1967] := 0;
+    data[1968] := 0;
+    data[1969] := 0;
+    data[1970] := 14;
+    data[1971] := 24;
+    data[1972] := 24;
+    data[1973] := 24;
+    data[1974] := 112;
+    data[1975] := 24;
+    data[1976] := 24;
+    data[1977] := 24;
+    data[1978] := 24;
+    data[1979] := 14;
+    data[1980] := 0;
+    data[1981] := 0;
+    data[1982] := 0;
+    data[1983] := 0;
+    data[1984] := 0;
+    data[1985] := 0;
+    data[1986] := 24;
+    data[1987] := 24;
+    data[1988] := 24;
+    data[1989] := 24;
+    data[1990] := 24;
+    data[1991] := 24;
+    data[1992] := 24;
+    data[1993] := 24;
+    data[1994] := 24;
+    data[1995] := 24;
+    data[1996] := 0;
+    data[1997] := 0;
+    data[1998] := 0;
+    data[1999] := 0;
+    data[2000] := 0;
+    data[2001] := 0;
+    data[2002] := 112;
+    data[2003] := 24;
+    data[2004] := 24;
+    data[2005] := 24;
+    data[2006] := 14;
+    data[2007] := 24;
+    data[2008] := 24;
+    data[2009] := 24;
+    data[2010] := 24;
+    data[2011] := 112;
+    data[2012] := 0;
+    data[2013] := 0;
+    data[2014] := 0;
+    data[2015] := 0;
+    data[2016] := 0;
+    data[2017] := 0;
+    data[2018] := 118;
+    data[2019] := 220;
+    data[2020] := 0;
+    data[2021] := 0;
+    data[2022] := 0;
+    data[2023] := 0;
+    data[2024] := 0;
+    data[2025] := 0;
+    data[2026] := 0;
+    data[2027] := 0;
+    data[2028] := 0;
+    data[2029] := 0;
+    data[2030] := 0;
+    data[2031] := 0;
+    data[2032] := 48;
+    data[2033] := 24;
+    data[2034] := 0;
+    data[2035] := 60;
+    data[2036] := 24;
+    data[2037] := 24;
+    data[2038] := 24;
+    data[2039] := 24;
+    data[2040] := 24;
+    data[2041] := 24;
+    data[2042] := 24;
+    data[2043] := 60;
+    data[2044] := 0;
+    data[2045] := 0;
+    data[2046] := 0;
+    data[2047] := 0;
+    data[2048] := 0;
+    data[2049] := 0;
+    data[2050] := 60;
+    data[2051] := 102;
+    data[2052] := 194;
+    data[2053] := 192;
+    data[2054] := 192;
+    data[2055] := 192;
+    data[2056] := 192;
+    data[2057] := 194;
+    data[2058] := 102;
+    data[2059] := 60;
+    data[2060] := 24;
+    data[2061] := 12;
+    data[2062] := 56;
+    data[2063] := 0;
+    data[2064] := 0;
+    data[2065] := 0;
+    data[2066] := 204;
+    data[2067] := 204;
+    data[2068] := 0;
+    data[2069] := 204;
+    data[2070] := 204;
+    data[2071] := 204;
+    data[2072] := 204;
+    data[2073] := 204;
+    data[2074] := 204;
+    data[2075] := 118;
+    data[2076] := 0;
+    data[2077] := 0;
+    data[2078] := 0;
+    data[2079] := 0;
+    data[2080] := 0;
+    data[2081] := 0;
+    data[2082] := 12;
+    data[2083] := 24;
+    data[2084] := 0;
+    data[2085] := 124;
+    data[2086] := 198;
+    data[2087] := 254;
+    data[2088] := 192;
+    data[2089] := 192;
+    data[2090] := 198;
+    data[2091] := 124;
+    data[2092] := 0;
+    data[2093] := 0;
+    data[2094] := 0;
+    data[2095] := 0;
+    data[2096] := 0;
+    data[2097] := 16;
+    data[2098] := 56;
+    data[2099] := 108;
+    data[2100] := 0;
+    data[2101] := 120;
+    data[2102] := 12;
+    data[2103] := 124;
+    data[2104] := 204;
+    data[2105] := 204;
+    data[2106] := 204;
+    data[2107] := 118;
+    data[2108] := 0;
+    data[2109] := 0;
+    data[2110] := 0;
+    data[2111] := 0;
+    data[2112] := 0;
+    data[2113] := 0;
+    data[2114] := 108;
+    data[2115] := 108;
+    data[2116] := 0;
+    data[2117] := 120;
+    data[2118] := 12;
+    data[2119] := 124;
+    data[2120] := 204;
+    data[2121] := 204;
+    data[2122] := 204;
+    data[2123] := 118;
+    data[2124] := 0;
+    data[2125] := 0;
+    data[2126] := 0;
+    data[2127] := 0;
+    data[2128] := 0;
+    data[2129] := 0;
+    data[2130] := 96;
+    data[2131] := 48;
+    data[2132] := 0;
+    data[2133] := 120;
+    data[2134] := 12;
+    data[2135] := 124;
+    data[2136] := 204;
+    data[2137] := 204;
+    data[2138] := 204;
+    data[2139] := 118;
+    data[2140] := 0;
+    data[2141] := 0;
+    data[2142] := 0;
+    data[2143] := 0;
+    data[2144] := 0;
+    data[2145] := 56;
+    data[2146] := 108;
+    data[2147] := 56;
+    data[2148] := 0;
+    data[2149] := 120;
+    data[2150] := 12;
+    data[2151] := 124;
+    data[2152] := 204;
+    data[2153] := 204;
+    data[2154] := 204;
+    data[2155] := 118;
+    data[2156] := 0;
+    data[2157] := 0;
+    data[2158] := 0;
+    data[2159] := 0;
+    data[2160] := 0;
+    data[2161] := 0;
+    data[2162] := 0;
+    data[2163] := 0;
+    data[2164] := 0;
+    data[2165] := 124;
+    data[2166] := 198;
+    data[2167] := 192;
+    data[2168] := 192;
+    data[2169] := 192;
+    data[2170] := 198;
+    data[2171] := 124;
+    data[2172] := 24;
+    data[2173] := 12;
+    data[2174] := 56;
+    data[2175] := 0;
+    data[2176] := 0;
+    data[2177] := 16;
+    data[2178] := 56;
+    data[2179] := 108;
+    data[2180] := 0;
+    data[2181] := 124;
+    data[2182] := 198;
+    data[2183] := 254;
+    data[2184] := 192;
+    data[2185] := 192;
+    data[2186] := 198;
+    data[2187] := 124;
+    data[2188] := 0;
+    data[2189] := 0;
+    data[2190] := 0;
+    data[2191] := 0;
+    data[2192] := 0;
+    data[2193] := 0;
+    data[2194] := 108;
+    data[2195] := 108;
+    data[2196] := 0;
+    data[2197] := 124;
+    data[2198] := 198;
+    data[2199] := 254;
+    data[2200] := 192;
+    data[2201] := 192;
+    data[2202] := 198;
+    data[2203] := 124;
+    data[2204] := 0;
+    data[2205] := 0;
+    data[2206] := 0;
+    data[2207] := 0;
+    data[2208] := 0;
+    data[2209] := 0;
+    data[2210] := 96;
+    data[2211] := 48;
+    data[2212] := 0;
+    data[2213] := 124;
+    data[2214] := 198;
+    data[2215] := 254;
+    data[2216] := 192;
+    data[2217] := 192;
+    data[2218] := 198;
+    data[2219] := 124;
+    data[2220] := 0;
+    data[2221] := 0;
+    data[2222] := 0;
+    data[2223] := 0;
+    data[2224] := 0;
+    data[2225] := 0;
+    data[2226] := 102;
+    data[2227] := 102;
+    data[2228] := 0;
+    data[2229] := 56;
+    data[2230] := 24;
+    data[2231] := 24;
+    data[2232] := 24;
+    data[2233] := 24;
+    data[2234] := 24;
+    data[2235] := 60;
+    data[2236] := 0;
+    data[2237] := 0;
+    data[2238] := 0;
+    data[2239] := 0;
+    data[2240] := 0;
+    data[2241] := 16;
+    data[2242] := 56;
+    data[2243] := 108;
+    data[2244] := 0;
+    data[2245] := 56;
+    data[2246] := 24;
+    data[2247] := 24;
+    data[2248] := 24;
+    data[2249] := 24;
+    data[2250] := 24;
+    data[2251] := 60;
+    data[2252] := 0;
+    data[2253] := 0;
+    data[2254] := 0;
+    data[2255] := 0;
+    data[2256] := 0;
+    data[2257] := 0;
+    data[2258] := 48;
+    data[2259] := 24;
+    data[2260] := 0;
+    data[2261] := 56;
+    data[2262] := 24;
+    data[2263] := 24;
+    data[2264] := 24;
+    data[2265] := 24;
+    data[2266] := 24;
+    data[2267] := 60;
+    data[2268] := 0;
+    data[2269] := 0;
+    data[2270] := 0;
+    data[2271] := 0;
+    data[2272] := 108;
+    data[2273] := 108;
+    data[2274] := 0;
+    data[2275] := 16;
+    data[2276] := 56;
+    data[2277] := 108;
+    data[2278] := 198;
+    data[2279] := 198;
+    data[2280] := 254;
+    data[2281] := 198;
+    data[2282] := 198;
+    data[2283] := 198;
+    data[2284] := 0;
+    data[2285] := 0;
+    data[2286] := 0;
+    data[2287] := 0;
+    data[2288] := 56;
+    data[2289] := 108;
+    data[2290] := 56;
+    data[2291] := 16;
+    data[2292] := 56;
+    data[2293] := 108;
+    data[2294] := 198;
+    data[2295] := 198;
+    data[2296] := 254;
+    data[2297] := 198;
+    data[2298] := 198;
+    data[2299] := 198;
+    data[2300] := 0;
+    data[2301] := 0;
+    data[2302] := 0;
+    data[2303] := 0;
+    data[2304] := 12;
+    data[2305] := 24;
+    data[2306] := 0;
+    data[2307] := 254;
+    data[2308] := 102;
+    data[2309] := 98;
+    data[2310] := 104;
+    data[2311] := 120;
+    data[2312] := 104;
+    data[2313] := 98;
+    data[2314] := 102;
+    data[2315] := 254;
+    data[2316] := 0;
+    data[2317] := 0;
+    data[2318] := 0;
+    data[2319] := 0;
+    data[2320] := 0;
+    data[2321] := 0;
+    data[2322] := 0;
+    data[2323] := 0;
+    data[2324] := 0;
+    data[2325] := 204;
+    data[2326] := 118;
+    data[2327] := 54;
+    data[2328] := 126;
+    data[2329] := 216;
+    data[2330] := 216;
+    data[2331] := 110;
+    data[2332] := 0;
+    data[2333] := 0;
+    data[2334] := 0;
+    data[2335] := 0;
+    data[2336] := 0;
+    data[2337] := 0;
+    data[2338] := 62;
+    data[2339] := 108;
+    data[2340] := 204;
+    data[2341] := 204;
+    data[2342] := 254;
+    data[2343] := 204;
+    data[2344] := 204;
+    data[2345] := 204;
+    data[2346] := 204;
+    data[2347] := 206;
+    data[2348] := 0;
+    data[2349] := 0;
+    data[2350] := 0;
+    data[2351] := 0;
+    data[2352] := 0;
+    data[2353] := 16;
+    data[2354] := 56;
+    data[2355] := 108;
+    data[2356] := 0;
+    data[2357] := 124;
+    data[2358] := 198;
+    data[2359] := 198;
+    data[2360] := 198;
+    data[2361] := 198;
+    data[2362] := 198;
+    data[2363] := 124;
+    data[2364] := 0;
+    data[2365] := 0;
+    data[2366] := 0;
+    data[2367] := 0;
+    data[2368] := 0;
+    data[2369] := 0;
+    data[2370] := 108;
+    data[2371] := 108;
+    data[2372] := 0;
+    data[2373] := 124;
+    data[2374] := 198;
+    data[2375] := 198;
+    data[2376] := 198;
+    data[2377] := 198;
+    data[2378] := 198;
+    data[2379] := 124;
+    data[2380] := 0;
+    data[2381] := 0;
+    data[2382] := 0;
+    data[2383] := 0;
+    data[2384] := 0;
+    data[2385] := 0;
+    data[2386] := 96;
+    data[2387] := 48;
+    data[2388] := 0;
+    data[2389] := 124;
+    data[2390] := 198;
+    data[2391] := 198;
+    data[2392] := 198;
+    data[2393] := 198;
+    data[2394] := 198;
+    data[2395] := 124;
+    data[2396] := 0;
+    data[2397] := 0;
+    data[2398] := 0;
+    data[2399] := 0;
+    data[2400] := 0;
+    data[2401] := 16;
+    data[2402] := 56;
+    data[2403] := 108;
+    data[2404] := 0;
+    data[2405] := 204;
+    data[2406] := 204;
+    data[2407] := 204;
+    data[2408] := 204;
+    data[2409] := 204;
+    data[2410] := 204;
+    data[2411] := 118;
+    data[2412] := 0;
+    data[2413] := 0;
+    data[2414] := 0;
+    data[2415] := 0;
+    data[2416] := 0;
+    data[2417] := 0;
+    data[2418] := 96;
+    data[2419] := 48;
+    data[2420] := 0;
+    data[2421] := 204;
+    data[2422] := 204;
+    data[2423] := 204;
+    data[2424] := 204;
+    data[2425] := 204;
+    data[2426] := 204;
+    data[2427] := 118;
+    data[2428] := 0;
+    data[2429] := 0;
+    data[2430] := 0;
+    data[2431] := 0;
+    data[2432] := 0;
+    data[2433] := 0;
+    data[2434] := 108;
+    data[2435] := 108;
+    data[2436] := 0;
+    data[2437] := 198;
+    data[2438] := 198;
+    data[2439] := 198;
+    data[2440] := 198;
+    data[2441] := 198;
+    data[2442] := 198;
+    data[2443] := 126;
+    data[2444] := 6;
+    data[2445] := 12;
+    data[2446] := 248;
+    data[2447] := 0;
+    data[2448] := 108;
+    data[2449] := 108;
+    data[2450] := 0;
+    data[2451] := 124;
+    data[2452] := 198;
+    data[2453] := 198;
+    data[2454] := 198;
+    data[2455] := 198;
+    data[2456] := 198;
+    data[2457] := 198;
+    data[2458] := 198;
+    data[2459] := 124;
+    data[2460] := 0;
+    data[2461] := 0;
+    data[2462] := 0;
+    data[2463] := 0;
+    data[2464] := 108;
+    data[2465] := 108;
+    data[2466] := 0;
+    data[2467] := 198;
+    data[2468] := 198;
+    data[2469] := 198;
+    data[2470] := 198;
+    data[2471] := 198;
+    data[2472] := 198;
+    data[2473] := 198;
+    data[2474] := 198;
+    data[2475] := 124;
+    data[2476] := 0;
+    data[2477] := 0;
+    data[2478] := 0;
+    data[2479] := 0;
+    data[2480] := 0;
+    data[2481] := 24;
+    data[2482] := 24;
+    data[2483] := 60;
+    data[2484] := 102;
+    data[2485] := 96;
+    data[2486] := 96;
+    data[2487] := 96;
+    data[2488] := 102;
+    data[2489] := 60;
+    data[2490] := 24;
+    data[2491] := 24;
+    data[2492] := 0;
+    data[2493] := 0;
+    data[2494] := 0;
+    data[2495] := 0;
+    data[2496] := 0;
+    data[2497] := 56;
+    data[2498] := 108;
+    data[2499] := 100;
+    data[2500] := 96;
+    data[2501] := 240;
+    data[2502] := 96;
+    data[2503] := 96;
+    data[2504] := 96;
+    data[2505] := 96;
+    data[2506] := 230;
+    data[2507] := 252;
+    data[2508] := 0;
+    data[2509] := 0;
+    data[2510] := 0;
+    data[2511] := 0;
+    data[2512] := 0;
+    data[2513] := 0;
+    data[2514] := 102;
+    data[2515] := 102;
+    data[2516] := 60;
+    data[2517] := 24;
+    data[2518] := 126;
+    data[2519] := 24;
+    data[2520] := 126;
+    data[2521] := 24;
+    data[2522] := 24;
+    data[2523] := 24;
+    data[2524] := 0;
+    data[2525] := 0;
+    data[2526] := 0;
+    data[2527] := 0;
+    data[2528] := 0;
+    data[2529] := 0;
+    data[2530] := 252;
+    data[2531] := 102;
+    data[2532] := 102;
+    data[2533] := 124;
+    data[2534] := 98;
+    data[2535] := 102;
+    data[2536] := 111;
+    data[2537] := 102;
+    data[2538] := 102;
+    data[2539] := 243;
+    data[2540] := 0;
+    data[2541] := 0;
+    data[2542] := 0;
+    data[2543] := 0;
+    data[2544] := 0;
+    data[2545] := 0;
+    data[2546] := 28;
+    data[2547] := 54;
+    data[2548] := 50;
+    data[2549] := 48;
+    data[2550] := 120;
+    data[2551] := 48;
+    data[2552] := 48;
+    data[2553] := 48;
+    data[2554] := 48;
+    data[2555] := 48;
+    data[2556] := 48;
+    data[2557] := 48;
+    data[2558] := 224;
+    data[2559] := 0;
+    data[2560] := 0;
+    data[2561] := 0;
+    data[2562] := 24;
+    data[2563] := 48;
+    data[2564] := 0;
+    data[2565] := 120;
+    data[2566] := 12;
+    data[2567] := 124;
+    data[2568] := 204;
+    data[2569] := 204;
+    data[2570] := 204;
+    data[2571] := 118;
+    data[2572] := 0;
+    data[2573] := 0;
+    data[2574] := 0;
+    data[2575] := 0;
+    data[2576] := 0;
+    data[2577] := 0;
+    data[2578] := 12;
+    data[2579] := 24;
+    data[2580] := 0;
+    data[2581] := 56;
+    data[2582] := 24;
+    data[2583] := 24;
+    data[2584] := 24;
+    data[2585] := 24;
+    data[2586] := 24;
+    data[2587] := 60;
+    data[2588] := 0;
+    data[2589] := 0;
+    data[2590] := 0;
+    data[2591] := 0;
+    data[2592] := 0;
+    data[2593] := 0;
+    data[2594] := 12;
+    data[2595] := 24;
+    data[2596] := 0;
+    data[2597] := 124;
+    data[2598] := 198;
+    data[2599] := 198;
+    data[2600] := 198;
+    data[2601] := 198;
+    data[2602] := 198;
+    data[2603] := 124;
+    data[2604] := 0;
+    data[2605] := 0;
+    data[2606] := 0;
+    data[2607] := 0;
+    data[2608] := 0;
+    data[2609] := 0;
+    data[2610] := 24;
+    data[2611] := 48;
+    data[2612] := 0;
+    data[2613] := 204;
+    data[2614] := 204;
+    data[2615] := 204;
+    data[2616] := 204;
+    data[2617] := 204;
+    data[2618] := 204;
+    data[2619] := 118;
+    data[2620] := 0;
+    data[2621] := 0;
+    data[2622] := 0;
+    data[2623] := 0;
+    data[2624] := 0;
+    data[2625] := 0;
+    data[2626] := 118;
+    data[2627] := 220;
+    data[2628] := 0;
+    data[2629] := 220;
+    data[2630] := 102;
+    data[2631] := 102;
+    data[2632] := 102;
+    data[2633] := 102;
+    data[2634] := 102;
+    data[2635] := 102;
+    data[2636] := 0;
+    data[2637] := 0;
+    data[2638] := 0;
+    data[2639] := 0;
+    data[2640] := 118;
+    data[2641] := 220;
+    data[2642] := 0;
+    data[2643] := 198;
+    data[2644] := 230;
+    data[2645] := 246;
+    data[2646] := 254;
+    data[2647] := 222;
+    data[2648] := 206;
+    data[2649] := 198;
+    data[2650] := 198;
+    data[2651] := 198;
+    data[2652] := 0;
+    data[2653] := 0;
+    data[2654] := 0;
+    data[2655] := 0;
+    data[2656] := 0;
+    data[2657] := 60;
+    data[2658] := 108;
+    data[2659] := 108;
+    data[2660] := 62;
+    data[2661] := 0;
+    data[2662] := 126;
+    data[2663] := 0;
+    data[2664] := 0;
+    data[2665] := 0;
+    data[2666] := 0;
+    data[2667] := 0;
+    data[2668] := 0;
+    data[2669] := 0;
+    data[2670] := 0;
+    data[2671] := 0;
+    data[2672] := 0;
+    data[2673] := 56;
+    data[2674] := 108;
+    data[2675] := 108;
+    data[2676] := 56;
+    data[2677] := 0;
+    data[2678] := 124;
+    data[2679] := 0;
+    data[2680] := 0;
+    data[2681] := 0;
+    data[2682] := 0;
+    data[2683] := 0;
+    data[2684] := 0;
+    data[2685] := 0;
+    data[2686] := 0;
+    data[2687] := 0;
+    data[2688] := 0;
+    data[2689] := 0;
+    data[2690] := 48;
+    data[2691] := 48;
+    data[2692] := 0;
+    data[2693] := 48;
+    data[2694] := 48;
+    data[2695] := 96;
+    data[2696] := 192;
+    data[2697] := 198;
+    data[2698] := 198;
+    data[2699] := 124;
+    data[2700] := 0;
+    data[2701] := 0;
+    data[2702] := 0;
+    data[2703] := 0;
+    data[2704] := 12;
+    data[2705] := 24;
+    data[2706] := 0;
+    data[2707] := 60;
+    data[2708] := 24;
+    data[2709] := 24;
+    data[2710] := 24;
+    data[2711] := 24;
+    data[2712] := 24;
+    data[2713] := 24;
+    data[2714] := 24;
+    data[2715] := 60;
+    data[2716] := 0;
+    data[2717] := 0;
+    data[2718] := 0;
+    data[2719] := 0;
+    data[2720] := 0;
+    data[2721] := 0;
+    data[2722] := 0;
+    data[2723] := 0;
+    data[2724] := 0;
+    data[2725] := 0;
+    data[2726] := 254;
+    data[2727] := 6;
+    data[2728] := 6;
+    data[2729] := 6;
+    data[2730] := 6;
+    data[2731] := 0;
+    data[2732] := 0;
+    data[2733] := 0;
+    data[2734] := 0;
+    data[2735] := 0;
+    data[2736] := 0;
+    data[2737] := 192;
+    data[2738] := 192;
+    data[2739] := 194;
+    data[2740] := 198;
+    data[2741] := 204;
+    data[2742] := 24;
+    data[2743] := 48;
+    data[2744] := 96;
+    data[2745] := 220;
+    data[2746] := 134;
+    data[2747] := 12;
+    data[2748] := 24;
+    data[2749] := 62;
+    data[2750] := 0;
+    data[2751] := 0;
+    data[2752] := 0;
+    data[2753] := 192;
+    data[2754] := 192;
+    data[2755] := 194;
+    data[2756] := 198;
+    data[2757] := 204;
+    data[2758] := 24;
+    data[2759] := 48;
+    data[2760] := 102;
+    data[2761] := 206;
+    data[2762] := 158;
+    data[2763] := 62;
+    data[2764] := 6;
+    data[2765] := 6;
+    data[2766] := 0;
+    data[2767] := 0;
+    data[2768] := 0;
+    data[2769] := 0;
+    data[2770] := 24;
+    data[2771] := 24;
+    data[2772] := 0;
+    data[2773] := 24;
+    data[2774] := 24;
+    data[2775] := 24;
+    data[2776] := 60;
+    data[2777] := 60;
+    data[2778] := 60;
+    data[2779] := 24;
+    data[2780] := 0;
+    data[2781] := 0;
+    data[2782] := 0;
+    data[2783] := 0;
+    data[2784] := 0;
+    data[2785] := 0;
+    data[2786] := 0;
+    data[2787] := 0;
+    data[2788] := 0;
+    data[2789] := 54;
+    data[2790] := 108;
+    data[2791] := 216;
+    data[2792] := 108;
+    data[2793] := 54;
+    data[2794] := 0;
+    data[2795] := 0;
+    data[2796] := 0;
+    data[2797] := 0;
+    data[2798] := 0;
+    data[2799] := 0;
+    data[2800] := 0;
+    data[2801] := 0;
+    data[2802] := 0;
+    data[2803] := 0;
+    data[2804] := 0;
+    data[2805] := 216;
+    data[2806] := 108;
+    data[2807] := 54;
+    data[2808] := 108;
+    data[2809] := 216;
+    data[2810] := 0;
+    data[2811] := 0;
+    data[2812] := 0;
+    data[2813] := 0;
+    data[2814] := 0;
+    data[2815] := 0;
+    data[2816] := 17;
+    data[2817] := 68;
+    data[2818] := 17;
+    data[2819] := 68;
+    data[2820] := 17;
+    data[2821] := 68;
+    data[2822] := 17;
+    data[2823] := 68;
+    data[2824] := 17;
+    data[2825] := 68;
+    data[2826] := 17;
+    data[2827] := 68;
+    data[2828] := 17;
+    data[2829] := 68;
+    data[2830] := 17;
+    data[2831] := 68;
+    data[2832] := 85;
+    data[2833] := 170;
+    data[2834] := 85;
+    data[2835] := 170;
+    data[2836] := 85;
+    data[2837] := 170;
+    data[2838] := 85;
+    data[2839] := 170;
+    data[2840] := 85;
+    data[2841] := 170;
+    data[2842] := 85;
+    data[2843] := 170;
+    data[2844] := 85;
+    data[2845] := 170;
+    data[2846] := 85;
+    data[2847] := 170;
+    data[2848] := 24;
+    data[2849] := 60;
+    data[2850] := 66;
+    data[2851] := 60;
+    data[2852] := 24;
+    data[2853] := 24;
+    data[2854] := 24;
+    data[2855] := 24;
+    data[2856] := 24;
+    data[2857] := 24;
+    data[2858] := 24;
+    data[2859] := 60;
+    data[2860] := 0;
+    data[2861] := 0;
+    data[2862] := 0;
+    data[2863] := 0;
+    data[2864] := 24;
+    data[2865] := 24;
+    data[2866] := 24;
+    data[2867] := 24;
+    data[2868] := 24;
+    data[2869] := 24;
+    data[2870] := 24;
+    data[2871] := 24;
+    data[2872] := 24;
+    data[2873] := 24;
+    data[2874] := 24;
+    data[2875] := 24;
+    data[2876] := 24;
+    data[2877] := 24;
+    data[2878] := 24;
+    data[2879] := 24;
+    data[2880] := 24;
+    data[2881] := 24;
+    data[2882] := 24;
+    data[2883] := 24;
+    data[2884] := 24;
+    data[2885] := 24;
+    data[2886] := 24;
+    data[2887] := 248;
+    data[2888] := 24;
+    data[2889] := 24;
+    data[2890] := 24;
+    data[2891] := 24;
+    data[2892] := 24;
+    data[2893] := 24;
+    data[2894] := 24;
+    data[2895] := 24;
+    data[2896] := 102;
+    data[2897] := 102;
+    data[2898] := 0;
+    data[2899] := 60;
+    data[2900] := 24;
+    data[2901] := 24;
+    data[2902] := 24;
+    data[2903] := 24;
+    data[2904] := 24;
+    data[2905] := 24;
+    data[2906] := 24;
+    data[2907] := 60;
+    data[2908] := 0;
+    data[2909] := 0;
+    data[2910] := 0;
+    data[2911] := 0;
+    data[2912] := 0;
+    data[2913] := 0;
+    data[2914] := 248;
+    data[2915] := 108;
+    data[2916] := 102;
+    data[2917] := 102;
+    data[2918] := 246;
+    data[2919] := 102;
+    data[2920] := 102;
+    data[2921] := 102;
+    data[2922] := 108;
+    data[2923] := 248;
+    data[2924] := 0;
+    data[2925] := 0;
+    data[2926] := 0;
+    data[2927] := 0;
+    data[2928] := 96;
+    data[2929] := 48;
+    data[2930] := 0;
+    data[2931] := 124;
+    data[2932] := 198;
+    data[2933] := 198;
+    data[2934] := 198;
+    data[2935] := 198;
+    data[2936] := 198;
+    data[2937] := 198;
+    data[2938] := 198;
+    data[2939] := 124;
+    data[2940] := 0;
+    data[2941] := 0;
+    data[2942] := 0;
+    data[2943] := 0;
+    data[2944] := 12;
+    data[2945] := 24;
+    data[2946] := 0;
+    data[2947] := 124;
+    data[2948] := 198;
+    data[2949] := 198;
+    data[2950] := 198;
+    data[2951] := 198;
+    data[2952] := 198;
+    data[2953] := 198;
+    data[2954] := 198;
+    data[2955] := 124;
+    data[2956] := 0;
+    data[2957] := 0;
+    data[2958] := 0;
+    data[2959] := 0;
+    data[2960] := 16;
+    data[2961] := 56;
+    data[2962] := 68;
+    data[2963] := 124;
+    data[2964] := 198;
+    data[2965] := 198;
+    data[2966] := 198;
+    data[2967] := 198;
+    data[2968] := 198;
+    data[2969] := 198;
+    data[2970] := 198;
+    data[2971] := 124;
+    data[2972] := 0;
+    data[2973] := 0;
+    data[2974] := 0;
+    data[2975] := 0;
+    data[2976] := 118;
+    data[2977] := 220;
+    data[2978] := 0;
+    data[2979] := 124;
+    data[2980] := 198;
+    data[2981] := 198;
+    data[2982] := 198;
+    data[2983] := 198;
+    data[2984] := 198;
+    data[2985] := 198;
+    data[2986] := 198;
+    data[2987] := 124;
+    data[2988] := 0;
+    data[2989] := 0;
+    data[2990] := 0;
+    data[2991] := 0;
+    data[2992] := 0;
+    data[2993] := 0;
+    data[2994] := 0;
+    data[2995] := 0;
+    data[2996] := 0;
+    data[2997] := 102;
+    data[2998] := 60;
+    data[2999] := 24;
+    data[3000] := 60;
+    data[3001] := 102;
+    data[3002] := 0;
+    data[3003] := 0;
+    data[3004] := 0;
+    data[3005] := 0;
+    data[3006] := 0;
+    data[3007] := 0;
+    data[3008] := 0;
+    data[3009] := 0;
+    data[3010] := 122;
+    data[3011] := 196;
+    data[3012] := 206;
+    data[3013] := 206;
+    data[3014] := 214;
+    data[3015] := 214;
+    data[3016] := 230;
+    data[3017] := 230;
+    data[3018] := 70;
+    data[3019] := 188;
+    data[3020] := 0;
+    data[3021] := 0;
+    data[3022] := 0;
+    data[3023] := 0;
+    data[3024] := 96;
+    data[3025] := 48;
+    data[3026] := 0;
+    data[3027] := 198;
+    data[3028] := 198;
+    data[3029] := 198;
+    data[3030] := 198;
+    data[3031] := 198;
+    data[3032] := 198;
+    data[3033] := 198;
+    data[3034] := 198;
+    data[3035] := 124;
+    data[3036] := 0;
+    data[3037] := 0;
+    data[3038] := 0;
+    data[3039] := 0;
+    data[3040] := 12;
+    data[3041] := 24;
+    data[3042] := 0;
+    data[3043] := 198;
+    data[3044] := 198;
+    data[3045] := 198;
+    data[3046] := 198;
+    data[3047] := 198;
+    data[3048] := 198;
+    data[3049] := 198;
+    data[3050] := 198;
+    data[3051] := 124;
+    data[3052] := 0;
+    data[3053] := 0;
+    data[3054] := 0;
+    data[3055] := 0;
+    data[3056] := 0;
+    data[3057] := 0;
+    data[3058] := 0;
+    data[3059] := 0;
+    data[3060] := 0;
+    data[3061] := 0;
+    data[3062] := 0;
+    data[3063] := 248;
+    data[3064] := 24;
+    data[3065] := 24;
+    data[3066] := 24;
+    data[3067] := 24;
+    data[3068] := 24;
+    data[3069] := 24;
+    data[3070] := 24;
+    data[3071] := 24;
+    data[3072] := 24;
+    data[3073] := 24;
+    data[3074] := 24;
+    data[3075] := 24;
+    data[3076] := 24;
+    data[3077] := 24;
+    data[3078] := 24;
+    data[3079] := 31;
+    data[3080] := 0;
+    data[3081] := 0;
+    data[3082] := 0;
+    data[3083] := 0;
+    data[3084] := 0;
+    data[3085] := 0;
+    data[3086] := 0;
+    data[3087] := 0;
+    data[3088] := 24;
+    data[3089] := 24;
+    data[3090] := 24;
+    data[3091] := 24;
+    data[3092] := 24;
+    data[3093] := 24;
+    data[3094] := 24;
+    data[3095] := 255;
+    data[3096] := 0;
+    data[3097] := 0;
+    data[3098] := 0;
+    data[3099] := 0;
+    data[3100] := 0;
+    data[3101] := 0;
+    data[3102] := 0;
+    data[3103] := 0;
+    data[3104] := 0;
+    data[3105] := 0;
+    data[3106] := 0;
+    data[3107] := 0;
+    data[3108] := 0;
+    data[3109] := 0;
+    data[3110] := 0;
+    data[3111] := 255;
+    data[3112] := 24;
+    data[3113] := 24;
+    data[3114] := 24;
+    data[3115] := 24;
+    data[3116] := 24;
+    data[3117] := 24;
+    data[3118] := 24;
+    data[3119] := 24;
+    data[3120] := 24;
+    data[3121] := 24;
+    data[3122] := 24;
+    data[3123] := 24;
+    data[3124] := 24;
+    data[3125] := 24;
+    data[3126] := 24;
+    data[3127] := 31;
+    data[3128] := 24;
+    data[3129] := 24;
+    data[3130] := 24;
+    data[3131] := 24;
+    data[3132] := 24;
+    data[3133] := 24;
+    data[3134] := 24;
+    data[3135] := 24;
+    data[3136] := 0;
+    data[3137] := 0;
+    data[3138] := 0;
+    data[3139] := 0;
+    data[3140] := 0;
+    data[3141] := 0;
+    data[3142] := 0;
+    data[3143] := 255;
+    data[3144] := 0;
+    data[3145] := 0;
+    data[3146] := 0;
+    data[3147] := 0;
+    data[3148] := 0;
+    data[3149] := 0;
+    data[3150] := 0;
+    data[3151] := 0;
+    data[3152] := 24;
+    data[3153] := 24;
+    data[3154] := 24;
+    data[3155] := 24;
+    data[3156] := 24;
+    data[3157] := 24;
+    data[3158] := 24;
+    data[3159] := 255;
+    data[3160] := 24;
+    data[3161] := 24;
+    data[3162] := 24;
+    data[3163] := 24;
+    data[3164] := 24;
+    data[3165] := 24;
+    data[3166] := 24;
+    data[3167] := 24;
+    data[3168] := 16;
+    data[3169] := 56;
+    data[3170] := 68;
+    data[3171] := 198;
+    data[3172] := 198;
+    data[3173] := 198;
+    data[3174] := 198;
+    data[3175] := 198;
+    data[3176] := 198;
+    data[3177] := 198;
+    data[3178] := 198;
+    data[3179] := 124;
+    data[3180] := 0;
+    data[3181] := 0;
+    data[3182] := 0;
+    data[3183] := 0;
+    data[3184] := 12;
+    data[3185] := 24;
+    data[3186] := 0;
+    data[3187] := 102;
+    data[3188] := 102;
+    data[3189] := 102;
+    data[3190] := 60;
+    data[3191] := 24;
+    data[3192] := 24;
+    data[3193] := 24;
+    data[3194] := 24;
+    data[3195] := 60;
+    data[3196] := 0;
+    data[3197] := 0;
+    data[3198] := 0;
+    data[3199] := 0;
+    data[3200] := 0;
+    data[3201] := 0;
+    data[3202] := 240;
+    data[3203] := 96;
+    data[3204] := 124;
+    data[3205] := 102;
+    data[3206] := 102;
+    data[3207] := 102;
+    data[3208] := 102;
+    data[3209] := 124;
+    data[3210] := 96;
+    data[3211] := 240;
+    data[3212] := 0;
+    data[3213] := 0;
+    data[3214] := 0;
+    data[3215] := 0;
+    data[3216] := 0;
+    data[3217] := 0;
+    data[3218] := 118;
+    data[3219] := 220;
+    data[3220] := 0;
+    data[3221] := 120;
+    data[3222] := 12;
+    data[3223] := 124;
+    data[3224] := 204;
+    data[3225] := 204;
+    data[3226] := 204;
+    data[3227] := 118;
+    data[3228] := 0;
+    data[3229] := 0;
+    data[3230] := 0;
+    data[3231] := 0;
+    data[3232] := 0;
+    data[3233] := 0;
+    data[3234] := 118;
+    data[3235] := 28;
+    data[3236] := 60;
+    data[3237] := 6;
+    data[3238] := 126;
+    data[3239] := 198;
+    data[3240] := 198;
+    data[3241] := 198;
+    data[3242] := 198;
+    data[3243] := 124;
+    data[3244] := 0;
+    data[3245] := 0;
+    data[3246] := 0;
+    data[3247] := 0;
+    data[3248] := 0;
+    data[3249] := 0;
+    data[3250] := 118;
+    data[3251] := 220;
+    data[3252] := 0;
+    data[3253] := 124;
+    data[3254] := 198;
+    data[3255] := 198;
+    data[3256] := 198;
+    data[3257] := 198;
+    data[3258] := 198;
+    data[3259] := 124;
+    data[3260] := 0;
+    data[3261] := 0;
+    data[3262] := 0;
+    data[3263] := 0;
+    data[3264] := 0;
+    data[3265] := 0;
+    data[3266] := 0;
+    data[3267] := 0;
+    data[3268] := 0;
+    data[3269] := 122;
+    data[3270] := 196;
+    data[3271] := 206;
+    data[3272] := 214;
+    data[3273] := 230;
+    data[3274] := 70;
+    data[3275] := 188;
+    data[3276] := 0;
+    data[3277] := 0;
+    data[3278] := 0;
+    data[3279] := 0;
+    data[3280] := 0;
+    data[3281] := 0;
+    data[3282] := 12;
+    data[3283] := 24;
+    data[3284] := 0;
+    data[3285] := 198;
+    data[3286] := 198;
+    data[3287] := 198;
+    data[3288] := 198;
+    data[3289] := 198;
+    data[3290] := 198;
+    data[3291] := 126;
+    data[3292] := 6;
+    data[3293] := 12;
+    data[3294] := 248;
+    data[3295] := 0;
+    data[3296] := 0;
+    data[3297] := 0;
+    data[3298] := 224;
+    data[3299] := 96;
+    data[3300] := 96;
+    data[3301] := 124;
+    data[3302] := 102;
+    data[3303] := 102;
+    data[3304] := 102;
+    data[3305] := 102;
+    data[3306] := 102;
+    data[3307] := 124;
+    data[3308] := 96;
+    data[3309] := 96;
+    data[3310] := 240;
+    data[3311] := 0;
+    data[3312] := 108;
+    data[3313] := 56;
+    data[3314] := 0;
+    data[3315] := 60;
+    data[3316] := 102;
+    data[3317] := 194;
+    data[3318] := 192;
+    data[3319] := 222;
+    data[3320] := 198;
+    data[3321] := 198;
+    data[3322] := 102;
+    data[3323] := 58;
+    data[3324] := 0;
+    data[3325] := 0;
+    data[3326] := 0;
+    data[3327] := 0;
+    data[3328] := 0;
+    data[3329] := 0;
+    data[3330] := 108;
+    data[3331] := 56;
+    data[3332] := 0;
+    data[3333] := 118;
+    data[3334] := 204;
+    data[3335] := 204;
+    data[3336] := 204;
+    data[3337] := 204;
+    data[3338] := 204;
+    data[3339] := 124;
+    data[3340] := 12;
+    data[3341] := 204;
+    data[3342] := 120;
+    data[3343] := 0;
+    data[3344] := 24;
+    data[3345] := 24;
+    data[3346] := 0;
+    data[3347] := 60;
+    data[3348] := 24;
+    data[3349] := 24;
+    data[3350] := 24;
+    data[3351] := 24;
+    data[3352] := 24;
+    data[3353] := 24;
+    data[3354] := 24;
+    data[3355] := 60;
+    data[3356] := 0;
+    data[3357] := 0;
+    data[3358] := 0;
+    data[3359] := 0;
+    data[3360] := 0;
+    data[3361] := 0;
+    data[3362] := 0;
+    data[3363] := 0;
+    data[3364] := 0;
+    data[3365] := 56;
+    data[3366] := 24;
+    data[3367] := 24;
+    data[3368] := 24;
+    data[3369] := 24;
+    data[3370] := 24;
+    data[3371] := 60;
+    data[3372] := 0;
+    data[3373] := 0;
+    data[3374] := 0;
+    data[3375] := 0;
+    data[3376] := 0;
+    data[3377] := 0;
+    data[3378] := 110;
+    data[3379] := 216;
+    data[3380] := 216;
+    data[3381] := 216;
+    data[3382] := 222;
+    data[3383] := 216;
+    data[3384] := 216;
+    data[3385] := 216;
+    data[3386] := 216;
+    data[3387] := 110;
+    data[3388] := 0;
+    data[3389] := 0;
+    data[3390] := 0;
+    data[3391] := 0;
+    data[3392] := 0;
+    data[3393] := 0;
+    data[3394] := 0;
+    data[3395] := 0;
+    data[3396] := 0;
+    data[3397] := 108;
+    data[3398] := 214;
+    data[3399] := 214;
+    data[3400] := 222;
+    data[3401] := 216;
+    data[3402] := 216;
+    data[3403] := 110;
+    data[3404] := 0;
+    data[3405] := 0;
+    data[3406] := 0;
+    data[3407] := 0;
+    data[3408] := 0;
+    data[3409] := 0;
+    data[3410] := 0;
+    data[3411] := 124;
+    data[3412] := 198;
+    data[3413] := 198;
+    data[3414] := 96;
+    data[3415] := 56;
+    data[3416] := 12;
+    data[3417] := 198;
+    data[3418] := 198;
+    data[3419] := 124;
+    data[3420] := 24;
+    data[3421] := 12;
+    data[3422] := 56;
+    data[3423] := 0;
+    data[3424] := 0;
+    data[3425] := 0;
+    data[3426] := 0;
+    data[3427] := 0;
+    data[3428] := 0;
+    data[3429] := 124;
+    data[3430] := 198;
+    data[3431] := 96;
+    data[3432] := 56;
+    data[3433] := 12;
+    data[3434] := 198;
+    data[3435] := 124;
+    data[3436] := 24;
+    data[3437] := 12;
+    data[3438] := 56;
+    data[3439] := 0;
+    data[3440] := 108;
+    data[3441] := 56;
+    data[3442] := 16;
+    data[3443] := 124;
+    data[3444] := 198;
+    data[3445] := 198;
+    data[3446] := 96;
+    data[3447] := 56;
+    data[3448] := 12;
+    data[3449] := 198;
+    data[3450] := 198;
+    data[3451] := 124;
+    data[3452] := 0;
+    data[3453] := 0;
+    data[3454] := 0;
+    data[3455] := 0;
+    data[3456] := 0;
+    data[3457] := 108;
+    data[3458] := 56;
+    data[3459] := 16;
+    data[3460] := 0;
+    data[3461] := 124;
+    data[3462] := 198;
+    data[3463] := 96;
+    data[3464] := 56;
+    data[3465] := 12;
+    data[3466] := 198;
+    data[3467] := 124;
+    data[3468] := 0;
+    data[3469] := 0;
+    data[3470] := 0;
+    data[3471] := 0;
+    data[3472] := 24;
+    data[3473] := 24;
+    data[3474] := 24;
+    data[3475] := 24;
+    data[3476] := 24;
+    data[3477] := 24;
+    data[3478] := 24;
+    data[3479] := 248;
+    data[3480] := 0;
+    data[3481] := 0;
+    data[3482] := 0;
+    data[3483] := 0;
+    data[3484] := 0;
+    data[3485] := 0;
+    data[3486] := 0;
+    data[3487] := 0;
+    data[3488] := 0;
+    data[3489] := 0;
+    data[3490] := 0;
+    data[3491] := 0;
+    data[3492] := 0;
+    data[3493] := 0;
+    data[3494] := 0;
+    data[3495] := 31;
+    data[3496] := 24;
+    data[3497] := 24;
+    data[3498] := 24;
+    data[3499] := 24;
+    data[3500] := 24;
+    data[3501] := 24;
+    data[3502] := 24;
+    data[3503] := 24;
+    data[3504] := 255;
+    data[3505] := 255;
+    data[3506] := 255;
+    data[3507] := 255;
+    data[3508] := 255;
+    data[3509] := 255;
+    data[3510] := 255;
+    data[3511] := 255;
+    data[3512] := 255;
+    data[3513] := 255;
+    data[3514] := 255;
+    data[3515] := 255;
+    data[3516] := 255;
+    data[3517] := 255;
+    data[3518] := 255;
+    data[3519] := 255;
+    data[3520] := 102;
+    data[3521] := 102;
+    data[3522] := 0;
+    data[3523] := 102;
+    data[3524] := 102;
+    data[3525] := 102;
+    data[3526] := 60;
+    data[3527] := 24;
+    data[3528] := 24;
+    data[3529] := 24;
+    data[3530] := 24;
+    data[3531] := 60;
+    data[3532] := 0;
+    data[3533] := 0;
+    data[3534] := 0;
+    data[3535] := 0;
+    data[3536] := 108;
+    data[3537] := 56;
+    data[3538] := 16;
+    data[3539] := 254;
+    data[3540] := 198;
+    data[3541] := 140;
+    data[3542] := 24;
+    data[3543] := 48;
+    data[3544] := 96;
+    data[3545] := 194;
+    data[3546] := 198;
+    data[3547] := 254;
+    data[3548] := 0;
+    data[3549] := 0;
+    data[3550] := 0;
+    data[3551] := 0;
+    data[3552] := 0;
+    data[3553] := 108;
+    data[3554] := 56;
+    data[3555] := 16;
+    data[3556] := 0;
+    data[3557] := 254;
+    data[3558] := 204;
+    data[3559] := 24;
+    data[3560] := 48;
+    data[3561] := 96;
+    data[3562] := 198;
+    data[3563] := 254;
+    data[3564] := 0;
+    data[3565] := 0;
+    data[3566] := 0;
+    data[3567] := 0;
+    data[3568] := 0;
+    data[3569] := 16;
+    data[3570] := 56;
+    data[3571] := 108;
+    data[3572] := 0;
+    data[3573] := 0;
+    data[3574] := 0;
+    data[3575] := 0;
+    data[3576] := 0;
+    data[3577] := 0;
+    data[3578] := 0;
+    data[3579] := 0;
+    data[3580] := 0;
+    data[3581] := 0;
+    data[3582] := 0;
+    data[3583] := 0;
+    data[3584] := 0;
+    data[3585] := 0;
+    data[3586] := 118;
+    data[3587] := 220;
+    data[3588] := 0;
+    data[3589] := 0;
+    data[3590] := 0;
+    data[3591] := 0;
+    data[3592] := 0;
+    data[3593] := 0;
+    data[3594] := 0;
+    data[3595] := 0;
+    data[3596] := 0;
+    data[3597] := 0;
+    data[3598] := 0;
+    data[3599] := 0;
+    data[3600] := 0;
+    data[3601] := 0;
+    data[3602] := 60;
+    data[3603] := 102;
+    data[3604] := 102;
+    data[3605] := 102;
+    data[3606] := 108;
+    data[3607] := 102;
+    data[3608] := 102;
+    data[3609] := 102;
+    data[3610] := 102;
+    data[3611] := 236;
+    data[3612] := 0;
+    data[3613] := 0;
+    data[3614] := 0;
+    data[3615] := 0;
+    data[3616] := 0;
+    data[3617] := 24;
+    data[3618] := 48;
+    data[3619] := 48;
+    data[3620] := 48;
+    data[3621] := 0;
+    data[3622] := 0;
+    data[3623] := 0;
+    data[3624] := 0;
+    data[3625] := 0;
+    data[3626] := 0;
+    data[3627] := 0;
+    data[3628] := 0;
+    data[3629] := 0;
+    data[3630] := 0;
+    data[3631] := 0;
+    data[3632] := 0;
+    data[3633] := 0;
+    data[3634] := 0;
+    data[3635] := 0;
+    data[3636] := 0;
+    data[3637] := 254;
+    data[3638] := 108;
+    data[3639] := 108;
+    data[3640] := 108;
+    data[3641] := 108;
+    data[3642] := 108;
+    data[3643] := 102;
+    data[3644] := 0;
+    data[3645] := 0;
+    data[3646] := 0;
+    data[3647] := 0;
+    data[3648] := 0;
+    data[3649] := 24;
+    data[3650] := 24;
+    data[3651] := 24;
+    data[3652] := 48;
+    data[3653] := 0;
+    data[3654] := 0;
+    data[3655] := 0;
+    data[3656] := 0;
+    data[3657] := 0;
+    data[3658] := 0;
+    data[3659] := 0;
+    data[3660] := 0;
+    data[3661] := 0;
+    data[3662] := 0;
+    data[3663] := 0;
+    data[3664] := 0;
+    data[3665] := 0;
+    data[3666] := 0;
+    data[3667] := 0;
+    data[3668] := 0;
+    data[3669] := 0;
+    data[3670] := 0;
+    data[3671] := 0;
+    data[3672] := 0;
+    data[3673] := 0;
+    data[3674] := 24;
+    data[3675] := 24;
+    data[3676] := 24;
+    data[3677] := 48;
+    data[3678] := 0;
+    data[3679] := 0;
+    data[3680] := 0;
+    data[3681] := 0;
+    data[3682] := 0;
+    data[3683] := 0;
+    data[3684] := 0;
+    data[3685] := 204;
+    data[3686] := 204;
+    data[3687] := 204;
+    data[3688] := 204;
+    data[3689] := 204;
+    data[3690] := 204;
+    data[3691] := 246;
+    data[3692] := 192;
+    data[3693] := 192;
+    data[3694] := 192;
+    data[3695] := 0;
+    data[3696] := 0;
+    data[3697] := 102;
+    data[3698] := 204;
+    data[3699] := 204;
+    data[3700] := 204;
+    data[3701] := 0;
+    data[3702] := 0;
+    data[3703] := 0;
+    data[3704] := 0;
+    data[3705] := 0;
+    data[3706] := 0;
+    data[3707] := 0;
+    data[3708] := 0;
+    data[3709] := 0;
+    data[3710] := 0;
+    data[3711] := 0;
+    data[3712] := 0;
+    data[3713] := 102;
+    data[3714] := 102;
+    data[3715] := 102;
+    data[3716] := 204;
+    data[3717] := 0;
+    data[3718] := 0;
+    data[3719] := 0;
+    data[3720] := 0;
+    data[3721] := 0;
+    data[3722] := 0;
+    data[3723] := 0;
+    data[3724] := 0;
+    data[3725] := 0;
+    data[3726] := 0;
+    data[3727] := 0;
+    data[3728] := 0;
+    data[3729] := 0;
+    data[3730] := 0;
+    data[3731] := 0;
+    data[3732] := 0;
+    data[3733] := 0;
+    data[3734] := 0;
+    data[3735] := 0;
+    data[3736] := 0;
+    data[3737] := 0;
+    data[3738] := 102;
+    data[3739] := 102;
+    data[3740] := 102;
+    data[3741] := 204;
+    data[3742] := 0;
+    data[3743] := 0;
+    data[3744] := 0;
+    data[3745] := 0;
+    data[3746] := 24;
+    data[3747] := 24;
+    data[3748] := 24;
+    data[3749] := 126;
+    data[3750] := 24;
+    data[3751] := 24;
+    data[3752] := 24;
+    data[3753] := 24;
+    data[3754] := 24;
+    data[3755] := 24;
+    data[3756] := 0;
+    data[3757] := 0;
+    data[3758] := 0;
+    data[3759] := 0;
+    data[3760] := 0;
+    data[3761] := 0;
+    data[3762] := 24;
+    data[3763] := 24;
+    data[3764] := 24;
+    data[3765] := 126;
+    data[3766] := 24;
+    data[3767] := 24;
+    data[3768] := 126;
+    data[3769] := 24;
+    data[3770] := 24;
+    data[3771] := 24;
+    data[3772] := 0;
+    data[3773] := 0;
+    data[3774] := 0;
+    data[3775] := 0;
+    data[3776] := 0;
+    data[3777] := 0;
+    data[3778] := 0;
+    data[3779] := 0;
+    data[3780] := 0;
+    data[3781] := 118;
+    data[3782] := 219;
+    data[3783] := 219;
+    data[3784] := 110;
+    data[3785] := 0;
+    data[3786] := 0;
+    data[3787] := 0;
+    data[3788] := 0;
+    data[3789] := 0;
+    data[3790] := 0;
+    data[3791] := 0;
+    data[3792] := 0;
+    data[3793] := 0;
+    data[3794] := 0;
+    data[3795] := 192;
+    data[3796] := 198;
+    data[3797] := 12;
+    data[3798] := 24;
+    data[3799] := 48;
+    data[3800] := 96;
+    data[3801] := 192;
+    data[3802] := 54;
+    data[3803] := 54;
+    data[3804] := 0;
+    data[3805] := 0;
+    data[3806] := 0;
+    data[3807] := 0;
+    data[3808] := 0;
+    data[3809] := 0;
+    data[3810] := 0;
+    data[3811] := 0;
+    data[3812] := 12;
+    data[3813] := 24;
+    data[3814] := 48;
+    data[3815] := 96;
+    data[3816] := 48;
+    data[3817] := 24;
+    data[3818] := 12;
+    data[3819] := 0;
+    data[3820] := 0;
+    data[3821] := 0;
+    data[3822] := 0;
+    data[3823] := 0;
+    data[3824] := 0;
+    data[3825] := 0;
+    data[3826] := 0;
+    data[3827] := 0;
+    data[3828] := 124;
+    data[3829] := 198;
+    data[3830] := 198;
+    data[3831] := 198;
+    data[3832] := 198;
+    data[3833] := 198;
+    data[3834] := 198;
+    data[3835] := 198;
+    data[3836] := 0;
+    data[3837] := 0;
+    data[3838] := 0;
+    data[3839] := 0;
+    data[3840] := 0;
+    data[3841] := 0;
+    data[3842] := 0;
+    data[3843] := 0;
+    data[3844] := 254;
+    data[3845] := 0;
+    data[3846] := 0;
+    data[3847] := 254;
+    data[3848] := 0;
+    data[3849] := 0;
+    data[3850] := 254;
+    data[3851] := 0;
+    data[3852] := 0;
+    data[3853] := 0;
+    data[3854] := 0;
+    data[3855] := 0;
+    data[3856] := 0;
+    data[3857] := 0;
+    data[3858] := 0;
+    data[3859] := 0;
+    data[3860] := 24;
+    data[3861] := 24;
+    data[3862] := 126;
+    data[3863] := 24;
+    data[3864] := 24;
+    data[3865] := 0;
+    data[3866] := 126;
+    data[3867] := 0;
+    data[3868] := 0;
+    data[3869] := 0;
+    data[3870] := 0;
+    data[3871] := 0;
+    data[3872] := 0;
+    data[3873] := 0;
+    data[3874] := 0;
+    data[3875] := 0;
+    data[3876] := 224;
+    data[3877] := 56;
+    data[3878] := 14;
+    data[3879] := 56;
+    data[3880] := 224;
+    data[3881] := 0;
+    data[3882] := 254;
+    data[3883] := 0;
+    data[3884] := 0;
+    data[3885] := 0;
+    data[3886] := 0;
+    data[3887] := 0;
+    data[3888] := 0;
+    data[3889] := 0;
+    data[3890] := 0;
+    data[3891] := 0;
+    data[3892] := 14;
+    data[3893] := 56;
+    data[3894] := 224;
+    data[3895] := 56;
+    data[3896] := 14;
+    data[3897] := 0;
+    data[3898] := 254;
+    data[3899] := 0;
+    data[3900] := 0;
+    data[3901] := 0;
+    data[3902] := 0;
+    data[3903] := 0;
+    data[3904] := 0;
+    data[3905] := 0;
+    data[3906] := 0;
+    data[3907] := 0;
+    data[3908] := 96;
+    data[3909] := 48;
+    data[3910] := 24;
+    data[3911] := 12;
+    data[3912] := 24;
+    data[3913] := 48;
+    data[3914] := 96;
+    data[3915] := 0;
+    data[3916] := 0;
+    data[3917] := 0;
+    data[3918] := 0;
+    data[3919] := 0;
+    data[3920] := 0;
+    data[3921] := 0;
+    data[3922] := 28;
+    data[3923] := 54;
+    data[3924] := 96;
+    data[3925] := 252;
+    data[3926] := 96;
+    data[3927] := 248;
+    data[3928] := 96;
+    data[3929] := 96;
+    data[3930] := 54;
+    data[3931] := 28;
+    data[3932] := 0;
+    data[3933] := 0;
+    data[3934] := 0;
+    data[3935] := 0;
+    data[3936] := 0;
+    data[3937] := 0;
+    data[3938] := 0;
+    data[3939] := 0;
+    data[3940] := 24;
+    data[3941] := 24;
+    data[3942] := 0;
+    data[3943] := 126;
+    data[3944] := 0;
+    data[3945] := 24;
+    data[3946] := 24;
+    data[3947] := 0;
+    data[3948] := 0;
+    data[3949] := 0;
+    data[3950] := 0;
+    data[3951] := 0;
+    data[3952] := 0;
+    data[3953] := 0;
+    data[3954] := 0;
+    data[3955] := 0;
+    data[3956] := 0;
+    data[3957] := 118;
+    data[3958] := 220;
+    data[3959] := 0;
+    data[3960] := 118;
+    data[3961] := 220;
+    data[3962] := 0;
+    data[3963] := 0;
+    data[3964] := 0;
+    data[3965] := 0;
+    data[3966] := 0;
+    data[3967] := 0;
+    data[3968] := 0;
+    data[3969] := 56;
+    data[3970] := 108;
+    data[3971] := 108;
+    data[3972] := 56;
+    data[3973] := 0;
+    data[3974] := 0;
+    data[3975] := 0;
+    data[3976] := 0;
+    data[3977] := 0;
+    data[3978] := 0;
+    data[3979] := 0;
+    data[3980] := 0;
+    data[3981] := 0;
+    data[3982] := 0;
+    data[3983] := 0;
+    data[3984] := 0;
+    data[3985] := 0;
+    data[3986] := 0;
+    data[3987] := 4;
+    data[3988] := 8;
+    data[3989] := 126;
+    data[3990] := 8;
+    data[3991] := 16;
+    data[3992] := 126;
+    data[3993] := 16;
+    data[3994] := 32;
+    data[3995] := 0;
+    data[3996] := 0;
+    data[3997] := 0;
+    data[3998] := 0;
+    data[3999] := 0;
+    data[4000] := 0;
+    data[4001] := 0;
+    data[4002] := 0;
+    data[4003] := 0;
+    data[4004] := 0;
+    data[4005] := 0;
+    data[4006] := 0;
+    data[4007] := 0;
+    data[4008] := 24;
+    data[4009] := 0;
+    data[4010] := 0;
+    data[4011] := 0;
+    data[4012] := 0;
+    data[4013] := 0;
+    data[4014] := 0;
+    data[4015] := 0;
+    data[4016] := 0;
+    data[4017] := 0;
+    data[4018] := 126;
+    data[4019] := 126;
+    data[4020] := 90;
+    data[4021] := 24;
+    data[4022] := 30;
+    data[4023] := 120;
+    data[4024] := 30;
+    data[4025] := 120;
+    data[4026] := 24;
+    data[4027] := 60;
+    data[4028] := 0;
+    data[4029] := 0;
+    data[4030] := 0;
+    data[4031] := 0;
+    data[4032] := 0;
+    data[4033] := 0;
+    data[4034] := 176;
+    data[4035] := 216;
+    data[4036] := 216;
+    data[4037] := 216;
+    data[4038] := 216;
+    data[4039] := 0;
+    data[4040] := 0;
+    data[4041] := 0;
+    data[4042] := 0;
+    data[4043] := 0;
+    data[4044] := 0;
+    data[4045] := 0;
+    data[4046] := 0;
+    data[4047] := 0;
+    data[4048] := 0;
+    data[4049] := 112;
+    data[4050] := 216;
+    data[4051] := 48;
+    data[4052] := 96;
+    data[4053] := 200;
+    data[4054] := 248;
+    data[4055] := 0;
+    data[4056] := 0;
+    data[4057] := 0;
+    data[4058] := 0;
+    data[4059] := 0;
+    data[4060] := 0;
+    data[4061] := 0;
+    data[4062] := 0;
+    data[4063] := 0;
+    data[4064] := 0;
+    data[4065] := 0;
+    data[4066] := 0;
+    data[4067] := 254;
+    data[4068] := 254;
+    data[4069] := 254;
+    data[4070] := 254;
+    data[4071] := 254;
+    data[4072] := 254;
+    data[4073] := 254;
+    data[4074] := 254;
+    data[4075] := 254;
+    data[4076] := 0;
+    data[4077] := 0;
+    data[4078] := 0;
+    data[4079] := 0;
+    data[4080] := 0;
+    data[4081] := 0;
+    data[4082] := 0;
+    data[4083] := 62;
+    data[4084] := 96;
+    data[4085] := 192;
+    data[4086] := 192;
+    data[4087] := 254;
+    data[4088] := 192;
+    data[4089] := 192;
+    data[4090] := 96;
+    data[4091] := 62;
+    data[4092] := 0;
+    data[4093] := 0;
+    data[4094] := 0;
+    data[4095] := 0;
+    codes[0] := 32; gidx[0] := 32;
+    codes[1] := 33; gidx[1] := 33;
+    codes[2] := 34; gidx[2] := 34;
+    codes[3] := 35; gidx[3] := 35;
+    codes[4] := 36; gidx[4] := 36;
+    codes[5] := 37; gidx[5] := 37;
+    codes[6] := 38; gidx[6] := 38;
+    codes[7] := 39; gidx[7] := 39;
+    codes[8] := 40; gidx[8] := 40;
+    codes[9] := 41; gidx[9] := 41;
+    codes[10] := 42; gidx[10] := 42;
+    codes[11] := 43; gidx[11] := 43;
+    codes[12] := 44; gidx[12] := 44;
+    codes[13] := 45; gidx[13] := 45;
+    codes[14] := 46; gidx[14] := 46;
+    codes[15] := 47; gidx[15] := 47;
+    codes[16] := 48; gidx[16] := 48;
+    codes[17] := 49; gidx[17] := 49;
+    codes[18] := 50; gidx[18] := 50;
+    codes[19] := 51; gidx[19] := 51;
+    codes[20] := 52; gidx[20] := 52;
+    codes[21] := 53; gidx[21] := 53;
+    codes[22] := 54; gidx[22] := 54;
+    codes[23] := 55; gidx[23] := 55;
+    codes[24] := 56; gidx[24] := 56;
+    codes[25] := 57; gidx[25] := 57;
+    codes[26] := 58; gidx[26] := 58;
+    codes[27] := 59; gidx[27] := 59;
+    codes[28] := 60; gidx[28] := 60;
+    codes[29] := 61; gidx[29] := 61;
+    codes[30] := 62; gidx[30] := 62;
+    codes[31] := 63; gidx[31] := 63;
+    codes[32] := 64; gidx[32] := 64;
+    codes[33] := 65; gidx[33] := 65;
+    codes[34] := 66; gidx[34] := 66;
+    codes[35] := 67; gidx[35] := 67;
+    codes[36] := 68; gidx[36] := 68;
+    codes[37] := 69; gidx[37] := 69;
+    codes[38] := 70; gidx[38] := 70;
+    codes[39] := 71; gidx[39] := 71;
+    codes[40] := 72; gidx[40] := 72;
+    codes[41] := 73; gidx[41] := 73;
+    codes[42] := 74; gidx[42] := 74;
+    codes[43] := 75; gidx[43] := 75;
+    codes[44] := 76; gidx[44] := 76;
+    codes[45] := 77; gidx[45] := 77;
+    codes[46] := 78; gidx[46] := 78;
+    codes[47] := 79; gidx[47] := 79;
+    codes[48] := 80; gidx[48] := 80;
+    codes[49] := 81; gidx[49] := 81;
+    codes[50] := 82; gidx[50] := 82;
+    codes[51] := 83; gidx[51] := 83;
+    codes[52] := 84; gidx[52] := 84;
+    codes[53] := 85; gidx[53] := 85;
+    codes[54] := 86; gidx[54] := 86;
+    codes[55] := 87; gidx[55] := 87;
+    codes[56] := 88; gidx[56] := 88;
+    codes[57] := 89; gidx[57] := 89;
+    codes[58] := 90; gidx[58] := 90;
+    codes[59] := 91; gidx[59] := 91;
+    codes[60] := 92; gidx[60] := 92;
+    codes[61] := 93; gidx[61] := 93;
+    codes[62] := 94; gidx[62] := 94;
+    codes[63] := 95; gidx[63] := 95;
+    codes[64] := 96; gidx[64] := 96;
+    codes[65] := 97; gidx[65] := 97;
+    codes[66] := 98; gidx[66] := 98;
+    codes[67] := 99; gidx[67] := 99;
+    codes[68] := 100; gidx[68] := 100;
+    codes[69] := 101; gidx[69] := 101;
+    codes[70] := 102; gidx[70] := 102;
+    codes[71] := 103; gidx[71] := 103;
+    codes[72] := 104; gidx[72] := 104;
+    codes[73] := 105; gidx[73] := 105;
+    codes[74] := 106; gidx[74] := 106;
+    codes[75] := 107; gidx[75] := 107;
+    codes[76] := 108; gidx[76] := 108;
+    codes[77] := 109; gidx[77] := 109;
+    codes[78] := 110; gidx[78] := 110;
+    codes[79] := 111; gidx[79] := 111;
+    codes[80] := 112; gidx[80] := 112;
+    codes[81] := 113; gidx[81] := 113;
+    codes[82] := 114; gidx[82] := 114;
+    codes[83] := 115; gidx[83] := 115;
+    codes[84] := 116; gidx[84] := 116;
+    codes[85] := 117; gidx[85] := 117;
+    codes[86] := 118; gidx[86] := 118;
+    codes[87] := 119; gidx[87] := 119;
+    codes[88] := 120; gidx[88] := 120;
+    codes[89] := 121; gidx[89] := 121;
+    codes[90] := 122; gidx[90] := 122;
+    codes[91] := 123; gidx[91] := 123;
+    codes[92] := 124; gidx[92] := 124;
+    codes[93] := 125; gidx[93] := 125;
+    codes[94] := 126; gidx[94] := 126;
+    codes[95] := 160; gidx[95] := 32;
+    codes[96] := 161; gidx[96] := 173;
+    codes[97] := 162; gidx[97] := 155;
+    codes[98] := 163; gidx[98] := 156;
+    codes[99] := 164; gidx[99] := 8;
+    codes[100] := 165; gidx[100] := 157;
+    codes[101] := 166; gidx[101] := 9;
+    codes[102] := 167; gidx[102] := 21;
+    codes[103] := 168; gidx[103] := 10;
+    codes[104] := 169; gidx[104] := 0;
+    codes[105] := 170; gidx[105] := 166;
+    codes[106] := 171; gidx[106] := 174;
+    codes[107] := 172; gidx[107] := 170;
+    codes[108] := 173; gidx[108] := 45;
+    codes[109] := 174; gidx[109] := 11;
+    codes[110] := 175; gidx[110] := 12;
+    codes[111] := 176; gidx[111] := 248;
+    codes[112] := 177; gidx[112] := 241;
+    codes[113] := 178; gidx[113] := 253;
+    codes[114] := 179; gidx[114] := 13;
+    codes[115] := 180; gidx[115] := 14;
+    codes[116] := 181; gidx[116] := 230;
+    codes[117] := 182; gidx[117] := 20;
+    codes[118] := 183; gidx[118] := 250;
+    codes[119] := 184; gidx[119] := 15;
+    codes[120] := 185; gidx[120] := 16;
+    codes[121] := 186; gidx[121] := 167;
+    codes[122] := 187; gidx[122] := 175;
+    codes[123] := 188; gidx[123] := 172;
+    codes[124] := 189; gidx[124] := 171;
+    codes[125] := 190; gidx[125] := 17;
+    codes[126] := 191; gidx[126] := 168;
+    codes[127] := 192; gidx[127] := 18;
+    codes[128] := 193; gidx[128] := 22;
+    codes[129] := 194; gidx[129] := 23;
+    codes[130] := 195; gidx[130] := 28;
+    codes[131] := 196; gidx[131] := 142;
+    codes[132] := 197; gidx[132] := 143;
+    codes[133] := 198; gidx[133] := 146;
+    codes[134] := 199; gidx[134] := 128;
+    codes[135] := 200; gidx[135] := 29;
+    codes[136] := 201; gidx[136] := 144;
+    codes[137] := 202; gidx[137] := 30;
+    codes[138] := 203; gidx[138] := 31;
+    codes[139] := 204; gidx[139] := 127;
+    codes[140] := 205; gidx[140] := 169;
+    codes[141] := 206; gidx[141] := 178;
+    codes[142] := 207; gidx[142] := 181;
+    codes[143] := 208; gidx[143] := 182;
+    codes[144] := 209; gidx[144] := 165;
+    codes[145] := 210; gidx[145] := 183;
+    codes[146] := 211; gidx[146] := 184;
+    codes[147] := 212; gidx[147] := 185;
+    codes[148] := 213; gidx[148] := 186;
+    codes[149] := 214; gidx[149] := 153;
+    codes[150] := 215; gidx[150] := 187;
+    codes[151] := 216; gidx[151] := 188;
+    codes[152] := 217; gidx[152] := 189;
+    codes[153] := 218; gidx[153] := 190;
+    codes[154] := 219; gidx[154] := 198;
+    codes[155] := 220; gidx[155] := 154;
+    codes[156] := 221; gidx[156] := 199;
+    codes[157] := 222; gidx[157] := 200;
+    codes[158] := 223; gidx[158] := 225;
+    codes[159] := 224; gidx[159] := 133;
+    codes[160] := 225; gidx[160] := 160;
+    codes[161] := 226; gidx[161] := 131;
+    codes[162] := 227; gidx[162] := 201;
+    codes[163] := 228; gidx[163] := 132;
+    codes[164] := 229; gidx[164] := 134;
+    codes[165] := 230; gidx[165] := 145;
+    codes[166] := 231; gidx[166] := 135;
+    codes[167] := 232; gidx[167] := 138;
+    codes[168] := 233; gidx[168] := 130;
+    codes[169] := 234; gidx[169] := 136;
+    codes[170] := 235; gidx[170] := 137;
+    codes[171] := 236; gidx[171] := 141;
+    codes[172] := 237; gidx[172] := 161;
+    codes[173] := 238; gidx[173] := 140;
+    codes[174] := 239; gidx[174] := 139;
+    codes[175] := 240; gidx[175] := 202;
+    codes[176] := 241; gidx[176] := 164;
+    codes[177] := 242; gidx[177] := 149;
+    codes[178] := 243; gidx[178] := 162;
+    codes[179] := 244; gidx[179] := 147;
+    codes[180] := 245; gidx[180] := 203;
+    codes[181] := 246; gidx[181] := 148;
+    codes[182] := 247; gidx[182] := 246;
+    codes[183] := 248; gidx[183] := 204;
+    codes[184] := 249; gidx[184] := 151;
+    codes[185] := 250; gidx[185] := 163;
+    codes[186] := 251; gidx[186] := 150;
+    codes[187] := 252; gidx[187] := 129;
+    codes[188] := 253; gidx[188] := 205;
+    codes[189] := 254; gidx[189] := 206;
+    codes[190] := 255; gidx[190] := 152;
+    codes[191] := 272; gidx[191] := 182;
+    codes[192] := 286; gidx[192] := 207;
+    codes[193] := 287; gidx[193] := 208;
+    codes[194] := 304; gidx[194] := 209;
+    codes[195] := 305; gidx[195] := 210;
+    codes[196] := 338; gidx[196] := 211;
+    codes[197] := 339; gidx[197] := 212;
+    codes[198] := 350; gidx[198] := 213;
+    codes[199] := 351; gidx[199] := 214;
+    codes[200] := 352; gidx[200] := 215;
+    codes[201] := 353; gidx[201] := 216;
+    codes[202] := 376; gidx[202] := 220;
+    codes[203] := 381; gidx[203] := 221;
+    codes[204] := 382; gidx[204] := 222;
+    codes[205] := 402; gidx[205] := 159;
+    codes[206] := 710; gidx[206] := 223;
+    codes[207] := 713; gidx[207] := 12;
+    codes[208] := 732; gidx[208] := 224;
+    codes[209] := 913; gidx[209] := 65;
+    codes[210] := 914; gidx[210] := 66;
+    codes[211] := 917; gidx[211] := 69;
+    codes[212] := 918; gidx[212] := 90;
+    codes[213] := 919; gidx[213] := 72;
+    codes[214] := 921; gidx[214] := 73;
+    codes[215] := 922; gidx[215] := 75;
+    codes[216] := 924; gidx[216] := 77;
+    codes[217] := 925; gidx[217] := 78;
+    codes[218] := 927; gidx[218] := 79;
+    codes[219] := 929; gidx[219] := 80;
+    codes[220] := 932; gidx[220] := 84;
+    codes[221] := 935; gidx[221] := 88;
+    codes[222] := 956; gidx[222] := 230;
+    codes[223] := 960; gidx[223] := 227;
+    codes[224] := 1025; gidx[224] := 31;
+    codes[225] := 1029; gidx[225] := 83;
+    codes[226] := 1030; gidx[226] := 73;
+    codes[227] := 1031; gidx[227] := 181;
+    codes[228] := 1032; gidx[228] := 74;
+    codes[229] := 1040; gidx[229] := 65;
+    codes[230] := 1042; gidx[230] := 66;
+    codes[231] := 1045; gidx[231] := 69;
+    codes[232] := 1050; gidx[232] := 75;
+    codes[233] := 1052; gidx[233] := 77;
+    codes[234] := 1053; gidx[234] := 72;
+    codes[235] := 1054; gidx[235] := 79;
+    codes[236] := 1056; gidx[236] := 80;
+    codes[237] := 1057; gidx[237] := 67;
+    codes[238] := 1058; gidx[238] := 84;
+    codes[239] := 1061; gidx[239] := 88;
+    codes[240] := 1072; gidx[240] := 97;
+    codes[241] := 1077; gidx[241] := 101;
+    codes[242] := 1086; gidx[242] := 111;
+    codes[243] := 1088; gidx[243] := 112;
+    codes[244] := 1089; gidx[244] := 99;
+    codes[245] := 1091; gidx[245] := 121;
+    codes[246] := 1093; gidx[246] := 120;
+    codes[247] := 1105; gidx[247] := 137;
+    codes[248] := 1109; gidx[248] := 115;
+    codes[249] := 1110; gidx[249] := 105;
+    codes[250] := 1111; gidx[250] := 139;
+    codes[251] := 1112; gidx[251] := 106;
+    codes[252] := 1198; gidx[252] := 89;
+    codes[253] := 8192; gidx[253] := 32;
+    codes[254] := 8193; gidx[254] := 32;
+    codes[255] := 8194; gidx[255] := 32;
+    codes[256] := 8195; gidx[256] := 32;
+    codes[257] := 8196; gidx[257] := 32;
+    codes[258] := 8197; gidx[258] := 32;
+    codes[259] := 8198; gidx[259] := 32;
+    codes[260] := 8199; gidx[260] := 32;
+    codes[261] := 8200; gidx[261] := 32;
+    codes[262] := 8201; gidx[262] := 32;
+    codes[263] := 8202; gidx[263] := 32;
+    codes[264] := 8208; gidx[264] := 45;
+    codes[265] := 8209; gidx[265] := 45;
+    codes[266] := 8210; gidx[266] := 45;
+    codes[267] := 8211; gidx[267] := 45;
+    codes[268] := 8212; gidx[268] := 1;
+    codes[269] := 8213; gidx[269] := 1;
+    codes[270] := 8216; gidx[270] := 226;
+    codes[271] := 8217; gidx[271] := 228;
+    codes[272] := 8218; gidx[272] := 229;
+    codes[273] := 8220; gidx[273] := 231;
+    codes[274] := 8221; gidx[274] := 232;
+    codes[275] := 8222; gidx[275] := 233;
+    codes[276] := 8224; gidx[276] := 234;
+    codes[277] := 8225; gidx[277] := 235;
+    codes[278] := 8226; gidx[278] := 7;
+    codes[279] := 8230; gidx[279] := 2;
+    codes[280] := 8239; gidx[280] := 32;
+    codes[281] := 8240; gidx[281] := 237;
+    codes[282] := 8249; gidx[282] := 238;
+    codes[283] := 8250; gidx[283] := 244;
+    codes[284] := 8252; gidx[284] := 19;
+    codes[285] := 8319; gidx[285] := 252;
+    codes[286] := 8359; gidx[286] := 158;
+    codes[287] := 8364; gidx[287] := 245;
+    codes[288] := 8366; gidx[288] := 251;
+    codes[289] := 8470; gidx[289] := 5;
+    codes[290] := 8482; gidx[290] := 3;
+    codes[291] := 8490; gidx[291] := 75;
+    codes[292] := 8491; gidx[292] := 143;
+    codes[293] := 8592; gidx[293] := 27;
+    codes[294] := 8593; gidx[294] := 24;
+    codes[295] := 8594; gidx[295] := 26;
+    codes[296] := 8595; gidx[296] := 25;
+    codes[297] := 8709; gidx[297] := 6;
+    codes[298] := 8712; gidx[298] := 255;
+    codes[299] := 8722; gidx[299] := 45;
+    codes[300] := 8734; gidx[300] := 236;
+    codes[301] := 8745; gidx[301] := 239;
+    codes[302] := 8776; gidx[302] := 247;
+    codes[303] := 8800; gidx[303] := 249;
+    codes[304] := 8801; gidx[304] := 240;
+    codes[305] := 8804; gidx[305] := 243;
+    codes[306] := 8805; gidx[306] := 242;
+    codes[307] := 8810; gidx[307] := 174;
+    codes[308] := 8811; gidx[308] := 175;
+    codes[309] := 8853; gidx[309] := 43;
+    codes[310] := 8854; gidx[310] := 45;
+    codes[311] := 8856; gidx[311] := 47;
+    codes[312] := 8857; gidx[312] := 46;
+    codes[313] := 8859; gidx[313] := 42;
+    codes[314] := 8860; gidx[314] := 61;
+    codes[315] := 9312; gidx[315] := 49;
+    codes[316] := 9313; gidx[316] := 50;
+    codes[317] := 9314; gidx[317] := 51;
+    codes[318] := 9315; gidx[318] := 52;
+    codes[319] := 9316; gidx[319] := 53;
+    codes[320] := 9317; gidx[320] := 54;
+    codes[321] := 9318; gidx[321] := 55;
+    codes[322] := 9319; gidx[322] := 56;
+    codes[323] := 9320; gidx[323] := 57;
+    codes[324] := 9398; gidx[324] := 65;
+    codes[325] := 9399; gidx[325] := 66;
+    codes[326] := 9400; gidx[326] := 67;
+    codes[327] := 9401; gidx[327] := 68;
+    codes[328] := 9402; gidx[328] := 69;
+    codes[329] := 9403; gidx[329] := 70;
+    codes[330] := 9404; gidx[330] := 71;
+    codes[331] := 9405; gidx[331] := 72;
+    codes[332] := 9406; gidx[332] := 73;
+    codes[333] := 9407; gidx[333] := 74;
+    codes[334] := 9408; gidx[334] := 75;
+    codes[335] := 9409; gidx[335] := 76;
+    codes[336] := 9410; gidx[336] := 77;
+    codes[337] := 9411; gidx[337] := 78;
+    codes[338] := 9412; gidx[338] := 79;
+    codes[339] := 9413; gidx[339] := 80;
+    codes[340] := 9414; gidx[340] := 81;
+    codes[341] := 9415; gidx[341] := 82;
+    codes[342] := 9416; gidx[342] := 83;
+    codes[343] := 9417; gidx[343] := 84;
+    codes[344] := 9418; gidx[344] := 85;
+    codes[345] := 9419; gidx[345] := 86;
+    codes[346] := 9420; gidx[346] := 87;
+    codes[347] := 9421; gidx[347] := 88;
+    codes[348] := 9422; gidx[348] := 89;
+    codes[349] := 9423; gidx[349] := 90;
+    codes[350] := 9424; gidx[350] := 97;
+    codes[351] := 9425; gidx[351] := 98;
+    codes[352] := 9426; gidx[352] := 99;
+    codes[353] := 9427; gidx[353] := 100;
+    codes[354] := 9428; gidx[354] := 101;
+    codes[355] := 9429; gidx[355] := 102;
+    codes[356] := 9430; gidx[356] := 103;
+    codes[357] := 9431; gidx[357] := 104;
+    codes[358] := 9432; gidx[358] := 105;
+    codes[359] := 9433; gidx[359] := 106;
+    codes[360] := 9434; gidx[360] := 107;
+    codes[361] := 9435; gidx[361] := 108;
+    codes[362] := 9436; gidx[362] := 109;
+    codes[363] := 9437; gidx[363] := 110;
+    codes[364] := 9438; gidx[364] := 111;
+    codes[365] := 9439; gidx[365] := 112;
+    codes[366] := 9440; gidx[366] := 113;
+    codes[367] := 9441; gidx[367] := 114;
+    codes[368] := 9442; gidx[368] := 115;
+    codes[369] := 9443; gidx[369] := 116;
+    codes[370] := 9444; gidx[370] := 117;
+    codes[371] := 9445; gidx[371] := 118;
+    codes[372] := 9446; gidx[372] := 119;
+    codes[373] := 9447; gidx[373] := 120;
+    codes[374] := 9448; gidx[374] := 121;
+    codes[375] := 9449; gidx[375] := 122;
+    codes[376] := 9450; gidx[376] := 48;
+    codes[377] := 9472; gidx[377] := 196;
+    codes[378] := 9473; gidx[378] := 196;
+    codes[379] := 9474; gidx[379] := 179;
+    codes[380] := 9475; gidx[380] := 179;
+    codes[381] := 9476; gidx[381] := 196;
+    codes[382] := 9477; gidx[382] := 196;
+    codes[383] := 9478; gidx[383] := 179;
+    codes[384] := 9479; gidx[384] := 179;
+    codes[385] := 9480; gidx[385] := 196;
+    codes[386] := 9481; gidx[386] := 196;
+    codes[387] := 9482; gidx[387] := 179;
+    codes[388] := 9483; gidx[388] := 179;
+    codes[389] := 9484; gidx[389] := 218;
+    codes[390] := 9485; gidx[390] := 218;
+    codes[391] := 9486; gidx[391] := 218;
+    codes[392] := 9487; gidx[392] := 218;
+    codes[393] := 9488; gidx[393] := 191;
+    codes[394] := 9489; gidx[394] := 191;
+    codes[395] := 9490; gidx[395] := 191;
+    codes[396] := 9491; gidx[396] := 191;
+    codes[397] := 9492; gidx[397] := 192;
+    codes[398] := 9493; gidx[398] := 192;
+    codes[399] := 9494; gidx[399] := 192;
+    codes[400] := 9495; gidx[400] := 192;
+    codes[401] := 9496; gidx[401] := 217;
+    codes[402] := 9497; gidx[402] := 217;
+    codes[403] := 9498; gidx[403] := 217;
+    codes[404] := 9499; gidx[404] := 217;
+    codes[405] := 9500; gidx[405] := 195;
+    codes[406] := 9501; gidx[406] := 195;
+    codes[407] := 9502; gidx[407] := 195;
+    codes[408] := 9503; gidx[408] := 195;
+    codes[409] := 9504; gidx[409] := 195;
+    codes[410] := 9505; gidx[410] := 195;
+    codes[411] := 9506; gidx[411] := 195;
+    codes[412] := 9507; gidx[412] := 195;
+    codes[413] := 9508; gidx[413] := 180;
+    codes[414] := 9509; gidx[414] := 180;
+    codes[415] := 9510; gidx[415] := 180;
+    codes[416] := 9511; gidx[416] := 180;
+    codes[417] := 9512; gidx[417] := 180;
+    codes[418] := 9513; gidx[418] := 180;
+    codes[419] := 9514; gidx[419] := 180;
+    codes[420] := 9515; gidx[420] := 180;
+    codes[421] := 9516; gidx[421] := 194;
+    codes[422] := 9517; gidx[422] := 194;
+    codes[423] := 9518; gidx[423] := 194;
+    codes[424] := 9519; gidx[424] := 194;
+    codes[425] := 9520; gidx[425] := 194;
+    codes[426] := 9521; gidx[426] := 194;
+    codes[427] := 9522; gidx[427] := 194;
+    codes[428] := 9523; gidx[428] := 194;
+    codes[429] := 9524; gidx[429] := 193;
+    codes[430] := 9525; gidx[430] := 193;
+    codes[431] := 9526; gidx[431] := 193;
+    codes[432] := 9527; gidx[432] := 193;
+    codes[433] := 9528; gidx[433] := 193;
+    codes[434] := 9529; gidx[434] := 193;
+    codes[435] := 9530; gidx[435] := 193;
+    codes[436] := 9531; gidx[436] := 193;
+    codes[437] := 9532; gidx[437] := 197;
+    codes[438] := 9533; gidx[438] := 197;
+    codes[439] := 9534; gidx[439] := 197;
+    codes[440] := 9535; gidx[440] := 197;
+    codes[441] := 9536; gidx[441] := 197;
+    codes[442] := 9537; gidx[442] := 197;
+    codes[443] := 9538; gidx[443] := 197;
+    codes[444] := 9539; gidx[444] := 197;
+    codes[445] := 9540; gidx[445] := 197;
+    codes[446] := 9541; gidx[446] := 197;
+    codes[447] := 9542; gidx[447] := 197;
+    codes[448] := 9543; gidx[448] := 197;
+    codes[449] := 9544; gidx[449] := 197;
+    codes[450] := 9545; gidx[450] := 197;
+    codes[451] := 9546; gidx[451] := 197;
+    codes[452] := 9547; gidx[452] := 197;
+    codes[453] := 9548; gidx[453] := 196;
+    codes[454] := 9549; gidx[454] := 196;
+    codes[455] := 9550; gidx[455] := 179;
+    codes[456] := 9551; gidx[456] := 179;
+    codes[457] := 9552; gidx[457] := 196;
+    codes[458] := 9553; gidx[458] := 179;
+    codes[459] := 9554; gidx[459] := 218;
+    codes[460] := 9555; gidx[460] := 218;
+    codes[461] := 9556; gidx[461] := 218;
+    codes[462] := 9557; gidx[462] := 191;
+    codes[463] := 9558; gidx[463] := 191;
+    codes[464] := 9559; gidx[464] := 191;
+    codes[465] := 9560; gidx[465] := 192;
+    codes[466] := 9561; gidx[466] := 192;
+    codes[467] := 9562; gidx[467] := 192;
+    codes[468] := 9563; gidx[468] := 217;
+    codes[469] := 9564; gidx[469] := 217;
+    codes[470] := 9565; gidx[470] := 217;
+    codes[471] := 9566; gidx[471] := 195;
+    codes[472] := 9567; gidx[472] := 195;
+    codes[473] := 9568; gidx[473] := 195;
+    codes[474] := 9569; gidx[474] := 180;
+    codes[475] := 9570; gidx[475] := 180;
+    codes[476] := 9571; gidx[476] := 180;
+    codes[477] := 9572; gidx[477] := 194;
+    codes[478] := 9573; gidx[478] := 194;
+    codes[479] := 9574; gidx[479] := 194;
+    codes[480] := 9575; gidx[480] := 193;
+    codes[481] := 9576; gidx[481] := 193;
+    codes[482] := 9577; gidx[482] := 193;
+    codes[483] := 9578; gidx[483] := 197;
+    codes[484] := 9579; gidx[484] := 197;
+    codes[485] := 9580; gidx[485] := 197;
+    codes[486] := 9581; gidx[486] := 218;
+    codes[487] := 9582; gidx[487] := 191;
+    codes[488] := 9583; gidx[488] := 217;
+    codes[489] := 9584; gidx[489] := 192;
+    codes[490] := 9585; gidx[490] := 47;
+    codes[491] := 9586; gidx[491] := 92;
+    codes[492] := 9587; gidx[492] := 88;
+    codes[493] := 9588; gidx[493] := 196;
+    codes[494] := 9589; gidx[494] := 179;
+    codes[495] := 9590; gidx[495] := 196;
+    codes[496] := 9591; gidx[496] := 179;
+    codes[497] := 9592; gidx[497] := 196;
+    codes[498] := 9593; gidx[498] := 179;
+    codes[499] := 9594; gidx[499] := 196;
+    codes[500] := 9595; gidx[500] := 179;
+    codes[501] := 9596; gidx[501] := 196;
+    codes[502] := 9597; gidx[502] := 179;
+    codes[503] := 9598; gidx[503] := 196;
+    codes[504] := 9599; gidx[504] := 179;
+    codes[505] := 9608; gidx[505] := 219;
+    codes[506] := 9617; gidx[506] := 176;
+    codes[507] := 9618; gidx[507] := 177;
+    codes[508] := 9632; gidx[508] := 254;
+    codes[509] := 9646; gidx[509] := 254;
+    codes[510] := 9650; gidx[510] := 24;
+    codes[511] := 9652; gidx[511] := 24;
+    codes[512] := 9654; gidx[512] := 26;
+    codes[513] := 9656; gidx[513] := 26;
+    codes[514] := 9660; gidx[514] := 25;
+    codes[515] := 9662; gidx[515] := 25;
+    codes[516] := 9664; gidx[516] := 27;
+    codes[517] := 9666; gidx[517] := 27;
+    codes[518] := 9672; gidx[518] := 4;
+    codes[519] := 9679; gidx[519] := 7;
+    codes[520] := 9744; gidx[520] := 46;
+    codes[521] := 9745; gidx[521] := 118;
+    codes[522] := 9746; gidx[522] := 120;
+    codes[523] := 9830; gidx[523] := 4;
+    codes[524] := 10007; gidx[524] := 120;
+    codes[525] := 10008; gidx[525] := 120;
+    codes[526] := 11197; gidx[526] := 120;
+    codes[527] := 65533; gidx[527] := 4;
+END tvfont.

BIN
tvision-m2/tvfont.o


+ 26 - 0
tvision-m2/tvg.def

@@ -0,0 +1,26 @@
+DEFINITION MODULE tvg;
+
+(* tigr graphics backend for the tv toolkit.
+
+   It drives the same view tree into an off-screen tigr bitmap instead of an
+   ANSI terminal: tv keeps building the cell buffer, tvg renders those cells
+   with tigr's font and turns tigr input into tv events.  Only programs that
+   call InitGfx need to link tigr/OpenGL; the terminal apps stay tigr-free.
+
+   Build (from the tvision-m2 directory):
+       gm2 -fiso -I. -I../modula2 -c tvg.mod
+   Link an application with:
+       ... tv.o tvg.o ../modula2/tigr.o ../modula2/helper.o -lGL -lX11
+*)
+
+FROM tv IMPORT Event;
+
+PROCEDURE InitGfx (title : ARRAY OF CHAR; cols, rows : INTEGER) : BOOLEAN;
+PROCEDURE Done;
+PROCEDURE Finish;                     (* tv.DrawTree + blit to the window *)
+PROCEDURE ReadEvent (VAR e : Event) : BOOLEAN;
+PROCEDURE Closed () : BOOLEAN;        (* window close / Esc requested *)
+PROCEDURE CellW () : INTEGER;
+PROCEDURE CellH () : INTEGER;
+
+END tvg.

+ 352 - 0
tvision-m2/tvg.mod

@@ -0,0 +1,352 @@
+IMPLEMENTATION MODULE tvg;
+
+(* Graphics backend: renders tv's cell buffer with tigr and feeds tigr input
+   back as tv events.  See tvg.def. *)
+
+FROM SYSTEM IMPORT ADDRESS, ADR, CAST, BYTE;
+FROM tigr IMPORT TigrPtr, tigrWindow, tigrFree, tigrUpdate, tigrClosed,
+                 tigrFill, tigrBlitTint, tigrBitmap, tigrClear, tigrPlot,
+                 tigrBlitMode, TPixelType, TIGR_BLEND_ALPHA,
+                 tigrMouse, tigrKeyDown, tigrReadChar,
+                 TIGR_FIXED,
+                 TK_ESCAPE, TK_RETURN, TK_TAB, TK_BACKSPACE, TK_SPACE,
+                 TK_LEFT, TK_RIGHT, TK_UP, TK_DOWN, TK_HOME, TK_END,
+                 TK_PAGEUP, TK_PAGEDN, TK_INSERT, TK_DELETE,
+                 TK_F1, TK_F2, TK_F3, TK_F4, TK_F5, TK_F6,
+                 TK_F7, TK_F8, TK_F9, TK_F10, TK_F11, TK_F12;
+IMPORT tv;
+IMPORT tvfont;
+
+
+VAR
+    bmp        : TigrPtr;
+    fontBmp    : TigrPtr;
+    cw, ch     : INTEGER;
+    qe         : ARRAY [0..63] OF tv.Event;
+    qh, qn     : INTEGER;
+    prevLeft   : BOOLEAN;
+    prevRight  : BOOLEAN;
+    prevMiddle : BOOLEAN;
+    prevX, prevY : INTEGER;
+    closedFlag : BOOLEAN;
+
+(*========================================================================*)
+(*  Colours                                                                *)
+(*========================================================================*)
+
+PROCEDURE Pal (i : INTEGER) : TPixelType;
+    VAR p : TPixelType; r, g, b : INTEGER;
+BEGIN
+    CASE i OF
+        0  : r:=0;   g:=0;   b:=0;
+      | 1  : r:=0;   g:=0;   b:=170;
+      | 2  : r:=0;   g:=170; b:=0;
+      | 3  : r:=0;   g:=170; b:=170;
+      | 4  : r:=170; g:=0;   b:=0;
+      | 5  : r:=170; g:=0;   b:=170;
+      | 6  : r:=170; g:=85;  b:=0;
+      | 7  : r:=170; g:=170; b:=170;
+      | 8  : r:=85;  g:=85;  b:=85;
+      | 9  : r:=85;  g:=85;  b:=255;
+      | 10 : r:=85;  g:=255; b:=85;
+      | 11 : r:=85;  g:=255; b:=255;
+      | 12 : r:=255; g:=85;  b:=85;
+      | 13 : r:=255; g:=85;  b:=255;
+      | 14 : r:=255; g:=255; b:=85;
+    ELSE
+        r:=255; g:=255; b:=255
+    END;
+    p.r := VAL(BYTE, r); p.g := VAL(BYTE, g);
+    p.b := VAL(BYTE, b); p.a := VAL(BYTE, 255);
+    RETURN p
+END Pal;
+
+PROCEDURE Fg (attr : CARDINAL) : TPixelType;
+BEGIN RETURN Pal(VAL(INTEGER, attr MOD 16)) END Fg;
+
+PROCEDURE Bg (attr : CARDINAL) : TPixelType;
+BEGIN RETURN Pal(VAL(INTEGER, (attr DIV 16) MOD 16)) END Bg;
+
+(*========================================================================*)
+(*  Font / cells                                                           *)
+(*========================================================================*)
+
+
+PROCEDURE Bit (b : BYTE; k : INTEGER) : BOOLEAN;
+    VAR m, i : INTEGER;
+BEGIN
+    m := 1;
+    FOR i := 1 TO k DO m := m * 2 END;
+    RETURN (VAL(INTEGER, b) DIV m) MOD 2 = 1
+END Bit;
+
+PROCEDURE BuildFont;
+    VAR g, r, c : INTEGER; white, clear : TPixelType;
+BEGIN
+    fontBmp := tigrBitmap(VAL(CARDINAL, tvfont.NG * tvfont.CW),
+                          VAL(CARDINAL, tvfont.CH));
+    clear.r := VAL(BYTE, 0); clear.g := VAL(BYTE, 0);
+    clear.b := VAL(BYTE, 0); clear.a := VAL(BYTE, 0);
+    tigrClear(fontBmp, clear);
+    tigrBlitMode(fontBmp, TIGR_BLEND_ALPHA);
+    white.r := VAL(BYTE, 255); white.g := VAL(BYTE, 255);
+    white.b := VAL(BYTE, 255); white.a := VAL(BYTE, 255);
+    FOR g := 0 TO tvfont.NG - 1 DO
+        FOR r := 0 TO tvfont.CH - 1 DO
+            FOR c := 0 TO tvfont.CW - 1 DO
+                IF Bit(tvfont.Row(g, r), tvfont.CW - 1 - c) THEN
+                    tigrPlot(fontBmp,
+                             VAL(CARDINAL, g * tvfont.CW + c),
+                             VAL(CARDINAL, r), white)
+                END
+            END
+        END
+    END
+END BuildFont;
+
+
+
+PROCEDURE Seg (px, py, pw, ph : INTEGER; p : TPixelType);
+BEGIN
+    IF (pw > 0) AND (ph > 0) THEN
+        tigrFill(bmp, VAL(CARDINAL, px), VAL(CARDINAL, py),
+                 VAL(CARDINAL, pw), VAL(CARDINAL, ph), p)
+    END
+END Seg;
+
+PROCEDURE DrawBoxGlyph (cp : CARDINAL; px, py : INTEGER; p : TPixelType);
+    VAR mx, my : INTEGER;
+BEGIN
+    mx := px + cw DIV 2;
+    my := py + ch DIV 2;
+    IF cp = 2500H THEN Seg(px, my, cw, 1, p)                      (* ─ *)
+    ELSIF cp = 2502H THEN Seg(mx, py, 1, ch, p)                   (* │ *)
+    ELSIF cp = 250CH THEN                                          (* ┌ *)
+        Seg(mx, my, cw - cw DIV 2, 1, p); Seg(mx, my, 1, ch - ch DIV 2, p)
+    ELSIF cp = 2510H THEN                                          (* ┐ *)
+        Seg(px, my, cw DIV 2 + 1, 1, p); Seg(mx, my, 1, ch - ch DIV 2, p)
+    ELSIF cp = 2514H THEN                                          (* └ *)
+        Seg(mx, my, cw - cw DIV 2, 1, p); Seg(mx, py, 1, ch DIV 2 + 1, p)
+    ELSIF cp = 2518H THEN                                          (* ┘ *)
+        Seg(px, my, cw DIV 2 + 1, 1, p); Seg(mx, py, 1, ch DIV 2 + 1, p)
+    ELSIF cp = 2550H THEN                                          (* ═ *)
+        Seg(px, my - 2, cw, 1, p); Seg(px, my + 1, cw, 1, p)
+    ELSIF cp = 2551H THEN                                          (* ║ *)
+        Seg(mx - 2, py, 1, ch, p); Seg(mx + 1, py, 1, ch, p)
+    ELSIF cp = 2554H THEN                                          (* ╔ *)
+        Seg(mx, my - 2, cw - cw DIV 2, 1, p); Seg(mx, my + 1, cw - cw DIV 2, 1, p);
+        Seg(mx - 1, my, 1, ch - ch DIV 2, p); Seg(mx + 2, my, 1, ch - ch DIV 2, p)
+    ELSIF cp = 2557H THEN                                          (* ╗ *)
+        Seg(px, my - 2, cw DIV 2 + 1, 1, p); Seg(px, my + 1, cw DIV 2 + 1, 1, p);
+        Seg(mx - 1, my, 1, ch - ch DIV 2, p); Seg(mx + 2, my, 1, ch - ch DIV 2, p)
+    ELSIF cp = 255AH THEN                                          (* ╚ *)
+        Seg(mx, my - 2, cw - cw DIV 2, 1, p); Seg(mx, my + 1, cw - cw DIV 2, 1, p);
+        Seg(mx - 1, py, 1, ch DIV 2 + 1, p); Seg(mx + 2, py, 1, ch DIV 2 + 1, p)
+    ELSIF cp = 255DH THEN                                          (* ╝ *)
+        Seg(px, my - 2, cw DIV 2 + 1, 1, p); Seg(px, my + 1, cw DIV 2 + 1, 1, p);
+        Seg(mx - 1, py, 1, ch DIV 2 + 1, p); Seg(mx + 2, py, 1, ch DIV 2 + 1, p)
+    END
+END DrawBoxGlyph;
+
+PROCEDURE DrawCell (x, y : INTEGER; cp, attr : CARDINAL);
+    VAR px, py, g : INTEGER; p : TPixelType;
+BEGIN
+    px := x * cw; py := y * ch;
+    Seg(px, py, cw, ch, Bg(attr));
+    IF cp >= 20H THEN
+        p := Fg(attr);
+        IF (cp >= 2500H) AND (cp <= 257FH) THEN
+            DrawBoxGlyph(cp, px, py, p)
+        ELSE
+            g := tvfont.Index(cp);
+            IF g < 0 THEN g := tvfont.Index(VAL(CARDINAL, ORD('?'))) END;
+            IF g >= 0 THEN
+                tigrBlitTint(bmp, fontBmp,
+                             VAL(CARDINAL, px), VAL(CARDINAL, py),
+                             VAL(CARDINAL, g * tvfont.CW), 0,
+                             VAL(CARDINAL, tvfont.CW), VAL(CARDINAL, tvfont.CH), p)
+            END
+        END
+    END
+END DrawCell;
+
+PROCEDURE BlitAll;
+    VAR x, y : INTEGER; cp, attr : CARDINAL;
+BEGIN
+    FOR y := 0 TO tv.Rows() - 1 DO
+        FOR x := 0 TO tv.Cols() - 1 DO
+            tv.CellAt(x, y, cp, attr);
+            DrawCell(x, y, cp, attr)
+        END
+    END
+END BlitAll;
+
+(*========================================================================*)
+(*  Event queue                                                            *)
+(*========================================================================*)
+
+PROCEDURE Enq (e : tv.Event);
+BEGIN
+    IF qn < 64 THEN
+        qe[(qh + qn) MOD 64] := e;
+        qn := qn + 1
+    END
+END Enq;
+
+PROCEDURE EnqKey (k : INTEGER);
+    VAR e : tv.Event;
+BEGIN
+    e.kind := tv.evKey; e.key := k; e.ch := 0; e.ctrl := FALSE;
+    e.mx := 0; e.my := 0; e.mbtn := 0;
+    e.mpressed := FALSE; e.mreleased := FALSE; e.mwheel := 0;
+    Enq(e)
+END EnqKey;
+
+PROCEDURE EnqChar (cp : CARDINAL);
+    VAR e : tv.Event;
+BEGIN
+    e.kind := tv.evKey; e.key := tv.kChar; e.ch := cp; e.ctrl := FALSE;
+    e.mx := 0; e.my := 0; e.mbtn := 0;
+    e.mpressed := FALSE; e.mreleased := FALSE; e.mwheel := 0;
+    Enq(e)
+END EnqChar;
+
+PROCEDURE EnqMouse (mx, my, btn : INTEGER; pressed, released : BOOLEAN;
+                    wheel : INTEGER);
+    VAR e : tv.Event;
+BEGIN
+    e.kind := tv.evMouse; e.key := tv.kNone; e.ch := 0; e.ctrl := FALSE;
+    e.mx := mx DIV cw; e.my := my DIV ch; e.mbtn := btn;
+    e.mpressed := pressed; e.mreleased := released; e.mwheel := wheel;
+    Enq(e)
+END EnqMouse;
+
+(*========================================================================*)
+(*  Input                                                                  *)
+(*========================================================================*)
+
+PROCEDURE Pump;
+    VAR mx, my : CARDINAL; buttons : CARDINAL;
+        left, right, middle : BOOLEAN; c : CARDINAL;
+        ix, iy, held : INTEGER;
+BEGIN
+    tigrUpdate(bmp);
+    IF tigrClosed(bmp) # 0 THEN
+        IF NOT closedFlag THEN closedFlag := TRUE; EnqKey(tv.kEsc) END
+    END;
+
+    IF tigrKeyDown(bmp, TK_ESCAPE) # 0 THEN EnqKey(tv.kEsc) END;
+    IF tigrKeyDown(bmp, TK_RETURN) # 0 THEN EnqKey(tv.kEnter) END;
+    IF tigrKeyDown(bmp, TK_TAB) # 0 THEN EnqKey(tv.kTab) END;
+    IF tigrKeyDown(bmp, TK_BACKSPACE) # 0 THEN EnqKey(tv.kBack) END;
+    IF tigrKeyDown(bmp, TK_SPACE) # 0 THEN EnqKey(tv.kSpace) END;
+    IF tigrKeyDown(bmp, TK_LEFT) # 0 THEN EnqKey(tv.kLeft) END;
+    IF tigrKeyDown(bmp, TK_RIGHT) # 0 THEN EnqKey(tv.kRight) END;
+    IF tigrKeyDown(bmp, TK_UP) # 0 THEN EnqKey(tv.kUp) END;
+    IF tigrKeyDown(bmp, TK_DOWN) # 0 THEN EnqKey(tv.kDown) END;
+    IF tigrKeyDown(bmp, TK_HOME) # 0 THEN EnqKey(tv.kHome) END;
+    IF tigrKeyDown(bmp, TK_END) # 0 THEN EnqKey(tv.kEnd) END;
+    IF tigrKeyDown(bmp, TK_PAGEUP) # 0 THEN EnqKey(tv.kPgUp) END;
+    IF tigrKeyDown(bmp, TK_PAGEDN) # 0 THEN EnqKey(tv.kPgDn) END;
+    IF tigrKeyDown(bmp, TK_INSERT) # 0 THEN EnqKey(tv.kIns) END;
+    IF tigrKeyDown(bmp, TK_DELETE) # 0 THEN EnqKey(tv.kDel) END;
+    IF tigrKeyDown(bmp, TK_F1) # 0 THEN EnqKey(tv.kF1) END;
+    IF tigrKeyDown(bmp, TK_F2) # 0 THEN EnqKey(tv.kF2) END;
+    IF tigrKeyDown(bmp, TK_F3) # 0 THEN EnqKey(tv.kF3) END;
+    IF tigrKeyDown(bmp, TK_F4) # 0 THEN EnqKey(tv.kF4) END;
+    IF tigrKeyDown(bmp, TK_F5) # 0 THEN EnqKey(tv.kF5) END;
+    IF tigrKeyDown(bmp, TK_F6) # 0 THEN EnqKey(tv.kF6) END;
+    IF tigrKeyDown(bmp, TK_F7) # 0 THEN EnqKey(tv.kF7) END;
+    IF tigrKeyDown(bmp, TK_F8) # 0 THEN EnqKey(tv.kF8) END;
+    IF tigrKeyDown(bmp, TK_F9) # 0 THEN EnqKey(tv.kF9) END;
+    IF tigrKeyDown(bmp, TK_F10) # 0 THEN EnqKey(tv.kF10) END;
+    IF tigrKeyDown(bmp, TK_F11) # 0 THEN EnqKey(tv.kF11) END;
+    IF tigrKeyDown(bmp, TK_F12) # 0 THEN EnqKey(tv.kF12) END;
+
+    LOOP
+        c := tigrReadChar(bmp);
+        IF c = 0 THEN EXIT END;
+        IF c >= 20H THEN EnqChar(c) END
+    END;
+
+    tigrMouse(bmp, mx, my, buttons);
+    ix := VAL(INTEGER, mx); iy := VAL(INTEGER, my);
+    left   := (buttons MOD 2) = 1;
+    right  := ((buttons DIV 2) MOD 2) = 1;
+    middle := ((buttons DIV 4) MOD 2) = 1;
+
+    IF left AND (NOT prevLeft) THEN EnqMouse(ix, iy, 1, TRUE, FALSE, 0) END;
+    IF (NOT left) AND prevLeft THEN EnqMouse(ix, iy, 1, FALSE, TRUE, 0) END;
+    IF right AND (NOT prevRight) THEN EnqMouse(ix, iy, 2, TRUE, FALSE, 0) END;
+    IF (NOT right) AND prevRight THEN EnqMouse(ix, iy, 2, FALSE, TRUE, 0) END;
+    IF middle AND (NOT prevMiddle) THEN EnqMouse(ix, iy, 3, TRUE, FALSE, 0) END;
+    IF (NOT middle) AND prevMiddle THEN EnqMouse(ix, iy, 3, FALSE, TRUE, 0) END;
+
+    held := 0;
+    IF left THEN held := 1
+    ELSIF right THEN held := 2
+    ELSIF middle THEN held := 3 END;
+    IF (ix # prevX) OR (iy # prevY) OR
+       (left # prevLeft) OR (right # prevRight) OR (middle # prevMiddle) THEN
+        EnqMouse(ix, iy, held, FALSE, FALSE, 0)
+    END;
+    prevX := ix; prevY := iy;
+    prevLeft := left; prevRight := right; prevMiddle := middle
+END Pump;
+
+PROCEDURE ReadEvent (VAR e : Event) : BOOLEAN;
+BEGIN
+    IF qn = 0 THEN Pump END;
+    IF qn = 0 THEN RETURN FALSE END;
+    e := qe[qh];
+    qh := (qh + 1) MOD 64;
+    qn := qn - 1;
+    RETURN TRUE
+END ReadEvent;
+
+(*========================================================================*)
+(*  Lifecycle                                                              *)
+(*========================================================================*)
+
+PROCEDURE InitGfx (title : ARRAY OF CHAR; cols, rows : INTEGER) : BOOLEAN;
+    VAR discard : INTEGER; ww, hh : INTEGER;
+BEGIN
+    cw := tvfont.CW; ch := tvfont.CH;
+    BuildFont;
+    IF cols < 10 THEN cols := 80 END;
+    IF rows < 3 THEN rows := 30 END;
+    ww := cols * cw; hh := rows * ch;
+    bmp := tigrWindow(VAL(CARDINAL, ww), VAL(CARDINAL, hh), title, TIGR_FIXED);
+    IF bmp = NIL THEN RETURN FALSE END;
+    IF NOT tv.InitVirtual(cols, rows) THEN RETURN FALSE END;
+    qh := 0; qn := 0;
+    prevLeft := FALSE; prevRight := FALSE; prevMiddle := FALSE;
+    prevX := -1; prevY := -1;
+    closedFlag := FALSE;
+    BlitAll;
+    tigrUpdate(bmp);
+    RETURN TRUE
+END InitGfx;
+
+PROCEDURE Finish;
+BEGIN
+    tv.DrawTree;
+    BlitAll
+END Finish;
+
+PROCEDURE Closed () : BOOLEAN;
+BEGIN RETURN closedFlag END Closed;
+
+PROCEDURE CellW () : INTEGER;
+BEGIN RETURN cw END CellW;
+
+PROCEDURE CellH () : INTEGER;
+BEGIN RETURN ch END CellH;
+
+PROCEDURE Done;
+BEGIN
+    IF bmp # NIL THEN tigrFree(bmp); bmp := NIL END;
+    IF fontBmp # NIL THEN tigrFree(fontBmp); fontBmp := NIL END
+END Done;
+
+END tvg.

BIN
tvision-m2/tvg.o


+ 7 - 1
tvision-m2/tvtty.def

@@ -8,7 +8,8 @@ DEFINITION MODULE FOR "C" tvtty;
 
 FROM SYSTEM IMPORT ADDRESS;
 
-EXPORT UNQUALIFIED tcgetattr, tcsetattr, ioctl, read, write, signal;
+EXPORT UNQUALIFIED tcgetattr, tcsetattr, ioctl, read, write, signal,
+                    fopen, fgets, fputs, fputc, fclose;
 
 PROCEDURE tcgetattr(fd : INTEGER; termios : ADDRESS) : INTEGER;
 PROCEDURE tcsetattr(fd, action : INTEGER; termios : ADDRESS) : INTEGER;
@@ -16,5 +17,10 @@ PROCEDURE ioctl(fd : INTEGER; request : CARDINAL; arg : ADDRESS) : INTEGER;
 PROCEDURE read(fd : INTEGER; buf : ADDRESS; count : CARDINAL) : INTEGER;
 PROCEDURE write(fd : INTEGER; buf : ADDRESS; count : CARDINAL) : INTEGER;
 PROCEDURE signal(sig : INTEGER; handler : ADDRESS) : ADDRESS;
+PROCEDURE fopen(path, mode : ARRAY OF CHAR) : ADDRESS;
+PROCEDURE fgets(buf : ADDRESS; n : INTEGER; f : ADDRESS) : ADDRESS;
+PROCEDURE fputs(s : ARRAY OF CHAR; f : ADDRESS) : INTEGER;
+PROCEDURE fputc(c : INTEGER; f : ADDRESS) : INTEGER;
+PROCEDURE fclose(f : ADDRESS) : INTEGER;
 
 END tvtty.