X7$ ?BOOT-U-No boot on volume ߋtv @ƎHkQ?O$ kQO$SRT11A DECRT11A ۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m; 9'3'T'3'Cy'3''}63''}[ 3''}23''}v33'28~3'28^73'Iq 3'?3'^ 3'Iq ļ 3'Iq Ľ 3'۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m۶m  @ƎMICROVMS MICROVMS04 SYSTEM DECFILE11B s ~ MICROVMS.[SYS0.SYSEXE]LINK.EXE;1~;1 MICROVMS.NBACKUP/VERIFY _DUB0: _DUA1:[000000]MICROVMS/SAVESET/IMAGE/INTERCHANGE/NOREWIND SYSTEM @ƎY4.4 _::  _DUA1: V4.4 ~   |P1;0;1;0;0;0{ @????????/????????;???}????/???A????;?M??M???/????????;g}gg}g??/?B??B???;GSS}SS_?/?@@B@@??;CIcOGcA?/A@??@A@?;kQQQk?_?/@AAAA@A?;??GEA???/????????;??wCA???/???@A???;??ACw???/??A@????;OSwOwSO?/?@???@??;OOO{OOO?/???@????;????????/?CB@????;OOOOOOO?/????????;????????/??BB????;??_OGCA?/A@??????;wCAAACw?/?@AAA@??;?GC}????/?AABAA??;CaaQQQK?/BAAAAAA?;AAAQYUa?/@AAAAA@?;_ogc}__?/????B???;]QIIIIq?/@AAAAA@?;wcQQQQ_?/@AAAAA@?;AAAaQIE?/??B?????;kQQQQQk?/@AAAAA@?;KQQQQI{?/?AAAA@??;??KK????/??BB????;??KK????/?CB@????;O?g?C?A?/????@?A?;ggggggg?/????????;A?C?g?O?/A?@?????;CAAqIIC?/???A????;{AQiiY{?/@AAAAA??;ogcacgo?/B?????B?;A}QQQQk?/ABAAAA@?;wCAAAAC?/?@AAAA@?;A}AAACw?/ABAAA@??;}QQQQAA?/BAAAAAA?;}QQQQAA?/B???????;wCAAaac?/?@AAAA@?;}OOOOO}?/B?????B?;?AA}AA??/?AABAA??;????A}A?/@AAAA@??;}OggCCA?/B???@@A?;}???????/BAAAAAA?;}CGOGC}?/B?????B?;}CGO_?}?/B????@B?;{AAAAA{?/@AAAAA@?;}QQQQQK?/B???????;{AAAaA{?/@AAAA@A?;}QQQqQK?/B????@A?;KQQQQQc?/@AAAAA@?;AAA}AAA?/???B????;}?????}?/@AAAAA@?;EW_?_WE?/??@A@???;}??o??}?/@A@?@A@?;ACgOgCA?/A@???@A?;ACGoGCA?/???B????;AAaQIEA?/ABAAAAA?;??}AAA??/??BAAA??;ACGO_???/?????@A?;?AAA}???/?AAAB???;OGCACGO?/????????;????????/AAAAAAA?;??AEG???/????????;?gggggo?/@AAAA@B?;}OGGGGo?/B@AAAA@?;oGGGGGO?/@AAAAAA?;oGGGGO}?/@AAAA@B?;ogggggo?/@AAAAA??;OO{QQAC?/??B?????;OggggOG?/DIIIIIC?;}OGGGGo?/B?????B?;??Gy????/?AABAA??;?????y??/EGGGGF??;}__OG???/B???@?A?;??A}????/??ABA???;wGO_OGo?/B??@??B?;wOGGGGo?/B?????B?;oGGGGGo?/@AAAAA@?;woGGGGo?/N?@@@@??;oGGGGow?/?@@@@?N?;GoOGGGO?/?B??????;Oggggg??/AAAAAA@?;GG}GG???/??@AA@??;w????w??/@AAAA@A?;W_???_W?/??@A@???;w??_??w?/@A@?@A@?;GO__OG??/A@??@A??;w???_w??/CHHHGF??;GGGggWG?/AABAAAA?;??OSiAA?/???@AAA?;???}????/???B????;AAiSO???/AAA@????;KAACGGE?/????????;P1;0;1;0;0;0{ @????????/????????;???y????/???B????;oGG{GGO?/@AAFAA@?;OO{QQAC?/ADB@@AA?;CIIqAAC?/???A????;acgogca?/???B????;CIIqAAC?/???A????;?SiiiQ??/?AAAA@??;CwgggwC?/@?????@?;wCqIICw?/@ACDDA@?;OiiiiY{?/AAAAAAA?;OgCQgCA?/??@A?@A?;CIIqAAC?/???A????;CIIqAAC?/???A????;CIIqAAC?/???A????;CIIqAAC?/???A????;?CIIIC??/????????;OOO{OOO?/AAABAAA?;?QXTTQ??/????????;?PPTTJ??/????????;CIIqAAC?/???A????;?w????w?/GF@AA@B?;K]QQ}Q}?/????B?B?;??WW????/????????;CIIqAAC?/???A????;??Q^O???/????????;[aaaaa[?/AAAAAAA?;ACgQCgO?/A@?A@???;C]_OGc??/A@CEDNC?;C]_Ogc??/A@?HKIH?;CIIqAAC?/???A????;?__Y????/@AAAAA@?;_ohdiq_?/B?????B?;_qidho_?/B?????B?;_qhdhq_?/B?????B?;_qhdiq`?/B?????B?;_pgcgp_?/B?????B?;_qlllq_?/B?????B?;wca}QQA?/B??BAAA?;wCAAAAC?/?@IIMA@?;{TTUUCC?/BAAAAAA?;{SUUTDC?/BAAAAAA?;{UTTTEC?/BAAAAAA?;{TSSSDC?/BAAAAAA?;?CD|EE??/?AABAA??;?EE|DC??/?AABAA??;?ED|DE??/?AABAA??;?DC{CD??/?AABAA??;CIIqAAC?/???A????;{EHPaA|?/B????@B?;wCDDEEw?/@AAAAA@?;wEEDDCw?/@AAAAA@?;wEDDDEw?/@AAAAA@?;yDDEEDw?/@AAAAA@?;wDCCCDw?/@AAAAA@?;{AA{QQA?/@AA@AAA?;{AaQIE|?/DBAAAA@?;{@@AA?{?/@AAAAA@?;{?AA@@{?/@AAAAA@?;{?A@A?{?/@AAAAA@?;{@???@{?/@AAAAA@?;CHO_OHC?/???B????;CIIqAAC?/???A????;wCQQQk??/F?@AAA@?;?giikko?/@AAAA@B?;?kkiigo?/@AAAA@B?;?ihhhio?/@AAAA@B?;?ihhiip?/@AAAA@B?;?igggio?/@AAAA@B?;?illlio?/@AAAA@B?;?ggoggo?/@AABAAA?;oGGGGGO?/@AIIMA@?;ogiikko?/@AAAAA??;okkiigo?/@AAAAA??;oihhhio?/@AAAAA??;oigggio?/@AAAAA??;?AI{C???/?AABAA??;?CKyA???/?AABAA??;?AHx@A??/?AABAA??;?AGw?A??/?AABAA??;CIIqAAC?/???A????;yPHIIHo?/B?????B?;oGIIKKo?/@AAAAA@?;oKKIIGo?/@AAAAA@?;oIHHHIo?/@AAAAA@?;qHHIIHo?/@AAAAA@?;oIGGGIo?/@AAAAA@?;oGGoggo?/@AABAAA?;oGGgWGs?/DABAAA@?;wAACCw??/@AAAA@A?;wCCAAw??/@AAAA@A?;wA@@@y??/@AAAA@A?;wA???y??/@AAAA@A?;wA??_y??/CHHHGF??;CIIqAAC?/???A????;P1;0;1;0;0;0{ @????????/????????;???}????/???A????;?M??M???/????????;g}gg}g??/?B??B???;GSS}SS_?/?@@B@@??;CIcOGcA?/A@??@A@?;kQQQk?_?/@AAAA@A?;??GEA???/????????;??wCA???/???@A???;??ACw???/??A@????;OSwOwSO?/?@???@??;OOO{OOO?/???@????;????????/?CB@????;OOOOOOO?/????????;????????/??BB????;??_OGCA?/A@??????;wCAAACw?/?@AAA@??;?GC}????/?AABAA??;CaaQQQK?/BAAAAAA?;AAAQYUa?/@AAAAA@?;_ogc}__?/????B???;]QIIIIq?/@AAAAA@?;wcQQQQ_?/@AAAAA@?;AAAaQIE?/??B?????;kQQQQQk?/@AAAAA@?;KQQQQI{?/?AAAA@??;??KK????/??BB????;??KK????/?CB@????;O?g?C?A?/????@?A?;ggggggg?/????????;A?C?g?O?/A?@?????;CAAqIIC?/???A????;{AQiiY{?/@AAAAA??;ogcacgo?/B?????B?;A}QQQQk?/ABAAAA@?;wCAAAAC?/?@AAAA@?;A}AAACw?/ABAAA@??;}QQQQAA?/BAAAAAA?;}QQQQAA?/B???????;wCAAaac?/?@AAAA@?;}OOOOO}?/B?????B?;?AA}AA??/?AABAA??;????A}A?/@AAAA@??;}OggCCA?/B???@@A?;}???????/BAAAAAA?;}CGOGC}?/B?????B?;}CGO_?}?/B????@B?;{AAAAA{?/@AAAAA@?;}QQQQQK?/B???????;{AAAaA{?/@AAAA@A?;}QQQqQK?/B????@A?;KQQQQQc?/@AAAAA@?;AAA}AAA?/???B????;}?????}?/@AAAAA@?;EW_?_WE?/??@A@???;}??o??}?/@A@?@A@?;ACgOgCA?/A@???@A?;ACGoGCA?/???B????;AAaQIEA?/ABAAAAA?;??}AAA??/??BAAA??;ACGO_???/?????@A?;?AAA}???/?AAAB???;OGCACGO?/????????;????????/????????;Ow{}{wO?/??@B@???;iS?i?Si?/A@?A?@A?;}Gg}___?/????N???;}IIa___?/???NAA??;[aaa__??/???NAAL?;}______?/???NAA??;?CIIIC??/????????;OOO{OOO?/AAABAAA?;}CGo}???/???NGGG?;EW_we__?/????N???;OOO^????/????????;OOOo????/???N????;???oOOOO/???N????;???^OOOO/????????;OOO~OOOO/???N????;@@@@@@@@/????????;CCCCCCCC/????????;OOOOOOOO/????????;????????/@@@@@@@@;????????/CCCCCCCC;???~OOOO/???N????;OOO~????/???N????;OOO^OOOO/????????;OOOoOOOO/???N????;???~????/???N????;O?g?C?A?/CCCCDCE?;A?C?g?O?/ECDCCCC?;GGwGGwG?/?A@??B??;gggwgki?/A@??????;OO{QQAC?/ADB@@AA?;???O????/????????; /***************************************************************************** font.c vt200 font generator v1.0 copywrite: Harold Z. Bencowitz Beaumont, Texas 21-mar-87 ****************************************************************************** description: font is a program written in whitesmith's C to allow one to easily create or alter downloadable fonts/character sets for vt200 series terminals. it will only run on a vt2**. it has only been tested on rt11 v5.3 and tsx+ v6.01 using a vt220. it can be used to edit a previous character set (stored as a disk file in a format which can be "typed" to download the font). the vt200 built-in dec character sets (ascii, special graphics, and multinational) are included as disk files to allow one to alter any or all of these characters to create new characters or character sets. one character at a time is edited while each pixel change is observed both at the normal size and double high/double wide. operating instructions: delete exit program F17 open a font file F18 close the current font file, save (exit) F20 close the current font file, discard (quit) PF1 open a new active character PF2 close the active character, save (exit) PF4 close the active character, discard (quit) up arrow move up one space down arrow move down one space right arrow move right one space left arrow move left one space select mark/unmark a cell remove unmark all cells only these keys are usable while the program is running unless the user is answering a prompt for a file name, a character, or a y/n answer in which case the entire keyboard is usable. while the program is running, there is always a current character set, either the default blank set, or a set loaded from a disk file. for comparison, the current set is displayed with the dec ascii, dec multinational, and dec special graphics sets. the operator must open an active character for editing. that character is then loaded (from the current set) into a grid. using the arrow keys (to move about the grid), the select key (to mark or unmark a dot), and the remove key (to remove all of the dots) one can create whatever character one wishes within the limits of a 8 by 10 cell. note that the top row, the bottom two rows, and the right column of dots are generally reserved for intercharacter spacing (the bottom ones are also used for descenders). each time a change is made, the active character is redisplayed in normal and double high/wide formats. the sixel string descibing the character is also displayed. when the editing of a character is complete, the active character must be closed by quitting (discard the changes) or exiting (save the character into the current set) before working on another character. at any time (unless an active character is open) the current character set can be closed by quitting (discard the changes) or exiting (save to a disk file). it can not be closed unless the active character is closed first. another current set can be loaded by specifying the name of an appropriate disk file whenever there is no current character set (only a null set). the disk file format includes escape sequences at the beginning and end so that the file can be downloaded to the terminal using a type command. the default (carriage return without entry) response to all prompts is abort command. thus there is no default input or output file name. however both the input and output files have the default file extension ".fnt". if one wishes to include use of downloaded character sets into a program, he may benefit from examining the c subroutines for downloading, designating, and selecting character sets which are included in vt.c my video routine library. limitations: the characters must be built manually by marking each dot. when answering prompts, the return or tab keys must be used not the enter key. the program has not been tested on a vt240 or vt241 or on any other versions of rt11 or tsx+. revision history: v1.0 completed march 21, 1987 installation/building: the distribution kit consists of font.c (source code, including this text, the only documentation), font.h (header file), vt.(c, obj) (video terminal library), hclib (c, obj) (my c library), ascii.fnt (font file for the dec ascii character set), decmul.fnt (font file for the dec multinational character set), and decspc.fnt (font file for the dec special graphics, ie vt100 line drawing set). implementation notes: character sets are designated as: g0 ascii g1 current downloaded set g2 multinational g3 dec special cfont[] is an array ([95][16]) containing the ascii version of the current font/character set. each of the 95 downlaodable characters is represented by a 16 character string which is the sixel code for a 8 wide by 10 high character cell. the active character is stored internally as an array ccells[8][10] where each represents one dot in the character of value YES or NO. ttt *****************************************************************************/ #include #include #include #define VERSION "v1.0" char achar[2] = { 0, 0 }; /* active character */ char ccells[8][10] = { 0 }; /* grid flags (dot off/on) */ char cfont[95][16] = { 0 }; /* sixel strings current set */ char save[18] = { 0 }; /* active character, last sixel */ char set1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz"; char set2[] = "0123456789!@#$%^&*()`~-_=+{}[];:'\"\\|,.?/<>"; int err_flag = NO; /* YES if error message displayed */ int cset_flag = NO; /* YES if a character set is open */ int xcur = 1; /* x and y grid coordiates of */ int ycur = 1; /* current position */ _main() { register int k, i = 0; int process(), vtclr(), screen(), istsx(), call_emt(), enter(); int ttflush(), vtscs(), move_cur(), vtttid(), vtesc(); unsigned int ijob; extern char cfont[][]; /* * set TSX singlechar mode, find terminal type */ if(istsx()) /* if running TSX+ */ i = call_emt(0152, 0, 'S'); /* set singlechar mode */ if(i < 0) { putstr(STDERR,"\nfont - unable to set singlechar mode\n",NULL); exit(); } i = vtttid(); /* get termianl type */ if(i != 200) { putstr(STDERR,"\nfont - illegal terminal type, not vt200\n",NULL); exit(); } /* * set terminal special mode, arrows to application mode */ ijob = JSW; JSW = ijob | 010000; vtesc("[?1h"); /* arrow key application mode */ /* * initialize current font */ for(i = 0; i < 95; i++) { for(k = 0; k < 16; k++) { cfont[i][k] = '?'; } } /* * initialize screen */ vtclr(2); /* clear screen */ screen(); /* make display */ move_cur(0, 0); /* home cursor */ ttflush(); /* * await keyboard input */ while(enter(&process)) /* respond to keyboard input */ ; /* * reset terminal and JSW */ JSW = ijob; /* reset JSW */ vtesc("[?1l"); /* arrow key movement mode */ vtclr(2); /* clear screen */ } /****************************************************************************/ int k_ocf() /* open a character set from a disk file */ { char fname[15]; register int c, i, k; int down_load(), getc(), vtmova(), vtmode(), vtmbox(); int vterln(), deftype(), dis_error(), vtebox(), move_cur(); FIO *fopen(), *fclose(), fpi; extern char achar[], set1[], set2[], cfont[][]; extern int cset_flag; /* * tests, active character or current set open? */ if(achar[0] != '\0' || cset_flag) { if(achar[0] != '\0') /* yes, active character */ dis_error("must close active character first"); else /* set currently open */ dis_error("must close current character set first"); return; } /* * get file name */ vtmova(6, 28); putstr(STDERR, "enter the input file name ", NULL); vtmode(8); vtmbox(6, 54, 14, ' '); i = vtebox(6, 54, 14, ' ', "s", fname, ""); vtmode(0); if(i < -1 || fname[0] == '\0') { dis_error("command aborted"); return; } deftype(fname, ".fnt"); /* * open file */ if(!fopen(&fpi, fname, READ)) { dis_error("unable to open file"); return; } /* * read in file */ vtmova(1, 55); putstr(STDERR, fname, NULL); i = getc(&fpi); c = getc(&fpi); if(i != '\033' || c != 'P') { /* is this the correct type of file */ dis_error("not a proper font file"); fclose(&fpi); return; } cset_flag = YES; while((c = getc(&fpi)) != '\n') ; /* burn up introducer string */ for(i = 0; i < 95; i++) { for(k = 0; k < 8; k++) cfont[i][k] = getc(&fpi); getc(&fpi); /* burn up / */ for(k = 8; k < 16; k++) cfont[i][k] = getc(&fpi); getc(&fpi); /* burn up ; */ getc(&fpi); /* burn up \n */ } fclose(&fpi); /* * download the character set */ down_load(); /* * erase prompt box, home cursor */ vtmova(6, 28); vterln(0); move_cur(0, 0); } /****************************************************************************/ int k_ccf(n) /* close (with/without saving to disk) the current font */ int n; { char nswer[2], fname[15]; static char s1[] = "P1;0;1;0;0;0\( @"; static char s2[] = "\\"; /* $\\ */ register int i, k; /* $P1;0;1;0;0;0\( @ */ int del_fnt(), move_cur(), vtmova(), vtmode(), vtmbox(), vtebox(); int ttflush(), vterln(), deftype(), dis_error(); FIO *fcreate(), *fclose(), fpo; extern char cfont[][], achar[]; extern int cset_flag; /* * tests, active char? current set open? */ if(achar[0] != '\0' || !cset_flag) { if(achar[0] != '\0') /* yes, active character */ dis_error("must close active character first"); else /* set currently open */ dis_error("no character set is open"); return; } /* * write font to disk */ if(n) { vtmova(6, 28); putstr(STDERR, "enter the output file name ", NULL); vtmode(8); vtmbox(6, 55, 14, ' '); i = vtebox(6, 55, 14, ' ', "s", fname, ""); vtmode(0); if(i < -1 || fname[0] == '\0') { dis_error("command aborted"); return; } deftype(fname, ".fnt"); if(fopen(&fpo, fname, READ)) { /* file with the same name? */ fclose(&fpo); vtmova(6, 28); vterln(0); putstr(STDERR,"do you wish to overwrite an existing file [y]?",NULL); vtmode(8); vtmbox(6, 76, 1, ' '); ttflush(); i = vtebox(6, 76, 1, ' ', "s", nswer, "y"); vtmode(0); if(i < -1 || nswer[0] == 'n' || nswer[0] == 'N') { dis_error("command aborted"); return; } } if(fcreate(&fpo, fname, WRITE)) { putf(&fpo, "%p", s1); putc(&fpo, '\n'); /**/ for(i = 0; i < 95; i++) { for(k = 0; k < 8; k++) { putc(&fpo, cfont[i][k]); } putc(&fpo, '/'); for(k = 8; k < 16; k++) { putc(&fpo, cfont[i][k]); } putc(&fpo, ';'); putc(&fpo, '\n'); /**/ } putf(&fpo, "%p", s2); fclose(&fpo); } } else { /* quit, discard set */ vtmova(6, 28); vterln(0); putstr(STDERR, "are you sure [y] ?", NULL); vtmode(8); vtmbox(6, 47, 1, ' '); ttflush(); i = vtebox(6, 47, 1, ' ', "s", nswer, "y"); vtmode(0); if(i < -1 || nswer[0] == 'n' || nswer[0] == 'N') { dis_error("command aborted"); return; } } cset_flag = NO; /* * initialize current font */ for(i = 0; i < 95; i++) { for(k = 0; k < 16; k++) { cfont[i][k] = '?'; } } /* * erase display of current font name, error line */ vtmova(1, 55); putstr(STDERR, " ", NULL); vtmova(6, 28); /* input/error line */ vterln(0); /* erase to end of line */ /* * download null font, home cursor */ del_fnt(); move_cur(0, 0); } /****************************************************************************/ int del_fnt() /* down load null font */ { static char s1[] = "P1;0;2;0;0;0\( @"; static char s2[] = ";\\"; static char s3[] = ";;;;;;;;;;;;;;;;;;;;;;;;"; /* $P1;0;1;0;0;0\( @ ;$\\ */ putstr(STDERR, s1, s3, s3, s3, s3, s2, NULL); } /****************************************************************************/ int down_load() /* download the entire current set */ { register int i, k; /* $P1;0;1;0;0;0\( @ */ static char s1[] = "P1;0;1;0;0;0\( @"; static char s2[] = "\\"; /* $\\ */ int putch(); extern char cfont[][]; putstr(STDERR, s1, NULL); for(i = 0; i < 95; i++) { for(k = 0; k < 8; k++) { putch(cfont[i][k]); } putch('/'); for(k = 8; k < 16; k++) { putch(cfont[i][k]); } putch(';'); } putch(-1); putstr(STDERR, s2, NULL); } /****************************************************************************/ int screen() /* initialize the screen */ { int del_fnt(), vtgrid(), vtdcs(), vtscs(), putstr(), vtmova(); extern char set1[], set2[], achar[]; /* * download null font */ del_fnt(); /* * designate character sets */ vtdcs(0, 'B'); vtdcs(1, '~'); vtdcs(2, '<'); vtdcs(3, '0'); /* * display program name and version number */ vtscs(0); /* ascii */ vtmova(1, 71); putstr(STDERR, "font", NULL); vtmova(1, 77); putstr(STDERR, VERSION, NULL); /* * make grid */ vtgrid(1, 0, 2, 1, 8, 10); /* * display character sets */ vtmova(13, 28); putstr(STDERR, set1, NULL); vtmova(14, 28); putstr(STDERR, set2, NULL); vtscs(1); /* downloaded character set */ vtmova(10, 28); putstr(STDERR, set1, NULL); vtmova(11, 28); putstr(STDERR, set2, NULL); vtscs(2); /* dec multinational */ vtmova(16, 28); putstr(STDERR, set1, NULL); vtmova(17, 28); putstr(STDERR, set2, NULL); vtscs(3); /* dec special graphics */ vtmova(19, 28); putstr(STDERR, set1, NULL); vtmova(20, 28); putstr(STDERR, set2, NULL); vtscs(0); /* * legend for double sized display of the active character */ vtmova(22, 0); putstr(STDERR, "current ascii multinat dec spc", NULL); } /****************************************************************************/ int k_cchar(n) /* close active character (with/without saving) */ int n; { char s0[18]; register int i, k, t; int dis_error(), move_cur(), vtdown(), c_to_s(), vtmova(), vterln(); extern char save[], set1[], set2[], cfont[][], achar[]; extern int cset_flag; /* * test is a character is active */ if(achar[0] == '\0') { dis_error("no active character is open"); return; } /* * erase display of current character */ vtmova(8, 28); vterln(0); /* erase to end of line */ vtmova(22, 60); /* erase sixel string */ vtclr(0); /* and double characters */ /* * if saving active character, download to current set */ if(n) { t = achar[0] - 32; c_to_s(s0); vtdown(achar[0], s0); /* download character */ cset_flag = YES; /* flag char set is open */ for(k = 0, i = 0; i < 8; i++) cfont[t][k++] = s0[i]; for(i = 9; i < 17; i++) cfont[t][k++] = s0[i]; } else /* restore the character */ vtdown(achar[0], save); /* download character */ /* * declare that no character is active */ achar[0] = '\0'; /* * erase character cell array */ for(i = 0; i < 8; i++) { for(k = 0; k < 10; k++) { if(ccells[i][k] == YES) { move_cur(i, k); putstr(STDERR, " ", NULL); ccells[i][k] = NO; } } } /* * home cursor */ move_cur(0, 0); } /****************************************************************************/ int k_ochar() /* select (open) an active character */ { char s0[18], si[3]; register int i, k, mask; int x, t; int vterln(), vtmode(), vtebox(), vtdouble(), vtscs(), move_cur(); int c_to_s(), dis_error(), vtmbox(), vtmova(); extern char save[], ccells[][], cfont[][], achar[]; /* * test if a character is already open */ if(achar[0] != '\0') { dis_error("must close active character first"); return; } /* * get character */ vtmova(6, 28); putstr(STDERR, "enter a character ", NULL); vtmode(8); vtmbox(6, 46, 2, ' '); i = vtebox(6, 46, 2, ' ', "s", si, ""); vtmode(0); if(i < -1 || si[0] < 32 || si[0] > 126) { dis_error("command aborted"); return; } achar[0] = si[0]; t = achar[0] - 32; /* * save sixel string */ for(i = 0; i < 8; i++) save[i] = cfont[t][i]; save[8] = '/'; for(i = 8; i < 16; i++) save[i + 1] = cfont[t][i]; save[17] = '\0'; /* * read sixel string into ccells and mark dots on grid */ for(i = 0; i < 8; i++) { x = cfont[t][i] - 63; for(k = 0; k < 6; k++) { mask = 1 << k; if(x & mask) { ccells[i][k] = YES; vtscs(3); move_cur(i, k); putstr(STDERR, "aa", NULL); vtscs(0); } else ccells[i][k] = NO; } } for(i = 0; i < 8; i++) { x = cfont[t][i + 8] - 63; for(k = 6; k < 10; k++) { mask = 1 << (k - 6); if(x & mask) { ccells[i][k] = YES; vtscs(3); move_cur(i, k); putstr(STDERR, "aa", NULL); vtscs(0); } else ccells[i][k] = NO; } } /* * display the character sixel string */ c_to_s(s0); vtmova(22, 60); putstr(STDERR, s0, NULL); /* * display active character */ vtmova(6, 28); /* input/error line */ vterln(0); /* erase to end of line */ vtmova(8, 28); errfmt("the active character is %oi octal %i decimal ",\ achar[0], achar[0]); /* * display the character */ vtmode(8); vtscs(1); putstr(STDERR, achar, NULL); movr(); vtscs(0); putstr(STDERR, achar, NULL); movr(); vtscs(2); putstr(STDERR, achar, NULL); movr(); vtscs(3); putstr(STDERR, achar, NULL); vtmode(0); /* * display active character, double high and wide */ i = 5; vtscs(1); vtdouble(23, i++, 0, achar); /* current font */ vtscs(0); vtdouble(23, i++, 0, achar); /* ASCII */ vtscs(2); vtdouble(23, i++, 0, achar); /* multinational */ vtscs(3); vtdouble(23, i, 0, achar); /* DEC special */ vtscs(0); move_cur(0, 0); } /****************************************************************************/ int c_to_s(s) /* convert the cell array into sixel string */ char *s; { int x; register int i, k, mask; extern char ccells[][]; for(i = 0; i < 8; i++) { x = 0; for(k = 0; k < 6; k++) { if(ccells[i][k] == YES) { mask = 1 << k; x |= mask; } } s[i] = x + 63; } s[8] = '/'; for(i = 0; i < 8; i++) { x = 0; for(k = 6; k < 10; k++) { if(ccells[i][k] == YES) { mask = 1 << (k - 6); x |= mask; } } s[i + 9] = x + 63; } s[17] = '\0'; } /****************************************************************************/ int update() /* update active character */ { char s0[18]; int c_to_s(), vtdown(), vtmova(), move_cur(); extern char achar[]; extern int xcur, ycur; /* * convert ccell to ascii, put it out ie download */ c_to_s(s0); /* * display the character */ vtdown(achar[0], s0); /* * display the character sixel string */ vtmova(22, 60); putstr(STDERR, s0, NULL); move_cur(xcur, ycur); } /****************************************************************************/ int k_remove() /* blank out the entire character */ { register int i, k; int tx, ty; int dis_error(), update(), move_cur(); extern char achar[], ccells[][]; extern int xcur, ycur; /* * test for active character */ if(achar[0] == '\0') { dis_error("no active character is open"); return; } /* * */ tx = xcur; ty = ycur; for(i = 0; i < 8; i++) { for(k = 0; k < 10; k++) { if(ccells[i][k] == YES) { ccells[i][k] = NO; move_cur(i, k); putstr(STDERR, " ", NULL); } } } update(); move_cur(tx, ty); } /****************************************************************************/ int k_mark() { int dis_error(), update(), vtscs(); extern char achar[], ccells[][]; extern int xcur, ycur; if(achar[0] == '\0') { dis_error("no active character is open"); return; } if(ccells[xcur][ycur] == NO) { ccells[xcur][ycur] = YES; vtscs(3); putstr(STDERR, "aa", NULL); vtscs(0); } else { ccells[xcur][ycur] = NO; putstr(STDERR, " ", NULL); } update(); } /****************************************************************************/ int move_cur(x, y) /* move the cursor to the absolute x-y coordinate of a box in the grid */ int x, y; { int vtmova(); extern int xcur, ycur; xcur = x; ycur = y; vtmova(2 * ++y, 3 * ++x); } /****************************************************************************/ int k_down() /* move the cursor down */ { int dis_error(), update(), move_cur(); extern char achar[]; extern int xcur, ycur; if(achar[0] == '\0') { dis_error("no active character is open"); return; } if(ycur >= 9) return; move_cur(xcur, ++ycur); update(); } /****************************************************************************/ int k_up() /* move the cursor up */ { int dis_error(), update(), move_cur(); extern int xcur, ycur; extern char achar[]; if(achar[0] == '\0') { dis_error("no active character is open"); return; } if(ycur <= 0) return; move_cur(xcur, --ycur); update(); } /****************************************************************************/ int k_right() /* move the cursor right */ { int dis_error(), update(), move_cur(); extern int ycur, xcur; extern char achar[]; if(achar[0] == '\0') { dis_error("no active character is open"); return; } if(xcur >= 7) return; move_cur(++xcur, ycur); update(); } /****************************************************************************/ int k_left() /* move the cursor left */ { int dis_error(), update(), move_cur(); extern int ycur, xcur; extern char achar[]; if(achar[0] == '\0') { dis_error("no active character is open"); return; } if(xcur <= 0) return; move_cur(--xcur, ycur); update(); } /****************************************************************************/ int vtesc(s) /* output string s to STDERR preceded by . */ char *s; { int putstr(); putstr(STDERR, "", s, NULL); } /****************************************************************************/ int key() /* get input from one keyboard key. returns code value. */ { char c, cc[2], cget(); int code; /* * */ if((c = cget()) != ESCAPE) switch (c) { case '\177': code = DELETE; break; default: return(ERROR); } else if((c = cget()) == 'O') { /* SS3 introducer */ c = cget(); switch (c) { case 'A': /* arrows */ code = UP; break; case 'B': code = DOWN; break; case 'C': code = RIGHT; break; case 'D': code = LEFT; break; case 'P': code = PF1; break; case 'Q': code = PF2; break; case 'S': code = PF4; break; default: return(ERROR); } } else if(c == '[') { /* CSI introducer */ cc[0] = cget(); if((cc[1] = cget()) == '~') /* editing keys */ switch (cc[0]) { /* editing keys (VT200) */ case '3': code = REMOVE; break; case '4': code = SELECT; break; default: return(ERROR); } else { /* function keys */ c = cget(); if(cc[0] == '3') { switch (cc[1]) { case '1': code = F17; break; case '2': code = F18; break; case '4': code = F20; break; default: return(ERROR); } } } } return(code); } /****************************************************************************/ int dis_error(s) /* display error message */ char *s; { int vterln(), vtmova(), vtmode(); extern int ycur, xcur, err_flag; err_flag = YES; vtmova(6, 28); vterln(0); vtmode(8); putstr(STDERR, "", s, NULL); vtmode(0); move_cur(xcur, ycur); } /****************************************************************************/ int deftype(file_name, file_ext) /* if a filename string does not contain '.' (no file extension is present) a file extension (file_ext) is added. returns 0 if no change, +2 if file extension added. */ char file_name[], file_ext[]; { char *cpystr(); register int ret = 0, i; /* * add file extension */ for(i = 0; file_name[i] != '\0'; i++) { if(file_name[i] == '.') /* if '.' found, no add ext */ return(0); } file_ext[4] = '\0'; /* extension only 4 char */ cpystr(file_name, file_name, file_ext, NULL); /* add file ext */ return(2); } /****************************************************************************/ int movr() /* move cursor one column to the right */ { static char s[] = ""; /* $[1C */ putstr(STDERR, s, NULL); } /****************************************************************************/ int process() /* process the responses to keystrokes */ { int code; int move_cur(), vtmova(), vterln(), key(), leave(); int k_remove(), k_mark(), k_up(), k_down(), k_right(), k_left(); int k_ocf(), dis_error(), k_ccf(), k_ochar(), k_cchar(); extern int err_flag; FOREVER { code = key(); if(err_flag) { vtmova(6, 28); /* input/error line */ vterln(0); /* erase to end of line */ move_cur(0, 0); err_flag = NO; } if(code == DELETE) leave(NO); else if(code == PF1) k_ochar(); else if(code == PF2) k_cchar(YES); else if(code == PF4) k_cchar(NO); else if(code == F17) k_ocf(); else if(code == F18) k_ccf(YES); else if(code == F20) k_ccf(NO); else if(code == UP) k_up(); else if(code == DOWN) k_down(); else if(code == RIGHT) k_right(); else if(code == LEFT) k_left(); else if(code == SELECT) k_mark(); else if(code == REMOVE) k_remove(); else dis_error("illegal key"); } } /***************************************************************************** font.c vt200 font generator v1.0 copywrite: Harold Z. Bencowitz Beaumont, Texas 21-mar-87 ****************************************************************************** description: font is a program written in whitesmith's C to allow one to easily create or alter downloadable fonts/character sets for vt200 series terminals. it will only run on a vt2**. it has only been tested on rt11 v5.3 and tsx+ v6.01 using a vt220. it can be used to edit a previous character set (stored as a disk file in a format which can be "typed" to download the font). the vt200 built-in dec character sets (ascii, special graphics, and multinational) are included as disk files to allow one to alter any or all of these characters to create new characters or character sets. one character at a time is edited while each pixel change is observed both at the normal size and double high/double wide. operating instructions: delete exit program F17 open a font file F18 close the current font file, save (exit) F20 close the current font file, discard (quit) PF1 open a new active character PF2 close the active character, save (exit) PF4 close the active character, discard (quit) up arrow move up one space down arrow move down one space right arrow move right one space left arrow move left one space select mark/unmark a cell remove unmark all cells only these keys are usable while the program is running unless the user is answering a prompt for a file name, a character, or a y/n answer in which case the entire keyboard is usable. while the program is running, there is always a current character set, either the default blank set, or a set loaded from a disk file. for comparison, the current set is displayed with the dec ascii, dec multinational, and dec special graphics sets. the operator must open an active character for editing. that character is then loaded (from the current set) into a grid. using the arrow keys (to move about the grid), the select key (to mark or unmark a dot), and the remove key (to remove all of the dots) one can create whatever character one wishes within the limits of a 8 by 10 cell. note that the top row, the bottom two rows, and the right column of dots are generally reserved for intercharacter spacing (the bottom ones are also used for descenders). each time a change is made, the active character is redisplayed in normal and double high/wide formats. the sixel string descibing the character is also displayed. when the editing of a character is complete, the active character must be closed by quitting (discard the changes) or exiting (save the character into the current set) before working on another character. at any time (unless an active character is open) the current character set can be closed by quitting (discard the changes) or exiting (save to a disk file). it can not be closed unless the active character is closed first. another current set can be loaded by specifying the name of an appropriate disk file whenever there is no current character set (only a null set). the disk file format includes escape sequences at the beginning and end so that the file can be downloaded to the terminal using a type command. the default (carriage return without entry) response to all prompts is abort command. thus there is no default input or output file name. however both the input and output files have the default file extension ".fnt". if one wishes to include use of downloaded character sets into a program, he may benefit from examining the c subroutines for downloading, designating, and selecting character sets which are included in vt.c my video routine library. limitations: the characters must be built manually by marking each dot. when answering prompts, the return or tab keys must be used not the enter key. the program has not been tested on a vt240 or vt241 or on any other versions of rt11 or tsx+. revision history: v1.0 completed march 21, 1987 installation/building: the distribution kit consists of font.c (source code, including this text, the only documentation), font.h (header file), vt.(c, obj) (video terminal library), hclib (c, obj) (my c library), ascii.fnt (font file for the dec ascii character set), decmul.fnt (font file for the dec multinational character set), and decspc.fnt (font file for the dec special graphics, ie vt100 line drawing set). implementation notes: character sets are designated as: g0 ascii g1 current downloaded set g2 multinational g3 dec special cfont[] is an array ([95][16]) containing the ascii version of the current font/character set. each of the 95 downlaodable characters is represented by a 16 character string which is the sixel code for a 8 wide by 10 high character cell. the active character is stored internally as an array ccells[8][10] where each represents one dot in the character of value YES or NO. /* * header for hp41c */ #define ERROR -1 /* * key codes */ #define DELETE 22 #define PF1 23 #define PF2 24 #define PF3 25 #define PF4 26 #define UP 28 #define DOWN 29 #define LEFT 30 #define RIGHT 31 #define ENTER 45 #define F17 57 #define F18 58 #define F19 59 #define F20 60 #define FIND 61 #define INSERT 62 #define REMOVE 63 #define SELECT 64 #define PREVIOUS 65 #define NEXT 66 e -VVU@ & #w <"  ! S& j !%  \ :&% # `  \ &% #$@U7\ j _  !Wpa?,V  B | &  | "  w\  wr!w `!ePJ QDJB}] A &  :] R%% X 6 e7]Na8] 6 Fe    V] '] w "]Na   NaNa (#% ] ^7 d  Na $%Ne .#Ne "# !P \ Ne "ONe "!  _ *Wp`@e,V5Ne "= Ne !     & 6 wNe z"Õ Wp`@e,V5Ne T"= Ne B"Ne 8" w VeFH N:HE^ D B   K^ B#% H 7 eH^NaI^ 7 6e  !WZSh^ R    ] "%  / be ]Na] / e  t!wWnwWNww8^ w3^Na *  NaNa | % KNe     ^ !%  L e ^Na^ L e  !>Wn:WN6NaNa % l]]Na $!% Na p  !_ $Wp`@,VNa F ] U]]Na %Ne ./Na  • Wp`@,VNa  ;Na   Na  7 L !_ 0Wp`?,V ]  w07   ] 4 %     & j  f  ^^^^^^ eww  ^ % !_ Wp`@,V h  \ ^ %wd/ @•  Wp`@,V $ ;  f <B&  ~ x < j 0 \  G   _ %M    _ % &  e  h  .\ % J  d\ v%  $  .\ P%   d\ 2%   .\ %  d\ %   .\ % ~  d\ % N  \  ^ %wjw Pe@B_  wH  0 <  +BeNe VNeA&  H  !>Wp@e,V @`AeaH \A& b 7A !5 8Wp `WU2&   _ %Wp `1Uĕ !Wp@e,V @`AeaH  &  w0  w eA_ E  |_ %   . ey_Naz_ . e  !W W~i_ Vwwf@b@e5 ! AWpat,V\ /Fĕ! AWpat,V\ 7iF !2AWpa@,Ve5 bt0]Wp `U & R  e_ % G !EAWpa@4Ve5• wet0wWp `U 2 &   a_ n%  w Wp `1U Ne t<  Na &%   >>&3_ <%   U %  n  U %  R  U %  6  U |% ĕ  U& &  e U& &  e U& &  e U& & e  & F w wWp `1U ww   !5  1Wp `WU3tP,@/ !%5 • $Wp `WU'etP@aAe?H  @0w@aAe?p  feNe 4Ne<&  <   Na %TCNC  ww e~<_ Z3(C$C !  'Wp `WU!Wp `1U&  _ X%  :Nf w  f ;_ :BWp @eUmBȋBWp @eUm~Bȕ  _ % TBWp @eUmHB _ % wf w BwB AWpN f > w\f 4;_ -A w: AAA &f :`  Aw AAA b f :.` -lAwbA \AXA ( f :J` d 2Aw*A $A A |f  ff` xewXfe 5W@h`w< ~5WO n5@p`w@wW[ :5 25W~&@`w 5W3@`wx?@9:<f ?    8 f` e ?? X ww   @`ȋ@`. @0 fff few f  ` %w|fe 5 ? 6  F & 7 >W- W- W- W- W-9 ~W-: vW-< fW- W- ^W- W- W-@ rW-? ` @w \D !ĕe07 B ` `%w:f W- W-PwNf  W- ` % f  %-W-* ` % f  %N f   ` % f  %  ` % ` z% f  j%N f   ` H% ` 8% f  (%w D !ĕe07@ ` %w w D• !  ` % w 5  1` ;`5  4` ;`5  5` ;`5  7` ;`m`2` ` @%w DBÕ !  Pw `` e` ;```` e` H`3` ` %f W-$W-~`@m7u?wp? ` x%`@m7Z? a Z%w< fe W-*W- 5 5W-no Na %w w e  @al  5!+ @aq @e`k@e`  @axX  5!, @a X  @aw @eX`  @at  5!3 @aq  @axX @e`u@e`  @am  5!P @aq  @an @e`j@e`0& Nf  J  Na t %   5! 4Nf    XNa @ %  @av Nf  Na %B& J w@  Nf   Na % w eaW-W- W-W-PwlW-@@m QQ@5 u WiWdWs WnWu  S& j %5Nf N   )@p fff  e5!@ Nmf p  fNa B%ښ@U7 5W- W-W- W-9 5W-[w 5W-CC m kwD @@ 5Wsw@ea Naf %@wW-o m @-o@@aAeAmp W-D & $W-A W-BW-2 5W-4  5W-~ @ @m5@p Nf Naff jeNf w%0W-98 W-+W--  WnWu"W-.WdW--WnW- wW-~w Wsw 5B- @@aAeAmp  @ap 5!w5 u- @e@mAAaH  w wWn@ea Naf %@-Wi Na&Na eWu %Na&Na pe$u= @wh Na&Na @eN a a &e@u=@w DBW-W-!!Pwa QP f  N a & w e  @U7   3   a % 5W-cW-Z  @e`H WW/ W-ZwV4wW?W6 W2w0WW[W?w W1W2 }W4W;W0e W1W7d W6W2 wdf w BeD !^ 5J!  r  @ae0pWp D @ae0p@e` $a % Na % )a % f % 5a %ww  @55= wnfw5w555&  @a@awFw ,eBC! @ bb@ be K @    5u5 ww @wfU@wwfeNa& % @Ewf  wpf Nf f f@t&Nm ew@w &B@eˋҔ we@&& HBFw DBC 4-  @wfeuu5 Ne fNa, e@w33EI3UI EUw 2DB        wfeuuNe fNa- Rewf  Va& h% N  *3wf w3Va&  wf Nefp@ ewv2 .     22w $D ra& 6 na - -e a& \%4 c&   j  ww  W-@&f % N&f &% wtw b W-@&f % N&f % w4w "D ra& 4 e4&& L%4 a&   Eww Dʋ ww DB ra&  -  a a& z % -w6a& J %4 f Na b w f NeffZ> Jeww @e  &f %eww N $05C #   C - . EE  %@w6 ע עע @  @ 50@ EE2 r El2 E@2 2 /5K <  vf&e e5W-  2 @  w w  e r      yYw DBCnN e w ̥09Wp `@e  w e @ef %5wZ5 D̋ %    ̋ @@  !5 w@ef %5w @   ʥw  -05 5 0 @ef %5  @wX  ʥ + 5 Ne Na& <%5 . Ne Naa %a hou 5Wh5Wo u *u-@@5 @`  Bmu . =:   ʥ  ʥ  5@w@` 5 u x`bp 3u-@@5'lNWaQ5 5 \@Av5u 5PuPuu Nf %p @ @me e @ e xe 5wd#f0NNaf e5 @@ e QQ Nef 0%5 @wc*i's$5 d@ e QQQQ @ e Na& B Wa!5 .@t@P5  HLE@ @ 5wNNaf l e5 @c @ e x@ e x cwiwswv wp@wf %  AWp@ecw`w FN 5 w(5 e 2   @w DBCnN e w ̥09Wp `@e  w eDˋ ע%  !&f %Ӌw^ ע-5 ע+ Ne Na 0%5 ע. Ne Na` %עa עhעoעu Wh•5Wo• Wu• עx5 wעb @ e 5@ e 5 wTu-@@5w:עp@ e 5N t5 wu-@@5wעf%@e5NN@ &&&&Na e 5@ e5 wעd+@e5%@@ &&&&Na ,e 5@ e5 wJעcעs עiעl'%עl(Wa>@ 55 M@e@mH@Av5ui@e5@ e 5Wa4עc4uO@e5@ &&Na e5@ e5 4@e5@ e5 % @t5uעcEEfNa %5 u- Naf %  Nff % wLu-w@Naf % f Nf %ww z$  a& %#w^w FDB ra& T L4  & & f e 4  x#7r# p#d= 7b#ww Nff H%5 c& wf N& f %ww DB ra& DC em5 '-#@ -$ !a a& :%4  a& %4 @w   \"%   GB" e@"  ,@ & 5a &f!e "e ! FIw D5EE  E `   & vf&e 8e ww n N 45C 'ע 7  $52C 6ע 7c % ` @w   d  P Nf \%@ĕ5!a   .%`5w tDB` 3e wZw HDce e `w0w Nf  d& " ww eD! Eec e! " !!e  se)-d!7 Z!5 7!R!L!N 57 6! 5N 5  w<@e= !w- w @@m- @@m7  fe  w @e 7! - c!d& @w 4 7 7!z t 7n  6b   2  4 2 w @eDB5 5 55  ̥  -    R+ W- 0% AW- =%:07A Ze  x%e %A Ze  x e ̥009-e/ @A  @Af>e^ F̥AZe  l8 6̥azfff \  ee@ 5u ̥AZ̥AZe eC- @w|w jeDB 55  ̥  -    R+ W- 0% AW- =%:07A Ze  x%e %A Ze  x e ̥0$9!e5"  = :̥AZe  l, *̥a z up AmC ̥AZ̥AZe e5u- @ww  !  r ww eD Wp@c5% ̋ wWp@ec5:̋ : Nf 5 c 5D5.̋ Nf 5Nefe 5.5  5̋ Nf 5NeNa $%   f b Na %   Na&e %5@wJ Na& %5W- @ W-  & Na&e e5@3   33 3  3  A v   3s G J7tw rDBC  @wbw PeDC  EE   9@w EE4 t E@4 Em4 J G Ȕe t   e@ EE5u EE@A  & vf&e e  w44 w&fHp    w D ̋ʋ w& &%f  c N N c  wrw XN 5& tt W-  tmtm t  @mAm@ 4t @ww eD@Av @A  5uҕ-   @ 5 u @Av @A@A N ffff & Ve`ffff Ne0@ Jʥ9e'  ww D   @ 5ӕ-@E   @ 5B- N 5r& %` 5r@e0 ˥9e'  ww neDC5 ע ˥  ע-#  745 ˥0ע957e@5 ע+  ע. ˥0ע957e@5  ˥AעZe  e  Na& e`Bm5& e5 55=@wNw [?1l[?1h font - illegal terminal type, not vt200  font - unable to set singlechar mode not a proper font fileunable to open file.fntcommand abortedsenter the input file name must close current character set firstmust close active character firstP1;0;1;0;0;0{ @\ command abortedysare you sure [y] ?%p%pcommand abortedysdo you wish to overwrite an existing file [y]?.fntcommand abortedsenter the output file name no character set is openmust close active character firstP1;0;2;0;0;0{ @;\;;;;;;;;;;;;;;;;;;;;;;;;P1;0;1;0;0;0{ @\current ascii multinat dec spcv1.0font no active character is openthe active character is %oi octal %i decimal aaaacommand abortedsenter a character must close active character first no active character is open aano active character is openno active character is openno active character is openno active character is openno active character is open^SVQNPFD>C6B,Af43421illegal key#3#4#6[ p;pppH%i%ixx()*+x @%d%ui0%ui%i%- nb%aiZP1;;1;0;0;0{ @\ eXabad leave call.taNULL FIO pointeraunchecked conditionaread error cwrite errorbad free callDK :  @ BCG@M [u+pdno memoryeerror /* hclib.c ****************************************************************************** DIRECTORY accept get variable values from STDIN, as if fortran ACCEPT aloadb loads buffer with binary array (as leading low-byte strings) alpho compare two strings for alphabetical order amod returns remainder from division of two doubles aunload unload buffer to list of variables including arrays bclose | =close file bcreate| =create a new file for buffered block output bopen |bio =open file for buffered block output bread | =read buffer from file in blocks bwrite | =write buffer to file in blocks btof convert buffer to float cacept get character variable values from STDIN (accept for char) *callc =macro routine calls c routine from fortran (not in hclib.obj) call_emt =call emt375 center_text center a string cget get character from STDIN without waiting for \n date =return the date datest =return system date as a "dd-mmm-yy" string define_file| =open or create binary direct access file dread |dio =read a record from a binary direct access file dwrite | =write a record to a binary direct access file defname insert default filename and/or filename extension delay =delay given number of seconds dtols convert double to leading low-byte string errext type error message and exit ftols convert float to leading low-byte string ftor50 convert ascii string filename to RADIX-50 getln get line of input from a file getword get one word from a file greet type greeting message at beginning of program *istsx =returns 1 if TSX+, 0 if rt11 or TSX version < 5 *limits =returns limits of available system memory loadbf loads buffer with binary data (as leading low-byte strings) lstod convert leading low-byte string to double lstof convert leading low-byte string to float month string of month name nint nearest integer option =was option specified on call to rt11 csi password =get password, exit if incorrect pause type message and pause until pflush empty printer output buffer putln put line of input to a file putword put word to a file rename =rename a file *rng =random number generator rtcsi =call the rt11 csi *maccsi =issue .csispc emt and pop options off the stack,used by rtcsi r50tof convert RADIX-50 filename to ascii string shell shell sort *swap_byte =swap the bytes of an integer stopcc =disable (and restore) control-C substi substitute one substring for another substring tics =elapsed time in tics since the last call time =return time of day timest return system time as a "hh-mm-ss" string *ttflush =flush rt11 input ring buffer ungetc unget a character unload unload buffer to list of variables unrad convert RADIX-50 integer to three ascii characters transcendental functions dabs absolute value of double darctan(x) arctangent x dcos(x) cosine x subcos used by dsin and dcos dexp(x) e to the x power (antiloge) d10exp(x) 10 to the x power (antilog10) dloge(x) natural logarithm (base e) x dlog10(x) logarithm (base 10) x dpower(y,x) y to the x power droot(x,y) x root y dsin(x) sine x subsin used by dsin and dcos dsqrt(x) square root x dtento(x,i) x times 10 to the i power (whitesmiths) fabs absolute value of float iabs absolute value of integer polynm calculate polynomial, used by transcendental functions power(x, i) x to the i power, used by transcendental functions * these routines are macros at least in part and require editing of *.mac code. they are also contained in hclib2.C and hclib2.mac. = these routines are rt11 dependent and thus non-portable installation instructions (for starting from scratch): hclib sources are gathered in 2 files: hclib.c which contains this directory and source code for all routines and hclib2.c which contains source code for istsx, limits, maccsi, rng, and swap_byte. these routines in hclib2.c are also in hclib.c (inactivated as comments) just to have everything in one place. hclib2.mac must be edited prior to assembly. run c hclib2 !contains limits, maccsi, rng, istsx, and swap_byte, !stop before assembly edit hclib2.mac !makes changes as per comments with source code macro hclib2 hclib.c must then be copied into individual *.c files names with the first 6 characters of the routine name. three files contain more than one subroutine. DIO has define_file, dread, dwrite, and the external definitions they use. BIO has bcreate, bclose, bopen, bread, and bwrite. DSINCO has dsin, dcos, sinsub, and cossub. use hclib.bat to compile all of these modules. use @hclib.bld to build them into library hclib.obj. installation instructions for a new routine (not macro): copy *.c source code module to this disk. add include statements to module update directory in hclib.c. add source code to hclib.c (positioned in alphabetical order). add module name to hclib.bld. run c * (thru macro, not link) library/insert hclib * *****************************************************************************/ #include #include /****************************************************************************/ int accept(s, t, add1) /* accepts data from STDIN in manner similar to FORTRAN IV ACCEPT statement. s is string typed as a prompt. t is a string indicating how to convert the data. it only uses i, f, and d. any number and combination of variables can be used. returns the number of variables accepted. if too many are entered they are ignored, if too few 0 is entered. exponents are ok with f or d. */ char *s; /* prompt string */ char *t; /* "format" string */ unsigned add1; /* first argument, an address */ { #define IBUFSIZE 90 register int nc, *p; /* p is pointer to next address */ int *pi; float *pf; double *pd; /* pointers to output variables */ char buff[IBUFSIZE], *pbuff; /* input buffer and pointer to it */ int i, nchars, n_variables = 0; BYTES btod(), btoi(), inbuf(), notbuf(), getlin(); double tempd; /* temporary double for float input */ errfmt(s); /* type prompt */ nchars = getlin(buff, IBUFSIZE); /* get input line */ while((i = inbuf(buff, nchars, ",")) < nchars) buff[i] = ' '; /* change ',' to ' ' */ while((i = notbuf(buff, nchars, " 0123456789.eE+-@")) < nchars) buff[i] = '@'; /* change bad chars to '@' */ nchars = squeeze(buff, nchars, '@'); /* remove all '@' */ pbuff = buff; /* pbuff points at bottom of buff */ p = &add1; /* point p at top of argument stack */ while(*t) { /* read the 'format' string */ switch(*t++) { case 'i' : /* integer */ if(nchars <= 0) { /* if no more text return 0 */ pi = *p++; *pi = 0; break; } nc = btoi(pbuff, nchars, *p++, 10); pbuff += nc; nchars -= nc; n_variables++; break; case 'f' : /* float */ pf = *p++; if(nchars <= 0) { *pf = 0.; break; } nc = btod(pbuff, nchars, &tempd); *pf = (float) tempd; pbuff += nc; nchars -= nc; n_variables++; break; case 'd' : /* double */ if(nchars <= 0) { pd = *p++; *pd = 0.; break; } nc = btod(pbuff, nchars, *p++); pbuff += nc; nchars -= nc; n_variables++; break; default : break; } } return(n_variables); } /****************************************************************************/ int *aloadb(s, topadd, wcnt, starta) /* loads wcnt 'integer' values from an array into the buffer starting at s. the buffer goes to a (top address + 1) of topadd. starta is the address of the first word of the array to load. char arrays can be done but must end on an even boundary. it returns the address for the next addition to buffer. */ register int *s; int *topadd; int wcnt; unsigned starta; { register int *p; /* pointer to next word to load */ char *itols(); p = starta; /* point p to start of array */ for( ; wcnt > 0; wcnt--) { if(s < topadd) itols(s++, *p++); else { errfmt("aloadb - attempt to over fill buffer\n"); return; } } return(s); } /****************************************************************************/ int alpho(s, t) /* compares two strings s and t as to alphabetic order. returns < 0 if s < t, 0 if they are equal, or > 0 if s > t. */ register char *s, *t; { for( ; *s == *t; s++, t++) { if(*s == '\0') return(0); } return(*s - *t); } /****************************************************************************/ double amod(x, y) /* returns the remainder of x divided by y */ double x, y; { return(x - (y * (int) (x / y))); } /****************************************************************************/ int *aunload(buffer, topadd, s, add1) /* unloads the buffer starting at buffer with a (top address + 1) of topadd into any combination and number of int, float, or double. char can not be done. add1 is the address of the first variable. it returns the next address to use (in buffer) unless there is an error in which case 0 is returned. s is a string indicating how to do the unload. i indicates int, f float, d double. all other non-numeric characters are ignored. a number preceding the i, f, or d indicates an array of this many variables */ register int *buffer; int *topadd; char *s; unsigned add1; { register int *p; /* pointer to next address */ char t[6], *message; int i, narray; int *pi, lstoi(); unsigned btoi(); float *pf, lstof(); double *pd, lstod(); message = "aunload - attempt to unload past end of buffer\n"; p = &add1; /* point p at top of argument stack */ while(*s) { /* read the 'format' string */ for(i = 0; *s >= '0' && *s <= '9'; i++) { /* # in array */ t[i] = *s++; if(!*s) return(buffer); /* if eostr */ } if(i) btoi(t, i, &narray, 10); else narray = 1; if(*s == 'i') { /* integer */ pi = *p++; for( ; narray > 0; narray--) { if(buffer >= topadd) { errfmt(message); return(0); } *pi++ = lstoi(buffer++); } } else if(*s == 'f') { /* float */ pf = *p++; for( ; narray > 0; narray--) { if(buffer + 1 >= topadd) { errfmt(message); return(0); } *pf++ = lstof(buffer++); buffer += 1; } } else if(*s == 'd') { /* double */ pd = *p++; for( ; narray > 0; narray--) { if(buffer + 3 >= topadd) { errfmt(message); return(0); } *pd++ = lstod(buffer++); buffer += 3; } } s++; } return(buffer); } /****************************************************************************/ /* there are five block structured I/O subroutines: bclose, bcreate, bopen, bread, bwrite, and also a routine ftor50 to convert ascii filename string to rad50 chan is the channel number. EMTERR is byte 052. */ int bclose(chan) /* close file number chan. returns: 3 created duplicate files. emt call is to .close */ int chan; { int emt(); if(emt(0374, 03000 + chan) < 0) { errfmt("unable to close file - duplicate files\n"); return(EMTERR); /* 3 */ } return(-1); /* success! */ } /****************************************************************************/ int bcreate(chan, name, length) /* create a new file chan. length is the size in blocks. length can an integer number of blocks, 0 the largest of 1/2 the largest space and all of the 2nd largest space, or -1 the largest empty space. returns the error: 0 channel already open, 1 no space if length given or full if not, 3 already exists. emt call is to .enter */ int chan, length; char *name; /* ASCII */ { int emt375(), name_rad50[4]; ftor50(name, name_rad50); if(emt375(01000 + chan, name_rad50, length) < 0) { if(!EMTERR) errfmt("unable to create file %p - channel already open\n",name); if(EMTERR == 1) errfmt("unable to create file %p - not enough space\n", name); if(EMTERR == 3) errfmt("unable to create file %p - protected file present\n",name); return(EMTERR); /* 0, 1, or 3 */ } return(-1); /* success! */ } /****************************************************************************/ int bopen(chan, name) /* opens file chan for buffered block output. returns error: 2 channel already open, 1 channel not found on device. the error code for channel already open is 0 but this is converted to 2 to allow passing -0 = 0 for a file of 0 blocks. if sucessful returns -(number of blocks). emt call is to .lookup */ int chan; char *name; /* ASCII */ { int i, emt375(), name_rad50[4]; ftor50(name, name_rad50); if((i = emt375(0400 + chan, name_rad50)) < 0) { if(!EMTERR) { errfmt("unable to open file %p - channel already open\n", name); return(2); } else if(EMTERR == 1) errfmt("unable to open file %p - file not found\n", name); return(EMTERR); /* 1 */ } return(-i); /* success! */ } /****************************************************************************/ int bread(chan, p, n, b, c) /* read #n 16-bit words to buffer p from block number #b of file chan. if c is zero (default) the emt call is to .readw, if it is 1 the emt call is to .read. returns: 0 attempted read past end of file, 1 hardware error, 2 channel not open. */ int chan, *p, n, b, c; { int emt375(); if(c != 1) c = 0; if(emt375(04000 + chan, b, p, n, c) < 0) { if(!EMTERR) errfmt("read error - attempted read past EOF\n"); if(EMTERR == 1) errfmt("read error - hardware error\n"); if(EMTERR == 2) errfmt("read error - channel not open\n"); return(EMTERR); /* 0, 1, or 2 */ } return(-1); /* success! */ } /****************************************************************************/ int bwrite(chan, p, n, b, c) /* write #n 16-bit words from buffer p to block number #b of file chan. if c is zero (default) the emt call is to .writw, if it is 1 the emt call is to .write. returns: 0 attempted write past end of file, 1 hardware error, 2 channel not open. */ int chan, *p, n, b, c; { int emt375(); if(c != 1) c = 0; if(emt375(04400 + chan, b, p, n, c) < 0) { if(!EMTERR) errfmt("write error - attempted write past EOF\n"); if(EMTERR == 1) errfmt("write error - hardware error\n"); if(EMTERR == 2)errfmt("write error - channel not open\n"); return(EMTERR); /* 0, 1, or 2 */ } return(-1); /* success! */ } /****************************************************************************/ unsigned btof(s, n, pfnum) /* converts the n char buffer starting at s into a float stored at address pfnum. the string is a text representation of the number. an exponent is allowed. leading whitespace is skipped and an optional sign and fraction are allowed. conversion stops at the end of n char or at the first unrecognizable char. it returns the number of char consumed. if it gets no digits, *pfnum is zero. see "the C programming language" page 69. */ char *s; /* starting address of buffer */ unsigned n; /* number of characters */ float *pfnum; /* address at which to store float */ { double dtento(), val, power; int power10, i, powsign = 1, sign = 1; for(i = 0; s[i] == ' ' || s[i] == '\n' || s[i] == '\t'; i++) if(i >= n) { /* skip whitespace */ *pfnum = 0.; return(0); } if(s[i] == '+' || s[i] == '-') /* deal with sign */ sign = (s[i++] == '+') ? 1 : -1; for(val = 0; s[i] >= '0' && s[i] <= '9'; i++) { if(i > n) { /* get digits before '.' */ *pfnum = sign * val; return(i); } val = 10 * val + s[i] - '0'; } if(s[i] == '.') i++; for(power = 1; s[i] >= '0' && s[i] <= '9'; i++) { if(i >= n) { /* get digits after '.' */ *pfnum = sign * val / power; return(i); } val = 10 * val + s[i] - '0'; power *= 10; } if(s[i] == 'e' || s[i] == 'E') { i++; if(s[i] == '+' || s[i] == '-') /* deal with exponent sign */ powsign = (s[i++] == '+') ? 1 : -1; } for(power10 = 0; s[i] >= '0' && s[i] <= '9'; i++) { if(i >= n) { /* get digits after 'e' */ *pfnum = (float) dtento((sign * val / power), powsign * power10); return(i); } power10 = 10 * power10 + s[i] - '0'; } *pfnum = (float) dtento((sign * val / power), powsign * power10); return(i); } /****************************************************************************/ int cacept(s, n, add1) /* accepts char variables in a manner similar to FORTRAN IV ACCEPT statement. s is a string to be typed as a prompt. n is the number of character variables. it returns the number of variables accepted. if too many are entered, they are ignored, if too few - 0 is entered. */ char *s; /* prompt string */ int n; /* number of variables */ unsigned add1; /* first argument, an address */ { #define IBUFSIZE 82 register *p; /* p is pointer to next address */ char *pc; /* pointer to output variables */ char buff[IBUFSIZE], *pbuff; /* input buffer and pointer to it */ int i, nchars, n_variables = 0; BYTES squeeze(), inbuf(), getlin(); errfmt(s); /* type prompt */ nchars = getlin(buff, IBUFSIZE); /* get input line */ while((i = inbuf(buff, nchars, " ,")) < nchars) buff[i] = '@'; /* change ' ,' to '@' */ nchars = squeeze(buff, nchars, '@'); /* remove all '@' */ pbuff = buff; /* pbuff points at bottom of buff */ p = &add1; /* point p at top of argument stack */ for(i = 0; i < n; i++) { /* read the 'format' string */ pc = *p++; if(nchars <= 0) { /* if no more text return 0 */ *pc = 0; break; } *pc = *pbuff++; nchars--; n_variables++; } return(n_variables); } /****************************************************************************/ /* callc this macro subroutine is not in hclib.obj. it must be edited and reassembled for each use. it can be used to allow a fortran program to call a C subroutine. fortran calls callc as "call callc(...)". any number of arguments can be used. since addresses are passed from fortran, double can be passed as well as int. the name of the c routine to call must be edited into callc before assembly. the c routine looks like "int csub(x,y,z)\nint *x;\ndouble *y;\n,int *z;\n" etc. return (ie fortran functions) doesnt work. the c routine can do no output to the terminal and very complicated c routines (calling others) will crash. fortran common can easily be had by passing the address of the first member and adding offsets. .dsabl reg .enabl gbl .psect c$text .globl callc callc: mov (%5),%4 ;number of arguments l1: mov %4,%3 ;2 * nargs is add %4,%3 ;the offset add %5,%3 ;added to %5 -> address of argument mov (%3),-(%6) ;push argument sob %4,l1 ;repeat if any more arguments jsr %7,csub ;edit in the name of the C routine to call mov (%5),%4 ;number of arguments l2: tst (%6)+ ;restore stack pointer sob %4,l2 ;repeat if more arguments rts %7 .end */ /****************************************************************************/ int call_emt(code, channel, arg1, arg2, arg3, arg4) /* issue a emt375 call */ unsigned code, channel, arg1, arg2, arg3, arg4; { return(emt375((code<<8) + channel, arg1, arg2, arg3, arg4)); } /****************************************************************************/ center_text(s, t, n, c) /* centers the string t within the first n characters of string s using fill character c before and after the centered text. n does not include the '\0'. if t is too long nothing is done. */ char *s, *t, c; int n; { unsigned lenstr(); int front, back; register int i, diff; if((diff = n - lenstr(t)) < 0) return; back = diff / 2; front = (diff % 2) + back; for(i = 0; i < front; i++) *s++ = c; for( ; *t != '\0'; ) *s++ = *t++; for(i = 0; i < back; i++) *s++ = c; *s = '\0'; } /****************************************************************************/ char cget() /* get character from STDIN without waiting for \n!! */ { char c; while(!read(STDIN, &c, 1)) ; return(c & BYTMASK); } /****************************************************************************/ int date(n) /* returns the date into a three int array, the first has the month, second the date, third the year. the argument is the address of int a[0]; the emt call is .date */ int n[]; { register int i; int emt(); if((i = emt(0374, 05000)) <= 0) { if(!i) errfmt("date - no date entered on system\n"); if(i < 0) errfmt("date - failed\n"); return; } n[2] = 1972 + (i & 037); n[1] = (i >>= 5) & 037; n[0] = (i >>= 5); } /****************************************************************************/ char *datest(s) /* return system date as a string "dd-mmm-yy" */ char *s; { char *p, *month(); int i, k = 0, n[3], date(); unsigned decode(); date(n); k = decode(s, 2, "%i", n[1]); s[k++] = '-'; p = month(n[0]); for(i = 0; i < 3; i++) s[k++] = p[i]; s[k++] = '-'; k += decode(&s[k], 2, "%i", n[2] - 1900); s[k] = '\0'; return(s); } /***************************************************************************/ /* the following extern declarations are required by define_file, dread, and dwrite, which follow */ extern int *inputb = NULL; /* block read buffer */ extern int outputb[BLOCKSIZE] = {0} /* block write buffer */ struct { int nrecs; /* number of records per file */ int words; /* number of 16-bit wrds per record */ } dfile[10] = {0}; /****************************************************************************/ int define_file(dfn, dfname, dnrecs, dwords, fnew) /* sets up a direct access binary disk file in the manner of the FORTRAN IV "DEFINE FILE" statement. dfn is file number (used as channel number), dfname is the file name, dnrecs is the number of records, dwords is the number of 16-bit words per record. fnew carries instructions regarding new files: if fnew is 0, no new file is created (ie return if unsuccessful open); if fnew is < 0, a new file must be created (ie delete an existing file); and if fnew is > 0 the file is created if it can not be opened. the default filename is dk:cfile*.dat where * is dfn. up to 10 files can be open at a time. allocation of space for the input buffer is based on the largest record size ever used in the program. note that a new file is only as large as the highest number block actually written to. returns -1 if successful, EMTERR if open or create fail, 2 if file number too high, or 0 if fnew is 0 and the file doesn't exist. use dread and dwrite with this routine */ int dfn; char *dfname; int dnrecs, dwords; int fnew; { int defname(), bcreate(), bopen(); int size, nblocks; static int bufsize = 0; char *alloc(), *free(); if(dfn > 9) { errfmt("define_file - file number > 9\n"); return(2); } defname(dfname, ".dat", dfn); if(fnew < 0) goto label1; if(bopen(dfn, dfname) != -1) { /* attempt to open */ if(EMTERR != 1) { if(!EMTERR) errfmt("define_file - channel in use\n"); else errfmt("define_file - unable to open file\n"); return(EMTERR); } if(fnew == 0) { /* if fnew=0, do not create */ errfmt("define_file - fnew = 0, unable to open file\n"); return(0); } label1: nblocks = (dnrecs * dwords) / BLOCKSIZE + 1; /*not,create it*/ if(bcreate(dfn, dfname, nblocks) != -1) { errfmt("define_file - unable to create file\n"); return(EMTERR); } } size = dwords + BLOCKSIZE; if(size > bufsize) { free(inputb, 0); inputb = alloc(size * 2, 0); bufsize = size; } dfile[dfn].nrecs = dnrecs; dfile[dfn].words = dwords; return(-1); } /****************************************************************************/ int dread(dfn, recnum, rwords, buffer) /* direct access read similar to a FORTRAN IV "READ" statement. dfn is the file number(channel number), recnum is the number of the record to read(starting at 0), rewords is the number of words of this record to read, and buffer is the integer buffer to fill. returns -1 if successful, the .readw error code if this fails, or a local error code (3 or 4). file must have been opened with define_file. */ int dfn, recnum, rwords; int *buffer; { int bread(); int bufwrd, wrdpos, block, i, j; if(dfn < 1 || dfn > 9) { errfmt("dread - file number out of range\n"); return(5); } if(recnum >= dfile[dfn].nrecs) { errfmt("dread - record index to high\n"); return(3); } if(rwords > dfile[dfn].words) { errfmt("dread - attempt to read more words than record\n"); return(4); } wrdpos = recnum * dfile[dfn].words; block = (wrdpos + 1) / BLOCKSIZE; /* starting block number */ wrdpos = wrdpos % BLOCKSIZE; bufwrd = wrdpos + rwords; /* how many to read */ if(bread(dfn, inputb, bufwrd, block) != -1) { errfmt("dread - unable to read\n"); return(EMTERR); } for(j = wrdpos, i = 0; i < rwords; j++, i++) buffer[i] = inputb[j]; return(-1); } /****************************************************************************/ int dwrite(dfn, recnum, rwords, buffer) /* direct access write similar to a FORTRAN IV "WRITE" statement. dfn is the file number(channel number), recnum is the number of the record to write(starting at 0), rewords is the number of words of this record to write, and buffer is the integer buffer with the values to write. returns -1 if successful, the .readw or .writew error code that was the failure, or a local error code (3 or 4). file must have been opened with define_file. */ int dfn, recnum, rwords; int *buffer; { int bread(), bwrite(); int nblocks, wrdpos, block, i, j, k; if(dfn < 1 || dfn > 9) { errfmt("dwrite - file number out of range\n"); return(5); } if(recnum >= dfile[dfn].nrecs) { errfmt("dwrite - record index too high\n"); return(3); } if(rwords > dfile[dfn].words) { errfmt("dwrite - attempt to write more words than record\n"); return(4); } wrdpos = recnum * dfile[dfn].words; /* word position to start */ block = (wrdpos + 1) / BLOCKSIZE; /* starting block number */ wrdpos = wrdpos % BLOCKSIZE; if(rwords % BLOCKSIZE == 0) /* number of blocks to write*/ nblocks = (wrdpos + rwords - 1) / BLOCKSIZE + 1; else nblocks = (wrdpos + rwords) / BLOCKSIZE + 1; for(k = 0; k < nblocks; k++) { if(k == 0 || k == nblocks - 1) { if(bread(dfn, outputb, BLOCKSIZE, block + k) != -1) { errfmt("dwrite - unable to read block\n"); return(EMTERR); } } if(k == 0) { j = wrdpos; i = 0; } else j = 0; for( ; j < BLOCKSIZE && i < rwords; j++, i++) outputb[j] = buffer[i]; if(bwrite(dfn, outputb, BLOCKSIZE, block + k) != -1) { errfmt("dwrite - unable to write\n"); return(EMTERR); } } return(-1); } /****************************************************************************/ int defname(file_name, file_ext, n) /* if a filename string is NULL add default file name based on n (ie cfile*.dat where * is n). if no file extension is present, it is added. if no device name is present "dk:" is added. returns 0 if no change, 1 if default name added, +2 if file extension added, +3 if device name added */ char file_name[], file_ext[]; int n; { char s[15], *cpystr(); int ret = 0, t; register int i, k; unsigned decode(); /* * change first \n to \0, convert lower to upper case */ for(i = 0; file_name[i] != '\0'; i++) { if(file_name[i] == '\n') { file_name[i] = '\0'; break; } } /* * default file name */ if(file_name[0] == '\0' || file_name[0] == '\n') { /* default name */ n %= 100; /* 0 <= n <= 99 */ cpystr(file_name, "DK:CFILE*.DAT", NULL); t = n > 9; decode(file_name + 8 - t, t + 1, "%i", n); return(1); } /* * is device name too long, if so shorten */ for(i = 0; file_name[i] != 0; i++) { if(file_name[i] == ':') { if(i > 3) { for(k = 3; file_name[i] != '\0'; i++, k++) file_name[k] = file_name[i]; file_name[k] = '\0'; } break; } } /* * is name too long, if so shorten */ for(i = 0; file_name[i] != 0; i++) { if(file_name[i] == ':') break; } if(file_name[i] != ':') i = 0; else i++; for(k = 0; file_name[k] != 0; k++) { if(file_name[k] == '.') break; } if(k - i > 6) { for(i += 6; file_name[k] != '\0'; i++, k++) file_name[i] = file_name[k]; file_name[i] = '\0'; } /* * is file extension too long, if so shorten */ for(i = 0; file_name[i] != 0; i++) { if(file_name[i] == '.') { if((lenstr(file_name) - i) > 4) { file_name[i + 4] = '\0'; } break; } } /* * add file extension */ for(i = 0; file_name[i] != '\0'; i++) { if(file_name[i] == '.') /* if '.' found, no add ext */ goto label1; } ret = 2; file_ext[4] = '\0'; /* extension only 4 char */ cpystr(file_name, file_name, file_ext, NULL); /* add file ext */ /* * add device name */ label1: /* for(i = 0; file_name[i] != '\0'; i++) { if(file_name[i] <= 'z' && file_name[i] >= 'a') file_name[i] -= 32; } */ /* * add device name */ for(i = 0; file_name[i] != '\0'; i++) { /* device name? */ if(file_name[i] == ':') return(ret); } cpystr(s, "DK:", file_name, NULL); /* add device name */ cpystr(file_name, s, NULL); return(ret + 3); } /****************************************************************************/ int delay(seconds) /* delay for seconds seconds */ unsigned seconds; { int time_1, time_2; int emt375(); LONG i; if(emt375(010400, &i) < 0) return; time_1 = i / 60; time_2 = time_1; while(seconds > time_2 - time_1) { if(emt375(010400, &i) < 0) return; time_2 = i / 60; } } /****************************************************************************/ char *dtols(s, d) /* the double version of itols. converts the value of a double into the 8 byte string starting at s. returns s (ie the address). this is faster than using union */ register int *s; double d; { register int *p; char *itols(); p = &d; itols(s++, *p++); itols(s++, *p++); itols(s++, *p++); itols(s, *p); return(s - 3); } /****************************************************************************/ int errext(s) /* prints error message and exits. */ char *s; { errfmt(s); exit(); } /****************************************************************************/ char *ftols(s, a) /* the float version of itols. converts the value of a float into the 4 byte string starting at s. returns s (ie the address). this is faster than using union */ register int *s; float a; { register int *p; char *itols(); p = &a; itols(s++, *p++); itols(s, *p); return(--s); } /****************************************************************************/ int ftor50(ascii, radix) /* converts an ascii string filename to RADIX-50 format in 4 integers pointed to by 'radix'. taken from c manual on rad50 routine */ char *ascii; int *radix; { int rad50(), n; unsigned lenstr(), scnstr(); n = scnstr(ascii, ':'); if(ascii[n]) { radix[0] = rad50(ascii, n); ascii += n + 1; } else radix[0] = 0; n = scnstr(ascii, '.'); radix[1] = rad50(ascii, n); radix[2] = rad50(ascii + 3, n - 3); radix[3] = (ascii[n] == '.') ? rad50(ascii + n + 1,\ lenstr(ascii + n + 1)) : 0; } /****************************************************************************/ int getln(fp, line, limit) /* get line (up to limit number of characters including \n\0) of input from the file with address fp. returns the number of characters (excluding the terminal '\0') or EOF. line is terminated with '\n' '\0'. '\0' is treated like any other char. */ FIO *fp; register char *line; int limit; { register int c, nc = 1; int getc(); while(nc < limit - 1 && (c = getc(fp)) != '\n') { if(c == EOF) return(EOF); *line++ = c; nc++; } *line++ = '\n'; *line = '\0'; return(nc); } /****************************************************************************/ int getword(fp, word, limit) /* gets one word (up to limit number of characters including \0) of input from the file with FIO address fp and places the word at address word. assumes that words are delimited by ascii <= ' '. returns the number of characters (excluding the terminal '\0') or EOF. the word is terminated with '\0' and thus always contains at least one character. */ FIO *fp; register char *word; register int limit; { int c; register int nc = 0; int getc(); while(nc < limit - 1 && (c = getc(fp)) > ' ') { *word++ = c; nc++; } if(c == EOF) return(EOF); *word = '\0'; return(nc); } /****************************************************************************/ int greet(message) /* types a greeting message for the begining of programs. */ char *message; { char *str1 = "\n=============================================\ ===================================\n\n"; errfmt(str1); errfmt(message); errfmt(str1); } /****************************************************************************/ /* int istsx() /* returns 1 if running under TSX+ v5 or later. returns 0 if running under RT11. */ .title istsx .enabl reg .enabl gbl .globl istsx .psect c$text,i,ro ; .mcall .serr rmon = 54 sysgen = 372 ; istsx: ; mov %5,-(%6) mov %6,%5 ; clr %0 mov rmon,%1 tst sysgen(%1) bpl lrt11 ; ltsx: mov #1,%0 jmp c$rets ; lrt11: .serr mov #tsxln,%0 emt 375 bcc ltsx ; out: clr %0 jmp c$rets ; .psect c$data,d,rw ; tsxln: .byte 0,110 .nlist BEX .even .end */ /****************************************************************************/ /* int limits(offset, plow, ptop, top) return bottom address of program, top address of program, and top address available for use. offset is how much space to leave at the top for the heap. the *.mac file must be edited as indicated below. unsigned offset, *plow, *ptop, *top; { register x; x = offset; *plow = 1; *ptop = 2; *top = 3; } */ /* .mcall .settop ;hzb added limits: jsr %5,c$sav .settop #-2 ;hzb added get it all tst 4(%5) ;hzb added leave heap space? beq label1 ;hzb added if not sub 4(%5),%0 ;hzb added .settop %0 ;hzb added reset top for heap label1: mov limmt,@6(%5) ;hzb changed return addresses mov limmt+2,@10(%5) ;hzb changed mov %0,@12(%5) ;hzb changed jmp c$ret .psect c$data,d,rw .even limmt: .limit ;hzb added .even */ /****************************************************************************/ int *loadbf(s, topadd, wcnt, arg1) /* loads wcnt 'integer' values into the buffer starting at s. the buffer goes to a (top address + 1) of topadd. arg1 is the first value to load. any number and combination of integer and double can be loaded as long as wcnt is correct and there is room in the buffer. float can not be done because it is converted to double when passed as an argument. also char can not be done. it returns the address for the next addition to buffer. */ register int *s; char *topadd; int wcnt; int arg1; { register int *p; /* pointer to next word to load */ char *itols(); p = &arg1; /* point p at top of stack */ for( ; wcnt > 0; wcnt--) { if(s < topadd) itols(s++, *p++); else { errfmt("loadbf - attempt to over fill buffer\n"); return; } } return(s); } /****************************************************************************/ double lstod(s) /* the double version of lstoi. converts the 8 byte string starting at s to a double which is then returned. this is faster than using union */ register int *s; { double a; register int *p; int lstoi(); p = &a; *p++ = lstoi(s++); *p++ = lstoi(s++); *p++ = lstoi(s++); *p = lstoi(s); return(a); } /****************************************************************************/ float lstof(s) /* the float version of lstoi. converts the 4 byte string starting at s to a float which is then returned. this is faster than using union */ register int *s; { register int *p; int lstoi(); float a; p = &a; *p++ = lstoi(s++); *p = lstoi(s); return(a); } /****************************************************************************/ /* int *maccsi(defr50, filspec) this is a macro-11 routine to be called from a C program to invoke the rt11 csi and thus return the filenames and options to the calling program. it allows for 10 (decimal) words of option results which are popped off the stack after the EMT is issued. the basic routine was generated by the C compiler based on code at the end of this section; the *.mac file was then edited. this routine is used by rtcsi. int defr50[4]; int filspec[39]; { static int *x, *y, optbuf[10]; x = defr50; y = filspec; return(optbuf); } */ /* ; .psect c$data,d,rw .even $1: ; this is x .blkb 2 .even $3: ; this is y .blkb 2 .even $5: ; this is optbuf .blkb 24 .psect c$text,i,ro .mcall .csispc ; hzb added ; maccsi: mov %5,-(%6) mov %6,%5 mov 4(%5),$1 ; put address of defr50 in $1 mov 6(%5),$3 ; put address of filspec in $1 ; ; hzb added (must have reg enabled!!!) ; .csispc $3,$1 ; call csi in special mode mov #12,%4 ; set counter to move 10. words mov #$5,%3 ; point at optbuf l1: mov (sp)+,(%3)+ ; pop off stack, move to optbuf sob %4,l1 ; if < 4 done, do another ; ; end hzb added ; mov #$5,%0 ; return address of option block jmp c$ret .psect c$text .even .psect c$data .even */ /****************************************************************************/ char *month(n) /* returns a pointer to a string containing the text representation of the month name. n is the number (1-12) of the month. taken from "the C programming language" */ int n; { static char *name[] = { "illegal month", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; return((n < 1 || n > 12) ? name[0] : name[n]); } /****************************************************************************/ int nint(x) /* return the nearest integer */ double x; { if(x >= 0.) return((int) (x + 0.5)); else return((int) (x - 0.5)); } /****************************************************************************/ int option(os, c) /* was an option selected in a call to the rt11 csi? rtcsi() converts option information to a null terminated string. option scans a string to see if a character is in it (returns 1) or not (returns 0). */ register char *os, c; { while(*os != '\0') { if(*os++ == c) return(YES); } return(NO); } /****************************************************************************/ int password(s, n) /* prompt for and accept password from operator. s is the string containing the password which must be matched. no more than 10 chars of the string will be used. n is the number of times the operator is allowed to try it; afterward the program exit()'s. */ char *s; int n; { char sinput[11]; int i, cmpstr(); unsigned ijob, getlin(); /* set terminal to special mode */ ijob = JSW; /* remember job status word */ JSW = ijob | 010000; /* set bit 12 */ /* loop n times */ for( ; n > 0; n--) { /* get input */ errfmt("\nenter password "); getlin(sinput, 10); /* terminate input string */ for(i = 0; i < 10; i++) { if(sinput[i] == '\n') break; } sinput[i] = '\0'; /* exit if password incorrect */ if(cmpstr(sinput, s) == YES) { JSW = ijob; /* terminal to previous mode */ errfmt("\n"); return; } } JSW = ijob; /* terminal to previous mode */ exit(); } /****************************************************************************/ int pause(s) /* type string s to terminal, then await return. */ char *s; { errfmt("pause - %p", s); getfmt("%x"); } /****************************************************************************/ int pflush(plp) /* flush LP: buffer by flooding it with nulls. plp is the address of the FIO of the printer. */ FIO *plp; { int i; for(i = 0; i < plp->_nleft; i++) putc(plp, '\0'); } /****************************************************************************/ int putln(fp, line, limit) /* put line of output (up to limit number of characters) to the file with address fp. returns the number of characters (including the terminal '\n'). line is terminated with '\n'. treats '\0' like any other char. */ FIO *fp; register char *line; register int limit; { register int nc = 1; int putc(); while(nc < limit && *line != '\n') { putc(fp, *line++); nc++; } putc(fp, '\n'); return(nc); } /****************************************************************************/ int putword(fp, word, limit) /* put word of output (up to limit number of characters) to the file with address fp. assumes that words are delimited by ascii <= ' '. returns the number of characters (including the terminal '\n'). the output word is terminated with '\n' thus always containing at least one character. */ FIO *fp; register char *word; register int limit; { register int nc = 1; int putc(); while(nc < limit && *word > ' ') { putc(fp, *word++); nc++; } putc(fp, '\n'); return(nc); } /****************************************************************************/ int rename(old_name, new_name, channel) /* rename a file. returns the error: -1 if it worked, 1 channel already open, 2 file not found, 3 protected file already exists. emt call is to .rename. */ char *old_name, *new_name; /* ASCII */ int channel; { int emt375(), name_rad50[8]; if(channel < 0. || channel > 19.) channel = 19.; ftor50(old_name, name_rad50); ftor50(new_name, &name_rad50[4]); if(emt375(02000 + channel, name_rad50) < 0) { if(EMTERR == 0) errfmt("rename - channel already open\n"); if(EMTERR == 1) errfmt("rename - file not found\n"); if(EMTERR == 2) errfmt("rename - invalid operation\n"); if(EMTERR == 3) errfmt("rename - protected file already exists\n"); return(EMTERR); } return(-1); /* success */ } /****************************************************************************/ /* float rng(addsd1, addsd2) pseudo-random number generator using the DEC RAN algorithm. see the mini-tasker, november 1979, Martin Ackroyd. the program below is converted to macro, %4 and %2 are changed to %2 and %3 respectively, and then the large block of text that follows must be added. sd1 and sd1 are int. contained in hclib2. register *addsd1; register *addsd2; { long ll; return; } */ /* the following code is present at start rng: jsr %5,c$sav add #-4,%6 mov 4(%5),%4 mov 6(%5),%2 the latter two lines are changed to mov 4(%5),%2 mov 6(%5),%3 the following is then added mov (%2),%0 mov (%3),%1 beq init ; asl %1 rol %0 ; add (%2),%0 add (%3),%1 adc %0 ; add (%3),%0 ; bpl next add #100000,%0 ; next: mov %0,(%2) mov %1,(%3) ; mov #201,%2 ; again: asl %1 rol %0 bcs done dec %2 br again ; done: clrb %1 bisb %0,%1 swab %1 clrb %0 bisb %2,%0 swab %0 ; ror %0 ror %1 ; mov %0,-12(%5) mov %1,-10(%5) ldf -12(%5),%0 ; br return init: mov #3,%1 inc %0 br next ; return: the last line was already there jmp c$ret */ /****************************************************************************/ int rtcsi(out_files, in_files, deftype, opts) /* call the rt11 csi in special mode (no lookup, fetch, or enter) to accept and process a command string from the terminal. returns -1 if successful, the error code if not. produces the names (as strings) of three output files and six input files. the names are blank if not entered. deftype is a 12 char string (4 times 3 char) with the default file types (input, output1, output2, output3). opts is a string which will contain the letter of each option selected (terminated be '\0' eg if options A and X were selected, opts would be "AX\0". the characters in opts are always upper case. although the rt11 csi returns more option information (ie which options go with which files and numberic values of options), use of this information is not yet supported. */ char out_files[3][15], in_files[6][15], deftype[12], opts[10]; { register int *poption, k, i; int filspec[39], defr50[4]; int r50tof(), rad50(), emt(), *maccsi(); /* * convert default type string to radix 50 */ for(i = 0; i < 4; i++) defr50[i] = rad50(&deftype[i * 3], 3); /* * maccsi is a macro11 subroutine which issues * an emt call to the rt11 csi in special mode */ poption = maccsi(defr50, filspec); /* * convert file names from radix 50 to strings */ for(i = 0; i < 3; i++) r50tof(&filspec[i * 5], &out_files[i][0]); for(i = 0; i < 6; i++) r50tof(&filspec[i * 4 + 15], &in_files[i][0]); /* * convert option information into a string */ for(k = 1, i = 0; i < poption[0]; k++) { opts[i++] = poption[k] & 0177; /* use lower 7 bits */ if((poption[k] & ~077777) != 0) /* if bit 15 set */ k++; /* burn the next word */ if(i >= 9 || k >= 9) /* save opts[9] for \0 */ break; } opts[i] = '\0'; /* * done */ return(-1); } /****************************************************************************/ int r50tof(radix, ascii) /* convert a 4 integer array containing a rt11 filename in radix 50 to an ascii string. */ int *radix; char *ascii; { int i; int unrad(); unsigned lenstr(), squeeze(); unrad(*radix++, &ascii[0]); ascii[3] = ':'; unrad(*radix++, &ascii[4]); unrad(*radix++, &ascii[7]); ascii[10] = '.'; unrad(*radix, &ascii[11]); ascii[14] = '\0'; /* * remove spaces */ squeeze(ascii, 15, ' '); /* * remove trailing '.', convert ":." to null string */ i = lenstr(ascii); if(ascii[--i] == '.') ascii[i] = '\0'; if(ascii[0] == ':' && ascii[1] == '\0') ascii[0] = '\0'; } /****************************************************************************/ int shell(n, pord, pexch, offset) /* shell sort. based on Software Tools and Knuth (algorithm for picking gap). pord is a routine with compares two items and pexch exchanges them. each is called with two arguments which are the indices (0 - n-1) of the items. offset is the index offset of where to start. n is the number of items. */ int n, offset; int (*pord)(), (*pexch)(); { int k; register i, j, gap; static int h[14] = { 0,1,4,13,40,121,364,1093,3280,9841,29524 88573,265720,797161 }; /* h[s+1] = 3*h[s]+1 */ for(k = 0; h[k] < n && k <= 14; k++) /* h[t+2] >= n, start h[t] */ ; if((k -= 2) < 1) k = 1; for( ; (gap = h[k]) > 0; k--) { for(i = gap + offset; i < n + offset; i++) { for(j = i - gap; j >= offset; j -= gap) { if((*pord) (j, j + gap) <= 0) break; (*pexch)(j, j + gap); } } } } /****************************************************************************/ /* int swap_byte(n) swap the bytes of n. the library (*.obj) version has had "swab %4" added at the appropriate place by changing "mov 4(%5),%4\nmov %4,%0\n" to "swab 4(%5)\nmov 4(%5),%0\n" in the .mac version before assembly. contained in hclib2. register int n; { return(n); } */ /****************************************************************************/ int *stopcc(n) /* calls .scca to inhibit control-c if n = 1, restore it if n = 0. it returns the address of termstat. if bit 15 of termstat is set a double cc has come in. it may put a control-c into terminal input buffer. emt call is to .scca */ int n; { INTERN termstat; int emt375(); if(n == 1) { if(emt375(016400, &termstat) < 0) /* turn off */ errfmt("stopcc - unable to turn off\n"); } else if(n == 0) { if(emt375(016400, 0) < 0) /* restore */ errfmt("stopcc - unable to turn on\n"); } else errfmt("stopcc - incorrect argument\n"); return(&termstat); } /****************************************************************************/ int substi(s, t, u, temp) /* if string s contains string t as a substring, substitute string u in place of string t. uses string temp as a temporary buffer. temp must thus be at least as long as (s - t) + u. returns YES if a substitution made, NO if not (to tell if all done if more than one t. */ register char *u; char *s, *t, *temp; { register i, k; unsigned substr(), lenstr(); i = substr(s, t); /* is it there? */ if(!s[i]) return(NO); /* if not, return unchanged */ for(k = 0; k < i; k++) temp[k] = s[k]; /* copy s prior to t */ while(*u != '\0') temp[k++] = *u++; /* copy in u */ for(i += lenstr(t); s[i] != '\0'; i++) temp[k++] = s[i]; /* copy in rest of s */ for(i = 0; i < k; i++) s[i] = temp[i]; /* copy temp back to s */ s[i] = '\0'; /* terminate it */ return(YES); } /****************************************************************************/ long tics() /* returns the elapsed time in tics since the last call. there are no arguments. the first call should be ignored, it is just for setup. emt call is to .gtim */ { long newtics, difftics; static long oldtics; int emt375(); if(emt375(010400, &newtics) < 0) { /* # of tics from midn */ errfmt("tics - failed\n"); return; } difftics = newtics - oldtics; /* minus tics at last call */ oldtics = newtics; return(difftics); } /****************************************************************************/ int time(n) /* returns the time into a four int array, first the hours, second the minutes, third the seconds, fourth the tics. the argument is the address of int a[4]; emt call is to .gtim */ FAST *n; { FAST k; LONG i; int emt375(); for(k = 0; k < 4; k++) /* zero the array */ *(n + k) = 0; if(emt375(010400, &i) < 0) { errfmt("time - failed\n"); return; } *n++ = i / 216000; /* hours */ *n++ = (i %= 216000) / 3600; /* minutes */ *n++ = (i %= 3600) / 60; /* seconds */ *n++ = i % 60; /* tics */ } /****************************************************************************/ char *timest(s) /* return system time as a string "hh-mm-ss" */ char *s; { int k, n[4], time(); unsigned decode(); time(n); k = decode(s, 2, "%i", n[0]); s[k++] = ':'; k += decode(&s[k], 2, "%i", n[1]); s[k++] = ':'; k += decode(&s[k], 2, "%i", n[2]); s[k] = '\0'; return(s); } /****************************************************************************/ int ttflush() /* flush the rt11 input ring buffer */ { } /* to build: compile the code above, then add the indented lines below .enabl gbl .globl ttflus .psect c$text,i,ro .mcall .ttinr ttflus: mov %5,-(%6) mov %6,%5 mov 44, r2 ; set bit 6 of JSW mov 44, r1 bis #100, r1 mov r1, 44 ; label: .ttinr bcc label ; go until no more characters ; mov r2, 44 ; reset JSW jmp c$rets .title ttflus .psect c$text,i,ro .even .psect c$data,d,rw .even .end */ /****************************************************************************/ int ungetc(fp, c) /* return character c to the file with FIO of address fp. I am not certain how this functions when getc() has just read across a block boundary. if getc() does not read the disk until the next call after exhausting the buffer, it should be ok. */ FIO *fp; int c; { if(fp->_fmode == READ) { if(fp->_nleft < BUFSIZE) { /* space to put it */ *--fp->_pnext = c; /* push char on buffer */ fp->_nleft++; /* bump the number left */ } } } /****************************************************************************/ int *unload(buffer, topadd, s, add1) /* unloads the buffer starting at buffer with a (top address + 1) of topadd into any combination and number of int, float, or double. add1 is the address of the first variable. char can not be done. it returns the next address to use (in buffer) unless there is an error in which case 0 is returned. s is a string indicating how to do the unload. i indicates int, f float, d double. all other characters are ignored. */ register int *buffer; int *topadd; char *s; unsigned add1; { register int *p; /* pointer to next address */ char *message; int *pi, lstoi(); float *pf, lstof(); double *pd, lstod(); message = "unload - attempt to unload past end of buffer\n"; p = &add1; /* point p at top of argument stack */ while(*s) { /* read the 'format' string */ switch(*s++) { case 'i' : if(buffer >= topadd) { errfmt(message); return(0); } pi = *p++; *pi = lstoi(buffer++); break; case 'f' : if(buffer + 1 >= topadd) { errfmt(message); return(0); } pf = *p++; *pf = lstof(buffer++); buffer += 1; break; case 'd' : if(buffer + 3 >= topadd) { errfmt(message); return(0); } pd = *p++; *pd = lstod(buffer++); buffer += 3; break; default : break; } } return(buffer); } /****************************************************************************/ int unrad(irad50, s) /* place in the 3 character string starting at s, the radix 50 contents of irad50. */ unsigned irad50; char *s; { int i; s[2] = irad50 % 050; /* r50 = (c0*050)+c1)*050+c2 */ irad50 = (irad50 - s[2]) / 050; s[1] = irad50 % 050; s[0] = (irad50 - s[1]) / 050; /* * convert radix 50 code to ascii */ for(i = 0; i < 3; i++) { if(s[i] <= 0 || s[i] > 047 || s[i] == 035) /* all illegals - 040 */ s[i] = ' '; else if(s[i] <= 032) /* A - Z, 1 - 32, 101 - 132 */ s[i] += 0100; else if(s[i] == 033) /* $, 033, 044 in ascii */ s[i] += 011; else /* s[i] >= 34 */ s[i] += 022; /* . or 0 - 9, 34&36-47 */ } } /****************************************************************************/ double dabs(x) /* returns absolute value of double x */ double x; { if(x >= 0) return(x); else return(-x); } /****************************************************************************/ double darctan(x) /* returns the arctangent of x (tan-1 x). the algorithm is from a DG fortran V manual */ double x; { int rflag = NO, zflag = NO, sign; double polynm(), r; static double a[] = { 197.20309568493503, 298.92803806939622, 125.57916643798066, 12.595802263029547}, b[] = { 197.20309568493503, 364.66240329770776, 207.69268173360463, 37.066086322091024, 1.0000}; sign = (x >= 0)? 1 : -1; if((x = abs(x)) > 1.) { rflag = YES; x = 1. / x; } if(x > 0.57735026918962577) { /* sqrt(3)/3 */ zflag = YES; x = (0.7320508075688773 * x - 1 + x) / (x + 1.7320508075688773); } /* sqrt(3), sqrt(3)-1 */ r = x * polynm(3, x, a) / polynm(4, x, b); if(zflag == YES) r += 0.52359877559829887; /* PI/6 */ if(rflag == YES) r = 1.5707963267948966 - r; /* PI/2 */ return(sign * r); } /****************************************************************************/ double dcos(x) /* returns the cosine of x. the algorithm is from an old DG fortran V manual. calls sinsub or cossub. */ double x; { int q, sign = 1; double r, sinsub(), cossub(); x = abs(x); x /= 0.7853981633974483; /* PI/4 */ q = (int) x; r = x - q; q %= 8; if(q >= 2 && q <= 5) sign = -1; if(q % 2) r = 1 - r; if(q == 0 || q == 3 || q == 4|| q == 7) return(sign * cossub(r)); else return(sign * sinsub(r)); } double cossub(x) /* used by dsin and dcos */ double x; { double polynm(); static double b[] = { 0.9999999999999999443, -0.30842513753403723, 0.15854344243734568E-01, -0.32599188645404001E-03, 0.359085912336036E-05, -0.2460945716614E-07, 0.11363812697E-09}; return(polynm(6, x, b)); } /****************************************************************************/ double dexp(x) /* returns the exponential (e to the x power) of double x. if error returns 0. the algorithm is from an old DG fortran V manual. */ double x; { int m, n, q, signfl = NO; double z, t, twoz1, twoz2, result; double power(), polynm(); static double a[] = { 1513.9067990543389, 20.202065651286927, 0.23093347753750234E-01}, b[] = { 4368.2116627275585, 233.18421142748162, 1.0}; if(!x) return(1.); if(x < 0.) { signfl = YES; x = -x; } if(x > 88.029691) { /* DG says 174.67308950110618 */ errfmt("dexp - argument too large\n"); return(0); } t = x * 1.4426950408889634; /* log2 e */ q = (int) t; z = t - q - 0.5; n = q % 4; m = (q - n) / 4.; twoz1 = z * polynm(2, z, a) / polynm(2, z, b); twoz2 = (.5 + .5 + twoz1) / (1 - twoz1); result = power(16., m) * power(2., n) * twoz2 * 1.4142135623730950; if(signfl == YES) return(1. / result); return(result); } /****************************************************************************/ double d10exp(x) /* returns 10 to the x power */ double x; { double dexp(); return(dexp(x * 2.302585092994046)); /* loge 10 */ } /****************************************************************************/ double dloge(x) /* returns the natural (base e) log of double x. if error returns 0. the algorithm is from an old DG fortran V manual. */ double x; { int n, m; double y, aa, logf, f = 0., r = 0., recp16 = 0.0625; double power(), polynm(); static double a[] = { -90.174691662040536, 93.463900642858538, -18.327870372215932}, b[] = { -45.087345831020306, 61.761065598471302, -20.733487895513939, 1.0}; if(x <= 0) { errfmt("dloge - argument is less than of equal to 0\n"); return(0); } if(x == 1) return(0.); if(x >= recp16) { /* next 10 lines */ for(n = 0; r < recp16 || r >= 1.; n++) /* x = 16to n *r */ r = x / power(16., n); n--; } else { for(n = 0; r < recp16 || r >= 1.; n--) r = x / power(16., n); n++; } for(m = 0; f < .5 || f >= 1.; m++) f = r * power(2., m); if(f <= 0.70710678118654752) { /* sqrt(.5) */ aa = 0.5; } /* --exponent ie(4n - m) by not --m */ else { aa = 1.0; --m; } y = (f - aa) / (f + aa); logf = y * polynm(2, y, a) / polynm(3, y, b); return(0.69314718055994531 * (4 * n - m) + logf); /* loge 2 */ } /****************************************************************************/ double dlog10(x) /* returns the log base 10 of double x. the algorithm is from an old DG fortran V manual. */ double x; { double dloge(); return(dloge(x) * 0.43429448190325183); /* log10 e */ } /****************************************************************************/ double dpower(y, x) /* returns the x-th power of y (ie y to the x). if error returns 0. the algorithm is from an old DG fortran V manual. */ double y; double x; { double dloge(), dexp(); if(y < 0 && x != 0) { errfmt("dpowr - argument is less than zero\n"); return(0); } if(y == 0 && x<= 0) { errfmt("dpowr - argument is zero\n"); return(0); } x *= dloge(y); if(abs(x) >= 88.029691) { /* DG says 174.67308950110618 */ errfmt("dpowr - arguments (x * ln(y)) too large\n"); return(0); } return(dexp(x)); } /****************************************************************************/ double droot(x, y) /* returns the x-th root of y */ double x; double y; { double dpower(); return(dpower(y, 1. / x)); } /****************************************************************************/ double dsin(x) /* returns the sine of x. the algorithm is from an old DG fortran V manual. calls sinsub or cossub. */ double x; { int q, sign = 1; double r, sinsub(), cossub(); if(x < 0) x = -x + PI; x /= 0.7853981633974483; /* PI/4 */ q = (int) x; r = x - q; q %= 8; if(q >= 4) sign = -1; if(q % 2) r = 1 - r; if(q == 0 || q == 3 || q == 4|| q == 7) return(sign * sinsub(r)); else return(sign * cossub(r)); } double sinsub(x) /* used by dsin and dcos */ double x; { double polynm(); static double a[] = { 0.78539816339744831, -0.80745512188280530E-01, 0.24903945701887361E-02, -0.36576204158455695E-04, 0.31336162166190400E-06, -0.1757149292755E-08, 0.6877100349E-11}; return(x * polynm(6, x, a)); } /****************************************************************************/ double dsqrt(x) /* return the square root of double x. the algorithm is from an old DG fortran V manual. if error returns -1. */ double x; { int i, p, m, n; double y, power(), r = 0, recp16 = 0.0625; double a = 0.22222222, b = 0.88888889; if(!x) return(0.); if(x < 0) { errfmt("sqrt - argument less than zero\n"); return(-1); } if(x >= recp16) { /* next 10 lines */ for(p = 0; r < recp16 || r >= 1.; p++) /* x = 16to p *r */ r = x / power(16., p); p--; } else { for(p = 0; r < recp16 || r >= 1.; p--) r = x / power(16., p); p++; } y = a + b * r; for(i = 0; i < 4; i++) /* iterate 4 times */ y = (r / y + y) / 2.; n = p % 2; /* convert p to 2m + n */ m = (p - n) /2.; return(power(16., m) * power(4., n) * y); } /****************************************************************************/ float fabs(x) /* returns absolute value of double x */ float x; { if(x >= 0) return(x); else return(-x); } /****************************************************************************/ int iabs(x) /* returns absolute value of double x */ int x; { if(x >= 0) return(x); else return(-x); } /****************************************************************************/ double polynm(order, x, cf_add) /* calculates a polynomial of degree order in x2 using a double array of coefficients with a starting address of cf_add. it returns the result. */ register int order; double x; double *cf_add; { register int i; static double lim_low[] = { 1e-19, 3.16228e-10, 4.64159e-7, 1.7783e-5, 1.58489e-4, 6.81292e-4 }; static double lim_high[] = { 1e19, 3.16228e9, 2.15443e6, 5.6234e4, 6.3096e3, 1.4678e3 }; double xabs, poly; double power(); xabs = abs(x); poly = *cf_add++; /* 0th order */ for(i = 0; i < order;) { if(xabs < lim_low[i] || xabs > lim_high[i]) break; /* if power would overflow */ poly += *cf_add++ * power(x, ++i * 2); } return(poly); } /****************************************************************************/ double power(x, pow) /* raises a double x to the int power pow */ double x; int pow; { double power = 1; if(pow >= 0) { for( ; pow > 0; pow--) power *= x; return(power); } else { for( ; pow < 0; pow++) power /= x; return(power); } } /****************************************************************************/ "@O 3{5rYzbh&[NkQuLs;!a/0X4WY YM%! } } *v : (<L" W 4( da\gK:be;u:, 0P`W6x zv+ z s/Ma#W""#!%v(Mc(v1,0M,*.`"j8v YMV a N`^! N^!{S@~"GX}"T`:#w;dgz#!=dw$d@$of"%x\g0M%F\g*&"v^&y{d' zy(1Ck~v(u~@)u~L"*wc"+4|]+,df}-xL.meO.s(x/VqM0e |1p!1 `1*e;1U1L;z4p<@5;IvuLs;L `"@ s"@  @( #8rh\Yzbhh&[NhkQh,uLs;ha  #4w  @= w0"  a $a . `"a j   #,Q,fww&  ww eBC! @ bb@ be K @    5 B a a a a  &a  .a 2 s"6  Pu5 ww 4@wf$$U@w$$w. `"  * `"2$6$>$F$J s"~!D}y" @,vL@""'@ <@@Y@ `"@r:0@  @@8@ a $ #0G!hga j,Jd fi~ 0123456789.eE+-@,-.  #J  #  #  #~ #w e5 N ZNa 5"fNa %5u-@e@mȕ fNa %5u-@e4  ""'$,vL .a " `"N0X4D `"@  @  #0(0X4ha  #0w DB ̋ @w   $ `"9FWD s"@  #0Wha t #&f5uu @@u wY  s"v YMmD""'@ N`^@ N(_@ N^@ `"@  @@8@ a 0 #0t YMh%a j8aunload - attempt to unload past end of buffer  #w eD@e 5 W0W9@e@mA Hw  NafNa eC   a Z `"x@8| Wi /5!N Wf% e5 /N @e5e = 0.""'X""'t N(_ Wd e5 N @e5e =e @e5e =e .""'J N^p N`^hN%D%Z@ s"@  #0%ha  #fe5 @@m @@m @@m @@m+@@m- u-= / @y| @m+55@@m0@@m9u-55=@w@@m. 5W @= \ s"@m@W5 5@@m0@@m9u-555=@@@me#@@mE<5 tW @@m@W55W 5  @@m+@@m-@ @m+55 @@m0 @@m9u-+AupN555& e=@AupN555& e=@wAWp>%Zh%Zx s"o&l @@m`@e5 n!D}y" @,vL@""'@ `"@r:0@  @ a  #0!hoa j  , #w e5 N RNa 5fNa %5u-@e@mȕ@@fNa %5@e5@=,  ""'$,vL .a df}\a `la h}   s"1^<L"DS@~@<@@e^@ s"@ a  #0<L"hDa j%i%i #fe5 Ne Nf e5@ @mȕ-N 55 W-@ @mAAmH @  <@ a ,e^LS@~H|@mȕ-NefNm e5`@@m@w a (e^B s"qfWDYy@Ky@e^@ `"@  @ a  #0>WhBa jDK:%iDK:CFILE*.DAT+ #w e5  @aȋ @a @aW 1 A rdu f %W-  5Nf"  Va ^Yy |a | feN ew @aȋ@a:!!•@aȋ@`AaH  @aȋ@a: -e^" `"_@`@a:    @`ȋ@`. e@`ȋ&@aA`H   @aȋ@a,t. N   @a0@a @aȋ @a.$ @0 fff e @aȋ @KylYyVa: @  fNa e Naf %@ew   a *Yy>YyL `"V( D\!+@~@ s"@  #0|( ha  #feNe ff<& u@@@- Ne wff<& $\!+0~X\!+b s"v~7^dD""'@of"@df}@ s"@ a d #06dhVa jkE=sMBԝ`=B.pF:|+eiD(/zA@C3@;\)@3cdexp - argument too large d #fe5 u@555705H w5785555u@5A*<a 0 Ha HL""'R s"Za 8C| ru@@A55& e &5& e 55@@5Wu5NA& ( "a 0df} :a Hdf}~of"zFe&fB& e 57@5W-@55%of"$a @~:bD |@,8^@W@""'@p!@ s"@U(@@*e;@U@ a a\ghwKh6:bh #0e;h$hu:ha j    **define_file - unable to create file define_file - fnew = 0, unable to open file define_file - unable to open file definEe_file - channel in use .datdefine_file - file number > 9  #feW-  ?Nf % Nf  +׭*D*J IAup A r 5N> a ""' (a 0fWDp!P*X* ^a b""'|ff % , *w@ e5w-*#   f 7w* Q ~ *p | a ,""'"*& s"8a *@a DU(@R,8^Xa ^a * ja Qn""' va ~z""'~*>,@ p@ p J a  a a 'dread - unable to read dread - attempt to read more words than record dread - record index to high dread - file number ouz_t of range ] #ofeW-W- I @ p-+ w@ p- @ upu@2N a I"""' 6a  <a +@""'H s" Va  \a `""' ra W  r5A ru@@m5Nff e  *u5 u-@ @m A mH.6a >U La P""'T*|a  a kkdwrite - unable to write dwrite - unable to read block dwrite - attempt to write more words than record dwrite - record i:ndex too high dwrite - file number out of range  #$f$feW-W-  @ p- w@ p- @ upu@)N a """' 6a  <a @""'H s" Va  \a `""' ra U  r5A ruA r @@m  r 5 @@m r 55 u-  @ 5  NNmf e  *9 u5 5 W-u-@ A Am p ). a $U 2a 6""':* va <NNmf e k *wK, a *e; *a k.""'2*6 s"^,D""'@of"@df}@ s"@ a v #0,ha j}qY~/*CbqWzoK4qY~/UwCT -.0@5@3e1@rzdloge - argument is less than of equal to 0  #fe55>5uH 5w555 55@55 55 .a H2""'J s"|,@5% NB& eu@u  5 @5#@5NB& eu@u *of"nof";785@5NA& e55 @5 55uu55& e &5a* a 8*of" ba pdf} za q:t&: e 55@ @7@5w df},a @4 s"N0D,@ s"@ a  #00hya j?[7q(# #"f5& e7w,a  s"^D""'@,@d@ s"@ a p #0ha jwC3dpowr - arguments (x * ln(y)) too large dpowr - argument is zero dpowr - argument is less than zero  #f u u K u u 1 w5& eu @u u 5 5 w@ u> a K ""' 8a 1<""'B s"L,ra |a W|5 & e6""'dgN`D s"@@  #0 `ha  #(f@5&5 & ew" s"fvDdf}@ s"@ a  #0Wh6x zhvh+ zhma jI@!h #feu555575555u5A ruW-W-A r U0a 3`|55 W-W-W- 5& $eu 5& euwZ s"a H@@M,=@#p7}ypbӳdyg/v mC #(f 5& e w" a df}" s"a @@IA!hI@!h #feu57@557H5555u5A ruW-A r 55 "a @.a HVp W-W-W- 5& $eu 5& $euwUP s"a P @PI@!h]-1#<5;7fijqЗ5<1 -in\ #,f P5& e 5w a Pdf}& s"V sD""'@of"@ s"@ a 0 #0f sha j8c?8`c@8Ssqrt - argument less than zero  #fe5>57575u u w555 55@55 5D*a "a  @a D""'L s"K|58@51 NB& eu@u  55555 W-555A5 Nu ,of"vB& eu@u A ru@@A5NA& e&fB& e 5w of"Nof"bof"p s"V/MDo;M@ `"@  @  #0N/Mha  #Vw D@e&e &e &e & ew&*  o;M,o;M:o;MDo;MP `"aN#Dd@ s"@ a  #0#h+a jA]ݱ #"f57& ewa d s"V""#D""'@ s"@ #}@  #0""#ha . #f N w""' #} s"5F%vD s"@  #0%vha \ #$fu55w  s"V(MDo;M@ `"@  @  #02(Mha  #:w D@e&e & w  o;M(o;M4 `"^(vDFwy@pp@Ky@ s"@  #0(vha  #fe:f 5@@mȋNf =@ 5`= .f 5@e5Nf =@ZFwy4ppVFwytppߓp|e5Nefe =@e5@@m.NNm fNm  =w3ppLKy\ppj s"V,0MD,@ &`"@  @  #0D,0Mha  #Lw DÕ@ N   ԕ w    ,@ `"YV,*D,@ `"@  @  #0J,*ha 6 #Rw DB  N 5W- T W- w,  ",L `"KN.`"D""'@ s"@ a T #0*.`"h'a j\ ================================================================================ r #2feN N N w& a ""' ""'(""', s"Fj8vD s"@  #0j8vha  #"f @@ wy  s"^YMVDo;M@""'@ `"@  @ a & #0@YMVhPa j.loadbf - attempt to over fill buffer  #Hw D@e   5! &e  w&  *o;M :a >""'B `"V N`^D N(_@ `"@  @  #0H N`^ha  #Pw eD@ee e e  5w*   N(_, N(_8 N(_@ N(_J `"V N^D N(_@ `"@  @  #00 N^ha A #8w eD@ee  5w   N(_( N(_2 `" FS@~D s"@ a ~ #0(S@~hna jph_YSOJE>4,#DecemberNovemberOctoberSeptemberAugustJulyJuneMayAprilMarchFebruaryJanuaryillegal mont:ph_ Y SOJE>4,#H |h #0fW-W- @ wa &a * s"FX}D s"@  #0*/X}ha  #2f55@5@w , s" NT`:D `"@  @  #0"T`:ha $ #*w DB̋  w  $ `"9f;dgzD,vL@""'@y@ s"@ #}@ a  #0;dgzh a j enter password  #fe$@U7$   Na 5 W- @e@m $ w$  @e@mN,$$ &a *""'8,vL^$b #}.|Na  w$ w )$y$ a ""'" s"V=dwD,'@""'@ s"@ a  #0 =dwha j%xpause - %p) #(f N  w.( a ""' a ,'" s"Nd@D s"@\g@  #0.d@h a ' #6fe5 @p-  f w$\g0 s"BFof"D s"@  #0Tof"ha   #\fe5  555 5 555 5w V s"V\g0MD `"@  @\g@  #0@\g0Mha  #Hw DBÕ  f  f w3  (\g:\gB `"{V\g*D `"@  @\g@  #0@\g*ha O #Hw DBÕ  f  f w  (\g:\gB `"{^v^D@}y" @Ky@ s"@  #0v^ha G #feN@e& @:Ne@e& Ne@e& @. Ne f @8B\x`|0 f %N 5 @@m.@@mW:@=w`}y"  KyZ s"Vy{dD\!+@""'@ s"@ a Z #0Zy{dh%a h_stopcc - incorrect argument stopcc - unable to turn on stopcc - unable to turn off  #bf W- ;       wR a \!+ &a ;*""'<\!+ Fa J""' Pa T""' Xa \ s"!^ zyD zy@Ky@ `"@  @  #0 zyha  #w DNf @`ȋ : @ `A`H ̋ @m N `@`ȋ  @m A`H  {   zyXKy *|@`A `H @`w $ `"$Vk~vD\!+@""'@ s"@ a  #0Xk~vha ftics - failed R #`feNe  @A 5uww@Aw@\!+ "a &""'4a 8a Ha Na Z s"nu~@D\!+@""'@~@ `"@  @S@ a  #0u~@hxa jtime - failed Z #w eD  a Ne  HffK ffK ff,  0\!+ :a >""'T~lS^|& ff& ff<& ff<& wR$ ~ S:~PSX `"Vu~L"De^@u~@@ s"@ a  #0u~L"ha j%i%i%iA #feNe Nf e5@ @mȕ:NfNm e5`@ @mȕ:Nf0u~@ a (e^ Ha Xe^ xa ,|Nm we5`@@m@wr e^& s"RFwc"D s"@  #04wc"ha L #<f@ @, @ x@ ws 6 s"v|]D""'@ <@ N`^@ N(_@ N^@ `"@  @ a @ #0|]ha jGd`f6iunload - attempt to unload past end of buffer ?.  #  #` #6  # #w eD@e  @ w5!N we =e5 N  :  a  0a 4 <F""'L `"Z N(_v""'MN|e =ee5 N e =e N^*""'< N`^ND `"@  @  #0ha  #w @C r(@AA@ r(5@C r(@AA@ r(=5 W-@@mȋ@@mr   |' @@m w@@mȕ @@m @@me@H@@m @@me H@@me  `"* HKVdf}Dof"@ `"@  @ a ` #0df}h]a jh J}a0"xlys51t8,lz<&:0%R2;o `#lj|*D ׭*( ׭* *wF* a D""'* a ( ""'$* ,a 0""'4*8 s"~ `D\!+@""'@ s"@\!@(v@ a  #0 |h2p!h `h*e;hUh(2a j0unable to close file - duplicate files  #:f Ne  *w,\! "a &""'**4 s"a (j(unable to create file %p - protected file present unable to create file %p - not enough space unable to create file %p - c;hannel already open  #2Z2feNef NNafe % * N ׭*N[ ׭*N( H(v0\!+:* Da H""'V* ba [f""'l* xa (|""'*w@* s"a `unable to open file %p - file not found unable to open file %p - channel already open y #zfeNef Nefe 5 *N @ w׭*N *H(v,\!+8* Ba F""'X s"\* ha l""'r*a 5jread error - channel not open read error - hardware error read error - attempted read past EOF _ #(c|(f W- 5 N fff fe e *M ׭*0 ׭* *wQT0\!+<* Ba MF""'R* Za 0^""'b* ja n""'r*v s"a sUnswrite error - channel not open write error - hardware error write error - attempted write past EOF  #|f W- 5 N fff fe e * ׭* ׭*s *wL0\!+<* Ba F""'R* Za ^""'b* ja sn""'r*v s"+FL;zD s"@  #0,L;zha R #4f , w w-& , s" $a . s"a  H^<@D""'@ `"@  @\!@ a 2 #0b<@hVa j9date - failed date - no date entered on system  #jw     @Eep@uEpu=  w4  \! a $""' \a `""'d `" Harold Z. Bencowitz810 Hospital Drive, Suite 240Beaumont, Texas9submission for the decus rt11 sig spring 1987 swap "tape" 22-Apr-87<CALEND.C 18 10-Mar-87 CALEND.SAV 29 10-Mar-87<FONT .H 1 29-Oct-86 FONT .SAV 51 30-Oct-86<ASCII .FNT 4P 30-Oct-86 DECSPC.FNT 4P 30-Oct-86<DECMUL.FNT 4P 03-Nov-86 HCLIB .C 126 10-Mar-87<HCLIB .OBJ 54 10-Mar-87 VT .C 63 24-Dec-86<VT .OBJ 31 29-Oct-86 FONT .C 54 21-Mar-87<FONT .DOC 11 21-Mar-87 CALEND.DOC 3 22-Apr-87<SPELL .DIC 253 15-Apr-87 SPELL .SAV 56 13-Feb-87<COMPD .SAV 39 18-Nov-86 SPELL .C 88 13-Feb-87<SPELL .DOC 15 22-Apr-87 README.1ST 3 22-Apr-87!COMPD .C 24 18-Nov-86  21 Files, 931 Blocks 43 Free blocksDthis submission includes "font" (font.c, font.h, font.doc, font.sav,Eascii.fnt, decspc.fnt, and decmul.fnt) a vt200 downloadable characterCfont editor; "calend" (calend.c, calend.sav, calend.doc) a calenderGdisplay program; and "spell" (spell.c, spell.doc, spell.sav, spell.dic,Gcompd.sav, compd.c) a spelling checker. hclib and vt are libraries used@for building the programs. there is a document for each program.Cspell.dic is the spelling dictionary which now contains 36289 wordsDin compressed format. the dictionary is only about 1/3 completed andDwill eventually contain around 90,000 - 100,000 words. program compd9compresses and decompresses word lists into dictionaries. /* vt.c VT100 video terminal routine library last changed 29-oct-86 Harold Z. Bencowitz ****************************************************************************** directory: |vtansi() ansi mode |vt52() vt52 mode vtbox(row, col, w, h) make box, line drawing set vtcln(r1, r2) clear rows vtclr(n) clear screen |vtcsav() save cursor |vtcres() restore cursor |vtdark() dark screen |vtrev() reverse video vtdouble(row, col, n, s)* write text in double size vtdown(s1, s2) down load character set |vtdsc(n, c) designate character set |vtscs(n) select character set vtebox(r, c, nc, fc, s, a, s0)* get entry from box vterln(n) erase line vterror() error message |vtgraf() graphics characters |vtnogf() graphics characters off vtgrid(row, col, w, h, a, d) make grid, line drawing set vthome() home cursor vtindx(n) index/reverse index ie scroll down/up |vtjump() jump scrolling |vtsmoo() smooth scrolling vtmbox(row, col, ncol, c)* write a 1 line high box vtmenu(row, col) get reply to menu vtmode(n) set attributes vtmova(row, column) * move cursor absolute vtmovr(n, k) * move cursor relative vtnext() next line vtrbox(nc, fc, is, a, s0) get entry from box, from current position vtrmbox(nc, fc) make box for vtrbox() |vtroll(top, bottom) scroll area |vtnoro() clear scroll area |vtrset() hard reset |vtsrst() soft reset vtttid() identify terminal vttxt(row, column, t) * write text on a line |vtwrap() wraparound mode |vtnowp() wraparound mode off |vt80() 80 columns |vt132() 132 columns vt0_9() down load characters 0 - 9 working(row) flash "working" * these will not work properly with 132 column display *****************************************************************************/ #include #include #define BASE 48 /****************************************************************************/ int vtebox(row, column, ncol, fc, is, address, s0) /* entry box - allow entry to a one line high box starting at row, column which is ncol wide. is is an instruction string "i", "u", "d", "s", "n" for int, unsigned, double, string, or numeric string respectively. address is the address at which to deposit the answer. video mode must be set before. fc is the fill character for the box. s0 is the string to place in the box at the beginning. returns the terminator key (\n, \b, or \t), -1 if bad arguments, or -(terminator key) if no data was entered. The latter allows one to distinguish from "0" entered vs no entry. right and left arrows can be used to move one character within the input string, up and down arrows can be used to move to the beginning or end of the input string respectively. */ int row, column, ncol, fc; char *is, *address, *s0; { register char s[81]; char *cpystr(), cget(), is0, *fs; register int itop, p; int i, c, nn, entry, *pi; int encode(), vtmova(), istsx(), call_emt(); unsigned lenstr(), ijob; double *pd; fs = "%- nb"; /* format for putstr below */ /* * test arguments */ if(row < 1 || row > 24) return(-1); if(column < 1 || column > 80) return(-1); if(ncol < 1) return(-1); if(ncol + column > 81) ncol = 81 - column; if(address == NULL) return(-1); is0 = is[0]; if(is0 != 'i' && is0 != 'd' && is0 != 's' && is0 != 'n' \ && is0 != 'u') return(-1); /* * move to position, initialize */ vtmova(row, column); p = itop = lenstr(s0); if(itop > 0) { fs[2] = fc; /* fs = "%- nb"; */ errfmt(fs, ncol, s0, itop); vtmova(row, column + (itop >= ncol ? ncol - 1 : itop)); cpystr(s, s0, NULL); } /* * set TSX singlechar mode */ if(istsx()) /* if running TSX+ */ i = call_emt(0152, 0, 'S'); /* set singlechar mode */ /* * vt100 to special mode */ ijob = JSW; JSW = ijob | 010000; /* * input characters */ while((c = cget()) != '\n' && c != '\b' && c != '\t') { if(c == ESCAPE) { if((c = cget()) == '[') { if((c = cget()) == 'C') { /* right */ if(p < itop) p++; } else if(c == 'D') { /* left */ if(p > 0) p--; } else if(c == 'A') /* up */ p = 0; else if(c == 'B') /* down */ p = itop; else if(c == '2') { /* vt200 F12 = BS */ if((c = cget()) == '4') { if((c = cget()) == '~') { c = '\b'; break; } } } } } else if(c == '\177' && p > 0) { /* delete */ for(i = p; i <= itop - 1; i++) { s[i-1] = s[i]; } --itop; --p; } else if(isdigit(c) || \ ((c == '+' || c == '-') && p == 0 && is0 != 'n' && is0 !='u')||\ (c == '.' && is0 == 'd') || \ (c == '-' && is0 == 'n') || \ ((c >= ' ' && c <= '~') && is0 == 's')) { for(i = itop - 1; i >= p; i--) { s[i+1] = s[i]; } s[p++] = c; itop++; if(itop > ncol) { for(i = 0; i < ncol; i++) s[i] = s[i + 1]; itop--; if(p > 0) p--; } } else continue; nn = column + (p >= ncol ? ncol - 1 : p); fs[2] = fc; /* fs = "%- nb"; */ vtmova(row, column); errfmt(fs, ncol, s, itop); vtmova(row, nn); } /* * vt100 to normal mode */ JSW = ijob; /* * finish processing the input string */ entry = (itop > 0 ? c : -(c)); if(is0 == 's') { s[itop] = '\0'; cpystr(address, s, NULL); return(entry); } else if(is0 == 'n') { s[itop] = '\0'; cpystr(address, s, NULL); return(entry); } else if(is0 == 'i') { if(itop != 0) encode(s, itop, "%i", address); else { pi = address; *pi = 0; } return(entry); } else if(is0 == 'u') { if(itop != 0) encode(s, itop, "%ui", address); else encode("0", 1, "%ui", address); return(entry); } else { /* is0 == 'd' */ if(itop != 0) encode(s, itop, "%d", address); else { pd = address; *pd = 0.; } return(entry); } } /****************************************************************************/ int vtmbox(row, column, ncol, c) /* write a 1 line high box starting at row, column which is ncol wide and filled with character c. video mode must be set before calling. */ register int column, ncol; int row, c; { int vtmova(); register int i; if(row < 1 || row > 24) return; if(column < 1 || column > 80) return; if(ncol + column > 81) ncol = 80 - column + 1; vtmova(row, column); for(i = 0; i < ncol; i++) errfmt("%ai", c); } /****************************************************************************/ int vtansi() /* ansi mode */ { static char s[] = "<"; /* $< */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vt52() /* vt52 mode */ { static char s[] = "[?2l"; /* $[?2l */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vtbox(row, column, width, height) /* draw a box using the vt100/vt200 special graphics character set. row and column are the location of the upper left corner. width and height are the width and height not including the outer character cells of the box, ie the smallest box is 0, 0. */ int row, column, width, height; { char s1[81], s2[81], s3[81]; register int i, k; int vtdcs(), vtmova(); /* * make top string */ k = 0; s1[k++] = 'l'; for(i = 0; i < width; i++) s1[k++] = 'q'; s1[k++] = 'k'; s1[k] = '\0'; /* * make sides string */ k = 0; s2[k++] = 'x'; for(i = 0; i < width; i++) s2[k++] = ' '; s2[k++] = 'x'; s2[k++] = '\0'; /* * make bottom string */ k = 0; s3[k++] = 'm'; for(i = 0; i < width; i++) s3[k++] = 'q'; s3[k++] = 'j'; s3[k] = '\0'; /* * output */ vtdcs(0, '0'); vtmova(row++, column); putstr(STDERR, s1, NULL); for(i = 0; i < height; i++) { vtmova(row++, column); putstr(STDERR, s2, NULL); } vtmova(row, column); putstr(STDERR, s3, NULL); vtdcs(0, 'B'); } /****************************************************************************/ int vtcln(r1, r2) /* clear rows r1 to r2 */ register int r1, r2; { int vtmova(), vterln(); register int i; for(i = r1; i <= r2; i++) { vtmova(i, 1); vterln(2); } } /****************************************************************************/ int vtclr(n) /* clear screen n may be 0 (cursor to end), 1 (cursor to beginning), or 2 (all). */ #define BASE 48 register int n; { static char s[] = ""; /* $[2J */ if(n < 0 || n > 2) n = 2; /* default is clear all */ s[2] = n + BASE; putstr(STDERR, s, NULL); } /****************************************************************************/ int vtcsav() /* save cursor */ { static char s[] = "7"; /* $7 */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vtcres() /* restore cursor */ { static char s[] = "8"; /* $7 */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vtdark() /* dark screen */ { static char s[] = "[?5l"; /* $[?5l */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vtrev() /* reverse video */ { static char s[] = "[?5h"; /* $[?5h */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vtdouble(row, column, n, s) /* write text in double size row and column are the upper left corner, s is the text to write, and n is code: 0 double height and width, 1 double height, 2 double width. */ int row, column, n; char *s; { static char s0[] = "#3"; /* $#3 */ static char s1[] = "#4"; /* $#4 */ static char s2[] = "#6"; /* $#6 */ int vtmova(); if(row < 0 || row > 24) return; if(column < 0 || column > 80) return; vtmova(row, column); if(n == 2) { putstr(STDERR, s2, NULL); putstr(STDERR, s, NULL); } else if(n == 1) { putstr(STDERR, s0, NULL); putstr(STDERR, s, NULL); vtmova(++row, column); putstr(STDERR, s1, NULL); putstr(STDERR, s, NULL); } else if(n == 0) { putstr(STDERR, s2, NULL); putstr(STDERR, s0, NULL); putstr(STDERR, s, NULL); vtmova(++row, column); putstr(STDERR, s2, NULL); putstr(STDERR, s1, NULL); putstr(STDERR, s, NULL); } } /****************************************************************************/ int vtdown(i, schars) /* down load a character set. schars is a strings such as "NGGGGGNo/N@@@@@N?". i indicates the character number to start at (ascii code). schars is a sixel pattern with the top and bottom halves of the character separated by '/'. multiple characters can be entered separated by ';'. */ register int i; char *schars; { static char s1[] = "P1;"; /* $P1; */ static char s2[] = ";1;0;0;0\( @"; /* ;1;0;0;0\( @ */ static char s3[] = "\\"; /* $\ */ char si[3]; register int k, t = 0; i -= 32; if(i > 94 || i < 0) { si[0] = '\0'; return; } if(i >= 10) { k = i / 10; si[t++] = '0' + k; i -= k * 10; } si[t++] = i + '0'; si[t] = '\0'; putstr(STDERR, s1, NULL); putstr(STDERR, si, NULL); putstr(STDERR, s2, NULL); putstr(STDERR, schars, NULL); putstr(STDERR, s3, NULL); } /****************************************************************************/ int vtdcs(gn, c) /* designate character set. G0, G1, G2, and G3 are selected by using values of 0, 1, 2, or 3 for gn. NOTE: only G0 and G1 are available for VT100. c is a character to select the character set. it may contain a single character B, <, or 0 for ASCII, DEC supplemental, and DEC special graphics respectively (hard character sets). NOTE: only B and 0 are available for the VT100. if c is '~'(tilda) the soft (down-line-loadable) character set is selected (named "@") */ int gn; int c; { static char s[] = "xx"; /* $xx */ static char t[] = "()*+"; static char s1[] = "x @"; /* $x@ */ if(gn < 0 || gn > 3) return; if(c != '~') { s[1] = t[gn]; s[2] = c; putstr(STDERR, s, NULL); } else { s1[1] = t[gn]; putstr(STDERR, s1, NULL); } } /****************************************************************************/ int vtscs(gn) /* select character set. gn of 0, 1, 2, or 3 selects G0, G1, G2, or G3 respectively. NOTE: only G0 and G1 are available for VT100. */ int gn; { char s[3]; if(gn < 0 || gn > 3) return; if(gn <= 1) { s[1] = '\0'; if(gn == 0) s[0] = '\017'; else s[0] = '\016'; } else { s[0] = '\033'; s[2] = '\0'; if(gn == 2) s[1] = 'n'; else s[1] = 'o'; } putstr(STDERR, s, NULL); } /****************************************************************************/ int vterln(n) /* erase line n may be 0 (cursor to end), 1 (cursor to beginning), or 2 (all). */ #define BASE 48 register int n; { static char s[] = ""; /* $[2K */ if(n < 0 || n > 2) n = 2; /* default is clear all */ s[2] = n + BASE; putstr(STDERR, s, NULL); } /****************************************************************************/ int vterror() /* error message go to row 24, column 1; erase the line; set mode reverse; ring bell */ { int vtmova(), vterln(), vtmode(); vtmova(24, 1); vterln(2); vtmode(8); errfmt("%ai%ai", '\007', '\007'); } /****************************************************************************/ int vtgraf() /* graphics characters */ { static char s[] = ")0"; /* $)0 */ static char s1[] = ""; /* SO shift out */ static char flag = NO; if(flag == NO) { putstr(STDERR, s, NULL); /* define G1 character set */ flag = YES; } putstr(STDERR, s1, NULL); /* shift out */ } /****************************************************************************/ int vtnogf() /* graphics characters off */ { static char s[] = ""; /* SI shift in */ putstr(STDERR, s, NULL); /* shift in */ } /****************************************************************************/ int vtgrid(row, column, width, height, across, down) /* draw a grid using the vt100/vt200 special graphics character set. row and column are the location of the upper left corner. width and height are the width and height not including the outer character cells of the boxs making, up the grid (ie the smallest box is 0, 0). across and down are the number of boxes in these directions. */ int row, column, width, height, across, down; { char s1[81], s2[81], s3[81], s4[81]; register int i, j, k; int vtdcs(), vtmova(); /* * make top string */ k = 0; s1[k++] = 'l'; for(j = 0; j < across; j++) { for(i = 0; i < width; i++) s1[k++] = 'q'; s1[k++] = 'w'; } s1[k - 1] = 'k'; s1[k] = '\0'; /* * make sides string */ k = 0; s2[k++] = 'x'; for(j = 0; j < across; j++) { for(i = 0; i < width; i++) s2[k++] = ' '; s2[k++] = 'x'; } s2[k] = '\0'; /* * make interior line string */ k = 0; s3[k++] = 't'; for(j = 0; j < across; j++) { for(i = 0; i < width; i++) s3[k++] = 'q'; s3[k++] = 'n'; } s3[k - 1] = 'u'; s3[k] = '\0'; /* * make bottom string */ k = 0; s4[k++] = 'm'; for(j = 0; j < across; j++) { for(i = 0; i < width; i++) s4[k++] = 'q'; s4[k++] = 'v'; } s4[k - 1] = 'j'; s4[k] = '\0'; /* * output */ vtdcs(0, '0'); vtmova(row++, column); putstr(STDERR, s1, NULL); for(j = 0; j < down; j++) { for(i = 0; i < height; i++) { vtmova(row++, column); putstr(STDERR, s2, NULL); } if(j == down - 1) break; vtmova(row++, column); putstr(STDERR, s3, NULL); } vtmova(row, column); putstr(STDERR, s4, NULL); vtdcs(0, 'B'); } /****************************************************************************/ int vthome() /* home cursor */ { static char s[] = ""; /* $[;H*/ putstr(STDERR, s, NULL); } /****************************************************************************/ int vtindx(n) /* index/reverse index ie scroll down/up n may be UP or DOWN */ register int n; { static char s[] = "D"; /* $D */ if(n == UP) s[1] = 'M'; else if(n == DOWN) s[1] = 'D'; else return; putstr(STDERR, s, NULL); } /****************************************************************************/ int vtjump() /* jump scrolling */ { static char s[] = "[?4l"; /* $[?4l */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vtsmoo() /* smooth scrolling */ { static char s[] = "[?4h"; /* $[?4h */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vtmenu(row, column) /* get one character form a "[ ]" box used for input to menus. writes box on screen in reverse video and gets one character in special mode. number keys must be followed by but arrows and PF keys work immediately. up, down, left, and right arrows return UP, DOWN, LEFT, and RIGHT respectively. PF1, PF2, PF3, and PF4 return PF1, PF2, PF3, and PF4 respectively. escape returns escape (ie 27 decimal). number keys return the numerical value. other inputs are not allowed. */ int row, column; { char cget(); register int c, l = NULL; int vterln(), vtmova(), vtmode(), putstr(), vtmovr(); unsigned ijob; vtmova(row, column - 1); /* go there */ vtmode(8); /* reverse video */ putstr(STDERR, "[ ]", NULL); /* make box */ vtmovr(LEFT, 2); /* move back into box */ /* * terminal to special mode */ ijob = JSW; JSW = ijob | 010000; /* * */ while((c = cget()) != '\n' || (l < '0' || l > '9')) { if(c == ESCAPE) { /* escape */ if((c = cget()) == '[') { if((c = cget()) == 'A') c = UP; else if(c == 'B') c = DOWN; else if(c == 'C') c = RIGHT; else if(c == 'D') c = LEFT; } else if(c == 'O') { if((c = cget()) == 'P') c = PF1; else if(c == 'Q') c = PF2; else if(c == 'R') c = PF3; else if(c == 'S') c = PF4; } } l = c; if(c >= PF1 && c <= RIGHT) break; if(c >= '0' && c <= '9') errfmt("%ai", c); else errfmt(" "); vtmovr(LEFT, 1); } if(l >= '0' && l <= '9') /* 0-9 return true value */ l -= 48; /* others return ASCII */ /* * terminal to normal mode */ JSW = ijob; vtmode(0); vterln(2); /* * end */ return(l); } /****************************************************************************/ int vtmode(n) /* set attributes n may be NULL or sum of any combination of 1 bold, 2 underscore, 4 blink, or 8 reverse. */ register int n; { static char s[] = ""; /* $[0m */ static char s1[] = "[ "; /* $[(8 spaces) */ register int i = 2; if(n < 0 || n > 15) return; putstr(STDERR, s, NULL); /* clear all attributes */ if(n == NULL) { return; } if(n & 1) { s1[i++] = '1'; s1[i++] = ';'; } if(n & 2) { s1[i++] = '4'; s1[i++] = ';'; } if(n & 4) { s1[i++] = '5'; s1[i++] = ';'; } if(n & 8) { s1[i++] = '7'; s1[i++] = ';'; } s1[i-1] = 'm'; s1[i] = '\0'; putstr(STDERR, s1, NULL); } /****************************************************************************/ int vtmova(row, column) /* move cursor absolute */ register int row, column; { static char s[] = "p;pppH"; /* $[pp;pppH */ register int i = 2; unsigned decode(); if(row < 0 || row > 24) return; if(column < 0 || column > 80) return; i += decode(&s[2], 2, "%i", row); s[i++] = ';'; i += decode(&s[i], 3, "%i", column); s[i++] = 'H'; s[i] = '\0'; putstr(STDERR, s, NULL); } /****************************************************************************/ int vtmovr(n, k) /* move cursor relative n may be UP, DOWN, RIGHT, or LEFT. k is the number of lines or spaces to move. */ register int n, k; { static char s[] = "pA"; /* $[ppA */ register int i = 2; unsigned decode(); if(n < UP || n > LEFT) return; if(n == UP || n == DOWN) { if(k < 1 || k > 23) return; } else { if(k < 1 || k > 79) return; } i += decode(&s[2], 2, "%i", k); if(n == UP) s[i] = 'A'; else if(n == DOWN) s[i] = 'B'; else if(n == LEFT) s[i] = 'D'; else if(n == RIGHT) s[i] = 'C'; s[++i] = '\0'; putstr(STDERR, s, NULL); } /****************************************************************************/ int vtnext() /* next line */ { static char s[] = "E"; /* $E*/ putstr(STDERR, s, NULL); } /****************************************************************************/ int vtrbox(ncol, fc, is, address, s0) /* entry box - allow entry to a one line high box which is ncol wide starting at current position. is is an instruction string "i", "u", "d", "s", "n" for int, unsigned, double, string, or numeric string respectively. address is the address at which to deposit the answer. video mode must be set before. fc is the fill character for the box. s0 is the string to place in the box at the beginning. returns the terminator key (\n, \b, or \t), -1 if bad arguments, or -(terminator key) if no data was entered. The latter allows one to distinguish from "0" entered vs no entry. right and left arrows can be used to move one character within the input string, up and down arrows can be used to move to the beginning or end of the input string respectively. */ int ncol, fc; char *is, *address, *s0; { register char s[81]; char *cpystr(), cget(), is0, *fs; int lastn = 0; int i, c, nn, entry, encode(), vtmovr(); register int itop, p; unsigned lenstr(), ijob; double *pd; fs = "%- nb"; /* format for putstr below */ /* * test arguments */ if(ncol < 1) return(-1); if(ncol > 80) ncol = 80; if(address == NULL) return(-1); is0 = is[0]; if(is0 != 'i' && is0 != 'd' && is0 != 's' && is0 != 'n' \ && is0 != 'u') return(-1); /* * move to position, initialize */ p = itop = lenstr(s0); if(itop > 0) { fs[2] = fc; /* fs = "%- nb"; */ errfmt(fs, ncol, s0, itop); vtmovr(LEFT, (itop >= ncol ? ncol - 1 : itop)); lastn = itop; /* new */ cpystr(s, s0, NULL); } /* * vt100 to special mode */ ijob = JSW; JSW = ijob | 010000; /* * input characters */ while((c = cget()) != '\n' && c != '\b' && c != '\t') { if(c == ESCAPE) { if((c = cget()) == '[') { if((c = cget()) == 'C') { /* right */ if(p < itop) p++; } else if(c == 'D') { /* left */ if(p > 0) p--; } else if(c == 'A') /* up */ p = 0; else if(c == 'B') /* down */ p = itop; } } else if(c == '\177' && p > 0) { /* delete */ for(i = p; i <= itop - 1; i++) { s[i-1] = s[i]; } --itop; --p; } else if(isdigit(c) || \ ((c == '+' || c == '-') && p == 0 && is0 != 'n' && is0 !='u')||\ (c == '.' && is0 == 'd') || \ (c == '-' && is0 == 'n') || \ ((c >= ' ' && c <= '~') && is0 == 's')) { for(i = itop - 1; i >= p; i--) { s[i+1] = s[i]; } s[p++] = c; itop++; if(itop > ncol) { for(i = 0; i < ncol; i++) s[i] = s[i + 1]; itop--; if(p > 0) p--; } } else continue; nn = (p >= ncol ? ncol - 1 : p); fs[2] = fc; /* fs = "%- nb"; */ vtmovr(LEFT, lastn); lastn = nn; /* new */ errfmt(fs, ncol, s, itop); vtmovr(LEFT, ncol - nn); } vtmovr(LEFT, nn); /* * vt100 to normal mode */ JSW = ijob; /* * finish processing the input string */ entry = (itop > 0 ? c : -(c)); if(is0 == 's') { s[itop] = '\0'; cpystr(address, s, NULL); return(entry); } else if(is0 == 'n') { s[itop] = '\0'; cpystr(address, s, NULL); return(entry); } else if(is0 == 'i') { if(itop != 0) encode(s, itop, "%i", address); else *address = 0; return(entry); } else if(is0 == 'u') { if(itop != 0) encode(s, itop, "%ui", address); else encode("0", 1, "%ui", address); return(entry); } else { /* is0 == 'd' */ if(itop != 0) encode(s, itop, "%d", address); else { pd = address; *pd = 0.; } return(entry); } } /****************************************************************************/ int vtrmbx(ncol, c) /* write a 1 line high box which is ncol wide and filled with character c. video mode must be set before calling. */ register int ncol; int c; { int vtmovr(); register int i; for(i = 0; i < ncol; i++) errfmt("%ai", c); vtmovr(LEFT, ncol); } /****************************************************************************/ int vtroll(top, bottom) /* scroll area */ register int top, bottom; { static char s[] = "p;ppr"; /* $[pp;ppr */ register int i = 2; unsigned decode(); if(top < 1 || top > 24) return; if(bottom < 1 || bottom > 24) return; if(bottom < top) return; i += decode(&s[2], 2, "%i", top); s[i++] = ';'; i += decode(&s[i], 2, "%i", bottom); s[i++] = 'r'; s[i] = '\0'; putstr(STDERR, s, NULL); } /****************************************************************************/ int vtnoro() /* clear scroll area */ { static char s[] = ""; /* $[r*/ putstr(STDERR, s, NULL); } /****************************************************************************/ int vtrset() /* hard reset */ { static char s[] = "c"; /* $c */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vtsrst() /* soft reset for VT220 */ { static char s[] = "[!p"; /* $[!p */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vtttid() /* determines terminal type. returns 52, 100, 101, 102, 125, 132, 200, or 208 indicating vt*. vt220 and vt240 both return 200. a return of 208 indicates a vt200 series in 8-bit mode. vt52 $/Z vt100 $[?1;Xc where X is: 0 no options 1 processor option (STP) 2 advanced video option (AVO) 3 AVO and STP 4 graphics option (GPO) 5 GPO and STP 6 GPO and AVO 7 GPO, STP, AVO 11 printer port (PP) 15 PP and GPO vt125 $[?12 vt132 $[?4;Xc where X is: 11 printer port (PP) 15 PP and GPO vt101 $[?1;0c vt102 $[?6c vt200 8 bit $?62 vt200 7 bit $[?62;X;X;.... where X is: 1 132 columns 2 printer port 6 selective erase 7 DRCS 8 UDK 9 7 bit character national replacement sets */ { char s_inp[21]; int c_inp, cget(); register int kount = 0, i = 0; int ttflush(); unsigned int ijob; /* * special terminal mode */ ijob = JSW; JSW = ijob | 010000; /* * get terminal id string */ label: if(kount++ > 3) /* quit if it doesn't work */ return(0); ttflush(); /* flush terminal input buffer */ putstr(STDERR, "Z", NULL); /* $Z */ for(i = 0; ((c_inp = cget()) != 'c' && c_inp != 'Z') && i < 20; i++) s_inp[i] = c_inp; /* read in the id string */ /* * process string */ if(s_inp[0] == ESCAPE && s_inp[1] == '\057' && c_inp == 'Z') { JSW = ijob; return(52); /* $/Z vt52 */ } if(s_inp[1] == '?' && s_inp[2] == '6' && s_inp[3] == '2') { JSW = ijob; return(208); /* vt200 eight bit mode */ } if(s_inp[0] != ESCAPE || s_inp[1] != '[' || s_inp[2] != '?') goto label; /* unrecognized string try again */ /* * reset terminal */ JSW = ijob; /* * process string */ if(s_inp[3] == '1') { if(s_inp[4] == '2') /* $[?12 vt125 */ return(125); else if(s_inp[4] == ';') { if(s_inp[5] == '0') /* $[?1;0 vt101 */ return(101); else if(s_inp[5] >= '1' && s_inp[5] <= '7') /*$[?1;(1-7)vt100 */ return(100); else return(0); /* this should never happen */ } else return(0); /* this should never happen */ } else if(s_inp[3] == '4') /* $[?4 vt132 */ return(132); else if(s_inp[3] == '6') { if(s_inp[4] == '2') /* $[?62 vt200 7 bit */ return(200); else if(s_inp[4] == '\0') /* $[?6 vt102 */ return(102); else return(0); /* this should never happen */ } else return(0); } /****************************************************************************/ int vttxt(row, column, s) /* write text on a line */ register int row, column; register char *s; { int vtmova(), vtmode(); if(row < 0 || row > 24) return; if(column < 0 || column > 80) return; vtmova(row, column); putstr(STDERR, s, NULL); } /****************************************************************************/ int vtwrap() /* wraparound mode */ { static char s[] = "[?7h"; /* $[?7h */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vtnowp() /* wraparound mode off */ { static char s[] = "[?7l"; /* $[?7l */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vt80() /* 80 columns */ { static char s[] = "[?3l"; /* $[?3l */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vt132() /* 132 columns */ { static char s[] = "[?3h"; /* $[?3/ */ putstr(STDERR, s, NULL); } /****************************************************************************/ int vt0_9() /* down load characters 0 - 9 */ { static char sa[]="wCAAACw?/?@AAA@??;?GC}????/?AABAA??;CaaQQQK?/BAAAAAA?;"; static char sb[]="AAAQYUa?/@AAAAA@?;_ogc}__?/????B???;]QIIIIq?/@AAAAA@?;"; static char sc[]="wcQQQQ_?/@AAAAA@?;AAAaQIE?/??B?????;kQQQQQk?/@AAAAA@?;"; static char sd[]="KQQQQI{?/?AAAA@??;"; static char s1[] = "P1;16;1;0;0;0\( @"; static char s2[] = "\\"; putstr(STDERR, s1, NULL); putstr(STDERR, sa, NULL); putstr(STDERR, sb, NULL); putstr(STDERR, sc, NULL); putstr(STDERR, sd, NULL); putstr(STDERR, s2, NULL); } /****************************************************************************/ int working(row) /* display "working" in blinking reverse video in the middle of row. */ register int row; { int vtmova(), vtmode(); vtmova(row, 36); vtmode(12); errfmt("working"); vtmode(0); vtmova(24, 1); } "@+?OxZÌ0M1M[qv ("( a\nr_sp^_g8X.S-X-!ae^ 21a Ba # _ P` Pw q 6ha&p&@ZƌZ*6Fsaq'XQXl~faOVZL s"@\gy@(a  #84ZhÌha j < #"f   %w" a \gy s"a [?2l #r"f   %w} a \gy s")^0MLnr@ `"@  @1a@( #8.0Mha T #6w DB   w  1a(nr0 `"VML `"@  @\gy@(a  #84Mha j  #<w D !ĕe07  %w(  "a  (a 0\gy6 `"PVvL s"@\gy@(a  #84[qhvha j 7 #"f   %w" a \gy s"a  8 #r"f   %w} a \gy s")V L s"@\gy@(a  #84 h"hba j[?5l #"f   %w" a \gy s"a [?5h #r"f   %wz a \gy s"&V aL s"@1a@\gy@(a  #86 ahXa j#3#4#6 #f RW- W-PwNf W-  % f  %-W-*  % f]4* s"61a Fa N\gy^\gy pa x\gyT|  %N f   % f  %   %  % f  %N H \gy1a &a .\gy>\gy Na V\gy ^a f\gyv\gywFf   %  % f  %. 1a a \gy $a ,\gy<\gyVnrL `"@  @\gy@(a  #84nrhxa j  #<w D !ĕe07  %w(  "a  (a 0\gy6 `"Pf_sL""'@e^@nr@ s"@1a@(a  #8:_sh a j%ai%ai #Bf     %w,1anr&e^ 2a 6""'< s"V pL s"@\gy@(a  #8Pph^h6a j)0k #>f    %  %w@ a  a \gy$a  *a 2\gy8 s"a   #6V"6f   %w] a \gy s"%N_L s"@\gy@(a  #8_ha j  #"f   %w a \gy s",V8XL `"@  @\gy@(a  #868Xha j D #>w D!M! D  %w)0  a $a  *a 2\gy8 `"VXL s"@\gy@(a  #84ShXha j[?4l #"f   %w" a \gy s"a ,[?4h #r"f   %wz a \gy s"&~!L}@""'@e^@nr@ `"@  @1a@Ba@\gy@(a  #8V!h,a j %ai[ ] #w  N f    % $@U7$ !  0 9! ![ @  1a"e^ (a 0\gy>BaD$R$V}t}|!Aą!<!9 0O 9L0I!O !Pĕ!Bĕ!Cĕ!Dĕ!Qĕ!R}:}fĕ!Sĕ!0 !9   w$  w> &a *""' 2a 6""'BBaL$Re^Znr` `"~Ve^L `"@  @\gy@(a  #8e^ha j[ [ #w D• !   % wĞ5  1 ;5  4 ;5  5 ;H  a (\gy2 `" Ba  La  \a  fa  va f@|5  7 ;m2  %)< a  a  a  $a  (a  .a 6\gyT^1aLe^@ `"@  @\gy@(a  #81aha jp;pppH%i%i #w DBÕ !  Pw  e` ; ` e` H3 ^  , `" 2a :a >e^ Na Ta \a be^ ra va |a | % \gy^BaLe^@ `"@  @\gy@(a  #8Bahka jpA%i #w DBÕ!!!!      Ow e`!A!B0  L `" Ra  Za 4^e^ pa +@| 0  %!D!C~4 a a a \gy *a 8a JN#L s"@\gy@(a  #8#ha j E #"f   %w a \gy s",n_Le^@ `"@ s"@  @\gy@(a  #8_h`hVa jp;ppr%i%i #Kw DBÕ!!  w   e` ; ` e` r3BV  0 `" :a Ba Fe^ Va \a da je^ za ~a |  % a \gya z  #"f   %w a \gy s"NwL s"@\gy@(a  #8wh(a j cs #"f L  %w a \gy s",f Le^@ `"@  @1a@\gy@( #8D ha ? #Lw DBC !  Pw&   %  , `"41aB\gyVpL s"@\gy@(a  #84hahphAa j[?7h #"f   %w" a \gy s"a [?7l #r"f   %wz a \gy s"&VƌL s"@\gy@(a  #84@hƌha j[?3l #"f   %w" a \gy s"a [?3h #r"f   %wz a \gy s"&f*6FL""'@e^@ `"@  @1a@(a  #8<*6Fha jworking #Dw D$&     w{8  1ae^ "a &""',e^81a> `"ND s"@\gy@ a  #0bha jxx()*+x @B #jf W-$W-~@m7w  %@m7    %wP $a ,a 2a  8a @\gy Ha Pa Va ^\gyd s"ND s"@\gy@  #0pha  #xfe W-*W- 5 5W-no Na %w?l\gyr s"NsD s"@\gy@ a  #0shla j [!p #"f   %w a \gy s",ND s"@\gy@ a  #0jha jwCAAACw?/?@AAA@??;?GC}????/?AABAA??;CaaQQQK?/BAAAAAA?;AAAQYUa?/@AAAAA@?;_ogc}__?/????B???;]QIIIIq?/@AAAAA@?;wcQQQQ_?/@AAAAY|A@?;AAAaQIE?/??B?????;kQQQQQk?/@AAAAA@?;KQQQQI{?/?AAAA@??;P1;16;1;0;0;0{ @\3 #rf   %  % 7 % n %  %  %w` a \gy a &\gy .a 76\gy >a nF\gy Na V\gy ^a f\gyl s"faD@ `"@  @1a@\gy@  #0Laha ) #w e   @al 5! @aq  @ak@e`  @axX 5! @a X  @axX @a   |0X  @am 5! @aq  @aj@e`0& Nf   Na % 5! NL^1ap\gy\f   XNa % Nf  Na %B& w.*1aa \gy21aD\gyPV `"fqD@ `"@  @1a@\gy@  #0qha V #w e  @al  5!+ @aq @e`k@e`  @axX  5!, @a X =   | @aw @eX`  @at  5!3 @aq  @axX @e`u@e`  @am  5!P @aq  @an @e`j@e`0& Nf   Na % Vh1az\gyt   5! 4Nf   XNa %  @av Nf  Na %B& w@ * 1a2\gyT1af\gyrx `"14 Nf   Na % z1a(\gy~D}@""'@Yy@Ky@ `"@  @Ba@s!e^@ a  #0>hQhpa jz%d%ui0%ui%i%- nbO #w e5 W- W-PP wuWiWdWs WnWuN    a > `"zKy\| )@pf ff e5!@  5 f Na %$@U7$ 5W- W-V&"""'@BaVYy\$j$n}bW- W-@ 5W-[e 5W-CJ [ YN w$ @@ 5Wsw@ea }*}JBaR$tNaf %@wW-Y W @-Y@@aAeAmp W-D  W-A W-B @Yy `"; 5@pN uNaff eNN w%0W-98 W-+W--"Ba>""'RBafl  WnWu"W-.WdW--WnW- w6W-~w*Wsw 5B- @@aAeAmp-  @ap 5!w5 u- @e@mAAaH  w wWn@ea Naf %@ xYyd*Wi N  &Na eWu "N  &Na e!= @w N &Na eN 6 a $s!e^ >a Js!e^\ `" ha ts!e^`6 e@u =@$ a  a s!e^a  %ai #z8w D N  w&  a ""',Ba2 `"-~D}@L;z@eO@""'@Yy@Ky@ `"@  @1a@s!e^@ a  #0nhha j%d%ui0%ui%i%- nbO #w eW-W- W-W-PwW-@@m QQ@5 u Wi<  a > `"p|WdWs WnWu S& j %5Nf N  )@p f/ff r.L;z@eOR1a\Kye5!@ Nmf  fNa %$@U7$ 5W- W-W- W-9 5W-,""'&1a8Yy>$L$P}x}4t[w 5W-CC m kw$ @@ 5Wsw@ea Naf %@wW-o m j }&$`Yyj `"@-o@@aAeAmp W-D & $W-A W-BW-2 5W-4  5W-~ V}f}Kl@ @m5@p Nf Naff eNf w%0W-98 W-+W--T,1aB""'R1az  WnWu"W-.WdW--WnW- wW-~w Wsw 5B- @@aAeAmpd  @ap 5!w5 u- @e@mAAaH  w wWn@ea Naf %@@ xYy-Wi N &Na eWku %N &Na e$u= @w N&Na e6 a $s!e^ >a Js!e^b `" na zs!e^N<\N e@u=@$ a  a s!e^a  %ai #pw DBW-W-!!Pwa QP f  N  &  0 `"N1a ^a b""'fl~D}@&[N@ `"@  @\gy@ a  #0\l~_ha j Z| #w e  $@U7$   3   % 5W-cW-Z  @e`H WW.  $ $2&[N 8a @\gyH}|/ W-Zw$4wW?W6 W2w$WW[W?w$W1W2 }W4$ `":$^$lW;W0e W1W7d W6W2 wf  6V `"VfaD `"@  @\gy@ a  #0fah8a jP1;;1;0;0;0{ @\  #w eD !^ 5J!  r  @ae0pWp D @ae0p@e`  % Na  la t\gyaF| %  % f %  %w4 \gy a \gy*\gy 2a :\gy@ `"$.b<ЮP:nPTRM<^ЬR@P ݬϜnSSTSTPSRRTPݣhRhPRP'ЮRR$ S<:UТPYYm(hֈ Џ|PԮTSSSSPSRRSP#gRKPRP ЏaPԮTծPPVkPVB1ЮPP$ Sj&}~ݏPYY Y0Ԯdhƈ}PYԮTQ ]`dOPP֤PPUPUP0PQP070qPVQP0)PVQ0ЏlPTVfVVTPUЏPQQPU:PѕqQP a;PaVQRxRRRSRfRURfyU RUfZSRR fSRUS R SS $R fR fRxRRRPRVQ1bRSfSRURSRf RUSSRUPPRx RPPxS~RRf SnPQ19Џ PRTScSST ѣ RУ RPR PRR>RR ]`dQP^^QaPHP}P^QaЏPhTмPмQQ¼֤ PЏlPЏdPTScSST2QQ ãQRxRRQ RRQPЏdPSYS$OUTPUT|l^ P2QGݬHPРPݏmݏBmݘPBdԼ RѬ ѬR bRռ ݬݏ*mբ ݼ CâP@ Լ /RѬ  ѬR bRռ  ݏJmEâ P@ZY^ЬVЬ Sݬi^WiЮPPnVXî P¬P@XXV(X cV VW~SZYX^^ݬi RrinWݬݏ*mhծ Rݏ*mhW îPVЬ V(VP"j `<QQj<QQݏsmhѬ VV ~FFPRybPbP`PЬTdRbSR=xSRdtTSPTPRPPQTQccQbaPPQR.bbPЏ`}~ݬRݢobR SRЬQQP@PPbQPbQcPbQQbQbPcPbbQ`a =zScRb>b1PP`Y P@˚@~:RyTDPSQSRRQSRRQSRRQQQ`RRQ`RRQ` RRQQdQQQdQQQdQQQdQQQdPPP([Z*YX,^gRb ݏڀmkТV5/;iQ&Pѡ YiPѠVViPݠݏ"mkPWWbRPFX >P=PPVݢ'Pݢݏ mkTS9TPSբ xSPPQ xSPPQQ ݏ#mkSTXVSSVFPТAb1BHhBiQPѡԮ$bbPPPTBD$PTb ݏ3mp|Ю$HcS8Hg rh% Ҩi_g jDRN~1h11|~A4ﮨR~}~}bR숏@^wxRn~QbRPhQBSRRRcݏmjRx-t[~ts`P ݏmj1ug~"h1 <  &151YPݠ{iRvPVUP<Qx QQx PfPPQSS SfݏmjT1eeSSebe~ݏSmjb ebf ݏ[mj~iP<`QAݠ9g{~Apg dh ݏmjU %Hg Q$;6iP<`~'iPݠ%& ݬ+ЬP@pc ݬr ݬPP[Z>YeX^ЬWG#x %3WbyV(Vz|jPjPjP j PPF|@*ОY|kW Y~@j Y~}~0j^ Y~LY~Y~1j Y~ Y~kW1Y~1@V(V|%V(V|V(V| V(V|1:CY~kﯤ|ﮢR煮PB`B`wRY|1 Y~1j11VvnW(Vh|}V~|5n6~.PݠYkn~PݠYu@kWmjcͣY뚨~kW8Y~6Y ~+'V(V(|}V~|^WpYǚ~kݬ\ݬЬQP@bAQ@bRRPcYЬXVVFiP@W(W@HWX VЬ P@ XP `-XݬX^ЬWоXЬYݩ~ZhVFbZgXZPxFwb@cQ @c  PP Ϯ 5C1ZV.Px@2bQPPPFbQxQP VZZV֮XhVFaQxQqPZݏ3mmiZiXZgGPZV0 ZXhVZgZFaxFaP iXfFa[[ VZZЩP(`PV`V֮XhVFLa[x[0PݩݩHnAiXZgHPigcPVxFaP VVBVOVD VXDQxA`0P1XP?@daV3@WaPQVg L^V1/F`QQ +Q& PQPVig@`PPPݏҀmjl1|ЬV<PPP,nP)Vݬ\PG V|`TЬVUfUPPf )fdPDTdٚGPP^Ь [PP(PppP@qpphqlЬPWWݬ h{ hPnЮUVffYYЬ USSY1XSY fS fXXX\ `dxSQQfPxPTT\h PZZ Zfݏmj1gZ1LG`P?Ь <QQWQ\qQQ`QQ URˏBR R5gg$XXR RQRR S R R\QU \ PP0~lʛdfYW[ݬq\kS1p\ `d}~\hPYݮݏ3mi*WSfS ݬPPjX'W^ЬVnV8<@8ЬTTgPR R1GRRC8TgPH1о2t[PUUG ݏm1z|~(P ݏm`1\PS&bUOVPSUBSУS;)~~(PSS SM It[PZZEZc ZAƣgЮPYЮX1TYЮXYLX_YF®XPY<ĮXEYRƮX6Y=xXX*YD!Y'TXXPVP vYXvXT1|Y1ݏmn_PP[Z_Z'YX^WЬVfP(ЬSSkPUP=W(SkPUU լݏ+m^U$W1?(PɏPP~@tVPPZYXW^ЬTT}~ݬ^P^ݬ?nnSnRSdT}~~P"1T}~ݬgP1ЮPPPPP UVS VS@ S-gi1ծ3Ѯ ?gi#giVSRh%ѬhP@nJhSծSRdUR}~U8~ݮ ݮS$~S Rj~RjV+giЬPP0WAV^Ь SUSU~CgP xSP~@fP`PP U~CgP xSP~@fP`1U~CP xSP~@P`RRR@ݬe xRPPnxRTU~CgP xSP~@fP`TnQTnQRRQKU~CgP xSP~@fP`Q}~Q?ЬPPTSЬRR ?BSdѬ ݬ.IdЬP?@!IdR ?BSd<UT^|Re ^ݬdnnPPnQQ SGP SRn5nR,n%PP SP R}~BPRּ֬SR#RSe ݬ RݬdP@@ RPSRRPTSЬQRQR~AdP xQP~@cP`@R~AdP xQP~@cP`&լ!R~AdP xQP~@cPxRR`QxQPP Ь PIРQC<`SԼS 8Ѭa*QСR<P<P<P S QP S R^ cbXРP2  ЮRR(ЮîPP inP]ݮl)ѬMf®.PRxPQQSPS fݬR f}~ݬƋQXW;VDUT|^hfg,zP<`Rݏˁm%NSUd^(ShfgRP0Q4QQ dRKP8d^(gRP<`RhfS@d/PXd^(wR|^wbDbtyP Pc MDb^(լHլCY|VGX1WV\hPVPPhP(PihPPVhPPY WȐV|^^ݬ^C~Z~YzXuWLV鹿UﮀSRգRTTTR ݏmfTWh~ݏmfRWh~ݏmfRT10~FReNiPPݏmfPPijURcMijPݏ;mf:}Re.Wh~ݏKmReWh~ݏCmfijR1kcS1 T^(PB\(DB\T{ tP <[P[[Px PPPP<~ۮЮVVS(.)c<"YYY <PPVԮQvvPww%}u~tߟPݏmFDSTC C u1& TPYPPY mܐq䟮\Pw{w!ݮhݮhdrPݏmCPHwBw!ݮ$ݮ$d9PݏmCct{\PwP!ݮ$ݮ$dPݏm_CuЮuզYY u ݏJm*CtPvv%}t~&sPݏmBЫ(,6ЮtЮ [Pjj oݫoPjj#}o~[Pݏm=qqel~ݏÂm= fknf^ݏm=GqR1TUOq1e RТ Xâ ePSSVSVYWXe1VnXnnPjP!}n~[Pݏm<լ9Rx RRѬR)R<XXRx RRRѬRWРU VРTQSaQмQcRQcRa| |P`ЬRb bb Ь ԠlլWUbV Tm[mZ0lY5:X^n ݏmhmP ݏ҂mhЬWmPՠ9kQvmPlլ ϬݬϛnV^ݠՠnVWW*mWk|~Y<~HPjj j~ݏmhW<QWQx QQnP(Q nP}i Qx QQ<VQVx VVWllQx WRRaաР}~˴XlWlVlUT^eSfRGѬ *ЬբvЬn ge~ݬhSeѬѬHbbRRPfPb}Ф ge~ݠhSeddZAdf[ZkY38X@W|^ЬRyTgPՠ2`Vf|iSki|BPTSiTФTT3ݬgfPTT!^g_jg x^ݏmhjTPg kPg ݏmhԧ gTP TAfPՠBP>P^f ^ݏmi7@Q@QQ Х < ~ngn ~SЬRУQ*cPRP!bRQRcݏm3RPPݬP `Q@}P }Sѣ4ЬPP( УcУգcRPAcףPt}P<Uk}Tլ~ePdd1dPQPQ~ePddP`%dPRb 1EY1RRPRPQQP dRRPRP QQP dDRRPRP QQP d0RRPRP QQP ddPSdSdQP@dSRPRRPRP QQP ddPݬeePݬe~ ݬݬ|F|VЬT]fԦЬPfQզ1yeRRQkTeѬ  RfQ#PRfQ*PDЦQ<SQSS RSUTe eQ SQQ ԦRfQСPPVPR~-!ziТPPPPP,dSPݠedSPՠ1 ݠ1#edSP#dSPՠ5ݠ5*edSP*SqPP$[Y^^ЬSSPtRR>@QSP<`V iVP` <`ViPVb~ ni}qPPX,iXWSbPP(Pb V giVXfXPP ZSR c*qP#KPR~ C}bլ  cPRPP8ZpP*PR~ ЬbPPЬR9 D ? : 5P`T SQA`TSQЬQPS.P%1%%11%1~DŽ ТnnSPPЬ PPPPtiRmibbP<@`ԠPPR<UR ݏme:iQ/iSQ@aTTR PTP%TRСBaPСRa`PRaPСQУSݏmeP hSRQRcecPRPXbQSУPQRP P PQРPPRRaP@aPPPQPaСPРСQRbQݏmݏm|ݬPV xP,nPfVPP"hQ aPСQPABSOLUTEҾ$LINECOMMANDFILEJOURNALNEW_VERSION OUTPUT2UPDATEBVOLUMERCOMMAND FILE: "!AD"!ASIMAGE FILE BEING PATCHED: "!AD"JOURNAL FILE: "!AD"UPDATE QUALIFIER VALUES:  !UL,*!/!/ PATCH Version 4-00 15-Sep-1984!/'!AD',-^X!XL ^X!XL:^X!XL !AD+^X!XL!AD+^X!XL:!AD+^X!XL'!AD'!AC!ASEXIT0201DATE/TIME OF PATCH: !%DECO LEVELS SET: !UL, octaldecimal hexadecimalbytewordlong  noBWLODECHOCINOIASNOASSYNOSYSCNOSCGLNOGL1  * &$0(!/&').%1Emodes:!ACsymbols,!ACinstruction,!ACascii,!ACscope,!ACglobals, !AC !ACR0R1R2R3R4R5R6R7R8R9R10R11APFPSPPCPSL'!AD': !/old: new: symbol "!AD" defined as !XL&symbol "!AD" redefined from !XL to !XLsymbol "!AD" defined as !XL&symbol "!AD" redefined from !XL to !XL PATCH> OLD> NEW> LOC> NAM> EXP> ECO> _>fghln y 'dg 'cQ 'R 'i1., 'jGc 'G '-!"/ 'RkcG ' 'A ' ' ' ' ' 'm{cH 'A ' '@ ' ' ' '{@c ' '{ '{@ ' '{ '@ ' 'm 'oc 'A ' 'B 'SLF)=DHK>MG 'LF<R=+ ' ' ' ' ' 'D ' '@ ' 'O ' 'O '> 'G ' ' ' ' ' ' ' ' 'c ' ' ' ' ' 'B ' 'pqRzc 'qRzc '*1&$0(/'% 'Bc ' 'A ' ' ' ' ' 'z ' ' ' ' 'rsRz 'sRz '- 'B ' 'A ' ' ' ' 'z ' ' ' ' 'tuRc 'uRc ' 'A ' ' 'c ' ' 'pvRzSLF)=DHK>MG 'vRzSLF)=DHK>MG 'A 'z '@ ' '@ ' 'A 'pwRz 'wRz 'B ' 'A ' ' ' ' ' ' ' 'z ' ' ' ' ' ' 'pxRz 'xRz 'B ' ' ' ' ' ' ' ' 'z ' ' ' ' ' 'z{c 'z '!"-/ '|c 'A ' ' ' ' ' 'Rk ' '}Rzc '2 'B '~zc '}zc 'z 'z 'G '> ' '> '!"-/ 'pRz 'Rz 'B ' 'A ' ' 'z ' ' ' ') ' '0Muw%Qu X]{'' ''LKJIH'-''5'=?C''A}؉;FK;I;++T\qa'V]XRZ[gR_jRjbRef'hRcddmdoRbdsZfRN}.؁.'_^]\Z'؜جR'R''R['..'++'#Y~}|{zyxwvutsrqpo' '  X+O4E04ETRQ7;9 >CAGILCAS1Yqdf`dfPNM iol'mONM#_^]\Zؠ_^]\Zآؽػغص# <? <? <?#<?<?  <?.3Nn' $"v؀',*17':J<'>'DLJRTZV'c#hshskom Iq Vuwy Um~'l'effgghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhwwwxxxjjvvvvoosssqqquu{}}~~zkk||ylnmmpprrttiiiii<<<<<, +<<<<<<<<<<<<<<<<<<<< <<++ ,+<<<<<<<<<<<<<<<<<<<<< <<<<<<<<%4)!6..5,,8<2< 13("0<79<' <<:5$5<<-8;8<<<<<<<<<<<<<<<< <<;8-82&222*##.<<<,=K!ACP4 Dllold patch area size: !XLold patch area address: !XLnew patch area size: !XLnew patch area address: !XLDSTGST!/empty free storage errorModule Begin Phase Error.Duplicate module !AD ignored.!/Module End Phase Error.!/Misplaced PSECT.!Premature End-of-DST Encountered.&!/PAT$add_module: scope depth overflow!/rtn end without begin#!/add_module: scope depth underflow-!/Premature end of DST in routine ADD_MODULE.!/DST MODULE misplaced.!/sat overflow!/lvt overflow!/FLD not supported0205^ЬX<P|~~ݼPݬ|~ 1ݬ~ PWWP7O85AAB.:BA$?B)C/C5C;C A C9>7O8A BBX;BAR?BACHCOCVC8UEU257UCUUUU<PQ<D ~ v < 5 OV c ( V790V8SSV8NN86008100V8NNP %PAx0, CI Port is Reinitializing ( xxx Retries Left). Check the Error Log. % %PAx0, CI Port is going Offline. c1Х$RТ8QBQ04$< QП#PA`QPޠXP`s`Q?(X`?TХ$RТ0RQPRPޟPР49У AяV750ϴAūTd0R09P ńS.PP PrQ2PPS}T~,Xb}TńR04,4¬¬¬° ´ ЏH¸¸”LF=P

ńRTUtttx€ F=´H= $ (П,?,<(0}}ޟ6QaPPQRa0P0 ńR<@= П6P1Х$SM 02Q+xQQQdPR,?,b?P0/0R0P1ńR1T0R e<P$Х$S P8+УSUTńS~0R0.PP ڎ1 ڎP1}T~0}TńR1TV750>QxQPPa1;(.0.aTRT0i'ЎTP ,P1P1ńThdP1<P0P0sP10R0ń ŀŁRŀ 0jRR'RŀP02ЎRQХ(PU2P0.1(0n.1#2 P0.1P0#.1P0.ŀ0C+1ńRGޟ6QaP PRPQba„PTП*Pń՟7%՟6ńT h0-0-RPńХ$PԠńR ŀ1]10R0~~hŠUH`Uڎ`UhcPU6Ѣ6UPP*<QPQ`  UЎ0Pb>?Ѣ6U'Ԣ6:U}SH?0,UQSU0R0uPQR1QPPd<P(1e0 P2У,RУTP}} УPP}}УPР4lS4(<PiP7ЎP(1T}$$ТPР4lS4RPТ,RԠ,PPR,0 ޢPޢT0 ЎRPP0 1 (<P0M 1( 10 P& (<PУQ 1;1)( aM.0P+<Pݣ ЎQ0n(<P}T~УhUݣd0U 7<,P}T<P0$ P&(<P0 10 P&(PХ$Q(1 Ў@}S Х(P`e<0aP}S Х(P`e԰Х$QСRPХ$Qޡ8PХ$QС780&UhЎdЎS781P1%ĴR01U<PT}S ЎT78 P1)10w0P0pޢQ27Pf( ff1R0ЎRPB0W0c0hPPFFBF}P<b&1<b&}P1С@Rԡ@B>PԀԀЏVMS$ЏLOOPЏBACKЏ P1УQDS8S0S*P*0R@ЎS!0 '!bТPТPP1PⰢ@ТbD<У,S(B<$PHFB0%P 0qP00<$P0 PR,P@Pɏ ` ĴRɏ PP]b =P0)RĴRɏ P1ĴR ĴRɏ ĴRɏ P]b =P0RQP `QQ|ɏQ P<PaQQ|PPPQĐRɏQ |ϚaQQ|˜PPPQĐRɏQ S|СTRԡT  1IоScTУUP~0R0UP~0ڎPЎPЎPՎ<DhńT    PP/G\ 01$QL~P P@)P`0n`)*PPՎ1ՎP)PP 0:1_0]1T1hPPUU\0ERP0rQ0D(0P" PɏP <<PT0kЎR0=16P wPϰPPUeޥSc cޣS2P@cP1#PUQRT01P0 0 0 Х$S1 i=1~Vc=U|PUPPUWGPˏPQP RWP0QQS SG$0P1SG<ĄP(: $"0P0s>0PPЏ>c=Pd=Pb=QQQPPP"070Ʒ"0>P0$Џ>01Џ1У0P}(,R0P1DR@0P1RT0P10(У0Pޟ6RRQbRRQ4Ѡ))3.Qһ)DD1T)DD1բ*RѠ,,Ѡ001S?(<?Ѡ,,oѠ00h PRbScScn70яRяVMS $ DR0ޣ88ޣ8<У PP4<PЎRУ@R0E&У QQ4URURSQP0= ЎU0MպУTR0PԣTɏ <Ԣ0?P<Џ`QPTQ` ޢ ޢ RQnRЮSQ0H}Q~(,ЮR: @PP}QPDԡ\,P@Ec<P<F0SQ1r0 P1ޢP}L=ПF=ЏVMS П+} b}?П?}T=}@+У0P Ě0cPSPcSSP Q<PPĴRQ Q QUSޟ6UeUU6!ޥ SPѣ,Tޥ PSQЎSЎU|Pޟ6RbRR6-bޢ SSQcSSQѣ,T<PcЎSЎRPգ41 Ě0TУ@R0V0%0LУTR0 У0PѠSccSԠSP1SQP1 SQP1}Q~RQQQ BQxRPPQQ} RR ٨}Q2UQ6c1Ձ78SU|8+0123456789ABCDEF82 7b0 7/ 72B27}A27 !) 7X  A+ 7 A- 7Jx>l@ <6@96@"@=6J@ H6@ F6@D64@=6}@C6 @16 @B6=A<6A<6A<6A<6GAD6AD6AARA A AM6 AM6L P0'Q0R%СTRԡTɏ <Ԣ 0 ЎRA<U0R0PTńTd<,QŀT|~~~>P|~^U߯PHeЮU2P8>Q2P>2P>Pcn|~T>|~~<&~>UХ$Tд,T|~~~PnP~~T~PPQUS0 U^T^>PRŀ}Ф?U`U)SSPUP ?QPSQAU3?AUQR0?ĴR?@UnP?PSQ@USd1rPUPÀÂPUVQP RV|φSxPPPPQTDcP     $ ( , 0 8 @      $ ( , 0 8 @   $,048D     $ ( , 0 8 @ P~R0R0[P߯PH{P~R0Rf0-P`߯WPHЏCP~R0R50P/߯&PHФP P PxЏ0PЎRڎP0RТ0Q S~84$00P*ݡݡ0Џ0xSȏ(Ў0Ў01ڎП6S1ńRQQЃɏQ< Qߺ<QSQɏQPP1] Qȏ@Џ <Pŏ'P,Q~ПT,nnQPՎP1 1П6S1xQ Q< 0Q UUQRURR PPЎU1UQЎUńRx,<Pŏ'P,Q~ӏПT,nnQPՎPPPP1q1RP PП<PЏʏtSRS0ЎQP  (QQ P@(P0ОScTУURRh0OԺʏ}R}TRRR'<<<'}P~2 P0}PRR}P~0R06P1}P~2 P1~ОScTУUФRR }P~2 P1aRRR 1R11 }P~~dRR1R1o R1Lڎ}PӏR(1ОScTУUd8 Rx1dRӏRRdОScTУUӏФRR }P~2 P1 R51}P~~RR1 R1R1R1ڎ}PtӏR h0}R}TӏR%}P~ńT 0cT2P1R%}P~ńT0cT2P}P~2P0)0R0P<,QŀEQ2PPSńQХ$PР8а,<?eeee!!K1 ?>tP9:4d,4϶d 4edϤϡϾϳϿϡPPPPPd? Х(QT2ЏQ0 P%ńP|Q`ԂRRRP}P~RP}P~SPL~QQQ`Qڎ}}}}}}}}}}}n}@+}PńT?8888!!1 ?tP 1x RR RRПPpPϢ,02ϝ,Ͼ0",Ϻ0,0)7}żx<PХ$Q4 PPPĜQP@TRRQRnRȏPQ(PՎP1&@,900P 0PĜQRQRĔQRQZХ$Sԣ4QdP1RRQ0г8P PPП,n0b><Pa0^P&(1(&PP'>@Q@a@7<PХ$R(1F@PRR<PТ78Х$Q(1@ХR<P@Ў}S Х(P`e8ݥХ$Q(1B@ХR<P@Ў}S Х(P`e<ݥХ$P(1RԥQ}SЎ "* P @4PТ @HQaP "b0t0Т @H1ԥ<Ў,e+7ЎU}S"6!RBH(B4RBTRR!"R0&ЎR0781pUU0UPP@0{0TR1gУTUPŪ8+ޣŨŪ1 4PUDRIVERX-822-MAR-1986 18:1322-MAR-1986 18:13VAX-11 Linker V04-00 .$$ABS$$.*[SYS0.SYSEXE]RECLAIM.EXE;1+,./ 4-0123 KPWO56wƎ7@(wƎ89GHJ 0DX0205(E RECLAIMX-2Ŏ04-00  ? ! CONVSHR_001(! FDLSHR_001 O! SORTSHR_001!  LIBRTL_001  \WPVHUKTϞS^<PR@*\H@PR18dH<d~(~eSPHac@cУDP٣PP~S0~eRBH䟮Bafn쟣gRߟ0(䟮 Tfn쟣gPЬSЬRQЬ PzcbQ`bTŢcQTQcbQbcQQ<`^,n䐏Pݬ^|VX^,n䐏Qݬf^PRl լ  ݬylլ ݬf RP|MVD^,nȐSȞ=؞1ܕlլݬfЬ̑lլ  lլ,n䞭l լ Ь l լЬlլ ݬf^<`^,n䐏Tl լЬ^<`^,n䐏URFݬ0^ !/ RECLAIM Statistics8Total Buckets Scanned: !8ULXData Buckets Reclaimed: !8ULIndex Buckets Reclaimed: !8ULTotal Buckets Reclaimed: !8ULElapsed Time: !AS!_CPU Time: !AS*Px$STATISTICS DFILE_NAME X@@t`HPx0  @CONVSHRFDLSHRSORTSHRLIBRTL*[SYS0.SYSEXE]RENAME.EXE;1+,./ 4-0123 KPWO5698xƎ7bxƎ89GHJ0DX0205(ERENAMEX-1 Ŏ04-00    ?!  LIBRTL_001LOGNEW_VERSIONP2P1TS8^|,Ԯ4m~ЏԮЏԮЏ(Ԯ,Џ Ԯ$ <~8  cP< oԮ cP `$d O,dP;$@ω. $|~LX cPRRR\ծ4Ю4P<ݏ3BЏ3PPЬPРP^}~7!AS --> !AS ? (Y,N,Q,All): <U^}Џɮ ~~} RR PTTET9TTe%Т(PnР}~ݏeTTPЬ P}~ݏXORϼ,ݼݼ ݬݏ:Dݼݼ ݬݏ1Ѽ Ąݏݬݏ bݼݼ ݬݏbP ЬPРRRCR :RЬP |~pЬ PРP`QQSRS`< P^^P PonP<^^jP PN,nnP[000000...]*.*;*Y&X^~Ԯ,nPPƐϞPЬWЧܞig,n`P`PZ\Ь V#`,n``f Ц0PRcSPR~p}R:[Rc:RcSPR~p^P r}ReR}Ree]}R:,RcS TTЏ000000RSPRP* %%t%tstPT* %%t%tqtR<`^,n䐏Po c ݬ) ^| VX^,n䐏Q%  ݬf^PRl լ  ݬlլ ݬf RP|VD^,nȐSȞ؞ܕlլݬfЬ̑lլ  lլ,n䞭l լ Ь l լЬlլ ݬf^<`^,n䐏Tl լЬ^<`^,n䐏Uݬh^ :--- :0 -- 0:00:00.00-ESTODAOMO@6i*ޮ^,nDnWY^ЏԭЏ(P,n0Џ jiPiP[iPiP<iP˔iP˰iPiPiP@WxVV$(V|gVWЪVV&(VgVWj ɸjRPЏ!ɸS#,jRPЏ),SЏPSkPXX{Q#PXXXݏ\!"W.VVg(V)nGWɨkg ЏPЏP}~ PcPIբ}~ݏcPԭ}~<>~PP Rq^< <~}~ ݏPRR4~0~P  PPRR ݬ^ЬV ݬ |~|~|~} ~ ݬ G,nnЏ nXЦ WW (W$hWXЬP<`WW(WhWXnPPXWW@ݦϯ Sά^@< <~ЬR> ЏPЏP}~ PcPLբ}~ݏcPԭ<>~}~0 PP RWЬVfUЬTUV)@XXWeUVϤ811~wW91@XSS WWVVPϚR|~|~Rݬ|~PբЬP բPPW^ЬVk(fQ ]`dOPP֤PPUPUP0PQP070qPVQP0)PVQ0ЏlPTVfVVTPUЏPQQPU:PѕqQP a;PaVQRxRRRSRfRURfyU RUfZSRR fSRUS R SS $R fR fRxRRRPRVQ1bRSfSRURSRf RUSSRUPPRx RPPxS~RRf SnPQ19Џ PRTScSST ѣ RУ RPR PRR>RR ]`dQP^^QaPHP}P^QaЏPTмPмQQ¼֤ PЏlPЏdPTScSST2QQ ãQRxRRQ RRQPЏdPlЏ4PЏDYЬSSP}QWP~ݞ, PPЏPPV1QaPQPQR<RPRRQRQ@@DbEHI>K7L\YJ`BPVpZV}_`G[]I>GRPjiPeЩDQ~dR,SbS}_NET0: cQJQ Q QQ?(bPPPP| }Q~0}QP}pV:=Vg1j:/Pa3P?2j(:*Vg :%Vg:?VgjШ(WOP4ЩDRPoP<4P/1j >i<P ?i<Piiiɔ@gЧhQR QRQ RQRQRQRQR QRQR QRQR QRQRQR QRQRQRQRQRQRQPPRRRgRgЩDQa$$a 4a 5aQ QQ@QDЩDQ~dV,SS(ʴڸc>i(ptcæSf3Џ"17="æSf03PPR<(~P R(%i1IwЎR|~|~VY ~  6 1gPШQ0p%V>V ? VШ8Q0O% V0V Q 0$0.P V0Po0Y0{.PfЦV V0sPI00U.P@ЦVV0-V00).PV00.PgP0$0#P0< 0<QQ0P$0$0-P01/P]EF0V0lPFE00P/0.P00.P=iPgf((   (1e0P*ee0g\e8g2iee$g0@eUQRQPPR4gQPPR$gQRQRR4g ШQRQRQRQ RQ R QRQR4g QR QRQR Q R QT#(PPT QRQRQR0.$g*QR QRQRQRQRRQ0b" ֟TVЪDW0 Pg 1N1W1O-jQ g%gQP0! Q0 0!0+P1"-jgP0!TUS<RTUQRQUU8}R  (Rc 5:PPPPCUU1  # P PPUUP SU02!(} R + RcP 0*PC -ja$g]0(,P10]0gO-jFP0   01 1g"0 0$Q.RPЦ8Q a ( aeSU 0 P0<Q4g Q0 4g QRQR0QRQRQRRQ04gЦ Q0ЦQ2gQ00F P0TզTզTզ T%g,զ(TTTT~P&T~ PT~PT~$P0 ^^R^`?H b0bT(be( cSU ^ P0mTզTTTT~ P0{[P0C[զ [[[r[C$^^R^ ݦ ?PP<PP(PbeSU$^[P$<PPQQPQQPQQ PQQ0Ў[֟ЪDW-j$g30ZP,0'gP0 500e&P0'<ćP֟-jЪDWgP0M0v֟|ЪDW-jg0#&gP0% 0N֟-jЪDWgP0 0.֟-j%ЪDWgP0 Ш01Y1`֟l1N)֟1E)֟1<)֟pЩDWP0dP`R0PXRgP00<Q000^%P+0&P0&g 0&P0&+U =UUUUP!! U#kUUxUUkUxUUPUU <VUV <VUVV,gg~PԀǠԀ gP0VЏ}QЏbR000f$P10%PBC4gg gV@ @V@<VV "VVVR0`PQ}RpSVSS<VVxVVV@@Vx VPS:"c::cSQR(RciRhPPUSSX/$<ʴPPQPR(Qbc5jj"}pP5jjpPtQ(Pac1j (c:jJ j*~0Vj\ІP(Pc...\S(04c,(8<c (ptc4g2j;Sp <ʀPP8g PSPp 7gPSQ.aXSPPSUP֟tЩDW( g g 1 &<ćPV0FP1RRP0 00p"P1V!0uP100T"P1>ЦV P0I$Q0ШQRQRQRRQ0ШQ00L0 "PSgP0  <Q0]0+0!P20P&04 P  0*#PЧJ0#PPWWgT#-f@ЩDUTdg<PTWPЎW}U~ЩDRU( <(~P(yХP ` bUQ0BVPПeUfVPPПVfVfVfU efUQ0 0LP(P}UW0]SWP*,nXgЩDPW((fk [PЎWP`Qa`1XPWgV=fg|~|~|~|~ <4~<~ P<~PЦ[VT0^P QTݹnP^|~|~|~Ypm <4~<~P P0ll<~P Ф[0-^P ֟`ЪDW * 0*gP0* 50 (.00P$0 PK?NЧdQRQRQRQRQ RʏR2gFFG֟\ЩDW0iSV0PDRR@P00(0 P(V0r0 PV00 PQQgP0QЩQR4gQR QV#(PPV QR QR QRRQ0(g 00S P 0VPV1P0gP070`0! P0s )iPPP1?VVgP0VЩ@Z0YZ00 P0 SƧ%dA:iN ta'DP( Џ P?hRiS Uޥԅ"RޥexU U@R(Rce U T|~|~Te|~<8~<(~ ?UUPgP ((U}P aP aPPPQQQQRQQyQQURQQbQQQЬY}Z}Z[Z,0P0$~i<1X00f ff1&χX0r10ZHXf\\PP\P*DQ[ZI2@[Z=3\ [Z/4<3PP[QQZQZ0 804ih111W0?r5Q [PPZΰ@BCDEFGH9X0( DPxPPEPPQ iPF!iP;"iP0#iP%$iP%iP&iP'iBGiFPP,iC $*.**.****0i 1i2iB@FLLRR(:4\\L:X._ekq44i.5i(6i"7i8i9i:i ;iGPWQ0EЎPfP0EfRz0k0_f f0~0r0s0t0|f90yx0qg 0iw!0av"0Yu#0Q$0Il%1X09@0!XAjsNqc;{9=8}2љ-8H}sQKB^-Z' `WHKi{"u5Gu2i~b9G Mi=AG؝P R4Mdꦔ9f); 2*ܲBzŦu7wԭ =t>Q<R^!w! L) %6UHQ XĐ%|cY!70A5Sh]!4X%D!?BZ㟗?qW~^&2,gEb~q2 'h 4B's Dc *HmlX>5߂Z-Xa'՘-bZ1`&Vd̹c,*ww2liv5h8{{:aZ kByt=VO|1ɋUV#*-N6U']E+Fd i` itV.Vߌ#u9n"D8a{(75 W@Fl8S*y/9J5"tAǐ$9t8lqSjmg+eHVIx㴡k̀ޮTO2<9Dn9O_v Y,m͌GH{ǵ&#o8q^?.\h)ׂM}h `;bsx#(N]:$ MO SaiPD@Lf1lӭ͟[M^>}U>YR.vbq~*$MAc)OmqX2uz{B,+P4/x VgӀ%]tpSD#2(tO*Xz=$DIN>h3u_3>%hadSF }DE1wA_mlzlJ*: umȎ~S}u[ C9gW뱚@9+ fGUK m_5n/[o"BtjD(;om]LbHMm d滭:~effbH!ud^+y:anKA[JYG:L{84n"Krso9Z,B6Tү`ʸ~ה][L!1j>|97G.'krj)KJ0 sp̊<2 }[ p?x WmA"#{*;6ȖJSTYSğC(O2\ !ɤ'zAARRpt6?́=<(Tdi| m@1Uw$̝oD\2WD}-xJMX{XeDci{tK֜e*ץ@(҇d}%\XT dI⑨m h/CT95inc2dGFKjcL*9ig[?O8tV3gpևP}o% dG_ΰh]?sT0CO9yi˺BZQQ:*=(,?V@h.…IFL 4#p4fo,܂8=|[yvgrlTӎ^ #;=C.TIJ҃ORxR\ٵaMJe WQv&Gf}]gVo 9u=撬Y[ 3Kw~wE6_ 5)qI&^F>)Ň^𖈁J⍸*cS·i#}vK*w~Ġ "e3[\f Y?o(N3wOSB'"L 3hV(ZF+b<`M a B$Qϭ'|Vm, ض|nQ]*Zb01eF?^3(?o|)?I| }iH4JH߄׺5#@GO5pbH/KWQkT-5aZPp<;.ORYGjw$Fǽ:NZaʼnf!qeq$_l4nה;-HQOȭ3ཐΔpZu!ӓ]ƻdo*̳-a@Qr1i8d R1^Im2-]VkXRj)[hL bw.);!(ÅS9k_~3ԵoAL y@;e2+X & m‰FHlߏfZj{h>)yHܻBtS?->-btk=.Zr=Ǯ;^>XATWY7ySggH1 5͛G@3-+K lR dlq;WIeWH~OgTo_)jlq1v4*Z񹅡Ps)Lͯc^ p:pgUVrUWX*ٺ(VT+Xh'@g3;wmerP} y,; gʮ)#Ӄ):M(vayc&4]JTv59ZمCqG|)YMWy!E5=\4|2;f2< YGWb:ӔEJ9ei< {܍[a5ԸݾB|lu\&ui`\?>զOAy!L XK -Ofw-x!q*9?|xDݱG ?bYC P3V 끀Rs4iGXҌ[z%A-2{6uկV ;;۱t[1ؚ dL#GMCA?;_c&K]d@ Aɽ<>6J./75۽a.jG/fB^k;[ӻ V)R +,#ɞ̛R&oyNWsTZ1-'(m/vYmU.ul.] /IEλe4 X<}ypz9Yե2PΣY0>um 0V5ыّ_edZBU!)t{ ,jH*NTu7L",48dw; |&`D "xX.#w'9Ǘ Mh߉(7~D tDZV $7H璴Lk=inڪB(/Ao0EFVߣI -QWc 9jMq5;Րʻb=>TO5 `Z"(FTH0Ls"9Jt>|)&pY{d=X3$wN }$9Xt^@nvV,OAQSi*pp<$39 Wg![cG|%[dlad(&6v#;f䶀uZZ ۴[3: Z"d)Zj=O1Dj+ .E.0'9,FrD!!"6%JFׇ@HBA1 z1 g`qOJ׭sni$ߗtڣN.k j^PPDaIJVJSy$L=1ռWNʆ g+ݏ|n)?kWG^8NnPXrf9[a ,=o ~?uhhUS(p2՛W$1ցE;b!ϳthJ"cmQ="8жpZ|d5d4qGv3uq_Thz Ut!=p2٧l^RU"EP}T5ktp5pOCDzD>[go\olI=ll!:kģ)V}OEm -&whNAwõ6x\*!男Ķ.\S+W8kF?β v̚Zt#3=:Jo8ℂ4GVBGg&*kᩎ#eIMsalAyڕDoJ|l grqf"5ԧj8\i&8y`Ro<jTi0O78k]z0L3]W)MRdW!Bta'xf;'`1em Ұ  A #|&~? +w7p Q/<38u2x7jesz7vNvڣy(X5^i/X1sEɅw@!nV@ wcu :#o $ 2aw,n`.ੰ VD>fu 9ɉ"0Arfg@YmEW~4yQ3EGO*Y$u-8fN4R}o_Hw\r .m=<-苑8I,_W2~:TKNA9׵x ά.},tHC jYpcE0xCyA%3׊jl5sяEj{DGz@棎c+Y .{m'ZajpIa=p5cV8,UCn`NJ7RfY@f."e+lA l|K@Ø#H0:68$R(^$2nhp`=nr wYUА#2 g .z3T785KiDWQ%SGN&*n1rR.>KL's0.5<ܟ?Hg0pF(RCXe+泻ڏ W2tC'H~@_X@$vNS WégL<& y$SiP Rzɮ{XE&HҷN^zxG݆16M&|x 0 -Y{eC.<_cls,0I U9zs1|I5f?;g- XpqOa.4xj\';w;$9nݓdSwIWїhsSԂ$DGF/O`]LOJhΠz+*kV:3Ǣnu2幢i.l"FOλ_p>-;u=H$Vf9{l4p"Q)' I#Q}$d [wA:M|σLbç˻~RzNno(q P/^ 9x4l.BP<'-t~c~E:> _|<0 /O~9lI!y=CbGsnœG{㮥[%U)' $.+a":B':t,,, Gk':+EhFGiބToIs8U'xÕ/=N m=8G@uSV%/2&~1 ]hDѶgbCQ.}͡!^^PbXZiQ녅X;~Щ$gv6 ᣡC;f{aGpI^ 49w)Oވ~USǩ)/ U93*aqIX2\ ܪyZmB2/VxlpA(}Vwfd}EqjTÅ2nrCDzyq-㼐YCXȱ͡ᙀ@d`9,A ,FGI(5qo8I:11>#(3NR~L܂zvl7 ez^F( jﰨ> ZfڅGMoɃ:GRi*яq_lF±W/QGz6if_mɵau,f}S"K҂R:ԭ5xnF1^FIPU6<1`Qnq4!೒m~E餴XicvOqJV=I!LJ/>KJNwSMcH_we6v5WjC[00np`5 ?[/ -uj+@*!$Ҁ,8xR Ohr`!Pb:A+VMT8a(0/5C>i"v47`:e{K!G[+|^W"T@~ |S+Wma:^gU~#DDnԨb\?RJ0UXLH!w=C7B0Stx6.LgH4#hL8k}B6ץo7nt⬨Thœ~Hgˁσ' dcqDO D8LdI~a'a;\v3gjxEg6 /h4LpJ?f#bkpD@OTo(-uE?7Ibfb/[c3 P##9 =_Z[JƖ0mxv.*@ex8tΞv`bjqqTE8.KatKJ`}"1oEȚ\ WŃ - &5uWH)PͣK(#ܷF9aM5կEΆ=F~ԳȽ{n7' Ckx݆(M[w3OnNG Yj`yTNKJz%3:{D3haDE49#ξef'A}6,?E BT"%̣C7Єi{Z~F %ç.>ay3ӥ&?S!q9mpEWl}Q6v"H#i>ݱ4"O˷K'mbœо΄-\"`3'>+n5wµ;uslTzڈ];Œ+Dž /_NzPF yA̸kLUTjOٜ-&4|G1?W?F~V2DTGͰ@Jifd]F[Vet ۴)M͇EϕB,TBǍY(у'$!5$iViUjږw-pc@oSU{L+06ѥ1AQ~DB^iUbKhumtX홡 /q:H&{M2IFCR$ҋɻ r9*Z`gݪ"W9!VB;&ܱbx7PhFva'X,7Z7vtC0v<~2=MfډdOAIۈ)yHeu?m$44 OR*D"P_ Ԫ"\*UVMOƃfsNj^e&N Iu)1 ^IJrL,3T`xbUе3G)Jz(y;-F+ 28)dRIMMڥMMU"c%yҀ6ۥh#>aū&s&Y)B<,|釠Hsh 5QcM߁Q?Z"?!XXR2Jdɺ$ɅnA @B+8_^ Q]@Y\~b& =터BVU8 O>VZfVy>P]kGXO\IADA6+C,(Z"דn't<(X^U)>k"<:;2Zv| ݺw\&)Y 2>2dfm~YjoTC+PMbɝ`!˟rJ&`FnC/ Bx=S0Qj)k+y7l]TzIVTӁRqIb0Y36RX= ރAyr7̄sy,3=O}(|~3-fr0Xy߆Mj㧵 +bR9HAnfF|ڦ!X^\1hM3/%F~d}!{Ń6_ɋ\pQlty[@{\а[oAE2 o%EPWH4_e'9 A6;f셧Cvy1EbbZ@c>|?p j=buRCFfà JJUsR7vzAH*VDC(¤a/oz㿬 ܷ=\u1-klRWM\CAks7>ex"dr7wzIzYѪTҠ:oBtA.)CC+q{[No5];gWp@r],JZĘE٢+HNrƈ8|Xօބ2EEx%60$w$8f1y[`͂^C6/.uuA41'))̖NRžv{bt!wiq|f E!:dmu,yL-1"ꈈfe"xUB>!p8s jtY^kboGMI&3-;i~+C懌Fh-ôII_v^|[!7trJV8: l(V0ϐwp. >|#xgc&\nY)c ~6z؀N*҈`[hɀL6XwL|.!j[ ·X )d;`#g%n{ ؁ph}9pTїhX$j]^I%KVJbL+PH/#L;!t,'J/> (a+(ZjBCAᑑ|&OtdTF6=[Ʒ;1zդ却EFdpz UBF]mc2Π<d;-qW:TՌa7Qg1Um"kSQȚ3ۀr'܁J\C~?:SZR"Ӥ,|>_gk,-\d{Sbg$C_)-'X^UG yULWr"mO&S(0_Q%gp{a ѫE]%JdCo2pdf3}]PۏA=O ]_JK4wz cfXlbU-xh50p_*2˦Ы.zP[㒰| /'Ѧ\KSֳ=izj۫ڀ UP]9/$,N 6$bB0<"q墀ץ=',/HCOuk(I=#춈޷[ Of} eW } '%F*?Q5qxΥ"Q`A4G^w ڭlM ΤN$uZ';,gՌ?ĺ = K-SoǠU:a)c}XMz&5cT;@x/! <m{ _zίJԿf1BfU(~0\Y zaK_t@ZSX'E3 Q_eb3h}GV哖9~XHWs %<[frEIrsr$ c|N.Glb3NwU ׏jhڒHEnӮc <%~CЃnt Ni7XvIo ΂C ]4WcLc0+K3gTb( SPHzభB^G|e᮳C,%Ǿ⵻seY%WbQw<Qv,X"*X`8o~TP^ؐ0<!YgcK6YGwCAUgqڰLxӺٌtu0v[2@Yd6`WQyDѵ8#A?nnC  F ѬzsjUNj+j{wS["ZBkQi"=)+.o4B$1p>EC ; :n,yB M+N~h)hVB)H~HW )&qK&bL%y< Hh%:~a&dSh\*:ݶ6 lvYQ^PŪ;]r[LWbz1lҒOt$ȇ*&_K1 qQY־GB#`Oe5E;4GVS;Ash1qX}  Sw;xb!nձs l8RQ&d<yC^;6-$љ[? .:qA\Wڤ:% bǒ3ZL0X8X\':FX*obl1at/Ϥd;H Y4o$bpBN@n*o{FI0!9EQGivrM'?Zt5z wjy[f'aGJK-(%^ާ&"{;n4!x8B)d 2Dv4uafY];͒jKgڌLeaeeO09J90@@nZV˟BZ]xmP)O3WI- =M64S X7*R1 &rĹ>V{>Tf_f9IDrun\~:OƓOWȚ[:CVAb S|08t V,ZTylW6_BPU?DwOǂX]i5~P5~Smaߑ+9;綬i ] 7;;no 9yk./ge@gK2cFVܔ'1P u8=1CHģcn  5[ VէU?4w:ȶZ6w[HXHAžty ƒGZ|K URFD{"i@Y"^$%+WPn#abzqAט)o  ҼYM`lm^};2n@9Vo?8NXuX-(U^n7QL C Y@/8؛xBS"&T E(N# 䈌#Zͧ IW|4ps\I.{~1w= kl=!8R|#&i@ڙ*mˁ@.rR @9} ڂ~dZ&Y{?`9©Rt.Xoa_#}$uUQDp+WR7ۢ:!w\6rw;oH7qo~)i:^D=4-0N]X e‰C,_`dWF56^"Fwu߾v:Hѭ~dkDS̰ sd$$?>Haz Tʬ|T_o^l(t:eb:ym"RW$KQ*8|cZB`c21[5@,N rV#hc.zG_ݠN4)H(̎<2R*@@l?@4$R-_~̉jտQ țW6Y9eQ-[%S!k87j2)@KgaF1WpLE9%gvoMA 3cy`{,fb>B/⬋Uw]ʾw[߰UK@yXSj @GPDkѰCpT{iXz"izp+ eTF/I{ɤB<9qFk-?.R[@ s?vCEG4ex"&t\c&J q(XV KЮސo~F ߫vJVN ?nu(]zKD =edP%HEÿ*/WAizzb\o|ͦx64xn&DAe.y7w pm72J-=H]>_858փY9/z\q~ZZfx7= ?w y,Wsyg2o7z 럒ZI| XEYDSk:J"}B,=^8'Gtt]ҧzy[JF#V;ah?&\8/>$k-d~E.Ϯ׽SM<Gbea uՔ7fiV)7.V`2/qx^wxծQ%0. 754ލS %lF*U 7]91f)gĦjiĴYW焛˃+MF[VQO cq7wxkY]EBN6jGZoEGiK#|y TM*j.I5ze >I x<7;Y9ϩ4'CqG\&(<Jts",S~̼53vƀrl[0>Q Ps: x{GL E"L_~nKZ/p8]`AI|ucz cnvW ,ZohQ[@*vp:9܉3ʨ}ob4CpPILC( K,r~YYRdrCy[:Vd ӆ Hn 9dD.+Tub&A/[`37܀H\IfrqdFHb|0"$G߼}-(s KE/MߨN2NuQPv)?}_Y<3TFъq?7͊{/U.And^шYGNN4Z*  1Ʊ8-gvYy}z m"- f292lRU dĵ78 sON)+ VYvpl$T7|غ w%#Cʼ{3s }~΁/ډ+Xm_~炧[6M^LT ;;;o=E(iŒvƜ9 ^\gq 0ڟL 2T6ov g,0s&]1fjKW7^gcތ6߭j KF)Q8EpLz7fnŊWG9rb|B2t3%J榡\#w;>.E%IQ5ÙtIpSuǓ{i-3 %o" g1ډ4IJxKbf+__pa'gVB-muEXD{hqXYn, 5NCbRty޼;_6LR}^²=N͕7g t/ٱ:~'_J]m3:c%2GrNۉ{רuiDlWFD~LI%YpY`iBX)}Fr3_Kp7pI\w}{:;ેhCTEMLAYnwb6>qB6HP\|>Vā&c,ѼِzY]}kdHw&N! ƶ$d^5:@ JD^/[1il2'lᘷS`/H q:$Q6,~BbȰTUy>,2\$Ω_t35sLZ8AН!rDPm#CK4vK//'zy؍>G#[oZpnLѤL+WQqJ"+QytsˬkT5tRF"1]Uw YsL`7zu0;6܈91_:NucbZ'&iw6.Jwj$!Q&n25D5Pr>A%vs+ 1p+5i DF4,GC:{\#A~"H+ D%➌ء^+$ǓPird{Q E[L*BmsĘWEx<%n(#|gl!G"< wAZoXDZ>#*}#GӞ ڳTi$LF-?+ v4d*p*5O\*N$bvDtM3Q"& ܹpIKAj @+=2p QyzdT>9d zr.k.0WC"X9%a JS$@G9e%rVf,\ݗ fG [kÜp&+5r|R U%f+gJ׎4jЈ^Wv$:8bNwJ ~RI،4&BD?h;ͷ{Ɗ@ϊFey.Wxq/Igdlb({/i xtuğ[r5K*v}M$W(L҆ǥ|0 yBf鬓f)ݝm4J*v=M BC n*SJ"t<nHXb6y!)7:S.Qvp?Fu`r ɔPCAOsZ3IQZnS1WWlΗzqqz.ɡ=*W9+\[enJ Q4F.;|VPPWk*IRInR'O\5!/F-'7ti_0+sY#!qZu ` _q+)=pd*⷟jn0uO2E!5aÊ*A ÿ @ֶڭʼP~4D|L[aJd^{@9̙CӔM9(alO8jM45cZC5{\WƏI?Eu3Nmu0~,@ۃ5]A0zIGT Æ $VxH0& $4֎Jƙp HN8١YmoNP$w#~u-I=f$p%/GҜY~s,%;%HDi)Mx0EM*+tלm-RO.8SsU莲Tٴ ,Q?(ㆁq'QG2XAl{K r'2Qhv(`,K)Y5E,?FMj*H @EpuD-}NeKI=FJ(m1gH*!P]~R?C 01HSnoB)Ԯ}T@vJN ׄx8~"KKSLX5P #A_`Ē/i'܏AHU]>HςN÷[Q/o+|6+t> ǀֿ Dg$YLGh~zd!p?AحC:׸$+࡟BzT#]ߺO8Ĵpq1aP˟ϛ $-G)A]G2 pkO%iA =B{ #P#պ#tr}"\r e[GRˆEV&P tYν/ɕ9Nc2T3,t}"4WhjM7huĢǩ/X,# K2>$eSA^`Ďɗғ"*ʳ= G;$gd PxW|hg_@}%іsa1~K by ֗[T6vɄЋc=mu,i|D xĢvTk>8kblR>]us*Ԥ%ˆy1#\pM]?WA-2p*@C1(Ualq@Ob~*ŖR~CڽzAGG)gJ;y9xup&`˯G)Efpbl'ZnxW0k1ЯA@KFˀ7ETp9b1{ǁ+PJ8*uN$k2D<>?.]k_ 8\dmsR>4G փtIS.(kt5NBM+$vo>o3Cłz)a \%X4,&F,kתA Q ^eрp N>D3Q( ,vMvR@'ox\o *u ܒv5^]ABBމ LK`Ƥ_.U}(wn ێ$,MzRYlSpLk9ѾشS8Ɉ Mg>࿻э016 W}A~ThgҶ/ bXꤜ==d]7UR9+HaO5Yj2@dBI\>Air30Igá/AgjBKMj4V C^]4,ܐ6)n+h$ hNW=M$)UwOhEOPY-I#Ϭ"jvvh5?Q:a^;r5YhI[k\+z>V ^;S,/S:*>.{xf SB N"kYL ׊ʑ ][RS-34 v%^c؜ibIEyP'pvIؼԵMI~O87tHQgLَMSuEh2,ӹR߽FdSBPL,sgz=Y%=EEQZ}T~e}sx:X!?Zb '}\h$qϧ0foK0+t5HXkl}ϳ7b~/uS-yܕKH4>fNWM|ӏm<,9E֣۩ EP ZAe>⃨tal,oUR]ZLXsn089p C'="Ѩ] !Ύ@v.m,*W+CsQYh*J}TDΚf9ቭ~ t7Q=vȭ_0Z[BK 1il*@H QaX9O+EK͙wytHx̝$LcWzl%`Iܗ{`mrՇLwkho?'(S55}F_VM,q1 2E dRfc$n<^m/:rĉ\HٜrtGp5πFdAOʢm3vH$kyH=TPpJ}#d|*y,'Z%ߟY1y"VmCE-tc/ʍq>>_xL}~ ~[,#ː {)9c&"\u$d9̀MTJ1=rQr&L,@ SiY)$A d 5  D(}jm]d`Q.w2&",/ܣ̝+9*y@h\a@ZU$f2 Yc~u+5R [3w3JlHt ;mL^Ho;KPH<!kulʙ9(<ш׹W52-nDДD֨)AbnKpq"D^]u"yKQo=[)a￴e%QF <7Q>c2hK(r|9,t0Y"t6qքq򣡻Ğ!YO7+س.{:\H˽sbJe6~hm}2Kfϳsࣟ2-MCK` Q(¾)Ux [g,e_>)x?ͬ+n3`%{Ԛ?fJ OP 5 cH,·ܾU+sqj('?[uϚ0H/4 G{! wצak^gT^#L" %rHLEy mBŌC+TSόn}KcE$f5vkiqOHȀى`_幗 CO(s%.SmfuOMtJ w'k*.7惠O`!!Ʉ" AQera%Ͻcw޾Ç 0"Mp)[bQ?'n_#`&n2MLxw-jѻ(,QS"]/0TAQMě4 Қ7fVoZ-ryWaLu(5#" /^|{vpX W{Z4!Kxi_3-8#64eh|U hR' f;"m* p a[_9`Cxܞ^BeSOߨF+owJfҚv4sUg\H # o WLH;T%yY/2ѩgT&u E3&AnIޫGĐ#nk 3 TensXn,,Zʙ.@[QKoDM+eAyqՆeøS.NP4LڈyέާYD|hM9ʽa, '승&wA:ҍ 8F>/|㺲cMk&xbc&] T1@(.ZγM}xb+w~EV0rޠ0 fԂ슌G<]@|W1V"}"[Ilm*3jů,|*L˗gQϲ!Z:EtLCA {Z㳋FL9Ae7ɸp+ڃ2#1YanAc XC](E޳T_l㬲#(AkOJ|GPV:gYTqp.yY q9]T;)QM}g)+Xfro>U 98W並朗Cm>47%ed&:܄A\9\*1PB94zxo4 >:׊@ =)"6XM*03qMSPPlyS8*6'eZCq|"8ϴR*Wtuf^쑗J[91+&f3KEpF.PE4y|s{|d[:#f)EOPb{DmP  HT/e QrZ'6Oe7itoCCޜx3~9\aׂ{6a% ?b~k\VlN"8 F[=eDRBy{CfX[f5U(qb2~v*x ste(Y~e/BQ2[![h&S?1I]ִ:ax=&@IOYCb7g.{[ Yi#"n^ 'ErҖ3یO~@&*nx>{\GEȹnpF#V?, "%Lt-=4Q;sfVi+xE@D`*#4c_>tU'q7l7+H.!MS1{ewr+m)wKsNU)WgrmLgusW.Iv,T${Z}T%2㾃H\W,.Z'HOy-on5YHG{\+ ށq[ @{bfhl^pp\A+Sr>A0uhŌi Sܘi UQ+޺Tf=y5h?h:c;ChD9k>"H#_ eF$aql3D 5>ɨCadSwBY77`1eqPSa$R0Lɔ-M6JZ $V]{C nrHdTeҼ[(RW~&i&1lR?O-9ϗ5ᇴvdž/٬ظk:fJ[ªf"+v*V5QO.zLb(GK?QU|]i[8)zy i< {aN0(Ct10{&%,lQ+` Rg,bW?~g24FCai Gi R/D+bŝ:{瞦Ѱ^ijM@;Rereڠ C*.k_L2<"."ް3< LVD9fn6*DA֦ 縘 '$WIWs1{ը0pA[U/6$1 ̄)桋Af-t+C粺 raɬ{h:=KwK v [~F*P]*L楘S=O-A@y,!6ONY'n{ð_ ۢ/W& :I-į컾˖F ,Zy<&]m8}f̶2f.)b㘜?k` RAeOLNO @†Hdk闶xi ;D^u]őЍ/I 5fboGB^, ҝgvxa7۫%8j"a+Jj\BQΠ;8~gYet7GD/8B|ڣ5C3˱\gݕY7<ȟ~^ӈE|&\ʻ==Uk=륨`.Wbut"!*DPjp 誅=?3q3Ԇ(> Alt >*}Xhoke2Q`ӊN)bb>vYκu/ܩ|y ;N9LodHz0  SvӢS ) r0Lj^T`܃b($pT-0@'װDKYK8m!GT*X #$~w$+!Eq[PF\= 3Zx]vI@nxQN_c%zUZ EM$|;5Ŋۇ.E}U)edK(hpqyc8Ws&~|fӚÖ"<>sXs+F;IދVS=x@` :soF9 ՝] kL\́)9qm<~֔FGrA,Z+>SQ yy^fߣr6W9 u8KwS({h$YzY<~[TzÔ fg_ϕ~:qTBzabggH<ʉscăkqݯB^tuw#(PLdY(رHslUS@(IvdqCbxL#~ K4N⥵n3֎j!D)v9XHł ~PpȘHpǹ,HTbᐐ xXӥPVuWܰ\iӦ#wn ىj;,$qtK;H0֝FJCZwwz?fNnZ.PFhဎǣq];<׻;E`E=Oc60k߁!MW7#Bă#^>P-:~\`InNٷ #DŽYc 7ݩS;&W2u-Cϳ@@evM(G~dP{7c@BOâW)U}$(՗`%öưN ;}LNC=ZpDdh83}gװ1̨nd!40@gEO?޼pwζZD3&eƏd+u+(S оûjLCh>crk-" 7h$#)W> fܕ=Xkl6g̐z(kYf9/J8u2YgL@ȡ!U#0nB鋛Q/ :'7~'mP7\Bb8!G{Ԙcz;EDÖ+xΤyYq b_SiWd6!fQ0ί!HPz{dvS03$U5s]BI>xGA. g( vqkhl n_n ^%4\1)fya5i !630|;oJlP_w_u7WgFcQ=|hjB[>?^*m~Z!p5]^K kGt,zTc?*wCz|' (h{q4Fdg#sucX % Ipiq0.ݔNSL$]3^ ;%OE I.+oAЃ73] ~=1-NRa L1D{W-Fk, 찧!+A{}䖩fCC7@E)l-Dž{i=|J@zZgaaN5֙3˫)o}B:a0Sv\ ~0C)ؙtZC5T>xy'a蟗BjFMX #i5J_ [ʀ+S)N0!C>]/:ĖoJ[|eGT|$5+v +\VU *B@ֈlZ7\60yr3Q|v?>M:[$B,_xErMw 7AWx,،=>?s--+Y{J>&t)[ vxP|\R4@'*ٶp;S +9s-9'%Guc"3J3{i*,|8k