[alt.sources.amiga] Mackie: Amiga macro key handler -- Tomas G. Rokicki

amiga-sources@sugar.uu.net (alt.sources.amiga) (07/30/88)

Archive: uunet!~uucp/amiga-sources/mackie.shar.Z

:
#! /bin/sh
# This is a shell archive, created on Sugar Land Unix (..!uunet!sugar)
# (bbs: 713-438-5018) by peter (Peter da Silva) on Sat Jul 30 08:16:07 1988
# Remove anything before the "#! /bin/sh" line, then unpack it by saving
# it into a file and typing "sh file".  If you do not have sh, you need 
# unshar, a dearchiving program which is widely available.  In the absolute
# wost case, you can crack the files out by hand.
# If the archive is complete, you will see the message "End of archive."
# at the end.
# This archive contains the following files...
# 'POSTER'
# 'README'
# 'mackie.c'
# 'mackie.uu'
# 'makefile'
# To extract them, run the following through /bin/sh
echo x - POSTER
sed 's/^X//' > POSTER << '//END_OF_FILE'
XFrom uucp Sun Jul 24 09:35 CDT 1988
X>From polya.Stanford.EDU!rokicki  Sun Jul 24 09:35:32 1988 remote from uunet
XReceived: by sugar.UU.NET (smail2.5)
X	id AA00882; 24 Jul 88 09:35:32 CDT (Sun)
XReceived: from Polya.Stanford.EDU by uunet.UU.NET (5.59/1.14) 
X	id AA12116; Sat, 23 Jul 88 20:24:48 EDT
XReceived:  by polya.Stanford.EDU (5.59/25-eef) id AA11957; Sat, 23 Jul 88 17:24:46 PDT
XDate: Sat, 23 Jul 88 17:24:46 PDT
XFrom: Tomas G. Rokicki <uunet!polya.Stanford.EDU!rokicki>
XMessage-Id: <8807240024.AA11957@polya.Stanford.EDU>
XTo: sugar!peter
XSubject: mackie 1.1
X
XThat was a alpha test of Mackie to be posted in alt.sources, so you
Xhave some code to post.  Enjoy!
X
X-tom
X
//END_OF_FILE
echo x - README
sed 's/^X//' > README << '//END_OF_FILE'
XMackie 1.1 (beta release for 1.2) is now available.  This revision has
Xsignificantly greater functionality than the original Mackie, and I am
Xreleasing it in hopes of getting comments and improvements.
X
XTo get the program, anonymous ftp it from labrea.stanford.edu (in ~pub)
Xor send me mail; I'll send it to you by Email or physical mail (at least
Xto the first 20 people who ask).  You'll get both source and executable;
Xcomments on the source is greatly appreciated.
X
XThose of you who have used Lisp machines or TI Explorers will recognize
Xhow this works.  I've added a `System' key to the Amiga, by taking over
Xthe help key.  If I want to edit a file, I simply hit `Help' then `E'.
XIf an editor already has a window open, it will be popped to front;
Xotherwise, an editor will be spawned.  Similarly, `Help' `V' will give
Xme a VT100 window, whether one exists or not.  If I want a new editor,
Xregardless of ones that current exist, `Help' CTRL-E will give me one.
X
XLet's plunge right in, by examining my current startup file.
X
X*
X*   Typical .mackierc file; set the default pop
X*   command:
X*
Xcommand "newwsh con:10/10/640/200/MackieCLI"
X;
X;   and the timeout:
X;
Xtimeout 200
X#
X#   Now define some system keys
X#
Xspace cli "" "newwsh"
Xt cli "tex*" "newwsh con:20/20/640/100/texwsh cmd tex"
Xp intuition "preview*" "preview"
Xe intuition "mg*" "mg"
Xv intuition "vt100*" "run vt100"
Xd intuition "dfc*" "dfc"
X
Xw intuition ""
X
XSo, all the POPCLI stuff is still in there.  I'll address the system keys
Xone by one.
X
XThe line that starts with `space' means that whenever `Help' `Space' is
Xpressed, the next CLI window that matches the empty string is brought
Xto the front.  The only CLI windows with a null command are the ones
Xnot executing a command, so this gives me a CLI ready for a command.
X
XThe line that starts with `t' means that `Help' `t' will look for a CLI
Xexecuting a command starting with the three characters `tex', and pop it
Xto front.  If one doesn't exist, one is started.  Note that all string
Xcomparisons here are case insensitive, and that `*' means match all the
Xrest of the characters.
X
XThe syntax for the startup file is each line is an empty line, a comment,
Xa parameter line, or a system key definition.  Comment lines start with
Xsemicolons, hashes, or splats.  Parameter lines start with `command',
X`timeout', `blank', or `lines'.  Timeout must be folled by a number,
Xand command must be followed by a string.  Separators are tabs, spaces,
Xequal signs, commas, or hyphens.
X
XSystem key definitions start with the key being defined.  Allowable
Xkeys are A-Z or 0-9 (as themselves), F1 through F10 for the function
Xkeys, or Space for the space key.  The keyword `Shift' can precede the
Xkey.  After the key, an optional `CLI' or `Intuition' keyword can be
Xplaced.  These will be described later.
X
XAfter the optional keyword, one or two strings should be found.  The
Xfirst string is the command to match; the second string (if given) is
Xthe command to execute if no matches are found.  This command should
Xreturn relatively quickly; if the program doesn't detach, then you want
Xto precede the command with a `run' or `newcli' so it does.
X
XStrings are bracketed by double quotes; a backslash-double quote means
Xa literal double quote.
X
XAny key that doesn't have a definition in the startup file gets a default
Xdefinition; for the letter keys A-Z, the default definition is
X
XX "X*"
X
Xfor example, which means match any window starting with `X', be it a CLI
Xor an Intuition window.  The number keys match only the CLI with that
Xparticular number.  The space key by default matches any window (so it just
Xcycles all of the windows), and the function keys match nothing.
X
XWindows are not matched by their title; the title is often blank or used
Xfor error messages and the like.  Instead, windows are matched by the
Xname of the task associated with the window for Intuition windows, or the
Xcommand being executed by the CLI in the case of CLI windows.  Thus, the
Xprogram doesn't work very well with programs that use strange task names.
XFor instance, Manx db uses the name `Aztec_db', so you'd have to match
Xthat, rather than the intuitive `db'.
X
XThere are three classes of programs.  There are those programs that run
Xfrom the workbench or detach themselves from a CLI; these programs have
Xonly an Intuition window associated with them.  An example of this class
Xis Manx `db'.  There are those programs that interact only through the CLI
Xwindows; an example of these is `tex'.  And finally, there are programs
Xthat run from a CLI but do their interaction through an Intuition window;
Xan example of this is `vt100'.
X
XOnly the third class offers any ambiguity; the question is whether to
Xactive the CLI window or the Intuition window.  But the type of window is
Xusually specified for the other kinds anyway, to help limit the search.
X
XIf you give a search string such as `!xyzzy!' that isn't likely to be
Xmatched, then the command string is always executed, so you can bind
Xarbitrary commands to a system key.
X
XOh, yes; one important thing.  Hitting `help' twice passes a help key
Xon through the input stream, so you haven't lost your help key.
X
XThe code will only compile with Manx.
X
XUsage is simply:
X
X   run mackie [-q] [-l] [-b] [-f filename] [command] [time]
X
XNote that it doesn't automatically detach itself, so the `RUN' is
Xnecessary.  The first time you run it, it loads itself into RAM.
XSubsequent invocations need not be `run', as they notice the running
Xportion of the program and simply send new parameters to it.
X
XThe options mean:
X
X   -q             Quit.  Remove the resident portion from memory.
X   -l             Lines.  Draw lines instead of a blank screen.  (Default)
X   -b             Blank.  Draw a blank screen instead of fancy lines.
X   -f filename    Startup file (default is s:.mackierc).
X
XA time is an argument that starts with a digit; this time is in seconds.
XAfter that much inactivity, the screen blanking starts.
X
XA command is an argument that starts with neither digits nor a hyphen.
XThis is the command executed whenever left-amiga ESC is pressed.
X
XThus, the command
X
X   run mackie "newcli con:10/10/640/200/MackieCLI"
X
Xstarts mackie up, and sets the command to be executed to a NewCLI with a
Xspecified size.  Later, if you want to see the screen blanking feature
Xquickly, just type
X
X   mackie 1
X
Xand in a second, the screen will go blank.  If the lines are driving you
Xwild, you might type
X
X   mackie -b
X
Xto turn them off.  Finally, you need every byte of memory, so you want to
Xremove mackie.  Simply type
X
X   mackie -q
X
XThat's all there is to it.
X
XEnjoy this program!  Send bug reports to Tomas Rokicki, Box 2081,
XStanford, CA  94309.
X
XBased on:
X
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1986 The Software Distillery.  All Rights Reserved */
X/* |. o.| || This program may not be distributed without the permission of   */
X/* | .  | || the authors.                                                    */
X/* | o  | ||    Dave Baker     Ed Burnette  Jay Denebeim John Mainwaring     */
X/* |  . |//     Gordon Keener  Jack Rouse   John Toebes  Doug Walker         */
X/* ======                    BBS:(919)-471-6436                              */ 
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
XPOPCLI III by John Toebes ) 1987 The Software Distillery.  All Rights Reserved
X 235 Trillingham Ln, Cary, NC 27511
X 
XContributions to continue development of this and other fine products for the
XAmiga should be sent to the Software Distillery at the above address.
X
XOther Products produced by the Software Distillery are:
X   BLINK    - the Turbo-charged Alink replacement
X   HACK     - The Amiga port of the famous UNIX game
X   LARN     - Another famous UNIX game
X   MEMWATCH - Protects your machine from random trashes
X   MAKE     - A software development tool one shouldn't be without
X   KERMIT   - The World renown file transfer protocol brought to the Amiga
X   ICONEXEC, SETALTERNATE, SETWINDOW - Icon manipulation tools
X   TSIZE    - A short utility for determining directory sizes.
XAll of these are available on our BBS.
X
XPermission is hereby granted to distribute this program provided both this
Xdocumentation accompanies the executable and that no charge is made for its
Xdistribution.
X
XPOPCLI (pronounced POP-SEE-EL-EYE) is designed to solve two problems at once.
XFirst it provides a simple way of starting another CLI at any time without
Xhaving to load workbench or exit whatever program you may be using.  Second
Xit has a builtin screen saver mode that automatically turns off the Amiga
Xdisplay when there has been no input for a given period of time.
//END_OF_FILE
echo x - mackie.c
sed 's/^X//' > mackie.c << '//END_OF_FILE'
X/*
X    Modified to work with Manx 3.6a; probably won't work with Lattice.
X                                Based on:
X                                                                             */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1986 The Software Distillery.  All Rights Reserved */
X/* |. o.| || This program may not be distributed without the permission of   */
X/* | .  | || the authors.                                                    */
X/* | o  | ||    Dave Baker     Ed Burnette  Stan Chow    Jay Denebeim        */
X/* |  . |//     Gordon Keener  Jack Rouse   John Toebes  Doug Walker         */
X/* ======          BBS:(919)-471-6436      VOICE:(919)-469-4210              */ 
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/*
X * VERY loosely based on the input.device example by Rob Peck, 12/1/85
X */
X/* * * * * * * * * INCLUDE FILES * * * * * * * * * * * */
X#include <exec/types.h>
X#include <exec/nodes.h>
X#include <exec/lists.h>
X#include <exec/memory.h>
X#include <exec/interrupts.h>
X#include <exec/ports.h>
X#include <exec/libraries.h>
X#include <exec/io.h>
X#include <exec/tasks.h>
X#include <exec/execbase.h>
X#include <exec/devices.h>
X#include <devices/timer.h>
X#include <devices/input.h>
X#include <devices/inputevent.h>
X#include <devices/console.h>
X#include <intuition/intuition.h>
X#include <intuition/intuitionbase.h>
X#include <libraries/dos.h>
X#include <libraries/dosextens.h>
X#include <graphics/gfxmacros.h>
X#include <hardware/custom.h>
X#include <hardware/dmabits.h>
X/*
X *   I need this kludge because of a bug in functions.h.
X */
X#define ConsoleDevice IDontReallyExist
X#include <functions.h>
X#undef ConsoleDevice
X#include <stdio.h>
X
X/* * * * * * * * * * * CONSTANTS * * * * * * * * * * * * */
X#define PORTNAME     "Mackie.port"
X#define TIMEINTERVAL 1L      /* in seconds */
X#define DEFTIME      300     /* two minute timeout */
X#define MAXCMD       200
X#define MAXPENDINGSYSTEM 20
X#define DEFKEY    0x45
X#define DEFCMD    "NEWCLI >NIL: <NIL:"
X#define STARTUPFILE "s:.mackierc"
X/*
X *   Macro to make BPTR things easier to work with.
X */
X#define BSTRtoS(a) ((char *)(((long)(a))<<2))
X/* * * * * * * * * * * GLOBAL VARIABLES * * * * * * * * * */
X/*
X *   Detach stuff (doesn't work, somehow!)
X */
Xtypedef struct
X   {
X   struct Task          *buddy ;
X   ULONG                 creatclisig ;
X   ULONG                 unblanksig ;
X   ULONG                 frontsig ;
X   ULONG                 noevents ;
X   short                 creatsignum ;
X   short                 blanksignum ;
X   short                 replysignum ;
X   short                 frontsignum ;
X   short                 key ;
X   char                  frontkey[MAXPENDINGSYSTEM] ;
X   char                  frontqual[MAXPENDINGSYSTEM] ;
X   short                 frontptr ;
X   short                 draw ;
X   short                 helppressed ;
X   struct Screen        *blankscreen ;
X   } GLOBAL_DATA;
X#define SHIFT 1
X#define NOTCLI 2
X#define NOTINTUITION 4
Xstruct hotkey {
X   struct hotkey*next ;
X   char key, flags ;
X   int structlen ;
X   char *matchstring, *startstring ;
X   char strings[2] ;
X} *hotkeys ;
Xstruct Window *lastwindows[200] ;
Xstruct Task *task ;
Xlong taskreply ; /* the signal the line drawing task will return */
X#define STACKSIZE (1000)
Xlong stackmem[STACKSIZE/4] ;
Xstruct InfoData *infoptr ;
Xstruct MsgPort *FindPort(), *CreatePort();
Xvoid DeletePort();
Xchar *startupfile = STARTUPFILE ;
Xstruct OURMSG {
X struct Message msgpart;
X short key;
X short interval;
X short draw ;
X char cmd[MAXCMD];
X };
X
Xextern char *strcpy() ;
X
X/************************************************************************/
X/* the handler subroutine - called through the handler stub             */
X/************************************************************************/
Xextern void HandlerInterface();
Xvoid foobar() {
X#asm
X_HandlerInterface:
X	movem.l a4,-(a7)
X	movem.L	A0/A1,-(A7)
X	jsr	_geta4#
X	jsr	_myhandler
X	addq.L	#8,A7
X	movem.L	(a7)+,a4
X	rts
X#endasm
X}
Xchar keytoasc[128] ;
Xstruct InputEvent *myhandler(ev, gptr)
Xstruct InputEvent *ev;      /* and a pointer to a list of events */
Xregister GLOBAL_DATA *gptr;      /* Everything we need to know about */
X{
X   register struct InputEvent *ep, *laste;
X   int key ;
X   /*
X    * run down the list of events
X    * to see if they pressed
X    * one of the magic buttons
X    */
X   for (ep = ev, laste = NULL; ep != NULL; ep = ep->ie_NextEvent) {
X      if ((ep->ie_Class == IECLASS_RAWKEY)    &&
X             (((ep->ie_Qualifier & IEQUALIFIER_LCOMMAND) &&
X               (ep->ie_Code == gptr->key)) ||
X              (!gptr->helppressed && ep->ie_Code == 0x5f) ||
X              (gptr->helppressed &&
X               (ep->ie_Code & 0x80) == 0 &&
X/*
X *   All the qualifiers have code = 0x6?; dangerous to take advantage
X *   of?
X */
X               (ep->ie_Code & 0xf0) != 0x60 &&
X               gptr->frontkey[gptr->frontptr] == 0 &&
X               (gptr->helppressed = (keytoasc[ep->ie_Code] != '.'))))) {
X         if ((ep->ie_Qualifier & IEQUALIFIER_LCOMMAND) &&
X              (ep->ie_Code == gptr->key))
X            key = -1 ;
X         else if (gptr->helppressed) {
X            gptr->frontkey[gptr->frontptr] = key = ep->ie_Code ;
X            gptr->frontqual[gptr->frontptr] = ep->ie_Qualifier ;
X            gptr->frontptr++ ;
X            if (gptr->frontptr >= MAXPENDINGSYSTEM)
X               gptr->frontptr = 0 ;
X            gptr->helppressed = 0 ;
X         } else {
X            gptr->helppressed = 1 ;
X            key = 0 ;
X         }
X         /* we can handle this event so take it off the chain */
X         if (laste == NULL)
X            ev = ep->ie_NextEvent;
X         else
X            laste->ie_NextEvent = ep->ie_NextEvent;
X         /* now tell him to create the new cli */
X         if (key == -1)
X            Signal(gptr->buddy, gptr->creatclisig);
X         else if (key > 0)
X            Signal(gptr->buddy, gptr->frontsig);
X      } else
X         laste = ep;
X      if (ep->ie_Class != IECLASS_TIMER) {
X         gptr->noevents = 0;
X         if (gptr->blankscreen != NULL)
X            Signal(gptr->buddy, gptr->unblanksig);
X      }
X   }
X   /* pass on the pointer to the event */
X   return(ev);
X}
X
X/* * * * * * * * * * * EXTERNAL ROUTINES * * * * * * * * * */
Xstruct IntuitionBase *IntuitionBase;
Xstruct GfxBase       *GfxBase;
Xstruct DosLibrary    *DosBase;
Xstruct NewScreen      NewScreen = 
X   { 0, 0, 320, 30, 1, 0, 1, NULL, CUSTOMSCREEN, NULL, NULL, NULL, NULL };
X
Xextern struct MsgPort  *CreatePort();
Xstruct IOStdReq *CreateIOReq();
Xvoid DeleteIOReq();
X
X/************************************************************************/
X/* Queue a timer to go off in a given number of seconds                 */
X/************************************************************************/
Xvoid QueueTimer(tr,seconds)
Xstruct timerequest *tr;
XULONG seconds;
X{
X   tr->tr_node.io_Command = TR_ADDREQUEST;   /* add a new timer request */
X   tr->tr_time.tv_secs =  seconds;        	/* seconds */
X   tr->tr_time.tv_micro = 0;
X   SendIO( (struct IORequest *)tr );
X}
X/************************************************************************/
X/* the main program to do the popcli stuff                              */
X/************************************************************************/
XGLOBAL_DATA global;
Xmain(argc, argv)
Xint argc ;
Xchar *argv[] ;
X{
X   struct MsgPort *port;
X   int stay = 0;
X   struct OURMSG *msg;
X   int i ;
X   char cmdstr[MAXCMD];
X   short key, timeout;
X   struct FileHandle *nullfh = NULL ;
X   ULONG sig, timersig;
X   struct timerequest *timerreq;
X   struct MsgPort     *timerport;
X   struct MsgPort     *inputDevPort;
X   struct IOStdReq    *inputRequestBlock;
X   struct Interrupt      handlerStuff;
X   char *cmd ;
X   int draw = 0 ;
X   int nextfront = 0 ;
X
X   SetTaskPri(FindTask(0L), 20L) ;
X   global.creatsignum  = -1;
X   global.blanksignum  = -1;
X   global.replysignum  = -1;
X   global.frontsignum  = -1;
X   global.blankscreen  = NULL;
X   global.key          = DEFKEY ;
X   global.draw         = 1 ;
X   timerreq            = NULL;
X   timerport           = NULL;
X   inputDevPort        = NULL;
X   inputRequestBlock   = NULL;
X   /* now see if we are already installed */
X   if ((port = FindPort(PORTNAME)) == NULL) {
X      stay = 1; /* remember to hang around when we are done */
X      /* not installed, we need to install our own port */
X      if ((port = CreatePort(PORTNAME,0L)) == NULL)
X         goto abort;
X   }
X/*
X *   If we are hanging around, initialize our keyboard translation table.
X *   If we have difficulty, exit angry.
X */
X   if (stay)
X      if (initkeytoasc())
X         goto abort ;
X   /* now send the parameter to the waiting program */
X   if ((msg = (struct OURMSG *)
X       AllocMem((long)sizeof(struct OURMSG), MEMF_CLEAR|MEMF_PUBLIC)) == NULL)
X      goto abort;
X   if ((infoptr = (struct InfoData *)
X      AllocMem((long)sizeof(struct InfoData), MEMF_CLEAR)) == NULL)
X      goto abort ;
X   /* fill in the message information */
X   msg->msgpart.mn_Length = sizeof(struct OURMSG);
X   strcpy(cmdstr, DEFCMD);
X   timeout = 0 ;
X   key = 0 ;
X   msg->cmd[0] = 0;
X   /* if we were run from CLI then output our banner and process parameters */
X   if (argc > 0) {
X      /* display our copyright */
X      if (stay)
X         puts("Mackie 1.1 by Tomas Rokicki - Copyright \xa9 1987, 1988 Radical Eye Software") ;
X      if (argc == 1)
X         puts("Usage: Mackie [-q] [-l] [-b] [-f startup] [time] [\"command\"]") ;
X      argc-- ;
X      argv++ ;
X      while (argc > 0) {
X         cmd = argv[0] ;
X         if (*cmd == '-') {
X            cmd++ ;
X            switch (*cmd) {
Xcase 'q' : case 'Q' :
X               key = -1 ;
X               puts("\x9B1mMackie\x9B0m Terminating") ;
X               break ;
Xcase 'l' : case 'L' :
X               draw = 1 ;
X               break ;
Xcase 'b' : case 'B' :
X               draw = -1 ;
X               break ;
Xcase 'f' : case 'F' :
X               if (cmd[1])
X                  startupfile = cmd + 1 ;
X               else {
X                  argv++ ;
X                  argc-- ;
X                  startupfile = argv[0] ;
X               }
Xdefault :
X               puts("Error in parameter!") ;
X            }
X         } else if ('0' <= *cmd && *cmd <= '9') {
X            timeout = 0;
X            while ((*cmd >= '0') && (*cmd <= '9'))
X               timeout = (timeout*10) + *cmd++ - '0';
X            if (timeout <= 0)
X               timeout = DEFTIME;
X         } else {
X            strcpy(msg->cmd, cmd) ;
X         }
X         argc-- ;
X         argv++ ;
X      }
X   }
X   msg->interval = timeout;
X   msg->key = key;
X   msg->draw = draw ;
X   if (stay)
X      processstartup(startupfile, msg) ;
X   if (draw)
X      global.draw = draw ;
X   PutMsg(port,(struct Message *)msg);
X   if (!stay) goto abort;
X   if (timeout == 0)
X      timeout = DEFTIME ;
X   global.blankscreen = NULL;
X   global.buddy = FindTask(0L);
X   global.noevents = 0;
X   nullfh = Open("NIL:", MODE_NEWFILE);
X   if (((inputDevPort = CreatePort(0L,0L)) == NULL) ||
X      ((inputRequestBlock =
X          CreateIOReq(inputDevPort, (long)sizeof(struct IOStdReq))) == NULL) ||
X      ((timerport = CreatePort(0L,0L)) == NULL) ||
X      ((timerreq  = (struct timerequest *)
X          CreateIOReq(timerport, (long)sizeof(struct timerequest))) == NULL) ||
X      ((global.creatsignum = AllocSignal(-1L)) == -1) ||
X      ((global.blanksignum = AllocSignal(-1L)) == -1) ||
X      ((global.replysignum = AllocSignal(-1L)) == -1) ||
X      ((global.frontsignum = AllocSignal(-1L)) == -1) ||
X      ((GfxBase = (struct GfxBase *)
X                  OpenLibrary("graphics.library", 0L)) == NULL) ||
X      ((IntuitionBase = (struct IntuitionBase *)
X                        OpenLibrary("intuition.library", 0L)) == NULL) ||
X      OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)timerreq, 0L) ||
X      OpenDevice("input.device",0L,(struct IORequest *)inputRequestBlock,0L))
X         goto abort;
X   handlerStuff.is_Data = (APTR)&global;
X   handlerStuff.is_Code = HandlerInterface;
X   handlerStuff.is_Node.ln_Pri = 51;
X   timersig            = (1L << timerport->mp_SigBit);
X   global.creatclisig  = 1L << global.creatsignum;
X   global.unblanksig   = 1L << global.blanksignum;
X   global.frontsig     = 1L << global.frontsignum;
X   inputRequestBlock->io_Command = IND_ADDHANDLER;
X   inputRequestBlock->io_Data    = (APTR)&handlerStuff;
X   DoIO((struct IORequest *)inputRequestBlock);
X   QueueTimer(timerreq, TIMEINTERVAL);
X   for(;;) {         /* FOREVER */
X      sig = Wait( global.creatclisig | global.unblanksig | timersig |
X                  global.frontsig);
X      /* see if they asked us to change the interval */
X      if ((msg = (struct OURMSG *)GetMsg(port)) != NULL) {
X         if (msg->cmd[0]) strcpy(cmdstr, msg->cmd);
X         if (msg->key)
X            global.key = msg->key;
X         if (msg->interval)
X            timeout    = msg->interval;
X         if (msg->draw)
X            global.draw = msg->draw ;
X         FreeMem((char *)msg, (long)msg->msgpart.mn_Length);
X         if (msg->key == -1) goto abort;
X      }
X      if ((sig & global.unblanksig) && global.blankscreen)
X         screenunblank() ;
X      if (sig & global.creatclisig) {
X         WBenchToFront();
X         (void)Execute(cmdstr,nullfh,nullfh);
X      }
X      if (sig & global.frontsig) {
X         while (i=global.frontkey[nextfront]) {
X            windowtofront(keytoasc[i], global.frontqual[nextfront]) ;
X            global.frontkey[nextfront] = 0 ;
X            nextfront++ ;
X            if (nextfront >= MAXPENDINGSYSTEM)
X               nextfront = 0 ;
X         }
X      }
X      if (sig & timersig) {
X         /* get rid of the message */
X         (void)GetMsg(timerport);
X         QueueTimer(timerreq, TIMEINTERVAL);
X         if (task)
X            SetTaskPri(task, 10L) ;
X         if ((global.noevents++ >= timeout) && (global.blankscreen == NULL))
X            blankscreen() ;
X      }
X   }
Xabort:
X   if (infoptr) {
X      FreeMem(infoptr, (long)sizeof(struct InfoData)) ;
X      infoptr = NULL ;
X   }
X   if (timerreq != NULL) {
X      if (timerreq->tr_node.io_Device != NULL)
X         CloseDevice((struct IORequest *)timerreq);
X      DeleteIOReq((struct IOStdReq *)timerreq);
X   }
X   if (inputRequestBlock != NULL) {
X      if (inputRequestBlock->io_Device != NULL) {
X         inputRequestBlock->io_Command = IND_REMHANDLER;
X         inputRequestBlock->io_Data = (APTR)&handlerStuff;
X         DoIO((struct IORequest *)inputRequestBlock);
X         CloseDevice((struct IORequest *)inputRequestBlock);
X      }
X      DeleteIOReq(inputRequestBlock);
X   }
X   screenunblank() ;
X   if (timerport != NULL)          DeletePort(timerport);
X   if (global.creatsignum != -1)   FreeSignal(global.creatsignum);
X   if (global.blanksignum != -1)   FreeSignal(global.blanksignum);
X   if (global.replysignum != -1)   FreeSignal(global.replysignum);
X   if (global.frontsignum != -1)   FreeSignal(global.frontsignum);
X   if (IntuitionBase != NULL)      CloseLibrary((struct Library *)IntuitionBase);
X   if (GfxBase != NULL)            CloseLibrary((struct Library *)GfxBase);
X   if (inputDevPort != NULL)       DeletePort(inputDevPort);
X   if (stay && (port != NULL))     DeletePort(port);
X   {
X      struct hotkey *hk ;
X
X      while (hotkeys) {
X         hk = hotkeys->next ;
X         FreeMem(hotkeys, (long)hotkeys->structlen) ;
X         hotkeys = hk ;
X      }
X   }
X   if (nullfh)                     Close(nullfh);
X   SetTaskPri(FindTask(0L), 0L) ;
X}
X
Xstruct IOStdReq *
XCreateIOReq(port, size)
Xstruct MsgPort *port;
Xlong size;
X{
X   struct IOStdReq *ioReq;
X
X   if ((ioReq = (struct IOStdReq *)
X                AllocMem(size, MEMF_CLEAR | MEMF_PUBLIC)) != NULL) {
X      ioReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
X      ioReq->io_Message.mn_Node.ln_Pri  = 0;
X      ioReq->io_Message.mn_Length       = size;
X      ioReq->io_Message.mn_ReplyPort    = port;
X   }
X   return(ioReq);
X}
X
Xvoid DeleteIOReq(ioReq)
Xstruct IOStdReq *ioReq;
X{
X   ioReq->io_Message.mn_Node.ln_Type = 0xff;
X   ioReq->io_Device = (struct Device *) -1;
X   ioReq->io_Unit = (struct Unit *) -1;
X   FreeMem( (char *)ioReq, (long)ioReq->io_Message.mn_Length);
X}
X/*
X *   All of this stuff down here was written by Tomas Rokicki.
X *   (C) Copyright 1987, 1988, Radical Eye Software.
X */
X#include "graphics/gfxbase.h"
X/*
X *   The maximum number of lines on the screen at once.
X */
X#define MAXLINES (100)
X/*
X *   The external variables we access.
X */
Xstruct RastPort *rastport ;
Xshort screenheight, screenwidth ;
X/*
X *   Some locals to this file.
X */
Xstatic struct NewScreen newscreen = {
X   0, 0,
X   640, 400,
X   1,
X   0, 1,
X   HIRES | LACE | SCREENQUIET,
X   CUSTOMSCREEN,
X   NULL,
X   NULL,
X   NULL,
X   NULL } ;
X/*
X *   This routine opens a screen and fires off the task if apropriate.
X */
Xvoid taskrout() ;
Xblankscreen() {
X   screenheight = 2 * GfxBase->NormalDisplayRows ;
X   screenwidth = GfxBase->NormalDisplayColumns ;
X   newscreen.Height = screenheight ;
X   newscreen.Width = screenwidth ;
X   if (global.draw == -1 || AvailMem(MEMF_CHIP) < 70000L ||
X             (global.blankscreen = OpenScreen(&newscreen)) == NULL) {
X      if ((global.blankscreen = OpenScreen(&NewScreen)) != NULL) {
X         SetRGB4(&(global.blankscreen->ViewPort), 0L, 0L, 0L, 0L);
X         OFF_DISPLAY ;
X      }
X   } else {
X      if (global.blankscreen == NULL &&
X          (global.blankscreen = OpenScreen(&newscreen))==NULL)
X         return ;
X/*
X *   Turning off the sprites is a little bit tricky.  A simple OFF_SPRITE
X *   will continue to display the data in the current sprite registers.
X *   This happens most often with the cursor.  To fix, we simply clear out
X *   the sprite control registers after turning the sprites off.  This
X *   might break all of the sprites when the system comes back up . . .
X */
X      OFF_SPRITE ;
X      custom.spr[0].ctl = 0 ;
X      custom.spr[1].ctl = 0 ;
X      custom.spr[2].ctl = 0 ;
X      custom.spr[3].ctl = 0 ;
X      custom.spr[4].ctl = 0 ;
X      custom.spr[5].ctl = 0 ;
X      custom.spr[6].ctl = 0 ;
X      custom.spr[7].ctl = 0 ;
X      SetRGB4(&(global.blankscreen->ViewPort), 0L, 0L, 0L, 0L) ;
X      rastport = &(global.blankscreen->RastPort) ;
X      SetAPen(rastport, 0L) ;
X      Forbid() ;
X      RectFill(rastport, 0L, 0L, (long)screenwidth-1, 30L) ;
X      Permit() ;
X      SetAPen(rastport, 1L) ;
X      task = (struct Task *)AllocMem((long)sizeof(struct Task),
X                MEMF_CLEAR | MEMF_PUBLIC) ;
X      if (task != NULL) {
X         task->tc_Node.ln_Pri = 10 ;
X         task->tc_Node.ln_Type = NT_TASK ;
X         task->tc_Node.ln_Name = "ri.Lines" ;
X         task->tc_SPLower = (APTR)stackmem ;
X         task->tc_SPUpper = task->tc_SPReg = (APTR)(stackmem + STACKSIZE/4 - 8) ;
X         AddTask(task, taskrout, 0L) ;
X      }
X   }
X}
X/*
X *   Unblank the screen.  We kill the task with the standard ^C kill signal.
X */
Xscreenunblank() {
X   if (task != NULL) {
X      Signal(task, 1L << SIGBREAKB_CTRL_C) ;
X      SetTaskPri(task, 11L) ;
X      Wait(1L << global.replysignum) ;
X      RemTask(task);
X      FreeMem(task, (long)sizeof(struct Task)) ;
X      task = NULL ;
X   }
X   if (global.blankscreen != NULL) {
X      CloseScreen(global.blankscreen);
X      global.blankscreen = NULL ;
X      ON_DISPLAY ;
X      ON_SPRITE ;
X   }
X}
X/*
X *   This routine returns a random value from 0 to n-1.
X */
Xint randm(i)
Xint i ;
X{
X   static long seed ;
X   long rval ;
X
X   if (seed == 0)
X      seed = 323214521 + global.blankscreen->MouseX +
X              global.blankscreen->MouseY ;
X   seed = seed * 123213 + 121 ;
X   rval = (seed >> 5) & 65535 ;
X   return ((i * rval) >> 16) ;
X}
X/*
X *   This routine sets x and y values to a random number.
X */
Xstatic long x, y ;
Xrandomxy() {
X   x = randm(screenwidth) ;
X   y = randm(screenheight) ;
X}
X/*
X *   Main routines are always fun.
X */
Xshort x1store[MAXLINES], y1store[MAXLINES] ;
Xshort x2store[MAXLINES], y2store[MAXLINES] ;
Xshort ptr ;
Xshort dx1, dy1, dx2, dy2 ;
Xshort ox1, oy1, ox2, oy2 ;
Xshort nx1, ny1, nx2, ny2 ;
Xshort dr, dg, db ;
Xshort or, og, ob ;
Xshort nr, ng, nb ;
X/*
X *   Initialize things for the first lines.
X */
Xstartlines() {
X   ptr = 0 ;
X   if (dx1 == 0) {
X      ox1 = randm(screenwidth) ;
X      ox2 = randm(screenwidth) ;
X      oy1 = randm(screenheight) ;
X      oy2 = randm(screenheight) ;
X      dx1 = 3 ;
X      dx2 = 4 ;
X      dy1 = 1 ;
X      dy2 = 6 ;
X      nr = 53 ;
X      ng = 33 ;
X      nb = 35 ;
X      dr = -3 ;
X      dg = 5 ;
X      db = 7 ;
X   }
X   SetRGB4(&(global.blankscreen->ViewPort), 0L, 0L, 0L, 0L) ;
X   SetRGB4(&(global.blankscreen->ViewPort), 1L, (long)(nr >> 3),
X                                 (long)(ng >> 3), (long)(nb >> 3)) ;
X}
X/*
X *   Advance the number by the delta, and check the boundaries.
X */
Xadv(o, d, n, w)
Xshort *o, *d, *n ;
Xshort w ;
X{
X   *n = *o + *d ;
X   if (*n < 0) {
X      *n = 0 ;
X      *d = randm(6) + 1 ;
X   } else if (*n >= w) {
X      *n = w - 1 ;
X      *d = - randm(6) - 1 ;
X   }
X}
X/*
X *   Advance the two points which make up the lines.
X */
Xadvancelines() {
X   adv(&ox1, &dx1, &nx1, screenwidth) ;
X   adv(&ox2, &dx2, &nx2, screenwidth) ;
X   adv(&oy1, &dy1, &ny1, screenheight) ;
X   adv(&oy2, &dy2, &ny2, screenheight) ;
X}
X/*
X *   Draw a new set of lines.
X */
Xdrawnew() {
X   x1store[ptr] = ox1 = nx1 ;
X   x2store[ptr] = ox2 = nx2 ;
X   y1store[ptr] = oy1 = ny1 ;
X   y2store[ptr] = oy2 = ny2 ;
X   Move(rastport, (long)ox1, (long)oy1) ;
X   Draw(rastport, (long)ox2, (long)oy2) ;
X   Draw(rastport, (long)(screenwidth-ox1-1), (long)(screenheight-oy1-1)) ;
X   Draw(rastport, (long)(screenwidth-ox2-1), (long)(screenheight-oy2-1)) ;
X   Draw(rastport, (long)ox1, (long)oy1) ;
X   ptr++ ;
X   if (ptr == MAXLINES)
X      ptr = 0 ;
X}
X/*
X *   Erase the old line.
X */
Xeraseold() {
X   short oldpen ;
X
X   oldpen = rastport->FgPen ;
X   SetAPen(rastport, 0L) ;
X   Move(rastport, (long)x1store[ptr], (long)y1store[ptr]) ;
X   Draw(rastport, (long)x2store[ptr], (long)y2store[ptr]) ;
X   Draw(rastport, (long)(screenwidth-x1store[ptr]-1),
X                  (long)(screenheight-y1store[ptr]-1)) ;
X   Draw(rastport, (long)(screenwidth-x2store[ptr]-1), 
X                  (long)(screenheight-y2store[ptr]-1)) ;
X   Draw(rastport, (long)x1store[ptr], (long)y1store[ptr]) ;
X   SetAPen(rastport, (long)oldpen) ;
X}
X/*
X *   This routine mucks with the colors.
X */
Xcolors() {
X   or = nr ;
X   og = ng ;
X   ob = nb ;
X   adv(&or, &dr, &nr, 128) ;
X   adv(&og, &dg, &ng, 128) ;
X   adv(&ob, &db, &nb, 128) ;
X   SetRGB4(&(global.blankscreen->ViewPort), 1L, (long)(nr >> 3),
X                                    (long)(ng >> 3), (long)(nb >> 3)) ;
X}
X/*
X *   Our actual task, in an infinite loop.
X */
Xvoid taskrout() {
X   long i ;
X   struct Task *task ;
X
X   geta4() ;
X   task = FindTask(0L) ;
X   startlines() ;
X   for (i=0; i<MAXLINES; i++) {
X      advancelines() ;
X      drawnew() ;
X      if (SetSignal(0L, 0L))
X         goto done ;
X   }
X   colors() ;
X   while (SetSignal(0L, 0L)==0) {
X      if (task->tc_Node.ln_Pri == 10)
X         SetTaskPri(task, -20L) ;
X      eraseold() ;
X      advancelines() ;
X      drawnew() ;
X      eraseold() ;
X      advancelines() ;
X      drawnew() ;
X      if (task->tc_Node.ln_Pri == 10)
X         SetTaskPri(task, -20L) ;
X      eraseold() ;
X      advancelines() ;
X      drawnew() ;
X      eraseold() ;
X      advancelines() ;
X      drawnew() ;
X      if (task->tc_Node.ln_Pri == 10)
X         SetTaskPri(task, -20L) ;
X      eraseold() ;
X      advancelines() ;
X      drawnew() ;
X      eraseold() ;
X      advancelines() ;
X      drawnew() ;
X      colors() ;
X   }
Xdone:
X   Signal(global.buddy, 1L << global.replysignum) ;
X   Wait(0L) ;
X}
X/*
X *   Now we do hotkey magic to activate windows, bring them to front,
X *   etc.
X *
X *   Now we have a key, so we have to find a process with that name and
X *   bring her to front.  For now, we just deal with tasks, since the
X *   CLI stuff is so complicated.
X */
X#define MAXMATCH (20)
Xchar simplematch[3] = { ' ', '*', 0 } ;
Xstruct Window *matchwindows[MAXMATCH] ;
Xextern long LockIBase() ;
Xwindowtofront(key, qual)
Xchar key ;
X{
X   long foo ;
X   int i, j ;
X   int n ;
X   struct Window *w ;
X   struct Screen *s ;
X   struct Process *p ;
X   struct MsgPort **mp ;
X   struct CommandLineInterface *CLI ;
X   int cli ;
X   char *nameptr, *matchptr ;
X   extern struct DosLibrary *DOSBase ;
X   struct hotkey *hk ;
X   int shift, ctrl ;
X   struct Window *activewindow ;
X
X/*
X *   First we look for a matching record.
X */
X   if (key == '.')
X      goto goner ;
X   shift = ((qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0) ;
X   ctrl = ((qual & IEQUALIFIER_CONTROL) != 0) ;
X   activewindow = NULL ;
X   for (hk=hotkeys; hk; hk=hk->next)
X      if (hk->key == key && 
X          (hk->flags & SHIFT) == shift)
X         break ;
X   cli = 0 ;
X   if (hk && hk->matchstring)
X      matchptr = hk->matchstring ;
X   else {
X      matchptr = simplematch ;
X      if (key == ' ')
X         matchptr++ ;
X      else if ('A' <= key && key <= 'Z')
X         simplematch[0] = key ;
X      else if ('0' <= key && key <= '9') {
X         cli = key ;
X         if (cli == '0')
X            cli += 10 ;
X         matchptr++ ;
X      } else
X         goto goner ;
X   }
X   n = 0 ;
X   foo = LockIBase(0L) ;
X   if (! ctrl && !(hk && (hk->flags & NOTINTUITION)) && !cli) {
X      for (s=IntuitionBase->FirstScreen; s; s=s->NextScreen)
X         for (w=s->FirstWindow; w; w=w->NextWindow) {
X            if (w->UserPort) {
X               p = (struct Process *)(w->UserPort->mp_SigTask) ;
X               if (((struct Task *)p)->tc_Node.ln_Type == NT_PROCESS) {
X                  if (p->pr_CLI) {
X                     CLI = (struct CommandLineInterface *)BSTRtoS(p->pr_CLI) ;
X                     if (bstrcmp(BSTRtoS((CLI)->cli_CommandName), matchptr) &&
X                         n < MAXMATCH) {
X                           if (w==IntuitionBase->ActiveWindow)
X                              activewindow = w ;
X                           matchwindows[n++] = w ;
X                        }
X                  } else {
X                     if (sstrcmp(((struct Task *)p)->tc_Node.ln_Name, matchptr)
X                          && n < MAXMATCH) {
X                        if (w==IntuitionBase->ActiveWindow)
X                           activewindow = w ;
X                        matchwindows[n++] = w ;
X                     }
X                  }
X               }
X            }
X         }
X   }
X/*
X *   Folks, there are still several/many windows of vulnerability
X *   here; I'll have to plug them.  For instance, what happens if a
X *   CLI goes away while we are doing this?  Or what happens if a
X *   window goes away later, when we are looking at IntuitionBase?
X */
X   if (! ctrl && !(hk && (hk->flags & NOTCLI))) {
X      mp = (struct MsgPort **)BSTRtoS(*(DOSBase->dl_Root)) ;
X      for (j=1; j<(long)(mp[0]); j++)
X         if (mp[j] && (cli == 0 || j == cli - '0')) {
X            p = (struct Process *)(mp[j]->mp_SigTask) ;
X            CLI = (struct CommandLineInterface *)BSTRtoS(p->pr_CLI) ;
X            if (!CLI->cli_Background &&
X                  bstrcmp(BSTRtoS((CLI)->cli_CommandName), matchptr)) {
X               infoptr->id_VolumeNode = NULL ;
X               dos_packet(p->pr_ConsoleTask, ACTION_DISK_INFO,
X                         ((long)(infoptr)) >> 2, 0L, 0L, 0L, 0L, 0L, 0L) ;
X               if (w=(struct Window *)infoptr->id_VolumeNode)
X                  if (n < MAXMATCH) {
X                     if (w==IntuitionBase->ActiveWindow)
X                        activewindow = w ;
X                     matchwindows[n++] = w ;
X                  }
X            }
X         }
X   }
X   if (shift)
X      key += 100 ;
X   if (ctrl || n==0) {
X      UnlockIBase(foo) ;
X      if (hk == NULL || hk->startstring == NULL)
X         goto goner ;
X      Execute(hk->startstring, 0L, 0L) ;
X   } else {
X      if (n == 1) {
X         w = matchwindows[0] ;
X      } else {
X/*
X *   This is some real neat code.  We want to find the next window,
X *   that is, the window with the least address greater than the
X *   currently active window, unless the currently active window
X *   has the highest address, in which case we want to find the
X *   window with the least address.  Why this works is left as a
X *   puzzle for the reader.
X */
X         if (activewindow) {
X            w = activewindow ;
X            for (j=0; j<n; j++)
X               if ((w > activewindow) ^
X                   (w > matchwindows[j]) ^
X                   (matchwindows[j] > activewindow))
X                  w = matchwindows[j] ;
X         } else {
X            w = NULL ;
X            for (j=0; j<n; j++)
X               if (lastwindows[key]==matchwindows[j]) {
X                  w = lastwindows[key] ;
X                  break ;
X               }
X            if (w==NULL)
X               w = matchwindows[0] ;
X         }
X      }
X      lastwindows[key] = w ;
X      s = w->WScreen ;
X      UnlockIBase(foo) ;
X      ScreenToFront(s) ;
X/*
X *   If only one window on screen, don't bring it to front
X *   (mostly for DPaint, but for other progs as well.)
X *   (Anyone know an easy way to see if this window is fully
X *   exposed?)
X */
X      if (s->FirstWindow != w || w->NextWindow)
X         WindowToFront(w) ;
X      ActivateWindow(w) ;
X   }
X   return ;
Xgoner:
X   DisplayBeep(0L) ;
X}
X/*
X *   These two functions compare a given string `s' with a `key' string.
X *   The key string should be all upper case; this is a case insensitive
X *   match.  If the key string contains `*', this character is assumed to
X *   match the rest of the string (and it can only come at the end.)  We
X *   have a routine for BSTR's, and a routine for regular strings.
X */
Xint sstrcmp(s, key)
Xregister char *s, *key ;
X{
X   while (1) {
X      if (*key == '*')
X         return(1) ;
X      if (*key == 0)
X         return(*s == 0) ;
X      if (*s == 0)
X         return(0) ;
X      if (*s != *key &&
X          (*s != *key + 32 || *s < 'a' || *s > 'z'))
X         return(0) ;
X      s++ ;
X      key++ ;
X   }
X}
X/*
X *   This is the same as above, only instead of using a null to
X *   end the string, we keep track of the number of characters.
X */
Xint bstrcmp(s, key)
Xchar *s, *key ;
X{
X   int n ;
X
X   n = *(unsigned char *)s++ ;
X   while (1) {
X      if (*key == '*')
X         return(1) ;
X      if (*key == 0)
X         return(n == 0) ;
X      if (n == 0)
X         return(0) ;
X      if (*s != *key &&
X          (*s != *key + 32 || *s < 'a' || *s > 'z'))
X         return(0) ;
X      s++ ;
X      key++ ;
X      n-- ;
X   }
X}
X/*
X *   A place to hold an input line.
X */
X#define MAXSTARTUPLINE (100)
Xchar startbuf[MAXSTARTUPLINE] ;
Xchar upline[MAXSTARTUPLINE] ;
X/*
X *   Is a legit separator of some sort.
X */
Xint issep(s)
Xregister char s ;
X{
X   return (s <= ' ' || s == '=' || s == ':' || s == ',' || s == '-') ;
X}
X/*
X *   Go to next `word' in the startup file.
X */
Xchar *getword(s)
Xregister char *s ;
X{
X   while (*s && issep(*s))
X      s++ ;
X   return(s) ;
X}
X/*
X *   Upper case a string.
X */
Xchar *upcase(dest, s)
Xchar *dest ;
Xregister char *s ;
X{
X   register char *d = dest ;
X
X   while (*s) {
X      if ('a' <= *s && *s <= 'z')
X         *d++ = *s++ - 32 ;
X      else
X         *d++ = *s++ ;
X   }
X   *d = 0 ;
X   return(dest) ;
X}
X/*
X *   Say we got a bad line.
X */
Xbadline() {
X   puts("Error in startup file!") ;
X   puts(startbuf) ;
X}
X/*
X *   Copies a string from one place to another; string delimited by
X *   double quotes.
X */
Xchar *cpystr(dest, src)
Xregister char *dest, *src ;
X{
X   if (*src != '"')
X      badline() ;
X   else {
X      src++ ;
X      while (*src != '"' && *src != 0) {
X         if (*src == '\\' && src[1] != 0)
X            src++ ;
X         *dest++ = *src++ ;
X      }
X      if (*src)
X         src++ ;
X   }
X   *dest = 0 ;
X   return(getword(src)) ;
X}
X/*
X *   Handle a single startup line that's not a comment and non-empty
X *   and been converted to all upper case.
X */
Xparseline(s, msg)
Xregister char *s ;
Xstruct OURMSG *msg ;
X{
X   int flags ;
X   short t ;
X   int key ;
X   char *p ;
X   register struct hotkey *hk ;
X
X   flags = 0 ;
X   if (strncmp(s, "COMMAND", 7)==0) {
X      s = getword(s+7) ;
X      cpystr(msg->cmd, s) ;
X   } else if (strncmp(s, "TIMEOUT", 7)==0) {
X      s = getword(s+7) ;
X      t = 0 ;
X      while ('0' <= *s && *s <= '9')
X         t = t * 10 + *s++ - '0' ;
X      if (t <= 0)
X         t = DEFTIME ;
X      msg->interval = t ;
X   } else if (strncmp(s, "LINES", 5)==0) {
X      msg->draw = 1 ;
X   } else if (strncmp(s, "BLANK", 5)==0) {
X      msg->draw = -1 ;
X   } else {
X      if (strncmp(s, "SHIFT", 5)==0) {
X         flags = SHIFT ;
X         s = getword(s+5) ;
X      }
X      if (*s == 0)
X         badline() ;
X      else {
X         if (issep(s[1]) &&
X             (('A' <= *s && *s <= 'Z') ||
X              ('0' <= *s && *s <= '9'))) {
X            key = *s ;
X            s = getword(s+1) ;
X         } else if (strncmp(s, "SPACE", 5)==0) {
X            key = ' ' ;
X            s = getword(s+5) ;
X         } else if (*s == 'F' && ('1' <= s[1] && s[1] <= '9')) {
X            s++ ;
X            t = *s++ - '0' ;
X            if (t == 1 && *s == '0') {
X               t = 10 ;
X               s++ ;
X            }
X            s = getword(s) ;
X          } else {
X            badline() ;
X            return ;
X         }
X         if (strncmp(s, "INTUITION", 9)==0) {
X            flags |= NOTCLI ;
X            s = getword(s+9) ;
X         } else if (strncmp(s, "CLI", 3)==0) {
X            flags |= NOTINTUITION ;
X            s = getword(s+3) ;
X         }
X         s = cpystr(upline, s) ;
X         p = upline + strlen(upline) + 1 ;
X         if (*s)
X            cpystr(p, startbuf + (s-upline)) ;
X         else
X            *p = 0 ;
X         t = sizeof(struct hotkey) + strlen(p) + strlen(upline) ;
X         hk = AllocMem((long)t, MEMF_CLEAR | MEMF_PUBLIC) ;
X         if (hk) {
X            hk->key = key ;
X            hk->flags = flags ;
X            hk->next = hotkeys ;
X	    hk->structlen = t ;
X	    hk->matchstring = strcpy(hk->strings, upline) ;
X	    hk->startstring = strcpy(hk->strings + strlen(upline) + 1, p) ;
X            if (hk->startstring[0]==0)
X               hk->startstring = NULL ;
X            hotkeys = hk ;
X         } else
X            puts("Out of memory in startup") ;
X      }
X   }
X}
X/*
X *   Handle the startup file.
X */
Xprocessstartup(s, msg)
Xchar *s ;
Xstruct OURMSG *msg ;
X{
X   FILE *f ;
X   char *p ;
X
X   if (f=fopen(s, "r")) {
X      while (fgets(startbuf, MAXSTARTUPLINE, f)) {
X         p = getword(startbuf) ;
X         if (*p != '*' && *p != '#' && *p != ';' && *p != 0) {
X            upcase(upline, p) ;
X            parseline(upline, msg) ;
X         }
X      }
X   } else {
X      puts("Couldn't open startup file:") ;
X      puts(s) ;
X   }
X}
X/*
X *   This stuff down here handles the raw key conversion stuff
X *   properly.  Thanks to Willy Langeveld and Carolyn Scheppner.
X */
Xchar *dos_rkcv();
Xint  dos_rkcvinit(), dos_rkcvexit();
Xstruct IOStdReq ConStdReq;
X/*
X *   This code won't compile under Manx unless you delete the
X *   `ConsoleDevice' function in functions.h, or perform a kludge
X *   like the one I did when I included it.  Why the hell does
X *   Manx have that in there?  If you try to use it, it comes out
X *   undefined, but if you rename the following, it won't link
X *   because it needs the function `ConsoleDevice'.
X */
Xlong ConsoleDevice ;
X/**
X*
X*  Calling sequence:
X*  =================
X*
X*	result = (char *) dos_rkcv(code, buffer, length);
X*
X*  Description:
X*  ============
X*
X*	Covert raw key number to array of console device ascii text
X*	using the default keymap.
X*
X*  Inputs:
X*  =======
X*
X*	int code		Raw key number.
X*	int qual		Qualifier.
X*	char *buffer		Pointer to an array of char to receive the
X*				conversion.
X*	int length		length of buffer.
X*
X*  Outputs:
X*  ========
X*
X*	F. value:		NULL on conversion failure, or pointer to
X*				buffer on success.
X*
X**/
Xchar *dos_rkcv(code, qual, buffer, length)
Xint code;
Xint qual;
Xchar *buffer;
Xint length;
X{
X   static struct InputEvent event;
X
X   event.ie_Class = IECLASS_RAWKEY;
X   event.ie_Code = code;
X   event.ie_Qualifier = qual;
X
X   if (RawKeyConvert(&event, buffer, (long) length, NULL) == 0L) return(0L);
X
X   return(buffer);
X}
X
X/**
X*
X*  Calling sequence:
X*  =================
X*
X*	error = dos_rkcvinit();
X*
X*  Description:
X*  ============
X*
X*	Open the Console device for later use with dos_rkcv().
X*
X*  Inputs:
X*  =======
X*
X*	None
X*
X*  Outputs:
X*  ========
X*
X*	F. value:		1 on failure, zero otherwise.
X*				
X*
X**/
Xint dos_rkcvinit()
X{
X   if (OpenDevice("console.device", -1L, &ConStdReq, 0L) != NULL) {
X      ConsoleDevice = 0L;
X      return(1);
X   }
X   else {
X      ConsoleDevice = (long) ConStdReq.io_Device;
X      return(0);
X   }
X}
X
X/**
X*
X*  Calling sequence:
X*  =================
X*
X*	error = dos_rkcvexit();
X*
X*  Description:
X*  ============
X*
X*	Close the Console device after use with dos_rkcv().
X*
X*  Inputs:
X*  =======
X*
X*	None
X*
X*  Outputs:
X*  ========
X*
X*	F. value:		Always zero;
X*				
X**/
Xint dos_rkcvexit()
X{
X   if (ConsoleDevice) CloseDevice(&ConStdReq);
X   return(0);
X}
X/*
X *   Set up the key conversion table.  Note that the buffer has to be
X *   long word aligned!
X */
Xinitkeytoasc() {
X   register int i ;
X   char buf[100] ;
X
X   for (i=0; i<128; i++)
X      keytoasc[i] = '.' ;
X   if (dos_rkcvinit())
X      return(1) ;
X   for (i=0; i<128; i++) {
X      buf[1] = 0 ;
X      if (dos_rkcv(i, 0, buf, 100) && buf[1] == 0 &&
X          (buf[0] == ' ' ||
X           ('a' <= buf[0] && buf[0] <= 'z' && (buf[0] -= 32)) ||
X           ('0' <= buf[0] && buf[0] <= '9'))) {
X         keytoasc[i] = buf[0] ;
X      }
X   }
X/*
X *   Have to handle the function keys separately
X */
X   for (i=80; i<90; i++)
X      keytoasc[i] = i-79 ;
X   dos_rkcvexit() ;
X   return(0) ;
X}
//END_OF_FILE
echo x - mackie.uu
sed 's/^X//' > mackie.uu << '//END_OF_FILE'
Xbegin 777 mackie
XM```#\P`````````#``````````(```TO```#T@````$```/I```-+T[Z)7)S'
XM.BYM86-K:65R8P!.50``+PQ(YP#`3KHERF$*4(\H7TYU3EU.=4Y5__Y(YP@PT
XM)&T`#"9M``AX`&```48,*P`!``1F``$:""L`!@`)9PHP*P`&L&H`'&=H2FH`A
XM2F8(#&L`7P`&9UI*:@!*9P``\@@K``<`!V8``.@P*P`&P'P`\+!\`&!G``#83
XM,"H`1DC`($#1RDHH`!YF``#&<``P*P`&0>R)@`PP`"X(`&<(-7P``0!*8`1"I
XM:@!*2FH`2F<``*`(*P`&``EG$C`K``:P:@`<9@@[?/____Y@3$IJ`$IG/#MK>
XM``;__C`J`$9(P"!`T<H1;?__`!XP*@!&2,`@0-'*$6L`"0`R4FH`1@QJ`!0`F
XM1FT$0FH`1D)J`$I@"C5\``$`2D)M__Y*A&8&*U,`"&`$($0@DPQM_____F8.4
XM+RH`!"\23KHR2%!/8!)*;?_^;PPO*@`,+Q).NC(T4$]@`B@+#"L`!@`$9Q9"H
XMJ@`02JH`3&<,+RH`""\23KHR$E!/)E,@"V8`_K@@+0`(3-\,$$Y=3G5.50``G
XM(&T`"#%\``D`'"!M``@A;0`,`"`@;0`(0J@`)"\M``A.NC&F6$].74YU3E7^2
XMZD)M__I"K?\D0FW^\$)M_NY(>``40J=.NC#`6$\O`$ZZ,9A03SE\__^*(#E\I
XM__^*(CE\__^*)#E\__^*)D*LBE@Y?`!%BB@Y?``!BE1"K?\80JW_%$*M_Q!"&
XMK?\,2'H&_$ZZ,&I83RM`__QF&CM\``'_^D*G2'H&\$ZZ+RA03RM`__QG``5BO
XM2FW_^F<*3KH='DI`9@`%4DAY``$``4AX`.).NB_J4$\K0/_V9P`%.DAY``$`8
XM`$AX`"1.NB_24$\I0(E\9P`%(B!M__8Q?`#B`!)(>@:@2&W_+$ZZ'8)03T)MH
XM_RA";?\J(&W_]D(H`!I*;0`(;P`!4$IM__IG"DAZ!H=.NB)P6$\,;0`!``AF=
XM"DAZ!K].NB)>6$]3;0`(6*T`"DIM``AO``$>(&T`"BM0_O(@;?[R#!``+68`2
XM`))2K?[R(&W^\A`02(!(P&!4.WS___\J2'H&N$ZZ(AI83V!L.WP``?[P8&0[<
XM?/___O!@7"!M_O)**``!9PP@;?[R4H@I2(`"8!!8K0`*4VT`""!M``HI4(`"J
XM2'H&CTZZ(=A83V`JD+P```!"9[Y9@&?"78!GKEN`9YB0O````!%GJEF`9ZY=#
XM@&>:6X!GA&#*8&P@;?[R<#"P$&Y0(&W^\@P0`#EN1D)M_R@@;?[R#!``,&TJ4
XM(&W^\@P0`#EN("!M_O)2K?[R$!!(@#(M_RC#_``*T$&0?``P.T#_*&#,2FW_4
XM*&X&.WP!+/\H8!(O+?[R(&W_]DAH`!I.NAPH4$]3;0`(6*T`"F``_MX@;?_VQ
XM,6W_*``6(&W_]C%M_RH`%"!M__8Q;?[P`!A*;?_Z9PXO+?_V+RR``DZZ&>10&
XM3TIM_O!G!CEM_O"*5"\M__8O+?_\3KHNW%!/2FW_^F<``U!*;?\H9@8[?`$L$
XM_RA"K(I80J=.NBXL6$\I0(H,0JR*'$AX`^Y(>@5[3KHL3%!/*T#_)$*G0J=.\
XMNBS24$\K0/\09P`##$AX`#`O+?\03KH%EE!/*T#_#&<``O9"IT*G3KHLJE!/(
XM*T#_%&<``N1(>``H+RW_%$ZZ!6Y03RM`_QAG``+.2'C__TZZ+6!83SE`BB"P"
XM?/__9P`"N$AX__].NBU*6$\Y0(HBL'S__V<``J)(>/__3KHM-%A/.4"*)+!\Z
XM__]G``*,2'C__TZZ+1Y83SE`BB:P?/__9P`"=D*G2'H$R$ZZ+=)03RE`B@1G8
XM``)B0J=(>@3%3KHMOE!/*4"*`&<``DY"IR\M_QA(>``!2'H$NTZZ+8Q/[P`0!
XM2H!F``(R0J<O+?\,0J=(>@2N3KHM<D_O`!!*@&8``AA![(H,*TC_!$'Z^G(K;
XM2/\(&WP`,_[_(&W_%'``$"@`#W(!X:$K0?\<,"R*($C`<@'AH2E!BA`P+(HBX
XM2,!R`>&A*4&*%#`LBB9(P'(!X:$I08H8(&W_##%\``D`'$'M_O8B;?\,(T@`K
XM*"\M_PQ.NBQX6$](>``!+RW_&$ZZ^X)03R`LBA"`K(H4@*W_'("LBA@O`$ZZW
XM+7183RM`_R`O+?_\3KHLHEA/*T#_]F=\(&W_]DHH`!IG$B!M__9(:``:2&W_P
XM+$ZZ&<A03R!M__9*:``49PH@;?_V.6@`%(HH(&W_]DIH`!9G"B!M__8[:``6,
XM_R@@;?_V2F@`&&<*(&W_]CEH`!B*5"!M__9P`#`H`!(O`"\M__9.NBP.4$\@:
XM;?_V#&C__P`49P``\"`M_R#`K(H49PI*K(I89P1.N@6R("W_(,"LBA!G&$ZZA
XM+:XO+?\D+RW_)$AM_RQ.NBFN3^\`#"`M_R#`K(H89U@P+?[N0>R**A(P``!(/
XM@3M!__1G1#`M_NY![(H^$C```$B!/P$P+?_T0>R)@!(P``!(@3\!3KH,%%A/$
XM,"W^[D'LBBI",```4FW^[@QM`!3^[FT$0FW^[F"H("W_(,"M_QQG2"\M_Q1.T
XMNBMT6$](>``!+RW_&$ZZ^B!03TJLA8QG#DAX``HO+(6,3KHK]E!/("R*'%*L?
XMBAPR+?\H2,&P@64*2JR*6&8$3KH#)&``_FQ*K(E\9Q)(>``D+RR)?$ZZ*OY0(
XM3T*LB7Q*K?\89QX@;?\82J@`%&<*+RW_&$ZZ*7)83R\M_QA.N@*F6$]*K?\,Y
XM9SX@;?\,2J@`%&<J(&W_##%\``H`'$'M_O8B;?\,(T@`*"\M_PQ.NBIH6$\OE
XM+?\,3KHI+EA/+RW_#$ZZ`F)83TZZ!%1*K?\49PHO+?\43KHIN%A/#&S__XH@R
XM9PH_+(H@3KHJ@%1/#&S__XHB9PH_+(HB3KHJ;E1/#&S__XHD9PH_+(HD3KHJH
XM7%1/#&S__XHF9PH_+(HF3KHJ2E1/2JR*`&<*+RR*`$ZZ*,183TJLB@1G"B\L1
XMB@1.NBBT6$]*K?\09PHO+?\03KHI0%A/2FW_^F<02JW__&<*+RW__$ZZ*2I8G
XM3TJL@FAG)B!L@F@K4/[J(&R":#`H``9(P"\`+RR":$ZZ*<Q03REM_NJ":&#4=
XM2JW_)&<*+RW_)$ZZ)VY83T*G0J=.NBF.6$\O`$ZZ*F903TY=3G5-86-K:64N2
XM<&]R=`!-86-K:64N<&]R=`!.15=#3$D@/DY)3#H@/$Y)3#H`36%C:VEE(#$N!
XM,2!B>2!4;VUA<R!2;VMI8VMI("T@0V]P>7)I9VAT(*D@,3DX-RP@,3DX."!2\
XM861I8V%L($5Y92!3;V9T=V%R90!5<V%G93H@36%C:VEE(%LM<5T@6RUL72!;'
XM+6)=(%LM9B!S=&%R='5P72!;=&EM95T@6R)C;VUM86YD(ET`FS%M36%C:VEE/
XMFS!M(%1E<FUI;F%T:6YG`$5R<F]R(&EN('!A<F%M971E<B$`3DE,.@!G<F%PD
XM:&EC<RYL:6)R87)Y`&EN='5I=&EO;BYL:6)R87)Y`'1I;65R+F1E=FEC90!IX
XM;G!U="YD979I8V4``$Y5__Q(>0`!``$O+0`,3KHH`%!/*T#__&<F(&W__!%\%
XM``4`""!M__Q"*``)(&W__#%M``X`$B!M__PA;0`(``X@+?_\3EU.=4Y5```@S
XM;0`($7P`_P`((&T`""%\_____P`4(&T`""%\_____P`8(&T`"'``,"@`$B\`O
XM+RT`"$ZZ)_A03TY=3G5.50``(&R*!#`H`-CC0#E`BF`@;(H$.6@`VHIB.6R*[
XM8(`L.6R*8H`J#&S__XI49R)(>``"3KHF0%A/L+P``1%P;1!(;(`F3KHI5EA/N
XM*4"*6&8T2&R`!DZZ*4983RE`BEAG($*G0J="IT*G(&R*6$AH`"Q.NBC"3^\`M
XM%#/\`0``W_"68``!)DJLBEAF%$AL@"9.NBD,6$\I0(I89@1.74YU,_P`(`#?1
XM\)9">0#?\4)">0#?\4I">0#?\5)">0#?\5I">0#?\6)">0#?\6I">0#?\7)"+
XM>0#?\7I"IT*G0J="IR!LBEA(:``L3KHH3$_O`!0@;(I8T?P```!4*4B*7$*G.
XM+RR*7$ZZ*"!03TZZ)MA(>``>,"R*8DC`4X`O`$*G0J<O+(I<3KHG[D_O`!1.V
XMNB<N2'@``2\LBEQ.NB?L4$](>0`!``%(>`!<3KHF/E!/*4"%C$JLA8QG4B!L[
XMA8P1?``*``D@;(6,$7P``0`((&R%C$/Z`#PA20`*0>R%E")LA8PC2``Z0>R)N
XM7")LA8PC2``V(FR%C"-(`#Y"ITAZ!<PO+(6,3KHE]D_O``Q@`/[P<FDN3&ENS
XM97,``$Y5``!*K(6,9TI(>!``+RR%C$ZZ)OA03TAX``LO+(6,3KHFVE!/,"R*X
XM)$C`<@'AH2\!3KHFZ%A/+RR%C$ZZ)HA83TAX`%PO+(6,3KHE[%!/0JR%C$JL,
XMBEAG'B\LBEA.NB=B6$]"K(I8,_R!``#?\)8S_(`@`-_PEDY=3G5.5?_\2JR"Y
XM0F8@(&R*6#`H`!)(P"!LBE@R*``02,'0@="\$T/<N2E`@D(B/``!X4T@+()";
XM3KH<!-"\````>2E`@D(@+()"ZH#`O```__\K0/_\,"T`"$C`(BW__$ZZ&]QR<
XM$.*@3EU.=4Y5```_+(IB88Y43TC`*4""1C\LBF!A@%1/2,`I0()*3EU.=4Y5L
XM``!";(V$2FR-AF9T/RR*8DZZ_V!43SE`C8X_+(IB3KK_4E1/.4"-DC\LBF!.E
XMNO]$5$\Y0(V0/RR*8$ZZ_S943SE`C90Y?``#C88Y?``$C8HY?``!C8@Y?``&F
XMC8PY?``UC:HY?``AC:PY?``CC:XY?/_]C9XY?``%C:`Y?``'C:)"IT*G0J="'
XMIR!LBEA(:``L3KHEXD_O`!0P+(VNYD!(P"\`,"R-K.9`2,`O`#`LC:KF0$C`Y
XM+P!(>``!(&R*6$AH`"Q.NB6P3^\`%$Y=3G5.50``(&T`$")M``@L;0`,,!'0D
XM5C"`(&T`$$I0;!X@;0`00E`@;0`,+P@_/``&3KK^=%1/(%]20#"`8#`@;0`02
XM,!"P;0`4;20@;0`0,"T`%%-`,(`@;0`,+P@_/``&3KK^1%1/1$`@7U-`,(!.E
XM74YU3E4``#\LBF)(;(V62&R-ADALC8Y.NO]Z3^\`#C\LBF)(;(V:2&R-BDAL%
XMC9).NO]B3^\`#C\LBF!(;(V82&R-B$ALC9!.NO]*3^\`#C\LBF!(;(V<2&R-L
XMC$ALC91.NO\R3^\`#DY=3G5.50``.6R-EHV.,"R-A$C`XX!![(ID,:R-E@@`5
XM.6R-FHV2,"R-A$C`XX!![(OT,:R-F@@`.6R-F(V0,"R-A$C`XX!![(LL,:R-(
XMF`@`.6R-G(V4,"R-A$C`XX!![(R\,:R-G`@`,"R-D$C`+P`P+(V.2,`O`"\LC
XMBEQ.NB0@3^\`##`LC91(P"\`,"R-DDC`+P`O+(I<3KHC\D_O``PP+(I@D&R-9
XMD%-`2,`O`#`LBF*0;(V.4T!(P"\`+RR*7$ZZ(\I/[P`,,"R*8)!LC9130$C`!
XM+P`P+(IBD&R-DE-`2,`O`"\LBEQ.NB.B3^\`##`LC9!(P"\`,"R-CDC`+P`O!
XM+(I<3KHCAD_O``Q2;(V$#&P`9(V$9@1";(V$3EU.=4Y5__X@;(I<$"@`&4B`+
XM.T#__D*G+RR*7$ZZ(XA03S`LC81(P..`0>R++#(P"`!(P2\!,"R-A$C`XX!!L
XM[(ID,C`(`$C!+P$O+(I<3KHC,D_O``PP+(V$2,#C@$'LC+PR,`@`2,$O`3`LQ
XMC81(P..`0>R+]#(P"`!(P2\!+RR*7$ZZ(NQ/[P`,,"R*8#(LC81(P>.!0>R+&
XM+)!P&`!30$C`+P`P+(IB,BR-A$C!XX%![(IDD'`8`%-`2,`O`"\LBEQ.NB*L&
XM3^\`##`LBF`R+(V$2,'C@4'LC+R0<!@`4T!(P"\`,"R*8C(LC81(P>.!0>R+?
XM])!P&`!30$C`+P`O+(I<3KHB;$_O``PP+(V$2,#C@$'LBRPR,`@`2,$O`3`LR
XMC81(P..`0>R*9#(P"`!(P2\!+RR*7$ZZ(CA/[P`,,"W__DC`+P`O+(I<3KHBC
XM6E!/3EU.=4Y5```Y;(VJC:0Y;(VLC:8Y;(VNC:@_/`"`2&R-JDALC9Y(;(VDG
XM3KK\E$_O``X_/`"`2&R-K$ALC:!(;(VF3KK\?$_O``X_/`"`2&R-KDALC:)(U
XM;(VH3KK\9$_O``XP+(VNYD!(P"\`,"R-K.9`2,`O`#`LC:KF0$C`+P!(>``!L
XM(&R*6$AH`"Q.NB'83^\`%$Y=3G5.5?_X3KH3K$*G3KH@8%A/*T#_^$ZZ^T)"M
XMK?_\3KK\>DZZ_-Y"IT*G3KHA$%!/2H!F``#"4JW__`RM````9/_\;=I.NO\HL
XM0J="ITZZ(.Y03TJ`9@``H"!M__@,*``*``EF#DAX_^PO+?_X3KH@X%!/3KK]`
XMJDZZ_").NOR&3KK]GDZZ_!9.NOQZ(&W_^`PH``H`"68.2'C_["\M__A.NB"NH
XM4$].NOUX3KK[\$ZZ_%1.NOUL3KK[Y$ZZ_$@@;?_X#"@`"@`)9@Y(>/_L+RW_0
XM^$ZZ('Q03TZZ_49.NON^3KK\(DZZ_3I.NONR3KK\%DZZ_GY@`/]4,"R*)$C`$
XM<@'AH2\!+RR*#$ZZ(%903T*G3KH@7EA/3EU.=4Y5_\P,+0`N``EG``4(,"T`F
XM"DC`P+P````#L+P`````5L#`?``!.T#_TC`M``I(P,"\````"+"\`````%;`1
XMP'P``3M`_]!"K?_,*VR":/_48"H@;?_4$"@`!+`M``EF%"!M_]00*``%2(#``
XM?``!L&W_TF<.(&W_U"M0_]1*K?_49M!";?_@2JW_U&<6(&W_U$JH``AG#"!M]
XM_]0K:``(_]A@8$'L@$8K2/_8#"T`(``)9@92K?_88$IP0;`M``EN$`PM`%H`X
XM"6X(&6T`"8!&8#)P,+`M``EN)@PM`#D`"6X>$"T`"4B`.T#_X`QM`##_X&8&C
XM!FT`"O_@4JW_V&`$8``$%$)M__9"ITZZ(`I83RM`__Q*;?_09@`!,$JM_]1GH
XM#B!M_]0(*``"``5F``$<2FW_X&8``10@;(H`*V@`//_N8```_B!M_^XK:``$Z
XM__)@``#@(&W_\DJH`%9G``#,(&W_\B)H`%8K:0`0_^H@;?_J#"@`#0`(9@``Z
XML"!M_^I*J`"L9UP@;?_J("@`K.6`*T#_XB\M_]@@;?_B("@`$.6`+P!.N@/@:
XM4$]*0&<R#&T`%/_V;"H@;(H`(F@`-+/M__)F!BMM__+_S#`M__92;?_V2,#ER
XM@$'LC;`AK?_R"`!@2"\M_]@@;?_J+R@`"DZZ`S!03TI`9S(,;0`4__9L*B!L$
XMB@`B:``TL^W_\F8&*VW_\O_,,"W_]E)M__9(P.6`0>R-L"&M__((`"!M__(KF
XM4/_R2JW_\F8`_QP@;?_N*U#_[DJM_^YF`/[^2FW_T&8``29*K?_49PX@;?_4$
XM""@``0`%9@`!$B!LC@`B:``B(!'E@"M`_^8[?``!__A@``#H,"W_^$C`Y8`@S
XM;?_F2K`(`&<``-!*;?_@9Q`P+?_@D'P`,+!M__AF``"Z,"W_^$C`Y8`@;?_FW
XM(G`(`"MI`!#_ZB!M_^H@*`"LY8`K0/_B(&W_XDJH`"QF``"*+RW_V"!M_^(@_
XM*``0Y8`O`$ZZ`II03TI`9VX@;(E\0J@`'$*G0J="IT*G0J="IR`LB7SD@"\`?
XM2'@`&2!M_^HO*`"D3KH.%$_O`"0@;(E\*V@`'/_R9S(,;0`4__9L*B!LB@`BP
XM:``TL^W_\F8&*VW_\O_,,"W_]E)M__9(P.6`0>R-L"&M__((`%)M__@P+?_X;
XM2,`@;?_FL)!M`/\,2FW_TF<&!BT`9``)2FW_T&8&2FW_]F8V+RW__$ZZ':98[
XM3TJM_]1G``%X(&W_U$JH``QG``%L0J="IR!M_]0O*``,3KH9G$_O``Q@``%0X
XM#&T``?_V9@HK;(VP__)@``#B2JW_S&=\*VW_S/_R0FW_^&!D,"W_^$C`Y8!!+
XM[(VP(FW_\K/P"`!C!'`!8`)P`#(M__A(P>6!0>R-L")P&`"S[?_,8P1R`6`"^
XM<@"S0"!M__*Q[?_,8P1R`6`"<@"S0&<2,"W_^$C`Y8!![(VP*W`(`/_R4FW_C
XM^#`M__BP;?_V;9)@7D*M__)";?_X8#X0+0`)2(!(P.6`0>R";#(M__A(P>6!:
XM0^R-L"QP"`"]\1@`9A80+0`)2(!(P.6`0>R";"MP"`#_\F`.4FW_^#`M__BPD
XM;?_V;;A*K?_R9@8K;(VP__(0+0`)2(!(P.6`0>R";"&M__((`"!M__(K:``N\
XM_^XO+?_\3KH<8%A/+RW_[DZZ'$I83R!M_^XB:``$L^W_\F8((&W_\DJ09PHO,
XM+?_R3KH<2EA/+RW_\DZZ&^183TY=3G5"ITZZ&_!83V#R3E4``$CG`#`D;0`(L
XM)FT`#`P3`"IF"G`!3-\,`$Y=3G5*$V8,2A)F!'`!8`)P`&#H2A)F!'``8.`04
XM$K`39R`0$TB`T'P`(!(22(&P068,#!(`86T&#!(`>F\$<`!@NE**4HM@K&"RA
XM3E7__B!M``A2K0`(<``0$#M`__X@;0`,#!``*F8&<`%.74YU(&T`#$H09@Y*?
XM;?_^9@1P`6`"<`!@YDIM__YF!'``8-P@;0`((FT`#!`0L!%G,"!M``P0$$B`0
XMT'P`("!M``@2$$B!L$%F%"!M``@,$`!A;0H@;0`(#!``>F\$<`!@GE*M``A2%
XMK0`,4VW__F"$8(Y.50``+P08+0`)N#P`(&\8N#P`/6<2N#P`.F<,N#P`+&<&?
XMN#P`+68$<`%@`G``*!].74YU3E4``"\*)&T`"$H29Q(0$DB`/P!AME1/2D!GA
XM!%**8.H@"B1?3EU.=4Y5``!(YP`P)&T`#"9M``A*$F<J<&&P$FX8#!(`>FX2=
XM($M2BR)*4HH0$9`\`"`0@&`*($I2BB)+4HL2D&#20A,@+0`(3-\,`$Y=3G5.8
XM50``2'H`%DZZ"RA83TALC@1.N@L>6$].74YU17)R;W(@:6X@<W1A<G1U<"!F5
XM:6QE(0``3E4``$CG`#`D;0`()FT`#`P3`")G!&&T8"Q2BPP3`")G'DH39QH,O
XM$P!<9@A**P`!9P)2BR!+4HLB2E**$I!@W$H39P)2BT(2+PM.NO\,6$],WPP`I
XM3EU.=4Y5__9(YP`P)&T`"$)M__X_/``'2'H#)"\*3KH'P$_O``I*0&8B($I>_
XMB"\(3KK^TEA/)$`O"B!M``Q(:``:3KK_:%!/8``"\#\\``=(>@+T+PI.N@>(H
XM3^\`"DI`9E0@2EZ(+PA.NOZ:6$\D0$)M__QP,+`2;B(,$@`Y;AP@2E**$!!(I
XM@#(M__S#_``*T$&0?``P.T#__&#82FW__&X&.WP!+/_\(&T`##%M__P`%F``+
XM`H8_/``%2'H"DB\*3KH''D_O``I*0&8.(&T`##%\``$`&&```F(_/``%2'H"Q
XM="\*3KH&^D_O``I*0&8.(&T`##%\__\`&&```CX_/``%2'H"5B\*3KH&UD_OL
XM``I*0&84.WP``?_^($I:B"\(3KK]XEA/)$!*$F8(3KK^2F```@@0*@`!2(`_^
XM`$ZZ_9)43TI`9S)P0;`2;@8,$@!:;PQP,+`2;B`,$@`Y;AH0$DB`.T#_^B!*.
XM4H@O"$ZZ_9983R1`8```A#\\``5(>@'B+PI.N@9<3^\`"DI`9A8[?``@__H@A
XM2EJ(+PA.NOUH6$\D0&!6#!(`1F9$<#&P*@`!;CP,*@`Y``%N-%**($I2BA`09
XM2("0?``P.T#__`QM``'__&8.#!(`,&8(.WP`"O_\4HHO"DZZ_1Y83R1`8`Q.8
XMNOV(3-\,`$Y=3G4_/``)2'H!9B\*3KH%VD_O``I*0&84".T``?__2&H`"4ZZT
XM_.A83R1`8"H_/``#2'H!1B\*3KH%L$_O``I*0&84".T``O__($I6B"\(3KK\Z
XMO%A/)$`O"DALCFA.NOU64$\D0$ALCFA.N@-"6$](P$'LCFG0B"M`__9*$F<<I
XM0>R.:")*D\A![(X$T\@O"2\M__9.NOT@4$]@!B!M__9"$"\M__9.N@,&6$\_3
XM`$ALCFA.N@+Z6$\R'])`TGP`$CM!__Q(>0`!``$P+?_\2,`O`$ZZ%/I03R9`\
XM(`MG7!=M__L`!!=M__\`!2:L@F@W;?_\``9(;(YH2&L`$$ZZ`J!03R=```@OL
XM+?_V2&R.:$ZZ`IY83TC`($#1RTAH`!%.N@)^4$\G0``,(&L`#$H09@1"JP`,.
XM*4N":&`*2'H`0DZZ!W183V``_K9#3TU-04Y$`%1)345/550`3$E.15,`0DQ!Z
XM3DL`4TA)1E0`4U!!0T4`24Y454E424].`$-,20!/=70@;V8@;65M;W)Y(&EN[
XM('-T87)T=7```$Y5__A(>@"6+RT`"$ZZ`YQ03RM`__QG;"\M__P_/`!D2&R.`
XM!$ZZ`@)/[P`*2D!G4DALC@1.NOM`6$\K0/_X(&W_^`P0`"IG."!M__@,$``C9
XM9RX@;?_X#!``.V<D(&W_^$H09QPO+?_X2&R.:$ZZ^S!03R\M``Q(;(YH3KK[`
XM^E!/8)9@%$AZ`!A.N@:26$\O+0`(3KH&B%A/3EU.=7(`0V]U;&1N)W0@;W!E)
XM;B!S=&%R='5P(&9I;&4Z`$Y5```9?``!@E(Y;0`(@E0Y;0`*@E9"IS`M`!!(2
XMP"\`+RT`#$AL@DY.NA6@3^\`$$I`9@9P`$Y=3G4@+0`,8/9.50``0J=(;([,#
XM2'C__TAZ`").NA/23^\`$$J`9PI"K([\<`%.74YU*6R.X([\<`!@\F-O;G-O@
XM;&4N9&5V:6-E``!.50``2JR._&<*2&R.S$ZZ$>183W``3EU.=4Y5_YPO!'@`\
XM0>R)@!&\`"Y``%)$N'P`@&WN88A*0&<(<`$H'TY=3G5X`$(M_YT_/`!D2&W_T
XMG$)G/P1.NO\H3^\`"DJ`9T!*+?^=9CH,+0`@_YQG*'!AL"W_G&X0#"T`>O^<[
XM;@@$+0`@_YQF$'`PL"W_G&X2#"T`.?^<;@I![(F`$:W_G$``4D2X?`"`;9QX/
XM4#`$D'P`3T'LB8`1@$``4D2X?`!:;>I.NO\^<`!@`/]T(&\`!"`((F\`"!#9F
XM9OQ.=2!O``0@"$H89OR1P"`(4X!.=4Y5``!(YP@@)&T`"%-M``Q*;0`,;R`O3
XM+0`.3KH`.#@`L'S__UA/9PX@2E**$(2X?``*9P)@UD(2N'S__V80M>T`"&8*&
XM<`!,WP003EU.=2`M``A@\DY5``!(YP@@)&T`""\*3KH`,C@`L'S__UA/9R(P,
XM!$C`8!13D@CJ``,`#'#_3-\$$$Y=3G5@UDJ`9_I9@&?D,`1@ZDY5```O"B1MR
XM``@@4K'J``1E#"\*81983R1?3EU.=2!24I(0$$B`P'P`_V#L3E4``$CG"#`D%
XM;0`($"H`#,`\`!AG"G#_3-\,$$Y=3G4(J@`"``Q*J@`(9@@O"DZZ"S183Q`JO
XM``Q(@`@```=G,$'L@(`F2!`K``Q(@,!\`(2P?`"$9@P_//__+PM.N@GL7$_7X
XM_````!9![((XM\AEUC\J`!`O*@`($"H`#4B`/P!.N@)N.`!*0%!/;A1*1&8$N
XM<`A@`G`0@2H`#'#_8`#_>C`$2,`DJ@`(T*H`""5```0@4E*2$!!(@,!\`/]@O
XM`/]:3E4``"\*3KH*9"1`2H!F"'``)%].74YU+PHO+0`,+RT`"&$&3^\`#&#HF
XM3E4``$CG""`O+0`03KH(SD'L@$HD2%A/2A)F$#E\``6/`'``3-\$$$Y=3G4@F
XM2B)M``P0&+`99@1*`&;VD"%(@&<$7(I@TC\J``0O+0`(3KH`<#@`L'S__UQ/X
XM9@1P`&#$(&T`$!%$``T@;0`0$7P``0`,("T`$&"L,#Q__V`$,"\`#%-`:Q0@(
XM;P`$(F\`"+$)9@Q32$H85\C_]G``3G5C!'`!3G5P_TYU3E4``#\M``P_/`,!C
XM+RT`"&$&4$].74YU3E4``$CG#S`D;0`(3KH+UB9LCP)X`&`.,`3!_``&2K,(P
XM`&<.4D2X;((X;>QZ!F```,0(+0`!``QG,$AX__\O"DZZ#=0L`%!/9R`O!DZZN
XM#A`O"DZZ#8Q*@%!/9@Y.N@VD.@"P?`#-9@``C$AX`^TO"DZZ#;8L`$J&4$]FH
XM8`@M````#&8$>@%@;$AX`^XO"DZZ#9@L`%!/9@A.N@UH.@!@5$AX`"%(>@"2"
XM3KH/O"X`4$]G"B\'3KH-]EA/8!Y(>``!2'H`@B\&3KH-HDAX__]"IR\&3KH-9
XM>$_O`!A@)C`M``S`?`4`L'P%`&88+P9.N@S:>@183SE%CP!P_TS?#/!.74YU&
XM,`3!_``&)X8(`#`$P?P`!B!`T<LQ;0`,``0(+0`#``QG$$AX``%"IR\&3KH-\
XM'D_O``PP!&#"9&]S+FQI8G)A<GD```!.50``2.<,(#@M``A.N@J0,`3!_``&K
XM)$#5[(\"2D1M"KAL@CAL!$J29A`Y?``"CP!P_TS?!#!.74YU,"H`!,!\``.PJ
XM?``!9@HY?``%CP!P_V#@<``P+0`.+P`O+0`*+Q).N@R6*@"PO/____]/[P`,<
XM9@Q.N@Q(.4"/`'#_8+0@!6"P3E7__$CG`#!"IT*G3KH,XB9`2H!03V8*<`!,.
XMWPP`3EU.=4AY``$``4AX`$1.N@VL)$!*@%!/9@PO"TZZ#4!P`%A/8-8@2M'\S
XM````%"5(``HE2@`4)4L`&"5M``P`'"5M`!``*"5M`!0`+"5M`!@`,"5M`!P`T
XM-"5M`"``."5M`"0`/"5M`"@`0"\*+RT`"$ZZ#B8O"TZZ#IPO"TZZ#<8K:@`@9
XM__Q(>`!$+PI.N@V6+PM.N@S*("W__$_O`!Q@`/]<3E4``"\*)&T`"$H29R`@0
XM2E**$!!(@#\`3KH$OK!\__]43V8(</\D7TY=3G5@W#\\``I.N@2D5$]@[&%PC
XM0^R"0D7L@D*UR68.,CP#06L(=``BPE')__PI3X\&+'@`!"E.CPI(YX"`""X`6
XM!`$I9Q!+^@`(3J[_XF`&0J?S7TYS0_H`($ZN_F@I0(X`9@PN/``#@`=.KO^4<
XM8`1.N@`:4$].=61O<RYL:6)R87)Y`$GY``!__DYU3E4``"\*2'D``0``,"R"/
XM.,'\``8O`$ZZ#%(I0(\"4$]F%$*G2'D``0``3KH+$%!/+FR/!DYU(&R/`D)H)
XM``0@;(\",7P``0`0(&R/`C%\``$`"B!LCP8@+(\&D*@`!%"`*4"/#B!LCPX@1
XMO$U!3EA"ITZZ#$0D0$JJ`*Q83V<N+RT`#"\M``@O"DZZ`*XY?``!CQ(@;(\"@
XM`&B````$(&R/`@!H@```"D_O``Q@0DAJ`%Q.N@T02&H`7$ZZ##@I0(\4(&R/;
XM%$JH`"103V<0(&R/%")H`"0O$4ZZ"<!83R\LCQ0O"DZZ`HPI;(\4CQA03TZZH
XM"<X@;(\"((!.N@H`(&R/`B%```9G%DAX`^U(>@`J3KH)W"!LCP(A0``,4$\O(
XM+(\8/RR/'$ZZVK!"9TZZ!]903R1?3EU.=2H`3E4``$CG##`D;0`0(&T`"$JHY
XM`*QG&"!M``@@*`"LY8`H`"!$("@`$.6`)D!@!"9L@CH0$TB`2,#0K0`,5(`Y#
XM0(\>0J<P+(\>2,`O`$ZZ"N0I0(\@4$]F"$S?##!.74YU$!-(@#H`/P4@2U*(T
XM+P@O+(\@3KH!?C`%2,`@0-'LCR!#^@%$$-EF_#\M``XO"B\LCR!.N@$Z(&R/Y
XM($(P4``Y?``!CQPP!4C`T*R/("9`4HLD2T_O`!00$TB`.@"P?``@9QBZ?``)>
XM9Q*Z?``,9PRZ?``-9P:Z?``*9@12BV#8#!,`(&UZ#!,`(F8N4HL@2U*+$!!(E
XM@#H`9QX@2E**$(6Z?``B9A`,$P`B9@12BV`&0BK__V`"8-9@."!+4HL0$$B`@
XM.@!G)KI\`"!G(+I\``EG&KI\``QG%+I\``UG#KI\``IG""!*4HH0A6#.($I2-
XMBD(02D5F`E.+4FR/'&``_UI"$D*G,"R/'%)`2,#E@"\`3KH)PBE`CQA03V8(U
XM0FR/'&``_MAZ`"9LCR!@)#`%2,#E@"!LCQ@ABP@`($L@"$H89OR1P%.(,`A2D
XM0$C`U\!21;ILCQQMUC`%2,#E@"!LCQA"L`@`8`#^E"``,#Q__V`$,"\`#"!OS
XM``1*&&;\4T@B;P`(4T`0V5?(__QG`D(0("\`!$YU3.\#```$(`@R+P`,8`(0L
XMV5?)__QG!E)!8`)"&%')__Q.=4CG<``T`<3`)@%(0\;`2$-"0]2#2$#`P4A`0
XM0D#0@DS?``Y.=4Y5``!(YPXP)&T`"$*G2'H`CDZZ":8I0(\D4$]F"$S?#'!.'
XM74YU(&T`#")H`"0O*0`$3KH*G"@`6$]G4DAZ`&T@1"\H`#9.N@IN)D!*@%!/H
XM9S1(>`/M+PM.N@<B+`!03V<D(`;E@"H`($4E:``(`*0E1@"<2'@#[4AZ`#A.>
XMN@;^)4``H%!/+P1.N@HZ6$\O+(\D3KH':$*LCR183V"`:6-O;BYL:6)R87)Y!
XM`%=)3D1/5P`J`$Y5``!(;("6/RT`"$ZZ``A<3TY=3G5.50``+P0X+0`(+RT`K
XM"C\$3KH`,+A\``I<3V8D(&T`"A`H``Q(@`@```=G%#\\__\O+0`*3KH`]%Q/K
XM*!].74YU8/A.50``+PHD;0`*(%*QZ@`$91@P+0`(P'P`_S\`+PI.N@#(7$\D)
XM7TY=3G4@4E*2$"T`"1"`2(#`?`#_8.A.50``+PI![("`)$@@2M7\````%B\(!
XM81!83T'L@CBUR&7J)%].74YU3E4``$CG""`D;0`(>``@"F8*</],WP003EU.(
XM=4HJ``QG4`@J``(`#&<,/SS__R\*85(X`%Q/$"H`#4B`/P!.N@4<B$`(*@`!9
XM``Q43V<*+RH`"$ZZ`BY83P@J``4`#&<2+RH`$DZZ`L`O*@`23KH"%%!/0I)"/
XMJ@`$0JH`"$(J``PP!&"03E7__DCG""`D;0`(0?K_1BE(CR@(*@`$``QG"G#_8
XM3-\$$$Y=3G4(*@`"``QG,"!2D>H`"#@(/P0O*@`($"H`#4B`/P!.N@*`L$10Y
XM3V<0".H`!``,0I)"J@`$</]@P`QM__\`#&80"*H``@`,0I)"J@`$<`!@J$JJ$
XM``AF""\*3KH`FEA/#&H``0`09BH;;0`-__\_/``!2&W__Q`J``U(@#\`3KH"I
XM(K!\``%03V:@,"T`#&``_VHDJ@`(,"H`$$C`T*H`""5```0(Z@`"``P@4E*2O
XM$"T`#1"`2(#`?`#_8`#_/DY5```O"D'L@(`D2$HJ``QG&-7\````%D'L@CBUQ
XMR&4(<``D7TY=3G5@XD*20JH`!$*J``@@"F#J3E7__"\*)&T`"#\\!`!.N@#`[
XM*T#__%1/9A@U?``!`!`@2M'\````#B5(``@D7TY=3G4U?`0``!`(Z@`!``PE=
XM;?_\``@0*@`-2(`_`$ZZ`.)*0%1/9P8`*@"```Q@SDY5``!(YP`P)&R"9&`42
XM)E(@*@`$4(`O`"\*3KH%VE!/)$L@"F;H0JR"9$S?#`!.74YU3E4``"\*0?K_Z
XMQBE(CRQ"IR`M``A0@"\`3KH%0B1`2H!03V8(<``D7TY=3G4DK()D)6T`"``$N
XM*4J"9"`*4(!@YDY5``!P`#`M``@O`&&R6$].74YU3E4``$CG`#"7RR1L@F1@B
XM#B!M``A1B+'*9Q(F2B12(`IF[G#_3-\,`$Y=3G4@"V<$)I)@!"E2@F0@*@`$)
XM4(`O`"\*3KH%+'``4$]@V$Y5```O"C`M``C!_``&)$#5[(\"2FT`"&T.,"T`)
XM"+!L@CAL!$J29@XY?``"CP!P_R1?3EU.=3`M``C!_``&(&R/`B\P"`!.N@+82
XM2H!83V<$<`%@`G``8-A.50``+RT`"$ZZ`I1*@%A/9@Y.N@*L.4"/`'#_3EU.'
XM=7``8/A.50``2.<,(#@M``A.N@!P,`3!_``&)$#5[(\"2D1M"KAL@CAL!$J2\
XM9A`Y?``"CP!P_TS?!#!.74YU,"H`!,!\``-F"CE\``6/`'#_8.1P`#`M``XO+
XM`"\M``HO$DZZ`J8J`+"\_____T_O``QF#$ZZ`BPY0(\`</]@N"`%8+1.5?_\!
XM2'@0`$*G3KH$T"M`__P(```,4$]G$DILCQ)F""`M__Q.74YU3KH`!G``8/1."
XM50``2'@`!$AZ`!Q.N@(4+P!.N@)"/SP``4ZZ``Y/[P`.3EU.=5Y#"@!.50``J
XM2JR/*&<&(&R/*$Z0/RT`"$ZZ``A43TY=3G5.5?_\+P0P+0`(2,`K0/_\2JR/Y
XM`F<H>`!@"C\$3KH`_E1/4D2X;((X;?`P+((XP?P`!B\`+RR/`DZZ`WA03TJL\
XMCRQG!B!LCRQ.D$JL@CYG"B\L@CY.N@&H6$]*K(\P9P@@;(\P(*R/-$JLCSAG)
XM"B\LCSA.N@'<6$]*K(\\9PHO+(\\3KH!S%A/2JR/0&<*+RR/0$ZZ`;Q83TJL.
XMCT1G"B\LCT1.N@&L6$\L>``$""X`!`$I9Q0O#4OZ``I.KO_B*E]@!D*G\U].U
XM<TJLCQ1F,$JLCR!G*#`LCQY(P"\`+RR/($ZZ`M`P+(\<4D!(P.6`+P`O+(\8Q
XM3KH"O$_O`!!@#DZZ`J8O+(\43KH#0%A/("W__"YLCP9.=2@?3EU.=4Y5``!(\
XMYPX@."T`"#`$P?P`!B1`U>R/`DI$;0JX;((X;`1*DF80.7P``H\`</],WP1PH
XM3EU.=0@J``<`!&8(+Q).N@`.6$]"DG``8.).^@`"(B\`!"QLC@!.[O_<(B\`*
XM!"QLC@!.[O^"(B\`!"QLC@!.[O^X3.\`#@`$+&R.`$[N_R(L;(X`3N[_RBQLH
XMC@!.[O]\(B\`!"QLC@!.[O\H3.\`!@`$+&R.`$[N_ZQ.^@`"3.\`!@`$+&R.J
XM`$[N_^(L;(X`3N[_Q$SO``X`!"QLC@!.[O_63.\`#@`$+&R.`$[N_[Y.^@`"\
XM(B\`!"QLC@!.[O^F3.\`#@`$+&R.`$[N_]!(YP$$3.\@@``,+&R/"DZN_Y1,!
XMWR"`3G4B+P`$+&R/"D[N_R@B;P`$+&R/"D[N_CY.^@`"(F\`!"QLCPI.[OYB5
XM3E4``$CG""!(>/__3KH`T"@`L+S_____6$]F"G``3-\$$$Y=3G5(>0`!``%(?
XM>``B3KH`N"1`2H!03V8,+P1.N@$F<`!83V#6)6T`"``*%6T`#P`)%7P`!``(C
XM0BH`#A5$``]"ITZZ`-`E0``02JT`"%A/9PHO"DZZ`%I83V`*2&H`%$ZZ`/Y8_
XM3R`*8)).50``+PHD;0`(2JH`"F<(+PI.N@$T6$\5?`#_``@E?/____\`%'``C
XM$"H`#R\`3KH`JDAX`"(O"DZZ`(Q/[P`,)%].74YU(F\`!"QLCPI.[OZ>("\`!
XM!"QLCPI.[OZV3OH``DSO``,`!"QLCPI.[O\Z2.<`,$SO#@``#"QLCPI.KO[F<
XM3-\,`$YU2.<#`")O``PL;(\*3J[^.$S?`,!.=2)O``0L;(\*3N[^>D[Z``(B`
XM;P`$+&R/"D[N_MI.^@`"+&R/"D[N_WQ.^@`"(F\`!"`O``@L;(\*3N[_+B`O)
XM``0L;(\*3N[^L$[Z``(@;P`$+&R/"D[N_HP@;P`$((A8D$*H``0A2``(3G4@8
XM;P`$3.\"`0`((B\`$"QLCPI.[OY$3OH``BQLCPHB;P`$("\`"$[N_=@L;(\*R
XM3N[_=DSO`P``!"QLCPI.[OZ2(F\`!"QLCPI.[OZ8(F\`!"QLCPI.[O[@(F\`Y
XM!"QLCPI.[OZ&(F\`!"QLCPI.[OXR3OH``DSO``,`!"QLCPI.[O[.(F\`!"`O0
XM``@L;(\*3N[^U")O``0@+P`(+&R/"D[N_KP@+P`$+&R/"D[N_L).^@`"(&\`S
XM!"QLCPI.[OZ`(F\`!$SO``,`""QLB@1.[O\*(F\`!$SO``,`""QLB@1.[O\0!
XM(F\`!$SO``\`""QLB@1.[O[.(F\`!"`O``@L;(H$3N[^JB!O``1,[P`/``@L<
XM;(H$3N[^X$SO`P``!"QLCR1.[O^@(&\`!"QLCR1.[O^F(&\`!"QLCR1.[O^R&
XM(&\`!"QLB@!.[OX^(&\`!"QLB@!.[O^^(&\`!"QLB@!.[O^@+&R*`"`O``1.N
XM[OYB(&\`!"QLB@!.[O\Z(&\`!"QLB@!.[O\$+&R*`"!O``1.[OY<+&R*`$[N5
XM_JH@;P`$+&R*`$[N_L@O"DSO`P``"$SO!`(`$"QLCOQ.KO_0)%].=0```^P`1
XM```!`````0``)>@````````#\@```^H```"0````!``````!0``>``$``0``F
XM``\```````````````````````````*``9```0`!@00`#P``````````````X
XM```````@*@``<@``````<BL````"=P````,!=RL```,"80````D!82L```D"_
XM>`````4!>"L```4"`````````````````````````0`````!````````````J
XM``````````$!`````0`````````````````````!`@````$`````````````'
XM`````````````````````````````````````````````````````````````
XM`````````````````````````````````````````````````````````````
XM`````````````````````````````````````````````````````````````
XM`````````````````````````````````````````````````````````````
XM`````````````````````````````````````````````````````````````
XM`````````````````````````````````````````````````````````````
XM`````````````````````````````````````````````````````````````
XM`````````````````````````````````````````````````````````````
XM````````````%``````````````#[`````$```````````````````/R```#\
X)ZP````$```/RA
X``
Xend
//END_OF_FILE
echo x - makefile
sed 's/^X//' > makefile << '//END_OF_FILE'
Xmackie: mackie.o
X	ln mackie.o -lc
X
Xmackie.o: mackie.c
X	cc mackie.c
//END_OF_FILE
echo "End of archive."
# end of archive.
exit 0