|
|
DataMuseum.dkPresents historical artifacts from the history of: CP/M |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about CP/M Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 15360 (0x3c00)
Types: TextFile
Names: »FCOPY.ASM«
└─⟦1f6b46325⟧ Bits:30004393 CP/M-80 rel. 1 Utilities source disk
└─⟦this⟧ »FCOPY.ASM«
TITLE 'MINI FLOPPY DISKETTE COPY UTILITY'
PAGE 43
;******************************************************************************
; CHRISTIAN ROVSING A/S MINI FLOPPY DISKETTE COPY PROGRAM
;******************************************************************************
;
;
; MINI FLOPPY DISKETTE COPY PROGRAM FOR DUPLICATING A CHRISTIAN
; ROVSING A/S FORMATTED MINI FLOPPY DISKETTE USING 96 TPI
; 5 1/4 INCH MINIFLOPPY DISK DRIVES. THIS COPY PROGRAM WILL
; ACCESS TWO SEPERATE DRIVES TO PERFORM THE COPY OPERATION.
;
; THIS PROGRAM CONFIGURATION WILL SUPPORT TWO MINI FLOPPY DRIVES.
; MINI FLOPPY FORMAT IS AS FOLLOWS:
;
; 77 TRACKS
; 16 RECORDS PER TRACK
; TWO HEADS/SIDES
; 256 BYTE RECORDS
; CP/M MAPS LOGICAL DRIVE E: TO THE MINI FLOPPY WITH
; ODD TRACKS ON HEAD 0 AND EVEN TRACKS ON HEAD 1
; PHYSICAL SECTORS SKEWED FOR LOGICAL ACCESS WITH ORDER
; OF: 1,2,5,6,9,10,13,14,3,4,7,8,11,12,15,16
;
PAGE
;***************************************************************************
;
;
;GENERAL EQUATES
;
CR EQU 0DH ;CARRIAGE RETURN CODE
LF EQU 0AH ;LINE FEED CODE
BS EQU 08H ;BACK SPACE CODE
BEL EQU 07H ;BELL RING CODE
ESC EQU 01BH ;ESCAPE CODE
TRUE EQU 0FFFFH ;TRUE CODE
FALSE EQU NOT TRUE ;FALSE CODE
;
;
;
;DEFINE MEMORY BASED I/O MODULE ENTRY POINTS
;
MODBASE EQU 0F800H ;SET JUMP TABLE EQUIVALENT ADDRESSES
;
INITSER EQU MODBASE+00 ;INITIALIZE SERIAL I/O PORTS
; ;(NO PARAMETERS)
SETCBAUD EQU MODBASE+03 ;SET CONSOLE I/O BAUD RATE FACTOR
; ;(HL) = COUNTER TIMER PARAMETER VALUE
SETLBAUD EQU MODBASE+06 ;SET LINE PRINTER I/O BAUD RATE FACTOR
; ;(HL) = COUNTER TIMER VALUE
SETLRMSK EQU MODBASE+09 ;SET LINE PRINTER SIO RECEIVER MASK VALUE
;(A) = LINE PRINTER SIO MASK BYTE
SETLRVAL EQU MODBASE+012 ;SET LINE PRINTER SIO RECEIVER POLL VALUE
; ;(A) = LINE PRINTER POLL VALUE
SETLTMSK EQU MODBASE+015 ;SET LINE PRINTER SIO TRANSMITTER MASK VALUE
; ;(A) = LINE PRINTER SIO MASK BYTE
SETLTVAL EQU MODBASE+018 ;SET LINE PRINTER SIO TRANSMITTER POLL VALUE
; ;(A) = LINE PRINTER SIO POLL VALUE BYTE
CONSTAT EQU MODBASE+021 ;GET CONSOLE STATUS
; ;RETURN (A)=00 FOR NOT READY INPUT
; ; (A)=FF FOR READY INPUT
CONIN EQU MODBASE+024 ;GO GET CONSOLE INPUT CHARACTER
; ;(A)=INPUT CONSOLE CHARACTER
CONOUT EQU MODBASE+027 ;PUT OUT CONSOLE CHAR
; ;(C)=CHARACTER TO OUTPUT
LPTSTAT EQU MODBASE+030 ;GET LINE PRINTER STATUS
; ;RETURN (A)=00 FOR NOT NEXT OUTPUT
; ; (A)=FF FOR READY OUTPUT
LPTIN EQU MODBASE+033 ;GO GET LINE PRINTER INPUT CHARACTER
; ;(A)=INPUT LPT SERIAL PORT CHARACTER
LPTOUT EQU MODBASE+036 ;PUT OUT LINE PRINTER CHARACTER
; ;(C)=LPT SERIAL OUTPUT CHARACTER
HUNIT EQU MODBASE+039 ;SELECT HARD DISK UNIT NUMBER
; ;(C)=UNIT NUMBER ON MSC 9205 CONTROLLER
HPLAT EQU MODBASE+042 ;SELECT HARD DISK PLATTER (HEAD) NUMBER
; ;(C)=HEAD SELECT NUMBER
HSURF EQU MODBASE+045 ;SELECT HARD DISK SURFACE(HEAD 2^2) NUMBER
; ;(C)=MSB OF HEAD NUMBER
HCYL EQU MODBASE+048 ;SELECT HARD DISK CYLINDER NUMBER
; ;(BC)=CYLINDER NUMBER
HREC EQU MODBASE+051 ;SELECT HARD DISK RECORD NUMBER
; ;(C)=RECORD NUMBER
HCNT EQU MODBASE+054 ;SELECT HARD DISK SECTOR COUNT
; ;(C)=RECORD COUNT
HBADDR EQU MODBASE+057 ;SET 9205 CONTROLLER DMA ADDRESS
; ;(BC)=16 BIT DATA BUFFER ADDRESS
HREST EQU MODBASE+060 ;RESTORE SELECTED HARD DISK UNIT
; ;(A) RETURNS ERROR CODE
HREAD EQU MODBASE+063 ;READ SELECTED SECTOR(S)
; ;(A) RETURNS ERROR CODE
HVERF EQU MODBASE+066 ;VERIFY SELECTED SECTOR(S)
; ;(A) RETURNS ERROR CODE
HWRIT EQU MODBASE+069 ;WRITE SELECTED SECTOR(S);
; ;(A) RETURNS ERROR CODE
HEXEC EQU MODBASE+072 ;EXECUTE SPECIAL COMMAND OF MSC 9205
; ;(C) ENTRY WITH MSC 9205 COMMAND
; ;(A) RETURNS ERROR CODE
HRESET EQU MODBASE+075 ;RESET HARD DISK CONTROLLER MSC 9205
; ;NO PARAMETERS
MUNIT EQU MODBASE+078 ;SELECT MINI FLOPPY UNIT NUMBER
; ;(C)=FLOPPY PHYSICAL UNIT NUMBER
MSURF EQU MODBASE+081 ;SELECT MINI FLOPPY SURFACE(HEAD) NUMBER
; ;(C)=FLOPPY SIDE NUMBER
MCYL EQU MODBASE+084 ;SELECT MINI FLOPPY CYLINDER(TRACK) NUMBER
; ;(C)=FLOPPY TRACK NUMBER
MREC EQU MODBASE+087 ;SELECT MINI FLOPPY RECORD NUMBER
; ;(C)=FLOPPY SECTOR NUMBER
MCNT EQU MODBASE+090 ;SELECT MINI FLOPPY PHYSICAL SECTOR COUNT
; ;(C)=MINI FLOPPY SECTOR COUNT
MSIZE EQU MODBASE+093 ;SELECT FLOPPY SECTOR SIZE (00)=256 BYTES
; ;(C)=MINI FLOPPY TRACK NUMBER
MBADDR EQU MODBASE+096 ;SET FLOPPY DISK DATA BUFFER ADDRESS
; ;(BC)=FLOPPY BUFFER ADDRESS
MREST EQU MODBASE+099 ;RESTORE SELECTED MINI FLOPPY UNIT
; ;(A)=RETURNS ERROR STATUS
MVERF EQU MODBASE+102 ;VERIFY (READ) SELECTED SECTOR
; ;(A)=RETURNS STATUS
MWRIT EQU MODBASE+105 ;WRITE SELECTED SECTOR
; ;(A)=RETURNED STATUS
MREAD EQU MODBASE+108 ;READ SELECTED SECTOR
; ;(A)=RETURNED STATUS
MWTRK EQU MODBASE+111 ;WRITE SELECTED FLOPPY TRACK
; ;(A)=RETURNED STATUS
MMODE EQU MODBASE+114 ;SET FLOPPY OPERATION MODE
; ;(C)=STANDARD MODE DEFINITION
MINST EQU MODBASE+117 ;FETCH CURRENT INSTRUCTION CODE
; ;(A)=RETURNED INSTRUCTION PATTERN
MMOFF EQU MODBASE+120 ;CHECK MINI FLOPPY MOTOR ON COUNT
; ;OUT TIMER
PAGE
;
; UNIT/MODE REGISTER FOR DISK DRIVES SELECT
;
; BIT 7 - COMPENSATION "1" ENABLES FLOPPY WRITE PRECOMPENSATION
; BIT 6 - DRIVE TYPE "1" SELECTS CLOCKING FOR A 5 1/4 DRIVE
; "0" SELECTS FOR AN 8 INCH UNIT
; BIT 5 - DENSITY "1" SETS FOR MFM DOUBLE DENSITY
; "0" SELECTS FM SINGLE DENSITY
COMPEN EQU 080H ;WRITE COMPENSATION ENABLE
MINIEN EQU 040H ;MINI DRIVE ENABLE
DENSEL EQU 020H ;BIT MASK FOR DENSITY SELECT
;
FSPT EQU 016 ;NUMBER OF MINI FLOPPY 256 BYTE
;SECTORS PER TRACK
FSECSIZ EQU 256 ;NUMBER OF BYTES IN A MINI FLOPPY SECTOR
FTPS EQU 77 ;NUMBER OF FLOPPY TRACKS PER SIDE
;
;******************************************************************************
;
;SET START OF PROGRAM CP/M TRANSIENT PROGRAM AREA
;
ORG 0100H
;
DI ;DON'T ALLOW INTERRUPTS HERE
JMP START
;
;
;
;COMPARE DOUBLE REGISTER PAIRS (DE) TO (HL) AND RETURN
;FLAGS SIMILAR TO STANDARD CMP B INSTRUCTION. IE (A) CORRESPONDS
;TO (DE) AND (B) CORRESPONDS TO (HL).
;
CDEHL:
MOV A,D ;CHECK HIGH BYTES FIRST
CMP H
RNZ ;RETURN IF HIGH BYTES SET FLAGS
MOV A,E
CMP L ;CHECK LOW BYTES
RET
;
PAGE
;******************************************************************************
;
START: ;BEGINNING OF PROGRAM
LXI SP,STCKK ;MAKE OURSELVES A STACK
;
SIGNON: ;SEND HELLO TO CRT
CALL CRLF
CALL CRLF
LXI D,STRMSG
CALL CRTMS
JMP MONITOR ;GO TO MONITOR ROUTINE
;
;
;FORMAT PROGRAM MESSAGES
;
STRMSG:
DB ESC,'Æ7;2m'
DB 'CHRISTIAN ROVSING A/S - CR8 DISKETTE COPY PROGRAM',CR,LF
DB 'FOR TANDON TM-100 96 TPI 5 1/4 MINI FLOPPY DRIVES',CR,LF
DB ESC,'Æ',6DH
DB CR,LF,CR,LF
DB ' INSERT SOURCE DISKETTE IN DRIVE A:',CR,LF
DB ' DESTINATION DISKETTE IN DRIVE B:',CR,LF
DB CR,LF
DB ' TYPE "Y" WHEN READY TO COPY (Y) ','#'
;
PAGE
;******************************************************************************
;
;
MONITOR:
CALL CECHO ;GET OPERATOR ENTRY CHARACTER
ANI 05FH ;CONVERT TO UPPER CASE
CPI 'Y' ;CHECK IF HE WANTS TO START
JNZ ENDCHK
;
;
;HERE IF TO COPY A DISKETTE IN A: TO A DISKETTE IN B:
;
LXI D,GOMS3 ;PRINT READY MESSAGE FOR FLOPPY
CALL CRTMS
CALL CECHO ;GET OPERATOR RESPONSE
ANI 05FH ;UPPER CASE
CPI 'Y'
JNZ ENDCHK ;END PROCESS IF NOT READY
;
CALL CRLF
CALL FLOPCPY ;GO COPY THE TWO DISKETTES
;
CPYDONE:
LXI D,COPDMS ;PRINT FORMAT COMPLETE MESSAGE
CALL CRTMS
JMP ENDCHK
;
;
GOMS3:
DB CR,LF,'READY TO COPY DISKETTE IN A: TO DISKETTE IN B: '
DB '(Y/N) ','#'
COPDMS:
DB CR,LF,'DISKETTE COPY COMPLETE',CR,LF,'#'
;
PAGE
;******************************************************************************
;
; OPERATION DONE OR ERROR EXIT POINT
;
;
ENDCHK:
LXI D,DONMSG ;PRINT DONE MESSAGE
CALL CRTMS
CALL CECHO ;GET OPERATOR ANSWER
ANI 05FH ;CONVERT RESPONSE TO UPPER CASE
CPI 'Y' ;SEE IF HE WANTS TO GO AGAIN
JZ SIGNON ;GO START ALL OVER AGAIN
;
CALL CRLF
JMP 0000H ;GO GO TO WARM BOOT
;
;
DONMSG:
DB CR,LF,'DO YOU WANT TO COPY ANOTHER DISK? (Y/N) ','#'
;
PAGE
;******************************************************************************
;
; GENERAL PURPOSE I/O SUBROUTINES
;
;
CRLF: ;ROUTINE TO DO CONSOL CR AND LF
MVI C,CR
CALL CONOUT
MVI C,LF
CALL CONOUT
RET
;
;
;
CECHO: ;ROUTINE TO GET AND ECHO A CHARACTER
CALL CONIN
MOV C,A
PUSH PSW
CALL CONOUT
POP PSW
ANI 07FH ;GET RID OF PARITY
RET
;
;
;
NBL: ;ROUTINE TO CONVERT A BYTE TO A HEX NIBBLE
SUI '0'
RC
ADI 0E9H
RC
ADI 06H
JP NIO
ADI 07H
RC
NIO:
ADI 10
ORA A
RET
;
PAGE
;
BYTEC: ;ROUTINE TO GET A HEX BYTE IN A
CALL CECHO ;GET CHARACTER
BYTC1:
CALL NBL ;CONVERT TO HEX
JC ERRR ;TO ERROR ROUTINE
RLC
RLC
RLC
RLC
PUSH PSW ;SAVE 1ST ENTRY
CALL CECHO ;GET 2ND CHARACTER
CALL NBL ;CONVERT IT TO HEX
JC ERRR
POP B ;RECOVER 1ST RESULT
ORA B ;COMBINE WITH 2ND
RET
;
;
;
CONI: ;ROUTINE TO GET A 1 BYTE PARAMETER
PUSH B
CALL BYTEC
POP B
RET
;
PAGE
;
PARAM: ;ROUTINE TO INPUT 4 HEX CHARACTERS
LXI H,0
PARM1:
CALL CECHO ;GET INPUT
CPI 0DH ;LOOK FOR RETURN
RZ
DAD H
DAD H
DAD H
DAD H
JC ERRR
CALL NBL ;CONVERT ENTRY TO HEX
JC ERRR
ORA L
MOV L,A
JMP PARM1 ;GO FOR NEXT CHARACTER
;
;
;
HLCO1: ;ROUTINE TO PRINT CONTENTS OF (HL)
MOV A,H
CALL BYTEO
MOV A,L
CALL BYTEO
RET
;
PAGE
;
BYTEO: ;ROUTINE TO OUTPUT A HEX BYTE TO THE CONSOLE
PUSH PSW
CALL BYTO1
MOV C,A
CALL CONOUT
POP PSW
CALL BYTO2
MOV C,A
CALL CONOUT
RET
;
BYTO1:
RRC
RRC
RRC
RRC
BYTO2:
ANI 0FH
CPI 0AH
JM BYTO3
ADI 07H
BYTO3:
ADI 030H
RET
;
;
;ERROR ON ENTRY OF OPERATOR PARAMETERS
;
ERRR:
MVI C,'?' ;OUTPUT UNKNOWN PARAMETER
CALL CONOUT
CALL CRLF
JMP ENDCHK ;GO TO OPERATOR END CHECK SEQUENCE
;
PAGE
;******************************************************************************
;
;
;CRTMS - ROUTINE TO DISPLAY A MESSAGE ON THE CRT. REGISTERS D AND E
; CONTAIN THE MESSAGE POINTER. END OF MESSAGE IS INDICATED BY
; A "#" CHARACTER.
;
;
CRTMS: ;ROUTINE PRINTS MESSAGE ON CRT
LDAX D
CPI '#' ;END MESSAGE MARKER
RZ ;YES - RETURN
MOV C,A
CALL CONOUT
INX D
JMP CRTMS
;
PAGE
;******************************************************************************
;
; ROUTINE TO COPY ALL TRACKS OF THE MINI FLOPPY DISKETTE
; IN DRIVE UNIT 0 (A:) TO THE CORRESPONDING TRACKS ON THE
; DISKETTE IN DRIVE UNIT 1 (B:). TRACKS ARE READ TWO AT A
; TIME INTO A LARGE BUFFER AT THE END OF THIS PROGRAM.
; THE SAME TRACKS ARE THEN WRITTEN FROM THE BUFFER. ONCE
; A TRACK IS WRITTEN IT A REREAD AS A MEANS OF VERIFYING
; THE COPY. THE DATA IS NOT FULLY COMPARED. ONLY A CRC
; CHECK. CRC'S ARE REALLY GOOD ANYWAY.
;
FLOPCPY:
MVI C,00H ;RESTORE UNIT 0
MOV A,C
STA FUNIT ;SAVE FOR ERROR REPORTING
CALL MUNIT
CALL MREST
ORA A
JNZ REPERR ;ERROR REPORT MAY BE NECESSARY
;
MVI C,01H ;RESTORE UNIT 1
MOV A,C
STA FUNIT ;SAVE FOR ERROR REPORTING
CALL MUNIT
CALL MREST
ORA A
JNZ REPERR
;
;
;HERE IS WHERE THE COPY WILL REALLY START
;
XRA A ;START LOOP COUNT AT 0
STA LOOPCNT
;
PAGE
;
COPYLOOP:
LXI D,TRKMSG ;PRINT TRACK NUMBER REPORT
CALL CRTMS
LDA LOOPCNT
ORA A
RAL
PUSH PSW ;SAVE TRACK #
CALL BYTEO ;PRINT FIRST TRACK NUMBER
LXI D,ANDMSG ;PRINT AND
CALL CRTMS
POP PSW
INR A
CALL BYTEO ;PRINT SECOND TRACK NUMBER
;
;
;READ IN TWO TRACKS TO THE BUFFER FROM DRIVE A:
;
MVI C,00H ;READ UNIT 0
MOV A,C
STA FUNIT ;SAVE FOR ERROR REPORTING
CALL MUNIT
LDA LOOPCNT ;SET TRACK NUMBER
MOV C,A
CALL MCYL
MVI C,01H ;SET START SECTOR NUMBER
CALL MREC
MVI C,00H ;SET SECTOR SIZE CODE
CALL MSIZE
MVI C,FSPT ;SET FLOPPY NUMBER OF SECTORS TO DO
CALL MCNT
LXI B,DATBF1 ;POINT TO FIRST TRACK BUFFER
CALL MBADDR
MVI C,00H ;READ SIDE ZERO FIRST
CALL MSURF
CALL MREAD ;GO READ TRACK INTO BUFFER
ORA A
JNZ REPERR ;GO REPORT ERROR IF SO
LXI B,DATBF2 ;POINT TO SECOND TRACK BUFFER
CALL MBADDR
MVI C,01H ;READ SIDE ONE NEXT
CALL MSURF
CALL MREAD ;GO READ SECOND TRACK IN
ORA A
JNZ REPERR ;GO REPORT ERROR IF ONE
;
;
;WRITE THE BUFFERS TO THE TWO TRACKS OF DRIVE B:
;
MVI C,01H ;WRITE UNIT 1
MOV A,C
STA FUNIT ;SAVE FOR ERROR REPORTING
CALL MUNIT
LDA LOOPCNT ;SET TRACK NUMBER
MOV C,A
CALL MCYL
MVI C,01H ;SET START SECTOR NUMBER
CALL MREC
MVI C,00H ;SET SECTOR SIZE CODE
CALL MSIZE
MVI C,FSPT ;SET FLOPPY NUMBER OF SECTORS TO DO
CALL MCNT
LXI B,DATBF1 ;POINT TO FIRST TRACK BUFFER
CALL MBADDR
MVI C,00H ;WRITE SIDE ZERO FIRST
CALL MSURF
CALL MWRIT ;GO READ TRACK INTO BUFFER
ORA A
JNZ REPERR ;GO REPORT ERROR IF SO
LXI B,DATBF2 ;POINT TO SECOND TRACK BUFFER
CALL MBADDR
MVI C,01H ;WRITE SIDE ONE NEXT
CALL MSURF
CALL MWRIT ;GO READ SECOND TRACK IN
ORA A
JNZ REPERR ;GO REPORT ERROR IF ONE
;
PAGE
;
;NOW READ DATA JUST WRITTEN TO VERIFY THE CRC'S
;OBVIOUSLY THIS WILL BE ON UNIT 01 (B:)
;
MVI C,01H ;READ UNIT 1
MOV A,C
STA FUNIT ;SAVE FOR ERROR REPORTING
CALL MUNIT
LDA LOOPCNT ;SET TRACK NUMBER
MOV C,A
CALL MCYL
MVI C,01H ;SET START SECTOR NUMBER
CALL MREC
MVI C,00H ;SET SECTOR SIZE CODE
CALL MSIZE
MVI C,FSPT ;SET FLOPPY NUMBER OF SECTORS TO DO
CALL MCNT
LXI B,DATBF1 ;POINT TO FIRST TRACK BUFFER
CALL MBADDR
MVI C,00H ;READ SIDE ZERO FIRST
CALL MSURF
CALL MREAD ;GO READ TRACK INTO BUFFER
ORA A
JNZ REPERR ;GO REPORT ERROR IF SO
LXI B,DATBF2 ;POINT TO SECOND TRACK BUFFER
CALL MBADDR
MVI C,01H ;READ SIDE ONE NEXT
CALL MSURF
CALL MREAD ;GO READ SECOND TRACK IN
ORA A
JNZ REPERR ;GO REPORT ERROR IF ONE
;
LDA LOOPCNT ;CHECK IF DONE WITH LOOP YET
INR A
STA LOOPCNT
CPI FTPS ;DONE WITH ALL TRACKS?
JNZ COPYLOOP ;..NOTE FIRST TRACK WAS #0
RET
;
PAGE
;
;MINI FLOPPY COPY TRACK REPORT MESSAGE
;
TRKMSG:
DB CR,'TRACK ','#'
ANDMSG:
DB ' AND ','#'
;
;
;****************************************************************************
;
;
;MINI FLOPPY ERROR REPORTING SUBROUTINE
;
REPERR:
PUSH PSW ;SAVE THE ERROR CODE
LXI D,ERRMSG ;PRINT ERROR MESSAGE
CALL CRTMS
POP PSW
CALL BYTEO ;OUTPUT ERROR CODE
LXI D,ERRMS1 ;PRINT REST OF MESSAGE
CALL CRTMS
LDA FUNIT ;PRINT DRIVE NUMBER WITH PROBLEM
ADI 'A'
MOV C,A
CALL CONOUT
LXI D,ERRMS2 ;FINISH THE COMPLETE PRINTING
CALL CRTMS
JMP ENDCHK
;
;
ERRMSG:
DB CR,LF,LF,BEL,BEL,' *** MINI FLOPPY DISK I/O ERROR - CODE(','#'
;
ERRMS1:
DB ') DRIVE ','#'
ERRMS2:
DB ': ***',CR,LF,'#'
;
PAGE
;
;****************************************************************************
;
; MINI FLOPPY COPY DATA STORAGE AREA FOR PARAMETERS
;
;
;
FUNIT:
DS 1 ;STORAGE FOR SELECTED MINI UNIT NUMBER
;
LOOPCNT:
DS 1 ;PLACE TO KEEP TRACK OF HOW MANY TRKS ARE DONE
;
;
DS 80 ;SETUP STORAGE FOR 40 LEVEL STACK
STCKK EQU $
;
DATBF1:
DS FSECSIZ*FSPT ;DATA BUFFER FOR SIDE 0 TRACK
;
DATBF2:
DS FSECSIZ*FSPT ;DATA BUFFER FOR SIDE 1 TRACK
;
END
;
;+++...END OF FILE
«eof»