[comp.sources.amiga] v89i027: qmenu - quick menu creation code

page@swan.ulowell.edu (Bob Page) (03/08/89)

Submitted-by: well!shf (Stuart H. Ferguson)
Posting-number: Volume 89, Issue 27
Archive-name: intuition/qmenu.1

[uuencoded test program included.  ..Bob]

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	ReadMe
#	Makefile
#	qmenu.c
#	qmenu.h
#	mtst.c
#	mtst.uu
# This archive created: Tue Mar  7 21:10:08 1989
cat << \SHAR_EOF > ReadMe
IntuiTools: qmenu

Here's a little quick menu creation code I put together for making menus
for Modeler 3D.  The instructions are in the comments.  Included are the
main code itself in a module and an example program.  The code compiles
under Manx 3.6, but I can't see why I wouldn't compile equally well 
elsewhere.

Enjoy,

	Stuart Ferguson		1/89
	(shf@well.UUCP)

	123 James Ave.
	Redwood City, Ca.
		94062
SHAR_EOF
cat << \SHAR_EOF > Makefile
# Quickmenu Module and test program (mtst).
# Manx 3.6 Makefile.

mtst : mtst.o qmenu.o
	ln mtst.o qmenu.o -lc -o $@

qmenu.o : qmenu.c qmenu.h
	cc qmenu.c -o $@

mtst.o : mtst.c qmenu.h
	cc mtst.c -o $@
SHAR_EOF
cat << \SHAR_EOF > qmenu.c
/*
 * Quick Menu Package -- An easy way to make simple (but nice) menus.
 *
 * The client programmer will generally use the GenMenu()/FreeMenu() 
 * interface which creates and frees a whole menu strip.  A menu strip
 * -- both the main strip and menu item strips -- is defined by a
 * NewMenu struct.  Each NewMenu struct (defined in qmenu.h) is just a
 * pointer to an array of strings and a pointer to an array of
 * NewMenu's.  The elements of the array of NewMenu's are paired with the
 * strings in the array and represent the sub menus for that string.
 * The string array is terminated with a null pointer.
 *
 * The package tries to do nice things, like automatically formatting
 * the menu strings into blocks with their command keys, and placing
 * markers pointing to subitem stips.  The strings for the menu items
 * can contain special control codes to control the optional 
 * characteristics of items.  Special codes come at the front of item
 * strings and are delimited with a special character (SPECIAL,
 * defined as '!' by default) and are listed briefly below:
 *
 *	c	Checkmark item
 *	t	Checkmark toggle
 *	+	Checkmark checked
 *	b	Highlight box
 *	n	Highlight none
 *	d	Disabled
 *	=C	Set command key to "C"
 *	0101...	Set item exclude mask
 *
 * Any number of 1's and 0's after the special character will set the
 * Mutual exclude bits for that item in the order they occur.  So the
 * first 1 or 0 will set bit 0 of the exclude mask, the second will
 * set bit 1, etc.  Any unset will be 0.
 *
 * Additionally, if the item string is "-", the item will be 
 * a non-selectable horizontal line (a "rule") that can be used to 
 * visually group similar items in the menu strip.  There only need
 * to be NewMenu structs in the array for text menu items, not rules,
 * but don't forget to account for rules when counting MenuItem's
 * since they take a slot.
 *
 *
 * GenMenu() takes a pointer to a NewMenu struct and will create a main
 * Menu strip from the strings in the struct, with menu items from the
 * associated NewMenu's.  It returns a pointer to a Menu struct which is
 * the first element in the list for this strip.
 *
 * GenStrip() takes a pointer to an array of strings and creates a
 * top-level set of Menu structs for the main menu strip.
 *
 * FreeMenu() frees a Menu strip created with either GenMenu() or
 * GenStrip().
 *
 * GenItems() takes a pointer to a NewMenu struct and creates a single
 * list of MenuItem's from the description.  It also takes an X and Y
 * offset for all the elements in the list.
 *
 * FreeMItem() frees structures created by the above function.
 *
 * AttachSubMenu() takes a single MenuItem and a NewMenu struct and
 * attaches the MenuItems created from that NewMenu struct to the
 * parent MenuItem.  The parent should also have been created with
 * GenItems() in order to work correctly.  AttachSubMenu() places a
 * little maker on the parent item to show that it has subitems.  It
 * returns 1 for sucess and 0 for failure.
 *
 * -- WARNING:
 *
 * The client programmer is completely responsible for keeping the
 * menus within the bounds of the screen and for keeping within the
 * limits of Intuition.  The menu structures will not adjust as they
 * hit the borders of the screen (which might be a nice enhancement).
 * The strings in the NewMenu structures cannot be changed or deleted
 * while the Menus are in use, although they can be used to create
 * multiple Menus from the same strings.
 *
 **
 * This code can be used and modified freely.  Do let me know of any
 * improvements or enhancements you may add, and be sure to give credit
 * where credit is due (in the comments) if you redistribute this code.
 *
 *	Stuart Ferguson		1/89
 *	(shf@well.UUCP)
 */
#include <intuition/intuition.h>
#include "qmenu.h"

/*
 * Some useful macros for allocating and freeing structures and
 * arrays of structures.
 */
#define NEW(typ)	(typ*)AllocMem((long)sizeof(typ),0L)
#define FREI(p)		FreeMem(p,(long)sizeof(*p))

#define NEW_N(typ,n)	(typ*)AllocMem((long)((n)*sizeof(typ)),0L)
#define FREI_N(p,n)	FreeMem(p,(long)((n)*sizeof(*p)))

char * AllocMem();

/*
 * Definitions for formatting the menus.  Glossary:
 *
 *	TEXTCOLOR	- color of the text items in the menus.
 *	MARKCOLOR	- color of the subitem marker.
 *	RULECOLOR	- color of the horizontal lines in the menus.
 *	RULEHEIGHT	- vertical thickness of the horizontal rules.
 *	RULEGAP		- vertical blank space around the rules.
 *	RULEMARGIN	- horizontal blank space around the rules.
 *	TEXTGAP		- vertical blank space around the text items.
 *	TEXTMARGIN	- horizontal blank space around the text items.
 *	MAINWID		- width of the text font on the main menu.
 *	MAINGAP		- spacing between items on the main menu strip.
 *	SUBINDENT	- overlap between items and their subitems.
 *	SUBDOWN		- vertical shift between items and their subitems.
 */
#define TEXTCOLOR	2
#define MARKCOLOR	3
#define RULECOLOR	0
#define RULEHEIGHT	2
#define RULEGAP		4
#define RULEMARGIN	10
#define TEXTGAP		2
#define TEXTMARGIN	4
#define MAINWID		10
#define MAINGAP		10
#define SUBINDENT	18
#define SUBDOWN		0

/*
 * Escape character for special control codes in text items strings.
 */
#define SPECIAL		'!'

/*
 * The extern "ta" is set by the client program for
 * the font to use for these menus.
 */
extern struct TextAttr ta;

/*
 * Generic templates to use for creating the dynamic menu structures. 
 */
static struct IntuiText
  generic_itext = {TEXTCOLOR, 0, JAM1, TEXTMARGIN/2, TEXTGAP/2, &ta,NULL,NULL},
  generic_smark = {MARKCOLOR, 0, JAM1, 0, TEXTGAP/2, &ta, (UBYTE *) ";", NULL};

static struct Menu
  generic_main = {NULL, 0, 0, 0, 10, MENUENABLED, NULL, NULL};

static struct MenuItem
  generic_mitem = {
	 NULL, 0, 0, 0, 0,
	 ITEMTEXT | ITEMENABLED | HIGHCOMP,
	 0, NULL, NULL, 0, NULL, 0
};

/* Image struct with no imagery for the horizontal lines.
 */
static struct Image
  generic_hrule = {0, 0, 1, RULEHEIGHT, 2, NULL, 0, RULECOLOR, NULL};

static struct MenuItem
  generic_hitem = {
	 NULL, RULEMARGIN/2, 0, 0, 0,
	 ITEMENABLED | HIGHNONE,
	 0, NULL, NULL, 0, NULL, 0
};


/*
 * Takes an array of strings and associated array of NewMenu structs
 * (as a single NewMenu struct) and constructs a menu strip from the
 * descripton.  This is the main high-level call that most clients
 * will make.
 */
struct Menu * GenMenu (nmen)
	register struct NewMenu *nmen;
{
	register short  i, ok, n;
	register struct Menu *mm;
	register struct MenuItem *mi;

	/* Count menus to be generated and create top level structure.
	 */
	for (n = 0; nmen->str[n]; n++) ;
	mm = GenStrip (nmen->str);
	if (!mm) return NULL;

	/* Create the item strip for each main menu and attach to the
	 * top level Menu structure.  Any failure causes the whole
	 * thing to crumble to dust.
	 */
	ok = 1;
	nmen = nmen->submenu;
	for (i = 0; i < n; i++) {
		if (nmen->str) {
			mi = GenItems (nmen, 0L, 0L);
			mm[i].FirstItem = mi;
			ok &= (mi != NULL);
		}
		nmen ++;
	}
	if (!ok) {
		FreeMenu (mm);
		return NULL;
	}
	return mm;
}


/*
 * Generate a menu strip.  Just creates the top level Menu structures,
 * linked together and intialized.  Takes an array of pointers to
 * strings.
 */
struct Menu * GenStrip (str)
	char **str;
{
	register short  i, x, num;
	register struct Menu *mm, *m;

	/*
	 * Create enough struct Menu's for the menu strip. 
	 */
	for (num = 0; str[num]; num++) ;
	mm = NEW_N (struct Menu, num);
	if (!mm) return NULL;

	/*
	 * Init the structures using the generic Menu struct as a template.
	 * NOTE: the size of the font for these item labels is unknown for
	 *       windows on the Workbench screen, so a size should be used
	 *       that will work with 60 & 80 column fonts. 
	 */
	x = 0;
	for (i = 0; i < num; i++) {
		m = &mm[i];
		*m = generic_main;
		m->LeftEdge = x;
		m->Width = strlen (str[i]) * MAINWID + TEXTMARGIN;
		x += m->Width + MAINGAP;
		m->MenuName = str[i];
		m->NextMenu = m + 1;
	}
	mm[num - 1].NextMenu = NULL;
	return mm;
}


/*
 * Attach a submenu to a MenuItem.  Takes the parent MenuItem and a
 * NewMenu structure that will be attached as a sub-menu.  
 * Attaches a ";" mark at the end of the parent item and calls
 * GenItems() to create the sub-menu strip.
 */
BOOL AttachSubMenu (mi, nmen)
	register struct MenuItem	*mi;
	struct NewMenu			*nmen;
{
	register struct IntuiText *it;

	/* Create an IntuiText with the marker and position it
	 * at the right edge of the item.
	 */
	if (!(it = NEW (struct IntuiText))) return FALSE;
	*it = generic_smark;
	it->LeftEdge = mi->Width - IntuiTextLength (it) - 2;

	/* Create the subitem structure and attach to the main item.
	 */
	if (!(mi->SubItem = GenItems
	      (nmen, (LONG) (mi->Width - SUBINDENT), (LONG) SUBDOWN))) {
		FREI (it);
		return FALSE;
	}

	/* Only if it all worked attach the new text structure.
	 */
	((struct IntuiText *) mi->ItemFill)->NextText = it;
	return TRUE;
}


/*
 * Takes the given menu text item and skips past the special control
 * codes while adjusting the associated MenuItem appropriately.
 * Special codes are in the form of "!x", where "x" is:
 *
 *	c	Checkmark item
 *	t	Checkmark toggle
 *	b	Highlight box
 *	n	Highlight none
 *	d	Disabled
 *	+	Checkmark checked
 *	=C	Set command key to "C"
 *	1010...	Set item exclude mask
 *
 * Takes the mostly defined MenuItem and diddles it.  Returns a pointer
 * to the item text with control codes stripped.
 */
static UBYTE * ProcessSpecialStuff (str, mi)
	char *str;
	struct MenuItem *mi;
{
	register LONG	x;
	register int	i;

	while (*str == SPECIAL) {
		switch (*++str) {
		    case 'c':
			mi->Flags |= CHECKIT;
			break;
		    case 't':
			mi->Flags |= CHECKIT | MENUTOGGLE;
			break;
		    case 'b':
			mi->Flags &= ~HIGHFLAGS;
			mi->Flags |= HIGHBOX;
			break;
		    case 'n':
			mi->Flags &= ~HIGHFLAGS;
			mi->Flags |= HIGHNONE;
			break;
		    case 'd':
			mi->Flags &= ~ITEMENABLED;
			break;
		    case '+':
			mi->Flags |= CHECKIT | CHECKED;
			break;
		    case '=':
			mi->Flags |= COMMSEQ;
			mi->Command = *++str;
			break;
		    case '0':
		    case '1':
			x = 0;
			i = 0;
			while (*str == '0' || *str == '1')
				x += (*str++ - '0') << (i++);
			mi->MutualExclude = x;
			str--;
			break;
		}
		str++;
	}
	return (UBYTE*) str;
}


/*
 * Construct a basic item list for a menu.  Takes a NewMenu structure
 * which contains a pointer to an array of pointers to strings and a 
 * pointer to an array of NewMenu structures.  The strings contain the
 * item text for each menu plus optional special control codes.  If the
 * string is "-", the item will be a horizontal rule rather than a text
 * item.  The NewMenu structures, if not NULL, are the sub-menu's for
 * each menu in the array.
 * "x" and "y" are the horizontal and vertical offsets of this set of
 * MenuItems.  These are set by AttachSubMenu() for positioning submenus
 * under their parent items.
 */
struct MenuItem *GenItems (nmen, x, y)
	struct NewMenu *nmen;
	LONG	x, y;
{
	register struct MenuItem *mi, *cmi;
	register struct IntuiText *itext;
	struct Image   *img;
	register short  i, len, max;
	short           n;
	struct NewMenu *sub;

	/* Count menu items (n) and allocate an array for the strip.
	 */
	for (n = 0; nmen->str[n]; n++) ;
	if (!(mi = NEW_N (struct MenuItem, n))) return NULL;

	/* Counts the number of rules in the menu ("-" strings)
	 * and allocates the structures for the lines and the text items.
	 */
	max = 0;
	for (i = 0; i < n; i++) max += (*nmen->str[i] == '-');
	if (n - max)
		if (!(itext = NEW_N (struct IntuiText, n - max))) {
			FREI_N (mi, n);
			return NULL;
		}
	if (max)
		if (!(img = NEW_N (struct Image, max))) {
			FREI_N (mi, n);
			if (n - max) FREI_N (itext, n - max);
			return NULL;
		}

	/* Loop through text menu items and initialize the
	 * associated IntuiText structures.  Compute the maximum
	 * width of the menu taking command keys into account while
	 * assigning all the other parts of the text MenuItem's.
	 */
	max = 0;
	for (i = 0; i < n; i++) {
		if (*nmen->str[i] == '-') continue;	/* skip rules */

		/* Init the text MenuItem to point to the assocd IntuiText.
		 */
		cmi = &mi[i];
		*cmi = generic_mitem;
		cmi->ItemFill = (APTR) itext;

		/* Init the IntuiText and adjust the MenuItem from the
		 * flags set in the menu text string.
		 */
		*itext = generic_itext;
		itext->IText = ProcessSpecialStuff (nmen->str[i], cmi);

		/* Make a first cut at measuring the length of the item.
		 */
		len = IntuiTextLength (itext) + TEXTMARGIN;

		/* If command key set, add to length.
		 */
		if (cmi->Flags & COMMSEQ) len += COMMWIDTH + MAINWID;

		/* If this is a checkmark item, shift the text over to
		 * make room and add that to the length.
		 * Compute the max length.
		 */
		if (cmi->Flags & CHECKIT) {
			itext->LeftEdge += CHECKWIDTH;
			len += CHECKWIDTH;
		}
		if (len > max) max = len;
		itext ++;
	}

	/* Secondary assignment loop.  Position the text MenuItems and
	 * init the horizontal lines.
	 */
	for (i = 0; i < n; i++) {
		cmi = &mi[i];

		if (*nmen->str[i] != '-') {
			cmi->LeftEdge = x;
			cmi->TopEdge = y;
			cmi->Width = max;
			cmi->Height = ta.ta_YSize + TEXTGAP;
			y += cmi->Height;
		} else {

			/* Rule items point to their Image structure
			 * and are just a little narrower than the
			 * menu itself.
			 */
			*img = generic_hrule;
			img->Width = max - RULEMARGIN;
			*cmi = generic_hitem;
			cmi->TopEdge = y + RULEGAP/2;
			y += RULEHEIGHT + RULEGAP;
			cmi->ItemFill = (APTR) img;
			img ++;
		}
		cmi->NextItem = cmi + 1;
	}
	mi[n - 1].NextItem = NULL;

	/* Attach submenu's, if any.
	 */
	if (!(sub = nmen->submenu)) return mi;

	/* Use "max" as a flag for the success of the attachments.
	 */
	max = 1;
	for (i = 0; i < n; i++) {
		if (*nmen->str[i] == '-') continue;
		if (sub->str)
			max &= AttachSubMenu (&mi[i], sub);
		sub ++;
	}
	if (!max) {
		FreeMItem (mi);
		return NULL;
	}
	return mi;
}


/*
 * Free a Menu structure created by GenStrip() that has items 
 * created with GenItems().
 */
void FreeMenu (mm)
	struct Menu    *mm;
{
	register short  i;
	register struct Menu *t;

	i = 0;
	for (t = mm; t; t = t->NextMenu) {
		if (t->FirstItem) FreeMItem (t->FirstItem);
		i++;
	}
	FREI_N (mm, i);
}


/*
 * Free a MenuItem structure created by GenItems().
 */
void FreeMItem (mi)
	register struct MenuItem *mi;
{
	register short  nit, nimg;
	register struct MenuItem *c;
	register struct IntuiText *it = NULL, *it1;
	struct Image   *img = NULL;

	/* Scan the MenuItem structures and count the number of images
	 * and IntuiText structures.  Find the pointer to the first of
	 * each structure in the set.  That will be the first element
	 * in the array that was allocated as a unit.
	 */
	nit = nimg = 0;
	for (c = mi; c; c = c->NextItem) {
		if (c->SubItem) FreeMItem (c->SubItem);
		if (c->Flags & ITEMTEXT) {
			it1 = (struct IntuiText *) c->ItemFill;
			if (!it) it = it1;
			nit++;

			/* Free the subitem marker, if any.
			 */
			if (it1->NextText) FREI (it1->NextText);
		} else {
			if (!img) img = (struct Image *) c->ItemFill;
			nimg++;
		}
	}

	/* Free the arrays of structures of images and texts, as
	 * well as the main array of MenuItem structures themselves.
	 */
	if (nit) FREI_N (it, nit);
	if (nimg) FREI_N (img, nimg);
	FREI_N (mi, nit + nimg);
}
SHAR_EOF
cat << \SHAR_EOF > qmenu.h
struct NewMenu {
	char **str;
	struct NewMenu *submenu;
};


struct Menu *GenMenu();
struct Menu *GenStrip();
struct MenuItem *GenItems();
LONG AttachSubItem();
void FreeMenu();
void FreeMItem();
SHAR_EOF
cat << \SHAR_EOF > mtst.c
/*
 * Example program for using quick menu package.  Contains the necessary
 * declarations for a simple menu strip which it creates and destroys after
 * letting the user play with it.
 */
#include <intuition/intuition.h>
#include "qmenu.h"


#define NILSUB	{NULL,NULL}

/*
 * String arrays get defined in sort-of reverse order.
 * I.e. the subitems get defined before the parent items.
 * (One rule is that menu items that cause a Requester to
 * appear are followed by "...".)
 * The string arrays themselves are terminated by a null 
 * string pointer.
 */
char *mpo_str[] = {
	"!=ORaw Text...",
	"Processed Text...",
	"Drawing...",
	"Picture...",
	"Old Settings...",
	NULL };

char *mps_str[] = {
	"!=TText...",
	"!=DDrawing...",
	"Picture...",
	NULL };

char *mp_str[] = {
	"!=NNew...",
	"Open",
	"!=SSave...",
	"Save as",
	"Print...",
	"Save Settings",
	"About...",
	"-",
	"!bQuit...",
	NULL };

/* Array of NewMenu structs to go with the above text items.
 * Needs to be a one-to-one correspondence between text items
 * (not rules) and NewMenu structs.
 */
struct NewMenu mp_sub[] = {
	NILSUB,
	{ mpo_str, NULL },
	NILSUB,
	{ mps_str, NULL },
	NILSUB,
	NILSUB,
	NILSUB,
	NILSUB
};

char *mes_str[] = {
	"!+!0111!=PPlain",
	"!c!1!=BBold",
	"!c!1!=IItalic",
	"!c!1!=UUnderline",
	NULL };

char *me_str[] = {
	"!=QUndo",
	"-",
	"!=ZDelete",
	"!=XCut",
	"!=CCopy",
	"!=VPaste",
	"-",
	"Set Font...",
	"Set Style",
	NULL };

struct NewMenu me_sub[] = {
	NILSUB,
	NILSUB,
	NILSUB,
	NILSUB,
	NILSUB,
	NILSUB,
	{ mes_str, NULL }
};

char *mdz_str[] = {
	"!=>In",
	"!=<Out",
	"!=MManual",
	NULL };

char *mdv_str[] = {
	"!+!tText",
	"!+!tLines",
	"!+!tImages",
	"!+!tBoxes",
	"!+!tLabels",
	NULL };

char *mds_str[] = {
	"Interlace",
	"Non-interlace",
	"Workbench",
	NULL };

char *md_str[] = { 
	"Zoom",
	"!=AAuto Scale",
	"-",
	"!c!tCoordinates",
	"Visible",
	"-",
	"Screen Colors...",
	"Screen Type",
	NULL };

struct NewMenu md_sub[] = {
	{ mdz_str, NULL },
	NILSUB,
	NILSUB,
	{ mdv_str, NULL },
	NILSUB,
	{ mds_str, NULL }
};

char *mhc_str[] = {
	"Plot...",
	"Set...",
	"Lay in...",
	NULL };

char *mhw_str[] = {
	"!+!0111111Full Impulse",
	"!c!1011111!=1Warp 1",
	"!c!1101111!=2Warp 2",
	"!c!1110111!=3Warp 3",
	"!c!1111011!=4Warp 4",
	"!c!1111101!=5Warp 5",
	"!c!1111110Space Normal",
	NULL };

char *mhp_str[] = {
	"Stun",
	"Kill",
	"Maim",
	"Burn",
	"Overload",
	"Ineffective",
	"Burn Out",
	NULL };

char *mh_str[] = {
	"New Course",
	"Speed",
	"Standard Orbit",
	"Tractor Beam...",
	"Lock Phasers",
	"-",
	"\"Make It So.\"",
	NULL };

struct NewMenu mh_sub[] = {
	{ mhc_str, NULL },
	{ mhw_str, NULL },
	NILSUB,
	NILSUB,
	{ mhp_str, NULL },
	NILSUB
};

char *mt_str[] = {
	"Hammer",
	"Screwdriver",
	"Chisel",
	"Knife",
	"Felt Pen",
	"Air Freshener",
	"-",
	"Hammer Size...",
	"Screw Type...",
	"Pine Scent...",
	NULL };

char *mm_str[] = {
	"Rotate...",
	"Spin...",
	"Turn Around...",
	"Flip Out...",
	"Randomize...",
	"Energize...",
	"Simplify",
	"Complexify",
	NULL };

char *main_str[] = {
	"Project",
	"Edit",
	"Display",
	"Tools",
	"Helm",
	"Modify",
	NULL };

struct NewMenu main_sub[] = {
	{ mp_str, mp_sub },
	{ me_str, me_sub },
	{ md_str, md_sub },
	{ mt_str, NULL },
	{ mh_str, mh_sub },
	{ mm_str, NULL }
};

struct NewMenu main_menu = { main_str, main_sub };

struct TextAttr ta = { (UBYTE*) "topaz.font", 8,0,0 };


/* Basic stuff for the test program.
 */
struct NewWindow nwin = {
	50,20, 200,100, -1,-1, CLOSEWINDOW,
	WINDOWCLOSE|WINDOWDRAG|ACTIVATE,
	NULL,NULL, (UBYTE*) "Test the Menus", NULL,NULL,
	0,0,0,0, WBENCHSCREEN
};

#define OLIB(var,nam)	(var=OpenLibrary(nam,33L))

struct IntuitionBase *IntuitionBase;
struct Window *mywin;


struct Window *OpenWindow();
void *OpenLibrary();
void *GetMsg();


main ()
{
	if (OLIB(IntuitionBase,"intuition.library")) {
		if (mywin = OpenWindow (&nwin)) {
			Body ();
			CloseWindow (mywin);
		}
		CloseLibrary (IntuitionBase);
	}
}


Body ()
{
	struct IntuiMessage *im;
	struct Menu *m;

	if (!(m = GenMenu (&main_menu))) return;

	SetMenuStrip (mywin, m);

	/* Wait for the close window message.
	 */
	while (!(im = (struct IntuiMessage *) GetMsg (mywin->UserPort)))
		WaitPort (mywin->UserPort);
	ReplyMsg (im);

	ReadMenuState (m);
	ClearMenuStrip (mywin);
	FreeMenu (m);
}


ReadMenuState (m)
	struct Menu *m;
{
	struct MenuItem	*mi;

	/* Get the text style menu array and test for checkmarks.
	 */
	mi = m[1].FirstItem[8].SubItem;
	printf ("Text Style: ");
	if (mi[0].Flags & CHECKED) printf ("Plain");
	if (mi[1].Flags & CHECKED) printf ("Bold ");
	if (mi[2].Flags & CHECKED) printf ("Italic ");
	if (mi[3].Flags & CHECKED) printf ("Underline");
	printf ("\n");
}
SHAR_EOF
cat << \SHAR_EOF > mtst.uu

begin 644 mtst
M```#\P`````````#``````````(```=@```!E@````$```/I```'8$[Z#*0AF
M/4]287<@5&5X="XN+@!0<F]C97-S960@5&5X="XN+@!$<F%W:6YG+BXN`%!I+
M8W1U<F4N+BX`3VQD(%-E='1I;F=S+BXN```A/51497AT+BXN`"$]1$1R87=I!
M;F<N+BX`4&EC='5R92XN+@`A/4Y.97<N+BX`3W!E;@`A/5-3879E+BXN`%-AU
M=F4@87,`4')I;G0N+BX`4V%V92!3971T:6YG<P!!8F]U="XN+@`M`"%B475I*
M="XN+@`A*R$P,3$Q(3U04&QA:6X`(6,A,2$]0D)O;&0`(6,A,2$]24ET86QIW
M8P`A8R$Q(3U556YD97)L:6YE```A/5%5;F1O`"T`(3U:1&5L971E`"$]6$-U]
M=``A/4-#;W!Y`"$]5E!A<W1E`"T`4V5T($9O;G0N+BX`4V5T(%-T>6QE`"$]V
M/DEN`"$]/$]U=``A/4U-86YU86P``"$K(71497AT`"$K(71,:6YE<P`A*R%T3
M26UA9V5S`"$K(71";WAE<P`A*R%T3&%B96QS``!);G1E<FQA8V4`3F]N+6ENR
M=&5R;&%C90!7;W)K8F5N8V@`6F]O;0`A/4%!=71O(%-C86QE`"T`(6,A=$-O@
M;W)D:6YA=&5S`%9I<VEB;&4`+0!38W)E96X@0V]L;W)S+BXN`%-C<F5E;B!44
M>7!E`%!L;W0N+BX`4V5T+BXN`$QA>2!I;BXN+@``(2LA,#$Q,3$Q,49U;&P@*
M26UP=6QS90`A8R$Q,#$Q,3$Q(3TQ5V%R<"`Q`"%C(3$Q,#$Q,3$A/3)787)PY
M(#(`(6,A,3$Q,#$Q,2$],U=A<G`@,P`A8R$Q,3$Q,#$Q(3TT5V%R<"`T`"%C*
M(3$Q,3$Q,#$A/35787)P(#4`(6,A,3$Q,3$Q,%-P86-E($YO<FUA;`!3='5N3
M`$MI;&P`36%I;0!"=7)N`$]V97)L;V%D`$EN969F96-T:79E`$)U<FX@3W5TZ
M`$YE=R!#;W5R<V4`4W!E960`4W1A;F1A<F0@3W)B:70`5')A8W1O<B!"96%MQ
M+BXN`$QO8VL@4&AA<V5R<P`M`")-86ME($ET(%-O+B(``$AA;6UE<@!38W)E,
M=V1R:79E<@!#:&ES96P`2VYI9F4`1F5L="!096X`06ER($9R97-H96YE<@`MA
M`$AA;6UE<B!3:7IE+BXN`%-C<F5W(%1Y<&4N+BX`4&EN92!38V5N="XN+@!2T
M;W1A=&4N+BX`4W!I;BXN+@!4=7)N($%R;W5N9"XN+@!&;&EP($]U="XN+@!2&
M86YD;VUI>F4N+BX`16YE<F=I>F4N+BX`4VEM<&QI9GD`0V]M<&QE>&EF>0!0A
M<F]J96-T`$5D:70`1&ES<&QA>0!4;V]L<P!(96QM`$UO9&EF>0``=&]P87HN^
M9F]N=```5&5S="!T:&4@365N=7,``$Y5``!(>``A2'H`.$ZZ&*103RE`A@9G=
M)DAL@MY.NAD@6$\I0(8*9PQA*B\LA@I.NACV6$\O+(8&3KH8'EA/3EU.=6EN2
M='5I=&EO;BYL:6)R87)Y`$Y5__A(;(+.3KH!&EA/*T#_^&8$3EU.=2\M__@O3
M+(8*3KH8U%!/(&R&"B\H`%9.NA@>6$\K0/_\9A`@;(8*+R@`5DZZ&$Q83V#<Q
M+RW__$ZZ&")83R\M__AA&%A/+RR&"DZZ&&183R\M__A.N@:P6$]@HDY5__P@!
M;0`((F@`,"MI`2S__$AZ`&Y.N@P<6$\@;?_\""@````,9PI(>@!E3KH,!EA//
M(&W__`@H````+F<*2'H`54ZZ"_!83R!M__P(*````%!G"DAZ`$5.N@O:6$\@,
M;?_\""@```!R9PI(>@`W3KH+Q%A/2'H`-TZZ"[I83TY=3G5497AT(%-T>6QEC
M.B``4&QA:6X`0F]L9"``271A;&EC(`!5;F1E<FQI;F4`"@``NP!.50``2.</Q
M,"1M``A\`&`"4D8P!DC`Y8`@4DJP"`!F\"\286983R9`(`MF"G``3-\,\$Y=>
M3G5Z`21J``1X`&`R2I)G*D*G0J<O"DZZ`L9/[P`,+@`P!,'\`!X@0-'+(4<`-
M$DJ'9P1P`6`"<`#*0%"*4D2X1FW*2D5F#"\+3KH%>EA/<`!@J"`+8*1.50``S
M2.<.,'P`8`)21C`&2,#E@"!M``A*L`@`9NY"IS`&P/P`'G(`,@`O`4ZZ%CA0D
M3R1`(`IF"G``3-\,<$Y=3G5Z`'@`8&(P!,'\`!XF0-?*($M#[(,V<`8@V5'(W
M__PPV3=%``0P!$C`Y8`@;0`(+S`(`$ZZ!?983\'\``I80#=```@P*P`(T'P`8
M"MI`,`1(P.6`(&T`""=P"```#B!+T?P````>)HA21+A&;9HP!E-`P?P`'D*R^
M"``@"F``_WQ.50``2.<`,"1M``A"ITAX`!1.NA624$\F0$J`9@IP`$S?#`!.(
M74YU($M#[(,B(-D@V2#9(-D@V2\+3KH6-%A/,BH`"))`54$W00`$0J<P*@`("
MD'P`$DC`+P`O+0`,3KH!:$_O``PE0``<9A!(>``4+PM.NA584$]P`&"D(&H`/
M$B%+`!!P`6"83E4``$CG#``@;0`(#!``(68``2)2K0`((&T`"!`02(!(P&``<
M`,H@;0`,".@````-8```^B!M``P`:``)``Q@``#L(&T`#`)H_S\`#"!M``P(*
MZ``'``U@``#4(&T`#`)H_S\`#"!M``P`:`#```Q@``"\(&T`#`)H_^\`#&``#
M`*X@;0`,`&@!`0`,8```H"!M``P(Z``"``U2K0`((&T`"")M``P34``:8```I
M@G@`>@`@;0`(#!``,&<*(&T`"`P0`#%F'"!M``A2K0`($!!(@)!\`#`R!5)%X
MXV!(P-B`8-`@;0`,(40`#E.M``A@/I"\````*V>*6X!GLE.`9ZZ0O`````QG(
MB)"\````)6<`_S13@&<`_Q)3@&<`_UB0O`````IG`/\V78!G`/\*4JT`"&``5
M_M8@+0`(3-\`,$Y=3G5.5?_V2.</,$)M__I@!%)M__HP+?_Z2,#E@"!M``@BV
M4$JQ"`!FZ$*G,"W_^L#\`")R`#(`+P%.NA.F4$\D0$J`9@IP`$S?#/!.74YU5
M?@!Z`&`@,`5(P.6`(&T`"")0('$(``P0`"UF!'`!8`)P`-Y`4D6Z;?_Z;=HP\
M+?_ZD$=G-D*G,"W_^I!'P/P`%'(`,@`O`4ZZ$TI03R@`9AHP+?_ZP/P`(G(`F
M,@`O`2\*3KH35E!/<`!@CDI'9U9"IS`'P/P`%'(`,@`O`4ZZ$Q103RM`__QFU
M/#`M__K`_``B<@`R`"\!+PI.NA,>4$\P+?_ZD$=G&#`M__J01\#\`!1R`#(`B
M+P$O!$ZZ$OY03W``8`#_-GX`>@!@``"@,`5(P.6`(&T`"")0('$(``P0`"UG)
M``"&,`7!_``B)D#7RB!+0^R#5'`'(-E1R/_\,-DG1``2($1#[(,.(-D@V2#9K
M(-D@V2\+,`5(P.6`(&T`"")0+S$(`$ZZ_4Y03R!$(4``#"\$3KH3*%A//`!8Q
M1@@K``(`#6<$W'P`)0@K````#6<,($0&:``3``3<?``3O$=O`CX&V+P````47
M4D6Z;?_Z;0#_7'H`8```H#`%P?P`(B9`U\HP!4C`Y8`@;0`((E`@<0@`#!``R
M+6<F-VT`#@`$-VT`$@`&-T<`"#`L@MI40#=```HP*P`*2,#1K0`08$P@;?_\N
M0^R#=B#9(-D@V2#9(-D@;?_\,`>0?``*,4``!"!+0^R#BG`'(-E1R/_\,-D@C
M+0`05(`W0``&7*T`$"=M__P`$@:M````%/_\($O1_````"(FB%)%NFW_^FT`V
M_UPP+?_Z4T#!_``B0K((`"!M``@K:``$__9F!B`*8`#]O'X!>@!@.C`%2,#ED
M@"!M``@B4"!Q"``,$``M9R(@;?_V2I!G%B\M__8P!<'\`"+0BB\`3KK[>E!/5
MSD!0K?_V4D6Z;?_Z;<!*1V8,+PIA4EA/<`!@`/UF(`I@`/U@3E4``$CG""!X&
M`"1M``A@$DJJ`!)G""\J`!)A*%A/4D0D4B`*9NHP!,#\`!YR`#(`+P$O+0`(G
M3KH0YE!/3-\$$$Y=3G5.5?_\2.</,"1M``A\`$*M__QZ`#@%)DI@3$JK`!QG@
M""\K`!QAVEA/""L``0`-9R8N*P`22H9F`BP'4D0@1TJH`!!G$$AX`!0@1R\H,
M`!!.NA"*4$]@#DJM__QF!BMK`!+__%)%)E,@"V:P2D1G%#`$P/P`%'(`,@`OQ
M`2\&3KH07%!/2D5G%C`%P/P`%'(`,@`O`2\M__Q.NA!"4$\P!-!%P/P`(G(`7
M,@`O`2\*3KH0+%!/3-\,\$Y=3G4@;P`$(`A*&&;\D<`@"%.`3G5A<$/LA@)%N
M[(8"M<EF#C(\`!5K"'0`(L)1R?_\*4^&#BQX``0I3H822.>`@`@N``0!*6<06
M2_H`"$ZN_^)@!D*G\U].<T/Z`"!.KOYH*4"&%F8,+CP``X`'3J[_E&`$3KH`Q
M&E!/3G5D;W,N;&EB<F%R>0!)^0``?_Y.=4Y5```O"DAY``$``#`LA?C!_``&A
M+P!.N@]:*4"&&E!/9A1"ITAY``$``$ZZ#QI03RYLA@Y.=2!LAAI":``$(&R&:
M&C%\``$`$"!LAAHQ?``!``H@;(8.("R&#I"H``10@"E`AAX@;(8>(+Q-04Y85
M0J=.N@\.)$!*J@"L6$]G+B\M``PO+0`(+PI.N@"N.7P``88B(&R&&@!H@```[
M!"!LAAH`:(````I/[P`,8$)(:@!<3KH//$AJ`%Q.N@[R*4"&)"!LAB1*J``DD
M4$]G$"!LAB0B:``D+Q%.N@X&6$\O+(8D+PI.N@)H*6R&)(8H4$].N@X&(&R&G
M&B"`3KH.)B!LAAHA0``&9Q9(>`/M2'H`*DZZ#@(@;(8:(4``#%!/+RR&*#\LF
MABQ.NO7@0F=.N@P@4$\D7TY=3G4J`$Y5``!(YPPP)&T`$"!M``A*J`"L9Q@@G
M;0`(("@`K.6`*``@1"`H`!#E@"9`8`0F;(7Z$!-(@$C`T*T`#%2`.4"&+D*G8
M,"R&+DC`+P!.N@WL*4"&,%!/9@A,WPPP3EU.=1`32(`Z`#\%($M2B"\(+RR&/
M,$ZZ`7XP!4C`($#1[(8P0_H!1!#99OP_+0`.+PHO+(8P3KH!.B!LAC!",%``?
M.7P``88L,`5(P-"LAC`F0%*+)$M/[P`4$!-(@#H`L'P`(&<8NGP`"6<2NGP`Y
M#&<,NGP`#6<&NGP`"F8$4HM@V`P3`"!M>@P3`")F+E*+($M2BQ`02(`Z`&<>U
M($I2BA"%NGP`(F80#!,`(F8$4HM@!D(J__]@`F#68#@@2U*+$!!(@#H`9R:ZB
M?``@9R"Z?``)9QJZ?``,9Q2Z?``-9PZZ?``*9P@@2E**$(5@SB!*4HI"$$I%W
M9@)3BU)LABQ@`/]:0A)"IS`LABQ20$C`Y8`O`$ZZ#,HI0(8H4$]F"$)LABQ@J
M`/[8>@`F;(8P8"0P!4C`Y8`@;(8H(8L(`"!+(`A*&&;\D<!3B#`(4D!(P-?`8
M4D6Z;(8L;=8P!4C`Y8`@;(8H0K`(`&``_I0@`#`\?_]@!#`O``P@;P`$2AAFN
M_%-((F\`"%-`$-E7R/_\9P)"$"`O``1.=4SO`P``!"`(,B\`#&`"$-E7R?_\4
M9P9206`"0AA1R?_\3G5.50``2.<.,"1M``A"ITAZ`(Y.N@Q<*4"&-%!/9@A,B
MWPQP3EU.=2!M``PB:``D+RD`!$ZZ#)0H`%A/9U)(>@!M($0O*``V3KH,9B9`<
M2H!03V<T2'@#[2\+3KH+;"P`4$]G)"`&Y8`J`"!%)6@`"`"D)48`G$AX`^U(5
M>@`X3KH+2"5``*!03R\$3KH,,EA/+RR&-$ZZ"WY"K(8T6$]@@&EC;VXN;&EBT
M<F%R>0!724Y$3U<`*@!.50``2&T`#"\M``A(>@1@3KH`F$_O``Q.74YU3E4`I
M`$CG""`D;0`.#&T`!``29@@@;0`(*!!@'$IM``QO#"!M``AP`#`0*`!@"B!M>
M``@P$$C`*`!";0`22FT`#&P01&T`#$J$;`A$A#M\``$`$C(M``Q(P2`$3KH#L
MD$'L@ZQ3BA2P```R+0`,2,$@!$ZZ`X8H`&;:2FT`$F<&4XH4O``M(`I,WP007
M3EU.=4Y5_R)(YP@P)&T`""9M``Q";?_Z*VT`$/_\($M2BQ`02(`X`&<``NZX3
M?``E9@`"S$(M_S`[?``!__@[?``@__8[?"<0__0@2U*+$!!(@#@`L'P`+68.$
M0FW_^"!+4HL0$$B`.`"X?``P9A`[?``P__8@2U*+$!!(@#@`N'P`*F88(&W_4
M_%2M__P[4/_R($M2BQ`02(`X`&`R0FW_\F`<,"W_\L'\``K01)!\`#`[0/_R;
M($M2BQ`02(`X`#`$4D!![(.^"#```@``9M2X?``N9EH@2U*+$!!(@#@`L'P`&
M*F88(&W__%2M__P[4/_T($M2BQ`02(`X`&`R0FW_]&`<,"W_],'\``K01)!\Y
M`#`[0/_T($M2BQ`02(`X`#`$4D!![(.^"#```@``9M0[?``"__"X?`!L9A(@.
M2U*+$!!(@#@`.WP`!/_P8!"X?`!H9@H@2U*+$!!(@#@`,`1(P&!Z.WP`"/_N8
M8!8[?``*_^Y@#CM\`!#_[F`&.WS_]O_N/RW_\$AM_S`_+?_N+RW__$ZZ_>0K(
M0/_J,"W_\$C`T:W__$_O``Q@7"!M__Q8K?_\(E`K2?_J(`E*&6;\D\!3B3M)T
M__!@2B!M__Q4K?_\.!!![?\O*TC_ZA"$8"B0O````&-GXE.`9Y*0O`````MG[
M`/]R68!GLE6`9P#_<%>`9P#_<F#,0>W_,)'M_^H[2/_P,"W_\+!M__1O!CMM8
M__3_\$IM__AG:"!M_^H,$``M9PH@;?_J#!``*V8N#&T`,/_V9B93;?_R(&W_'
MZE*M_^H0$$B`/P!.DK!\__]43V8*</],WPP03EU.=6`6/RW_]DZ2L'S__U1/^
M9@1P_V#D4FW_^C`M__)3;?_RL&W_\&[<0FW_[F`@(&W_ZE*M_^H0$$B`/P!.9
MDK!\__]43V8$</]@L%)M_^X@;?_J2A!G"C`M_^ZP;?_T;<XP+?_NT6W_^DIM"
M__AF*&`8/SP`($Z2L'S__U1/9@9P_V``_WA2;?_Z,"W_\E-M__*P;?_P;MI@B
M%C\$3I*P?/__5$]F!G#_8`#_4E)M__I@`/T(,"W_^F``_T)(YT@`0H1*@&H$;
M1(!21$J!:@9$@0I$``%A/DI$9P)$@$S?`!)*@$YU2.=(`$*$2H!J!$2`4D1*F
M@6H"1(%A&B`!8-@O`6$2(`$B'TJ`3G4O`6$&(A]*@$YU2.<P`$A!2D%F($A!_
M-@$T`$)`2$"`PR(`2$`R`H+#,`%"04A!3-\`#$YU2$$F`2(`0D%(04A`0D!TN
M#]"`TX&V@6($DH-20%'*__),WP`,3G5.50``2&R$5C\M``A.N@`(7$].74YU+
M3E4``"\$."T`""\M``H_!$ZZ`#"X?``*7$]F)"!M``H0*``,2(`(```'9Q0_#
M//__+RT`"DZZ`/1<3R@?3EU.=6#X3E4``"\*)&T`"B!2L>H`!&48,"T`",!\Z
M`/\_`"\*3KH`R%Q/)%].74YU(%)2DA`M``D0@$B`P'P`_V#H3E4``"\*0>R$G
M0"1(($K5_````!8O"&$06$]![(7XM<AEZB1?3EU.=4Y5``!(YP@@)&T`"'@`^
M(`IF"G#_3-\$$$Y=3G5**@`,9U`(*@`"``QG##\\__\O"F%2.`!<3Q`J``U(W
M@#\`3KH%'(A`""H``0`,5$]G"B\J``A.N@(N6$\(*@`%``QG$B\J`!).N@+`T
M+RH`$DZZ`A103T*20JH`!$*J``A"*@`,,`1@D$Y5__Y(YP@@)&T`"$'Z_T8IU
M2(8X""H`!``,9PIP_TS?!!!.74YU""H``@`,9S`@4I'J``@X"#\$+RH`"!`J_
M``U(@#\`3KH"@+!$4$]G$`CJ``0`#$*20JH`!'#_8,`,;?__``QF$`BJ``(`J
M#$*20JH`!'``8*A*J@`(9@@O"DZZ`)I83PQJ``$`$&8J&VT`#?__/SP``4AM/
M__\0*@`-2(`_`$ZZ`B*P?``!4$]FH#`M``Q@`/]J)*H`"#`J`!!(P-"J``@EK
M0``$".H``@`,(%)2DA`M``T0@$B`P'P`_V``_SY.50``+PI![(1`)$A**@`,-
M9QC5_````!9![(7XM<AE"'``)%].74YU8.)"DD*J``1"J@`((`I@ZDY5__PO6
M"B1M``@_/`0`3KH`P"M`__Q43V88-7P``0`0($K1_`````XE2``()%].74YU>
M-7P$```0".H``0`,)6W__``($"H`#4B`/P!.N@#B2D!43V<&`"H`@``,8,Y.=
M50``2.<`,"1LA@)@%"92("H`!%"`+P`O"DZZ!%903R1+(`IFZ$*LA@),WPP`3
M3EU.=4Y5```O"D'Z_\8I2(8\0J<@+0`(4(`O`$ZZ!``D0$J`4$]F"'``)%]."
M74YU)*R&`B5M``@`!"E*A@(@"E"`8.9.50``<``P+0`(+P!ALEA/3EU.=4Y5#
M``!(YP`PE\LD;(8"8`X@;0`(48BQRF<2)DHD4B`*9NYP_TS?#`!.74YU(`MGS
M!":28`0I4H8"("H`!%"`+P`O"DZZ`ZAP`%!/8-A.50``+PHP+0`(P?P`!B1`+
MU>R&&DIM``AM#C`M``BP;(7X;`1*DF8..7P``H9`</\D7TY=3G4P+0`(P?P`8
M!B!LAAHO,`@`3KH"QDJ`6$]G!'`!8`)P`&#83E4``"\M``A.N@*02H!83V8.&
M3KH"FCE`AD!P_TY=3G5P`&#X3E4``$CG#"`X+0`(3KH`<#`$P?P`!B1`U>R&-
M&DI$;0JX;(7X;`1*DF80.7P``H9`</],WP0P3EU.=3`J``3`?``#9@HY?``%"
MAD!P_V#D<``P+0`.+P`O+0`*+Q).N@)F*@"PO/____]/[P`,9@Q.N@(:.4"&+
M0'#_8+@@!6"T3E7__$AX$`!"ITZZ`MXK0/_\"```#%!/9Q)*;(8B9@@@+?_\E
M3EU.=4ZZ``9P`&#T3E4``$AX``1(>@`<3KH!\"\`3KH"`C\\``%.N@`.3^\`)
M#DY=3G5>0PH`3E4``$JLACAG!B!LACA.D#\M``A.N@`(5$].74YU3E7__"\$Y
M,"T`"$C`*T#__$JLAAIG*'@`8`H_!$ZZ`/Y43U)$N&R%^&WP,"R%^,'\``8OE
M`"\LAAI.N@'T4$]*K(8\9P8@;(8\3I!*K(7^9PHO+(7^3KH!:%A/2JR&0F<(U
M(&R&0B"LAD9*K(9*9PHO+(9*3KH!A%A/2JR&3F<*+RR&3DZZ`7183TJLAE)G%
M"B\LAE).N@%D6$]*K(969PHO+(963KH!5%A/+'@`!`@N``0!*6<4+PU+^@`*A
M3J[_XBI?8`9"I_-?3G-*K(8D9C!*K(8P9R@P+(8N2,`O`"\LAC!.N@%,,"R&(
M+%)`2,#E@"\`+RR&*$ZZ`3A/[P`08`Y.N@$B+RR&)$ZZ`5Y83R`M__PN;(8.4
M3G4H'TY=3G5.50``2.<.(#@M``@P!,'\``8D0-7LAAI*1&T*N&R%^&P$2I)FY
M$#E\``*&0'#_3-\$<$Y=3G4(*@`'``1F""\23KH`"EA/0I)P`&#B(B\`!"QLA
MAA9.[O_<(B\`!"QLAA9.[O^"(B\`!"QLAA9.[O^X+&R&%D[N_\HL;(863N[_=
M?"(O``0L;(863N[_*$SO``8`!"QLAA9.[O_B+&R&%D[N_\1.^@`"(B\`!"QLH
MAA9.[O^F3.\`#@`$+&R&%D[N_]!(YP$$3.\@@``,+&R&$DZN_Y1,WR"`3G5._
M^@`"(F\`!"QLAA).[OYB3OH``DSO``,`!"QLAA).[O\Z(F\`!"QLAA).[O[:G
M+&R&$D[N_WQ.^@`"(F\`!"`O``@L;(823N[_+D[Z``(@;P`$+&R&$D[N_HQ.7
M^@`"+&R&$B)O``0@+P`(3N[]V$[Z``(B;P`$+&R&$D[N_H9,[P`#``0L;(82J
M3N[^SD[Z``(@;P`$+&R&$D[N_H!,[P,```0L;(8T3N[_H"!O``0L;(8T3N[_>
MIB!O``0L;(8T3N[_LB!O``0L;(8&3N[_RB!O``0L;(8&3N[_N"!O``0L;(8&5
M3N[^MB!O``0L;(8&3N[_-$SO`P``!"QLA@9.[O[X``````/L`````0````$`?
M``T:`````````_(```/J```!@`````0````3````)0```#`````[````````Q
M`$P```!7````90````````!P````>@```'\```"*````D@```)L```"I````1
ML@```+0`````````````````````````````````````````&```````````^
M`````````````````````````````````````````+X```#.````V@```.@`.
M````````^@```0(```$$```!#@```14```$=```!)@```2@```$T````````*
M`````````````````````````````````````````````````````````````
M`````)`````````!/@```40```%+`````````58```%?```!:0```70```%^U
M`````````8H```&4```!H@````````&L```!L0```;\```'!```!T0```=D`0
M``';```![`````````$$``````````````````````````````$4````````C
M```````````!+`````````'X```"`````@<````````"$@```BD```(]```"Q
M40```F4```)Y```"C0````````*D```"J0```JX```*S```"N````L$```+-$
M`````````M8```+A```"YP```O8```,&```#$P```Q4````````!D```````D
M``&@``````````````````````````````'````````````````````#)```)
M`RL```,W```#/@```T0```--```#6P```UT```-L```#>@````````.(```#X
MD@```YH```.I```#M0```\(```/.```#UP````````/B```#Z@```^\```/W!
M```#_0``!`(`````````*````%````"D````S````3P```%@```",```````^
M``'@```"`````EP````````"@````IP```0*``@````R`!0`R`!D__\```(`I
M```0"@`````````````$%@```````````````````````0(``````@`!```"\
MU````````````P````````$```+4```%G`````````````````````H``0``:
M````````````````````````````````````4@``````````````````````2
M```````````!``(``@````````````````````4`````````T```````````:
M````````````````,#$R,S0U-C<X.6%B8V1E9@```"`@("`@("`@(#`P,#`PR
M("`@("`@("`@("`@("`@("`@D$!`0$!`0$!`0$!`0$!`0`P,#`P,#`P,#`Q`(
M0$!`0$!`"0D)"0D)`0$!`0$!`0$!`0$!`0$!`0$!`0%`0$!`0$`*"@H*"@H"(
M`@("`@("`@("`@("`@("`@("`D!`0$`@``````````````````$``````0``(
M```````````````````!`0````$``````````````````````0(````!````'
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
M`````````````````````!0``````````````^P````7`````0```%@```!H;
M````_````6````%X```!B````@````((```"(````IP```*@```"I````J@`=
M``*L```"L````K0```*\```"P````L0```+,```"T````Q0```,H````9```B
M````````````!`````@````,````$````!@````<````(````"@````L````0
M,````#0````X````/````$````!$````2````)````"4````F````)P```"D@
M````J````*P```"P````M````+@```"\````P````,0```$$```!"````0P`+
M``$4```!&````1P```$@```!)````2P```$P```!-````3P```%````!1```G
M`4@```%,```!4````50```%8```!D````90```&8```!H````:0```&H```!$
MK````;````&T```!N````<````'$```!R````<P```'0```!U````=@```'@'
M```!Y````>@```'L```!\````?0```'X```",````C0```(X```"/````D``\
M``)$```"2````DP```)0```"5````EP```)@```"9````F@```)L```"<```V
M`G0```)X```"@````H0```*(```"C````I````*4```"U````O8```,L````U
1`````_(```/K`````0```_*(A
``
end
size 9692
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.