Path: utzoo!dciem!nrcaer!scs!spl1!laidbak!att!osu-cis!killer!chasm
From: chasm@killer.UUCP (Charles Marslett)
Newsgroups: comp.sys.atari.8bit
Subject: Re: Disk exchanges with IBM PCs
Message-ID: <4286@killer.UUCP>
Date: 2 Jun 88 03:28:33 GMT
Article-I.D.: killer.4286
References: <4235@killer.UUCP> <3205@bsu-cs.UUCP>
Organization: The Unix(R) Connection, Dallas, Texas
Lines: 1609
Summary: Here it is

In article <3205@bsu-cs.UUCP>, cfchiesa@bsu-cs.UUCP (Christopher Chiesa) writes:
> In article <4235@killer.UUCP>, chasm@killer.UUCP (Charles Marslett) writes:
> > 
> > I have a short utility program to read and write Atari MYDOS format
> > double density diskettes on IBM PCs and clones -- the program could
> > be reasonably posted here or in one of the IBM newsgroups.  Could
> > someone recommend where?  And is there really any interest in such
> > a program?
> >
> 
> Yes, I'd be VERY interested in such a program.  Don't know where you'd post
> it, although if you can look at a list of newsgroups (the file .newsrc in your
> main directory, usually) you can probably puzzle it out.   I'd say it would
> depend somewhat on the nature and size of the posting: source vs. binary, and
> how long (a judgement call).  Suggested search pattern:
> 
>   Short sources:  comp.sys.atari.8bit  and  comp.sys.ibm-pc (check this name)

OK, I think it's sorta short, and the alternatives may not get read by the
people who want it.  (Donning my asbestoses in case someone strongly disagrees
with my size estimate!)

This is a "traditional" shar file with the MSDOS executable uuencoded on the
end.

This is a utility program that allows you to read, write and format diskettes
on an IBM PC or compatible in the MYDOS double density format for the Atari
8-bit computers.  The utility does not support any of the 128-byte sector
formats, but the source is included (in case you come up with a way to add
such support).  The program has been compiled with Microsoft C and MASM.

I hope you find it useful.

Charles Marslett
Wordmark Systems
chasm@killer.UUCP
===========================================================================
Disclaimer:  I said it didn*t I???  And I*m honest (-: . . .
===========================================================================

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh READ.ME <<'END_OF_READ.ME'
XThe UTIL program is used to read and
Xwrite Atari double density diskettes
Xon an IBM-compatible computer.  The
Xtwo source files for the utility are
XUTIL.C and ATARIO.ASM.
X
XEnter UTIL with no parameters and a
Xhelp message will be displayed.  To
Xread, write or format a disk, enter
Xthe commands /R, /W or /I.  The
Xcommand for displaying the directory
Xis /L.  If the command line contains
Xa /B, the files will not be translat-
Xed to/from ATASCII (i.e., they are
Xbinary files).  The command line for
Xall but the /W function will end with
Xa drive identifier (A:, B:, C: or D:)
X-- this is the ABSOLUTE drive number,
Xnot the one MSDOS uses.  An external
X3.5" drive will usually be drive C:,
Xnot D: or E: or whatever DOS calls
Xit.  Use the /L command until you are
Xsure you know which drive is which!
X
XTo write to the Atari diskette, the
Xdrive identifier is followed by a
Xlist of file names to be written to
Xthe Atari diskette.
X
X                   Good luck,
X                   Charles Marslett
END_OF_READ.ME
if test 986 -ne `wc -c atario.asm <<'END_OF_atario.asm'
X	title	ATARI Disk I/O Library
X
X	public	_savefb
X	public	_restfb
X	public	_aread
X	public	_awrite
X	public	_aformat
X	public	_cd
X	public	_md
X	public	_dmainit
X	public	_getds
X	public	_ffirst
X	public	_fnext
X
XDGROUP	group	_DATA
X
X_DATA	segment	byte public 'DATA'
X	extrn	_tracks:byte
X	extrn	_track_offset:byte
X	extrn	_sector_offset:byte
X_DATA	ends
X
XIGROUP	group	_TEXT
X
X_TEXT	segment	byte public 'CODE'
X	assume	cs:IGROUP,ds:DGROUP
X;
X;	Return first address of a 512-byte buffer in a character array
X;
X_dmainit proc	near
X	push	bp
X	mov	bp,sp
X	mov	ax,4[bp]
X	mov	bx,ds
X	mov	cl,4
X	shl	bx,cl
X	add	bx,ax
X	cmp	bx,0FE00h
X	jbe	dmax
X	sub	ax,bx
Xdmax:	pop	bp
X	ret
X_dmainit endp
X;
X;	Save Current Disk Format in 10-Byte Save Area
X;
X;	savefb(sectorsize, sectorcount, savearea)
X;	   int sectorsize, sectorcount;
X;	   char savearea[10];
X;
X_savefb	proc	near
X	push	bp
X	mov	bp,sp
X	push	ds
X	push	di
X	push	si
X
X	cld
X	xor	si,si
X	push	ds
X	pop	es				;Segment address of save area
X	mov	ds,si
X	lds	si,dword ptr ds:[4*1Eh]		;Address of ctl block to DS:SI
X	mov	di,8[bp]			;Get address of save area
X	mov	cx,5				;length in words
X	rep movsw				;copy block to local memory
X	sub	si,10				;point back to 1-st of ctl blk
X	mov	al,byte ptr 4[bp]		;ARG1 = sector size code
X	mov	ah,byte ptr 6[bp]		;ARG2 = sectors/track
X	mov	word ptr [si+3],ax		;Store data back into block
X	mov	byte ptr [si+5],28		;Inter-sector gap length (was 42)
X	mov	byte ptr [si+7],24		;Leading gap length (was 80)
X	mov	byte ptr cs:secptk,ah
X	mov	ah,0				;reset the disk system
X	mov	bx,ax
X	shl	bx,1
X	mov	bx,cs:sec_size[bx]
X	mov	cs:data_ln,bx
X	int	13H
X
X	pop	si
X	pop	di
X	pop	ds
X	pop	bp
X	ret
X_savefb	endp
X;
X;	Restore MSDOS Format to Disk Control Block
X;
X;	restfb(savearea)
X;	   char savearea[10];
X;
X_restfb	proc	near
X	push	bp
X	mov	bp,sp
X	push	ds
X	push	di
X	push	si
X
X	xor	cx,cx
X	loop	$
X	cld
X	mov	si,4[bp]
X	xor	ax,ax
X	mov	es,ax
X	les	di,dword ptr es:[4*1Eh]
X	mov	cl,5
X	rep movsw
X	int	13H
X
X	pop	si
X	pop	di
X	pop	ds
X	pop	bp
X;	xor	cx,cx
X;	loop	$
X	ret
X_restfb	endp
X;
X;	Read a MYDOS Sector
X;
X;	aread(sector, drive, bufad)
X;	   int sector, drive;
X;	   char bufad[512];
X;
X_aread	proc	near
X	push	bp
X	mov	bp,sp
X	push	es
X	push	si
X	push	di
X
X	call	reg_set
X	call	vread			;Read one sector
X	jc	reterr
X	xor	ax,ax			;Return zero if no error
Xreterr:
X
X	pop	di
X	pop	si
X	pop	es			;Return it directly
X	pop	bp
X	ret
X_aread	endp
X;
Xvread	proc	near
X	call	io_setup
Xretry:	push	dx
X	push	cx
X	push	bx
X	mov	ax,0201h		;Command code/Number of sectors
X	int	13H
X	pushf				;Save CY flag
X	push	ax
X	jnc	flip
X	dec	cs:errcnt
X	je	flip
X	pop	ax
X	popf
X	mov	ah,00h			;Recalibrate disk system
X	int	13H
X	pop	bx
X	pop	cx
X	pop	dx
X	jmp	short retry
X;
Xflip:	pop	ax
X	popf
X	pop	bx
X	pop	cx
X	pop	dx
X
X	pushf
X	mov	cx,128			;Complement data bits
Xfliplp:	not	word ptr es:[bx]
X	inc	bx
X	inc	bx
X	loop	fliplp
X	popf				;Restore CY flag
X
X	ret				;and return (CY/AX contain status)
Xvread	endp
X;
X;	Write a MYDOS Sector
X;
X;	awrite(sector, drive, bufad)
X;	   int sector, drive;
X;	   char bufad[512];
X;
X_awrite	proc	near
X	push	bp
X	mov	bp,sp
X	push	es
X	push	si
X	push	di
X
X	call	reg_set
X	call	vwrite			;Write one sector
X
X	pop	di
X	pop	si
X	pop	es
X	pop	bp
X	ret
X_awrite	endp
X;
Xvwrite	proc	near
X	call	io_setup
Xwrtry:	push	dx
X	push	cx
X	push	bx
X	mov	cx,128
Xwrcomp:	not	word ptr es:[bx]
X	inc	bx
X	inc	bx
X	loop	wrcomp
X	pop	bx
X	pop	cx
X	push	cx
X	push	bx
X	mov	ax,0301h		;Command code/Number of sectors
X	int	13H
X	jnc	vw_xit
X	push	ax
X	mov	ah,00h			;Recalibrate disk system
X	int	13H
X	pop	ax
X	pop	bx
X	pop	cx
X	pop	dx
X	dec	cs:errcnt
X	jne	wrtry
X	push	cx
X	push	bx
X	mov	cx,128
Xerrcmp:	not	word ptr es:[bx]
X	inc	bx
X	inc	bx
X	loop	errcmp
X	pop	cx
X	pop	bx
X	stc
X	ret				;and return (CY/AX contain status)
X
Xvw_xit:	pop	bx
X	push	bx
X	mov	cx,128
Xwrrcmp:	not	word ptr es:[bx]
X	inc	bx
X	inc	bx
X	loop	wrrcmp
X	mov	ax,0			;Indicate no error
X	pop	bx
X	pop	cx
X	pop	dx
X	ret
Xvwrite	endp
X;
X;	Format a MYDOS Track
X;
X;	aformat(track, drive, buf, seq)
X;	   int sector, drive;
X;	   char buf[512];
X;	   char seq[26];
X;
X_aformat proc	near
X	push	bp
X	mov	bp,sp
X	push	ds
X	push	es
X	push	di
X	mov	di,8[bp]		;Point to the buffer
X	mov	ax,ds
X	mov	es,ax
X	mov	ah,1
X	mov	bx,10[bp]		;Point to sector sequence table
X	mov	ch,4[bp]		;Get track no.
X
X	cld
Xbldft:	mov	al,ds:[bx]
X	cmp	al,0FFh
X	je	endbft
X	inc	bx
X	mov	es:[di],ch		;Track No.
X	inc	di
X	mov	byte ptr es:[di],0	;Head No.
X	inc	di
X	stosw				;Sector No. and Bytes/Sector
X	jmp	short bldft
X
Xendbft:	sub	bx,10[bp]
X	mov	ax,bx
X	mov	bx,8[bp]		;368h
X	mov	cl,1			;Sector number (junk)
X	mov	dh,0			;Head number
X	mov	dl,byte ptr 6[bp]	;Drive number
X	mov	ah,05h			;Format command
X	int	13h
X	mov	ax,0
X	jnc	afex			;Return 0 if OK, -1 if error
X	dec	ax
Xafex:	pop	di
X	pop	es
X	pop	ds
X	pop	bp
X	ret
X_aformat endp
X
Xio_setup proc	near
X	dec	ax			;Make sector number 0-based
X	xor	dx,dx			;and 64-bit long
X	div	word ptr cs:secptk	;convert to track/sector format
X	inc	dl
Xfmt_su:	mov	ch,al			;track number
X	mov	cl,dl			;sector number
X	mov	dh,0			;Head number
X	cmp	ch,_tracks		;Second side?
X	jb	dord
X	inc	dh
X	test	_track_offset+1,80h	;Same or different directions
X	jz	dorev
X	add	ch,_track_offset	;track = track - [40|80]
X	jmp	short doadj
Xdorev:	mov	ch,_track_offset	;track = [80|160] - track
X	sub	ch,al
Xdoadj:	test	_sector_offset+1,80h
X	jnz	dord			;if < 0, no change
X	mov	cl,_sector_offset
X	sub	cl,dl			;else sector = K - sector
X	cmp	cl,byte ptr cs:secptk
X	jbe	dord			;Where K can be > max sector #
X	sub	cl,byte ptr cs:secptk
X	dec	ch			;presume reversed sequence
X	test	_track_offset+1,80h
X	jz	dord
X	add	ch,2			;if forward track sequence
Xdord:
X	mov	dl,byte ptr 6[bp]	;Drive number
X	mov	cs:errcnt,5		;Retry 5 times only!
X	ret
Xio_setup endp
X
Xreg_set	proc	near
X	mov	bx,8[bp]		;ARG2 = buffer address
X	mov	ax,ds
X	mov	es,ax
X	mov	ax,4[bp]		;Get ATARI FMS sector no.
X	ret
Xreg_set	endp
X;
X;  Change to a new current directory
X;	cd(ptr)
X;	  char *ptr;  /* new directory name */
X;	  returns 0 if successful, 3 if invalid directory
X;
X_cd	proc	near
X	push	bp
X	mov	bp,sp
X	mov	dx,4[bp]
X	mov	ah,3Bh
X	int	21h
X	jc	ret_cd
X	xor	ax,ax
Xret_cd:	pop	bp
X	ret
X_cd	endp
X
X;
X;  Make a new directory
X;	md(ptr)
X;	  char *ptr;  /* new directory name */
X;	  returns 0 if successful, 3 if invalid path
X;		  5 if access denied
X;
X_md	proc	near
X	push	bp
X	mov	bp,sp
X	mov	dx,4[bp]
X	mov	ah,39h
X	int	21h
X	jc	ret_md
X	xor	ax,ax
Xret_md:	pop	bp
X	ret
X_md	endp
X;
X;	Parse and search for files with wild card names
X;
X;	ffirst(dta,name)
X;
X_ffirst	proc	near
X	push	bp
X	mov	bp,sp
X	mov	dx,6[bp]
X	mov	ah,4Eh
X	mov	cx,7
X	jmp	short getfile
X_ffirst	endp
X;
X;	fnext(dta)
X;
X_fnext	proc	near
X	push	bp
X	mov	bp,sp
X	mov	ah,2Fh
X	int	21h
X	push	si
X	mov	si,4[bp]
X	mov	cx,22			;Size of buffer in words
Xrstdata:
X	lodsw
X	mov	es:[bx],ax
X	inc	bx
X	inc	bx
X	loop	rstdata
X	pop	si
X	mov	ah,4Fh
Xgetfile:
X	int	21h
X	jc	reten
X	mov	ah,2Fh
X	int	21h
X
X	push	di
X	mov	di,4[bp]
X	mov	cx,22			;Size of buffer in words
Xcpydata:
X	mov	ax,es:[bx]
X	mov	ds:[di],ax
X	inc	di
X	inc	di
X	inc	bx
X	inc	bx
X	loop	cpydata
X	pop	di
X	xor	ax,ax
X	pop	bp
X	ret
X
Xreten:	push	ax
X	mov	di,4[bp]
X	mov	cx,22
X	mov	ax,0FFFFh
X	rep stosw
X	pop	ax
X	pop	bp
X	ret
X_fnext	endp
X
X_getds	proc	near
X	mov	ax,ds
X	ret
X_getds	endp
X
Xsec_size dw	128,256,512,1024,2048,4096
X
Xdata_ln	dw	256		;size of a sector in bytes
Xsecptk	dw	0
Xerrcnt	db	0
X_TEXT	ends
X	end
END_OF_atario.asm
if test 7101 -ne `wc -c util.c <<'END_OF_util.c'
X#include 
X
X#define SECSIZE 256       /* Change this to handle 1050 dbl density disks */
X
X#if SECSIZE == 256
X#define SECCODE 1
X#define SECTORS 18
X#else
X#define SECCODE 0
X#define SECTORS 26
X#endif
X
Xint ls_file();
Xint cat_file();
Xint dup_file();
Xchar *dmainit();
XFILE *fopen(), *bopen();
X
Xstruct dta {
X   char reserved[21];
X   char attr;
X   int utime;
X   int udate;
X   long len;
X   char name[13];
X   char dummy[3];
X   } fdata;
X
Xint drive, cmd;
Xint first;
Xint save[5];
Xchar seq[27] = {6,12,18,5,11,17,4,10,16,3,9,15,2,8,14,1,7,13,0xFF};
Xint bitmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
Xunsigned char *bp;
Xint *seccnt;
Xint tracks;
Xint track_offset, sector_offset;
X
Xunsigned char buf[1024];
Xunsigned char map[1280];
Xunsigned char dirbuf[1024];
Xchar dirname[100];
X
Xunsigned int bpp = 0;
Xint bin_flag = 0;
Xunsigned char dosbuf[10240];
X
Xmain(argc, argv)
X   int argc;
X   char *argv[];
X   {
X   int sec, ct;
X   char *p, *argp;
X
X   
X   bp = dmainit(buf);
X#ifdef DEBUG
X   if (bp != buf)
X      printf("Buffer base moved from %x to %x\n", buf, bp);
X#endif
X   seccnt = (int *) &map[3];
X   for (ct=0; ct<1280; ct++)
X      map[ct] = 0;
X   first = '\t';
X   dirname[0] = '\0';
X   drive = 0;
X   track_offset = -40;
X   tracks = 40;
X   sector_offset = -1;
X   while (--argc >= 0) {
X      argp = *++argv;
X      if ((argp[0] == '/' || argp[0] == '-')) {
X         if (argp[2] == '\0') {
X            if (argp[1] == 'B' || argp[1] == 'b')
X               bin_flag = 1;
X            else
X               cmd = argp[1] & 0xDF;
X            }
X         else if (argp[1] == 'T' || argp[1] == 't') {
X            track_offset = - atoi(&argp[2]);
X            tracks = (track_offset > -60)? 40: 80;
X            }
X         else if (argp[1] == 'P' || argp[1] == 'p') {
X            track_offset = atoi(&argp[2]);
X            tracks = (track_offset < 60)? 40: 80;
X            }
X         else if (argp[1] == 'S' || argp[1] == 's') {
X            sector_offset = atoi(&argp[2]);
X            }
X         }
X      else if (argp[1] == ':' && argp[2] == '\0') {
X         drive = (argp[0]-'A') & 0x1F;
X         break;
X         }
X      else if (argp[1] == '\0') {
X         cmd = argp[0] & 0xDF;
X         break;
X         }
X      else {
X         argv--;
X         argp++;
X         break;
X         }
X      }
X#ifdef DEBUG
X   printf ("Binary flag = %s\n", bin_flag? "on": "off");
X   printf ("Tracks = %d, offset = %d, sector offset = %d\n",
X         tracks, track_offset, sector_offset);
X   printf("CMD=%c, DRIVE=%c:\n", cmd, drive+'A');
X#endif
X   savefb(SECCODE,SECTORS,save);
X#ifdef DEBUG
X   printf("SAVE=0x%04X.0x%04X.0x%04X.0x%04X.0x%04X\n", save[0], save[1],
X         save[2], save[3], save[4]);
X#endif
X   switch (cmd) {
X      case 'W':			/* Write directories or files(from MSDOS) */
X         getmap(drive);
X         msdir(argc,&argv[1]);
X         putmap(drive);
X         break;
X      case 'I':			/* Initialize (Format) an Atari Disk */
X         fmtdisk(drive);
X         break;
X      case 'L':			/* List an Atari Directory */
X         listdir(361, ls_file);
X         break;
X      case 'P':			/* Display/Print Atari (printable) files */
X         listdir(361, cat_file);
X         break;
X      case 'R':			/* Read Atari formatted disk files(to MSDOS)*/
X         listdir(361, dup_file);
X         break;
X      default:
X         printf ("Invalid switch: only L/istDir, P/rintFiles, R/eadFiles,\n");
X         printf ("    W/riteFiles or I/nitializeDisk\n");
X         printf ("Usage: util /[L|P|R|I] [/T80] [A|B|C|D]:      or\n");
X         printf ("       util /W [A|B|C|D]: file [file ... ]\n");
X      }
X   restfb(save);
X   }
X
Xdump()
X   {
X   int ct;
X   char *p;
X
X   for (p=bp, ct=0; ct != 256; p += 16, ct += 16) {
X      printf ("%03X %02X%02X %02X%02X %02X%02X %02X%02X",
X            ct, p[0]&0xFF, p[1]&0xFF, p[2]&0xFF, p[3]&0xFF,
X            p[4]&0xFF, p[5]&0xFF, p[6]&0xFF, p[7]&0xFF);
X      printf (" %02X%02X %02X%02X %02X%02X %02X%02X\n",
X            p[8]&0xFF, p[9]&0xFF, p[10]&0xFF, p[11]&0xFF,
X            p[12]&0xFF, p[13]&0xFF, p[14]&0xFF, p[15]&0xFF);
X      }
X   }
X
Xlistdir(sec, filefunc)
X   int sec;
X   int (*filefunc)();
X   {
X   int k, j, i, *num;
X   unsigned char *p, *tp, *dp;
X   char text[30];
X
X   printf("Files in \"%c:%s\"\n", drive+'A', dirname);
X   for (j=0; j<1024; sec++) {
X      if (aread(sec, drive, bp)) {
X         printf("Failure reading directory!  Operation aborted!\n");
X         return;
X         }
X#ifdef TRACE
X      dump();
X#endif
X      for (i=0; i < 128;)
X         dirbuf[j++] = bp[i++];
X      }
X#ifdef DEBUG
X   printf("Directory read:\n");
X#endif
X   for (p=dirbuf; p < dirbuf+1024; p+=16) {
X      if (*p == 0) {
X#ifdef DEBUG
X         printf("End of directory at byte %d\n", p-dirbuf);
X#endif
X         break;
X         }
X#ifndef DEBUG
X      if ((*p & 0x91) != 0x00)
X         continue;
X#endif
X      for (tp=text, dp=p+5; *dp > ' ' && dp != p+13;)
X         *tp++ = *dp++;
X      if (p[13] > ' ') {
X         *tp++ = '.';
X         *tp++ = p[13];
X         if (p[14] > ' ') {
X            *tp++ = p[14];
X            if (p[15] > ' ')
X               *tp++ = p[15];
X            }
X         }
X      *tp = '\0';
X      num = (int *) (p+1);
X      (*filefunc)(text, num[1], num[0], *p);
X      }
X   if (first == '\n') {
X      putchar('\n');
X      first = '\t';
X      }
X   for (p=dirbuf; p < dirbuf+1024; p+=16) {
X      if (*p == 0)
X         return;
X      if ((*p & 0x91) != 0x10)
X         continue;
X      for (tp=text, dp=p+5; *dp > ' ' && dp != p+13;)
X         *tp++ = *dp++;
X      if (p[13] > ' ') {
X         *tp++ = '.';
X         *tp++ = p[13];
X         if (p[14] > ' ') {
X            *tp++ = p[14];
X            if (p[15] > ' ')
X               *tp++ = p[15];
X            }
X         }
X      *tp = '\0';
X#ifdef DEBUG
X      printf("Subdirectory :%s!\n", text);
X#endif
X      num = (int *) (p+1);
X      k = strlen(dirname);
X      dirname[k] = '\\';
X      dirname[k+1] = '\0';
X      strcat(dirname, text);
X      if (cmd = 'D')
X         if (cd(text) != 0)
X            if (md(text) != 0) {
X               printf("Cannot use or create directory \"%s\"\n", text);
X               return;
X               }
X      listdir(num[1], filefunc);
X      if (cmd == 'D')
X         cd("..");
X      dirname[k] = '\0';
X      }
X   }
X
Xls_file(name, at, size, flags)
X   char *name;
X   int at, size, flags;
X   {
X   printf ("%c%c%c%-12s[%04X] %d secs%c",
X         flags&0x20?'*':' ', flags&0x10?':':' ',
X         flags&0x04?'!':flags&0x02?' ':'#',
X         name, at, size, first);
X   first ^= '\n' ^ '\t';
X   }
X
Xcat_file(name, at, size, flags)
X   char *name;
X   int at, size, flags;
X   {
X   int x, ct;
X   unsigned char *p;
X
X   printf("Print %s(%ld bytes, f=%02X)?", name, size*((long)SECSIZE-3L),
X         flags);
X   x = getchar() & 0xDF;
X   if (x != '\n')
X      while (getchar() != '\n')
X         ;
X   if (x == 'Y') {
X      for (x = at; x != 0; x = ((bp[SECSIZE-3]<<8)+bp[SECSIZE-2]) & 0x03FF) {
X         while (aread(x, drive, bp))
X            printf ("5 Failures reading sector on Atari disk\n");
X         for (ct=bp[SECSIZE-1], p=bp; ct > 0; ct--, p++) {
X            if (*p == 0x7F)
X               putchar('\t');
X            else if (*p == 0x9B)
X               putchar('\n');
X            else
X               putchar(*p);
X            }
X         }
X      }
X   }
X
Xdup_file(name, at, size, flags)
X   char *name;
X   int at, size, flags;
X   {
X   int x, ct, mask;
X   char binary_copy;
X   unsigned char *p;
X   FILE *outf;
X
X   binary_copy = bin_flag;
X   printf("Copy %s(%ld bytes, f=%02X)?", name, size*((long)SECSIZE-3L),
X         flags);
X   mask = (flags & 0x04)? 0xFF: 0x03;
X   x = getchar() & 0xDF;
X   if (x != '\n')
X      while (getchar() != '\n')
X         ;
X   if (x == 'Y' || x == 'A' || x == 'B') {
X      if (x == 'A')
X         binary_copy = 0;
X      else if (x == 'B')
X         binary_copy = 1;
X      outf = bopen(name, "wb");
X      if (outf == NULL) {
X         printf ("Cannot create file \"%s\"", name);
X         return;
X         }
X      for (x = at; x != 0;
X	    x = ((bp[SECSIZE-3]&mask) << 8)+(bp[SECSIZE-2] & 0xFF)) {
X         while (aread(x, drive, bp))
X            printf ("5 Failures reading sector on Atari disk\n");
X#ifdef DEBUG
X         printf ("Link data = %02x, %02x, %02x\n", bp[SECSIZE-3],
X               bp[SECSIZE-2], bp[SECSIZE-1]);
X#endif
X         for (ct=bp[SECSIZE-1], p=bp; ct > 0; ct--, p++) {
X#ifdef TRACE
X            putchar(*p);
X#endif
X            if (binary_copy)
X               bput(*p, outf);
X            else if (*p == 0x7F)
X               bput('\t', outf);
X            else if (*p == 0x9B) {
X               bput('\r', outf);
X               bput('\n', outf);
X               }
X            else
X               bput(*p, outf);
X            }
X         }
X      bclose(outf);
X      }
X   }
X
Xgetmap(drive)
X   int drive;
X   {
X   int p, n, k;
X   char *mp;
X
X   for (mp = map, n=0; n++ < sizeof(map);)
X      *mp++ = 0;
X   mp = map;
X   n = 360;
X   p = 3;
X   do {
X      if (aread (n--, drive, bp)) {
X         printf ("Unable to read the Atari disk VTOC/Bit Map!  Program aborted!\n");
X         exit(1);
X         }
X      for (k=0; k<256; k++)
X         *mp++ = bp[k];
X      if (map[0] > (sizeof(map)/256 + 2)) {
X         printf ("Invalid drive, more than %d sectors\n",
X               (sizeof(map) - 10)*8);
X         exit(1);
X         }
X      } while (++p <= map[0]);
X#ifdef DEBUG
X   printf ("Drive %c: map header: <%02X> %02x%02x %02x%02x ", drive+'A',
X         map[0], map[2], map[1], map[4], map[3]);
X   printf ("%02x %02x %02x %02x %02x\n", map[5], map[6], map[7], map[8],
X         map[9]);
X#endif
X   }
X
Xputmap(drive)
X   int drive;
X   {
X   int p, n, k;
X   char *mp;
X
X   mp = map;
X   n = 360;
X   p = map[0];
X   do {
X      for (k=0; k<256; k++)
X         bp[k] = *mp++;
X      awrite (n--, drive, bp);
X      } while (--p >= 3);
X#ifdef DEBUG
X   printf ("Drive %c: map header: <%02X> %02x%02x %02x%02x ", drive+'A',
X         map[0], map[2], map[1], map[4], map[3]);
X   printf ("%02x %02x %02x %02x %02x\n", map[5], map[6], map[7], map[8],
X         map[9]);
X#endif
X   }
X
Xmsdir(argc,argv)
X   int argc;
X   char *argv[];
X   {
X   int rc, k, sc, fno, bk, bk0, bkn;
X   FILE *inf;
X
X   restfb(save);
X   bkn = -1;
X   while (--argc >= 0) {
X#ifdef DEBUG
X      printf ("Argument <<%s>>\n", *argv);
X#endif
X      if ((rc = ffirst(&fdata, *argv)) == 0) {
X         do {
X            printf ("Copying <<%s>>, Length = %ld\n", fdata.name, fdata.len);
X            inf = fopen(fdata.name, (bin_flag? "rb": "r"));
X            savefb(SECCODE,SECTORS,save);
X            fno = dirfnd(fdata.name);
X            bk0 = bk = alloc();
X#ifdef DEBUG
X            printf ("   First block = %d (FNO=%d)\n", bk, fno);
X#endif
X            k = (fno<<4) & 0x0070;
X            bp[k+3] = bk;
X            bp[k+4] = bk>>8;
X            k = (fno>>3) + 361;
X#ifdef DEBUG
X            printf("   Writing dir bk. %d, drive %c:\n", k, drive+'A');
X#endif
X            awrite(k, drive, bp);
X            restfb(save);
X            sc = 1;
X            fno <<= 2;
X            k = 0;
X            while ((rc = fgetc(inf)) >= 0) {
X               if (rc == '\t')
X                  rc = 0x7F;
X               else if (rc == '\n')
X                  rc = 0x9B;
X
X               if (k >= SECSIZE-3) {
X                  bkn = alloc();
X                  if (bkn <= 0) {
X                     printf ("No more sectors available\n");
X                     break;
X                     }
X#ifdef DEBUG
X                  printf ("   Writing block %d (fno=%04X,link=%d)\n", bk,
X                        fno, bkn);
X#endif
X                  bp[SECSIZE-3] = fno + (bkn>>8);
X                  bp[SECSIZE-2] = bkn & 0xFF;
X                  bp[SECSIZE-1] = SECSIZE-3;
X                  savefb(SECCODE,SECTORS,save);
X                  awrite(bk, drive, bp);
X                  restfb(save);
X                  bk = bkn;
X                  k = 0;
X                  sc++;
X                  }
X               bp[k++] = rc;
X               }
X            fclose(inf);
X            bp[SECSIZE-3] = fno;
X            bp[SECSIZE-2] = 0;
X            bp[SECSIZE-1] = k;
X#ifdef DEBUG
X            printf ("   Writing last block %d (fno=%04X,size=%d)\n", bk,
X                  fno, k);
X#endif
X            savefb(SECCODE,SECTORS,save);
X            awrite(bk, drive, bp);
X            bk = bk0;
X            dirup(sc, 0x42, fno>>2);
X            restfb(save);
X            } while (fnext(&fdata) == 0 && bkn != 0);
X         }
X      else
X         printf ("%s <<%s>>\n",
X               rc<18? "Invalid path for": "No matching file", *argv);
X      argv++;
X      }
X   savefb(SECCODE,SECTORS,save);
X   }
X
Xdirfnd(name)
X   char *name;
X   {
X   char *name0, *cp;
X   char namev[12];
X   int j, k, first;
X
X   k = 0;
X   for (j=0; j<11; j++)
X      namev[j] = ' ';
X   namev[11] = '\0';
X   while (*name != '.' && *name != '\0') {
X      namev[k++] = *name++;
X      if (k >= 11)
X         break;
X      }
X   if (k < 11 && *name == '.') {
X      k = 8;
X      while (*++name != '\0' && k < 11) {
X         if (*name == '\n')
X            break;
X         namev[k++] = *name;
X         }
X      }
X   first = -1;
X   for (k=361; k<369; k++) {
X      if (aread(k, drive, bp)) {
X         printf ("Unable to read ROOT directory for updating! Program aborted!\n");
X         exit(1);
X         }
X      for (j=0; j<0x80; j += 0x10) {
X         if (namecomp(&bp[j+5], namev)) {
X            first = ((k-361)<<3) + (j>>4);
X#ifdef DEBUG
X            printf("   Replaced file no. = %d\n", first);
X#endif
X            return (first);
X            }
X         if (bp[j] == 0) {
X            if (first < 0)
X               first = ((k-361)<<3) + (j>>4);
X            goto allcf;
X            }
X         if ((bp[j] & 0x80) && first < 0)
X            first = ((k-361)<<3) + (j>>4);
X         }
X      }
X   allcf:
X#ifdef DEBUG
X   printf ("allocated file no. = %d\n", first);
X#endif
X   if (first < 0) {
X      printf ("No directory entries free\n");
X      exit(1);
X      }
X   if ((first>>3) != (k-361))
X      while (aread((first>>3)+361, drive, bp))
X         ;
X   cp = &bp[(first & 0x07)<<4];
X   *cp = 0x03;
X   cp += 5;
X   for (k=0; k<11; k++)
X      *cp++ = namev[k];
X#ifdef DEBUG
X   printf ("%s==>%s(FNO=%d)\n", name0, namev, first);
X#endif
X   return (first);
X   }
X
Xdirup(cnt, attr, indx)
X   int cnt, attr, indx;
X   {
X   int k;
X
X   while (aread(361+(indx>>3), drive, bp))
X      ;
X   k = (indx<<4) & 0x0070;
X   bp[k] = attr;
X   *(int *)(&bp[k+1]) = cnt;
X   awrite(361+(indx>>3), drive, bp);
X   }
X
Xalloc()
X   {
X   int p, x, mask;
X
X   for (x=10; map[x] == 0; x++)
X      if (x >= 1280)
X         return(0);
X   p = (x-10)<<3;
X   mask = 0x80;
X   while ((map[x] & mask) == 0) {
X      mask >>= 1;
X      p++;
X      }
X   map[x] &= ~mask;
X   --*seccnt;
X   return (p);
X   }
X
Xdealloc(sec)
X   int sec;
X   {
X   map[(sec >> 3) + 10] |= bitmask[sec & 0x07];
X   }
X
Xnamecomp(a, b)
X   char *a, *b;
X   {
X   int i;
X
X   for (i=0; i<11; i++)
X      if (*a++ != *b++)
X         return(0);
X   return (1);
X   }
X
XFILE *bopen(name, mode)
X   char *name, *mode;
X   {
X   FILE *val;
X
X   restfb(save);
X   val = fopen(name, mode);
X   savefb(SECCODE,SECTORS,save);
X   return (val);
X   }
X
Xbput(data, out)
X   int data;
X   FILE *out;
X   {
X   int len;
X
X   if (bpp >= sizeof(dosbuf)) {
X      restfb(save);
X      len = fwrite (dosbuf, 1, sizeof(dosbuf), out);
X      if (len != sizeof(dosbuf))
X         printf ("Error writing to DOS file, %d bytes not written\n",
X               sizeof(dosbuf) - len);
X#ifdef DEBUG
X      printf("Writing block of %d bytes to DOS file\n", sizeof(dosbuf));
X#endif
X      bpp = 0;
X      savefb(SECCODE,SECTORS,save);
X      }
X   dosbuf[bpp++] = data;
X   }
X
Xbclose(out)
X   FILE *out;
X   {
X   int len;
X
X   restfb(save);
X   if (bpp != 0) {
X      len = fwrite(dosbuf, 1, bpp, out);
X      if (len != bpp)
X         printf ("Error closing file, %d bytes not written\n", bpp - len);
X      }
X#ifdef DEBUG
X   printf ("Last file block contains %d bytes\n", bpp);
X#endif
X   bpp = 0;
X   fclose(out);
X   savefb(SECCODE,SECTORS,save);
X   }
X
Xfmtdisk(drive)
X   int drive;
X   {
X   int ct;
X
X   for (ct=0; ct<40; ct++) {
X      if (aformat(ct, drive, bp, seq) < 0)
X      printf ("Error formatting track %d\n", ct);
X      }
X   for (ct=0; ct<512; ct++)
X      map[ct] = 0;
X   map[0] = 2;
X   map[1] = map[3] = 0xc4;
X   map[2] = map[4] = 0x02;
X   for (ct=4; ct<360; ct++)
X      dealloc(ct);
X   for (ct=369; ct<720; ct++)
X      dealloc(ct);
X   for (ct=0; ct<1024; ct++)
X      dirbuf[ct] = 0;
X   putmap(drive);
X   for (ct=361; ct < 369; ct++)
X      awrite(ct, drive, dirbuf);
X   }
X
END_OF_util.c
if test 16321 -ne `wc -c util.uue <<'END_OF_util.uue'
Xbegin 644 util.exe
XM35J? 1X !  @ #\$__]8!P (TF Z$P  '@    $ $ 0I T43  #/$P  I 0Ia
XM P                                                          a
XM                                                            a
XM                                                            a
XM                                                            a
XM                                                            a
XM                                                            a
XM                                                            a
XM                                                            a
XM                                                            a
XM                                                            a
XM                                            58OL@^P*5U:X)CU0a
XMZ+L0@\0"HX 'QP:2/),-QT;\   KP+F  K^0#1X'\JN 1OT%QP:"!PD Q@:4a
XM/ "CA ?'!BI#V/_'!BA!* #'!B9!__^+?@:+=OK_3@1Y ^F^ (/' HLU@#POa
XM= B /"UT ^F4 (!\ @!U((!\ 4)T!H!\ 6)U",<&+ $! .O,BD0!)=\ HY Za
XMZ\&0@'P!5'0&@'P!='4:C40"4.@G,(/$ O?8HRI#/<3_?B2X* #K(I" ? %0a
XM= : ? %P=1R-1 )0Z $P@\0"HRI#/3P ?-RX4 "C*$'I<_^0@'P!4W0)@'P!a
XME3_Y" ? $Z=7J ? ( =72*!)@M00 E'P"Ca
XMA >)?@:)=OJXA@M0N!( 4+@! %#HL0^#Q :AD#H]20!U ^F! #U, '4#Z8, a
XM/5  =0/IBP ]4@!U ^F) #U7 '0^N$( 4.A]&8/$ KA[ %#HLXD(!\ 0!U"HH$)=\ HY ZZXB#[P)&ZX+_-H0'Z)T&a
XM@\0"BT8&!0( 4/]V!.B7!X/$!/\VA ?H,P>#Q +K)O\VA ?H.P[K\I"X" 50a
XMN&D!4.B? (/$!.L,N&8%Z^Z0N+0&Z^B0N(8+4.@^#X/$ EY?B^5=PU6+[(/La
XM!%=6BS: !RO_BD0'*N10BD0&4(I$!5"*1 10BD0#4(I$ E"*1 %0B@105[@Na
XM 5#HLQB#Q!2*1 \JY%"*1 Y0BD0-4(I$#%"*1 M0BD0*4(I$"5"*1 A0N%@<: a
XM ,=&V(  1X'^  1\K8E^!(EVUL=&_H8'BW[XBU[^@#\ =26)?OB#/H('"G0#a
XMZ;8 _PX:!7D#Z9D L J+'A@%_P88!8@'Z9@ BU[^]@>1=7"-1MJ+^(OS@\8%a
XMB\OK#XO!!0T .\9T"XH$B 5&1X \('?LB7;ZBU[^@'\-('8BQ@4N1XI'#8@%a
XM1X!_#B!V$HI'#H@%1X!_#R!V!HI'#X@%1\8% (O#0(E&_(H'*N10BU[\_S?_a
XM=P*-1MI0_U8&@\0(@T;^$(%^_H8+<@/I5?_I2O^0N!@%4+@* %#H(QB#Q 3'a
XM!H('"0#'1OZ&!XM^^(M>_H _ '4#Z1D!B@_E#R,V([ N?__a
XM,\#RKO?125^)3M2+V<:'E#Q5/ !7C7[:OI0\C-".P+G__S/ \J[WT2OYa
XMB]F'_KG___*N3XO+T>GRI1/)\J1?N$0 HY ZC4;:4.@.#H/$ @O =!Z-1MI0a
XMZ! .@\0""\!T$(U&VE"XOP%0Z"T6@\0$ZS;_=@:+7OS_=P+HL/V#Q 2#/I Za
XM1'4*N.0!4.C,#8/$ HM>U,:'E#P @T;^$(%^_H8+

7XOE7<.0a XM58OL_S:"!_]V"/]V!O]V!/9&"@1T!K@A .L0D/9&"@)T!K@@ .L$D+@C %#Va XM1@H0= :X.@#K!)"X( !0]D8*('0&N"H ZP20N" 4+CG 5#HE16#Q!" -H('a XM UW#D%6+[(/L!E=6_W8*N/T F5)0BT8(F5)0Z)PL4E#_=@2X P)0Z&05@\0*a XM_PX2!7@/BQX0!?\&$ 6*!RKDZPN0N! %4.B!%8/$ B7? (E&^CT* '0D_PX2a XM!7@/BQX0!?\&$ 6*!RKDZPN0N! %4.A7%8/$ CT* '7<@W[Z670#Z<< BT8&a XMB4;ZBW[\Z:P N" "4.CW%(/$ O\V@ ?_-H0'5NA5"X/$!@O =>.+'H 'BH?_a XM "KDB_B+PXE&_@O_?F*+\( \?W4?_PX:!7@/L F+'A@%_P88!8@'ZSZ0N!@%a XM4+@) .LMD( \FW45_PX:!7@%L KKVI"X& 50N H ZQ.0_PX:!7@$B@3KQ;@8a XM!5"*!"KD4.AR%8/$!$]&"_]UHXEV_HL>@ >*I_T *L"*C_X *NT#P8#D XE&a XM^H-^^@!T!HMV^NE2_XE^_%Y?B^5=PY!5B^R#[ Q75J L 8A&]/]V"KC] )E2a XM4(M&")E24.A(*U)0_W8$N$D"4.@0%(/$"O9&"@1T!;C_ .L#N , B4;X_PX2a XM!7@.BQX0!?\&$ 6*!RKDZPJX$ 50Z!T4@\0")=\ B4;Z/0H ="3_#A(%> ^+a XM'A %_P80!8H'*N3K"Y"X$ 50Z/,3@\0"/0H ==R#?OI9= ^#?OI!= F#?OI"a XM= /I\0"#?OI!=0;&1O0 ZPJ#?OI"=03&1O0!N&4"4/]V!.B,!X/$!(E&]@O a XM=13_=@2X: )0Z&83@\0$7E^+Y5W#D(M&!HE&^NMUN( "4.A-$X/$ O\V@ ?_a XM-H0'5NBK"8/$!@O =>.+'H 'BH?_ "KDB4;\B\.)1OZ#?OP ?B2+?O:+\(!^a XM] !T0%>*!"KD4.A3!X/$!/]._$:#?OP =>2)=OZ+'H 'BH?] "KD(T;XBN@Ja XMR8J'_@ JY /(B4[Z@W[Z '0GBW;ZZXJ /']U!U>X"0#KNI" /)MUKU>X#0!0a XMZ ,'@\0$5[@* .NC_W;VZ&8'@\0"7E^+Y5W#D%6+[(/L"%=6OI -*\GK!9#&a XM! !&B\%!/0 %?/2)=OJ)3OB_D W'1OAH <=&_@, _S: !_]V!/]V^/].^.C0a XM"(/$!@O =!2XJ0)0Z%42@\0"N $ 4.@+#(/$ BO)B_>+%H 'B]D#VHH'B 1&a XM08'Y %\\(O^B4[\@#Z0#0=V&+BP)U"XZ )0Z!D2@\0$N $ 4.C/"X/$ O]&a XM_HM&_HH.D TJ[3O!=HF)?OI>7XOE7<.058OL@^P(5U:_D W'1OAH :"0#2KDa XMB4;^*\F+]XL6@ >+V0/:B@2(!T9!@?D 7SPB_Z)3OS_-H '_W8$_W;X_T[Xa XMZ&((@\0&_T[^@W[^ WW'B7[Z7E^+Y5W#58OL@^P25U:XA@M0Z-0'@\0"QT;Xa XM___I+@*+7@;_-[CX/%#H4PF#Q 2)1OP+P'0#Z?,!BW[X_S84/?\V$CVX%CU0a XMN T#4.A/$8/$"(,^+ $ = 6X*P/K [@N U"X%CU0Z-$/@\0$B4;TN(8+4+@2a XM %"X 0!0Z"('@\0&N!8]4.CF 8/$ HE&_NA)!(E&\(E&\HM&_K$$T^ E< ")a XM1O8#!H 'B4;NB]B*1O"(1P.*1O&(1P2+1OZQ ]/X!6D!B4;V_S: !_\VA =0a XMZ($'@\0&N(8+4.@-!X/$ L=&^@$ L0+39O['1O8 (MV_.D2 8/^"G4#OIL a XM@7[V_0!] ^GR .C1 XOX"_]^ ^F0 +@P U#HA1"#Q *)=OS_=O3H*0Z#Q *+a XM'H 'BD;^B(?] ,:'_@ BD;VB(?_ +B&"U"X$@!0N $ 4.A2!H/$!O\V@ ?_a XM-H0'_W;PZ/0&@\0&BT;RB4;PBT;^T?C1^%"X0@!0_W;ZZ.("@\0&N(8+4.AEa XM!H/$ KCX/%#H_@>#Q (+P'0#Z8X "_]U ^F' .F:_HL>@ >*1OZ+U[$(T_H"a XMPHB'_0"+QXB'_@#&A_\ _;B&"U"X$@!0N $ 4.C1!8/$!O\V@ ?_-H0'_W;Pa XMZ',&@\0&N(8+4.C_!8/$ HE^\,=&]@ _T;ZBU[V QZ !XO&B ?_1O;_=O3Ha XM !Z#Q *+\ OV?0/I!/^#_@ET ^G4_KY_ .G6_HE^^.L?D(M>!O\W@W[\$GT%a XMN$L#ZP.X7 -0N&T#4.A7#X/$!H-&!@+_3@1X ^G*_;B&"U"X$@!0N $ 4.@[a XM!8/$!EY?B^5=PU6+[(/L'%=6QT;J #'1NP +@@(+D% (U^\!8'\JNJ@T;La XM"\9&^P"+=@2+3NJ /"YT$X \ '0.B_F*!(A#\$9!@_D+?.B)=@2)3NJ#^0M]a XM*XO>@#\N=22Y" #K"9"+^8H$B$/P04: / !T"H/Y"WT%@#P*=>B)=@2)3NJ_a XM___'1NII <=&Z$@+BW;L_S: !_\VA ?_=NKH P6#Q 8+P'04N'@#4.B(#H/$a XM K@! %#H/@B#Q (K]HM&Z(E&YHE&Y(U&\%"+'H 'C4 %4.@S H/$! O =!R+a XM_K$$T_\#?N2![T@+B\>)?NZ)=NQ>7XOE7<.0BQZ !X X '43"_]]0XO^L033a XM_P-^YH'O2 OK-(L>@ ?V (!T$0O_?0V+_K$$T_\#?NB![T@+@\80@?Z 'R/a XM@T;H"/]&ZH%^ZG$!?0/I2O^)?NZ)=NP+_WT4N+8#4.C=#8/$ K@! %#HDP>#a XMQ *+1NZQ ]/XBT[J@>EI 3O!=#O_-H '_S:$!XM&[K$#T_@%:0%0Z!4$@\0&a XM"\!T'HMV[K$#T_Z!QFD!_S: !_\VA =6Z/<#@\0&"\!U[8M&[B4' +$$T^ #a XM!H 'B4;\B]C&!P.#1OP%QT;J "+7ORY!0"+^XUV\!X'\J6D@T;J"X-&_ N+a XM1NY>7XOE7<.058OL@^P$5O\V@ ?_-H0'BT8(L0/3^ 5I 5#HD@.#Q 8+P'0>a XMBW8(L0/3_H'&:0'_-H '_S:$!U;H= .#Q 8+P'7MBT8(L033X"5P (E&_HOPa XM S: !XI&!H@$BT8$B40!_S: !_\VA >+1@BQ ]/X!6D!4.B! X/$!EZ+Y5W#a XM58OL@^P(5KX* .L!1H"\D T =1"!_@ %?/(KP(EV_%Z+Y5W#B7;\B\:Q ]/@a XM+5 B4;^QT;Z@ "+WO:'D V =1V*AY -*N2+\(M6_HM.^M'Y0HO!A<9T]XE6a XM_HE.^HM>_(M&^O?0((>0#8L>DCS_#XM&_EZ+Y5W#58OL5HM>!+$#T_N+=@2#a XMY@?1YHJ$&@$(AYH-7EW#58OL@^P"5U8KR8M^!(MV!D>L.$7_=!$KP(E^!(EVa XM!HE._EY?B^5=PT&#^0M\XHE^!(EV!HE._K@! %Y?B^5=PU6+[(/L KB&"U#Ha XM+ *#Q +_=@;_=@3H<0J#Q 2)1OZXA@M0N!( 4+@! %#HP@&+1OZ+Y5W#D%6+a XM[(/L H$^*@$ *')0N(8+4.CN 8/$ O]V!K@ *%"X 0!0N) 24.A2"H/$"(E&a XM_CT *'01N H*T;^4+C1 U#H=0N#Q 3'!BH! "XA@M0N!( 4+@! %#H7P&#a XMQ :+'BH!_P8J 8I&!(B'D!*+Y5W#D%6+[(/L KB&"U#HA &#Q *#/BH! '0Na XM_W8$_S8J ;@! %"XD!)0Z.$)@\0(B4;^H2H!.4;^= XK1OY0N ($4.@$"X/$a XM!,<&*@$ /]V!.BE"(/$ KB&"U"X$@!0N $ 4.CE (OE7<.058OL@^P$5U8Ka XM]HM^!+C^ %#_-H '5U;HV &#Q @+P'T+5K@L!%#HM0J#Q 1&@_XH?-N)=O['a XM1OX "O N0 !OY -'@?RJX!&_P+&!I - K#$HI,-HI$-L *BE VBD@V^! !6a XMZ"S^@\0"1H'^: %\\HEV_KYQ 5;H&/Z#Q )&@?[0 GSRB7;^QT;^ KP+D a XM K^&!QX'\JN 1O\$_W8$Z$KX@\0"OFD!BWX$N(8'4%=6Z-\ @\0&1H'^<0%\a XM[8EV_EY?B^5=PY!5B^R+1@2,V[$$T^,#V('[ /YV BO#7<-5B^P>5U;\,_8>a XM!X[>Q39X (M^"+D% /.E@^X*BD8$BF8&B40#QD0%',9$!Q@NB"8V$[0 B]C1a XMXRZ+GR@3+HD>-!/-$UY?'UW#58OL'E=6,\GB_OR+=@0SP([ )L0^> "Q!?.Ea XMS1->7Q]=PU6+[ 965^A >@) '(",\!?7@==P^C6 %)14[@! LT3G%!S$B[^a XM#C@3= M8G;0 S1-;65KKXEB=6UE:G+F ";W%T-#XOF=PU6+[ 965^CX .@%a XM %]>!UW#Z)( 4E%3N8 )O<70T/B^5M945.X 0/-$W,@4+0 S1-86UE:+OX.a XM.!-UV%%3N8 )O<70T/B^5E;^<-;4[F ";W%T-#XOFX !;65K#58OL'@97a XMBWX(C-B.P+0!BUX*BFX$_(H'//]T#4,FB"U')L8% $>KZ^TK7@J+PXM>"+$!a XMM@"*5@:T!!_@ 0<@.^ !#ZCM>!Q"Y#^W,0%A_H]P$SP%#H=@2X_TS-(8/Da XM_C:))DX$-HDF2@2+QK$$T^!(-J-(! /WB38" (S#*][WV[1*S2$VC!Z_!!8'a XM_+]0![DP0RO/,\#SJA8?Z#L %A_HD@/H 0(S[?\VX 3_-MX$_S;a XM: 9S!18?Z4T!-L4&< :,VKL# #;_'F@&%A^.!K\$)HL.+ #C-H[!,_\F@#T a XM="RY# "^H 3SIG0+N?]_,\#RKG49Z^4&'@_R 2LF)&L_L!T 4BJXO<6a XM'[L$ ("GR 2_N !$S2%R"O;"@'0%@(_(!$!+>>>^= :_= ;HH@"^= :_= ;Ha XMB@##58OLOG8'OW8'Z'T OG0&OW8&Z'0 ZP-5B^R^=@:_=@;H9@"^=@:_=@;Ha XM; #HN0 +P'0+@WX$ '4%QT8$_P"Y#P"[!0#VA\@$ 70$M#[-(4/B\N@' (M&a XM!+1,S2&+#FH&XP>[ @#_'F@&'L46K02X "7-(1^ /NH$ '0-'J#K!,46[ 2Ta XM)/V_]'K\L,[]W,.@^\$BP4+10)T\O\=Z^[# %6+[+C\a XM %#H>P*#/O $ '0$_Q;P!+C_ %#H:0*+Y5W#N ( Z5O^68O<*]AR"CL>\@1Ra XM!(OC_^$SP.E%_E8S]KE" #+D_*PRX.+[@/15= WHKO^X 0!0Z"P"N $ 7L./a XM!O0$N@( .!;!!'0IC@:_!":.!BP C ;D!#/ F;D @#/_\JZN=?M'1XD^X@2Ya XM___RKO?1B]&_ 0"^@0".'K\$K#P@=/L\"73W/ UT;PK =&M'3JP\('3H/ ETa XMY#P-=%P*P'18/")T)#Q<= -"Z^0SR4&L/%QT^CPB= 0#T>O3B\'1Z1/1J %Ua XMRNL!3JP\#70K"L!T)SPB=+H\7'0#0NOL,\E!K#Q<=/H\(G0$ ]'KVXO!T>D3a XMT:@!==+KEQ8?B3[ XOXKXHO$H]X$B]@#^Q8'-HD_0T/%-N($a XMK*H*P'7ZOH$ -HX>OP3K S/ JJP\('3[/ ET]SP-=0/I?P *P'4#ZWF0-HD_a XM0T-.K#P@=-L\"737/ UT8@K =%X\(G0G/%QT ZKKY#/)0:P\7'3Z/")T!K!GSJG,&L"*JZ\5.K#P-="X*P'0J/")TMSQ<= .JZ^PSR4&L/%QTa XM^CPB= :P7/.JZ]FP7-'I\ZISEK BJNO-,\"J%A_'!P _R;T!%6+[%6.'K\$a XM,\F+P8OIB_E)BS8L OV=!".QB: /@ '0&\JY%KG7Z19= )/Z+_='E \46a XM'U>_"0#HA0!?B\^+_0/XB2[@!!X'CMXS]DGC$X$\.T-T!8E^ $5%K*H*P'7Za XMXNV)3@ 6'UV+Y5W#58OL5E<>!XM6!+Y^!JT[PG000)9T#).+A[0%B4;\5NA@:#Q ) = %'@\8(.38H!G/FB\=>7XOE7<-5B^R#[ )6Z(X/B_ +a XM]G005O]V!O]V!.@V!(/$!NL#D"O 7HOE7<.058OL@^P(5U:+=@2+?@J+1@;Wa XM9@B)1OZ)1OR#?@8 = :#?@@ =08KP.D+ 9#V108,=66+WX'K$ 6Q ]/[B\/1a XMXP/8T>/VA[ % 75,]T;\_P%U(/]V_%:*10>84.B($H/$!HE&^#W__W2]*]+Wa XM=@;IQ0"0_TT"> N*!(L=_P6(!^L,D%>*!)A0Z*X!@\0$]D4&('631O]._/9%a XM!@AU0(O?@>L0!;$#T_N+P]'C ]C1X_:'L 4!=%SK)?]- G@+B@2+'?\%B ?Ka XM#)!7B@284.AH 8/$!/9%!B!U4T;_3OR#?OP =$F#?0( =,^+10(K1OP;R2/!a XM T;\B4;Z4%;_->C.%H/$!HM&^@$% _ I1OPI10+KR_]V_%:*10>84.C($8/$a XM!HE&^#W__W0#*4;\BT;^*T;\Z33_D%Y?B^5=PU6+[(/L"%=6OA@%C48&B4;\a XM5NC/ X/$ HOXC48&4/]V!%;H1P6#Q :)1OA65^@X!(/$!(M&^%Y?B^5=PU6+a XM[(/L E:+=@2+QBT0!;$#T_B+R-'@ \'1X 6P!8E&_O9$!H-T!O9$!D!T![C_a XM_^F( )#V1 8"= : 3 8@Z^V 3 8!BU[^@"?[]D0&#'4BB]Z!ZQ %L0/3^XO#a XMT>,#V-'C]H>P!0%U"5;HUP&#Q +K!8M$!(D$BU[^_W<"_W0$BD0'F%#H"!"#a XMQ :)1 (+P'0%/?__=1F#? ( = 6P(.L#D+ 0"$0&QT0" #I?O^0_TP"BQS_a XM!(H'*N1>B^5=PU6+[(/L"%=6BW8&BD0'F(E&^HO&+1 %L0/3^(O(T> #P='@a XM!; %B4;X]D0&@W0&]D0&0'0+@$P&(+C__^D0 9#V1 8!=>^ 3 8"@&0&[RO a XMB40"B_B)?OSV1 8,=5^+WH'K$ 6Q ]/[B\/1XP/8T>/VA[ % 75&@?X8!70&a XM@?X@!74S_W;ZZ.D4@\0""\!U+?\&#@6!_A@%=0:XD OK!)"X*D&)1 2)!(M>a XM^,=' @ "Q@@>L0!;$#T_N+P]'C ]C1X_:'a XML 4!=%"+/"M\!(M$!$")!(M>^(M' DB)1 (+_WX35_]T!/]V^NBO#X/$!HE&a XM_.L:D(M>^O:'R 0@= ^X @!0*\!04%/HE R#Q B+7 2*1@2(!^L7D+\! (O'a XM4(U&!%#_=OKH<@^#Q :)1OPY?OQT ^GK_HI&!"KD7E^+Y5W#D%6+[%:+=@3Va XM1 :#=!WV1 8(=!?_= 3H>1"#Q * 9 ;W*\")!(E$!(E$ EY=PY!5B^R#[ )6a XMBT8$+1 %L0/3^(O(T> #P='@!; %B4;^N "4.A0$(/$ HM>!(E'! O = ^ a XM3P8(BU[^QT<" +K%Y"+7@2 3P8$BT;^0(E'!(M>_L=' @$ BUX$B_.+1 2)a XM!\=' @ 7HOE7<-5B^R#[ I75HMV"(M>!HH'F#UA '0H/7( = L]=P!T%"O a XMZOTD/?' @!U/X'/ @"#a XMY_ZR@/]&!HM>!H _ '0V"\ET,HH'F#TK '3:/6( =!,]= !U%8O'J0# =0Z!a XMSP! Z]*0B\>I ,!T!2O)Z\:0@<\ @.N_B%;\B4[^N*0!4%?_=@3HEPN#Q :)a XM1OH+P'T#Z6[_BD;\B$0&_P8.!8O&+1 %L0/3^(O(T> #P='@!; %B4;X*L"+a XM7OB(!YB)1 +'1P0 "O B02)1 2*1OJ(1 >+QEY?B^5=PU6+[(/L!%:+=@3_a XM!@X%@?X8!74(QT;^D OK#)"!_B %=23'1OXJ0?9$!@QU&8O>@>L0!;$#T_N+a XMP]'C ]C1X_:'L 4!= 0KP.LUB\8M$ 6Q ]/XB\C1X /!T> %L 6)1OR+1OZ)a XM1 2)!(M>_+@ HE' HE$ L8' 8!,!@*X 0!>B^5=PU6+[(/L E:#?@0 =%N!a XM?@88!70'@7X&( 5U=HM>!HI'!YA0Z. 1@\0""\!T9(M&!BT0!;$#T_B+R-'@a XM \'1X 6P!8E&_O]V!NA+ (/$ HM>_L8' ,=' @ BUX&B_,KP(D$B4<$ZRJ0a XMBUX&@7\$D MT!X%_!"I!=1B*1P>84.B%$8/$ @O = G_=@;H" "#Q )>B^5=a XMPU6+[(/L!%=6BW8$*_^*1 8D SP"=4;V1 8(=1F+WH'K$ 6Q ]/[B\/1XP/8a XMT>/VA[ % 70GBP0K1 2)1OP+P'X;4/]T!(I$!YA0Z%\,@\0&.T;\= > 3 8@a XMO___BT0$B03'1 ( (O'7E^+Y5W#58OLN&0!Z!WU5U:+=@:-AI[^HVX'BT8(a XMHUX'BT8$HU('QP9H!P QP9F!P Z7P"@#PE= /I6 +'!FH' 0 KP*-:!Z-6a XM!Z-D!Z-8!Z-B!Z-@!Z-4!Z-0!Z-#AIS^((N&G/XM8P ]%0!V ^D4 0/ DR[_IR8CBQY>!XL?a XMH68'B0>#!EX' NEI 9#_!F0'QP90!P N H 4.A_ 8/$ NE1 9"X" #K\)#_a XM!E0'_P96!X,^8@< =0G'!FP' 0#K!Y#'!FP' #_!F('QP9J!P0 @SY8!PAUa XM ^F( "O HU@'B4;\.09P!W0GH7 'B4;\@SY!P*X$ !0Z/\ @\0"N#H 4.C/ X/$ H-^_ !T(H,^a XM7 < =!6+1OPM!0"C< <+P'T"*\"C< ?K!Y#'!G ' "#+EX'!+@0 %#HO@"#a XMQ +I'_^X$ #I+_\KP%#HX@'I*O^0N $ Z_.0_[:<_NBY ND9_X,^6 < = .+a XMQDZ+_D> /0!T!8 ])77UB\5NCM X/$!HOW@#P = /I?/V#/F8' '59a XMBQY2!_9'!B!T3[C__^M-TB+N(=@BV"+8(N(B[B'B(N(BXB+B(M8A B(((N(Ba XMXB+((N(BZB'B(N(BPB*#/F@' '03@SYF!P!U$(L>4@?V1P8@=;?K!$;KF9"Aa XM9@=>7XOE7<.058OL@^P85U:#?@0*= 3_!F0'@SY8!P)T!X,^6 <0=1:+'EX'a XMBP>+5P*)1OR)5OZ#!EX'!.LJ@SYD!P!T$8L>7@>+!XE&_,=&_@ ZPZ0BQY>a XM!XL'F8E&_(E6_H,&7@<"@SY0!P!T#8M&_ M&_G0%BT8$ZP(KP*-R!XLV;@>#a XM/F0' '4J@W[^ 'TD@WX$"G47Q@0M1HM&_(M6_O?8@]( ]]J)1OR)5O['1O@!a XM .L%QT;X "-1NB+^/]V!%?_=O[_=OSH%0V#Q B#/F(' '0A5^AW#(/$ HL.a XM:@!P+ID0"#/E@'$'47a XMBQY>!XL'BU<"B4;XB5;Z@P9>!P3K%9"+'EX'BP>)1OR)1OB,7OJ#!EX' H,^a XM6 <0=0V+1O@+1OIU%+@J!NL)@W[\ '4)N#$&B4;XC%[ZBT;XBU;ZB4;RB5;Ta XM*_8Y-F('=!R+#FH'ZPZ0Q%[R_T;R)H _ '051CO.?A#K[9!&Q%[R_T;R)H _a XM '7SBSYP!RO^@SY7XOE7<-5B^R#[ 2A7@>)1OZ#?@1G= :#?@1'=02P >L"*L"(1OR#a XM/F(' '4&QP9J!P8 @'[\ '0-@SYJ!P!U!L<&:@!PC'!G(' "A6@<+!F '=!/_=O[_%EX&@\0"a XM"\!T!;@! .L"*\!0Z @!B^5=PU6+[%:#/F@' '4OBQY2!_]/ G@.BD8$BS?_a XM!X@$*N3K"Y!3_W8$Z&_U@\0$0'4'_P9H!^L%D/\&9@=>7<.058OL@^P"5U:#a XM/F@' '5)BW8$"_9^0NL5_S92!_\V= ?H-_6#Q 1 =03_!F@'B\9."\!^%HL>a XM4@?_3P)XVZ!T!XL__P>(!2KDZ]R#/F@' '4'BT8$ 09F!UY?B^5=PU6+[(/La XM E=6BW8(@SYH!P!U4.L<_S92!\1>!":*!YA0Z-GT@\0$0'4$_P9H!_]&!(O&a XM3@O =!V+'E('_T\">-3$7@0FB@>+'E('BS__!X@%*N3KTH,^: < =0>+1@@!a XM!F8'7E^+Y5W#58OL@^P*5U:+-FX'*\")1OR)1OJ#/G0','48.09B!W02.094a XM!W0&.09L!W4&QP9T!R BSYP!U;H,0F#Q *)1O@K^"M^!(,^7 < =1B /"UUa XM$X,^= 7@>+/X,&7@<"1NM(D( \+74&QT;^__]&*_^ /#!\-8 \.7\Pa XM.3YB!W4+@#PP=0;'!G0', "*!)B+S]'AT>$#S]'A \B#Z3"+^4: /#!\!8 \a XM.7[ABT;^]^^+^(M>!(D_B\9>7XOE7<.058OL@^P"5KXX!HI.!.L"D$: / !Ta XM"CH,=?:X 0#K Y KP%Z+Y5W#D%6+[(/L E:^$ 6+#B@&]D0&@W46*\")1 *(a XM1 :)1 2)!,9$!_^+QNL,D(O&@\8(.\%UVRO 7HOE7<-5B^Q6BW8$_TP"> J+a XM'/\$B@!#L>Q@1R!K@ "?GK"[0^S2%R!<:'a XMR 0 Z:[N58OL@^P$BUX$.Q[&!'(%N )ZRKW1@@ @'1(@WX* '0:,\F+T;@!a XM0LTA2BX !;YZS:)5OZ)1OR+T;@"0LTA T8&$U8(a XM>0V+3OZ+5ORX $+-(>O8BU8&BTX(BD8*M$+-(7(%@*?(!/WI1^Y5B^R#[ 0Ra XM_XA^_HM&!HO(QD;\ *D @'40J0! =0?V!C\&@'4$QD;\@(M6!"0#"L>T/V3]D;^_W4'a XM]T8& @!U,+0^S2&*1@8D PI&_HM6!+0]S2%RVI/V1OT!=13W1@@! '0-@,D!a XMBU8$N %#S2%RO_9&_$!U/8M6!+@ 0\TAB\$RR24! '0"L1#W1@8( '0#@,D@a XM.Q[&!'(*M#[-(;@ &.G%_@I._(#) 8B/R 2+PXOE7<,RR>OP#8M6!NN6BU8&ZY2 ?O\*a XM==OKO@!5B^R#[ B+7@0['L8$<@>X GYZ:_K]H?(!"!T"[@"0C/)B]'-(7+Ka XM]H?(!(!T;HM6!AX',\")1OZ)1OS\5U:+^HORB6;XBTX(XU2P"O*N=4KHU ]a XMJ !V2(/L HO! O;= 2 3_X!B^5=PU6+[%97NT &@S\ =2D>![@% .AS 74%a XM,\"9ZR1 )/ZC0 :C0@:6QP0! (/&!,=$_O[_B39&!HM.!(S8CL#H"0!?7HOEa XM7YS\HMW ORMB_ZH 71"2#O!L% _G^3/Z+QHS:C-$[T70%)HP>3@:)a XM?P+#)L8&5 8"/?[_="6+_@/PK:@!=/*+_D@[P7.]B] #\*VH 73B \(% @"+a XM]XE$_NOFBT<("\!T!([8ZQ0F_@Y4!G01C-B,USO'= 4FCAY*!HLWZ[R+=P8Sa XMP.AJ #O&= TD 4! F.A> '0-_DW^Z!P = 663D[KF8S8C-$[P70$)J-.!HL'a XMB4<",\"9PU&+1?ZH 70#*\A)04&Z_W\F.Q90!G8$T>IU]8O! \9R%0/"<@WWa XMTB/"*\;H# !U"/?2T>IUY3/ 6<-24>@= '085XO^B_ #\L=$_O[_B7<&B]8Ka XMUTJ)5?Y865K#4U STAY24E"X 0!0!A_H#P"#Q B#^O\?6EMT @O2PP!5B^Q6a XM5P:#?@@ =3B_3@2+5@:+1@1(=0?H4P!R)^M(BS:>!$AT$3OW= V+1 *)1@Q6a XMZ#H 7G,P@\8$@?Z>!',$"])U!KC__YGK'8O:@\,/T=NQ ]/KM$C-(7+IDHD$a XMB50"B3:>!#/ !U]>B^5=PXM.#(OW.4P"= R#Q@2!_IX$=?+YZS^+V@,<2 1S)H/##]';T>O1Z]'K._=U"0/9H;\$*]B.P+1*S2%R#3OWa XM=02)%D@$DH<$B]'#58OLB]>+WHS8CL"+?@0SP+G___*NC77_BWX&N?__\J[Wa XMT2OYA_Z+1@3WQ@$ = *D2='I\Z43R?.DB_.+^EW# %6+[(O7B]Z+=@:+_HS8a XMCL SP+G___*N]]&+?@2+QZ@!= *D2='I\Z43R?.DB_.+^EW#58OLB]>,V([ a XMBWX$,\"Y___RKO?129&+^EW# .D! !5B^Q75HMV!#/ F3/;K#P@=/L\"73Wa XM4#PM= 0\*W4!K#PY=Q\L,'(;T>/1THO+B_K1X]'2T>/1T@/9$]<#V(/2 .OS .E0 %6+[(M>!#L>Q@1]$8/[ 'P,]H?(!$!T!;@! .L",\"+Y5W#a XM %6+[(O7B]Z,V([ BW8&BWX$B\>+3@CC#J@!= *D2='I\Z43R?.DB_.+^EW#a XMBTX*BT8$BU8&BWX(5QX'_),*P'03@_D*=0X+TGD*L"VJ]]N#T@#WVHOWDC/2a XM"\!T O?QD_?QDH?3!# \.78"!">JB\(+PW7BB 5/K(8%B$3_C40!.\=R\EA?a XM7HOE7<, 58OLBU8$M$'-(>DQY@!5B^R+1@:+7@H+V(M>"'4+BT8$]^.+Y5W"a XM" #WXXO(BT8$]V8* \B+1@3WXP/1B^5=P@@ !-4R!2=6XM5&EMa XM92!,:6)R87)Y("T@0V]P>7)I9VAT("AC*2 Q.3@X+"!-:6-R;W-O9G0@0V]Ra XM2$@($]P97)A=&EO;B!A8F]R=&5D(0H 0V%N;F]T('5S92!O2 E71E71Ea XM