diff --git a/docs/quickstart.md b/docs/quickstart.md index 0d5e3fa..4960823 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -1,56 +1,48 @@ # Tek4010 Quick Start +This is a Tektronix 4010 graphics terminal emulator. +It is not a full VT100/xterm terminal. + Basic usage: - tek4010 [options] command [command options] - -The command is required, for example: cat, head, -telnet, or rsh. + tek4010 [options] --- ## Examples -To use the included examples and demos, go to the -Tek4010 directory first +To use the included examples and demos, start tek4010 with the command + + tek4010 + +In the tek4010 window, change to the Tek4010 directory: + + cd Tek4010 Display a plot file: - tek4010 -noexit cat test.plt - -ARDS example: - - tek4010 -noexit -ARDS cat ardsfiles/trek.pic - -Text output: - - tek4010 -noexit head -n 32 src/tek4010.c + cat test.plt Animation: - tek4010 cat animation.plt + cat animation.plt Demo script: - tek4010 demos/demo.sh - ---- - -## Important option - --noexit - -Keeps the window open after the command finishes. + sh demos/demo.sh --- ## Options +By default, the screen clears automatically when the bottom is reached. +Use -noAutoClear to disable this. + | Option | Description | |----------|------------------------------------------| -| -noexit | Keep window open after command | | -fast | Fast rendering without fading | | -full | Full screen mode (Ctrl-Q to close) | +| -half | Use half of the screen width. | | -b9600… | Emulate terminal baud rates | --- diff --git a/dodekagon.plt b/dodekagon.plt deleted file mode 100644 index 978ea97..0000000 --- a/dodekagon.plt +++ /dev/null @@ -1 +0,0 @@ - ,f:^1u9N ,f:^5u5N ,f:^7e/_ ,f:^5u*O ,f:^1u&O ,f:^,f$_ ,f:^&v&O ,f:^"v*O ,f:^!g/^ ,f:^"v5N ,f:^&v9N 1u9N5u5N 1u9N7e/_ 1u9N5u*O 1u9N1u&O 1u9N,f$_ 1u9N&v&O 1u9N"v*O 1u9N!g/^ 1u9N"v5N 1u9N&v9N 5u5N7e/_ 5u5N5u*O 5u5N1u&O 5u5N,f$_ 5u5N&v&O 5u5N"v*O 5u5N!g/^ 5u5N"v5N 5u5N&v9N 7e/_5u*O 7e/_1u&O 7e/_,f$_ 7e/_&v&O 7e/_"v*O 7e/_!g/^ 7e/_"v5N 7e/_&v9N 5u*O1u&O 5u*O,f$_ 5u*O&v&O 5u*O"v*O 5u*O!g/^ 5u*O"v5N 5u*O&v9N 1u&O,f$_ 1u&O&v&O 1u&O"v*O 1u&O!g/^ 1u&O"v5N 1u&O&v9N ,f$_&v&O ,f$_"v*O ,f$_!g/^ ,f$_"v5N ,f$_&v9N &v&O"v*O &v&O!g/^ &v&O"v5N &v&O&v9N "v*O!g/^ "v*O"v5N "v*O&v9N !g/^"v5N !g/^&v9N "v5N&v9N  ` @ \ No newline at end of file diff --git a/src/main.c b/src/main.c index ef9ce32..fa585e4 100644 --- a/src/main.c +++ b/src/main.c @@ -107,6 +107,9 @@ void check_graphics_response(long lag) long now = tube_mSeconds(); + if (brightCounter <= 0) + return; + // ignore startup phase (first 1000 ms) if (now < STARTUP_IGNORE_MSEC) return; @@ -439,8 +442,11 @@ int main (int argc, char *argv[]) } gtk_window_set_title(GTK_WINDOW(window), windowName); - + + gtk_widget_set_can_focus(window, TRUE); gtk_widget_show_all(window); + gtk_window_present(GTK_WINDOW(window)); + gtk_widget_grab_focus(window); gtk_main(); diff --git a/src/tube.c b/src/tube.c index 62817fd..5a86442 100755 --- a/src/tube.c +++ b/src/tube.c @@ -84,7 +84,7 @@ struct keyCode { struct keyCode keyTable[MAXKEYCODES]; -int argNoexit = 0; // options +int argNoexit = 1; // options int argRaw = 0; int argBaud = 19200; int argTab1 = 0; @@ -92,7 +92,7 @@ int argFull = 0; int argFullV = 0; int argARDS = 0; int argAPL = 0; -int argAutoClear = 0; +int argAutoClear = 1; int argKeepSize = 0; int argHideCursor = 0; int argWait = 0; @@ -119,6 +119,7 @@ int specialPlotMode = 0; int defocussed = 0; int intensity = 100; int aplMode = 0; +pid_t childPid = -1; int argPty = 0; @@ -314,6 +315,8 @@ void tube_init(int argc, char* argv[]) size_t bufsize = 127; int firstArg = 1; int ptyMaster = -1; + argAutoClear = 1; + argNoexit = 1; printf("tek4010 version 2.0\n"); windowName = "Tektronix 4010/4014 emulator"; if (argc > 19) { @@ -338,6 +341,8 @@ void tube_init(int argc, char* argv[]) argRaw = 1; else if (strcmp(argv[firstArg],"-noexit") == 0) argNoexit = 1; + else if (strcmp(argv[firstArg],"-exit") == 0) + argNoexit = 0; else if (strcmp(argv[firstArg],"-b100000") == 0) argBaud = 100000; else if (strcmp(argv[firstArg],"-b38400") == 0) @@ -364,6 +369,8 @@ void tube_init(int argc, char* argv[]) argFullV = 1; else if (strcmp(argv[firstArg],"-autoClear") == 0) argAutoClear = 1; + else if (strcmp(argv[firstArg],"-noAutoClear") == 0) + argAutoClear = 0; else if (strcmp(argv[firstArg],"-keepsize") == 0) argKeepSize = 1; else if (strcmp(argv[firstArg],"-hidecursor") == 0) @@ -429,13 +436,14 @@ void tube_init(int argc, char* argv[]) printf("Cannot fork pseudo terminal\n"); exit(1); } -else if (pid == 0) { - setenv("TERM", "vt100", 1); - setenv("PS1", "Tek4010$ ", 1); - execl("/bin/sh", "sh", "-i", (char *) NULL); - _exit(127); -} - + else if (pid == 0) { + setenv("TERM", "vt100", 1); + setenv("PS1", "tek4010$ ", 1); + execl("/bin/sh", "sh", "-i", (char *) NULL); + _exit(127); + } + + childPid = pid; getDataPipe[0] = ptyMaster; putKeysPipe[1] = dup(ptyMaster); if (putKeysPipe[1] == -1) { @@ -516,6 +524,9 @@ else if (pid == 0) { } // parent process + + childPid = pid; + free(str); close(getDataPipe[1]); // not used @@ -566,31 +577,34 @@ int tube_on_timer_event() // is child process still running? - int status; - if (argWait && (tube_isInput() == 0) && (waitpid(-1, &status, WNOHANG))) { - if (firstWait == 0) - firstWait = tube_mSeconds(); - else { - if ((int)((tube_mSeconds() - firstWait) / 1000) > argWait) { - tube_quit(); - gtk_main_quit(); - printf("Process has been terminated after %d seconds\n", argWait); - exit(0); - } - } - } - else if ((!argNoexit) && (tube_isInput() == 0) && (waitpid(-1, &status, WNOHANG))) { - long t = tube_mSeconds(); - // printf("Execution time: %0.3f sec\n", (double)t/1000.0); - // if (t > 0) { - // printf("Average screen refresh rate: %0.1f Hz\n",(double)(1000.0*refreshCount)/t); - // printf("Average character rate: %0.0f baud\n",(double)(8000.0*charCount)/t); - // } - tube_quit(); - gtk_main_quit(); - printf("Process has been terminated\n"); - exit(0); - } + int status; + int childExited = 0; + + if (childPid > 0) { + if (waitpid(childPid, &status, WNOHANG) == childPid) + childExited = 1; + } + + if (childExited) { + if (argPty || !argNoexit) { + tube_quit(); + gtk_main_quit(); + printf("Process has been terminated\n"); + exit(0); + } + + if (argWait) { + if (firstWait == 0) + firstWait = tube_mSeconds(); + else if ((int)((tube_mSeconds() - firstWait) / 1000) > argWait) { + tube_quit(); + gtk_main_quit(); + printf("Process has been terminated after %d seconds\n", argWait); + exit(0); + } + } + } + if (brightCounter > 0) brightCounter--; diff --git a/src/tube.h b/src/tube.h index fb6564b..680a2f4 100755 --- a/src/tube.h +++ b/src/tube.h @@ -47,6 +47,7 @@ extern int aplMode; extern int plotPointMode; extern int writeThroughMode; +extern pid_t childPid; extern int argPty; extern int tube_x0, tube_x2, tube_y0, tube_y2; diff --git a/tektests/circles b/tektests/circles new file mode 100755 index 0000000..3a2a16d Binary files /dev/null and b/tektests/circles differ diff --git a/tektests/circles.c b/tektests/circles.c index 506d663..320bbce 100644 --- a/tektests/circles.c +++ b/tektests/circles.c @@ -48,7 +48,7 @@ void endDraw() fflush(stdout); } -int drawCircle(int x,int y,int r) +void drawCircle(int x,int y,int r) { int i; double arg; @@ -63,12 +63,12 @@ int drawCircle(int x,int y,int r) int main (int argc, char *argv[]) { drawCircle(512, 340, 200); - drawCircle(612, 340, 100); - drawCircle(412, 340, 100); - drawCircle(512, 240, 100); + drawCircle(612, 340, 100); + drawCircle(412, 340, 100); + drawCircle(512, 240, 100); drawCircle(512, 440, 100); startDraw(212,340); draw(812,340); endDraw(); startDraw(512,040); draw(512,640); endDraw(); - startDraw(1,1); endDraw(); // move the cursor out of the way + //startDraw(1,1); endDraw(); // move the cursor out of the way } diff --git a/tektests/circles.plt b/tektests/circles.plt deleted file mode 100644 index 4b4412b..0000000 --- a/tektests/circles.plt +++ /dev/null @@ -1 +0,0 @@ -*t6HHzG+`GfGmFsEyDC,eAk@q5^w\}Y-cWiTnRtOyLH.dEiAn4^sZxV|Q/aMeHjDn3_rZuUyP|K0`Ec@f2ZhUkOmIpCr1]tWuQwKxEy0_zY{RLF|@{/ZTNzGyAx.[wUuOtIrCp-]mWkQhKfFc@`,[/|UyPuKrFnAj+\eXaS.|OxJsFnBi*_d[-XyTtQnNiLcI,}GwDqBk@e)_+]y\s[mZfY`Y*zYtXnYhYbY){Zu[o\i]c_(}*@wBqDkGeI'LzNtQoTiXd[&_z+BuFpJlOgScX%~\z,AvFsKoPlUh[e-@bF`K$}Q{Wx]v.CtIsOqUp[o/AnGmNTZl0@mFLRnYo_p1EqKsQtWv]x2C{I}O%`UbZe3@hElKoPsUvZz_~4D&cHgMlQpVuZz^5A'dEiHoLtOzRT(eWkYq\w^}6@)cAiCoDuE{F*bGhGnGtH*t6HHzG+`GfFlDrCx@~5^,d[iXnTsQxL|H-aCd4^hYkTnNpHsBt3\vVwPJxDw2^XvRtLsFp@n1ZkThOdJaE,|@x0\sWnTiPdM+~JxHrElDfB`A*zAt@nAhAbB)|DvEpHjJdM(PzTuWp\l1@gEdJ`O'}TzZx2@uFtLrRqX^p3DqJPrVt\u4BxHzN}T(`Yd^g5ClHpLuQzTX)d[j^p6@vC|D*bFhGnGtH*t0@@z/_+`_f^l\r[xX~V,dSiPnLsIxD|@-a.[dVhQkLnFp@s-ZtTvNwHBx,\wVPvJtDs+^pXnRkLhGdBa*],|XxTsOnLiHdE+~Bx@r)]l\fZ`Y*zYtXnYhYbZ)|\v]p*@jBdE(HzLuOpTlXg]d+B`G'}LzRxXu^t,DrJqPVp\q-BHrNtTuZx.@zF}L(`QdVg[l/@pDuIzLP)dSjVpXv[|\*b^h_n_t0@'p3DDvC|C(bBh@n2_t\zZ)`WeTjPoMtHxD}1_*`ZdUgPjJlDo0^pXrRsLFt@s/ZTrNpHoBl.\jVgPdK`F)}Ax-\tXoSjPeL`I(zFtDnAh@b,^'|]v]p\j]d]&~^x-@rAlDfF`I%{LvPqSlXh\c.A`F$|KyPvVt\q/BpHnNmTZl0@mFLnRpXq^t1DvJyP|U%`Zc_h2DlHqMvP{T&`WfZl\r_x3@~B'dCjCpD-x3DD~C.dCjBp@v2_|\/bZhWmTrPwM|H0`De1_hZlUoPrJtDw0^xXzR{LF|@{/ZTzNxHwBt.\rVoPlKhFeA`-\/|XwSrPmLhIbF.|DvAp@j,^d]-~]x\r]l]f^`-@,zAtDnFhIcL+~PyStXp\k.AhFdKaP*~V|\y/BxHvNuTZt0@uFLvRxXy^|1D~J+aPdUhZk_p2DtHyM~P,cThWnZt\z_-`3@fBlCrCxD*t&Tt9L!`0@4@ a A \ No newline at end of file diff --git a/tektests/dodecagon b/tektests/dodecagon new file mode 100755 index 0000000..4413425 Binary files /dev/null and b/tektests/dodecagon differ diff --git a/tektests/dodecagon.c b/tektests/dodecagon.c new file mode 100755 index 0000000..fafc840 --- /dev/null +++ b/tektests/dodecagon.c @@ -0,0 +1,29 @@ +/* dodecagon.c */ +/* rricharz 2019 */ + + +#include +#include +#include +#include "tekio.h" + +int main (int argc, char *argv[]) +{ + int angle, angle1; + double rad = 3.14159265 / 180; + int xcenter = MAXX / 2; + int ycenter = MAXY / 2; + int radius = 9 * MAXY / 20; + + clearScreen(); + for (angle = 0; angle < 360; angle += 30) { + for (angle1 = angle + 30; angle1 < 360; angle1 += 30) { + drawVector((int)(xcenter + radius * cos(rad * angle)), + (int)(ycenter + radius * sin (rad * angle)), + (int)(xcenter + radius * cos (rad * angle1)), + (int)(ycenter + radius * sin (rad * angle1))); + } + } + moveAlpha(34,0); + exit(0); +} diff --git a/tektests/incremental b/tektests/incremental new file mode 100755 index 0000000..41869d0 Binary files /dev/null and b/tektests/incremental differ diff --git a/tektests/incremental.plt b/tektests/incremental.plt deleted file mode 100644 index 8d4baee..0000000 --- a/tektests/incremental.plt +++ /dev/null @@ -1 +0,0 @@ -$l0@PEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII \ No newline at end of file diff --git a/tektests/makefile b/tektests/makefile index 50a90f3..5171054 100644 --- a/tektests/makefile +++ b/tektests/makefile @@ -1,8 +1,11 @@ CC = gcc LDFLAGS = -lm -all: incremental circles +all: incremental circles dodecagon incremental: incremental.c circles: circles.c + +dodecagon: tekio.h tekio.c dodecagon.c + cc -o dodecagon dodecagon.c tekio.c -lm diff --git a/tektests/tekio.c b/tektests/tekio.c new file mode 100755 index 0000000..aff652a --- /dev/null +++ b/tektests/tekio.c @@ -0,0 +1,170 @@ +/* tecio.c 2.11 BSD Tektronix graphics */ +/* io functions for Tektronix 4010 */ +/* cc 2019 rricharz */ +/* If you want to use this, you need to */ +/* be in tek4010 terminal. */ +/* See https://github.com/rricharz/Tek4010 */ + +#include +#include +#include +#include "tekio.h" + +static int xs,ys; + +void startDraw(int x1, int y1) +{ + if (x1 < 0) x1 = 0; + if (x1 >= MAXX) x1 = MAXX -1; + if (y1 < 0) y1 = 0; + if (y1 >= MAXY) y1 = MAXY - 1; + putchar(29); + putchar((y1 >> 5) + 32); + putchar((y1 & 31) + 96); + putchar((x1 >> 5) + 32); + putchar((x1 & 31) + 64); + xs = x1; + ys = y1; +} + +void draw(int x2, int y2) +{ + int hxchange, lychange; + + if (x2 < 0) x2 = 0; + if (x2 >= MAXX) x2 = MAXX -1; + if (y2 < 0) y2 = 0; + if (y2 >= MAXY) y2 = MAXY - 1; + + if ((y2 >> 5) != (ys >> 5)) /* if high y has changed */ + putchar((y2 >> 5) + 32); + hxchange = (x2 >> 5) != (xs >> 5); + lychange = (y2 & 31) != (ys & 31); + if (hxchange || lychange) putchar((y2 & 31) + 96); + if (hxchange) /* if high order x has changed */ + putchar((x2 >> 5) + 32); + putchar((x2 & 31) + 64); + xs = x2; + ys = y2; +} + +void endDraw() +{ + putchar(31); + fflush(stdout); +} + +void moveTo(int x1, int y1) +{ + startDraw(x1,y1); + endDraw(); +} + +void moveAlpha(int line, int column) +{ + int vDotsPerChar; + double hDotsPerChar; + if (line < 1) line = 1; + if (line > MAXLINES) line = MAXLINES; + if (column < 1) column = 1; + if (column > MAXCOLUMNS) column = MAXCOLUMNS; + vDotsPerChar = MAXY / MAXLINES; + hDotsPerChar = (double)(MAXX)/(double)(MAXCOLUMNS); + moveTo((int)((double)(column - 1) * hDotsPerChar), MAXY - line * vDotsPerChar); +} + +void drawVector(int x1, int y1, int x2, int y2) +{ + startDraw(x1,y1); + if (x2 < 0) x2 = 0; + if (x2 >= MAXX) x2 = MAXX -1; + if (y2 < 0) y2 = 0; + if (y2 >= MAXY) y2 = MAXY - 1; + draw(x2,y2); + endDraw(); +} + +void clearScreen() +{ + putchar(27); + putchar(12); +} + + +void startWriteThrough() +{ + putchar(27); + putchar('p'); + fflush(stdout); +} + +void endWriteThrough() +{ + putchar(27); + putchar('`'); + fflush(stdout); +} + +void drawRectangle(int x1, int y1, int x2, int y2) +{ + startDraw(x1,y1); + draw(x2,y1); + draw(x2,y2); + draw(x1,y2); + draw(x1,y1); + endDraw(); +} + +void drawCircle(int x, int y, int r) +{ + int i; + double arg; + startDraw(x + r, y); + for (i = 0; i <= r; i++) { + arg = (double)(i) * PI2 / (double) r; + draw(x + (int)((double)r * cos(arg)), y + (int)((double)r * sin(arg))); + } + endDraw(); +} + +void drawJustifiedText(char *s, int line, int justify) +/* justify 0=left, 1=center; 2=right */ +{ + int length; + length = strlen(s); + switch (justify) { + case 1: moveAlpha(line, 1); break; + case 2: moveAlpha(line, (MAXCOLUMNS - length) / 2); break; + case 3: moveAlpha(line, MAXCOLUMNS - length + 1); break; + } + printf("%s",s); +} + +int fix(double r) +/* round double and convert to int */ +{ + if (r >= 0) return (int)(r + 0.5); + else return (int)(r - 0.5); +} + +void setCharacterSize(int size) +{ + if ((size >= 1) && (size <= 4)) { + putchar(27); + putchar('7' + size); + } + else + printf("setCharacterSize: Illegal size %d\n", size); +} + +void setLineMode(int type) +{ + if ((type >= SOLID) && (type <= LONGDASH)) { + putchar(27); + putchar(95 + type); + } + else + printf("SetLineMode: illegal type %d\n", type); +} + + diff --git a/tektests/tekio.h b/tektests/tekio.h new file mode 100755 index 0000000..927b15c --- /dev/null +++ b/tektests/tekio.h @@ -0,0 +1,77 @@ +/* tecio.h 2.11 BSD Tektronix graphics */ +/* io functions for Tektronix 4010 */ +/* cc 2019 rricharz */ +/* If you want to use this, you need to */ +/* be in tek4010 */ +/* See https://github.com/rricharz/Tek4010 */ + +#define MAXX 1023 /* Tektronix graphics screen size */ +#define MAXY 780 + +#define MAXCOLUMNS 74 /* Tektronix alpha screen size */ +#define MAXLINES 35 + +/* */ +/* clear screen with */ +/* clearScreen() */ +/* */ +/* draw individual vectors with */ +/* drawVector(x1,y1,x2,y2) */ +/* */ +/* draw a string using graphics coordinates */ +/* moveTo(x1,y1) */ +/* printf(.....) */ +/* */ +/* draw a string using alpha coordinates */ +/* moveAlpha(line,column) */ +/* printf(.....) */ +/* */ +/* fast draw multiple joint vectors */ +/* startDraw(x1,y1) */ +/* draw(x2,y2) */ +/* draw(x3,y3) */ +/* ............. */ +/* endDraw() */ +/* */ +/* drawRectange(x1,y1.x2.y2) */ +/* */ +/* drawCircle(x,y,r) */ +/* */ +/* drawJustifiedText(s, line, justify) */ +/* justify 0=left, 1=center; 2=right */ +/* */ +/* writethrough mode for short animations */ +/* startWriteThrough() */ +/* endWriteThrough() */ +/* */ +/* setCharacterSize(size) */ +/* select character size 1..4 */ +/* */ +/* void setLineMode(type) */ +/* set line type */ +/* SOLID,DOTTED,DOTDASH,SHORTDASH,LONGDASH */ + +#define PI 3.14159265 +#define PI2 6.28318531 + +#define SOLID 1 +#define DOTTED 2 +#define DOTDASH 3 +#define SHORTDASH 4 +#define LONGDASH 5 + +extern void drawVector(int x1, int y1, int x2, int y2); +extern void moveTo(int lx, int ly); +extern void moveAlpha(int line, int column); +extern void clearScreen(void); +extern void startDraw(int lx, int ly); +extern void draw(int x2, int y2); +extern void endDraw(void); +extern void startWriteThrough(); +extern void endWriteThrough(); +extern void drawRectangle(int x1, int y1, int x2, int y2); +extern void drawCircle(int x, int y, int r); +extern void drawJustifiedText(char *s, int line, int justify); +extern int fix(double r); +extern void setCharacterSize(int size); +extern void setLineMode(int type); diff --git a/test.plt b/test.plt index 23de809..7cc4b72 100644 --- a/test.plt +++ b/test.plt @@ -1 +1 @@ -6d:Ld M3o*P{:U5w+Z!u O }(Z#s7Y6d9B` ]3p+J~9]4w+H!t \a)Q$q7[6d\5|!N3p,A9Fx*W!s!Jg*H%m7[6c6X5x!_3q,V8O2{*H!r!Xm*^&h7Y6c5V5t"P3r-I}7X1)[!r"Gu+S'a7V6b4X5q#A3r-Zz7B1e)N!r"V~,F'y7Q6a3[5n#S3s.Iv6L0l)D!s#E"g,X(p7K6`3A5k$D3s.Vp5W/u(Z!t#U"q-I)f7D52Jh$U3s/Aj5B.~(R!u$D"|-Y)z6]5~1Tf%E3r/Jc4N.i(K!w$T#g.H*n6T5}1@c%U3r/S2{3[-u(E!z%C#r.U+`6K5{0Na&E3q/Y2s3H-b(@!|%R#~/A+q6B5z/]4~&U3o/_2j2V,p'\"`&A$j/L,b5X5y/N4|'D3m0C2a2E+'Y"c&P$w/W,q5N5w/A4y'R3k0G1w1T+o'W"h&_%c0@-`5D5v.U4w(@3h0I1m1D+a'V"lM%p0H-n4Y5t.J4u(M3e0J1cU*s'U"q\%}0O-{4O5s.A4r(Z3b0K0yG*f'V"w(I&i0V.g4E5q-Y4p)F2~0K0n/Y)z'W"|(W&v0[.s3Z5o-Q4n)Q2z0J0c/L)o'X#b)D'c1@.~3P5n-K4k)\2v0H/y/@)e'Z#i)P'o1D/h3G5l-E4h*F2q0F/n.U({']#p)]'|1G/r2]5j-A4f*P2l0D/d.J(s(@#w*H(h1J/{2S5h,]4c*Y2g0A.y.@(k(D#~*T(t1L0d2J5f,Y4`+A2b/^.o-V(d(H$e*^)`1N0l2A \ No newline at end of file + ,f:^1u9N,f:^5u5N,f:^7e/_,f:^5u*O,f:^1u&O,f:^f%@,f:^&v&O,f:^"v*O,f:^!g/^,f:^"v5N,f:^&v9N1u9N5u5N1u9N7e/_1u9N5u*O1u9Nu&O1u9N,f%@1u9N&v&O1u9N"v*O1u9N!g/^1u9N"v5N1u9N&vN5u5N7e/_5u5Nu*O5u5N1u&O5u5N,f%@5u5N&v&O5u5N"v*O5u5N!g/^5u5N"vN5u5N&v9N7e/_5u*O7e/_1u&O7e/_,f%@7e/_&v&O7e/_"v*O7e/_!g^7e/_"v5N7e/_&v9N5u*O1u&O5u*O,f%@5u*O&v&O5u*O"vO5u*O!g/^5u*O"v5N5u*O&v9N1u&O,f%@1u&O&vO1u&O"v*O1u&O!g/^1u&O"v5N1u&O&v9N,f%@&v&O,f%@"v*O,f%@!g/^,f%@"v5N,f%@&v9N&v&O"v*O&v&O!g/^&v&O"v5N&v&Ov9N"v*O!g/^"v*Ov5N"v*O&v9N!g/^"v5N!g/^&v9N"v5N&v9N!` @ \ No newline at end of file