--- title: "Text1" id: 70954 type: "computer_media" slug: "text1" url: "http://localhost/computer_media/text1/" markdown_url: "http://localhost/computer_media/text1.md" published_at: "2026-08-24T23:18:34+00:00" modified_at: "2026-08-24T23:21:34+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/08/text-1.png" alt: "TEST screen" excerpt: "A full word processor with tape load/save, screen editing, search-and-replace, and machine code block-move routines crammed into a single BASIC program." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Word Processor" slug: "word-processor" taxonomy: "genre" url: "http://localhost/type/word-processor/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Text1%20%28198x%29%28-%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/08/text-1.png" alt: "TEST screen" media_type_tags: "Word Processor" --- # Text1 Text1 is a full-featured word processor program that supports text entry, tape-based load and save, screen editing, printing, and search-and-replace operations. It stores text in a raw memory buffer starting at address 38000, using POKE and PEEK extensively to manipulate bytes directly, and employs machine code routines loaded from tape (via `LOAD “text1 C” CODE`) for block-move and search operations triggered through `RANDOMIZE USR`. Special characters encoded as bytes 128–144 are used to represent formatting markers such as line breaks, paragraph breaks, and page breaks. The program detects a printer by polling port 251 via `IN` and adjusts its output mode accordingly, and it uses a cursor-navigation subroutine driven by keys 5–8 for screen editing in the scan/edit mode. *** ### Program Structure Text1 is organized as a menu-driven word processor with subroutines at low line numbers and major functional sections branched to via `GO TO VAL b$*1000` from line 930. The six operational modes map to line ranges as follows: | Menu Choice | Line Range | Function | | --- | --- | --- | | 1 | 1000–1500 | Enter text | | 2 | 2000–2050 | LOAD text from tape | | 3 | 3000–3420 | PRINT text | | 4 | 4000–4800 | Scan/edit text | | 5 | 5000–5030 | SAVE text on tape | | 6 | 6010–6030 | Set parameters | | 7 | 7000 | STOP work | Initialization runs through lines 5800–6030 on first load: a UDG is defined at line 5800 (a small bracket character for UDG-A), the machine code overlay is loaded from tape at line 5810, and workspace variables are set at line 6010. The main menu loop sits at lines 900–930. ### Memory Layout The program uses a fixed memory map for its text buffer and scratch areas: - `te = 38000` — base address of the text buffer - `li = 37000` — line input scratch buffer (used by the `GO SUB 60` keyboard entry routine) - `37998–37999` — two-byte little-endian word storing the current text length `c1` (written before SAVE, read after LOAD) - `37001–37002` — stores a byte count used during the Move operation (line 4800) - `c2 = 15000` — maximum number of characters the buffer can hold - `q = 23670`, `r = 23671` — system variables SEED (low and high bytes), tapped after each `RANDOMIZE` to extract a 16-bit value for machine code parameter passing ### Machine Code Interface All block-memory operations and search functions are handled by a machine code binary loaded separately from tape as `"text1 C" CODE`. Parameters are passed to the routines by a consistent idiom: `RANDOMIZE` is called with the desired value, then `PEEK q` and `PEEK r` (the SEED system variable, low and high bytes) are POKEd into argument slots within the machine code block, and finally `RANDOMIZE USR address` calls the routine. Two main entry points are used: - `USR 60000` (subroutine at line 30) — forward block move; takes three parameters: count `v1`, destination `v2`, source `v3` - `USR 60014` (subroutine at line 35) — reverse block move (for inserting/overlapping regions) - `USR 60028` (subroutine at line 81) — string search; takes start address `li`, text base `te+c2`, and end position `c3`; returns result flag in `PEEK 60143` and found position via `PEEK 60135/60136` - `USR 60151` (subroutine at line 100) — adjusts scroll/display parameters for edge-of-buffer conditions Subroutine 85 (lines 85–87) clamps the cursor position `c` to the valid range `[1, c1]` before any machine code call that uses `c` as an offset. ### Key BASIC Idioms The program makes heavy use of arithmetic on boolean-like expressions to avoid explicit numeric literals, following a common Sinclair BASIC space-saving convention: - `SGN PI` evaluates to `1` (since PI > 0) - `NOT PI` evaluates to `0` - `PI + PI` evaluates to approximately `6.28`, which truncates to `6` when used in `PRINT AT` - `VAL "number"` in `GO TO`, `GO SUB`, and `POKE` targets is a well-known memory optimization that avoids storing the floating-point number in the BASIC line - The keypress-wait idiom at lines 10–11 (`PAUSE 0` is not used here; instead line 10 waits for key-up then line 11 waits for key-down) is a clean debounce sequence ### Text Entry (Lines 1000–1500) Characters are POKEd directly into the buffer at `37999 + c` where `c` is a one-based character index. The display position `b` tracks column (0–32); every 33rd character, `POKE 23692, 9` suppresses the scroll prompt. The ENTER key opens a sub-menu (line 1100) offering line break (`▀`, code 131), paragraph break (`▜`, code 134), and page break (`▞`, code 139) markers — these special bytes drive the printer routine at lines 3000–3420. The quote character (code 34) is remapped to UDG-A (code 144) since bare quotes would interfere with string handling. ### Print Routine (Lines 3000–3420) The printer section walks the buffer byte by byte, assembling words into lines of up to 32 characters using a look-ahead to avoid splitting words. The variable `x` is the current buffer pointer; `y` is the tentative end of the next print segment. Special marker bytes branch to distinct handlers: - Codes >127 (other than 144/UDG-A) signal a formatting marker; code 139 triggers a paragraph break (lines 3200–3230), code 134 triggers a page break (lines 3300–3320) - Page formatting at lines 3400–3420 prints a five-line footer/header with a page number stored in `x2` - The printer-present flag `p` (set at line 901 via `IN 251`) controls whether `COPY` is issued (line 21) or INPUT is used to pause (line 22) ### Scan/Edit Mode (Lines 4000–4800) The scan/edit mode uses the machine code scroll routine (via `GO SUB 95`) to display a 320-character window centered on the cursor position `c`. Movement keys 5/6/7/8 (via `GO SUB 40`, lines 40–50) move a flashing cursor through the displayed text, updating both screen position `(m, n)` and buffer index `c` together. Additional single-letter commands from the sub-menu at line 4600 provide: - **Type** (`z`) — inserts from current position using the machine code block-move routines - **Seek** — calls the machine code search (line 4610) - **Alter** (search-and-replace) — lines 4630–4670 search for one string and replace with another using block moves - **Move** — relocates a previously cut block stored in the scratch buffer at address 37003 (lines 4800–4820) - **Delete** — marks start with `g`, moves cursor to end with repeated `d` keypresses, then shifts the remainder of the buffer left (line 4230) ### Save and Load (Lines 2000–2050, 5000–5030) Before saving, the two-byte text length `c1` is written to addresses 37998–37999 using the `RANDOMIZE`/`PEEK q`/`PEEK r` parameter idiom, so the entire block from 37998 is saved as a self-describing chunk. The SAVE covers `c1 + 2` bytes. After loading, line 2040 reconstructs `c1` from those same two bytes. A VERIFY step is offered after SAVE (line 5020–5030). ### Notable Techniques and Anomalies - Line 901 uses a compound `IN 251` test (checking for both `58` and `126`) to detect printer presence; result is stored as `0` or `1` in `p` using boolean arithmetic rather than IF/THEN. - Line 2 fills `a$` with 320 spaces and returns immediately — this string is PRINTed in display mode to blank the screen efficiently before the machine code fills it. - `POKE 23692, 9` at lines 1020 and 6030 resets the scroll counter, preventing the “scroll?” prompt from appearing during rapid text output. - Line 4160 has a subtle off-by-one guard: when `c` reaches 1 it clears the screen and goes to entry mode, preventing the reverse scroll machine code from being called with an invalid address. - The REM at line 3220 contains code that was commented out (alternative page-break formatting), which is an unusual but valid approach to preserving old code within the listing. - Line 1500 checks `INKEY$ <> "z"` to loop — this is a deliberate pause at buffer-full, requiring the user to press Z to force a tape save, after which `GO TO SGN PI` (line 1510) jumps to line 1, which is a non-existent target — likely intended as a program termination or reset point. ## Source Code ``` 1 GO TO 900 2 LET a$=" ":RETURN 10 IF INKEY$ <>"" THEN GO TO VAL "10" 11 LET b$= INKEY$:IF b$="" THEN GO TO VAL "11" 12 BEEP .02, NOT PI:RETURN 20 PRINT b$( TO y-x):LET x=y+1 21 IF x1=22 AND p= SGN PI THEN COPY :CLS :LET x1= NOT PI 22 IF x1=22 AND p= NOT PI THEN INPUT c$:CLS :LET x1= NOT PI 23 LET x1=x1+ SGN PI:LET x4=x4+ SGN PI:RETURN 25 PRINT AT PI+ PI, PI+ PI;" KEEP TAPE RUNNING " 30 GO SUB 85:RANDOMIZE v1:POKE VAL "60001", PEEK q:POKE VAL "60002", PEEK r:RANDOMIZE v2:POKE VAL "60004", PEEK q:POKE VAL "60005", PEEK r:RANDOMIZE v3:POKE VAL "60009", PEEK q:POKE VAL "60010", PEEK r:RANDOMIZE USR VAL "60000":RETURN 35 GO SUB 85:RANDOMIZE v1:POKE VAL "60015", PEEK q:POKE VAL "60016", PEEK r:RANDOMIZE v2:POKE VAL "60018", PEEK q:POKE VAL "60019", PEEK r:RANDOMIZE v3:POKE VAL "60023", PEEK q:POKE VAL "60024", PEEK r:RANDOMIZE USR VAL "60014":RETURN 40 LET c$= SCREEN$ (m,n):PRINT FLASH SGN PI; AT m,n;c$ 41 GO SUB 11:PRINT AT m,n;c$ 42 IF b$="5" THEN LET n=n- SGN PI:LET c=c- SGN PI 43 IF b$="6" THEN LET m=m+ SGN PI:LET c=c+32 44 IF b$="7" THEN LET m=m- SGN PI:LET c=c-32 45 IF b$="8" THEN LET n=n+ SGN PI:LET c=c+1 46 IF n<0 THEN LET n=n+32:LET m=m-1 47 IF n>31 THEN LET n=n-32:LET m=m+1 48 IF m<0 THEN LET c=c+32:LET m=m+ SGN PI:GO TO 48 49 IF m>19 THEN LET c=c-32:LET m=m- SGN PI:GO TO 49 50 RETURN 60 PRINT AT 20, NOT PI;" KEY TEXT " 61 PRINT ;:LET c3=li:LET b= NOT PI 62 GO SUB 10:LET a= CODE b$:IF a=13 THEN RETURN 63 IF CODE b$=34 THEN LET a=144:LET b$= CHR$ a 64 IF a=12 THEN GO TO 70 65 IF a<32 OR (a>127 AND a <>144) THEN GO TO 62 66 PRINT b$;:POKE c3,a:LET b=b+ SGN PI:LET c3=c3+ SGN PI:IF b=32 THEN LET b= NOT PI:POKE 23692,9 67 IF c3=37997 THEN RETURN 68 GO TO 62 70 LET c3=c3- SGN PI:IF c3
  • c1 THEN LET c=c1 87 RETURN 90 INPUT "from cursor?";b$:RANDOMIZE te:IF b$="z" THEN RANDOMIZE te+c 91 POKE VAL "60135", PEEK q:POKE VAL "60136", PEEK r:RETURN 95 LET v1=640:LET v2=26734:LET v3=c+37680:IF c<321 OR c>c1-320 THEN GO SUB 97 96 GO SUB 30:CLS :GO SUB 2:PRINT a$:LET m=10:LET n= NOT PI:PRINT FLASH SGN PI; AT m,n; SCREEN$ (m,n):RETURN 97 GO SUB 100 98 IF c<321 THEN LET v1=c+319:LET v2=27055-c:LET v3=te:RETURN 99 LET v1=320+c1-c:LET v2=26734:LET v3=c+37680:RETURN 100 RANDOMIZE 26734:POKE VAL "60152", PEEK q:POKE VAL "60153", PEEK r:RANDOMIZE 27373:POKE VAL "60155", PEEK q:POKE VAL "60156", PEEK r:POKE VAL "60158", VAL "32":RANDOMIZE USR VAL "60151":RETURN 900 CLS :PRINT " TEXT 1 "'''"1 Enter text"'"2 LOAD text from tape"'"3 PRINT text"'"4 Scan/edit text"'"5 SAVE text on tape"'"6 Set parameters"'"7 STOP work" 901 LET p=(VAL "1" AND IN VAL "251"= VAL "58")+(VAL "0" AND IN VAL "251"= VAL "126") 904 PRINT ''" Status Board" 906 PRINT '" Printer is "; INK VAL "7"; PAPER VAL "4";"ON" AND p; PAPER VAL "2";"OFF" AND NOT p 907 PRINT '" Text entered is ";c1 910 GO SUB 10:IF LEN b$ <>1 OR b$<"1" OR b$>"7" THEN GO TO 900 920 CLS :IF b$="1" THEN PRINT AT 21, NOT PI;"_"; AT 21, NOT PI; 930 GO TO VAL b$*1000 1000 GO SUB 10:IF c>c2 THEN GO TO 1500 1010 IF CODE b$<32 OR CODE b$>127 THEN GO TO 1040 1015 IF CODE b$=34 THEN LET b$="[UDG-A]" 1020 POKE 37999+c, CODE b$:PRINT b$;:LET b=b+ SGN PI:LET c=c+ SGN PI:IF b=33 THEN LET b= SGN PI:POKE 23692,9 1025 IF c>c1 THEN LET c1=c 1030 GO TO 1000 1040 LET d=21 1050 IF CODE b$ <>12 THEN GO TO 1080 1060 LET b=b- SGN PI:POKE 37999+c, CODE " ":LET c=c- SGN PI:IF b= NOT PI THEN LET b=32:LET d=d- SGN PI:PRINT " "; AT 19, NOT PI; 1070 PRINT AT d,b-1;"_ "; AT d,b-1;:GO SUB 10:GO TO 1050 1080 IF CODE b$<128 AND CODE b$>31 THEN GO TO 1010 1090 IF CODE b$ <>13 THEN GO TO 1000 1100 INPUT "1line 2para 3page ZmenuENTERedit";b$:IF LEN b$ <>1 OR (b$ <>"z" AND (b$<"1" OR b$>"3")) THEN GO TO VAL "4000" 1110 IF b$="z" THEN GO TO SGN PI 1120 IF b$="1" THEN LET b$="▀" 1130 IF b$="2" THEN LET b$="▜" 1140 IF b$="3" THEN LET b$="▞" 1150 POKE VAL "37999+c", CODE b$:PRINT b$;:LET c=c+ SGN PI:LET b=b+ SGN PI:IF b>31 THEN LET b=1 1160 GO TO 1000 1500 BEEP VAL ".1", VAL "20":PRINT AT VAL "9", VAL "9";" BUFFER FULL "; TAB VAL "9";" FILE ON TAPE ":IF INKEY$ <>"z" THEN GO TO VAL "1500" 1510 GO TO SGN PI 2000 PRINT "Enter text name (max. 10 chars.":INPUT b$:PRINT 'b$ 2010 PRINT '"OK? Press C":INPUT c$:IF c$ <>"c" THEN GO TO VAL "900" 2020 LET p= NOT PI:LET b= SGN PI:POKE VAL "23692", VAL "9" 2030 PRINT '"Play tape":LOAD b$ CODE 2040 LET c1= VAL "PEEK 37998+256* PEEK 37999" 2050 GO TO SGN PI 3000 LET x=te 3010 LET x1= SGN PI:LET x2=x1:LET x4=x1 3020 LET y=31 3030 LET f= PEEK x:IF f=144 THEN GO TO 3050 3040 IF f>127 THEN LET x=x+ SGN PI:IF f <>131 THEN GO TO 3200 3050 IF INKEY$="z" THEN GO TO 1 3055 IF x-te>c1 THEN PAUSE VAL "600":GO TO 1 3060 LET f= NOT PI:LET b$="":FOR j=x TO x+y:LET b$=b$+ CHR$ PEEK j:IF (PEEK j>127 AND PEEK j <>144) AND f= NOT PI THEN LET f=j 3070 NEXT j:LET y=j:IF f>0 THEN LET y=f 3080 LET f= NOT PI:FOR j=x TO y:IF PEEK j=32 THEN LET f= SGN PI:LET j=y 3090 NEXT j:IF f= NOT PI THEN GO TO 3110 3100 IF PEEK y <>32 AND PEEK y<128 THEN LET y=y- SGN PI:GO TO 3100 3110 GO SUB 20:IF PEEK y>127 THEN LET x=x-1 3120 GO SUB 3400:GO TO 3020 3200 IF f <>139 THEN GO TO 3300 3210 PRINT :GO SUB 21:GO SUB 3400:LET a=x3-x4:IF a<3 THEN FOR j=1 TO a:PRINT :GO SUB 21:GO SUB 3400:NEXT j:GO TO 3230 3220 REM PRINT :GO SUB 21:GO SUB 3400:PRINT :GO SUB 21:GO SUB 3400 3230 PRINT " ";:LET y=26:GO TO 3030 3300 IF f <>134 THEN LET x=x+ SGN PI:GO TO 3020 3310 LET a=x3-x4:PRINT :GO SUB 21:FOR j=1 TO a:PRINT :GO SUB 21:NEXT j:GO SUB 3410 3320 GO TO 3020 3400 IF x4c1 THEN LET c=c1 4020 GO SUB 95 4030 GO SUB 40 4050 IF b$="p" THEN LET c=c+608:GO TO 4000 4060 IF b$="q" THEN LET c=c-608:GO TO 4000 4070 IF b$="e" THEN GO TO 4200 4080 IF b$="z" THEN GO TO 4600 4090 IF b$="c" THEN LET x=c+37999:CLS :GO TO 3005 4100 IF m>19 OR m<0 THEN LET m= NOT PI:LET n= NOT PI 4110 GO TO 4030 4120 LET b= SGN PI 4130 GO SUB 85:GO SUB 100:IF c<640 THEN GO TO 4160 4140 LET v1=640:LET v2=26734:LET v3=c+37359:GO SUB 30 4150 CLS :GO SUB 2:PRINT 'a$;:GO TO 1000 4160 LET c=c- SGN PI:IF c= SGN PI THEN CLS :PRINT AT 21, NOT PI;:GO TO VAL "1000" 4170 LET v1=c:LET v2=27373:LET v3=37999+c:GO SUB 35:LET c=c+ SGN PI:GO TO 4150 4200 INPUT "D delete A Add";b$:IF c<321 THEN LET c=c-1 4205 IF b$ <>"d" OR c<1 OR c>c1 THEN GO TO 4300 4210 LET g=c:PRINT AT m,n; OVER SGN PI;"_" 4220 GO SUB 40:IF b$ <>"d" THEN GO TO 4220 4225 IF cc1 THEN GO TO 4000 4230 LET b=c-g+ SGN PI:LET v1=b:LET v2=37003:LET v3=te+g:GO SUB 30:RANDOMIZE b:POKE li,255:POKE 37001, PEEK q:POKE 37002, PEEK r:LET v1=c1-c:LET c=c+ SGN PI:LET v2=te+g:LET v3=te+c:GO SUB 30 4240 LET a=c-g:LET c=c-a:LET c1=c1-a:GO TO 4000 4300 IF b$ <>"a" OR c<1 OR c >=c1 THEN GO TO 4000 4310 LET c=c+ SGN PI:GO SUB 60 4320 LET a=c3-li:IF a<1 THEN GO TO 4000 4330 LET v1=c1-c+ SGN PI:LET v2=te+c1+a:LET v3=te+c1:GO SUB 35 4340 LET v1=a:LET v2=te+c:LET v3=li:GO SUB 30 4350 LET c1=c1+a:LET c=c+a:GO TO 4000 4600 GO SUB 85:PRINT FLASH SGN PI; AT m,n; SCREEN$ (m,n):INPUT "type?";b$:IF b$="z" THEN LET c=c+ SGN PI:GO TO 4120 4601 INPUT "edit?";b$:IF b$="z" THEN GO TO VAL "4000" 4602 INPUT "seek?";b$:IF b$="z" THEN GO TO VAL "4610" 4603 INPUT "alter";b$:IF b$="z" THEN GO TO VAL "4630" 4604 INPUT "move?";b$:IF b$="z" THEN GO TO VAL "4800" 4605 INPUT "menu?";b$:IF b$="z" THEN GO TO SGN PI 4606 GO TO VAL "4600" 4610 GO SUB 90:GO SUB 80 4615 IF f= NOT PI OR b>c1 THEN GO SUB 75:GO TO VAL "4600" 4620 LET c=b:GO SUB 95:INPUT "repeat?";b$:IF b$ <>"z" THEN LET c=c+ SGN PI:GO SUB 81:GO TO 4615 4625 GO TO VAL "4600" 4630 GO SUB 90:GO SUB 60:PRINT AT VAL "21", NOT PI;"NEW TEXT ",,;:LET b= VAL "12":LET v2=c3:GO SUB VAL "62":LET c4=c3:LET c3=v2:IF c3=c4 THEN GO TO VAL "4000" 4635 GO SUB 81:IF f= NOT PI OR b>c1 THEN GO SUB 75:GO TO VAL "4600" 4640 LET c=b:GO SUB 95:INPUT "replace?";b$:IF b$ <>"z" THEN GO TO 4665 4650 LET m=c3-li:LET n=c4-c3:LET v1=c1-c-m:LET v2=te+c:LET v3=v2+m:GO SUB 30:LET v2=37999+c1-m+n:LET v3=37999+c1-m:GO SUB 35:LET v1=n:LET v2=te+c:LET v3=li+m:GO SUB 30 4660 LET c1=c1-m+n:GO SUB 95 4665 INPUT "repeat?";b$:IF b$="z" THEN LET c=c+ SGN PI:GO TO 4635 4670 GO TO VAL "4600" 4800 IF PEEK li <>255 THEN GO TO 4000 4810 IF c=c1 THEN LET c1=c1+1 4820 LET b= VAL "PEEK 37001+256* PEEK 37002":LET v1=c1-c:LET v2=37999+c1+b:LET v3=c1+37999:GO SUB 35:LET v1=b:LET v2=c+te:LET v3=37003:GO SUB 30:LET c1=c1+b:GO TO 4000 5000 PRINT "Enter text name ":INPUT b$:PRINT b$''"C if OK":INPUT c$:CLS :IF c$ <>"c" THEN GO TO SGN PI 5010 RANDOMIZE c1:POKE VAL "37998", PEEK q:POKE VAL "37999", PEEK r 5020 PRINT " PULL OUT EAR PLUG ":SAVE b$ CODE VAL "37998", VAL "c1+2":INPUT "Key ""V"" TO VERIFY ";z$:IF z$ <>"v" THEN GO TO SGN PI 5030 CLS :PRINT FLASH SGN PI;" REPLACE EAR PLUG ":PRINT ''''"Rewind and play tape":VERIFY b$ CODE :GO TO SGN PI 5800 FOR j= NOT PI TO VAL "7":POKE USR "a"+j, NOT PI:NEXT j:POKE USR "a"+1, VAL "36":POKE USR "a"+ VAL "2", VAL "36" 5810 LOAD "text1 C"CODE 6010 CLS :LET te= VAL "38000":LET li= VAL "37000":LET x3= VAL "22":LET p= NOT PI:IF IN VAL "251"= VAL "58" THEN LET p= SGN PI:PRINT '"How many lines/page?":INPUT x3:PRINT x3'"C if OK":INPUT b$:IF b$ <>"c" THEN CLS :GO TO VAL "6000" 6020 LET c2= VAL "15000":LET q= VAL "23670":LET r= VAL "23671":PRINT '"Key T to set up text space."'"CAUTION destroys existing text":INPUT b$:IF b$ <>"t" THEN GO TO SGN PI 6030 LET b= SGN PI:LET c= SGN PI:LET c1= SGN PI:POKE VAL "23692", VAL "9":GO TO SGN PI 7000 PRINT AT VAL "9", VAL "8";"END OF PROGRAM" ```