[comp.windows.news] cyber.shar.splitag

don@TUMTUM.CS.UMD.EDU (Don Hopkins) (11/23/89)

======== START OF cyber.shar.splitag ========
X    exch {
X      PushExec
X    } {
X      pop
X    } ifelse
X  } def
X
X  /ifelse load { % bool trueproc falseproc
X    3 -1 roll { exch } if % wrongproc rightproc
X    PushExec pop
X  } def
X
X  iexec-single-forall-types begin
X    {/arraytype /packedarraytype /stringtype}
X    {true def} forall
X  end % iexec-single-forall-types
X
X  /forall load { % obj proc => -
X    10 dict begin
X      /continuation /forall def
X      /proc exch def
X      /obj exch cvlit def
X      /i 0 def
X      //iexec-single-forall-types obj type known {
X	/continue { % dict => -
X	  begin
X	    i obj length lt {
X	      currentdict cvx PushExec
X	      obj i get
X	      /proc load PushExec
X	      /i i 1 add def
X	    } if
X	  end
X	} def
X	/namestring {
X	  (forall: proc=% obj=% @ %: %)
X	  [ /proc load  /obj load  i 
X	    1 index length 1 index gt { 2 copy get } (*done*) ifelse
X          ] sprintf
X	} def
X      } {
X	/keys [
X	  obj {pop} forall
X	] def
X	/continue { % dict => -
X	  begin
X	    i obj length lt {
X	      currentdict cvx PushExec
X	      keys i get % key
X	      obj 1 index get % key val
X	      /proc load PushExec
X	      /i i 1 add def
X	    } if
X	  end
X	} def
X	/namestring {
X	  (forall: proc=% obj=% @ %: %)
X	  [ /proc load  /obj load  
X	    keys i
X	    1 index length 1 index gt { 
X	      get 2 copy get
X	    } {
X	      pop null (*done*)
X	    } ifelse
X	  ] sprintf
X	} def
X      } ifelse
X      currentdict cvx PushExec
X    end
X  } def
X
X  /for load { % first step last proc
X    10 dict begin
X      /continuation /for def
X      /proc exch def
X      /last exch def
X      /step exch def
X      /first exch def
X      /i first def
X      /continue { % dict => -
X        begin
X	  i last step 0 gt {le} {ge} ifelse {
X	    currentdict cvx PushExec
X	    i
X	    /proc load PushExec
X	    /i i step add def
X	  } if
X	end
X      } def
X      /namestring {
X	(for: proc=% first=% step=% last=% i=%)
X	[/proc load  first step last i] sprintf
X      } def
X      currentdict cvx PushExec
X    end
X  } def
X
X  /repeat load {
X    10 dict begin
X      /continuation /repeat def
X      /proc exch def
X      /times exch def
X      /i 0 def
X      /continue { % dict => -
X        begin
X	  i times lt {
X	    currentdict cvx PushExec
X	    /proc load PushExec
X	    /i i 1 add def
X	  } if
X	end
X      } def
X      /namestring {
X	(repeat: proc=% times=% i=%)
X	[/proc load times i] sprintf
X      } def
X      currentdict cvx PushExec
X    end
X  } def
X
X  /loop load {
X    10 dict begin
X      /continuation /loop def
X      /proc exch def
X      /continue { % dict => -
X        begin
X	  currentdict cvx PushExec
X	  /proc load PushExec
X	end
X      } def
X      /namestring {
X        /proc load (loop: proc=%) sprintf
X      } def
X      currentdict cvx PushExec
X    end
X  } def
X
X  /pathforallvec load {
X%...
X  } def
X
X  iexec-exit-stoppers begin
X    {/forall /for /repeat /loop /pathforallvec}
X    {true def} forall
X  end % iexec-exit-stoppers
X
X  /exit load {
X    { ExecSP 0 lt { % exit out of interpreter?
X	true exit
X      } {
X        PopExec % obj
X	dup dup xcheck exch type /dicttype eq and { % obj
X	  dup /continuation known {
X	    dup /continuation get iexec-exit-stoppers exch known {
X		pop false exit
X	      } {
X	        pop
X	      } ifelse
X	  } {
X	    pop
X	  } ifelse
X	} { % obj
X	  pop
X	} ifelse
X      } ifelse
X    } loop
X
X    { {exit} exit } if
X  } def
X
X  /stop load {
X    { ExecSP 0 lt { % stop out of interpreter?
X	true exit
X      } {
X        PopExec % obj
X	dup dup xcheck exch type /dicttype eq and { % obj
X	  dup /continuation known {
X	    dup /continuation get /stopped eq {
X	      pop true false exit
X	    } {
X	      pop
X	    } ifelse
X	  } {
X	    pop
X	  } ifelse
X	} { % obj
X	  pop
X	} ifelse
X      } ifelse
X    } loop
X
X    { {stop} exit } if
X  } def
X
X  /stopped load { % proc
X    10 dict begin
X      /continuation /stopped def
X      /continue { % dict => -
X	pop false
X      } def
X      /proc 1 index def % debugging
X      /namestring {
X	/proc load (stopped: proc=%) sprintf
X      } def
X      currentdict cvx PushExec
X      PushExec
X    end
X  } def
X
X  /send load { % <args> message object => <results>
X    { currentdict } MumbleFrotz % message object context
X    2 copy eq { % message object context
X      pop pop cvx PushExec
X    } { % message object context
X      10 dict begin
X	/continuation /send def
X	/context
X	  exch dup /ParentDictArray known not { pop null } if
X	def % message object
X        /object exch def % message
X	/message 1 index def % message
X	/continue { % cdict => -
X          { % cdict
X	    ParentDictArray dup type /arraytype ne { % X11/NeWS
X	      /ParentDictArray get length 1 add
X	    } {
X	      length
X	    } ifelse
X            1 add {end} repeat
X	    /context get % context
X	    dup null eq { % context
X	      pop %
X	    } { % idict context
X	      dup /ParentDictArray get {begin} forall begin %
X	    } ifelse %
X	  } MumbleFrotz
X	} def
X	/unwind /continue load def
X        /namestring {
X	  (send: message=% object=% context=%)
X	  [/message load object context] sprintf
X        } def
X	currentdict cvx PushExec
X        object context % message object context
X      end % of cdict
X      { null ne {
X	  ParentDictArray length 1 add {end} repeat
X	} if
X        dup /ParentDictArray get
X        dup type /arraytype ne { % X11/NeWS
X          dup /ParentDictArray get
X	  {begin} forall begin begin % message
X        } {
X	  {begin} forall begin % message
X        } ifelse
X      } MumbleFrotz % message
X      cvx PushExec %
X    } ifelse
X  } def
X  
X% supersend (operator in X11/NeWS, proc in 1.1?)
X
X  /currentfile load { % => file
X    null
X    ExecStack length 1 sub -1 0 {
X      ExecStack exch get % obj
X      dup type /filetype eq {
X	exit
X      } {
X        pop
X      } ifelse
X    } for
X    dup null eq {
X      pop currentfile
X    } {
X      exch pop
X    } ifelse
X  } def
X
X  % We have to have the send contexts set up right when we do a fork, since
X  % the child process inherits them. (i.e. so ThisWindow works)
X  /fork load {
X    {fork} iexec-reenter
X  } def
X
X  /countexecstack load {
X    /countexecstack dbgbreak
X  } def
X
X  /quit load {
X    /quit dbgbreak
X  } def
X
Xend % iexec-operators
X
Xiexec-names begin
X
X  /sendstack {
X    [ iexec-sends
X      currentprocess /SendContexts get aload pop
X    ]
X  } def
X
X  /iexecing? true def
X
X  % meta-exec is a hook back up to the interpreter context.
X  /meta-exec {
X    exec
X  } def
X
X  /append {
X    {{append} stopped} MumbleFrotz
X    ?iexec-handle-error
X  } def
X
X  /sprintf {
X    {{sprintf} stopped} MumbleFrotz
X    ?iexec-handle-error
X  } def
X
X% execstack
X
Xend % iexec-names
X
Xend % systemdict
X
//go.sysin dd *
if [ `wc -c < ps.ps` != 17287 ]; then
	made=false
	echo error transmitting ps.ps --
	echo length should be 17287, not `wc -c < ps.ps`
else
	made=true
fi
if $made; then
	chmod 664 ps.ps
	echo -n '	'; ls -ld ps.ps
fi
echo Extracting scrap.ps
sed 's/^X//' <<'//go.sysin dd *' >scrap.ps
X% From owen@Sun.COM Mon Dec 12 21:12:13 1988
X% Date: Mon, 5 Dec 88 11:25:55 PST
X% From: owen@Sun.COM (Owen Densmore)
X% To: don@amanda.cs.umd.edu
X% Subject: Re:  scrap.ps & codebook.ps
X% 
X% The scrap.ps file is possibly not that interesting because it
X% is fairly out of date.  I'll send anyway.
X% ===============================================================
X%	scrap.ps
X%	Anybody can pick over these for whatever purpose they'd like.
X%	They are random pieces used in a class given at Sun for
X%	tech support engineers.
X%        Note:   The /demo procedures included below are small code
X%                fragments illustrating various parts of the system.
X%                Because they all have the same name, each one should
X%                be cut & paste to NeWS individually, as needed. 
X% ===============================================================
X%			Misc:
X% ===============================================================
X/cds {countdictstack =} def
X/ps {pstack} def
X/fb {framebuffer} def
X/temp {
X    executive systemdict begin (~/ps/server/NeWS/scrap.ps)run end
X} def
X/scrap {(~/ps/server/NeWS/scrap.ps)run} def
X% ---------------------------------------------------------
X/setshade { % GrayOrColor => - (set gray or color)
X    dup type /colortype eq {setcolor} {setgray} ifelse
X} def
X% ---------------------------------------------------------
X/fillcanvas { % GrayOrColor => - (Fills current canvas w/ GrayOrColor)
X    setshade clippath fill
X} def
X% ---------------------------------------------------------
X/insetrect { % delta x y w h => x' y' w' h' (return new rect inset by delta)
X10 dict begin
X    [/h /w /y /x /delta] {exch def} forall
X    x delta add y delta add w delta dup add sub h delta dup add sub
Xend
X} def
X% ---------------------------------------------------------
X/rectpath { % x y w h => - (make a rect path)
X    4 2 roll moveto
X    dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath
X} def
X% ---------------------------------------------------------
X/ovalpath { % x y w h => - (make a oval path)
X    matrix currentmatrix 5 1 roll		% xfm x y w h
X    4 2 roll translate scale			% xfm
X    .5 .5 translate 0 0 .5 0 360 arc closepath	% xfm
X    setmatrix					% -
X} def
X% ---------------------------------------------------------
X/starpath { % x y w h  =>  -  (make a star path)
X    matrix currentmatrix 5 1 roll		% xfm x y w h
X    4 2 roll translate scale			% xfm
X    .2 0 moveto .5 1 lineto .8 0 lineto		% xfm
X    0 .65 lineto 1 .65 lineto closepath		% xfm
X    setmatrix					% -
X} def
X% ===============================================================
X%		Canvases:
X% ===============================================================
X/demo {
Xgsave
X    framebuffer setcanvas
X    100 100 translate 0 0 300 300 rectpath
X    
X    /can framebuffer newcanvas def
X    can reshapecanvas 
X    can /Mapped true put
X    
X    can setcanvas .5 fillcanvas
Xgrestore
X} def
X% ---------------------------------------------------------
X/pathcanvas { % x y w h parent path => canvas (make a "path" shaped canvas)
X10 dict begin
X    gsave
X    cvx [/path /parent /h /w /y /x] {exch def} forall
X    /can parent newcanvas def
X
X    parent setcanvas
X    x y translate 0 0 w h path
X    
X    can reshapecanvas
X    can /Mapped true put
X    can
X    grestore
Xend
X} def
X% ---------------------------------------------------------
X/rectcanvas { {rectpath} pathcanvas } def % x y w h parent => canvas
X/rectcanvas { /rectpath pathcanvas } def % x y w h parent => canvas
X
X/demo {
X    /can 100 100 200 200 framebuffer rectcanvas def
X    can setcanvas .5 fillcanvas
X} def
X% ---------------------------------------------------------
X/ovalcanvas { {ovalpath} pathcanvas } def % x y w h parent => canvas
X
X/demo {
X    /can 100 100 200 200 framebuffer ovalcanvas def
X    can setcanvas .5 fillcanvas
X} def
X% ---------------------------------------------------------
X/starcanvas { {starpath} pathcanvas } def % x y w h parent => canvas
X
X/demo {
X    /can 100 100 200 200 framebuffer starcanvas def
X    can setcanvas .5 fillcanvas
X} def
X% ===============================================================
X%		Sub Canvases:
X% ===============================================================
X/demo {
X    /can 100 100 200 200 framebuffer rectcanvas def
X    /can1 10 10 180 180 can rectcanvas def 
X    can setcanvas .5 fillcanvas
X    can1 setcanvas 1 fillcanvas
X} def
X% ---------------------------------------------------------
X/demo {
X    /can 100 100 200 200 framebuffer ovalcanvas def
X    /can1 10 10 180 180 can ovalcanvas def 
X    can setcanvas .5 fillcanvas
X    can1 setcanvas 1 fillcanvas
X} def
X% ---------------------------------------------------------
X/demo {
X    /can 100 100 200 200 framebuffer starcanvas def
X    /can1 25 25 150 150 can starcanvas def 
X    can setcanvas .5 fillcanvas
X    can1 setcanvas 1 fillcanvas
X} def
X% ---------------------------------------------------------
X/demo {
X    /look { % canvas => - (print a canvas & its sub-tree)
X	countdictstack 2 sub {(    ) print} repeat dup ==
X	begin
X	    TopChild null ne {TopChild look} if
X	    CanvasBelow
X	end
X	dup null ne {look} {pop} ifelse
X    } def
X    framebuffer look
X} def
X% ===============================================================
X%		Transparency:
X% ===============================================================
X/demo { % transparent? => - (make /can & /can1)
Xgsave
X    framebuffer setcanvas
X    100 100 translate 0 0 300 300 rectpath
X    
X    /can framebuffer newcanvas def
X    can reshapecanvas 
X    can /Mapped true put
X    
X    can setcanvas
X    75 75 translate 0 0 150 150 ovalpath
X    
X    /can1 can newcanvas def
X    can1 reshapecanvas 
X    can1 /Transparent 3 -1 roll put
X    can1 /Mapped true put
Xgrestore
X} def
X
X/demo1 {
X    true demo
X    can1 setcanvas .5 fillcanvas
X    can setcanvas 0 fillcanvas
X    can1 setcanvas .5 fillcanvas
X    
X    false demo
X    can1 setcanvas .5 fillcanvas
X    can setcanvas 0 fillcanvas
X} def
X% ===============================================================
X%		Overlay Canvases:
X% ===============================================================
X/demo { % needs /can to be defined
X    /Times-Roman findfont 36 scalefont setfont
X
X    /olay can createoverlay def
X    can setcanvas 1 fillcanvas
X    0 setshade 20 20 moveto (Here Is Some Text) show
X    olay setcanvas
X    
X    0 fillcanvas
X    erasepage
X    
X    20 20 50 50 ovalpath stroke
X    20 100 moveto (Here Is Some Text) show
X    erasepage
X} def
X% ===============================================================
X%		Lightweight Processes
X% ===============================================================
X/demo {
X    /p {2 2 add} def
X    p =
X	% 4
X    /pp {p} fork def
X    pp =
X	% process(7663140, runnable)
X    pp waitprocess =
X	% 4
X} def
X% ---------------------------------------------------------
X/demo {
X    /p {2 2 add} fork def
X    p =
X	% process(7762460, runnable)
X    pause
X    p =
X	% process(7762460, zombie)
X    p waitprocess =
X	% 4
X} def
X% ---------------------------------------------------------
X/demo {
X    /p {1 2 3} fork def
X    p waitprocess =
X	% 3
X    /p {[1 2 3]} fork def
X    p waitprocess dup ==
X	% [1 2 3]
X    aload pop ps clear
X	% 1 2 3 
X} def
X% ---------------------------------------------------------
X/demo {
X    clear
X    /a 1 def
X    /p null def
X    /peek { % - => array  (Return an array showing the current status.)
X	[ count 1 roll ]
X	[   exch
X	    (Dictstack=% a=% Stack=) [countdictstack a] sprintf
X	    exch
X	]
X    } def
X    
X    10 dict begin
X	/a 10 def
X	(Hi!)
X	/p {
X	    peek
X	} fork store
X	pop
X    end
X    
X    peek ==
X    %	[(Dictstack=2 a=1 Stack=) []]
X    p waitprocess ==
X    %	[(Dictstack=3 a=10 Stack=) [(Hi!) /p]]
X} def
X/demo {
X    /a 1 def
X    /PrintStatus { % - => - (Print current processes status.)
X	(State of process:%\n    a=% Dictstack=% stack=)
X	    [currentprocess a countdictstack] printf
X	pstack
X    } def
X    
X    PrintStatus
X    
X%State of process:process(2222550, runnable)
X%    a=1 Dictstack=2 stack=Empty stack
X
X    10 dict begin
X	/a 10 def
X	(Hi!)
X	/p {
X	    PrintStatus
X	} fork store
X	pop
X    end
X    
X%State of process:process(4041374, runnable)
X%    a=10 Dictstack=3 stack=(Hi!) /p 
X} def
X% ===============================================================
X%		Events & Interests
X% ===============================================================
X/snoop {
X    /snoopprocess {
X	createevent expressinterest {awaitevent dup == redistributeevent} loop
X    } fork def
X} def
X/killsnoop {snoopprocess killprocess} def
X
X/demo {
X    snoop
X% event(0x1f7f3c, [382,223], name(/MouseDragged), action(null))
X% event(0x1f42f0, [382,223], name(/LeftMouseButton), action(/DownTransition))
X% event(0x1f7f3c, [382,223], name(/LeftMouseButton), action(/UpTransition))
X% event(0x1f7f3c, [382,223], name(28493), action(/DownTransition))
X% event(0x1f7f3c, [382,223], name(28493), action(/UpTransition))
X% event(0x1f42f0, [356,229], name(/MouseDragged), action(null))
X    killsnoop
X} def
X% ---------------------------------------------------------
X/settarget { % - => - (set tty target = current selection holder)
X    /TtyTarget createevent dup begin
X	/Name /InsertValue def
X	/Process /PrimarySelection getselection /SelectionHolder get def
X	/Canvas /PrimarySelection getselection /Canvas get def
X    end def
X} def
X
X/sendtarget { % string => - (send string to current tty target)
X    TtyTarget /Action 3 -1 roll put
X    TtyTarget sendevent
X} def
X
X/demo {
X    settarget
X    (ls\n) sendtarget
X    (ps\n) sendtarget
X} def
X
X/demo {
X    settarget
X    (
X        1 2 add =
X    ) sendtarget
X} def
X/demo {
X    settarget
X(/settarget { % - => - (set tty target = current selection holder)
X    /TtyTarget createevent dup begin
X	/Name /InsertValue def
X	/Process /PrimarySelection getselection /SelectionHolder get def
X	/Canvas /PrimarySelection getselection /Canvas get def
X    end def
X} def
X
X/sendtarget { % string => - (send string to current tty target)
X    TtyTarget /Action 3 -1 roll put
X    TtyTarget sendevent
X} def
X) sendtarget
X} def
X% ---------------------------------------------------------
X/demo {
X    /sendtimeevent { % timedelta => -
X	createevent begin
X	    /Name /Timer def
X	    /TimeStamp exch currenttime add def
X	    currentdict
X	end sendevent
X    } def
X
X    /p {
X        /timercount 0 def
X        createevent dup /Name /Timer put expressinterest
X        {   awaitevent pop
X            (Tick\n) print
X            /timercount timercount 1 add def
X            timercount 10 eq {exit} if
X	    1 60 div sendtimeevent
X        } loop
X    } fork def
X    
X    p =
X    (Starting processes:\n) print
X    1 60 div sendtimeevent
X    p waitprocess pop
X    p =
X% process(2716670, runnable)
X% Starting processes:
X% Tick
X% Tick
X% Tick
X% Tick
X% Tick
X% Tick
X% Tick
X% Tick
X% Tick
X% Tick
X% process(2716670, zombie)
X} def
X% ---------------------------------------------------------
X/demo {
X    /sendnameevent { % name => -
X	createevent dup /Name 4 -1 roll put sendevent
X    } def
X
X    /p1 {
X        /p1count 0 def
X        createevent dup /Name /Tick put expressinterest
X        {   awaitevent pop
X            (Tick ) print
X            /Tock sendnameevent
X            /p1count p1count 1 add def
X            p1count 10 eq {exit} if
X        } loop
X    } fork def
X    
X    /p2 {
X        /p2count 0 def
X        createevent dup /Name /Tock put expressinterest
X        {   awaitevent pop
X            (Tock!\n) print
X            /Tick sendnameevent
X            /p2count p2count 1 add def
X            p2count 10 eq {exit} if
X        } loop
X    } fork def
X    
X    p1 = p2 =
X    (Starting processes:\n) print
X    /Tick sendnameevent
X    21 {pause} repeat
X    p1 = p2 =
X% process(4244540, input_wait)
X% process(2716670, runnable)
X% Starting processes:
X% Tick Tock!
X% Tick Tock!
X% Tick Tock!
X% Tick Tock!
X% Tick Tock!
X% Tick Tock!
X% Tick Tock!
X% Tick Tock!
X% Tick Tock!
X% Tick Tock!
X% process(4244540, zombie)
X% process(2716670, zombie)
X} def
X% ===============================================================
X%		ADD MONITORS
X% ===============================================================
X
X% ===============================================================
X%		Keyboard
X% ===============================================================
X/snoop {
X    /snoopprocess {
X	createevent dup /Priority 10 put expressinterest
X	{awaitevent dup == redistributeevent} loop
X    } fork def
X} def
X/killsnoop {snoopprocess killprocess} def
X
X% snoop
X% event(0x27836C, [184,325], name(/MouseDragged), action(null))
X% event(0x27836C, [186,325], name(28493), action(/DownTransition))
X% event(0x24C17C, [186,325], name(28493), action(/UpTransition))
X% event(0x27836C, [186,325], name(/RightMouseButton), action(/DownTransition))
X% event(0x26CFA4, [170,324], name(/RightMouseButton), action(/UpTransition))
X% event(0x279564, [0,0], name(/DoItEvent), action(/Window))
X% event(0x24C1D8, [169,324], name(/MouseDragged), action(null))
X% killsnoop
X
X% ---------------------------------------------------------
X/demo {(
X% Text Sample  (Jerry Farrell)
X/MaxLen 1024 def
X/buffer MaxLen string def
X/buflen 0 def
X
X/addchar {
X    buflen MaxLen lt {
X	buffer buflen Name put
X	/buflen buflen 1 add store
X    } if
X} def
X/backchar {
X    buflen 0 gt {
X	/buflen buflen 1 sub store
X    } if
X} def
X/clearline {
X    /buflen 0 def
X} def
X/replaceline {
X    Action length MaxLen gt {
X	/Action Action 0 MaxLen getinterval def
X    } if
X    buffer 0 Action putinterval
X    /buflen Action length store
X} def
X
X/namedict dictbegin
X      8		/backchar load def		%  BS
X     10		/clearline load def		%  LF
X     13		/clearline load def		%  CR
X     21		/clearline load def 		%  ^U
X     32 1 126	{ /addchar load def } for	%  printable characters
X    127		/backchar load def		%  DEL
X    /InsertValue /replaceline load def		%  strings
Xdictend def
X
X/win framebuffer /new DefaultWindow send def
X{   /PaintClient {
X	1 fillcanvas 0 setgray 10 10 moveto
X	buffer 0 buflen getinterval show
X    } def
X    /FrameLabel (Text Example) def
X    /DestroyClient {
X	kbdinterests ClientCanvas revokekbdinterests
X	KbdHandler killprocessgroup
X    } def
X} win send
X/reshapefromuser win send
X/map win send
X
X/KbdHandler {
X    /kbdinterests win /ClientCanvas get addkbdinterests def
X    { awaitevent begin
X	namedict Name known {
X	    namedict Name get exec
X	    /paintclient win send
X	} if
X	end
X    } loop
X} fork def
X) runprogram }def
X% ---------------------------------------------------------
X/seteventmgrcallback {	% interest proc => -
X    /ClientData 10 dict dup /CallBack 5 -1 roll put put
X} def
X/eventmgrkbdinterest {	% callback can Editkeys? Fnames? Fstrings? => proc
X    [6 1 roll] {
X	3 index addkbdinterests				% p can E? FN? FS? a
X	exch {[4 index addfunctionstringsinterest] append} if	% p can E? FN? a
X	exch {[3 index addfunctionnamesinterest] append} if	% p can E? a
X	exch {[2 index addeditkeysinterest] append} if	% p can a
X	{2 index seteventmgrcallback} forall		% p can
X	pop pop
X    } append cvx
X} def
X/demo {
X    framebuffer setcanvas
X    100 100 translate 0 0 300 300 rectpath
X    /can framebuffer newcanvas def
X    can reshapecanvas 
X    can /Mapped true put
X    can setcanvas .5 fillcanvas
X
X    /MyEventProc {==} def
X    /p [
X	PointButton {interactivemove  .5 fillcanvas}
X	/DownTransition can eventmgrinterest
X	
X	{MyEventProc} can true true false eventmgrkbdinterest
X    ] forkeventmgr def
X} def
X% ===============================================================
X%		User Interaction
X% ===============================================================
X/interact { % proc startup? => result
X% Repeatedly call proc, with x0 y0 x y defined in a local
X% dictionary, whenever MouseDragged & MouseUp.  If startup?
X% also call on initial MouseDown.  Returns TOS of tracker.
X% Uses "callback" procedures stored in interests.
X20 dict begin
X    /startup? exch def
X    /proc exch cvx def
X
X    currentcursorlocation /y0 exch def /x0 exch def
X    /x x0 def /y y0 def
X    /callproc {/x XLocation store /y YLocation store proc} def
X    
X    MakeInteractInterests
X    
X    {   startup?
X            {[StartInterest]}
X            {proc [TrackInterest StopInterest]} ifelse
X        {expressinterest} forall
X        {   awaitevent begin
X            	Interest /ClientData get exec
X            end
X        } loop
X    } fork waitprocess
Xend
X} def
X
X/MakeInteractInterests { % proc startup?
X    /StartInterest createevent dup begin
X	/Name [/LeftMouseButton /RightMouseButton /MiddleMouseButton] def
X	/Action /DownTransition def
X	/ClientData {
X	    /x0 XLocation store /y0 YLocation store
X	    StopInterest /Name Name put
X	    TrackInterest expressinterest
X	    StopInterest expressinterest
X	    callproc
X	} def 
X    end def
X    /TrackInterest createevent dup begin
X	/Name /MouseDragged def
X	/ClientData {callproc} def 
X    end def
X    /StopInterest createevent dup begin
X	/Action /UpTransition def
X	/ClientData {callproc exit} def 
X    end def
X} def
X% ---------------------------------------------------------
X/demo {
X    /p { (x0=% y0=% x=% y=%\n) [x0 y0 x y] printf } def
X    /p true interact ==
X    /p false interact ==
X% x0=463 y0=283 x=463 y=283
X% x0=463 y0=283 x=422 y=267
X% x0=463 y0=283 x=298 y=193
X% x0=463 y0=283 x=238 y=153
X% x0=463 y0=283 x=10 y=59
X% x0=463 y0=283 x=-64 y=37
X% x0=463 y0=283 x=-66 y=35
X% x0=463 y0=283 x=-66 y=35
X% null
X} def
X% ---------------------------------------------------------
X/calcbbox {x0 x min y0 y min x x0 sub abs y y0 sub abs} def
X/getbbox { % canvas pathproc startup? => [x y w h] (relative to canvas)
X    gsave
X    3 -1 roll createoverlay setcanvas		% pathproc bool
X    {	erasepage calcbbox
X        4 index cvx exec stroke			% use the path proc
X	Action /UpTransition eq {
X	    erasepage [calcbbox]
X	} if
X    } exch interact				% pathproc array
X    exch pop					% array
X    grestore
X} def
X
X/demo {
X    framebuffer /starpath true getbbox
X    /can exch aload pop framebuffer starcanvas def
X    can setcanvas .5 fillcanvas
X} def
X% ---------------------------------------------------------
X/canvasfromuser { % parent pathproc => canvas
X    2 copy true getbbox aload pop	% parent proc x y w h
X    6 -2 roll pathcanvas		% canvas
X} def
X
X/demo {
X    /can framebuffer /starpath canvasfromuser def
X    can setcanvas .5 fillcanvas
X} def
X% ---------------------------------------------------------
X/slidecanvas { % canvas startup? => - (interactively move canvas)
X    gsave
X    1 index /Parent get setcanvas
X    {gsave dup setcanvas x y movecanvas grestore} exch interact
X    pop pop
X    grestore
X} def
X/slidecanvas { % canvas startup? => - (interactively move canvas)
X    gsave
X    exch dup /Parent get setcanvas	% bool canvas (parent=current)
X    dup getcanvaslocation		% bool canvas x1 y1
X    {	gsave 2 index setcanvas			% canvas x1 y1
X        x x0 sub 2 index add			% canvas x1 y1 x
X        y y0 sub 2 index add movecanvas		% canvas x1 y1
X        grestore
X    } 5 -1 roll interact		% canvas x1 y1 result
X    pop pop pop pop
X    grestore
X} def
X
X/demo {
X    can true slidecanvas
X} def
X% ===============================================================
X%		Utilities
X% ===============================================================
X/isutility { % keyword => bool
X    load type /arraytype eq =
X} def
X
X/demo {
X    /add isutility
X    %	false
X    /rectpath isutility
X    %	true
X
X%   forkeventmgr: interests => process (fork a process with these interests)
X%   eventmgrinterest: eventname eventproc action canvas => interest
X
X} def
X% ===============================================================
X%		Classes
X% ===============================================================
X/temp { % FCS documentation
X
X/Foo Object                 % Foo is a subclass of Object
Xdictbegin                   % (initialized) instance variables
X    /Value   0 def
X    /Time    null def
Xdictend
Xclassbegin
X    /ClassTime currenttime def  % The class variable "ClassTime".
X
X    % class methods
X    /new { % - => - (Make a new Foo)
X        /new super send begin
X            /resettime self send
X            currentdict
X        end
X    } def
X    /printvars { % - => - (Print current state)
X        (..we got: Value=%, Time=%.\n) [Value Time] printf
X    } def
X    /changevalue { % value => - (Change the value of "Value")
X        /Value exch def
X    } def
X    /resettime { % - => - (Change Time to the current time)
X        /Time currenttime def
X    } def
Xclassend def
X
X/foo /new Foo send def
X/printvars foo send
X% ..we got: Value=0, Time=1.31435.
X
X(A String) /changevalue foo send
X/printvars foo send
X% ..we got: Value=A String, Time=1.31435.
X
X/resettime foo send
X/printvars foo send
X% ..we got: Value=A String, Time=1.31667.
X
X{/Time ClassTime def} foo send
X/printvars foo send
X% ..we got: Value=A String, Time=1.31168.
X
X{currenttime Time sub round /changevalue self send} /doit foo send
X/printvars foo send
X% ..we got: Value=0, Time=1.31168.
X
X{currenttime 60 mul round} /changevalue foo send
X/printvars foo send 1000 {pause} repeat /printvars foo send
X% ..we got: Value=79, Time=1.31168.
X% ..we got: Value=81, Time=1.31168.
X
X} def
X% ===============================================================
X/demo { % page 62-65 of smalltalk blue book
X    /One Object [] classbegin
X	/test {1} def
X	/result1 {/test self send} def
X    classend def
X
X    /Two One [] classbegin
X	/test {2} def
X    classend def
X    
X    /ex1 /new One send def
X    /ex2 /new Two send def
X    
X    /test ex1 send =
X    /result1 ex1 send =
X    /test ex2 send =
X    /result1 ex2 send =
X
X    /Three Two [] classbegin
X	/result2 {/result1 self send} def
X	/result3 {/test super send} def
X    classend def
X    /Four Three [] classbegin
X	/test {4} def
X    classend def
X    
X    /ex3 /new Three send def
X    /ex4 /new Four send def
X    
X    /test ex3 send =
X    /result1 ex4 send =
X    /result2 ex3 send =
X    /result2 ex4 send =
X    /result3 ex3 send =
X    /result3 ex4 send =
X} def
X% ===============================================================
X/Canvas Object [/TheCanvas /EventMgr /Height /Width]
Xclassbegin
X    /FillColor	1 1 1 rgbcolor def
X    /EdgeColor	.5 .5 .5 rgbcolor def
X    /EdgeSize	8 def
X
X    /new { % ParentCanvas => instance
X        /new super send begin
X            /TheCanvas exch newcanvas store
X            currentdict
X        end
X    } def
X    
X    /path {rectpath} def % x y w h => - (currentpath now is my kind of path)
X    
X    /reshape { % x y w h => -
X    gsave
X        TheCanvas /Parent get setcanvas
X        /Height exch def /Width exch def translate
X        0 0 Width Height /path self send
X        TheCanvas reshapecanvas
X    grestore
X    } def
X    
X    /reshapefromuser { % - => -
X        TheCanvas /Parent get /path true getbbox
X        aload pop /reshape self send
X    } def
X    
X    /paint { % - => -
X    gsave
X        TheCanvas setcanvas
X        EdgeColor fillcanvas FillColor setcolor
X        EdgeSize 0 0 Width Height		% delta x y w h
X        insetrect /path self send		% -
X        fill
X    grestore
X    } def
X
X    /fix { % - => -
X    gsave
X        TheCanvas setcanvas
X        damagepath clipcanvas
X        /paint self send
X        newpath clipcanvas
X    grestore
X    } def
X
X    /map { % - => -
X        EventMgr null eq {/fork self send} if
X        TheCanvas /Mapped true put
X    } def
X    
X    /fork { % - => -
X        /EventMgr [
X            PointButton {TheCanvas canvastotop}
X            /DownTransition TheCanvas eventmgrinterest
X            
X            AdjustButton {TheCanvas false slidecanvas}
X            /DownTransition TheCanvas eventmgrinterest
X            
X            /Damaged {/fix self send}
X            null TheCanvas eventmgrinterest
X        ] forkeventmgr def
X    } def
Xclassend def
X% ---------------------------------------------------------
X/demo {
X    /can framebuffer /new Canvas send def
X    /reshapefromuser can send
X    /map can send
X    
X    10 20 100 200 /reshape can send
X} def
X% ---------------------------------------------------------
X/OvalCanvas Canvas []
Xclassbegin
X    /path {ovalpath} def
Xclassend def
X
X/demo {
X    /can1 framebuffer /new OvalCanvas send def
X    /reshapefromuser can1 send
X    /map can1 send
X} def
X% ---------------------------------------------------------
X/StarCanvas Canvas []
Xclassbegin
X    /EdgeSize	20 def
X    /path {starpath} def
Xclassend def
X
X/demo {
X    /can2 framebuffer /new StarCanvas send def
X    /reshapefromuser can2 send
X    /map can2 send
X} def
X% ===============================================================
X%		Windows & Menus
X% ===============================================================
X/demo {
X    /win framebuffer /new DefaultWindow send def
X    {   /FrameLabel (USENIX  is  a  Star!) def
X        /IconImage /hello_world def
X        /PaintClient {
X            .5 fillcanvas 1 setshade
X            clippath pathbbox starpath fill
X        } def
X    } win send
X    /reshapefromuser win send
X    /map win send
X} def
X% ---------------------------------------------------------
X/demo {
X    /StarGray 1 def
X    /FillGray .5 def
X    /FillCanvasWithStar { % stargray fillgray => -
X	fillcanvas setshade
X	clippath pathbbox starpath fill
X    } def
X    /SetStarGrays { % stargray fillgray => -
X        /FillGray exch store /StarGray exch store
X	/paintclient win send
X    } def
X    
X    /win framebuffer /new DefaultWindow send def
X    {   /FrameLabel (USENIX  is  a  Star!) def
X        /PaintIcon {.25 .75 FillCanvasWithStar 0 strokecanvas} def
X        /PaintClient {StarGray FillGray FillCanvasWithStar} def
X	/ClientMenu [
X            (White Star)		{  1  FillGray SetStarGrays}
X            (Lite Star)			{.75  FillGray SetStarGrays}
X            (Gray Star)			{.50  FillGray SetStarGrays}
X            (Dark Star)			{.25  FillGray SetStarGrays}
X            (Black Star)		{  0  FillGray SetStarGrays}
X            (White Fill)		{StarGray   1 SetStarGrays}
X            (Gray Fill)			{StarGray .50 SetStarGrays}
X            (Black Fill)		{StarGray   0 SetStarGrays}
X	] /new DefaultMenu send def
X    } win send
X    /reshapefromuser win send
X    /map win send
X} def
X% ---------------------------------------------------------
X/demo {
X    /StarGray 1 def
X    /FillGray .5 def
X    /FillCanvasWithStar { % stargray fillgray => -
X	fillcanvas setshade
X	clippath pathbbox starpath fill
X    } def
X    /SetStarGrays { % stargray fillgray => -
X        /FillGray exch store /StarGray exch store
X	/paintclient win send
X    } def
X    
X    /GetMenuNumber {/currentkey self send cvr} def % - => num
X    /StarGraysMenu
X	[(.1) (.2) (.25) (.3) (.4) (.5) (.6) (.7) (.75) (.8) (.9) (1.0)]
X	[{GetMenuNumber FillGray SetStarGrays}]
X	/new DefaultMenu send def
X    /FillGraysMenu
X	[(.1) (.2) (.25) (.3) (.4) (.5) (.6) (.7) (.75) (.8) (.9) (1.0)]
X	[{StarGray GetMenuNumber SetStarGrays}]
X	/new DefaultMenu send def
X    
X    /win framebuffer /new DefaultWindow send def
X    {   /FrameLabel (USENIX  is  a  Star!) def
X        /PaintIcon {.25 .75 FillCanvasWithStar 0 strokecanvas} def
X        /PaintClient {StarGray FillGray FillCanvasWithStar} def
X	/ClientMenu [
X            (White on Black)		{  1   0 SetStarGrays}
X            (Black on White)		{  0   1 SetStarGrays}
X            (Lite on Dark)		{.75 .25 SetStarGrays}
X            (Star Grays =>)		StarGraysMenu
X            (Fill Grays =>)		FillGraysMenu
X	] /new DefaultMenu send def
X    } win send
X    /reshapefromuser win send
X    /map win send
X} def
X% ===============================================================
X%		Custom Windows
X% ===============================================================
X/OvalWindow LiteWindow []
Xclassbegin
X    /Border 16 def
X    /FrameFillColor .75 .75 .75 rgbcolor def
X    
X    /ShapeFrameCanvas { % - => - ([Re]set frame canvas' shape)
X	gsave
X	ParentCanvas setcanvas
X	FrameX FrameY translate 0 0 FrameWidth FrameHeight ovalpath
X	FrameCanvas reshapecanvas
X	grestore
X    } def
X    /PaintFrame	{ % - => - (Paint frame canvas)
X        FrameFillColor fillcanvas PaintFocus
X    } def
X    /PaintFocus { % - => - (Paint frame focus)
X	gsave
X	FrameCanvas setcanvas
X	KeyFocus? {0} {FrameFillColor} ifelse setshade
X	Border 2 div 0 0 FrameWidth FrameHeight insetrect ovalpath stroke
X	grestore
X    } def
X    /ShapeClientCanvas { % - => - ([Re]set client canvas' shape)
X	ClientCanvas null ne {
X	    gsave
X	    FrameCanvas setcanvas
X	    Border 0 0 FrameWidth FrameHeight insetrect
X	    4 2 roll translate 0 0 4 2 roll ovalpath
X	    ClientCanvas reshapecanvas
X	    grestore
X	} if
X    } def
Xclassend def
X
X/demo {
X    /win framebuffer /new OvalWindow send def
X    {   /IconImage /hello_world def
X        /PaintClient {1 fillcanvas} def
X    } win send
X    /reshapefromuser win send
X    /map win send
X} def
X% ===============================================================
X%		Development
X% ===============================================================
X/demo {
X    /win framebuffer /new DefaultWindow send def
X    /reshapefromuser win send
X    /map win send
X    
X    /paintme {.5 fillcanvas} def
X    win /PaintClient {paintme} put
X} def
X% ---------------------------------------------------------
X/runprogram { % string => - (exececute the string as a psh program)
X    (/tmp/pshscript) (w) file		% str file
X    dup 3 -1 roll			% file file str
X    writestring closefile		% -
X    (psh /tmp/pshscript) forkunix
X} def
X%
X% timeit
X%
X/Temp 10 dict dup begin
X    /timeitms { % - => int
X	% (T2-T1)*60000/Count -or- (T2-T1)/(minim*Count)
X	T2 T1 sub
X	60000 mul
X	Count div
X	% truncate at third decimal.
X	1000 mul round 1000 div
X    } def
Xend def
X/timeit { % count test => -
X    //Temp begin
X	/Proc 1 index def
X	/Count 2 index def
X	/T1 currenttime def
X    end
X    repeat currenttime
X    //Temp begin
X	/T2 exch def
X	(Time: % ms, Loops: %, Test: ) [timeitms Count] printf /Proc load ==
X    end
X} def
X%------------------------------------------
X%  from Sam Leffler @ Pixar
X% Time: 6998.291 ms
X/bubblesort {   % array => array        (sort array with bubble sort)
X10 dict begin
X    /a exch def
X    a length 2 sub -1 -1 {                      % for j=n-2 step -1 until 0 do
X        0 1 3 -1 roll {                         % for i=0 step 1 until j do
X            /i exch def
X            a i 1 add get a i get lt {          % if a[i+1] < a[i] then
X               a i get                          % a[i]
X               a i 1 add get a i 3 -1 roll put  % a[i] = a[i+1]
X               a i 1 add 3 -1 roll put          % a[i+1] = a[i]
X            } if
X        } for
X    } for
X    a
Xend
X} def
X%------------------------------------------
X% Time: 1952.82 ms (358% faster!)
X/SiftDown { % L U => -
X    /U exch def
X    /L exch def
X    /Xl X L get def
X    {
X    	/C L 2 mul 1 add def
X    	C U gt {exit} if
X    	/Xc X C get def
X    	/C+1 C 1 add def
X    	
X    	C+1 U le {
X    	    X C+1 get dup Xc Bigger?
X    	        {/Xc exch def /C C+1 def} {pop} ifelse
X    	} if
X    	
X    	Xl Xc Bigger? {exit} if
X    	X L Xc put
X    	/L C def
X    } loop
X    X L Xl put
X} def
X/heapsort { % array proc => array (sorted)
X10 dict begin
X    /Bigger? exch cvx def		% a b bigger? => t if a>b
X    /X exch def
X    /N X length 1 sub def
X    
X    % Make the heap
X    N					% X N
X    dup 1 sub 2 div floor -1 0 {	% N n; for: |N/2| -1 0
X	1 index SiftDown
X    } for				% N
X    
X    % Sort the heap
X    -1 1 {				% i:N -1 1
X        /I exch def
X        X 0 get X I get
X        X 0 3 -1 roll put
X        X I 3 -1 roll put
X        0 I 1 sub SiftDown
X    } for
X    X
Xend
X} def
X
X% Time: 1679.69 ms (16% faster than above)
X/SiftDown { % L U => -
X    /U exch def
X    /L exch def
X    /Xl X L get def
X    {	L 2 mul 1 add			% C (i.e child index)
X    	dup U gt {pop exit} if
X    	X 1 index get			% C Xc
X    	1 index 1 add			% C Xc C+1
X    	
X    	dup U le {
X    	    X 1 index get		% C Xc C+1 Xc+1
X	    dup 3 index Bigger? {4 2 roll} if
X    	    pop pop			% C' Xc' (largest child)
X    	} {pop} ifelse
X    	
X    	Xl 1 index Bigger? {pop pop exit} if
X    	X L 3 -1 roll put
X    	/L exch def
X    } loop
X    X L Xl put
X} def
X/heapsort { % array proc => array (sorted)
X10 dict begin
X    /Bigger? exch cvx def		% a b bigger? => t if a>b
X    /X exch def
X    
X    % Make the heap
X    X dup length 1 sub			% X N
X    dup 1 sub 2 div floor -1 0 {	% X N for: |N/2| -1 0
X	1 index SiftDown
X    } for				% X N
X    
X    % Sort the heap
X    -1 1 {				% X i:N -1 1
X        2 copy 1 index 0		% X i X i X 0
X        4 copy get 3 1 roll get exch	% X i X i X 0 Xi X0
X        4 1 roll put put		% X i
X
X        0 exch 1 sub SiftDown
X    } for
Xend
X} def
X
X% Time: 1599.43 ms (6% faster than above)
X% Converting /Bigger? to use /gt rather than {gt}: 1499.634!
X% Using gt rather than Bigger? 100ms faster.
X/SiftDown { % X L U => -
X    3 1 roll 2 copy get exch		% U X Xl L
X    {
X    	dup 2 mul 1 add			% U X Xl L C (i.e child index)
X    	dup 5 index gt {pop exit} if	% C>U: exit
X    	3 index 1 index get		% U X Xl L C Xc
X    	1 index 1 add			% U X Xl L C Xc C+1
X    	
X    	dup 7 index le {		% C+1<=U: check right child
X    	    5 index 1 index get		% U X Xl L C Xc C+1 Xc+1
X	    dup 3 index Bigger?		% Xc+1 > Xc: roll
X	    	{4 2 roll} if
X    	    pop pop			% U X Xl L C' Xc' (largest child)
X    	} {pop} ifelse
X    					% U X Xl L C Xc
X    	3 index 1 index Bigger?		% Xl > Xc: exit
X    	    {pop pop exit} if
X    	4 index 3 index 3 -1 roll put	% U X Xl L C; X[L]=Xc
X    	exch pop			% U X Xl L'; L=C
X    } loop
X    exch put pop			% -; X[L]=Xl
X} def
X/heapsort { % array proc => array (sorted)
X10 dict begin
X    /Bigger? exch cvx def		% a b bigger? => t if a>b
X    
X    % Make the heap
X    dup length 1 sub			% X N
X    dup 1 sub 2 div floor -1 0 {	% X N n ; for: |N/2| -1 0
X	3 copy exch SiftDown pop
X    } for				% X N
X    
X    % Sort the heap
X    -1 1 {				% X i:N -1 1
X
X        57 type =
X	    11.56 type =
X	        true type =
X		    (Foo) type =
X		        /Foo type =
X			    [1 2 3] type =
X			        {3 4 add} type =
X				    {3 4 add} xcheck =
X				        10 dict type =
X					
X					    clear pstack
X					        64 (Hi) /Name pstack
X						    exch pstack
X						        dup pstack
X							    2 index pstack
X							        pop pop pstack
X								    3 1 roll
X								    pstack
X								        3 copy
X									pstack
X
X									clear
X									
X
X									/min
X									{dup 2
X									index
X									lt
X									pstack
X
X									{xch
X									pop
X									(1st)
X									==}
X
X									{op
X									(2nd)
X									==}
X
X									ielse
X									} def
X
X									   76
X									   -6
X									   min
X									   ==
X
X
X
X									   -676 m =
X									2 copy 1 index 0		% X i X i X 0
X        4 copy get 3 1 roll get exch	% X i X i X 0 Xi X0
X        4 1 roll put put		% X i
X        2 copy 1 sub 0 exch SiftDown pop % X
X    } for
Xend
X} def
X%------------------------------------------
X
X
//go.sysin dd *
if [ `wc -c < scrap.ps` != 34241 ]; then
	made=false
	echo error transmitting scrap.ps --
	echo length should be 34241, not `wc -c < scrap.ps`
else
	made=true
fi
if $made; then
	chmod 664 scrap.ps
	echo -n '	'; ls -ld scrap.ps
fi
echo Extracting cond.ps
sed 's/^X//' <<'//go.sysin dd *' >cond.ps
Xsystemdict begin
X
X/setpacking {pop} ?def
X/currentpacking false ?def
X
X%
X% A "cond" (condition) statement: Consists of predicate-proc pairs.
X% The first predicate that evaluates to true executes its correnponding
X% procedure.  Thus:
X%
X%    2 {
X%        {dup 1 eq}	{(one)}
X%        {dup 2 eq}	{(two)}
X%        true		{(other)}
X%    } cond
X%
X% results in "2 (two)" being left on the stack.  Note "true" effects
X% a default branch.
X%
X% The implementation is very wierd.  Here are the author's notes:
X% Here's another entry in the cond-test.  It's like Owen & Jerry's last
X% ones in that it uses forall to step through all the elements, except
X% instead of leaving a boolean or integer on the top of the stack to tell
X% it what to do on the next iteration, it puts the code to be executed
X% itself.  Notice the mind-bending self referentiality:
X% 
X% NextProc contains the code to be executed the next time a test is to be
X% made, "exec null exit" gets executed in the clause after a true result,
X% "pop /NextProc" gets executed in the clause after a false result -
X% which is setting up for the next test.
X%
X% The "/NextProc" in the definition of /NextProc should really be
X% //NextProc except that NextProc isn't defined yet...
X% I then reach into the array and install it after /NextProc
X% is defined.
X% 
Xcurrentpacking	    	% bool left on stack for later setpacking call
Xfalse setpacking
X/NextProc { exec { { exec null exit } } { { pop /NextProc } } ifelse } def
X//NextProc 2 get 0 get 1 //NextProc put % replace placeholder by a recursion
Xsetpacking
X
X/cond { % args array => args
X    //NextProc			% args a nextproc
X    exch {			% args nextproc ai
X	exch exec		% args newnextproc
X    } forall
X    pop
X} ?def
Xcurrentdict /NextProc undef
X
Xend % systemdict
//go.sysin dd *
if [ `wc -c < cond.ps` != 1749 ]; then
	made=false
	echo error transmitting cond.ps --
	echo length should be 1749, not `wc -c < cond.ps`
else
	made=true
fi
if $made; then
	chmod 664 cond.ps
	echo -n '	'; ls -ld cond.ps
fi
echo Extracting trace.ps
sed 's/^X//' <<'//go.sysin dd *' >trace.ps
X% Copyright (c) 1989, Sun Microsystems, Inc.  RESTRICTED RIGHTS LEGEND:
X% Use, duplication, or disclosure by the Government is subject to
X% restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in
X% Technical Data and Computer Software clause at DFARS 52.227-7013 and
X% in similar clauses in the FAR and NASA FAR Supplement.
X%
X%	@(#)trace.ps 1.9 89/05/17
X%
X
X% Trace utilities.
X
X% How to use the trace utilities.
X%
X% Here is a summary of the most commonly used trace functions.  See the
X% documentation above the function definitions in the code for more
X% information and for more functions.
X%
X% /<function> trace			% find fn in dict stack
X% /<method> /trace <object> send	% find fn in class dict stack
X% /<function> untrace
X% /<method> /untrace <object> send
X%
X% listtraces				% list all set traces
X% untraceall				% remove all set traces
X%
X% /traceclass <class> send		% trace all methods in a class
X% /untraceclass <class> send
X%
X% /<method> /tracesupers <object> send	% trace method in class & all supers
X% /<method> /untracesupers <object> send
X%
X% The trace works by replacing the function's definition with one that
X% wraps the original definition with calls to functions tracein and
X% traceout.  The default versions of these functions print the
X% dictionary and name of the traced function, and the dictionary stack.
X% Untrace removes the wrapper.  Here are some samples:
X%
X% /reshape /trace ClassButton send
X% /but /demo OpenLookButton send def
X% /B /setname but send
X% 0 0 100 20 /reshape but send
X% In  ClassButton /reshape ["B"]:  0 0 100 20 
X% Out ClassButton /reshape ["B"]:  Empty stack
X%
X% The last two lines are produced by trace.  They show the class and
X% method being entered and exited, the object on the top of the dict
X% stack, i.e. the instance to which /reshape was sent, and the operand
X% stack contents.  Since we used /setname to name the instance "B", that
X% is what trace prints.
X%
X% Here's a more involved example:
X%
X% /newinit /tracesupers ClassButton send
X% listtraces
X% Object: /newinit
X% ClassCanvas: /newinit
X% ClassControl: /newinit
X% ClassButton: /newinit
X%
X% (Hello) {pop} framebuffer /new OpenLookButton send
X% In  ClassButton /newinit [.OpenLookButton]:  (Hello) array{1} 
X%  In  ClassControl /newinit [.OpenLookButton]:  (Hello) array{1} 
X%   In  ClassCanvas /newinit [.OpenLookButton]:  (Hello) array{1} 
X%    In  Object /newinit [.OpenLookButton]:  (Hello) array{1} 
X%    Out Object /newinit [.OpenLookButton]:  (Hello) array{1} 
X%   Out ClassCanvas /newinit [.OpenLookButton]:  (Hello) array{1} 
X%  Out ClassControl /newinit [.OpenLookButton]:  (Hello) 
X%  In  Object /newinit [.OpenLookButtonGraphic]:  (Hello) 
X%  Out Object /newinit [.OpenLookButtonGraphic]:  (Hello) 
X% Out ClassButton /newinit [.OpenLookButton]:  Empty stack
X%
X% This illustrates:
X%   /tracesupers traces a method in all superclasses.
X%   listtraces shows traced methods and their classes.
X%   Trace output is indented to show nested calls.
X%   Unnamed instances of classes are printed as .ClassName
X%
X% If you turn off autobinding you can trace operators:
X%
X% false setautobind
X% /add trace
X% 5 6 add
X% In  systemdict /add []:  5 6 
X% Out systemdict /add []:  11 
X%
X% You can even trace send.  If you are feeling real adventurous, try
X% tracing def or store!
X
X
X% Implementation:
X%
X% The /trace function finds the named function in a dictionary then wraps
X% the function with calls to the tracein and traceout functions.  The
X% /untrace function finds the function, looks at it to see if it has the
X% trace wrapper, then removes the wrapper.
X%
X% An array of traced functions is kept in tracelist.  Since the first
X% two elements of the trace wrapper are the dictionary and function name
X% of the traced function, they can be used to locate the function for
X% removing the trace.  Function /untraceall goes through the list and
X% removes all the traces.  Function /listtraces displays all functions
X% in the list.
X
Xsystemdict begin
X
X/print-operator /print load def
X/printf-operator /printf load def
X
X    % NeWS 1.1 compatibility
X
X    %
X
X    systemdict /XNeWS? known not {
X      systemdict /XNeWS? false put
X    } if
X
X    XNeWS? not { % Is it NeWS 1.1?
X
X% Force print not to autobind
X/print {//print-operator} def
X/printf {//printf-operator} def
X
X/setpacking {pop} ?def
X/currentpacking false ?def
X
X% from basics.ps
X
X%
X% A "cond" (condition) statement: Consists of predicate-proc pairs.
X% The first predicate that evaluates to true executes its correnponding
X% procedure.  Thus:
X%
X%    2 {
X%        {dup 1 eq}	{(one)}
X%        {dup 2 eq}	{(two)}
X%        true		{(other)}
X%    } cond
X%
X% results in "2 (two)" being left on the stack.  Note "true" effects
X% a default branch.
X%
X% The implementation is very wierd.  Here are the author's notes:
X% Here's another entry in the cond-test.  It's like Owen & Jerry's last
X% ones in that it uses forall to step through all the elements, except
X% instead of leaving a boolean or integer on the top of the stack to tell
X% it what to do on the next iteration, it puts the code to be executed
X% itself.  Notice the mind-bending self referentiality:
X% 
X% NextProc contains the code to be executed the next time a test is to be
X% made, "exec null exit" gets executed in the clause after a true result,
X% "pop /NextProc" gets executed in the clause after a false result -
X% which is setting up for the next test.
X%
X% The "/NextProc" in the definition of /NextProc should really be
X% //NextProc except that NextProc isn't defined yet...
X% I then reach into the array and install it after /NextProc
X% is defined.
X% 
Xcurrentpacking	    	% bool left on stack for later setpacking call
Xfalse setpacking
X% Beginning of string
X% This is a string so the scanner doesn't see //NextProc before it's defined.
X(
X/NextProc { exec { { exec null exit } } { { pop /NextProc } } ifelse } def
X//NextProc 2 get 0 get 1 //NextProc put % replace placeholder by a recursion
Xsetpacking
X
X/cond { % args array => args
X    //NextProc			% args a nextproc
X    exch {			% args nextproc ai
X	exch exec		% args newnextproc
X    } forall
X    pop
X} ?def
Xcurrentdict /NextProc undef
X% End the string and execute it:
X) cvx exec
X
X/isarray? { % any => boolean
X    type dup /arraytype eq  exch /packedarraytype eq or
X} def
X
X% from util.ps
X
X%%%%%%%%%%%%%%%%%%%
X% array utilities %
X%%%%%%%%%%%%%%%%%%%
X
X/arraycontains? { % array value => bool ; returns true if value is in array.
X    exch false exch {			% value bool ai
X	2 index eq {pop true exit} if
X    } forall				% value bool
X    exch pop
X} def
X
X/arraysequal? { % A B => bool
X    0 exch {				% A i bi
X    	2 index 2 index get ne		% A i bool
X	{exit} {1 add} ifelse		% A i
X    } forall
X    exch length eq
X} def
X
X/arrayindex { 	% array value => index true -or- false
X    exch 0 exch {				% value i ai
X	2 index eq				% value i
X	    {exch pop true exit} {1 add} ifelse
X    } forall					% i true -or- value i
X    dup true ne {pop pop false} if		% i true -or- false
X} def
X
X% From class.ps
X(
X/Temp 10 dict dup begin
X   /dicttype dup def
X   /canvastype dup def
X   /eventtype dup def
X   /processtype dup def
Xend def
X/isobject? { % obj => bool; test for "sendable" object (instance or class).
X  //Temp 1 index type known {
X      /ParentDictArray known
X  } {pop false} ifelse
X} def
X/isclass? { % obj => bool; test for class.
X  //Temp 1 index type known {
X      /ClassName known
X  } {pop false} ifelse
X} def
X/isinstance? { % obj => bool; test for instance of class.
X  //Temp 1 index type known {
X      dup /ParentDictArray known exch /ClassName known not and
X  } {pop false} ifelse
X} def
X) cvx exec
X
X{ % Send to Object:
X  /installmethod { % name proc => -; compile and install a new method.
X      ParentDict % NeWS 1.1 /methodcompile takes different args!
X      /methodcompile self send def
X  } dup exec % what convenience!
X
X  /superclasses { % - => array ;return inheritance array.
X      ParentDictArray
X      dup type /dicttype eq {
X	  dup /ParentDictArray get
X	  exch 1 array astore append
X      } if
X  } installmethod
X  % NeWS 1.1 has subclass names, instead of the actual subclasses
X  /subclasses {
X      [ SubClasses {
X	  dup where {
X	    exch get
X	  } { pop } ifelse
X	} forall 
X      ]
X  } installmethod
X
X  % Routines to handle promotion of defaults to instance vars.
X  % promote: promote a class variable to an instance variable.
X  % promoted?: check if the variable is an instance variable.
X  % ?promote: promote variable if it differs from the class version.
X  % unpromote: remove variable from instance vars.
X  /promote {self 3 1 roll put} installmethod % name object => -
X  /promoted? {self exch known} installmethod % name => bool
X  /unpromote {self exch undef} installmethod % name => -; remove name as an instance
X  /?promote { % name object => -
X      % Note: the value of the variable is determined by /send because
X      % it may be executable.
X      2 copy exch self send eq {pop pop} {/promote self send} ifelse
X  } installmethod
X
X    /classname { ClassName } def
X
X    /name { Name } installmethod % - => name
X    /setname { self /Name 3 -1 roll put } installmethod % name => -
X    /id { ID } installmethod % - => name
X    /setid { self /ID 3 -1 roll put } installmethod % name => -
X
X% Class Variables
X    /Name	{ClassName} def
X    /ID		null def
X
X} Object send
X
X    } if % end if NeWS 1.1
X
X    % CyberSpace pallet interface
X
X/args { pop pop } ?def
X
X/TraceDict 200 dict def
XTraceDict begin
X  /list-traces /listtraces def
X  /show-trace-stats /showtracestats def
X  /list-callcount-stats {
X    /callcount listtracestats
X  } def
X  /list-totaltime-stats {
X    /totaltime listtracestats
X  } def
X  /clear-trace-stats { {procname} null args
X    cleartracestats
X  } def
X  /set-trace-output { null null args
X    currentfile settraceoutput
X  } def
X  /set-trace-default { null null args
X    /defaulttracein /defaulttraceout settracefunctions
X  } def
X  /set-trace-fast { null null args
X    /fasttracein /fasttraceout settracefunctions
X  } def
X  /trace-name { {procname} null args
X    trace
X  } def
X  /trace-class-method { {class procname} null args
X    exch /trace exch send
X  } def
X  /untrace-name { {procname} null args
X    trace
X  } def
X  /untrace-all /untraceall def
X  /trace-list { null {array} args
X    tracelist
X  } def
X  /trace-class { {class} null args
X    /traceclass exch send
X  } def
X  /untrace-class { {class} null args
X    /traceclass exch send
X  } def
X  /trace-supers { {class procname} null args
X    exch /tracesupers exch send
X  } def
X  /untrace-supers { {class procname} null args
X    exch /untracesupers exch send
X  } def
X  /trace-subclasses { {class} null args
X    /tracesubclasses exch send
X  } def
X  /trace-superclasses { {class} null args
X    /tracesubclasses exch send
X  } def
Xend
X
X    % This function in systemdict makes sure ClassName is always in a
X    % dictionary on the dict stack.  Objects all have their own class
X    % name.  This function provides names for /systemdict and /userdict.
X    % It returns the dictionary itself for other dictionaries.
X    %
X    % The use of this is a little bad and hacky because /ClassName is used
X    % as a method for any object (including classes themselves), even though
X    % it is not an advertised method in class Object.
X    %
X    /ClassName { % - => name | dict
X        currentdict
X        dup userdict   eq {pop /userdict} if
X        dup systemdict eq {pop /systemdict} if
X    } def
X    
X    % Each traced function has a dictionary of information about the function.
X    % The dictionary contains:
X    %
X    % Key	    	Value
X    % /dictname		Printable name of dictionary (class) containing routine
X    % /fnname		Printable name of function
X    % /fndict		The actual dictionary containing the routine
X    % /callcount	Number of times routine is called
X    % /totaltime	Total time spent in the routine
X    % /stackdelta	Change in # of objects on stack from entry to exit
X    
X    % Array of info dicts for all traced functions.
X    %
X    /tracelist [] def
X    
X    
X% Functions for Setting and Removing Traces:
X    
X    % Add trace to a function.  Usually used in a send context on a
X    % method in a class.
X    %
X    %    /procname trace
X    %    /procname /trace object send
X    %
X    /trace { % procname => -
X        %
X        % Locate the named proc by finding the given name in the current
X        % dictionary stack.  Get the value associated with it, usually a
X        % function.  Construct a new function that is the old one with a
X        % wrapper around it.  The new function is:
X        %
X        % {<tracedict> tracein <oldproc> exec <tracedict> traceout}
X        %
X        % Where <tracedict> is a dictionary with the keys listed above.
X        %
X        % If the proc is already of the form above, i.e. is already being
X        % traced, the trace function does nothing.
X        %
X        4 dict begin
X    	/proc exch def
X    	proc where {
X    	    /dct exch def
X    	    /dctname /ClassName dct send def
X    	    
X    	    dct proc get istraced? not {
X    
X    		% Create trace info dictionary.
X    		/tracedict 6 dict dup begin
X    		    /dictname dctname def
X    		    /fnname proc def
X    		    /fndict dct def
X    		    /callcount 0 def
X    		    /stackdelta null def
X    		    /totaltime 0 def
X    		end def
X    
X    		% Add trace info dict to trace array.
X     		tracelist [tracedict] append
X    		/tracelist exch store
X    
X    		% Build wrapper code.
X    		[
X    		    tracedict /tracein cvx 
X    		    dct proc get
X    		    dup isarray? {/exec cvx} if
X    		    tracedict /traceout cvx
X    		] cvx
X    		
X    		% Store new wrapped code in place of old.
X    		dct proc 3 -1 roll put
X    	    } if
X    	} if
X        end
X    } def
X    
X    % Remove trace from one method.
X    %
X    %    /procname untrace
X    %    /procname /untrace object send
X    %
X    /untrace { % procname => -
X        %
X        % The given proc is located in the current dictionary stack, and
X        % if it has the trace wrapper code, the wrapper code is removed
X        % and the trace dict is removed from the tracelist array.
X        %
X        1 dict begin
X    	/proc exch def
X    
X    	proc load      	    	    	% proc
X    	dup istraced? {
X    	    dup 0 get exch    	    	% tracedict proc
X    	    2 get 			% tracedict oldproc
X    	    proc exch store		% tracedict
X    
X    	    % Remove from tracelist.
X    	    tracelist exch arrayindex {
X    		tracelist exch arraydelete
X    		/tracelist exch store
X    	    } if
X    	} {pop} ifelse
X        end
X    } def
X    
X    % Return true if the given proc has the trace wrapper around it.
X    %
X    /istraced? { % proc => -
X	dup isarray? {
X	    dup length 5 ge {
X		1 get /tracein eq
X	    } {pop false} ifelse
X	} {pop false} ifelse
X    } def
X    
X    % Remove all traces that have been set.
X    %
X    /untraceall { % - => -
X	% Note: we loop through a copy of the tracelist array because
X	% untrace alters the original array.
X	tracelist dup length array copy {
X	    begin   	    	    	    % tracedict	
X		fndict begin	    	    % dict containing routine
X		    fnname untrace
X		end
X	    end
X	    pause
X	} forall
X	/trace_level 0 store
X    } def
X    
X    % Trace all methods in a class. 
X    % 
X    %    /traceclass class send
X    %
X    /traceclass { % - => -
X	% Note: check for class Object is a kludge because some methods
X	% in that class are used by the trace utilities and infinite
X	% loops can occur if they are traced.
X	Object currentdict ne {
X	    currentdict {
X		xcheck {trace} {pop} ifelse
X	    } forall
X	} if
X    } def
X    
X    % Untrace all methods in a class.
X    %
X    %    /untraceclass class send
X    %
X    /untraceclass { % - => -
X	currentdict {
X	    xcheck {untrace} {pop} ifelse
X	} forall
X    } def
X    
X    % Trace a method in a class and all its superclasses.
X    %
X    %    /method /tracesupers class send
X    %    /method /tracesupers object send
X    %
X    /tracesupers { % method => -
X	/superclasses self send self arrayappend {
X	    2 copy exch known {
X		2 copy /trace exch send
X	    } if
X	    pop
X	} forall
X	pop
X    } def
X    
X    % Untrace a method in a class and all its superclasses.
X    %
X    %    /method /untracesupers class send
X    %    /method /untracesupers object send
X    %
X    /untracesupers { % method => -
X	/superclasses self send self arrayappend {
X	    2 copy exch known {
X		2 copy /untrace exch send
X	    } if
X	    pop
X	} forall
X	pop
X    } def
X    
X    % Trace a class and all its subclasses.
X    %
X    %    /tracesubclasses class send
X    %
X    /tracesubclasses { % - => -
X	{(Tracing %\n) [/classname self send] printf} traceoutput
X	/traceclass self send
X	/subclasses self send {
X	    pause
X	    /tracesubclasses exch send
X	} forall
X    } def
X    
X    % Trace a class and all its superclasses.
X    %
X    %    /tracesuperclasses class|instance send
X    %
X    /tracesuperclasses { % - => -
X	{(Tracing %\n) [/classname self send] printf} traceoutput
X	/traceclass self send
X	/superclasses self send {
X	    pause
X	    /traceclass exch send
X	} forall
X    } def
X    
X    
X% Functions for Displaying Traces and Statistics:
X    
X    % List all traced functions.
X    %
X    /listtraces { % - => -
X	{
X	    tracelist {
X		begin
X		    (%: /%\n)
X		    [dictname fnname] printf
X		end
X	    } forall
X	} traceoutput
X    } def
X    
X    % Display the stats collected for a particular proc.
X    %
X    /showtracestats { % procname => -
X        load
X        dup istraced? {
X    	0 get begin
X    	    {
X    		(% /%:\n) [dictname fnname] printf
X    		(  Calls:        %\n) [callcount] printf
X    		(  Time:         %\n) [totaltime] printf
X    		(  Stack delta:  ) printf stackdelta ==
X    	    } traceoutput
X    	end
X        } {pop} ifelse
X    } def
X    
X    % Show a sorted list of all traced functions with statistics.
X    % Argument is the name of the field to sort by: /callcount or /totaltime.
X    %
X    %    /callcount: sort by how often function was called
X    %    /totaltime: sort by total time spent in function
X    %
X    /listtracestats { % sortby => -
X        1 dict begin
X    	/attribute exch def
X    
X    	% Build array of all functions that were called at least once.
X    	[tracelist {dup /stackdelta get null eq {pop} if} forall]
X    
X    	% Sort the array.
X    	{
X    	    attribute get exch
X    	    attribute get exch
X    	    lt
X    	} quicksort 	    	    	% array
X    	
X    	{
X    	    {
X    		begin
X    		    (%  %: /% /callcount=% /totaltime=% stack=%\n)
X    		    [attribute cvx exec
X    			dictname fnname callcount totaltime stackdelta]
X    		    printf
X    		end
X    	    } forall
X    	} traceoutput
X        end
X    } def
X    
X    % Zero the function call counts for all traced routines.
X    %
X    /cleartracestats { % - => -
X	tracelist {
X	    dup /callcount 0 put
X	    /totaltime 0 put
X	} forall
X    } def
X    
X    
X% Functions Called on Entry and Exit of Traced Functions:
X    
X    % Note: Functions called within traces are bound immediately so you can
X    % trace any operator inside them (e.g. send, store) without worrying about
X    % infinite recursion. It is assumed that these operators are not
X    % traced when these functions are defined.
X    
X    /trace_level 0 def
X    /trace_indent 1 def
X    /trace_stackcounts 100 array def
X    /trace_entertimes 100 array def
X    
X    % Function called on entry to traced function.
X    %
X    /tracein { % tracedict => -
X        pop
X    } def
X    
X    % Function called on exit from traced function.
X    %
X    /traceout { % tracedict => -
X        pop
X    } def
X    
X    % Change trace in and trace out functions. The arguments are either 
X    % executable arrays or the names of functions.
X    %
X    /settracefunctions { % tracein traceout => -
X        dup xcheck not {load} if
X        /traceout exch store
X        dup xcheck not {load} if
X        /tracein exch store
X    } def
X    
X    % The next two functions display messages of the form
X    %
X    %     In/Out <class> /<method> [<object>]: <stack>
X    %
X    % Where <class> is the dictionary containing the traced function,
X    %      <method> is the name of the traced function,
X    %      <object> is the printable name of the currentdict
X    %       <stack> is the current contents of the operand stack.
X    %
X    % The messages are prefixed by blank spaces so the nesting structure
X    % is apparent visually.  Each Out message is always aligned directly
X    % below its corresponding In message.
X    
X    % Function called on entry into a traced function.
X    %
X    /defaulttracein { % tracedict => -
X        count trace_stackcounts trace_level 3 -1 roll put
X    
X        {
X    	begin
X    	    trace_level trace_indent mul { ( ) print } repeat
X    	    (In  % /% [%]:  )
X    	    [dictname fnname
X    		currentdict end
X    		currentdict isobject?
X    		    {currentdict objectstring} {nullstring} ifelse
X    		exch begin
X    	    ] printf
X    	    /callcount callcount 1 add store
X    	end
X    	showstack
X        } traceoutput
X    
X        trace_entertimes trace_level
X        /trace_level trace_level 1 add store
X        currenttime put
X    } bind def
X    
X    % Function called on exit from a traced function.
X    %
X    /defaulttraceout { % tracedict => -
X        currenttime
X        /trace_level trace_level 1 sub store
X        trace_entertimes trace_level get sub exch   	    % time tracedict
X    
X        begin				      	    % time
X    	count trace_stackcounts trace_level get sub	    % time count
X    	
X    	% Update the stack delta.
X    	dup stackdelta eq {pop}{
X    	    stackdelta type {
X    		/integertype {[exch stackdelta]}
X    		/arraytype {
X    		    stackdelta 1 index arraycontains? {
X    			pop stackdelta
X    		    }{
X    			[exch] stackdelta append
X    		    } ifelse
X    		}
X    	    } case
X    	    /stackdelta exch store
X    	} ifelse
X    	
X    	totaltime add
X    	/totaltime exch store
X    	{
X    	    trace_level trace_indent mul { ( ) print } repeat
X    	    (Out % /% [%]:  )
X    	    [dictname fnname
X    		currentdict end
X    		currentdict isobject?
X        		    {currentdict objectstring} {nullstring} ifelse
X    		exch begin
X    	    ] printf
X    	    showstack
X    	} traceoutput
X        end
X    } bind def
X    
X    % A tracein function that collects stats without printing anything.
X    %
X    /fasttracein { % tracedict => -
X        begin
X    	/callcount callcount 1 add store
X    	/stackdelta 99 store
X        end
X    
X        trace_entertimes trace_level
X        /trace_level trace_level 1 add store
X        currenttime put
X    } bind def
X    
X    % A traceout function that collects stats without printing anything.
X    %
X    /fasttraceout { % tracedict => -
X        currenttime
X        /trace_level trace_level 1 sub store
X        trace_entertimes trace_level get sub exch   	 % time tracedict
X    
X        begin
X    	totaltime add
X    	/totaltime exch store
X        end
X    } bind def
X
X    % Initialize the tracein and traceout functions to the defaults.
X    %
X    /defaulttracein /defaulttraceout settracefunctions
X
X% Functions for Printing Objects:
X    
X    % Return a printable string for an object.
X    %
X    % type = nametype:
X    %   Executable: 	    name
X    %   Non-executable:     /name
X    % type = stringtype:    (string)
X    % Objects:
X    %   Class: 	    	    ClassName
X    %   Named instance:	    "name"
X    %   Other instances:    .ClassName
X    % Special dicts:
X    %   systemdict:  	    systemdict
X    %	userdict:	    userdict
X    %
X    /objectstring { % object => string
X	dup type {
X	    /nametype {dup xcheck {(%)}{(/%)} ifelse [3 -1 roll] sprintf}
X	    /stringtype {((%)) [3 -1 roll] sprintf}
X	    /Default {
X		dup isobject? {
X		    dup isclass? {
======== END OF cyber.shar.splitag ========