[comp.sys.nsc.32k] Estdio and Hybrid 1.5/1.3 on pc532, really kernel diffs

jkp@sauna.hut.fi (Jyrki Kuoppala) (02/21/91)

In article <9102191835.AA07256@lev.seri.gov>, sverre@lev (Sverre Froyen) writes:
In article <9102191835.AA07256@lev.seri.gov>, sverre@lev (Sverre Froyen) writes:
>Couple of bugs in Minix 1.5/1.3 that appeared:
>
>Pipes fail intermittently!  This caused the yinstall.sh script
>to fail and may be the cause of the failure of GNU diff3.
>My guess is that this is a kernel bug since I have seen it under
>shell, bash, and diff3 (both with Minix stdio and with Estdio).

Kludge fix:

Change

#define PIPE_SIZE        (NR_DZONE_NUM*BLOCK_SIZE)   /* pipe size in bytes  */

to

#define PIPE_SIZE        (NR_DZONE_NUM*BLOCK_SIZE*8)   /* pipe size in bytes  */

in fs/const.h and recompile the kernel.  Works fine for me.

While you're at it, also change:

#define MAX_STACK_GROWTH_PGS	16

to

#define MAX_STACK_GROWTH_PGS	1000

in kernel-1.3/alloc_32k.c, you'll need it when linking GNU emacs with
GNU ld (alloca doesn't work for anything bigger than a few bytes or so
with the original definition).

What the hell, here's all of my kernel diffs so far, they're supposed
to add non-blocking IO on ttys and fix some bugs.  Don't trust them or
ask me why they won't work for you or why they're so ugly ;-), they
just happen to work for me and might be useful for someone.  More
kernel diffs like those for ptys, TCP/IP, host-to-host scsi device
etc., and bug fixes to these are welcome, however.

You should also add FIONREAD to libc, I don't have the lib diffs at hand now.

And one more of those nice limits you'll want to fix is the
exec-family maximum argv / environment size - should be easy to find
somewhere in libc, don't have it handy now.

PS.  There's some of my backup stuff in
nic.funet.fi:pub/misc/pc532/jkp-backups/1.5 for the 1.5 kernel.  No
GNU binaries yet, but perhaps soon.  Bad news, many of the GNU
binaries for 1.3 don't work with the 1.5 kernel because a bit
different mechanism is used.

diff -cr orig-1.5.10/fs/const.h kernel/fs/const.h
*** orig-1.5.10/fs/const.h	Fri Feb 15 13:31:52 1991
--- kernel/fs/const.h	Sun Feb 17 02:23:18 1991
***************
*** 53,59 ****
  #define NR_INDIRECTS     (BLOCK_SIZE/ZONE_NUM_SIZE)  /* # zones/indir block */
  #define INTS_PER_BLOCK   (BLOCK_SIZE/sizeof(int))    /* # integers/block    */
  #define SUPER_SIZE       sizeof(struct super_block)  /* super_block size    */
! #define PIPE_SIZE        (NR_DZONE_NUM*BLOCK_SIZE)   /* pipe size in bytes  */
  #define MAX_ZONES (NR_DZONE_NUM+NR_INDIRECTS+(long)NR_INDIRECTS*NR_INDIRECTS)
  						     /* max zones in a file */
  #if (MACHINE == PC532)
--- 53,59 ----
  #define NR_INDIRECTS     (BLOCK_SIZE/ZONE_NUM_SIZE)  /* # zones/indir block */
  #define INTS_PER_BLOCK   (BLOCK_SIZE/sizeof(int))    /* # integers/block    */
  #define SUPER_SIZE       sizeof(struct super_block)  /* super_block size    */
! #define PIPE_SIZE        (NR_DZONE_NUM*BLOCK_SIZE*8) /* pipe size in bytes  */
  #define MAX_ZONES (NR_DZONE_NUM+NR_INDIRECTS+(long)NR_INDIRECTS*NR_INDIRECTS)
  						     /* max zones in a file */
  #if (MACHINE == PC532)
diff -cr orig-1.5.10/fs/device.c kernel/fs/device.c
*** orig-1.5.10/fs/device.c	Fri Feb 15 13:31:54 1991
--- kernel/fs/device.c	Sun Feb 17 17:10:13 1991
***************
*** 194,199 ****
--- 194,202 ----
   */
  
    int task_nr, major_device;
+   register struct fproc *fp; /* jkp */
+ 
+   fp = &fproc[ mess_ptr->PROC_NR ]; /* jkp */
  
    if (fp->fs_tty == 0) {
  	mess_ptr->DEVICE = NULL_DEV;
diff -cr orig-1.5.10/fs/open.c kernel/fs/open.c
*** orig-1.5.10/fs/open.c	Fri Feb 15 13:31:57 1991
--- kernel/fs/open.c	Sun Feb 17 16:44:28 1991
***************
*** 262,269 ****
   */
  
    if (find_filp(rip, bits & W_BIT ? R_BIT : W_BIT) == NIL_FILP) { 
! 	if (oflags & O_NONBLOCK) return(bits & W_BIT ? ENXIO : OK);
! 	suspend(XOPEN); /* suspend caller */
    } else if (susp_count > 0) {/* revive blocked processes */
  	release(rip, OPEN, susp_count);
  	release(rip, CREAT, susp_count);
--- 262,272 ----
   */
  
    if (find_filp(rip, bits & W_BIT ? R_BIT : W_BIT) == NIL_FILP) { 
!     if (oflags & O_NONBLOCK) {
!       if (bits & W_BIT)
! 	return ENXIO ;
!     } else
!       suspend(XOPEN); /* suspend caller */
    } else if (susp_count > 0) {/* revive blocked processes */
  	release(rip, OPEN, susp_count);
  	release(rip, CREAT, susp_count);
diff -cr orig-1.5.10/kernel-1.3/alloc_32k.c kernel/kernel-1.3/alloc_32k.c
*** orig-1.5.10/kernel-1.3/alloc_32k.c	Fri Feb 15 13:32:43 1991
--- kernel/kernel-1.3/alloc_32k.c	Sun Feb 17 17:34:01 1991
***************
*** 61,67 ****
  #include "proc.h"
  #include <minix/mmu.h>
  
! #define MAX_STACK_GROWTH_PGS	16
  
  extern char end[];		/* end of data segment, symbol created by ld */
  static long first_page_adr;
--- 61,67 ----
  #include "proc.h"
  #include <minix/mmu.h>
  
! #define MAX_STACK_GROWTH_PGS	1000
  
  extern char end[];		/* end of data segment, symbol created by ld */
  static long first_page_adr;
diff -cr orig-1.5.10/kernel-1.3/tty.c kernel/kernel-1.3/tty.c
*** orig-1.5.10/kernel-1.3/tty.c	Fri Feb 15 13:32:54 1991
--- kernel/kernel-1.3/tty.c	Sun Feb 17 19:22:06 1991
***************
*** 428,433 ****
--- 428,435 ----
  {
  /* A process wants to read from a terminal. */
  
+   int code;
+ 
    if (tp->tty_inleft > 0) {	/* if someone else is hanging, give up */
  	tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO);
  	return;
***************
*** 440,446 ****
    tp->tty_inleft = m_ptr->COUNT;
  
    /* Try to get chars.  This call either gets enough, or gets nothing. */
!   tty_reply(TASK_REPLY, m_ptr->m_source, (int) tp->tty_inproc, rd_chars(tp));
  }
  
  
--- 442,453 ----
    tp->tty_inleft = m_ptr->COUNT;
  
    /* Try to get chars.  This call either gets enough, or gets nothing. */
!   code = rd_chars(tp);
!   if (code == SUSPEND && m_ptr->TTY_FLAGS) { /* hja */
! 	code = EAGAIN;	/* NONBLOCK */
! 	tp->tty_inleft = 0;
!   }
!   tty_reply(TASK_REPLY, m_ptr->m_source, (int) tp->tty_inproc, code);
  }
  
  
***************
*** 613,620 ****
     * Oops, even bitmapped terminals need suspension after an XOFF.
     */
    if (tp->tty_outleft > 0) {
  	tty_reply(TASK_REPLY, (int) tp->tty_otcaller, (int) tp->tty_outproc,
! 		  SUSPEND);
  	tp->tty_waiting = SUSPENDED;
    }
  }
--- 620,630 ----
     * Oops, even bitmapped terminals need suspension after an XOFF.
     */
    if (tp->tty_outleft > 0) {
+         int code;
+         if (m_ptr->TTY_FLAGS) code = EAGAIN; /* hja */
+         else code = SUSPEND;
  	tty_reply(TASK_REPLY, (int) tp->tty_otcaller, (int) tp->tty_outproc,
! 		  code);
  	tp->tty_waiting = SUSPENDED;
    }
  }
***************
*** 714,719 ****
--- 724,738 ----
  	/* Discard current input and output. */
  	tty_icancel(tp);
  	tty_ocancel(tp);
+ 	break;
+ #endif
+ #ifdef FIONREAD
+      case FIONREAD:
+ 	r = tp->tty_mode & (CBREAK | RAW);
+ 	if (tp->tty_lfct > 0 || (r != 0 && tp->tty_incount > 0)) 
+ 		flags = tp->tty_incount;
+ 	else flags = 0;
+ 	r = OK;
  	break;
  #endif
    }

Real fix for the pipes (I haven't tested this):

From: kevin@nuchat.UUCP (Kevin Brown)
Newsgroups: comp.os.minix
Subject: Fix to Minix pipes (1.5.10)...
Message-ID: <1991Jan15.194514.3841@menudo.uh.edu>
Date: 15 Jan 91 19:45:14 GMT
Reply-To: kevin@nuchat.UUCP (Kevin Brown)
Organization: Teenage Mutant Ninja NiceGuys [tm] :-)
Lines: 288

When playing with GNU tar, I discovered that Minix pipes have an arbitrary
limit of how much you can write to them using the write() system call (and,
it turns out, how much you can read from them).  Needless to say, this limit 
should not exist at all (it doesn't on any Unix I've ever played with.  On 
most versions of Unix, large writes to pipes are just blocked).  So instead 
of fixing GNU tar to work with this arbitrary limit, I decided to fix Minix 
itself.  The following patch reflects the changes I made.  UUdecode the 
following, and then decompress it.  This will give you a file, pipe.patch, 
which you should apply by moving it to the directory containing your fs 
source code and doing a "patch <pipe.patch".  Be sure to save the originals
somewhere, just in case (I did enclose most of the changes in an #ifdef/
#endif pair.  You can define WIMPY_PIPES if you don't want most of my
patches to be compiled, though the field additions to the fproc structure
will still be there.  See the comments I put in there for an explanation).

These changes have NOT been extensively tested, so be sure to keep your
current Minix image around in case it acts up on you!  I had some strange
problems, but I think I've fixed them (you have to treat MM's requests
differently from that of other processes.  Sigh.  Since the file system 
is a Minix process, and is SUPPOSED to be "generic", it shouldn't have to 
treat MM's requests any differently from anyone else's).  There were a 
couple of times I was REAL WORRIED about the consistency of my file systems 
on my hard drive in testing the previous versions of this thing.  :-)

Right now, it seems to be stable.  Either way, though, I would NOT recommend
trying out this code on your hard disk without making sure it works properly
on a floppy-based system or, better yet, the RAMdisk.  This is easy to test: 
make a root file system on a floppy and tell the menu that it's your root 
file system.  If you have shoelace, then ask someone how to test the kernel 
in floppy mode only.  I don't use shoelace, so I don't really know...

If anyone sees any fatal flaws in my logic, please notify me immediately
(preferably by posting a message to this newsgroup)!

The way it works is this: The file system's main loop looks through the
list of processes for one that has been suspended (i.e. had not finished
servicing a system call when the resource being used ran out.  This
manifests itself mainly in writes to or reads from a pipe).  If it finds
one, it simply repeats the same system call that had previously been made,
but with fewer bytes left to process (the part of the message that
contains how many bytes to process, nbytes, is modified by the system call
code itself, so this value always reflects how much work, if any, is left).

I have added two fields to the file system process structure.  One keeps
track of how many bytes were originally requested, and how many are actually
left to process.  This was necessary to insure that do_read() and do_write()
will return the proper values for large reads/writes dealing with pipes.


So let's say we're writing to a pipe, and we want to write 10000 bytes.
Well, the pipe size itself is only 7168 bytes, so we have to break the write
up into multiple writes of at most 7168 bytes each.  This is done in
do_read() and do_write().  These two routines had originally just called
read_write() with the appropriate flag (read or write).  They now do the
following:

	* Check to see if the file being operated on is a pipe.  If not,
	  then just call read_write() with the appropriate flag and
	  return the appropriate result.

	* Otherwise, check to see if the amount of work to do is less than
	  the size of the pipe.  If so, then just call read_write() with
	  the appropriate flag and return the appropriate result.

	* Otherwise, we have a request that's bigger than the pipe proper,
	  so we loop, calling read_write() with nbytes of at most PIPE_SIZE
	  bytes.  Each time we go through the loop, we decrement the amount
	  of work left to do by the file system by the amount read or written
	  as a result of the call to read_write().

Now, the reason I added the two new fields to the process structure in fs
is so that if you try to request a large data transfer to/from a pipe, the
proper number of bytes that have actually been processed will be returned to
the caller.  Since read_write() and everything that read_write() calls
depends on nbytes, which is basically a global associated with the given
process, we can't store the large value there because read_write() doesn't
like large values for nbytes when dealing with pipes.  So we keep track of
how much work we actually have to do, and how much work was requested, by
keeping those values in the process structure itself.  This is guaranteed
to work, because the process' request will be repeatedly invoked until the
system call is done (either because the work is finished or because of an
error).

GNU tar is happy now, and so I'm happy now.  At least until I find that
there's some nasty and subtle bug in my code...:-)

So here's the compressed and uuencoded patch file.  Enjoy!


--
			Kevin Brown
		Addresses in preferred order:
		    csci31f7@cl.uh.edu 
		nuchat!kevin@uunet.uu.net


table
 !"#$%&'()*+,-./0123456789:;<=>?
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
begin 644 pipe.patch.Z
M'YV-*@*">,.&S(LQ;]S,H>,"30(J=<J 4!+&#8@8-2[.T#$CA@X8,2[FR!%#z
M08N3(! J9.@0HD2*%C%JY.A1!@V1)!4$W,FSIPJ= F^PB#$#!$\%($",(%/&y
M3!HW$IU(^9+$R1,B1:8DW<IUAHP$+U0H!3&'S1LZ<T \!2%B+4(Y942H=?.&x
M*0@Z8<2PD:CB!5*E3)U"!2'URY0J4(I(T<JU<0VP8D>0-8MV+MDZ<,K( :'Ww
MS9@U=_/N->HWJ8(0@)L^E6ADBF$J088L^2(D"Y6L25'(N"'#*-DT>LJ\,0,"v
MQ1@T83:K2)$"1-C?P0<2=SIZ3IZ%9=J0Q?N9]-^_SYNDF3.F#!LV%8772:MRu
M8<7*??\N53WX<.*I38(<23)D*PP\1-U@!&0@M!'&&6F, 8(;=;0AAF8I)837t
M:F18-@=FFK7067?QG=0""$(1!8*'+<@7V&J$35755;@UMI57!$I6UEEIK=66s
M16_%-5==$N&E%U^EI2985%/9IQAC+B;UV',R4E:C11=FMMF&H/DX6GRFH3;?r
MD""T]EILL]5V&V,HQ "#3;[- 9QPQ!F'G'+,.2>6FM$-!P)U$EF'G7;N<1@Dq
M>&*)1YYYZ$'UQGH1KO1>6E@*B:*1^.G'GW\ SB @@08BJ""##D*HTH105;A6p
ME!E2Z9U/J 8$E%@TQ, "#388M9-)*+7Z*@XC>F@B?1)59<0320;[U7-WH*&9o
M1&N1$09>7[PAQQEJ/6G&&W?*\89V8M211D'>);4EBD4X0<073QCQA1%),%%$n
M8RV820.!;(+ %!UEC$%OA8TJL(*C@QDQ;GY3+)%  C#<< .F8>!QY[82,46>m
M'&G 08>ST8)@0U'Q[0LH"$1HEH8=951(9QF,!OGM8%H\X4017SA111.&):'%l
MNEN-/!P*>B14QA=NR)%" HTQR5D>]#X)0LZ#]9Q4HR<3^041*:_<\LN-H5!8k
MU"R[W,04+<CP<]"1':VST4_QR%5\.PU4T MFP&'M& T]%-%$%5V4$5$T?112j
M#".5Y.&=;GL6MTMTQW3W1C/ H$,-.>!44JJHK@J"##*PL)NLJOY-^:LPY'K2i
M7TD=EQS@7^ UQQH[#$Q@L0FB$=KI%0>NX(5S9.8&4Q4FU.U63]%!.AQID)'Zh
MP,_)3G*-^ :95.^_GR$'',,3:/P<:3E_*!S>:;SO<U08>R=!9MWQ%+1TW$&Mg
M4^:1D59R$JT7LF5T>"^"@<=1"WQF<J71!AQ[M5&&&WBA0QH2P@+.U($.^EH:f
M")(@KX2<P'?_&X-9YM C8VEG+74;01K,<+NF@. *26@"%++P!2@D(3%:>= 8e
MPN"^XH2A.7DXU DJA!R0)= W$P,!7+*UK0K%3R+_$R!<0+ &S4"%#6HA3@SKd
M (([O.=].12=&\Y008G<KPPW%(O^^)>=("YK@&XH8$4JA (Q-,=]FPF<\\+0c
MAK3$;UGR*H/M<F>1^(UG.W*H@[WJ )<"EL$%9W!!%D$ ASD4T'QUX%8->T2Mb
M!T5H?PRKD/CB=Q?OS8&-$@&A"$EH0A3&43!I$*#NPC"'0;[1=W;Z(1&-:!X0a
MU*&#FV'=<=3BNSM&"0YOH* /J95'-[@@*=U;U@G<^ 9JM4&/:!BD^>2PA@+.z
M@5H,# ,;G'B=N4BP#G91Y;3.\P;Q3?$NYEM8^M)2K#+\<#,_S,,)AAB&/4J3y
M#7D8I/MRMQFZ,"2+?MG7\@"8E+:5[BS2% /12#:\YTP,+T@4:-'N0BTRG(]Bx
M=DS+&Z3T1=UEC'?\))U"2;87,]"AH&+9:%HZZKL<.O1[Z$3#'2>JF8I:Y*)_w
MZ0/@WK:%PD!!"D\8PA2ZL(/O).4Y1DA#^D!@!VE&9 Z_1)M "&*0,YAE<'.#v
MB=UFTA&].8Y6'W+J&Z#ZDKK)!&^)6USC^)83R/E$<F8:2D:.\K>TQB!6)/I+u
M$;!P&RDX82Z^<R@ OP 7_N4!I MREH'.DP<0P& '9#$G0R^RV*>H5 RAU*$<t
MX;F[N=;UKLRC'1R^@)!7?I1X8N'4@S9C)]FE1;/_P]U +'+%RM)5,9CE)USLs
M\+'Q 5:T$"IMQ*SXMN.1;+&.G.W'WG=1R\(6KPLJPQTX^T[ AF2#R;T#6:Y#r
M+^VL\#Q^9 ,%#>O:RTK'#*73H;*,109<S@&PY@TE&!<+ES!4* S&<F]WC[N0q
M/-IK1W91@1S&&[(OE(TIJ2O>&WH'H1S^EY&2E2]\RR#?1AG7KBEYTYWZM(8Mp
M>&D*L)$-;6R3%9X22)5!'<T4J)N=86ZGG6M(JE_2QM07&.@I+AB#W+IJ.*IZo
M!"17_=N+?2ECPDGUJXA3'..N:M:>2"YQ+)A!K(Z2E%])X0I!D (1B#K@"F4+n
MO+@D" I2T-,F/^')49ZR':H\8?^Z(91;[G*7O@QE*5,Y>""@(AV^((9BSAD.m
MR<$DO>0PAS2?9LU@=O.8X2SG+RQS#7[V<J"GS!0[A-<L[N4K&Q,-Z#:+F<R0l
M)L,72"4'2F,5!$A6LN=*I&A+O]G*=<!R,=E :2>;>M 5,L,<S(QF+O_%U6$^k
M=9S-26<[?P'/<M"S9OIL:]3@VLW,*_2A6\WF7#?ZT6^(=+#;P.Q%ZSK3F\90j
MIVUMFB(?)6TVJ)P-<,5D$(!.3B#HWAWOJ,H=@\ L$ZTD'.5,3F<UDY"]I=YOi
M0RG&VR7V=FGI*QN$BM3=)85UHT$!%:10A2(T9P]_3H"R[9UFT":V,L6BUAC+h
M?%TDYBLI"6@;"'H  A.TC:89][" "8Q.^[TM-#_"HQY]UZ@$</H+:!QY<=K6g
M A_XLREFT%:%>D#RPWRA"DF8\@_2S?!UZ:!+06#"%!R.V)_.J0Y+[Q!*PLV"f
M<8_:IUOAGDIKY$;ON1O>V#OEKC%N[P).CX(UHD._19;:@$^6X"H^-\(EHO"Fe
M/SSB4%ENQW4^<696G$ 4Q#@:-.YO63/W/+O[2\BQ1W*3RVX+*0^P6'#)\L7*d
M#N;5H8-]:1XDFVL;YQ3<#,E1P'.?;Q;H0A]YT:MP]*2#8.D+;S@(GFZ$J$^=c
MRV&_>M97[&U5I0T'-6!!#FY2[K 0_?G0C[[TIT_]ZEO_^M;_R594H#J)\_K0b
MW6^,]I>&_?*;__SHCWY\4'/3)%@A"+?1=>$1G8(_[R%+P2>,8-]96"=&=EKUa
MI%QS 0<']$L@@ 3=5 8@(P<%!%WKI("U-44G$"U_MGV!Y0;!82UB=!FUDUKOz
M\W8%LAZ^XTAAX$1%%"J")'Y_PA5P@2#8L1GU-7,SY1E&\3P]]3?(IWP9$5=6y
MEWX^^(- V /C9Q3=-W_A=S:@HP)!N(1,6'WK!P+M]W[QEVS?1W'UAQKW9VZHx
M877Z)P>#15G^YSL &%T#6(!)@8!WH(":T8#$\8"T15L22(%;J$!T@8&:\08;w
MB%H=5"$@>$P+P1D248)A<((A8X!28$Y\I!",M4$5J$!I*%GE,5SO52#'<R!Ev
M4$ 4DX'4 EV/*%P@,XEOEX)GLX);T8+CL6<R=U\G1X/Z!3VKXFUH!0/)%P.Tu
MB#GCISK/TW/^I(>J17)6006&4053D!CB4@1$@%AA01?OEA!4M!G(,47C4W,#t
MDXNNQU<0^(DZ]XM?( 5%8 7N5Q5'H&:X>(WC<Q(]A1KC2 >)*(X)T >2AV=Gs
M-@8H( +S%R&)1 9N\$"2]8:!Z 8Q!!4B4$!6,35-P&U;X8YM!0,V,!0QT!L\r
M" *X" >ZN%F\^#Z^^ 3 >!C#&"Y8<8QRHHQF,440\HP(,D72F #4Z$^>:)&$q
M@9';V(W?Z 3A*'G32(Y39(X15Y/J* <6@0(P8) #XXX@!X\),H_UV%D%D8^^p
MLY(@4!'_&!<"^00$:9!)X8[%9WP"08NS* .=PU8H08L+V9 .J2NFP149IW-Mo
MX )ML&F'(@?EH6;]-&N#1W)IN99TD >9T5/Z)%D[V9,Q8)!":6[=ME1KTUYDn
M$&,S5CA3!58WUAMDY3<H89B(Z6->=3AY P.=\YBO6&22(P.N(@/D-BO>\A37m
M9!<B &QLU! B(!^DR0;8)!$BP&FJ^1T?TC1=\B]!$##!DA0%<S#/82 *@R=Ql
M]# 1,S&;<4<7XQT?\A=1"'_KXC_48XFN!)WG97'4*9UC2$IK,#X@, 59@&&Yk
MN00HY4JI%R%P4%@?5VFYQCQR('AH\$KT=X,HX9F6 U>Z<I4_D39>D62AJ2K;j
MUX0 &J"- @55( 1,,"G,XU#6Z%Y;]A<0-X=PT9<H8)B&!C'T@@+<& 1$ ([,i
MH6:!29LH@61O=1,/:10!>J)+.* %>J#]D:!OL*!DT*!)\:!:J!0;U$'$H4DCh
M5$(GE!4$0@3&U$Z+1TB[E1:OM!?4PU#<<A;&TI[C 22-&(/W=6 U&#'G6#.Bg
M)X/4@3TJ8 97FA2F^(+(-3)?*EDNB(JB(P=BT09Y<&57VHC/<07'0DN!)880f
MY3UFT$XEA1R^<T5IL4A-"1T2,7!MP&]-Z6_Q@RB(5!"-Z!MTX87\QY>)" )%e
M8 1"D 1'D$25)!%N(%*$E&?^@XII.$030RWH\2R7V$02L:ADT*ABH08BF!+Od
ME&":=@<66@9;=JA6UC ZTT2AY#JA9(!5X 8 J(Y/!$]N5Z0-Y*H@ *AJ5Q%Tc
MD0?<^2 U-$ ,2!;4\H@(L3__<TGT,IZ1U:1_Y*I^@1IP*A9!Q6>^HZW&TATYb
M1$'(0ARA9&+MEAW.4E@&X@:6F%+"Q![OQ)WK(4ASZ!M)0!S/5$ _9!&/"*M_a
MB&=)JH9R0#0J]4W2Q(SLQ6"U>JM;=D@J=1S,BA=%Y*]#9"=-T 3C&;!)(:=-z
M23T-(A$EVT0.Y#LMY*<N4+/D^F>-"%TH<)9$!P(E6T(X-00M(P57")$1.JD3y
MBK$5&DI\EZ$;*I,=BK-S*';_HZH15B]50BWPJJD153':E ;J>A?ZLZIE< (@x
M XA5VW'O X ?.W:2%0='Q1!)4;!T.AX(:RP*BRQG)D#2M":;*JA$952_-88_w
MQ*RAF!1/<$[B0T&'-*@,=K9V-$7K$Y+C.K!/F+-M$GB/QP9_AXXCHW.=.E#Gv
M%7&MYT\'%5"BJW-D2KH268TB15*JNR9EZH[F.K5BX03=9+5R]K=;JJM_2Z6<u
M!T":88!TFX8/6*<-Q)UA0*29P0)M6[4+&ZN#1Z&VRK1;1KS$8;Q#](QD,' 4t
MR[RI&C^'<@9HX+R6NZEYVZQA +G4(GH,5DN^0TJ!VH%CD ;2)*L4)+"C*+6\s
MTR8[1WB\MJ6L1P9QTK-.D"[GDBY0T!Q'RY/%H1ERP%D\4FS]6QPA@ *LIXO;r
MLEEEDP(]EP:_MEO,$7$-W)/4J[%.RZ$4S+]<B+O2Q:Y8NUA;"UVJQ$:'PD]Vq
M<F@# 3$E&:EP ;<D<R^R:A$/PJQ!QP;4L1>2]*NK)1&#ET,G;+TI,'>:>K!6p
MR["^TW',&L47VAP;5\+ZNWWE6J/+TR:ENUFGRP:>R@,DUTDL,P4RXW @0*-_o
MID%F$!@<4P1"4 5'$'%NTSMM(@(*:IA;]G2&R9TE8&6IFQ#E4;,NP 5N$) +n
M(E(4G !_#$"!C )I[*DDE\@I ,F2?,;_A%"4?*4CD%J,6+M&BX@.G+215KT7m
MFL)0N\)S2+MDC&Y!L*=W%+QRIZIF"T3NH1?C05[RMJZKNBU(Y*R-U%Z@@1F;l
MNL5E ,1_V#L:YSM[04HE%4[ AA8&* 0'5$EWY#\5479PI$JM-1Y*R:R0!2W_k
M,[ZNDT/<.QK:E$A(],-Q:X!R>KQG4 =Y)KQ0U$AFT1VOQ!1RT+:YY,0)00;Jj
ME1"&A*V:*I56X00&FE/BZ42GE1GUBSZ2)!%8+*D.7 3Z$015$<9+,\:8NW,:i
MS :;90;H<09I80(@ -$J,]&R4;0HR<H]"=)'(-).0,OYAP3'0J_R(\YT(!>Ih
MY#W2= ;.\JMIF12Y#,YIP<N-^\L)-G#!X4-\RJS:*Q%*S9WORC^1Y<RJ=&@&g
MV#T2X11A&[G0\H@G94OK&XC4]+PIP4=PP4^\#"%79@804D;UPD+;]8CB WDMf
M%%D&IA!\5$'E;"S0?+]Y#2%W?9RGI5C.'#A20EEKP6"SQ+3!)DIND (D[1USe
MR*97IG-NDAS+T=AR\*:VJW\O/*C%A#V>M2V;"A<FIHQMX"RK:F_ Q:M0D7=Sd
MN'<[U[K^]+I-X3L^8%B="Y&ANU"K)\K$[5$@<-QN'#,STQQ+-]UP/#.[!S@3c
M26>B2U*FO$%XC!5[W,?H>,ET$,B#C+&%'%C2=<C?E,A#4S2.#,H%M-PD0\&Gb
M?#NI#)&?2W)<C*NR? 0^32#Y?+8&DDW>8\]!?+&OK+&>G;)\:K4G90;6HAWBa
M&G&^P11S)%%UM. X';BN2;9Q=A;8^[<E+.)S,QX:+A9(2LX6H8EW"[U<?1:'z
M"@(0["Q4W+5W5"QPU(DXW>*+I4IJ*P<G_HA*';]'<X<SGKXIOGAIN( %XI1"y
M[JG(L:M5^W90])YID:>;@0+KP<^$%:B:2(GC7,Q";L[Y1D[(#(B<$=!%1 ;.x
MU+[>4U0C;K4I'M@)A47HB$-H8"UW8!&"6%AKH78KQ+@&I.1E+DW/9.:*J'9Cw
M?:L%W>=B@1SL,4%;;D6[Y;NSJDK*@A?PXSVM=>5-R0:&&4^4CK86(9E)T00,v
M=F;?]*Q+;BU#7.J-+LX6403ELEI_>T6>+>3%6^-*GEX"=+9V'A%-;K5.H3"Ju
MA-J$-&#"VW)"SLM#CJ=@^X<;5<SJ.P=*J>KXYAF^52%Y8$YS)^1*S1DH5NV,t
M! ?Z"S27BXXZ^[D\@-QS7,?B[4'DS<<YB=[J_:*$G )/E^.;8<@XC<AD8-^"s
MJM^H; 8YF>(H,#*5;,L1]QRZ;@0[S(&VHR:Z4UIKCL^\K8\KU$=7'*LE+.10r
M'H*SI,/&>[9ZE2?GDQSM#MH0&>]^V[,_V? ASGK"C<8 I<:I^R'._=W%7>#/q
M<00VOKS$/EPJ'J^ZJUA=Z^5SKNQIH#!BK=BI[NR/;1EN(T=YQMGCJ4I0@0?Pp
MVU*<'?-/F #.3I=MFFH@L"^KBXZBS?8DA]JSR\+H-@6D2>(K1,1YLAYS]#X8o
M!'D1U;CJR[YN?B%P\;&\%.(U[$Y(A%ND11R>VO((V_,&&/1%0U+,&LX588F*n
M3*M+V\51S]8Q6_@(=E).J=:-=4^6.\9V/-YZK.]SR._%(<C^SMX #P*'V)<&m
M/]^_99C5<BW@^\B17$"-RMW5N,D_C_S#+?0>I?#\S? 0FO.BK/P+!?0[[]V9l
M/_2JK13FL5W/(01E *@#5T1_N]0]C$3KS:!>[&\=/;U*"\NX&N%/Z/ !CJ$@k
M_;0$#OT*31QQ&D([RHUIA4;QH093\9$<(V$HR");=&YDRO>3"! 'Y.BL]O0%j
M6-J!D#T?1 HD 2H CDH.3*,2FP:C8<"?5.] #H$8 NT*-& 0,E!4W$!YD&%Ei
M@.D))ST79P =0VDD:2"0R+R!H;.2GNXX;H6&TTRHB/'!OD"C\6 ^8-8 ITWCh
MMSX$?DL+]<<$WC0)5:DN%8%3,S3I.1R'&#:&I%(0@ +$:,I80&BA=3X$Y4@^g
M,J C?!VNX "U"P24/!-PN8Q!#'@%-" 'E$D>\,UYAC40 NO%"/P[)O YH, 8f
MM@);X M\5S%04\W -F<]I$NIX@PYT+=!I 30 W/)0K,(0)#7"$&(T;I V!'Le
M.4HP83#!Z. $*1E-FH*)" 5404QED+*@6-B"W:$+?H$O& ;O1$L[%5<)K<P d
M'# 4: #&F!6:PP;0 ,O!&];@)'P.50 .?#J$YEF&C>]Z; 5'&CF[%4!RC@-\c
MTCSD":^E&KVV&=P+&8 +24H:/<$140W?DQM '03"4XV[DM)() +PNRAV#$=]b
M$ #(27K4%$@@ P/S<93B1@XCS#5,AZEK'>XV6E7Y$$KV\'[1CR:-@0;A7Z@%a
M-?2'YQ ;>BK@U^B\W.X8&#[0(CQ$:Q@1I8<E]'J39&+Q+H9Q$:T283((\F\Rz
M197*9&,^@F/J&Y\F)?:8E5AC&--'R$PP$3\AP*'0GW["W\@!EB,DE*CTI$%<y
MH&LR3;)F-NV+HEB:) (/, -C ("P@8;@ Q((4SR*3K%0G1D\<!"N!55D34;Qx
M-;&%*S.;1E-81(H,HRS:J+,(FU81W$ #J\DL-D6V<&"4XEJ<BZ<)5*G%JR@6w
M8Y.V48NWIMD@&WXB_[Z @8 #?D8GIHW-(0,:1[DQ42@J,J8?%66@$!0_45#Rv
M3T;5.]3P'*" 9@! VB'26:\[5D!0VWVC9--E3\BJ\R )P11.<V49RWK5P0VHu
MPCP4V/DT,F 6#9FA*!E[H_FAC"P*N6!&".>@^%<\Q&,ZJAZBD!\5I.H'^#)2t
M;N#%*:G<H;B>E,Q+"E*JEM"%_,()RU1V7!@JS2AXJ484IE!19I%=Y+$,G"E/s
M\2;6U-H;CZJ,"\FI(1)9[,G7PU-Z2MOY*=,WO_P6H3)4&R=1U9M[Q*P>U1<Jr
M+"EN%68J&N8]QB%J"E408E0Q$E.5'*@(X6-5S.K]S:K[U_YV50,9#"&1E@@Kq
M8N4LC)7P0E;/<5F=+V<UX:#5&Y!6WX1:K2]K-?H0&K=2",OBK%&,<'4L/MN[p
MRS_IZ@_!,'>EM1(A=)E794<B^(_;%K&FG+YJ1L7,Q'0<@(54F!7=LF():^0Uo
M+%*2%B"6Q%)>(8E\++X')\4X5NOX6(/HMX0\B4"R3-880ED?)!"Q+/_ALTR6n
M^>AV,ZM(.;*;%1\UU<X:4CWK9]V4G#*T;)K]BW^WJCC,QCNX_[H?%S)KZ0L6m
M9JW$PO1X7))<&&EM;/FRL_4@TM8[65O.HFW=$0:W$$Y<9+%;Z,MJ/07UTK>Bl
M@RKY7,=N<-TI/G<VOEUYH!X&*'$UJ<65JA[1-8-<$\NEE3J=X2--VAS269JKk
MXR0WFU/S)IGHNE*3I[M9O]]"<MX>1-*'98$?5DOT6,OLWG-P84UO3YVU#>:[j
M5 GP@G9[YLB5K2%B'QV*\@)?YJM69LGH]8?@'YGL8NKR>,6S=WE%[I8[BY<6i
M:%Y*!&5V%]H+_%I9\PNCV2\D<N@JU_[JDSKK?Y&<0B/ [E@!\T4(#%TP@07Fh
MT7H2!)-@3(&"E3$+AL',0$KC8'0!"8(P7V<H<][]6Y2UD7^=*]9FM20E#*R4g
M2.VV>1;I +.8R0[+@4_!AT6SN/4^]AX@,F*))(F]CQ#9JY[8F(R-HL]W01<Kf
M1B^SV#M9;%!S_ODN,,8G;YG.JGX];XVUL1Y%W>08'=,2]XXXY#OS!I%HWSP:e
MCE+LZ<"RWN>I&-D?J5D([PE6,K<I C19V$Q=G8R (3RP2<I$%__K;R3,92)*d
MV6@'8V:?E'BK[:EU+:FV*8&9E1AF6^[''3/(0S#% #-S)6G'ZM5*4JD=<P@<c
MN69_J'S8C^3 S9*"-]-E:0'7D3-Q";ZB13H[7^L,Q]&%.D"^%DL\JR)W@IZ]b
MK7N6LM8E5^-GP<:?[1(]*-!@B4';+BI!H7&VAM;HH(M,DVA,@*(U$?E%OS:(a
M4-EH(*"C)<B0-M*ZYDG+8#YG@U7 EO;28EK+F&G9LZ8ESKY4''0:3_-I7 BHz
MT;9+.3_>EU$C#C6,#2@U"X4&FAH(D)QNBW*N/'?(8*Q:YD0@YVNKE3BOIK7 y
MFLP*G;F-F90U:Y?6@B6%VT2GY:TUI;AVOH@<70LBSZ[S.#N^MD):"&!K<X.-x
M'<X%Q(?8Q.5B2RC;T+&A2PAA2R0;]J!LFL&R603,!JSVC$OY=:VO$<4]XK!Zw
MTM1IRZ&IS5O>KMSE*U^;*P$@LNV<E*VT8-MP6\^<E(ZDY;7&)J)2$@ZVA%W'v
MC032J 0P#IM;]GMNQ@T*D<WL)L>NVQR-8]OMC!:W\';'\%WL8YN6#&)@LMH'u
M-[O8TZ$++\Q"T4W15=^*G[,L&H=3^OFW9ODR&R?4ZGX&KFPA./<"/$FG@\N:t
MUTO":<X&$OPPW+$0<ARN[O Z59+B8J7N,G%S"X""./KI2EE<JI..;R3&,;E4s
MB>2.WA"5 ];B6@5(M]7C)AR0ZTMICLXYL4]IY&+I*U5TNU1@=LQFE8"D7+Y"r
M=1#)-U@Y^=(I6<N:VW*(PB*"N0L1J997F9.=:"[5J3EPEZ1HH".A$B$CZJD2q
M5WI,)Y4[I97NKI( .D%'34(='&F8I?&;F=,[9.N,R:N;G7]+_DVZ;%KIY)<$p
M.6A83=-E!DXG^+S'IUM>A4[4;3I2)TU.796+@:L.8QD@5U<1O%J+G'74PF@Ro
M.H-:-RK>*M6HF0&),M0%DKV$7:!*>L9.<"6[1[3L_A;6VZ'2+M51NQSRM<)6n
MME,[EJ[;=5-;&>Y P#HL=ZGNW(F!=$=4O<?$8'<MSEC.O#8A[^@=C7I]?K2\m
M[3M!FMX(Z8O*C+E/X&VW$F;P$![$,V4+#^?1SX>W)B(>_R(0+I5BZ"&-9Q$Xl
M'CLM.''R0X(\]D'XQ&>02W4G[YBD/-VV0#^DR[L3,"^K1AR:%QULGDU#A:V,k
M<**NZ\?\-@L<)7IBP>@-NX^H]&II35T[4 VR7JM&QU.G'NA\9E</BJ;0:*?Uj
M^DK76R^$JT&6 ;%'2\@>&#%[8PSMR5:U-]K<'K>$2$M4Y]"]1@0Y\P_><X%Zi
MKVXXDHHD*@1=1465CZAS]KW$5T(7'_UL?,;J\36(T<(S)Y_.*(C2Y/*]4><'h
M06LEYWN2[T.@@#ZT6B,%J^\@F*C/'ZD^ \/Z'J:-ZJ-J\X\V(KY92.??T]E]g
MB6B1+A181B_JB/W8+<1/DAT_S>KS.*L>?7YP-2%.O[E*83T5]NMNG[7[G3(Wf
MB&[$'_E+ ^9/E:"_H*G^SBJ$\UT:$O)P2$EX*.\EKH*9LRS#]C]TDQQYE"<Ae
#@+<1d
 c
end


--
			Kevin Brown
		Addresses in preferred order:
		    csci31f7@cl.uh.edu 
		nuchat!kevin@uunet.uu.net
//Jyrki