[fa.info-mac] source for explor.c

info-mac@uw-beaver (01/18/85)

From: John Mark Agosta <INFO-MAC-REQUEST@SUMEX-AIM.ARPA>

16-Jan-85 22:55:58-PST,19154;000000000001
Return-Path: <winkler@harvard.ARPA>
Received: from harvard.ARPA by SUMEX-AIM.ARPA with TCP; Wed 16 Jan 85 22:54:31-PST
Date: Thu, 17 Jan 85 01:57:32 EST
From: winkler@harvard.ARPA (Dan Winkler)
To: info-mac@sumex
Subject: Explorer DA (in C)

Here is the explorer desk accessory that comes with the Manx Aztec C
system.  It is written by superprogrammer Jim Goodnow (who reportedly
produces bug-free C code faster than lex or yacc).  Explorer is public
domain (sort of -- you can give it away but not sell it).  It is the
first desk accessory we've heard of written entirely in C (almost --
there are a few lines of assembly at the beginning).  

Explorer let's you browse through memory while an application is
running looking at memory as hex or as strings.  The box at the top of
the explorer window lets you specify a start address for the display
(this is more convenient than scrolling through the half megabyte
address space on a Fat Mac).

First suggested use: cheating at Zork.  If you look through Zork with
fedit you'll find that Zork encrypts its strings on the disk.  But who
knows what you'll find when you look through RAM?  It must decrypt them
sometime before displaying them.  (If you look through the CP/M version
of WordStar with something like fedit, you'll find the message "Nosey,
aren't you?")

Manx says they are working on a source level C debugger.  They were
going to devote their efforts to a resource editor instead, but they
decided they liked Apple's, licensed it, and stopped working on their
own.  I've been using Aztec C on our Hyperdrive Mac.  There are some
problems but overall I think it's still the best Mac development system
available (except for cost which is where Sumacc wins) and has the
fastest time from edit to run (compiles about as fast as Sumacc on a
normally loaded Vax and has no downloading; also supports overlays and
stdio).  Text scrolling is much faster than it was in the beta release.
I used the beta release to compile the Mac version of xlisp that is
floating around.  Maybe it's time to find the latest xlisp sources and
use this lates Manx compiler to compiler them.

So here is explor.c (the Manx C source of the explorer desk accessory)
and explor.hex (the binhex encoded version of the compiled explor 
desk accessory).  

Dan. (winkler@harvard)

::::::::::::::
explor.c
::::::::::::::
/*
 *              Explorer - Version 1.0
 *
 *          A Desk Accessory for the Macintosh
 *
 *  Copyright (C) 1984 by Manx Software Systems, Inc.
 *      May be used, but not sold without permission.
 *
 *  written by Jim Goodnow II, December 7-8, 1984
 */

#asm
main
    dc.w    $2400           ;ctl-enable, need time
    dc.w    5*60            ;update every 5 seconds
    dc.w    $000a           ;detect mouse and key down events
    dc.w    -777            ;menu ID number (must be negative)

    dc.w    open_-main      ;open routine
    dc.w    nop_-main       ;prime routine
    dc.w    control_-main   ;control routine
    dc.w    nop_-main       ;status routine
    dc.w    close_-main     ;close routine

title_
    dc.b    8
    dc.b    "Explorer"
    ds      0               ;for alignment

    public  _Uend_,_Dorg_,_Cend_

save_
    lea     main+(_Uend_-_Dorg_)+(_Cend_-main),a4       ;set up globals
    move.l  a0,Pbp_                                     ;save pb pointer
    move.l  a1,Dp_                                      ;save DCE pointer
    rts

restore_
    move.l  Pbp_,a0
    rts
#endasm

#define _DRIVER
#define SMALL_MEM
#include    <quickdraw.h>
#include    <toolutil.h>
#include    <window.h>
#include    <memory.h>
#include    <osutil.h>
#include    <menu.h>
#include    <control.h>
#undef SMALL_MEM
#include    <event.h>
#include    <textedit.h>
#include    <pb.h>
#include    <desk.h>

#define TRUE    0x100
#define FALSE   0x000

#define NLINES  16                  /* number of lines in window    */
#define MENUID  -777                /* must be negative             */
#define MEMTOP  (*(long *)0x108)    /* top of memory 128 or 512K    */
#define SP      (*(struct storage **)Dp->dCtlStorage)

DCEPtr Dp;
ParmBlkPtr Pbp;

Rect Wind_rect = {100, 150, 275, 360};
Rect Scrl_rect = {-1, 194, 176, 211};
Rect Cont_rect = {0, 0, 176, 194};
Rect Full_rect = {0, 0, 176, 211};
Rect Edit_rect = {-1, 44, 12, 90};

Cursor Ibeam = {
0x3838, 0x3C78, 0x0280, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0280, 0x3C78, 0x3838,
0x3838, 0x3C78, 0x0280, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0280, 0x3C78, 0x3838,
0x0008, 0x0008 };

struct storage {
    MenuHandle      menu;
    ControlHandle   vscrl;
    char *          where;
    short           autoupdate;
    short           size;
    short           incr;
    TEHandle        hte;
};

open()
{
    register WindowPtr wp;
    register struct DCE *dp;
    register struct storage *sp;
    extern char title[];
    struct windowpeek {
        GrafPort    port;
        int         windowKind;
    };

    save();
    dp = Dp;
    if (dp->dCtlWindow == 0) {
        HLock(dp->dCtlStorage = NewHandle((long)sizeof(struct storage)));
        sp = SP;
        dp->dCtlWindow =
        wp = NewWindow(0L, &Wind_rect, title, TRUE, noGrowDocProc, -1L, TRUE, 0L);
        ((struct windowpeek *)wp)->windowKind = dp->dCtlRefNum;
        sp->vscrl = NewControl(wp, &Scrl_rect, "", FALSE, 0, 0, 0x7fff, scrollBarProc, 0L);
        sp->hte = 0;
        sp->where = 0;
        sp->size = 0;
        sp->autoupdate = 0;
        sp->incr = MEMTOP / 0x8000L;
        sp->menu = NewMenu(MENUID, "\PExplorer");
        AppendMenu(sp->menu,
            "\PAuto-Refresh;Hand-Refresh;(-;Hexadecimal!\x12;Ascii");
        HUnlock(dp->dCtlStorage);
    }
    restore();
    return(0);
}

close()
{
    register struct DCE *dp;

    save();
    dp = Dp;
    TEDispose(SP->hte);
    DisposeWindow(dp->dCtlWindow);
    dp->dCtlWindow = 0;
    DeleteMenu(MENUID);
    DrawMenuBar();
    DisposHandle(SP->menu);
    DisposHandle(dp->dCtlStorage);
    restore();
    return(0);
}

nop()
{
    return(0);
}

control()
{
    register struct storage *sp;
    Point pt;
    register int item;

    save();
    HLock(Dp->dCtlStorage);
    sp = SP;
    SetPort(Dp->dCtlWindow);
    switch(Pbp->u.cp.csCode) {
    case accEvent:
        doevent(sp, *(EventRecord **)&Pbp->u.cp.csParam);
        break;
    case accRun:
        if (sp->autoupdate)
            draw_wind();
        break;
    case accCursor:
        if (sp->hte)
            TEIdle(sp->hte);
        GetMouse(&pt);
        if (PtInRect(pass(pt), &Edit_rect) & TRUE)
            SetCursor(&Ibeam);
        else
            InitCursor();
        break;
    case accMenu:
        switch(item = ((int *)&Pbp->u.cp.csParam)[1]) {
        case 1:                             /* auto refresh     */
            sp->autoupdate ^= TRUE;
            CheckItem(sp->menu, 1, sp->autoupdate);
            break;
        case 2:                             /* manual refresh   */
            draw_wind();
            break;
        case 4:
        case 5:
            sp->size = item==4?8:16;
            CheckItem(sp->menu, 4, item==4?TRUE:FALSE);
            CheckItem(sp->menu, 5, item==5?TRUE:FALSE);
            EraseRect(&Cont_rect);
            draw_wind();
            break;
        }
        break;
    case accUndo:
        break;
    case accCut:
        TECut(sp->hte);
        break;
    case accCopy:
        TECopy(sp->hte);
        break;
    case accPaste:
        TEPaste(sp->hte);
        break;
    case accClear:
        TEDelete(sp->hte);
        break;
    }
    HUnlock(Dp->dCtlStorage);
    restore();
    return(0);
}

doevent(sp, ep)
register struct storage *sp;
register EventRecord *ep;
{
    register int c;
    register long l;
    ControlHandle chdl;
    pascal void scrlup(), scrldn();
    long xtol();

    switch(ep->what) {
    case keyDown:
        if ((ep->modifiers & (cmdKey | optionKey)) == 0) {
            c = (char)ep->message;
            if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || c == 8) {
                TEKey(c, sp->hte);
                break;
            }
            if ((c == '\r' || c == 3) && (l = xtol(sp->hte)) != -1) {
                sp->where = l;
                TESetSelect(0L, 1000L, sp->hte);
                draw_wind();
                break;
            }
        }
        SysBeep(2);
        break;
    case mouseDown:
        GlobalToLocal(&ep->where);
        if (PtInRect(pass(ep->where), &Cont_rect)&TRUE) {
            if (PtInRect(pass(ep->where), &Edit_rect) & TRUE)
                TEClick(pass(ep->where), ep->modifiers&shiftKey?TRUE:FALSE, sp->hte);
        }
        else {
            c = FindControl(pass(ep->where), Dp->dCtlWindow, &chdl);
            switch(c) {
            case inUpButton:
                TrackControl(chdl, pass(ep->where), scrlup);
                break;
            case inDownButton:
                TrackControl(chdl, pass(ep->where), scrldn);
                break;
            case inPageUp:
                scrlpage(chdl, c, -NLINES);
                break;
            case inPageDown:
                scrlpage(chdl, c, NLINES);
                break;
            case inThumb:
                TrackControl(chdl, pass(ep->where), 0L);
                sp->where = (char *)((long)sp->incr * GetCtlValue(chdl));
                draw_wind();
                break;
            }
        }
        break;
    case activateEvt:
        if (ep->modifiers&1) {
            if (sp->size == 0) {
                signature();
                sp->size = 8;
            }
            InsertMenu(sp->menu, 0);
            ShowControl(sp->vscrl);
            TEActivate(sp->hte);
        }
        else {
            DeleteMenu(MENUID);
            HideControl(sp->vscrl);
            TEDeactivate(sp->hte);
        }
        DrawMenuBar();
        break;
    case updateEvt:
        BeginUpdate(ep->message);
        draw_wind();
        DrawControls(ep->message);
        EndUpdate(ep->message);
        break;
    }
}

signature()
{
    register WindowPtr wp;
    register long tick;
    Rect r;

    wp = Dp->dCtlWindow;
    wp->txFont = 0;
    wp->txSize = 0;
    wp->txMode = srcCopy;
    MoveTo(90, 20);
    DrawString("\Pby");
    MoveTo(50,40);
    DrawString("\PJim Goodnow II");
    MoveTo(55, 60);
    DrawString("\Pusing Aztec C");
    MoveTo(10, 90);
    DrawString("\PManx ");
    Move(0, 20);
    DrawString("\PSoftware ");
    Move(0, 20);
    DrawString("\PSystems");
    Move(0, 20);
    DrawString("\PInc.");
    for (tick=TickCount()+100;TickCount() < tick;)
        ;
    EraseRect(&wp->portRect);
    wp->txFont = 4;
    wp->txSize = 9;
    r = Edit_rect;
    InsetRect(&r, 4, 1);
    SP->hte = TENew(&r, &r);
}

draw_wind()
{
    register unsigned char *cp, *wp;
    register unsigned long l;
    register int k, i, j;
    struct storage *sp;
    char buf[40];
    static char hex[] = "0123456789abcdef";

    sp = SP;
    l = sp->where;
    if (l < 0)
        l = 0;
    if (l > MEMTOP - sp->size*NLINES)
        l = MEMTOP - sp->size * NLINES;
    wp = sp->where = l;
    SetCtlValue(sp->vscrl, (int)(l/sp->incr));
    RectRgn(Dp->dCtlWindow->clipRgn, &Cont_rect);
    MoveTo(4, 9);
    DrawString("\PStart: ");
    TEUpdate(&Edit_rect, sp->hte);
    FrameRect(&Edit_rect);
    for (i=0;i<NLINES;i++) {
        k = i * sp->size;
        MoveTo(4, i*10+24);
        cp = buf;
        l = wp + k;
        for (j=5;j>=0;l>>=4)
            cp[j--] = hex[l%16];
        cp += 6;
        *cp++ = ':';
        if (sp->size == 8) {
            for (j=0;j<8;j++) {
                *cp++ = ' ';
                *cp++ = hex[wp[k+j]/16];
                *cp++ = hex[wp[k+j]%16];
            }
        }
        *cp = 0;
        DrawString(ctop(buf));
        if (sp->size == 16) {
            cp = buf;
            *cp++ = 17;
            *cp++ = ' ';
            for (j=0;j<16;j++) {
                if (wp[k+j] > 0x1f && wp[k+j] < 0x80)
                    *cp++ = wp[k+j];
                else
                    *cp++ = '.';
            }
            DrawString(buf);
        }
    }
    RectRgn(Dp->dCtlWindow->clipRgn, &Full_rect);
}

pascal void
scrlup(chdl, code)
ControlHandle chdl;
int code;
{
    scroll(chdl, code, inUpButton);
}

pascal void
scrldn(chdl, code)
ControlHandle chdl;
int code;
{
    scroll(chdl, code, inDownButton);
}

scroll(chdl, code, where)
ControlHandle chdl;
{
    register struct storage *sp;

#asm
    move.l  a4,-(sp)
    lea     main+(_Uend_-_Dorg_)+(_Cend_-main),a4       ;set up globals
#endasm
    if (code == where) {
        sp = SP;
        if (where == inUpButton)
            sp->where -= sp->size;
        else
            sp->where += sp->size;
        draw_wind();
    }
    ;
#asm
    move.l  (sp)+,a4
#endasm
}

scrlpage(chdl, code, amount)
ControlHandle chdl;
{
    Point pt;
    struct storage *sp;

    sp = SP;
    do {
        GetMouse(&pt);
        if (TestControl(chdl, pass(pt)) == code) {
            sp->where += sp->size*amount;
            draw_wind();
        }
    } while (StillDown()&TRUE);
}

long
xtol(hte)
TEHandle hte;
{
    register char *cp;
    register long i = 0, l = 0;
    register int c, n;

    n = (*hte)->length;
    cp = *(*hte)->hText;
    while (n--) {
        c = *cp++;
        if (c >= 'a' && c <= 'f')
            c -= 'a' - 10;
        else if (c >= '0' && c <= '9')
            c -= '0';
        else {
            TESetSelect(i, i+1, hte);
            return(-1);
        }
        l = l * 16 + c;
        i++;
    }
    return(l);
}

::::::::::::::
explor.hex
::::::::::::::
(This file must be converted with BinHex.Hex)
#DRVRManx$0000
***COMPRESSED
***RESOURCE FORK
(    0    T(   ,"    #P                     
(                                           
(                                           
(                                           
(                                           
(                                           
(                                           
(                                           
(   # 0D  $L  K\]P P 8X!F &. 3((17AP;&]R97( 
($GZ"^8I2/_V*4G_^DYU(&S_]DYU3E8  $CG#!!AXB@L
(/_Z)$1*J@ >9@  WB1$+PHO/    !9.N@ID6$\D7R5 
(  4+P!.N@F46$\D;/_Z(FH %"H1)$0O"D*G0J=(;/[N
($AZ_Y0_/ $ /SP !"\\_____S\\ 0!"IZD3(!\F0"1?
("5  !XD1#=J !@ ;"1%+PI"IR\+2&S^]DAL_UI"9T)G
($)G/SQ__S\\ !!"IZE4(!\D7R5   0D14*J !(D14*J
(  ()$5":@ .)$5":@ ,)$4F. $(= _DJS5# ! D12\*
($*G/SS\]TAL_UNI,2 ?)%\D@"1%+Q)(;/]EJ3,D1"\J
(  43KH(X%A/3KK_!'  3-\(,$Y>3G5.5@  2.< $$ZZ
(/[@)FS_^B1L__HB:@ 4)%$O*@ 2J<TO*P >J11"JP >
(#\\_/>I-JDW)&S_^B)J !0D42\23KH)/%A/+RL %$ZZ
( DR6$].NOZH< !,WP@ 3EY.=4Y6  !P $Y>3G5.5O_\
($CG"!!.NOYZ)&S_^B\J !1.N@A(6$\D;/_Z(FH %"91
("1L__HO*@ >J',D;/_V,"H &F   2(D;/_V+RH '"\+
($ZZ 4103V   2)*:P ,9P1.N@1X8  !%$JK !)G!B\K
(  2J=I(;O_\J7)"9R\N__Q(;/\.J*TP'\!\ 0!G"$AL
(/\6J%%@ JA08   X"1L__8P*@ >. !@=@IK 0  #"\3
(#\\  $_*P ,J45@<DZZ!!Q@;+A\  1F"#=\  @ #F &
(#=\ !  #B\3/SP !+A\  1F!C8\ 0!@ G8 /P.I12\3
(#\\  6X?  %9@8V/ $ 8 )V #\#J45(;/[^J*-.N@/,
(& <  +_?/^0  +_EO^6L'P !F0*XT P.P#J3OL  &!*
(&!(+RL $JG68$ O*P 2J=5@."\K !*IVV P+RL $JG7
(& H_L[^XO[P_R3_N  "_[K_PO_*_]*0? ! L'P "F0*
(.- ,#L WD[[   D;/_Z+RH %$ZZ!O!83TZZ_11P $S?
( @03EY.=4Y6__Q(YPX0)FX ""@N  PD1# 28  "'"1$
(#8J  [&? D 9FXD1"8J  )(@SH#NGP ,&T&NGP .6\2
(+I\ &%M!KI\ &9O!KI\  AF##\%+RL $JG<8  ![+I\
(  -9P:Z?  #9BXO*P 23KH%Z%A/+ "PO/____]G&B=&
(  (0J<O/    ^@O*P 2J=%.N@*X8  !LC\\  *IR&  
( &H)@36O     HO ZAQ0F<D1"\J  I(;/[^J*TP'\!\
( $ 9SQ"9R1$+RH "DAL_PZHK3 ?P'P! &<B)$0O*@ *
("1$-BH #L9\ @!G!C8\ 0!@ G8 /P,O*P 2J=1@  #"
($)G)$0O*@ *)&S_^B\J !Y(;O_\J6PP'SH , 5@  "(
($)G+R[__"1$+RH "DAZ!$2I:# ?8   BD)G+R[__"1$
("\J  I(>@10J6@P'V!R/SS_\#\%+R[__$ZZ!*Y03V!@
(#\\ ! _!2\N__Q.N@2<4$]@3D)G+R[__"1$+RH "D*G
(*EH,!\V*P 02,,O T)G+R[__*E@,!](P"8?QL G0P (
($ZZ :A@&I!\ !1G /]T4T!GAE- 9YA30&>FD'P :F>R
(&   (8D1#8J  [&?  !9R)*:P .9@AA>#=\  @ #B\3
($)GJ34O*P $J5<O*P 2J=A@$C\\_/>I-B\K  2I6"\K
(  2J=FI-V! )$0O*@ "J2).N@$X)$0O*@ "J6DD1"\J
(  "J2-@(@ "_EP  OW8  (  O_"  +_?K!\  ED"N- 
(# [ .1.^P  3-\(<$Y>3G5.5O_X2.<($"1L__HF:@ >
($)K $1":P!*0FL 2#\\ %H_/  4J)-(;/^7J(0_/  R
(#\\ "BHDTAL_YNHA#\\ #<_/  \J)-(;/^KJ(0_/  *
(#\\ %JHDTAL_[JHA$)G/SP %*B42&S_P:B$0F<_/  4
(*B42&S_S*B$0F<_/  4J)1(;/_5J(1"IZEU(!\H -B\
(    &1"IZEU(!^PA&P"8/0F"]:\    $"\#J*,W?  $
( !$-WP "0!*1>[_^$/L_PXDV2392&[_^#\\  0_/  !
(*BI)&S_^B)J !0D42\*0J=(;O_X2&[_^*G2(!\D7R5 
(  23-\($$Y>3G5.5O_22.</$"1L__HB:@ 4+5'_^B1N
(/_Z*BH "+J\     &0">@ D;O_Z-BH #NE#2,,D. $(
()2#NH)C%"1N__HV*@ .Z4-(PR0X 0B4@RH")&[_^B5%
(  (* 4D;O_Z+RH !" %)&[_^C(J !!(P4ZZ WH_ *EC
("1L__HB:@ >+RD '$AL_OZHWS\\  0_/  )J)-(;/_L
(*B$2&S_#B1N__HO*@ 2J=-(;/\.J*%^ +Y\ !!L  %:
("1N__H\*@ .S,<_/  $-@?&_  *UGP &#\#J)-%[O_2
("9*2,8J!MJ$/7P !?_^#&X  /_^;1XV+O_^4V[__B0%
(,2\    #T7L_]L7LB@ , #HC6#:7(LD2U*+%+P .B1N
(/_Z#&H "  .9EA";O_^#&X "/_^;$PD2U*+%+P ("1+
(%*+-@;6;O_^(D04,3  Q'P _^A*0^S_VQ2Q(  D2U*+
(#8&UF[__B)$%#$P ,1\ /_$?  /0^S_VQ2Q( !2;O_^
(&"L0A-(;O_23KH"[EA/+P"HA"1N__H,:@ 0  YF=$7N
(/_2)DHD2U*+%+P $21+4HL4O  @0F[__@QN !#__FQ,
(#8&UF[__B1$%#(P ,1\ /^T?  ?8R@V!M9N__XD1!0R
(#  Q'P _[1\ (!D$B1+4HLV!M9N__XB1!2Q, !@""1+
(%*+%+P +E)N__Y@K$AN_]*HA%)'8 #^HB1L__HB:@ >
("\I !Q(;/\&J-],WPCP3EY.=4Y6  !(YQ @/SP %#\N
(  (+RX "F$R4$],WP0(3EX@7UQ/3M!.5@  2.<0(#\\
(  5/RX ""\N  IA#E!/3-\$"$Y>(%]<3T[03E8  $CG
(  0+PQ)^@,B-BX #+9N  YF+"1L__HB:@ 4)E$,;@ 4
(  .9@PV*P .2,.7JP (8 HV*P .2,/7JP (3KK]3BA?
($S?" !.7DYU3E;_^"1L__HB:@ 4+5'_^$AN__RI<D)G
("\N  @O+O_\J68P'[!N  QF%B1N__@V*@ .QNX #DC#
(->J  A.NOT$0F>I<S ?P'P! &;$3EY.=4Y6  !(YP\0
('@ >@ D;@ ((E(^*0 \)&X "")2)&D /B92-@=31TI#
(&=4)$M2BQ822(,\ [Q\ &%M#+Q\ &9N!IQ\ %=@*KQ\
(  P;0R\?  Y;@:<?  P8!@O!"8$4H,O R\N  BIT7#_
($S?"/!.7DYU2,8F!>F#*@;:@U*$8*0@!6#F(&\ !* I
($[Z ,X@;P $H"I.^@#$+P1"A$J :@1$@%)$2H%J!D2!
( I$  %A+DI$9P)$@"@?3G4O!$*$2H!J!$2 4D1*@6H&
($2!"D0  6$,( %.^O_:800@ 4YU2.<P $A!2D%F*$A!
($)#@,%H#C0 0D!(0(#!-@ P H#!(@!(0# #2$!"04A!
($S?  Q.=4A!0H)V'^. XY*4@6L04H!1R__T8 [C@..2
(-2!:O!1R__VU($B DS?  Q.=2!O  2@(T[Z !8@+P $
(*$B3OH  D/M__XR@" (3G5#[?_^,H!.=2!O  0B2! \
(   $A 0P! !9OA32)')( @2@" )3G4 9 "6 1,!:/__
( #" +  TP      L #"      "P -/__P L  P 6C@X
(#QX H !  $  0 !  $  0 !  $  0 !  * /'@X.#@X
(#QX H !  $  0 !  $  0 !  $  0 !  * /'@X.  (
(  (  A%>'!L;W)E<@ P075T;RU2969R97-H.TAA;F0M
(%)E9G)E<V@[*"T[2&5X861E8VEM86PA$CM!<V-I:0 "
(&)Y  Y*:6T@1V]O9&YO=R!)20 -=7-I;F<@07IT96,@
($, !4UA;G@@  E3;V9T=V%R92  !U-Y<W1E;7, !$EN
(&,N # Q,C,T-38W.#EA8F-D968 !U-T87)T.B      
(                                           
(  < #(  $125E(    * !\  "          "0!%>'!L
!&]R97(
***END OF DATA
***CRC:40E3
16-Jan-85 22:55:58-PST,19154;000000000001
Return-Path: <winkler@harvard.ARPA>
Received: from harvard.ARPA by SUMEX-AIM.ARPA with TCP; Wed 16 Jan 85 22:54:31-PST
Date: Thu, 17 Jan 85 01:57:32 EST
From: winkler@harvard.ARPA (Dan Winkler)
To: info-mac@sumex
Subject: Explorer DA (in C)

Here is the explorer desk accessory that comes with the Manx Aztec C
system.  It is written by superprogrammer Jim Goodnow (who reportedly
produces bug-free C code faster than lex or yacc).  Explorer is public
domain (sort of -- you can give it away but not sell it).  It is the
first desk accessory we've heard of written entirely in C (almost --
there are a few lines of assembly at the beginning).  

Explorer let's you browse through memory while an application is
running looking at memory as hex or as strings.  The box at the top of
the explorer window lets you specify a start address for the display
(this is more convenient than scrolling through the half megabyte
address space on a Fat Mac).

First suggested use: cheating at Zork.  If you look through Zork with
fedit you'll find that Zork encrypts its strings on the disk.  But who
knows what you'll find when you look through RAM?  It must decrypt them
sometime before displaying them.  (If you look through the CP/M version
of WordStar with something like fedit, you'll find the message "Nosey,
aren't you?")

Manx says they are working on a source level C debugger.  They were
going to devote their efforts to a resource editor instead, but they
decided they liked Apple's, licensed it, and stopped working on their
own.  I've been using Aztec C on our Hyperdrive Mac.  There are some
problems but overall I think it's still the best Mac development system
available (except for cost which is where Sumacc wins) and has the
fastest time from edit to run (compiles about as fast as Sumacc on a
normally loaded Vax and has no downloading; also supports overlays and
stdio).  Text scrolling is much faster than it was in the beta release.
I used the beta release to compile the Mac version of xlisp that is
floating around.  Maybe it's time to find the latest xlisp sources and
use this lates Manx compiler to compiler them.

So here is explor.c (the Manx C source of the explorer desk accessory)
and explor.hex (the binhex encoded version of the compiled explor 
desk accessory).  

Dan. (winkler@harvard)

::::::::::::::
explor.c
::::::::::::::
/*
 *              Explorer - Version 1.0
 *
 *          A Desk Accessory for the Macintosh
 *
 *  Copyright (C) 1984 by Manx Software Systems, Inc.
 *      May be used, but not sold without permission.
 *
 *  written by Jim Goodnow II, December 7-8, 1984
 */

#asm
main
    dc.w    $2400           ;ctl-enable, need time
    dc.w    5*60            ;update every 5 seconds
    dc.w    $000a           ;detect mouse and key down events
    dc.w    -777            ;menu ID number (must be negative)

    dc.w    open_-main      ;open routine
    dc.w    nop_-main       ;prime routine
    dc.w    control_-main   ;control routine
    dc.w    nop_-main       ;status routine
    dc.w    close_-main     ;close routine

title_
    dc.b    8
    dc.b    "Explorer"
    ds      0               ;for alignment

    public  _Uend_,_Dorg_,_Cend_

save_
    lea     main+(_Uend_-_Dorg_)+(_Cend_-main),a4       ;set up globals
    move.l  a0,Pbp_                                     ;save pb pointer
    move.l  a1,Dp_                                      ;save DCE pointer
    rts

restore_
    move.l  Pbp_,a0
    rts
#endasm

#define _DRIVER
#define SMALL_MEM
#include    <quickdraw.h>
#include    <toolutil.h>
#include    <window.h>
#include    <memory.h>
#include    <osutil.h>
#include    <menu.h>
#include    <control.h>
#undef SMALL_MEM
#include    <event.h>
#include    <textedit.h>
#include    <pb.h>
#include    <desk.h>

#define TRUE    0x100
#define FALSE   0x000

#define NLINES  16                  /* number of lines in window    */
#define MENUID  -777                /* must be negative             */
#define MEMTOP  (*(long *)0x108)    /* top of memory 128 or 512K    */
#define SP      (*(struct storage **)Dp->dCtlStorage)

DCEPtr Dp;
ParmBlkPtr Pbp;

Rect Wind_rect = {100, 150, 275, 360};
Rect Scrl_rect = {-1, 194, 176, 211};
Rect Cont_rect = {0, 0, 176, 194};
Rect Full_rect = {0, 0, 176, 211};
Rect Edit_rect = {-1, 44, 12, 90};

Cursor Ibeam = {
0x3838, 0x3C78, 0x0280, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0280, 0x3C78, 0x3838,
0x3838, 0x3C78, 0x0280, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100,
0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0280, 0x3C78, 0x3838,
0x0008, 0x0008 };

struct storage {
    MenuHandle      menu;
    ControlHandle   vscrl;
    char *          where;
    short           autoupdate;
    short           size;
    short           incr;
    TEHandle        hte;
};

open()
{
    register WindowPtr wp;
    register struct DCE *dp;
    register struct storage *sp;
    extern char title[];
    struct windowpeek {
        GrafPort    port;
        int         windowKind;
    };

    save();
    dp = Dp;
    if (dp->dCtlWindow == 0) {
        HLock(dp->dCtlStorage = NewHandle((long)sizeof(struct storage)));
        sp = SP;
        dp->dCtlWindow =
        wp = NewWindow(0L, &Wind_rect, title, TRUE, noGrowDocProc, -1L, TRUE, 0L);
        ((struct windowpeek *)wp)->windowKind = dp->dCtlRefNum;
        sp->vscrl = NewControl(wp, &Scrl_rect, "", FALSE, 0, 0, 0x7fff, scrollBarProc, 0L);
        sp->hte = 0;
        sp->where = 0;
        sp->size = 0;
        sp->autoupdate = 0;
        sp->incr = MEMTOP / 0x8000L;
        sp->menu = NewMenu(MENUID, "\PExplorer");
        AppendMenu(sp->menu,
            "\PAuto-Refresh;Hand-Refresh;(-;Hexadecimal!\x12;Ascii");
        HUnlock(dp->dCtlStorage);
    }
    restore();
    return(0);
}

close()
{
    register struct DCE *dp;

    save();
    dp = Dp;
    TEDispose(SP->hte);
    DisposeWindow(dp->dCtlWindow);
    dp->dCtlWindow = 0;
    DeleteMenu(MENUID);
    DrawMenuBar();
    DisposHandle(SP->menu);
    DisposHandle(dp->dCtlStorage);
    restore();
    return(0);
}

nop()
{
    return(0);
}

control()
{
    register struct storage *sp;
    Point pt;
    register int item;

    save();
    HLock(Dp->dCtlStorage);
    sp = SP;
    SetPort(Dp->dCtlWindow);
    switch(Pbp->u.cp.csCode) {
    case accEvent:
        doevent(sp, *(EventRecord **)&Pbp->u.cp.csParam);
        break;
    case accRun:
        if (sp->autoupdate)
            draw_wind();
        break;
    case accCursor:
        if (sp->hte)
            TEIdle(sp->hte);
        GetMouse(&pt);
        if (PtInRect(pass(pt), &Edit_rect) & TRUE)
            SetCursor(&Ibeam);
        else
            InitCursor();
        break;
    case accMenu:
        switch(item = ((int *)&Pbp->u.cp.csParam)[1]) {
        case 1:                             /* auto refresh     */
            sp->autoupdate ^= TRUE;
            CheckItem(sp->menu, 1, sp->autoupdate);
            break;
        case 2:                             /* manual refresh   */
            draw_wind();
            break;
        case 4:
        case 5:
            sp->size = item==4?8:16;
            CheckItem(sp->menu, 4, item==4?TRUE:FALSE);
            CheckItem(sp->menu, 5, item==5?TRUE:FALSE);
            EraseRect(&Cont_rect);
            draw_wind();
            break;
        }
        break;
    case accUndo:
        break;
    case accCut:
        TECut(sp->hte);
        break;
    case accCopy:
        TECopy(sp->hte);
        break;
    case accPaste:
        TEPaste(sp->hte);
        break;
    case accClear:
        TEDelete(sp->hte);
        break;
    }
    HUnlock(Dp->dCtlStorage);
    restore();
    return(0);
}

doevent(sp, ep)
register struct storage *sp;
register EventRecord *ep;
{
    register int c;
    register long l;
    ControlHandle chdl;
    pascal void scrlup(), scrldn();
    long xtol();

    switch(ep->what) {
    case keyDown:
        if ((ep->modifiers & (cmdKey | optionKey)) == 0) {
            c = (char)ep->message;
            if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || c == 8) {
                TEKey(c, sp->hte);
                break;
            }
            if ((c == '\r' || c == 3) && (l = xtol(sp->hte)) != -1) {
                sp->where = l;
                TESetSelect(0L, 1000L, sp->hte);
                draw_wind();
                break;
            }
        }
        SysBeep(2);
        break;
    case mouseDown:
        GlobalToLocal(&ep->where);
        if (PtInRect(pass(ep->where), &Cont_rect)&TRUE) {
            if (PtInRect(pass(ep->where), &Edit_rect) & TRUE)
                TEClick(pass(ep->where), ep->modifiers&shiftKey?TRUE:FALSE, sp->hte);
        }
        else {
            c = FindControl(pass(ep->where), Dp->dCtlWindow, &chdl);
            switch(c) {
            case inUpButton:
                TrackControl(chdl, pass(ep->where), scrlup);
                break;
            case inDownButton:
                TrackControl(chdl, pass(ep->where), scrldn);
                break;
            case inPageUp:
                scrlpage(chdl, c, -NLINES);
                break;
            case inPageDown:
                scrlpage(chdl, c, NLINES);
                break;
            case inThumb:
                TrackControl(chdl, pass(ep->where), 0L);
                sp->where = (char *)((long)sp->incr * GetCtlValue(chdl));
                draw_wind();
                break;
            }
        }
        break;
    case activateEvt:
        if (ep->modifiers&1) {
            if (sp->size == 0) {
                signature();
                sp->size = 8;
            }
            InsertMenu(sp->menu, 0);
            ShowControl(sp->vscrl);
            TEActivate(sp->hte);
        }
        else {
            DeleteMenu(MENUID);
            HideControl(sp->vscrl);
            TEDeactivate(sp->hte);
        }
        DrawMenuBar();
        break;
    case updateEvt:
        BeginUpdate(ep->message);
        draw_wind();
        DrawControls(ep->message);
        EndUpdate(ep->message);
        break;
    }
}

signature()
{
    register WindowPtr wp;
    register long tick;
    Rect r;

    wp = Dp->dCtlWindow;
    wp->txFont = 0;
    wp->txSize = 0;
    wp->txMode = srcCopy;
    MoveTo(90, 20);
    DrawString("\Pby");
    MoveTo(50,40);
    DrawString("\PJim Goodnow II");
    MoveTo(55, 60);
    DrawString("\Pusing Aztec C");
    MoveTo(10, 90);
    DrawString("\PManx ");
    Move(0, 20);
    DrawString("\PSoftware ");
    Move(0, 20);
    DrawString("\PSystems");
    Move(0, 20);
    DrawString("\PInc.");
    for (tick=TickCount()+100;TickCount() < tick;)
        ;
    EraseRect(&wp->portRect);
    wp->txFont = 4;
    wp->txSize = 9;
    r = Edit_rect;
    InsetRect(&r, 4, 1);
    SP->hte = TENew(&r, &r);
}

draw_wind()
{
    register unsigned char *cp, *wp;
    register unsigned long l;
    register int k, i, j;
    struct storage *sp;
    char buf[40];
    static char hex[] = "0123456789abcdef";

    sp = SP;
    l = sp->where;
    if (l < 0)
        l = 0;
    if (l > MEMTOP - sp->size*NLINES)
        l = MEMTOP - sp->size * NLINES;
    wp = sp->where = l;
    SetCtlValue(sp->vscrl, (int)(l/sp->incr));
    RectRgn(Dp->dCtlWindow->clipRgn, &Cont_rect);
    MoveTo(4, 9);
    DrawString("\PStart: ");
    TEUpdate(&Edit_rect, sp->hte);
    FrameRect(&Edit_rect);
    for (i=0;i<NLINES;i++) {
        k = i * sp->size;
        MoveTo(4, i*10+24);
        cp = buf;
        l = wp + k;
        for (j=5;j>=0;l>>=4)
            cp[j--] = hex[l%16];
        cp += 6;
        *cp++ = ':';
        if (sp->size == 8) {
            for (j=0;j<8;j++) {
                *cp++ = ' ';
                *cp++ = hex[wp[k+j]/16];
                *cp++ = hex[wp[k+j]%16];
            }
        }
        *cp = 0;
        DrawString(ctop(buf));
        if (sp->size == 16) {
            cp = buf;
            *cp++ = 17;
            *cp++ = ' ';
            for (j=0;j<16;j++) {
                if (wp[k+j] > 0x1f && wp[k+j] < 0x80)
                    *cp++ = wp[k+j];
                else
                    *cp++ = '.';
            }
            DrawString(buf);
        }
    }
    RectRgn(Dp->dCtlWindow->clipRgn, &Full_rect);
}

pascal void
scrlup(chdl, code)
ControlHandle chdl;
int code;
{
    scroll(chdl, code, inUpButton);
}

pascal void
scrldn(chdl, code)
ControlHandle chdl;
int code;
{
    scroll(chdl, code, inDownButton);
}

scroll(chdl, code, where)
ControlHandle chdl;
{
    register struct storage *sp;

#asm
    move.l  a4,-(sp)
    lea     main+(_Uend_-_Dorg_)+(_Cend_-main),a4       ;set up globals
#endasm
    if (code == where) {
        sp = SP;
        if (where == inUpButton)
            sp->where -= sp->size;
        else
            sp->where += sp->size;
        draw_wind();
    }
    ;
#asm
    move.l  (sp)+,a4
#endasm
}

scrlpage(chdl, code, amount)
ControlHandle chdl;
{
    Point pt;
    struct storage *sp;

    sp = SP;
    do {
        GetMouse(&pt);
        if (TestControl(chdl, pass(pt)) == code) {
            sp->where += sp->size*amount;
            draw_wind();
        }
    } while (StillDown()&TRUE);
}

long
xtol(hte)
TEHandle hte;
{
    register char *cp;
    register long i = 0, l = 0;
    register int c, n;

    n = (*hte)->length;
    cp = *(*hte)->hText;
    while (n--) {
        c = *cp++;
        if (c >= 'a' && c <= 'f')
            c -= 'a' - 10;
        else if (c >= '0' && c <= '9')
            c -= '0';
        else {
            TESetSelect(i, i+1, hte);
            return(-1);
        }
        l = l * 16 + c;
        i++;
    }
    return(l);
}

::::::::::::::
explor.hex
::::::::::::::
(This file must be converted with BinHex.Hex)
#DRVRManx$0000
***COMPRESSED
***RESOURCE FORK
(    0    T(   ,"    #P                     
(                                           
(                                           
(                                           
(                                           
(                                           
(                                           
(                                           
(   # 0D  $L  K\]P P 8X!F &. 3((17AP;&]R97( 
($GZ"^8I2/_V*4G_^DYU(&S_]DYU3E8  $CG#!!AXB@L
(/_Z)$1*J@ >9@  WB1$+PHO/    !9.N@ID6$\D7R5 
(  4+P!.N@F46$\D;/_Z(FH %"H1)$0O"D*G0J=(;/[N
($AZ_Y0_/ $ /SP !"\\_____S\\ 0!"IZD3(!\F0"1?
("5  !XD1#=J !@ ;"1%+PI"IR\+2&S^]DAL_UI"9T)G
($)G/SQ__S\\ !!"IZE4(!\D7R5   0D14*J !(D14*J
(  ()$5":@ .)$5":@ ,)$4F. $(= _DJS5# ! D12\*
($*G/SS\]TAL_UNI,2 ?)%\D@"1%+Q)(;/]EJ3,D1"\J
(  43KH(X%A/3KK_!'  3-\(,$Y>3G5.5@  2.< $$ZZ
(/[@)FS_^B1L__HB:@ 4)%$O*@ 2J<TO*P >J11"JP >
(#\\_/>I-JDW)&S_^B)J !0D42\23KH)/%A/+RL %$ZZ
( DR6$].NOZH< !,WP@ 3EY.=4Y6  !P $Y>3G5.5O_\
($CG"!!.NOYZ)&S_^B\J !1.N@A(6$\D;/_Z(FH %"91
("1L__HO*@ >J',D;/_V,"H &F   2(D;/_V+RH '"\+
($ZZ 4103V   2)*:P ,9P1.N@1X8  !%$JK !)G!B\K
(  2J=I(;O_\J7)"9R\N__Q(;/\.J*TP'\!\ 0!G"$AL
(/\6J%%@ JA08   X"1L__8P*@ >. !@=@IK 0  #"\3
(#\\  $_*P ,J45@<DZZ!!Q@;+A\  1F"#=\  @ #F &
(#=\ !  #B\3/SP !+A\  1F!C8\ 0!@ G8 /P.I12\3
(#\\  6X?  %9@8V/ $ 8 )V #\#J45(;/[^J*-.N@/,
(& <  +_?/^0  +_EO^6L'P !F0*XT P.P#J3OL  &!*
(&!(+RL $JG68$ O*P 2J=5@."\K !*IVV P+RL $JG7
(& H_L[^XO[P_R3_N  "_[K_PO_*_]*0? ! L'P "F0*
(.- ,#L WD[[   D;/_Z+RH %$ZZ!O!83TZZ_11P $S?
( @03EY.=4Y6__Q(YPX0)FX ""@N  PD1# 28  "'"1$
(#8J  [&? D 9FXD1"8J  )(@SH#NGP ,&T&NGP .6\2
(+I\ &%M!KI\ &9O!KI\  AF##\%+RL $JG<8  ![+I\
(  -9P:Z?  #9BXO*P 23KH%Z%A/+ "PO/____]G&B=&
(  (0J<O/    ^@O*P 2J=%.N@*X8  !LC\\  *IR&  
( &H)@36O     HO ZAQ0F<D1"\J  I(;/[^J*TP'\!\
( $ 9SQ"9R1$+RH "DAL_PZHK3 ?P'P! &<B)$0O*@ *
("1$-BH #L9\ @!G!C8\ 0!@ G8 /P,O*P 2J=1@  #"
($)G)$0O*@ *)&S_^B\J !Y(;O_\J6PP'SH , 5@  "(
($)G+R[__"1$+RH "DAZ!$2I:# ?8   BD)G+R[__"1$
("\J  I(>@10J6@P'V!R/SS_\#\%+R[__$ZZ!*Y03V!@
(#\\ ! _!2\N__Q.N@2<4$]@3D)G+R[__"1$+RH "D*G
(*EH,!\V*P 02,,O T)G+R[__*E@,!](P"8?QL G0P (
($ZZ :A@&I!\ !1G /]T4T!GAE- 9YA30&>FD'P :F>R
(&   (8D1#8J  [&?  !9R)*:P .9@AA>#=\  @ #B\3
($)GJ34O*P $J5<O*P 2J=A@$C\\_/>I-B\K  2I6"\K
(  2J=FI-V! )$0O*@ "J2).N@$X)$0O*@ "J6DD1"\J
(  "J2-@(@ "_EP  OW8  (  O_"  +_?K!\  ED"N- 
(# [ .1.^P  3-\(<$Y>3G5.5O_X2.<($"1L__HF:@ >
($)K $1":P!*0FL 2#\\ %H_/  4J)-(;/^7J(0_/  R
(#\\ "BHDTAL_YNHA#\\ #<_/  \J)-(;/^KJ(0_/  *
(#\\ %JHDTAL_[JHA$)G/SP %*B42&S_P:B$0F<_/  4
(*B42&S_S*B$0F<_/  4J)1(;/_5J(1"IZEU(!\H -B\
(    &1"IZEU(!^PA&P"8/0F"]:\    $"\#J*,W?  $
( !$-WP "0!*1>[_^$/L_PXDV2392&[_^#\\  0_/  !
(*BI)&S_^B)J !0D42\*0J=(;O_X2&[_^*G2(!\D7R5 
(  23-\($$Y>3G5.5O_22.</$"1L__HB:@ 4+5'_^B1N
(/_Z*BH "+J\     &0">@ D;O_Z-BH #NE#2,,D. $(
()2#NH)C%"1N__HV*@ .Z4-(PR0X 0B4@RH")&[_^B5%
(  (* 4D;O_Z+RH !" %)&[_^C(J !!(P4ZZ WH_ *EC
("1L__HB:@ >+RD '$AL_OZHWS\\  0_/  )J)-(;/_L
(*B$2&S_#B1N__HO*@ 2J=-(;/\.J*%^ +Y\ !!L  %:
("1N__H\*@ .S,<_/  $-@?&_  *UGP &#\#J)-%[O_2
("9*2,8J!MJ$/7P !?_^#&X  /_^;1XV+O_^4V[__B0%
(,2\    #T7L_]L7LB@ , #HC6#:7(LD2U*+%+P .B1N
(/_Z#&H "  .9EA";O_^#&X "/_^;$PD2U*+%+P ("1+
(%*+-@;6;O_^(D04,3  Q'P _^A*0^S_VQ2Q(  D2U*+
(#8&UF[__B)$%#$P ,1\ /_$?  /0^S_VQ2Q( !2;O_^
(&"L0A-(;O_23KH"[EA/+P"HA"1N__H,:@ 0  YF=$7N
(/_2)DHD2U*+%+P $21+4HL4O  @0F[__@QN !#__FQ,
(#8&UF[__B1$%#(P ,1\ /^T?  ?8R@V!M9N__XD1!0R
(#  Q'P _[1\ (!D$B1+4HLV!M9N__XB1!2Q, !@""1+
(%*+%+P +E)N__Y@K$AN_]*HA%)'8 #^HB1L__HB:@ >
("\I !Q(;/\&J-],WPCP3EY.=4Y6  !(YQ @/SP %#\N
(  (+RX "F$R4$],WP0(3EX@7UQ/3M!.5@  2.<0(#\\
(  5/RX ""\N  IA#E!/3-\$"$Y>(%]<3T[03E8  $CG
(  0+PQ)^@,B-BX #+9N  YF+"1L__HB:@ 4)E$,;@ 4
(  .9@PV*P .2,.7JP (8 HV*P .2,/7JP (3KK]3BA?
($S?" !.7DYU3E;_^"1L__HB:@ 4+5'_^$AN__RI<D)G
("\N  @O+O_\J68P'[!N  QF%B1N__@V*@ .QNX #DC#
(->J  A.NOT$0F>I<S ?P'P! &;$3EY.=4Y6  !(YP\0
('@ >@ D;@ ((E(^*0 \)&X "")2)&D /B92-@=31TI#
(&=4)$M2BQ822(,\ [Q\ &%M#+Q\ &9N!IQ\ %=@*KQ\
(  P;0R\?  Y;@:<?  P8!@O!"8$4H,O R\N  BIT7#_
($S?"/!.7DYU2,8F!>F#*@;:@U*$8*0@!6#F(&\ !* I
($[Z ,X@;P $H"I.^@#$+P1"A$J :@1$@%)$2H%J!D2!
( I$  %A+DI$9P)$@"@?3G4O!$*$2H!J!$2 4D1*@6H&
($2!"D0  6$,( %.^O_:800@ 4YU2.<P $A!2D%F*$A!
($)#@,%H#C0 0D!(0(#!-@ P H#!(@!(0# #2$!"04A!
($S?  Q.=4A!0H)V'^. XY*4@6L04H!1R__T8 [C@..2
(-2!:O!1R__VU($B DS?  Q.=2!O  2@(T[Z !8@+P $
(*$B3OH  D/M__XR@" (3G5#[?_^,H!.=2!O  0B2! \
(   $A 0P! !9OA32)')( @2@" )3G4 9 "6 1,!:/__
( #" +  TP      L #"      "P -/__P L  P 6C@X
(#QX H !  $  0 !  $  0 !  $  0 !  * /'@X.#@X
(#QX H !  $  0 !  $  0 !  $  0 !  * /'@X.  (
(  (  A%>'!L;W)E<@ P075T;RU2969R97-H.TAA;F0M
(%)E9G)E<V@[*"T[2&5X861E8VEM86PA$CM!<V-I:0 "
(&)Y  Y*:6T@1V]O9&YO=R!)20 -=7-I;F<@07IT96,@
($, !4UA;G@@  E3;V9T=V%R92  !U-Y<W1E;7, !$EN
(&,N # Q,C,T-38W.#EA8F-D968 !U-T87)T.B      
(                                           
(  < #(  $125E(    * !\  "          "0!%>'!L
!&]R97(
***END OF DATA
***CRC:40E3
-------