Newsgroups: alt.sources From: jepler@nyx.cs.du.edu (Jeff Epler) Subject: AAT 1.0 -- Another Animation Tool (part01/01) Message-ID: <1993Jul21.205013.3511@mnemosyne.cs.du.edu> Sender: usenet@mnemosyne.cs.du.edu (netnews admin account) Organization: Nyx, Public Access Unix (sponsored by U. of Denver Math/CS dept.) Disclaimer1: Nyx is a public access Unix system run by the University of Disclaimer2: Denver for the Denver community. The University has neither Disclaimer3: control over nor responsibility for the opinions of users. Date: Wed, 21 Jul 93 20:50:13 GMT Lines: 1048 This is version 1.0 of AAT, Another Animation Tool. AAT allows you to use a simple script-language to mostly automate the process of animation when used with your favorite raytracer/renderer. AAT should compile on any ANSI-C compiler. Version 1.0 has been tested on DOS GCC, DOS TurboC 2.0, and GCC on a Sun4. (An earlier version, 0.2, was successfully compiled on many UNIX platforms.) Unlike previous version of AAT, the need for another program, Rayscene, is removed. AAT does the whole process of reading a script and source-file and writing many destination files. Just unpack the Shar archive and type MAKE. The executable aat should end up in the directory. If you don't use gcc, you'll need to edit makefile, however. (Larger modifications will be needed if you don't have an ansi c compiler.) If you have any comments about AAT, send them to jepler@nyx.cs.du.edu #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'aat/aat.c' <<'END_OF_FILE' X/* Another Animation Tool X X Created by Jeff Epler X X This program is a middle-man, creating files suitable for use by X RAYSCENE. With the commands available to you, creation of animation X will be easier than the use of the RANGE command that was a part of X RAYSCENE. Just create a data file like in simple.aat and pipe it X to aat. Stdout will contain a file suitable to be a rayscene X array. X X You are free to use and improve this program. If you make any X signifigant revisions to it, please drop me a line... X X internet address jepler@nyx.cs.du.edu X X version 0.1 07-10-93 Very limited control, linear movement only X X version 0.2 07-14-93 Added other types of motion, RANDOM option, X changed format to add more flexibility. X First version released on the Internet. X X version 0.3 07-15-93 Fixed some silly booboos (RANDOM didn't work, X the name of the program was wrong in the output X file.) and updated README to list info about X platforms it's been compiled on. I'll now say X that I'm confident it'll compile on most any ANSI-C X compiler. X Added SIN-type motion X Added frame-omission and frame-addition options X To emit only one frame of every F, invoke AAT: X aat -oF [...] X X To increase the number of frames by a factor of F, X invoke AAT: X aat -mF [...] X X If the -o option is used, the last frame is always X output. The -o and -m options cannot be used X together. X X A note to TurboC users: Due to the braindead-ness X of DOS, the 80x86 architecture, Borland compilers, X memory models, and anything Intel related, you'll X need to decrease the max_frames or max_variables X constants to make this compile. As packaged, the X array 'double variables[][]' is bigger than the X 64K limit on structures. Get GCC or another decent X 32-bit compiler and stop worrying about it! X X aversion 1.0 07/22/93 A new note to TurboC users: I wrote workaround code X for the variables[] array -- Now it's allocated at X runtime, and can exceed 64K. The upper limit on X frames is probably about 64k/sizeof(double) right X now. You should compile with the large model (MAKE X should do this for you, however.) X X Very nearly a complete substitute for Rayscene now X -- Using a style very much like Rayscene, one can X generate many .POV/... files with just AAT. X That's what the 1.0 means. X X Command-line is changed: X X aat -mX -oX -bNAME -iNAME AAT-NAME X X The switch letters are not case sensitive. X -m and -o specify to Multiply or Omit frames. X (X is an integer.) -b specifies the base name X for the output files. -i specifies the name of X the original file. AAT-NAME is the name of your X .aat file. All have reasonable defaults. -m X and -o both default to 1, -b to aat, -o to X aat.pov. AAT-NAME has no default value. X X The only feature really lacking in this program X vs. rayscene is script generation. However, I X feel that this is trivial -- With a decent UNIX X shell script or (for DOS) a relatively simple X alias/batch under 4DOS can do it. A batch for X 4DOS to render all .POV files in a directory is X now included in the distribution. X XInput file structure: X XVARIABLES: // Two slashes comment rest of line. X = // No spaces here X [ ... ] X XFRAME [integer] // Whitespace where shown here. X // Tabs, spaces, returns are all whitespace. X X [ FRAMES ] X [ TO [ MODE ] [ FRAMES ] ] X [ RANDOM [ FRAMES ] ] X [ SIN [ FRAMES ] ] X [ ... ] X XEND X XThe following modes are supported: X 1. Simple linear motion X 2. Acceleration X**2 X 3. Deceleration 2*X - X**2 X 4. Start & Stop -- Starts as #2, ends as #3 X X X*/ X X#ifdef __TURBOC__ X#define arraycludge X#else X#undef arraycludge X#endif X X#ifdef __TURBOC__ X#include X#else X#include X#endif X X#include X#include X#include X#include X#include X X#ifdef test X#undef stdin XFILE *stdin; X#define inname "test.pov" X#endif X X#ifndef hasstrcmpi X X/* Returns 0 if equal, !=0 if unequal */ Xint strcmpi(const char *s1, const char *s2) { X while (toupper(*(s1++))==toupper(*(s2++))) if (*(s1-1)==0) return 0; X return *(s2-1)-*(s1-1); X} X#endif X X X#define max_variables 64 X#define max_idlength 16 X#define max_frames 500 X#define REPCHAR '$' X#define suffix "pov" X#define banner \ X"/* This file was generated by AAT 1.0\n"\ X" Another Animation Package was written by Jeff Epler\n"\ X" jepler@nyx.cs.du.edu\n"\ X"*/\n" X X#ifndef RAND_MAX X#define RAND_MAX 0xffff X#endif X X#define frand() (rand()/(double)RAND_MAX) X X#ifdef arraycludge Xdouble **variables; X#else Xdouble variables[max_variables][max_frames]; X#endif X Xint vpointer [max_variables]={0}; Xchar vnames [max_variables][max_idlength]; Xint vflags [max_variables],vv=0; Xint fnum; X Xint fileline=0; Xint name2number(const char *variablename) { X int l; X X for(l=0;l */ X /* TO [ MODE ] [ FRAMES */ X /* RANDOM */ X int i,by,f; X double old,new; X X if (!strcmp(word,"FRAMES")) { X word=readOneWord(aatfile); X f=m_option*atoi(word); X word=readOneWord(aatfile); X } X i=name2number(word); X if (i==-1) { fprintf(stderr,"Error: Unrecognized identifier \"%s\"\n",word); exit(1); } X if (vpointer[i]>bf) { fprintf(stderr,"Error: Variable %s redfined at frame %d\n",vnames[i],bf); exit(1); } X word=readOneWord(aatfile); X if (strcmp(word,"TO")&&strcmp(word,"RANDOM")&&strcmp(word,"SIN")) { fprintf(stderr,"Error: Expected token \"TO\" or \"RANDOM\" but got \"%s\"\n",word); exit(1); } X if (!strcmp(word,"TO")) { X int fr; X word=readOneWord(aatfile); X new=atof(word); X word=readOneWord(aatfile); X if (0==strcmp(word,"MODE")) { X word=readOneWord(aatfile); X by=atoi(word); X word=readOneWord(aatfile); X } else by=1; X if (!strcmp(word,"FRAMES")) { X word=readOneWord(aatfile); X fr=m_option*atoi(word); X word=readOneWord(aatfile); X } else fr=f; X old=variables[i][vpointer[i]-1]; X for(l=0;lhf) hf=vpointer[i]; X X X for(i=0;ivpointer[0]) fcount++; X X X for(fnum=m_option;fnumvpointer[0]) { X#ifdef test X out=stdout; X printf("%s%04d.%s\n\n\n","pov",++i,"pov"); X#else X sprintf(filename,"%s%04d.%s",basename,++i,suffix); X out=fopen(filename,"w"); X fputs(banner,out); X#endif X in=fopen(inname,"r"); X while(!feof(in)) { X fgets(linebuf,160,in); X expand(expanded,linebuf); X fputs(expanded,out); X } X fclose(in); X#ifndef test X fclose(out); X#endif X } X X fprintf(stderr,"%d frames output\n",fcount); X } X X return 0; X X} END_OF_FILE if test 17403 -ne `wc -c <'aat/aat.c'`; then echo shar: \"'aat/aat.c'\" unpacked with wrong size! fi # end of 'aat/aat.c' fi if test -f 'aat/aat.o' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'aat/aat.o'\" else echo shar: Extracting \"'aat/aat.o'\" \(9712 characters\) sed "s/^X//" >'aat/aat.o' <<'END_OF_FILE' XX ÿ²`° Ò@X`ÿ€¢ $€X X`ÿ²`ÐN@Xàÿ€¢ $€X X X Another Animation Package was written by Jeff Epler X jepler@nyx.cs.du.edu X*/ X Â*` X Â*` X Â*` X X Â*` X Â*` X Â*` X Â*` X Â*` X Â*` X Â*` X X@X¿èÐ@@X!X@X¦ ÿþ echo shar: 123 control characters may be missing from \"'aat/aat.o'\" if test 9712 -ne `wc -c <'aat/aat.o'`; then echo shar: \"'aat/aat.o'\" unpacked with wrong size! fi # end of 'aat/aat.o' fi if test -f 'aat/aatlang.doc' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'aat/aatlang.doc'\" else echo shar: Extracting \"'aat/aatlang.doc'\" \(1539 characters\) sed "s/^X//" >'aat/aatlang.doc' <<'END_OF_FILE' XInput file structure: X XVARIABLES: // Two slashes comment rest of line. X = // No spaces here X [ ... ] X XFRAME [integer] // Whitespace where shown here. X // Tabs, spaces, returns are all whitespace. X X [ FRAMES ] X [ TO [ MODE ] [ FRAMES ] ] X [ RANDOM [ FRAMES ] ] X [ SIN [ FRAMES ] ] X [ ... ] X XEND X XYou may have one VARIABLES: block, but many FRAME blocks. The FRAMES Xcommand should only appear at the top of a FRAME block, otherwise the Xparser will probably think it's a FRAMES modifier to the previous command. X X XData-file structure: X XAAT understands little about the structure of your renderer's input-file. XIt makes a couple of assumptions: X XThe banner inserted at the top uses /* and */ to signal a comment. If your Xrenderer doesn't do this, you can yank the banner altogether, or change the Xtext in the delimiters only. I'd prefer the second, obviously. X XIf your renderer uses $ as a meaningful character, you'll have to change Xthe program's #define REPCHAR line. X XAAT copies from the data-file to a generated file, character-for-character Xuntil it enocounters a $ symbol. Then, it reads to another $ or a Xwhitespace. Then, the value of the named variable is written to the output Xinstead of the $ and the text following. X X END_OF_FILE if test 1539 -ne `wc -c <'aat/aatlang.doc'`; then echo shar: \"'aat/aatlang.doc'\" unpacked with wrong size! fi # end of 'aat/aatlang.doc' fi if test -f 'aat/compat.doc' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'aat/compat.doc'\" else echo shar: Extracting \"'aat/compat.doc'\" \(1759 characters\) sed "s/^X//" >'aat/compat.doc' <<'END_OF_FILE' X[ This came to me in mail, about compiling version 0.2 of aat. ] X X XHi Jeff, XI just found your posting of 'aat' in alt.sources, and gave it a try. I Xthought it's quite nice, so I checked its portability on some local systems, Xall running under some flavour of Unix. I hope you find this list helpful: X X- Compiling on DEC 5000/33 under Ultrix 4.3: Xcc: One warning about 'const char *' not yet being implemented Xgcc: Everything ok X X- Compiling on DEC Alpha 300 under OSF1 10.41: Xcc: no problems X X- Compiling on Sun Sparcstation II resp. SS 10 under SunOS 4.1.2 / 4.1.3 Xcc: doesn't like the function headers at all - had to break up e.g.: X int main(int argc, char **argv) Xinto X int main(argc, argv) X int argc; X char **argv; X X(It's an old, non-Ansi compiler). After these changes, everything went fine. X X- Compiling on IBM RS/6000 under AIX (2.3, I suppose): Xcc: no problems X X- Compiling on Hewlett Packard 9000/755 under HPUX A.09.01: Xc89: (POSIX-conformant C compiler) no problems Xcc: requires un-prototype'ing (sp?), just like on SUNs. after that, no probs. X X- Compiling on Apollo Domain DN3500 under DomainOS 10.3: Xcc: no problems X X- Finally, compiling on our good old Ftp server - PCS Cadmus under MUnix 3.2Aa: Xcc: didn't find include file 'stdlib.h', some unresolvable symbols - but this Xshould not worry you, it's an OLD system :-) X X X[ Stuff omitted ] X XBye for now, XFrank X-- X+ Frank Neumann, Hauptstr. 107, 26131 Oldenburg The Amiga still is it. + X+ InterNet: Frank.Neumann@arbi.informatik.uni-oldenburg.de IRC:Franky + X+ UUCP:neumann@uniol.uucp InHouse:amigo@faramir Z-Netz:Neumann@uniol.zer + X+ 'When this function is called, we are in BIG trouble. [...]' + X+ - from: AmiTCP, maint.ps, p. 89: void panic(const char *fmt, ...) + END_OF_FILE if test 1759 -ne `wc -c <'aat/compat.doc'`; then echo shar: \"'aat/compat.doc'\" unpacked with wrong size! fi # end of 'aat/compat.doc' fi if test -f 'aat/makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'aat/makefile'\" else echo shar: Extracting \"'aat/makefile'\" \(379 characters\) sed "s/^X//" >'aat/makefile' <<'END_OF_FILE' X# This is for GCC: XCFLAGS = -O -c XCC = gcc XLFLAGS = -o aat -lm XOBJ = o X X# This is for CC: X#CFLAGS = -O -c X#CC = cc X#LFLAGS = -o aat -lm X#OBJ = o X X# This is for TurboC: X#CFLAGS = -ml -c -Dhasstrcmpi X#CC = TCC X#LFLAGS = -ml X#OBJ = obj X Xaat: aat.c X $(CC) $(CFLAGS) aat.c X $(CC) aat.$(OBJ) $(LFLAGS) X X strip aat X# Comment that for TurboC X X# aout2exe aat X# Uncomment that for DOS GCC END_OF_FILE if test 379 -ne `wc -c <'aat/makefile'`; then echo shar: \"'aat/makefile'\" unpacked with wrong size! fi # end of 'aat/makefile' fi if test -f 'aat/manypov.btm' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'aat/manypov.btm'\" else echo shar: Extracting \"'aat/manypov.btm'\" \(383 characters\) sed "s/^X//" >'aat/manypov.btm' <<'END_OF_FILE' Xrem This BTM file demonstrates how 4DOS can do a directory-full of Xrem POV files at one shot, eliminating the need for a script file Xrem generated by AAT Xfor %p in (*.pov) do ( Xif exist %@name[%p].tga c:\graphics\povsrc\povray.exe -i%p-o%@name[%p].tga -l c:\graphics\pov +c %& Xif not exist %@name[%p].tga c:\graphics\povsrc\povray.exe -i%p -o%@name[%p].tga -l c:\graphics\pov %& X) X END_OF_FILE if test 383 -ne `wc -c <'aat/manypov.btm'`; then echo shar: \"'aat/manypov.btm'\" unpacked with wrong size! fi # end of 'aat/manypov.btm' fi if test -f 'aat/readme' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'aat/readme'\" else echo shar: Extracting \"'aat/readme'\" \(6232 characters\) sed "s/^X//" >'aat/readme' <<'END_OF_FILE' X/* Another Animation Tool X X Created by Jeff Epler X X This program is a middle-man, creating files suitable for use by X RAYSCENE. With the commands available to you, creation of animation X will be easier than the use of the RANGE command that was a part of X RAYSCENE. Just create a data file like in simple.aat and pipe it X to aat. Stdout will contain a file suitable to be a rayscene X array. X X You are free to use and improve this program. If you make any X signifigant revisions to it, please drop me a line... X X internet address jepler@nyx.cs.du.edu X X version 0.1 07-10-93 Very limited control, linear movement only X X version 0.2 07-14-93 Added other types of motion, RANDOM option, X changed format to add more flexibility. X First version released on the Internet. X X version 0.3 07-15-93 Fixed some silly booboos (RANDOM didn't work, X the name of the program was wrong in the output X file.) and updated README to list info about X platforms it's been compiled on. I'll now say X that I'm confident it'll compile on most any ANSI-C X compiler. X Added SIN-type motion X Added frame-omission and frame-addition options X To emit only one frame of every F, invoke AAT: X aat -oF [...] X X To increase the number of frames by a factor of F, X invoke AAT: X aat -mF [...] X X If the -o option is used, the last frame is always X output. The -o and -m options cannot be used X together. X X A note to TurboC users: Due to the braindead-ness X of DOS, the 80x86 architecture, Borland compilers, X memory models, and anything Intel related, you'll X need to decrease the max_frames or max_variables X constants to make this compile. As packaged, the X array 'double variables[][]' is bigger than the X 64K limit on structures. Get GCC or another decent X 32-bit compiler and stop worrying about it! X X aversion 1.0 07/22/93 A new note to TurboC users: I wrote workaround code X for the variables[] array -- Now it's allocated at X runtime, and can exceed 64K. The upper limit on X frames is probably about 64k/sizeof(double) right X now. You should compile with the large model (MAKE X should do this for you, however.) X X Very nearly a complete substitute for Rayscene now X -- Using a style very much like Rayscene, one can X generate many .POV/... files with just AAT. X That's what the 1.0 means. X X Command-line is changed: X X aat -mX -oX -bNAME -oNAME AAT-NAME X X The switch letters are not case sensitive. X -m and -o specify to Multiply or Omit frames. X (X is an integer.) -b specifies the base name X for the output files. -o specifies the name of X the original file. AAT-NAME is the name of your X .aat file. All have reasonable defaults. -m X and -o both default to 1, -b to aat, -o to X aat.pov, and aat-name to aat.aat. X X The only feature really lacking in this program X vs. rayscene is script generation. However, I X feel that this is trivial -- With a decent UNIX X shell script or (for DOS) a relatively simple X alias/batch under 4DOS can do it. A batch for X 4DOS to render all .POV files in a directory is X now included in the distribution. X XInput file structure: X XVARIABLES: // Two slashes comment rest of line. X = // No spaces here X [ ... ] X XFRAME [integer] // Whitespace where shown here. X // Tabs, spaces, returns are all whitespace. X X [ FRAMES ] X [ TO [ MODE ] [ FRAMES ] ] X [ RANDOM [ FRAMES ] ] X [ SIN [ FRAMES ] ] X [ ... ] X XEND X XThe following modes are supported: X 1. Simple linear motion X 2. Acceleration X**2 X 3. Deceleration 2*X - X**2 X 4. Start & Stop -- Starts as #2, ends as #3 X X X*/ X XThis version (1.0) of AAT is a complete replacement for Rayscene. With one Xprogram, you can now process .aat scripts and output files for your Xrenderer. (As shipped, AAT works perfectly with POV 1.0 -- For other Xrenderers, some of the options will need to be changed. This will probably Xrequire source modifications.) X XTo see AAT in action, just type: Xaat simple.aat -isimple.pov X XThis will read the script simple.aat and the POV file simple.pov. It Xshould produce 25 frames named aat0001.pov .. aat0025.pov. X XNow, you must have POV render all 25 frames, and then use some other tool Xto make the separate frames into an animation. (Unlike Rayscene, AAT Xdoesn't generate a script for you. It's my opinion that it's easy enough Xto write a shell script for a UNIX shell or the DOS shell 4DOS that this Xwasn't on my priority list.) When you're done, you'll be treated to a very Xsimple show: Above a rotating checker plane, a sphere changes size and Xcolour. X XSee the file aatlang.doc for details about AAT files and how to insert Xvariables in your data-files. (If you're familiar with Rayscene, you Xshould be able to write data-files immediately. $ is used for the Xvariable-signal character, and a variable-name is terminated with either Xwhitespace or another $ symbol. The only difference you should worry about Xis that AAT does _not_ allow whitespace in variable names.) END_OF_FILE if test 6232 -ne `wc -c <'aat/readme'`; then echo shar: \"'aat/readme'\" unpacked with wrong size! fi # end of 'aat/readme' fi if test -f 'aat/simple.aat' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'aat/simple.aat'\" else echo shar: Extracting \"'aat/simple.aat'\" \(519 characters\) sed "s/^X//" >'aat/simple.aat' <<'END_OF_FILE' Xvariables: X X red=0 green=0 blue=0 X radius=.5 X X floor=0 X Xframe 1: X floor to 180 frames 25 X red to 1 frames 5 X radius to 2 mode 4 frames 15 X Xframe 4: X green to 1 frames 5 X Xframe 6: X red to .5 frames 10 X Xframe 7: X blue to 1 frames 5 X Xframe 9: X green to .5 frames 10 X Xframe 12: X blue to .5 frames 10 X Xframe 16: X radius to .5 mode 4 frames 10 X Xframe 22: X red to 0 frames 3 X green to 0 frames 3 X blue to 0 frames 3 X Xend END_OF_FILE if test 519 -ne `wc -c <'aat/simple.aat'`; then echo shar: \"'aat/simple.aat'\" unpacked with wrong size! fi # end of 'aat/simple.aat' fi if test -f 'aat/simple.pov' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'aat/simple.pov'\" else echo shar: Extracting \"'aat/simple.pov'\" \(584 characters\) sed "s/^X//" >'aat/simple.pov' <<'END_OF_FILE' X#include "colors.inc" // The include files contain X#include "shapes.inc" // pre-defined scene elements X#include "textures.inc" X Xcamera { X location <0 2 -6> X direction <0 0 1.5> X up <0 1 0> X right <1.33 0 0> X look_at <0 1 2> X} X X Xobject { X sphere { <0 $radius$ 2> $radius$ } X texture {color red $red$ blue $blue$ green $green$ phong .7 phong_size 40} X} X Xobject { light_source { < 2 4 -3 > color White } } X Xobject { X plane {<0 1 0> 0 } X texture { X checker X color Red X color Blue X X rotate <0 $floor$ 0> X translate <0 0 2> X } X no_shadow X} END_OF_FILE if test 584 -ne `wc -c <'aat/simple.pov'`; then echo shar: \"'aat/simple.pov'\" unpacked with wrong size! fi # end of 'aat/simple.pov' fi if test -f 'aat/todo' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'aat/todo'\" else echo shar: Extracting \"'aat/todo'\" \(1395 characters\) sed "s/^X//" >'aat/todo' <<'END_OF_FILE' X(This isn't in any sort of priority ordering. It's just here. -- Xdenotes things that haven't been started, // things that are half done.) X X X-- Make source-code less of an ugly mess. Not all that stuff belongs in X main() that finds itself there anyhow. (Sorry, this only happens when X someone else does it, or I get really bored.) X X-- Add internal representation of vectors: X to < > [...] X X-- Make aat read rayscene .arr-style files. X X// Write a decent description of the input-file structure than is in the X readme file. X X There's now something better than there was before. But it could X be better. I prefer to add a new gimmick than explain the ones I X already have. X X// Add a way to relate two or three variables (IE based on one, constrain X other so that the two are a point on some circle) X X Partially answered need -- With the SIN-type motion, you are able to X do this. It's still annoying to do, though. (Nearly as annoying as X using sin.exe that rayshade provides.) Ideally, I would have something X like: X X CONSTRAIN TO BY CIRCLE X [ FRAMES ] X X (where the three doubles would be center X, Y and radius so that: X (variable1-double1)**2+(variable2-double2)**2==(double3)**2) X X However, I'm not sure how I'd prefer this to work, exactly. X END_OF_FILE if test 1395 -ne `wc -c <'aat/todo'`; then echo shar: \"'aat/todo'\" unpacked with wrong size! fi # end of 'aat/todo' fi echo shar: End of shell archive. exit 0 -- Jeff Epler jepler@nyx.cs.du.edu (Preferred) or bx304@cleveland.freenet.edu ____ "Nuke the unborn gay whales" -- Never seen on a protest sign \bi/ I have no time for petty theft, I have no time for sex, \/ But I have time for what I like, And that is what is best.