; 09/04/2000
; mode4_eps in progress
; mode3_latex in progress
; elements in hrules must be in a col <255 bytes

%include "util.mac"
%include "icedump.inc"
%include "wiat.inc"


global Parse_ScreenDump
global Parse_ScreenDump.EmodeFileName
global Parse_ScreenDump.EmodeExtPtr
global Parse_ScreenDump.modeMsg


extern sdata
extern ON_TOGGLE_EXPERT_MODE.Emode
extern EmodeSub.IncDumpNum
extern SetCB
extern Parser.error
extern TempBuffer
extern GetVideoMem


bits 32


;-------------------------------------------------------------------------------
; SCREENDUMP [<file>]
;-------------------------------------------------------------------------------
segment _LTEXT
Parse_ScreenDump:
	mov	dl,byte [ON_TOGGLE_EXPERT_MODE.Emode]
	cmp	dl,'E'			; see if in expert mode
	je	.modeE

	call	[pSkipWhiteSpace]	; skip to <file name>
	jz	near .modeToggle

	mov	ebp,[dClient_ESI]	; store pointer to file name
	mov	[ebp],esi
	jmp	short .continue

.modeE:
	mov	edi,.EmodeFileName
	mov	ebp,[dClient_ESI]	; store ptr to filename
	mov	[ebp],edi
	add	edi,[.EmodeExtPtr]	; get offset of the extension
	call	EmodeSub.IncDumpNum

.continue:
	push	byte SERVICE_DUMP
	mov	ebp,[dClient_EAX]
	pop	dword [ebp]

	mov	ebp,[dClient_EDI]	; store start address of our buffer
	mov	edi,[TempBuffer]
	mov	[ebp],edi

	call	GetVideoMem		; get start of video memory
	mov	esi,eax

	mov	eax,[bLINES_current]
	movzx	eax,byte [eax]

	mov	ecx,eax			; need this in ecx for the outer loop
	mov	ebx,[dWIDTH_current]
	mov	ebx,[ebx]
	mul	ebx

	mov	dl,[.mode]
	cmp	dl,'0'
	je	.mode0

	cmp	dl,'2'
	je	near mode2_html		; code is a little further /fOSSiL/
					; to save some bytes on short jumps
	cmp	dl,'3'
	je	near mode3_latex

	cmp	dl,'4'
	je	near mode4_eps

	lea	eax,[eax+2*ecx]		; fixup for the extra cr/lf
	mov	ebp,[dClient_ECX]	; store length of our buffer
	mov	[ebp],eax

	cmp	eax,TempBuffer_size
	ja	near Parser.error

	mov	ax,0x0A0D		; cr/lf

.getNextPatchDatum:
	push	ecx			; yeah, sloppy, i know :) /Ghiri/
	mov	ecx,ebx

.innerloop:
	movsb
	inc	esi
	loop	.innerloop		; parse and copy raw screen

	stosw				; put in cr/lf
	pop	ecx
	loop	.getNextPatchDatum

	jmp	short .setCB

.mode0:
	add	eax,eax

	cmp	eax,TempBuffer_size
	ja	near Parser.error

	mov	ecx,eax
	rep	movsb

.setDumpLength:
	mov	ebp,[dClient_ECX]	; store length of block
	mov	[ebp],eax

.setCB:
	call	SetCB

	mov	ebp,[fExecuteMoreCommands]	; set internal Winice flag to 0
	mov	byte [ebp],0

	popad
	retn


.modeToggle:
	mov	al,[.mode]		; 3-pos toggle /fOSSiL/
	inc	al
	cmp	al,'5'			; now 5-pos toggle
	jb	.modeToggle_n0

	mov	al,'0'

.modeToggle_n0:
	mov	[.mode],al
	mov	esi,.modeMsg
	call	[pPrintToCommandWindow]
	jmp	Parser.error


segment _LDATA
.modeMsg:	db 'Screen dumper set to mode '
.mode:		db '1',0

.EmodeViewFilename: db 'Current auto-dump filename: '
.EmodeFileName: db 'C:\DEFAULT.00/',0		; watch out for .EmodeExtPtr

; this should pad up to OPT_EMODE_FILENAMELEN and leave extra space
; for dump-number
TIMES OPT_EMODE_FILENAMELEN-($-.EmodeFileName)+1+OPT_EMODE_NUMLEN	db 0

.EmodeExtPtr:	dd 11


;----------------------------------
; /fOSSiL/  RAW-->html
; Let the games begin...
;----------------------------------
segment _LTEXT
mode2_html:
	cmp	eax,TempBuffer_size/2	; EAX contains #bytes
	ja	near Parser.error

	mov	eax,.begin		; write html header
	call	.write

; ebx = Width, ecx = Height

.loop1:	
	mov	eax,.line1		; write row header part 1
	call	.write

	xor	eax,eax
	lodsw
	push	eax			; we will need it
	shr	eax,12
	call	.wclr			; write backcolor

	mov	eax,.line2
	call	.write			; write row header part 2
	pop	eax

	push	ecx
	mov	ecx,ebx
	jmp	.loop2_nl

.loop2:
	lodsw

.loop2_nl:
	ror	eax,8
	cmp	ah,al			; check current color
	je	.loop2_nc
	call	.setcolor		; set font color
	mov	ah,al			; save current color

.loop2_nc:
	rol	eax,8

	call	.wchar			; xlat and write char out
	loop	.loop2

	pop	ecx

	mov	eax,.endline		; write endline
	call	.write

	loop	.loop1

	mov	eax,.end		; write end block
	call	.write

	sub	edi,[TempBuffer]
	mov	ebp,[dClient_ECX]	; store length of block
	mov	[ebp],edi

	call	SetCB

	mov	ebp,[fExecuteMoreCommands]	; set internal Winice flag to 0
	mov	byte [ebp],0

	popad
	retn

.write:
	push	esi
	mov	esi,eax

.w_loop:
	lodsb
	or	al,al
	jz	.w_done

	stosb
	jmp	short .w_loop

.w_done:
	pop	esi
	retn

.setcolor:
	push	eax
	mov	eax,.setclr1		; write <FONT...
	call	.write

	mov	eax,[esp]
	call	.wclr			; write color code

	mov	eax,.setclr2
	call	.write			; write end tag

	pop	eax
	retn

.wclr:
	mov	edx,eax
	mov	eax,'AF00'
	mov	dh,3
	shl	dl,5		; check and adjust intensity
	jnc	.wc_loop	; CF=0 when intensity low

	add	al,5

.wc_loop:
	shl	dl,1		; test next bit
	jc	.wc_nr1

	ror	eax,16		; switch to '00', also clc
;	clc			; left for clarity, if it helps =)

.wc_nr1:
	stosw
	jc	.wc_nr2

	ror	eax,16			; put it back now

.wc_nr2:
	dec	dh
	jnz	.wc_loop

	retn

.wchar:
; some lame char xlat
; unfortunately, a nessecity for html
	push	esi
	push	eax
	mov	dl,al
	mov	esi,.xltab

.ch_next:
	lodsb
	cmp	dl,al
	jz	.chout

	or	al,al
	jz	.ch_nomatch

.ch_skip:	
	lodsb
	or	al,al
	jnz	.ch_skip

	jmp	.ch_next

.ch_nomatch:	
	cmp	dl,32		; no matching xlat entry found
	jb	.chout		; check if 32-127 ascii code

	cmp	dl,127		; and if not, print ' '
	ja	.chout

	mov	al,dl
	stosb
	jmp	short .ch_end

.chout:
	mov	eax,esi		; we've moved on to 1->many char xlat
	call	.write		; so now we have to print strings

.ch_end:
	pop	eax
	pop	esi
	retn


segment _LDATA
.begin:	db '<HTML><BODY>',13,10
	db '<TABLE bgcolor="black"><TR><TD><TABLE border="0">',13,10,0

.end:	db '</TABLE></TD></TABLE>',13,10
	db '</BODY></HTML>',0

.line1:		db '<TR bgcolor="#',0
.line2:		db '"><TD><PRE>',0
.endline:	db '</TD>',13,10,0

.setclr1:	db '<FONT color="#',0
.setclr2:	db '">',0

.xltab:	db 16,'>',0,	17,'&lt;',0,	24,'^',0,	25,'v',0
	db 30,'^',0,	31,'v',0,	196,'-',0,	'<','&lt;',0
	db 0,' ',0


;----------------------------------
; /Ghiri/  RAW-->LaTeX
; Goddamn, I had to look at fOSSiL's HTML code after all :p
;----------------------------------
; ESI = ptr to raw dump
; EAX = # bytes in raw dump
; EBX = Width
; ECX = Height

segment _LTEXT
mode3_latex:
	cmp	eax,TempBuffer_size/2
	ja	near Parser.error

	mov	eax,.begin		; write LaTeX header
	call	.write

.loop1:					; line loop
	mov	dword [.colorchangeflag],0
	mov	eax,.line1		; write row header part 1
	call	.write

	xor	eax,eax
	lodsw
	push	eax			; we will need it
	shr	eax,12
	call	.wclrbk			; write backcolor
	mov	eax,[esp]
	ror	eax,8
	call	.writefirsttextcolor	; special handling
	pop	eax	
	cmp	byte [.green],1		; see if we are cleaning up after a hrule
	je	.specialgreen

	ror	eax,8			; fix color for first byte in line		

	push	ecx
	mov	ecx,ebx
	jmp	.loop2_nl
	
.specialgreen:				; special handling for cleanup after hrule lines
	xor	eax,eax
	mov	[.green],al
	dec	ecx			; reduce #lines
	jmp	.loop1
	
.writefirsttextcolor:			; set original text color
	dec	edi
	call	.wclr
	retn

.loop2:					; chars in a line loop
	lodsw
	ror	eax,8
	cmp	ah,al			; check current color
	je	.loop2_nc

	call	.setcolor		; set text color

.loop2_nl:
	mov	ah,al			; save current color

.loop2_nc:
	rol	eax,8

	call	.wchar			; xlat and write char out
	loop	.loop2			; chars in a line loops

	pop	ecx

	mov	eax,[.colorchangeflag]
	cmp	eax,1
	mov	eax,.colorendline
	je	.writeendtag
	
	mov	eax,.endline		; write endline

.writeendtag:
	call	.write
	dec	ecx				; loop for each line (too far for loop instruction)
	jecxz	.outloop1	

	jmp	.loop1

.outloop1:

	mov	eax,.end		; write end block
	call	.write

	sub	edi,[TempBuffer]
	mov	ebp,[dClient_ECX]	; store length of block
	mov	[ebp],edi

	call	SetCB

	mov	ebp,[fExecuteMoreCommands]	; set internal Winice flag to 0
	mov	byte [ebp],0

	popad
	retn

.write:
	push	esi
	mov	esi,eax

.w_loop:
	lodsb
	or	al,al
	jz	.w_done

	stosb
	jmp	short .w_loop

.w_done:
	pop	esi
	retn

.setcolor:				; closes previous latex textcolor command and begins new one
	push	eax
	mov	eax,[.colorchangeflag]
	cmp	eax,0
	mov	dword [.colorchangeflag],1
	mov	eax,.setclrfirst
	je	.firstcolorchange

	mov	eax,.setclr1

.firstcolorchange:
	call	.write

	mov	eax,[esp]
	call	.wclr			; write color code

	pop	eax
	retn

.wclrbk:				; different color routine (use different shade of grey)
	and	eax,7			; ignore intensity bit
	cmp	eax,7
	jne	.c0

	mov	eax,.cLightGrey	
	call	.write
	retn

.wclr:					; sets color code
	and	eax,7			; ignore intensity bit
	cmp	eax,7
	jne	.c0

	mov	eax,.cDarkGrey	
	call	.write
	retn

.c0:
	cmp	eax,0			; code is ugly, but works. perhaps will
	jne	.c1			; cleanup before release

	mov	eax,.cBlack
	call	.write
	retn

.c1:	
	cmp	eax,1
	jne	.c2

	mov	eax,.cBlue
	call	.write
	retn

.c2:	
	cmp	eax,2
	je	.caseGreen

.c3:	
	cmp	eax,3
	jne	.c4

	mov	eax,.cCyan
	call	.write
	retn

.c4:	
	cmp	eax,4
	jne	.c5

	mov	eax,.cRed
	call	.write
	retn

.c5:	
	cmp	eax,5
	jne	.c6

	mov	eax,.cMagenta
	call	.write
	retn

.c6:	
	mov	eax,.cYellow
	call	.write
	retn

.caseGreen:
	; assume we never have green backgrounds
	; assume green text only if we want to draw hlines
	; assume all hlines are green
	; no color information passed to \putline command
	sub	edi,.sizeline1+.sizecBlack-3	; roll back already written commands
	
	mov	eax,.put		; write out \putline
	call	.write

	; 1st pass: scan line to see how many params we shall be passing

	push	esi			; save esi for 2nd pass
	mov	dword [.counter],0
	mov	dword [.latexGreenParamCount],0

.sg1:
	inc	dword [.counter]	
	cmp	ebx,[.counter]		; see if reached max cols
	jle 	.sg3

	lodsw				

	cmp	al,0xc4			; look for dashes
	je 	.sg1
	
	inc	dword [.latexGreenParamCount]

.sg2:
	inc	dword [.counter]
	cmp	ebx,[.counter]
	jle .sg3

	lodsw			; load byte (skip attribute)
	cmp	al,0xc4
	jne .sg2

	jmp .sg1

.sg3:
	;write # params
	mov	eax,[.latexGreenParamCount]

	cmp	eax,0
	jne	.colone

	mov	eax,.colsnone
	jmp	.colwrite

.colone:
	cmp	eax,1
	jne	.coltwo

	mov	eax,.colsone
	jmp	.colwrite

.coltwo:
	cmp	eax,2
	jne	.colthree

	mov	eax,.colstwo
	jmp	.colwrite

.colthree:
	cmp	eax,3
	jne	.colfour

	mov	eax,.colsthree
	jmp	.colwrite

.colfour:
	mov	eax,.colsfour

.colwrite:
	call	.write
	pop	esi		; restore esi for 2nd pass

	; 2nd pass: read in columns and params
	
	mov	dword [.counter],0
.cg1:
	inc	dword [.counter]	
	cmp	ebx,[.counter]		; see if reached max cols
	jle 	.cg3

	lodsw				

	cmp	al,0xc4			; look for dashes
	je 	.cg1

	;write column offset
	push	eax		; save first byte
	mov	al,'{'
	stosb
	mov	eax,[.counter]
	call	.BaseConvert	; write out eax to esi assume 9<eax<100;
	mov	al,'}'		; this can be modified to support more columns if necessary
	stosb
	mov	al,'{'
	stosb
	pop	eax		; restore first byte

.cg2:
	call	.wchar		; write with filtering
	inc	dword [.counter]
	cmp	ebx,[.counter]
	jle	.cg3
	lodsw			; load byte (skip attribute)
	cmp	al,0xc4
	jne	.cg2
	mov	al,'}'
	stosb
	jmp	.cg1

.cg3:
	;write end tag	
	mov	eax,.endhrule
	call	.write
	mov	al,1		; flag that we need special handling
	mov	[.green],al	; we can get rid of this ugly kludge by
	retn			; fixing up stack and jumping to code we want

.BaseConvert:			; converts the number in eax to ascii and writes out to edi
	push	eax		; this is taken from some old code i have
	push	ebx
	push	ecx
	
	mov	ebx,eax
	mov	ecx,204h	; the '2' is the number of digits to write out (for more cols)
	ror	ebx,8		; need to change amount we ror by too, if we want more cols

.Loop1:
	rol	ebx,cl
	mov	al,bl
	and	al,0Fh
	add	al,90h
	daa	
	adc	al,40h
	daa
	stosb
	dec	ch
	jnz	.Loop1
	
	pop	ecx
	pop	ebx
	pop	eax
	retn

.wchar:
; some lame char xlat
; unfortunately, a nessecity for LaTeX
	push	esi
	push	eax
	mov	dl,al
	mov	esi,.xltab

.ch_next:
	lodsb
	cmp	dl,al
	jz	.chout

	or	al,al
	jz	.ch_nomatch

.ch_skip:	
	lodsb
	or	al,al
	jnz	.ch_skip

	jmp	.ch_next

.ch_nomatch:	
	cmp	dl,32		; no matching xlat entry found
	jb	.chout		; check if 32-127 ascii code

	cmp	dl,127		; and if not, print ' '
	ja	.chout

	mov	al,dl
	stosb
	jmp	short .ch_end

.chout:
	mov	eax,esi		; we've moved on to 1->many char xlat
	call	.write		; so now we have to print strings

.ch_end:
	pop	eax
	pop	esi
	retn


segment _LDATA
.begin:	db '\begin{figure}[hbp]',13,10,'\begin{centering}',13,10,'\footnotesize',13,10,0
.line1:		db '\SIline',0
.sizeline1	equ $-.line1
.colorendline:	db '}}',13,10,0
.endline:	db '}',13,10,0
.setclr1:	db '}'
.setclrfirst:	db '\textcolour',0
.put:		db '\putinline',0
.endhrule	db 13,10,0
.green		db 0
.end:	db '\normalsize',13,10,'\end{centering}',13,10,'\caption{\textit{\LaTeXe ~screendump created with IceDump}}',13,10,'\end{figure}',13,10,0


; these colors are not chosen to match size exactly...
.cBlack:	db '{black}{',0
.sizecBlack	equ $-.cBlack
.cBlue:		db '{blue}{',0
.cCyan:		db '{cyan}{',0
.cRed:		db '{red}{',0
.cMagenta:	db '{magenta}{',0
.cYellow:	db '{yellow}{',0
.cLightGrey:	db '{lightgrey}{',0	; .uk spelling r0x :)
.cDarkGrey:	db '{darkgrey}{',0
.colsnone	db 'none',0
.colsone	db 'one',0
.colstwo	db 'two',0
.colsthree	db 'three',0
.colsfour	db 'four',0
.counter:	dd	0
.latexGreenParamCount	dd	0
.colorchangeflag	dd	0

.xltab:	
	; replaced with macros so that can change appearance w/o recompile
	db 16,'\SIarrowright',0,	
	db 17,'\SIarrowleft',0,	
	db 24,'\SIuparrowsml',0,	
	db 25,'\SIdownarrowsml',0
	db 30,'\SIuparrow',0,	
	db 31,'\SIdownarrow',0,	

	; filtering for LaTeX command sequences
	db 196,'-',0,		'$','\$',0,		'&','\&',0,		'%','\%',0,
	db '_','\_',0,		'^','\^{}',0,		'~','\~{}',0,		'\','$\backslash$',0,
	db ' ','~',0,	

	db 0,'~',0

;----------------------------------
; /igNorAMUS/  RAW-->EPS
;----------------------------------
; ESI = ptr to raw dump
; EDI = ptr to TempBuffer
; EAX = # bytes in raw dump
; EBX = Width (chars)
; ECX = Height (chars)

segment _LTEXT
mode4_eps:
	cmp	eax,TempBuffer_size/2
	ja	near Parser.error

	lea	esi,[esi+2*eax]	; end of data block

	mov	eax,.EPSbegin
	call	.writeBuf
	jc	near Parser.error

	mov	eax,412877		; 6.3*65536
	mul	ebx
	shr	eax,16
	call	.writeDwordD

	mov	eax,.onespace
	call	.writeBuf
	jc	near Parser.error

	mov	eax,642253		; 9.8*65536
	mul	ecx
	shr	eax,16
	call	.writeDwordD

	mov	eax,.EPSEndComm
	call	.writeBuf
	jc	near Parser.error

	mov	eax,.EPSdict
	call	.writeBuf
	jc	near Parser.error

	mov	edx,ebx
	neg	edx
	lea	esi,[esi+2*edx]		; last line

.EPSdmp:
	mov	eax,.linebeg
	call	.writeBuf
	jc	near Parser.error

	lea	eax,[ebx*4+edi]
	sub	eax,[TempBuffer]
	cmp	eax,TempBuffer_size
	jae	near Parser.error

	lea	eax,[ebx*2]
	call	.writeBytesH
	mov	eax,.lineend
	call	.writeBuf
	jc	near Parser.error

	lea	esi,[esi+4*edx]		; last line
	dec	ecx
	jnz	.EPSdmp

	mov	eax,.EPSend
	call	.writeBuf
	jc	near Parser.error


	sub	edi,[TempBuffer]
	mov	ebp,[dClient_ECX]	; store length of block
	mov	[ebp],edi

	call	SetCB

	mov	ebp,[fExecuteMoreCommands]	; set internal Winice flag to 0
	mov	byte [ebp],0

	popad
	retn


.writeDwordD:			; writes (positive) number in eax out (as ASCII)
	push	ecx
	push	edx
	push	edi
	mov	ecx,10

.wDDdivloop:
	xor	edx,edx
	div	ecx
	add	edx,30h
	mov	[edi],dl
	inc	edi
	or	eax,eax
	jnz	.wDDdivloop

	pop	ecx
	mov	edx,edi
	dec	edx
	jmp	short .wDDreverse
	
.wDDrevloop:
	mov	al,[ecx]
	mov	ah,[edx]
	mov	[ecx],ah
	mov	[edx],al
	inc	ecx
	dec	edx

.wDDreverse:
	cmp	edx,ecx
	ja	.wDDrevloop

	pop	edx
	pop	ecx
	retn


.writeBytesH:			; writes out content of given buffer in hex
	push	ecx		; esi = buffer ptr, eax = buffer length
	push	edx
	mov	ecx,eax

.wBHloop:
	lodsb
	mov	ah,al
	shr	al,4
	and	ah,0Fh
	cmp	al,10
	sbb	dl,dl
	cmp	ah,10
	sbb	dh,dh
	add	ax,3737h
	and	dx,0707h
	sub	ax,dx
	stosw
	dec	ecx
	jnz	.wBHloop

	pop	edx
	pop	ecx
	retn

.writeBuf:			; writes out buffer (pointed by eax) to 1st 0 occurence
	push	ecx		; if TempBuffer would overflow, C=1 is returned
	push	esi
	mov	esi,eax
	push	edi
	mov	edi,eax
	xor	ecx,ecx
	xor	eax,eax
	dec	ecx
	repne	scasb
	not	ecx
	dec	ecx
	pop	edi
	lea	eax,[ecx+edi]
	sub	eax,[TempBuffer]
	cmp	eax,TempBuffer_size
	jae	.wBend

	rep	movsb
	stc

.wBend:
	cmc
	pop	esi
	pop	ecx
	retn

segment _LDATA
.onespace	db ' ',0
.linebeg	db '(',0
.lineend	db ') dumpline',13,10,0
.EPSbegin	db '%!PS-Adobe-2.0 EPSF-1.2',13,10,'%%Creator: IceDump EPS Export v1.0',13,10
		db '%%BoundingBox: 0 0 ',0
.EPSEndComm	db 13,10,'%%EndComments',13,10,13,10,0
.EPSend		db 13,10,'grestore',13,10,'%%EOF',13,10,0
.EPSdict	db '/scaling 7 def',13,10
		db '/cboxwidth scaling 0.9 mul def',13,10
		db '/cboxheight scaling 1.4 mul def',13,10
		db '/cboxdepth scaling 0.3 mul def',13,10
		db '/cboxlmargin scaling 0.0 mul def',13,10
		db '/dumplmargin 24 def',13,10
		db '/dumpbottom 24 def',13,10
		db '/tinyoverlap scaling 0.001 mul def',13,10,13,10
		db '/h2icmd (16#00) def',13,10
		db '/hextoint {h2icmd exch 3 exch putinterval h2icmd cvx exec} bind def',13,10,13,10
		db '/charmid {gsave cboxwidth 2 div cboxheight 2 div rmoveto scaling 10 div dup scale} bind def',13,10
		db '/trianglemid {gsave scaling 10 div dup scale 4.5 4.5 rmoveto} bind def',13,10
		db '/triangle {0 3 rmoveto -3 -6 rlineto 6 0 rlineto closepath} bind def',13,10
		db '/ftriau {charmid triangle fill grestore} bind def',13,10
		db '/ftriad {charmid 180 rotate triangle fill grestore} bind def',13,10
		db '/ftrial {charmid 90 rotate triangle fill grestore} bind def',13,10
		db '/ftriar {charmid 270 rotate triangle fill grestore} bind def',13,10
		db '/arrow {0 -4.5 rmoveto 0 9 rlineto -2 -3 rmoveto 2 3 rlineto 2 -3 rlineto} bind def',13,10
		db '/arrowu {charmid arrow stroke grestore} bind def',13,10
		db '/arrowd {charmid 180 rotate arrow stroke grestore} bind def',13,10
		db '/roof {charmid 0 3 rmoveto -3 -3 rlineto 0 -2 rlineto 6 0 rlineto 0 2 rlineto closepath stroke grestore} bind def',13,10
		db '/hline {tinyoverlap neg cboxheight 2 div rmoveto cboxwidth tinyoverlap add 0 rlineto stroke} bind def',13,10,13,10
		db '/dchars',13,10
		db '[( ) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.)',13,10
		db ' /ftriar /ftrial (.) (.) (.) (.) (.) (.) /arrowu /arrowd (.) (.) (.) (.) /ftriau /ftriad',13,10
		db ' ( ) (!) (") (#) ($) (%) (&) (',39,39,') (\() (\)) (*) (+) (,) (-) (.) (/)',13,10
		db ' (0) (1) (2) (3) (4) (5) (6) (7) (8) (9) (:) (;) (<) (=) (>) (?)',13,10
		db ' (@) (A) (B) (C) (D) (E) (F) (G) (H) (I) (J) (K) (L) (M) (N) (O)',13,10
		db ' (P) (Q) (R) (S) (T) (U) (V) (W) (X) (Y) (Z) ([) (\\) (]) (^) (_)',13,10
		db ' (`) (a) (b) (c) (d) (e) (f) (g) (h) (i) (j) (k) (l) (m) (n) (o)',13,10
		db ' (p) (q) (r) (s) (t) (u) (v) (w) (x) (y) (z) ({) (|) (}) (~) /roof',13,10
		db ' (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.)',13,10
		db ' (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.)',13,10
		db ' (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.)',13,10
		db ' (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.)',13,10
		db ' (.) (.) (.) (.) /hline (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.)',13,10
		db ' (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.)',13,10
		db ' (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.)',13,10
		db ' (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.) (.)] bind def',13,10,13,10
		db '/dcolors',13,10
		db '[{0 setgray} {0 0 1 setrgbcolor} {0 1 0 setrgbcolor} {0 1 1 setrgbcolor}',13,10
		db ' {1 0 0 setrgbcolor} {1 0 1 setrgbcolor} {0.6 0.4 0.4 setrgbcolor} {0.9 setgray}',13,10
		db ' {0.7 setgray} {0.6 0.8 1.0 setrgbcolor} {0.7 1 0.7 setrgbcolor} {0.5 1 1 setrgbcolor}',13,10
		db ' {1 0.5 0.5 setrgbcolor} {1 0.5 1 setrgbcolor} {1 1 0 setrgbcolor} {1 setgray}] bind def',13,10,13,10
		db '/cbbox {',13,10
		db '  2 index 16 idiv dcolors exch get cvx exec',13,10
		db '  newpath 2 copy moveto',13,10
		db '  cboxwidth 0 rlineto 0 cboxheight tinyoverlap add rlineto cboxwidth neg 0 rlineto closepath fill',13,10
		db '  exch cboxlmargin add exch cboxdepth add',13,10
		db '  newpath moveto',13,10
		db '  16 mod dcolors exch get cvx exec',13,10
		db '  dchars exch get dup type /stringtype eq {show} {cboxlmargin neg cboxdepth neg rmoveto cvx exec} ifelse',13,10
		db '} bind def',13,10,13,10
		db '/dumplineat {',13,10
		db '  0 4 2 index length 4 sub {',13,10
		db '  2 copy 2 getinterval hextoint exch 2 index exch 2 add 2 getinterval hextoint',13,10
		db '  3 index 5 index cbbox exch cboxwidth add exch} for',13,10
		db '} bind def',13,10
		db '/dumpline {dumpbottom exch dumplmargin exch dumplineat /dumpbottom dumpbottom cboxheight add def} bind def',13,10,13,10
		db 'gsave',13,10
		db '/Courier-Bold findfont scaling 1.5 mul scalefont setfont',13,10
		db '1 setlinecap 1 setlinewidth',13,10,13,10
		db 0
