[comp.sources.amiga] v89i117: memdiag - memory diagnostic tools

page%swap@Sun.COM (Bob Page) (05/09/89)

Submitted-by: jc3b21!fgd3@uunet.UU.NET (Fabbian G. Dufoe)
Posting-number: Volume 89, Issue 117
Archive-name: kernel/memdiag.1

The memory diagnostic program (MD) identifies addresses which cause
memory errors.  The memory quarantine program (MQ) removes defective
addresses from the system's memory free list.

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	ReadMe
#	MD.doc
#	MQ.doc
#	Memory.doc
#	AddAddr.c
#	MD.c
#	MQ.c
#	MD.uu
#	MQ.uu
# This is archive 1 of a 1-part kit.
# This archive created: Mon May  8 11:35:21 1989
echo "extracting ReadMe"
sed 's/^X//' << \SHAR_EOF > ReadMe
X     This archive contains source code, executables, and documentation for
XMD, a memory diagnostic program, and MQ, a program to quarantine defective
Xmemory locations.  Both programs are public domain.  When you unpack the
Xarchive you should have the following files:
X
X     ReadMe--This file
X     AddAddr.c--Source for a function used in MD
X     Makefile--input for Lattice lmk to compile and link MD and MQ
X     MD*--Executable memory diagnostic program
X     MD.c--Source for memory diagnostic
X     MD.doc--Documentation for memory diagnostic
X     MD.uue*--Uuencoded executable memory diagnostic program
X     Memory.doc--Background information on the Amiga's memory management
X     MQ*--Executable memory quarantine program
X     MQ.c--Source for memory quarantine
X     MQ.doc--Documentation for memory quarantine
X     MQ.uue*--Uuencoded executable memory quarantine
X
X*Archives will contain either the executable programs or the uuencoded
X executables, but not both.
X
X     MD will run with any Amiga configuration but requires a stack size of
X10000.  It does not take over the machine but it does soak up any available
Xmemory while it is running.  It takes about 8 minutes to test a 2.5MB
Xmachine.
X
X     MQ will run with any Amiga configuration and a stack size as small as
X4000.  It suspends multi-tasking during its execution but only requires
Xabout one second to run.
SHAR_EOF
echo "extracting MD.doc"
sed 's/^X//' << \SHAR_EOF > MD.doc
XMD--Memory Diagnostic
X
XSYNOPSIS: (CLI environment)
X
X     stack 10000
X     MD [>reportfile] [-qaddressfile]
X
X
XDESCRIPTION:
X
X     MD is a memory diagnostic program.  It tests your system's memory and
Xreports any addresses where errors occur.  A memory error occurs when the
Xvalue read from an address is not the value which was stored there.
X
X     MD runs from the Command Line Interface (CLI).  It requires a stack
Xsize of 10000 bytes.  It writes its report to standard output.  It also
Xsends status messages to standard error. If you want to save the report for
Xlater review (and separate it from the status messages) redirect standard
Xoutput to a file (for example, "MD >MD.rpt").
X
X
XCOMMAND LINE OPTIONS:
X
X     The "-q" option builds a file of bad addresses for use by MQ, the
Xmemory quarantine program.  Specify the filename to which you want the
Xaddresses written immediately after the q without a space.  The file will
Xcontain a list of addresses where MD found an error.
X
X     If you suspect intermittent memory problems you should run MD
Xrepeatedly, saving the output to different files.  By comparing several
Xreports you can identify addresses which fail occasionally.  The quarantine
Xfiles MD produces are ASCII characters so you can edit them as necessary to
Xbuild a complete list of defective addresses.
X
X     MD tests memory by comparing values read from an address with a known
Xvalue previously written to that address.  It does not interfere with other
Xtasks in the system (except by soaking up memory which they might need).  It
Xsends its report to standard output so it can be redirected to a disk file
Xor printer.
X
X
XINPUT:
X
X     MD does not read external data.
X
X
XOUTPUT:
X
X     The diagnostic report begins with a header identifying the program,
Xauthor, and version, and the time of the test.  Next it lists the blocks of
Xmemory it examined.  The listing gives the block's number, address (in
Xhexadecimal notation), and size (in decimal).  Errors are listed as they are
Xencountered, one to a line.  The line identifies the address where the error
Xoccurred, the value found at that address, and the value MD expected to
Xfind.  All values are hexadecimal.  For example:
X
X          ERROR! Address:   21646C  found: 20  expected:  0
X
XAt the end of the report MD records the number of errors it found.
X
X     As MD executes it displays status messages.  The messages advise the
Xuser MD is allocating blocks, sorting them, initializing blocks, and testing
Xthem.  They identify the block number and its size as well as the value used
Xto initialize or test it.
X
X     If the -q option is specified on the command line MD will list all the
Xaddresses where memory errors occurred to the specified file.  The addresses
Xare expressed as ASCII characters representing hexadecimal values.  Each
Xaddress is on a separate line.  The addresses are sorted in ascending order
Xand there are no duplicates.
X
X
XEXECUTION:
X
X     MD takes about 8 minutes to test a 2.5MB machine.  During that time
Xthere will not be enough memory left to run other jobs.  When MD finishes,
Xhowever, it will release all the memory it used and other jobs can resume
Xwithout rebooting.  MD will not interfere with other jobs that are executing
Xwhen it is invoked but it is possible to create a deadlock if there are
Xother active jobs in the system.  Besides that, MD cannot test memory that
Xis allocated to another process.  Consequently, it is best to run MD
Ximmediately after booting the system.
X
X     The recommended way to run MD is to create a special Workbench boot
Xdisk with at least 200 free blocks.  Deleting the Utilities directory will
Xfree that much space from a standard Workbench disk.  Copy MD to the disk. 
XChange the Startup-Sequence file in the s directory to set the stack size to
X10000.  After booting with this disk use the date command to set the date
Xand time if necessary.  Then you can execute MD as many times as you wish,
Xdirecting the output to a different file each time.  By examining the
Xreports you can identify the addresses where memory errors occurred.
X
X
XPROGRAM LOGIC:
X
X     MD is quite simple.  It allocates all the memory the system will give
Xit.  Then it writes a value into each address.  It compares the value it
Xreads back with the one it wrote and if they're different it records the
Xerror.
X
X     The algorithm for allocating memory is straightforward.  MD begins by
Xrequesting a 1MB block of memory.  Each time its request is successful it
Xrepeats it.  When the request fails MD cuts its block size in half and tries
Xagain.  The iteration ends when MD can't get any 1-byte blocks.
X
X     MD sorts the blocks into ascending order so the report it produces will
Xbe a little easier to follow.  That's purely a cosmetic feature to make the
Xuser more comfortable.  (Remember, I was the user for whom it was written
Xand ordered lists make more sense to me.)
X
X     MD tests memory with four values.  They are 0, 0xff, 0x55, and 0xaa.
XThe test begins by initializing all the bytes in each block to 0.  Next the
Xcontents of each byte are compared to 0.  If the values don't match MD
Xreports the error.  It stores the next test value at that address and moves
Xon.  When all the memory has been checked for the first value and loaded
Xwith the next value MD makes a second pass through all the memory.  A third
Xpass checks for 0x55 and loads 0xaa.  The final pass looks for 0xaa in each
Xbyte.
X
X     At first glance it seems less efficient to make so many passes through
Xmemory.  Why not test all four values at each byte before moving on to the
Xnext address?  There are two reasons.  Had the program been written
Xsomething like this:
X
X          char *address;
X          for (address = start; address < end; address++)
X          {
X               *address = 0;
X               if (*address != 0)
X                    printf("ERROR! ...");
X               *address = 0xff;
X               if (*address != 0xff)
X                    printf("ERROR! ...");
X          }
X
Xthe compiler might outsmart you.  It could see that nothing is done with
X*address so it might keep it in a register to speed up the program.  It
Xwould be fast, all right, but it wouldn't tell you anything.
X
X     The second reason is to allow time for memory errors to occur.  The
Xapproach I used reduces the possibility that an address might hold the
Xcorrect value briefly but lose it after some time has passed.  I don't know
Xhow probable that is.  It seemed a good idea to prevent it anyway.
X
X     After all the blocks have been tested MD returns them to the system's
Xmemory free list.
X
X     Send questions, comments, or bug reports to:
X
X--Fabbian Dufoe
X  350 Ling-A-Mor Terrace South
X  St. Petersburg, Florida  33705
X  813-823-2350
X
XUUCP: ...uunet!pdn!jc3b21!fgd3
SHAR_EOF
echo "extracting MQ.doc"
sed 's/^X//' << \SHAR_EOF > MQ.doc
XMQ--Memory Quarantine
X
X
XSYNOPSIS: (CLI environment)
X
X     MQ [<addressfile] [>statusfile]
X
X
XDESCRIPTION:
X
X     MQ makes addresses which cause memory errors unavailable to the system. 
XIt works by removing those memory locations from the system's memory free
Xlist so they appear to be allocated to another process.  MQ is intended as a
Xtemporary fix for memory failures until you can replace the defective RAM
Xchips.
X
X     MQ runs from the Command Line Interface (CLI).  It reads data from
Xstandard input and writes a status message to standard output.
X
X
XCOMMAND LINE OPTIONS:
X
X     MQ does not recognize any command line options.
X
X
XINPUT:
X
X     MQ reads a list of addresses to be quarantined from standard input. 
XThe addresses must be in ascending order and expressed as ASCII characters
Xrepresenting hexadecimal values.  There can be a maximum of 100 addresses. 
XMQ will ignore any addresses beyond the first 100.  If necessary additional
Xaddresses can be quarantined by running MQ again with a different list. 
XMQ's companion program, MD (a memory diagnostic), can produce a file for
Xdirect input to MQ.
X
X
XOUTPUT:
X
X     When MQ finishes it writes a status message to standard output.  The
Xmessage tells the number of bytes that were quarantined.
X
X
XEXECUTION:
X
X     MQ's execution time is usually less than the time required to load the
Xprogram.  The entire process takes about a second.
X
X     The recommended way to use MQ is to put it in your Startup-Sequence
Xfile.  It should appear in the Startup-Sequence as early as possible.  MQ
Xwill fragment memory so certain applications may have to be run before you
Xcan run MQ.  For example, if you want a recoverable RAM disk (RAD:) you must
Xhave 880K of contiguous memory available.  If MQ doesn't leave you with that
Xlarge a block you can run MQ after you create your RAD: disk.  You will have
Xdefective memory in the RAD: disk but if it is in a location that isn't
Xaccessed it will be harmless.
X
X     Use MD to create a file of defective memory locations.  Then copy that
Xfile to your Workbench disk.  Add a line to your Startup-Sequence file
Xinvoking MQ with standard input redirected from the address list file.  Then
Xeach time you boot your system the defective memory locations will be
Xquarantined.
X
X
XPROGRAM LOGIC:
X
X     MQ searches the system's memory free list to find each chunk of free
Xmemory which contains one or more of the bad addresses it reads from
Xstandard input.  It modifies the memory free list so the bad addresses will
Xbe excluded.  The smallest block of memory that can be allocated is eight
Xbytes.  Thus the memory free list loses eight bytes for each bad address
Xthat is quarantined.  MQ does not keep track of the quarantined memory so
Xthere is no way to recover it without rebooting the system.
X
X     As MQ examines each block of memory it goes through its list of bad
Xaddresses.  If the block ends before the bad address MQ goes on to the next
Xblock.  If the block starts after the bad address MQ gets the next address.
XIf the bad address falls within the block MQ resizes the block to exclude
Xit.
X
X     Each block of memory is described by a MemChunk structure which
Xcontains a pointer to the next block and the size of the current block.  The
Xstructure is defined in exec/memory.h as follows:
X
X/****** MemChunk ****************************************************/
X
Xstruct   MemChunk
X{
X    struct  MemChunk *mc_Next;   /* pointer to next chunk */
X    ULONG   mc_Bytes;      /* chunk byte size   */
X};
X
X     MQ calculates the number of bytes between the start of the block and
Xthe bad address, then rounds it down to a multiple of 8.  That will be the
Xnew size of the block.  Let's call it Size1.  Then it adds that size plus 8
Xto the beginning address of the block to get the starting address of a new
Xblock.  We'll call it NewChunk.  To calculate the size of the new block MQ
Xadds 8 to Size1 and subtracts the result from the original block size. We'll
Xcall it Size2.
X
X     Because the original block may be as small as 8 bytes and because the
Xbad address may be within 8 bytes of either end of the block Size1 and Size2
Xmay be zero.  If Size2 is zero MQ simply reduces the size of the original
Xblock by storing Size1 in the original block's mc_Bytes field. Otherwise it
Xcreates a new block at NewChunk.
X
X     Each block of memory contains a pointer to the next block (mc_Next) and
Xthe size of the current block (mc_Bytes).  So MQ takes the next block
Xpointer from the original block and puts it at NewChunk->mc_Next.  Then it
Xputs Size2 at NewChunk->mc_Bytes.
X
X     If Size1 is zero MQ copies the address from the original block's
Xmc_Next field to the mc_Next field of the previous block.  If the previous
Xblock pointer is NULL the original block is the first one in the list.  In
Xthat case MQ copies the mc_Next field from the original block to the
Xmh_First field in the MemHeader structure.
X
X     Send questions, comments, or bug reports to:
X
X--Fabbian Dufoe
X  350 Ling-A-Mor Terrace South
X  St. Petersburg, Florida  33705
X  813-823-2350
X
XUUCP: ...uunet!pdn!jc3b21!fgd3
SHAR_EOF
echo "extracting Memory.doc"
sed 's/^X//' << \SHAR_EOF > Memory.doc
XMemory Management on the Amiga
X     by Fabbian G. Dufoe, III
X
X     Because AmigaDOS is a multi-tasking operating system it requires a more
Xcomplicated memory management scheme than most personal computer operating
Xsystems have.  Single-tasking systems can get by with setting the upper and
Xlower limits of the free memory region.  With different processes starting
Xand stopping independently free memory gets fragmented.  The system has to
Xknow where to find each fragment if it's to use memory efficiently.
X
X     AmigaDOS keeps a list of available memory.  When a process needs RAM it
Xasks the operating system to allocate some.  The system searches the memory
Xfree list to see if there is a big enough block available.  If so it
Xallocates it to the process and removes it from the memory free list.  When
Xthe process frees the memory the system returns it to the memory free list. 
XThe operating system doesn't keep track of which process allocated the
Xmemory, so if a process fails to return it there is no way to recover it
Xwithout rebooting the system.
X
X     Like everything in the Amiga's operating system, the path to the memory
Xfree list begins with a pointer to the exec library ExecBase structure.  The
XExecBase structure and all the structures and lists the system uses for
Xmemory management are defined in the include files listed in the ROM Kernel
XExec Manual.  These same files are supplied with your C compiler or
Xassembler.   They are also available in the Native Developer's Kit available
X>from Commodore Amiga Technical Support (CATS).
X
X     Opening the exec library returns a pointer to the ExecBase structure:
X
X     struct ExecBase *ExecBase;
X     ExecBase = (struct ExecBase *)OpenLibrary("exec.library, 0L);
X
X     The ExecBase structure is defined in exec/execbase.h.  One of the
Xfields in the ExecBase structure is MemList.  It's a List structure that
Xcontains pointers to the list of memory regions which make up the memory
Xfree list.  There is a MemList structure documented in the ROM Kernel Manual
Xand in exec/memory.h.  It is not related to the List structure named MemList
Xin the ExecBase structure.  The similar names could easily confuse you.
X  
X     Exec/lists.h defines a List structure as follows:
X
X     struct List { 
X         struct  Node *lh_Head;
X         struct  Node *lh_Tail;
X         struct  Node *lh_TailPred;
X         UBYTE   lh_Type;
X         UBYTE   l_pad;
X     };
X
XThe Node structure is defined in exec/nodes.h as follows:
X
X     struct Node { 
X         struct  Node *ln_Succ;
X         struct  Node *ln_Pred;
X         UBYTE   ln_Type;
X         BYTE    ln_Pri; 
X         char    *ln_Name; 
X     };
X
X     The memory free list is organized as a list of lists.  MemList points
Xto a list of memory regions.  A region is a block of contiguous memory from
Xwhich Exec can draw memory.  Each region is described by a MemHeader
Xstructure.  When the system is initialized it creates a region for chip RAM
Xand one for each expansion RAM board in the system.
X
X     If the expansion RAM boards occupy contiguous memory you can combine
Xtheir regions into one with a program called MergeMem.  MergeMem is in the
XSystem directory of the 1.3 Workbench disk.
X
X     The MemHeader structure is documented in exec/memory.h as follows:
X
X     struct     MemHeader {
X         struct  Node mh_Node;
X         UWORD   mh_Attributes;     /* characteristics of this region */
X         struct  MemChunk *mh_First; /* first free region          */
X         APTR    mh_Lower;          /* lower memory bound          */
X         APTR    mh_Upper;          /* upper memory bound+1          */
X         ULONG   mh_Free;          /* total number of free bytes     */ 
X     };
X
X     So the following gives the address of the first region in the memory
Xfree list:
X
X     struct MemHeader *MemHeader;
X     MemHeader = (struct MemHeader *)ExecBase->MemList.lh_Head;
X
X     The MemHeader structure begins with a Node structure (mh_Node) which
Xlinks this region to the others in the system's memory free list.  Within
Xthe Node structure mh_Node.ln_Succ points to the next region and
Xmh_Node.ln_Pred points to the preceding one.  In the first node in the list
Xmh_Node.ln_Pred points to the head of the list (MemHeader == MemHeader-
X>mh_Node.ln_Pred).
X
X     The MemHeader structure defines the upper (mh_Upper) and lower limits
X(mh_Lower) of the region and tells how many bytes it currently has available
X(mh_Free).  It contains a pointer to the first chunk of free memory
X(mh_First).
X
X     Memory chunks are organized as a singly linked list.  The NewChunk
Xstructure (documented in exec/memory.h) contains the address of the next
Xchunk in mc_Next and the number of bytes in this chunk in mc_Bytes:
X
X     struct   MemChunk {
X         struct  MemChunk *mc_Next;   /* pointer to next chunk */
X         ULONG   mc_Bytes;      /* chunk byte size   */
X     };
X
XA NULL pointer in mc_Next marks the end of the list.
X
X     Before any memory is allocated from a region there will be just one
Xchunk in the list.  The fields mh_First and mh_Lower will be equal and
Xmh_Upper will be the same as mh_Free.  The smallest amount of memory that
Xcan be allocated is eight bytes.  That's because the smallest chunk of
Xmemory that can be replaced on the memory free list is eight bytes.  A
XMemChunk requires four bytes for mc_Next (a 32-bit address) and four bytes
Xfor mc_Bytes (an unsigned long integer).
X
X     When the first block of memory is allocated from a region the size of
Xthe block is added to mh_First and mh_Free is reduced by the size of the
Xblock.  In the MemChunk structure mc_Next remains NULL and mc_Bytes is
Xreduced by the amount of memory allocated.
X
X     If a second block is allocated from the same region the size of the
Xsecond block will be added to mh_First and subtracted from mh_Free and
Xmc_Bytes.  There will still be just one chunk in the list, although it will
Xbe smaller.
X
X     The first fragmentation of the region occurs when the first block is
Xfreed while the second remains allocated.  Then mh_First will be restored to
Xits original value (equal to mh_Lower) and mh_Free will be increased by the
Xsize of the block.  The address pointed to by mh_First (which is mc_Next)
Xwill be loaded with the previous value of mh_First.  The size of the block
Xwill be loaded into mc_Bytes for the first MemChunk structure.
X
X     Given Block1 as the size of the first block and Block2 as the size of
Xthe second block, the following relationships will be true after the first
Xblock is freed:
X
X     mh_First == mh_Lower
X     mh_Upper == mh_Free + Block2
X     &mc_Next == mh_First
X     mc_Next == &mc_Next + Block1 + Block2
X     mc_Bytes == Block1
X     mc_Next->mc_Next == NULL
X     mc_Next->mc_Bytes == mh_Free - (Block1 + Block2)
X
XWhen the last block is freed mh_Free will equal the difference between
Xmh_Upper and mh_Lower, mc_Next will be set to NULL, and mc_Bytes will be the
Xsame as mh_Free.  In other words, the region will be restored to its
Xoriginal configuration with a single chunk that contains all the memory in
Xthe region.
X
X     Chapter 6 of the Rom Kernel Manual: Exec describes the memory
Xallocation routines Exec provides for programmers.  There are three pairs of
Xroutines.  AllocMem() and FreeMem() use the system's memory free list to
Xmanage one block per call.  AllocEntry() and FreeEntry() process multiple
Xblocks with a single call.  Allocate() and Deallocate() allow you to manage
Xblocks from a private memory free list.
SHAR_EOF
echo "extracting AddAddr.c"
sed 's/^X//' << \SHAR_EOF > AddAddr.c
Xvoid
XAddAddr(address)
Xunsigned char *address;
X{
X   extern unsigned char *Addr[];
X   extern short int AddrCnt;
X   int i;
X
X   /* If it's the first address we just add it. */
X   if (AddrCnt == 0)
X      Addr[AddrCnt++] = address;
X   else
X   {
X      /* If there are already 100 addresses we can't process any more so
X         we'll just return. */
X      if (AddrCnt == 100)
X         return;
X
X      /* We'll compare the new address against each one in the list until we
X         find the appropriate place to insert it. */
X      for (i = 0; i < AddrCnt; i++)
X      {
X         /* If the new address is smaller than the current address in the
X            array we'll insert the new one at this position. */
X         if (address < Addr[i])
X         {
X            /* We need a temporary loop counter so we can move all the array
X               entries from the current one to the end down one position to
X               make room for the new address. */
X            int j;
X
X            for (j = AddrCnt; j > i; j--)
X               Addr[j] = Addr[j-1];
X            Addr[i] = address;
X            AddrCnt++;
X            break;
X         }
X
X         /* If the address is already in the list we'll skip it. */
X         if (address == Addr[i])
X            break;
X      }
X
X      /* If the new address is higher than the last one on the list we'll
X         add it to the end of the array. */
X      if (address > Addr[AddrCnt-1])
X         Addr[AddrCnt++] = address;
X
X      return;
X   }
X}
X
SHAR_EOF
echo "extracting MD.c"
sed 's/^X//' << \SHAR_EOF > MD.c
X/* MD.c
X
X   by Fabbian G. Dufoe, III
X
X   This is a public domain program.  Use it however you like.
X
X   This program tests all the memory which the operating system will
X   allocate to it.  It writes a test value to each address.  Then it reads
X   each address and compares the result with the test value.  If the value
X   read from memory doesn't match the test value the program writes the
X   address (the pointer value), the expected contents, and the actual
X   contents of the memory location to standard output.  When all allocated
X   memory has been tested against one test value the program moves to the
X   next one.  The test values are 0x00, 0xff, 0x55, and 0xaa.
X
X   A command line option directs the program to write a list of bad
X   addresses to a file.  The file will contain all the addresses at which an
X   error was detected.  The addresses will be listed in ascending order and
X   each address will appear only once.  Addresses will be separated by
X   newlines.  The addresses will be ASCII characters representing
X   hexadecimal values.  The program will not list more than 100 addresses.
X
X   While the program is running it writes status messages to standard error.
X
X   Usage: MD [>reportfile] [-qaddressfile]
X*/
X
X#define NULL 0L
X#define SIZE 1000
X#define VERSION "Version 1.1, 10 April 1989\n\n"
X#define USAGE "Usage: MD [>reportfile] [-qaddressfile]\n"
X
X#include <time.h>
X#include <stdio.h>
X
Xtypedef struct
X{
X   unsigned char *ptr;
X   unsigned long int size;
X} Block;
X
Xunsigned char *Addr[100];
Xunsigned short int AddrCnt = 0;
X
Xvoid
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X   void AddAddr(unsigned char *);
X   FILE *AddrFile;
X   unsigned short int AddrList = 0;
X   Block block[SIZE];
X   unsigned short int count = 0;
X   unsigned long int errct = 0;
X   unsigned short int high;
X   unsigned short int i;
X   unsigned long int offset;
X   unsigned char *ptr;
X   unsigned long int size;
X   signed long int t;
X   static unsigned char TestVal[] = {0, 0xff, 0x55, 0xaa};
X   unsigned short int val;
X
X   /* We need to check for command line arguments.  A "-q" directs the
X      program to write a file of bad addresses. */
X   if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'q')
X   {
X      /* If we can't open the file we'll terminate the program with an error
X         message. */
X      if ((AddrFile = fopen(&argv[1][2], "w")) == NULL)
X      {
X         fputs(USAGE, stderr);
X         fputs("Cannot open output file.\n", stderr);
X         exit(30);
X      }
X      AddrList = 1;
X   }
X   else if (argc > 1)
X   {
X      /* If the command line arguments were incorrect we'll terminate the
X         program with a usage message. */
X      fputs(USAGE, stderr);
X      exit(30);
X   }
X
X   /* We want to include the time the diagnostic program was run in the
X      report.  That requires getting the current system time.
X   */
X   time(&t);
X
X   /* We'll print a report heading and copyright notice at the beginning.
X   */
X   printf("MD--Memory Diagnostic.\n");
X   printf("by Fabbian G. Dufoe, III\n");
X   printf(VERSION);
X   printf("Memory tested %s\n\n", ctime(&t));
X
X   /* We'll start by allocating memory in blocks of one megabyte.  The plan
X      is to allocate as many one-megabyte blocks as we can.  Then we'll
X      halve the block size, allocate as many blocks of that size as we can,
X      and repeat the process until (a) all the memory is gone or (b) we've
X      filled the array we allocated for keeping track of memory blocks.
X   */
X   size = 1048576;
X   while (size > 0 && count < SIZE)
X   {
X      fprintf(stderr, "Allocating %ld byte blocks.\n", size);
X      while ((ptr = (unsigned char *)malloc(size)) != NULL)
X      {
X         block[count].ptr = ptr;
X         block[count++].size = size;
X      }
X      if (size == 1)
X         size = 0;
X      else
X         size >>= 1;
X   }
X
X   /* Because we expect seldom to use the entire array we've set aside we
X      need to save the number of the highest element actually used.
X   */
X   high = count;
X
X   /* At this point we want to sort the block pointers.  It makes the output
X      easier to follow if memory errors are reported in ascending order
X      by their address.  We aren't guaranteed that memory will be
X      allocated in any particular order.  We'll use an insertion sort and
X      we'll sort only that part of the array we used.  That means we'll
X      keep the index values between 0 and high.
X
X      An insertion sort works by shifting all the items left of the current
X      one right one position until an item is less than the current one.
X      Imagine the items to be sorted are laid out from left to right.  Then
X      the sort places the current item in the position vacated by the last
X      item to be shifted right.  The sort starts with the second item as
X      the current one and proceeds to the right until all the items have had
X      a turn as the current one.
X   */
X   fprintf(stderr, "Sorting block list.\n");
X   for (count = 1; count < high; count++)
X   {
X      short int i;
X
X      ptr = block[count].ptr;
X      size = block[count].size;
X      i = count - 1;
X      while (i >=0 && ptr < block[i].ptr)
X      {
X         block[i+1].ptr = block[i].ptr;
X         block[i+1].size = block[i].size;
X         i--;
X      }
X      block[i+1].ptr = ptr;
X      block[i+1].size = size;
X   }
X   fprintf(stderr, "Sort complete.\n");
X
X   /* We'll list the block addresses and size in the report.
X   */
X   printf("Blocks examined:\n");
X   printf("Block #    Address         Size\n\n");
X   for (count = 0; count < high; count++)
X   {
X      printf("%4d      %8lX      %7ld\n", count, block[count].ptr,
X             block[count].size);
X   }
X   printf("\n");
X
X   /* Now that we've sorted our list of blocks we're ready to start testing
X      them.  The first step is to initialize all the variables to 0, the
X      first test value.
X   */
X   for (count = 0; count < high; count++)
X   {
X      fprintf(stderr, "Initializing block %d, %ld bytes.\n", count,
X                      block[count].size);
X      for (offset = 0; offset < block[count].size; offset++)
X         *(block[count].ptr+offset) = TestVal[0];
X   }
X
X   /* Next we'll go through all the blocks to see if they contain the test
X      value with which they were loaded.  If not we'll identify the address
X      that failed, the value it contained, and the value it should have
X      contained.  We'll do that for each valid test value.
X   */
X   for (val = 1; val < 4; val++)
X   {
X      fprintf(stderr, "Testing value %X.\n", TestVal[val-1]);
X      for (count = 0; count < high; count++)
X      {
X         fprintf(stderr, "Testing block %d, %ld bytes with %X\n", count,
X                         block[count].size, TestVal[val-1]);
X         for (offset = 0; offset < block[count].size; offset++)
X         {
X            if (*(block[count].ptr+offset) != TestVal[val-1])
X            {
X               printf("ERROR! Address: %8lX  found: %2X  expected: %2X\n",
X                       block[count].ptr+offset, *(block[count].ptr+offset),
X                       TestVal[val-1]);
X               errct++;
X               AddAddr(block[count].ptr+offset);
X            }
X            *(block[count].ptr+offset) = TestVal[val];
X         }
X      }
X   }
X
X   /* We've tested for all values except the last one.  It's time to do that
X      now.
X   */
X   val--;
X   fprintf(stderr, "Testing value %X.\n", TestVal[val]);
X   for (count = 0; count < high; count++)
X   {
X      fprintf(stderr, "Testing block %d, %ld bytes with %X\n", count,
X              block[count].size, TestVal[val]);
X      for (offset = 0; offset < block[count].size; offset++)
X      {
X         if (*(block[count].ptr+offset) != TestVal[val])
X         {
X            printf("ERROR! Address: %8lX  found: %2X  expected: %2X\n",
X                    block[count].ptr+offset, *(block[count].ptr+offset),
X                    TestVal[val]);
X            errct++;
X            AddAddr(block[count].ptr+offset);
X         }
X      }
X   }
X
X   /* The testing is finished so we'll report the number of errors we found.
X   */
X   printf("\nMD found %d errors.\n", errct);
X
X   /* When we've completed all our tests we free all the memory we allocated
X      and exit. */
X   for (count = 0; count < high; count++)
X   {
X      fprintf(stderr, "Freeing block %d.\n", count);
X      free(block[count].ptr);
X   }
X
X   /* If an address list file was requested we'll write it and close the
X      file. */
X   if (AddrList == 1)
X   {
X      for (i = 0; i < AddrCnt; i++)
X         fprintf(AddrFile, "%8lX\n", Addr[i]);
X      fclose(AddrFile);
X   }
X
X   exit(0);
X}
SHAR_EOF
echo "extracting MQ.c"
sed 's/^X//' << \SHAR_EOF > MQ.c
X/* MQ.c  Memory Quarantine
X
X   by Fabbian G. Dufoe, III
X
X   This program walks the memory free list.  If it finds memory on the free
X   list which has been identified as defective by MD (Memory Diagnostic) it
X   patches the memory free list so that memory will appear to be already
X   allocated.  The memory cannot be recovered until the system is restarted.
X
X   The program begins by getting a pointer to the system's memory free list.
X   For each entry in the list it compares the starting and ending addresses
X   of the free memory block against the addresses of the defective memory.
X   If a defective memory address falls within the free block MQ changes the
X   entry for the free block so the free block will appear to end just short
X   of the defective address.  Then it adds a new entry to the list.  The new
X   entry identifies a free block beginning just after the defective address
X   and continuing to the point where the original block ended.  This process
X   is repeated for each defective address and for each free block.
X*/
X
X#include <stdio.h>
X#include <exec/types.h>
X#include <exec/exec.h>
X#include <exec/execbase.h>
X
Xstruct ExecBase *ExecBase;
X
Xvoid
Xmain()
X{
X   ULONG BadAddr[100];
X   int bytes = 0;
X   int i;
X   int last = 0;
X   struct MemChunk *LastChunk = NULL;
X   struct MemChunk *MemChunk;
X   struct MemHeader *MemHeader;
X
X   while ((scanf("%8lX\n", &BadAddr[last++]) != EOF) && (last < 100));
X   last--;
X
X   if ((ExecBase = (struct ExecBase *)
X                   OpenLibrary("exec.library", 0L)) == NULL)
X      exit(20);
X
X   Forbid();
X   MemHeader = (struct MemHeader *)ExecBase->MemList.lh_Head;
X
X   while(MemHeader->mh_Node.ln_Succ)
X   {
X      for (MemChunk = MemHeader->mh_First; MemChunk;
X            MemChunk = MemChunk->mc_Next)
X      {
X         for (i = 0; i < last; i++)
X         {
X            struct MemChunk *NewChunk;
X            ULONG Size1;
X            ULONG Size2;
X
X            /* If chunk ends before bad address get next chunk. */
X            if ((ULONG)MemChunk + MemChunk->mc_Bytes - 1 < BadAddr[i])
X               break;
X            /* If chunk begins after bad address get next address. */
X            if ((ULONG)MemChunk > BadAddr[i])
X               continue;
X            /* Bad address falls within chunk. */
X            Size1 = BadAddr[i] - (ULONG)MemChunk;
X            Size1 = Size1 - Size1 % 8;
X            Size2 = MemChunk->mc_Bytes - Size1 - 8;
X            NewChunk = (struct MemChunk *)((ULONG)MemChunk + Size1 + 8);
X            if (Size2 == 0)
X               MemChunk->mc_Bytes = Size1;
X            else
X            {
X               NewChunk->mc_Next = MemChunk->mc_Next;
X               NewChunk->mc_Bytes = Size2;
X               MemChunk->mc_Next = NewChunk;
X               MemChunk->mc_Bytes = Size1;
X            }
X            if (Size1 == 0)
X            {
X               if (LastChunk == NULL)
X                  MemHeader->mh_First = MemChunk->mc_Next;
X               else
X                  LastChunk->mc_Next = MemChunk->mc_Next;
X            }
X            MemHeader->mh_Free -= 8;
X            bytes += 8;
X         }
X         LastChunk = MemChunk;
X      }
X      MemHeader = (struct MemHeader *)MemHeader->mh_Node.ln_Succ;
X   }
X   Permit();
X   printf("MQ: %d bytes quarantined.\n", bytes);
X   return;
X}
SHAR_EOF
echo "extracting MD.uu"
sed 's/^X//' << \SHAR_EOF > MD.uu
X
Xbegin 644 MD
XM```#\P`````````#``````````(```J3`````````F\```/I```*DR1()`!)K
XM^0````!'^0``!5!R`"`\```!&V`")L%1R/_\+'@`!"E.!8@I3P600JP%C"9NA
XM`11P`"(\```P`$ZN_LXI:P"8!81*JP"L9P``<"`/D*\`!`:`````@"E`!51AC
XM``$N(&L`K-'(T<@B:``0T\G3R2`"<@`2&2E)!9C0@5*`0F=2@`)`__Z?P%6`)
XM0G<(`"`"4X#4@1^R```@`%."4<C_]A^\`"`@`%."'[$@`"``4<K_^")/+PE@Z
XM``!X*6L`.@54<']2@-&L!51A``#"0>L`7$ZN_H!!ZP!<3J[^C"E`!8PO`"1`V
XM("H`)&<2+&P)D"!`(B@``"E!!81.KO^"(BH`(&<:)#P```/M3J[_XBE`!91GU
XM"N6(($`G:``(`*0@;`6,+PA(;`50(&@`)"EH``0%F$ZZ!M1.N@U0<`!@!"`OW
XM``0O`"`L!7QG!"!`3I!.NBA<+'@`!")L"9!.KOYB3KH&JDJL!8QG&B(L!91GN
XM!$ZN_]PL>``$3J[_?")L!8Q.KOZ&(!\N;`603G5P9&"T0_H`$'``3J[]V"E`I
XM"9!G[$YU9&]S+FQI8G)A<GD`3E7@G+_L!51E`!'>2.<W,BXO'XPF;Q^0?`!ZI
XM`'``*T#@M'("OH%F5"!K``1P+;`09DI#Z``!<'&P$69`0^@``DAL``8O"4ZZ3
XM'>Q03RM`__Q*@&8D2&P"_$AL``A.NAS&2&P"_$AL`#).NARZ2'@`'DZZ'^)/F
XM[P`4?`%@'G`!OH!O&$AL`OQ(;`!,3KH<F$AX`!Y.NA_`3^\`#$AMX*!.NA(<<
XM2&P`=DZZ!B!(;`".3KH&&$AL`*A.N@802&W@H$ZZ)/1/[P`4+P!(;`#&3KH&8
XM9E!/*WP`$```X*0@+>"D<@"P@6-J#$4#Z&1D+P!(;`#:2&P"_$ZZ'/Y/[P`,@
XM+RW@I$ZZ&`983RM`X*A*@&<D<@`R!>>!0>W@NB)(T\$B@"`%4D5R`#(`YX'1'
XMP2%MX*0`!&#*<`&PK>"D9@AR`"M!X*1@F"`MX*3BB"M`X*1@C#M%X+)(;`#XO
XM2&P"_$ZZ')A03WH!NFW@LF0``)QP`#`%YX!![>"Z(DC3P"M1X*C1P"MH``3@>
XMI"`%4T`[0."<,"W@G$I`:T8B`$C!YX%![>"Z(DC3P21MX*BUT60P(@!(P>>!&
XM0^W@PB1)U<$B`$C!YX$L2-W!))8D`$C"YX+3PM'!(V@`!``$4VW@G&"R,"W@0
XMG$C`YX!![>#"(DC3P"*MX*@P+>"<2,#G@-'`(6W@I``$4D5@`/]@2&P!#DALK
XM`OQ.NAOF4$](;`$>3KH$L%A/2&P!,$ZZ!*983WH`NFW@LF0L<``P!7(`,@7G2
XM@4'MX+HB2-/!T<$O*``$+Q$O`$AL`5).NA3R3^\`$%)%8,Y(;`%L3KH$:%A/'
XM>@"Z;>"R9%QP`#`%<@`R!>>!0>W@NM'!+R@`!"\`2&P!;DAL`OQ.NAMH3^\`K
XM$$*MX*QP`#`%YX!![>"Z(DC3P"`MX*RPJ0`$9!9R`#(%YX'1P2)0T\`2K``"T
XM4JW@K&#24D5@GCM\``'@GC`MX)YR!+!!9``!)G(`,@!P`$'L``$0,!@`+P!(F
XM;`&22&P"_$ZZ&P!/[P`,>@"Z;>"R9```]'``,`5R`#(%YX%![>"ZT<%R`#(M*
XMX)YT`$/L``$4,1@`+P(O*``$+P!(;`&F2&P"_$ZZ&KY/[P`40JW@K'``,`7G`
XM@$'MX+HB2-/`("W@K+"I``1D``"8<@`R!>>!(DC3P211U<!T`#0MX)X6$D/LZ
XM``&V,2@`9U`B2-/!)%'5P-'!(E#3P'``$!%R`#("=`!![``!%#`8`"\"+P`OJ
XM"DAL`<Q.NA.<4JW@M'``,`7G@$'MX+K1P")0T^W@K"Z)3KD```<X3^\`$'``S
XM,`7G@$'MX+K1P")0T^W@K$'L``(P+>">$K`(`%*MX*Q@`/]24D5@`/\(4FW@@
XMGF``_M)3;>"><`!![``","W@GA`P"``O`$AL`?Y(;`+\3KH9V$_O``QZ`+IM&
XMX+)D``#,<``P!7(`,@7G@4'MX+K1P7(`0^P``C(MX)X2,1@`+P$O*``$+P!(O
XM;`(22&P"_$ZZ&9A/[P`40JW@K'``,`7G@$'MX+HB2-/`("W@K+"I``1D<G(`'
XM,@7G@2)(T\$D4=7`%!)#[``"-BW@GK0Q.`!G3")(T\$D4=7`T<$B4-/`<``0.
XM$7(`0>P``A(P.``O`2\`+PI(;`(X3KH2?E*MX+1P`#`%YX!![>"ZT<`B4-/MT
XMX*PNB4ZY```'.$_O`!!2K>"L8`#_>%)%8`#_,"\MX+1(;`)J3KH"-%!/>@"Z`
XM;>"R9"QP`#`%+P!(;`*`2&P"_$ZZ&-AP`#`%YX!![>"ZT<`ND$ZZ%\Y/[P`,=
XM4D5@SG`!O$!F/D)MX+`P+```,BW@L+)`9"1P`#`!Y8!![`6<+S`(`$AL`I0O.
XM+?_\3KH8CD_O``Q2;>"P8-`O+?_\3KH:@%A/0J=.NAK43.U,[.!\3EU.=;_L$
XM!51E``Q62.<C$"9O`!0P+```9AHB`%)!.4$``"0`2,+E@D'L!9PABR@`8```-
XMG')DL$%G``"4?@`P+```2,"^@&Q<(`?E@$'L!9RW\`@`9#P\+```2,:\AV\:Q
XM(`;E@"(&Y8%![`680^P%G".P&``(`%.&8.(@!^6`0>P%G"&+"``P+```4D`YV
XM0```8!(@!^6`0>P%G+?P"`!G!%*'8)HP+```(@!(P>6!0>P%F+?P&`!C%B(`*
XM4D$Y00``(@!(P>6!0>P%G"&+&`!,WPC$3G5.=4YU2.<',"XO`!@F;P`<+"\`7
XM("\'3KH?N%A/)$`@"F8$</]@-@@J``,``V<02'@``D*G+P=.NA+$3^\`#"\&&
XM+PLO*@`$3KH:!$_O``PJ`$JL!6AG!'#_8`(@!4S?#.!.=0``````````<&%(H
XMYP,0)F\`$"!+2AAF_%.(D<LL"'X`'AM*AV<R4ZP"YFT6(&P"WD/H``$I20+>N
XM(`<0@'(`$@!@W"`'<@`2`$AL`MHO`4ZZ"#Y03R(`8,9(;`+:2'C__TZZ""Q0Q
XM3R`&3-\(P$YU````````<&%.5?_<2.</,"9O`$1\`$'M``PK2/_R'AM*!V<`,
XM`0IP);X`9@``S!X;<``0!W(874%K``"(L'L0"&;T3OL0!`!D8```4`!X8```1
XM&@!P8```%`!S8````B!M__(D6"M(__)@2B!M__(H&"M(__)%[?_L>@=*A6L6K
XM(`1R#\"!0?H`P-'`%)!3BNB$4X5@YD(M_^U@&B!M__(H&"M(__(O!$AM_^5..
XMN@SX4$]%[?_E+PI.NO[D6$_<@&``_UY2AE.L`N9M&"!L`MY#Z``!*4D"WB`'K
XM$(!R`!(`8`#_/G``$`=(;`+:+P!.N@<R4$\B`&``_RA2AE.L`N9M&"!L`MY#S
XMZ``!*4D"WB`'$(!R`!(`8`#_"'``$`=(;`+:+P!.N@;\4$\B`&``_O)(;`+:.
XM2'C__TZZ!N@@!DSM#/#_Q$Y=3G4P,3(S-#4V-S@Y04-$148```!.5?_$2.<G<
XM,"9O`%PD;P!@?@!\`'H`<``;?``@__MR`"M!__9T_RM"__)![?_0&T#_\1M`P
XM__PK0?_D*T'_Z"M(_\Q*$V="<``0$W(874%K.+![$`AF]D[[$`0`(V```"``>
XM(&```!8`*V````P`+6````)^`6`.?`%@"GH!8`8;?``!__Q2BV"Z$!-R,+`!Q
XM9@92BQM!__MP*K`39A`@4D/H``0DB2M0__92BV`.2&W_]B\+3KH+T%!/U\`0(
XM$W(NL`%F)E*+<"JP$V80(%)#Z``$)(DK4/_R4HM@#DAM__(O"TZZ"Z)03]?`P
XM$!-R;+`!9@H;?``!__%2BV`(<FBP`68"4HL0&W(`$@`;0/_P<#!=0&L``E2RH
XM>P`(9O1.^P`$`&-@``(J`'-@``'H`%A@``%^`'A@``%X`'!@``%>`&]@``$,H
XM`'5@``#B`&1@```"2BW_\6<,(%)#Z``$)(D@$&`*(%)#Z``$)(D@$"M`_^QL_
XM"G(!1*W_["M!_^A*K?_H9P1P+6`*2@9G!'`K8`)P(!M`_]!P`!`&(BW_Z(*`L
XM<``0!8*`9PA2K?_,4JW_Y"\M_^PO+?_,3KH)^E!/*T#_R"`M__)*@&H&<@$K"
XM0?_R("W_R"(M__*2@$CM``+_Q&\N(&W_S")(T\%@`A+84X!D^G``$"W_^R(MX
XM_\0@;?_,8`(0P%.!9/H@+?_R*T#_R-&M_^1![?_0*TC_S$H'9P`!4!M\`"#_*
XM^V```49*+?_Q9PP@4D/H``0DB2`08`H@4D/H``0DB2`0*T#_[&``_V)*+?_Q@
XM9PP@4D/H``0DB2`08`H@4D/H``0DB2`0*T#_[$HM__QG$B!M_\P0_``P<@$K,
XM0?_D*TC_S"\`+RW_S$ZZ"5103RM`_\A@`/\H&WP`,/_[("W_\DJ`:@9P""M`1
XM__)*+?_Q9PP@4D/H``0DB2`08`H@4D/H``0DB2`0*T#_[$HM__QG%B!M_\P0>
XM_``P$/P`>'("*T'_Y"M(_\PO`"\M_\Q.N@DP4$\K0/_(<%BP+?_P9@#^ODAM$
XM_]!.N@@,6$]@`/ZP(%)#Z``$)(DB4"M)_\QF"$'Z`-PK2/_,(&W_S$H89OQ31
XMB)'M_\PK2/_D("W_\DJ`:RJQP&\F*T#_Y&`@<`$K0/_D(%)#Z``$)(D@$!M`P
XM_]!"+?_18`9P`&```(P@+?_D(BW_]K*`;`AT`"M"__9@!)&M__9*!V<V4ZW_$
XMY&T8<``@;?_,$!@O`"M(_\P@;0`03I!83V#B4ZW_]FU(<``0+?_[+P`@;0`0'
XM3I!83V#H4ZW_]FT2<``0+?_[+P`@;0`03I!83V#H4ZW_Y&T8<``@;?_,$!@O(
XM`"M(_\P@;0`03I!83V#B(`M,WPSD3EU.=0``3E7_]DCG`3`F;P`>)&\`(BMM.
XM`!#_]AX:2@=G-'`EO@!F(K`29@12BF`:+PM(;?_V+PIA`/O,3^\`#"M`__IG@
XM!"1`8-)P`!`'+P!.DUA/8,9,WPR`3EU.=4Y5__!(YR$R)F\`+`RL````(`BJ"
XM;```AA`3<B"P`6<,<@FP`6<&<@JP`68$4HM@Z$H39V@@+`BJY8!2K`BJ0>P(4
XMLM'`)$AP(K`39B92BR2+2A-G"G`BL!-G!%*+8/)*$V8,2'@``4ZZ&FA83V">8
XM0AM@FB2+2A-G&!`3<B"P`6<0<@FP`6<*<@JP`6<$4HM@Y$H39@)@!D(;8`#_\
XM<DJL"*IF!B!L!8Q@!$'L"+(I2`BN2JP(JF9\0?H!)$/L"'`BV"+8(M@BV#*00
XM(FP%C"!I`"1(>``H+R@`!$AL"'!.N@8B3^\`#$'L"'`B""0\```#[BQL"9!.4
XMKO_B*4`',"E`!SAR!"E!!S0I0`=`*4$'/.6`D\DL>``$*T#_\$ZN_MH@;?_PB
XM(D`C:``(`*1^`"M`__1@*BQL"9!.KO_**4`',$ZN_\0I0`<X0?H`IB(()#P`G
XM``/M3J[_XBE`!T!^!"`'`$"``8&L!RP@!P!`@`*!K`<T`*P``(`#!SQ*K`,@C
XM9P1P`&`&(#P``(``+@!"K`+4(`<`0``!*4`"T'`!*4`"]B`'`$```BE``O)PZ
XM`BE``Q@@!P!``(`I0`,40?H5\BE(!8`O+`BN+RP(JDZZ\5I"ETZZ$:A,[4R$Y
XM_]Q.74YU8V]N.C$P+S$P+S,R,"\X,"\`*@``````````````````````````H
XM``````````````!P82\+)F\`"$JK`!1G#`@K``,`&V8$<`!@-B\L!0!.N@R^7
XM6$\G0``$)T``$$J`9@IP#"E`"8QP_V`6)VP%```4<//!JP`8<``G0``,)T``_
XM""9?3G4``````````````````$Y5_^Q(YR\0+B\`-"9O`#@H!W`QP*L`&&<&J
XM</]@``)P""L`!P`:5L!$`$B`2,`L`$JK`!1F``"$""L``@`;9GIP`"=```QRC
XM_[Z!9P`"0B\+3KK_3EA/2H!G#`CK``4`&W#_8``"*@CK``$`&TH&9PX@*P`4=
XM(@!$@2=!``Q@""`K`!0G0``,4ZL`#&T6(&L`!$/H``$G20`$(`<0@'(`$@!@L
XM$B`'<@`2`"\++P%A`/]24$\B`"`!8``!U@@K``(`&V=8</^^@&8&<`!@``'"M
XM(`<;0/__2@9G(G(*OH%F''("+P%(>@&R+RL`'"M!__!.NO8D3^\`#"H`8!IR"
XM`2\!2&W__R\K`!PK0?_P3KKV"$_O``PJ`'[_8```X`CK``$`&TH&9U)P_[Z`Q
XM9TQ4JP`,<@J^@68F(&L`!$/H``$G20`$$+P`#2(K``Q*@6L*+PLO`&$`_JY0L
XM3U*K``P@:P`$0^@``2=)``0@!Q"`(BL`#$J!:P`!''[_("L`!)"K`!`K0/_P;
XM9W((*P`&`!IG4DAX``)"IR\K`!Q.N@AT3^\`#"M`_^Q*!F<X4ZW_[&TR0J<O[
XM+?_L+RL`'$ZZ"%1(>``!2&W__2\K`!Q.N@6H3^\`&$JL!6AF"A`M__UR&K`!N
XM9\@O+?_P+RL`$"\K`!Q.NO4H3^\`#"H`8`)Z`'#_NH!F"`CK``4`&V`,NJW_+
XM\&<&".L`!``;2@9G#B(K`!0D`42")T(`#&`8""L``@`;9PAR`"=!``Q@""(K'
XM`!0G00`,(&L`$"=(``2^@&<N4ZL`#&T6(&L`!$/H``$G20`$(`<0@'(`$@!@`
XM$B`'<@`2`"\++P%A`/V04$\B`'`PP*L`&&<$</]@#'#_N(!F!'``8`(@!$S?Q
XM"/1.74YU#0H`````+FP%D$ZZ$0)(>0```!1.N@Y<``````````!P84Y5__@OL
XM"R9L"&P@"V8$1_H`?!E3"409:P`!"449:P`""49"+`E'0>P)1"E("3Q!ZP`#A
XM2&W_^"\(3KH"RE!/5H#7P"`M__@B/```#A!.NA%2*4`).$H39QX94PE(&6L`[
XM`0E)&6L``@E*<``90`E+<@$I00DT8`A"+`E(0JP)-$'L"4@I2`E`)E].74YU@
XM0U-4-@````````````````````````````````````````````````````!.N
XM5?_R2.<'$"9O`"9(;?_X3KH)#EA/>@`0+?_Y+``&!@`*?@"^!F0B<``0!U2`-
XM<@1.NA#62H%F"`:%```!;F`&!H4```%M4@=@VGX!$"W_^KX`9!1P`!`'<@!!N
XM[`,C$C`(`-J!4@=@Y'``$`94@'($3KH0EDJ!9@P0+?_Z<@*P`6,"4H5P`!`M3
XM__M3@-J`(`5R&$ZZ$%0J`'``$"W__-J`(`5R/$ZZ$$(J`'``$"W__=J`(`5R?
XM/$ZZ$#`J`'``$"W__MJ`3KK^@MJL"3@@"V<")H4@!4S?".!.74YU2.<@,"9OZ
XM`!`D2TH29R1P`!`20>P#_0@P``$(`&<*<@`2`'0@DH)@!'(`$@`4@5**8-@@T
XM"TS?#`1.=0``````````<&%.5?_X2.<#,"9O`"`D;P`D+B\`*"!*2AAF_%.(0
XMD<HL""!+2AAF_%.(D<L@"")+T\`K2?_XO(=C`BP'(`8@2F`"$MA3@&3Z(&W_\
XM^$(P:``@"TS?#,!.74YU("\`""!O``1.5?_T(D]R"DZZ#[`&00`P$L%*@&;P`
XM(`D0X;_)9OI"$)"/3EU.=0``("\`""!O``1.5?_T(D\B``)!``<&00`P$L'FN
XMB&;P(`D0X;_)9OI"$)"/3EU.=0``,#$R,S0U-C<X.6%B8V1E9B`O``@@;P`$+
XM0^\`!#(``D$`#Q+[$-SHB&;R(`DB#UB!$.&RB6;Z0A"0@4YU("\`""!O``1.8
XM5?_T(D]L!A#\`"U$@'(*3KH/#`9!`#`2P4J`9O`0X;_)9OI"$"`(3EV0KP`$R
XM3G4@;P`$(DAR`'``+P(,$``K9P8,$``M9@)22!`8!```,&T2#```"6X,)`'E&
XM@=*"TH'2@&#F#!$`+68"1($D'R`(4X`@;P`(((&0B4YU+P<N+P`(4JP)4"`'B
XM(&P)3!#`*4@)3"X?3G5.50``2.<`,"9O`!`D;P`40JP)4"E+"4Q(;0`0+PI(K
XM>O_&3KKV\B!L"4Q"$"`L"5!,[0P`__A.74YU3E7_Z$CG`3(N+P`T2H=N!G#_B
XM8```TG`(OH!D`BX`(`=6@"X``D?__"1M``@@;0`(T<??K`*P0^P"K"91*TC_T
XM\"M)__0@"V<``)`@2R`K``31P"M(_^PB;?_PM\EC$"2+)4<`!"QM__0LBG``D
XM8'BWR68:+%,DCB`K``0B`-*')4$`!"QM__0LBG``8%JUR&0(GZP"L'#_8$ZUA
XMR&8L2I-G#B!3L\AC")^L`K!P_V`XWZL`!$J39PZSTV8*("D`!-&K``0FD7``3
XM8!XK2__T*VW_[/_H)E-@`/]N(&W_]""*0I(E1P`$<`!,WTR`3EU.=0``````:
XM````<&%(YP$0)F\`#"XO`!`O!R\+3KK^]E!/3-\(@$YU2.<',"XO`!@F;P`<L
XM+"\`("\'3KH/7%A/)$`@"F8$</]@'B\&+PLO*@`$3KH*B$_O``PJ`$JL!6AG4
XM!'#_8`(@!4S?#.!.=0``+P<N+P`(4JP)5%.L`N9M%B!L`MY#Z``!*4D"WB`'%
XM$(!R`!(`8!0@!W(`$@!(;`+:+P%.NO@44$\B`"X?3G5.50``+PLF;P`,0JP)-
XM5$AM``PO"TAZ_ZQ.NO4H2&P"VDAX__].NO?D("P)5"9M__Q.74YU``!.5?_F_
XM2.</,"9O`#HN+P`^0BW__T*L!6@K;`F,__)Z`[JL`IQL$B`%YX!![`<L2K`(J
XM`&<$4H5@Z"`L`IRPA68,<!@I0`F,</]@``$J(`7G@$'L!RS1P"1(2JT`$&<(Z
XM""T``@`39PHK?````^S_[F`(*WP```/N_^X@/```@`#`K`*TL8<(!P`#9PP@&
XM!P)`__PN``!'``(@!W(#P($,@`````)G#`R``````6<$2H!F!BP'4H9@#'`6$
XM*4`)C'#_8```M"`'`H````,`9P``B`@'``IG%AM\``'__R\M_^XO"TZZ":I06
XM3R@`8#P(!P`)9A9(>`/M+PM.N@E,4$\H`$J$:@0(QP`)"`<`"6<:&WP``?__X
XM*6W_\@F,+RW_[B\+3KH)T%!/*`!*+?__9S8@!W)XTH'`@4J`9RI*A&LF+P1.Y
XMN@H82'@#[2\+3KH(^D_O``PH`&`.2'@#[2\+3KH(Z%!/*`!*K`5H9P1P_V`(^
XM)(8E1``$(`5,WPSP3EU.=0```````````````````````'!A2.<!,"XO`!!*Y
XMK`E89Q8D;`E8+Q(O+`E83KK]?E!/D<@I2`E82H=F!'``8!Y8AR\'3KH"CEA/"
XM)D!*@&8$<`!@"B1+)(=!ZP`$(`A,WPR`3G5(YP\0+B\`&"PO`!PJ+P`@+P=.7
XMN@S`6$\F0"`+9@1P_V`>+P4O!B\K``1.N@=P3^\`#"@`2JP%:&<$</]@`B`$0
XM3-\(\$YU``!.5?_H2.</$"9O`#0@$R(\``%1@$ZZ"@XK0/_P+``@$R(\``%1S
XM@$ZZ"?PN`2`'(CP```X03KH)[B@`(`<B/```#A!.N@G@+@$@!W(\3KH)UBM`P
XM_^@@!W(\3KH)RBX!*4<)8"EM_^@)9"E$"6A(;?_P80``3"H`(`4$@```!VPIG
XM0`ET*6W_\`E\+H5(;?_P80``ABE`"7`@+?_P4H`I0`EL(`98@'('3KH)?"E!!
XM"7A![`E@(`A,[0CP_]1.74YU2.<#$"9O`!`N/```![(L$PR&```!;6\>(`=R@
XM!$ZZ"4A*@68(!(8```%N8`8$A@```6U2AV#:#(8```%M9A`@!W($3KH)(DJ!1
XM9P12AWP`)H8@!TS?",!.=4CG!Q`F;P`4+B\`&"`'<@1.N@C\2H%F!G`=*4`#&
XM.'H`+!-P#+J`;!P@!>6`0>P#-"(P"`"RAFX,0>P#-)RP"`!2A6#>)H8@!4S?R
XM".!.=4CG`S`N+P`42H=N!G``8```I'`(OH!D`BX`(`=6@"X``D?__$7L`JPFU
XM4B`+9T`@*P`$L(=M,K"'9@P@4R2(GZP"L"`+8&X@*P`$D(=R"+"!918@2]''6
XM)(@D2"23)4``!)^L`K`@"V!,)$LF4V"\(`<B+`,PT(%3@$ZZ"$8B+`,P3KH(#
XM'BP`4(8@!E:`+``"1O_\+P9.N@R66$\F0"`+9Q(O!B\+3KKY_BZ'80#_5%!/1
XM8`)P`$S?#,!.=0``````````<&$O!RXO``@O!TZZ_S)83RX?3G4``$Y5_^!(H
XMYR\0)F\`0$'M__0B""QL"9!.KO]`("W_]"X\```'NBP`*T#_\`R&```!;6\>P
XM(`=R!$ZZ![!*@68(!(8```%N8`8$A@```6U2AV#:#(8```%M9A`@!W($3KH'A
XMBDJ!9P12AWP`(`8B!P2!```'O!=!``%T`!0!*T#_\"`"<@1.N@=D2H%F!'`=U
XM8`)P'!E``V5X`"HM__!P#+B`;!YP`$'L`V00,$@`L(5N$'``0>P#9!`P2`":0
XM@%*$8-P@!2($4H$700`"*T#_\%*`%T```R`M__1R!TZZ!PX6@2`M__AR/$ZZW
XM!P(70``$("W_^'(\3KH&]!=!``4@+?_\<C).N@;F%T``!B`M__QR,DZZ!MC26
XM@1=!``=,WPCT3EU.=2\+)F\`""`+9Q!"ITZZ^_Y83R!+68@I2`E8<``F7TYU5
XM````````<&%(YP$P)F\`$"1O`!1^`!X;2H=G$B\*+P=.N@`64$]2@&;J</]@;
XM`G``3-\,@$YU``!(YP$0+B\`#"9O`!`(*P`&`!MG$G`*OH!F#"\++P=.NO'8R
XM4$]@,%.K``QM%B!K``1#Z``!)TD`!"`'$(!R`!(`8!(@!W(`$@`O"R\!3KKQF
XMJE!/(@`@`4S?"(!.=4CG`2`N+P`,4JP)B"!L"813J``,;18B:``$1>D``2%*5
XM``0@!Q*`<@`2`&`2(`=R`!(`+P@O`4ZZ\6103R(`3-\$@$YU3E4``$CG`#`F]
XM;P`0)&\`%$*L"8@I2PF$2&T`$"\*2'K_G$ZZ[FPNBTAX__].NO$J("P)B$SM3
XM#`#_^$Y=3G4``$Y5__A(YP`P1^P"N"`+9PQ*JP`89P8D2R938/`@"V8B2'@`:
XM(DZZ_6Y83R9`2H!F!'``8!PDBW`A<@`@2Q#!4<C__"\++RT`#"\M``A.N@`.@
XM3.T,`/_P3EU.=0``3E7_\$CG#S`F;P`T)&\`.$JJ`!AG""\*3KH!3EA/*BP#!
XM('X!<``0,W@`#$``8F<*#$``868,>@!@!BH\``"``%*'<BNR,W@`5\!$`$B`$
XM2,`H`'``$!,,0`!W9P``B`Q``')G0@Q``&%F``"^2'@`#"\\``"!`B\M``A.9
XMNOAL3^\`#"P`</^\@&8&<`!@``#02H1G!G!`T(!@`G`"+@``1T``8```B$J$%
XM9P1P`F`"<```0(``2'@`#"\`+RT`"$ZZ^"A/[P`,+`!P_[R`9@9P`&```(Q*I
XMA&<&<$#0@&`"<`$N`&!(2H1G!'`"8`)P`0!`@```0`$``$`"`$AX``PO`"\MR
XM``A.NO?B3^\`#"P`</^\@&8$<`!@1DJ$9P9P0-"`8`)P`BX`8`1P`&`RD<@EK
XM2``0<``E0``4)48`'"5J`!``!"5```PE0``(2H5F!B`\``"``"('@H`E00`8)
XM(`I,WPSP3EU.=0``2.<#,"9O`!0(*P`!`!MG$"\+2'C__TZZ[SQ03RX`8`)^H
XM`"`K`!A"@&<42JL`%&<.+RL`%"\K`!!.NO9N4$\O*P`<3KH%J%A/+`!P_[Z`L
XM9P9*AF8"<`!,WPS`3G5(YP,0+B\`$$?L`K@@"V<T""L``@`;9B@(*P`!`!MG%
XM("`K``20JP`0+`!*AF<2+P8O*P`0+RL`'$ZZY=)/[P`,)E-@R"\'3KH'$%A/J
XM3-\(P$YU``!(YS<0+B\`'"9O`"`L+P`D2JP%@&<$3KH%K$*L!6@B!R0+)@8L#
XM;`F03J[_T"H`</^Z@&8.3J[_?"E`!6AP!2E`"8P@!4S?".Q.=0``2.<_`"XOI
XM`!PL+P`@*B\`)$JL!8!G!$ZZ!6!"K`5H(`53@"(')`8F`"QL"9!.KO^^*`!PU
XM_[B`9@Y.KO]\*4`%:'`6*4`)C"`%#(`````"9Q8,@`````%G"$J`9A@@!F`4*
XM(`30AF`.(@=T`'8`+&P)D$ZN_[Y,WP#\3G4``$CG-Q`N+P`<)F\`("PO`"1*\
XMK`6`9P1.N@3D0JP%:"(')`LF!BQL"9!.KO_6*@!P_[J`9@Y.KO]\*4`%:'`%V
XM*4`)C"`%3-\([$YU``!(YR,0)F\`%"XO`!A*K`6`9P1.N@2<0JP%:"(+)`<LR
XM;`F03J[_XBP`2H9F$DZN_WPI0`5H<`(I0`F,</]@`B`&3-\(Q$YU``!.5?_\B
XM2.<A$"9O`!A*K`6`9P1.N@140JP%:"(+=/XL;`F03J[_K"X`2H=G"B('3J[_Y
XMIG#_8"8B"R0\```#[DZN_^(N`$J'9A).KO]\*4`%:'`"*4`)C'#_8`(@!TS?-
XM"(1.74YU3E7__$CG(1`F;P`82JP%@&<$3KH#\$*L!6@B"W3^+&P)D$ZN_ZPN&
XM`$J'9PPB!TZN_Z8B"TZN_[@B"R0\```#[DZN_^(N`$J'9A).KO]\*4`%:'`"_
XM*4`)C'#_8`(@!TS?"(1.74YU```O!RXO``A*K`6`9P1.N@..(@<L;`F03J[_*
XMW'``+A].=4Y5_[`O#DJL"5QF$D/Z`(AP`"QX``1.KOW8*4`)7'``(&P%F!`H+
XM__]#[?^P8`(2V%.`9/IP`"!L!9@0*/__0C4(L$'M_[`I2`-\2'@`*$AX`/IPW
XM`"\`+P!(;`.8<@`O`4AL`X0O`4ZZ`V1(>``43KH$3"QM_ZQ.74YU*BH@4W1AC
XM8VL@3W9E<F9L;W<@*BH``$58250``&EN='5I=&EO;BYL:6)R87)Y````````V
XM`````````$CG,``D`"8!2$)(0\3!QL#`P=1#2$)"0M""3-\`#$YU2H!J```>.
XM1(!*@6H```Q$@6$``"!$@4YU80``&$2`1(%.=4J!:@``#$2!80``!D2`3G4O[
XM`DA!-`%F```B2$!(04A"-`!G```&A,$P`DA`-`"$P3`"2$(R`B0?3G4O`W80J
XM#$$`@&0```;AF5%##$$(`&0```;IF5E##$$@`&0```;EF55#2D%K```&XYE3:
XM0S0`YJA(0D)"YJI(0X#!-@`P`C0#2$'$P9""9```"%-#T(%D_G(`,@-(0^>XT
XM2$#!028?)!].=4Y5_YY(YS,R?@`@;`68'BC__W!/OH!O`BX`(`=#[?^O8`(2I
XMV%.`9/I"-7BOD\DL>``$3J[^VB9`2JL`K&=,("L`K.6`)$`L*@`X2H9F!"PK8
XM`*!*AF<T(@9!^@"R)`AV"RQL"9!.KO_0($=2AR`(&[P`"@BO(@9![?^O)`@F?
XM!RQL"9!.KO_0</]@3DJL"5QF$D/Z`(9P`"QX``1.KOW8*4`)7$'M_Z\I2`/,)
XM2'@`/$AX`/IP`"\`+P!(;`/H2&P#U$AL`\!"ITZZ`6Q/[P`@4X!G!'#_8`)P@
XM`$S?3,Q.74YU*BH@57-E<B!!8F]R="!297%U97-T960@*BH``$-/3E1)3E5%'
XM``!!0D]25``J*BH@0G)E86LZ(`!I;G1U:71I;VXN;&EB<F%R>0```$Y5__POH
XM"R9O`!!.NNQ$(!.0K`DX*T#__$AM__Q.NO/.+H!.N@$8)FW_^$Y=3G4``$CGM
XM`1`N+P`,+P=.N@`\6$\F0"`+9@1P_V`H""L``@`#9P9P`":`8!HO*P`$3KK\D
XMOEA/<``F@$JL!6AG!'#_8`)P`$S?"(!.=2\'+B\`"'``*4`%:$J':R*^K`*<'
XM;!P@!^>`0>P'+$JP"`!G#B`'YX!![`<LT<`@"&`(<`DI0`F,<``N'TYU``!([
XMYP$"<``B/```,``L>``$3J[^SBX``H<``#``2H=F!'``8"!*K`6`9Q@@;`6`U
XM3I!*@&8$<`!@#$AX`!1.N@$"6$\@!TS?0(!.=6&T3G4``$CG,#(L;`E<(&\`^
XM&")O`!PD;P`@)F\`)"`O`"@B+P`L)"\`,"8O`#1.KOZD3-],#$YU```O"R9OD
XM``@@*P`8Y8`B*P`0Y8$O*P`4+Q,O*P`$+RL`""\K``Q![`4$+S`8`$'L!30OK
XM,`@`2'H`9$AL"91.NNY`3^\`)$'L"90@""9?3G5*86X`1F5B`$UA<@!!<'(`J
XM36%Y`$IU;@!*=6P`075G`%-E<`!/8W0`3F]V`$1E8P!3=6X`36]N`%1U90!7.
XM960`5&AU`$9R:0!3870`)7,@)7,@)3`R9"`E,#)D.B4P,F0Z)3`R9"`Q.24P2
XM,F0*`$CG!P`N+P`0("P"G%.`+`!*1FLP(`9(P.>`0>P'+"HP"`!*!6<:"`4`+
XM`F84(`9(P.>`0>P'+"\P"`1.NOKH6$]31F#,+P=.NM>>6$],WP#@3G4``$CG)
XM`#(F;`FP(`MG%"13(DL@*P`(+'@`!$ZN_RXF2F#HD<@I2`FT*4@)L$S?3`!.9
XM=4CG`3(N+P`4<`S>@"`'<@`L>``$3J[_.B9`(`MF!'``8#HG1P`(1>P)L"!J'
XM``0G2``$D<@FB$J29@(DBTJJ``1G!B)J``0BBR5+``1*K`*@9@0I2P*@0>L`+
XM#"`(3-],@$YU``````````````````````/L`````@````````:,```%;@``D
XM``(````"````#`````8````````#\@```^D````````#\@```^H```%4````N
XM_U6J=P!5<V%G93H@340@6SYR97!O<G1F:6QE72!;+7%A9&1R97-S9FEL95T*M
XM``!#86YN;W0@;W!E;B!O=71P=70@9FEL92X*`%5S86=E.B!-1"!;/G)E<&]R_
XM=&9I;&5=(%LM<6%D9')E<W-F:6QE70H``$U$+2U-96UO<GD@1&EA9VYO<W1I=
XM8RX*`&)Y($9A8F)I86X@1RX@1'5F;V4L($E)20H`5F5R<VEO;B`Q+C$L(#$P5
XM($%P<FEL(#$Y.#D*"@``365M;W)Y('1E<W1E9"`E<PH*``!!;&QO8V%T:6YG3
XM("5L9"!B>71E(&)L;V-K<RX*``!3;W)T:6YG(&)L;V-K(&QI<W0N"@``4V]R8
XM="!C;VUP;&5T92X*`$)L;V-K<R!E>&%M:6YE9#H*`$)L;V-K(",@("`@061DI
XM<F5S<R`@("`@("`@(%-I>F4*"@`E-&0@("`@("`E.&Q8("`@("`@)3=L9`H`@
XM``H`26YI=&EA;&EZ:6YG(&)L;V-K("5D+"`E;&0@8GET97,N"@``5&5S=&EN`
XM9R!V86QU92`E6"X*``!497-T:6YG(&)L;V-K("5D+"`E;&0@8GET97,@=VETG
XM:"`E6`H``$524D]2(2!!9&1R97-S.B`E.&Q8("!F;W5N9#H@)3)8("!E>'!ER
XM8W1E9#H@)3)8"@``5&5S=&EN9R!V86QU92`E6"X*``!497-T:6YG(&)L;V-KL
XM("5D+"`E;&0@8GET97,@=VET:"`E6`H``$524D]2(2!!9&1R97-S.B`E.&Q8`
XM("!F;W5N9#H@)3)8("!E>'!E8W1E9#H@)3)8"@``"DU$(&9O=6YD("5D(&5R!
XM<F]R<RX*`$9R965I;F<@8FQO8VL@)60N"@``)3AL6`H````````H````````=
XM`````````````````````(`````"V@``````````````````````````````<
XM`````````````OP`````````````````````````````````````````````^
XM`````````````````````````````````````````````(``'QP?'A\>'Q\>1
XM'QX?```$`````!\````<````'P```!X````?````'@```!\````?````'@``Q
XM`!\````>````'Q\<'QX?'A\?'A\>'___````#@`.````````````````__\`A
XM```$``0````````E%@```W#__P````0`!````````"4L`````/__````#@`.G
XM````````)Q0`````__\````$``0``````````````ZS__P````0`!```````V
XM`"<P`````/__````!``$````````)SH``````"`@("`@("`@("@H*"@H("`@&
XM("`@("`@("`@("`@("`@2!`0$!`0$!`0$!`0$!`0$(2$A(2$A(2$A(00$!`0`
XM$!`0@8&!@8&!`0$!`0$!`0$!`0$!`0$!`0$!`0$0$!`0$!""@H*"@H("`@("^
XM`@("`@("`@("`@("`@("`A`0$!`@("`@("`@("`@*"@H*"@@("`@("`@("`@H
XM("`@("`@("!($!`0$!`0$!`0$!`0$!`0A(2$A(2$A(2$A!`0$!`0$!"!@8&!4
XM@8$!`0$!`0$!`0$!`0$!`0$!`0$!`1`0$!`0$(*"@H*"@@("`@("`@("`@("8
XM`@("`@("`@("$!`0$"````````(````HZ@``*.X``"CR```H]@``*/H``"C^<
XM```I`@``*08``"D*```I#@``*1(``"D6```I&@``*1X``"DB```I)@``*2H`U
XM`"DN```I,@```^P````8````````!4P```5(```%1```!4````4\```%.```C
XM!30```4P```%+```!2@```4D```%(```!1P```48```%%```!1````4,```%<
XM"```!00```/T```#X````[@```.D```#D`````0````"```#T````Y0```+:L
X,```"N`````````/RO
X``
Xend
Xsize 12432
SHAR_EOF
echo "extracting MQ.uu"
sed 's/^X//' << \SHAR_EOF > MQ.uu
X
Xbegin 644 MQ
XM```#\P`````````#``````````)```:10````$```1]```/I```&D21()`!).
XM^0````!'^0```A!R`"`\````FV`")L%1R/_\+'@`!"E.`D@I3P)00JP"3"9N4
XM`11P`"(\```P`$ZN_LXI:P"8`D1*JP"L9P``<"`/D*\`!`:`````@"E``A1A=
XM``$N(&L`K-'(T<@B:``0T\G3R2`"<@`2&2E)`EC0@5*`0F=2@`)`__Z?P%6`&
XM0G<(`"`"4X#4@1^R```@`%."4<C_]A^\`"`@`%."'[$@`"``4<K_^")/+PE@Z
XM``!X*6L`.@(4<']2@-&L`A1A``#"0>L`7$ZN_H!!ZP!<3J[^C"E``DPO`"1`M
XM("H`)&<2+&P$;"!`(B@``"E!`D1.KO^"(BH`(&<:)#P```/M3J[_XBE``E1G&
XM"N6(($`G:``(`*0@;`),+PA(;`(0(&@`)"EH``0"6$ZZ`:!.N@B$<`!@!"`OD
XM``0O`"`L`CQG!"!`3I!.NA@<+'@`!")L!&Q.KOYB3KH!=DJL`DQG&B(L`E1GS
XM!$ZN_]PL>``$3J[_?")L`DQ.KOZ&(!\N;`)03G5P9&"T0_H`$'``3J[]V"E`C
XM!&QG[$YU9&]S+FQI8G)A<GD`3E7^2$CG/S!P`"X`1^W^6"M`_E`K0/Y44H<O<
XM"TAL``!.N@\24$]8BU*`9P9P9+Z`;>8@!U.`0J=(;``&+T``*$ZZ&#Y03RE`H
XM`EQ*@&8*2'@`%$ZZ$JA83TZZ&`8@;`)<)F@!0F```)XD:P`08```CGH`>`!@3
XM=D'M_EC1Q"9((`HB*@`$T(%3@"03L()E9"`*L()B5"`*E(`@`G8'P(.4@"P"!
XMDH8N`5&'9@8E1@`$8!0@"M"&4(`@0""2(4<`!"2`)48`!"9M_DQ*AF842JW^K
XM4&8((%(G2``08`8@;?Y0())1JP`<4*W^5%*%6(2ZKP`@;80K2OY0)%(F;?Y,,
XM(`IF`/]P)E,K2_Y,2I-F`/]<3KH78"\M_E1(;``43KH`Y$SM#/S^*$Y=3G5.:
XM=4YU2.<',"XO`!@F;P`<+"\`("\'3KH58%A/)$`@"F8$</]@-@@J``,``V<0%
XM2'@``D*G+P=.NA!T3^\`#"\&+PLO*@`$3KH1X$_O``PJ`$JL`BAG!'#_8`(@L
XM!4S?#.!.=0``````````<&%(YP,0)F\`$"!+2AAF_%.(D<LL"'X`'AM*AV<R2
XM4ZP`=FT6(&P`;D/H``$I20!N(`<0@'(`$@!@W"`'<@`2`$AL`&HO`4ZZ"*90T
XM3R(`8,9(;`!J2'C__TZZ")103R`&3-\(P$YU````````<&%.5?_<2.</,"9OD
XM`$1\`$'M``PK2/_R'AM*!V<``0IP);X`9@``S!X;<``0!W(874%K``"(L'L0U
XM"&;T3OL0!`!D8```4`!X8```&@!P8```%`!S8````B!M__(D6"M(__)@2B!M3
XM__(H&"M(__)%[?_L>@=*A6L6(`1R#\"!0?H`P-'`%)!3BNB$4X5@YD(M_^U@[
XM&B!M__(H&"M(__(O!$AM_^5.N@Q84$]%[?_E+PI.NO[D6$_<@&``_UY2AE.LC
XM`'9M&"!L`&Y#Z``!*4D`;B`'$(!R`!(`8`#_/G``$`=(;`!J+P!.N@>:4$\B7
XM`&``_RA2AE.L`'9M&"!L`&Y#Z``!*4D`;B`'$(!R`!(`8`#_"'``$`=(;`!JF
XM+P!.N@=D4$\B`&``_O)(;`!J2'C__TZZ!U`@!DSM#/#_Q$Y=3G4P,3(S-#4V?
XM-S@Y04-$148```!.5?_@2.<G,"9O`$`D;P!,<`!R`!(3*T#_\"M`_^Q![`$)E
XM"#```A@`9R@@+?_L<@I.NA$"<@`2&W0/PH+0@2M`_^QP`!`30>P!"0@P``(()
XM`&;8$!-R;+`!9@I2BW`!*T#_\&`(<FBP`68"4HL@;0`,3I`N`'!CL!-G%D'LE
XM`0D(,``#>`!G"B!M``Q.D"X`8.IP_[Z`9@P@;0`0((=P`&```YAP`!`3<C9=#
XM06L``WRP>Q`(9O1.^Q`$`'-@``,V`&-@``+B`&A@``*&`%A@``%&`'A@``%``
XM`'!@``$N`&]@``"^`&1@```,`'5@```"?`!@-GP`2JW_[&<*#*T````!_^QOH
XM)'`MOH!G!G(KOH%F&+Z`9@1P_V`"<``L`"!M``Q.D"X`4ZW_[$'L`0D(,``"<
XM>`!F#"!M`!`@AW``8``"^D*M_^@@+?_H<@I.N@_H(@=T#\*"T($K0/_H(&T`?
XM#$Z0+@!3K?_L9PQ![`$)"#```G@`9M`@"F<``K1*AFH$1*W_Z$JM__!F#"!2\
XM("W_Z""`8``"FB!2(*W_Z&```I!P,+Z`;09P-[Z`;PP@;0`0((=P`&```H1"U
XMK?_H("W_Z.>`(@=T!\*"T($K0/_H(&T`#$Z0+@!3K?_L9PQP,+Z`;09P-[Z`S
XM;]0@"F<``D)*K?_P9@P@4B`M_^@@@&```C`@4B"M_^A@``(F2JW_[&8&<`@KG
XM0/_L0>P!"0@P``=X`&8,(&T`$""'<`!@``(.*@<@;0`,3I`N`$JM_^QG"@RM1
XM`````O_L;SQP,+J`9C9P>+Z`9P9P6+Z`9BH@;0`,3I`N`$'L`0D(,``'>`!FP
XM#"!M`!`@AW``8``!PD*M_^A3K?_L8$)![`$)"#```E@`9PH@!7(PD($K0/_HJ
XM0>P!"0@P``!8`&<*(`5R-Y"!*T#_Z$'L`0D(,``!6`!G"B`%<E>0@2M`_^A3&
XMK?_L9V)![`$)"#``!W@`9U8@+?_HZ8`K0/_H0>P!"0@P``)X`&<*(`=R,)"!O
XM@:W_Z$'L`0D(,```>`!G"B`'<C>0@8&M_^A![`$)"#```7@`9PH@!W)7D(&!^
XMK?_H(&T`#$Z0+@!@F"`*9P``_$JM__!F#"!2("W_Z""`8```ZB!2(*W_Z&``L
XM`.!![`$)"#```G@`9@P@;0`0((=P`&```-1\`"`&<@I.N@W&(@=T#\*"T($L)
XM`")M``Q.D2X`4ZW_[&<,0>P!"0@P``)X`&;4(`IG``"4(%(@!C"`8```BB`*J
XM9PP@4D/H``$DB2`'$(!3K?_L;R`@;0`,3I`N`'#_OH!G$B`*9^@@4D/H``$DU
XMB2`'$(!@VG#_OH!F"B!M`!`@AW``8$Y!ZP`!(`A@1B`*9PP@4D/H``$DB2`'#
XM$(`@;0`,3I`N`'#_OH!G$E.M_^QG#$'L`0D(,``#>`!GT"!20A!@!'``8`P@^
XM;0`0((=!ZP`!(`A,WPSD3EU.=0```````'!A2.<A$"XO`!`F;P`4</^^@&=@]
XM""L````;9UAR,,*K`!A*@69.""L``@`;9Q@B!Q=!`"!!ZP`@)T@`!'0!)T(``
XM""`!8"X@:P`$(FL`$+/(9@1P_V`>4ZL`!"!K``0@!Q"`""L`!P`:9P93JP`($
XM8`12JP`(3-\(A$YU3E7_\$CG(3(F;P`L#*P````@`]IL``"&$!-R(+`!9PQRJ
XM";`!9P9R"K`!9@12BV#H2A-G:"`L`]KE@%*L`]I![`/BT<`D2'`BL!-F)E*+%
XM)(M*$V<*<"*P$V<$4HM@\DH39@Q(>``!3KH.]%A/8)Y"&V":)(M*$V<8$!-RB
XM(+`!9Q!R";`!9PIR"K`!9P12BV#D2A-F`F`&0AM@`/]R2JP#VF8&(&P"3&`$T
XM0>P#XBE(`]Y*K`/:9GQ!^@$D0^P#H"+8(M@BV"+8,I`B;`),(&D`)$AX`"@O5
XM*``$2&P#H$ZZ!;9/[P`,0>P#H"(()#P```/N+&P$;$ZN_^(I0`)D*4`";'($<
XM*4$":"E``G0I00)PY8"3R2QX``0K0/_P3J[^VB!M__`B0"-H``@`I'X`*T#_C
XM]&`J+&P$;$ZN_\HI0`)D3J[_Q"E``FQ!^@"F(@@D/````^U.KO_B*4`"='X$)
XM(`<`0(`!@:P"8"`'`$"``H&L`F@`K```@`,"<$JL`+!G!'``8`8@/```@``N)
XM`$*L`&0@!P!```$I0`!@<`$I0`"&(`<`0``"*4``@G`"*4``J"`'`$``@"E`*
XM`*1!^@N>*4@"0"\L`]XO+`/:3KKV)D*73KH)'$SM3(3_W$Y=3G5C;VXZ,3`OU
XM,3`O,S(P+S@P+P`J`````````````````````````````````````````'!AF
XM+PLF;P`(2JL`%&<,""L``P`;9@1P`&`V+RP"#$ZZ"*I83R=```0G0``02H!FP
XM"G`,*4`$:'#_8!8G;`(,`!1P\\&K`!AP`"=```PG0``()E].=0``````````V
XM````````3E7_[$CG+Q`N+P`T)F\`."@'<#'`JP`89P9P_V```G`(*P`'`!I6%
XMP$0`2(!(P"P`2JL`%&8``(0(*P`"`!MF>G``)T``#'+_OH%G``)"+PM.NO].P
XM6$]*@&<,".L`!0`;</]@``(J".L``0`;2@9G#B`K`!0B`$2!)T$`#&`(("L`S
XM%"=```Q3JP`,;18@:P`$0^@``2=)``0@!Q"`<@`2`&`2(`=R`!(`+PLO`6$`F
XM_U)03R(`(`%@``'6""L``@`;9UAP_[Z`9@9P`&```<(@!QM`__]*!F<B<@J^X
XM@68<<@(O`4AZ`;(O*P`<*T'_\$ZZ];Q/[P`,*@!@&G(!+P%(;?__+RL`'"M!,
XM__!.NO6@3^\`#"H`?O]@``#@".L``0`;2@9G4G#_OH!G3%2K``QR"KZ!9B8@G
XM:P`$0^@``2=)``00O``-(BL`#$J!:PHO"R\`80#^KE!/4JL`#"!K``1#Z``!:
XM)TD`!"`'$(`B*P`,2H%K``$<?O\@*P`$D*L`$"M`__!G<@@K``8`&F=22'@`M
XM`D*G+RL`'$ZZ!;Q/[P`,*T#_[$H&9SA3K?_L;3)"IR\M_^PO*P`<3KH%G$AX2
XM``%(;?_]+RL`'$ZZ!41/[P`82JP"*&8*$"W__7(:L`%GR"\M__`O*P`0+RL`3
XM'$ZZ],!/[P`,*@!@`GH`</^Z@&8(".L`!0`;8`RZK?_P9P8(ZP`$`!M*!F<.8
XM(BL`%"0!1((G0@`,8!@(*P`"`!MG"'(`)T$`#&`((BL`%"=!``P@:P`0)T@`E
XM!+Z`9RY3JP`,;18@:P`$0^@``2=)``0@!Q"`<@`2`&`2(`=R`!(`+PLO`6$`V
XM_9!03R(`<##`JP`89P1P_V`,</^X@&8$<`!@`B`$3-\(]$Y=3G4-"@````!(R
XMYP<0)F\`%`@K``<`&E;`1`!(@$C`+@!P,,"K`!AG"D*K``AP_V```5@(*P`'^
XM`!MG%`@K``8`&V<,+PM(>/__3KK](E!/2JL`%&8V0JL`"`@K``(`&V<2<`$G6
XM0``40>L`("=(`!!@``"$+PM.NOR66$]*@&=V".L`!0`;</]@``$`2@=G9E2KE
XM``@@*P`(2H!N6B!K``1#Z``!)TD`!'P`'!`@!@R`````&F<N#(`````-9C)3I
XMJP`(;10@:P`$0^@``2=)``1P`!`08```M"\+80#_+EA/8```J`CK``0`&W#__
XM8```G"`&8```E@@K``$`&V9.".L````;+RL`%"\K`!`O*P`<3KH#:$_O``PJ>
XM`$J%:@8(ZP`%`!M*A68&".L`!``;2H5O&DH'9PH@!42`)T``"&`$)T4`""!KT
XM`!`G2``$<#+`JP`89Q9*!V<(</\G0``(8`9P`"=```AP_V`@4ZL`"&T2(&L`'
XM!$/H``$G20`$<``0$&`(+PMA`/Z$6$],WPC@3G4``$Y5__A(YP,P)F\`("1OZ
XM`"0N+P`H($I*&&;\4XB1RBP(($M*&&;\4XB1RR`((DO3P"M)__B\AV,"+`<@U
XM!B!*8`(2V%.`9/H@;?_X0C!H`"`+3-\,P$Y=3G4@+P`((&\`!$Y5__0B3VP&^
XM$/P`+42`<@I.N@7`!D$`,!+!2H!F\!#AO\EF^D(0(`A.79"O``1.=4Y5_^A(&
XMYR,P)F\`-$'M``Q^`"M(_^Q*$V<``1I\`!P;0>P!"0@P``-H`&;J<"6\@&8`,
XM`+IP);`39CA3K`!0;0YP`"!L`$P0&"E(`$Q@"DAL`$A.NOV46$\L`$'L`0D(X
XM,``#:`!FU'`EO(!GJB`'8```QG`JL!-G#"MM_^S_Z%BM_^Q@")'(4HLK2/_HF
XM0JW_]"\M_^A(;?_T2'H`I"\+3KKS?$_O`!`D0$J`5L!$`$B`2,!*@&<")DHB/
XM+?_T=/^R@F822H!G`E*'2H=O!"`'8&8@`F!B2H%G#$AL`$@O`4ZZ]X103R`*6
XM9D8@!V!*4ZP`4&T.<``@;`!,$!@I2`!,8`I(;`!(3KK\XEA/*T#_]"!M__1#(
XM[`$)(`@(,0`#"`!FS"`M__2PAF<`_NX@!V`(4H=@`/[D(`=,WPS$3EU.=5.L6
XM`%!M#G``(&P`3!`8*4@`3&`*2&P`2$ZZ_)!83TYU``!.5?_H2.<!,BXO`#1*C
XMAVX&</]@``#2<`B^@&0"+@`@!U:`+@`"1__\)&T`""!M``C1Q]^L`$1#[`!`9
XM)E$K2/_P*TG_]"`+9P``D"!+("L`!-'`*TC_[")M__"WR6,0)(LE1P`$+&W_S
XM]"R*<`!@>+?)9AHL4R2.("L`!"(`TH<E00`$+&W_]"R*<`!@6K7(9`B?K`!$[
XM</]@3K7(9BQ*DV<.(%.SR&,(GZP`1'#_8#C?JP`$2I-G#K/39@H@*0`$T:L`,
XM!":1<`!@'BM+__0K;?_L_^@F4V``_VX@;?_T((I"DB5'``1P`$S?3(!.74YU%
XM``````````!P84CG!S`N+P`8)F\`'"PO`"`O!TZZ!0!83R1`(`IF!'#_8!XO6
XM!B\++RH`!$ZZ`F!/[P`,*@!*K`(H9P1P_V`"(`5,WPS@3G4``$CG#Q`N+P`89
XM+"\`'"HO`"`O!TZZ!+A83R9`(`MF!'#_8!XO!2\&+RL`!$ZZ`9Q/[P`,*`!*A
XMK`(H9P1P_V`"(`1,WPCP3G4``````````'!A2.<#,"XO`!1*AVX&<`!@``"DY
XM<`B^@&0"+@`@!U:`+@`"1__\1>P`0"92(`MG0"`K``2PAVTRL(=F#"!3)(B?`
XMK`!$(`M@;B`K``20AW((L(%E%B!+T<<DB"1()),E0``$GZP`1"`+8$PD2R93^
XM8+P@!R(L`+30@5.`3KH"!B(L`+1.N@'>+`!0AB`&5H`L``)&__PO!DZZ!398?
XM3R9`(`MG$B\&+PM.NOW*+H=A`/]44$]@`G``3-\,P$YU``````````!P82\'R
XM+B\`""\'3KK_,EA/+A].=0``2.<#$"XO`!!'[`!((`MG-`@K``(`&V8H""L`,
XM`0`;9R`@*P`$D*L`$"P`2H9G$B\&+RL`$"\K`!Q.NNWV3^\`#"938,@O!TZZ;
XM!"A83TS?",!.=0``2.<W$"XO`!PF;P`@+"\`)$JL`D!G!$ZZ`X!"K`(H(@<D_
XM"R8&+&P$;$ZN_]`J`'#_NH!F#DZN_WPI0`(H<`4I0`1H(`5,WPCL3G4``$CG;
XM/P`N+P`<+"\`("HO`"1*K`)`9P1.N@,T0JP"*"`%4X`B!R0&)@`L;`1L3J[_>
XMOB@`</^X@&8.3J[_?"E``BAP%BE`!&@@!0R``````F<6#(`````!9PA*@&88:
XM(`9@%"`$T(9@#B('=`!V`"QL!&Q.KO^^3-\`_$YU``!(YS<0+B\`'"9O`"`L0
XM+P`D2JP"0&<$3KH"N$*L`B@B!R0+)@8L;`1L3J[_UBH`</^Z@&8.3J[_?"E`4
XM`BAP!2E`!&@@!4S?".Q.=0``+P<N+P`(2JP"0&<$3KH"=B('+&P$;$ZN_]QPQ
XM`"X?3G5(YS``)``F`4A"2$/$P<;`P,'40TA"0D+0@DS?``Q.=4J`:@``'D2`B
XM2H%J```,1(%A```@1(%.=6$``!A$@$2!3G5*@6H```Q$@6$```9$@$YU+P)(!
XM030!9@``(DA`2$%(0C0`9P``!H3!,`)(0#0`A,$P`DA",@(D'TYU+P-V$`Q!M
XM`(!D```&X9E10PQ!"`!D```&Z9E90PQ!(`!D```&Y9E50TI!:P``!N.94T,T$
XM`.:H2$)"0N:J2$.`P38`,`(T`TA!Q,&0@F0```A30]"!9/YR`#(#2$/GN$A`%
XMP4$F'R0?3G5.5?^>2.<S,GX`(&P"6!XH__]P3[Z`;P(N`"`'0^W_KV`"$MA3)
XM@&3Z0C5XKY/)+'@`!$ZN_MHF0$JK`*QG3"`K`*SE@"1`+"H`.$J&9@0L*P"@-
XM2H9G-"(&0?H`LB0(=@LL;`1L3J[_T"!'4H<@"!N\``H(KR(&0>W_KR0()@<L)
XM;`1L3J[_T'#_8$Y*K`1D9A)#^@"&<``L>``$3J[]V"E`!&1![?^O*4@`V$AX\
XM`#Q(>`#Z<``O`"\`2&P`]$AL`.!(;`#,0J=.N@$(3^\`(%.`9P1P_V`"<`!,C
XMWTS,3EU.=2HJ(%5S97(@06)O<G0@4F5Q=65S=&5D("HJ``!#3TY424Y510``[
XM04)/4E0`*BHJ($)R96%K.B``:6YT=6ET:6]N+FQI8G)A<GD`````````````;
XM```````O!RXO``AP`"E``BA*AVLBOJP`,&P<(`?G@$'L`F!*L`@`9PX@!^>``
XM0>P"8-'`(`A@"'`)*4`$:'``+A].=0``````````<&%(YP$"<``B/```,``LK
XM>``$3J[^SBX``H<``#``2H=F!'``8"!*K`)`9Q@@;`)`3I!*@&8$<`!@#$AX)
XM`!1.N@!&6$\@!TS?0(!.=6&T3G4``$CG,#(L;`1D(&\`&")O`!PD;P`@)F\`C
XM)"`O`"@B+P`L)"\`,"8O`#1.KOZD3-],#$YU``!(YP<`+B\`$"`L`#!3@"P`F
XM2D9K,"`&2,#G@$'L`F`J,`@`2@5G&@@%``)F%"`&2,#G@$'L`F`O,`@$3KK\=
XMO%A/4T9@S"\'3KKGWEA/3-\`X$YU``!(YP`R)FP$<"`+9Q0D4R)+("L`""QX(
XM``1.KO\N)DI@Z)'(*4@$="E(!'!,WTP`3G5(YP$R+B\`%'`,WH`@!W(`+'@`P
XM!$ZN_SHF0"`+9@1P`&`Z)T<`"$7L!'`@:@`$)T@`!)'()HA*DF8")(M*J@`$,
XM9P8B:@`$(HLE2P`$2JP`-&8$*4L`-$'K``P@"$S?3(!.=0``````````````T
XM````+PXL>0```DA.KO]\+%].=2\.+'D```)(3J[_=BQ?3G4O#BQY```"2")O9
XM``@@+P`,3J[]V"Q?3G4```/L````!0````(``!HP```:(```&A`````,````R
XM!@````````/R0``#Z0````````/R0``#Z@```(0E.&Q8"@!E>&5C+FQI8G)A5
XM<GD``$U1.B`E9"!B>71E<R!Q=6%R86YT:6YE9"X*```````H````````````/
XM``````````````````!J````````````````````````````````````````J
XM````C```````````````````````````````````````````````````````,
XM````````````````````````````````````@`````0`__\````.``X`````>
XM```7]`````#__P````0`!```````````````N/__````!``$````````&!``W
XM````__\````$``0````````8&@``````("`@("`@("`@*"@H*"@@("`@("`@`
XM("`@("`@("`@("!($!`0$!`0$!`0$!`0$!`0A(2$A(2$A(2$A!`0$!`0$!"!Q
XM@8&!@8$!`0$!`0$!`0$!`0$!`0$!`0$!`1`0$!`0$(*"@H*"@@("`@("`@("5
XM`@("`@("`@("`@("$!`0$"`@("`@("`@("`H*"@H*"`@("`@("`@("`@("`@@
XM("`@($@0$!`0$!`0$!`0$!`0$!"$A(2$A(2$A(2$$!`0$!`0$(&!@8&!@0$!8
XM`0$!`0$!`0$!`0$!`0$!`0$!$!`0$!`0@H*"@H*"`@("`@("`@("`@("`@("<
XM`@("`@(0$!`0(````````@````/L`````P````````$`````[````,0````#2
X8`````@```-P```!J````2`````````/R%
X``
Xend
Xsize 7404
SHAR_EOF
echo "End of archive 1 (of 1)"
# if you want to concatenate archives, remove anything after this line
exit