; ************************** AMUS Program Label ****************************** ; Filename: D.M68 Date: 02/06/90 ; Category: UTIL Hash Code: 315-624-543-525 Version: 2.0(107) ; Initials: ULTR/AM Name: DAVID PALLMANN ; Company: ULTRASOFT CORPORATION Telephone #: 5163484848 ; Related Files: WLDSCN.LIB (wildcard scanner, hash 275-510-373-412) ; Min. Op. Sys.: AMOSL 1.3B Expertise Level: BEG ; Special: Requires 2.0 assembler ; Description: Directory program. Defaults to wide directory. ; Type /H for a list of options. Has some unique, useful switches such as ; /MIN:n and /MAX:n to see only files of a certain size. ; **************************************************************************** ;**************************************************************************** ;* * ;* D * ;* Directory Command * ;* * ;**************************************************************************** ;Copyright (C) 1986, 1989 UltraSoft Corporation. All Rights Reserved. ; ;Related Files: WLDSCN.LIB - wildcard scanner ; ;Assembly Instructions: ; ; 1. You need the 2.0 assembler. You can't assemble D otherwise. ; 2. .M68 D ; 3. .LNKLIT D,WLDSCN.LIB/L ; ;To make FIND.LIT (defaults to ALL:[]), specify .M68 D/V:1 ; ;Written by: David Pallmann ; ;1.0(100) 12-Sep-86 created. /DFP ; ;2.0(101) 30-Dec-88 link with updated wildcard scanner for AMOS 2.0 and ; extended file structure support. /DFP ;2.0(102) 06-Jan-89 use new per-user SSD protection scheme. /DFP ;2.0(103) 28-Nov-89 SSD protection removed, donated to AMUS. /DFP ;2.0(104) 22-Jan-90 correct bug with /N - showed wrong # of blocks. /DFP ;2.0(105) 23-Jan-90 add /V:1 assembly option to make FIND.LIT. /DFP ;2.0(106) 06-Feb-90 correct help descriptions of /MIN and /MAX switches. /DFP ;2.0(107) 06-Feb-90 relinked with 1.9 version of WLDSCN. /DFP VMAJOR =2 VMINOR =0 VSUB =0 VEDIT =107. VWHO =0 NVALU FIND IF EQ,FIND,ASMMSG "Creating D.LIT" IF EQ,FIND,OBJNAM D.LIT IF NE,FIND,ASMMSG "Creating FIND.LIT" IF NE,FIND,OBJNAM FIND.LIT AUTOEXTERN SEARCH SYS SEARCH SYSSYM SEARCH TRM ;----------------------------------- ;don't let the 1.X assembler through ;----------------------------------- SYMBOL1 =1 SYMBOL2 =2 IF EQ,SYMBOL1-SYMBOL2,ASMERP "?The 2.0 assembler is required" ;---------------- ;ASCII characters ;---------------- LF =12 ; line feed CR =15 ; carriage return ESC =33 ; escape ;-------------- ;registers used ;-------------- MEM =A5 ; points to work memory INDEX =A4 ; points to current file DDB TRM =A3 SIZE =D3 COL =D5 ; contains column count COUNT =D4 ; contains file number ;----------- ;work memory ;----------- .OFINI .OFDEF OLD.DEV,2 ; old device .OFDEF OLD.DRV,2 ; old drive .OFDEF OLD.PPN,2 ; old PPN .OFDEF TOTAL.FILES,4 ; total files .OFDEF TOTAL.BLOCKS,4 ; total blocks .OFDEF GRAND.FILES,4 ; grand total - files .OFDEF GRAND.BLOCKS,4 ; grand total - blocks .OFDEF MIN.SIZE,4 ; min block size .OFDEF MAX.SIZE,4 ; max block size .OFDEF WIDTH,4 ; width .OFDEF FLAGS,4 ; flags: F$WIDTH=1 ; width was specified F$SIZ=2 ; show file sizes F$VER=4 ; show file version numbers F$TOTAL=10 ; show totals F$NO=20 ; no file information 'cept totals F$PAGE=40 ; page handling F$CONTIG=100 ; show contiguous files in low intensity F$LOW=1000000 ; low intensity F$NEGATE=2000000 ; switch negate flag .OFDEF FILE,D.DDB ; work DDB .OFDEF DELAY,2 ; output speed (1/10 seconds to wait) .OFDEF BUFFER,80. ; conversion buffer [105] .OFSIZ MEMSIZ ;------ ;macros ;------ DEFINE BIT SRC,DST MOV DST,D7 AND SRC,D7 ENDM DEFINE RNE BEQ 1$$ RTN 1$$: ENDM DEFINE REQ BNE 1$$ RTN 1$$: ENDM DEFINE RLE BGT 1$$ RTN 1$$: ENDM DEFINE RGE BLT 1$$ RTN 1$$: ENDM DEFINE RLO BHIS 1$$ RTN 1$$: ENDM DEFINE RHI BLOS 1$$ RTN 1$$: ENDM DEFINE TFUNC CODE PUSH D1 MOVW #-1_8.+^D,D1 TCRT POP D1 ENDM DEFINE LOW=TFUNC 11 DEFINE HIGH=TFUNC 12 DEFINE JUMP=TFUNC 95 DEFINE SMOOTH=TFUNC 98 DEFINE MOVWL SRC,DST CLR D7 MOVW SRC,D7 MOV D7,DST ENDM DEFINE DEPACK ADDR PUSH A1 IF NB,ADDR,LEA A1,ADDR CALL DEPACK POP A1 ENDM ;----------------------- ;wildcard scanner macros ;----------------------- DEFINE WINIT IF NDF,W.INIT,EXTERN W.INIT CALL W.INIT ENDM DEFINE WSPEC EXT IF NDF,W.SPEC,EXTERN W.SPEC CALL W.SPEC IF B,EXT,ASCII /???/ IF NB,EXT,ASCII /'EXT/ BYTE 0 ENDM DEFINE WSCAN IF NDF,W.SCAN,EXTERN W.SCAN CALL W.SCAN ENDM DEFINE WFULL IF NDF,W.FULL,EXTERN W.FULL CALL W.FULL ENDM DEFINE WLIST ADDR IF NDF,W.LIST,EXTERN W.LIST IF NB,ADDR PUSH A0 LEA A0,ADDR ENDC CALL W.LIST IF NB,ADDR POP A0 ENDC ENDM ;--------------------------------------- ;start of code - standard initialization ;--------------------------------------- START: PHDR -1,,PH$REE!PH$REU ; program header - reentrant, reusable GETIMP MEMSIZ,MEM ; allocate local memory - index w/MEM INIT FILE(MEM) WINIT ; initialize wildcard scanner - sets A4 MOV #4,WIDTH(MEM) ; default display width to siz CLR COUNT ; clear file count MOV #F$SIZ!F$TOTAL,FLAGS(MEM) JOBIDX ; MOV JOBTRM(A6),TRM ; ORW #T$IMI!T$ECS,T.STS(TRM) ; SET MAX.SIZE(MEM) ; JMP COMMAND.LINE ; ;----------------------------------------------------------------------- ;command line processing - check for /W:n switch before, after file spec ;----------------------------------------------------------------------- COMMAND.LINE: IF NE,FIND LEA A0,BUFFER(MEM) ; [105]... MOVB #'A,(A0)+ ; MOVB #'L,(A0)+ ; MOVB #'L,(A0)+ ; MOVB #':,(A0)+ ; MOVB #'[,(A0)+ ; MOVB #'],(A0)+ ; 10$: LIN ; BEQ 20$ ; MOVB (A2)+,(A0)+ ; BR 10$ ; 20$: MOVB #CR,(A0)+ ; MOVB #LF,(A0)+ ; CLRB @A0 ; LEA A2,BUFFER(MEM) ; ...[105] ENDC BYP ; bypass white spac CALL SWITCH ; check for switches WSPEC ; process wildcard filespec JNE EXIT ; error CALL SWITCH ; check for switches again CALL FIND.FILE BEQ DISPLAY.DIRECTORY ; got one - start display TYPECR %No such files ; no files - break the news CRLF ; next line JMP CHECK.FOR.COMMA ; get next spec ;---------------------------------------------------------------- ;display account number and ersatz name if first time in this PPN ;---------------------------------------------------------------- DISPLAY.DIRECTORY: WFULL ; convert DDB @INDEX to FULL spec CMMW D.DEV(INDEX),OLD.DEV(MEM) ; has device changed? BNE DISPLAY.ACCOUNT ; yes - display new account CMMW D.DRV(INDEX),OLD.DRV(MEM) ; has drive number changed? BNE DISPLAY.ACCOUNT ; yes - display new account CMMW D.PPN(INDEX),OLD.PPN(MEM) ; has PPN changed? JEQ DISPLAY.FILE ; no - bypass account display DISPLAY.ACCOUNT: TST COUNT ; is this the first file displayed? BEQ 20$ ; yes - skip first crlf CMM COL,WIDTH(MEM) ; are we in mid-line? BEQ 10$ ; no CALL NEW.LINE 10$: BIT #F$TOTAL,FLAGS(MEM) BEQ 14$ CALL SHOW.TOTAL CLR TOTAL.BLOCKS(MEM) CLR TOTAL.FILES(MEM) 14$: CALL NEW.LINE 20$: INC COUNT DEPACK D.DEV(INDEX) ; output the device code CLR D1 ; ... MOVW D.DRV(INDEX),D1 ; get the drive number DCVT 0,OT$TRM ; print it TYPE :[ ; ... PRPPN D.PPN(INDEX) ; print the PPN TYPE ] ; ... MOVW D.DEV(INDEX),OLD.DEV(MEM) ; store MOVW D.DRV(INDEX),OLD.DRV(MEM) ; new device, drive, MOVW D.PPN(INDEX),OLD.PPN(MEM) ; and PPN DISPLAY.ERSATZ: MOV ERSATZ,D7 ; get ersatz table address JEQ DISPLAY.FILE ; isn't any MOV D7,A0 ; put in A0 10$: CTRLC EXIT ; ^C check CMMW EZ.DEV(A0),D.DEV(INDEX) ; device code match? BNE 20$ ; no CMMW EZ.UNT(A0),D.DRV(INDEX) ; drive number match? BNE 20$ ; no CMMW EZ.PPN(A0),D.PPN(INDEX) ; PPN match? BNE 20$ ; no TYPE < - > ; figured out the ersatz name, SAVE A1,A2 LEA A2,BUFFER(MEM) LEA A1,EZ.NAM(A0) UNPACK UNPACK 12$: CMMB -(A2),#40 BEQ 12$ CLRB 1(A2) TTYL BUFFER(MEM) TYPE : REST A1,A2 BR 30$ ; ... 20$: ADD #EZ.SIZ,A0 ; on to next ersatz entry TSTW @A0 ; at end of table? BNE 10$ ; no - check next entry 30$: CALL NEW.LINE ; print newline ;------------------------------- ;display file name and extension ;------------------------------- DISPLAY.FILE: BIT #F$NO,FLAGS(MEM) JNE UPDATE.TOTALS CMM D.LSZ(INDEX),#512. BLOS 10$ CALL LOW.INTENSITY BR 20$ 10$: CALL HIGH.INTENSITY 20$: DEPACK D.FIL(INDEX) ; print file DEPACK D.FIL+2(INDEX) ; name TYPE . ; print dot DEPACK D.EXT(INDEX) ; print extension MOVW D.DEV(INDEX),FILE+D.DEV(MEM) MOVW D.DRV(INDEX),FILE+D.DRV(MEM) MOV D.FIL(INDEX),FILE+D.FIL(MEM) MOVW D.EXT(INDEX),FILE+D.EXT(MEM) MOVW D.PPN(INDEX),FILE+D.PPN(MEM) ;[104] MOV D.FSZ(INDEX),SIZE UPDATE.TOTALS: MOV D.FSZ(INDEX),SIZE ; [104] BIT #F$TOTAL,FLAGS(MEM) BEQ DISPLAY.SIZE ADD SIZE,TOTAL.BLOCKS(MEM) INC TOTAL.FILES(MEM) DISPLAY.SIZE: BIT #F$SIZ,FLAGS(MEM) ; /S specified? BEQ DISPLAY.VERSION ; no TYPESP MOV SIZE,D1 PUSH A2 LEA A2,BUFFER(MEM) DCVT 0,OT$MEM!OT$ZER MOV #5,D0 10$: MOVB #40,(A2)+ SOB D0,10$ CLRB BUFFER+5(MEM) TTYL BUFFER(MEM) POP A2 DISPLAY.VERSION: BIT #F$VER,FLAGS(MEM) ; /V specified? JEQ ADVANCE ; no LOOKUP FILE(MEM) MOV FILE+D.BAS(MEM),FILE+D.REC(MEM) READ FILE(MEM) MOV FILE+D.BUF(MEM),A0 CMMB 2(A0),#-1 BEQ 10$ CMMB 2(A0),#-2 BNE ADVANCE 10$: ADD #4,A0 VCVT @A0,OT$TRM!OT$LSP ADVANCE: BIT #F$NO,FLAGS(MEM) BNE DISPLAY.NEXT DEC COL ; dec column BEQ 10$ ; end of line TYPE < > ; ... BIT #F$SIZ,FLAGS(MEM) BNE DISPLAY.NEXT TYPE < > BR DISPLAY.NEXT ; on to next file 10$: CALL NEW.LINE ; print newline DISPLAY.NEXT: CTRLC EXIT ; ^C check CALL FIND.FILE JEQ DISPLAY.DIRECTORY ; got one - go display it 10$: TST TOTAL.FILES(MEM) BEQ 20$ CALL SHOW.TOTAL CALL NEW.LINE BR CHECK.FOR.COMMA 20$: CMM COL,WIDTH(MEM) ; are we in mid-line? BEQ CHECK.FOR.COMMA ; no CALL NEW.LINE ; yeah - go to next line ;------------------------------------------------------------- ;check for comma (indicates another file spec on command line) ;------------------------------------------------------------- CHECK.FOR.COMMA: CMMB (A2)+,#<',> ; another spec present? BNE SHOW.GRAND.TOTAL TST COUNT BEQ 10$ CALL NEW.LINE 10$: CLR COUNT ; clear count in case we're not done CLRW OLD.PPN(MEM) CLR TOTAL.FILES(MEM) CLR TOTAL.BLOCKS(MEM) JMP COMMAND.LINE SHOW.GRAND.TOTAL: TST GRAND.FILES(MEM) JEQ EXIT CMM GRAND.FILES(MEM),TOTAL.FILES(MEM) JEQ EXIT TYPESP Grand total of MOV GRAND.BLOCKS(MEM),D1 DCVT 0,OT$TRM!OT$TSP TYPE block CMP D1,#1 BEQ 20$ TYPE s 20$: TYPE < in > MOV GRAND.FILES(MEM),D1 DCVT 0,OT$TRM TYPE < file> CMP D1,#1 BEQ 30$ TYPE s 30$: CALL NEW.LINE EXIT: BIT #F$PAGE,FLAGS(MEM) BEQ 10$ JUMP 10$: EXIT ; exit to AMOS ;--------------------------------------------------------------- ;switch processing - only switch currently supported is /W:width ;--------------------------------------------------------------- SWITCH: AND #^C,FLAGS(MEM) BYP CMMB @A2,#'/ ; slash present? RNE ; no - return BCALL SWITCH2 BR SWITCH SWITCH2: INC A2 MOVB (A2)+,D1 UCS CMPB D1,#'C JEQ SWITCH.C CMPB D1,#'F JEQ SWITCH.F CMPB D1,#'M JEQ SWITCH.M CMPB D1,#'N JEQ SWITCH.N CMPB D1,#'S JEQ SWITCH.S CMPB D1,#'P JEQ SWITCH.P CMPB D1,#'T JEQ SWITCH.T CMPB D1,#'V JEQ SWITCH.V CMPB D1,#'W JEQ SWITCH.W CMPB D1,#'H JEQ SWITCH.H CMPB D1,#'? JEQ SWITCH.H JMP SWITCH.ERROR ;------------------------------------------- ;/C - show contiguous files in low intensity ;------------------------------------------- SWITCH.C: BIT #F$NEGATE,FLAGS(MEM) BNE 10$ OR #F$CONTIG,FLAGS(MEM) HIGH RTN 10$: AND #^C,FLAGS(MEM) RTN ;------------------------------------------------------ ;/F - show full file information - equivalent to /S/V/T ;------------------------------------------------------ SWITCH.F: CALL SWITCH.C ; /C CALL SWITCH.S ; /S CALL SWITCH.V ; /V CALL SWITCH.T ; /T RTN ;------------------ ;/H, /? - show help ;------------------ SWITCH.H: DEFINE LINE TEXT ASCII #TEXT# BYTE CR ENDM TTYI LINE LINE LINE IF EQ,FIND,LINE IF NE,FIND,LINE LINE LINE < /F - "full" - same as /C/S/V/T> LINE < /N - no filenames, just totals> LINE < /NOx - negates action of "/x"> LINE < /MIN:n - show files n blocks or larger in size> LINE < /MAX:n - show files n blocks or smaller in size> LINE < /P - "page" - use smooth scroll> LINE < /S - show file sizes (default)> LINE < /T - show file totals (default)> LINE < /V - show version numbers> LINE < /W:n - show n files per line (default: 4)> LINE LINE < SPACE - suspend/resume output> LINE BYTE 0 EVEN EXIT ;---------------------------------------------------------- ;/N - display no filenames, only account numbers and totals ;---------------------------------------------------------- SWITCH.N: CMMB @A2,#'O BEQ SWITCH.NO BIT #F$NEGATE,FLAGS(MEM) BNE 10$ OR #F$NO,FLAGS(MEM) AND #^C,FLAGS(MEM) RTN 10$: AND #^C,FLAGS(MEM) RTN SWITCH.NO: XOR #F$NEGATE,FLAGS(MEM) JMP SWITCH2 ;---------------------------------- ;/M - beginning of /MAX:n or /MIN:n ;---------------------------------- SWITCH.M: MOVB (A2)+,D1 UCS CMPB D1,#'I JEQ SWITCH.MIN CMPB D1,#'A JNE SWITCH.ERROR ;--------------------------------------- ;/MAX:n - set maximum block size to show ;--------------------------------------- SWITCH.MAX: MOVB (A2)+,D1 UCS CMPB D1,#'X JNE SWITCH.ERROR BIT #F$NEGATE,FLAGS(MEM) BNE 10$ CMMB (A2)+,#': JNE SWITCH.ERROR GTDEC MOV D1,MAX.SIZE(MEM) RTN 10$: SET MAX.SIZE(MEM) RTN ;--------------------------------------- ;/MIN:n - set minimum block size to show ;--------------------------------------- SWITCH.MIN: MOVB (A2)+,D1 UCS CMPB D1,#'N JNE SWITCH.ERROR BIT #F$NEGATE,FLAGS(MEM) BNE 10$ CMMB (A2)+,#': JNE SWITCH.ERROR GTDEC MOV D1,MIN.SIZE(MEM) RTN 10$: CLR MIN.SIZE(MEM) RTN ;------------------------------- ;/P - "page" - set smooth scroll ;------------------------------- SWITCH.P: BIT #F$NEGATE,FLAGS(MEM) BNE 10$ OR #F$PAGE,FLAGS(MEM) SMOOTH RTN 10$: AND #^C,FLAGS(MEM) JUMP RTN ;--------------------------------------- ;/S - show file sizes, set width to four ;--------------------------------------- SWITCH.S: BIT #F$NEGATE,FLAGS(MEM) BNE 10$ OR #F$SIZ,FLAGS(MEM) BIT #F$WIDTH,FLAGS(MEM) RNE CMM WIDTH(MEM),#4 RLE MOV #4,WIDTH(MEM) RTN 10$: AND #^C,FLAGS(MEM) BIT #F$WIDTH,FLAGS(MEM) RNE CMM WIDTH(MEM),#4 RNE MOV #6,WIDTH(MEM) RTN ;------------------------------------------------- ;/V - display file version numbers, set width to 1 ;------------------------------------------------- SWITCH.V: BIT #F$NEGATE,FLAGS(MEM) BNE 10$ OR #F$VER,FLAGS(MEM) BIT #F$WIDTH,FLAGS(MEM) RNE MOV #1,WIDTH(MEM) RTN 10$: AND #^C,FLAGS(MEM) BIT #F$WIDTH,FLAGS(MEM) RNE CMM WIDTH(MEM),#1 RNE MOV #6,WIDTH(MEM) RTN ;--------------------------- ;/T - show block/file totals ;--------------------------- SWITCH.T: BIT #F$NEGATE,FLAGS(MEM) BNE 10$ OR #F$TOTAL,FLAGS(MEM) RTN 10$: AND #^C,FLAGS(MEM) RTN ;------------------------------------------- ;/W:n - set width (number of files per line) ;------------------------------------------- SWITCH.W: BIT #F$NEGATE,FLAGS(MEM) BNE 20$ MOV #4,D1 CMMB @A2,#': BNE 10$ INC A2 GTDEC 10$: CMP D1,#1 BLO FORMAT.ERROR MOV D1,WIDTH(MEM) OR #F$WIDTH,FLAGS(MEM) JMP SWITCH 20$: AND #^C,FLAGS(MEM) MOV #4,WIDTH(MEM) RTN SWITCH.ERROR: LEA A1,UNKNOWN.SWITCH CALL $CMDER EXIT FORMAT.ERROR: LEA A1,COMMAND.FORMAT.ERROR CALL $CMDER EXIT ;------------------------ ;Show total blocks, files ;------------------------ SHOW.TOTAL: MOV TOTAL.BLOCKS(MEM),D1 REQ CMM COL,WIDTH(MEM) ; are we in mid-line? BEQ 10$ ; no CALL NEW.LINE ; yeah - go to next line 10$: TYPESP Total of DCVT 0,OT$TRM!OT$TSP TYPE block CMP D1,#1 BEQ 20$ TYPE s 20$: TYPE < in > MOV TOTAL.FILES(MEM),D1 DCVT 0,OT$TRM TYPE < file> CMP D1,#1 BEQ 30$ TYPE s 30$: CALL NEW.LINE MOV TOTAL.BLOCKS(MEM),D7 ADD D7,GRAND.BLOCKS(MEM) MOV TOTAL.FILES(MEM),D7 ADD D7,GRAND.FILES(MEM) RTN ;------------------------------------------------------------- ;subroutine - convert RAD50 triplet @A1 to ASCII and output it ;------------------------------------------------------------- DEPACK: SAVE A1,A2 SUB #4,SP MOV SP,A2 UNPACK CLRB @A2 TTYL @SP ADD #4,SP REST A1,A2 RTN ;---------------------------------- ;subroutine - output CR/LF and wait ;---------------------------------- NEW.LINE: SAVE D0 CRLF MOV WIDTH(MEM),COL CALL HIGH.INTENSITY MOVWL DELAY(MEM),D0 BEQ 10$ MUL D0,#1000. SLEEP D0 10$: REST D0 CHECK.CHAR: TST T.ICC(TRM) REQ KBD EXIT CMPB D1,#ESC JEQ EXIT CMPB D1,#40 JEQ SUSPEND CMPB D1,#'S-'@ JEQ SUSPEND CMPB D1,#'0 RLO CMPB D1,#'9 RHI AND #177,D1 SUBB #'0,D1 MOVW D1,DELAY(MEM) BR CHECK.CHAR SUSPEND: KBD EXIT CMPB D1,#ESC JEQ EXIT CMPB D1,#'S-'@ BEQ SUSPEND RTN ;------------------------------------ ;subroutine - find next matching file ;------------------------------------ FIND.FILE: CTRLC 10$ WSCAN ; get first file - return @INDEX RNE CMM D.FSZ(INDEX),MIN.SIZE(MEM) BLO FIND.FILE CMM D.FSZ(INDEX),MAX.SIZE(MEM) BHI FIND.FILE 10$: LCC #PS.Z RTN ;------------------------------ ;subroutine - set low intensity ;------------------------------ LOW.INTENSITY: BIT #F$CONTIG,FLAGS(MEM) ; do we care about intensity? REQ ; no BIT #F$LOW,FLAGS(MEM) ; low intensity flag set? RNE ; yes - do nothing LOW OR #F$LOW,FLAGS(MEM) RTN ;------------------------------- ;subroutine - set high intensity ;------------------------------- HIGH.INTENSITY: BIT #F$CONTIG,FLAGS(MEM) ; do we care about intensity? REQ ; no BIT #F$LOW,FLAGS(MEM) ; low intensity flag set? REQ ; no - do nothing HIGH AND #^C,FLAGS(MEM) RTN ;------------ ;switch table ;------------ SWITCH.TABLE: BYTE 'S,F$SIZ ; /S - show file sizes BYTE 'V,F$VER ; /V - show file version numbers BYTE 0 EVEN ;-------------- ;text constants ;-------------- UNKNOWN.SWITCH: ASCIZ /Unknown switch/ COMMAND.FORMAT.ERROR: ASCIZ /Command format error/ EVEN END .