[comp.sys.amiga] YAIFFR

ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) (06/25/87)

[ REPLACE 'INEWS' ]

	This is an IFF reader I wrote as part of a project at work, and
thought it would be of public interest.  So here it is.

	By the way, I would appreciate any E-mailed comments on the quality
of my code.  I've suddenly taken an interest in improving my coding
practices and techniques, and would appreciate any and all comments,
including comments on readability, elegance, and efficiency.  You can start
as far back as you want (with "Oing" if you like).

					Thanks,
					Schwab

-------- Olver North: Overseas Shipping and Receiving --------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	Makefile
#	myiff.h
#	main.c
#	iff.c
# This archive created: Wed Jun 24 23:32:45 1987
# By:	Leo 'Bols Ewhac' Schwab (Hole Earth 'Lectronic Loss (or words to that effect))
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
	As part of a project for my new employer, I had to write an IFF ILBM
reader.  It wasn't fun.  Since an IFF reader has very little value as far as
proprietary secrets go, I asked my boss if I could toss the ILBM reader into
the public domain, and save some other poor soul the effort of writing one.
He agreed (address nice letters to UmeCorp).

	Some of you may, after looking at the code, notice a striking
resemblence to the PD IFF reader, 'plop'.  This is no accident; I used
'plop' as a template for my IFF reader.  'Plop' as it was was unsatisfactory
for my needs, since it wasn't general.  I'm reasonably certain mine is.
Mine handles HAM, HIRES, and overscan.

MANUFACTURE:
	Manx 3.4b (and probably other versions as well):

1> make

USEAGE:
	main filename [filename...]

	The program will load the ILBM file "filename", then ask you to
press RETURN.  When you do so, the picture will be displayed.  To exit the
program (or move on to the next file on the argument list), press RETURN
again.  I know, not a very wonderful user interface, but it was supposed to
be an internal hack.

	I hope someone finds this thing useful, from a code appreciation
standpoint.

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
Leo L. Schwab -- The Guy in The Cape	ihnp4!ptsfa -\
 \_ -_	 Bike shrunk by popular demand,	      dual ---> !{well,unicom}!ewhac
O----^o	 But it's still the only way to fly.  hplabs / (pronounced "AE-wack")
"Work FOR?  I don't work FOR anybody!  I'm just having fun."  -- The Doctor
SHAR_EOF
fi
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
# :ts=8
# Makefile for IFF reader.  I'm getting better at these....

OBJECTS =	main.o iff.o

main: $(OBJECTS)
	ln $(OBJECTS) -lc -o main

main.o iff.o: myiff.h
SHAR_EOF
fi
if test -f 'myiff.h'
then
	echo shar: "will not over-write existing file 'myiff.h'"
else
cat << \SHAR_EOF > 'myiff.h'
/*  :ts=8 bk=0
 *
 * myiff.h:	Definitions for my IFF reader.
 *
 * Leo L. Schwab			8705.11
 */

/*  Masking techniques  */
#define	mskNone			0
#define	mskHasMask		1
#define	mskHasTransparentColor	2
#define	mskLasso		3

/*  Compression techniques  */
#define	cmpNone			0
#define	cmpByteRun1		1

/*  Bitmap header (BMHD) structure  */
struct BitMapHeader {
	UWORD	w, h;		/*  Width, height in pixels */
	WORD	x, y;		/*  x, y position for this bitmap  */
	UBYTE	nplanes;	/*  # of planes  */
	UBYTE	Masking;
	UBYTE	Compression;
	UBYTE	pad1;
	UWORD	TransparentColor;
	UWORD	XAspect, YAspect;
	WORD	PageWidth, PageHeight;
};

/*  Color register structure (not really used)  */
struct ColorRegister {
	UBYTE red, green, blue;
};

/*  Makes my life easier.  */
union typekludge {
	char type_str[4];
	long type_long;
};

struct ChunkHeader {
	union typekludge chunktype;
	long chunksize;
};
#define	TYPE		chunktype.type_long
#define	STRTYPE		chunktype.type_str


/*  Useful macro from EA (the only useful thing they ever made)  */
#define MAKE_ID(a, b, c, d)\
	( ((long)(a)<<24) + ((long)(b)<<16) + ((long)(c)<<8) + (long)(d) )

/*  IFF types we may encounter  */
#define	FORM	MAKE_ID('F', 'O', 'R', 'M')
#define	ILBM	MAKE_ID('I', 'L', 'B', 'M')
#define	BMHD	MAKE_ID('B', 'M', 'H', 'D')
#define	CMAP	MAKE_ID('C', 'M', 'A', 'P')
#define	BODY	MAKE_ID('B', 'O', 'D', 'Y')

#define	GRAB	MAKE_ID('G', 'R', 'A', 'B')
#define	DEST	MAKE_ID('D', 'E', 'S', 'T')
#define	SPRT	MAKE_ID('S', 'P', 'R', 'T')
#define	CAMG	MAKE_ID('C', 'A', 'M', 'G')
#define	CRNG	MAKE_ID('C', 'R', 'N', 'G')
#define	CCRT	MAKE_ID('C', 'C', 'R', 'T')
#define	DPPV	MAKE_ID('D', 'P', 'P', 'V')


/*  Other useful things.  */
#define	CHUNKHEADERSIZE		sizeof (struct ChunkHeader)
#define	SUBTYPESIZE		sizeof (long)


/*  What functions return  */
extern void	*OpenLibrary(), *AllocMem(), *AllocRaster(), *GetColorMap();

struct ViewPort	*readform();
SHAR_EOF
fi
if test -f 'main.c'
then
	echo shar: "will not over-write existing file 'main.c'"
else
cat << \SHAR_EOF > 'main.c'
/*  :ts=8 bk=0
 *
 * main.c:	Driver for the cheesy IFF ILBM reader.
 *
 * Leo L. Schwab			8705.11
 */

#include <exec/types.h>
#include <graphics/gfxbase.h>
#include <graphics/view.h>
#include <stdio.h>
#include <fcntl.h>
#include "myiff.h"


extern FILE	*fopen();


struct ViewPort		*vp;
struct View		v, *oldview;
struct GfxBase		*GfxBase;
FILE			*fd;

main (ac, av)
char **av;
{
	struct ChunkHeader ch;

	openstuff ();		/*  It helps to plug it in...  */

	/*
	 * Scan all arguments and treat them as files.
	 */
	while (++av, --ac) {
		puts (*av);
		if (!(fd = fopen (*av, "r"))) {
			fail ("File open failed.");
			continue;
		}

		if (!getchunkheader (fd, &ch)) {
			fail ("Can't discover file type.");
			continue;
		}
		if (ch.TYPE != FORM) {
			fail ("Not an IFF file.");
			continue;
		}

		if (!(vp = readform (fd, ch.chunksize))) {
			fail ("readform() failed.");
			continue;
		}
		fclose (fd);  fd = NULL;

		puts ("Waiting for you to press RETURN...");
		getchar ();

		/*
		 * And now we make the views.
		 */
		oldview = GfxBase -> ActiView;

		InitView (&v);
		v.DxOffset = oldview -> DxOffset;  /* Track	 */
		v.DyOffset = oldview -> DyOffset;  /* Preferences */

		v.ViewPort = vp;

		if (vp -> Modes & LACE)
			v.Modes |= LACE;

		centerpict (vp);

		MakeVPort (&v, vp);
		MrgCop (&v);
		LoadView (&v);

		getchar ();	/*  Wait for next press of RETURN  */
		cleanup ();
	}

	closestuff ();
}

/*
 * A sleazy hack for overscan images.  If the guy is using 'morerows',
 * then this doesn't quite work.
 */
centerpict (vp)
register struct ViewPort *vp;
{
	if (vp -> Modes & HIRES)
		vp -> DxOffset += (640 - vp->DWidth) / 2;
	else
		vp -> DxOffset += (320 - vp->DWidth) / 2;

	if (vp -> Modes & LACE)
		vp -> DyOffset += (400 - vp->DHeight) / 2;
	else
		vp -> DyOffset += (200 - vp->DHeight) / 2;
}

openstuff ()
{
	if (!(GfxBase = OpenLibrary ("graphics.library", 0L)))
		die ("Dale is out for the moment.");
}

cleanup ()
{
	if (oldview) {
		LoadView (oldview);
		WaitTOF ();
		if (v.LOFCprList) {
			FreeCprList (v.LOFCprList);
			v.LOFCprList = NULL;
		}
		if (v.SHFCprList) {
			FreeCprList (v.SHFCprList);
			v.SHFCprList = NULL;
		}
		oldview = NULL;
	}

	if (vp) {
		closeviewport (vp);
		vp = NULL;
	}
	if (fd) {
		fclose (fd);
		fd = NULL;
	}
}

closestuff ()
{
	cleanup ();

	if (GfxBase)	CloseLibrary (GfxBase);
}

fail (str)
char *str;
{
	puts (str);
	cleanup ();
}

die (str)
char *str;
{
	puts (str);
	closestuff ();
	exit (20);
}
SHAR_EOF
fi
if test -f 'iff.c'
then
	echo shar: "will not over-write existing file 'iff.c'"
else
cat << \SHAR_EOF > 'iff.c'
/*  :ts=8 bk=0
 *
 * iff.c:	A cheesy IFF ILBM reader.
 *
 * Leo L. Schwab			8705.11
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/view.h>
#include <stdio.h>
#include "myiff.h"


static struct ViewPort	*viewport;		/*  Working viewport  */



/*
 * Okay, here's how this works.  This routine assumes that the file
 * descriptor points to just past the FORM type and size fields in the file.
 * It returns a pointer to a ViewPort structure with all necessary
 * substructures, suitable for MakeVPort()ing.  It assumes someone else will
 * know how to deallocate all said structures and resources.  Fortunately,
 * there's enough information in ViewPorts to be able to intelligently free
 * anything they may use.
 */
struct ViewPort *
readform (fd, formsize)
FILE *fd;			/*  File descriptor  */
long formsize;			/*  Size of this FORM  */
{
	struct BitMapHeader	bmhd;
	struct ChunkHeader	ch;
	long			subtype;
	register int		i, n;
	char			gotheader = 0, gotcmap = 0, gotcamg = 0;
	void			*tmp;

	if (!getsubtype (fd, &subtype))
		return (NULL);
	formsize -= sizeof (subtype);

	if (subtype != ILBM) {
		puts ("FORM not an ILBM, skipping...");
		skipchunk (fd, formsize - sizeof (subtype));
		return (NULL);
	}

	if (!(viewport = AllocMem ((long) sizeof (*viewport), MEMF_CLEAR)))
		ackphft ("ViewPort allocation failed.");
	InitVPort (viewport);

	while (formsize > 0) {

		if (!getchunkheader (fd, &ch))
			ackphft ("Malformed IFF FORM.");
		formsize -= sizeof (ch);

		switch (ch.TYPE) {
		case BMHD: {
			register struct BitMap *bm;
			register struct RasInfo *ri;

			fread (&bmhd, (int) ch.chunksize, 1, fd);

			if (!(bm = AllocMem ((long) sizeof (*bm),
					     MEMF_CLEAR)))
				ackphft ("BitMap allocation failed.");
			InitBitMap (bm,
				    (long) bmhd.nplanes,
				    (long) bmhd.w, (long) bmhd.h);

			if (!(ri = AllocMem ((long) sizeof (*ri),
					     MEMF_CLEAR)))
				ackphft ("RasInfo allocation failed.");
			ri -> BitMap = bm;
			ri -> RxOffset = ri -> RyOffset = NULL;
			ri -> Next = NULL;

			viewport -> DWidth = bmhd.w;
			viewport -> DHeight = bmhd.h;
			viewport -> RasInfo = ri;

			gotheader = 1;
			break;
		}

		case CMAP: {
			register UBYTE *ctable;
			register UWORD *cmap;

			if (!(ctable = AllocMem (ch.chunksize, NULL)))
				ackphft ("EA colortable alloc failed.");
			fread (ctable, (int) ch.chunksize, 1, fd);

			if (!(cmap = AllocMem (ch.chunksize * 2 / 3, NULL)))
				ackphft ("Colormap alloc failed.");

			for (i = n = 0; n < ch.chunksize; i++, n+=3)
				cmap[i] = ((ctable[n]   >> 4) << 8) +
					  ((ctable[n+1] >> 4) << 4) +
					  ( ctable[n+2] >> 4);

			if ((1 << bmhd.nplanes) != i)
puts ("Warning: Colormap not sized to nplanes, hope it's HAM.");
			viewport -> ColorMap = GetColorMap ((long) i);
			LoadRGB4 (viewport, cmap, (long) i);
			FreeMem (cmap, ch.chunksize * 2 / 3);
			FreeMem (ctable, ch.chunksize);

			gotcmap = 1;
			break;
		}

		case CAMG:
			/*  Use subtype as a temporary buffer  */
			fread (&subtype, (int) ch.chunksize, 1, fd);
			viewport -> Modes = (UWORD) (subtype & 0xffff);

			gotcamg = 1;
			break;

		case BODY:
			if (!gotheader || !gotcmap)
				ackphft ("BODY before BMHD or CMAP.");

			loadbitmap (fd, viewport, &bmhd);
			break;

		case CRNG:
		case GRAB:
		case DEST:
		case SPRT:
		case DPPV:	/*  Anyone know what this one is for?  */
			skipchunk (fd, ch.chunksize);
			break;

		default:
			printf ("Unrecognized chunk: 0x%lx\n", ch.TYPE);
			skipchunk (fd, ch.chunksize);
		}

		formsize -= ch.chunksize;
		if (ch.chunksize & 1) {		/*  Odd length chunk  */
			formsize --;
			fseek (fd, 1L, 1);
		}
	}

	/*  Post-processing in case of lack of CAMG chunk  */
	if (!gotcamg) {
		if (bmhd.w > 370)	/*  Arbitrary limit  */
			viewport -> Modes |= HIRES;
		if (bmhd.h > 256)
			viewport -> Modes |= LACE;
	}

	tmp = viewport;
	viewport = NULL;
	return (tmp);
}

loadbitmap (fd, vp, header)
FILE *fd;
struct ViewPort *vp;
struct BitMapHeader *header;
{
	register struct BitMap	*bm;
	register int		i, n;
	int			plane_offset = 0;

	bm = vp -> RasInfo -> BitMap;

	if (header->Compression != cmpNone &&
	    header->Compression != cmpByteRun1)
		ackphft ("Unrecognized compression technique.");

	for (i=0; i < bm->Depth; i++)
		if (!(bm -> Planes[i] = AllocRaster ((long) vp -> DWidth,
						     (long) vp -> DHeight)))
			ackphft ("Bitplane allocation failed.");

	for (i=0; i < bm->Rows; i++) {
		for (n=0; n < bm->Depth; n++) {
/*- - - - - - - - - - -*/
if (!header->Compression) {	/* No compression */
	if (!fread (bm -> Planes[n] + plane_offset,
		    bm -> BytesPerRow, 1, fd))
		ackphft ("Failure in BODY read.");

} else {
	int		so_far;
	register UBYTE	*dest = bm -> Planes[n] + plane_offset;
	char		len;

	/*
	 * Note:  All file I/O after this point is assumed to be sucessful.
	 * This is clearly a poor assumption, but it saves on typing.
	 * And besides, putting the checking in is simple :-) :-).
	 */
	so_far = bm -> BytesPerRow;
	while (so_far > 0) {
		if ((len = getc (fd)) >= 0) {	/*  Literal byte copy  */
			so_far -= ++len;
			fread (dest, len, 1, fd);
			dest += len;

		} else if ((UBYTE) len == 128)	/*  NOP  */
			;

		else if (len < 0) {		/*  Replication count  */
			UBYTE	byte;

			len = -len + 1;
			so_far -= len;
			byte = getc (fd);
			while (--len >= 0)
				*dest++ = byte;
		}
	}
	if (so_far)
		ackphft ("Compression quite screwed up.");
}
/*- - - - - - - - - - -*/
		}
		plane_offset += bm -> BytesPerRow;
	}
}


getchunkheader (fd, header)
FILE *fd;		/*  File descriptor (that's what 'fd' stands for)  */
struct ChunkHeader *header;
{
	return (fread (header, sizeof (*header), 1, fd));
}

getsubtype (fd, type)
FILE *fd;
long *type;
{
	/*  !! NOT PORTABLE !!  */
	return (fread (type, sizeof (*type), 1, fd));
}

skipchunk (fd, size)
FILE *fd;
long size;
{
	fseek (fd, size, 1);
}

/*
 * This function assumes the existence of the global variable viewport, which
 * is a pointer to a working ViewPort structure.  This is to allow graceful
 * cleanup of allocated resources in case of an exceptional failure.
 */
freepict ()
{
	register struct BitMap *bm;
	register int i;

	if (viewport) {
		if (viewport -> RasInfo) {

/*- - - - - - - - - - -*/
if (bm = viewport -> RasInfo -> BitMap) {
	for (i=0; i < bm->Depth; i++)
		if (bm -> Planes[i])
			FreeRaster (bm -> Planes[i],
				    (long) viewport -> DWidth,
				    (long) viewport -> DHeight);
	FreeMem (bm, (long) sizeof (*bm));
}
/*- - - - - - - - - - -*/

			FreeMem (viewport -> RasInfo,
				 (long) sizeof (struct RasInfo));
		}

		if (viewport -> ColorMap)
			FreeColorMap (viewport -> ColorMap);

		FreeVPortCopLists (viewport);
		FreeMem (viewport, (long) sizeof (*viewport));
		viewport = NULL;
	}
}

closeviewport (vp)
struct ViewPort *vp;
{
	viewport = vp;
	freepict ();
}

/*
 * Premature termination routine.
 */
ackphft (str)
char *str;
{
	freepict ();
	die (str);
}
SHAR_EOF
fi
exit 0
#	End of shell archive

ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) (07/04/87)

[ Say, what happened to Scott Turner? ]

	Some lesser primate ( :-) :-) :-) ) asked if I could post a
uuencoded executable of my cheesy IIF reader program.  So here 'tis.

USEAGE:
	yaiffr filename [filename ...]

	The program will load each filename in turn, and when it's loaded,
ask you to press RETURN (I never said it was pretty).  When through viewing,
press RETURN again to proceed to the next file (if any).

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
Leo L. Schwab -- The Guy in The Cape	ihnp4!ptsfa -\
 \_ -_	 Bike shrunk by popular demand,	      dual ---> !{well,unicom}!ewhac
O----^o	 But it's still the only way to fly.  hplabs / (pronounced "AE-wack")
"Work FOR?  I don't work FOR anybody!  I'm just having fun."  -- The Doctor

_-_ Print out.  Cut here.  Feed what's below to optical character reader -_-_
begin 644 yaiffr
M   #\P         #          (   BC    O     $   /I   (HT[Z#GQ.
M5?_X3KH"'EBM  I3;0 (9P !)B!M  HO$$ZZ%*983TAZ 1X@;0 *+Q!.N@VR
M4$\I0(*L9@Q(>@$*3KH"Q%A/8,9(;?_X+RR"K$ZZ"?903TI 9@Q(>@#^3KH"
MIEA/8*@,K49/4DW_^&<,2'H! DZZ I!83V"2+RW__"\L@JQ.N@*T4$\I0(*.
M9@Y(>@#S3KH"<%A/8 #_<B\L@JQ.NAI,6$]"K(*L2'H ZDZZ%!983TAL@,Q.
MN@OZ6$\@;(*H*6@ (H*D2&R"DDZZ(3Y83R!L@J0Y:  .@J @;(*D.6@ #(*>
M*6R"CH*2(&R"C@@H  ( (6<&".P  H*C+RR"CDZZ +983R\L@HY(;(*23KHA
M,%!/2&R"DDZZ(3183TAL@I).NB$06$](;(#,3KH+A%A/3KH!1&  _M).N@&L
M3EU.=7( 1FEL92!O<&5N(&9A:6QE9"X 0V%N)W0@9&ES8V]V97(@9FEL92!T
M>7!E+@!.;W0@86X@249&(&9I;&4N ')E861F;W)M*"D@9F%I;&5D+@!786ET
M:6YG(&9O<B!Y;W4@=&\@<')E<W,@4D5455).+BXN  !.50  +PHD;0 (,"H 
M(,!\@ !G%# \ H"0:@ 82,"!_  "T6H '& 2,#P!0)!J !A(P('\  +1:@ <
M""H  @ A9Q0P/ &0D&H &DC @?P  M%J !Y@$C \ ,B0:@ :2,"!_  "T6H 
M'B1?3EU.=4Y5  !"ITAZ !Q.NA\\4$\I0(*H9@I(>@ =3KH UEA/3EU.=6=R
M87!H:6-S+FQI8G)A<GD 1&%L92!I<R!O=70@9F]R('1H92!M;VUE;G0N  !.
M50  2JR"I&<Z+RR"I$ZZ'ZQ83TZZ'\Q*K(*69PXO+(*63KH?)EA/0JR"EDJL
M@IIG#B\L@II.NA\26$]"K(*:0JR"I$JL@HYG#B\L@HY.N@BJ6$]"K(*.2JR"
MK&<.+RR"K$ZZ&!!83T*L@JQ.74YU3E4  &&*2JR"J&<*+RR"J$ZZ'AY83TY=
M3G5.50  +RT "$ZZ$;A83TZZ_V9.74YU3E4  "\M  A.NA&B6$]AP#\\ !1.
MNAO@5$].74YU3E7_UDCG##!"+?_=0BW_W$(M_]M(;?_>+RT "$ZZ!Q!03TI 
M9@IP $S?##!.74YU6:T # RM24Q"3?_>9R!(>@-V3KH12EA/("T #%F +P O
M+0 (3KH&^%!/< !@RDAY  $  $AX "A.NAV(4$\I0(*&9@I(>@->3KH'U%A/
M+RR"ADZZ'EQ83TJM  QO  +L2&W_XB\M  A.N@9T4$]*0&8*2'H#3$ZZ!Z98
M3U&M  P@+?_B8  "2"\M  @_/  !/RW_Z$AM_^I.N@>:3^\ #$AY  $  $AX
M "A.NAT64$\D0$J 9@I(>@,<3KH'8EA/<  P+?_L+P!P # M_^HO '  $"W_
M\B\ +PI.NAVV3^\ $$AY  $  $AX  Q.NAS44$\F0$J 9@I(>@+T3KH'(%A/
M)TH !$)K  I":P (0I,@;(*&,6W_Z@ 8(&R"AC%M_^P &B!L@H8A2P D&WP 
M ?_=8  !ZD*G+RW_YDZZ'(103R1 2H!F"DAZ K].N@;06$\O+0 (/SP  3\M
M_^@O"DZZ!M)/[P ,0J<@+?_FXX!R TZZ%)PO $ZZ'$A03R9 2H!F"DAZ I].
MN@:46$]Z #@%8#8P!$C XX!R !(R4 #H2>%!- 520G8 %C(@ .A+Z4/20S0%
M5$)V !8R( #H2])#-X$( %)$5D4P!4C L*W_YFW <  0+?_R<@'A8;)$9PI(
M>@)83KH/=EA/, 1(P"\ 3KH<DEA/(&R"AB%   0P!$C +P O"R\L@H9.NARN
M3^\ #" M_^;C@'(#3KH3\B\ +PM.NAO"4$\O+?_F+PI.NANV4$\;?  !_]Q@
M  #@+RT "#\\  $_+?_H2&W_WDZZ!>)/[P ,("W_WL"\  #__R!L@H8Q0  @
M&WP  ?_;8   K$HM_]UG!DHM_]QF"DAZ ?%.N@686$](;?_J+RR"AB\M  A.
MN@(03^\ #&!^+RW_YB\M  A.N@1T4$]@;B\M_^)(>@'73KH/DE!/+RW_YB\M
M  A.N@164$]@4)"\0DU(1&< _;*0O  !_!5GE)"\ /(([F< _UB0O  +] EG
M /Y$D+P !0SW9Z20O #S!0UGG)"\  K] F>4D+P# ?#L9XR0O O^$1)GA&"2
M("W_YI&M  P(+0  _^EG&%.M  P_/  !2'@  2\M  A.N@5*3^\ "F  _1!*
M+?_;9B0,;0%R_^IC"B!L@H8(Z  ' " ,;0$ _^QC"B!L@H8(Z  " "$K;(*&
M_]9"K(*&("W_UF  _'1&3U)-(&YO="!A;B!)3$)-+"!S:VEP<&EN9RXN+@!6
M:65W4&]R="!A;&QO8V%T:6]N(&9A:6QE9"X 36%L9F]R;65D($E&1B!&3U)-
M+@!":71-87 @86QL;V-A=&EO;B!F86EL960N %)A<TEN9F\@86QL;V-A=&EO
M;B!F86EL960N $5!(&-O;&]R=&%B;&4@86QL;V,@9F%I;&5D+@!#;VQO<FUA
M<"!A;&QO8R!F86EL960N %=A<FYI;F<Z($-O;&]R;6%P(&YO="!S:7IE9"!T
M;R!N<&QA;F5S+"!H;W!E(&ET)W,@2$%-+@!"3T19(&)E9F]R92!"34A$(&]R
M($--05 N %5N<F5C;V=N:7IE9"!C:'5N:SH@,'@E;'@* $Y5__I(YPPP0FW_
M_B!M  PB:  D)&D !"!M !!**  *9Q8@;0 0#"@  0 *9PI(>@&23KH#0EA/
M> !@.B!M  PP*  :2, O "!M  PP*  82, O $ZZ&4103S($2,'E@2!!T<HA
M0  (9@I(>@%Z3KH#!EA/4D1P ! J  6X0&6\> !@  $N>@!@  $4(&T $$HH
M  IF/"\M  @_/  !/Q(P!4C Y8 @0-'*,"W__DC (F@ "-/ +PE.N@+23^\ 
M#$I 9@I(>@$\3KH"K%A/8   S# %2,#E@"! T<HP+?_^2, F:  (U\ [4O_\
M2FW__&\  )HO+0 (3KH#[%A/&T#_^TH ;312+?_[$"W_^TB D6W__"\M  @_
M/  !$"W_^TB /P O"TZZ F1/[P ,$"W_^TB 2,#7P&!.<  0+?_[L'P @&8"
M8$!*+?_[;#H0+?_[2(!$0%) &T#_^Q M__M(@)%M__PO+0 (3KH#>EA/&T#_
M^E,M__M*+?_[;0H@2U*+$*W_^F#L8 #_8DIM__QG"DAZ (1.N@'>6$]217  
M$"H !;I 90#^Y# 2T6W__E)$N&H  F4 _LY,WPPP3EU.=55N<F5C;V=N:7IE
M9"!C;VUP<F5S<VEO;B!T96-H;FEQ=64N $)I='!L86YE(&%L;&]C871I;VX@
M9F%I;&5D+@!&86EL=7)E(&EN($)/1%D@<F5A9"X 0V]M<')E<W-I;VX@<75I
M=&4@<V-R97=E9"!U<"X 3E4  "\M  @_/  !/SP ""\M  Q.N@% 3^\ #$Y=
M3G5.50  +RT "#\\  $_/  $+RT #$ZZ 2!/[P ,3EU.=4Y5   _/  !+RT 
M#"\M  A.N@%:3^\ "DY=3G5.50  2.<(($JL@H9G  "\(&R"ADJH "1G?"!L
M@H8B:  D)&D !" *9UIX &! , 1(P.6 ($#1RDJH  AG+B!L@H8P*  :2, O
M "!L@H8P*  82, O # $2,#E@"! T<HO*  (3KH6R$_O  Q21'  $"H !;A 
M9;9(>  H+PI.NA8N4$](>  ,(&R"AB\H "1.NA8<4$\@;(*&2J@ !&<.(&R"
MAB\H  1.NA9L6$\O+(*&3KH6C%A/2'@ *"\L@H9.NA7L4$]"K(*&3-\$$$Y=
M3G5.50  *6T "(*&3KK_(DY=3G5.50  3KK_%B\M  A.NO>&6$].74YU3E7_
M_DCG#" D;0 (0FW__F T.BT #& F+RT $$ZZ 3PX +!\__]83V8,,"W__DS?
M!#!.74YU($I2BA"$4T5*16;64FW__C M__ZP;0 .;<(P+?_^8-A.5?_\2.<(
M("1M  @(J@ #  P(*@ "  QG'#\\__\O"DZZ#UY*0%Q/9PIP_TS?!!!.74YU
M8!8,;0 ! !!F#DJ29PH@*@ $D)*1K0 ,0JH !$*2/RT $"\M  P0*@ -2( _
M $ZZ!:Y*@%!/; 1P_V"\< !@N$Y5__PO"B1M  @_/  !0J<0*@ -2( _ $ZZ
M!80K0/_\""H  @ ,4$]G#" 2D*H "-&M__Q@#DJ29PH@*@ $D)*1K?_\("W_
M_"1?3EU.=4Y5  !(YP@@)&T ""\*3KH ,C@ L'S__UA/9R(P!$C 8!13D@CJ
M  , #'#_3-\$$$Y=3G5@UDJ 9_I9@&?D, 1@ZDY5   O"B1M  @@4K'J  1E
M#"\*81983R1?3EU.=2!24I(0$$B P'P _V#L3E4  $CG"# D;0 ($"H #, \
M !AG"G#_3-\,$$Y=3G4(J@ "  Q*J@ (9@@O"DZZ#SI83Q J  Q(@ @   =G
M,$'L@,PF2! K  Q(@,!\ (2P? "$9@P_//__+PM.N@WR7$_7_    !9![(*$
MM\AEUC\J ! O*@ ($"H #4B /P!.N@8V. !*0%!/;A1*1&8$< A@ G 0@2H 
M#'#_8 #_>C $2, DJ@ (T*H ""5   0@4E*2$!!(@,!\ /]@ /]:3E4  "\*
M3KH.:B1 2H!F"'  )%].74YU+PHO+0 ,+RT "&$&3^\ #&#H3E4  $CG"" O
M+0 03KH,U$'L@ (D2%A/2A)F$#E\  6"L'  3-\$$$Y=3G4O+0 ,+PI.N@9&
M2D!03V<$7(I@V#\J  0O+0 (3KH$/C@ L'S__UQ/9@1P &#*(&T $!%$  T@
M;0 0$7P  0 ,("T $&"R87!#[(*&1>R"AK7)9@XR/  ::PAT "+"4<G__"E/
M@K(L>  $*4Z"MDCG@( (+@ $ 2EG$$OZ  A.KO_B8 9"I_-?3G-#^@ @3J[^
M:"E @KIF#"X\  . !TZN_Y1@!$ZZ !I03TYU9&]S+FQI8G)A<GD 2?D  '_^
M3G5.50  +PI(>0 !   P+(*$P?P !B\ 3KH2'BE @KY03V840J=(>0 !  !.
MNA'>4$\N;(*R3G4@;(*^0F@ !"!L@KXQ?  ! ! @;(*^,7P  0 *(&R"LB L
M@K*0J  $4( I0(+"(&R"PB"\34%.6$*G3KH1TB1 2JH K%A/9RXO+0 ,+RT 
M""\*3KH KCE\  &"QB!L@KX :(    0@;(*^ &B    *3^\ #&!"2&H 7$ZZ
M$?1(:@!<3KH1LBE @L@@;(+(2J@ )%!/9Q @;(+((F@ )"\13KH0I%A/+RR"
MR"\*3KH%)"EL@LB"S%!/3KH0I"!L@KX@@$ZZ$-(@;(*^(4  !F<62'@#[4AZ
M "I.NA"N(&R"OB%   Q03R\L@LP_+(+03KKOYD)G3KH.[%!/)%].74YU*@!.
M50  2.<,,"1M ! @;0 (("@ K.6 *  @1" H !#E@"9 $!-(@$C T*T #%2 
M.4""TD*G,"R"TDC +P!.NA# *4""U%!/9@A,WPPP3EU.=1 32( Z #\%($M2
MB"\(+RR"U$ZZ 4Y(>@%(, 5(P-"L@M0O $ZZ!! _+0 .+PHO+(+43KH#KB!L
M@M1",%  .7P  8+0, 5(P-"L@M0F0%*+)$M/[P <$!-(@#H L'P (&<8NGP 
M"6<2NGP #&<,NGP #6<&NGP "F8$4HM@V P3 "!M>@P3 ")F+E*+($M2BQ 0
M2( Z &<>($I2BA"%NGP (F80#!, (F8$4HM@!D(J__]@ F#68#@@2U*+$!!(
M@#H 9R:Z?  @9R"Z?  )9QJZ?  ,9Q2Z?  -9PZZ?  *9P@@2E**$(5@SB!*
M4HI"$$I%9@)3BU)L@M!@ /]:0A)"IS L@M!20$C Y8 O $ZZ#YXI0(+,4$]F
M"$)L@M!@ /[8>@ F;(+48!XP!4C Y8 @;(+,(8L( "\+3KH(9%) 2,#7P%A/
M4D6Z;(+0;=PP!4C Y8 @;(+,0K ( &  _IH@ $SO P  !" (,B\ #& "$-E7
MR?_\9P9206 "0AA1R?_\3G5.50  2.<,(#@M  A.N@RD, 3!_  &)$#5[(*^
M2D1M"KAL@H1L!$J29A Y?  "@K!P_TS?!#!.74YU,"T #DC 4X O "\M  HO
M$DZZ#HHJ +"\_____T_O  QF#$ZZ#C(Y0(*P</]@RD*G0J<O$DZZ#F9/[P ,
M8+I.50  /RT ##\\ P$O+0 (80903TY=3G5.50  2.</,"1M  A.N@P4)FR"
MOG@ 8 XP!,'\  9*LP@ 9PY21+AL@H1M['H&8   Q @M  $ #&<P2'C__R\*
M3KH-TBP 4$]G("\&3KH.!B\*3KH-F$J 4$]F#DZZ#:(Z +!\ ,UF  ",2'@#
M[2\*3KH-L"P 2H903V9@""T    ,9@1Z 6!L2'@#[B\*3KH-DBP 4$]F"$ZZ
M#68Z &!42'@ (4AZ )).N@XV+@!03V<*+P=.N@W46$]@'DAX  %(>@""+P9.
MN@V82'C__T*G+P9.N@UR3^\ && F,"T #,!\!0"P? 4 9A@O!DZZ#.9Z!%A/
M.46"L'#_3-\,\$Y=3G4P!,'\  8GA@@ , 3!_  &($#1RS%M  P ! @M  , 
M#&<02'@  4*G+P9.N@T83^\ ## $8,)D;W,N;&EB<F%R>0   $Y5  !(YPP@
M."T "$ZZ"LXP!,'\  8D0-7L@KY*1&T*N&R"A&P$2I)F$#E\  *"L'#_3-\$
M,$Y=3G4P*@ $P'P  [!\  %F"CE\  6"L'#_8.!P # M  XO "\M  HO$DZZ
M#) J +"\_____T_O  QF#$ZZ#$8Y0(*P</]@M" %8+ P/'__8 0P+P ,(&\ 
M!$H89OQ32")O  A30!#95\C__&<"0A @+P $3G4P/'__8 0P+P ,4T!K%"!O
M  0B;P (L0EF#%-(2AA7R/_V< !.=6,$< %.=7#_3G4@;P $( @B;P ($-EF
M_$YU3E4  "\*)&T "$H29R @2E**$!!(@#\ 3KH%4K!\__]43V8(</\D7TY=
M3G5@W#\\  I.N@4X5$]@[$Y5  !(YPXP)&T "$*G2'H CDZZ#& I0(+84$]F
M"$S?#'!.74YU(&T #")H "0O*0 $3KH-2B@ 6$]G4DAZ &T@1"\H #9.N@T<
M)D!*@%!/9S1(> /M+PM.N@M<+ !03V<D( ;E@"H ($4E:  ( *0E1@"<2'@#
M[4AZ #A.N@LX)4  H%!/+P1.N@SH6$\O+(+83KH+AD*L@MA83V" :6-O;BYL
M:6)R87)Y %=)3D1/5P J $Y5  !(;0 ,+RT "$AZ!'!.N@"83^\ #$Y=3G5.
M50  2.<(("1M  X,;0 $ !)F""!M  @H$& <2FT #&\,(&T "'  ,! H & *
M(&T "# 02, H $)M !)*;0 ,;!!$;0 ,2H1L"$2$.WP  0 2,BT #$C!( 1.
MN@..0>R .%.*%+   #(M  Q(P2 $3KH#A"@ 9MI*;0 29P93BA2\ "T@"DS?
M!!!.74YU3E7_(DCG"# D;0 ()FT #$)M__HK;0 0__P@2U*+$!!(@#@ 9P "
M[+A\ "5F  +*0BW_,#M\  '_^#M\ "#_]CM\)Q#_]"!+4HL0$$B . "P?  M
M9@Y";?_X($M2BQ 02( X +A\ #!F$#M\ ##_]B!+4HL0$$B . "X?  J9A@@
M;?_\5*W__#M0__(@2U*+$!!(@#@ 8#)";?_R8!PP+?_RP?P "M!$D'P ,#M 
M__(@2U*+$!!(@#@ , 120$'L@$H(,  "  !FU+A\ "YF6B!+4HL0$$B . "P
M?  J9A@@;?_\5*W__#M0__0@2U*+$!!(@#@ 8#)";?_T8!PP+?_TP?P "M!$
MD'P ,#M __0@2U*+$!!(@#@ , 120$'L@$H(,  "  !FU#M\  +_\+A\ &QF
M$B!+4HL0$$B .  [?  $__!@$+A\ &AF"B!+4HL0$$B .  P!$C 8'@[?  (
M_^Y@%CM\  K_[F ..WP $/_N8 8[?/_V_^X_+?_P2&W_,#\M_^XO+?_\3KK]
MY"M _^HP+?_P2,#1K?_\3^\ #&!:(&W__%BM__PK4/_J+RW_ZDZZ @P[0/_P
M6$]@2B!M__Q4K?_\.!!![?\O*TC_ZA"$8"B0O    &-GXE. 9Y20O     MG
M /]T68!GM%6 9P#_<E> 9P#_=&#,0>W_,)'M_^H[2/_P,"W_\+!M__1O!CMM
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!.
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@
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*
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!T
M#]" TX&V@6($DH-20%'*__),WP ,3G4@;P $( A*&&;\D< @"%. 3G5.50  
M2&R XC\M  A.N@ (7$].74YU3E4  "\$."T ""\M  H_!$ZZ #"X?  *7$]F
M)"!M  H0*  ,2( (   '9Q0_//__+RT "DZZ /1<3R@?3EU.=6#X3E4  "\*
M)&T "B!2L>H !&48,"T ",!\ /\_ "\*3KH R%Q/)%].74YU(%)2DA M  D0
M@$B P'P _V#H3E4  "\*0>R S"1(($K5_    !8O"&$06$]![(*$M<AEZB1?
M3EU.=4Y5  !(YP@@)&T "'@ ( IF"G#_3-\$$$Y=3G5**@ ,9U (*@ "  QG
M##\\__\O"F%2. !<3Q J  U(@#\ 3KH$[HA ""H  0 ,5$]G"B\J  A.N@(N
M6$\(*@ %  QG$B\J !).N@+ +RH $DZZ A103T*20JH !$*J  A"*@ ,, 1@
MD$Y5__Y(YP@@)&T "$'Z_T8I2(+<""H !  ,9PIP_TS?!!!.74YU""H  @ ,
M9S @$I"J  @X #\$+RH "! J  U(@#\ 3KH"@+!$4$]G$ CJ  0 #$*20JH 
M!'#_8, ,;?__  QF$ BJ  ( #$*20JH !'  8*A*J@ (9@@O"DZZ )I83PQJ
M  $ $&8J&VT #?__/SP  4AM__\0*@ -2( _ $ZZ B*P?  !4$]FH# M  Q@
M /]J)*H "# J !!(P-"J  @E0  $".H  @ ,(%)2DA M  T0@$B P'P _V  
M_SY.50  +PI![(#,)$A**@ ,9QC5_    !9![(*$M<AE"'  )%].74YU8.)"
MDD*J  1"J@ (( I@ZDY5__PO"B1M  @_/ 0 3KH P"M __Q43V88-7P  0 0
M($K1_     XE2  ()%].74YU-7P$   0".H  0 ,)6W__  ($"H #4B /P!.
MN@#B2D!43V<& "H @  ,8,Y.50  2.< ,"1L@HI@%"92("H !%" +P O"DZZ
M!$Y03R1+( IFZ$*L@HI,WPP 3EU.=4Y5   O"D'Z_\8I2(+@0J<@+0 (4( O
M $ZZ _@D0$J 4$]F"'  )%].74YU)*R"BB5M  @ !"E*@HH@"E" 8.9.50  
M<  P+0 (+P!ALEA/3EU.=4Y5  !(YP PE\LD;(**8 X@;0 (48BQRF<2)DHD
M4B *9NYP_TS?# !.74YU( MG!":28 0I4H**("H !%" +P O"DZZ Z!P %!/
M8-A.50  +PHP+0 (P?P !B1 U>R"ODIM  AM#C M  BP;(*$; 1*DF8..7P 
M H*P</\D7TY=3G4P+0 (P?P !B!L@KXO, @ 3KH"F$J 6$]G!' !8 )P &#8
M3E4  "\M  A.N@)B2H!83V8.3KH";#E @K!P_TY=3G5P &#X3E4  $CG#" X
M+0 (3KH <# $P?P !B1 U>R"ODI$;0JX;(*$; 1*DF80.7P  H*P</],WP0P
M3EU.=3 J  3 ?  #9@HY?  %@K!P_V#D<  P+0 .+P O+0 *+Q).N@)>*@"P
MO/____]/[P ,9@Q.N@'L.4""L'#_8+@@!6"T3E7__$AX$ !"ITZZ LXK0/_\
M"   #%!/9Q)*;(+&9@@@+?_\3EU.=4ZZ  9P &#T3E4  $AX  1(>@ <3KH!
MT"\ 3KH!^C\\  %.N@ .3^\ #DY=3G5>0PH 3E4  $JL@MQG!B!L@MQ.D#\M
M  A.N@ (5$].74YU3E7__"\$,"T "$C *T#__$JL@KYG*'@ 8 H_!$ZZ -!4
M3U)$N&R"A&WP,"R"A,'\  8O "\L@KY.N@'L4$]*K(+@9P8@;(+@3I!*K(+D
M9PHO+(+D3KH!FEA/2JR"Z&<*+RR"Z$ZZ 8I83TJL@NQG"B\L@NQ.N@%Z6$\L
M>  $""X ! $I9Q0O#4OZ  I.KO_B*E]@!D*G\U].<TJL@LAF,$JL@M1G*# L
M@M)(P"\ +RR"U$ZZ 7(P+(+04D!(P.6 +P O+(+,3KH!7D_O !!@#DZZ 4@O
M+(+(3KH!?%A/("W__"YL@K).=2@?3EU.=4Y5  !(YPX@."T "# $P?P !B1 
MU>R"ODI$;0JX;(*$; 1*DF80.7P  H*P</],WP1P3EU.=0@J  < !&8(+Q).
MN@ *6$]"DG  8.(B+P $+&R"ND[N_]PB+P $+&R"ND[N_X(B+P $+&R"ND[N
M_[@L;(*Z3N[_RBQL@KI.[O]\(B\ !"QL@KI.[O\H3.\ !@ $+&R"ND[N_ZQ,
M[P &  0L;(*Z3N[_XBQL@KI.[O_$3.\ #@ $+&R"ND[N_]9,[P .  0L;(*Z
M3N[_OB(O  0L;(*Z3N[_IDSO  X !"QL@KI.[O_02.<!!$SO((  #"QL@K9.
MKO^43-\@@$YU3OH  B)O  0L;(*V3N[^8D[Z  ),[P #  0L;(*V3N[_.B)O
M  0L;(*V3N[^VBQL@K9.[O]\3OH  B)O  0@+P (+&R"MD[N_RX@;P $+&R"
MMD[N_HQ.^@ "+&R"MB)O  0@+P (3N[]V")O  0L;(*V3N[^ADSO  , !"QL
M@K9.[O[.(&\ !"QL@K9.[OZ 3.\  P $+&R"J$[N_A0@;P $+&R"J$[N_< @
M;P $+&R"J$[N_<P@;P $3.\  P (+&R"J$[N_@X@;P $+&R"J$[N_>0@+P $
M+&R"J$[N_<8@;P $3.\ !P (+&R"J$[N_GHB;P $+&R"J$[N_I@@;P $+&R"
MJ$[N_S1,[P,   0@+P ,+&R"J$[N_T B;P $+&R"J$[N_R),[P,   0L;(*H
M3N[_*")O  0L;(*H3N[_+BQL@JA.[O[R3.\#   $+&R"V$[N_Z @;P $+&R"
MV$[N_Z8@;P $+&R"V$[N_[(      ^P    !     0  #O(        #\@  
M ^H   "A<@      <BL    "=P    ,!=RL   ,"80    D!82L   D">   
M  4!>"L   4"        ,#$R,S0U-C<X.6%B8V1E9@   " @(" @(" @(# P
M,# P(" @(" @(" @(" @(" @(" @D$! 0$! 0$! 0$! 0$! 0 P,# P,# P,
M# Q 0$! 0$! "0D)"0D) 0$! 0$! 0$! 0$! 0$! 0$! 0% 0$! 0$ *"@H*
M"@H" @(" @(" @(" @(" @(" @(" D! 0$ @                  $     
M 0                     ! 0    $                      0(    !
M                                                            
M                                                            
M                                                            
M                                                            
M                                                            
M                                                            
M                                                            
M                                                            
D                         !0   /R   #ZP    $   /R
 
end